diff options
32 files changed, 1347 insertions, 306 deletions
diff --git a/babeld/babeld.c b/babeld/babeld.c index 1d2f60e3ad..4e68f05df4 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -538,7 +538,7 @@ resize_receive_buffer(int size) } static void -babel_distribute_update (struct distribute_ctx *ctx, struct distribute *dist) +babel_distribute_update (struct distribute_ctx *ctx __attribute__((__unused__)), struct distribute *dist) { struct interface *ifp; babel_interface_nfo *babel_ifp; @@ -593,7 +593,7 @@ babel_distribute_update_all (struct prefix_list *notused) } static void -babel_distribute_update_all_wrapper (struct access_list *notused) +babel_distribute_update_all_wrapper (struct access_list *notused __attribute__((__unused__))) { babel_distribute_update_all(NULL); } @@ -872,16 +872,18 @@ babeld_quagga_init(void) /* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */ int -input_filter(const unsigned char *id, +input_filter(const unsigned char *id __attribute__((__unused__)), const unsigned char *prefix, unsigned short plen, - const unsigned char *neigh, unsigned int ifindex) + const unsigned char *neigh __attribute__((__unused__)), + unsigned int ifindex) { return babel_filter(0, prefix, plen, ifindex); } int -output_filter(const unsigned char *id, const unsigned char *prefix, - unsigned short plen, unsigned int ifindex) +output_filter(const unsigned char *id __attribute__((__unused__)), + const unsigned char *prefix, unsigned short plen, + unsigned int ifindex) { return babel_filter(1, prefix, plen, ifindex); } diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d349922c52..c15dada9c1 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2450,6 +2450,10 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, if (!peer->nexthop.ifp) { zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing", peer->host); + if (CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_ADV) && + CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_RCV)) + bgp_notify_send(peer->connection, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_UNREACH_NEXT_HOP); return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 319638e412..dfebc00e0a 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -149,6 +149,7 @@ static const struct message bgp_notify_update_msg[] = { {BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, "/Optional Attribute Error"}, {BGP_NOTIFY_UPDATE_INVAL_NETWORK, "/Invalid Network Field"}, {BGP_NOTIFY_UPDATE_MAL_AS_PATH, "/Malformed AS_PATH"}, + {BGP_NOTIFY_UPDATE_UNREACH_NEXT_HOP, "/Unreachable Link-Local Address"}, {0}}; static const struct message bgp_notify_cease_msg[] = { diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index dc6e0d33c2..8a0c6e10d6 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -766,7 +766,7 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, if (detail) route_vty_out_detail(vty, bgp, bd, bgp_dest_get_prefix(bd), pi, AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED, - json_path, NULL); + json_path, NULL, 0); else route_vty_out(vty, &bd->rn->p, pi, 0, SAFI_EVPN, json_path, false); @@ -893,7 +893,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, if (detail) route_vty_out_detail(vty, bgp, dest, &tmp_p, pi, AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED, json_path, - NULL); + NULL, 0); else route_vty_out(vty, &tmp_p, pi, 0, SAFI_EVPN, @@ -2569,7 +2569,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, json_path = json_object_new_array(); route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, safi, - RPKI_NOT_BEING_USED, json_path, NULL); + RPKI_NOT_BEING_USED, json_path, NULL, 0); if (json) json_object_array_add(json_paths, json_path); @@ -2697,7 +2697,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, } route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p, pi, afi, safi, - RPKI_NOT_BEING_USED, json_path, NULL); + RPKI_NOT_BEING_USED, json_path, NULL, 0); if (json) json_object_array_add(json_paths, json_path); @@ -2807,7 +2807,7 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, json_path = json_object_new_array(); route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, safi, - RPKI_NOT_BEING_USED, json_path, NULL); + RPKI_NOT_BEING_USED, json_path, NULL, 0); if (json) json_object_array_add(json_paths, json_path); @@ -2919,7 +2919,7 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, json_path = json_object_new_array(); route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, - safi, RPKI_NOT_BEING_USED, json_path, NULL); + safi, RPKI_NOT_BEING_USED, json_path, NULL, 0); if (json) json_object_array_add(json_paths, json_path); @@ -3055,7 +3055,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp, json_path = json_object_new_array(); route_vty_out_detail(vty, bgp, dest, p, pi, AFI_L2VPN, SAFI_EVPN, - RPKI_NOT_BEING_USED, json_path, NULL); + RPKI_NOT_BEING_USED, json_path, NULL, 0); if (json) json_object_array_add(json_paths, json_path); @@ -3227,7 +3227,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, AFI_L2VPN, SAFI_EVPN, - RPKI_NOT_BEING_USED, json_path, NULL); + RPKI_NOT_BEING_USED, json_path, NULL, + 0); } else route_vty_out(vty, p, pi, 0, SAFI_EVPN, json_path, false); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 46e529f03d..6a8df3b68e 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1052,6 +1052,7 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, struct bgp_path_info *bpi_ultimate; struct bgp *bgp_nexthop; struct bgp_table *table; + struct interface *ifp; bool nh_valid; bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi); @@ -1062,6 +1063,15 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, else bgp_nexthop = bgp_orig; + /* The nexthop is invalid if its VRF does not exist */ + if (bgp_nexthop->vrf_id == VRF_UNKNOWN) + return false; + + /* The nexthop is invalid if its VRF interface is down*/ + ifp = if_get_vrf_loopback(bgp_nexthop->vrf_id); + if (ifp && !if_is_up(ifp)) + return false; + /* * No nexthop tracking for redistributed routes, for * EVPN-imported routes that get leaked, or for routes @@ -1126,8 +1136,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, struct bgp_path_info *bpi; struct bgp_path_info *new; struct bgp_path_info_extra *extra; - struct bgp_path_info *parent = source_bpi; struct bgp_labels bgp_labels = {}; + struct bgp *bgp_nexthop; bool labelssame; uint8_t i; @@ -1159,8 +1169,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, * match parent */ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { - if (bpi->extra && bpi->extra->vrfleak && - bpi->extra->vrfleak->parent == parent) + if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->parent == source_bpi) break; } @@ -1174,6 +1183,16 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, labelssame = bgp_path_info_labels_same(bpi, bgp_labels.label, bgp_labels.num_labels); + bgp_nexthop = bpi->extra->vrfleak->bgp_orig ?: bgp_orig; + if (bgp_nexthop->vrf_id == VRF_UNKNOWN) { + if (debug) { + zlog_debug("%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, origin VRF does not exist, not leaking", + __func__, to_bgp->name_pretty, source_bpi->flags, + bpi->flags, p); + } + return NULL; + } + if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED) && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { if (debug) { @@ -1185,9 +1204,11 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, return NULL; } - if (attrhash_cmp(bpi->attr, new_attr) && labelssame - && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { - + if (attrhash_cmp(bpi->attr, new_attr) && labelssame && + !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && + leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi, source_bpi, bpi, + bgp_orig, p, + debug) == !!CHECK_FLAG(bpi->flags, BGP_PATH_VALID)) { bgp_attr_unintern(&new_attr); if (debug) zlog_debug( @@ -1274,6 +1295,14 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, return NULL; } + if (bgp_orig->vrf_id == VRF_UNKNOWN) { + if (debug) { + zlog_debug("%s: ->%s(s_flags: 0x%x): %pFX: New route, origin VRF does not exist, not leaking", + __func__, to_bgp->name_pretty, source_bpi->flags, p); + } + return NULL; + } + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0, to_bgp->peer_self, new_attr, bn); @@ -1297,9 +1326,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, if (bgp_labels.num_labels) new->extra->labels = bgp_labels_intern(&bgp_labels); - new->extra->vrfleak->parent = bgp_path_info_lock(parent); - bgp_dest_lock_node( - (struct bgp_dest *)parent->net); + new->extra->vrfleak->parent = bgp_path_info_lock(source_bpi); + bgp_dest_lock_node((struct bgp_dest *)source_bpi->net); new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig); diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 2ef7ec97e3..c8e15372b6 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -38,7 +38,7 @@ extern struct zclient *zclient; static void register_zebra_rnh(struct bgp_nexthop_cache *bnc); static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc); -static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p); +static bool make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p); static void bgp_nht_ifp_initial(struct event *thread); DEFINE_HOOK(bgp_nht_path_update, (struct bgp *bgp, struct bgp_path_info *pi, bool valid), @@ -330,7 +330,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, /* This will return true if the global IPv6 NH is a link local * addr */ - if (make_prefix(afi, pi, &p) < 0) + if (!make_prefix(afi, pi, &p)) return 1; /* @@ -1026,7 +1026,7 @@ void bgp_cleanup_nexthops(struct bgp *bgp) * make_prefix - make a prefix structure from the path (essentially * path's node. */ -static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) +static bool make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) { int is_bgp_static = ((pi->type == ZEBRA_ROUTE_BGP) @@ -1036,12 +1036,13 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) struct bgp_dest *net = pi->net; const struct prefix *p_orig = bgp_dest_get_prefix(net); struct in_addr ipv4; + struct peer *peer = pi->peer; + struct attr *attr = pi->attr; if (p_orig->family == AF_FLOWSPEC) { - if (!pi->peer) - return -1; - return bgp_flowspec_get_first_nh(pi->peer->bgp, - pi, p, afi); + if (!peer) + return false; + return bgp_flowspec_get_first_nh(peer->bgp, pi, p, afi); } memset(p, 0, sizeof(struct prefix)); switch (afi) { @@ -1051,34 +1052,32 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) p->u.prefix4 = p_orig->u.prefix4; p->prefixlen = p_orig->prefixlen; } else { - if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) { - ipv4_mapped_ipv6_to_ipv4( - &pi->attr->mp_nexthop_global, &ipv4); + if (IS_MAPPED_IPV6(&attr->mp_nexthop_global)) { + ipv4_mapped_ipv6_to_ipv4(&attr->mp_nexthop_global, &ipv4); p->u.prefix4 = ipv4; p->prefixlen = IPV4_MAX_BITLEN; } else { if (p_orig->family == AF_EVPN) - p->u.prefix4 = - pi->attr->mp_nexthop_global_in; + p->u.prefix4 = attr->mp_nexthop_global_in; else - p->u.prefix4 = pi->attr->nexthop; + p->u.prefix4 = attr->nexthop; p->prefixlen = IPV4_MAX_BITLEN; } } break; case AFI_IP6: p->family = AF_INET6; - if (pi->attr->srv6_l3vpn) { + if (attr->srv6_l3vpn) { p->prefixlen = IPV6_MAX_BITLEN; - if (pi->attr->srv6_l3vpn->transposition_len != 0 && + if (attr->srv6_l3vpn->transposition_len != 0 && BGP_PATH_INFO_NUM_LABELS(pi)) { - IPV6_ADDR_COPY(&p->u.prefix6, &pi->attr->srv6_l3vpn->sid); + IPV6_ADDR_COPY(&p->u.prefix6, &attr->srv6_l3vpn->sid); transpose_sid(&p->u.prefix6, decode_label(&pi->extra->labels->label[0]), - pi->attr->srv6_l3vpn->transposition_offset, - pi->attr->srv6_l3vpn->transposition_len); + attr->srv6_l3vpn->transposition_offset, + attr->srv6_l3vpn->transposition_len); } else - IPV6_ADDR_COPY(&(p->u.prefix6), &(pi->attr->srv6_l3vpn->sid)); + IPV6_ADDR_COPY(&(p->u.prefix6), &(attr->srv6_l3vpn->sid)); } else if (is_bgp_static) { p->u.prefix6 = p_orig->u.prefix6; p->prefixlen = p_orig->prefixlen; @@ -1086,28 +1085,35 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) /* If we receive MP_REACH nexthop with ::(LL) * or LL(LL), use LL address as nexthop cache. */ - if (pi->attr && - pi->attr->mp_nexthop_len == - BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL && - (IN6_IS_ADDR_UNSPECIFIED( - &pi->attr->mp_nexthop_global) || - IN6_IS_ADDR_LINKLOCAL(&pi->attr->mp_nexthop_global))) - p->u.prefix6 = pi->attr->mp_nexthop_local; + if (attr && attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL && + (IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global) || + IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global))) + p->u.prefix6 = attr->mp_nexthop_local; /* If we receive MR_REACH with (GA)::(LL) * then check for route-map to choose GA or LL */ - else if (pi->attr && - pi->attr->mp_nexthop_len == - BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - if (CHECK_FLAG(pi->attr->nh_flags, - BGP_ATTR_NH_MP_PREFER_GLOBAL)) - p->u.prefix6 = - pi->attr->mp_nexthop_global; + else if (attr && attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + if (CHECK_FLAG(attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL)) + p->u.prefix6 = attr->mp_nexthop_global; else - p->u.prefix6 = - pi->attr->mp_nexthop_local; + p->u.prefix6 = attr->mp_nexthop_local; + } else if (attr && attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL && + IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) { + /* If we receive MP_REACH with GUA as LL, we should + * check if we have Link-Local Next Hop capability also. + */ + if (!(CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_ADV) && + CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_RCV))) { + zlog_warn("%s: received IPv6 global next-hop as Link-Local, but no capability exchanged", + __func__); + p->u.prefix6 = attr->mp_nexthop_global; + } else { + p->u.prefix6 = attr->mp_nexthop_global; + p->prefixlen = IPV6_MAX_BITLEN; + return false; + } } else - p->u.prefix6 = pi->attr->mp_nexthop_global; + p->u.prefix6 = attr->mp_nexthop_global; p->prefixlen = IPV6_MAX_BITLEN; } break; @@ -1119,7 +1125,7 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) } break; } - return 0; + return true; } /** diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 6451c7cf38..be04d87b74 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -43,6 +43,7 @@ const struct message capcode_str[] = { { CAPABILITY_CODE_ROLE, "Role" }, { CAPABILITY_CODE_SOFT_VERSION, "Software Version" }, { CAPABILITY_CODE_PATHS_LIMIT, "Paths-Limit" }, + { CAPABILITY_CODE_LINK_LOCAL, "Link-Local Next Hop" }, { 0 } }; @@ -63,6 +64,7 @@ const size_t cap_minsizes[] = { [CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN, [CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN, [CAPABILITY_CODE_PATHS_LIMIT] = CAPABILITY_CODE_PATHS_LIMIT_LEN, + [CAPABILITY_CODE_LINK_LOCAL] = CAPABILITY_CODE_LINK_LOCAL_LEN, }; /* value the capability must be a multiple of. @@ -1067,6 +1069,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_ROLE: case CAPABILITY_CODE_SOFT_VERSION: case CAPABILITY_CODE_PATHS_LIMIT: + case CAPABILITY_CODE_LINK_LOCAL: /* Check length. */ if (caphdr.length < cap_minsizes[caphdr.code]) { zlog_info( @@ -1168,6 +1171,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_SOFT_VERSION: ret = bgp_capability_software_version(peer, &caphdr); break; + case CAPABILITY_CODE_LINK_LOCAL: + SET_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_RCV); + break; case CAPABILITY_CODE_PATHS_LIMIT: ret = bgp_capability_paths_limit(peer, &caphdr); break; @@ -1968,6 +1974,16 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN); } + /* Link-Local Next Hop capability. */ + if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_LINK_LOCAL)) { + SET_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_ADV); + stream_putc(s, BGP_OPEN_OPT_CAP); + ext_opt_params ? stream_putw(s, CAPABILITY_CODE_LINK_LOCAL_LEN + 2) + : stream_putc(s, CAPABILITY_CODE_LINK_LOCAL_LEN + 2); + stream_putc(s, CAPABILITY_CODE_LINK_LOCAL); + stream_putc(s, CAPABILITY_CODE_LINK_LOCAL_LEN); + } + /* FQDN capability */ if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_FQDN) && cmd_hostname_get()) { diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 3a8cba9b7d..abe3b51f5d 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -54,6 +54,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_EXT_MESSAGE 6 /* Extended Message Support */ #define CAPABILITY_CODE_ROLE 9 /* Role Capability */ #define CAPABILITY_CODE_PATHS_LIMIT 76 /* Paths Limit Capability */ +#define CAPABILITY_CODE_LINK_LOCAL 77 /* draft-white-linklocal-capability */ /* Capability Length */ #define CAPABILITY_CODE_MP_LEN 4 @@ -71,6 +72,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_EXT_MESSAGE_LEN 0 /* Extended Message Support */ #define CAPABILITY_CODE_ROLE_LEN 1 #define CAPABILITY_CODE_SOFT_VERSION_LEN 1 +#define CAPABILITY_CODE_LINK_LOCAL_LEN 0 /* Cooperative Route Filtering Capability. */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index f8726ffff9..3e90d7881c 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1245,6 +1245,18 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, /* Encode MP_EXT capability. */ switch (capability_code) { + case CAPABILITY_CODE_LINK_LOCAL: + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_LINK_LOCAL); + stream_putc(s, 0); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", peer, + action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", + capability, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); + + COND_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_ADV, action == CAPABILITY_ACTION_SET); + break; case CAPABILITY_CODE_SOFT_VERSION: stream_putc(s, action); stream_putc(s, CAPABILITY_CODE_SOFT_VERSION); @@ -3769,6 +3781,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, case CAPABILITY_CODE_ROLE: case CAPABILITY_CODE_SOFT_VERSION: case CAPABILITY_CODE_PATHS_LIMIT: + case CAPABILITY_CODE_LINK_LOCAL: if (hdr->length < cap_minsizes[hdr->code]) { zlog_info("%pBP: %s Capability length error: got %u, expected at least %u", peer, capability, hdr->length, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f46977af69..36690d55f4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2506,8 +2506,16 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, } else if (!ibgp_to_ibgp && !transparent && !CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT) && IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local) && peer->shared_network && - (from == bgp->peer_self || peer->sort == BGP_PEER_EBGP)) - global_and_ll = true; + (from == bgp->peer_self || peer->sort == BGP_PEER_EBGP)) { + /* If an implementation intends to send a single link-local forwarding + * address in the Next Hop field of the MP_REACH_NLRI, it MUST set the + * length of the Next Hop field to 16 and include only the IPv6 link-local + * address in the Next Hop field. + */ + if (!(CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_ADV) && + CHECK_FLAG(peer->cap, PEER_CAP_LINK_LOCAL_RCV))) + global_and_ll = true; + } if (global_and_ll) { if (safi == SAFI_MPLS_VPN) @@ -9946,6 +9954,7 @@ void route_vty_out(struct vty *vty, const struct prefix *p, "ipv6"); json_object_string_add(json_nexthop_global, "scope", "global"); + json_object_int_add(json_nexthop_global, "length", attr->mp_nexthop_len); /* We display both LL & GL if both have been * received */ @@ -9969,6 +9978,8 @@ void route_vty_out(struct vty *vty, const struct prefix *p, "ipv6"); json_object_string_add(json_nexthop_ll, "scope", "link-local"); + json_object_int_add(json_nexthop_global, "length", + attr->mp_nexthop_len); if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global, &attr->mp_nexthop_local) != @@ -10784,7 +10795,7 @@ static void route_vty_out_detail_es_info(struct vty *vty, void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, const struct prefix *p, struct bgp_path_info *path, afi_t afi, safi_t safi, enum rpki_states rpki_curr_state, json_object *json_paths, - struct attr *pattr) + struct attr *pattr, uint16_t show_opts) { char buf[INET6_ADDRSTRLEN]; char vni_buf[30] = {}; @@ -11090,6 +11101,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, "ipv6"); json_object_string_add(json_nexthop_global, "scope", "global"); + json_object_int_add(json_nexthop_global, "length", attr->mp_nexthop_len); } else { if (nexthop_hostname) vty_out(vty, " %pI6(%s)", @@ -11277,6 +11289,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object_string_add(json_nexthop_ll, "afi", "ipv6"); json_object_string_add(json_nexthop_ll, "scope", "link-local"); + json_object_int_add(json_nexthop_ll, "length", attr->mp_nexthop_len); json_object_boolean_true_add(json_nexthop_ll, "accessible"); @@ -11811,6 +11824,16 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, llgr_remaining); } + /* Display internal data if asked */ + if (CHECK_FLAG(show_opts, BGP_SHOW_OPT_INTERNAL_DATA)) { + if (!json_paths) { + vty_out(vty, " net: %p, path: %p, pathext: %p, attr: %p\n", path->net, + path, path->extra, attr); + vty_out(vty, " flags net: 0x%u, path: 0x%u, attr: 0x%" PRIu64 "\n", + path->net->flags, path->flags, attr->flag); + } + } + /* Output some debug about internal state of the dest flags */ if (json_paths) { if (CHECK_FLAG(bn->flags, BGP_NODE_PROCESS_SCHEDULED)) @@ -12242,7 +12265,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa route_vty_out_detail(vty, bgp, dest, dest_p, pi, family2afi(dest_p->family), safi, - rpki_curr_state, json_paths, NULL); + rpki_curr_state, json_paths, NULL, + show_flags); } else { route_vty_out(vty, dest_p, pi, display, safi, json_paths, wide); @@ -12760,7 +12784,8 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, static void bgp_show_path_info(const struct prefix_rd *pfx_rd, struct bgp_dest *bgp_node, struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, json_object *json, enum bgp_path_type pathtype, int *display, - enum rpki_states rpki_target_state, struct attr *attr) + enum rpki_states rpki_target_state, struct attr *attr, + uint16_t show_opts) { struct bgp_path_info *pi; int header = 1; @@ -12804,7 +12829,8 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd, struct bgp_dest * && (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH) || CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)))) route_vty_out_detail(vty, bgp, bgp_node, bgp_dest_get_prefix(bgp_node), pi, - afi, safi, rpki_curr_state, json_paths, attr); + afi, safi, rpki_curr_state, json_paths, attr, + show_opts); } if (json && json_paths) { @@ -12841,12 +12867,11 @@ const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, } /* Display specified route of BGP table. */ -static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, - struct bgp_table *rib, const char *ip_str, - afi_t afi, safi_t safi, - enum rpki_states rpki_target_state, - struct prefix_rd *prd, int prefix_check, - enum bgp_path_type pathtype, bool use_json) +static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, struct bgp_table *rib, + const char *ip_str, afi_t afi, safi_t safi, + enum rpki_states rpki_target_state, struct prefix_rd *prd, + int prefix_check, enum bgp_path_type pathtype, bool use_json, + uint16_t show_opts) { int ret; int display = 0; @@ -12891,8 +12916,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, continue; } - bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, - json, pathtype, &display, rpki_target_state, NULL); + bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, json, + pathtype, &display, rpki_target_state, NULL, show_opts); bgp_dest_unlock_node(rm); } @@ -12951,8 +12976,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, rm = longest_pfx; bgp_dest_lock_node(rm); - bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, - json, pathtype, &display, rpki_target_state, NULL); + bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, json, + pathtype, &display, rpki_target_state, NULL, show_opts); bgp_dest_unlock_node(rm); } @@ -12979,7 +13004,7 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, if (!prefix_check || dest_p->prefixlen == match.prefixlen) { bgp_show_path_info(NULL, dest, vty, bgp, afi, safi, json, pathtype, - &display, rpki_target_state, NULL); + &display, rpki_target_state, NULL, show_opts); } bgp_dest_unlock_node(dest); @@ -12999,10 +13024,10 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, } /* Display specified route of Main RIB */ -static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, - afi_t afi, safi_t safi, struct prefix_rd *prd, - int prefix_check, enum bgp_path_type pathtype, - enum rpki_states rpki_target_state, bool use_json) +static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, afi_t afi, + safi_t safi, struct prefix_rd *prd, int prefix_check, + enum bgp_path_type pathtype, enum rpki_states rpki_target_state, + bool use_json, uint16_t show_opts) { if (!bgp) { bgp = bgp_get_default(); @@ -13019,9 +13044,9 @@ static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, if (safi == SAFI_LABELED_UNICAST) safi = SAFI_UNICAST; - return bgp_show_route_in_table(vty, bgp, bgp->rib[afi][safi], ip_str, - afi, safi, rpki_target_state, prd, - prefix_check, pathtype, use_json); + return bgp_show_route_in_table(vty, bgp, bgp->rib[afi][safi], ip_str, afi, safi, + rpki_target_state, prd, prefix_check, pathtype, use_json, + show_opts); } static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc, @@ -13383,7 +13408,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, |A.B.C.D/M longer-prefixes\ |X:X::X:X/M longer-prefixes\ |"BGP_SELF_ORIG_CMD_STR"\ - |detail-routes$detail_routes\ + |detail-routes$detail_routes [internal$internal]\ ] [json$uj [detail$detail_json] | wide$wide]", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_WITH_LABEL_HELP_STR @@ -13434,6 +13459,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, "Display route and more specific routes\n" BGP_SELF_ORIG_HELP_STR "Display detailed version of all routes\n" + "Display detailed version of all routes including internal data\n" JSON_STR "Display detailed version of JSON output\n" "Increase table width for longer prefixes\n") @@ -13462,6 +13488,9 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, if (detail_routes) SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL); + if (internal) + SET_FLAG(show_flags, BGP_SHOW_OPT_INTERNAL_DATA); + /* [<ipv4|ipv6> [all]] */ if (all) { SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL); @@ -13750,7 +13779,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, DEFUN (show_ip_bgp_route, show_ip_bgp_route_cmd, - "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> [<bestpath|multipath>] [rpki <valid|invalid|notfound>] [json]", + "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> [internal] [<bestpath|multipath>] [rpki <valid|invalid|notfound>] [json]", SHOW_STR IP_STR BGP_STR @@ -13761,6 +13790,7 @@ DEFUN (show_ip_bgp_route, "IPv4 prefix\n" "Network in the BGP routing table to display\n" "IPv6 prefix\n" + "Display internal data additionally\n" "Display only the bestpath\n" "Display only multipaths\n" "Display only paths that match the specified rpki state\n" @@ -13777,6 +13807,7 @@ DEFUN (show_ip_bgp_route, struct bgp *bgp = NULL; enum bgp_path_type path_type; bool uj = use_json(argc, argv); + uint16_t show_opts = 0; int idx = 0; @@ -13814,6 +13845,10 @@ DEFUN (show_ip_bgp_route, prefix = argv[idx]->arg; + /* Display internal data also */ + if (argv_find(argv, argc, "internal", &idx)) + SET_FLAG(show_opts, BGP_SHOW_OPT_INTERNAL_DATA); + /* [<bestpath|multipath>] */ if (argv_find(argv, argc, "bestpath", &idx)) path_type = BGP_PATH_SHOW_BESTPATH; @@ -13822,8 +13857,8 @@ DEFUN (show_ip_bgp_route, else path_type = BGP_PATH_SHOW_ALL; - return bgp_show_route(vty, bgp, prefix, afi, safi, NULL, prefix_check, - path_type, RPKI_NOT_BEING_USED, uj); + return bgp_show_route(vty, bgp, prefix, afi, safi, NULL, prefix_check, path_type, + RPKI_NOT_BEING_USED, uj, show_opts); } DEFUN (show_ip_bgp_regexp, @@ -14681,9 +14716,8 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix, return CMD_WARNING; } - return bgp_show_route(vty, bgp, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0, - BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, - use_json(argc, argv)); + return bgp_show_route(vty, bgp, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_SHOW_ALL, + RPKI_NOT_BEING_USED, use_json(argc, argv), 0); } #endif /* KEEP_OLD_VPN_COMMANDS */ @@ -14715,9 +14749,8 @@ DEFUN (show_bgp_l2vpn_evpn_route_prefix, vty_out(vty, "Unable to figure out Network\n"); return CMD_WARNING; } - return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, - prefix_check, BGP_PATH_SHOW_ALL, - RPKI_NOT_BEING_USED, use_json(argc, argv)); + return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, prefix_check, + BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, use_json(argc, argv), 0); } static void show_adj_route_header(struct vty *vty, struct peer *peer, @@ -14873,8 +14906,9 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (use_json) json_net = json_object_new_object(); - bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, safi, json_net, - BGP_PATH_SHOW_ALL, &display, RPKI_NOT_BEING_USED, NULL); + bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, safi, + json_net, BGP_PATH_SHOW_ALL, &display, + RPKI_NOT_BEING_USED, NULL, show_flags); if (use_json) json_object_object_addf(json_ar, json_net, "%pFX", rn_p); @@ -15010,7 +15044,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, pass_in = dest; bgp_show_path_info(NULL, pass_in, vty, bgp, afi, safi, json_net, BGP_PATH_SHOW_ALL, &display, - RPKI_NOT_BEING_USED, NULL); + RPKI_NOT_BEING_USED, NULL, show_flags); if (use_json) json_object_object_addf( json_ar, json_net, @@ -15062,7 +15096,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, bgp_show_path_info(NULL, dest, vty, bgp, afi, safi, json_net, BGP_PATH_SHOW_ALL, &display, RPKI_NOT_BEING_USED, - adj->attr); + adj->attr, show_flags); if (use_json) json_object_object_addf(json_ar, json_net, "%pFX", rn_p); @@ -15108,9 +15142,10 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (use_json) json_net = json_object_new_object(); - bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, - safi, json_net, BGP_PATH_SHOW_BESTPATH, - &display, RPKI_NOT_BEING_USED, NULL); + bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, + afi, safi, json_net, + BGP_PATH_SHOW_BESTPATH, &display, + RPKI_NOT_BEING_USED, NULL, show_flags); if (use_json) json_object_object_addf( json_ar, json_net, @@ -15754,10 +15789,9 @@ DEFUN (show_bgp_afi_vpn_rd_route, } if (!strcmp(argv[5]->arg, "all")) - return bgp_show_route(vty, NULL, argv[6]->arg, afi, - SAFI_MPLS_VPN, NULL, 0, BGP_PATH_SHOW_ALL, - RPKI_NOT_BEING_USED, - use_json(argc, argv)); + return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, NULL, 0, + BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, use_json(argc, argv), + 0); ret = str2prefix_rd(argv[5]->arg, &prd); if (!ret) { @@ -15765,9 +15799,8 @@ DEFUN (show_bgp_afi_vpn_rd_route, return CMD_WARNING; } - return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, &prd, - 0, BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, - use_json(argc, argv)); + return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, &prd, 0, + BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, use_json(argc, argv), 0); } static struct bgp_distance *bgp_distance_new(void) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index c4cbbee0c7..1f854cad19 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -752,6 +752,7 @@ DECLARE_HOOK(bgp_route_update, #define BGP_SHOW_OPT_JSON_DETAIL (1 << 7) #define BGP_SHOW_OPT_TERSE (1 << 8) #define BGP_SHOW_OPT_ROUTES_DETAIL (1 << 9) +#define BGP_SHOW_OPT_INTERNAL_DATA (1 << 10) /* Prototypes. */ extern void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi, @@ -969,7 +970,7 @@ extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, const struct prefix *p, struct bgp_path_info *path, afi_t afi, safi_t safi, enum rpki_states, json_object *json_paths, - struct attr *attr); + struct attr *attr, uint16_t show_opts); extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 98021f7ef4..fd4fd8afd6 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -114,6 +114,10 @@ FRR_CFG_DEFAULT_BOOL(BGP_SOFT_VERSION_CAPABILITY, { .val_bool = true, .match_profile = "datacenter", }, { .val_bool = false }, ); +FRR_CFG_DEFAULT_BOOL(BGP_LINK_LOCAL_CAPABILITY, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, +); FRR_CFG_DEFAULT_BOOL(BGP_DYNAMIC_CAPABILITY, { .val_bool = true, .match_profile = "datacenter", }, { .val_bool = false }, @@ -623,6 +627,8 @@ int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name, if (DFLT_BGP_SOFT_VERSION_CAPABILITY) SET_FLAG((*bgp)->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY); + if (DFLT_BGP_LINK_LOCAL_CAPABILITY) + SET_FLAG((*bgp)->flags, BGP_FLAG_LINK_LOCAL_CAPABILITY); if (DFLT_BGP_DYNAMIC_CAPABILITY) SET_FLAG((*bgp)->flags, BGP_FLAG_DYNAMIC_CAPABILITY); @@ -4436,6 +4442,24 @@ DEFPY (bgp_default_software_version_capability, return CMD_SUCCESS; } +DEFPY (bgp_default_link_local_capability, + bgp_default_link_local_capability_cmd, + "[no] bgp default link-local-capability", + NO_STR + BGP_STR + "Configure BGP defaults\n" + "Advertise Link-Local Next Hop capability for all neighbors\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (no) + UNSET_FLAG(bgp->flags, BGP_FLAG_LINK_LOCAL_CAPABILITY); + else + SET_FLAG(bgp->flags, BGP_FLAG_LINK_LOCAL_CAPABILITY); + + return CMD_SUCCESS; +} + DEFPY (bgp_default_dynamic_capability, bgp_default_dynamic_capability_cmd, "[no] bgp default dynamic-capability", @@ -6065,6 +6089,34 @@ DEFPY(neighbor_capability_software_version, return ret; } +/* neighbor capability link-local */ +DEFPY(neighbor_capability_link_local, + neighbor_capability_link_local_cmd, + "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor capability link-local", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise Link-Local Next Hop capability to the peer\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (no) + ret = peer_flag_unset_vty(vty, neighbor, PEER_FLAG_CAPABILITY_LINK_LOCAL); + else + ret = peer_flag_set_vty(vty, neighbor, PEER_FLAG_CAPABILITY_LINK_LOCAL); + + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, CAPABILITY_CODE_LINK_LOCAL, + no ? CAPABILITY_ACTION_UNSET : CAPABILITY_ACTION_SET); + + return ret; +} + static int peer_af_flag_modify_vty(struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, uint64_t flag, int set) @@ -14942,6 +14994,16 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object_object_add(json_cap, "softwareVersion", json_soft_version); + /* Link-Local Next Hop capability */ + json_object *json_link_local = NULL; + + json_link_local = json_object_new_object(); + json_object_boolean_add(json_link_local, "advertised", + !!CHECK_FLAG(p->cap, PEER_CAP_LINK_LOCAL_ADV)); + json_object_boolean_add(json_link_local, "received", + !!CHECK_FLAG(p->cap, PEER_CAP_LINK_LOCAL_RCV)); + json_object_object_add(json_cap, "linkLocalNextHop", json_link_local); + /* Graceful Restart */ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) || CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) { @@ -15369,6 +15431,21 @@ CPP_NOTICE("Remove `gracefulRestartCapability` JSON field") vty_out(vty, "\n"); + /* Link-Local Next Hop capability */ + vty_out(vty, " Link-Local Next Hop Capability:"); + + if (CHECK_FLAG(p->cap, PEER_CAP_LINK_LOCAL_ADV)) + vty_out(vty, " advertised link-local"); + else + vty_out(vty, " not advertised"); + + if (CHECK_FLAG(p->cap, PEER_CAP_LINK_LOCAL_RCV)) + vty_out(vty, " received link-local"); + else + vty_out(vty, " not received"); + + vty_out(vty, "\n"); + /* Graceful Restart */ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) || CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) { @@ -18913,6 +18990,15 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, addr); } + /* capability link-local */ + if (CHECK_FLAG(bgp->flags, BGP_FLAG_LINK_LOCAL_CAPABILITY)) { + if (!peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_LINK_LOCAL)) + vty_out(vty, " no neighbor %s capability link-local\n", addr); + } else { + if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_LINK_LOCAL)) + vty_out(vty, " neighbor %s capability link-local\n", addr); + } + /* dont-capability-negotiation */ if (peergroup_flag_check(peer, PEER_FLAG_DONT_CAPABILITY)) vty_out(vty, " neighbor %s dont-capability-negotiate\n", addr); @@ -19622,6 +19708,11 @@ int bgp_config_write(struct vty *vty) ? "" : "no "); + if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_LINK_LOCAL_CAPABILITY) != + SAVE_BGP_LINK_LOCAL_CAPABILITY) + vty_out(vty, " %sbgp default link-local-capability\n", + CHECK_FLAG(bgp->flags, BGP_FLAG_LINK_LOCAL_CAPABILITY) ? "" : "no "); + if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY) != SAVE_BGP_DYNAMIC_CAPABILITY) vty_out(vty, @@ -20728,6 +20819,9 @@ void bgp_vty_init(void) /* bgp default software-version-capability */ install_element(BGP_NODE, &bgp_default_software_version_capability_cmd); + /* bgp default link-local-capability */ + install_element(BGP_NODE, &bgp_default_link_local_capability_cmd); + /* bgp default dynamic-capability */ install_element(BGP_NODE, &bgp_default_dynamic_capability_cmd); @@ -21383,6 +21477,9 @@ void bgp_vty_init(void) /* "neighbor capability software-version" commands.*/ install_element(BGP_NODE, &neighbor_capability_software_version_cmd); + /* "neighbor capability link-local" commands.*/ + install_element(BGP_NODE, &neighbor_capability_link_local_cmd); + /* "neighbor capability orf prefix-list" commands.*/ install_element(BGP_NODE, &neighbor_capability_orf_prefix_hidden_cmd); install_element(BGP_NODE, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index efb2c00fa5..2672f38291 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1575,6 +1575,9 @@ struct peer *peer_new(struct bgp *bgp) if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY)) peer_flag_set(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_LINK_LOCAL_CAPABILITY)) + peer_flag_set(peer, PEER_FLAG_CAPABILITY_LINK_LOCAL); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY)) peer_flag_set(peer, PEER_FLAG_DYNAMIC_CAPABILITY); @@ -2964,6 +2967,11 @@ static void peer_group2peer_config_copy(struct peer_group *group, SET_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY); + /* capability link-local apply */ + if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_LINK_LOCAL)) + if (CHECK_FLAG(conf->flags, PEER_FLAG_CAPABILITY_LINK_LOCAL)) + SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_LINK_LOCAL); + /* password apply */ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD)) PEER_STR_ATTR_INHERIT(peer, group, password, @@ -3410,17 +3418,6 @@ static struct bgp *bgp_create(as_t *as, const char *name, } bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp)); - bgp->as = *as; - if (as_pretty) - bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_pretty); - else - bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, asn_asn2asplain(*as)); - - if (asnotation != ASNOTATION_UNDEFINED) { - bgp->asnotation = asnotation; - SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION); - } else - asn_str2asn_notation(bgp->as_pretty, NULL, &bgp->asnotation); if (BGP_DEBUG(zebra, ZEBRA)) { if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) @@ -3464,6 +3461,18 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->peer = list_new(); peer_init: + bgp->as = *as; + if (as_pretty) + bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_pretty); + else + bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, asn_asn2asplain(*as)); + + if (asnotation != ASNOTATION_UNDEFINED) { + bgp->asnotation = asnotation; + SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION); + } else + asn_str2asn_notation(bgp->as_pretty, NULL, &bgp->asnotation); + bgp->peer->cmp = (int (*)(void *, void *))peer_cmp; bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, "BGP Peer Hash"); @@ -4834,6 +4843,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_EXTENDED_LINK_BANDWIDTH, 0, peer_change_none}, {PEER_FLAG_LONESOUL, 0, peer_change_reset_out}, {PEER_FLAG_TCP_MSS, 0, peer_change_none}, + {PEER_FLAG_CAPABILITY_LINK_LOCAL, 0, peer_change_none}, {0, 0, 0}}; static const struct peer_flag_action peer_af_flag_action_list[] = { @@ -4921,7 +4931,10 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list, static void peer_flag_modify_action(struct peer *peer, uint64_t flag) { - if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) + if (flag == PEER_FLAG_DYNAMIC_CAPABILITY || flag == PEER_FLAG_CAPABILITY_ENHE || + flag == PEER_FLAG_CAPABILITY_FQDN || flag == PEER_FLAG_CAPABILITY_SOFT_VERSION || + flag == PEER_FLAG_DONT_CAPABILITY || flag == PEER_FLAG_OVERRIDE_CAPABILITY || + flag == PEER_FLAG_STRICT_CAP_MATCH || flag == PEER_FLAG_CAPABILITY_LINK_LOCAL) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; else if (flag == PEER_FLAG_PASSIVE) peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index ee904391c1..d02c1c924d 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -566,6 +566,7 @@ struct bgp { #define BGP_FLAG_IPV6_NO_AUTO_RA (1ULL << 40) #define BGP_FLAG_L3VNI_SCHEDULE_FOR_INSTALL (1ULL << 41) #define BGP_FLAG_L3VNI_SCHEDULE_FOR_DELETE (1ULL << 42) +#define BGP_FLAG_LINK_LOCAL_CAPABILITY (1ULL << 43) /* BGP default address-families. * New peers inherit enabled afi/safis from bgp instance. @@ -1410,6 +1411,8 @@ struct peer { #define PEER_CAP_SOFT_VERSION_RCV (1ULL << 28) #define PEER_CAP_PATHS_LIMIT_ADV (1U << 29) #define PEER_CAP_PATHS_LIMIT_RCV (1U << 30) +#define PEER_CAP_LINK_LOCAL_ADV (1ULL << 31) +#define PEER_CAP_LINK_LOCAL_RCV (1ULL << 32) /* Capability flags (reset in bgp_stop) */ uint32_t af_cap[AFI_MAX][SAFI_MAX]; @@ -1543,6 +1546,7 @@ struct peer { #define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */ #define PEER_FLAG_EXTENDED_LINK_BANDWIDTH (1ULL << 39) #define PEER_FLAG_DUAL_AS (1ULL << 40) +#define PEER_FLAG_CAPABILITY_LINK_LOCAL (1ULL << 41) /* *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART @@ -2100,6 +2104,7 @@ struct bgp_nlri { #define BGP_NOTIFY_UPDATE_OPT_ATTR_ERR 9 #define BGP_NOTIFY_UPDATE_INVAL_NETWORK 10 #define BGP_NOTIFY_UPDATE_MAL_AS_PATH 11 +#define BGP_NOTIFY_UPDATE_UNREACH_NEXT_HOP 12 /* draft-white-linklocal-capability */ /* BGP_NOTIFY_CEASE sub codes (RFC 4486). */ #define BGP_NOTIFY_CEASE_MAX_PREFIX 1 diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 99d8bcfce4..d9f63700f0 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -4067,9 +4067,15 @@ static void rfapiProcessPeerDownRt(struct peer *peer, bpi, import_table, afi, -1); import_table->holddown_count[afi] += 1; } - rfapiBiStartWithdrawTimer(import_table, rn, bpi, - afi, safi, - timer_service_func); + if (bm->terminating) { + if (safi == SAFI_MPLS_VPN) + rfapiExpireVpnNow(import_table, rn, bpi, 1); + else + rfapiExpireEncapNow(import_table, rn, bpi); + + } else + rfapiBiStartWithdrawTimer(import_table, rn, bpi, afi, safi, + timer_service_func); } } } diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 5add30b6f4..a1dd799392 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1953,6 +1953,15 @@ Configuring Peers are not supporting this capability or supporting BGP Capabilities Negotiation RFC 2842. +.. clicmd:: neighbor PEER capability link-local + + Send the Link-Local Next Hop capability in the BGP OPEN message to the neighbor. + This is useful in data center environments where point-to-point (unnumbered) links + are utilized. This capability standardizes the operation of BGP over a + point-to-point links using link-local IPv6 addressing only. + + Enabled by default for the ``datacenter`` profile. + .. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> accept-own Enable handling of self-originated VPN routes containing ``accept-own`` community. @@ -4638,7 +4647,7 @@ incoming/outgoing directions. If ``json`` option is specified, output is displayed in JSON format. -.. clicmd:: show [ip] bgp [afi] [safi] [all] detail-routes +.. clicmd:: show [ip] bgp [afi] [safi] [all] detail-routes [internal] Display the detailed version of all routes. The same format as using ``show [ip] bgp [afi] [safi] PREFIX``, but for the whole BGP table. @@ -4646,6 +4655,9 @@ incoming/outgoing directions. If ``all`` option is specified, ``ip`` keyword is ignored and, routes displayed for all AFIs and SAFIs. + ``internal`` option is used to display internal data additionally. JSON + output is not supported with this option. + If ``afi`` is specified, with ``all`` option, routes will be displayed for each SAFI in the selected AFI. diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index 3024bb57ea..5f95fe48a4 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -561,12 +561,6 @@ const struct frr_yang_module_info frr_isisd_info = { } }, { - .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type", - .cbs = { - .modify = isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify, - } - }, - { .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list", .cbs = { .cli_show = cli_show_isis_frr_remote_lfa_plist, @@ -598,12 +592,6 @@ const struct frr_yang_module_info frr_isisd_info = { } }, { - .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type", - .cbs = { - .modify = isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify, - } - }, - { .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list", .cbs = { .cli_show = cli_show_isis_frr_remote_lfa_plist, diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index fb391534e2..6bd3b39bc7 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -1763,26 +1763,6 @@ int isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy( } /* - * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type - */ -int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify( - struct nb_cb_modify_args *args) -{ - struct lfa_tiebreaker *tie_b; - struct isis_area *area; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - tie_b = nb_running_get_entry(args->dnode, NULL, true); - area = tie_b->area; - tie_b->type = yang_dnode_get_enum(args->dnode, NULL); - lsp_regenerate_schedule(area, area->is_type, 0); - - return NB_OK; -} - -/* * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list */ int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify( @@ -1912,26 +1892,6 @@ int isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy( } /* - * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type - */ -int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify( - struct nb_cb_modify_args *args) -{ - struct lfa_tiebreaker *tie_b; - struct isis_area *area; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - tie_b = nb_running_get_entry(args->dnode, NULL, true); - area = tie_b->area; - tie_b->type = yang_dnode_get_enum(args->dnode, NULL); - lsp_regenerate_schedule(area, area->is_type, 0); - - return NB_OK; -} - -/* * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list */ int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify( diff --git a/lib/zlog_5424.c b/lib/zlog_5424.c index 4c60d4b405..6265ce3b1f 100644 --- a/lib/zlog_5424.c +++ b/lib/zlog_5424.c @@ -782,7 +782,7 @@ static void zlog_5424_cycle(struct zlog_cfg_5424 *zcf, int fd) } old = zcf->active ? &zcf->active->zt : NULL; - old = zlog_target_replace(old, &zlt->zt); + old = zlog_target_replace(old, zlt ? &zlt->zt : NULL); zcf->active = zlt; /* oldt->fd == fd happens for zlog_5424_apply_meta() */ @@ -1076,9 +1076,17 @@ bool zlog_5424_apply_dst(struct zlog_cfg_5424 *zcf) bool zlog_5424_apply_meta(struct zlog_cfg_5424 *zcf) { + int fd; + frr_with_mutex (&zcf->cfg_mtx) { if (zcf->active) - zlog_5424_cycle(zcf, zcf->active->fd); + fd = zcf->active->fd; + else if (zcf->prio_min != ZLOG_DISABLED) + fd = zlog_5424_open(zcf, -1); + else + fd = -1; + if (fd >= 0) + zlog_5424_cycle(zcf, fd); } return true; diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py index 1d7aa97473..c454c9c4a4 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py @@ -78,6 +78,13 @@ def setup_module(mod): "tcpdump -nni r1-eth0 -s 0 -w {} &".format(pcap_file), stdout=None ) + tgen.net["r2"].cmd( + """ +ip link add vrf1 type vrf table 10 +ip link set vrf1 up +""" + ) + for _, (rname, router) in enumerate(tgen.routers().items(), 1): logger.info("Loading router %s" % rname) router.load_frr_config( diff --git a/tests/topotests/bgp_ipv6_link_local_capability/__init__.py b/tests/topotests/bgp_ipv6_link_local_capability/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_ipv6_link_local_capability/__init__.py diff --git a/tests/topotests/bgp_ipv6_link_local_capability/r1/frr.conf b/tests/topotests/bgp_ipv6_link_local_capability/r1/frr.conf new file mode 100644 index 0000000000..1cf7f3b913 --- /dev/null +++ b/tests/topotests/bgp_ipv6_link_local_capability/r1/frr.conf @@ -0,0 +1,15 @@ +! +int lo + ip address 10.0.0.1/32 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + bgp default link-local-capability + neighbor r1-eth0 interface remote-as auto + address-family ipv6 unicast + network 2001:db8::1/128 + neighbor r1-eth0 activate + exit-address-family + ! +! diff --git a/tests/topotests/bgp_ipv6_link_local_capability/r2/frr.conf b/tests/topotests/bgp_ipv6_link_local_capability/r2/frr.conf new file mode 100644 index 0000000000..4af053dcf6 --- /dev/null +++ b/tests/topotests/bgp_ipv6_link_local_capability/r2/frr.conf @@ -0,0 +1,13 @@ +! +int lo + ip address 10.0.0.2/32 +! +router bgp 65002 + no bgp ebgp-requires-policy + bgp default link-local-capability + neighbor r2-eth0 interface remote-as auto + address-family ipv6 unicast + neighbor r2-eth0 activate + exit-address-family + ! +! diff --git a/tests/topotests/bgp_ipv6_link_local_capability/test_bgp_ipv6_link_local_capability.py b/tests/topotests/bgp_ipv6_link_local_capability/test_bgp_ipv6_link_local_capability.py new file mode 100644 index 0000000000..1822f17ee4 --- /dev/null +++ b/tests/topotests/bgp_ipv6_link_local_capability/test_bgp_ipv6_link_local_capability.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2024 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.common_config import step + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + tgen.add_router("r1") + tgen.add_router("r2") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_ipv6_link_local_capability(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show bgp neighbor json")) + expected = { + "r2-eth0": { + "neighborCapabilities": { + "linkLocalNextHop": { + "advertised": True, + "received": True, + } + } + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge initially" + + def _bgp_check_received_nexthops(): + output = json.loads(r2.vtysh_cmd("show bgp 2001:db8::1/128 json")) + expected = { + "paths": [ + { + "valid": True, + "nexthops": [ + { + "hostname": "r1", + "afi": "ipv6", + "scope": "global", + "length": 16, + "accessible": True, + } + ], + "peer": { + "routerId": "10.0.0.1", + "hostname": "r1", + "interface": "r2-eth0", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_received_nexthops) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see 2001:db8::1/128" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf index d3ababde3a..e3f8b242a1 100644 --- a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf @@ -1,3 +1,7 @@ +vrf DONNA + ip route 172.16.3.0/24 10.0.0.254 +exit-vrf +! int dummy0 ip address 10.0.4.1/24 no shut @@ -28,6 +32,9 @@ ip router-id 10.0.4.1 ! router bgp 99 no bgp ebgp-requires-policy + ! 10.0.4.254 peer session will not be established + ! it is there just to activate the ipv4 vpn table + neighbor 10.0.4.254 remote-as external address-family ipv4 unicast redistribute connected rd vpn export 10.0.4.1:1 @@ -36,11 +43,14 @@ router bgp 99 export vpn import vpn ! + address-family ipv4 vpn + neighbor 10.0.4.254 activate ! router bgp 99 vrf DONNA no bgp ebgp-requires-policy address-family ipv4 unicast redistribute connected + network 172.16.3.0/24 label vpn export 101 rd vpn export 10.0.4.1:1 rt vpn export 10.0.4.1:101 diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json new file mode 100644 index 0000000000..c7ff2f4f80 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json @@ -0,0 +1,155 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": [ + { + "valid": null, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "ZITA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json new file mode 100644 index 0000000000..1797d78582 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json @@ -0,0 +1,103 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": null, + "172.16.101.0/24": null + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json new file mode 100644 index 0000000000..4b0eaaa052 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json @@ -0,0 +1,120 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": null, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": null, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": null + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json new file mode 100644 index 0000000000..de18bc8463 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json @@ -0,0 +1,120 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": null + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json new file mode 100644 index 0000000000..0c249e241e --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json @@ -0,0 +1,137 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "ZITA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py b/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py index a44f07b560..67e53cb0cc 100644 --- a/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py @@ -13,6 +13,7 @@ Test basic VPNv4 route leaking """ +import json import os import sys from functools import partial @@ -60,6 +61,22 @@ def teardown_module(mod): tgen.stop_topology() +def test_bgp_convergence(): + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + + def test_vrf_route_leak_donna(): logger.info("Ensure that routes are leaked back and forth") tgen = get_topogen() @@ -119,20 +136,20 @@ def test_vrf_route_leak_donna(): ], }, ], - "172.16.101.0/24": [ + "172.16.3.0/24": [ { - "protocol": "bgp", - "selected": None, + "protocol": "static", + "selected": True, "nexthops": [ { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, + "fib": True, + "interfaceName": "dummy1", + "active": True, + } ], }, ], + "172.16.101.0/24": None, } test_func = partial( @@ -191,20 +208,21 @@ def test_vrf_route_leak_eva(): "protocol": "connected", } ], - "172.16.101.0/24": [ + "172.16.3.0/24": [ { "protocol": "bgp", - "selected": None, + "selected": True, "nexthops": [ { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + } ], }, ], + "172.16.101.0/24": None, } test_func = partial( @@ -258,6 +276,20 @@ def test_vrf_route_leak_default(): "protocol": "connected", } ], + "172.16.3.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + } + ], + }, + ], } test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) @@ -298,34 +330,8 @@ interface EVA # Test DONNA VRF. expect = { - "10.0.1.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "EVA", - "vrf": "EVA", - "active": None, - }, - ], - }, - ], - "10.0.3.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "EVA", - "vrf": "EVA", - "active": None, - }, - ], - }, - ], + "10.0.1.0/24": None, + "10.0.3.0/24": None, } test_func = partial( @@ -349,6 +355,14 @@ interface EVA result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_eva_down.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_vrf_route_leak_donna_after_eva_up(): logger.info("Ensure that route states change after EVA interface goes up") @@ -404,6 +418,14 @@ interface EVA result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_vrf_route_leak_donna_add_vrf_zita(): logger.info("Add VRF ZITA and ensure that the route from VRF ZITA is updated") @@ -417,20 +439,7 @@ def test_vrf_route_leak_donna_add_vrf_zita(): # Test DONNA VRF. expect = { - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "ZITA", - "vrf": "ZITA", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( @@ -439,6 +448,14 @@ def test_vrf_route_leak_donna_add_vrf_zita(): result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_add_zita.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_vrf_route_leak_donna_set_zita_up(): logger.info("Set VRF ZITA up and ensure that the route from VRF ZITA is updated") @@ -480,6 +497,14 @@ interface ZITA result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_zita_up.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_vrf_route_leak_donna_delete_vrf_zita(): logger.info("Delete VRF ZITA and ensure that the route from VRF ZITA is deleted") @@ -502,6 +527,101 @@ def test_vrf_route_leak_donna_delete_vrf_zita(): result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + + +def test_vrf_route_leak_default_delete_prefix(): + logger.info( + "Remove BGP static prefix 172.16.3.0/24 from VRF DONNA and ensure that the route is deleted on default" + ) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +router bgp 99 vrf DONNA + address-family ipv4 unicast + no network 172.16.3.0/24 +""" + ) + + # Test default VRF. + expect = { + "172.16.3.0/24": None, + } + + test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP VRF default check failed:\n{}".format(diff) + + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_del_donna_prefix.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + + +def test_vrf_route_leak_default_prefix_back(): + logger.info( + "Set back BGP static prefix 172.16.3.0/24 to VRF DONNA and ensure that the route is set on default" + ) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +router bgp 99 vrf DONNA + address-family ipv4 unicast + network 172.16.3.0/24 +""" + ) + + # Test default VRF. + expect = { + "172.16.3.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + } + ], + }, + ], + } + + test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP VRF default check failed:\n{}".format(diff) + + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_memory_leak(): "Run the memory leak test and report results." diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py index 6d4b436bcc..3bc36862bf 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py +++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py @@ -123,20 +123,7 @@ def test_vrf_route_leak_donna(): ], }, ], - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( @@ -195,20 +182,7 @@ def test_vrf_route_leak_eva(): "protocol": "connected", } ], - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( @@ -302,34 +276,8 @@ interface EVA # Test DONNA VRF. expect = { - "10.0.1.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "EVA", - "vrf": "EVA", - "active": None, - }, - ], - }, - ], - "10.0.3.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "EVA", - "vrf": "EVA", - "active": None, - }, - ], - }, - ], + "10.0.1.0/24": None, + "10.0.3.0/24": None, } test_func = partial( @@ -421,20 +369,7 @@ def test_vrf_route_leak_donna_add_vrf_zita(): # Test DONNA VRF. expect = { - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "ZITA", - "vrf": "ZITA", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( |
