diff options
-rw-r--r-- | lib/zebra.h | 1 | ||||
-rw-r--r-- | zebra/rib.h | 1 | ||||
-rw-r--r-- | zebra/zebra_fpm.c | 2 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 324 | ||||
-rw-r--r-- | zebra/zebra_static.c | 16 | ||||
-rw-r--r-- | zebra/zebra_vty.c | 7 | ||||
-rw-r--r-- | zebra/zserv.c | 5 |
7 files changed, 214 insertions, 142 deletions
diff --git a/lib/zebra.h b/lib/zebra.h index da069d1df..5bb7dfaf4 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -471,6 +471,7 @@ extern const char *zserv_command_string (unsigned int command); #define ZEBRA_FLAG_STATIC 0x40 #define ZEBRA_FLAG_REJECT 0x80 #define ZEBRA_FLAG_SCOPE_LINK 0x100 +#define ZEBRA_FLAG_FIB_OVERRIDE 0x200 #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ diff --git a/zebra/rib.h b/zebra/rib.h index 285166f06..96301a8af 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -87,6 +87,7 @@ struct rib /* to simplify NHT logic when NHs change, instead of doing a NH by NH cmp */ #define RIB_ENTRY_NEXTHOPS_CHANGED 0x2 #define RIB_ENTRY_CHANGED 0x4 +#define RIB_ENTRY_SELECTED_FIB 0x8 /* Nexthop information. */ u_char nexthop_num; diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 220fddaf6..bc9d22e00 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -892,7 +892,7 @@ zfpm_route_for_update (rib_dest_t *dest) RIB_DEST_FOREACH_ROUTE (dest, rib) { - if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) continue; return rib; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 775619ac2..6bd5417ac 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -432,7 +432,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, /* if the next hop is imported from another table, skip it */ if (match->type == ZEBRA_ROUTE_TABLE) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -628,7 +628,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -793,7 +793,7 @@ rib_match (afi_t afi, safi_t safi, vrf_id_t vrf_id, { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -929,7 +929,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -949,7 +949,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id) /* * This clone function, unlike its original rib_lookup_ipv4(), checks * if specified IPv4 route record (prefix/mask -> gate) exists in - * the whole RIB and has ZEBRA_FLAG_SELECTED set. + * the whole RIB and has RIB_ENTRY_SELECTED_FIB set. * * Return values: * -1: error @@ -989,7 +989,7 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate, { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -1299,14 +1299,19 @@ rib_uninstall (struct route_node *rn, struct rib *rib) { rib_table_info_t *info = rn->table->info; - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) { if (info->safi == SAFI_UNICAST) zfpm_trigger_update (rn, "rib_uninstall"); - redistribute_delete (&rn->p, rib); if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); + UNSET_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB); + } + + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + { + redistribute_delete (&rn->p, rib); UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED); } } @@ -1374,76 +1379,70 @@ rib_gc_dest (struct route_node *rn) } static void -rib_process_add_route (struct zebra_vrf *zvrf, struct route_node *rn, - struct rib *select) +rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, + struct rib *new) { char buf[INET6_ADDRSTRLEN]; - int installed = 1; zfpm_trigger_update (rn, "new route selected"); /* Update real nexthop. This may actually determine if nexthop is active or not. */ - if (!nexthop_active_update (rn, select, 1)) + if (!nexthop_active_update (rn, new, 1)) { - UNSET_FLAG(select->status, RIB_ENTRY_CHANGED); + UNSET_FLAG(new->status, RIB_ENTRY_CHANGED); return; } - SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); + SET_FLAG (new->status, RIB_ENTRY_SELECTED_FIB); if (IS_ZEBRA_DEBUG_RIB) { inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%u:%s/%d: Adding route rn %p, rib %p (type %d)", - zvrf->vrf_id, buf, rn->p.prefixlen, rn, select, select->type); + zvrf->vrf_id, buf, rn->p.prefixlen, rn, new, new->type); } - if (!RIB_SYSTEM_ROUTE (select)) + if (!RIB_SYSTEM_ROUTE (new)) { - if (rib_install_kernel (rn, select, 0)) + if (rib_install_kernel (rn, new, 0)) { - installed = 0; inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_warn ("%u:%s/%d: Route install failed", zvrf->vrf_id, buf, rn->p.prefixlen); } } - /* Update for redistribution. */ - if (installed) - redistribute_update (&rn->p, select, NULL); - UNSET_FLAG(select->status, RIB_ENTRY_CHANGED); + UNSET_FLAG(new->status, RIB_ENTRY_CHANGED); } static void -rib_process_del_route (struct zebra_vrf *zvrf, struct route_node *rn, - struct rib *fib) +rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, + struct rib *old) { char buf[INET6_ADDRSTRLEN]; zfpm_trigger_update (rn, "removing existing route"); - /* Withdraw redistribute and uninstall from kernel. */ + /* Uninstall from kernel. */ if (IS_ZEBRA_DEBUG_RIB) { inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%u:%s/%d: Deleting route rn %p, rib %p (type %d)", - zvrf->vrf_id, buf, rn->p.prefixlen, rn, fib, fib->type); + zvrf->vrf_id, buf, rn->p.prefixlen, rn, old, old->type); } - redistribute_delete(&rn->p, fib); - if (!RIB_SYSTEM_ROUTE (fib)) - rib_uninstall_kernel (rn, fib); + if (!RIB_SYSTEM_ROUTE (old)) + rib_uninstall_kernel (rn, old); - UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + UNSET_FLAG (old->status, RIB_ENTRY_SELECTED_FIB); /* Update nexthop for route, reset changed flag. */ - nexthop_active_update (rn, fib, 1); - UNSET_FLAG(fib->status, RIB_ENTRY_CHANGED); + nexthop_active_update (rn, old, 1); + UNSET_FLAG(old->status, RIB_ENTRY_CHANGED); } static void -rib_process_update_route (struct zebra_vrf *zvrf, struct route_node *rn, - struct rib *select, struct rib *fib) +rib_process_update_fib (struct zebra_vrf *zvrf, struct route_node *rn, + struct rib *old, struct rib *new) { char buf[INET6_ADDRSTRLEN]; struct nexthop *nexthop = NULL, *tnexthop; @@ -1458,13 +1457,13 @@ rib_process_update_route (struct zebra_vrf *zvrf, struct route_node *rn, * We have to install or update if a new route has been selected or * something has changed. */ - if (select != fib || - CHECK_FLAG (select->status, RIB_ENTRY_CHANGED)) + if (new != old || + CHECK_FLAG (new->status, RIB_ENTRY_CHANGED)) { zfpm_trigger_update (rn, "updating existing route"); /* Update the nexthop; we could determine here that nexthop is inactive. */ - if (nexthop_active_update (rn, select, 1)) + if (nexthop_active_update (rn, new, 1)) nh_active = 1; /* If nexthop is active, install the selected route, if appropriate. If @@ -1475,18 +1474,18 @@ rib_process_update_route (struct zebra_vrf *zvrf, struct route_node *rn, { if (IS_ZEBRA_DEBUG_RIB) { - if (select != fib) + if (new != old) zlog_debug ("%u:%s/%d: Updating route rn %p, rib %p (type %d) " "old %p (type %d)", zvrf->vrf_id, buf, rn->p.prefixlen, - rn, select, select->type, fib, fib->type); + rn, new, new->type, old, old->type); else zlog_debug ("%u:%s/%d: Updating route rn %p, rib %p (type %d)", - zvrf->vrf_id, buf, rn->p.prefixlen, rn, select, select->type); + zvrf->vrf_id, buf, rn->p.prefixlen, rn, new, new->type); } /* Non-system route should be installed. */ - if (!RIB_SYSTEM_ROUTE (select)) + if (!RIB_SYSTEM_ROUTE (new)) { - if (rib_install_kernel (rn, select, 1)) + if (rib_install_kernel (rn, new, 1)) { installed = 0; inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); @@ -1496,26 +1495,23 @@ rib_process_update_route (struct zebra_vrf *zvrf, struct route_node *rn, } /* If install succeeded or system route, cleanup flags for prior route. */ - if (installed && select != fib) + if (installed && new != old) { - if (RIB_SYSTEM_ROUTE(select)) + if (RIB_SYSTEM_ROUTE(new)) { - if (!RIB_SYSTEM_ROUTE (fib)) - rib_uninstall_kernel (rn, fib); + if (!RIB_SYSTEM_ROUTE (old)) + rib_uninstall_kernel (rn, old); } else { - for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) + for (nexthop = old->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } } /* Update for redistribution. */ if (installed) - { - SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); - redistribute_update (&rn->p, select, (select == fib) ? NULL : fib); - } + SET_FLAG (new->status, RIB_ENTRY_SELECTED_FIB); } /* @@ -1524,28 +1520,22 @@ rib_process_update_route (struct zebra_vrf *zvrf, struct route_node *rn, */ if (!nh_active || !installed) { - struct rib *del; - if (IS_ZEBRA_DEBUG_RIB) { - if (select != fib) + if (new != old) zlog_debug ("%u:%s/%d: Deleting route rn %p, rib %p (type %d) " "old %p (type %d) - %s", zvrf->vrf_id, buf, rn->p.prefixlen, - rn, select, select->type, fib, fib->type, + rn, new, new->type, old, old->type, nh_active ? "install failed" : "nexthop inactive"); else zlog_debug ("%u:%s/%d: Deleting route rn %p, rib %p (type %d) - %s", - zvrf->vrf_id, buf, rn->p.prefixlen, rn, select, select->type, + zvrf->vrf_id, buf, rn->p.prefixlen, rn, new, new->type, nh_active ? "install failed" : "nexthop inactive"); } - del = (select == fib) ? select : fib; - - redistribute_delete(&rn->p, del); - - if (!RIB_SYSTEM_ROUTE (del)) - rib_uninstall_kernel (rn, del); - UNSET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); + if (!RIB_SYSTEM_ROUTE (old)) + rib_uninstall_kernel (rn, old); + UNSET_FLAG (new->status, RIB_ENTRY_SELECTED_FIB); } } else @@ -1556,33 +1546,33 @@ rib_process_update_route (struct zebra_vrf *zvrf, struct route_node *rn, * netlink reporting interface up before IPv4 or IPv6 protocol is ready * to add routes. */ - if (!RIB_SYSTEM_ROUTE (select)) + if (!RIB_SYSTEM_ROUTE (new)) { int in_fib = 0; - for (ALL_NEXTHOPS_RO(select->nexthop, nexthop, tnexthop, recursing)) + for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing)) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { in_fib = 1; break; } if (!in_fib) - rib_install_kernel (rn, select, 0); + rib_install_kernel (rn, new, 0); } } /* Update prior route. */ - if (select != fib) + if (new != old) { - UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + UNSET_FLAG (old->status, RIB_ENTRY_SELECTED_FIB); /* Set real nexthop. */ - nexthop_active_update (rn, fib, 1); - UNSET_FLAG(fib->status, RIB_ENTRY_CHANGED); + nexthop_active_update (rn, old, 1); + UNSET_FLAG(old->status, RIB_ENTRY_CHANGED); } /* Clear changed flag. */ - UNSET_FLAG(select->status, RIB_ENTRY_CHANGED); + UNSET_FLAG(new->status, RIB_ENTRY_CHANGED); } /* Check if 'alternate' RIB entry is better than 'current'. */ @@ -1633,33 +1623,32 @@ rib_process (struct route_node *rn) { struct rib *rib; struct rib *next; - struct rib *fib = NULL; - struct rib *select = NULL; - struct rib *del = NULL; + struct rib *old_selected = NULL; + struct rib *new_selected = NULL; + struct rib *old_fib = NULL; + struct rib *new_fib = NULL; struct rib *best = NULL; char buf[INET6_ADDRSTRLEN]; rib_dest_t *dest; struct zebra_vrf *zvrf = NULL; vrf_id_t vrf_id = VRF_UNKNOWN; - rib_table_info_t *info; assert (rn); - info = rn->table->info; - + dest = rib_dest_from_rnode (rn); if (dest) { zvrf = rib_dest_vrf (dest); vrf_id = zvrf->vrf_id; } - + if (IS_ZEBRA_DEBUG_RIB) inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug ("%u:%s/%d: Processing rn %p", vrf_id, buf, rn->p.prefixlen, rn); - RNODE_FOREACH_RIB_SAFE (rn, rib, next) + RNODE_FOREACH_RIB (rn, rib) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug ("%u:%s/%d: Examine rib %p (type %d) status %x flags %x " @@ -1669,31 +1658,23 @@ rib_process (struct route_node *rn) UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED); - /* Currently installed rib. */ + /* Currently selected rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { - assert (fib == NULL); - fib = rib; + assert (old_selected == NULL); + old_selected = rib; } - - /* Unlock removed routes, so they'll be freed, bar the FIB entry, - * which we need to do do further work with below. - */ - if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + /* Currently in fib */ + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) { - if (rib != fib) - { - if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, vrf_id, "rn %p, removing rib %p", - (void *)rn, (void *)rib); - rib_unlink (rn, rib); - } - else - del = rib; - - continue; + assert (old_fib == NULL); + old_fib = rib; } - + + /* Skip deleted entries from selection */ + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + /* Skip unreachable nexthop. */ /* This first call to nexthop_active_update is merely to determine if * there's any change to nexthops associated with this RIB entry. Now, @@ -1710,9 +1691,15 @@ rib_process (struct route_node *rn) { if (rib->type == ZEBRA_ROUTE_TABLE) { + /* XXX: HERE BE DRAGONS!!!!! + * In all honesty, I have not yet figured out what this part + * does or why the RIB_ENTRY_CHANGED test above is correct + * or why we need to delete a route here, and also not whether + * this concerns both selected and fib route, or only selected + * or only fib */ /* This entry was denied by the 'ip protocol table' route-map, we * need to delete it */ - if (rib != fib) + if (rib != old_selected) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s/%d: imported via import-table but denied " @@ -1721,15 +1708,12 @@ rib_process (struct route_node *rn) rib_unlink (rn, rib); } else - del = rib; + SET_FLAG (rib->status, RIB_ENTRY_REMOVED); } continue; } - if (info->safi == SAFI_MULTICAST) - continue; - /* Infinite distance. */ if (rib->distance == DISTANCE_INFINITY) { @@ -1737,33 +1721,101 @@ rib_process (struct route_node *rn) continue; } - best = rib_choose_best(select, rib); - if (select && best != select) - UNSET_FLAG (select->status, RIB_ENTRY_CHANGED); + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE)) + { + best = rib_choose_best(new_fib, rib); + if (new_fib && best != new_fib) + UNSET_FLAG (new_fib->status, RIB_ENTRY_CHANGED); + new_fib = best; + } + else + { + best = rib_choose_best(new_selected, rib); + if (new_selected && best != new_selected) + UNSET_FLAG (new_selected->status, RIB_ENTRY_CHANGED); + new_selected = best; + } if (best != rib) UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); - select = best; - } /* RNODE_FOREACH_RIB_SAFE */ + } /* RNODE_FOREACH_RIB */ + + /* If no FIB override route, use the selected route also for FIB */ + if (new_fib == NULL) + new_fib = new_selected; /* After the cycle is finished, the following pointers will be set: - * select --- the winner RIB entry, if any was found, otherwise NULL - * fib --- the SELECTED RIB entry, if any, otherwise NULL - * del --- equal to fib, if fib is queued for deletion, NULL otherwise - * rib --- NULL + * old_selected --- RIB entry currently having SELECTED + * new_selected --- RIB entry that is newly SELECTED + * old_fib --- RIB entry currently in kernel FIB + * new_fib --- RIB entry that is newly to be in kernel FIB + * + * new_selected will get SELECTED flag, and is going to be redistributed + * the zclients. new_fib (which can be new_selected) will be installed in kernel. */ + if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug ("%u:%s/%d: After processing: select %p fib %p del %p", - vrf_id, buf, rn->p.prefixlen, select, fib, del); + { + zlog_debug ("%u:%s/%d: After processing: old_selected %p new_selected %p old_fib %p new_fib %p", + vrf_id, buf, rn->p.prefixlen, + (void *)old_selected, + (void *)new_selected, + (void *)old_fib, + (void *)new_fib); + } + + /* Buffer RIB_ENTRY_CHANGED here, because it will get cleared if + * fib == selected */ + bool selected_changed = new_selected && CHECK_FLAG(new_selected->status, + RIB_ENTRY_CHANGED); + + /* Update fib according to selection results */ + if (new_fib && old_fib) + rib_process_update_fib (zvrf, rn, old_fib, new_fib); + else if (new_fib) + rib_process_add_fib (zvrf, rn, new_fib); + else if (old_fib) + rib_process_del_fib (zvrf, rn, old_fib); + + /* Redistribute SELECTED entry */ + if (old_selected != new_selected || selected_changed) + { + struct nexthop *nexthop, *tnexthop; + int recursing; + + /* Check if we have a FIB route for the destination, otherwise, + * don't redistribute it */ + for (ALL_NEXTHOPS_RO(new_fib ? new_fib->nexthop : NULL, nexthop, + tnexthop, recursing)) + { + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) + { + break; + } + } + if (!nexthop) + new_selected = NULL; - /* Same RIB entry is selected. Update FIB and finish. */ - if (select && select == fib) - rib_process_update_route (zvrf, rn, select, select); - else if (select && fib) - rib_process_update_route (zvrf, rn, select, fib); - else if (select) - rib_process_add_route (zvrf, rn, select); - else if (fib) - rib_process_del_route (zvrf, rn, fib); + if (new_selected && new_selected != new_fib) + { + nexthop_active_update(rn, new_selected, 1); + UNSET_FLAG(new_selected->status, RIB_ENTRY_CHANGED); + } + + if (old_selected) + { + if (!new_selected) + redistribute_delete(&rn->p, old_selected); + if (old_selected != new_selected) + UNSET_FLAG (old_selected->flags, ZEBRA_FLAG_SELECTED); + } + + if (new_selected) + { + /* Install new or replace existing redistributed entry */ + SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED); + redistribute_update (&rn->p, new_selected, old_selected); + } + } #if 0 if (select && select == fib) @@ -1940,12 +1992,18 @@ rib_process (struct route_node *rn) } #endif - /* FIB route was removed, should be deleted */ - if (del) + /* Remove all RIB entries queued for removal */ + RNODE_FOREACH_RIB_SAFE (rn, rib, next) { - if (IS_ZEBRA_DEBUG_RIB) - rnode_debug (rn, vrf_id, "Deleting fib %p, rn %p", (void *)del, (void *)rn); - rib_unlink (rn, del); + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + { + if (IS_ZEBRA_DEBUG_RIB) + { + rnode_debug (rn, vrf_id, "rn %p, removing rib %p", + (void *)rn, (void *)rib); + } + rib_unlink(rn, rib); + } } /* @@ -2512,7 +2570,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p, vrf_id_t vrf_id) */ RNODE_FOREACH_RIB (rn, rib) { - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) && + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB) && ! RIB_SYSTEM_ROUTE (rib)) { changed = 1; @@ -2658,7 +2716,7 @@ rib_delete (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) fib = rib; if (rib->type != type) @@ -2719,7 +2777,7 @@ rib_delete (afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); } else { @@ -3096,7 +3154,7 @@ rib_close_table (struct route_table *table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { - if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) continue; if (info->safi == SAFI_UNICAST) diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index f2362e687..1dc54e171 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -320,13 +320,21 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ /* If there are other active nexthops, do an update. */ if (rib->nexthop_active_num > 1) { - rib_install_kernel (rn, rib, 1); - redistribute_update (&rn->p, rib, NULL); + /* Update route in kernel if it's in fib */ + if (CHECK_FLAG(rib->status, RIB_ENTRY_SELECTED_FIB)) + rib_install_kernel (rn, rib, 1); + /* Update redistribution if it's selected */ + if (CHECK_FLAG(rib->flags, ZEBRA_FLAG_SELECTED)) + redistribute_update (&rn->p, rib, NULL); } else { - redistribute_delete (&rn->p, rib); - rib_uninstall_kernel (rn, rib); + /* Remove from redistribute if selected route becomes inactive */ + if (CHECK_FLAG(rib->flags, ZEBRA_FLAG_SELECTED)) + redistribute_delete (&rn->p, rib); + /* Remove from kernel if fib route becomes inactive */ + if (CHECK_FLAG(rib->status, RIB_ENTRY_SELECTED_FIB)) + rib_uninstall_kernel (rn, rib); } } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index e76e4ab8f..41e1293e7 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2023,6 +2023,10 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) } if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); + else if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) + vty_out (vty, ", fib"); + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE)) + vty_out (vty, ", fib-override"); if (rib->refcnt) vty_out (vty, ", refcnt %ld", rib->refcnt); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) @@ -2299,7 +2303,8 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib, len += vty_out (vty, "[%d]", rib->instance); len += vty_out (vty, "%c%c %s", CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) - ? '>' : ' ', + ? '>' : CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB) + ? '!' : ' ', CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', prefix2str (&rn->p, buf, sizeof buf)); diff --git a/zebra/zserv.c b/zebra/zserv.c index 3b2095d65..969d860c2 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -668,8 +668,7 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p, break; } - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) - || nexthop_has_fib_child(nexthop)) + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX); @@ -927,7 +926,7 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, struc * are looking up. Therefore, we will just iterate over the top * chain of nexthops. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) num += zsend_write_nexthop (s, nexthop); stream_putc_at (s, nump, num); /* store nexthop_num */ |