diff options
36 files changed, 998 insertions, 858 deletions
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index d031d34f1f..e6d81e54c4 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3757,9 +3757,9 @@ DEFUN(show_bgp_l2vpn_evpn_route, type = BGP_EVPN_MAC_IP_ROUTE; else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0) type = BGP_EVPN_IMET_ROUTE; - else if (strncmp(argv[type_idx + 1]->arg, "es", 2) == 0) + else if (strncmp(argv[type_idx + 1]->arg, "e", 1) == 0) type = BGP_EVPN_ES_ROUTE; - else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0) + else if (strncmp(argv[type_idx + 1]->arg, "p", 1) == 0) type = BGP_EVPN_IP_PREFIX_ROUTE; else return CMD_WARNING; diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 64529f6ef3..7e5e07099d 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -503,7 +503,7 @@ static int bgp_capability_restart(struct peer *peer, if (bgp_debug_neighbor_events(peer)) zlog_debug( "%s Address family %s is%spreserved", - peer->host, afi_safi_print(afi, safi), + peer->host, get_afi_safi_str(afi, safi, false), CHECK_FLAG( peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 99522a6522..d3a08d23d9 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -140,7 +140,7 @@ static struct stream *bgp_update_packet_eor(struct peer *peer, afi_t afi, if (bgp_debug_neighbor_events(peer)) zlog_debug("send End-of-RIB for %s to %s", - afi_safi_print(afi, safi), peer->host); + get_afi_safi_str(afi, safi, false), peer->host); s = stream_new(BGP_MAX_PACKET_SIZE); @@ -1660,7 +1660,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) bgp_clear_stale_route(peer, afi, safi); zlog_info("%%NOTIFICATION: rcvd End-of-RIB for %s from %s in vrf %s", - afi_safi_print(afi, safi), peer->host, + get_afi_safi_str(afi, safi, false), peer->host, vrf ? vrf->name : VRF_DEFAULT_NAME); } } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 183debddba..32c9fb16f3 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2750,7 +2750,7 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi, zlog_info( "%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, " "limit %ld", - afi_safi_print(afi, safi), peer->host, + get_afi_safi_str(afi, safi, false), peer->host, peer->pcount[afi][safi], peer->pmax[afi][safi]); SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT); @@ -2811,7 +2811,7 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi, zlog_info( "%%MAXPFX: No. of %s prefix received from %s reaches %ld, max %ld", - afi_safi_print(afi, safi), peer->host, + get_afi_safi_str(afi, safi, false), peer->host, peer->pcount[afi][safi], peer->pmax[afi][safi]); SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD); @@ -10696,7 +10696,7 @@ static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi, return CMD_WARNING; } - vty_out(vty, "BGP %s RIB statistics\n", afi_safi_print(afi, safi)); + vty_out(vty, "BGP %s RIB statistics\n", get_afi_safi_str(afi, safi, false)); /* labeled-unicast routes live in the unicast table */ if (safi == SAFI_LABELED_UNICAST) @@ -10895,7 +10895,7 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi, if (use_json) { json_object_string_add(json, "prefixCountsFor", peer->host); json_object_string_add(json, "multiProtocol", - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, true)); json_object_int_add(json, "pfxCounter", peer->pcount[afi][safi]); @@ -10921,10 +10921,10 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi, && bgp_flag_check(peer->bgp, BGP_FLAG_SHOW_HOSTNAME)) { vty_out(vty, "Prefix counts for %s/%s, %s\n", peer->hostname, peer->host, - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, false)); } else { vty_out(vty, "Prefix counts for %s, %s\n", peer->host, - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, false)); } vty_out(vty, "PfxCt: %ld\n", peer->pcount[afi][safi]); @@ -11552,7 +11552,7 @@ DEFUN (show_ip_bgp_neighbor_received_prefix_filter, if (count) { if (!uj) vty_out(vty, "Address Family: %s\n", - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, false)); prefix_bgp_show_prefix_list(vty, afi, name, uj); } else { if (uj) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 7f1a9b71c1..aaae9e380e 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -4158,6 +4158,18 @@ DEFUN (no_set_aspath_prepend, return ret; } +DEFUN (no_set_aspath_prepend_lastas, + no_set_aspath_prepend_lastas_cmd, + "no set as-path prepend last-as [(1-10)]", + NO_STR + SET_STR + "Transform BGP AS_PATH attribute\n" + "Prepend to the as-path\n" + "Use the peers AS-number\n" + "Number of times to insert\n") +{ + return no_set_aspath_prepend(self, vty, argc, argv); +} DEFUN (set_aspath_exclude, set_aspath_exclude_cmd, @@ -5123,6 +5135,7 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &set_aspath_prepend_lastas_cmd); install_element(RMAP_NODE, &set_aspath_exclude_cmd); install_element(RMAP_NODE, &no_set_aspath_prepend_cmd); + install_element(RMAP_NODE, &no_set_aspath_prepend_lastas_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_all_cmd); install_element(RMAP_NODE, &set_origin_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 4447c2ccf8..f6aca6fbf5 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -22,6 +22,7 @@ #include "command.h" #include "lib/json.h" +#include "lib_errors.h" #include "lib/zclient.h" #include "prefix.h" #include "plist.h" @@ -130,6 +131,80 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) return BGP_IPV4_NODE; } +static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi) +{ + if (afi == AFI_IP && safi == SAFI_UNICAST) + return "IPv4 Unicast"; + else if (afi == AFI_IP && safi == SAFI_MULTICAST) + return "IPv4 Multicast"; + else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) + return "IPv4 Labeled Unicast"; + else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) + return "IPv4 VPN"; + else if (afi == AFI_IP && safi == SAFI_ENCAP) + return "IPv4 Encap"; + else if (afi == AFI_IP && safi == SAFI_FLOWSPEC) + return "IPv4 Flowspec"; + else if (afi == AFI_IP6 && safi == SAFI_UNICAST) + return "IPv6 Unicast"; + else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) + return "IPv6 Multicast"; + else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) + return "IPv6 Labeled Unicast"; + else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) + return "IPv6 VPN"; + else if (afi == AFI_IP6 && safi == SAFI_ENCAP) + return "IPv6 Encap"; + else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC) + return "IPv6 Flowspec"; + else if (afi == AFI_L2VPN && safi == SAFI_EVPN) + return "L2VPN EVPN"; + else { + flog_err(EC_LIB_DEVELOPMENT, "New afi/safi that needs to be taken care of?"); + return "Unknown"; + } +} + +/* + * Please note that we have intentionally camelCased + * the return strings here. So if you want + * to use this function, please ensure you + * are doing this within json output + */ +static const char *get_afi_safi_json_str(afi_t afi, safi_t safi) +{ + if (afi == AFI_IP && safi == SAFI_UNICAST) + return "ipv4Unicast"; + else if (afi == AFI_IP && safi == SAFI_MULTICAST) + return "ipv4Multicast"; + else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) + return "ipv4LabeledUnicast"; + else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) + return "ipv4Vpn"; + else if (afi == AFI_IP && safi == SAFI_ENCAP) + return "ipv4Encap"; + else if (afi == AFI_IP && safi == SAFI_FLOWSPEC) + return "ipv4Flowspec"; + else if (afi == AFI_IP6 && safi == SAFI_UNICAST) + return "ipv6Unicast"; + else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) + return "ipv6Multicast"; + else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) + return "ipv6LabeledUnicast"; + else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) + return "ipv6Vpn"; + else if (afi == AFI_IP6 && safi == SAFI_ENCAP) + return "ipv6Encap"; + else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC) + return "ipv6Flowspec"; + else if (afi == AFI_L2VPN && safi == SAFI_EVPN) + return "l2VpnEvpn"; + else { + flog_err(EC_LIB_DEVELOPMENT, "New afi/safi that needs to be taken care of?"); + return "Unknown"; + } +} + /* Utility function to get address family from current node. */ afi_t bgp_node_afi(struct vty *vty) { @@ -584,7 +659,7 @@ static void bgp_clear_vty_error(struct vty *vty, struct peer *peer, afi_t afi, case BGP_ERR_AF_UNCONFIGURED: vty_out(vty, "%%BGP: Enable %s address family for the neighbor %s\n", - afi_safi_print(afi, safi), peer->host); + get_afi_safi_str(afi, safi, false), peer->host); break; case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED: vty_out(vty, @@ -738,7 +813,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, if (!found) vty_out(vty, "%%BGP: No %s peer belonging to peer-group %s is configured\n", - afi_safi_print(afi, safi), arg); + get_afi_safi_str(afi, safi, false), arg); return CMD_SUCCESS; } @@ -760,7 +835,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, if (!found) vty_out(vty, "%%BGP: No external %s peer is configured\n", - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, false)); return CMD_SUCCESS; } @@ -784,7 +859,7 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, if (!found) vty_out(vty, "%%BGP: No %s peer is configured with AS %s\n", - afi_safi_print(afi, safi), arg); + get_afi_safi_str(afi, safi, false), arg); return CMD_SUCCESS; } @@ -8213,7 +8288,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, vty_out(vty, "\nTotal number of neighbors %d\n", count); else { vty_out(vty, "No %s neighbor is configured\n", - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, false)); } if (dn_count) { @@ -8260,12 +8335,14 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, is_first = 0; vty_out(vty, "\"%s\":", - afi_safi_json(afi, - safi)); + get_afi_safi_str(afi, + safi, + true)); } else { vty_out(vty, "\n%s Summary:\n", - afi_safi_print(afi, - safi)); + get_afi_safi_str(afi, + safi, + false)); } } bgp_show_summary(vty, bgp, afi, safi, use_json); @@ -8410,74 +8487,12 @@ DEFUN (show_ip_bgp_summary, return bgp_show_summary_vty(vty, vrf, afi, safi, uj); } -const char *afi_safi_print(afi_t afi, safi_t safi) +const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json) { - if (afi == AFI_IP && safi == SAFI_UNICAST) - return "IPv4 Unicast"; - else if (afi == AFI_IP && safi == SAFI_MULTICAST) - return "IPv4 Multicast"; - else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) - return "IPv4 Labeled Unicast"; - else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) - return "IPv4 VPN"; - else if (afi == AFI_IP && safi == SAFI_ENCAP) - return "IPv4 Encap"; - else if (afi == AFI_IP && safi == SAFI_FLOWSPEC) - return "IPv4 Flowspec"; - else if (afi == AFI_IP6 && safi == SAFI_UNICAST) - return "IPv6 Unicast"; - else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) - return "IPv6 Multicast"; - else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) - return "IPv6 Labeled Unicast"; - else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) - return "IPv6 VPN"; - else if (afi == AFI_IP6 && safi == SAFI_ENCAP) - return "IPv6 Encap"; - else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC) - return "IPv6 Flowspec"; - else if (afi == AFI_L2VPN && safi == SAFI_EVPN) - return "L2VPN EVPN"; - else - return "Unknown"; -} - -/* - * Please note that we have intentionally camelCased - * the return strings here. So if you want - * to use this function, please ensure you - * are doing this within json output - */ -const char *afi_safi_json(afi_t afi, safi_t safi) -{ - if (afi == AFI_IP && safi == SAFI_UNICAST) - return "ipv4Unicast"; - else if (afi == AFI_IP && safi == SAFI_MULTICAST) - return "ipv4Multicast"; - else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) - return "ipv4LabeledUnicast"; - else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) - return "ipv4Vpn"; - else if (afi == AFI_IP && safi == SAFI_ENCAP) - return "ipv4Encap"; - else if (afi == AFI_IP && safi == SAFI_FLOWSPEC) - return "ipv4Flowspec"; - else if (afi == AFI_IP6 && safi == SAFI_UNICAST) - return "ipv6Unicast"; - else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) - return "ipv6Multicast"; - else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) - return "ipv6LabeledUnicast"; - else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) - return "ipv6Vpn"; - else if (afi == AFI_IP6 && safi == SAFI_ENCAP) - return "ipv6Encap"; - else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC) - return "ipv6Flowspec"; - else if (afi == AFI_L2VPN && safi == SAFI_EVPN) - return "l2VpnEvpn"; + if (for_json) + return get_afi_safi_json_str(afi, safi); else - return "Unknown"; + return get_afi_safi_vty_str(afi, safi); } /* Show BGP peer's information. */ @@ -8855,14 +8870,14 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi, "prefixAllowedRestartIntervalMsecs", p->pmax_restart[afi][safi] * 60000); } - json_object_object_add(json_neigh, afi_safi_print(afi, safi), + json_object_object_add(json_neigh, get_afi_safi_str(afi, safi, true), json_addr); } else { filter = &p->filter[afi][safi]; vty_out(vty, " For address family: %s\n", - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, false)); if (peer_group_active(p)) vty_out(vty, " %s peer-group member\n", @@ -9569,8 +9584,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object *json_sub = NULL; json_sub = json_object_new_object(); - print_store = afi_safi_print( - afi, safi); + print_store = get_afi_safi_str( + afi, safi, true); if (CHECK_FLAG( p->af_cap[afi] @@ -9748,9 +9763,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, [AFI_IP] [safi], PEER_CAP_ENHE_AF_RCV)) { - print_store = afi_safi_print( + print_store = get_afi_safi_str( AFI_IP, - safi); + safi, true); json_object_string_add( json_nxt, print_store, @@ -9850,8 +9865,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object_object_add( json_multi, - afi_safi_print(afi, - safi), + get_afi_safi_str(afi, + safi, + true), json_exten); } } @@ -9957,9 +9973,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, restart_af_count++; json_object_object_add( json_restart, - afi_safi_print( + get_afi_safi_str( afi, - safi), + safi, + true), json_sub); } } @@ -10018,9 +10035,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, PEER_CAP_ADDPATH_AF_TX_RCV)) { vty_out(vty, " %s: TX ", - afi_safi_print( + get_afi_safi_str( afi, - safi)); + safi, + false)); if (CHECK_FLAG( p->af_cap @@ -10029,9 +10047,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, PEER_CAP_ADDPATH_AF_TX_ADV)) vty_out(vty, "advertised %s", - afi_safi_print( + get_afi_safi_str( afi, - safi)); + safi, + false)); if (CHECK_FLAG( p->af_cap @@ -10061,9 +10080,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, PEER_CAP_ADDPATH_AF_RX_RCV)) { vty_out(vty, " %s: RX ", - afi_safi_print( + get_afi_safi_str( afi, - safi)); + safi, + false)); if (CHECK_FLAG( p->af_cap @@ -10072,9 +10092,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, PEER_CAP_ADDPATH_AF_RX_ADV)) vty_out(vty, "advertised %s", - afi_safi_print( + get_afi_safi_str( afi, - safi)); + safi, + false)); if (CHECK_FLAG( p->af_cap @@ -10145,9 +10166,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, PEER_CAP_ENHE_AF_RCV)) vty_out(vty, " %s\n", - afi_safi_print( + get_afi_safi_str( AFI_IP, - safi)); + safi, + false)); } } @@ -10194,8 +10216,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, || p->afc_recv[afi][safi]) { vty_out(vty, " Address Family %s:", - afi_safi_print(afi, - safi)); + get_afi_safi_str( + afi, + safi, + false)); if (p->afc_adv[afi][safi]) vty_out(vty, " advertised"); @@ -10280,9 +10304,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, restart_af_count ? ", " : "", - afi_safi_print( + get_afi_safi_str( afi, - safi), + safi, + false), CHECK_FLAG( p->af_cap [afi] @@ -10321,8 +10346,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, PEER_STATUS_EOR_SEND)) { json_object_boolean_true_add( json_grace_send, - afi_safi_print(afi, - safi)); + get_afi_safi_str(afi, + safi, + true)); eor_send_af_count++; } } @@ -10332,8 +10358,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, PEER_STATUS_EOR_RECEIVED)) { json_object_boolean_true_add( json_grace_recv, - afi_safi_print(afi, - safi)); + get_afi_safi_str(afi, + safi, + true)); eor_receive_af_count++; } } @@ -10371,8 +10398,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, "%s%s", eor_send_af_count ? ", " : "", - afi_safi_print(afi, - safi)); + get_afi_safi_str(afi, + safi, + false)); eor_send_af_count++; } } @@ -10386,8 +10414,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, eor_receive_af_count ? ", " : "", - afi_safi_print(afi, - safi)); + get_afi_safi_str(afi, + safi, + false)); eor_receive_af_count++; } } @@ -11319,7 +11348,7 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, /* Provide context for the block */ json_object_string_add(json, "vrf", name ? name : "default"); json_object_string_add(json, "afiSafi", - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, true)); if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT)) { @@ -11400,11 +11429,11 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, BGP_CONFIG_VRF_TO_VRF_IMPORT)) vty_out(vty, "This VRF is not importing %s routes from any other VRF\n", - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, false)); else { vty_out(vty, "This VRF is importing %s routes from the following VRFs:\n", - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, false)); for (ALL_LIST_ELEMENTS_RO( bgp->vpn_policy[afi].import_vrf, @@ -11428,11 +11457,11 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, BGP_CONFIG_VRF_TO_VRF_EXPORT)) vty_out(vty, "This VRF is not exporting %s routes to any other VRF\n", - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, false)); else { vty_out(vty, "This VRF is exporting %s routes to the following VRFs:\n", - afi_safi_print(afi, safi)); + get_afi_safi_str(afi, safi, false)); for (ALL_LIST_ELEMENTS_RO( bgp->vpn_policy[afi].export_vrf, @@ -11809,7 +11838,7 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) FOREACH_AFI_SAFI (afi, safi) { if (conf->afc[afi][safi]) { af_cfgd = 1; - vty_out(vty, " %s;", afi_safi_print(afi, safi)); + vty_out(vty, " %s;", get_afi_safi_str(afi, safi, false)); } } if (!af_cfgd) @@ -14478,12 +14507,13 @@ ALIAS (show_community_list, DEFUN (show_community_list_arg, show_bgp_community_list_arg_cmd, - "show bgp community-list <(1-500)|WORD>", + "show bgp community-list <(1-500)|WORD> detail", SHOW_STR BGP_STR "List community-list\n" "Community-list number\n" - "Community-list name\n") + "Community-list name\n" + "Detailed information on community-list\n") { int idx_comm_list = 3; struct community_list *list; @@ -14492,8 +14522,8 @@ DEFUN (show_community_list_arg, if (argv_find(argv, argc, "ip", &idx)) { vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n"); vty_out(vty, "if you are using this please migrate to the below command.\n"); - vty_out(vty, "'show bgp community-list <(1-500)|WORD>'\n"); - zlog_warn("Deprecated option: 'ip show community-list <(1-500)|WORD>' being used"); + vty_out(vty, "'show bgp community-list <(1-500)|WORD> detail'\n"); + zlog_warn("Deprecated option: 'show ip community-list <(1-500)|WORD>' being used"); } list = community_list_lookup(bgp_clist, argv[idx_comm_list]->arg, 0, COMMUNITY_LIST_MASTER); @@ -14632,28 +14662,6 @@ CPP_NOTICE("bgpd: remove deprecated 'ip large-community-list <(1-99)|(100-500)|s #endif DEFUN (lcommunity_list_standard, bgp_lcommunity_list_standard_cmd, - "bgp large-community-list (1-99) <deny|permit>", - BGP_STR - LCOMMUNITY_LIST_STR - "Large Community list number (standard)\n" - "Specify large community to reject\n" - "Specify large community to accept\n") -{ - return lcommunity_list_set_vty(vty, argc, argv, - LARGE_COMMUNITY_LIST_STANDARD, 0); -} - -ALIAS (lcommunity_list_standard, - ip_lcommunity_list_standard_cmd, - "ip large-community-list (1-99) <deny|permit>", - IP_STR - LCOMMUNITY_LIST_STR - "Large Community list number (standard)\n" - "Specify large community to reject\n" - "Specify large community to accept\n") - -DEFUN (lcommunity_list_standard1, - bgp_lcommunity_list_standard1_cmd, "bgp large-community-list (1-99) <deny|permit> AA:BB:CC...", BGP_STR LCOMMUNITY_LIST_STR @@ -14666,8 +14674,8 @@ DEFUN (lcommunity_list_standard1, LARGE_COMMUNITY_LIST_STANDARD, 0); } -ALIAS (lcommunity_list_standard1, - ip_lcommunity_list_standard1_cmd, +ALIAS (lcommunity_list_standard, + ip_lcommunity_list_standard_cmd, "ip large-community-list (1-99) <deny|permit> AA:BB:CC...", IP_STR LCOMMUNITY_LIST_STR @@ -14702,30 +14710,6 @@ ALIAS (lcommunity_list_expanded, DEFUN (lcommunity_list_name_standard, bgp_lcommunity_list_name_standard_cmd, - "bgp large-community-list standard WORD <deny|permit>", - BGP_STR - LCOMMUNITY_LIST_STR - "Specify standard large-community-list\n" - "Large Community list name\n" - "Specify large community to reject\n" - "Specify large community to accept\n") -{ - return lcommunity_list_set_vty(vty, argc, argv, - LARGE_COMMUNITY_LIST_STANDARD, 1); -} - -ALIAS (lcommunity_list_name_standard, - ip_lcommunity_list_name_standard_cmd, - "ip large-community-list standard WORD <deny|permit>", - IP_STR - LCOMMUNITY_LIST_STR - "Specify standard large-community-list\n" - "Large Community list name\n" - "Specify large community to reject\n" - "Specify large community to accept\n") - -DEFUN (lcommunity_list_name_standard1, - bgp_lcommunity_list_name_standard1_cmd, "bgp large-community-list standard WORD <deny|permit> AA:BB:CC...", BGP_STR LCOMMUNITY_LIST_STR @@ -14739,8 +14723,8 @@ DEFUN (lcommunity_list_name_standard1, LARGE_COMMUNITY_LIST_STANDARD, 1); } -ALIAS (lcommunity_list_name_standard1, - ip_lcommunity_list_name_standard1_cmd, +ALIAS (lcommunity_list_name_standard, + ip_lcommunity_list_name_standard_cmd, "ip large-community-list standard WORD <deny|permit> AA:BB:CC...", IP_STR LCOMMUNITY_LIST_STR @@ -15003,12 +14987,13 @@ ALIAS (show_lcommunity_list, DEFUN (show_lcommunity_list_arg, show_bgp_lcommunity_list_arg_cmd, - "show bgp large-community-list <(1-500)|WORD>", + "show bgp large-community-list <(1-500)|WORD> detail", SHOW_STR BGP_STR "List large-community list\n" - "large-community-list number\n" - "large-community-list name\n") + "Large-community-list number\n" + "Large-community-list name\n" + "Detailed information on large-community-list\n") { struct community_list *list; int idx = 0; @@ -15016,14 +15001,14 @@ DEFUN (show_lcommunity_list_arg, if (argv_find(argv, argc, "ip", &idx)) { vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n"); vty_out(vty, "if you are using this please migrate to the below command.\n"); - vty_out(vty, "'show bgp large-community-list <(1-500)|WORD>'\n"); - zlog_warn("Deprecated option: 'ip show large-community-list <(1-500)|WORD>' being used"); + vty_out(vty, "'show bgp large-community-list <(1-500)|WORD> detail'\n"); + zlog_warn("Deprecated option: 'show ip large-community-list <(1-500)|WORD>' being used"); } list = community_list_lookup(bgp_clist, argv[3]->arg, 0, LARGE_COMMUNITY_LIST_MASTER); if (!list) { - vty_out(vty, "%% Can't find extcommunity-list\n"); + vty_out(vty, "%% Can't find large-community-list\n"); return CMD_WARNING; } @@ -15404,12 +15389,13 @@ ALIAS (show_extcommunity_list, DEFUN (show_extcommunity_list_arg, show_bgp_extcommunity_list_arg_cmd, - "show bgp extcommunity-list <(1-500)|WORD>", + "show bgp extcommunity-list <(1-500)|WORD> detail", SHOW_STR BGP_STR "List extended-community list\n" "Extcommunity-list number\n" - "Extcommunity-list name\n") + "Extcommunity-list name\n" + "Detailed information on extcommunity-list\n") { int idx_comm_list = 3; struct community_list *list; @@ -15418,8 +15404,8 @@ DEFUN (show_extcommunity_list_arg, if (argv_find(argv, argc, "ip", &idx)) { vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n"); vty_out(vty, "if you are using this please migrate to the below command.\n"); - vty_out(vty, "'show bgp extcommunity-list <(1-500)|WORD>'\n"); - zlog_warn("Deprecated option: 'ip show extcommunity-list <(1-500)|WORD>' being used"); + vty_out(vty, "'show bgp extcommunity-list <(1-500)|WORD> detail'\n"); + zlog_warn("Deprecated option: 'show ip extcommunity-list <(1-500)|WORD>' being used"); } list = community_list_lookup(bgp_clist, argv[idx_comm_list]->arg, 0, EXTCOMMUNITY_LIST_MASTER); @@ -15566,10 +15552,8 @@ static void community_list_vty(void) /* Large Community List */ install_element(CONFIG_NODE, &bgp_lcommunity_list_standard_cmd); - install_element(CONFIG_NODE, &bgp_lcommunity_list_standard1_cmd); install_element(CONFIG_NODE, &bgp_lcommunity_list_expanded_cmd); install_element(CONFIG_NODE, &bgp_lcommunity_list_name_standard_cmd); - install_element(CONFIG_NODE, &bgp_lcommunity_list_name_standard1_cmd); install_element(CONFIG_NODE, &bgp_lcommunity_list_name_expanded_cmd); install_element(CONFIG_NODE, &no_bgp_lcommunity_list_standard_all_cmd); install_element(CONFIG_NODE, @@ -15581,10 +15565,8 @@ static void community_list_vty(void) install_element(VIEW_NODE, &show_bgp_lcommunity_list_cmd); install_element(VIEW_NODE, &show_bgp_lcommunity_list_arg_cmd); install_element(CONFIG_NODE, &ip_lcommunity_list_standard_cmd); - install_element(CONFIG_NODE, &ip_lcommunity_list_standard1_cmd); install_element(CONFIG_NODE, &ip_lcommunity_list_expanded_cmd); install_element(CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd); - install_element(CONFIG_NODE, &ip_lcommunity_list_name_standard1_cmd); install_element(CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd); install_element(CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd); install_element(CONFIG_NODE, diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index d9df2b4cfe..961467e229 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -45,8 +45,7 @@ struct bgp; "Address Family modifier\n" extern void bgp_vty_init(void); -extern const char *afi_safi_print(afi_t afi, safi_t safi); -extern const char *afi_safi_json(afi_t afi, safi_t safi); +extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json); extern void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp); extern void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp); extern void bgp_config_write_rpkt_quanta(struct vty *vty, struct bgp *bgp); diff --git a/configure.ac b/configure.ac index 134c8692d4..676c984385 100755 --- a/configure.ac +++ b/configure.ac @@ -1061,6 +1061,7 @@ case "$host_os" in AC_CHECK_LIB([nsl], [main]) AC_CHECK_LIB([umem], [main]) SOLARIS="solaris" + AC_MSG_WARN([--Solaris support is being considered for deprecation, please let us know if you are still using this--]) ;; linux*) AC_MSG_RESULT([Linux]) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index c329ab6d9f..92d4126cec 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1169,19 +1169,24 @@ AS path access list is user defined AS path. Using AS Path in Route Map -------------------------- -.. index:: match as-path WORD -.. clicmd:: match as-path WORD +.. index:: [no] match as-path WORD +.. clicmd:: [no] match as-path WORD + For a given as-path, WORD, match it on the BGP as-path given for the prefix + and if it matches do normal route-map actions. The no form of the command + removes this match from the route-map. -.. index:: set as-path prepend AS-PATH -.. clicmd:: set as-path prepend AS-PATH +.. index:: [no] set as-path prepend AS-PATH +.. clicmd:: [no] set as-path prepend AS-PATH - Prepend the given string of AS numbers to the AS_PATH. + Prepend the given string of AS numbers to the AS_PATH of the BGP path's NLRI. + The no form of this command removes this set operation from the route-map. -.. index:: set as-path prepend last-as NUM -.. clicmd:: set as-path prepend last-as NUM +.. index:: [no] set as-path prepend last-as NUM +.. clicmd:: [no] set as-path prepend last-as NUM Prepend the existing last AS number (the leftmost ASN) to the AS_PATH. + The no form of this command removes this set operation from the route-map. .. _bgp-communities-attribute: diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c index fa89c80049..8fc7997d79 100644 --- a/isisd/isis_bfd.c +++ b/isisd/isis_bfd.c @@ -19,7 +19,9 @@ #include <zebra.h> #include "zclient.h" +#include "nexthop.h" #include "bfd.h" +#include "lib_errors.h" #include "isisd/isis_bfd.h" #include "isisd/isis_zebra.h" @@ -33,17 +35,19 @@ DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session") struct bfd_session { - struct in_addr dst_ip; - struct in_addr src_ip; + int family; + union g_addr dst_ip; + union g_addr src_ip; int status; }; -static struct bfd_session *bfd_session_new(struct in_addr *dst_ip, - struct in_addr *src_ip) +static struct bfd_session *bfd_session_new(int family, union g_addr *dst_ip, + union g_addr *src_ip) { struct bfd_session *rv; rv = XCALLOC(MTYPE_BFD_SESSION, sizeof(*rv)); + rv->family = family; rv->dst_ip = *dst_ip; rv->src_ip = *src_ip; return rv; @@ -58,15 +62,60 @@ static void bfd_session_free(struct bfd_session **session) *session = NULL; } +static bool bfd_session_same(const struct bfd_session *session, int family, + const union g_addr *src, const union g_addr *dst) +{ + if (session->family != family) + return false; + + switch (session->family) { + case AF_INET: + if (!IPV4_ADDR_SAME(&session->dst_ip.ipv4, &dst->ipv4)) + return false; + if (!IPV4_ADDR_SAME(&session->src_ip.ipv4, &src->ipv4)) + return false; + break; + case AF_INET6: + if (!IPV6_ADDR_SAME(&session->dst_ip.ipv6, &dst->ipv6)) + return false; + if (!IPV6_ADDR_SAME(&session->src_ip.ipv6, &src->ipv6)) + return false; + break; + default: + flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u", + __func__, session->family); + exit(1); + } + + return true; +} + static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst, int new_status) { if (!adj->bfd_session) return; - if (adj->bfd_session->dst_ip.s_addr != dst->u.prefix4.s_addr) + if (adj->bfd_session->family != dst->family) return; + switch (adj->bfd_session->family) { + case AF_INET: + if (!IPV4_ADDR_SAME(&adj->bfd_session->dst_ip.ipv4, + &dst->u.prefix4)) + return; + break; + case AF_INET6: + if (!IPV6_ADDR_SAME(&adj->bfd_session->dst_ip.ipv6, + &dst->u.prefix6)) + return; + break; + default: + flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u", + __func__, adj->bfd_session->family); + exit(1); + } + int old_status = adj->bfd_session->status; adj->bfd_session->status = new_status; @@ -76,7 +125,7 @@ static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst, if (isis->debugs & DEBUG_BFD) { char dst_str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET, &adj->bfd_session->dst_ip, + inet_ntop(adj->bfd_session->family, &adj->bfd_session->dst_ip, dst_str, sizeof(dst_str)); zlog_debug("ISIS-BFD: Peer %s on %s changed from %s to %s", dst_str, adj->circuit->interface->name, @@ -100,14 +149,14 @@ static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, NULL, &status, NULL, vrf_id); - if (!ifp || dst_ip.family != AF_INET) + if (!ifp || (dst_ip.family != AF_INET && dst_ip.family != AF_INET6)) return 0; if (isis->debugs & DEBUG_BFD) { char dst_buf[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET, &dst_ip.u.prefix4, - dst_buf, sizeof(dst_buf)); + inet_ntop(dst_ip.family, &dst_ip.u.prefix, dst_buf, + sizeof(dst_buf)); zlog_debug("ISIS-BFD: Received update for %s on %s: Changed state to %s", dst_buf, ifp->name, bfd_get_status_str(status)); @@ -171,7 +220,7 @@ static void isis_bfd_zebra_connected(struct zclient *zclient) bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); } -static void bfd_debug(struct in_addr *dst, struct in_addr *src, +static void bfd_debug(int family, union g_addr *dst, union g_addr *src, const char *interface, int command) { if (!(isis->debugs & DEBUG_BFD)) @@ -180,8 +229,8 @@ static void bfd_debug(struct in_addr *dst, struct in_addr *src, char dst_str[INET6_ADDRSTRLEN]; char src_str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET, dst, dst_str, sizeof(dst_str)); - inet_ntop(AF_INET, src, src_str, sizeof(src_str)); + inet_ntop(family, dst, dst_str, sizeof(dst_str)); + inet_ntop(family, src, src_str, sizeof(src_str)); const char *command_str; @@ -209,10 +258,11 @@ static void bfd_handle_adj_down(struct isis_adjacency *adj) if (!adj->bfd_session) return; - bfd_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, - adj->circuit->interface->name, ZEBRA_BFD_DEST_DEREGISTER); + bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip, + &adj->bfd_session->src_ip, adj->circuit->interface->name, + ZEBRA_BFD_DEST_DEREGISTER); - bfd_peer_sendmsg(zclient, NULL, AF_INET, + bfd_peer_sendmsg(zclient, NULL, adj->bfd_session->family, &adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, adj->circuit->interface->name, @@ -228,33 +278,50 @@ static void bfd_handle_adj_down(struct isis_adjacency *adj) static void bfd_handle_adj_up(struct isis_adjacency *adj, int command) { struct isis_circuit *circuit = adj->circuit; + int family; + union g_addr dst_ip; + union g_addr src_ip; + struct list *local_ips; + struct prefix *local_ip; - if (!circuit->bfd_info - || !circuit->ip_router - || !adj->ipv4_address_count) + if (!circuit->bfd_info) goto out; - struct list *local_ips = fabricd_ip_addrs(adj->circuit); - - if (!local_ips) + /* + * If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer + * creating a BFD session over IPv6. + */ + if (circuit->ipv6_router && adj->ipv6_address_count) { + family = AF_INET6; + dst_ip.ipv6 = adj->ipv6_addresses[0]; + local_ips = circuit->ipv6_link; + if (!local_ips || list_isempty(local_ips)) + goto out; + local_ip = listgetdata(listhead(local_ips)); + src_ip.ipv6 = local_ip->u.prefix6; + } else if (circuit->ip_router && adj->ipv4_address_count) { + family = AF_INET; + dst_ip.ipv4 = adj->ipv4_addresses[0]; + local_ips = fabricd_ip_addrs(adj->circuit); + if (!local_ips || list_isempty(local_ips)) + goto out; + local_ip = listgetdata(listhead(local_ips)); + src_ip.ipv4 = local_ip->u.prefix4; + } else goto out; - struct in_addr *dst_ip = &adj->ipv4_addresses[0]; - struct prefix_ipv4 *local_ip = listgetdata(listhead(local_ips)); - struct in_addr *src_ip = &local_ip->prefix; - if (adj->bfd_session) { - if (adj->bfd_session->dst_ip.s_addr != dst_ip->s_addr - || adj->bfd_session->src_ip.s_addr != src_ip->s_addr) + if (bfd_session_same(adj->bfd_session, family, &src_ip, + &dst_ip)) bfd_handle_adj_down(adj); } if (!adj->bfd_session) - adj->bfd_session = bfd_session_new(dst_ip, src_ip); + adj->bfd_session = bfd_session_new(family, &dst_ip, &src_ip); - bfd_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, - circuit->interface->name, command); - bfd_peer_sendmsg(zclient, circuit->bfd_info, AF_INET, + bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip, + &adj->bfd_session->src_ip, circuit->interface->name, command); + bfd_peer_sendmsg(zclient, circuit->bfd_info, adj->bfd_session->family, &adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, circuit->interface->name, diff --git a/lib/ferr.c b/lib/ferr.c index 8afc926c41..fd5fb50172 100644 --- a/lib/ferr.c +++ b/lib/ferr.c @@ -170,7 +170,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json) DEFUN_NOSH(show_error_code, show_error_code_cmd, - "show error <(1-4294967296)|all> [json]", + "show error <(1-4294967295)|all> [json]", SHOW_STR "Information on errors\n" "Error code to get info about\n" diff --git a/lib/frrcu.c b/lib/frrcu.c index 7e6475b648..54626f909d 100644 --- a/lib/frrcu.c +++ b/lib/frrcu.c @@ -55,7 +55,6 @@ #include "atomlist.h" DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread") -DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier") DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head) @@ -226,7 +225,7 @@ static void rcu_bump(void) { struct rcu_next *rn; - rn = XMALLOC(MTYPE_RCU_NEXT, sizeof(*rn)); + rn = XMALLOC(MTYPE_RCU_THREAD, sizeof(*rn)); /* note: each RCUA_NEXT item corresponds to exactly one seqno bump. * This means we don't need to communicate which seqno is which @@ -269,7 +268,7 @@ static void rcu_bump(void) * "last item is being deleted - start over" case, and then we may end * up accessing old RCU queue items that are already free'd. */ - rcu_free_internal(MTYPE_RCU_NEXT, rn, head_free); + rcu_free_internal(MTYPE_RCU_THREAD, rn, head_free); /* Only allow the RCU sweeper to run after these 2 items are queued. * @@ -45,6 +45,8 @@ DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected") DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label") DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters") +static struct interface *if_lookup_by_ifindex(ifindex_t ifindex, + vrf_id_t vrf_id); static int if_cmp_func(const struct interface *, const struct interface *); static int if_cmp_index_func(const struct interface *ifp1, const struct interface *ifp2); @@ -257,8 +259,9 @@ void if_delete(struct interface *ifp) XFREE(MTYPE_IF, ifp); } -/* Interface existance check by index. */ -struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id) +/* Used only internally to check within VRF only */ +static struct interface *if_lookup_by_ifindex(ifindex_t ifindex, + vrf_id_t vrf_id) { struct vrf *vrf; struct interface if_tmp; @@ -271,6 +274,19 @@ struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id) return RB_FIND(if_index_head, &vrf->ifaces_by_index, &if_tmp); } +/* Interface existance check by index. */ +struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id) +{ + switch (vrf_get_backend()) { + case VRF_BACKEND_UNKNOWN: + case VRF_BACKEND_NETNS: + return(if_lookup_by_ifindex(ifindex, vrf_id)); + case VRF_BACKEND_VRF_LITE: + return(if_lookup_by_index_all_vrf(ifindex)); + } + return NULL; +} + const char *ifindex2ifname(ifindex_t ifindex, vrf_id_t vrf_id) { struct interface *ifp; @@ -329,7 +345,7 @@ struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex) return NULL; RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - ifp = if_lookup_by_index(ifindex, vrf->vrf_id); + ifp = if_lookup_by_ifindex(ifindex, vrf->vrf_id); if (ifp) return ifp; } @@ -337,7 +353,7 @@ struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex) return NULL; } -/* Lookup interface by IPv4 address. */ +/* Lookup interface by IP address. */ struct interface *if_lookup_exact_address(void *src, int family, vrf_id_t vrf_id) { @@ -369,7 +385,7 @@ struct interface *if_lookup_exact_address(void *src, int family, return NULL; } -/* Lookup interface by IPv4 address. */ +/* Lookup interface by IP address. */ struct connected *if_lookup_address(void *matchaddr, int family, vrf_id_t vrf_id) { @@ -489,7 +505,7 @@ struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) switch (vrf_get_backend()) { case VRF_BACKEND_UNKNOWN: case VRF_BACKEND_NETNS: - ifp = if_lookup_by_index(ifindex, vrf_id); + ifp = if_lookup_by_ifindex(ifindex, vrf_id); if (ifp) return ifp; return if_create_ifindex(ifindex, vrf_id); @@ -383,16 +383,12 @@ struct connected { /* N.B. the ZEBRA_IFA_PEER flag should be set if and only if a peer address has been configured. If this flag is set, the destination field must contain the peer address. - Otherwise, if this flag is not set, the destination address - will either contain a broadcast address or be NULL. */ /* Address of connected network. */ struct prefix *address; - /* Peer or Broadcast address, depending on whether ZEBRA_IFA_PEER is - set. - Note: destination may be NULL if ZEBRA_IFA_PEER is not set. */ + /* Peer address, if ZEBRA_IFA_PEER is set, otherwise NULL */ struct prefix *destination; /* Label for Linux 2.2.X and upper. */ diff --git a/lib/northbound.h b/lib/northbound.h index 69d7c8e0ee..ce79d907f9 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -347,15 +347,6 @@ struct nb_callbacks { * dnode * libyang data node that should be shown in the form of a CLI * command. - * - * show_defaults - * Specify whether to display default configuration values or not. - * This parameter can be ignored most of the time since the - * northbound doesn't call this callback for default leaves or - * non-presence containers that contain only default child nodes. - * The exception are commands associated to multiple configuration - * nodes, in which case it might be desirable to hide one or more - * parts of the command when this parameter is set to false. */ void (*cli_show_end)(struct vty *vty, struct lyd_node *dnode); }; diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index c691bb27aa..884c01a457 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -757,7 +757,7 @@ DEFPY (config_load, "configuration load\ <\ file [<json$json|xml$xml> [translate WORD$translator_family]] FILENAME$filename\ - |transaction (1-4294967296)$tid\ + |transaction (1-4294967295)$tid\ >\ [replace$replace]", "Configuration related settings\n" @@ -923,12 +923,12 @@ DEFPY (show_config_compare, <\ candidate$c1_candidate\ |running$c1_running\ - |transaction (1-4294967296)$c1_tid\ + |transaction (1-4294967295)$c1_tid\ >\ <\ candidate$c2_candidate\ |running$c2_running\ - |transaction (1-4294967296)$c2_tid\ + |transaction (1-4294967295)$c2_tid\ >\ [<json$json|xml$xml> [translate WORD$translator_family]]", SHOW_STR @@ -1029,11 +1029,11 @@ ALIAS (show_config_compare, "show configuration compare\ <\ running$c1_running\ - |transaction (1-4294967296)$c1_tid\ + |transaction (1-4294967295)$c1_tid\ >\ <\ running$c2_running\ - |transaction (1-4294967296)$c2_tid\ + |transaction (1-4294967295)$c2_tid\ >\ [<json$json|xml$xml> [translate WORD$translator_family]]", SHOW_STR @@ -1192,7 +1192,7 @@ DEFPY (show_config_transaction, show_config_transaction_cmd, "show configuration transaction\ [\ - (1-4294967296)$transaction_id\ + (1-4294967295)$transaction_id\ [<json$json|xml$xml> [translate WORD$translator_family]]\ [<\ with-defaults$with_defaults\ @@ -1593,7 +1593,7 @@ static int nb_cli_rollback_configuration(struct vty *vty, DEFPY (rollback_config, rollback_config_cmd, - "rollback configuration (1-4294967296)$transaction_id", + "rollback configuration (1-4294967295)$transaction_id", "Rollback to a previous state\n" "Running configuration\n" "Transaction ID\n") diff --git a/lib/prefix.c b/lib/prefix.c index 1a4a914e05..ad8dea273e 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -853,7 +853,7 @@ void prefix_ipv4_free(struct prefix_ipv4 *p) prefix_free((struct prefix *)p); } -/* When string format is invalid return 0. */ +/* If given string is valid return 1 else return 0 */ int str2prefix_ipv4(const char *str, struct prefix_ipv4 *p) { int ret; @@ -881,8 +881,10 @@ int str2prefix_ipv4(const char *str, struct prefix_ipv4 *p) cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); memcpy(cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; - ret = inet_aton(cp, &p->prefix); + ret = inet_pton(AF_INET, cp, &p->prefix); XFREE(MTYPE_TMP, cp); + if (ret == 0) + return 0; /* Get prefix length. */ plen = (uint8_t)atoi(++pnt); @@ -1023,7 +1025,7 @@ void prefix_ipv6_free(struct prefix_ipv6 *p) prefix_free((struct prefix *)p); } -/* If given string is valid return pin6 else return NULL */ +/* If given string is valid return 1 else return 0 */ int str2prefix_ipv6(const char *str, struct prefix_ipv6 *p) { char *pnt; @@ -348,6 +348,15 @@ void vty_hello(struct vty *vty) vty_out(vty, "MOTD file not found\n"); } else if (host.motd) vty_out(vty, "%s", host.motd); + +#if CONFDATE > 20200901 + CPP_NOTICE("Please remove solaris code from system as it is deprecated"); +#endif +#ifdef SUNOS_5 + zlog_warn("If you are using FRR on Solaris, the FRR developers would love to hear from you\n"); + zlog_warn("Please send email to dev@lists.frrouting.org about this message\n"); + zlog_warn("We are considering deprecating Solaris and want to find users of Solaris systems\n"); +#endif } /* Put out prompt and wait input from user. */ diff --git a/lib/zclient.c b/lib/zclient.c index 6937700199..2d79d9b3c5 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -325,8 +325,9 @@ int zclient_read_header(struct stream *s, int sock, uint16_t *size, if (*size && stream_read(s, sock, *size) != *size) return -1; -stream_failure: return 0; +stream_failure: + return -1; } bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr) @@ -1056,8 +1057,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID)) STREAM_GETL(s, api->tableid); -stream_failure: return 0; +stream_failure: + return -1; } static void zapi_encode_prefix(struct stream *s, struct prefix *p, @@ -2254,7 +2256,7 @@ int tm_table_manager_connect(struct zclient *zclient) return (int)result; stream_failure: - return 0; + return -1; } /** @@ -2321,8 +2323,9 @@ int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, if (zclient_debug) zlog_debug("Table Chunk assign: %u - %u ", *start, *end); -stream_failure: return 0; +stream_failure: + return -1; } /** diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 2564c6f330..8fa91f500c 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3442,6 +3442,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, else vty_out(vty, " This interface is UNNUMBERED,"); } else { + struct in_addr dest; + const char *dstr; + /* Show OSPF interface information. */ if (use_json) { json_object_string_add( @@ -3455,46 +3458,40 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, inet_ntoa(oi->address->u.prefix4), oi->address->prefixlen); - if (oi->connected->destination - || oi->type == OSPF_IFTYPE_VIRTUALLINK) { - struct in_addr *dest; - const char *dstr; - - if (CONNECTED_PEER(oi->connected) - || oi->type == OSPF_IFTYPE_VIRTUALLINK) - dstr = "Peer"; - else - dstr = "Broadcast"; + /* For Vlinks, showing the peer address is + * probably more informative than the local + * interface that is being used */ + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) { + dstr = "Peer"; + dest = oi->vl_data->peer_addr; + } else if (CONNECTED_PEER(oi->connected) + && oi->connected->destination) { + dstr = "Peer"; + dest = oi->connected->destination->u.prefix4; + } else { + dstr = "Broadcast"; + dest.s_addr = ipv4_broadcast_addr( + oi->connected->address->u.prefix4.s_addr, + oi->connected->address->prefixlen); + } - /* For Vlinks, showing the peer address is - * probably more - * * * * * informative than the local - * interface that is being used - * * * * */ + if (use_json) { + json_object_string_add( + json_interface_sub, + "ospfIfType", dstr); if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - dest = &oi->vl_data->peer_addr; + json_object_string_add( + json_interface_sub, + "vlinkPeer", + inet_ntoa(dest)); else - dest = &oi->connected->destination->u - .prefix4; - - if (use_json) { json_object_string_add( json_interface_sub, - "ospfIfType", dstr); - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - json_object_string_add( - json_interface_sub, - "vlinkPeer", - inet_ntoa(*dest)); - else - json_object_string_add( - json_interface_sub, - "localIfUsed", - inet_ntoa(*dest)); - } else - vty_out(vty, " %s %s,", dstr, - inet_ntoa(*dest)); - } + "localIfUsed", + inet_ntoa(dest)); + } else + vty_out(vty, " %s %s,", dstr, + inet_ntoa(dest)); } if (use_json) { json_object_string_add(json_interface_sub, "area", diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index 78016dc9ce..8e1b62ac15 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -1170,7 +1170,7 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa) /* Test Preparation: Switch and activate address-family. */ if (!is_attr_type_global(pa->type)) { test_log(test, "prepare: switch address-family to [%s]", - afi_safi_print(pa->afi, pa->safi)); + get_afi_safi_str(pa->afi, pa->safi, false)); test_execute(test, "address-family %s %s", str_from_afi(pa->afi), str_from_safi(pa->safi)); test_execute(test, "neighbor %s activate", g->name); @@ -1237,7 +1237,7 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa) /* Test Preparation: Switch and activate address-family. */ if (!is_attr_type_global(pa->type)) { test_log(test, "prepare: switch address-family to [%s]", - afi_safi_print(pa->afi, pa->safi)); + get_afi_safi_str(pa->afi, pa->safi, false)); test_execute(test, "address-family %s %s", str_from_afi(pa->afi), str_from_safi(pa->safi)); test_execute(test, "neighbor %s activate", g->name); @@ -1285,7 +1285,7 @@ static void test_peer_attr(struct test *test, struct test_peer_attr *pa) /* Test Preparation: Switch and activate address-family. */ if (!is_attr_type_global(pa->type)) { test_log(test, "prepare: switch address-family to [%s]", - afi_safi_print(pa->afi, pa->safi)); + get_afi_safi_str(pa->afi, pa->safi, false)); test_execute(test, "address-family %s %s", str_from_afi(pa->afi), str_from_safi(pa->safi)); test_execute(test, "neighbor %s activate", g->name); diff --git a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py index 2b9c411ff2..9f92b4b290 100755 --- a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py +++ b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py @@ -219,7 +219,8 @@ def test_next_hop_attribute(request): dut = "r1" protocol = "bgp" result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True + assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ + " present in RIB".format(tc_name) # Configure next-hop-self to bgp neighbor input_dict_1 = { @@ -484,7 +485,7 @@ def test_localpref_attribute(request): "neighbor": { "r1": { "dest_link": { - "r3": { + "r2": { "route_maps": [ {"name": "RMAP_LOCAL_PREF", "direction": "in"} @@ -499,6 +500,7 @@ def test_localpref_attribute(request): } } } + result = create_router_bgp(tgen, topo, input_dict_4) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) diff --git a/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py b/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py index d3892e9d07..b8975997ea 100755 --- a/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py +++ b/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py @@ -386,8 +386,8 @@ def test_ip_prefix_lists_out_permit(request): tc_name, result) result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ + " present in RIB".format(tc_name) write_test_footer(tc_name) @@ -497,8 +497,8 @@ def test_ip_prefix_lists_in_deny_and_permit_any(request): dut = "r3" protocol = "bgp" result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ + " present in RIB".format(tc_name) write_test_footer(tc_name) @@ -542,7 +542,6 @@ def test_delete_prefix_lists(request): result = verify_prefix_lists(tgen, input_dict_2) assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) - logger.info(result) # Delete prefix list input_dict_2 = { @@ -714,9 +713,8 @@ def test_ip_prefix_lists_out_deny_and_permit_any(request): dut = "r4" protocol = "bgp" result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) - + assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ + " present in RIB".format(tc_name) write_test_footer(tc_name) @@ -859,8 +857,8 @@ def test_modify_prefix_lists_in_permit_to_deny(request): dut = "r3" protocol = "bgp" result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ + " present in RIB".format(tc_name) write_test_footer(tc_name) @@ -972,8 +970,8 @@ def test_modify_prefix_lists_in_deny_to_permit(request): dut = "r3" protocol = "bgp" result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ + " present in RIB".format(tc_name) # Modify ip prefix list input_dict_1 = { @@ -1152,8 +1150,8 @@ def test_modify_prefix_lists_out_permit_to_deny(request): dut = "r4" protocol = "bgp" result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ + " present in RIB".format(tc_name) write_test_footer(tc_name) @@ -1265,8 +1263,8 @@ def test_modify_prefix_lists_out_deny_to_permit(request): dut = "r4" protocol = "bgp" result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ + " present in RIB".format(tc_name) # Modify ip prefix list input_dict_1 = { @@ -1439,8 +1437,8 @@ def test_ip_prefix_lists_implicit_deny(request): dut = "r4" protocol = "bgp" result = verify_rib(tgen, "ipv4", dut, input_dict_1, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ + " present in RIB".format(tc_name) write_test_footer(tc_name) diff --git a/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py index de6c35ba8f..ed350ebfeb 100644 --- a/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py +++ b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py @@ -88,7 +88,7 @@ def test_bgp_maximum_prefix_invalid(): while True: output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) if output['192.168.255.1']['bgpState'] == 'Established': - if output['192.168.255.1']['addressFamilyInfo']['IPv4 Unicast']['acceptedPrefixCounter'] == 2: + if output['192.168.255.1']['addressFamilyInfo']['ipv4Unicast']['acceptedPrefixCounter'] == 2: return True def _bgp_comm_list_delete(router): diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 2613f45f1c..0275b820cc 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -32,7 +32,8 @@ from lib.common_config import (create_common_configuration, load_config_to_router, check_address_types, generate_ips, - find_interface_with_greater_ip) + find_interface_with_greater_ip, + run_frr_cmd, retry) BGP_CONVERGENCE_TIMEOUT = 10 @@ -116,8 +117,8 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False): logger.debug("Router %s: 'bgp' not present in input_dict", router) continue - result = __create_bgp_global(tgen, input_dict, router, build) - if result is True: + data_all_bgp = __create_bgp_global(tgen, input_dict, router, build) + if data_all_bgp: bgp_data = input_dict[router]["bgp"] bgp_addr_data = bgp_data.setdefault("address_family", {}) @@ -134,8 +135,18 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False): or ipv6_data.setdefault("unicast", {}) else False if neigh_unicast: - result = __create_bgp_unicast_neighbor( - tgen, topo, input_dict, router, build) + data_all_bgp = __create_bgp_unicast_neighbor( + tgen, topo, input_dict, router, + config_data=data_all_bgp) + + try: + result = create_common_configuration(tgen, router, data_all_bgp, + "bgp", build) + except InvalidCLIError: + # Traceback + errormsg = traceback.format_exc() + logger.error(errormsg) + return errormsg logger.debug("Exiting lib API: create_router_bgp()") return result @@ -157,77 +168,66 @@ def __create_bgp_global(tgen, input_dict, router, build=False): True or False """ - result = False logger.debug("Entering lib API: __create_bgp_global()") - try: - - bgp_data = input_dict[router]["bgp"] - del_bgp_action = bgp_data.setdefault("delete", False) - if del_bgp_action: - config_data = ["no router bgp"] - result = create_common_configuration(tgen, router, config_data, - "bgp", build=build) - return result - config_data = [] + bgp_data = input_dict[router]["bgp"] + del_bgp_action = bgp_data.setdefault("delete", False) + if del_bgp_action: + config_data = ["no router bgp"] - if "local_as" not in bgp_data and build: - logger.error("Router %s: 'local_as' not present in input_dict" - "for BGP", router) - return False + return config_data - local_as = bgp_data.setdefault("local_as", "") - cmd = "router bgp {}".format(local_as) - vrf_id = bgp_data.setdefault("vrf", None) - if vrf_id: - cmd = "{} vrf {}".format(cmd, vrf_id) - - config_data.append(cmd) + config_data = [] - router_id = bgp_data.setdefault("router_id", None) - del_router_id = bgp_data.setdefault("del_router_id", False) - if del_router_id: - config_data.append("no bgp router-id") - if router_id: - config_data.append("bgp router-id {}".format( - router_id)) + if "local_as" not in bgp_data and build: + logger.error("Router %s: 'local_as' not present in input_dict" + "for BGP", router) + return False - aggregate_address = bgp_data.setdefault("aggregate_address", - {}) - if aggregate_address: - network = aggregate_address.setdefault("network", None) - if not network: - logger.error("Router %s: 'network' not present in " - "input_dict for BGP", router) - else: - cmd = "aggregate-address {}".format(network) + local_as = bgp_data.setdefault("local_as", "") + cmd = "router bgp {}".format(local_as) + vrf_id = bgp_data.setdefault("vrf", None) + if vrf_id: + cmd = "{} vrf {}".format(cmd, vrf_id) + + config_data.append(cmd) + + router_id = bgp_data.setdefault("router_id", None) + del_router_id = bgp_data.setdefault("del_router_id", False) + if del_router_id: + config_data.append("no bgp router-id") + if router_id: + config_data.append("bgp router-id {}".format( + router_id)) + + aggregate_address = bgp_data.setdefault("aggregate_address", + {}) + if aggregate_address: + network = aggregate_address.setdefault("network", None) + if not network: + logger.error("Router %s: 'network' not present in " + "input_dict for BGP", router) + else: + cmd = "aggregate-address {}".format(network) - as_set = aggregate_address.setdefault("as_set", False) - summary = aggregate_address.setdefault("summary", False) - del_action = aggregate_address.setdefault("delete", False) - if as_set: - cmd = "{} {}".format(cmd, "as-set") - if summary: - cmd = "{} {}".format(cmd, "summary") + as_set = aggregate_address.setdefault("as_set", False) + summary = aggregate_address.setdefault("summary", False) + del_action = aggregate_address.setdefault("delete", False) + if as_set: + cmd = "{} {}".format(cmd, "as-set") + if summary: + cmd = "{} {}".format(cmd, "summary") - if del_action: - cmd = "no {}".format(cmd) + if del_action: + cmd = "no {}".format(cmd) - config_data.append(cmd) + config_data.append(cmd) - result = create_common_configuration(tgen, router, config_data, - "bgp", build=build) - except InvalidCLIError: - # Traceback - errormsg = traceback.format_exc() - logger.error(errormsg) - return errormsg - - logger.debug("Exiting lib API: create_bgp_global()") - return result + return config_data -def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, build=False): +def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, + config_data=None): """ Helper API to create configuration for address-family unicast @@ -240,124 +240,118 @@ def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, build=False): * `build` : Only for initial setup phase this is set as True. """ - result = False logger.debug("Entering lib API: __create_bgp_unicast_neighbor()") - try: - config_data = ["router bgp"] - bgp_data = input_dict[router]["bgp"]["address_family"] - for addr_type, addr_dict in bgp_data.iteritems(): - if not addr_dict: - continue + add_neigh = True + if "router bgp "in config_data: + add_neigh = False + bgp_data = input_dict[router]["bgp"]["address_family"] - if not check_address_types(addr_type): - continue + for addr_type, addr_dict in bgp_data.iteritems(): + if not addr_dict: + continue + if not check_address_types(addr_type): + continue + + addr_data = addr_dict["unicast"] + if addr_data: config_data.append("address-family {} unicast".format( addr_type )) - addr_data = addr_dict["unicast"] - advertise_network = addr_data.setdefault("advertise_networks", - []) - for advertise_network_dict in advertise_network: - network = advertise_network_dict["network"] - if type(network) is not list: - network = [network] - - if "no_of_network" in advertise_network_dict: - no_of_network = advertise_network_dict["no_of_network"] - else: - no_of_network = 1 - - del_action = advertise_network_dict.setdefault("delete", - False) + advertise_network = addr_data.setdefault("advertise_networks", + []) + for advertise_network_dict in advertise_network: + network = advertise_network_dict["network"] + if type(network) is not list: + network = [network] + + if "no_of_network" in advertise_network_dict: + no_of_network = advertise_network_dict["no_of_network"] + else: + no_of_network = 1 - # Generating IPs for verification - prefix = str( - ipaddr.IPNetwork(unicode(network[0])).prefixlen) - network_list = generate_ips(network, no_of_network) - for ip in network_list: - ip = str(ipaddr.IPNetwork(unicode(ip)).network) + del_action = advertise_network_dict.setdefault("delete", + False) - cmd = "network {}/{}\n".format(ip, prefix) - if del_action: - cmd = "no {}".format(cmd) + # Generating IPs for verification + prefix = str( + ipaddr.IPNetwork(unicode(network[0])).prefixlen) + network_list = generate_ips(network, no_of_network) + for ip in network_list: + ip = str(ipaddr.IPNetwork(unicode(ip)).network) - config_data.append(cmd) + cmd = "network {}/{}".format(ip, prefix) + if del_action: + cmd = "no {}".format(cmd) - max_paths = addr_data.setdefault("maximum_paths", {}) - if max_paths: - ibgp = max_paths.setdefault("ibgp", None) - ebgp = max_paths.setdefault("ebgp", None) - if ibgp: - config_data.append("maximum-paths ibgp {}".format( - ibgp - )) - if ebgp: - config_data.append("maximum-paths {}".format( - ebgp - )) - - aggregate_address = addr_data.setdefault("aggregate_address", - {}) - if aggregate_address: - ip = aggregate_address("network", None) - attribute = aggregate_address("attribute", None) - if ip: - cmd = "aggregate-address {}".format(ip) - if attribute: - cmd = "{} {}".format(cmd, attribute) + config_data.append(cmd) - config_data.append(cmd) + max_paths = addr_data.setdefault("maximum_paths", {}) + if max_paths: + ibgp = max_paths.setdefault("ibgp", None) + ebgp = max_paths.setdefault("ebgp", None) + if ibgp: + config_data.append("maximum-paths ibgp {}".format( + ibgp + )) + if ebgp: + config_data.append("maximum-paths {}".format( + ebgp + )) + + aggregate_address = addr_data.setdefault("aggregate_address", + {}) + if aggregate_address: + ip = aggregate_address("network", None) + attribute = aggregate_address("attribute", None) + if ip: + cmd = "aggregate-address {}".format(ip) + if attribute: + cmd = "{} {}".format(cmd, attribute) - redistribute_data = addr_data.setdefault("redistribute", {}) - if redistribute_data: - for redistribute in redistribute_data: - if "redist_type" not in redistribute: - logger.error("Router %s: 'redist_type' not present in " - "input_dict", router) - else: - cmd = "redistribute {}".format( - redistribute["redist_type"]) - redist_attr = redistribute.setdefault("attribute", - None) - if redist_attr: - cmd = "{} {}".format(cmd, redist_attr) - del_action = redistribute.setdefault("delete", False) - if del_action: - cmd = "no {}".format(cmd) - config_data.append(cmd) + config_data.append(cmd) - if "neighbor" in addr_data: - neigh_data = __create_bgp_neighbor(topo, input_dict, - router, addr_type) - config_data.extend(neigh_data) + redistribute_data = addr_data.setdefault("redistribute", {}) + if redistribute_data: + for redistribute in redistribute_data: + if "redist_type" not in redistribute: + logger.error("Router %s: 'redist_type' not present in " + "input_dict", router) + else: + cmd = "redistribute {}".format( + redistribute["redist_type"]) + redist_attr = redistribute.setdefault("attribute", + None) + if redist_attr: + cmd = "{} {}".format(cmd, redist_attr) + del_action = redistribute.setdefault("delete", False) + if del_action: + cmd = "no {}".format(cmd) + config_data.append(cmd) - for addr_type, addr_dict in bgp_data.iteritems(): - if not addr_dict or not check_address_types(addr_type): - continue + if "neighbor" in addr_data: + neigh_data = __create_bgp_neighbor(topo, input_dict, + router, addr_type, add_neigh) + config_data.extend(neigh_data) - addr_data = addr_dict["unicast"] - if "neighbor" in addr_data: - neigh_addr_data = __create_bgp_unicast_address_family( - topo, input_dict, router, addr_type) + for addr_type, addr_dict in bgp_data.iteritems(): + if not addr_dict or not check_address_types(addr_type): + continue - config_data.extend(neigh_addr_data) + addr_data = addr_dict["unicast"] + if "neighbor" in addr_data: + neigh_addr_data = __create_bgp_unicast_address_family( + topo, input_dict, router, addr_type, add_neigh) - result = create_common_configuration(tgen, router, config_data, - None, build=build) + config_data.extend(neigh_addr_data) - except InvalidCLIError: - # Traceback - errormsg = traceback.format_exc() - logger.error(errormsg) - return errormsg logger.debug("Exiting lib API: __create_bgp_unicast_neighbor()") - return result + return config_data -def __create_bgp_neighbor(topo, input_dict, router, addr_type): +def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True): """ Helper API to create neighbor specific configuration @@ -391,7 +385,8 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type): neigh_cxt = "neighbor {}".format(ip_addr) - config_data.append("{} remote-as {}".format(neigh_cxt, remote_as)) + if add_neigh: + config_data.append("{} remote-as {}".format(neigh_cxt, remote_as)) if addr_type == "ipv6": config_data.append("address-family ipv6 unicast") config_data.append("{} activate".format(neigh_cxt)) @@ -429,7 +424,8 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type): return config_data -def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type): +def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type, + add_neigh=True): """ API prints bgp global config to bgp_json file. @@ -474,9 +470,9 @@ def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type): dest_link]["ipv6"].split("/")[0] neigh_cxt = "neighbor {}".format(ip_addr) - config_data.append("address-family {} unicast".format( - addr_type - )) + #config_data.append("address-family {} unicast".format( + # addr_type + #)) if deactivate: config_data.append( "no neighbor {} activate".format(deactivate)) @@ -531,6 +527,7 @@ def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type): ############################################# # Verification APIs ############################################# +@retry(attempts=3, wait=2, return_is_str=True) def verify_router_id(tgen, topo, input_dict): """ Running command "show ip bgp json" for DUT and reading router-id @@ -565,7 +562,7 @@ def verify_router_id(tgen, topo, input_dict): errormsg(str) or True """ - logger.info("Entering lib API: verify_router_id()") + logger.debug("Entering lib API: verify_router_id()") for router in input_dict.keys(): if router not in tgen.routers(): continue @@ -576,9 +573,9 @@ def verify_router_id(tgen, topo, input_dict): "del_router_id", False) logger.info("Checking router %s router-id", router) - show_bgp_json = rnode.vtysh_cmd("show ip bgp json", + show_bgp_json = run_frr_cmd(rnode, "show bgp summary json", isjson=True) - router_id_out = show_bgp_json["routerId"] + router_id_out = show_bgp_json["ipv4Unicast"]["routerId"] router_id_out = ipaddr.IPv4Address(unicode(router_id_out)) # Once router-id is deleted, highest interface ip should become @@ -598,100 +595,84 @@ def verify_router_id(tgen, topo, input_dict): router_id_out) return errormsg - logger.info("Exiting lib API: verify_router_id()") + logger.debug("Exiting lib API: verify_router_id()") return True +@retry(attempts=20, wait=2, return_is_str=True) def verify_bgp_convergence(tgen, topo): """ API will verify if BGP is converged with in the given time frame. Running "show bgp summary json" command and verify bgp neighbor state is established, - Parameters ---------- * `tgen`: topogen object * `topo`: input json file data * `addr_type`: ip_type, ipv4/ipv6 - Usage ----- # To veriry is BGP is converged for all the routers used in topology results = verify_bgp_convergence(tgen, topo, "ipv4") - Returns ------- errormsg(str) or True """ - logger.info("Entering lib API: verify_bgp_confergence()") + logger.debug("Entering lib API: verify_bgp_convergence()") for router, rnode in tgen.routers().iteritems(): - logger.info("Verifying BGP Convergence on router %s:", router) - - for retry in range(1, 11): - show_bgp_json = rnode.vtysh_cmd("show bgp summary json", - isjson=True) - # Verifying output dictionary show_bgp_json is empty or not - if not bool(show_bgp_json): - errormsg = "BGP is not running" - return errormsg + logger.info("Verifying BGP Convergence on router %s", router) + show_bgp_json = run_frr_cmd(rnode, "show bgp summary json", + isjson=True) + # Verifying output dictionary show_bgp_json is empty or not + if not bool(show_bgp_json): + errormsg = "BGP is not running" + return errormsg - # To find neighbor ip type + # To find neighbor ip type + bgp_addr_type = topo["routers"][router]["bgp"]["address_family"] + for addr_type in bgp_addr_type.keys(): + if not check_address_types(addr_type): + continue total_peer = 0 - bgp_addr_type = topo["routers"][router]["bgp"]["address_family"] - for addr_type in bgp_addr_type.keys(): - if not check_address_types(addr_type): - continue - - bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] - - for bgp_neighbor in bgp_neighbors: - total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"]) - - for addr_type in bgp_addr_type.keys(): - bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] - - no_of_peer = 0 - for bgp_neighbor, peer_data in bgp_neighbors.iteritems(): - for dest_link in peer_data["dest_link"].keys(): - data = topo["routers"][bgp_neighbor]["links"] - if dest_link in data: - neighbor_ip = \ - data[dest_link][addr_type].split("/")[0] - if addr_type == "ipv4": - ipv4_data = show_bgp_json["ipv4Unicast"][ - "peers"] - nh_state = ipv4_data[neighbor_ip]["state"] - else: - ipv6_data = show_bgp_json["ipv6Unicast"][ - "peers"] - nh_state = ipv6_data[neighbor_ip]["state"] - - if nh_state == "Established": - no_of_peer += 1 - if no_of_peer == total_peer: - logger.info("BGP is Converged for router %s", router) - break - else: - logger.warning("BGP is not yet Converged for router %s", - router) - sleeptime = 2 * retry - if sleeptime <= BGP_CONVERGENCE_TIMEOUT: - # Waiting for BGP to converge - logger.info("Waiting for %s sec for BGP to converge on" - " router %s...", sleeptime, router) - sleep(sleeptime) - else: - show_bgp_summary = rnode.vtysh_cmd("show bgp summary") - errormsg = "TIMEOUT!! BGP is not converged in {} " \ - "seconds for router {} \n {}".format( - BGP_CONVERGENCE_TIMEOUT, router, - show_bgp_summary) - return errormsg + bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] + + for bgp_neighbor in bgp_neighbors: + total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"]) + + for addr_type in bgp_addr_type.keys(): + if not check_address_types(addr_type): + continue + bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] - logger.info("Exiting API: verify_bgp_confergence()") + no_of_peer = 0 + for bgp_neighbor, peer_data in bgp_neighbors.iteritems(): + for dest_link in peer_data["dest_link"].keys(): + data = topo["routers"][bgp_neighbor]["links"] + if dest_link in data: + neighbor_ip = \ + data[dest_link][addr_type].split("/")[0] + if addr_type == "ipv4": + ipv4_data = show_bgp_json["ipv4Unicast"][ + "peers"] + nh_state = ipv4_data[neighbor_ip]["state"] + else: + ipv6_data = show_bgp_json["ipv6Unicast"][ + "peers"] + nh_state = ipv6_data[neighbor_ip]["state"] + + if nh_state == "Established": + no_of_peer += 1 + if no_of_peer == total_peer: + logger.info("BGP is Converged for router %s", router) + else: + errormsg = "BGP is not converged for router {}".format( + router) + return errormsg + + logger.debug("Exiting API: verify_bgp_convergence()") return True @@ -723,7 +704,7 @@ def modify_as_number(tgen, topo, input_dict): errormsg(str) or True """ - logger.info("Entering lib API: modify_as_number()") + logger.debug("Entering lib API: modify_as_number()") try: new_topo = deepcopy(topo["routers"]) @@ -757,11 +738,12 @@ def modify_as_number(tgen, topo, input_dict): logger.error(errormsg) return errormsg - logger.info("Exiting lib API: modify_as_number()") + logger.debug("Exiting lib API: modify_as_number()") return True +@retry(attempts=3, wait=2, return_is_str=True) def verify_as_numbers(tgen, topo, input_dict): """ This API is to verify AS numbers for given DUT by running @@ -791,7 +773,7 @@ def verify_as_numbers(tgen, topo, input_dict): errormsg(str) or True """ - logger.info("Entering lib API: verify_as_numbers()") + logger.debug("Entering lib API: verify_as_numbers()") for router in input_dict.keys(): if router not in tgen.routers(): continue @@ -800,7 +782,7 @@ def verify_as_numbers(tgen, topo, input_dict): logger.info("Verifying AS numbers for dut %s:", router) - show_ip_bgp_neighbor_json = rnode.vtysh_cmd( + show_ip_bgp_neighbor_json = run_frr_cmd(rnode, "show ip bgp neighbor json", isjson=True) local_as = input_dict[router]["bgp"]["local_as"] bgp_addr_type = topo["routers"][router]["bgp"]["address_family"] @@ -846,7 +828,7 @@ def verify_as_numbers(tgen, topo, input_dict): "neighbor %s, found expected: %s", router, bgp_neighbor, remote_as) - logger.info("Exiting lib API: verify_AS_numbers()") + logger.debug("Exiting lib API: verify_AS_numbers()") return True @@ -873,7 +855,7 @@ def clear_bgp_and_verify(tgen, topo, router): errormsg(str) or True """ - logger.info("Entering lib API: clear_bgp_and_verify()") + logger.debug("Entering lib API: clear_bgp_and_verify()") if router not in tgen.routers(): return False @@ -883,20 +865,14 @@ def clear_bgp_and_verify(tgen, topo, router): peer_uptime_before_clear_bgp = {} # Verifying BGP convergence before bgp clear command for retry in range(1, 11): - sleeptime = 2 * retry - if sleeptime <= BGP_CONVERGENCE_TIMEOUT: - # Waiting for BGP to converge - logger.info("Waiting for %s sec for BGP to converge on router" - " %s...", sleeptime, router) - sleep(sleeptime) - else: - errormsg = "TIMEOUT!! BGP is not converged in {} seconds for" \ - " router {}".format(BGP_CONVERGENCE_TIMEOUT, router) - return errormsg + sleeptime = 3 + # Waiting for BGP to converge + logger.info("Waiting for %s sec for BGP to converge on router" + " %s...", sleeptime, router) + sleep(sleeptime) - show_bgp_json = rnode.vtysh_cmd("show bgp summary json", + show_bgp_json = run_frr_cmd(rnode, "show bgp summary json", isjson=True) - logger.info(show_bgp_json) # Verifying output dictionary show_bgp_json is empty or not if not bool(show_bgp_json): errormsg = "BGP is not running" @@ -950,33 +926,33 @@ def clear_bgp_and_verify(tgen, topo, router): " clear", router) break else: - logger.warning("BGP is not yet Converged for router %s " - "before bgp clear", router) + logger.info("BGP is not yet Converged for router %s " + "before bgp clear", router) + else: + errormsg = "TIMEOUT!! BGP is not converged in 30 seconds for" \ + " router {}".format(router) + return errormsg logger.info(peer_uptime_before_clear_bgp) # Clearing BGP logger.info("Clearing BGP neighborship for router %s..", router) for addr_type in bgp_addr_type.keys(): if addr_type == "ipv4": - rnode.vtysh_cmd("clear ip bgp *") + run_frr_cmd(rnode, "clear ip bgp *") elif addr_type == "ipv6": - rnode.vtysh_cmd("clear bgp ipv6 *") + run_frr_cmd(rnode, "clear bgp ipv6 *") peer_uptime_after_clear_bgp = {} # Verifying BGP convergence after bgp clear command - for retry in range(1, 11): - sleeptime = 2 * retry - if sleeptime <= BGP_CONVERGENCE_TIMEOUT: - # Waiting for BGP to converge - logger.info("Waiting for %s sec for BGP to converge on router" - " %s...", sleeptime, router) - sleep(sleeptime) - else: - errormsg = "TIMEOUT!! BGP is not converged in {} seconds for" \ - " router {}".format(BGP_CONVERGENCE_TIMEOUT, router) - return errormsg + for retry in range(11): + sleeptime = 3 + # Waiting for BGP to converge + logger.info("Waiting for %s sec for BGP to converge on router" + " %s...", sleeptime, router) + sleep(sleeptime) + - show_bgp_json = rnode.vtysh_cmd("show bgp summary json", + show_bgp_json = run_frr_cmd(rnode, "show bgp summary json", isjson=True) # Verifying output dictionary show_bgp_json is empty or not if not bool(show_bgp_json): @@ -1028,9 +1004,12 @@ def clear_bgp_and_verify(tgen, topo, router): router) break else: - logger.warning("BGP is not yet Converged for router %s after" - " bgp clear", router) - + logger.info("BGP is not yet Converged for router %s after" + " bgp clear", router) + else: + errormsg = "TIMEOUT!! BGP is not converged in 30 seconds for" \ + " router {}".format(router) + return errormsg logger.info(peer_uptime_after_clear_bgp) # Comparing peerUptimeEstablishedEpoch dictionaries if peer_uptime_before_clear_bgp != peer_uptime_after_clear_bgp: @@ -1041,7 +1020,7 @@ def clear_bgp_and_verify(tgen, topo, router): " {}".format(router) return errormsg - logger.info("Exiting lib API: clear_bgp_and_verify()") + logger.debug("Exiting lib API: clear_bgp_and_verify()") return True @@ -1077,7 +1056,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict): errormsg(str) or True """ - logger.info("Entering lib API: verify_bgp_timers_and_functionality()") + logger.debug("Entering lib API: verify_bgp_timers_and_functionality()") sleep(5) router_list = tgen.routers() for router in input_dict.keys(): @@ -1090,7 +1069,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict): router) show_ip_bgp_neighbor_json = \ - rnode.vtysh_cmd("show ip bgp neighbor json", isjson=True) + run_frr_cmd(rnode, "show ip bgp neighbor json", isjson=True) bgp_addr_type = input_dict[router]["bgp"]["address_family"] @@ -1178,7 +1157,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict): sleep(keepalivetimer) sleep(2) show_bgp_json = \ - rnode.vtysh_cmd("show bgp summary json", + run_frr_cmd(rnode, "show bgp summary json", isjson=True) if addr_type == "ipv4": @@ -1192,17 +1171,13 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict): (holddowntimer - keepalivetimer): if nh_state != "Established": errormsg = "BGP neighborship has not gone " \ - "down in {} sec for neighbor {}\n" \ - "show_bgp_json: \n {} ".format( - timer, bgp_neighbor, - show_bgp_json) + "down in {} sec for neighbor {}" \ + .format(timer, bgp_neighbor) return errormsg else: logger.info("BGP neighborship is intact in %s" - " sec for neighbor %s \n " - "show_bgp_json : \n %s", - timer, bgp_neighbor, - show_bgp_json) + " sec for neighbor %s", + timer, bgp_neighbor) #################### # Shutting down peer interface and verifying that BGP @@ -1229,7 +1204,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict): sleep(keepalivetimer) sleep(2) show_bgp_json = \ - rnode.vtysh_cmd("show bgp summary json", + run_frr_cmd(rnode, "show bgp summary json", isjson=True) if addr_type == "ipv4": @@ -1242,22 +1217,19 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict): if timer == holddowntimer: if nh_state == "Established": errormsg = "BGP neighborship has not gone " \ - "down in {} sec for neighbor {}\n" \ - "show_bgp_json: \n {} ".format( - timer, bgp_neighbor, - show_bgp_json) + "down in {} sec for neighbor {}" \ + .format(timer, bgp_neighbor) return errormsg else: logger.info("BGP neighborship has gone down in" - " %s sec for neighbor %s \n" - "show_bgp_json : \n %s", - timer, bgp_neighbor, - show_bgp_json) + " %s sec for neighbor %s", + timer, bgp_neighbor) - logger.info("Exiting lib API: verify_bgp_timers_and_functionality()") + logger.debug("Exiting lib API: verify_bgp_timers_and_functionality()") return True +@retry(attempts=3, wait=2, return_is_str=True) def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, attribute): """ @@ -1319,7 +1291,7 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, sleep(2) logger.info("Verifying router %s RIB for best path:", router) - sh_ip_bgp_json = rnode.vtysh_cmd(command, isjson=True) + sh_ip_bgp_json = run_frr_cmd(rnode, command, isjson=True) for route_val in input_dict.values(): net_data = route_val["bgp"]["address_family"]["ipv4"]["unicast"] @@ -1380,7 +1352,7 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, else: command = "show ipv6 route json" - rib_routes_json = rnode.vtysh_cmd(command, isjson=True) + rib_routes_json = run_frr_cmd(rnode, command, isjson=True) # Verifying output dictionary rib_routes_json is not empty if not bool(rib_routes_json): @@ -1417,6 +1389,7 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, return True +@retry(attempts=3, wait=2, return_is_str=True) def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict, attribute): """ @@ -1451,7 +1424,7 @@ def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict, errormsg(str) or True """ - logger.info("Entering lib API: verify_best_path_as_per_admin_distance()") + logger.debug("Entering lib API: verify_best_path_as_per_admin_distance()") router_list = tgen.routers() if router not in router_list: return False @@ -1490,7 +1463,7 @@ def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict, compare = "LOWEST" # Show ip route - rib_routes_json = rnode.vtysh_cmd(command, isjson=True) + rib_routes_json = run_frr_cmd(rnode, command, isjson=True) # Verifying output dictionary rib_routes_json is not empty if not bool(rib_routes_json): diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 75880cfd28..2ec3ea255c 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -23,6 +23,11 @@ from datetime import datetime from time import sleep from subprocess import call from subprocess import STDOUT as SUB_STDOUT +from subprocess import PIPE as SUB_PIPE +from subprocess import Popen +from functools import wraps +from re import search as re_search + import StringIO import os import ConfigParser @@ -41,6 +46,7 @@ FRRCFG_FILE = "frr_json.conf" FRRCFG_BKUP_FILE = "frr_json_initial.conf" ERROR_LIST = ["Malformed", "Failure", "Unknown"] +ROUTER_LIST = [] #### CD = os.path.dirname(os.path.realpath(__file__)) @@ -142,6 +148,35 @@ class InvalidCLIError(Exception): pass +def run_frr_cmd(rnode, cmd, isjson=False): + """ + Execute frr show commands in priviledged mode + + * `rnode`: router node on which commands needs to executed + * `cmd`: Command to be executed on frr + * `isjson`: If command is to get json data or not + + :return str: + """ + + if cmd: + ret_data = rnode.vtysh_cmd(cmd, isjson=isjson) + + if True: + if isjson: + logger.debug(ret_data) + print_data = rnode.vtysh_cmd(cmd.rstrip("json"), isjson=False) + else: + print_data = ret_data + + logger.info('Output for command [ %s] on router %s:\n%s', + cmd.rstrip("json"), rnode.name, print_data) + return ret_data + + else: + raise InvalidCLIError('No actual cmd passed') + + def create_common_configuration(tgen, router, data, config_type=None, build=False): """ @@ -186,6 +221,7 @@ def create_common_configuration(tgen, router, data, config_type=None, frr_cfg_fd.write(config_map[config_type]) for line in data: frr_cfg_fd.write("{} \n".format(str(line))) + frr_cfg_fd.write("\n") except IOError as err: logger.error("Unable to open FRR Config File. error(%s): %s" % @@ -215,10 +251,13 @@ def reset_config_on_routers(tgen, routerName=None): logger.debug("Entering API: reset_config_on_routers") router_list = tgen.routers() - for rname, router in router_list.iteritems(): + for rname in ROUTER_LIST: if routerName and routerName != rname: continue + router = router_list[rname] + logger.info("Configuring router %s to initial test configuration", + rname) cfg = router.run("vtysh -c 'show running'") fname = "{}/{}/frr.sav".format(TMPDIR, rname) dname = "{}/{}/delta.conf".format(TMPDIR, rname) @@ -235,16 +274,35 @@ def reset_config_on_routers(tgen, routerName=None): f.close() - command = "/usr/lib/frr/frr-reload.py --input {}/{}/frr.sav" \ - " --test {}/{}/frr_json_initial.conf > {}". \ - format(TMPDIR, rname, TMPDIR, rname, dname) - result = call(command, shell=True, stderr=SUB_STDOUT) + run_cfg_file = "{}/{}/frr.sav".format(TMPDIR, rname) + init_cfg_file = "{}/{}/frr_json_initial.conf".format(TMPDIR, rname) + command = "/usr/lib/frr/frr-reload.py --input {} --test {} > {}". \ + format(run_cfg_file, init_cfg_file, dname) + result = call(command, shell=True, stderr=SUB_STDOUT, + stdout=SUB_PIPE) # Assert if command fail if result > 0: - errormsg = ("Command:{} is failed due to non-zero exit" - " code".format(command)) - return errormsg + logger.error("Delta file creation failed. Command executed %s", + command) + with open(run_cfg_file, 'r') as fd: + logger.info('Running configuration saved in %s is:\n%s', + run_cfg_file, fd.read()) + with open(init_cfg_file, 'r') as fd: + logger.info('Test configuration saved in %s is:\n%s', + init_cfg_file, fd.read()) + + err_cmd = ['/usr/bin/vtysh', '-m', '-f', run_cfg_file] + result = Popen(err_cmd, stdout=SUB_PIPE, stderr=SUB_PIPE) + output = result.communicate() + for out_data in output: + temp_data = out_data.decode('utf-8').lower() + for out_err in ERROR_LIST: + if out_err.lower() in temp_data: + logger.error("Found errors while validating data in" + " %s", run_cfg_file) + raise InvalidCLIError(out_data) + raise InvalidCLIError("Unknown error in %s", output) f = open(dname, "r") delta = StringIO.StringIO() @@ -264,7 +322,7 @@ def reset_config_on_routers(tgen, routerName=None): delta.write("end\n") output = router.vtysh_multicmd(delta.getvalue(), pretty_output=False) - logger.info("New configuration for router {}:".format(rname)) + delta.close() delta = StringIO.StringIO() cfg = router.run("vtysh -c 'show running'") @@ -276,6 +334,8 @@ def reset_config_on_routers(tgen, routerName=None): # Router current configuration to log file or console if # "show_router_config" is defined in "pytest.ini" if show_router_config: + logger.info("Configuration on router {} after config reset:". + format(rname)) logger.info(delta.getvalue()) delta.close() @@ -297,34 +357,39 @@ def load_config_to_router(tgen, routerName, save_bkup=False): logger.debug("Entering API: load_config_to_router") router_list = tgen.routers() - for rname, router in router_list.iteritems(): - if rname == routerName: - try: - frr_cfg_file = "{}/{}/{}".format(TMPDIR, rname, FRRCFG_FILE) - frr_cfg_bkup = "{}/{}/{}".format(TMPDIR, rname, - FRRCFG_BKUP_FILE) - with open(frr_cfg_file, "r") as cfg: - data = cfg.read() - if save_bkup: - with open(frr_cfg_bkup, "w") as bkup: - bkup.write(data) - - output = router.vtysh_multicmd(data, pretty_output=False) - for out_err in ERROR_LIST: - if out_err.lower() in output.lower(): - raise InvalidCLIError("%s" % output) - except IOError as err: - errormsg = ("Unable to open config File. error(%s):" - " %s", (err.errno, err.strerror)) - return errormsg + for rname in ROUTER_LIST: + if routerName and routerName != rname: + continue - logger.info("New configuration for router {}:".format(rname)) - new_config = router.run("vtysh -c 'show running'") + router = router_list[rname] + try: + frr_cfg_file = "{}/{}/{}".format(TMPDIR, rname, FRRCFG_FILE) + frr_cfg_bkup = "{}/{}/{}".format(TMPDIR, rname, + FRRCFG_BKUP_FILE) + with open(frr_cfg_file, "r+") as cfg: + data = cfg.read() + logger.info("Applying following configuration on router" + " {}:\n{}".format(rname, data)) + if save_bkup: + with open(frr_cfg_bkup, "w") as bkup: + bkup.write(data) + + output = router.vtysh_multicmd(data, pretty_output=False) + for out_err in ERROR_LIST: + if out_err.lower() in output.lower(): + raise InvalidCLIError("%s" % output) + + cfg.truncate(0) + except IOError as err: + errormsg = ("Unable to open config File. error(%s):" + " %s", (err.errno, err.strerror)) + return errormsg - # Router current configuration to log file or console if - # "show_router_config" is defined in "pytest.ini" - if show_router_config: - logger.info(new_config) + # Router current configuration to log file or console if + # "show_router_config" is defined in "pytest.ini" + if show_router_config: + new_config = router.run("vtysh -c 'show running'") + logger.info(new_config) logger.debug("Exting API: load_config_to_router") return True @@ -337,21 +402,25 @@ def start_topology(tgen): * `tgen` : topogen object """ - global TMPDIR + global TMPDIR, ROUTER_LIST # Starting topology tgen.start_topology() # Starting deamons + router_list = tgen.routers() + ROUTER_LIST = sorted(router_list.keys(), + key=lambda x: int(re_search('\d+', x).group(0))) TMPDIR = os.path.join(LOGDIR, tgen.modname) - for rname, router in router_list.iteritems(): + router_list = tgen.routers() + for rname in ROUTER_LIST: + router = router_list[rname] try: os.chdir(TMPDIR) - # Creating rouer named dir and empty zebra.conf bgpd.conf files + # Creating router named dir and empty zebra.conf bgpd.conf files # inside the current directory - if os.path.isdir('{}'.format(rname)): os.system("rm -rf {}".format(rname)) os.mkdir('{}'.format(rname)) @@ -371,13 +440,11 @@ def start_topology(tgen): router.load_config( TopoRouter.RD_ZEBRA, '{}/{}/zebra.conf'.format(TMPDIR, rname) - # os.path.join(tmpdir, '{}/zebra.conf'.format(rname)) ) # Loading empty bgpd.conf file to router, to start the bgp deamon router.load_config( TopoRouter.RD_BGP, '{}/{}/bgpd.conf'.format(TMPDIR, rname) - # os.path.join(tmpdir, '{}/bgpd.conf'.format(rname)) ) # Starting routers @@ -548,7 +615,7 @@ def write_test_header(tc_name): """ Display message at beginning of test case""" count = 20 logger.info("*"*(len(tc_name)+count)) - logger.info("START -> Testcase : %s", tc_name) + logger.info("START -> Testcase : %s" % tc_name) logger.info("*"*(len(tc_name)+count)) @@ -556,10 +623,65 @@ def write_test_footer(tc_name): """ Display message at end of test case""" count = 21 logger.info("="*(len(tc_name)+count)) - logger.info("PASSED -> Testcase : %s", tc_name) + logger.info("Testcase : %s -> PASSED", tc_name) logger.info("="*(len(tc_name)+count)) +def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0): + """ + Retries function execution, if return is an errormsg or exception + + * `attempts`: Number of attempts to make + * `wait`: Number of seconds to wait between each attempt + * `return_is_str`: Return val is an errormsg in case of failure + * `initial_wait`: Sleeps for this much seconds before executing function + + """ + + def _retry(func): + + @wraps(func) + def func_retry(*args, **kwargs): + _wait = kwargs.pop('wait', wait) + _attempts = kwargs.pop('attempts', attempts) + _attempts = int(_attempts) + if _attempts < 0: + raise ValueError("attempts must be 0 or greater") + + if initial_wait > 0: + logger.info("Waiting for [%s]s as initial delay", initial_wait) + sleep(initial_wait) + + _return_is_str = kwargs.pop('return_is_str', return_is_str) + for i in range(1, _attempts + 1): + try: + _expected = kwargs.setdefault('expected', True) + kwargs.pop('expected') + ret = func(*args, **kwargs) + logger.debug("Function returned %s" % ret) + if return_is_str and isinstance(ret, bool): + return ret + elif return_is_str and _expected is False: + return ret + + if _attempts == i: + return ret + except Exception as err: + if _attempts == i: + logger.info("Max number of attempts (%r) reached", + _attempts) + raise + else: + logger.info("Function returned %s", err) + if i < _attempts: + logger.info("Retry [#%r] after sleeping for %ss" + % (i, _wait)) + sleep(_wait) + func_retry._original = func + return func_retry + return _retry + + ############################################# # These APIs, will used by testcase ############################################# @@ -589,17 +711,17 @@ def create_interfaces_cfg(tgen, topo, build=False): interface_name = destRouterLink else: interface_name = data["interface"] - interface_data.append("interface {}\n".format( + interface_data.append("interface {}".format( str(interface_name) )) if "ipv4" in data: intf_addr = c_data["links"][destRouterLink]["ipv4"] - interface_data.append("ip address {}\n".format( + interface_data.append("ip address {}".format( intf_addr )) if "ipv6" in data: intf_addr = c_data["links"][destRouterLink]["ipv6"] - interface_data.append("ipv6 address {}\n".format( + interface_data.append("ipv6 address {}".format( intf_addr )) result = create_common_configuration(tgen, c_router, @@ -662,7 +784,7 @@ def create_static_routes(tgen, input_dict, build=False): for router in input_dict.keys(): if "static_routes" not in input_dict[router]: errormsg = "static_routes not present in input_dict" - logger.info(errormsg) + logger.debug(errormsg) continue static_routes_list = [] @@ -768,7 +890,7 @@ def create_prefix_lists(tgen, input_dict, build=False): for router in input_dict.keys(): if "prefix_lists" not in input_dict[router]: errormsg = "prefix_lists not present in input_dict" - logger.info(errormsg) + logger.debug(errormsg) continue config_data = [] @@ -922,7 +1044,7 @@ def create_route_maps(tgen, input_dict, build=False): for router in input_dict.keys(): if "route_maps" not in input_dict[router]: errormsg = "route_maps not present in input_dict" - logger.info(errormsg) + logger.debug(errormsg) continue rmap_data = [] for rmap_name, rmap_value in \ @@ -1014,7 +1136,7 @@ def create_route_maps(tgen, input_dict, build=False): # Weight if weight: - rmap_data.append("set weight {} \n".format( + rmap_data.append("set weight {}".format( weight)) # Adding MATCH and SET sequence to RMAP if defined @@ -1092,7 +1214,8 @@ def create_route_maps(tgen, input_dict, build=False): ############################################# # Verification APIs ############################################# -def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): +@retry(attempts=10, return_is_str=True, initial_wait=2) +def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): """ Data will be read from input_dict or input JSON file, API will generate same prefixes, which were redistributed by either create_static_routes() or @@ -1140,7 +1263,7 @@ def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): errormsg(str) or True """ - logger.info("Entering lib API: verify_rib()") + logger.debug("Entering lib API: verify_rib()") router_list = tgen.routers() for routerInput in input_dict.keys(): @@ -1160,9 +1283,8 @@ def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): else: command = "show ipv6 route json" - sleep(10) logger.info("Checking router %s RIB:", router) - rib_routes_json = rnode.vtysh_cmd(command, isjson=True) + rib_routes_json = run_frr_cmd(rnode, command, isjson=True) # Verifying output dictionary rib_routes_json is not empty if bool(rib_routes_json) is False: @@ -1257,30 +1379,10 @@ def _verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): logger.info("Verified routes in router %s RIB, found routes" " are: %s", dut, found_routes) - logger.info("Exiting lib API: verify_rib()") + logger.debug("Exiting lib API: verify_rib()") return True -def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None, expected=True): - """ - Wrapper function for `_verify_rib` that tries multiple time to get results. - - When the expected result is `False` we actually should expect for an string instead. - """ - - # Use currying to hide the parameters and create a test function. - test_func = partial(_verify_rib, tgen, addr_type, dut, input_dict, next_hop, protocol) - - # Call the test function and expect it to return True, otherwise try it again. - if expected is True: - _, result = topotest.run_and_expect(test_func, True, count=20, wait=6) - else: - _, result = topotest.run_and_expect_type(test_func, str, count=20, wait=6) - - # Return as normal. - return result - - def verify_admin_distance_for_static_routes(tgen, input_dict): """ API to verify admin distance for static routes as defined in input_dict/ @@ -1311,7 +1413,7 @@ def verify_admin_distance_for_static_routes(tgen, input_dict): errormsg(str) or True """ - logger.info("Entering lib API: verify_admin_distance_for_static_routes()") + logger.debug("Entering lib API: verify_admin_distance_for_static_routes()") for router in input_dict.keys(): if router not in tgen.routers(): @@ -1326,7 +1428,7 @@ def verify_admin_distance_for_static_routes(tgen, input_dict): command = "show ip route json" else: command = "show ipv6 route json" - show_ip_route_json = rnode.vtysh_cmd(command, isjson=True) + show_ip_route_json = run_frr_cmd(rnode, command, isjson=True) logger.info("Verifying admin distance for static route %s" " under dut %s:", static_route, router) @@ -1356,7 +1458,7 @@ def verify_admin_distance_for_static_routes(tgen, input_dict): format(network, router)) return errormsg - logger.info("Exiting lib API: verify_admin_distance_for_static_routes()") + logger.debug("Exiting lib API: verify_admin_distance_for_static_routes()") return True @@ -1384,7 +1486,7 @@ def verify_prefix_lists(tgen, input_dict): errormsg(str) or True """ - logger.info("Entering lib API: verify_prefix_lists()") + logger.debug("Entering lib API: verify_prefix_lists()") for router in input_dict.keys(): if router not in tgen.routers(): @@ -1393,7 +1495,7 @@ def verify_prefix_lists(tgen, input_dict): rnode = tgen.routers()[router] # Show ip prefix list - show_prefix_list = rnode.vtysh_cmd("show ip prefix-list") + show_prefix_list = run_frr_cmd(rnode, "show ip prefix-list") # Verify Prefix list is deleted prefix_lists_addr = input_dict[router]["prefix_lists"] @@ -1403,12 +1505,12 @@ def verify_prefix_lists(tgen, input_dict): for prefix_list in prefix_lists_addr[addr_type].keys(): if prefix_list in show_prefix_list: - errormsg = ("Prefix list {} is not deleted from router" + errormsg = ("Prefix list {} is/are present in the router" " {}".format(prefix_list, router)) return errormsg - logger.info("Prefix list %s is/are deleted successfully" + logger.info("Prefix list %s is/are not present in the router" " from router %s", prefix_list, router) - logger.info("Exiting lib API: verify_prefix_lissts()") + logger.debug("Exiting lib API: verify_prefix_lissts()") return True diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py index 4130451d2e..7a00fe4c50 100644 --- a/tests/topotests/lib/topojson.py +++ b/tests/topotests/lib/topojson.py @@ -20,6 +20,7 @@ from collections import OrderedDict from json import dumps as json_dumps +from re import search as re_search import ipaddr import pytest @@ -38,6 +39,9 @@ from lib.common_config import ( from lib.bgp import create_router_bgp +ROUTER_LIST = [] + + def build_topo_from_json(tgen, topo): """ Reads configuration from JSON file. Adds routers, creates interface @@ -48,13 +52,15 @@ def build_topo_from_json(tgen, topo): * `topo`: json file data """ - listRouters = [] - for routerN in sorted(topo['routers'].iteritems()): - logger.info('Topo: Add router {}'.format(routerN[0])) - tgen.add_router(routerN[0]) - listRouters.append(routerN[0]) + ROUTER_LIST = sorted(topo['routers'].keys(), + key=lambda x: int(re_search('\d+', x).group(0))) + + listRouters = ROUTER_LIST[:] + for routerN in ROUTER_LIST: + logger.info('Topo: Add router {}'.format(routerN)) + tgen.add_router(routerN) + listRouters.append(routerN) - listRouters.sort() if 'ipv4base' in topo: ipv4Next = ipaddr.IPv4Address(topo['link_ip_start']['ipv4']) ipv4Step = 2 ** (32 - topo['link_ip_start']['v4mask']) @@ -78,7 +84,7 @@ def build_topo_from_json(tgen, topo): elif 'link' in x: return int(x.split('-link')[1]) else: - return int(x.split('r')[1]) + return int(re_search('\d+', x).group(0)) for destRouterLink, data in sorted(topo['routers'][curRouter]['links']. \ iteritems(), key=lambda x: link_sort(x[0])): @@ -179,12 +185,13 @@ def build_config_from_json(tgen, topo, save_bkup=True): data = topo["routers"] for func_type in func_dict.keys(): - logger.info('Building configuration for {}'.format(func_type)) + logger.info('Checking for {} configuration in input data'.format( + func_type)) func_dict.get(func_type)(tgen, data, build=True) for router in sorted(topo['routers'].keys()): - logger.info('Configuring router {}...'.format(router)) + logger.debug('Configuring router {}...'.format(router)) result = load_config_to_router(tgen, router, save_bkup) if not result: diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini index 7ea38491d8..2ab994215a 100644 --- a/tests/topotests/pytest.ini +++ b/tests/topotests/pytest.ini @@ -15,7 +15,7 @@ norecursedirs = .git example-test lib docker # Display router current configuration during test execution, # by default configuration will not be shown -show_router_config = True +# show_router_config = True # Default daemons binaries path. #frrdir = /usr/lib/frr diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index fba754f626..b053392bff 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -164,9 +164,10 @@ static int vtysh_reconnect(struct vtysh_client *vclient); static void vclient_close(struct vtysh_client *vclient) { if (vclient->fd >= 0) { - vty_out(vty, - "Warning: closing connection to %s because of an I/O error!\n", - vclient->name); + if (vty->of) + vty_out(vty, + "Warning: closing connection to %s because of an I/O error!\n", + vclient->name); close(vclient->fd); /* indicate as candidate for reconnect */ vclient->fd = VTYSH_WAS_ACTIVE; @@ -237,8 +238,11 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line, continue; if (nread <= 0) { - vty_out(vty, "vtysh: error reading from %s: %s (%d)", - vclient->name, safe_strerror(errno), errno); + if (vty->of) + vty_out(vty, + "vtysh: error reading from %s: %s (%d)", + vclient->name, safe_strerror(errno), + errno); goto out_err; } @@ -383,7 +387,7 @@ static int vtysh_client_run_all(struct vtysh_client *head_client, rc_all = rc; } } - if (wrong_instance && !correct_instance) { + if (wrong_instance && !correct_instance && vty->of) { vty_out(vty, "%% [%s]: command ignored as it targets an instance that is not running\n", head_client->name); diff --git a/zebra/connected.c b/zebra/connected.c index 4101a4bf24..ffc991861c 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -120,10 +120,6 @@ struct connected *connected_check_ptp(struct interface *ifp, struct connected *ifc; struct listnode *node; - /* ignore broadcast addresses */ - if (p->prefixlen != IPV4_MAX_PREFIXLEN) - d = NULL; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { if (!prefix_same(ifc->address, p)) continue; @@ -143,6 +139,12 @@ static int connected_same(struct connected *ifc1, struct connected *ifc2) if (ifc1->ifp != ifc2->ifp) return 0; + if (ifc1->flags != ifc2->flags) + return 0; + + if (ifc1->conf != ifc2->conf) + return 0; + if (ifc1->destination) if (!ifc2->destination) return 0; @@ -154,12 +156,6 @@ static int connected_same(struct connected *ifc1, struct connected *ifc2) if (!prefix_same(ifc1->destination, ifc2->destination)) return 0; - if (ifc1->flags != ifc2->flags) - return 0; - - if (ifc1->conf != ifc2->conf) - return 0; - return 1; } @@ -276,7 +272,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) /* Add connected IPv4 route to the interface. */ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, - uint16_t prefixlen, struct in_addr *broad, + uint16_t prefixlen, struct in_addr *dest, const char *label, uint32_t metric) { struct prefix_ipv4 *p; @@ -302,59 +298,39 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, : prefixlen; ifc->address = (struct prefix *)p; - /* If there is broadcast or peer address. */ - if (broad) { - p = prefix_ipv4_new(); - p->family = AF_INET; - p->prefix = *broad; - p->prefixlen = prefixlen; - ifc->destination = (struct prefix *)p; - + /* If there is a peer address. */ + if (CONNECTED_PEER(ifc)) { /* validate the destination address */ - if (CONNECTED_PEER(ifc)) { - if (IPV4_ADDR_SAME(addr, broad)) + if (dest) { + p = prefix_ipv4_new(); + p->family = AF_INET; + p->prefix = *dest; + p->prefixlen = prefixlen; + ifc->destination = (struct prefix *)p; + + if (IPV4_ADDR_SAME(addr, dest)) flog_warn( EC_ZEBRA_IFACE_SAME_LOCAL_AS_PEER, "warning: interface %s has same local and peer " "address %s, routing protocols may malfunction", ifp->name, inet_ntoa(*addr)); } else { - if (broad->s_addr - != ipv4_broadcast_addr(addr->s_addr, prefixlen)) { - char buf[2][INET_ADDRSTRLEN]; - struct in_addr bcalc; - bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr, - prefixlen); - flog_warn( - EC_ZEBRA_BCAST_ADDR_MISMATCH, - "warning: interface %s broadcast addr %s/%d != " - "calculated %s, routing protocols may malfunction", - ifp->name, - inet_ntop(AF_INET, broad, buf[0], - sizeof(buf[0])), - prefixlen, - inet_ntop(AF_INET, &bcalc, buf[1], - sizeof(buf[1]))); - } - } - - } else { - if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) { zlog_debug( "warning: %s called for interface %s " "with peer flag set, but no peer address supplied", __func__, ifp->name); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } - - /* no broadcast or destination address was supplied */ - if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp)) - zlog_debug( - "warning: PtP interface %s with addr %s/%d needs a " - "peer address", - ifp->name, inet_ntoa(*addr), prefixlen); } + /* no destination address was supplied */ + if (!dest && (prefixlen == IPV4_MAX_PREFIXLEN) + && if_is_pointopoint(ifp)) + zlog_debug( + "warning: PtP interface %s with addr %s/%d needs a " + "peer address", + ifp->name, inet_ntoa(*addr), prefixlen); + /* Label of this address. */ if (label) ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); @@ -464,7 +440,7 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p) /* Delete connected IPv4 route to the interface. */ void connected_delete_ipv4(struct interface *ifp, int flags, struct in_addr *addr, uint16_t prefixlen, - struct in_addr *broad) + struct in_addr *dest) { struct prefix p, d; struct connected *ifc; @@ -475,10 +451,10 @@ void connected_delete_ipv4(struct interface *ifp, int flags, p.prefixlen = CHECK_FLAG(flags, ZEBRA_IFA_PEER) ? IPV4_MAX_PREFIXLEN : prefixlen; - if (broad) { + if (dest) { memset(&d, 0, sizeof(struct prefix)); d.family = AF_INET; - d.u.prefix4 = *broad; + d.u.prefix4 = *dest; d.prefixlen = prefixlen; ifc = connected_check_ptp(ifp, &p, &d); } else @@ -489,7 +465,7 @@ void connected_delete_ipv4(struct interface *ifp, int flags, /* Add connected IPv6 route to the interface. */ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, - struct in6_addr *broad, uint16_t prefixlen, + struct in6_addr *dest, uint16_t prefixlen, const char *label, uint32_t metric) { struct prefix_ipv6 *p; @@ -514,10 +490,10 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, p->prefixlen = prefixlen; ifc->address = (struct prefix *)p; - if (broad) { + if (dest) { p = prefix_ipv6_new(); p->family = AF_INET6; - IPV6_ADDR_COPY(&p->prefix, broad); + IPV6_ADDR_COPY(&p->prefix, dest); p->prefixlen = prefixlen; ifc->destination = (struct prefix *)p; } else { @@ -547,7 +523,7 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, } void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address, - struct in6_addr *broad, uint16_t prefixlen) + struct in6_addr *dest, uint16_t prefixlen) { struct prefix p, d; struct connected *ifc; @@ -557,10 +533,10 @@ void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address, memcpy(&p.u.prefix6, address, sizeof(struct in6_addr)); p.prefixlen = prefixlen; - if (broad) { + if (dest) { memset(&d, 0, sizeof(struct prefix)); d.family = AF_INET6; - IPV6_ADDR_COPY(&d.u.prefix6, broad); + IPV6_ADDR_COPY(&d.u.prefix6, dest); d.prefixlen = prefixlen; ifc = connected_check_ptp(ifp, &p, &d); } else diff --git a/zebra/connected.h b/zebra/connected.h index 7672bec006..14f6cb2db0 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -40,12 +40,12 @@ extern struct connected *connected_check_ptp(struct interface *ifp, extern void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, uint16_t prefixlen, - struct in_addr *broad, const char *label, + struct in_addr *dest, const char *label, uint32_t metric); extern void connected_delete_ipv4(struct interface *ifp, int flags, struct in_addr *addr, uint16_t prefixlen, - struct in_addr *broad); + struct in_addr *dest); extern void connected_delete_ipv4_unnumbered(struct connected *ifc); @@ -53,12 +53,12 @@ extern void connected_up(struct interface *ifp, struct connected *ifc); extern void connected_down(struct interface *ifp, struct connected *ifc); extern void connected_add_ipv6(struct interface *ifp, int flags, - struct in6_addr *address, struct in6_addr *broad, + struct in6_addr *address, struct in6_addr *dest, uint16_t prefixlen, const char *label, uint32_t metric); extern void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address, - struct in6_addr *broad, uint16_t prefixlen); + struct in6_addr *dest, uint16_t prefixlen); extern int connected_is_unnumbered(struct interface *); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 2c536c5d1f..e157c2d70a 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -888,11 +888,13 @@ static int netlink_address_ctx(const struct zebra_dplane_ctx *ctx) p = dplane_ctx_get_intf_dest(ctx); addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &p->u.prefix, bytelen); - } else if (cmd == RTM_NEWADDR && - dplane_ctx_intf_has_dest(ctx)) { - p = dplane_ctx_get_intf_dest(ctx); + } else if (cmd == RTM_NEWADDR) { + struct in_addr broad = { + .s_addr = ipv4_broadcast_addr(p->u.prefix4.s_addr, + p->prefixlen) + }; addattr_l(&req.n, sizeof(req), IFA_BROADCAST, - &p->u.prefix, bytelen); + &broad, bytelen); } } @@ -1065,7 +1067,7 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) else connected_delete_ipv4( ifp, flags, (struct in_addr *)addr, - ifa->ifa_prefixlen, (struct in_addr *)broad); + ifa->ifa_prefixlen, NULL); } if (ifa->ifa_family == AF_INET6) { if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) { @@ -1091,8 +1093,7 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) metric); } else connected_delete_ipv6(ifp, (struct in6_addr *)addr, - (struct in6_addr *)broad, - ifa->ifa_prefixlen); + NULL, ifa->ifa_prefixlen); } return 0; diff --git a/zebra/interface.c b/zebra/interface.c index a2f80aff4e..6486c01430 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1081,12 +1081,10 @@ static void connected_dump_vty(struct vty *vty, struct connected *connected) vty_out(vty, "/%d", p->prefixlen); /* If there is destination address, print it. */ - if (connected->destination) { - vty_out(vty, - (CONNECTED_PEER(connected) ? " peer " : " broadcast ")); + if (CONNECTED_PEER(connected) && connected->destination) { + vty_out(vty, " peer "); prefix_vty_out(vty, connected->destination); - if (CONNECTED_PEER(connected)) - vty_out(vty, "/%d", connected->destination->prefixlen); + vty_out(vty, "/%d", connected->destination->prefixlen); } if (CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY)) @@ -2684,12 +2682,6 @@ static int ip_address_install(struct vty *vty, struct interface *ifp, p = prefix_ipv4_new(); *p = pp; ifc->destination = (struct prefix *)p; - } else if (p->prefixlen <= IPV4_MAX_PREFIXLEN - 2) { - p = prefix_ipv4_new(); - *p = lp; - p->prefix.s_addr = ipv4_broadcast_addr(p->prefix.s_addr, - p->prefixlen); - ifc->destination = (struct prefix *)p; } /* Label. */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 3655763164..cc73effaf9 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1019,33 +1019,28 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, label_buf[0] = '\0'; assert(nexthop); - for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) { - char label_buf1[20]; + char label_buf1[20]; - nh_label = nh->nh_label; - if (!nh_label || !nh_label->num_labels) - continue; + nh_label = nexthop->nh_label; - for (int i = 0; i < nh_label->num_labels; i++) { - if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) - continue; + for (int i = 0; nh_label && i < nh_label->num_labels; i++) { + if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) + continue; - if (IS_ZEBRA_DEBUG_KERNEL) { - if (!num_labels) - sprintf(label_buf, "label %u", - nh_label->label[i]); - else { - sprintf(label_buf1, "/%u", - nh_label->label[i]); - strlcat(label_buf, label_buf1, - sizeof(label_buf)); - } + if (IS_ZEBRA_DEBUG_KERNEL) { + if (!num_labels) + sprintf(label_buf, "label %u", + nh_label->label[i]); + else { + sprintf(label_buf1, "/%u", nh_label->label[i]); + strlcat(label_buf, label_buf1, + sizeof(label_buf)); } - - out_lse[num_labels] = - mpls_lse_encode(nh_label->label[i], 0, 0, 0); - num_labels++; } + + out_lse[num_labels] = + mpls_lse_encode(nh_label->label[i], 0, 0, 0); + num_labels++; } if (num_labels) { @@ -1210,33 +1205,28 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, label_buf[0] = '\0'; assert(nexthop); - for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) { - char label_buf1[20]; + char label_buf1[20]; - nh_label = nh->nh_label; - if (!nh_label || !nh_label->num_labels) - continue; + nh_label = nexthop->nh_label; - for (int i = 0; i < nh_label->num_labels; i++) { - if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) - continue; + for (int i = 0; nh_label && i < nh_label->num_labels; i++) { + if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) + continue; - if (IS_ZEBRA_DEBUG_KERNEL) { - if (!num_labels) - sprintf(label_buf, "label %u", - nh_label->label[i]); - else { - sprintf(label_buf1, "/%u", - nh_label->label[i]); - strlcat(label_buf, label_buf1, - sizeof(label_buf)); - } + if (IS_ZEBRA_DEBUG_KERNEL) { + if (!num_labels) + sprintf(label_buf, "label %u", + nh_label->label[i]); + else { + sprintf(label_buf1, "/%u", nh_label->label[i]); + strlcat(label_buf, label_buf1, + sizeof(label_buf)); } - - out_lse[num_labels] = - mpls_lse_encode(nh_label->label[i], 0, 0, 0); - num_labels++; } + + out_lse[num_labels] = + mpls_lse_encode(nh_label->label[i], 0, 0, 0); + num_labels++; } if (num_labels) { diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 5414502fa3..512a9b4021 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -134,7 +134,7 @@ struct dplane_intf_info { #define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */ #define DPLANE_INTF_SECONDARY (1 << 1) #define DPLANE_INTF_BROADCAST (1 << 2) -#define DPLANE_INTF_HAS_DEST (1 << 3) +#define DPLANE_INTF_HAS_DEST DPLANE_INTF_CONNECTED #define DPLANE_INTF_HAS_LABEL (1 << 4) /* Interface address/prefix */ @@ -2022,9 +2022,6 @@ static enum zebra_dplane_result intf_addr_update_internal( ctx->u.intf.dest_prefix = *(ifc->destination); ctx->u.intf.flags |= (DPLANE_INTF_CONNECTED | DPLANE_INTF_HAS_DEST); - } else if (ifc->destination) { - ctx->u.intf.dest_prefix = *(ifc->destination); - ctx->u.intf.flags |= DPLANE_INTF_HAS_DEST; } if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index f4b86f3cfe..895a545bfe 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -25,6 +25,7 @@ #include "lib/nexthop.h" #include "lib/nexthop_group_private.h" #include "lib/routemap.h" +#include "lib/mpls.h" #include "zebra/connected.h" #include "zebra/debug.h" @@ -38,6 +39,10 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, struct nexthop *nexthop) { struct nexthop *resolved_hop; + uint8_t num_labels = 0; + mpls_label_t labels[MPLS_MAX_LABELS]; + enum lsp_types_t label_type = ZEBRA_LSP_NONE; + int i = 0; resolved_hop = nexthop_new(); SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); @@ -94,11 +99,24 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, if (newhop->flags & NEXTHOP_FLAG_ONLINK) resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; - /* Copy labels of the resolved route */ - if (newhop->nh_label) - nexthop_add_labels(resolved_hop, newhop->nh_label_type, - newhop->nh_label->num_labels, - &newhop->nh_label->label[0]); + /* Copy labels of the resolved route and the parent resolving to it */ + if (newhop->nh_label) { + for (i = 0; i < newhop->nh_label->num_labels; i++) + labels[num_labels++] = newhop->nh_label->label[i]; + label_type = newhop->nh_label_type; + } + + if (nexthop->nh_label) { + for (i = 0; i < nexthop->nh_label->num_labels; i++) + labels[num_labels++] = nexthop->nh_label->label[i]; + + /* If the parent has labels, use its type */ + label_type = nexthop->nh_label_type; + } + + if (num_labels) + nexthop_add_labels(resolved_hop, label_type, num_labels, + labels); resolved_hop->rparent = nexthop; _nexthop_add(&nexthop->resolved, resolved_hop); |
