diff options
79 files changed, 4609 insertions, 553 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 72905a6acb..3d93e8a1ac 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -825,55 +825,56 @@ bool attrhash_cmp(const void *p1, const void *p2) && attr1->med == attr2->med && attr1->local_pref == attr2->local_pref && attr1->rmap_change_flags == attr2->rmap_change_flags) { - if (attr1->aggregator_as == attr2->aggregator_as - && attr1->aggregator_addr.s_addr - == attr2->aggregator_addr.s_addr - && attr1->weight == attr2->weight - && attr1->tag == attr2->tag - && attr1->label_index == attr2->label_index - && attr1->mp_nexthop_len == attr2->mp_nexthop_len - && bgp_attr_get_ecommunity(attr1) - == bgp_attr_get_ecommunity(attr2) - && bgp_attr_get_ipv6_ecommunity(attr1) - == bgp_attr_get_ipv6_ecommunity(attr2) - && bgp_attr_get_lcommunity(attr1) - == bgp_attr_get_lcommunity(attr2) - && bgp_attr_get_cluster(attr1) - == bgp_attr_get_cluster(attr2) - && bgp_attr_get_transit(attr1) - == bgp_attr_get_transit(attr2) - && bgp_attr_get_aigp_metric(attr1) - == bgp_attr_get_aigp_metric(attr2) - && attr1->rmap_table_id == attr2->rmap_table_id - && (attr1->encap_tunneltype == attr2->encap_tunneltype) - && encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs) + if (attr1->aggregator_as == attr2->aggregator_as && + attr1->aggregator_addr.s_addr == + attr2->aggregator_addr.s_addr && + attr1->weight == attr2->weight && + attr1->tag == attr2->tag && + attr1->label_index == attr2->label_index && + attr1->mp_nexthop_len == attr2->mp_nexthop_len && + bgp_attr_get_ecommunity(attr1) == + bgp_attr_get_ecommunity(attr2) && + bgp_attr_get_ipv6_ecommunity(attr1) == + bgp_attr_get_ipv6_ecommunity(attr2) && + bgp_attr_get_lcommunity(attr1) == + bgp_attr_get_lcommunity(attr2) && + bgp_attr_get_cluster(attr1) == + bgp_attr_get_cluster(attr2) && + bgp_attr_get_transit(attr1) == + bgp_attr_get_transit(attr2) && + bgp_attr_get_aigp_metric(attr1) == + bgp_attr_get_aigp_metric(attr2) && + attr1->rmap_table_id == attr2->rmap_table_id && + (attr1->encap_tunneltype == attr2->encap_tunneltype) && + encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs) #ifdef ENABLE_BGP_VNC && encap_same(bgp_attr_get_vnc_subtlvs(attr1), bgp_attr_get_vnc_subtlvs(attr2)) #endif && IPV6_ADDR_SAME(&attr1->mp_nexthop_global, - &attr2->mp_nexthop_global) - && IPV6_ADDR_SAME(&attr1->mp_nexthop_local, - &attr2->mp_nexthop_local) - && IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in, - &attr2->mp_nexthop_global_in) - && IPV4_ADDR_SAME(&attr1->originator_id, - &attr2->originator_id) - && overlay_index_same(attr1, attr2) - && !memcmp(&attr1->esi, &attr2->esi, sizeof(esi_t)) - && attr1->es_flags == attr2->es_flags - && attr1->mm_sync_seqnum == attr2->mm_sync_seqnum - && attr1->df_pref == attr2->df_pref - && attr1->df_alg == attr2->df_alg - && attr1->nh_ifindex == attr2->nh_ifindex - && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex - && attr1->distance == attr2->distance - && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn) - && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn) - && attr1->srte_color == attr2->srte_color - && attr1->nh_type == attr2->nh_type - && attr1->bh_type == attr2->bh_type - && attr1->otc == attr2->otc) + &attr2->mp_nexthop_global) && + IPV6_ADDR_SAME(&attr1->mp_nexthop_local, + &attr2->mp_nexthop_local) && + IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in, + &attr2->mp_nexthop_global_in) && + IPV4_ADDR_SAME(&attr1->originator_id, + &attr2->originator_id) && + overlay_index_same(attr1, attr2) && + !memcmp(&attr1->esi, &attr2->esi, sizeof(esi_t)) && + attr1->es_flags == attr2->es_flags && + attr1->mm_sync_seqnum == attr2->mm_sync_seqnum && + attr1->df_pref == attr2->df_pref && + attr1->df_alg == attr2->df_alg && + attr1->nh_ifindex == attr2->nh_ifindex && + attr1->nh_flag == attr2->nh_flag && + attr1->nh_lla_ifindex == attr2->nh_lla_ifindex && + attr1->distance == attr2->distance && + srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn) && + srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn) && + attr1->srte_color == attr2->srte_color && + attr1->nh_type == attr2->nh_type && + attr1->bh_type == attr2->bh_type && + attr1->otc == attr2->otc) return true; } @@ -2254,6 +2255,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; + if (if_is_operative(peer->nexthop.ifp)) + SET_FLAG(attr->nh_flag, + BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr->nh_flag, + BGP_ATTR_NH_IF_OPERSTATE); } break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: @@ -2271,6 +2278,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; + if (if_is_operative(peer->nexthop.ifp)) + SET_FLAG(attr->nh_flag, + BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr->nh_flag, + BGP_ATTR_NH_IF_OPERSTATE); } if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { @@ -4682,7 +4695,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, } /* AIGP */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) && + if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) && (CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) || peer->sort != BGP_PEER_EBGP)) { /* At the moment only AIGP Metric TLV exists for AIGP diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index a34da1a6de..f8beb5fba9 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -170,6 +170,12 @@ struct attr { uint32_t med; uint32_t local_pref; ifindex_t nh_ifindex; + uint8_t nh_flag; + +#define BGP_ATTR_NH_VALID 0x01 +#define BGP_ATTR_NH_IF_OPERSTATE 0x02 +#define BGP_ATTR_NH_MP_PREFER_GLOBAL 0x04 /* MP Nexthop preference */ +#define BGP_ATTR_NH_REFRESH 0x08 /* Path origin attribute */ uint8_t origin; @@ -220,9 +226,6 @@ struct attr { /* MP Nexthop length */ uint8_t mp_nexthop_len; - /* MP Nexthop preference */ - uint8_t mp_nexthop_prefer_global; - /* Static MAC for EVPN */ uint8_t sticky; diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index bfde1c127e..9e540b63cb 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -51,6 +51,8 @@ #include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_packet.h" +#include "bgpd/bgp_debug_clippy.c" + unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_neighbor_events; unsigned long conf_bgp_debug_events; @@ -324,7 +326,7 @@ static void bgp_debug_list_add_entry(struct list *list, const char *host, } static bool bgp_debug_list_remove_entry(struct list *list, const char *host, - struct prefix *p) + const struct prefix *p) { struct bgp_debug_filter *filter; struct listnode *node, *nnode; @@ -630,17 +632,14 @@ static void bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc, } static int bgp_debug_parse_evpn_prefix(struct vty *vty, struct cmd_token **argv, - int argc, struct prefix **argv_pp) + int argc, struct prefix *argv_p) { - struct prefix *argv_p; struct ethaddr mac = {}; struct ipaddr ip = {}; int evpn_type = 0; int mac_idx = 0; int ip_idx = 0; - argv_p = *argv_pp; - if (bgp_evpn_cli_parse_type(&evpn_type, argv, argc) < 0) return CMD_WARNING; @@ -1023,49 +1022,42 @@ DEFUN (no_debug_bgp_keepalive_peer, } /* debug bgp bestpath */ -DEFUN (debug_bgp_bestpath_prefix, +DEFPY (debug_bgp_bestpath_prefix, debug_bgp_bestpath_prefix_cmd, - "debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>", + "debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>$prefix", DEBUG_STR BGP_STR "BGP bestpath\n" "IPv4 prefix\n" "IPv6 prefix\n") { - struct prefix *argv_p; - int idx_ipv4_ipv6_prefixlen = 3; - - argv_p = prefix_new(); - (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p); - apply_mask(argv_p); - if (!bgp_debug_bestpath_prefixes) bgp_debug_bestpath_prefixes = list_new(); if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL, - argv_p)) { + prefix)) { vty_out(vty, "BGP bestpath debugging is already enabled for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, argv_p); + bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix); if (vty->node == CONFIG_NODE) { DEBUG_ON(bestpath, BESTPATH); } else { TERM_DEBUG_ON(bestpath, BESTPATH); vty_out(vty, "BGP bestpath debugging is on for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + prefix_str); } return CMD_SUCCESS; } -DEFUN (no_debug_bgp_bestpath_prefix, +DEFPY (no_debug_bgp_bestpath_prefix, no_debug_bgp_bestpath_prefix_cmd, - "no debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>", + "no debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>$prefix", NO_STR DEBUG_STR BGP_STR @@ -1073,18 +1065,12 @@ DEFUN (no_debug_bgp_bestpath_prefix, "IPv4 prefix\n" "IPv6 prefix\n") { - int idx_ipv4_ipv6_prefixlen = 4; - struct prefix *argv_p; - int found_prefix = 0; - - argv_p = prefix_new(); - (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p); - apply_mask(argv_p); + bool found_prefix = false; if (bgp_debug_bestpath_prefixes && !list_isempty(bgp_debug_bestpath_prefixes)) { found_prefix = bgp_debug_list_remove_entry( - bgp_debug_bestpath_prefixes, NULL, argv_p); + bgp_debug_bestpath_prefixes, NULL, prefix); if (list_isempty(bgp_debug_bestpath_prefixes)) { if (vty->node == CONFIG_NODE) { @@ -1099,10 +1085,10 @@ DEFUN (no_debug_bgp_bestpath_prefix, if (found_prefix) vty_out(vty, "BGP bestpath debugging is off for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + prefix_str); else vty_out(vty, "BGP bestpath debugging was not enabled for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + prefix_str); return CMD_SUCCESS; } @@ -1410,8 +1396,6 @@ DEFUN (no_debug_bgp_update_direct_peer, return CMD_SUCCESS; } -#include "bgpd/bgp_debug_clippy.c" - DEFPY (debug_bgp_update_prefix_afi_safi, debug_bgp_update_prefix_afi_safi_cmd, "debug bgp updates prefix l2vpn$afi evpn$safi type <<macip|2> mac <X:X:X:X:X:X|X:X:X:X:X:X/M> [ip <A.B.C.D|X:X::X:X>]|<multicast|3> ip <A.B.C.D|X:X::X:X>|<prefix|5> ip <A.B.C.D/M|X:X::X:X/M>>", @@ -1439,39 +1423,33 @@ DEFPY (debug_bgp_update_prefix_afi_safi, "IPv4 prefix\n" "IPv6 prefix\n") { - struct prefix *argv_p; + struct prefix argv_p; int ret = CMD_SUCCESS; - argv_p = prefix_new(); - ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p); - if (ret != CMD_SUCCESS) { - prefix_free(&argv_p); + if (ret != CMD_SUCCESS) return ret; - } if (!bgp_debug_update_prefixes) bgp_debug_update_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, argv_p)) { + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, + &argv_p)) { vty_out(vty, "BGP updates debugging is already enabled for %pFX\n", - argv_p); - prefix_free(&argv_p); + &argv_p); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, argv_p); + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p); if (vty->node == CONFIG_NODE) { DEBUG_ON(update, UPDATE_PREFIX); } else { TERM_DEBUG_ON(update, UPDATE_PREFIX); - vty_out(vty, "BGP updates debugging is on for %pFX\n", argv_p); + vty_out(vty, "BGP updates debugging is on for %pFX\n", &argv_p); } - prefix_free(&argv_p); - return CMD_SUCCESS; } @@ -1503,22 +1481,18 @@ DEFPY (no_debug_bgp_update_prefix_afi_safi, "IPv4 prefix\n" "IPv6 prefix\n") { - struct prefix *argv_p; + struct prefix argv_p; bool found_prefix = false; int ret = CMD_SUCCESS; - argv_p = prefix_new(); - ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p); - if (ret != CMD_SUCCESS) { - prefix_free(&argv_p); + if (ret != CMD_SUCCESS) return ret; - } if (bgp_debug_update_prefixes && !list_isempty(bgp_debug_update_prefixes)) { found_prefix = bgp_debug_list_remove_entry( - bgp_debug_update_prefixes, NULL, argv_p); + bgp_debug_update_prefixes, NULL, &argv_p); if (list_isempty(bgp_debug_update_prefixes)) { if (vty->node == CONFIG_NODE) { @@ -1532,20 +1506,19 @@ DEFPY (no_debug_bgp_update_prefix_afi_safi, } if (found_prefix) - vty_out(vty, "BGP updates debugging is off for %pFX\n", argv_p); + vty_out(vty, "BGP updates debugging is off for %pFX\n", + &argv_p); else vty_out(vty, "BGP updates debugging was not enabled for %pFX\n", - argv_p); - - prefix_free(&argv_p); + &argv_p); return ret; } -DEFUN (debug_bgp_update_prefix, +DEFPY (debug_bgp_update_prefix, debug_bgp_update_prefix_cmd, - "debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>", + "debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>$prefix", DEBUG_STR BGP_STR "BGP updates\n" @@ -1553,39 +1526,32 @@ DEFUN (debug_bgp_update_prefix, "IPv4 prefix\n" "IPv6 prefix\n") { - int idx_ipv4_ipv6_prefixlen = 4; - struct prefix *argv_p; - - argv_p = prefix_new(); - (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p); - apply_mask(argv_p); - if (!bgp_debug_update_prefixes) bgp_debug_update_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, argv_p)) { + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix)) { vty_out(vty, "BGP updates debugging is already enabled for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, argv_p); + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix); if (vty->node == CONFIG_NODE) { DEBUG_ON(update, UPDATE_PREFIX); } else { TERM_DEBUG_ON(update, UPDATE_PREFIX); vty_out(vty, "BGP updates debugging is on for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + prefix_str); } return CMD_SUCCESS; } -DEFUN (no_debug_bgp_update_prefix, +DEFPY (no_debug_bgp_update_prefix, no_debug_bgp_update_prefix_cmd, - "no debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>", + "no debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>$prefix", NO_STR DEBUG_STR BGP_STR @@ -1594,18 +1560,12 @@ DEFUN (no_debug_bgp_update_prefix, "IPv4 prefix\n" "IPv6 prefix\n") { - int idx_ipv4_ipv6_prefixlen = 5; - struct prefix *argv_p; - int found_prefix = 0; - - argv_p = prefix_new(); - (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p); - apply_mask(argv_p); + bool found_prefix = false; if (bgp_debug_update_prefixes && !list_isempty(bgp_debug_update_prefixes)) { found_prefix = bgp_debug_list_remove_entry( - bgp_debug_update_prefixes, NULL, argv_p); + bgp_debug_update_prefixes, NULL, prefix); if (list_isempty(bgp_debug_update_prefixes)) { if (vty->node == CONFIG_NODE) { @@ -1620,10 +1580,10 @@ DEFUN (no_debug_bgp_update_prefix, if (found_prefix) vty_out(vty, "BGP updates debugging is off for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + prefix_str); else vty_out(vty, "BGP updates debugging was not enabled for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + prefix_str); return CMD_SUCCESS; } @@ -1693,9 +1653,9 @@ DEFUN (debug_bgp_graceful_restart, } -DEFUN (debug_bgp_zebra_prefix, +DEFPY (debug_bgp_zebra_prefix, debug_bgp_zebra_prefix_cmd, - "debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>", + "debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>$prefix", DEBUG_STR BGP_STR "BGP Zebra messages\n" @@ -1703,30 +1663,22 @@ DEFUN (debug_bgp_zebra_prefix, "IPv4 prefix\n" "IPv6 prefix\n") { - int idx_ipv4_ipv6_prefixlen = 4; - struct prefix *argv_p; - - argv_p = prefix_new(); - (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p); - apply_mask(argv_p); - if (!bgp_debug_zebra_prefixes) bgp_debug_zebra_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, argv_p)) { + if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix)) { vty_out(vty, "BGP zebra debugging is already enabled for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, argv_p); + bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix); if (vty->node == CONFIG_NODE) DEBUG_ON(zebra, ZEBRA); else { TERM_DEBUG_ON(zebra, ZEBRA); - vty_out(vty, "BGP zebra debugging is on for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + vty_out(vty, "BGP zebra debugging is on for %s\n", prefix_str); } return CMD_SUCCESS; @@ -1768,9 +1720,9 @@ DEFUN (no_debug_bgp_graceful_restart, return CMD_SUCCESS; } -DEFUN (no_debug_bgp_zebra_prefix, +DEFPY (no_debug_bgp_zebra_prefix, no_debug_bgp_zebra_prefix_cmd, - "no debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>", + "no debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>$prefix", NO_STR DEBUG_STR BGP_STR @@ -1779,18 +1731,12 @@ DEFUN (no_debug_bgp_zebra_prefix, "IPv4 prefix\n" "IPv6 prefix\n") { - int idx_ipv4_ipv6_prefixlen = 5; - struct prefix *argv_p; - int found_prefix = 0; - - argv_p = prefix_new(); - (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p); - apply_mask(argv_p); + bool found_prefix = false; if (bgp_debug_zebra_prefixes && !list_isempty(bgp_debug_zebra_prefixes)) { found_prefix = bgp_debug_list_remove_entry( - bgp_debug_zebra_prefixes, NULL, argv_p); + bgp_debug_zebra_prefixes, NULL, prefix); if (list_isempty(bgp_debug_zebra_prefixes)) { if (vty->node == CONFIG_NODE) @@ -1803,11 +1749,10 @@ DEFUN (no_debug_bgp_zebra_prefix, } if (found_prefix) - vty_out(vty, "BGP zebra debugging is off for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + vty_out(vty, "BGP zebra debugging is off for %s\n", prefix_str); else vty_out(vty, "BGP zebra debugging was not enabled for %s\n", - argv[idx_ipv4_ipv6_prefixlen]->arg); + prefix_str); return CMD_SUCCESS; } diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 32a5e14b11..84c847d796 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -142,15 +142,21 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, &bpi2->attr->mp_nexthop_global); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - addr1 = (bpi1->attr->mp_nexthop_prefer_global) + addr1 = (CHECK_FLAG( + bpi1->attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) ? bpi1->attr->mp_nexthop_global : bpi1->attr->mp_nexthop_local; - addr2 = (bpi2->attr->mp_nexthop_prefer_global) + addr2 = (CHECK_FLAG( + bpi2->attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) ? bpi2->attr->mp_nexthop_global : bpi2->attr->mp_nexthop_local; - if (!bpi1->attr->mp_nexthop_prefer_global - && !bpi2->attr->mp_nexthop_prefer_global) + if (!CHECK_FLAG(bpi1->attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL) && + !CHECK_FLAG(bpi2->attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) compare = !bgp_interface_same( bpi1->peer->ifp, bpi2->peer->ifp); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 0270695c2f..9b86c9b4b1 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1060,9 +1060,11 @@ 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; bool nh_valid; bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi); + table = bgp_dest_table(bpi_ultimate->net); if (bpi->extra && bpi->extra->bgp_orig) bgp_nexthop = bpi->extra->bgp_orig; @@ -1070,13 +1072,25 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, bgp_nexthop = bgp_orig; /* - * No nexthop tracking for redistributed routes or for + * No nexthop tracking for redistributed routes, + * for static (i.e. coming from the bgp network statement or for * EVPN-imported routes that get leaked. */ if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE || is_pi_family_evpn(bpi_ultimate)) nh_valid = 1; - else + else if (bpi_ultimate->type == ZEBRA_ROUTE_BGP && + bpi_ultimate->sub_type == BGP_ROUTE_STATIC && table && + (table->safi == SAFI_UNICAST || + table->safi == SAFI_LABELED_UNICAST)) { + /* Routes from network statement */ + if (CHECK_FLAG(bgp_nexthop->flags, BGP_FLAG_IMPORT_CHECK)) + nh_valid = bgp_find_or_add_nexthop( + to_bgp, bgp_nexthop, afi, safi, bpi_ultimate, + NULL, 0, p); + else + nh_valid = 1; + } else /* * TBD do we need to do anything about the * 'connected' parameter? @@ -1266,6 +1280,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, if (debug) zlog_debug("%s: ->%s: %pBD Found route, changed attr", __func__, to_bgp->name_pretty, bn); + UNSET_FLAG(bpi->attr->nh_flag, BGP_ATTR_NH_REFRESH); return bpi; } @@ -1864,11 +1879,31 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ uint32_t num_labels = 0; int nexthop_self_flag = 1; struct bgp_path_info *bpi_ultimate = NULL; + struct bgp_path_info *bpi; int origin_local = 0; struct bgp *src_vrf; + struct interface *ifp; int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); + /* + * For VRF-2-VRF route-leaking, + * the source will be the originating VRF. + * + * If ACCEPT_OWN mechanism is enabled, then we SHOULD(?) + * get the source VRF (BGP) by looking at the RD. + */ + struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi); + + if (path_vpn->extra && path_vpn->extra->bgp_orig) + src_vrf = path_vpn->extra->bgp_orig; + else if (src_bgp) + src_vrf = src_bgp; + else + src_vrf = from_bgp; + + bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL); + if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) { if (debug) zlog_debug("%s: skipping: %s", __func__, debugmsg); @@ -1928,6 +1963,18 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ community_strip_accept_own(&static_attr); + for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { + if (bpi->extra && bpi->extra->parent == path_vpn) + break; + } + + if (bpi && + leak_update_nexthop_valid(to_bgp, bn, &static_attr, afi, safi, + path_vpn, bpi, src_vrf, p, debug)) + SET_FLAG(static_attr.nh_flag, BGP_ATTR_NH_VALID); + else + UNSET_FLAG(static_attr.nh_flag, BGP_ATTR_NH_VALID); + /* * Nexthop: stash and clear * @@ -1970,6 +2017,22 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ break; } + if (static_attr.nexthop.s_addr == INADDR_ANY && + IN6_IS_ADDR_UNSPECIFIED(&static_attr.mp_nexthop_global)) { + ifp = if_get_vrf_loopback(src_vrf->vrf_id); + if (ifp) + static_attr.nh_ifindex = ifp->ifindex; + } else if (static_attr.nh_ifindex) + ifp = if_lookup_by_index(static_attr.nh_ifindex, + src_vrf->vrf_id); + else + ifp = NULL; + + if (ifp && if_is_operative(ifp)) + SET_FLAG(static_attr.nh_flag, BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(static_attr.nh_flag, BGP_ATTR_NH_IF_OPERSTATE); + /* * route map handling */ @@ -2051,22 +2114,6 @@ static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ zlog_debug("%s: pfx %pBD: num_labels %d", __func__, path_vpn->net, num_labels); - /* - * For VRF-2-VRF route-leaking, - * the source will be the originating VRF. - * - * If ACCEPT_OWN mechanism is enabled, then we SHOULD(?) - * get the source VRF (BGP) by looking at the RD. - */ - struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi); - - if (path_vpn->extra && path_vpn->extra->bgp_orig) - src_vrf = path_vpn->extra->bgp_orig; - else if (src_bgp) - src_vrf = src_bgp; - else - src_vrf = from_bgp; - leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels, num_labels, src_vrf, &nexthop_orig, nexthop_self_flag, debug); @@ -2821,6 +2868,10 @@ int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd, { struct bgp *bgp; struct bgp_table *table; + uint16_t show_flags = 0; + + if (use_json) + SET_FLAG(show_flags, BGP_SHOW_OPT_JSON); bgp = bgp_get_default(); if (bgp == NULL) { @@ -2832,7 +2883,7 @@ int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd, } table = bgp->rib[afi][SAFI_MPLS_VPN]; return bgp_show_table_rd(vty, bgp, SAFI_MPLS_VPN, table, prd, type, - output_arg, use_json); + output_arg, show_flags); } DEFUN (show_bgp_ip_vpn_all_rd, diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 25a4a1b521..6bbdbdc1a9 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -500,11 +500,8 @@ static void bgp_connected_cleanup(struct route_table *table, if (!bc) return; - bc->refcnt--; - if (bc->refcnt == 0) { - XFREE(MTYPE_BGP_CONN, bc); - bgp_dest_set_bgp_connected_ref_info(bn, NULL); - } + XFREE(MTYPE_BGP_CONN, bc); + bgp_dest_set_bgp_connected_ref_info(bn, NULL); } bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type, diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index cf8ff524e9..b6b0c584d7 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -46,6 +46,7 @@ #include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_evpn.h" #include "bgpd/bgp_rd.h" +#include "bgpd/bgp_mplsvpn.h" extern struct zclient *zclient; @@ -388,7 +389,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, if (pi && is_route_parent_evpn(pi)) bnc->is_evpn_gwip_nexthop = true; - if (is_bgp_static_route) { + if (is_bgp_static_route && !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)) { SET_FLAG(bnc->flags, BGP_STATIC_ROUTE); /* If we're toggling the type, re-register */ @@ -423,8 +424,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); - } else if (peer && !connected - && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) { + } else if (peer && !connected && + CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) { UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); @@ -834,10 +835,13 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) { struct bgp_nexthop_cache_head *tree = NULL; struct bgp_nexthop_cache *bnc_nhc, *bnc_import; + struct bgp_path_info *pi; + struct bgp_dest *dest; struct bgp *bgp; struct prefix match; struct zapi_route nhr; afi_t afi; + safi_t safi; bgp = bgp_lookup_by_vrf_id(vrf_id); if (!bgp) { @@ -858,25 +862,37 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) tree = &bgp->nexthop_cache_table[afi]; bnc_nhc = bnc_find(tree, &match, nhr.srte_color, 0); - if (!bnc_nhc) { - if (BGP_DEBUG(nht, NHT)) - zlog_debug( - "parse nexthop update(%pFX(%u)(%s)): bnc info not found for nexthop cache", - &nhr.prefix, nhr.srte_color, bgp->name_pretty); - } else + if (bnc_nhc) bgp_process_nexthop_update(bnc_nhc, &nhr, false); + else if (BGP_DEBUG(nht, NHT)) + zlog_debug( + "parse nexthop update(%pFX(%u)(%s)): bnc info not found for nexthop cache", + &nhr.prefix, nhr.srte_color, bgp->name_pretty); tree = &bgp->import_check_table[afi]; bnc_import = bnc_find(tree, &match, nhr.srte_color, 0); - if (!bnc_import) { - if (BGP_DEBUG(nht, NHT)) - zlog_debug( - "parse nexthop update(%pFX(%u)(%s)): bnc info not found for import check", - &nhr.prefix, nhr.srte_color, bgp->name_pretty); - } else + if (bnc_import) { bgp_process_nexthop_update(bnc_import, &nhr, true); + safi = nhr.safi; + if (bgp->rib[afi][safi]) { + dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, + &match, NULL); + + for (pi = bgp_dest_get_bgp_path_info(dest); pi; + pi = pi->next) + if (pi->peer == bgp->peer_self && + pi->type == ZEBRA_ROUTE_BGP && + pi->sub_type == BGP_ROUTE_STATIC) + vpn_leak_from_vrf_update( + bgp_get_default(), bgp, pi); + } + } else if (BGP_DEBUG(nht, NHT)) + zlog_debug( + "parse nexthop update(%pFX(%u)(%s)): bnc info not found for import check", + &nhr.prefix, nhr.srte_color, bgp->name_pretty); + /* * HACK: if any BGP route is dependant on an SR-policy that doesn't * exist, zebra will never send NH updates relative to that policy. In @@ -989,7 +1005,8 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) */ else if (pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - if (pi->attr->mp_nexthop_prefer_global) + if (CHECK_FLAG(pi->attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) p->u.prefix6 = pi->attr->mp_nexthop_global; else diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 95493c11f8..e478abc44a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -277,8 +277,10 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi) } /* Free bgp route information. */ -static void bgp_path_info_free(struct bgp_path_info *path) +void bgp_path_info_free_with_caller(const char *name, + struct bgp_path_info *path) { + frrtrace(2, frr_bgp, bgp_path_info_free, path, name); bgp_attr_unintern(&path->attr); bgp_unlink_nexthop(path); @@ -389,8 +391,10 @@ static int bgp_dest_set_defer_flag(struct bgp_dest *dest, bool delete) return -1; } -void bgp_path_info_add(struct bgp_dest *dest, struct bgp_path_info *pi) +void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest, + struct bgp_path_info *pi) { + frrtrace(2, frr_bgp, bgp_path_info_add, dest, pi, name); struct bgp_path_info *top; top = bgp_dest_get_bgp_path_info(dest); @@ -8679,6 +8683,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, afi_t afi; route_map_result_t ret; struct bgp_redist *red; + struct interface *ifp; /* Make default attribute. */ bgp_attr_default_set(&attr, bgp, BGP_ORIGIN_INCOMPLETE); @@ -8728,6 +8733,11 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, } attr.nh_type = nhtype; attr.nh_ifindex = ifindex; + ifp = if_lookup_by_index(ifindex, bgp->vrf_id); + if (ifp && if_is_operative(ifp)) + SET_FLAG(attr.nh_flag, BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr.nh_flag, BGP_ATTR_NH_IF_OPERSTATE); attr.med = metric; attr.distance = distance; @@ -8911,7 +8921,11 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type, bgp_aggregate_decrement(bgp, bgp_dest_get_prefix(dest), pi, afi, SAFI_UNICAST); bgp_path_info_delete(dest, pi); - bgp_process(bgp, dest, afi, SAFI_UNICAST); + if (!CHECK_FLAG(bgp->flags, + BGP_FLAG_DELETE_IN_PROGRESS)) + bgp_process(bgp, dest, afi, SAFI_UNICAST); + else + bgp_path_info_reap(dest, pi); } } } @@ -9410,9 +9424,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, "link-local"); if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global, - &attr->mp_nexthop_local) - != 0) - && !attr->mp_nexthop_prefer_global) + &attr->mp_nexthop_local) != + 0) && + !CHECK_FLAG(attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) json_object_boolean_true_add( json_nexthop_ll, "used"); else @@ -9424,10 +9439,11 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } else { /* Display LL if LL/Global both in table unless * prefer-global is set */ - if (((attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - && !attr->mp_nexthop_prefer_global) - || (path->peer->conf_if)) { + if (((attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) && + !CHECK_FLAG(attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) || + (path->peer->conf_if)) { if (path->peer->conf_if) { len = vty_out(vty, "%s", path->peer->conf_if); @@ -10689,7 +10705,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object_boolean_true_add(json_nexthop_ll, "accessible"); - if (!attr->mp_nexthop_prefer_global) + if (!CHECK_FLAG(attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) json_object_boolean_true_add(json_nexthop_ll, "used"); else @@ -10699,7 +10716,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, " (%s) %s\n", inet_ntop(AF_INET6, &attr->mp_nexthop_local, buf, INET6_ADDRSTRLEN), - attr->mp_nexthop_prefer_global + CHECK_FLAG(attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL) ? "(prefer-global)" : "(used)"); } @@ -11248,6 +11266,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); bool wide = CHECK_FLAG(show_flags, BGP_SHOW_OPT_WIDE); bool all = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL); + bool detail_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON_DETAIL); + bool detail_routes = CHECK_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL); if (output_cum && *output_cum != 0) header = false; @@ -11281,8 +11301,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, } /* Check for 'json detail', where we need header output once per dest */ - if (use_json && CHECK_FLAG(show_flags, BGP_SHOW_OPT_DETAIL) && - type != bgp_show_type_dampend_paths && + if (use_json && detail_json && type != bgp_show_type_dampend_paths && type != bgp_show_type_damp_neighbor && type != bgp_show_type_flap_statistics && type != bgp_show_type_flap_neighbor) @@ -11545,17 +11564,19 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, vty_out(vty, "Default local pref %u, ", bgp->default_local_pref); vty_out(vty, "local AS %u\n", bgp->as); - vty_out(vty, BGP_SHOW_SCODE_HEADER); - vty_out(vty, BGP_SHOW_NCODE_HEADER); - vty_out(vty, BGP_SHOW_OCODE_HEADER); - vty_out(vty, BGP_SHOW_RPKI_HEADER); + if (!detail_routes) { + vty_out(vty, BGP_SHOW_SCODE_HEADER); + vty_out(vty, BGP_SHOW_NCODE_HEADER); + vty_out(vty, BGP_SHOW_OCODE_HEADER); + vty_out(vty, BGP_SHOW_RPKI_HEADER); + } if (type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) vty_out(vty, BGP_SHOW_DAMP_HEADER); else if (type == bgp_show_type_flap_statistics || type == bgp_show_type_flap_neighbor) vty_out(vty, BGP_SHOW_FLAP_HEADER); - else + else if (!detail_routes) vty_out(vty, (wide ? BGP_SHOW_HEADER_WIDE : BGP_SHOW_HEADER)); header = false; @@ -11598,16 +11619,30 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, AFI_IP, safi, use_json, json_paths); else { - if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_DETAIL)) + if (detail_routes || detail_json) { + const struct prefix_rd *prd = NULL; + + if (dest->pdest) + prd = bgp_rd_from_dest( + dest->pdest, safi); + + if (!use_json) + route_vty_out_detail_header( + vty, bgp, dest, + bgp_dest_get_prefix( + dest), + prd, table->afi, safi, + NULL); + route_vty_out_detail( - vty, bgp, dest, - bgp_dest_get_prefix(dest), pi, + vty, bgp, dest, dest_p, pi, family2afi(dest_p->family), safi, RPKI_NOT_BEING_USED, json_paths); - else + } else { route_vty_out(vty, dest_p, pi, display, safi, json_paths, wide); + } } display++; } @@ -11689,7 +11724,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, struct bgp_table *table, struct prefix_rd *prd_match, - enum bgp_show_type type, void *output_arg, bool use_json) + enum bgp_show_type type, void *output_arg, + uint16_t show_flags) { struct bgp_dest *dest, *next; unsigned long output_cum = 0; @@ -11697,13 +11733,10 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, unsigned long json_header_depth = 0; struct bgp_table *itable; bool show_msg; - uint16_t show_flags = 0; + bool use_json = !!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); show_msg = (!use_json && type == bgp_show_type_normal); - if (use_json) - SET_FLAG(show_flags, BGP_SHOW_OPT_JSON); - for (dest = bgp_table_top(table); dest; dest = next) { const struct prefix *dest_p = bgp_dest_get_prefix(dest); @@ -11769,7 +11802,7 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, /* use MPLS and ENCAP specific shows until they are merged */ if (safi == SAFI_MPLS_VPN) { return bgp_show_table_rd(vty, bgp, safi, table, NULL, type, - output_arg, use_json); + output_arg, show_flags); } if (safi == SAFI_FLOWSPEC && type == bgp_show_type_detail) { @@ -12651,7 +12684,8 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, |A.B.C.D/M longer-prefixes\ |X:X::X:X/M longer-prefixes\ |optimal-route-reflection [WORD$orr_group_name]\ - ] [json$uj [detail$detail] | wide$wide]", + |detail-routes$detail_routes\ + ] [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 "Display the entries for all address families\n" @@ -12701,6 +12735,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, "Display route and more specific routes\n" "Display Optimal Route Reflection RR Clients\n" "ORR Group name\n" + "Display detailed version of all routes\n" JSON_STR "Display detailed version of JSON output\n" "Increase table width for longer prefixes\n") @@ -12724,8 +12759,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, SET_FLAG(show_flags, BGP_SHOW_OPT_JSON); } - if (detail) - SET_FLAG(show_flags, BGP_SHOW_OPT_DETAIL); + if (detail_json) + SET_FLAG(show_flags, BGP_SHOW_OPT_JSON_DETAIL); + + if (detail_routes) + SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL); /* [<ipv4|ipv6> [all]] */ if (all) { @@ -14702,7 +14740,7 @@ DEFUN (show_ip_bgp_flowspec_routes_detailed, struct bgp *bgp = NULL; int idx = 0; bool uj = use_json(argc, argv); - uint16_t show_flags = BGP_SHOW_OPT_DETAIL; + uint16_t show_flags = BGP_SHOW_OPT_ROUTES_DETAIL; if (uj) { argc--; diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 3fa58c0dfb..e16e077029 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -663,8 +663,9 @@ DECLARE_HOOK(bgp_process, #define BGP_SHOW_OPT_AFI_IP6 (1 << 4) #define BGP_SHOW_OPT_ESTABLISHED (1 << 5) #define BGP_SHOW_OPT_FAILED (1 << 6) -#define BGP_SHOW_OPT_DETAIL (1 << 7) +#define BGP_SHOW_OPT_JSON_DETAIL (1 << 7) #define BGP_SHOW_OPT_TERSE (1 << 8) +#define BGP_SHOW_OPT_ROUTES_DETAIL (1 << 9) /* Prototypes. */ extern void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi, @@ -865,7 +866,7 @@ extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, struct bgp_table *table, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, - bool use_json); + uint16_t show_flags); extern void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi); extern bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, uint8_t type, uint8_t stype, @@ -882,4 +883,12 @@ bgp_path_selection_reason2str(enum bgp_path_selection_reason reason); extern bool bgp_addpath_encode_rx(struct peer *peer, afi_t afi, safi_t safi); extern const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, safi_t safi); +extern void bgp_path_info_free_with_caller(const char *caller, + struct bgp_path_info *path); +extern void bgp_path_info_add_with_caller(const char *caller, + struct bgp_dest *dest, + struct bgp_path_info *pi); +#define bgp_path_info_add(A, B) \ + bgp_path_info_add_with_caller(__func__, (A), (B)) +#define bgp_path_info_free(B) bgp_path_info_free_with_caller(__func__, (B)) #endif /* _QUAGGA_BGP_ROUTE_H */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 1ce2eb4352..f779b34371 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3531,11 +3531,11 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix, if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN) || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) { /* Set next hop preference to global */ - path->attr->mp_nexthop_prefer_global = true; + SET_FLAG(path->attr->nh_flag, BGP_ATTR_NH_MP_PREFER_GLOBAL); SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } else { - path->attr->mp_nexthop_prefer_global = false; + UNSET_FLAG(path->attr->nh_flag, BGP_ATTR_NH_MP_PREFER_GLOBAL); SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c index 2d70aa94d3..fe0c33251e 100644 --- a/bgpd/bgp_snmp_bgp4v2.c +++ b/bgpd/bgp_snmp_bgp4v2.c @@ -145,10 +145,24 @@ static struct peer *bgpv2PeerTable_lookup(struct variable *v, oid name[], size_t namelen = v ? v->namelen : BGP4V2_PEER_ENTRY_OFFSET; oid *offset = name + namelen; sa_family_t family = name[namelen - 1] == 4 ? AF_INET : AF_INET6; + int afi_len = IN_ADDR_SIZE; + size_t offsetlen = *length - namelen; + + if (family == AF_INET6) + afi_len = IN6_ADDR_SIZE; + + /* Somehow with net-snmp 5.7.3, every OID item in an array + * is uninitialized and has a max random value, let's zero it. + * With 5.8, 5.9, it works fine even without this hack. + */ + if (!offsetlen) { + for (int i = 0; i < afi_len; i++) + *(offset + i) = 0; + } if (exact) { if (family == AF_INET) { - oid2in_addr(offset, IN_ADDR_SIZE, &addr->ip._v4_addr); + oid2in_addr(offset, afi_len, &addr->ip._v4_addr); peer = peer_lookup_all_vrf(addr); return peer; } else if (family == AF_INET6) { @@ -163,11 +177,11 @@ static struct peer *bgpv2PeerTable_lookup(struct variable *v, oid name[], switch (sockunion_family(&peer->su)) { case AF_INET: oid_copy_in_addr(offset, &peer->su.sin.sin_addr); - *length = IN_ADDR_SIZE + namelen; + *length = afi_len + namelen; return peer; case AF_INET6: oid_copy_in6_addr(offset, &peer->su.sin6.sin6_addr); - *length = IN6_ADDR_SIZE + namelen; + *length = afi_len + namelen; return peer; default: break; @@ -367,9 +381,10 @@ static uint8_t *bgpv2PeerErrorsTable(struct variable *v, oid name[], } return SNMP_STRING(""); case BGP4V2_PEER_LAST_ERROR_SENT_DATA: - if (peer->last_reset == PEER_DOWN_NOTIFY_SEND || - peer->last_reset == PEER_DOWN_RTT_SHUTDOWN || - peer->last_reset == PEER_DOWN_USER_SHUTDOWN) + if ((peer->last_reset == PEER_DOWN_NOTIFY_SEND || + peer->last_reset == PEER_DOWN_RTT_SHUTDOWN || + peer->last_reset == PEER_DOWN_USER_SHUTDOWN) && + peer->notify.data) return SNMP_STRING(peer->notify.data); else return SNMP_STRING(""); @@ -420,7 +435,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, { oid *offset; int offsetlen; - struct bgp_path_info *path; + struct bgp_path_info *path, *min; struct bgp_dest *dest; union sockunion su; unsigned int len; @@ -500,6 +515,8 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, else addr->prefixlen = len * 8; + addr->family = family; + dest = bgp_node_get(bgp->rib[afi][SAFI_UNICAST], addr); offset++; @@ -525,8 +542,8 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, if (!dest) return NULL; - while ((dest = bgp_route_next(dest))) { - struct bgp_path_info *min = NULL; + do { + min = NULL; for (path = bgp_dest_get_bgp_path_info(dest); path; path = path->next) { @@ -564,6 +581,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, offset = name + namelen; + /* Encode prefix into OID */ if (family == AF_INET) oid_copy_in_addr(offset, &rn_p->u.prefix4); else @@ -573,6 +591,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, *offset = rn_p->prefixlen; offset++; + /* Encode peer's IP into OID */ if (family == AF_INET) { oid_copy_in_addr(offset, &min->peer->su.sin.sin_addr); @@ -584,6 +603,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, } addr->prefixlen = rn_p->prefixlen; + addr->family = rn_p->family; bgp_dest_unlock_node(dest); @@ -594,7 +614,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, memset(&paddr.ip._v4_addr, 0, afi_len); else memset(&paddr.ip._v6_addr, 0, afi_len); - } + } while ((dest = bgp_route_next(dest))); return NULL; } @@ -684,7 +704,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], case BGP_ATTR_NHLEN_IPV6_GLOBAL: return SNMP_INTEGER(2); case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - if (path->attr->mp_nexthop_prefer_global) + if (CHECK_FLAG(path->attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) return SNMP_INTEGER(2); else return SNMP_INTEGER(4); @@ -698,7 +719,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], case BGP_ATTR_NHLEN_IPV6_GLOBAL: return SNMP_IP6ADDRESS(path->attr->mp_nexthop_global); case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - if (path->attr->mp_nexthop_prefer_global) + if (CHECK_FLAG(path->attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) return SNMP_IP6ADDRESS( path->attr->mp_nexthop_global); else @@ -733,7 +755,7 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], case BGP4V2_NLRI_MED: if (CHECK_FLAG(path->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) - return SNMP_INTEGER(path->attr->local_pref); + return SNMP_INTEGER(path->attr->med); else return SNMP_INTEGER(0); case BGP4V2_NLRI_ATOMIC_AGGREGATE: diff --git a/bgpd/bgp_trace.h b/bgpd/bgp_trace.h index 14149b5139..7cc8f24e06 100644 --- a/bgpd/bgp_trace.h +++ b/bgpd/bgp_trace.h @@ -247,6 +247,71 @@ TRACEPOINT_EVENT( ) TRACEPOINT_LOGLEVEL(frr_bgp, bgp_dest_unlock, TRACE_INFO) +/* + * peer_lock/peer_unlock + */ +TRACEPOINT_EVENT( + frr_bgp, + bgp_peer_lock, + TP_ARGS(struct peer *, peer, + const char *, name), + TP_FIELDS( + ctf_string(caller, name) + ctf_string(peer, PEER_HOSTNAME(peer)) + ctf_integer(unsigned int, count, peer->lock) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, bgp_peer_lock, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + bgp_peer_unlock, + TP_ARGS(struct peer *, peer, + const char *, name), + TP_FIELDS( + ctf_string(caller, name) + ctf_string(peer, PEER_HOSTNAME(peer)) + ctf_integer(unsigned int, count, peer->lock) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, bgp_peer_unlock, TRACE_INFO) + +/* + * bgp_path_info_add/bgp_path_info_free + */ +TRACEPOINT_EVENT( + frr_bgp, + bgp_path_info_add, + TP_ARGS(struct bgp_dest *, dest, + struct bgp_path_info *, bpi, + const char *, name), + TP_FIELDS( + ctf_string(caller, name) + ctf_string(prefix, bgp_dest_get_prefix_str(dest)) + ctf_string(peer, PEER_HOSTNAME(bpi->peer)) + ctf_integer(unsigned int, dest_lock, + bgp_dest_get_lock_count(dest)) + ctf_integer(unsigned int, peer_lock, bpi->peer->lock) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, bgp_path_info_add, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + bgp_path_info_free, + TP_ARGS(struct bgp_path_info *, bpi, + const char *, name), + TP_FIELDS( + ctf_string(caller, name) + ctf_string(prefix, bgp_dest_get_prefix_str(bpi->net)) + ctf_string(peer, PEER_HOSTNAME(bpi->peer)) + ctf_integer(unsigned int, dest_lock, + bgp_dest_get_lock_count(bpi->net)) + ctf_integer(unsigned int, peer_lock, bpi->peer->lock) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, bgp_path_info_free, TRACE_INFO) + TRACEPOINT_EVENT( frr_bgp, evpn_mac_ip_zsend, diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 5ab1a6afa6..f6e7b444c6 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -234,6 +234,7 @@ static int bgp_ifp_up(struct interface *ifp) struct connected *c; struct nbr_connected *nc; struct listnode *node, *nnode; + struct bgp *bgp_default = bgp_get_default(); struct bgp *bgp; bgp = ifp->vrf->info; @@ -256,6 +257,14 @@ static int bgp_ifp_up(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_up(ifp); + if (bgp_default && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -264,6 +273,7 @@ static int bgp_ifp_down(struct interface *ifp) struct connected *c; struct nbr_connected *nc; struct listnode *node, *nnode; + struct bgp *bgp_default = bgp_get_default(); struct bgp *bgp; struct peer *peer; @@ -303,6 +313,14 @@ static int bgp_ifp_down(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_down(ifp); + if (bgp_default && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -390,10 +408,16 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) { struct listnode *node, *nnode; + struct bgp_path_info *pi; + struct bgp_table *table; + struct bgp_dest *dest; struct connected *ifc; struct peer *peer; - struct bgp *bgp; + struct bgp *bgp, *from_bgp, *bgp_default; + struct listnode *next; struct prefix *addr; + afi_t afi; + safi_t safi; bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -421,9 +445,6 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) * we do not want the peering to bounce. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - afi_t afi; - safi_t safi; - if (addr->family == AF_INET) continue; @@ -439,6 +460,44 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) } } + bgp_default = bgp_get_default(); + afi = family2afi(addr->family); + safi = SAFI_UNICAST; + + /* When the last IPv4 address was deleted, Linux removes all routes + * using the interface so that bgpd needs to re-send them. + */ + if (bgp_default && afi == AFI_IP) { + for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, from_bgp)) { + table = from_bgp->rib[afi][safi]; + if (!table) + continue; + + for (dest = bgp_table_top(table); dest; + dest = bgp_route_next(dest)) { + for (pi = bgp_dest_get_bgp_path_info(dest); pi; + pi = pi->next) { + if (pi->type == ZEBRA_ROUTE_BGP && + pi->attr && + pi->attr->nh_ifindex == + ifc->ifp->ifindex) { + SET_FLAG(pi->attr->nh_flag, + BGP_ATTR_NH_REFRESH); + } + } + } + + if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) + continue; + + vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi, + bgp_default, from_bgp); + + vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi, + bgp_default, from_bgp); + } + } + connected_free(&ifc); return 0; @@ -1007,7 +1066,8 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex) || path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { /* Check if route-map is set to prefer global over link-local */ - if (path->attr->mp_nexthop_prefer_global) { + if (CHECK_FLAG(path->attr->nh_flag, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) { nexthop = &path->attr->mp_nexthop_global; if (IN6_IS_ADDR_LINKLOCAL(nexthop)) *ifindex = path->attr->nh_ifindex; @@ -1307,6 +1367,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, uint8_t distance; struct peer *peer; struct bgp_path_info *mpinfo; + struct bgp_path_info *bpi_ultimate; struct bgp *bgp_orig; uint32_t metric; struct attr local_attr; @@ -1355,13 +1416,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, peer = info->peer; - if (info->type == ZEBRA_ROUTE_BGP - && info->sub_type == BGP_ROUTE_IMPORTED) { - - /* Obtain peer from parent */ - if (info->extra && info->extra->parent) - peer = ((struct bgp_path_info *)(info->extra->parent)) - ->peer; + if (info->type == ZEBRA_ROUTE_BGP) { + bpi_ultimate = bgp_get_imported_bpi_ultimate(info); + peer = bpi_ultimate->peer; } tag = info->attr->tag; @@ -1532,7 +1589,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, api_nh->weight = nh_weight; - if (mpinfo->extra && !sid_zero(&mpinfo->extra->sid[0].sid) && + if (mpinfo->extra && + bgp_is_valid_label(&mpinfo->extra->label[0]) && + !sid_zero(&mpinfo->extra->sid[0].sid) && !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) { sid_info = &mpinfo->extra->sid[0]; @@ -1540,12 +1599,16 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, sizeof(api_nh->seg6_segs)); if (sid_info->transposition_len != 0) { - if (!bgp_is_valid_label( - &mpinfo->extra->label[0])) - continue; - mpls_lse_decode(mpinfo->extra->label[0], &label, &ttl, &exp, &bos); + + if (label < MPLS_LABEL_UNRESERVED_MIN) { + if (bgp_debug_zebra(&api.prefix)) + zlog_debug( + "skip invalid SRv6 routes: transposition scheme is used, but label is too small"); + continue; + } + transpose_sid(&api_nh->seg6_segs, label, sid_info->transposition_offset, sid_info->transposition_len); @@ -1626,9 +1689,8 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, zlog_debug( "Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI " count %d nhg %d", - valid_nh_count ? "add" : "delete", bgp->vrf_id, - &api.prefix, api.metric, api.tag, api.nexthop_num, - nhg_id); + is_add ? "add" : "delete", bgp->vrf_id, &api.prefix, + api.metric, api.tag, api.nexthop_num, nhg_id); for (i = 0; i < api.nexthop_num; i++) { api_nh = &api.nexthops[i]; @@ -3188,6 +3250,7 @@ extern struct zebra_privs_t bgpd_privs; static int bgp_ifp_create(struct interface *ifp) { + struct bgp *bgp_default = bgp_get_default(); struct bgp *bgp; if (BGP_DEBUG(zebra, ZEBRA)) @@ -3202,6 +3265,17 @@ static int bgp_ifp_create(struct interface *ifp) bgp_update_interface_nbrs(bgp, ifp, ifp); hook_call(bgp_vrf_status_changed, bgp, ifp); + + if (bgp_default && + (if_is_loopback_exact(ifp) || + (if_is_vrf(ifp) && ifp->vrf->vrf_id != VRF_DEFAULT))) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 734e44f252..9b4aa38d7a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -93,6 +93,7 @@ #include "bgpd/bgp_evpn_mh.h" #include "bgpd/bgp_mac.h" #include "bgpd/bgp_orr.h" +#include "bgp_trace.h" DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)"); DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information"); @@ -1194,6 +1195,7 @@ static void peer_free(struct peer *peer) /* increase reference count on a struct peer */ struct peer *peer_lock_with_caller(const char *name, struct peer *peer) { + frrtrace(2, frr_bgp, bgp_peer_lock, peer, name); assert(peer && (peer->lock >= 0)); peer->lock++; @@ -1206,6 +1208,7 @@ struct peer *peer_lock_with_caller(const char *name, struct peer *peer) */ struct peer *peer_unlock_with_caller(const char *name, struct peer *peer) { + frrtrace(2, frr_bgp, bgp_peer_unlock, peer, name); assert(peer && (peer->lock > 0)); peer->lock--; diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index eae9859ba1..b65d90e1b3 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -3847,6 +3847,13 @@ struct rfapi_cfg *bgp_rfapi_cfg_new(struct rfapi_rfp_cfg *cfg) return h; } +static void bgp_rfapi_rfgn_list_delete(void *data) +{ + struct rfapi_rfg_name *rfgn = data; + free(rfgn->name); + rfgn_free(rfgn); +} + void bgp_rfapi_cfg_destroy(struct bgp *bgp, struct rfapi_cfg *h) { afi_t afi; @@ -3858,8 +3865,13 @@ void bgp_rfapi_cfg_destroy(struct bgp *bgp, struct rfapi_cfg *h) if (h->l2_groups != NULL) list_delete(&h->l2_groups); list_delete(&h->nve_groups_sequential); + + h->rfg_export_direct_bgp_l->del = bgp_rfapi_rfgn_list_delete; list_delete(&h->rfg_export_direct_bgp_l); + + h->rfg_export_zebra_l->del = bgp_rfapi_rfgn_list_delete; list_delete(&h->rfg_export_zebra_l); + if (h->default_rt_export_list) ecommunity_free(&h->default_rt_export_list); if (h->default_rt_import_list) diff --git a/debian/changelog b/debian/changelog index ad43f13e33..e3b6634594 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,11 +4,11 @@ frr (8.5~dev-1) UNRELEASED; urgency=medium -- Donatas Abraitis <donatas@opensourcerouting.org> Tue, 04 Oct 2022 16:00:00 +0500 -frr (8.4~dev-1) UNRELEASED; urgency=medium +frr (8.4-0) unstable; urgency=medium - * FRR Dev 8.4 + * New upstream release FRR 8.4 - -- Jafar Al-Gharaibeh <jafar@atcorp.com> Wed, 20 Jul 2022 10:00:00 +0500 + -- Jafar Al-Gharaibeh <jafar@atcorp.com> Tue, 01 Nov 2022 10:00:00 +0500 frr (8.3-0) unstable; urgency=medium diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 0b8e967264..f751eb3a75 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -4325,6 +4325,17 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. If ``json`` option is specified, output is displayed in JSON format. +.. clicmd:: show [ip] bgp [afi] [safi] [all] detail-routes + + Display the detailed version of all routes. The same format as using + ``show [ip] bgp [afi] [safi] PREFIX``, but for the whole BGP table. + + If ``all`` option is specified, ``ip`` keyword is ignored and, + routes displayed for all AFIs and SAFIs. + + If ``afi`` is specified, with ``all`` option, routes will be displayed for + each SAFI in the selected AFI. + .. _bgp-display-routes-by-community: Displaying Routes by Community Attribute diff --git a/doc/user/evpn.rst b/doc/user/evpn.rst index 0737ab6f07..c8052803cc 100644 --- a/doc/user/evpn.rst +++ b/doc/user/evpn.rst @@ -441,7 +441,7 @@ Here a traditional ``vxlan`` interface is created with the name "vni100" which uses a VTEP-IP of 100.64.0.1, carries VNI 100, and has Dynamic VTEP learning disabled. IPv6 address autoconfiguration is disabled for "vni100", then the interface is enslaved to "br100", ARP/ND suppression is enabled, and Dynamic -VTEP Learning is disabled. +MAC Learning is disabled. .. code-block:: shell diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 69c1c18d3c..0dff2ea448 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -831,6 +831,13 @@ Showing Information Show the OSPF routing table, as determined by the most recent SPF calculation. +.. clicmd:: show ip ospf [vrf <NAME|all>] border-routers [json] + + Show the list of ABR and ASBR border routers summary learnt via + OSPFv2 Type-3 (Summary LSA) and Type-4 (Summary ASBR LSA). + User can get that information as JSON format when ``json`` keyword + at the end of cli is presented. + .. clicmd:: show ip ospf (1-65535) route orr [NAME] .. clicmd:: show ip ospf [vrf <NAME|all>] route orr [NAME] diff --git a/doc/user/snmp.rst b/doc/user/snmp.rst index b9058cc0d3..0bf3565b2e 100644 --- a/doc/user/snmp.rst +++ b/doc/user/snmp.rst @@ -115,6 +115,65 @@ Then, you can use the following command to check everything works as expected: OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109 [...] +An example below is how to query SNMP for BGP: + + .. code-block:: shell + + $ # BGP4-MIB (https://www.circitor.fr/Mibs/Mib/B/BGP4-MIB.mib) + $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.2.1.15 + + $ # BGP4V2-MIB (http://www.circitor.fr/Mibs/Mib/B/BGP4V2-MIB.mib) + $ # Information about the peers (bgp4V2PeerTable): + $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.3.5.1.1.2 + ... + .1.3.6.1.3.5.1.1.2.1.1.1.4.192.168.10.124 = Gauge32: 0 + .1.3.6.1.3.5.1.1.2.1.1.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 0 + .1.3.6.1.3.5.1.1.2.1.2.1.4.192.168.10.124 = INTEGER: 1 + .1.3.6.1.3.5.1.1.2.1.2.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2 + .1.3.6.1.3.5.1.1.2.1.3.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 11 + .1.3.6.1.3.5.1.1.2.1.3.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 2A 02 47 80 0A BC 00 00 00 00 00 00 00 00 00 01 + .1.3.6.1.3.5.1.1.2.1.4.1.4.192.168.10.124 = INTEGER: 1 + .1.3.6.1.3.5.1.1.2.1.4.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2 + .1.3.6.1.3.5.1.1.2.1.5.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 7C + .1.3.6.1.3.5.1.1.2.1.5.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 2A 02 47 80 0A BC 00 00 00 00 00 00 00 00 00 02 + .1.3.6.1.3.5.1.1.2.1.6.1.4.192.168.10.124 = Gauge32: 179 + .1.3.6.1.3.5.1.1.2.1.6.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 179 + .1.3.6.1.3.5.1.1.2.1.7.1.4.192.168.10.124 = Gauge32: 65002 + .1.3.6.1.3.5.1.1.2.1.7.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 65002 + .1.3.6.1.3.5.1.1.2.1.8.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 11 + .1.3.6.1.3.5.1.1.2.1.8.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: C0 A8 0A 11 + .1.3.6.1.3.5.1.1.2.1.9.1.4.192.168.10.124 = Gauge32: 41894 + .1.3.6.1.3.5.1.1.2.1.9.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 39960 + .1.3.6.1.3.5.1.1.2.1.10.1.4.192.168.10.124 = Gauge32: 65001 + .1.3.6.1.3.5.1.1.2.1.10.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 65001 + .1.3.6.1.3.5.1.1.2.1.11.1.4.192.168.10.124 = Hex-STRING: C8 C8 C8 CA + .1.3.6.1.3.5.1.1.2.1.11.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: C8 C8 C8 CA + .1.3.6.1.3.5.1.1.2.1.12.1.4.192.168.10.124 = INTEGER: 2 + .1.3.6.1.3.5.1.1.2.1.12.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2 + .1.3.6.1.3.5.1.1.2.1.13.1.4.192.168.10.124 = INTEGER: 6 + .1.3.6.1.3.5.1.1.2.1.13.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 6 + + $ # Information about the BGP table (bgp4V2NlriTable): + $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.3.5.1.1.9 + ... + .1.3.6.1.3.5.1.1.9.1.22.1.4.10.0.2.0.24.192.168.10.124 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.22.1.4.10.10.100.0.24.192.168.10.124 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.1.32.192.168.10.124 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.2.32.192.168.10.124 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.3.32.192.168.10.124 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.0.0.24.192.168.10.124 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.1.0.24.192.168.10.124 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.10.0.24.192.168.10.124 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.22.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.0.64.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.24.1.4.10.0.2.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.1.4.10.10.100.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.1.32.192.168.10.124 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.2.32.192.168.10.124 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.3.32.192.168.10.124 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.0.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.1.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.10.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.0.64.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 02 01 FD E9 The AgentX protocol can be transported over a Unix socket or using TCP or UDP. It usually defaults to a Unix socket and depends on how NetSNMP was built. If @@ -132,5 +191,7 @@ Here is the syntax for using AgentX: .. clicmd:: agentx + Once enabled, it can't be unconfigured. Only removing from the daemons file + the keyword ``agentx`` takes an effect. .. include:: snmptrap.rst diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 3608f828e8..c05a29af4e 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -309,6 +309,15 @@ the default route. User can get that information as JSON string when ``json`` key word at the end of cli is presented. +.. clicmd:: show ip nht route-map [vrf <NAME|all>] [json] + + This command displays route-map attach point to nexthop tracking and + displays list of protocol with its applied route-map. + When zebra considers sending NHT resoultion, the nofification only + sent to appropriate client protocol only after applying route-map filter. + User can get that information as JSON format when ``json`` keyword + at the end of cli is presented. + PBR dataplane programming ========================= @@ -564,9 +564,24 @@ size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz, return count; } +/* Get the VRF loopback interface, i.e. the loopback on the default VRF + * or the VRF interface. + */ +struct interface *if_get_vrf_loopback(vrf_id_t vrf_id) +{ + struct interface *ifp = NULL; + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + + FOR_ALL_INTERFACES (vrf, ifp) + if (if_is_loopback(ifp)) + return ifp; + + return NULL; +} /* Get interface by name if given name interface doesn't exist create - one. */ + * one. + */ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id, const char *vrf_name) { @@ -532,6 +532,7 @@ static inline bool if_address_is_local(const void *matchaddr, int family, struct vrf; extern struct interface *if_lookup_by_name_vrf(const char *name, struct vrf *vrf); extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id); +extern struct interface *if_get_vrf_loopback(vrf_id_t vrf_id); extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id, const char *vrf_name); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 07061b6f57..0fd6e15ed6 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1585,7 +1585,11 @@ ospf6_asbr_summary_remove_lsa_and_route(struct ospf6 *ospf6, zlog_debug( "%s: Remove the blackhole route", __func__); + ospf6_zebra_route_update_remove(aggr->route, ospf6); + if (aggr->route->route_option) + XFREE(MTYPE_OSPF6_EXTERNAL_INFO, + aggr->route->route_option); ospf6_route_delete(aggr->route); aggr->route = NULL; } @@ -2736,8 +2740,13 @@ ospf6_summary_add_aggr_route_and_blackhole(struct ospf6 *ospf6, struct ospf6_external_aggr_rt *aggr) { struct ospf6_route *rt_aggr; + struct ospf6_route *old_rt = NULL; struct ospf6_external_info *info; + /* Check if a route is already present. */ + if (aggr->route) + old_rt = aggr->route; + /* Create summary route and save it. */ rt_aggr = ospf6_route_create(ospf6); rt_aggr->type = OSPF6_DEST_TYPE_NETWORK; @@ -2756,6 +2765,16 @@ ospf6_summary_add_aggr_route_and_blackhole(struct ospf6 *ospf6, /* Add next-hop to Null interface. */ ospf6_add_route_nexthop_blackhole(rt_aggr); + /* Free the old route, if any. */ + if (old_rt) { + ospf6_zebra_route_update_remove(old_rt, ospf6); + + if (old_rt->route_option) + XFREE(MTYPE_OSPF6_EXTERNAL_INFO, old_rt->route_option); + + ospf6_route_delete(old_rt); + } + ospf6_zebra_route_update_add(rt_aggr, ospf6); } @@ -3024,8 +3043,8 @@ static void ospf6_aggr_handle_external_info(void *data) (void)ospf6_originate_type5_type7_lsas(rt, ospf6); } -static void -ospf6_asbr_summary_config_delete(struct ospf6 *ospf6, struct route_node *rn) +void ospf6_asbr_summary_config_delete(struct ospf6 *ospf6, + struct route_node *rn) { struct ospf6_external_aggr_rt *aggr = rn->info; @@ -3167,14 +3186,6 @@ void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr) hash_clean(aggr->match_extnl_hash, ospf6_aggr_unlink_external_info); - if (aggr->route) { - if (aggr->route->route_option) - XFREE(MTYPE_OSPF6_EXTERNAL_INFO, - aggr->route->route_option); - - ospf6_route_delete(aggr->route); - } - if (IS_OSPF6_DEBUG_AGGR) zlog_debug("%s: Release the aggregator Address(%pFX)", __func__, diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 0487bb14c3..0d2a98aeba 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -182,4 +182,6 @@ void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr); void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6); void ospf6_fill_aggr_route_details(struct ospf6 *ospf6, struct ospf6_external_aggr_rt *aggr); +void ospf6_asbr_summary_config_delete(struct ospf6 *ospf6, + struct route_node *rn); #endif /* OSPF6_ASBR_H */ diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 439b94c9af..a4ba1fb569 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -106,6 +106,23 @@ struct ospf6_neighbor *ospf6_area_neighbor_lookup(struct ospf6_area *area, return NULL; } +static void ospf6_neighbor_clear_ls_lists(struct ospf6_neighbor *on) +{ + struct ospf6_lsa *lsa; + struct ospf6_lsa *lsanext; + + ospf6_lsdb_remove_all(on->summary_list); + if (on->last_ls_req) { + ospf6_lsa_unlock(on->last_ls_req); + on->last_ls_req = NULL; + } + ospf6_lsdb_remove_all(on->request_list); + for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { + ospf6_decrement_retrans_count(lsa); + ospf6_lsdb_remove(lsa, on->retrans_list); + } +} + /* create ospf6_neighbor */ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, struct ospf6_interface *oi) @@ -147,14 +164,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, void ospf6_neighbor_delete(struct ospf6_neighbor *on) { - struct ospf6_lsa *lsa, *lsanext; - - ospf6_lsdb_remove_all(on->summary_list); - ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { - ospf6_decrement_retrans_count(lsa); - ospf6_lsdb_remove(lsa, on->retrans_list); - } + ospf6_neighbor_clear_ls_lists(on); ospf6_lsdb_remove_all(on->dbdesc_list); ospf6_lsdb_remove_all(on->lsupdate_list); @@ -339,12 +349,7 @@ void negotiation_done(struct thread *thread) zlog_debug("Neighbor Event %s: *NegotiationDone*", on->name); /* clear ls-list */ - ospf6_lsdb_remove_all(on->summary_list); - ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { - ospf6_decrement_retrans_count(lsa); - ospf6_lsdb_remove(lsa, on->retrans_list); - } + ospf6_neighbor_clear_ls_lists(on); /* Interface scoped LSAs */ for (ALL_LSDB(on->ospf6_if->lsdb, lsa, lsanext)) { @@ -464,7 +469,6 @@ void loading_done(struct thread *thread) void adj_ok(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa, *lsanext; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -486,19 +490,13 @@ void adj_ok(struct thread *thread) } else if (on->state >= OSPF6_NEIGHBOR_EXSTART && !need_adjacency(on)) { ospf6_neighbor_state_change(OSPF6_NEIGHBOR_TWOWAY, on, OSPF6_NEIGHBOR_EVENT_ADJ_OK); - ospf6_lsdb_remove_all(on->summary_list); - ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { - ospf6_decrement_retrans_count(lsa); - ospf6_lsdb_remove(lsa, on->retrans_list); - } + ospf6_neighbor_clear_ls_lists(on); } } void seqnumber_mismatch(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa, *lsanext; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -515,12 +513,7 @@ void seqnumber_mismatch(struct thread *thread) SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT); - ospf6_lsdb_remove_all(on->summary_list); - ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { - ospf6_decrement_retrans_count(lsa); - ospf6_lsdb_remove(lsa, on->retrans_list); - } + ospf6_neighbor_clear_ls_lists(on); THREAD_OFF(on->thread_send_dbdesc); on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */ @@ -532,7 +525,6 @@ void seqnumber_mismatch(struct thread *thread) void bad_lsreq(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa, *lsanext; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -549,12 +541,7 @@ void bad_lsreq(struct thread *thread) SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT); - ospf6_lsdb_remove_all(on->summary_list); - ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { - ospf6_decrement_retrans_count(lsa); - ospf6_lsdb_remove(lsa, on->retrans_list); - } + ospf6_neighbor_clear_ls_lists(on); THREAD_OFF(on->thread_send_dbdesc); on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */ @@ -567,7 +554,6 @@ void bad_lsreq(struct thread *thread) void oneway_received(struct thread *thread) { struct ospf6_neighbor *on; - struct ospf6_lsa *lsa, *lsanext; on = (struct ospf6_neighbor *)THREAD_ARG(thread); assert(on); @@ -582,12 +568,7 @@ void oneway_received(struct thread *thread) OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD); thread_add_event(master, neighbor_change, on->ospf6_if, 0, NULL); - ospf6_lsdb_remove_all(on->summary_list); - ospf6_lsdb_remove_all(on->request_list); - for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { - ospf6_decrement_retrans_count(lsa); - ospf6_lsdb_remove(lsa, on->retrans_list); - } + ospf6_neighbor_clear_ls_lists(on); THREAD_OFF(on->thread_send_dbdesc); THREAD_OFF(on->thread_send_lsreq); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index eb89a14cd3..db45fa5f5c 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -498,6 +498,7 @@ void ospf6_delete(struct ospf6 *o) struct route_node *rn = NULL; struct ospf6_area *oa; struct vrf *vrf; + struct ospf6_external_aggr_rt *aggr; QOBJ_UNREG(o); @@ -536,8 +537,11 @@ void ospf6_delete(struct ospf6 *o) } for (rn = route_top(o->rt_aggr_tbl); rn; rn = route_next(rn)) - if (rn->info) - ospf6_external_aggregator_free(rn->info); + if (rn->info) { + aggr = rn->info; + ospf6_asbr_summary_config_delete(o, rn); + ospf6_external_aggregator_free(aggr); + } route_table_finish(o->rt_aggr_tbl); XFREE(MTYPE_OSPF6_TOP, o->name); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 8c87a568c0..0cb9d02725 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -1169,8 +1169,8 @@ static void ospf_db_desc_proc(struct stream *s, struct ospf_interface *oi, if (IS_OPAQUE_LSA(lsah->type) && !CHECK_FLAG(nbr->options, OSPF_OPTION_O)) { flog_warn(EC_OSPF_PACKET, - "LSA[Type%d:%pI4]: Opaque capability mismatch?", - lsah->type, &lsah->id); + "LSA[Type%d:%pI4] from %pI4: Opaque capability mismatch?", + lsah->type, &lsah->id, &lsah->adv_router); OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_SeqNumberMismatch); return; } diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 4f60ce22a9..58fcbfa4a9 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -1956,9 +1956,10 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread) rt_time = monotime_since(&start_time, NULL); /* Free old all routers routing table */ - if (ospf->oall_rtrs) - /* ospf_route_delete (ospf->old_rtrs); */ + if (ospf->oall_rtrs) { ospf_rtrs_free(ospf->oall_rtrs); + ospf->oall_rtrs = NULL; + } /* Update all routers routing table */ ospf->oall_rtrs = ospf->all_rtrs; @@ -1967,9 +1968,10 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread) ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs); #endif /* Free old ABR/ASBR routing table */ - if (ospf->old_rtrs) - /* ospf_route_delete (ospf->old_rtrs); */ + if (ospf->old_rtrs) { ospf_rtrs_free(ospf->old_rtrs); + ospf->old_rtrs = NULL; + } /* Update ABR/ASBR routing table */ ospf->old_rtrs = ospf->new_rtrs; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 0bab045ef4..43b7de552a 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -6614,14 +6614,17 @@ static void show_lsa_detail_proc(struct vty *vty, struct route_table *rt, route_lock_node(start); for (rn = start; rn; rn = route_next_until(rn, start)) if ((lsa = rn->info)) { - if (json) { - json_lsa = json_object_new_object(); - json_object_array_add(json, json_lsa); - } + if (show_function[lsa->data->type] != NULL) { + if (json) { + json_lsa = + json_object_new_object(); + json_object_array_add(json, + json_lsa); + } - if (show_function[lsa->data->type] != NULL) show_function[lsa->data->type]( vty, lsa, json_lsa); + } } route_unlock_node(start); } @@ -6640,9 +6643,6 @@ static void show_lsa_detail(struct vty *vty, struct ospf *ospf, int type, json_object *json_areas = NULL; json_object *json_lsa_array = NULL; - if (json) - json_lsa_type = json_object_new_object(); - switch (type) { case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_LSA: @@ -6685,6 +6685,7 @@ static void show_lsa_detail(struct vty *vty, struct ospf *ospf, int type, } if (json) { + json_lsa_type = json_object_new_object(); json_object_object_add(json_lsa_type, "areas", json_areas); json_object_object_add(json, @@ -7158,6 +7159,9 @@ DEFUN (show_ip_ospf_database_max, vty_out(vty, "%% OSPF is not enabled in vrf %s\n", vrf_name); + if (uj) + json_object_free(json); + return CMD_SUCCESS; } ret = (show_ip_ospf_database_common( @@ -7169,6 +7173,9 @@ DEFUN (show_ip_ospf_database_max, ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); if (ospf == NULL || !ospf->oi_running) { vty_out(vty, "%% OSPF is not enabled in vrf default\n"); + if (uj) + json_object_free(json); + return CMD_SUCCESS; } @@ -11209,15 +11216,37 @@ DEFUN (show_ip_ospf_instance_reachable_routers, static int show_ip_ospf_border_routers_common(struct vty *vty, struct ospf *ospf, - uint8_t use_vrf) + uint8_t use_vrf, + json_object *json) { - if (ospf->instance) - vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance); + json_object *json_vrf = NULL; + json_object *json_router = NULL; - ospf_show_vrf_name(ospf, vty, NULL, use_vrf); + if (json) { + if (use_vrf) + json_vrf = json_object_new_object(); + else + json_vrf = json; + json_router = json_object_new_object(); + } + + if (ospf->instance) { + if (!json) + vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance); + else + json_object_int_add(json_vrf, "ospfInstance", + ospf->instance); + } + + ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf); if (ospf->new_table == NULL) { - vty_out(vty, "No OSPF routing information exist\n"); + if (!json) + vty_out(vty, "No OSPF routing information exist\n"); + else { + json_object_free(json_router); + json_object_free(json_vrf); + } return CMD_SUCCESS; } @@ -11225,22 +11254,35 @@ static int show_ip_ospf_border_routers_common(struct vty *vty, show_ip_ospf_route_network (vty, ospf->new_table); */ /* Show Router routes. */ - show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs, NULL); + show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs, json_router); - vty_out(vty, "\n"); + if (json) { + json_object_object_add(json_vrf, "routers", json_router); + if (use_vrf) { + if (ospf->vrf_id == VRF_DEFAULT) + json_object_object_add(json, "default", + json_vrf); + else + json_object_object_add(json, ospf->name, + json_vrf); + } + } else { + vty_out(vty, "\n"); + } return CMD_SUCCESS; } -DEFUN (show_ip_ospf_border_routers, +DEFPY (show_ip_ospf_border_routers, show_ip_ospf_border_routers_cmd, - "show ip ospf [vrf <NAME|all>] border-routers", + "show ip ospf [vrf <NAME|all>] border-routers [json]", SHOW_STR IP_STR "OSPF information\n" VRF_CMD_HELP_STR "All VRFs\n" - "Show all the ABR's and ASBR's\n") + "Show all the ABR's and ASBR's\n" + JSON_STR) { struct ospf *ospf = NULL; struct listnode *node = NULL; @@ -11250,6 +11292,11 @@ DEFUN (show_ip_ospf_border_routers, int inst = 0; int idx_vrf = 0; uint8_t use_vrf = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); @@ -11265,32 +11312,47 @@ DEFUN (show_ip_ospf_border_routers, ospf_output = true; ret = show_ip_ospf_border_routers_common( - vty, ospf, use_vrf); + vty, ospf, use_vrf, json); } - if (!ospf_output) + if (uj) + vty_json(vty, json); + else if (!ospf_output) vty_out(vty, "%% OSPF is not enabled\n"); + + return ret; } else { ospf = ospf_lookup_by_inst_name(inst, vrf_name); if (ospf == NULL || !ospf->oi_running) { - vty_out(vty, - "%% OSPF is not enabled in vrf %s\n", - vrf_name); + if (uj) + vty_json(vty, json); + else + vty_out(vty, + "%% OSPF is not enabled in vrf %s\n", + vrf_name); + return CMD_SUCCESS; } - - ret = show_ip_ospf_border_routers_common(vty, ospf, - use_vrf); } } else { /* Display default ospf (instance 0) info */ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); if (ospf == NULL || !ospf->oi_running) { - vty_out(vty, "%% OSPF is not enabled in vrf default\n"); + if (uj) + vty_json(vty, json); + else + vty_out(vty, + "%% OSPF is not enabled in vrf default\n"); + return CMD_SUCCESS; } + } - ret = show_ip_ospf_border_routers_common(vty, ospf, use_vrf); + if (ospf) { + ret = show_ip_ospf_border_routers_common(vty, ospf, use_vrf, + json); + if (uj) + vty_json(vty, json); } return ret; @@ -11317,7 +11379,7 @@ DEFUN (show_ip_ospf_instance_border_routers, if (!ospf || !ospf->oi_running) return CMD_SUCCESS; - return show_ip_ospf_border_routers_common(vty, ospf, 0); + return show_ip_ospf_border_routers_common(vty, ospf, 0, NULL); } static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf, diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 2403b567a5..a5d40ad176 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -852,6 +852,10 @@ static void ospf_finish_final(struct ospf *ospf) ospf_route_delete(ospf, ospf->new_table); ospf_route_table_free(ospf->new_table); } + if (ospf->oall_rtrs) + ospf_rtrs_free(ospf->oall_rtrs); + if (ospf->all_rtrs) + ospf_rtrs_free(ospf->all_rtrs); if (ospf->old_rtrs) ospf_rtrs_free(ospf->old_rtrs); if (ospf->new_rtrs) diff --git a/pathd/path_pcep_config.c b/pathd/path_pcep_config.c index 99b1c349a9..873b0ccd37 100644 --- a/pathd/path_pcep_config.c +++ b/pathd/path_pcep_config.c @@ -453,8 +453,7 @@ int path_pcep_config_update_path(struct path *path) } if (number_of_sid_clashed) - SET_FLAG(segment->segment_list->flags, - F_SEGMENT_LIST_SID_CONFLICT); + SET_FLAG(segment_list->flags, F_SEGMENT_LIST_SID_CONFLICT); else srte_apply_changes(); diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 3bfb31e0c6..dff1b4fed4 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -166,8 +166,8 @@ struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil, const char *name) { if (PIM_DEBUG_MROUTE) { - pim_sgaddr sg = {.src = *oil_mcastgrp(c_oil), - .grp = *oil_origin(c_oil)}; + pim_sgaddr sg = {.src = *oil_origin(c_oil), + .grp = *oil_mcastgrp(c_oil)}; zlog_debug( "%s(%s): Del oil for %pSG, Ref Count: %d (Predecrement)", diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 71e62bf769..a3f5f6b0cd 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -793,9 +793,18 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %changelog -* Wed Jul 20 2022 Martin Winter <mwinter@opensourcerouting.org> - %{version} - -* Tue Oct 04 2022 Donatas Abraitis <donatas@opensourcerouting.org> - 8.4 +* Tue Nov 01 2022 Martin Winter <mwinter@opensourcerouting.org> - %{version} + +* Tue Nov 01 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.4 +- New BGP command (neighbor PEER soo) to configure SoO to prevent routing loops and suboptimal routing on dual-homed sites. +- Command debug bgp allow-martian replaced to bgp allow-martian-nexthop because previously we allowed using martian next-hops when debug is turned on. +- Implement BGP Prefix Origin Validation State Extended Community rfc8097 +- Implement Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages rfc9234 +- BMP L3VPN support +- PIMv6 support +- MLD support +- New command to enable using reserved IPv4 ranges as normal addresses for BGP next-hops, interface addresses, etc. +- For a full list of bug fixes, please refer to https://frrouting.org/release/ * Wed Jul 13 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.3 - General: diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf index 46831bb711..375bbea9ff 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf @@ -4,6 +4,8 @@ hostname ce1 ! interface lo ip address 99.0.0.1/32 + ip address 5.1.0.1/24 + ip address 6.0.2.1/24 ! interface ce1-eth0 description to r1 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf index fb4d8cc9c4..90dd3c55b4 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf @@ -4,6 +4,8 @@ hostname ce2 ! interface lo ip address 99.0.0.2/32 + ip address 5.1.0.1/24 + ip address 6.0.2.1/24 ! interface ce2-eth0 description to r3 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf index e316de5690..cf7396eb12 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf @@ -19,6 +19,7 @@ router bgp 5227 network 5.1.3.0/24 route-map rm-nh network 6.0.1.0/24 route-map rm-nh network 6.0.2.0/24 route-map rm-nh-same + network 6.0.3.0/24 route-map rm-nh-same neighbor 192.168.1.1 activate exit-address-family ! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf index 77a1163a4b..df6ac47b08 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf @@ -4,6 +4,7 @@ hostname ce3 ! interface lo ip address 99.0.0.3/32 + ip address 6.0.3.1/24 ! interface ce3-eth0 description to r4 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf index 60d9e93108..9a6ca08a0b 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf @@ -19,6 +19,7 @@ router bgp 5228 vrf ce4-cust2 network 5.4.3.0/24 route-map rm-nh network 6.0.1.0/24 route-map rm-nh network 6.0.2.0/24 route-map rm-nh-same + network 6.0.3.0/24 route-map rm-nh-same neighbor 192.168.2.1 activate exit-address-family ! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf index e55c9e779a..0e3a736292 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf @@ -4,6 +4,7 @@ hostname ce4 ! interface ce4-cust2 ip address 99.0.0.4/32 + ip address 6.0.3.1/24 ! interface ce4-eth0 description to r4 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py index 5161d8471f..b2bf5f5f63 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -175,6 +175,20 @@ def ltemplatePreRouterStartHook(): "setup {0} vrf {0}-cust1, {0}-eth4. enabled mpls input.".format(rtr) ) # configure cust2 VRFs & MPLS + rtrs = ["r1"] + cmds = [ + "ip link add {0}-cust3 type vrf table 20", + "ip link set dev {0}-cust3 up", + "ip link add {0}-cust4 type vrf table 30", + "ip link set dev {0}-cust4 up", + "ip link add {0}-cust5 type vrf table 40", + "ip link set dev {0}-cust5 up", + ] + for rtr in rtrs: + for cmd in cmds: + cc.doCmd(tgen, rtr, cmd.format(rtr)) + logger.info("setup {0} vrf {0}-cust3 and{0}-cust4.".format(rtr)) + # configure cust2 VRFs & MPLS rtrs = ["r4"] cmds = [ "ip link add {0}-cust2 type vrf table 20", diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf index 8d42cfc0d8..24e9f95372 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf @@ -11,6 +11,7 @@ log file bgpd.log debugging #debug bgp vpn leak-from-vrf #debug bgp vpn label #debug bgp updates out +#debug bgp nht router bgp 5226 bgp router-id 1.1.1.1 @@ -39,6 +40,11 @@ router bgp 5227 vrf r1-cust1 neighbor 192.168.1.2 timers 3 10 address-family ipv4 unicast + network 10.2.3.4/32 + network 192.0.0.0/24 + + redistribute connected + neighbor 192.168.1.2 activate neighbor 192.168.1.2 next-hop-self @@ -51,5 +57,47 @@ router bgp 5227 vrf r1-cust1 exit-address-family +router bgp 5228 vrf r1-cust3 + bgp router-id 192.168.1.1 + + address-family ipv4 unicast + rd vpn export 10:13 + rt vpn import 52:100 + + import vpn + export vpn + exit-address-family + + +router bgp 5227 vrf r1-cust4 + no bgp network import-check + + bgp router-id 192.168.1.1 + + address-family ipv4 unicast + network 28.0.0.0/24 + + rd vpn export 10:14 + rt vpn export 52:100 + + import vpn + export vpn + exit-address-family + + +router bgp 5227 vrf r1-cust5 + bgp router-id 192.168.1.1 + + address-family ipv4 unicast + redistribute connected + + label vpn export 105 + rd vpn export 10:15 + rt vpn both 52:100 + + import vpn + export vpn + exit-address-family + ! end diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/staticd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/staticd.conf new file mode 100644 index 0000000000..59430fdf99 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/staticd.conf @@ -0,0 +1,6 @@ +hostname r1 +log file staticd.log +! +vrf r1-cust1 + ip route 192.0.0.0/24 192.168.1.2 +exit-vrf diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf index 221bc7a839..e81bc6b2ab 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf @@ -4,6 +4,9 @@ hostname r1 password zebra #debug zebra packet +#debug zebra rib detailed +#debug zebra dplane detailed +#debug zebra nexthop detail interface lo ip address 1.1.1.1/32 @@ -18,6 +21,14 @@ interface r1-eth4 ip address 192.168.1.1/24 no link-detect +interface r1-cust1 + ip address 10.4.5.6/24 + no link-detect + +interface r1-cust5 + ip address 29.0.0.1/32 + no link-detect + ip forwarding diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py index 91a7adf997..89369241a8 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py @@ -81,3 +81,24 @@ if ret != False and found != None: "wait", "CE3->CE4 (loopback) ping", ) + luCommand( + "r1", + "ip vrf exec r1-cust1 ping 6.0.3.1 -I 10.4.5.6 -c 1", + " 0. packet loss", + "wait", + "R1(r1-cust1)->CE3/4 (loopback) ping", + ) + luCommand( + "r1", + "ip vrf exec r1-cust1 ping 6.0.3.1 -I 10.4.5.6 -c 1", + " 0. packet loss", + "pass", + "R1(r1-cust1)->CE3/4 (loopback) ping", + ) + luCommand( + "r1", + "ip vrf exec r1-cust5 ping 6.0.3.1 -I 29.0.0.1 -c 1", + " 0. packet loss", + "pass", + "R1(r1-cust5)->CE3/4 ( (loopback) ping", + ) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py index 75158b127e..e9647898ab 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py @@ -72,3 +72,53 @@ luCommand( "wait", "CE4->PE4 ping", ) +ret = luCommand( + "r1", + "ip vrf exec r1-cust5 ping 29.0.0.1 -I 29.0.0.1 -c 1", + " 0. packet loss", + "pass", + "Ping its own IP. Check https://bugzilla.kernel.org/show_bug.cgi?id=203483 if it fails", +) +luCommand( + "r1", + "ip vrf exec r1-cust5 ping 192.168.1.1 -I 29.0.0.1 -c 1", + " 0. packet loss", + "pass", + "R1(r1-cust5)->R1(r1-cust1 - r1-eth4) ping", +) +luCommand( + "r1", + "ip vrf exec r1-cust5 ping 192.168.1.2 -I 29.0.0.1 -c 1", + " 0. packet loss", + "wait", + "R1(r1-cust5)->CE1 ping", +) +luCommand( + "r1", + "ip vrf exec r1-cust5 ping 192.168.1.2 -I 29.0.0.1 -c 1", + " 0. packet loss", + "pass", + "R1(r1-cust5)->CE1 ping", +) +luCommand( + "r1", + "ip vrf exec r1-cust5 ping 99.0.0.1 -I 29.0.0.1 -c 1", + " 0. packet loss", + "pass", + "R1(r1-cust5)->CE1 (loopback) ping", +) +luCommand( + "r1", + "ip vrf exec r1-cust5 ping 5.1.0.1 -I 29.0.0.1 -c 1", + " 0. packet loss", + "wait", + "R1(r1-cust5)->CE1 (loopback) ping", + time=30, +) +luCommand( + "r1", + "ip vrf exec r1-cust5 ping 5.1.0.1 -I 29.0.0.1 -c 1", + " 0. packet loss", + "pass", + "R1(r1-cust5)->CE1 (loopback) ping", +) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py index 1e2758c1c9..3242e3bd3a 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py @@ -54,15 +54,44 @@ bgpribRequireUnicastRoutes("ce4", "ipv4", "ce4-cust2", "Cust 4 routes in ce1", w # # r1 vtysh -c "show bgp vrf r1-cust1 ipv4" # -want_r1_cust1_routes = [ +want_r1_cust1_3_5_routes = [ {"p": "5.1.0.0/24", "n": "99.0.0.1"}, {"p": "5.1.1.0/24", "n": "99.0.0.1"}, {"p": "6.0.1.0/24", "n": "99.0.0.1"}, {"p": "6.0.2.0/24", "n": "99.0.0.1"}, + {"p": "10.2.3.4/32", "n": "0.0.0.0", "bp": False}, + {"p": "10.4.5.0/24", "n": "0.0.0.0", "bp": True}, + {"p": "28.0.0.0/24", "n": "0.0.0.0", "bp": True}, + {"p": "29.0.0.1/32", "n": "0.0.0.0", "bp": True}, {"p": "99.0.0.1/32", "n": "192.168.1.2"}, + {"p": "192.0.0.0/24", "n": "0.0.0.0", "bp": True}, + {"p": "192.168.1.0/24", "n": "0.0.0.0", "bp": True}, ] bgpribRequireUnicastRoutes( - "r1", "ipv4", "r1-cust1", "Customer 1 routes in r1 vrf", want_r1_cust1_routes + "r1", "ipv4", "r1-cust1", "Customer 1 routes in r1 vrf", want_r1_cust1_3_5_routes +) +bgpribRequireUnicastRoutes( + "r1", "ipv4", "r1-cust3", "Customer 3 routes in r1 vrf", want_r1_cust1_3_5_routes +) +bgpribRequireUnicastRoutes( + "r1", "ipv4", "r1-cust5", "Customer 5 routes in r1 vrf", want_r1_cust1_3_5_routes +) + +want_r1_cust4_routes = [ + {"p": "5.1.0.0/24", "n": "99.0.0.1", "exist": False}, + {"p": "5.1.1.0/24", "n": "99.0.0.1", "exist": False}, + {"p": "6.0.1.0/24", "n": "99.0.0.1", "exist": False}, + {"p": "6.0.2.0/24", "n": "99.0.0.1", "exist": False}, + {"p": "10.2.3.4/32", "n": "0.0.0.0", "exist": False}, + {"p": "10.4.5.0/24", "n": "0.0.0.0", "exist": False}, + {"p": "28.0.0.0/24", "n": "0.0.0.0", "bp": True}, + {"p": "29.0.0.1/32", "n": "0.0.0.0", "exist": False}, + {"p": "99.0.0.1/32", "n": "192.168.1.2", "exist": False}, + {"p": "192.0.0.0/24", "n": "0.0.0.0", "exist": False}, + {"p": "192.168.1.0/24", "n": "0.0.0.0", "exist": False}, +] +bgpribRequireUnicastRoutes( + "r1", "ipv4", "r1-cust4", "Customer 4 routes in r1 vrf", want_r1_cust4_routes ) want_r3_cust1_routes = [ @@ -70,10 +99,20 @@ want_r3_cust1_routes = [ {"p": "5.1.1.0/24", "n": "99.0.0.2"}, {"p": "6.0.1.0/24", "n": "99.0.0.2"}, {"p": "6.0.2.0/24", "n": "99.0.0.2"}, + {"p": "10.2.3.4/32", "n": "0.0.0.0", "exist": False}, + {"p": "28.0.0.0/24", "n": "1.1.1.1", "bp": True}, + {"p": "29.0.0.1/32", "n": "1.1.1.1", "bp": True}, {"p": "99.0.0.2/32", "n": "192.168.1.2"}, + {"p": "192.0.0.0/24", "n": "1.1.1.1", "bp": True}, + {"p": "192.168.1.0/24", "n": "1.1.1.1", "bp": True}, ] bgpribRequireUnicastRoutes( - "r3", "ipv4", "r3-cust1", "Customer 1 routes in r3 vrf", want_r3_cust1_routes + "r3", + "ipv4", + "r3-cust1", + "Customer 1 routes in r3 vrf", + want_r3_cust1_routes, + retry=30, ) want_r4_cust1_routes = [ @@ -81,10 +120,20 @@ want_r4_cust1_routes = [ {"p": "5.1.3.0/24", "n": "99.0.0.3"}, {"p": "6.0.1.0/24", "n": "99.0.0.3"}, {"p": "6.0.2.0/24", "n": "99.0.0.3"}, + {"p": "10.2.3.4/32", "n": "0.0.0.0", "exist": False}, + {"p": "28.0.0.0/24", "n": "1.1.1.1", "bp": True}, + {"p": "29.0.0.1/32", "n": "1.1.1.1", "bp": True}, {"p": "99.0.0.3/32", "n": "192.168.1.2"}, + {"p": "192.0.0.0/24", "n": "1.1.1.1", "bp": True}, + {"p": "192.168.1.0/24", "n": "1.1.1.1", "bp": True}, ] bgpribRequireUnicastRoutes( - "r4", "ipv4", "r4-cust1", "Customer 1 routes in r4 vrf", want_r4_cust1_routes + "r4", + "ipv4", + "r4-cust1", + "Customer 1 routes in r4 vrf", + want_r4_cust1_routes, + retry=30, ) want_r4_cust2_routes = [ @@ -92,10 +141,20 @@ want_r4_cust2_routes = [ {"p": "5.4.3.0/24", "n": "99.0.0.4"}, {"p": "6.0.1.0/24", "n": "99.0.0.4"}, {"p": "6.0.2.0/24", "n": "99.0.0.4"}, + {"p": "10.2.3.4/32", "n": "0.0.0.0", "exist": False}, + {"p": "28.0.0.0/24", "n": "1.1.1.1", "bp": True}, + {"p": "29.0.0.1/32", "n": "1.1.1.1", "bp": True}, {"p": "99.0.0.4/32", "n": "192.168.2.2"}, + {"p": "192.0.0.0/24", "n": "1.1.1.1", "bp": True}, + {"p": "192.168.1.0/24", "n": "1.1.1.1", "bp": True}, ] bgpribRequireUnicastRoutes( - "r4", "ipv4", "r4-cust2", "Customer 2 routes in r4 vrf", want_r4_cust2_routes + "r4", + "ipv4", + "r4-cust2", + "Customer 2 routes in r4 vrf", + want_r4_cust2_routes, + retry=30, ) ######################################################################## @@ -667,7 +726,7 @@ bgpribRequireUnicastRoutes( luCommand( "ce1", 'vtysh -c "show bgp ipv4 uni"', - "12 routes and 12", + "18 routes and 19", "wait", "Local and remote routes", 10, @@ -689,7 +748,7 @@ bgpribRequireUnicastRoutes( luCommand( "ce2", 'vtysh -c "show bgp ipv4 uni"', - "12 routes and 15", + "18 routes and 22", "wait", "Local and remote routes", 10, @@ -721,7 +780,7 @@ luCommand("r4", 'vtysh -c "show ip route vrf r4-cust2"') luCommand( "ce3", 'vtysh -c "show bgp ipv4 uni"', - "12 routes and 13", + "18 routes and 19", "wait", "Local and remote routes", 10, @@ -743,7 +802,7 @@ bgpribRequireUnicastRoutes( luCommand( "ce4", 'vtysh -c "show bgp vrf ce4-cust2 ipv4 uni"', - "12 routes and 14", + "18 routes and 21", "wait", "Local and remote routes", 10, diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf new file mode 100644 index 0000000000..d82a21e1f9 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf @@ -0,0 +1,31 @@ +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + no bgp default ipv4-unicast + neighbor 192.168.12.2 remote-as external + neighbor 192.168.12.2 timers 1 3 + neighbor 192.168.12.2 timers connect 1 + neighbor 2001:db8::12:2 remote-as external + neighbor 2001:db8::12:2 timers 1 3 + neighbor 2001:db8::12:2 timers connect 1 + ! + address-family ipv4 unicast + network 10.0.0.0/31 route-map p1 + network 10.0.0.2/32 route-map p2 + neighbor 192.168.12.2 activate + exit-address-family + address-family ipv6 unicast + network 2001:db8::1/128 route-map p1 + network 2001:db8:1::/56 route-map p2 + neighbor 2001:db8::12:2 activate + exit-address-family +! +route-map p1 permit 10 + set metric 1 +exit +route-map p2 permit 10 + set metric 2 + set origin incomplete +exit +! diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf new file mode 100644 index 0000000000..0807e89d08 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf @@ -0,0 +1,5 @@ +! +interface r1-eth0 + ip address 192.168.12.1/24 + ipv6 address 2001:db8::12:1/64 +! diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf new file mode 100644 index 0000000000..3512e66cec --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf @@ -0,0 +1,23 @@ +! +debug bgp updates +! +router bgp 65002 + no bgp ebgp-requires-policy + no bgp network import-check + no bgp default ipv4-unicast + neighbor 192.168.12.1 remote-as external + neighbor 192.168.12.1 timers 1 3 + neighbor 192.168.12.1 timers connect 1 + neighbor 2001:db8::12:1 remote-as external + neighbor 2001:db8::12:1 timers 1 3 + neighbor 2001:db8::12:1 timers connect 1 + ! + address-family ipv4 unicast + neighbor 192.168.12.1 activate + exit-address-family + address-family ipv6 unicast + neighbor 2001:db8::12:1 activate + exit-address-family +! +agentx +! diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf new file mode 100644 index 0000000000..032b93b676 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf @@ -0,0 +1,17 @@ +agentAddress 127.0.0.1,[::1] + +group public_group v1 public +group public_group v2c public +access public_group "" any noauth prefix all all none + +rocommunity public default + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx + +agentXSocket /etc/frr/agentx +agentXPerms 777 755 root frr diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf new file mode 100644 index 0000000000..db6d7005a0 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf @@ -0,0 +1,5 @@ +! +interface r2-eth0 + ip address 192.168.12.2/24 + ipv6 address 2001:db8::12:2/64 +! diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py new file mode 100755 index 0000000000..53ca10930b --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2022 Donatas Abraitis <donatas@opensourcerouting.org> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test some of the BGP4V2-MIB entries. +""" + +import os +import sys +import json +from time import sleep +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.snmptest import SnmpTester +from lib import topotest + +pytestmark = [pytest.mark.bgpd, pytest.mark.snmp] + + +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): + snmpd = os.system("which snmpd") + if snmpd: + error_msg = "SNMP not installed - skipping" + pytest.skip(error_msg) + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + for rname, router in tgen.routers().items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, "{}/bgpd.conf".format(rname)), + "-M snmp", + ) + router.load_config( + TopoRouter.RD_SNMP, + os.path.join(CWD, "{}/snmpd.conf".format(rname)), + "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX", + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_snmp_bgp4v2(): + tgen = get_topogen() + + r2 = tgen.gears["r2"] + + def _bgp_converge_summary(): + output = json.loads(r2.vtysh_cmd("show bgp summary json")) + expected = { + "ipv4Unicast": { + "peers": { + "192.168.12.1": { + "state": "Established", + "pfxRcd": 2, + } + } + }, + "ipv6Unicast": { + "peers": { + "2001:db8::12:1": { + "state": "Established", + "pfxRcd": 2, + } + } + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge_summary) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see connections established" + + def _bgp_converge_prefixes(): + output = json.loads(r2.vtysh_cmd("show bgp all json")) + expected = { + "ipv4Unicast": { + "routes": { + "10.0.0.0/31": [ + { + "metric": 1, + "origin": "IGP", + } + ], + "10.0.0.2/32": [ + { + "metric": 2, + "origin": "incomplete", + } + ], + } + }, + "ipv6Unicast": { + "routes": { + "2001:db8::1/128": [ + { + "metric": 1, + "origin": "IGP", + } + ], + "2001:db8:1::/56": [ + { + "metric": 2, + "origin": "incomplete", + } + ], + } + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge_prefixes) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see prefixes from R1" + + snmp = SnmpTester(r2, "localhost", "public", "2c", "-Ln -On") + + def _snmpwalk_remote_addr(): + expected = { + "1.3.6.1.3.5.1.1.2.1.5.1.4.192.168.12.1": "C0 A8 0C 01", + "1.3.6.1.3.5.1.1.2.1.5.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "20 01 0D B8 00 00 00 00 00 00 00 00 00 12 00 01", + } + + # bgp4V2PeerRemoteAddr + output, _ = snmp.walk(".1.3.6.1.3.5.1.1.2.1.5") + return output == expected + + _, result = topotest.run_and_expect(_snmpwalk_remote_addr, True, count=10, wait=1) + assertmsg = "Can't fetch SNMP for bgp4V2PeerRemoteAddr" + assert result, assertmsg + + def _snmpwalk_peer_state(): + expected = { + "1.3.6.1.3.5.1.1.2.1.13.1.4.192.168.12.1": "6", + "1.3.6.1.3.5.1.1.2.1.13.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "6", + } + + # bgp4V2PeerState + output, _ = snmp.walk(".1.3.6.1.3.5.1.1.2.1.13") + return output == expected + + _, result = topotest.run_and_expect(_snmpwalk_peer_state, True, count=10, wait=1) + assertmsg = "Can't fetch SNMP for bgp4V2PeerState" + assert result, assertmsg + + def _snmpwalk_peer_last_error_code_received(): + expected = { + "1.3.6.1.3.5.1.1.3.1.1.1.4.192.168.12.1": "0", + "1.3.6.1.3.5.1.1.3.1.1.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "0", + } + + # bgp4V2PeerLastErrorCodeReceived + output, _ = snmp.walk(".1.3.6.1.3.5.1.1.3.1.1") + return output == expected + + _, result = topotest.run_and_expect( + _snmpwalk_peer_last_error_code_received, True, count=10, wait=1 + ) + assertmsg = "Can't fetch SNMP for bgp4V2PeerLastErrorCodeReceived" + assert result, assertmsg + + def _snmpwalk_origin(): + expected = { + "1.3.6.1.3.5.1.1.9.1.9.1.4.10.0.0.0.31.192.168.12.1": "1", + "1.3.6.1.3.5.1.1.9.1.9.1.4.10.0.0.2.32.192.168.12.1": "3", + "1.3.6.1.3.5.1.1.9.1.9.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1", + "1.3.6.1.3.5.1.1.9.1.9.2.16.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "3", + } + + # bgp4V2NlriOrigin + output, _ = snmp.walk(".1.3.6.1.3.5.1.1.9.1.9") + return output == expected + + _, result = topotest.run_and_expect(_snmpwalk_origin, True, count=10, wait=1) + assertmsg = "Can't fetch SNMP for bgp4V2NlriOrigin" + assert result, assertmsg + + def _snmpwalk_med(): + expected = { + "1.3.6.1.3.5.1.1.9.1.17.1.4.10.0.0.0.31.192.168.12.1": "1", + "1.3.6.1.3.5.1.1.9.1.17.1.4.10.0.0.2.32.192.168.12.1": "2", + "1.3.6.1.3.5.1.1.9.1.17.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1", + "1.3.6.1.3.5.1.1.9.1.17.2.16.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "2", + } + + # bgp4V2NlriMed + output, _ = snmp.walk(".1.3.6.1.3.5.1.1.9.1.17") + return output == expected + + _, result = topotest.run_and_expect(_snmpwalk_med, True, count=10, wait=1) + assertmsg = "Can't fetch SNMP for bgp4V2NlriMed" + assert result, assertmsg + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf new file mode 100644 index 0000000000..823a56d53f --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf @@ -0,0 +1,9 @@ +log file zebra.log +! +hostname ce1 +! +interface eth0 + ip address 172.16.0.1/24 +! +line vty +! diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf new file mode 100644 index 0000000000..15779aa0d5 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf @@ -0,0 +1,41 @@ +frr defaults traditional +! +hostname pe1 +password zebra +! +log stdout notifications +log monitor notifications +log commands +! +router bgp 65001 + bgp router-id 192.0.2.1 + ! + segment-routing srv6 + locator default + exit + ! +! +router bgp 65001 vrf vrf10 + bgp router-id 192.0.2.1 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export auto + rd vpn export 65001:10 + rt vpn both 0:10 + import vpn + export vpn + exit-address-family + ! +! +router bgp 65001 vrf vrf20 + bgp router-id 192.0.2.1 + ! + address-family ipv4 unicast + rd vpn export 65001:20 + rt vpn both 0:10 + import vpn + export vpn + exit-address-family + ! +! diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json new file mode 100644 index 0000000000..dc86d7c978 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json @@ -0,0 +1,31 @@ +{ + "vrfName": "default", + "routerId": "192.0.2.1", + "localAS": 65001, + "routes": { + "routeDistinguishers": { + "65001:10": { + "172.16.0.0/24": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "prefix": "172.16.0.0", + "prefixLen": 24, + "network": "172.16.0.0\/24", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "vrf10", + "nexthops": [ + { + "hostname": "pe1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } + } +} diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json new file mode 100644 index 0000000000..ce2d5c19c3 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json @@ -0,0 +1,25 @@ +{ + "vrfName": "vrf10", + "routerId": "192.0.2.1", + "localAS": 65001, + "routes": { + "172.16.0.0/24": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "prefix": "172.16.0.0", + "prefixLen": 24, + "network": "172.16.0.0\/24", + "origin": "incomplete", + "nexthops": [ + { + "hostname": "pe1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json new file mode 100644 index 0000000000..2ce936b291 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json @@ -0,0 +1,22 @@ +{ + "172.16.0.0\/24": [ + { + "prefix": "172.16.0.0\/24", + "prefixLen": 24, + "protocol": "bgp", + "vrfName": "vrf20", + "selected": true, + "destSelected": true, + "installed": true, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "vrf10", + "vrf": "vrf10", + "active": true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json new file mode 100644 index 0000000000..6a88d39a8c --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json @@ -0,0 +1,27 @@ +{ + "vrfName": "vrf20", + "routerId": "192.0.2.1", + "localAS": 65001, + "routes": { + "172.16.0.0/24": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "prefix": "172.16.0.0", + "prefixLen": 24, + "network": "172.16.0.0\/24", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "vrf10", + "nexthops": [ + { + "hostname": "pe1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf new file mode 100644 index 0000000000..52341fc4fc --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf @@ -0,0 +1,27 @@ +log file zebra.log +! +hostname pe1 +! +interface lo + ip address 10.0.0.1/32 +! +interface eth0 vrf vrf10 + ip address 172.16.0.254/24 +! +line vty +! +segment-routing + srv6 + locators + locator default + prefix 2001:db8:2::/64 block-len 40 node-len 24 func-bits 16 + exit + ! + exit + ! + exit + ! +exit +! +end +! diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py new file mode 100755 index 0000000000..16f8adb3c5 --- /dev/null +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python + +# Copyright (c) 2022, LINE Corporation +# Authored by Ryoga Saito <ryoga.saito@linecorp.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import os +import re +import sys +import json +import functools +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.common_config import required_linux_kernel_version + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + tgen.add_router("pe1") + tgen.add_router("ce1") + + tgen.add_link(tgen.gears["pe1"], tgen.gears["ce1"], "eth0", "eth0") + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + for rname, router in tgen.routers().items(): + router.load_config(TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname))) + router.load_config(TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname))) + + tgen.gears["pe1"].run("ip link add vrf10 type vrf table 10") + tgen.gears["pe1"].run("ip link set vrf10 up") + tgen.gears["pe1"].run("ip link add vrf20 type vrf table 20") + tgen.gears["pe1"].run("ip link set vrf20 up") + tgen.gears["pe1"].run("ip link set eth0 master vrf10") + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def open_json_file(path): + try: + with open(path, "r") as f: + return json.load(f) + except IOError: + assert False, "Could not read file {}".format(path) + + +def check(name, command, checker): + tgen = get_topogen() + router = tgen.gears[name] + + def _check(): + try: + return checker(router.vtysh_cmd(command)) + except: + return False + + logger.info('[+] check {} "{}"'.format(name, command)) + _, result = topotest.run_and_expect(_check, None, count=10, wait=0.5) + assert result is None, "Failed" + + +def check_vrf10_bgp_rib(output): + expected = open_json_file("%s/pe1/results/vrf10_ipv4_unicast.json" % CWD) + actual = json.loads(output) + return topotest.json_cmp(actual, expected) + + +def check_default_bgp_vpn_rib(output): + expected = open_json_file("%s/pe1/results/default_ipv4_vpn.json" % CWD) + actual = json.loads(output) + return topotest.json_cmp(actual, expected) + + +def check_vrf20_bgp_rib(output): + expected = open_json_file("%s/pe1/results/vrf20_ipv4_unicast.json" % CWD) + actual = json.loads(output) + return topotest.json_cmp(actual, expected) + + +def check_vrf20_rib(output): + expected = open_json_file("%s/pe1/results/vrf20_ipv4.json" % CWD) + actual = json.loads(output) + return topotest.json_cmp(actual, expected) + + +def test_rib(): + check("pe1", "show bgp vrf vrf10 ipv4 unicast json", check_vrf10_bgp_rib) + check("pe1", "show bgp ipv4 vpn json", check_default_bgp_vpn_rib) + check("pe1", "show bgp vrf vrf20 ipv4 unicast json", check_vrf20_bgp_rib) + check("pe1", "show ip route vrf vrf20 json", check_vrf20_rib) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_unique_rid/bgp_unique_rid.json b/tests/topotests/bgp_unique_rid/bgp_unique_rid.json new file mode 100644 index 0000000000..c42ce29954 --- /dev/null +++ b/tests/topotests/bgp_unique_rid/bgp_unique_rid.json @@ -0,0 +1,505 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:DB8:F::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4": { + "ipv4": "auto", + "ipv6": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r5": { + "ipv4": "auto", + "ipv6": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r4-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {}, + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {}, + "r3-link5": {}, + "r3-link6": {}, + "r3-link7": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {}, + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {}, + "r3-link5": {}, + "r3-link6": {}, + "r3-link7": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + }, + "ospf": { + "router_id": "100.1.1.3", + "neighbors": { + "r4": {}, + "r5": {} + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "r4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {}, + "r4-link1": {}, + "r4-link2": {}, + "r4-link3": {}, + "r4-link4": {}, + "r4-link5": {}, + "r4-link6": {}, + "r4-link7": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {}, + "r4-link1": {}, + "r4-link2": {}, + "r4-link3": {}, + "r4-link4": {}, + "r4-link5": {}, + "r4-link6": {}, + "r4-link7": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } + }, + "ospf": { + "router_id": "10.10.10.10", + "neighbors": { + "r3": {} + } + } + }, + "r5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } + }, + "ospf": { + "router_id": "100.1.1.5", + "neighbors": { + "r3": {} + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/bgp_unique_rid/bgp_unique_rid_vrf.json b/tests/topotests/bgp_unique_rid/bgp_unique_rid_vrf.json new file mode 100644 index 0000000000..1e280f1847 --- /dev/null +++ b/tests/topotests/bgp_unique_rid/bgp_unique_rid_vrf.json @@ -0,0 +1,529 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:DB8:F::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback", + "vrf": "GREEN" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "GREEN" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "GREEN" + } + }, + "bgp": [ + { + "local_as": "100", + "vrf": "GREEN", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } + } + ], + "vrfs": [ + { + "name": "GREEN", + "id": "1" + } + ] + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback", + "vrf": "GREEN" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "GREEN" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "GREEN" + } + }, + "bgp": [ + { + "local_as": "100", + "vrf": "GREEN", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } + } + ], + "vrfs": [ + { + "name": "GREEN", + "id": "1" + } + ] + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback", + "vrf": "GREEN" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "GREEN" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "GREEN" + }, + "r4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r5": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "RED" + }, + "r4-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": [ + { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3": {}, + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {}, + "r3-link5": {}, + "r3-link6": {}, + "r3-link7": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3": {}, + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {}, + "r3-link5": {}, + "r3-link6": {}, + "r3-link7": {} + } + } + } + } + } + } + }, + { + "local_as": "100", + "vrf": "GREEN", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + }, + { + "local_as": "100", + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + ], + "vrfs": [ + { + "name": "RED", + "id": "1" + }, + { + "name": "GREEN", + "id": "2" + } + ] + }, + "r4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": [{ + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {}, + "r4-link1": {}, + "r4-link2": {}, + "r4-link3": {}, + "r4-link4": {}, + "r4-link5": {}, + "r4-link6": {}, + "r4-link7": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {}, + "r4-link1": {}, + "r4-link2": {}, + "r4-link3": {}, + "r4-link4": {}, + "r4-link5": {}, + "r4-link6": {}, + "r4-link7": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } + }] + }, + "r5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback", + "vrf": "RED" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "RED" + } + }, + "bgp": [ + { + "local_as": "300", + "vrf":"RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + }, + { + "redist_type": "connected" + } + ] + } + } + } + } + ], + "vrfs": [ + { + "name": "RED", + "id": "1" + } + ] + } + } +}
\ No newline at end of file diff --git a/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py b/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py new file mode 100644 index 0000000000..7156310536 --- /dev/null +++ b/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py @@ -0,0 +1,906 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2022 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import sys +import time +import pytest +import inspect +import os +from copy import deepcopy + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +"""Following tests are covered to test bgp unique rid functionality. +1. Verify eBGP session when same and different router ID is configured. +2. Verify iBGP session when same and different router ID is configured. +3. Verify two different eBGP sessions initiated with same router ID. +4. Chaos - Verify bgp unique rid functionality in chaos scenarios. +5. Chaos - Verify bgp unique rid functionality when router reboots with same loopback id. +6. Chaos - Verify bgp unique rid functionality when router reboots without any ip addresses. +""" + +################################# +# TOPOLOGY +################################# +""" + + +-------+ + +--------- | R2 | + | +-------+ + |iBGP | + +-------+ | + | R1 | |iBGP + +-------+ | + | | + | iBGP +-------+ eBGP +-------+ + +---------- | R3 |========= | R4 | + +-------+ +-------+ + | + |eBGP + | + +-------+ + | R5 | + +-------+ + + +""" + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topojson import build_config_from_json +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd, pytest.mark.staticd] + +# Required to instantiate the topology builder class. +from lib.common_config import ( + start_topology, + write_test_header, + step, + write_test_footer, + verify_rib, + check_address_types, + reset_config_on_routers, + check_router_status, + stop_router, + kill_router_daemons, + start_router_daemons, + start_router, +) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, + create_router_bgp, + clear_bgp_and_verify, +) + +# Global variables +topo = None +bgp_convergence = False +NETWORK = { + "ipv4": [ + "192.168.20.1/32", + "192.168.20.2/32", + "192.168.21.1/32", + "192.168.21.2/32", + "192.168.22.1/32", + "192.168.22.2/32", + ], + "ipv6": [ + "fc07:50::1/128", + "fc07:50::2/128", + "fc07:150::1/128", + "fc07:150::2/128", + "fc07:1::1/128", + "fc07:1::2/128", + ], +} + +bgp_convergence = False +ADDR_TYPES = check_address_types() +routerid = {"ipv4": "10.10.10.14", "ipv6": "fd00:0:0:3::2"} + + +def setup_module(mod): + """setup_module. + + Set up the pytest environment + * `mod`: module name + """ + global topo + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_unique_rid.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start daemons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Checking BGP convergence + global bgp_convergence + global ADDR_TYPES + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "setup_module :Failed \n Error:" " {}".format( + bgp_convergence + ) + logger.info("Running setup_module() done") + + +def teardown_module(): + """Teardown the pytest environment""" + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +##################################################### +# Tests starting +##################################################### + + +def test_bgp_unique_rid_ebgp_p0(): + """ + TC: 1 + Verify eBGP session when same and different router ID is configured. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip("skipped because of BGP Convergence failure") + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Configure base config as per the topology") + reset_config_on_routers(tgen) + + step( + "Base config should be up, verify using BGP convergence on all \ + the routers for IPv4 and IPv6 nbrs" + ) + + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Configure the same router id between R4 and R3 10.10.10.10") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10"}}, + "r4": {"bgp": {"router_id": "10.10.10.10"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Configure the same router id between R5 and R3 (10.10.10.10)") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10"}}, + "r5": {"bgp": {"router_id": "10.10.10.10"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("modify the router id on r3 to different router id (11.11.11.11)") + input_dict = {"r3": {"bgp": {"router_id": "11.11.11.11"}}} + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Reset bgp process") + step("Verify neighbours are in ESTAB state.") + dut = "r3" + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Clear ip bgp process with *") + step("Verify neighbours are in ESTAB state.") + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbours between R3 and R4 in EVPN address family.") + input_dict = { + "r3": { + "bgp": { + "address_family": { + "l2vpn": { + "evpn": { + "advertise": { + "ipv4": {"unicast": {}}, + "ipv6": {"unicast": {}}, + } + } + } + } + } + }, + "r4": { + "bgp": { + "address_family": { + "l2vpn": { + "evpn": { + "advertise": { + "ipv4": {"unicast": {}}, + "ipv6": {"unicast": {}}, + } + } + } + } + } + }, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_bgp_unique_rid_ibgp_p0(): + """ + TC: 2 + Verify iBGP session when same and different router ID is configured. + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip("skipped because of BGP Convergence failure") + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Configure base config as per the topology") + reset_config_on_routers(tgen) + + step( + "Base config should be up, verify using BGP convergence on all \ + the routers for IPv4 and IPv6 nbrs" + ) + + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Configure the same router id between R1 and R3 (10.10.10.10)") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10"}}, + "r1": {"bgp": {"router_id": "10.10.10.10"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in idle state.") + result = verify_bgp_convergence(tgen, topo, expected=False) + assert result is not True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + + step("Configure the same router id between R2 and R3 (10.10.10.10)") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10"}}, + "r2": {"bgp": {"router_id": "10.10.10.10"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in idle state.") + result = verify_bgp_convergence(tgen, topo, expected=False) + assert result is not True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + + step("modify the router id on r3 to different router id (11.11.11.11)") + input_dict = {"r3": {"bgp": {"router_id": "11.11.11.11"}}} + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo, dut="r3") + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Reset bgp process") + step("Verify neighbours are in ESTAB state.") + dut = "r3" + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Clear ip bgp process with *") + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_bgp_unique_rid_multi_bgp_nbrs_p0(): + """ + TC: 3 + 3. Verify two different eBGP sessions initiated with same router ID + + """ + tgen = get_topogen() + global bgp_convergence, topo + + if bgp_convergence is not True: + pytest.skip("skipped because of BGP Convergence failure") + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Configure base config as per the topology") + reset_config_on_routers(tgen) + + step( + "Base config should be up, verify using BGP convergence on all \ + the routers for IPv4 and IPv6 nbrs" + ) + + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Configure the same router id between R3, R4 and R5 (10.10.10.10)") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10"}}, + "r4": {"bgp": {"router_id": "10.10.10.10"}}, + "r5": {"bgp": {"router_id": "10.10.10.10"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Configure the same IP address on on R4 and R5 loopback address and \ + change the neighborship to loopback neighbours between R3 to R4 \ + and R3 to R5 respectively." + ) + + topo1 = deepcopy(topo) + + for rtr in ["r4", "r5"]: + topo1["routers"][rtr]["links"]["lo"]["ipv4"] = "192.168.1.1/32" + + topo1["routers"]["r3"]["links"]["lo"]["ipv4"] = "192.168.1.3/32" + build_config_from_json(tgen, topo1, save_bkup=False) + + step( + "change the neighborship to loopback neighbours between R3 to R4 and R3 to R5 respectively." + ) + for rtr in ["r4", "r5"]: + configure_bgp_on_rtr = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": {"neighbor": {rtr: {"dest_link": {"lo": {}}}}} + } + } + }, + } + } + result = create_router_bgp(tgen, topo1, configure_bgp_on_rtr) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + bgp_convergence = verify_bgp_convergence(tgen, topo1, dut="r3") + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step("Change the IP address on the R4 loopback.") + topo1["routers"]["r4"]["links"]["lo"]["ipv4"] = "192.168.1.4/32" + build_config_from_json(tgen, topo1, save_bkup=False) + + step("Verify neighbours should be again in ESTAB state. (show ip bgp neighbours)") + bgp_convergence = verify_bgp_convergence(tgen, topo1, dut="r3") + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step("Clear ip bgp process with *") + result = clear_bgp_and_verify(tgen, topo, router="r3") + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_bgp_unique_rid_chaos1_p2(): + """ + TC: 4 + 4. Chaos - Verify bgp unique rid functionality in chaos scenarios. + + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip("skipped because of BGP Convergence failure") + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Configure base config as per the topology") + reset_config_on_routers(tgen) + + step( + "Base config should be up, verify using BGP convergence on all \ + the routers for IPv4 and IPv6 nbrs" + ) + + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Configure the same router id between R3, R4 and R5 (10.10.10.10)") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10"}}, + "r4": {"bgp": {"router_id": "10.10.10.10"}}, + "r5": {"bgp": {"router_id": "10.10.10.10"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify eBGP session when same router ID is configured and bgpd process is restarted" + ) + + # restart bgpd router and verify + kill_router_daemons(tgen, "r3", ["bgpd"]) + start_router_daemons(tgen, "r3", ["bgpd"]) + + step( + "The session should be established between R3 & R4. " + "Once after restart bgp, neighbor should come back up ." + ) + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step( + "Verify eBGP session when same router ID is configured and neighbor shutdown is issued and again no shutdown." + ) + + input_dict = { + "r3": { + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3-link1": {"shutdown": True}, + "r3-link2": {"shutdown": True}, + "r3-link3": {"shutdown": True}, + "r3-link4": {"shutdown": True}, + "r3-link5": {"shutdown": True}, + "r3-link6": {"shutdown": True}, + "r3-link7": {"shutdown": True}, + } + }, + "r5": {"dest_link": {"r3": {"shutdown": True}}}, + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3-link1": {"shutdown": True}, + "r3-link2": {"shutdown": True}, + "r3-link3": {"shutdown": True}, + "r3-link4": {"shutdown": True}, + "r3-link5": {"shutdown": True}, + "r3-link6": {"shutdown": True}, + "r3-link7": {"shutdown": True}, + } + }, + "r5": {"dest_link": {"r3": {"shutdown": True}}}, + } + } + }, + }, + } + } + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + input_dict = { + "r3": { + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3-link1": {"shutdown": False}, + "r3-link2": {"shutdown": False}, + "r3-link3": {"shutdown": False}, + "r3-link4": {"shutdown": False}, + "r3-link5": {"shutdown": False}, + "r3-link6": {"shutdown": False}, + "r3-link7": {"shutdown": False}, + } + }, + "r5": {"dest_link": {"r3": {"shutdown": False}}}, + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3-link1": {"shutdown": False}, + "r3-link2": {"shutdown": False}, + "r3-link3": {"shutdown": False}, + "r3-link4": {"shutdown": False}, + "r3-link5": {"shutdown": False}, + "r3-link6": {"shutdown": False}, + "r3-link7": {"shutdown": False}, + } + }, + "r5": {"dest_link": {"r3": {"shutdown": False}}}, + } + } + }, + }, + } + } + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "The session should be established between R3 & R4. " + "Once after restart bgp, neighbor should come back up ." + ) + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step( + "Verify eBGP session when same router ID is configured and neighbor config is deleted & reconfigured." + ) + + input_dict = { + "r3": { + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {}, + "r3-link5": {}, + "r3-link6": {}, + "r3-link7": {}, + } + }, + "r5": {"dest_link": {"r3": {}}}, + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {}, + "r3-link5": {}, + "r3-link6": {}, + "r3-link7": {}, + } + }, + "r5": {"dest_link": {"r3": {}}}, + } + } + }, + }, + } + } + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "The session should be established between R3 & R4. " + "Once after restart bgp, neighbor should come back up ." + ) + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step( + "Verify eBGP session when same router ID is configured and FRR router is restarted." + ) + stop_router(tgen, "r3") + start_router(tgen, "r3") + + step( + "The session should be established between R3 & R4. " + "Once after restart bgp, neighbor should come back up ." + ) + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step( + "Verify eBGP session when same router ID is configured and zebra process is restarted" + ) + + kill_router_daemons(tgen, "r3", ["zebra"]) + start_router_daemons(tgen, "r3", ["zebra"]) + + step( + "The session should be established between R3 & R4. " + "Once after restart bgp, neighbor should come back up ." + ) + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + write_test_footer(tc_name) + + +def test_bgp_unique_rid_chaos3_p2(): + """ + TC: 4 + 4. Chaos - Verify bgp unique rid functionality when router reboots with same loopback id. + + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip("skipped because of BGP Convergence failure") + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Configure base config as per the topology") + reset_config_on_routers(tgen) + + global topo + topo1 = deepcopy(topo) + + for rtr in topo["routers"].keys(): + topo1["routers"][rtr]["links"]["lo"]["ipv4"] = "192.168.1.1/32" + + topo1["routers"]["r3"]["links"]["lo"]["ipv4"] = "192.168.1.3/32" + build_config_from_json(tgen, topo1, save_bkup=False) + + step("verify bgp convergence before starting test case") + + bgp_convergence = verify_bgp_convergence(tgen, topo1) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step( + "Configure loopback on R1 to R5 with IP address 1.1.1.1 on all the routers. Change neighborship on all the routers using loopback neighborship ids." + ) + for rtr in ["r1", "r2", "r4", "r5"]: + configure_bgp_on_rtr = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": {"neighbor": {rtr: {"dest_link": {"lo": {}}}}} + } + } + }, + } + } + result = create_router_bgp(tgen, topo1, configure_bgp_on_rtr) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + bgp_convergence = verify_bgp_convergence(tgen, topo1, dut="r3") + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step("Reboot the router (restart frr) or using watch frr.") + stop_router(tgen, "r3") + start_router(tgen, "r3") + + step("Neighbors between R3, R4 and R3 to R5 should be in ESTB state.") + bgp_convergence = verify_bgp_convergence(tgen, topo1, dut="r3") + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step("Clear bgp process.") + clear_bgp_and_verify(tgen, topo, "r3") + + step("Neighbors between R3, R4 and R3 to R5 should be in ESTB state.") + bgp_convergence = verify_bgp_convergence(tgen, topo1, dut="r3") + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + write_test_footer(tc_name) + + +def test_bgp_unique_rid_chaos4_p2(): + """ + TC: 6 + 6. Chaos - Verify bgp unique rid functionality when router reboots without any ip addresses. + + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip("skipped because of BGP Convergence failure") + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + + reset_config_on_routers(tgen) + + global topo + topo1 = deepcopy(topo) + topo2 = deepcopy(topo) + + step( + "Configure base config as per the topology without loopback as well as Ip address on any of the interface." + ) + for rtr in topo["routers"].keys(): + for intf in topo["routers"][rtr]["links"].keys(): + topo1["routers"][rtr]["links"][intf].pop("ipv4") + topo1["routers"][rtr]["links"][intf].pop("ipv6") + if intf is "lo": + topo1["routers"][rtr]["links"][intf].pop("ipv4") + + build_config_from_json(tgen, topo1, save_bkup=False) + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step("Configure the ip addresses on the physical interfaces") + build_config_from_json(tgen, topo2, save_bkup=False) + + step("All the neighbors should be in ESTAB state.") + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step("Configure loopback addresses with higher IP address ") + build_config_from_json(tgen, topo, save_bkup=False) + + step("All the neighbors should be in ESTAB state.") + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step("Reboot the router (restart frr) or using watch frr.") + stop_router(tgen, "r3") + start_router(tgen, "r3") + + step("Neighbors between R3, R4 and R3 to R5 should be in ESTB state.") + bgp_convergence = verify_bgp_convergence(tgen, topo, dut="r3") + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_unique_rid/test_bgp_unique_rid_vrf.py b/tests/topotests/bgp_unique_rid/test_bgp_unique_rid_vrf.py new file mode 100644 index 0000000000..e009efee87 --- /dev/null +++ b/tests/topotests/bgp_unique_rid/test_bgp_unique_rid_vrf.py @@ -0,0 +1,479 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2022 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import sys +import time +import pytest +import inspect +import os +from copy import deepcopy + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +"""Following tests are covered to test bgp unique rid functionality. +1. Verify iBGP session when same and different router ID is configured in user VRF(GREEN). +2. Verify eBGP session when same and different router ID is configured in user vrf (VRF RED) +3. Verify two different eBGP sessions initiated with same router ID in user VRf (RED and GREEN) +""" + +################################# +# TOPOLOGY +################################# +""" + + +-------+ + +--------- | R2 | + | +-------+ + |iBGP | + +-------+ | + | R1 | |iBGP + +-------+ | + | | + | iBGP +-------+ eBGP +-------+ + +---------- | R3 |========= | R4 | + +-------+ +-------+ + | + |eBGP + | + +-------+ + | R5 | + +-------+ + + +""" + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topojson import build_config_from_json +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + +# Required to instantiate the topology builder class. +from lib.common_config import ( + start_topology, + write_test_header, + step, + write_test_footer, + check_address_types, + reset_config_on_routers, + check_router_status, +) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, + create_router_bgp, + clear_bgp_and_verify, +) + +# Global variables +topo = None +bgp_convergence = False +NETWORK = { + "ipv4": [ + "192.168.20.1/32", + "192.168.20.2/32", + "192.168.21.1/32", + "192.168.21.2/32", + "192.168.22.1/32", + "192.168.22.2/32", + ], + "ipv6": [ + "fc07:50::1/128", + "fc07:50::2/128", + "fc07:150::1/128", + "fc07:150::2/128", + "fc07:1::1/128", + "fc07:1::2/128", + ], +} + +bgp_convergence = False +ADDR_TYPES = check_address_types() + + +def setup_module(mod): + """setup_module. + + Set up the pytest environment + * `mod`: module name + """ + global topo + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_unique_rid_vrf.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start daemons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Checking BGP convergence + global bgp_convergence + global ADDR_TYPES + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "setup_module :Failed \n Error:" " {}".format( + bgp_convergence + ) + logger.info("Running setup_module() done") + + +def teardown_module(): + """Teardown the pytest environment""" + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +##################################################### +# Tests starting +##################################################### + + +def test_bgp_unique_rid_ebgp_vrf_p0(): + """ + TC: 1 + Verify iBGP session when same and different router ID is configured in user VRF(GREEN). + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip("skipped because of BGP Convergence failure") + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Configure base config as per the topology") + reset_config_on_routers(tgen) + + step( + "Base config should be up, verify using BGP convergence on all \ + the routers for IPv4 and IPv6 nbrs" + ) + + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Configure the same router id between R4 and R3 10.10.10.10") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10", "local_as": 100, "vrf": "RED"}}, + "r4": {"bgp": {"router_id": "10.10.10.10", "local_as": 200, "vrf": "RED"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Configure the same router id between R5 and R3 (10.10.10.10)") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10", "local_as": 100, "vrf": "RED"}}, + "r5": {"bgp": {"router_id": "10.10.10.10", "local_as": 300, "vrf": "RED"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("modify the router id on r3 to different router id (11.11.11.11)") + input_dict = { + "r3": {"bgp": {"router_id": "11.11.11.11", "local_as": 100, "vrf": "RED"}} + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Reset bgp process") + step("Verify neighbours are in ESTAB state.") + dut = "r3" + result = clear_bgp_and_verify(tgen, topo, router="r3") + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Clear ip bgp process with *") + step("Verify neighbours are in ESTAB state.") + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbours between R3 and R4 in EVPN address family.") + input_dict = { + "r3": { + "bgp": { + "local_as": 100, + "vrf": "RED", + "address_family": { + "l2vpn": { + "evpn": { + "advertise": { + "ipv4": {"unicast": {}}, + "ipv6": {"unicast": {}}, + } + } + } + }, + } + }, + "r4": { + "bgp": { + "local_as": 200, + "vrf": "RED", + "address_family": { + "l2vpn": { + "evpn": { + "advertise": { + "ipv4": {"unicast": {}}, + "ipv6": {"unicast": {}}, + } + } + } + }, + } + }, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_bgp_unique_rid_ibgp_vrf_p0(): + """ + TC: 2 + Verify eBGP session when same and different router ID is configured in user vrf (VRF RED) + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip("skipped because of BGP Convergence failure") + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Configure base config as per the topology") + reset_config_on_routers(tgen) + + step( + "Base config should be up, verify using BGP convergence on all \ + the routers for IPv4 and IPv6 nbrs" + ) + + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Configure the same router id between R1 and R3 (10.10.10.10)") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10", "local_as": 100, "vrf": "RED"}}, + "r1": {"bgp": {"router_id": "10.10.10.10", "local_as": 100, "vrf": "RED"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Configure the same router id between R2 and R3 (10.10.10.10)") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10", "local_as": 100, "vrf": "RED"}}, + "r2": {"bgp": {"router_id": "10.10.10.10", "local_as": 100, "vrf": "RED"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("modify the router id on r3 to different router id (11.11.11.11)") + input_dict = { + "r3": {"bgp": {"router_id": "11.11.11.11", "local_as": 100, "vrf": "RED"}} + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo, dut="r3") + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Reset bgp process") + step("Verify neighbours are in ESTAB state.") + dut = "r3" + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Clear ip bgp process with *") + result = clear_bgp_and_verify(tgen, topo, dut) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_bgp_unique_rid_multi_bgp_nbrs_vrf_p0(): + """ + TC: 3 + Verify two different eBGP sessions initiated with same router ID in user VRf (RED and GREEN) + + """ + tgen = get_topogen() + global bgp_convergence, topo + + if bgp_convergence is not True: + pytest.skip("skipped because of BGP Convergence failure") + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Configure base config as per the topology") + reset_config_on_routers(tgen) + + step( + "Base config should be up, verify using BGP convergence on all \ + the routers for IPv4 and IPv6 nbrs" + ) + + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Configure the same router id between R3, R4 and R5 (10.10.10.10)") + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10", "local_as": 100, "vrf": "RED"}}, + "r4": {"bgp": {"router_id": "10.10.10.10", "local_as": 200, "vrf": "RED"}}, + "r5": {"bgp": {"router_id": "10.10.10.10", "local_as": 300, "vrf": "RED"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify neighbours are in ESTAB state.") + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Configure the same IP address on on R4 and R5 loopback address and \ + change the neighborship to loopback neighbours between R3 to R4 \ + and R3 to R5 respectively." + ) + + topo1 = deepcopy(topo) + + for rtr in ["r4", "r5"]: + topo1["routers"][rtr]["links"]["lo"]["ipv4"] = "192.168.1.1/32" + + topo1["routers"]["r3"]["links"]["lo"]["ipv4"] = "192.168.1.3/32" + build_config_from_json(tgen, topo1, save_bkup=False) + + step( + "change the neighborship to loopback neighbours between R3 to R4 and R3 to R5 respectively." + ) + for rtr in ["r4", "r5"]: + configure_bgp_on_rtr = { + "r3": { + "bgp": { + "local_as": 100, + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": {"neighbor": {rtr: {"dest_link": {"lo": {}}}}} + } + }, + }, + } + } + result = create_router_bgp(tgen, topo1, configure_bgp_on_rtr) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + bgp_convergence = verify_bgp_convergence(tgen, topo1, dut="r3") + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step("Change the IP address on the R4 loopback.") + topo1["routers"]["r4"]["links"]["lo"]["ipv4"] = "192.168.1.4/32" + build_config_from_json(tgen, topo1, save_bkup=False) + + step("Verify neighbours should be again in ESTAB state. (show ip bgp neighbours)") + bgp_convergence = verify_bgp_convergence(tgen, topo1, dut="r3") + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step("Clear ip bgp process with *") + result = clear_bgp_and_verify(tgen, topo, router="r3") + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf index 03dfbf9322..0540a62096 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf +++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf @@ -1,5 +1,11 @@ hostname r1 + +#debug bgp vpn leak-to-vrf +#debug bgp vpn leak-from-vrf +#debug bgp nht + + router bgp 99 vrf DONNA no bgp ebgp-requires-policy address-family ipv4 unicast diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf index 35038557df..731a00829d 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf +++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf @@ -16,3 +16,9 @@ int dummy4 ip address 10.0.3.1/24 no shut ! +int EVA + no shut +! +int DONNA + no shut +! 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 191a0b53ec..be07c85997 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 @@ -29,6 +29,7 @@ import os import sys from functools import partial import pytest +import time CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -77,7 +78,117 @@ def teardown_module(mod): tgen.stop_topology() -def test_vrf_route_leak(): +def check_bgp_rib(router, vrf, in_fib): + if in_fib: + attr = [{"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}] + else: + attr = [{"protocol": "bgp", "nexthops": []}] + + if vrf == "DONNA": + expect = { + "10.0.0.0/24": [ + { + "protocol": "connected", + } + ], + "10.0.1.0/24": attr, + "10.0.2.0/24": [{"protocol": "connected"}], + "10.0.3.0/24": attr, + } + else: + expect = { + "10.0.0.0/24": attr, + "10.0.1.0/24": [ + { + "protocol": "connected", + } + ], + "10.0.2.0/24": attr, + "10.0.3.0/24": [ + { + "protocol": "connected", + } + ], + } + + test_func = partial( + topotest.router_json_cmp, router, "show ip route vrf %s json" % vrf, expect + ) + return topotest.run_and_expect(test_func, None, count=10, wait=0.5) + + +def check_bgp_fib(router, vrf, in_rib): + # Check FIB + # DONNA + # 10.0.1.0/24 dev EVA proto bgp metric 20 + # 10.0.3.0/24 dev EVA proto bgp metric 20 + # EVA + # 10.0.0.0/24 dev DONNA proto bgp metric 20 + # 10.0.2.0/24 dev DONNA proto bgp metric 20 + + if vrf == "DONNA": + table = 1001 + nh_vrf = "EVA" + else: + table = 1002 + nh_vrf = "DONNA" + + negate = "" if in_rib else "! " + + cmd = "%sip route show table %s | grep %s" % (negate, table, nh_vrf) + result = False + retry = 5 + output = "" + while retry: + retry -= 1 + try: + output = router.cmd_raises(cmd) + result = True + break + except: + time.sleep(0.1) + + logger.info("VRF %s leaked FIB content %s: %s", vrf, cmd, output) + + return result, output + + +def check_bgp_ping(router, vrf): + if vrf == "DONNA": + cmd = "ip vrf exec DONNA ping -c1 10.0.1.1 -I 10.0.0.1" + else: + cmd = "ip vrf exec EVA ping -c1 10.0.0.1 -I 10.0.1.1" + + result = False + retry = 5 + output = "" + while retry: + retry -= 1 + try: + output = router.cmd_raises(cmd) + result = True + break + except: + time.sleep(0.1) + + return result, output + + +def check_bgp_ping_own_ip(router): + cmd = "ip vrf exec DONNA ping -c1 10.0.0.1 -I 10.0.0.1" + + output = "" + try: + output = router.cmd_raises(cmd) + result = True + except: + result = False + pass + + return result, output + + +def test_vrf_route_leak_test1(): logger.info("Ensure that routes are leaked back and forth") tgen = get_topogen() # Don't run this test if we have any failure. @@ -86,53 +197,86 @@ def test_vrf_route_leak(): r1 = tgen.gears["r1"] - # Test DONNA VRF. - expect = { - "10.0.0.0/24": [ - { - "protocol": "connected", - } - ], - "10.0.1.0/24": [ - {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} - ], - "10.0.2.0/24": [{"protocol": "connected"}], - "10.0.3.0/24": [ - {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} - ], - } - - test_func = partial( - topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + result, output = check_bgp_ping_own_ip(r1) + assert ( + result + ), "Ping from VRF fails - check https://bugzilla.kernel.org/show_bug.cgi?id=203483\n:{}".format( + output ) - result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) - assert result, "BGP VRF DONNA check failed:\n{}".format(diff) - - # Test EVA VRF. - expect = { - "10.0.0.0/24": [ - {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} - ], - "10.0.1.0/24": [ - { - "protocol": "connected", - } - ], - "10.0.2.0/24": [ - {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} - ], - "10.0.3.0/24": [ - { - "protocol": "connected", - } - ], - } - test_func = partial( - topotest.router_json_cmp, r1, "show ip route vrf EVA json", expect + for vrf in ["EVA", "DONNA"]: + result, diff = check_bgp_rib(r1, vrf, True) + assert result, "BGP RIB VRF {} check failed:\n{}".format(vrf, diff) + result, output = check_bgp_fib(r1, vrf, True) + assert result, "BGP FIB VRF {} check failed:\n{}".format(vrf, output) + result, output = check_bgp_ping(r1, vrf) + assert result, "Ping from VRF {} failed:\n{}".format(vrf, output) + + +def test_vrf_route_leak_test2(): + logger.info( + "Ensure that leaked are still present after VRF iface IP address deletion" ) - result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) - assert result, "BGP VRF EVA check failed:\n{}".format(diff) + 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"] + + logger.info("Adding and removing an IPv4 address to EVA and DONNA VRF ifaces") + r1.cmd("ip address add 1.1.1.1/32 dev EVA && ip address del 1.1.1.1/32 dev EVA") + r1.cmd("ip address add 2.2.2.2/32 dev DONNA && ip address del 2.2.2.2/32 dev DONNA") + + for vrf in ["EVA", "DONNA"]: + result, diff = check_bgp_rib(r1, vrf, True) + assert result, "BGP RIB VRF {} check failed:\n{}".format(vrf, diff) + result, output = check_bgp_fib(r1, vrf, True) + assert result, "BGP FIB VRF {} check failed:\n{}".format(vrf, output) + result, output = check_bgp_ping(r1, vrf) + assert result, "Ping from VRF {} failed:\n{}".format(vrf, output) + + +def test_vrf_route_leak_test3(): + logger.info("Ensure that setting down the VRF ifaces invalidates leaked routes") + 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"] + + logger.info("Setting down EVA and DONNA VRF ifaces") + r1.cmd("ip link set EVA down") + r1.cmd("ip link set DONNA down") + + for vrf in ["EVA", "DONNA"]: + result, diff = check_bgp_rib(r1, vrf, False) + assert result, "BGP RIB VRF {} check failed:\n{}".format(vrf, diff) + result, output = check_bgp_fib(r1, vrf, False) + assert result, "BGP FIB VRF {} check failed:\n{}".format(vrf, output) + + +def test_vrf_route_leak_test4(): + logger.info("Ensure that setting up the VRF ifaces validates leaked routes") + 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"] + + logger.info("Setting up EVA and DONNA VRF ifaces") + r1.cmd("ip link set EVA up") + r1.cmd("ip link set DONNA up") + + for vrf in ["EVA", "DONNA"]: + result, diff = check_bgp_rib(r1, vrf, True) + assert result, "BGP RIB VRF {} check failed:\n{}".format(vrf, diff) + result, output = check_bgp_fib(r1, vrf, True) + assert result, "BGP FIB VRF {} check failed:\n{}".format(vrf, output) + result, output = check_bgp_ping(r1, vrf) + assert result, "Ping from VRF {} failed:\n{}".format(vrf, output) def test_memory_leak(): diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index a09b0b8b2e..2be0f5773b 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -1909,7 +1909,7 @@ def clear_bgp(tgen, addr_type, router, vrf=None, neighbor=None): logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) -def clear_bgp_and_verify(tgen, topo, router): +def clear_bgp_and_verify(tgen, topo, router, rid=None): """ This API is to clear bgp neighborship and verify bgp neighborship is coming up(BGP is converged) usinf "show bgp summary json" command @@ -1959,7 +1959,11 @@ def clear_bgp_and_verify(tgen, topo, router): return errormsg # To find neighbor ip type - bgp_addr_type = topo["routers"][router]["bgp"]["address_family"] + try: + bgp_addr_type = topo["routers"][router]["bgp"]["address_family"] + except TypeError: + bgp_addr_type = topo["routers"][router]["bgp"][0]["address_family"] + total_peer = 0 for addr_type in bgp_addr_type.keys(): @@ -2019,10 +2023,15 @@ def clear_bgp_and_verify(tgen, topo, router): logger.info("Clearing BGP neighborship for router %s..", router) for addr_type in bgp_addr_type.keys(): if addr_type == "ipv4": - run_frr_cmd(rnode, "clear ip bgp *") + if rid: + run_frr_cmd(rnode, "clear bgp ipv4 {}".format(rid)) + else: + run_frr_cmd(rnode, "clear bgp ipv4 *") elif addr_type == "ipv6": - run_frr_cmd(rnode, "clear bgp ipv6 *") - + if rid: + run_frr_cmd(rnode, "clear bgp ipv6 {}".format(rid)) + else: + run_frr_cmd(rnode, "clear bgp ipv6 *") peer_uptime_after_clear_bgp = {} # Verifying BGP convergence after bgp clear command for retry in range(50): @@ -2042,7 +2051,11 @@ def clear_bgp_and_verify(tgen, topo, router): return errormsg # To find neighbor ip type - bgp_addr_type = topo["routers"][router]["bgp"]["address_family"] + try: + bgp_addr_type = topo["routers"][router]["bgp"]["address_family"] + except TypeError: + bgp_addr_type = topo["routers"][router]["bgp"][0]["address_family"] + total_peer = 0 for addr_type in bgp_addr_type.keys(): if not check_address_types(addr_type): @@ -2797,7 +2810,11 @@ def verify_best_path_as_per_admin_distance( if route in rib_routes_json: st_found = True # Verify next_hop in rib_routes_json - if [nh for nh in rib_routes_json[route][0]["nexthops"] if nh['ip'] == _next_hop]: + if [ + nh + for nh in rib_routes_json[route][0]["nexthops"] + if nh["ip"] == _next_hop + ]: nh_found = True else: errormsg = ( diff --git a/tests/topotests/lib/bgprib.py b/tests/topotests/lib/bgprib.py index 35a57d0a99..01439373c5 100644 --- a/tests/topotests/lib/bgprib.py +++ b/tests/topotests/lib/bgprib.py @@ -37,6 +37,7 @@ from lib.lutil import luCommand, luResult, LUtil import json import re +import time # gpz: get rib in json form and compare against desired routes class BgpRib: @@ -48,7 +49,15 @@ class BgpRib: for pfx in pfxtbl.keys(): if debug: self.log("trying pfx %s" % pfx) - if pfx != want["p"]: + if "exist" in want and want["exist"] == False: + if pfx == want["p"]: + if debug: + self.log("unexpected route: pfx=" + want["p"]) + return 0 + if debug: + self.log("unwant pfx=" + want["p"] + ", not " + pfx) + continue + elif pfx != want["p"]: if debug: self.log("want pfx=" + want["p"] + ", not " + pfx) continue @@ -75,53 +84,67 @@ class BgpRib: if debug: self.log("missing route: pfx=" + want["p"] + ", nh=" + want["n"]) return 0 + if "exist" in want and want["exist"] == False: + return 1 + return 0 - def RequireVpnRoutes(self, target, title, wantroutes, debug=0): + def RequireVpnRoutes(self, target, title, wantroutes, retry=0, wait=1, debug=0): import json logstr = "RequireVpnRoutes " + str(wantroutes) - # non json form for humans - luCommand( - target, - 'vtysh -c "show bgp ipv4 vpn"', - ".", - "None", - "Get VPN RIB (non-json)", - ) - ret = luCommand( - target, - 'vtysh -c "show bgp ipv4 vpn json"', - ".*", - "None", - "Get VPN RIB (json)", - ) - if re.search(r"^\s*$", ret): - # degenerate case: empty json means no routes - if len(wantroutes) > 0: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) - rib = json.loads(ret) - rds = rib["routes"]["routeDistinguishers"] - for want in wantroutes: - found = 0 - if debug: - self.log("want rd %s" % want["rd"]) - for rd in rds.keys(): - if rd != want["rd"]: - continue + retry += 1 + while retry: + retry -= 1 + # non json form for humans + luCommand( + target, + 'vtysh -c "show bgp ipv4 vpn"', + ".", + "None", + "Get VPN RIB (non-json)", + ) + ret = luCommand( + target, + 'vtysh -c "show bgp ipv4 vpn json"', + ".*", + "None", + "Get VPN RIB (json)", + ) + if re.search(r"^\s*$", ret): + # degenerate case: empty json means no routes + if len(wantroutes) > 0: + luResult(target, False, title, logstr) + return + luResult(target, True, title, logstr) + rib = json.loads(ret) + rds = rib["routes"]["routeDistinguishers"] + for want in wantroutes: + found = 0 if debug: - self.log("found rd %s" % rd) - table = rds[rd] - if self.routes_include_wanted(table, want, debug): - found = 1 - break - if not found: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + self.log("want rd %s" % want["rd"]) + for rd in rds.keys(): + if rd != want["rd"]: + continue + if debug: + self.log("found rd %s" % rd) + table = rds[rd] + if self.routes_include_wanted(table, want, debug): + found = 1 + break + if not found: + if retry: + break + luResult(target, False, title, logstr) + return + if not found and retry: + time.sleep(wait) + continue + luResult(target, True, title, logstr) + break - def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): + def RequireUnicastRoutes( + self, target, afi, vrf, title, wantroutes, retry=0, wait=1, debug=0 + ): logstr = "RequireUnicastRoutes %s" % str(wantroutes) vrfstr = "" if vrf != "": @@ -130,48 +153,62 @@ class BgpRib: if (afi != "ipv4") and (afi != "ipv6"): self.log("ERROR invalid afi") - cmdstr = "show bgp %s %s unicast" % (vrfstr, afi) - # non json form for humans - cmd = 'vtysh -c "%s"' % cmdstr - luCommand(target, cmd, ".", "None", "Get %s %s RIB (non-json)" % (vrfstr, afi)) - cmd = 'vtysh -c "%s json"' % cmdstr - ret = luCommand( - target, cmd, ".*", "None", "Get %s %s RIB (json)" % (vrfstr, afi) - ) - if re.search(r"^\s*$", ret): - # degenerate case: empty json means no routes - if len(wantroutes) > 0: - luResult(target, False, title, logstr) + retry += 1 + while retry: + retry -= 1 + cmdstr = "show bgp %s %s unicast" % (vrfstr, afi) + # non json form for humans + cmd = 'vtysh -c "%s"' % cmdstr + luCommand( + target, cmd, ".", "None", "Get %s %s RIB (non-json)" % (vrfstr, afi) + ) + cmd = 'vtysh -c "%s json"' % cmdstr + ret = luCommand( + target, cmd, ".*", "None", "Get %s %s RIB (json)" % (vrfstr, afi) + ) + if re.search(r"^\s*$", ret): + # degenerate case: empty json means no routes + if len(wantroutes) > 0: + luResult(target, False, title, logstr) + return + luResult(target, True, title, logstr) + rib = json.loads(ret) + try: + table = rib["routes"] + # KeyError: 'routes' probably means missing/bad VRF + except KeyError as err: + if vrf != "": + errstr = "-script ERROR: check if wrong vrf (%s)" % (vrf) + else: + errstr = "-script ERROR: check if vrf missing" + if retry: + time.sleep(wait) + continue + luResult(target, False, title + errstr, logstr) return + # if debug: + # self.log("table=%s" % table) + for want in wantroutes: + if debug: + self.log("want=%s" % want) + if not self.routes_include_wanted(table, want, debug): + if retry: + time.sleep(wait) + continue + luResult(target, False, title, logstr) + return luResult(target, True, title, logstr) - rib = json.loads(ret) - try: - table = rib["routes"] - # KeyError: 'routes' probably means missing/bad VRF - except KeyError as err: - if vrf != "": - errstr = "-script ERROR: check if wrong vrf (%s)" % (vrf) - else: - errstr = "-script ERROR: check if vrf missing" - luResult(target, False, title + errstr, logstr) - return - # if debug: - # self.log("table=%s" % table) - for want in wantroutes: - if debug: - self.log("want=%s" % want) - if not self.routes_include_wanted(table, want, debug): - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + break BgpRib = BgpRib() -def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0): - BgpRib.RequireVpnRoutes(target, title, wantroutes, debug) +def bgpribRequireVpnRoutes(target, title, wantroutes, retry=0, wait=1, debug=0): + BgpRib.RequireVpnRoutes(target, title, wantroutes, retry, wait, debug) -def bgpribRequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug=0): - BgpRib.RequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug) +def bgpribRequireUnicastRoutes( + target, afi, vrf, title, wantroutes, retry=0, wait=1, debug=0 +): + BgpRib.RequireUnicastRoutes(target, afi, vrf, title, wantroutes, retry, wait, debug) diff --git a/tests/topotests/lib/snmptest.py b/tests/topotests/lib/snmptest.py index fe5ff28979..d695443906 100644 --- a/tests/topotests/lib/snmptest.py +++ b/tests/topotests/lib/snmptest.py @@ -36,11 +36,12 @@ from lib.topolog import logger class SnmpTester(object): "A helper class for testing SNMP" - def __init__(self, router, iface, community, version): + def __init__(self, router, iface, community, version, options=""): self.community = community self.version = version self.router = router self.iface = iface + self.options = options logger.info( "created SNMP tester: SNMPv{0} community:{1}".format( self.version, self.community @@ -52,7 +53,9 @@ class SnmpTester(object): Helper function to build a string with SNMP configuration for commands. """ - return "-v {0} -c {1} {2}".format(self.version, self.community, self.iface) + return "-v {0} -c {1} {2} {3}".format( + self.version, self.community, self.options, self.iface + ) @staticmethod def _get_snmp_value(snmp_output): diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt index 86c089ab3b..6bafbbb556 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt @@ -5,5 +5,5 @@ B>* 10.0.3.0/24 [20/20] via 10.0.30.3, r1-eth2 (vrf neno), weight 1, XX:XX:XX O>* 10.0.4.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX O 10.0.20.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX C>* 10.0.20.0/24 is directly connected, r1-eth1, XX:XX:XX -B>* 10.0.30.0/24 [20/0] is directly connected, r1-eth2 (vrf neno), weight 1, XX:XX:XX +B>* 10.0.30.0/24 [20/0] is directly connected, neno (vrf neno), weight 1, XX:XX:XX O>* 10.0.40.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt index 9681d8a04e..3ed6b1b3a1 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt @@ -7,4 +7,4 @@ B>* 10.0.4.0/24 [20/20] via 10.0.40.4, r2-eth2 (vrf ray), weight 1, XX:XX:XX O 10.0.20.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX C>* 10.0.20.0/24 is directly connected, r2-eth1, XX:XX:XX O>* 10.0.30.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX -B>* 10.0.40.0/24 [20/0] is directly connected, r2-eth2 (vrf ray), weight 1, XX:XX:XX +B>* 10.0.40.0/24 [20/0] is directly connected, ray (vrf ray), weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt index ce9903ae71..4ad8441d85 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt @@ -1,9 +1,9 @@ VRF ray: B 10.0.1.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX -B 10.0.2.0/24 [20/0] is directly connected, r2-eth0 (vrf default) inactive, weight 1, XX:XX:XX +B 10.0.2.0/24 [20/0] is directly connected, lo (vrf default) inactive, weight 1, XX:XX:XX B>* 10.0.3.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX O>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2, weight 1, XX:XX:XX -B 10.0.20.0/24 [20/0] is directly connected, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX +B 10.0.20.0/24 [20/0] is directly connected, lo (vrf default) inactive, weight 1, XX:XX:XX B>* 10.0.30.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX O 10.0.40.0/24 [110/10] is directly connected, r2-eth2, weight 1, XX:XX:XX C>* 10.0.40.0/24 is directly connected, r2-eth2, XX:XX:XX diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 7c5d91d4dc..bf402e1bef 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -1514,6 +1514,7 @@ def ignore_unconfigurable_lines(lines_to_add, lines_to_del): [ ctx_keys[0].startswith(x) for x in [ + "agentx", "frr version", "frr defaults", "username", diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index a72cb6e809..be7eb3ecdf 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -354,6 +354,7 @@ int main(int argc, char **argv, char **env) const char *pathspace_arg = NULL; char pathspace[MAXPATHLEN] = ""; const char *histfile = NULL; + const char *histfile_env = getenv("VTYSH_HISTFILE"); /* SUID: drop down to calling user & go back up when needed */ elevuid = geteuid(); @@ -611,10 +612,8 @@ int main(int argc, char **argv, char **env) * VTYSH_HISTFILE is preferred over command line * argument (-H/--histfile). */ - if (getenv("VTYSH_HISTFILE")) { - const char *file = getenv("VTYSH_HISTFILE"); - - strlcpy(history_file, file, sizeof(history_file)); + if (histfile_env) { + strlcpy(history_file, histfile_env, sizeof(history_file)); } else if (histfile) { strlcpy(history_file, histfile, sizeof(history_file)); } else { diff --git a/zebra/connected.c b/zebra/connected.c index c01be58e82..57c7f1925b 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -387,10 +387,14 @@ void connected_down(struct interface *ifp, struct connected *ifc) .ifindex = ifp->ifindex, .vrf_id = ifp->vrf->vrf_id, }; - struct zebra_vrf *zvrf; - uint32_t count = 0; + struct zebra_vrf *zvrf, *zvrf_iter; + uint32_t count_ipv4 = 0; struct listnode *cnode; struct connected *c; + struct route_table *table; + struct route_node *rn; + struct route_entry *re, *next; + struct vrf *vrf; zvrf = ifp->vrf->info; if (!zvrf) { @@ -456,12 +460,14 @@ void connected_down(struct interface *ifp, struct connected *ifc) prefix_copy(&cp, CONNECTED_PREFIX(c)); apply_mask(&cp); - if (prefix_same(&p, &cp) && - !CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN)) - count++; + if (CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN)) + continue; - if (count >= 1) + if (prefix_same(&p, &cp)) return; + + if (cp.family == AF_INET) + count_ipv4++; } /* @@ -474,6 +480,60 @@ void connected_down(struct interface *ifp, struct connected *ifc) rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); + /* When the last IPv4 address of an interface is deleted, Linux removes + * all routes using this interface without any Netlink advertisement. + * The removed routes include those that only have this particular + * interface as a nexthop. Among those, remove the kernel one from the + * FRR RIB and reinstall the other that have been added from FRR. + */ + if (afi == AFI_IP && count_ipv4 == 0 && if_is_operative(ifp)) { + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + zvrf_iter = vrf->info; + + if (!zvrf_iter) + continue; + + table = zvrf_iter->table[AFI_IP][SAFI_UNICAST]; + if (!table) + continue; + + for (rn = route_top(table); rn; + rn = srcdest_route_next(rn)) { + RNODE_FOREACH_RE_SAFE (rn, re, next) { + if (CHECK_FLAG(re->status, + ROUTE_ENTRY_REMOVED)) + continue; + if (re->nhe->ifp != ifp) + continue; + if (re->type == ZEBRA_ROUTE_KERNEL) + rib_delete( + afi, SAFI_UNICAST, + zvrf_iter->vrf->vrf_id, + re->type, 0, re->flags, + &rn->p, NULL, &nh, 0, + zvrf_iter->table_id, + re->metric, + re->distance, false); + else if (re->type != + ZEBRA_ROUTE_CONNECT) { + SET_FLAG(re->status, + ROUTE_ENTRY_CHANGED); + UNSET_FLAG( + re->status, + ROUTE_ENTRY_INSTALLED); + rib_add(afi, SAFI_UNICAST, + zvrf_iter->vrf->vrf_id, + re->type, 0, 0, &rn->p, + NULL, &nh, re->nhe_id, + zvrf_iter->table_id, + re->metric, 0, + re->distance, 0, false); + } + } + } + } + } + /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { if (IS_ZEBRA_DEBUG_MPLS) diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 066ef8a8d0..4f43cea493 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -143,26 +143,48 @@ static void show_vrf_proto_rm(struct vty *vty, struct zebra_vrf *zvrf, } static void show_vrf_nht_rm(struct vty *vty, struct zebra_vrf *zvrf, - int af_type) + int af_type, json_object *json) { int i; - vty_out(vty, "Protocol : route-map\n"); - vty_out(vty, "-------------------------------------\n"); + if (!json) { + vty_out(vty, "Protocol : route-map\n"); + vty_out(vty, "-------------------------------------\n"); + } for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { + if (json) { + if (NHT_RM_NAME(zvrf, af_type, i)) + json_object_string_add( + json, zebra_route_string(i), + NHT_RM_NAME(zvrf, af_type, i)); + else + json_object_string_add( + json, zebra_route_string(i), "none"); + } else { + if (NHT_RM_NAME(zvrf, af_type, i)) + vty_out(vty, "%-24s : %-10s\n", + zebra_route_string(i), + NHT_RM_NAME(zvrf, af_type, i)); + else + vty_out(vty, "%-24s : none\n", + zebra_route_string(i)); + } + } + + if (json) { if (NHT_RM_NAME(zvrf, af_type, i)) - vty_out(vty, "%-24s : %-10s\n", zebra_route_string(i), + json_object_string_add(json, "any", + NHT_RM_NAME(zvrf, af_type, i)); + else + json_object_string_add(json, "any", "none"); + } else { + if (NHT_RM_NAME(zvrf, af_type, i)) + vty_out(vty, "%-24s : %-10s\n", "any", NHT_RM_NAME(zvrf, af_type, i)); else - vty_out(vty, "%-24s : none\n", zebra_route_string(i)); + vty_out(vty, "%-24s : none\n", "any"); } - - if (NHT_RM_NAME(zvrf, af_type, i)) - vty_out(vty, "%-24s : %-10s\n", "any", - NHT_RM_NAME(zvrf, af_type, i)); - else - vty_out(vty, "%-24s : none\n", "any"); } static int show_proto_rm(struct vty *vty, int af_type, const char *vrf_all, @@ -198,35 +220,78 @@ static int show_proto_rm(struct vty *vty, int af_type, const char *vrf_all, } static int show_nht_rm(struct vty *vty, int af_type, const char *vrf_all, - const char *vrf_name) + const char *vrf_name, bool use_json) { struct zebra_vrf *zvrf; + json_object *json = NULL; + json_object *json_vrfs = NULL; + + if (use_json) { + json = json_object_new_object(); + json_vrfs = json_object_new_object(); + json_object_string_add(json, "afi", + (af_type == AFI_IP) ? "ipv4" : "ipv6"); + } if (vrf_all) { struct vrf *vrf; + if (use_json) + json_object_object_add(json, "vrfs", json_vrfs); + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { zvrf = (struct zebra_vrf *)vrf->info; if (zvrf == NULL) continue; - vty_out(vty, "VRF: %s\n", zvrf->vrf->name); - show_vrf_nht_rm(vty, zvrf, af_type); + if (use_json) { + json_object *json_proto = NULL; + json_object *json_vrf = NULL; + json_vrf = json_object_new_object(); + json_object_object_add( + json_vrfs, zvrf->vrf->name, json_vrf); + json_proto = json_object_new_object(); + json_object_object_add(json_vrf, "protocols", + json_proto); + show_vrf_nht_rm(vty, zvrf, af_type, json_proto); + } else { + vty_out(vty, "VRF: %s\n", zvrf->vrf->name); + show_vrf_nht_rm(vty, zvrf, af_type, NULL); + } } } else { + json_object *json_proto = NULL; + json_object *json_vrf = NULL; vrf_id_t vrf_id = VRF_DEFAULT; if (vrf_name) VRF_GET_ID(vrf_id, vrf_name, false); zvrf = zebra_vrf_lookup_by_id(vrf_id); - if (!zvrf) + if (!zvrf) { + json_object_free(json); + json_object_free(json_vrfs); return CMD_SUCCESS; + } - vty_out(vty, "VRF: %s\n", zvrf->vrf->name); - show_vrf_nht_rm(vty, zvrf, af_type); + if (use_json) { + json_object_object_add(json, "vrfs", json_vrfs); + json_vrf = json_object_new_object(); + json_object_object_add(json_vrfs, zvrf->vrf->name, + json_vrf); + json_proto = json_object_new_object(); + json_object_object_add(json_vrf, "protocols", + json_proto); + show_vrf_nht_rm(vty, zvrf, af_type, json_proto); + } else { + vty_out(vty, "VRF: %s\n", zvrf->vrf->name); + show_vrf_nht_rm(vty, zvrf, af_type, NULL); + } } + if (use_json) + vty_json(vty, json); + return CMD_SUCCESS; } @@ -854,14 +919,19 @@ DEFPY_YANG (no_ip_protocol_nht_rmap, DEFPY_YANG (show_ip_protocol_nht, show_ip_protocol_nht_cmd, - "show ip nht route-map [vrf <NAME$vrf_name|all$vrf_all>]", + "show ip nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]", SHOW_STR IP_STR - "IP nexthop tracking table\n" - "IP Next Hop tracking filtering status\n" - VRF_FULL_CMD_HELP_STR) + "IPv4 nexthop tracking table\n" + "IPv4 Next Hop tracking filtering status\n" + VRF_CMD_HELP_STR + "All VRFs\n" + JSON_STR) { - int ret = show_nht_rm(vty, AFI_IP, vrf_all, vrf_name); + int ret; + bool uj = use_json(argc, argv); + + ret = show_nht_rm(vty, AFI_IP, vrf_all, vrf_name, uj); return ret; } @@ -936,14 +1006,19 @@ DEFPY_YANG (no_ipv6_protocol_nht_rmap, DEFPY_YANG (show_ipv6_protocol_nht, show_ipv6_protocol_nht_cmd, - "show ipv6 nht route-map [vrf <NAME$vrf_name|all$vrf_all>]", + "show ipv6 nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]", SHOW_STR IP6_STR - "Next Hop filtering status\n" - "Route-map\n" - VRF_FULL_CMD_HELP_STR) + "IPv6 nexthop tracking table\n" + "IPv6 Next Hop tracking filtering status\n" + VRF_CMD_HELP_STR + "All VRFs\n" + JSON_STR) { - int ret = show_nht_rm(vty, AFI_IP6, vrf_all, vrf_name); + int ret; + bool uj = use_json(argc, argv); + + ret = show_nht_rm(vty, AFI_IP6, vrf_all, vrf_name, uj); return ret; } |
