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 | |
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, ...
-rw-r--r-- | zebra/connected.c | 9 | ||||
-rw-r--r-- | zebra/rib.h | 2 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 61 |
3 files changed, 71 insertions, 1 deletions
diff --git a/zebra/connected.c b/zebra/connected.c index a3e20096..80cb8cbc 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -42,18 +42,25 @@ extern struct zebra_t zebrad; static void connected_withdraw (struct connected *ifc) { + if (! ifc) return; /* Update interface address information to protocol daemon. */ if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) { + int count; + zebra_interface_address_delete_update (ifc->ifp, ifc); - if_subnet_delete (ifc->ifp, ifc); + count = if_subnet_delete (ifc->ifp, ifc); if (ifc->address->family == AF_INET) + { connected_down_ipv4 (ifc->ifp, ifc); + if (count == 0) + rib_flush_interface (AFI_IP, ifc->ifp); + } #ifdef HAVE_IPV6 else connected_down_ipv6 (ifc->ifp, ifc); diff --git a/zebra/rib.h b/zebra/rib.h index b98410aa..c374df37 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -273,6 +273,8 @@ extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); extern void rib_update (void); extern void rib_weed_tables (void); extern void rib_sweep_route (void); +struct interface; +extern void rib_flush_interface (afi_t afi, struct interface *ifp); extern void rib_close (void); extern void rib_init (void); 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 |