diff options
Diffstat (limited to 'bgpd/bgp_zebra.c')
-rw-r--r-- | bgpd/bgp_zebra.c | 729 |
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 |