summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_zebra.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_zebra.c')
-rw-r--r--bgpd/bgp_zebra.c729
1 files changed, 579 insertions, 150 deletions
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index d0b9216a..92883d5d 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -39,6 +39,8 @@ Boston, MA 02111-1307, USA. */
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_nht.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
@@ -46,6 +48,44 @@ struct in_addr router_id_zebra;
/* Growable buffer for nexthops sent to zebra */
struct stream *bgp_nexthop_buf = NULL;
+struct stream *bgp_ifindices_buf = NULL;
+
+/* These array buffers are used in making a copy of the attributes for
+ route-map apply. Arrays are being used here to minimize mallocs and
+ frees for the temporary copy of the attributes.
+ Given the zapi api expects the nexthop buffer to contain pointer to
+ pointers for nexthops, we couldnt have used a single nexthop variable
+ on the stack, hence we had two options:
+ 1. maintain a linked-list and free it after zapi_*_route call
+ 2. use an array to avoid number of mallocs.
+ Number of supported next-hops are finite, use of arrays should be ok. */
+struct attr attr_cp[BGP_MAXIMUM_MAXPATHS];
+struct attr_extra attr_extra_cp[BGP_MAXIMUM_MAXPATHS];
+int attr_index = 0;
+
+/* Once per address-family initialization of the attribute array */
+#define BGP_INFO_ATTR_BUF_INIT()\
+do {\
+ memset(attr_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr));\
+ memset(attr_extra_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr_extra));\
+ attr_index = 0;\
+} while (0)
+
+#define BGP_INFO_ATTR_BUF_COPY(info_src, info_dst)\
+do { \
+ *info_dst = *info_src; \
+ assert(attr_index != BGP_MAXIMUM_MAXPATHS);\
+ attr_cp[attr_index].extra = &attr_extra_cp[attr_index]; \
+ bgp_attr_dup (&attr_cp[attr_index], info_src->attr); \
+ bgp_attr_deep_dup (&attr_cp[attr_index], info_src->attr); \
+ info_dst->attr = &attr_cp[attr_index]; \
+ attr_index++;\
+} while (0)
+
+#define BGP_INFO_ATTR_BUF_FREE(info) \
+do { \
+ bgp_attr_deep_free(info->attr); \
+} while (0)
/* Router-id update message from zebra. */
static int
@@ -58,7 +98,7 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length,
zebra_router_id_update_read(zclient->ibuf,&router_id);
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
{
char buf[128];
prefix2str(&router_id, buf, sizeof(buf));
@@ -76,6 +116,55 @@ bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length,
return 0;
}
+/* Nexthop update message from zebra. */
+static int
+bgp_read_nexthop_update (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ bgp_parse_nexthop_update();
+ return 0;
+}
+
+static void
+bgp_nbr_connected_add (struct nbr_connected *ifc)
+{
+ struct listnode *node, *nnode, *mnode;
+ struct bgp *bgp;
+ struct peer *peer;
+
+ for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
+ {
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0))
+ {
+ if (peer_active(peer))
+ BGP_EVENT_ADD (peer, BGP_Stop);
+ BGP_EVENT_ADD (peer, BGP_Start);
+ }
+ }
+ }
+}
+
+static void
+bgp_nbr_connected_delete (struct nbr_connected *ifc)
+{
+ struct listnode *node, *nnode, *mnode;
+ struct bgp *bgp;
+ struct peer *peer;
+
+ for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
+ {
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0))
+ {
+ BGP_EVENT_ADD (peer, BGP_Stop);
+ }
+ }
+ }
+}
+
/* Inteface addition message from zebra. */
static int
bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length,
@@ -85,7 +174,7 @@ bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length,
ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
- if (BGP_DEBUG(zebra, ZEBRA) && ifp)
+ if (BGP_DEBUG (zebra, ZEBRA) && ifp)
zlog_debug("Zebra rcvd: interface add %s", ifp->name);
return 0;
@@ -102,7 +191,7 @@ bgp_interface_delete (int command, struct zclient *zclient,
ifp = zebra_interface_state_read (s, vrf_id);
ifp->ifindex = IFINDEX_INTERNAL;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Zebra rcvd: interface delete %s", ifp->name);
return 0;
@@ -115,6 +204,7 @@ bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length,
struct stream *s;
struct interface *ifp;
struct connected *c;
+ struct nbr_connected *nc;
struct listnode *node, *nnode;
s = zclient->ibuf;
@@ -123,12 +213,15 @@ bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length,
if (! ifp)
return 0;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Zebra rcvd: interface %s up", ifp->name);
for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
bgp_connected_add (c);
+ for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
+ bgp_nbr_connected_add (nc);
+
return 0;
}
@@ -139,6 +232,7 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length,
struct stream *s;
struct interface *ifp;
struct connected *c;
+ struct nbr_connected *nc;
struct listnode *node, *nnode;
s = zclient->ibuf;
@@ -146,12 +240,15 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length,
if (! ifp)
return 0;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Zebra rcvd: interface %s down", ifp->name);
for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
bgp_connected_delete (c);
+ for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
+ bgp_nbr_connected_delete (nc);
+
/* Fast external-failover */
{
struct listnode *mnode;
@@ -188,7 +285,7 @@ bgp_interface_address_add (int command, struct zclient *zclient,
if (ifc == NULL)
return 0;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra(ifc->address))
{
char buf[128];
prefix2str(ifc->address, buf, sizeof(buf));
@@ -213,7 +310,7 @@ bgp_interface_address_delete (int command, struct zclient *zclient,
if (ifc == NULL)
return 0;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra(ifc->address))
{
char buf[128];
prefix2str(ifc->address, buf, sizeof(buf));
@@ -229,6 +326,58 @@ bgp_interface_address_delete (int command, struct zclient *zclient,
return 0;
}
+static int
+bgp_interface_nbr_address_add (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct nbr_connected *ifc = NULL;
+
+ ifc = zebra_interface_nbr_address_read (command, zclient->ibuf);
+
+ if (ifc == NULL)
+ return 0;
+
+ if (bgp_debug_zebra(ifc->address))
+ {
+ char buf[128];
+ prefix2str(ifc->address, buf, sizeof(buf));
+ zlog_debug("Zebra rcvd: interface %s nbr address add %s",
+ ifc->ifp->name, buf);
+ }
+
+ if (if_is_operative (ifc->ifp))
+ bgp_nbr_connected_add (ifc);
+
+ return 0;
+}
+
+static int
+bgp_interface_nbr_address_delete (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct nbr_connected *ifc = NULL;
+
+ ifc = zebra_interface_nbr_address_read (command, zclient->ibuf);
+
+ if (ifc == NULL)
+ return 0;
+
+ if (bgp_debug_zebra(ifc->address))
+ {
+ char buf[128];
+ prefix2str(ifc->address, buf, sizeof(buf));
+ zlog_debug("Zebra rcvd: interface %s nbr address delete %s",
+ ifc->ifp->name, buf);
+ }
+
+ if (if_is_operative (ifc->ifp))
+ bgp_nbr_connected_delete (ifc);
+
+ nbr_connected_free (ifc);
+
+ return 0;
+}
+
/* Zebra route add and delete treatment. */
static int
zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
@@ -239,6 +388,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
struct in_addr nexthop;
struct prefix_ipv4 p;
unsigned char plength = 0;
+ ifindex_t ifindex;
s = zclient->ibuf;
nexthop.s_addr = 0;
@@ -264,7 +414,11 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
{
api.ifindex_num = stream_getc (s);
- stream_getl (s); /* ifindex, unused */
+ ifindex = stream_getl (s); /* ifindex, unused */
+ }
+ else
+ {
+ ifindex = 0;
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
@@ -273,33 +427,40 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
else
api.metric = 0;
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+ api.tag = stream_getw (s);
+ else
+ api.tag = 0;
+
if (command == ZEBRA_IPV4_ROUTE_ADD)
{
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u",
+ zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u tag %d",
zebra_route_string(api.type),
inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
- api.metric);
+ api.metric,
+ api.tag);
}
- bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL,
- api.metric, api.type);
+ bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, ifindex,
+ api.metric, api.type, api.tag);
}
else
{
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv4 route delete %s %s/%d "
- "nexthop %s metric %u",
+ "nexthop %s metric %u tag %d",
zebra_route_string(api.type),
inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
- api.metric);
+ api.metric,
+ api.tag);
}
bgp_redistribute_delete((struct prefix *)&p, api.type);
}
@@ -317,6 +478,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
struct in6_addr nexthop;
struct prefix_ipv6 p;
unsigned char plength = 0;
+ ifindex_t ifindex;
s = zclient->ibuf;
memset (&nexthop, 0, sizeof (struct in6_addr));
@@ -342,7 +504,11 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
{
api.ifindex_num = stream_getc (s);
- stream_getl (s); /* ifindex, unused */
+ ifindex = stream_getl (s); /* ifindex, unused */
+ }
+ else
+ {
+ ifindex = 0;
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
@@ -353,37 +519,44 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
else
api.metric = 0;
+ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
+ api.tag = stream_getw (s);
+ else
+ api.tag = 0;
+
/* Simply ignore link-local address. */
if (IN6_IS_ADDR_LINKLOCAL (&p.prefix))
return 0;
if (command == ZEBRA_IPV6_ROUTE_ADD)
{
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u",
+ zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u tag %d",
zebra_route_string(api.type),
inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
- api.metric);
+ api.metric,
+ api.tag);
}
- bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop,
- api.metric, api.type);
+ bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, ifindex,
+ api.metric, api.type, api.tag);
}
else
{
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET6_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d "
- "nexthop %s metric %u",
+ "nexthop %s metric %u tag %d",
zebra_route_string(api.type),
inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])),
- api.metric);
+ api.metric,
+ api.tag);
}
bgp_redistribute_delete ((struct prefix *) &p, api.type);
}
@@ -571,17 +744,22 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
if (local->sa.sa_family == AF_INET)
{
nexthop->v4 = local->sin.sin_addr;
- ifp = if_lookup_by_ipv4 (&local->sin.sin_addr);
+ if (peer->update_if)
+ ifp = if_lookup_by_name (peer->update_if);
+ else
+ ifp = if_lookup_by_ipv4_exact (&local->sin.sin_addr);
}
if (local->sa.sa_family == AF_INET6)
{
if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
{
- if (peer->ifname)
- ifp = if_lookup_by_name (peer->ifname);
+ if (peer->conf_if || peer->ifname)
+ ifp = if_lookup_by_index (if_nametoindex (peer->conf_if ? peer->conf_if : peer->ifname));
}
+ else if (peer->update_if)
+ ifp = if_lookup_by_name (peer->update_if);
else
- ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr);
+ ifp = if_lookup_by_ipv6_exact (&local->sin6.sin6_addr);
}
if (!ifp)
@@ -661,14 +839,73 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
return ret;
}
+static struct in6_addr *
+bgp_info_to_ipv6_nexthop (struct bgp_info *info)
+{
+ struct in6_addr *nexthop = NULL;
+
+ /* Only global address nexthop exists. */
+ if (info->attr->extra->mp_nexthop_len == 16)
+ nexthop = &info->attr->extra->mp_nexthop_global;
+
+ /* If both global and link-local address present. */
+ if (info->attr->extra->mp_nexthop_len == 32)
+ {
+ /* Workaround for Cisco's nexthop bug. */
+ if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
+ && info->peer->su_remote->sa.sa_family == AF_INET6)
+ nexthop = &info->peer->su_remote->sin6.sin6_addr;
+ else
+ nexthop = &info->attr->extra->mp_nexthop_local;
+ }
+
+ return nexthop;
+}
+
+static int
+bgp_table_map_apply (struct route_map *map, struct prefix *p,
+ struct bgp_info *info)
+{
+ if (route_map_apply(map, p, RMAP_BGP, info) != RMAP_DENYMATCH)
+ return 1;
+
+ if (bgp_debug_zebra(p))
+ {
+ if (p->family == AF_INET)
+ {
+ char buf[2][INET_ADDRSTRLEN];
+ zlog_debug("Zebra rmap deny: IPv4 route %s/%d nexthop %s",
+ inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
+ p->prefixlen,
+ inet_ntop(AF_INET, &info->attr->nexthop, buf[1],
+ sizeof(buf[1])));
+ }
+ if (p->family == AF_INET6)
+ {
+ char buf[2][INET6_ADDRSTRLEN];
+ zlog_debug("Zebra rmap deny: IPv6 route %s/%d nexthop %s",
+ inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
+ p->prefixlen,
+ inet_ntop(AF_INET6, bgp_info_to_ipv6_nexthop(info), buf[1],
+ sizeof(buf[1])));
+ }
+ }
+ return 0;
+}
+
void
-bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi)
+bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
+ afi_t afi, safi_t safi)
{
int flags;
u_char distance;
struct peer *peer;
struct bgp_info *mpinfo;
size_t oldsize, newsize;
+ u_int32_t nhcount, metric;
+ struct bgp_info local_info;
+ struct bgp_info *info_cp = &local_info;
+ u_short tag = 0;
if (zclient->sock < 0)
return;
@@ -676,9 +913,15 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_BGP], VRF_DEFAULT))
return;
+ if (bgp->main_zebra_update_hold)
+ return;
+
flags = 0;
peer = info->peer;
+ if ((info->attr->extra) && (info->attr->extra->tag != 0))
+ tag = info->attr->extra->tag;
+
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED)
{
SET_FLAG (flags, ZEBRA_FLAG_IBGP);
@@ -689,46 +932,108 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
- /* resize nexthop buffer size if necessary */
- if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
- (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1)))
- {
- newsize = (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1));
- newsize = stream_resize (bgp_nexthop_buf, newsize);
- if (newsize == oldsize)
- {
- zlog_err ("can't resize nexthop buffer");
- return;
- }
- }
-
- stream_reset (bgp_nexthop_buf);
+ nhcount = 1 + bgp_info_mpath_count (info);
if (p->family == AF_INET)
{
struct zapi_ipv4 api;
struct in_addr *nexthop;
+ char buf[2][INET_ADDRSTRLEN];
+ int valid_nh_count = 0;
+
+ /* resize nexthop buffer size if necessary */
+ if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
+ (sizeof (struct in_addr *) * nhcount))
+ {
+ newsize = (sizeof (struct in_addr *) * nhcount);
+ newsize = stream_resize (bgp_nexthop_buf, newsize);
+ if (newsize == oldsize)
+ {
+ zlog_err ("can't resize nexthop buffer");
+ return;
+ }
+ }
+ stream_reset (bgp_nexthop_buf);
+ nexthop = NULL;
+
+ /* Metric is currently based on the best-path only. */
+ metric = info->attr->med;
+
+ if (bgp->table_map[afi][safi].name)
+ {
+ BGP_INFO_ATTR_BUF_INIT();
+
+ /* Copy info and attributes, so the route-map apply doesn't modify the
+ BGP route info. */
+ BGP_INFO_ATTR_BUF_COPY(info, info_cp);
+ if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+ {
+ metric = info_cp->attr->med;
+ nexthop = &info_cp->attr->nexthop;
+
+ if (info_cp->attr->extra)
+ tag = info_cp->attr->extra->tag;
+ }
+ BGP_INFO_ATTR_BUF_FREE(info_cp);
+ }
+ else
+ {
+ nexthop = &info->attr->nexthop;
+ }
+
+ if (nexthop)
+ {
+ stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
+ valid_nh_count++;
+ }
api.vrf_id = VRF_DEFAULT;
api.flags = flags;
nexthop = &info->attr->nexthop;
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
+
for (mpinfo = bgp_info_mpath_first (info); mpinfo;
- mpinfo = bgp_info_mpath_next (mpinfo))
- {
- nexthop = &mpinfo->attr->nexthop;
- stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
- }
+ mpinfo = bgp_info_mpath_next (mpinfo))
+ {
+ nexthop = NULL;
+
+ if (bgp->table_map[afi][safi].name)
+ {
+ /* Copy info and attributes, so the route-map apply doesn't modify the
+ BGP route info. */
+ BGP_INFO_ATTR_BUF_COPY(mpinfo, info_cp);
+ if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+ nexthop = &info_cp->attr->nexthop;
+ BGP_INFO_ATTR_BUF_FREE(info_cp);
+ }
+ else
+ {
+ nexthop = &mpinfo->attr->nexthop;
+ }
+
+ if (nexthop == NULL)
+ continue;
+
+ stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
+ valid_nh_count++;
+ }
+ api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
- api.nexthop_num = 1 + bgp_info_mpath_count (info);
+ api.nexthop_num = valid_nh_count;
api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
api.ifindex_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
- api.metric = info->attr->med;
+ api.metric = metric;
+
+ if (tag)
+ {
+ SET_FLAG (api.message, ZAPI_MESSAGE_TAG);
+ api.tag = tag;
+ }
distance = bgp_distance_apply (p, info, bgp);
@@ -738,24 +1043,20 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
api.distance = distance;
}
- if (BGP_DEBUG(zebra, ZEBRA))
- {
- int i;
- char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u"
- " count %d",
- inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
- p->prefixlen,
- inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])),
- api.metric, api.nexthop_num);
- for (i = 1; i < api.nexthop_num; i++)
- zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s",
- i, inet_ntop(AF_INET, api.nexthop[i], buf[1],
- sizeof(buf[1])));
- }
-
- zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient,
- (struct prefix_ipv4 *) p, &api);
+ if (bgp_debug_zebra(p))
+ {
+ int i;
+ zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u tag %d"
+ " count %d", (valid_nh_count ? "add":"delete"),
+ inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
+ p->prefixlen, api.metric, api.tag, api.nexthop_num);
+ for (i = 0; i < api.nexthop_num; i++)
+ zlog_debug(" IPv4 [nexthop %d] %s", i+1,
+ inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1])));
+ }
+
+ zapi_ipv4_route (valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD: ZEBRA_IPV4_ROUTE_DELETE,
+ zclient, (struct prefix_ipv4 *) p, &api);
}
/* We have to think about a IPv6 link-local address curse. */
@@ -764,40 +1065,131 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
ifindex_t ifindex;
struct in6_addr *nexthop;
struct zapi_ipv6 api;
+ int valid_nh_count = 0;
+ char buf[2][INET6_ADDRSTRLEN];
+
+ /* resize nexthop buffer size if necessary */
+ if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
+ (sizeof (struct in6_addr *) * nhcount))
+ {
+ newsize = (sizeof (struct in6_addr *) * nhcount);
+ newsize = stream_resize (bgp_nexthop_buf, newsize);
+ if (newsize == oldsize)
+ {
+ zlog_err ("can't resize nexthop buffer");
+ return;
+ }
+ }
+ stream_reset (bgp_nexthop_buf);
+
+ /* resize ifindices buffer size if necessary */
+ if ((oldsize = stream_get_size (bgp_ifindices_buf)) <
+ (sizeof (unsigned int) * nhcount))
+ {
+ newsize = (sizeof (unsigned int) * nhcount);
+ newsize = stream_resize (bgp_ifindices_buf, newsize);
+ if (newsize == oldsize)
+ {
+ zlog_err ("can't resize nexthop buffer");
+ return;
+ }
+ }
+ stream_reset (bgp_ifindices_buf);
ifindex = 0;
nexthop = NULL;
-
- assert (info->attr->extra);
-
- /* Only global address nexthop exists. */
- if (info->attr->extra->mp_nexthop_len == 16)
- nexthop = &info->attr->extra->mp_nexthop_global;
-
- /* If both global and link-local address present. */
- if (info->attr->extra->mp_nexthop_len == 32)
- {
- /* Workaround for Cisco's nexthop bug. */
- if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
- && peer->su_remote->sa.sa_family == AF_INET6)
- nexthop = &peer->su_remote->sin6.sin6_addr;
- else
- nexthop = &info->attr->extra->mp_nexthop_local;
- if (info->peer->nexthop.ifp)
- ifindex = info->peer->nexthop.ifp->ifindex;
- }
+ assert (info->attr->extra);
- if (nexthop == NULL)
- return;
+ /* Metric is currently based on the best-path only. */
+ metric = info->attr->med;
+
+ if (bgp->table_map[afi][safi].name)
+ {
+ BGP_INFO_ATTR_BUF_INIT();
+
+ /* Copy info and attributes, so the route-map apply doesn't modify the
+ BGP route info. */
+ BGP_INFO_ATTR_BUF_COPY(info, info_cp);
+ if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+ {
+ metric = info_cp->attr->med;
+ nexthop = bgp_info_to_ipv6_nexthop(info_cp);
+
+ if (info_cp->attr->extra)
+ tag = info_cp->attr->extra->tag;
+ }
+ BGP_INFO_ATTR_BUF_FREE(info_cp);
+ }
+ else
+ {
+ nexthop = bgp_info_to_ipv6_nexthop(info);
+ }
+
+ if (nexthop)
+ {
+ if (IN6_IS_ADDR_LINKLOCAL (nexthop))
+ {
+ if (info->attr->extra->mp_nexthop_len == 32)
+ if (info->peer->nexthop.ifp)
+ ifindex = info->peer->nexthop.ifp->ifindex;
+
+ if (!ifindex)
+ {
+ if (info->peer->conf_if || info->peer->ifname)
+ ifindex = if_nametoindex (info->peer->conf_if ? info->peer->conf_if : info->peer->ifname);
+ else if (info->peer->nexthop.ifp)
+ ifindex = info->peer->nexthop.ifp->ifindex;
+ }
+ }
+
+ stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
+ stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
+ valid_nh_count++;
+ }
- if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex)
- {
- if (info->peer->ifname)
- ifindex = ifname2ifindex (info->peer->ifname);
- else if (info->peer->nexthop.ifp)
- ifindex = info->peer->nexthop.ifp->ifindex;
- }
+ for (mpinfo = bgp_info_mpath_first (info); mpinfo;
+ mpinfo = bgp_info_mpath_next (mpinfo))
+ {
+ ifindex = 0;
+ nexthop = NULL;
+
+ if (bgp->table_map[afi][safi].name)
+ {
+ /* Copy info and attributes, so the route-map apply doesn't modify the
+ BGP route info. */
+ BGP_INFO_ATTR_BUF_COPY(mpinfo, info_cp);
+ if (bgp_table_map_apply(bgp->table_map[afi][safi].map, p, info_cp))
+ nexthop = bgp_info_to_ipv6_nexthop(info_cp);
+ BGP_INFO_ATTR_BUF_FREE(info_cp);
+ }
+ else
+ {
+ nexthop = bgp_info_to_ipv6_nexthop(mpinfo);
+ }
+
+ if (nexthop == NULL)
+ continue;
+
+ if (mpinfo->attr->extra->mp_nexthop_len == 32)
+ if (mpinfo->peer->nexthop.ifp)
+ ifindex = mpinfo->peer->nexthop.ifp->ifindex;
+
+ if (!ifindex)
+ {
+ if (mpinfo->peer->conf_if || mpinfo->peer->ifname)
+ ifindex = if_nametoindex (mpinfo->peer->conf_if ? mpinfo->peer->conf_if : mpinfo->peer->ifname);
+ else if (mpinfo->peer->nexthop.ifp)
+ ifindex = mpinfo->peer->nexthop.ifp->ifindex;
+ }
+
+ if (ifindex == 0)
+ continue;
+
+ stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
+ stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
+ valid_nh_count++;
+ }
/* Make Zebra API structure. */
api.vrf_id = VRF_DEFAULT;
@@ -806,29 +1198,57 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa
api.message = 0;
api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
- api.nexthop_num = 1;
- api.nexthop = &nexthop;
+ api.nexthop_num = valid_nh_count;
+ api.nexthop = (struct in6_addr **)STREAM_DATA (bgp_nexthop_buf);
SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
- api.ifindex_num = 1;
- api.ifindex = &ifindex;
+ api.ifindex_num = valid_nh_count;
+ api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf);
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
- api.metric = info->attr->med;
+ api.metric = metric;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (tag)
{
- char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u",
- inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
- p->prefixlen,
- inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])),
- api.metric);
+ SET_FLAG (api.message, ZAPI_MESSAGE_TAG);
+ api.tag = tag;
}
- zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient,
- (struct prefix_ipv6 *) p, &api);
+ if (bgp_debug_zebra(p))
+ {
+ int i;
+ zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u tag %d",
+ valid_nh_count ? "add" : "delete",
+ inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
+ p->prefixlen, api.metric, api.tag);
+ for (i = 0; i < api.nexthop_num; i++)
+ zlog_debug(" IPv6 [nexthop %d] %s (%d)", i+1,
+ inet_ntop(AF_INET6, api.nexthop[i], buf[1], sizeof(buf[1])),
+ api.ifindex[i]);
+ }
+
+ zapi_ipv6_route (valid_nh_count ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE,
+ zclient, (struct prefix_ipv6 *) p, &api);
}
}
+/* Announce all routes of a table to zebra */
+void
+bgp_zebra_announce_table (struct bgp *bgp, afi_t afi, safi_t safi)
+{
+ struct bgp_node *rn;
+ struct bgp_table *table;
+ struct bgp_info *ri;
+
+ table = bgp->rib[afi][safi];
+ if (!table) return;
+
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ for (ri = rn->info; ri; ri = ri->next)
+ if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
+ && ri->type == ZEBRA_ROUTE_BGP
+ && ri->sub_type == BGP_ROUTE_NORMAL)
+ bgp_zebra_announce (&rn->p, ri, bgp, afi, safi);
+}
+
void
bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
{
@@ -842,6 +1262,10 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
return;
peer = info->peer;
+
+ if (peer->bgp && peer->bgp->main_zebra_update_hold)
+ return;
+
flags = 0;
if (peer->sort == BGP_PEER_IBGP)
@@ -869,13 +1293,20 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if ((info->attr->extra) && (info->attr->extra->tag != 0))
+ {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = info->attr->extra->tag;
+ }
+
+ if (bgp_debug_zebra(p))
{
char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u",
+ zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u tag %d",
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen,
- api.metric);
+ api.metric,
+ api.tag);
}
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient,
@@ -886,7 +1317,6 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
if (p->family == AF_INET6)
{
struct zapi_ipv6 api;
-
api.vrf_id = VRF_DEFAULT;
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
@@ -897,13 +1327,20 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if ((info->attr->extra) && (info->attr->extra->tag != 0))
+ {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = info->attr->extra->tag;
+ }
+
+ if (bgp_debug_zebra(p))
{
char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u",
+ zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u tag %d",
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen,
- api.metric);
+ api.metric,
+ api.tag);
}
zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient,
@@ -928,15 +1365,32 @@ bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type)
if (zclient->sock < 0)
return CMD_WARNING;
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type));
-
+
/* Send distribute add message to zebra. */
zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT);
return CMD_SUCCESS;
}
+int
+bgp_redistribute_resend (struct bgp *bgp, afi_t afi, int type)
+{
+ /* Return if zebra connection is not established. */
+ if (zclient->sock < 0)
+ return -1;
+
+ if (BGP_DEBUG (zebra, ZEBRA))
+ zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type));
+
+ /* Send distribute add message to zebra. */
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type, VRF_DEFAULT);
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT);
+
+ return 0;
+}
+
/* Redistribute with route-map specification. */
int
bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type,
@@ -996,7 +1450,7 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type)
&& zclient->sock >= 0)
{
/* Send distribute delete message to zebra. */
- if (BGP_DEBUG(zebra, ZEBRA))
+ if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Zebra send: redistribute delete %s",
zebra_route_string(type));
zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type,
@@ -1009,35 +1463,6 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type)
return CMD_SUCCESS;
}
-/* Unset redistribution route-map configuration. */
-int
-bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type)
-{
- if (! bgp->rmap[afi][type].name)
- return 0;
-
- /* Unset route-map. */
- free (bgp->rmap[afi][type].name);
- bgp->rmap[afi][type].name = NULL;
- bgp->rmap[afi][type].map = NULL;
-
- return 1;
-}
-
-/* Unset redistribution metric configuration. */
-int
-bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type)
-{
- if (! bgp->redist_metric_flag[afi][type])
- return 0;
-
- /* Unset metric. */
- bgp->redist_metric_flag[afi][type] = 0;
- bgp->redist_metric[afi][type] = 0;
-
- return 1;
-}
-
void
bgp_zclient_reset (void)
{
@@ -1062,14 +1487,18 @@ bgp_zebra_init (struct thread_master *master)
zclient->interface_delete = bgp_interface_delete;
zclient->interface_address_add = bgp_interface_address_add;
zclient->interface_address_delete = bgp_interface_address_delete;
+ zclient->interface_nbr_address_add = bgp_interface_nbr_address_add;
+ 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->interface_up = bgp_interface_up;
zclient->interface_down = bgp_interface_down;
zclient->ipv6_route_add = zebra_read_ipv6;
zclient->ipv6_route_delete = zebra_read_ipv6;
+ zclient->nexthop_update = bgp_read_nexthop_update;
bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE);
+ bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE);
}
void