Zebra: Redistribute replace handling corner cases

Ticket: CM-7309
Reviewed By: CCR-3448
Testing Done: passing route_ospf_route_thrash, the new redist test

When zebra was modified to have redistributed routes follow a replace
logic instead of the del-add, one case was missed. When a route is
replaced with a change only to the source protocol (say from static
to bgp), its possible that the new source protocol is not selected
for redistribution by a client. Since we did not delete the route
initially, if the add is not allowed for the new source protocol
for a client, we need to send a delete of that redistributed route.
This is what the patch fixes.

Signed-off-by: Dinesh G Dutt <ddutt@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
This commit is contained in:
vivek 2015-10-20 21:52:52 -07:00
parent 5048fe1444
commit c41fc67b25
4 changed files with 63 additions and 45 deletions

View File

@ -171,58 +171,73 @@ zebra_redistribute (struct zserv *client, int type, u_short instance)
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
} }
/* Either advertise a route for redistribution to registered clients or */
/* withdraw redistribution if add cannot be done for client */
void void
redistribute_add (struct prefix *p, struct rib *rib) redistribute_update (struct prefix *p, struct rib *rib, struct rib *prev_rib)
{ {
struct listnode *node, *nnode; struct listnode *node, *nnode;
struct zserv *client; struct zserv *client;
int send_redistribute;
int afi;
afi = family2afi(p->family);
if (!afi)
{
zlog_warn("%s: Unknown AFI/SAFI prefix received\n", __FUNCTION__);
return;
}
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
{ {
if (is_default (p)) send_redistribute = 0;
{
if ((p->family == AF_INET) && if (is_default(p) && client->redist_default)
(client->redist_default || send_redistribute = 1;
redist_check_instance(&client->redist[AFI_IP][rib->type],
rib->instance))) if (redist_check_instance(&client->redist[afi][rib->type],
rib->instance))
send_redistribute = 1;
if (send_redistribute)
{
switch (afi)
{ {
case AFI_IP:
client->redist_v4_add_cnt++; client->redist_v4_add_cnt++;
zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client, zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client,
p, rib); p, rib);
} break;
#ifdef HAVE_IPV6 case AFI_IP6:
if ((p->family == AF_INET6) && client->redist_v6_add_cnt++;
(client->redist_default ||
redist_check_instance(&client->redist[AFI_IP6][rib->type],
rib->instance)))
{
client->redist_v6_add_cnt++;
zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client, zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client,
p, rib); p, rib);
} break;
#endif /* HAVE_IPV6 */ default:
} zlog_warn("%s: Unknown AFI/SAFI prefix received\n", __FUNCTION__);
else break;
{ }
if ((p->family == AF_INET) && }
redist_check_instance(&client->redist[AFI_IP][rib->type], else if (prev_rib &&
rib->instance)) redist_check_instance(&client->redist[afi][prev_rib->type],
rib->instance))
{
switch (afi)
{ {
client->redist_v4_add_cnt++; case AFI_IP:
zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client, client->redist_v4_del_cnt++;
p, rib); zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_DEL, client, p,
} prev_rib);
#ifdef HAVE_IPV6 break;
if ((p->family == AF_INET6) && case AFI_IP6:
redist_check_instance(&client->redist[AFI_IP6][rib->type], client->redist_v6_del_cnt++;
rib->instance)) zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
{ prev_rib);
client->redist_v6_add_cnt++; break;
zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client, default:
p, rib); break;
} }
#endif /* HAVE_IPV6 */ }
}
} }
} }

View File

@ -33,7 +33,7 @@ extern void zebra_redistribute_delete (int, struct zserv *, int);
extern void zebra_redistribute_default_add (int, struct zserv *, int); extern void zebra_redistribute_default_add (int, struct zserv *, int);
extern void zebra_redistribute_default_delete (int, struct zserv *, int); extern void zebra_redistribute_default_delete (int, struct zserv *, int);
extern void redistribute_add (struct prefix *, struct rib *); extern void redistribute_update (struct prefix *, struct rib *, struct rib *);
extern void redistribute_delete (struct prefix *, struct rib *); extern void redistribute_delete (struct prefix *, struct rib *);
extern void zebra_interface_up_update (struct interface *); extern void zebra_interface_up_update (struct interface *);

View File

@ -19,10 +19,10 @@ void zebra_redistribute_default_delete (int a, struct zserv *b, int c)
{ return; } { return; }
#endif #endif
void redistribute_add (struct prefix *a, struct rib *b) void redistribute_update (struct prefix *a, struct rib *b, struct rib *c)
{ return; } { return; }
#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA
#pragma weak redistribute_delete = redistribute_add #pragma weak redistribute_delete = redistribute_update
#else #else
void redistribute_delete (struct prefix *a, struct rib *b) void redistribute_delete (struct prefix *a, struct rib *b)
{ return; } { return; }

View File

@ -1709,7 +1709,7 @@ rib_process (struct route_node *rn)
rib_install_kernel (rn, select, update_ok); rib_install_kernel (rn, select, update_ok);
/* assuming that the receiver knows how to dedup */ /* assuming that the receiver knows how to dedup */
redistribute_add (&rn->p, select); redistribute_update (&rn->p, select, NULL);
} }
else else
{ {
@ -1808,7 +1808,10 @@ rib_process (struct route_node *rn)
rib_install_kernel (rn, select, update_ok); rib_install_kernel (rn, select, update_ok);
SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);
/* Unconditionally announce, this part is exercised by new routes */ /* Unconditionally announce, this part is exercised by new routes */
redistribute_add (&rn->p, select); /* If we cannot add, for example route added is learnt by the */
/* protocol we're trying to redistribute to, delete the redist */
/* This is notified by setting the is_update to 1 */
redistribute_update (&rn->p, select, fib);
} }
else else
{ {
@ -2953,7 +2956,7 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
if (rib->nexthop_active_num > 1) if (rib->nexthop_active_num > 1)
{ {
rib_install_kernel (rn, rib, 1); rib_install_kernel (rn, rib, 1);
redistribute_add (&rn->p, rib); redistribute_update (&rn->p, rib, NULL);
} }
else else
{ {
@ -3725,7 +3728,7 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si)
if (rib->nexthop_active_num > 1) if (rib->nexthop_active_num > 1)
{ {
rib_install_kernel (rn, rib, 0); rib_install_kernel (rn, rib, 0);
redistribute_add (&rn->p, rib); redistribute_update (&rn->p, rib, NULL);
} }
} }