summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_zebra.c12
-rw-r--r--isisd/isis_zebra.c6
-rw-r--r--lib/zclient.c16
-rw-r--r--lib/zclient.h4
-rw-r--r--lib/zebra.h6
-rw-r--r--ospf6d/ospf6_zebra.c6
-rw-r--r--ospfd/ospf_asbr.c29
-rw-r--r--ospfd/ospf_zebra.c24
-rw-r--r--ripd/rip_zebra.c6
-rw-r--r--zebra/redistribute.c34
-rw-r--r--zebra/zebra_rib.c24
-rw-r--r--zebra/zserv.c98
-rw-r--r--zebra/zserv.h4
13 files changed, 175 insertions, 94 deletions
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index ee6b32244..c7b0b4364 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -484,7 +484,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
else
api.tag = 0;
- if (command == ZEBRA_IPV4_ROUTE_ADD)
+ if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
{
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,
api.metric, api.type, api.instance, api.tag);
}
- else
+ else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL)
{
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))
return 0;
- if (command == ZEBRA_IPV6_ROUTE_ADD)
+ if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
{
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,
api.metric, api.type, api.instance, api.tag);
}
- else
+ else if (command == ZEBRA_REDISTRIBUTE_IPV6_DEL)
{
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->ipv4_route_add = 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_down = bgp_interface_down;
#ifdef HAVE_IPV6
zclient->ipv6_route_add = 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 */
zclient->nexthop_update = bgp_read_nexthop_update;
zclient->import_check_update = bgp_read_import_check_update;
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index f4179e50e..a29ad6817 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -555,7 +555,7 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient,
else
api.metric = 0;
- if (command == ZEBRA_IPV4_ROUTE_ADD)
+ if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
{
if (isis->debugs & DEBUG_ZEBRA)
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->ipv4_route_add = 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
zclient->ipv6_route_add = 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 */
return;
diff --git a/lib/zclient.c b/lib/zclient.c
index e071228cc..623ca1583 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1259,6 +1259,22 @@ zclient_read (struct thread *thread)
if (zclient->bfd_dest_replay)
(*zclient->bfd_dest_replay) (command, zclient, length);
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:
break;
}
diff --git a/lib/zclient.h b/lib/zclient.h
index 1fbb80da9..8caf682d8 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -98,6 +98,10 @@ struct zclient
int (*nexthop_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 (*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. */
diff --git a/lib/zebra.h b/lib/zebra.h
index 41de01ec2..0a1dd7f46 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -438,7 +438,11 @@ struct in_pktinfo
#define ZEBRA_BFD_DEST_DEREGISTER 35
#define ZEBRA_BFD_DEST_UPDATE 36
#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
* the command value in the old zserv header. To allow old and new
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index a28571493..f97a9db72 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -261,7 +261,7 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
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,
api.nexthop_num, nexthop);
else
@@ -649,8 +649,12 @@ ospf6_zebra_init (struct thread_master *master)
zclient->interface_address_delete = ospf6_zebra_if_address_update_delete;
zclient->ipv4_route_add = 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_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 */
/* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
index 5eb97d8f6..397ab6037 100644
--- a/ospfd/ospf_asbr.c
+++ b/ospfd/ospf_asbr.c
@@ -142,6 +142,7 @@ ospf_external_info_add (u_char type, u_short instance, struct prefix_ipv4 p,
struct external_info *new;
struct route_node *rn;
struct ospf_external *ext;
+ char inetbuf[INET6_BUFSIZ];
ext = ospf_external_lookup(type, instance);
if (!ext)
@@ -152,12 +153,20 @@ ospf_external_info_add (u_char type, u_short instance, struct prefix_ipv4 p,
if (rn)
if (rn->info)
{
- route_unlock_node (rn);
- zlog_warn ("Redistribute[%s][%d]: %s/%d already exists, discard.",
+ new = rn->info;
+ 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,
- inet_ntoa (p.prefix), p.prefixlen);
- /* XFREE (MTYPE_OSPF_TMP, rn->info); */
- return rn->info;
+ inet_ntoa (p.prefix), p.prefixlen, inetbuf);
+ XFREE (MTYPE_OSPF_EXTERNAL_INFO, rn->info);
+ rn->info = NULL;
}
/* 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->tag = tag;
+ /* we don't unlock rn from the get() because we're attaching the info */
if (rn)
rn->info = new;
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
- zlog_debug ("Redistribute[%s]: %s/%d external info created.",
- ospf_redist_string(type),
- inet_ntoa (p.prefix), p.prefixlen);
+ {
+ inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf, INET6_BUFSIZ);
+ 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;
}
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 8c152cdf7..a95b2e1b6 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -1070,7 +1070,7 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
if (ospf == NULL)
return 0;
- if (command == ZEBRA_IPV4_ROUTE_ADD)
+ if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
{
/* XXX|HACK|TODO|FIXME:
* 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,
nexthop, api.tag);
-
+ if (ei == NULL)
+ {
+ /* Nothing has changed, so nothing to do; return */
+ return 0;
+ }
if (ospf->router_id.s_addr == 0)
/* Set flags to generate AS-external-LSA originate event
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);
if (!current)
ospf_external_lsa_originate (ospf, ei);
- else if (IS_LSA_MAXAGE (current))
- ospf_external_lsa_refresh (ospf, current,
- ei, LSA_REFRESH_FORCE);
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);
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->ipv4_route_add = 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_delete_hook (ospf_filter_update);
diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c
index e0092f542..a5cc8260d 100644
--- a/ripd/rip_zebra.c
+++ b/ripd/rip_zebra.c
@@ -140,10 +140,10 @@ rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
api.metric = 0;
/* 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,
&nexthop, api.metric, api.distance);
- else
+ else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL)
rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex);
return 0;
@@ -683,6 +683,8 @@ rip_zclient_init (struct thread_master *master)
zclient->ipv4_route_delete = rip_zebra_read_ipv4;
zclient->interface_up = rip_interface_up;
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_node (&zebra_node, config_write_zebra);
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 0f4cf9521..f55b04ee0 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -105,7 +105,7 @@ zebra_redistribute_default (struct zserv *client)
RNODE_FOREACH_RIB (rn, newrib)
if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
&& 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);
}
}
@@ -125,7 +125,7 @@ zebra_redistribute_default (struct zserv *client)
RNODE_FOREACH_RIB (rn, newrib)
if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
&& 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);
}
}
@@ -151,7 +151,7 @@ zebra_redistribute (struct zserv *client, int type, u_short instance)
&& zebra_check_addr (&rn->p))
{
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
@@ -166,7 +166,7 @@ zebra_redistribute (struct zserv *client, int type, u_short instance)
&& zebra_check_addr (&rn->p))
{
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 */
}
@@ -187,7 +187,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
rib->instance)))
{
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
if ((p->family == AF_INET6) &&
@@ -196,7 +197,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
rib->instance)))
{
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 */
}
@@ -207,7 +209,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
rib->instance))
{
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
if ((p->family == AF_INET6) &&
@@ -215,7 +218,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
rib->instance))
{
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 */
}
@@ -240,15 +244,15 @@ redistribute_delete (struct prefix *p, struct rib *rib)
(client->redist_default ||
redist_check_instance(&client->redist[AFI_IP][rib->type],
rib->instance)))
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p,
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_DEL, client, p,
rib);
#ifdef HAVE_IPV6
if ((p->family == AF_INET6) &&
(client->redist_default ||
redist_check_instance(&client->redist[AFI_IP6][rib->type],
rib->instance)))
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p,
- rib);
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
+ rib);
#endif /* HAVE_IPV6 */
}
else
@@ -256,14 +260,14 @@ redistribute_delete (struct prefix *p, struct rib *rib)
if ((p->family == AF_INET) &&
redist_check_instance(&client->redist[AFI_IP][rib->type],
rib->instance))
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p,
- rib);
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_DEL, client, p,
+ rib);
#ifdef HAVE_IPV6
if ((p->family == AF_INET6) &&
redist_check_instance(&client->redist[AFI_IP6][rib->type],
rib->instance))
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p,
- rib);
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
+ rib);
#endif /* HAVE_IPV6 */
}
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 8e873211a..4e4306b9f 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1683,13 +1683,11 @@ rib_process (struct route_node *rn)
{
zfpm_trigger_update (rn, "updating existing route");
- redistribute_delete (&rn->p, select);
-
if (! RIB_SYSTEM_ROUTE (select))
{
/* For v4, use the replace semantics of netlink. */
if (PREFIX_FAMILY (&rn->p) == AF_INET)
- update_ok = 1;
+ update_ok = 1;
else
rib_uninstall_kernel (rn, select);
}
@@ -1709,10 +1707,15 @@ rib_process (struct route_node *rn)
}
if (! RIB_SYSTEM_ROUTE (select))
rib_install_kernel (rn, select, update_ok);
+
+ /* assuming that the receiver knows how to dedup */
redistribute_add (&rn->p, select);
}
else
{
+ /* Withdraw unreachable redistribute route */
+ redistribute_delete(&rn->p, select);
+
/* For IPv4, do the uninstall here. */
if (update_ok)
rib_uninstall_kernel (rn, select);
@@ -1753,7 +1756,9 @@ rib_process (struct route_node *rn)
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))
{
@@ -1762,7 +1767,7 @@ rib_process (struct route_node *rn)
*/
if (PREFIX_FAMILY (&rn->p) == AF_INET)
{
- if (!select || RIB_SYSTEM_ROUTE(select))
+ if (!select)
rib_uninstall_kernel (rn, fib);
else
update_ok = 1;
@@ -1802,6 +1807,7 @@ rib_process (struct route_node *rn)
if (! RIB_SYSTEM_ROUTE (select))
rib_install_kernel (rn, select, update_ok);
SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);
+ /* Unconditionally announce, this part is exercised by new routes */
redistribute_add (&rn->p, select);
}
else
@@ -1812,6 +1818,8 @@ rib_process (struct route_node *rn)
assert (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);
}
@@ -2941,7 +2949,6 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
{
- redistribute_delete (&rn->p, rib);
/* If there are other active nexthops, do an update. */
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);
}
else
- rib_uninstall_kernel (rn, rib);
+ {
+ redistribute_delete (&rn->p, rib);
+ rib_uninstall_kernel (rn, rib);
+ }
}
/* Delete the nexthop and dereg from NHT */
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 1bd5b9882..ba3c59aaf 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -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
- * ZEBRA_IPV6_ROUTE_ADD via zsend_route_multipath in the following
- * situations:
- * - when the client starts up, and requests default information
- * by sending a ZEBRA_REDISTRIBUTE_DEFAULT_ADD to the zebra server, in the
- * - 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
+ * This is the new function to announce and withdraw redistributed routes, used
+ * by Zebra. This is the old zsend_route_multipath() function. That function
+ * was duplicating code to send a lot of information that was essentially thrown
+ * away or ignored by the receiver. This is the leaner function that is not a
+ * duplicate of the zapi_ipv4_route_add/del.
*
- * The zebra server sends clients a ZEBRA_IPV4_ROUTE_DELETE or a
- * ZEBRA_IPV6_ROUTE_DELETE via zsend_route_multipath when:
- * - 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.
+ * The primary difference is that this function merely sends a single NH instead of
+ * all the nexthops.
*/
int
-zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
- struct rib *rib)
+zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p,
+ struct rib *rib)
{
int psize;
struct stream *s;
@@ -512,17 +499,19 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
unsigned long nhnummark = 0, messmark = 0;
int nhnum = 0;
u_char zapi_flags = 0;
-
+ struct nexthop dummy_nh;
+
s = client->obuf;
stream_reset (s);
-
+ memset(&dummy_nh, 0, sizeof(struct nexthop));
+
zserv_create_header (s, cmd);
-
+
/* Put type and nexthop. */
stream_putc (s, rib->type);
stream_putw (s, rib->instance);
stream_putc (s, rib->flags);
-
+
/* marker for message flags field */
messmark = stream_get_endp (s);
stream_putc (s, 0);
@@ -532,30 +521,45 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
stream_putc (s, p->prefixlen);
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)
{
+ /* 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)
|| nexthop_has_fib_child(nexthop))
{
SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
-
if (nhnummark == 0)
{
nhnummark = stream_get_endp (s);
stream_putc (s, 1); /* placeholder */
}
-
nhnum++;
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_IFINDEX:
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;
#endif
default:
- if (cmd == ZEBRA_IPV4_ROUTE_ADD
- || cmd == ZEBRA_IPV4_ROUTE_DELETE)
+ if (cmd == ZEBRA_REDISTRIBUTE_IPV4_ADD
+ || cmd == ZEBRA_REDISTRIBUTE_IPV4_DEL)
{
struct in_addr empty;
memset (&empty, 0, sizeof (struct in_addr));
@@ -596,7 +604,7 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
}
/* 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);
stream_putc (s, rib->distance);
@@ -610,14 +618,14 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
stream_putw(s, rib->tag);
}
}
-
+
/* write real message flags value */
stream_putc_at (s, messmark, zapi_flags);
-
+
/* Write next-hop number */
if (nhnummark)
stream_putc_at (s, nhnummark, nhnum);
-
+
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 41aaecef1..41a4b9ea9 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -149,8 +149,8 @@ extern void nbr_connected_replacement_add_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_route_multipath (int, struct zserv *, struct prefix *,
- struct rib *);
+extern int zsend_redistribute_route (int, struct zserv *, struct prefix *,
+ struct rib *);
extern int zsend_router_id_update(struct zserv *, struct prefix *);
extern pid_t pid;