summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--zebra/connected.c9
-rw-r--r--zebra/rib.h2
-rw-r--r--zebra/zebra_rib.c61
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