diff options
author | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2009-04-29 22:16:00 -0700 |
---|---|---|
committer | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2009-04-29 23:09:06 -0700 |
commit | 3a0ab9d1718175098bebca664f2004ec4daacfed (patch) | |
tree | 5ba6a7353686ffca0841fd69404ca079653c3f62 /zebra/zebra_rib.c | |
parent | 11bbc07a287d883f3013567f897290859c428286 (diff) | |
download | quagga-3a0ab9d1718175098bebca664f2004ec4daacfed.tar.bz2 quagga-3a0ab9d1718175098bebca664f2004ec4daacfed.tar.xz |
Handle kernel flush when address is deleted
When interface addresses are deleted, the kernel will flush all
routes. Quagga needs to follow this correctly.
Relates to DHCP bugs 4314, 4315, ...
Diffstat (limited to 'zebra/zebra_rib.c')
-rw-r--r-- | zebra/zebra_rib.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 3679882e..d4395db1 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1308,6 +1308,7 @@ end: zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn); } + /* Take a list of route_node structs and return 1, if there was a record * picked from it and processed by rib_process(). Don't process more, * than one RN record; operate only in the specified sub-queue. @@ -3067,6 +3068,66 @@ rib_sweep_route (void) rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } + +/* When all IPV4 subnets are gone on Linux, the kernel frees all routes */ +void +rib_flush_interface(afi_t afi, struct interface *ifp) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib, *next; + + table = vrf_table(afi, SAFI_UNICAST, 0); + if (!table) + return; + + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: flushing references to %s", __func__, ifp->name); + + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + struct nexthop *nexthop; + + next = rib->next; + + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + + switch(rib->type) { + case ZEBRA_ROUTE_KERNEL: + if ( (nexthop = rib->nexthop) && + (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX || + nexthop->type == NEXTHOP_TYPE_IFINDEX) && + nexthop->ifindex == ifp->ifindex) + { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: calling rib_delnode (%p, %p) on kernel RIB entry", + __func__, rn, rib); + rib_delnode(rn, rib); + } + break; + + case ZEBRA_ROUTE_STATIC: + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + switch(nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (nexthop->ifindex == ifp->ifindex) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + break; + case NEXTHOP_TYPE_IFNAME: + case NEXTHOP_TYPE_IPV4_IFNAME: + case NEXTHOP_TYPE_IPV6_IFNAME: + if (strcmp(nexthop->ifname, ifp->name) == 0) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } + } + } +} /* Close RIB and clean up kernel routes. */ static void |