diff options
-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 |