Zebra: Make redistribute do replace instead of del/add for better convergence

Ticket: CM-6768
Reviewed By: CCR-3207
Testing Done: bgpsmoke, smoke, topo to create failure

Redistributing routes goes through a del/add cycle whenever a redistributed
is updated. This del/add cycle causes disruption by causing traffic loss
for brief/long periods of time(6-8 s in case of OSPF). The modifications in
this patch remove the del/add cycle to ensure that this disruption doesn't
happen.

Also fixed sending no forwarding address when announcing IPv4 routes with IPv6
nexthops, and sending nexthop only when there is a single path.

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:38:38 -07:00
parent d0f9e40016
commit 5048fe1444
13 changed files with 175 additions and 94 deletions

View File

@ -484,7 +484,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
else else
api.tag = 0; api.tag = 0;
if (command == ZEBRA_IPV4_ROUTE_ADD) if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
{ {
if (bgp_debug_zebra((struct prefix *)&p)) if (bgp_debug_zebra((struct prefix *)&p))
{ {
@ -500,7 +500,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, ifindex, bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, ifindex,
api.metric, api.type, api.instance, api.tag); api.metric, api.type, api.instance, api.tag);
} }
else else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL)
{ {
if (bgp_debug_zebra((struct prefix *)&p)) if (bgp_debug_zebra((struct prefix *)&p))
{ {
@ -582,7 +582,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
if (IN6_IS_ADDR_LINKLOCAL (&p.prefix)) if (IN6_IS_ADDR_LINKLOCAL (&p.prefix))
return 0; return 0;
if (command == ZEBRA_IPV6_ROUTE_ADD) if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
{ {
if (bgp_debug_zebra((struct prefix *)&p)) if (bgp_debug_zebra((struct prefix *)&p))
{ {
@ -598,7 +598,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, ifindex, bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, ifindex,
api.metric, api.type, api.instance, api.tag); api.metric, api.type, api.instance, api.tag);
} }
else else if (command == ZEBRA_REDISTRIBUTE_IPV6_DEL)
{ {
if (bgp_debug_zebra((struct prefix *)&p)) if (bgp_debug_zebra((struct prefix *)&p))
{ {
@ -1696,11 +1696,15 @@ bgp_zebra_init (struct thread_master *master)
zclient->interface_nbr_address_delete = bgp_interface_nbr_address_delete; zclient->interface_nbr_address_delete = bgp_interface_nbr_address_delete;
zclient->ipv4_route_add = zebra_read_ipv4; zclient->ipv4_route_add = zebra_read_ipv4;
zclient->ipv4_route_delete = zebra_read_ipv4; zclient->ipv4_route_delete = zebra_read_ipv4;
zclient->redistribute_route_ipv4_add = zebra_read_ipv4;
zclient->redistribute_route_ipv4_del = zebra_read_ipv4;
zclient->interface_up = bgp_interface_up; zclient->interface_up = bgp_interface_up;
zclient->interface_down = bgp_interface_down; zclient->interface_down = bgp_interface_down;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
zclient->ipv6_route_add = zebra_read_ipv6; zclient->ipv6_route_add = zebra_read_ipv6;
zclient->ipv6_route_delete = zebra_read_ipv6; zclient->ipv6_route_delete = zebra_read_ipv6;
zclient->redistribute_route_ipv6_add = zebra_read_ipv6;
zclient->redistribute_route_ipv6_del = zebra_read_ipv6;
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
zclient->nexthop_update = bgp_read_nexthop_update; zclient->nexthop_update = bgp_read_nexthop_update;
zclient->import_check_update = bgp_read_import_check_update; zclient->import_check_update = bgp_read_import_check_update;

View File

@ -555,7 +555,7 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient,
else else
api.metric = 0; api.metric = 0;
if (command == ZEBRA_IPV4_ROUTE_ADD) if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
{ {
if (isis->debugs & DEBUG_ZEBRA) if (isis->debugs & DEBUG_ZEBRA)
zlog_debug ("IPv4 Route add from Z"); zlog_debug ("IPv4 Route add from Z");
@ -606,9 +606,13 @@ isis_zebra_init (struct thread_master *master)
zclient->interface_address_delete = isis_zebra_if_address_del; zclient->interface_address_delete = isis_zebra_if_address_del;
zclient->ipv4_route_add = isis_zebra_read_ipv4; zclient->ipv4_route_add = isis_zebra_read_ipv4;
zclient->ipv4_route_delete = isis_zebra_read_ipv4; zclient->ipv4_route_delete = isis_zebra_read_ipv4;
zclient->redistribute_route_ipv4_add = isis_zebra_read_ipv4;
zclient->redistribute_route_ipv4_del = isis_zebra_read_ipv4;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
zclient->ipv6_route_add = isis_zebra_read_ipv6; zclient->ipv6_route_add = isis_zebra_read_ipv6;
zclient->ipv6_route_delete = isis_zebra_read_ipv6; zclient->ipv6_route_delete = isis_zebra_read_ipv6;
zclient->redistribute_route_ipv6_add = isis_zebra_read_ipv6;
zclient->redistribute_route_ipv6_del = isis_zebra_read_ipv6;
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
return; return;

View File

@ -1259,6 +1259,22 @@ zclient_read (struct thread *thread)
if (zclient->bfd_dest_replay) if (zclient->bfd_dest_replay)
(*zclient->bfd_dest_replay) (command, zclient, length); (*zclient->bfd_dest_replay) (command, zclient, length);
break; break;
case ZEBRA_REDISTRIBUTE_IPV4_ADD:
if (zclient->redistribute_route_ipv4_add)
(*zclient->redistribute_route_ipv4_add) (command, zclient, length);
break;
case ZEBRA_REDISTRIBUTE_IPV4_DEL:
if (zclient->redistribute_route_ipv4_del)
(*zclient->redistribute_route_ipv4_del) (command, zclient, length);
break;
case ZEBRA_REDISTRIBUTE_IPV6_ADD:
if (zclient->redistribute_route_ipv6_add)
(*zclient->redistribute_route_ipv6_add) (command, zclient, length);
break;
case ZEBRA_REDISTRIBUTE_IPV6_DEL:
if (zclient->redistribute_route_ipv6_del)
(*zclient->redistribute_route_ipv6_del) (command, zclient, length);
break;
default: default:
break; break;
} }

View File

@ -98,6 +98,10 @@ struct zclient
int (*nexthop_update) (int, struct zclient *, uint16_t); int (*nexthop_update) (int, struct zclient *, uint16_t);
int (*import_check_update) (int, struct zclient *, uint16_t); int (*import_check_update) (int, struct zclient *, uint16_t);
int (*bfd_dest_replay) (int, struct zclient *, uint16_t); int (*bfd_dest_replay) (int, struct zclient *, uint16_t);
int (*redistribute_route_ipv4_add) (int, struct zclient *, uint16_t);
int (*redistribute_route_ipv4_del) (int, struct zclient *, uint16_t);
int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t);
int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t);
}; };
/* Zebra API message flag. */ /* Zebra API message flag. */

View File

@ -438,7 +438,11 @@ struct in_pktinfo
#define ZEBRA_BFD_DEST_DEREGISTER 35 #define ZEBRA_BFD_DEST_DEREGISTER 35
#define ZEBRA_BFD_DEST_UPDATE 36 #define ZEBRA_BFD_DEST_UPDATE 36
#define ZEBRA_BFD_DEST_REPLAY 37 #define ZEBRA_BFD_DEST_REPLAY 37
#define ZEBRA_MESSAGE_MAX 38 #define ZEBRA_REDISTRIBUTE_IPV4_ADD 38
#define ZEBRA_REDISTRIBUTE_IPV4_DEL 39
#define ZEBRA_REDISTRIBUTE_IPV6_ADD 40
#define ZEBRA_REDISTRIBUTE_IPV6_DEL 41
#define ZEBRA_MESSAGE_MAX 42
/* Marker value used in new Zserv, in the byte location corresponding /* Marker value used in new Zserv, in the byte location corresponding
* the command value in the old zserv header. To allow old and new * the command value in the old zserv header. To allow old and new

View File

@ -261,7 +261,7 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
zebra_route_string(api.type), prefixstr, nexthopstr, ifindex); zebra_route_string(api.type), prefixstr, nexthopstr, ifindex);
} }
if (command == ZEBRA_IPV6_ROUTE_ADD) if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p, ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p,
api.nexthop_num, nexthop); api.nexthop_num, nexthop);
else else
@ -649,8 +649,12 @@ ospf6_zebra_init (struct thread_master *master)
zclient->interface_address_delete = ospf6_zebra_if_address_update_delete; zclient->interface_address_delete = ospf6_zebra_if_address_update_delete;
zclient->ipv4_route_add = NULL; zclient->ipv4_route_add = NULL;
zclient->ipv4_route_delete = NULL; zclient->ipv4_route_delete = NULL;
zclient->redistribute_route_ipv4_add = NULL;
zclient->redistribute_route_ipv4_del = NULL;
zclient->ipv6_route_add = ospf6_zebra_read_ipv6; zclient->ipv6_route_add = ospf6_zebra_read_ipv6;
zclient->ipv6_route_delete = ospf6_zebra_read_ipv6; zclient->ipv6_route_delete = ospf6_zebra_read_ipv6;
zclient->redistribute_route_ipv6_add = ospf6_zebra_read_ipv6;
zclient->redistribute_route_ipv6_del = ospf6_zebra_read_ipv6;
/* redistribute connected route by default */ /* redistribute connected route by default */
/* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */ /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */

View File

@ -142,6 +142,7 @@ ospf_external_info_add (u_char type, u_short instance, struct prefix_ipv4 p,
struct external_info *new; struct external_info *new;
struct route_node *rn; struct route_node *rn;
struct ospf_external *ext; struct ospf_external *ext;
char inetbuf[INET6_BUFSIZ];
ext = ospf_external_lookup(type, instance); ext = ospf_external_lookup(type, instance);
if (!ext) if (!ext)
@ -152,12 +153,20 @@ ospf_external_info_add (u_char type, u_short instance, struct prefix_ipv4 p,
if (rn) if (rn)
if (rn->info) if (rn->info)
{ {
route_unlock_node (rn); new = rn->info;
zlog_warn ("Redistribute[%s][%d]: %s/%d already exists, discard.", if ((new->ifindex == ifindex) &&
(new->nexthop.s_addr == nexthop.s_addr) && (new->tag == tag))
{
route_unlock_node(rn);
return NULL; /* NULL => no LSA to refresh */
}
inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf, INET6_BUFSIZ);
zlog_warn ("Redistribute[%s][%d]: %s/%d discarding old info with NH %s.",
ospf_redist_string(type), instance, ospf_redist_string(type), instance,
inet_ntoa (p.prefix), p.prefixlen); inet_ntoa (p.prefix), p.prefixlen, inetbuf);
/* XFREE (MTYPE_OSPF_TMP, rn->info); */ XFREE (MTYPE_OSPF_EXTERNAL_INFO, rn->info);
return rn->info; rn->info = NULL;
} }
/* Create new External info instance. */ /* Create new External info instance. */
@ -167,13 +176,17 @@ ospf_external_info_add (u_char type, u_short instance, struct prefix_ipv4 p,
new->nexthop = nexthop; new->nexthop = nexthop;
new->tag = tag; new->tag = tag;
/* we don't unlock rn from the get() because we're attaching the info */
if (rn) if (rn)
rn->info = new; rn->info = new;
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
zlog_debug ("Redistribute[%s]: %s/%d external info created.", {
ospf_redist_string(type), inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf, INET6_BUFSIZ);
inet_ntoa (p.prefix), p.prefixlen); zlog_debug ("Redistribute[%s]: %s/%d external info created, with NH %s",
ospf_redist_string(type),
inet_ntoa (p.prefix), p.prefixlen, inetbuf);
}
return new; return new;
} }

View File

@ -1070,7 +1070,7 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
if (ospf == NULL) if (ospf == NULL)
return 0; return 0;
if (command == ZEBRA_IPV4_ROUTE_ADD) if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
{ {
/* XXX|HACK|TODO|FIXME: /* XXX|HACK|TODO|FIXME:
* Maybe we should ignore reject/blackhole routes? Testing shows that * Maybe we should ignore reject/blackhole routes? Testing shows that
@ -1098,7 +1098,11 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
ei = ospf_external_info_add (api.type, api.instance, p, ifindex, ei = ospf_external_info_add (api.type, api.instance, p, ifindex,
nexthop, api.tag); nexthop, api.tag);
if (ei == NULL)
{
/* Nothing has changed, so nothing to do; return */
return 0;
}
if (ospf->router_id.s_addr == 0) if (ospf->router_id.s_addr == 0)
/* Set flags to generate AS-external-LSA originate event /* Set flags to generate AS-external-LSA originate event
for each redistributed protocols later. */ for each redistributed protocols later. */
@ -1116,17 +1120,19 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
current = ospf_external_info_find_lsa (ospf, &ei->p); current = ospf_external_info_find_lsa (ospf, &ei->p);
if (!current) if (!current)
ospf_external_lsa_originate (ospf, ei); ospf_external_lsa_originate (ospf, ei);
else if (IS_LSA_MAXAGE (current))
ospf_external_lsa_refresh (ospf, current,
ei, LSA_REFRESH_FORCE);
else else
zlog_warn ("ospf_zebra_read_ipv4() : %s already exists", {
inet_ntoa (p.prefix)); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
zlog_debug ("ospf_zebra_read_ipv4() : %s refreshing LSA",
inet_ntoa (p.prefix));
ospf_external_lsa_refresh (ospf, current,
ei, LSA_REFRESH_FORCE);
}
} }
} }
} }
} }
else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */ else /* if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL) */
{ {
ospf_external_info_delete (api.type, api.instance, p); ospf_external_info_delete (api.type, api.instance, p);
if (is_prefix_default (&p)) if (is_prefix_default (&p))
@ -1554,6 +1560,8 @@ ospf_zebra_init (struct thread_master *master, u_short instance)
zclient->interface_address_delete = ospf_interface_address_delete; zclient->interface_address_delete = ospf_interface_address_delete;
zclient->ipv4_route_add = ospf_zebra_read_ipv4; zclient->ipv4_route_add = ospf_zebra_read_ipv4;
zclient->ipv4_route_delete = ospf_zebra_read_ipv4; zclient->ipv4_route_delete = ospf_zebra_read_ipv4;
zclient->redistribute_route_ipv4_add = ospf_zebra_read_ipv4;
zclient->redistribute_route_ipv4_del = ospf_zebra_read_ipv4;
access_list_add_hook (ospf_filter_update); access_list_add_hook (ospf_filter_update);
access_list_delete_hook (ospf_filter_update); access_list_delete_hook (ospf_filter_update);

View File

@ -140,10 +140,10 @@ rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
api.metric = 0; api.metric = 0;
/* Then fetch IPv4 prefixes. */ /* Then fetch IPv4 prefixes. */
if (command == ZEBRA_IPV4_ROUTE_ADD) if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex,
&nexthop, api.metric, api.distance); &nexthop, api.metric, api.distance);
else else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL)
rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex); rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex);
return 0; return 0;
@ -683,6 +683,8 @@ rip_zclient_init (struct thread_master *master)
zclient->ipv4_route_delete = rip_zebra_read_ipv4; zclient->ipv4_route_delete = rip_zebra_read_ipv4;
zclient->interface_up = rip_interface_up; zclient->interface_up = rip_interface_up;
zclient->interface_down = rip_interface_down; zclient->interface_down = rip_interface_down;
zclient->redistribute_route_ipv4_add = rip_zebra_read_ipv4;
zclient->redistribute_route_ipv4_del = rip_zebra_read_ipv4;
/* Install zebra node. */ /* Install zebra node. */
install_node (&zebra_node, config_write_zebra); install_node (&zebra_node, config_write_zebra);

View File

@ -105,7 +105,7 @@ zebra_redistribute_default (struct zserv *client)
RNODE_FOREACH_RIB (rn, newrib) RNODE_FOREACH_RIB (rn, newrib)
if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
&& newrib->distance != DISTANCE_INFINITY) && newrib->distance != DISTANCE_INFINITY)
zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client, &rn->p, newrib);
route_unlock_node (rn); route_unlock_node (rn);
} }
} }
@ -125,7 +125,7 @@ zebra_redistribute_default (struct zserv *client)
RNODE_FOREACH_RIB (rn, newrib) RNODE_FOREACH_RIB (rn, newrib)
if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
&& newrib->distance != DISTANCE_INFINITY) && newrib->distance != DISTANCE_INFINITY)
zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client, &rn->p, newrib);
route_unlock_node (rn); route_unlock_node (rn);
} }
} }
@ -151,7 +151,7 @@ zebra_redistribute (struct zserv *client, int type, u_short instance)
&& zebra_check_addr (&rn->p)) && zebra_check_addr (&rn->p))
{ {
client->redist_v4_add_cnt++; client->redist_v4_add_cnt++;
zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client, &rn->p, newrib);
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
@ -166,7 +166,7 @@ zebra_redistribute (struct zserv *client, int type, u_short instance)
&& zebra_check_addr (&rn->p)) && zebra_check_addr (&rn->p))
{ {
client->redist_v6_add_cnt++; client->redist_v6_add_cnt++;
zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client, &rn->p, newrib);
} }
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
} }
@ -187,7 +187,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
rib->instance))) rib->instance)))
{ {
client->redist_v4_add_cnt++; client->redist_v4_add_cnt++;
zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client,
p, rib);
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if ((p->family == AF_INET6) && if ((p->family == AF_INET6) &&
@ -196,7 +197,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
rib->instance))) rib->instance)))
{ {
client->redist_v6_add_cnt++; client->redist_v6_add_cnt++;
zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client,
p, rib);
} }
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
} }
@ -207,7 +209,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
rib->instance)) rib->instance))
{ {
client->redist_v4_add_cnt++; client->redist_v4_add_cnt++;
zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client,
p, rib);
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if ((p->family == AF_INET6) && if ((p->family == AF_INET6) &&
@ -215,7 +218,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
rib->instance)) rib->instance))
{ {
client->redist_v6_add_cnt++; client->redist_v6_add_cnt++;
zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client,
p, rib);
} }
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
} }
@ -240,15 +244,15 @@ redistribute_delete (struct prefix *p, struct rib *rib)
(client->redist_default || (client->redist_default ||
redist_check_instance(&client->redist[AFI_IP][rib->type], redist_check_instance(&client->redist[AFI_IP][rib->type],
rib->instance))) rib->instance)))
zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_DEL, client, p,
rib); rib);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if ((p->family == AF_INET6) && if ((p->family == AF_INET6) &&
(client->redist_default || (client->redist_default ||
redist_check_instance(&client->redist[AFI_IP6][rib->type], redist_check_instance(&client->redist[AFI_IP6][rib->type],
rib->instance))) rib->instance)))
zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
rib); rib);
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
} }
else else
@ -256,14 +260,14 @@ redistribute_delete (struct prefix *p, struct rib *rib)
if ((p->family == AF_INET) && if ((p->family == AF_INET) &&
redist_check_instance(&client->redist[AFI_IP][rib->type], redist_check_instance(&client->redist[AFI_IP][rib->type],
rib->instance)) rib->instance))
zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_DEL, client, p,
rib); rib);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if ((p->family == AF_INET6) && if ((p->family == AF_INET6) &&
redist_check_instance(&client->redist[AFI_IP6][rib->type], redist_check_instance(&client->redist[AFI_IP6][rib->type],
rib->instance)) rib->instance))
zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
rib); rib);
#endif /* HAVE_IPV6 */ #endif /* HAVE_IPV6 */
} }
} }

View File

@ -1683,13 +1683,11 @@ rib_process (struct route_node *rn)
{ {
zfpm_trigger_update (rn, "updating existing route"); zfpm_trigger_update (rn, "updating existing route");
redistribute_delete (&rn->p, select);
if (! RIB_SYSTEM_ROUTE (select)) if (! RIB_SYSTEM_ROUTE (select))
{ {
/* For v4, use the replace semantics of netlink. */ /* For v4, use the replace semantics of netlink. */
if (PREFIX_FAMILY (&rn->p) == AF_INET) if (PREFIX_FAMILY (&rn->p) == AF_INET)
update_ok = 1; update_ok = 1;
else else
rib_uninstall_kernel (rn, select); rib_uninstall_kernel (rn, select);
} }
@ -1709,10 +1707,15 @@ rib_process (struct route_node *rn)
} }
if (! RIB_SYSTEM_ROUTE (select)) if (! RIB_SYSTEM_ROUTE (select))
rib_install_kernel (rn, select, update_ok); rib_install_kernel (rn, select, update_ok);
/* assuming that the receiver knows how to dedup */
redistribute_add (&rn->p, select); redistribute_add (&rn->p, select);
} }
else else
{ {
/* Withdraw unreachable redistribute route */
redistribute_delete(&rn->p, select);
/* For IPv4, do the uninstall here. */ /* For IPv4, do the uninstall here. */
if (update_ok) if (update_ok)
rib_uninstall_kernel (rn, select); rib_uninstall_kernel (rn, select);
@ -1753,7 +1756,9 @@ rib_process (struct route_node *rn)
zfpm_trigger_update (rn, "removing existing route"); zfpm_trigger_update (rn, "removing existing route");
redistribute_delete (&rn->p, fib); /* If there's no route to replace this with, withdraw redistribute */
if (!select)
redistribute_delete(&rn->p, fib);
if (! RIB_SYSTEM_ROUTE (fib)) if (! RIB_SYSTEM_ROUTE (fib))
{ {
@ -1762,7 +1767,7 @@ rib_process (struct route_node *rn)
*/ */
if (PREFIX_FAMILY (&rn->p) == AF_INET) if (PREFIX_FAMILY (&rn->p) == AF_INET)
{ {
if (!select || RIB_SYSTEM_ROUTE(select)) if (!select)
rib_uninstall_kernel (rn, fib); rib_uninstall_kernel (rn, fib);
else else
update_ok = 1; update_ok = 1;
@ -1802,6 +1807,7 @@ rib_process (struct route_node *rn)
if (! RIB_SYSTEM_ROUTE (select)) if (! RIB_SYSTEM_ROUTE (select))
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 */
redistribute_add (&rn->p, select); redistribute_add (&rn->p, select);
} }
else else
@ -1812,6 +1818,8 @@ rib_process (struct route_node *rn)
assert (fib); assert (fib);
rib_uninstall_kernel (rn, fib); rib_uninstall_kernel (rn, fib);
} }
/* if "select", the earlier redist delete wouldn't have happened */
redistribute_delete(&rn->p, select);
} }
UNSET_FLAG(select->flags, ZEBRA_FLAG_CHANGED); UNSET_FLAG(select->flags, ZEBRA_FLAG_CHANGED);
} }
@ -2941,7 +2949,6 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
{ {
redistribute_delete (&rn->p, rib);
/* If there are other active nexthops, do an update. */ /* If there are other active nexthops, do an update. */
if (rib->nexthop_active_num > 1) if (rib->nexthop_active_num > 1)
{ {
@ -2949,7 +2956,10 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
redistribute_add (&rn->p, rib); redistribute_add (&rn->p, rib);
} }
else else
rib_uninstall_kernel (rn, rib); {
redistribute_delete (&rn->p, rib);
rib_uninstall_kernel (rn, rib);
}
} }
/* Delete the nexthop and dereg from NHT */ /* Delete the nexthop and dereg from NHT */

View File

@ -480,31 +480,18 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp)
} }
/* /*
* The zebra server sends the clients a ZEBRA_IPV4_ROUTE_ADD or a * This is the new function to announce and withdraw redistributed routes, used
* ZEBRA_IPV6_ROUTE_ADD via zsend_route_multipath in the following * by Zebra. This is the old zsend_route_multipath() function. That function
* situations: * was duplicating code to send a lot of information that was essentially thrown
* - when the client starts up, and requests default information * away or ignored by the receiver. This is the leaner function that is not a
* by sending a ZEBRA_REDISTRIBUTE_DEFAULT_ADD to the zebra server, in the * duplicate of the zapi_ipv4_route_add/del.
* - case of rip, ripngd, ospfd and ospf6d, when the client sends a
* ZEBRA_REDISTRIBUTE_ADD as a result of the "redistribute" vty cmd,
* - when the zebra server redistributes routes after it updates its rib
* *
* The zebra server sends clients a ZEBRA_IPV4_ROUTE_DELETE or a * The primary difference is that this function merely sends a single NH instead of
* ZEBRA_IPV6_ROUTE_DELETE via zsend_route_multipath when: * all the nexthops.
* - a "ip route" or "ipv6 route" vty command is issued, a prefix is
* - deleted from zebra's rib, and this info
* has to be redistributed to the clients
*
* XXX The ZEBRA_IPV*_ROUTE_ADD message is also sent by the client to the
* zebra server when the client wants to tell the zebra server to add a
* route to the kernel (zapi_ipv4_add etc. ). Since it's essentially the
* same message being sent back and forth, this function and
* zapi_ipv{4,6}_{add, delete} should be re-written to avoid code
* duplication.
*/ */
int int
zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p,
struct rib *rib) struct rib *rib)
{ {
int psize; int psize;
struct stream *s; struct stream *s;
@ -512,9 +499,11 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
unsigned long nhnummark = 0, messmark = 0; unsigned long nhnummark = 0, messmark = 0;
int nhnum = 0; int nhnum = 0;
u_char zapi_flags = 0; u_char zapi_flags = 0;
struct nexthop dummy_nh;
s = client->obuf; s = client->obuf;
stream_reset (s); stream_reset (s);
memset(&dummy_nh, 0, sizeof(struct nexthop));
zserv_create_header (s, cmd); zserv_create_header (s, cmd);
@ -532,30 +521,45 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
stream_putc (s, p->prefixlen); stream_putc (s, p->prefixlen);
stream_write (s, (u_char *) & p->u.prefix, psize); stream_write (s, (u_char *) & p->u.prefix, psize);
/*
* XXX The message format sent by zebra below does not match the format
* of the corresponding message expected by the zebra server
* itself (e.g., see zread_ipv4_add). The nexthop_num is not set correctly,
* (is there a bug on the client side if more than one segment is sent?)
* nexthop ZEBRA_NEXTHOP_IPV4 is never set, ZEBRA_NEXTHOP_IFINDEX
* is hard-coded.
*/
/* Nexthop */
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
{ {
/* We don't send any nexthops when there's a multipath */
if (rib->nexthop_active_num > 1)
{
SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
stream_putc(s, 1);
if (p->family == AF_INET)
{
stream_put_in_addr (s, &dummy_nh.gate.ipv4);
}
else if (p->family == AF_INET6)
{
stream_write (s, (u_char *) &dummy_nh.gate.ipv6, 16);
}
else
{
/* We don't handle anything else now, abort */
zlog_err("%s: Unable to redistribute route of unknown family, %d\n",
__func__, p->family);
return -1;
}
stream_putc (s, 1);
stream_putl (s, 0); /* dummy ifindex */
break;
}
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
|| nexthop_has_fib_child(nexthop)) || nexthop_has_fib_child(nexthop))
{ {
SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX); SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
if (nhnummark == 0) if (nhnummark == 0)
{ {
nhnummark = stream_get_endp (s); nhnummark = stream_get_endp (s);
stream_putc (s, 1); /* placeholder */ stream_putc (s, 1); /* placeholder */
} }
nhnum++; nhnum++;
switch(nexthop->type) switch(nexthop->type)
@ -568,12 +572,16 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6_IFINDEX:
case NEXTHOP_TYPE_IPV6_IFNAME: case NEXTHOP_TYPE_IPV6_IFNAME:
stream_write (s, (u_char *) &nexthop->gate.ipv6, 16); /* Only BGP supports IPv4 prefix with IPv6 NH, so kill this */
if (p->family == AF_INET)
stream_put_in_addr(s, &dummy_nh.gate.ipv4);
else
stream_write (s, (u_char *) &nexthop->gate.ipv6, 16);
break; break;
#endif #endif
default: default:
if (cmd == ZEBRA_IPV4_ROUTE_ADD if (cmd == ZEBRA_REDISTRIBUTE_IPV4_ADD
|| cmd == ZEBRA_IPV4_ROUTE_DELETE) || cmd == ZEBRA_REDISTRIBUTE_IPV4_DEL)
{ {
struct in_addr empty; struct in_addr empty;
memset (&empty, 0, sizeof (struct in_addr)); memset (&empty, 0, sizeof (struct in_addr));
@ -596,7 +604,7 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
} }
/* Metric */ /* Metric */
if (cmd == ZEBRA_IPV4_ROUTE_ADD || cmd == ZEBRA_IPV6_ROUTE_ADD) if (cmd == ZEBRA_REDISTRIBUTE_IPV4_ADD || cmd == ZEBRA_REDISTRIBUTE_IPV6_ADD)
{ {
SET_FLAG (zapi_flags, ZAPI_MESSAGE_DISTANCE); SET_FLAG (zapi_flags, ZAPI_MESSAGE_DISTANCE);
stream_putc (s, rib->distance); stream_putc (s, rib->distance);

View File

@ -149,8 +149,8 @@ extern void nbr_connected_replacement_add_ipv6 (struct interface *,
struct in6_addr *, u_char); struct in6_addr *, u_char);
extern void nbr_connected_delete_ipv6 (struct interface *, struct in6_addr *, u_char); extern void nbr_connected_delete_ipv6 (struct interface *, struct in6_addr *, u_char);
extern int zsend_interface_update (int, struct zserv *, struct interface *); extern int zsend_interface_update (int, struct zserv *, struct interface *);
extern int zsend_route_multipath (int, struct zserv *, struct prefix *, extern int zsend_redistribute_route (int, struct zserv *, struct prefix *,
struct rib *); struct rib *);
extern int zsend_router_id_update(struct zserv *, struct prefix *); extern int zsend_router_id_update(struct zserv *, struct prefix *);
extern pid_t pid; extern pid_t pid;