Commit 98bdd04e for quagga.net
commit 98bdd04e3fdd6790453e0dce13853c2472ce5d15
Author: Gerrie Roos <gerrie@xiplink.com>
Date: Wed Jan 17 21:16:55 2018 +0000
zebra/redistribute: Implicit withdraw needs to be explicit if update isn't sent
* redistribute.{c,h}: (redistribute_add) update of redistributed route is an
implicit withdraw of the old route. The RIB therefore doesn't bother
deleting the old route, if doing a redistribute_add. However, if the
updated route is /not/ sent to a client that received the previous route,
then such a client is left with bogus state.
This can happen when the new route is of a type that the client doesn't
redistibute.
Fix by passing in the old route, and adding an explicit delete of the old
route where necessary.
* zebra_rib.c: (rib_process) pass on the old route too, as per above.
* redistribute_null.c: testing stub
See bug #971
Modification to fix the problem at the redistribute layer instead of the RIB
suggested by paul@jakma.org.
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index a7a6b258..6d466acf 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -182,11 +182,11 @@ zebra_redistribute (struct zserv *client, int type, vrf_id_t vrf_id)
}
void
-redistribute_add (struct prefix *p, struct rib *rib)
+redistribute_add (struct prefix *p, struct rib *rib, struct rib *rib_old)
{
struct listnode *node, *nnode;
struct zserv *client;
-
+
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
{
if ((is_default (p) &&
@@ -204,6 +204,21 @@ redistribute_add (struct prefix *p, struct rib *rib)
zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
}
}
+ else if (rib_old && vrf_bitmap_check (client->redist[rib_old->type],
+ rib_old->vrf_id))
+ {
+ /* redistribute_add has implicit withdraw semantics, so there
+ * may be an old route already redistributed that is being updated.
+ *
+ * However, if the new route is of a type that is /not/ redistributed
+ * to the client, then we must ensure the old route is explicitly
+ * withdrawn.
+ */
+ if (p->family == AF_INET)
+ zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, rib_old);
+ if (p->family == AF_INET6)
+ zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, rib_old);
+ }
}
}
diff --git a/zebra/redistribute.h b/zebra/redistribute.h
index ce840094..196d7c30 100644
--- a/zebra/redistribute.h
+++ b/zebra/redistribute.h
@@ -34,7 +34,7 @@ extern void zebra_redistribute_default_add (int, struct zserv *, int,
extern void zebra_redistribute_default_delete (int, struct zserv *, int,
vrf_id_t);
-extern void redistribute_add (struct prefix *, struct rib *);
+extern void redistribute_add (struct prefix *, struct rib *new, struct rib *old);
extern void redistribute_delete (struct prefix *, struct rib *);
extern void zebra_interface_up_update (struct interface *);
diff --git a/zebra/redistribute_null.c b/zebra/redistribute_null.c
index 5584d12c..99272b6b 100644
--- a/zebra/redistribute_null.c
+++ b/zebra/redistribute_null.c
@@ -44,7 +44,7 @@ void zebra_redistribute_default_delete (int a, struct zserv *b, int c,
{ return; }
#endif
-void redistribute_add (struct prefix *a, struct rib *b)
+void redistribute_add (struct prefix *a, struct rib *b, struct rib *c)
{ return; }
#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA
#pragma weak redistribute_delete = redistribute_add
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 9ca02904..857abcab 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1320,7 +1320,7 @@ rib_process (struct route_node *rn)
{
/* Install new or replace existing redistributed entry */
SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED);
- redistribute_add (&rn->p, new_selected);
+ redistribute_add (&rn->p, new_selected, old_selected);
}
}