diff options
40 files changed, 5688 insertions, 1348 deletions
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index ff655048a8..9f1fe64813 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -1307,8 +1307,12 @@ static struct bmp *bmp_open(struct bmp_targets *bt, int bmp_sock) } bt->cnt_accept++; - setsockopt(bmp_sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); - setsockopt(bmp_sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); + if (setsockopt(bmp_sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) + flog_err(EC_LIB_SOCKET, "bmp: %d can't setsockopt SO_KEEPALIVE: %s(%d)", + bmp_sock, safe_strerror(errno), errno); + if (setsockopt(bmp_sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) + flog_err(EC_LIB_SOCKET, "bmp: %d can't setsockopt TCP_NODELAY: %s(%d)", + bmp_sock, safe_strerror(errno), errno); zlog_info("bmp[%s] connection established", buf); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index f8cd3de68c..e37581c8e2 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2394,8 +2394,9 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn, return 0; } -static void bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi, - struct bgp_node *rn) +static struct bgp_path_info * +bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi, + struct bgp_node *rn) { struct attr *attr_new; struct bgp_path_info *pi; @@ -2416,6 +2417,8 @@ static void bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi, pi->extra->num_labels = parent_pi->extra->num_labels; } bgp_path_info_add(rn, pi); + + return pi; } /* Install EVPN route entry in ES */ @@ -2542,7 +2545,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, break; if (!pi) - bgp_create_evpn_bgp_path_info(parent_pi, rn); + pi = bgp_create_evpn_bgp_path_info(parent_pi, rn); else { if (attrhash_cmp(pi->attr, &attr) && !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) { @@ -2606,7 +2609,7 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, break; if (!pi) - bgp_create_evpn_bgp_path_info(parent_pi, rn); + pi = bgp_create_evpn_bgp_path_info(parent_pi, rn); else { if (attrhash_cmp(pi->attr, parent_pi->attr) && !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) { @@ -3020,8 +3023,7 @@ static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf, * SVI comes up with MAC and stored in hash, triggers * bgp_mac_rescan_all_evpn_tables. */ - if (pi->attr && - memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) { + if (memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) { if (bgp_debug_update(pi->peer, NULL, NULL, 1)) { char buf1[PREFIX_STRLEN]; char attr_str[BUFSIZ] = {0}; diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 2d6523ed31..80384c12c6 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -294,7 +294,7 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, } if (!path) return; - if (path->attr && path->attr->ecommunity) { + if (path->attr->ecommunity) { /* Print attribute */ attr = path->attr; s = ecommunity_ecom2str(attr->ecommunity, diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index c8b7e5155f..9e1c89b71c 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -22,6 +22,7 @@ /* clang-format off */ #include <zebra.h> #include <pthread.h> // for pthread_mutex_unlock, pthread_mutex_lock +#include <sys/uio.h> // for writev #include "frr_pthread.h" #include "linklist.h" // for list_delete, list_delete_all_node, lis... @@ -275,35 +276,96 @@ static uint16_t bgp_write(struct peer *peer) { uint8_t type; struct stream *s; - int num; int update_last_write = 0; - unsigned int count = 0; + unsigned int count; uint32_t uo = 0; uint16_t status = 0; uint32_t wpkt_quanta_old; + int writenum = 0; + int num; + unsigned int iovsz; + unsigned int strmsz; + unsigned int total_written; + wpkt_quanta_old = atomic_load_explicit(&peer->bgp->wpkt_quanta, memory_order_relaxed); + struct stream *ostreams[wpkt_quanta_old]; + struct stream **streams = ostreams; + struct iovec iov[wpkt_quanta_old]; + + s = stream_fifo_head(peer->obuf); + + if (!s) + goto done; + + count = iovsz = 0; + while (count < wpkt_quanta_old && iovsz < array_size(iov) && s) { + ostreams[iovsz] = s; + iov[iovsz].iov_base = stream_pnt(s); + iov[iovsz].iov_len = STREAM_READABLE(s); + writenum += STREAM_READABLE(s); + s = s->next; + ++iovsz; + ++count; + } + + strmsz = iovsz; + total_written = 0; - while (count < wpkt_quanta_old && (s = stream_fifo_head(peer->obuf))) { - int writenum; - do { - writenum = stream_get_endp(s) - stream_get_getp(s); - num = write(peer->fd, stream_pnt(s), writenum); + do { + num = writev(peer->fd, iov, iovsz); - if (num < 0) { - if (!ERRNO_IO_RETRY(errno)) { - BGP_EVENT_ADD(peer, TCP_fatal_error); - SET_FLAG(status, BGP_IO_FATAL_ERR); - } else { - SET_FLAG(status, BGP_IO_TRANS_ERR); - } + if (num < 0) { + if (!ERRNO_IO_RETRY(errno)) { + BGP_EVENT_ADD(peer, TCP_fatal_error); + SET_FLAG(status, BGP_IO_FATAL_ERR); + } else { + SET_FLAG(status, BGP_IO_TRANS_ERR); + } + + break; + } else if (num != writenum) { + unsigned int msg_written = 0; + unsigned int ic = iovsz; - goto done; - } else if (num != writenum) - stream_forward_getp(s, num); + for (unsigned int i = 0; i < ic; i++) { + size_t ss = iov[i].iov_len; - } while (num != writenum); + if (ss > (unsigned int) num) + break; + + msg_written++; + iovsz--; + writenum -= ss; + num -= ss; + } + + total_written += msg_written; + + assert(total_written < count); + + memmove(&iov, &iov[msg_written], + sizeof(iov[0]) * iovsz); + streams = &streams[msg_written]; + stream_forward_getp(streams[0], num); + iov[0].iov_base = stream_pnt(streams[0]); + iov[0].iov_len = STREAM_READABLE(streams[0]); + + writenum -= num; + num = 0; + assert(writenum > 0); + } else { + total_written = strmsz; + } + + } while (num != writenum); + + /* Handle statistics */ + for (unsigned int i = 0; i < total_written; i++) { + s = stream_fifo_pop(peer->obuf); + + assert(s == ostreams[i]); /* Retrieve BGP packet type. */ stream_set_getp(s, BGP_MARKER_SIZE + 2); @@ -351,9 +413,8 @@ static uint16_t bgp_write(struct peer *peer) break; } - count++; - - stream_free(stream_fifo_pop(peer->obuf)); + stream_free(s); + ostreams[i] = NULL; update_last_write = 1; } diff --git a/bgpd/bgp_io.h b/bgpd/bgp_io.h index 14a12d3705..75d014f38e 100644 --- a/bgpd/bgp_io.h +++ b/bgpd/bgp_io.h @@ -22,7 +22,7 @@ #ifndef _FRR_BGP_IO_H #define _FRR_BGP_IO_H -#define BGP_WRITE_PACKET_MAX 10U +#define BGP_WRITE_PACKET_MAX 64U #define BGP_READ_PACKET_MAX 10U #include "bgpd/bgpd.h" diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 2d50d1c9ea..83194e010a 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -706,7 +706,7 @@ int bgp_pbr_build_and_validate_entry(struct prefix *p, if (ret < 0) return -1; /* extract actiosn from flowspec ecom list */ - if (path && path->attr && path->attr->ecommunity) { + if (path && path->attr->ecommunity) { ecom = path->attr->ecommunity; for (i = 0; i < ecom->size; i++) { ecom_eval = (struct ecommunity_val *) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 1161480548..f61d397c51 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -249,8 +249,7 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi) /* Free bgp route information. */ static void bgp_path_info_free(struct bgp_path_info *path) { - if (path->attr) - bgp_attr_unintern(&path->attr); + bgp_attr_unintern(&path->attr); bgp_unlink_nexthop(path); bgp_path_info_extra_free(&path->extra); @@ -2939,17 +2938,9 @@ static bool overlay_index_equal(afi_t afi, struct bgp_path_info *path, if (afi != AFI_L2VPN) return true; - if (!path->attr) { - memset(&temp, 0, sizeof(temp)); - path_eth_s_id = &temp.esi; - path_gw_ip = &temp.ip; - if (eth_s_id == NULL && gw_ip == NULL) - return true; - } else { - path_eth_s_id = &(path->attr->evpn_overlay.eth_s_id); - path_gw_ip = &(path->attr->evpn_overlay.gw_ip); - } + path_eth_s_id = &(path->attr->evpn_overlay.eth_s_id); + path_gw_ip = &(path->attr->evpn_overlay.gw_ip); if (gw_ip == NULL) { memset(&temp, 0, sizeof(temp)); @@ -3165,8 +3156,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, goto filtered; } - if (pi && pi->attr && - pi->attr->rmap_table_id != new_attr.rmap_table_id) { + if (pi && pi->attr->rmap_table_id != new_attr.rmap_table_id) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) /* remove from RIB previous entry */ bgp_zebra_withdraw(p, pi, bgp, safi); @@ -6719,6 +6709,10 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, /* Make default attribute. */ bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE); + /* + * This must not be NULL to satisfy Coverity SA + */ + assert(attr.aspath); switch (nhtype) { case NEXTHOP_TYPE_IFINDEX: @@ -7121,14 +7115,6 @@ void route_vty_out(struct vty *vty, struct prefix *p, /* Print attribute */ attr = path->attr; - if (!attr) { - if (json_paths) - json_object_array_add(json_paths, json_path); - else - vty_out(vty, "\n"); - - return; - } /* * If vrf id of nexthop is different from that of prefix, @@ -7713,64 +7699,56 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p, /* Print attribute */ attr = path->attr; - if (attr) { - if (((p->family == AF_INET) - && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) - || (safi == SAFI_EVPN && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) - || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP - || safi == SAFI_EVPN) { - if (json) - json_object_string_add( - json_out, "mpNexthopGlobalIn", - inet_ntoa( - attr->mp_nexthop_global_in)); - else - vty_out(vty, "%-16s", - inet_ntoa( - attr->mp_nexthop_global_in)); - } else { - if (json) - json_object_string_add( - json_out, "nexthop", - inet_ntoa(attr->nexthop)); - else - vty_out(vty, "%-16s", - inet_ntoa(attr->nexthop)); - } - } else if (((p->family == AF_INET6) - && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) - || (safi == SAFI_EVPN - && BGP_ATTR_NEXTHOP_AFI_IP6(attr)) - || (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - char buf_a[512]; - if (attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL) { - if (json) - json_object_string_add( - json_out, "mpNexthopGlobalIn", - inet_ntop( - AF_INET6, - &attr->mp_nexthop_global, - buf_a, sizeof(buf_a))); - else - vty_out(vty, "%s", - inet_ntop( - AF_INET6, - &attr->mp_nexthop_global, - buf_a, sizeof(buf_a))); - } else if (attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - snprintfrr(buf_a, sizeof(buf_a), "%pI6(%pI6)", - &attr->mp_nexthop_global, - &attr->mp_nexthop_local); - if (json) - json_object_string_add( - json_out, - "mpNexthopGlobalLocal", buf_a); - else - vty_out(vty, "%s", buf_a); - } + if (((p->family == AF_INET) + && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) + || (safi == SAFI_EVPN && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) + || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP + || safi == SAFI_EVPN) { + if (json) + json_object_string_add( + json_out, "mpNexthopGlobalIn", + inet_ntoa(attr->mp_nexthop_global_in)); + else + vty_out(vty, "%-16s", + inet_ntoa(attr->mp_nexthop_global_in)); + } else { + if (json) + json_object_string_add( + json_out, "nexthop", + inet_ntoa(attr->nexthop)); + else + vty_out(vty, "%-16s", inet_ntoa(attr->nexthop)); + } + } else if (((p->family == AF_INET6) + && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) + || (safi == SAFI_EVPN && BGP_ATTR_NEXTHOP_AFI_IP6(attr)) + || (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { + char buf_a[512]; + + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) { + if (json) + json_object_string_add( + json_out, "mpNexthopGlobalIn", + inet_ntop(AF_INET6, + &attr->mp_nexthop_global, + buf_a, sizeof(buf_a))); + else + vty_out(vty, "%s", + inet_ntop(AF_INET6, + &attr->mp_nexthop_global, + buf_a, sizeof(buf_a))); + } else if (attr->mp_nexthop_len + == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + snprintfrr(buf_a, sizeof(buf_a), "%pI6(%pI6)", + &attr->mp_nexthop_global, + &attr->mp_nexthop_local); + if (json) + json_object_string_add(json_out, + "mpNexthopGlobalLocal", + buf_a); + else + vty_out(vty, "%s", buf_a); } } @@ -7817,101 +7795,96 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p, /* Print attribute */ attr = path->attr; - if (attr) { - char buf1[BUFSIZ]; - int af = NEXTHOP_FAMILY(attr->mp_nexthop_len); + char buf1[BUFSIZ]; + int af = NEXTHOP_FAMILY(attr->mp_nexthop_len); - switch (af) { - case AF_INET: - inet_ntop(af, &attr->mp_nexthop_global_in, buf, BUFSIZ); - if (!json_path) { - vty_out(vty, "%-16s", buf); - } else { - json_object_string_add(json_nexthop, "ip", buf); + switch (af) { + case AF_INET: + inet_ntop(af, &attr->mp_nexthop_global_in, buf, BUFSIZ); + if (!json_path) { + vty_out(vty, "%-16s", buf); + } else { + json_object_string_add(json_nexthop, "ip", buf); - json_object_string_add(json_nexthop, "afi", - "ipv4"); + json_object_string_add(json_nexthop, "afi", "ipv4"); - json_object_object_add(json_path, "nexthop", - json_nexthop); - } - break; - case AF_INET6: - inet_ntop(af, &attr->mp_nexthop_global, buf, BUFSIZ); - inet_ntop(af, &attr->mp_nexthop_local, buf1, BUFSIZ); - if (!json_path) { - vty_out(vty, "%s(%s)", buf, buf1); - } else { - json_object_string_add(json_nexthop, - "ipv6Global", buf); + json_object_object_add(json_path, "nexthop", + json_nexthop); + } + break; + case AF_INET6: + inet_ntop(af, &attr->mp_nexthop_global, buf, BUFSIZ); + inet_ntop(af, &attr->mp_nexthop_local, buf1, BUFSIZ); + if (!json_path) { + vty_out(vty, "%s(%s)", buf, buf1); + } else { + json_object_string_add(json_nexthop, "ipv6Global", buf); - json_object_string_add(json_nexthop, - "ipv6LinkLocal", buf1); + json_object_string_add(json_nexthop, "ipv6LinkLocal", + buf1); - json_object_string_add(json_nexthop, "afi", - "ipv6"); + json_object_string_add(json_nexthop, "afi", "ipv6"); - json_object_object_add(json_path, "nexthop", - json_nexthop); - } - break; - default: - if (!json_path) { - vty_out(vty, "?"); - } else { - json_object_string_add(json_nexthop, "Error", - "Unsupported address-family"); - } + json_object_object_add(json_path, "nexthop", + json_nexthop); } + break; + default: + if (!json_path) { + vty_out(vty, "?"); + } else { + json_object_string_add(json_nexthop, "Error", + "Unsupported address-family"); + } + } - char *str = esi2str(&(attr->evpn_overlay.eth_s_id)); + char *str = esi2str(&(attr->evpn_overlay.eth_s_id)); - if (!json_path) - vty_out(vty, "%s", str); - else - json_object_string_add(json_overlay, "esi", str); + if (!json_path) + vty_out(vty, "%s", str); + else + json_object_string_add(json_overlay, "esi", str); - XFREE(MTYPE_TMP, str); + XFREE(MTYPE_TMP, str); - if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)p)) { - inet_ntop(AF_INET, &(attr->evpn_overlay.gw_ip.ipv4), - buf, BUFSIZ); - } else if (is_evpn_prefix_ipaddr_v6((struct prefix_evpn *)p)) { - inet_ntop(AF_INET6, &(attr->evpn_overlay.gw_ip.ipv6), - buf, BUFSIZ); - } + if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)p)) { + inet_ntop(AF_INET, &(attr->evpn_overlay.gw_ip.ipv4), buf, + BUFSIZ); + } else if (is_evpn_prefix_ipaddr_v6((struct prefix_evpn *)p)) { + inet_ntop(AF_INET6, &(attr->evpn_overlay.gw_ip.ipv6), buf, + BUFSIZ); + } - if (!json_path) - vty_out(vty, "/%s", buf); - else - json_object_string_add(json_overlay, "gw", buf); - - if (attr->ecommunity) { - char *mac = NULL; - struct ecommunity_val *routermac = ecommunity_lookup( - attr->ecommunity, ECOMMUNITY_ENCODE_EVPN, - ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC); - if (routermac) - mac = ecom_mac2str((char *)routermac->val); - if (mac) { - if (!json_path) { - vty_out(vty, "/%s", (char *)mac); - } else { - json_object_string_add(json_overlay, - "rmac", mac); - } - XFREE(MTYPE_TMP, mac); + if (!json_path) + vty_out(vty, "/%s", buf); + else + json_object_string_add(json_overlay, "gw", buf); + + if (attr->ecommunity) { + char *mac = NULL; + struct ecommunity_val *routermac = ecommunity_lookup( + attr->ecommunity, ECOMMUNITY_ENCODE_EVPN, + ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC); + + if (routermac) + mac = ecom_mac2str((char *)routermac->val); + if (mac) { + if (!json_path) { + vty_out(vty, "/%s", (char *)mac); + } else { + json_object_string_add(json_overlay, "rmac", + mac); } + XFREE(MTYPE_TMP, mac); } + } - if (!json_path) { - vty_out(vty, "\n"); - } else { - json_object_object_add(json_path, "overlay", - json_overlay); + if (!json_path) { + vty_out(vty, "\n"); + } else { + json_object_object_add(json_path, "overlay", json_overlay); - json_object_array_add(json_paths, json_path); - } + json_object_array_add(json_paths, json_path); } } @@ -7958,23 +7931,23 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p, /* Print attribute */ attr = path->attr; - if (attr) { - /* Print aspath */ - if (attr->aspath) { - if (use_json) - json_object_string_add(json, "asPath", - attr->aspath->str); - else - aspath_print_vty(vty, "%s", attr->aspath, " "); - } - /* Print origin */ + /* Print aspath */ + if (attr->aspath) { if (use_json) - json_object_string_add(json, "origin", - bgp_origin_str[attr->origin]); + json_object_string_add(json, "asPath", + attr->aspath->str); else - vty_out(vty, "%s", bgp_origin_str[attr->origin]); + aspath_print_vty(vty, "%s", attr->aspath, " "); } + + /* Print origin */ + if (use_json) + json_object_string_add(json, "origin", + bgp_origin_str[attr->origin]); + else + vty_out(vty, "%s", bgp_origin_str[attr->origin]); + if (!use_json) vty_out(vty, "\n"); } @@ -8053,23 +8026,23 @@ static void flap_route_vty_out(struct vty *vty, struct prefix *p, /* Print attribute */ attr = path->attr; - if (attr) { - /* Print aspath */ - if (attr->aspath) { - if (use_json) - json_object_string_add(json, "asPath", - attr->aspath->str); - else - aspath_print_vty(vty, "%s", attr->aspath, " "); - } - /* Print origin */ + /* Print aspath */ + if (attr->aspath) { if (use_json) - json_object_string_add(json, "origin", - bgp_origin_str[attr->origin]); + json_object_string_add(json, "asPath", + attr->aspath->str); else - vty_out(vty, "%s", bgp_origin_str[attr->origin]); + aspath_print_vty(vty, "%s", attr->aspath, " "); } + + /* Print origin */ + if (use_json) + json_object_string_add(json, "origin", + bgp_origin_str[attr->origin]); + else + vty_out(vty, "%s", bgp_origin_str[attr->origin]); + if (!use_json) vty_out(vty, "\n"); } @@ -8295,819 +8268,739 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, attr = path->attr; - if (attr) { - /* Line1 display AS-path, Aggregator */ - if (attr->aspath) { - if (json_paths) { - if (!attr->aspath->json) - aspath_str_update(attr->aspath, true); - json_object_lock(attr->aspath->json); - json_object_object_add(json_path, "aspath", - attr->aspath->json); - } else { - if (attr->aspath->segments) - aspath_print_vty(vty, " %s", - attr->aspath, ""); - else - vty_out(vty, " Local"); - } - } - - if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED)) { - if (json_paths) - json_object_boolean_true_add(json_path, - "removed"); + /* Line1 display AS-path, Aggregator */ + if (attr->aspath) { + if (json_paths) { + if (!attr->aspath->json) + aspath_str_update(attr->aspath, true); + json_object_lock(attr->aspath->json); + json_object_object_add(json_path, "aspath", + attr->aspath->json); + } else { + if (attr->aspath->segments) + aspath_print_vty(vty, " %s", attr->aspath, ""); else - vty_out(vty, ", (removed)"); + vty_out(vty, " Local"); } + } - if (CHECK_FLAG(path->flags, BGP_PATH_STALE)) { - if (json_paths) - json_object_boolean_true_add(json_path, - "stale"); - else - vty_out(vty, ", (stale)"); - } + if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED)) { + if (json_paths) + json_object_boolean_true_add(json_path, "removed"); + else + vty_out(vty, ", (removed)"); + } - if (CHECK_FLAG(attr->flag, - ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) { - if (json_paths) { - json_object_int_add(json_path, "aggregatorAs", - attr->aggregator_as); - json_object_string_add( - json_path, "aggregatorId", - inet_ntoa(attr->aggregator_addr)); - } else { - vty_out(vty, ", (aggregated by %u %s)", - attr->aggregator_as, - inet_ntoa(attr->aggregator_addr)); - } - } + if (CHECK_FLAG(path->flags, BGP_PATH_STALE)) { + if (json_paths) + json_object_boolean_true_add(json_path, "stale"); + else + vty_out(vty, ", (stale)"); + } - if (CHECK_FLAG(path->peer->af_flags[afi][safi], - PEER_FLAG_REFLECTOR_CLIENT)) { - if (json_paths) - json_object_boolean_true_add( - json_path, "rxedFromRrClient"); - else - vty_out(vty, ", (Received from a RR-client)"); + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) { + if (json_paths) { + json_object_int_add(json_path, "aggregatorAs", + attr->aggregator_as); + json_object_string_add( + json_path, "aggregatorId", + inet_ntoa(attr->aggregator_addr)); + } else { + vty_out(vty, ", (aggregated by %u %s)", + attr->aggregator_as, + inet_ntoa(attr->aggregator_addr)); } + } - if (CHECK_FLAG(path->peer->af_flags[afi][safi], - PEER_FLAG_RSERVER_CLIENT)) { - if (json_paths) - json_object_boolean_true_add( - json_path, "rxedFromRsClient"); - else - vty_out(vty, ", (Received from a RS-client)"); - } + if (CHECK_FLAG(path->peer->af_flags[afi][safi], + PEER_FLAG_REFLECTOR_CLIENT)) { + if (json_paths) + json_object_boolean_true_add(json_path, + "rxedFromRrClient"); + else + vty_out(vty, ", (Received from a RR-client)"); + } - if (CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) { - if (json_paths) - json_object_boolean_true_add( - json_path, "dampeningHistoryEntry"); - else - vty_out(vty, ", (history entry)"); - } else if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) { - if (json_paths) - json_object_boolean_true_add( - json_path, "dampeningSuppressed"); - else - vty_out(vty, ", (suppressed due to dampening)"); - } + if (CHECK_FLAG(path->peer->af_flags[afi][safi], + PEER_FLAG_RSERVER_CLIENT)) { + if (json_paths) + json_object_boolean_true_add(json_path, + "rxedFromRsClient"); + else + vty_out(vty, ", (Received from a RS-client)"); + } - if (!json_paths) - vty_out(vty, "\n"); + if (CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) { + if (json_paths) + json_object_boolean_true_add(json_path, + "dampeningHistoryEntry"); + else + vty_out(vty, ", (history entry)"); + } else if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) { + if (json_paths) + json_object_boolean_true_add(json_path, + "dampeningSuppressed"); + else + vty_out(vty, ", (suppressed due to dampening)"); + } - /* Line2 display Next-hop, Neighbor, Router-id */ - /* Display the nexthop */ - if ((bn->p.family == AF_INET || bn->p.family == AF_ETHERNET - || bn->p.family == AF_EVPN) - && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP - || safi == SAFI_EVPN - || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP - || safi == SAFI_EVPN) { - if (json_paths) - json_object_string_add( - json_nexthop_global, - nexthop_fqdn ? "fqdn" : "ip", - nexthop_fqdn - ? nexthop_fqdn - : inet_ntoa( - attr->mp_nexthop_global_in)); - else - vty_out(vty, " %s", - nexthop_fqdn - ? nexthop_fqdn - : inet_ntoa( - attr->mp_nexthop_global_in)); - } else { - if (json_paths) - json_object_string_add( - json_nexthop_global, - nexthop_fqdn ? "fqdn" : "ip", - nexthop_fqdn - ? nexthop_fqdn - : inet_ntoa( - attr->nexthop)); - else - vty_out(vty, " %s", - nexthop_fqdn - ? nexthop_fqdn - : inet_ntoa( - attr->nexthop)); - } + if (!json_paths) + vty_out(vty, "\n"); + /* Line2 display Next-hop, Neighbor, Router-id */ + /* Display the nexthop */ + if ((bn->p.family == AF_INET || bn->p.family == AF_ETHERNET + || bn->p.family == AF_EVPN) + && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN + || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP + || safi == SAFI_EVPN) { if (json_paths) - json_object_string_add(json_nexthop_global, - "afi", "ipv4"); + json_object_string_add( + json_nexthop_global, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntoa( + attr->mp_nexthop_global_in)); + else + vty_out(vty, " %s", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntoa( + attr->mp_nexthop_global_in)); } else { - if (json_paths) { + if (json_paths) json_object_string_add( json_nexthop_global, nexthop_fqdn ? "fqdn" : "ip", nexthop_fqdn ? nexthop_fqdn - : inet_ntop( - AF_INET6, - &attr->mp_nexthop_global, - buf, - INET6_ADDRSTRLEN)); - json_object_string_add(json_nexthop_global, - "afi", "ipv6"); - json_object_string_add(json_nexthop_global, - "scope", "global"); - } else { + : inet_ntoa(attr->nexthop)); + else vty_out(vty, " %s", nexthop_fqdn ? nexthop_fqdn - : inet_ntop( - AF_INET6, - &attr->mp_nexthop_global, - buf, - INET6_ADDRSTRLEN)); - } + : inet_ntoa(attr->nexthop)); } - /* Display the IGP cost or 'inaccessible' */ - if (!CHECK_FLAG(path->flags, BGP_PATH_VALID)) { - if (json_paths) - json_object_boolean_false_add( - json_nexthop_global, "accessible"); - else - vty_out(vty, " (inaccessible)"); + if (json_paths) + json_object_string_add(json_nexthop_global, "afi", + "ipv4"); + } else { + if (json_paths) { + json_object_string_add( + json_nexthop_global, + nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntop(AF_INET6, + &attr->mp_nexthop_global, + buf, INET6_ADDRSTRLEN)); + json_object_string_add(json_nexthop_global, "afi", + "ipv6"); + json_object_string_add(json_nexthop_global, "scope", + "global"); } else { - if (path->extra && path->extra->igpmetric) { - if (json_paths) - json_object_int_add( - json_nexthop_global, "metric", - path->extra->igpmetric); - else - vty_out(vty, " (metric %u)", - path->extra->igpmetric); - } + vty_out(vty, " %s", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntop(AF_INET6, + &attr->mp_nexthop_global, + buf, INET6_ADDRSTRLEN)); + } + } - /* IGP cost is 0, display this only for json */ - else { - if (json_paths) - json_object_int_add(json_nexthop_global, - "metric", 0); - } + /* Display the IGP cost or 'inaccessible' */ + if (!CHECK_FLAG(path->flags, BGP_PATH_VALID)) { + if (json_paths) + json_object_boolean_false_add(json_nexthop_global, + "accessible"); + else + vty_out(vty, " (inaccessible)"); + } else { + if (path->extra && path->extra->igpmetric) { + if (json_paths) + json_object_int_add(json_nexthop_global, + "metric", + path->extra->igpmetric); + else + vty_out(vty, " (metric %u)", + path->extra->igpmetric); + } + /* IGP cost is 0, display this only for json */ + else { if (json_paths) - json_object_boolean_true_add( - json_nexthop_global, "accessible"); + json_object_int_add(json_nexthop_global, + "metric", 0); } - /* Display peer "from" output */ - /* This path was originated locally */ - if (path->peer == bgp->peer_self) { + if (json_paths) + json_object_boolean_true_add(json_nexthop_global, + "accessible"); + } - if (safi == SAFI_EVPN - || (bn->p.family == AF_INET - && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - if (json_paths) - json_object_string_add( - json_peer, "peerId", "0.0.0.0"); - else - vty_out(vty, " from 0.0.0.0 "); - } else { - if (json_paths) - json_object_string_add(json_peer, - "peerId", "::"); - else - vty_out(vty, " from :: "); - } + /* Display peer "from" output */ + /* This path was originated locally */ + if (path->peer == bgp->peer_self) { + if (safi == SAFI_EVPN + || (bn->p.family == AF_INET + && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { if (json_paths) - json_object_string_add( - json_peer, "routerId", - inet_ntoa(bgp->router_id)); + json_object_string_add(json_peer, "peerId", + "0.0.0.0"); + else + vty_out(vty, " from 0.0.0.0 "); + } else { + if (json_paths) + json_object_string_add(json_peer, "peerId", + "::"); else - vty_out(vty, "(%s)", inet_ntoa(bgp->router_id)); + vty_out(vty, " from :: "); } - /* We RXed this path from one of our peers */ - else { - - if (json_paths) { - json_object_string_add( - json_peer, "peerId", - sockunion2str(&path->peer->su, buf, - SU_ADDRSTRLEN)); - json_object_string_add( - json_peer, "routerId", - inet_ntop(AF_INET, - &path->peer->remote_id, buf1, - sizeof(buf1))); - - if (path->peer->hostname) - json_object_string_add( - json_peer, "hostname", - path->peer->hostname); + if (json_paths) + json_object_string_add(json_peer, "routerId", + inet_ntoa(bgp->router_id)); + else + vty_out(vty, "(%s)", inet_ntoa(bgp->router_id)); + } - if (path->peer->domainname) - json_object_string_add( - json_peer, "domainname", - path->peer->domainname); + /* We RXed this path from one of our peers */ + else { - if (path->peer->conf_if) - json_object_string_add( - json_peer, "interface", + if (json_paths) { + json_object_string_add(json_peer, "peerId", + sockunion2str(&path->peer->su, + buf, + SU_ADDRSTRLEN)); + json_object_string_add(json_peer, "routerId", + inet_ntop(AF_INET, + &path->peer->remote_id, + buf1, sizeof(buf1))); + + if (path->peer->hostname) + json_object_string_add(json_peer, "hostname", + path->peer->hostname); + + if (path->peer->domainname) + json_object_string_add(json_peer, "domainname", + path->peer->domainname); + + if (path->peer->conf_if) + json_object_string_add(json_peer, "interface", + path->peer->conf_if); + } else { + if (path->peer->conf_if) { + if (path->peer->hostname + && bgp_flag_check(path->peer->bgp, + BGP_FLAG_SHOW_HOSTNAME)) + vty_out(vty, " from %s(%s)", + path->peer->hostname, + path->peer->conf_if); + else + vty_out(vty, " from %s", path->peer->conf_if); } else { - if (path->peer->conf_if) { - if (path->peer->hostname - && bgp_flag_check( - path->peer->bgp, - BGP_FLAG_SHOW_HOSTNAME)) - vty_out(vty, " from %s(%s)", - path->peer->hostname, - path->peer->conf_if); - else - vty_out(vty, " from %s", - path->peer->conf_if); - } else { - if (path->peer->hostname - && bgp_flag_check( - path->peer->bgp, - BGP_FLAG_SHOW_HOSTNAME)) - vty_out(vty, " from %s(%s)", - path->peer->hostname, - path->peer->host); - else - vty_out(vty, " from %s", - sockunion2str( - &path->peer->su, - buf, - SU_ADDRSTRLEN)); - } - - if (attr->flag - & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) - vty_out(vty, " (%s)", - inet_ntoa(attr->originator_id)); + if (path->peer->hostname + && bgp_flag_check(path->peer->bgp, + BGP_FLAG_SHOW_HOSTNAME)) + vty_out(vty, " from %s(%s)", + path->peer->hostname, + path->peer->host); else - vty_out(vty, " (%s)", - inet_ntop( - AF_INET, - &path->peer->remote_id, - buf1, sizeof(buf1))); + vty_out(vty, " from %s", + sockunion2str(&path->peer->su, + buf, + SU_ADDRSTRLEN)); } - } - /* - * Note when vrfid of nexthop is different from that of prefix - */ - if (path->extra && path->extra->bgp_orig) { - vrf_id_t nexthop_vrfid = path->extra->bgp_orig->vrf_id; + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + vty_out(vty, " (%s)", + inet_ntoa(attr->originator_id)); + else + vty_out(vty, " (%s)", + inet_ntop(AF_INET, + &path->peer->remote_id, buf1, + sizeof(buf1))); + } + } - if (json_paths) { - const char *vn; + /* + * Note when vrfid of nexthop is different from that of prefix + */ + if (path->extra && path->extra->bgp_orig) { + vrf_id_t nexthop_vrfid = path->extra->bgp_orig->vrf_id; - if (path->extra->bgp_orig->inst_type - == BGP_INSTANCE_TYPE_DEFAULT) + if (json_paths) { + const char *vn; - vn = VRF_DEFAULT_NAME; - else - vn = path->extra->bgp_orig->name; + if (path->extra->bgp_orig->inst_type + == BGP_INSTANCE_TYPE_DEFAULT) + vn = VRF_DEFAULT_NAME; + else + vn = path->extra->bgp_orig->name; - json_object_string_add(json_path, "nhVrfName", - vn); + json_object_string_add(json_path, "nhVrfName", vn); - if (nexthop_vrfid == VRF_UNKNOWN) { - json_object_int_add(json_path, - "nhVrfId", -1); - } else { - json_object_int_add(json_path, - "nhVrfId", (int)nexthop_vrfid); - } + if (nexthop_vrfid == VRF_UNKNOWN) { + json_object_int_add(json_path, "nhVrfId", -1); } else { - if (nexthop_vrfid == VRF_UNKNOWN) - vty_out(vty, " vrf ?"); - else - vty_out(vty, " vrf %u", nexthop_vrfid); + json_object_int_add(json_path, "nhVrfId", + (int)nexthop_vrfid); } + } else { + if (nexthop_vrfid == VRF_UNKNOWN) + vty_out(vty, " vrf ?"); + else + vty_out(vty, " vrf %u", nexthop_vrfid); } + } - if (nexthop_self) { - if (json_paths) { - json_object_boolean_true_add(json_path, - "announceNexthopSelf"); - } else { - vty_out(vty, " announce-nh-self"); - } + if (nexthop_self) { + if (json_paths) { + json_object_boolean_true_add(json_path, + "announceNexthopSelf"); + } else { + vty_out(vty, " announce-nh-self"); } + } - if (!json_paths) - vty_out(vty, "\n"); + if (!json_paths) + vty_out(vty, "\n"); - /* display the link-local nexthop */ - if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - if (json_paths) { - json_nexthop_ll = json_object_new_object(); - json_object_string_add( - json_nexthop_ll, - nexthop_fqdn ? "fqdn" : "ip", - nexthop_fqdn - ? nexthop_fqdn - : inet_ntop( - AF_INET6, - &attr->mp_nexthop_local, - buf, - INET6_ADDRSTRLEN)); - json_object_string_add(json_nexthop_ll, "afi", - "ipv6"); - json_object_string_add(json_nexthop_ll, "scope", - "link-local"); + /* display the link-local nexthop */ + if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + if (json_paths) { + json_nexthop_ll = json_object_new_object(); + json_object_string_add( + json_nexthop_ll, nexthop_fqdn ? "fqdn" : "ip", + nexthop_fqdn + ? nexthop_fqdn + : inet_ntop(AF_INET6, + &attr->mp_nexthop_local, + buf, INET6_ADDRSTRLEN)); + json_object_string_add(json_nexthop_ll, "afi", "ipv6"); + json_object_string_add(json_nexthop_ll, "scope", + "link-local"); + + json_object_boolean_true_add(json_nexthop_ll, + "accessible"); + if (!attr->mp_nexthop_prefer_global) json_object_boolean_true_add(json_nexthop_ll, - "accessible"); + "used"); + else + json_object_boolean_true_add( + json_nexthop_global, "used"); + } else { + vty_out(vty, " (%s) %s\n", + inet_ntop(AF_INET6, &attr->mp_nexthop_local, + buf, INET6_ADDRSTRLEN), + attr->mp_nexthop_prefer_global + ? "(prefer-global)" + : "(used)"); + } + } + /* If we do not have a link-local nexthop then we must flag the + global as "used" */ + else { + if (json_paths) + json_object_boolean_true_add(json_nexthop_global, + "used"); + } - if (!attr->mp_nexthop_prefer_global) - json_object_boolean_true_add( - json_nexthop_ll, "used"); + /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid, + * Int/Ext/Local, Atomic, best */ + if (json_paths) + json_object_string_add(json_path, "origin", + bgp_origin_long_str[attr->origin]); + else + vty_out(vty, " Origin %s", + bgp_origin_long_str[attr->origin]); + + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { + if (json_paths) { + /* + * Adding "metric" field to match with + * corresponding CLI. "med" will be + * deprecated in future. + */ + json_object_int_add(json_path, "med", attr->med); + json_object_int_add(json_path, "metric", attr->med); + } else + vty_out(vty, ", metric %u", attr->med); + } + + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { + if (json_paths) + json_object_int_add(json_path, "localpref", + attr->local_pref); + else + vty_out(vty, ", localpref %u", attr->local_pref); + } + + if (attr->weight != 0) { + if (json_paths) + json_object_int_add(json_path, "weight", attr->weight); + else + vty_out(vty, ", weight %u", attr->weight); + } + + if (attr->tag != 0) { + if (json_paths) + json_object_int_add(json_path, "tag", attr->tag); + else + vty_out(vty, ", tag %" ROUTE_TAG_PRI, attr->tag); + } + + if (!CHECK_FLAG(path->flags, BGP_PATH_VALID)) { + if (json_paths) + json_object_boolean_false_add(json_path, "valid"); + else + vty_out(vty, ", invalid"); + } else if (!CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) { + if (json_paths) + json_object_boolean_true_add(json_path, "valid"); + else + vty_out(vty, ", valid"); + } + + if (path->peer != bgp->peer_self) { + if (path->peer->as == path->peer->local_as) { + if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { + if (json_paths) + json_object_string_add( + json_peer, "type", + "confed-internal"); else - json_object_boolean_true_add( - json_nexthop_global, "used"); + vty_out(vty, ", confed-internal"); } else { - vty_out(vty, " (%s) %s\n", - inet_ntop(AF_INET6, - &attr->mp_nexthop_local, buf, - INET6_ADDRSTRLEN), - attr->mp_nexthop_prefer_global - ? "(prefer-global)" - : "(used)"); + if (json_paths) + json_object_string_add( + json_peer, "type", "internal"); + else + vty_out(vty, ", internal"); + } + } else { + if (bgp_confederation_peers_check(bgp, + path->peer->as)) { + if (json_paths) + json_object_string_add( + json_peer, "type", + "confed-external"); + else + vty_out(vty, ", confed-external"); + } else { + if (json_paths) + json_object_string_add( + json_peer, "type", "external"); + else + vty_out(vty, ", external"); } } - /* If we do not have a link-local nexthop then we must flag the - global as "used" */ - else { - if (json_paths) - json_object_boolean_true_add( - json_nexthop_global, "used"); + } else if (path->sub_type == BGP_ROUTE_AGGREGATE) { + if (json_paths) { + json_object_boolean_true_add(json_path, "aggregated"); + json_object_boolean_true_add(json_path, "local"); + } else { + vty_out(vty, ", aggregated, local"); } + } else if (path->type != ZEBRA_ROUTE_BGP) { + if (json_paths) + json_object_boolean_true_add(json_path, "sourced"); + else + vty_out(vty, ", sourced"); + } else { + if (json_paths) { + json_object_boolean_true_add(json_path, "sourced"); + json_object_boolean_true_add(json_path, "local"); + } else { + vty_out(vty, ", sourced, local"); + } + } - /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid, - * Int/Ext/Local, Atomic, best */ + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) { if (json_paths) - json_object_string_add( - json_path, "origin", - bgp_origin_long_str[attr->origin]); + json_object_boolean_true_add(json_path, + "atomicAggregate"); else - vty_out(vty, " Origin %s", - bgp_origin_long_str[attr->origin]); + vty_out(vty, ", atomic-aggregate"); + } - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { - if (json_paths) { + if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH) + || (CHECK_FLAG(path->flags, BGP_PATH_SELECTED) + && bgp_path_info_mpath_count(path))) { + if (json_paths) + json_object_boolean_true_add(json_path, "multipath"); + else + vty_out(vty, ", multipath"); + } - /* - * Adding "metric" field to match with - * corresponding CLI. "med" will be - * deprecated in future. - */ - json_object_int_add(json_path, "med", - attr->med); - json_object_int_add(json_path, "metric", - attr->med); - } else - vty_out(vty, ", metric %u", attr->med); - } + // Mark the bestpath(s) + if (CHECK_FLAG(path->flags, BGP_PATH_DMED_SELECTED)) { + first_as = aspath_get_first_as(attr->aspath); - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { - if (json_paths) - json_object_int_add(json_path, "localpref", - attr->local_pref); + if (json_paths) { + if (!json_bestpath) + json_bestpath = json_object_new_object(); + json_object_int_add(json_bestpath, "bestpathFromAs", + first_as); + } else { + if (first_as) + vty_out(vty, ", bestpath-from-AS %u", first_as); else - vty_out(vty, ", localpref %u", - attr->local_pref); + vty_out(vty, ", bestpath-from-AS Local"); } + } - if (attr->weight != 0) { - if (json_paths) - json_object_int_add(json_path, "weight", - attr->weight); - else - vty_out(vty, ", weight %u", attr->weight); + if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) { + if (json_paths) { + if (!json_bestpath) + json_bestpath = json_object_new_object(); + json_object_boolean_true_add(json_bestpath, "overall"); + json_object_string_add( + json_bestpath, "selectionReason", + bgp_path_selection_reason2str(bn->reason)); + } else { + vty_out(vty, ", best"); + vty_out(vty, " (%s)", + bgp_path_selection_reason2str(bn->reason)); } + } - if (attr->tag != 0) { - if (json_paths) - json_object_int_add(json_path, "tag", - attr->tag); - else - vty_out(vty, ", tag %" ROUTE_TAG_PRI, - attr->tag); - } + if (json_bestpath) + json_object_object_add(json_path, "bestpath", json_bestpath); - if (!CHECK_FLAG(path->flags, BGP_PATH_VALID)) { - if (json_paths) - json_object_boolean_false_add(json_path, - "valid"); - else - vty_out(vty, ", invalid"); - } else if (!CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) { - if (json_paths) - json_object_boolean_true_add(json_path, - "valid"); - else - vty_out(vty, ", valid"); + if (!json_paths) + vty_out(vty, "\n"); + + /* Line 4 display Community */ + if (attr->community) { + if (json_paths) { + if (!attr->community->json) + community_str(attr->community, true); + json_object_lock(attr->community->json); + json_object_object_add(json_path, "community", + attr->community->json); + } else { + vty_out(vty, " Community: %s\n", + attr->community->str); } + } - if (path->peer != bgp->peer_self) { - if (path->peer->as == path->peer->local_as) { - if (CHECK_FLAG(bgp->config, - BGP_CONFIG_CONFEDERATION)) { - if (json_paths) - json_object_string_add( - json_peer, "type", - "confed-internal"); - else - vty_out(vty, - ", confed-internal"); - } else { - if (json_paths) - json_object_string_add( - json_peer, "type", - "internal"); - else - vty_out(vty, ", internal"); - } - } else { - if (bgp_confederation_peers_check( - bgp, path->peer->as)) { - if (json_paths) - json_object_string_add( - json_peer, "type", - "confed-external"); - else - vty_out(vty, - ", confed-external"); - } else { - if (json_paths) - json_object_string_add( - json_peer, "type", - "external"); - else - vty_out(vty, ", external"); - } - } - } else if (path->sub_type == BGP_ROUTE_AGGREGATE) { - if (json_paths) { - json_object_boolean_true_add(json_path, - "aggregated"); - json_object_boolean_true_add(json_path, - "local"); - } else { - vty_out(vty, ", aggregated, local"); - } - } else if (path->type != ZEBRA_ROUTE_BGP) { - if (json_paths) - json_object_boolean_true_add(json_path, - "sourced"); - else - vty_out(vty, ", sourced"); + /* Line 5 display Extended-community */ + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) { + if (json_paths) { + json_ext_community = json_object_new_object(); + json_object_string_add(json_ext_community, "string", + attr->ecommunity->str); + json_object_object_add(json_path, "extendedCommunity", + json_ext_community); } else { - if (json_paths) { - json_object_boolean_true_add(json_path, - "sourced"); - json_object_boolean_true_add(json_path, - "local"); - } else { - vty_out(vty, ", sourced, local"); - } + vty_out(vty, " Extended Community: %s\n", + attr->ecommunity->str); } + } - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) { - if (json_paths) - json_object_boolean_true_add(json_path, - "atomicAggregate"); - else - vty_out(vty, ", atomic-aggregate"); + /* Line 6 display Large community */ + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { + if (json_paths) { + if (!attr->lcommunity->json) + lcommunity_str(attr->lcommunity, true); + json_object_lock(attr->lcommunity->json); + json_object_object_add(json_path, "largeCommunity", + attr->lcommunity->json); + } else { + vty_out(vty, " Large Community: %s\n", + attr->lcommunity->str); } + } - if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH) - || (CHECK_FLAG(path->flags, BGP_PATH_SELECTED) - && bgp_path_info_mpath_count(path))) { + /* Line 7 display Originator, Cluster-id */ + if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) + || (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) { if (json_paths) - json_object_boolean_true_add(json_path, - "multipath"); + json_object_string_add( + json_path, "originatorId", + inet_ntoa(attr->originator_id)); else - vty_out(vty, ", multipath"); + vty_out(vty, " Originator: %s", + inet_ntoa(attr->originator_id)); } - // Mark the bestpath(s) - if (CHECK_FLAG(path->flags, BGP_PATH_DMED_SELECTED)) { - first_as = aspath_get_first_as(attr->aspath); + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) { + int i; if (json_paths) { - if (!json_bestpath) - json_bestpath = - json_object_new_object(); - json_object_int_add(json_bestpath, - "bestpathFromAs", first_as); - } else { - if (first_as) - vty_out(vty, ", bestpath-from-AS %u", - first_as); - else - vty_out(vty, - ", bestpath-from-AS Local"); - } - } + json_cluster_list = json_object_new_object(); + json_cluster_list_list = + json_object_new_array(); + + for (i = 0; i < attr->cluster->length / 4; + i++) { + json_string = json_object_new_string( + inet_ntoa(attr->cluster + ->list[i])); + json_object_array_add( + json_cluster_list_list, + json_string); + } - if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) { - if (json_paths) { - if (!json_bestpath) - json_bestpath = - json_object_new_object(); - json_object_boolean_true_add(json_bestpath, - "overall"); - json_object_string_add(json_bestpath, - "selectionReason", - bgp_path_selection_reason2str(bn->reason)); + /* + * struct cluster_list does not have + * "str" variable like aspath and community + * do. Add this someday if someone asks + * for it. + * json_object_string_add(json_cluster_list, + * "string", attr->cluster->str); + */ + json_object_object_add(json_cluster_list, + "list", + json_cluster_list_list); + json_object_object_add(json_path, "clusterList", + json_cluster_list); } else { - vty_out(vty, ", best"); - vty_out(vty, " (%s)", - bgp_path_selection_reason2str(bn->reason)); + vty_out(vty, ", Cluster list: "); + + for (i = 0; i < attr->cluster->length / 4; + i++) { + vty_out(vty, "%s ", + inet_ntoa(attr->cluster + ->list[i])); + } } } - if (json_bestpath) - json_object_object_add(json_path, "bestpath", - json_bestpath); - if (!json_paths) vty_out(vty, "\n"); + } - /* Line 4 display Community */ - if (attr->community) { - if (json_paths) { - if (!attr->community->json) - community_str(attr->community, true); - json_object_lock(attr->community->json); - json_object_object_add(json_path, "community", - attr->community->json); - } else { - vty_out(vty, " Community: %s\n", - attr->community->str); - } - } - - /* Line 5 display Extended-community */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) { - if (json_paths) { - json_ext_community = json_object_new_object(); - json_object_string_add(json_ext_community, - "string", - attr->ecommunity->str); - json_object_object_add(json_path, - "extendedCommunity", - json_ext_community); - } else { - vty_out(vty, " Extended Community: %s\n", - attr->ecommunity->str); - } - } - - /* Line 6 display Large community */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { - if (json_paths) { - if (!attr->lcommunity->json) - lcommunity_str(attr->lcommunity, true); - json_object_lock(attr->lcommunity->json); - json_object_object_add(json_path, - "largeCommunity", - attr->lcommunity->json); - } else { - vty_out(vty, " Large Community: %s\n", - attr->lcommunity->str); - } - } + if (path->extra && path->extra->damp_info) + bgp_damp_info_vty(vty, path, json_path); - /* Line 7 display Originator, Cluster-id */ - if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) - || (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { - if (attr->flag - & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) { - if (json_paths) - json_object_string_add( - json_path, "originatorId", - inet_ntoa(attr->originator_id)); - else - vty_out(vty, " Originator: %s", - inet_ntoa(attr->originator_id)); - } + /* Remote Label */ + if (path->extra && bgp_is_valid_label(&path->extra->label[0]) + && (safi != SAFI_EVPN && !is_route_parent_evpn(path))) { + mpls_label_t label = label_pton(&path->extra->label[0]); - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) { - int i; + if (json_paths) + json_object_int_add(json_path, "remoteLabel", label); + else + vty_out(vty, " Remote label: %d\n", label); + } - if (json_paths) { - json_cluster_list = - json_object_new_object(); - json_cluster_list_list = - json_object_new_array(); + /* Label Index */ + if (attr->label_index != BGP_INVALID_LABEL_INDEX) { + if (json_paths) + json_object_int_add(json_path, "labelIndex", + attr->label_index); + else + vty_out(vty, " Label Index: %d\n", + attr->label_index); + } - for (i = 0; - i < attr->cluster->length / 4; - i++) { - json_string = json_object_new_string( - inet_ntoa( - attr->cluster->list - [i])); - json_object_array_add( - json_cluster_list_list, - json_string); - } + /* Line 8 display Addpath IDs */ + if (path->addpath_rx_id + || bgp_addpath_info_has_ids(&path->tx_addpath)) { + if (json_paths) { + json_object_int_add(json_path, "addpathRxId", + path->addpath_rx_id); - /* struct cluster_list does not have - "str" variable like - * aspath and community do. Add this - someday if someone - * asks for it. - json_object_string_add(json_cluster_list, - "string", attr->cluster->str); - */ - json_object_object_add( - json_cluster_list, "list", - json_cluster_list_list); - json_object_object_add( - json_path, "clusterList", - json_cluster_list); - } else { - vty_out(vty, ", Cluster list: "); + /* Keep backwards compatibility with the old API + * by putting TX All's ID in the old field + */ + json_object_int_add( + json_path, "addpathTxId", + path->tx_addpath + .addpath_tx_id[BGP_ADDPATH_ALL]); - for (i = 0; - i < attr->cluster->length / 4; - i++) { - vty_out(vty, "%s ", - inet_ntoa( - attr->cluster->list - [i])); - } - } + /* ... but create a specific field for each + * strategy + */ + for (i = 0; i < BGP_ADDPATH_MAX; i++) { + json_object_int_add( + json_path, + bgp_addpath_names(i)->id_json_name, + path->tx_addpath.addpath_tx_id[i]); } + } else { + vty_out(vty, " AddPath ID: RX %u, ", + path->addpath_rx_id); - if (!json_paths) - vty_out(vty, "\n"); - } - - if (path->extra && path->extra->damp_info) - bgp_damp_info_vty(vty, path, json_path); - - /* Remote Label */ - if (path->extra && bgp_is_valid_label(&path->extra->label[0]) - && (safi != SAFI_EVPN && !is_route_parent_evpn(path))) { - mpls_label_t label = label_pton(&path->extra->label[0]); - - if (json_paths) - json_object_int_add(json_path, "remoteLabel", - label); - else - vty_out(vty, " Remote label: %d\n", label); - } - - /* Label Index */ - if (attr->label_index != BGP_INVALID_LABEL_INDEX) { - if (json_paths) - json_object_int_add(json_path, "labelIndex", - attr->label_index); - else - vty_out(vty, " Label Index: %d\n", - attr->label_index); + route_vty_out_tx_ids(vty, &path->tx_addpath); } + } - /* Line 8 display Addpath IDs */ - if (path->addpath_rx_id - || bgp_addpath_info_has_ids(&path->tx_addpath)) { - if (json_paths) { - json_object_int_add(json_path, "addpathRxId", - path->addpath_rx_id); - - /* Keep backwards compatibility with the old API - * by putting TX All's ID in the old field - */ - json_object_int_add( - json_path, "addpathTxId", - path->tx_addpath.addpath_tx_id - [BGP_ADDPATH_ALL]); + /* If we used addpath to TX a non-bestpath we need to display + * "Advertised to" on a path-by-path basis + */ + if (bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) { + first = 1; - /* ... but create a specific field for each - * strategy - */ - for (i = 0; i < BGP_ADDPATH_MAX; i++) { - json_object_int_add( - json_path, - bgp_addpath_names(i) - ->id_json_name, - path->tx_addpath - .addpath_tx_id[i]); - } - } else { - vty_out(vty, " AddPath ID: RX %u, ", - path->addpath_rx_id); + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + addpath_capable = + bgp_addpath_encode_tx(peer, afi, safi); + has_adj = bgp_adj_out_lookup( + peer, path->net, + bgp_addpath_id_for_peer(peer, afi, safi, + &path->tx_addpath)); + + if ((addpath_capable && has_adj) + || (!addpath_capable && has_adj + && CHECK_FLAG(path->flags, + BGP_PATH_SELECTED))) { + if (json_path && !json_adv_to) + json_adv_to = json_object_new_object(); - route_vty_out_tx_ids(vty, &path->tx_addpath); + route_vty_out_advertised_to( + vty, peer, &first, + " Advertised to:", json_adv_to); } } - /* If we used addpath to TX a non-bestpath we need to display - * "Advertised to" on a path-by-path basis - */ - if (bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) { - first = 1; - - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - addpath_capable = - bgp_addpath_encode_tx(peer, afi, safi); - has_adj = bgp_adj_out_lookup( - peer, path->net, - bgp_addpath_id_for_peer( - peer, afi, safi, - &path->tx_addpath)); - - if ((addpath_capable && has_adj) - || (!addpath_capable && has_adj - && CHECK_FLAG(path->flags, - BGP_PATH_SELECTED))) { - if (json_path && !json_adv_to) - json_adv_to = - json_object_new_object(); - - route_vty_out_advertised_to( - vty, peer, &first, - " Advertised to:", - json_adv_to); - } + if (json_path) { + if (json_adv_to) { + json_object_object_add( + json_path, "advertisedTo", json_adv_to); } - - if (json_path) { - if (json_adv_to) { - json_object_object_add(json_path, - "advertisedTo", - json_adv_to); - } - } else { - if (!first) { - vty_out(vty, "\n"); - } + } else { + if (!first) { + vty_out(vty, "\n"); } } + } - /* Line 9 display Uptime */ - tbuf = time(NULL) - (bgp_clock() - path->uptime); - if (json_paths) { - json_last_update = json_object_new_object(); - json_object_int_add(json_last_update, "epoch", tbuf); - json_object_string_add(json_last_update, "string", - ctime(&tbuf)); - json_object_object_add(json_path, "lastUpdate", - json_last_update); - } else - vty_out(vty, " Last update: %s", ctime(&tbuf)); + /* Line 9 display Uptime */ + tbuf = time(NULL) - (bgp_clock() - path->uptime); + if (json_paths) { + json_last_update = json_object_new_object(); + json_object_int_add(json_last_update, "epoch", tbuf); + json_object_string_add(json_last_update, "string", + ctime(&tbuf)); + json_object_object_add(json_path, "lastUpdate", + json_last_update); + } else + vty_out(vty, " Last update: %s", ctime(&tbuf)); - /* Line 10 display PMSI tunnel attribute, if present */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) { - const char *str = lookup_msg(bgp_pmsi_tnltype_str, - attr->pmsi_tnl_type, - PMSI_TNLTYPE_STR_DEFAULT); - - if (json_paths) { - json_pmsi = json_object_new_object(); - json_object_string_add(json_pmsi, - "tunnelType", str); - json_object_int_add(json_pmsi, - "label", - label2vni(&attr->label)); - json_object_object_add(json_path, "pmsi", - json_pmsi); - } else - vty_out(vty, - " PMSI Tunnel Type: %s, label: %d\n", - str, label2vni(&attr->label)); - } + /* Line 10 display PMSI tunnel attribute, if present */ + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) { + const char *str = + lookup_msg(bgp_pmsi_tnltype_str, attr->pmsi_tnl_type, + PMSI_TNLTYPE_STR_DEFAULT); + if (json_paths) { + json_pmsi = json_object_new_object(); + json_object_string_add(json_pmsi, "tunnelType", str); + json_object_int_add(json_pmsi, "label", + label2vni(&attr->label)); + json_object_object_add(json_path, "pmsi", json_pmsi); + } else + vty_out(vty, " PMSI Tunnel Type: %s, label: %d\n", + str, label2vni(&attr->label)); } /* We've constructed the json object for this path, add it to the json @@ -9131,8 +9024,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, json_object_object_add(json_path, "peer", json_peer); json_object_array_add(json_paths, json_path); - } else - vty_out(vty, "\n"); + } } #define BGP_SHOW_HEADER_CSV "Flags, Network, Next Hop, Metric, LocPrf, Weight, Path" @@ -10693,13 +10585,12 @@ static void bgp_table_stats_rn(struct bgp_node *rn, struct bgp_node *top, for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) { ts->counts[BGP_STATS_RIB]++; - if (pi->attr - && (CHECK_FLAG(pi->attr->flag, - ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)))) + if (CHECK_FLAG(pi->attr->flag, + ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) ts->counts[BGP_STATS_AGGREGATES]++; /* as-path stats */ - if (pi->attr && pi->attr->aspath) { + if (pi->attr->aspath) { unsigned int hops = aspath_count_hops(pi->attr->aspath); unsigned int size = aspath_size(pi->attr->aspath); as_t highest = aspath_highest(pi->attr->aspath); @@ -11270,7 +11161,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, if (type == bgp_show_adj_route_received || type == bgp_show_adj_route_filtered) { for (ain = rn->adj_in; ain; ain = ain->next) { - if (ain->peer != peer || !ain->attr) + if (ain->peer != peer) continue; if (header1) { diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index a038b0e7a9..d0cea547ec 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -700,7 +700,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, if (type == RMAP_BGP && prefix->family == AF_INET) { path = (struct bgp_path_info *)object; - if (!path || !path->attr) + if (!path) return RMAP_NOMATCH; /* If nexthop interface's index can't be resolved and nexthop is @@ -868,8 +868,7 @@ route_match_vni(void *rule, const struct prefix *prefix, * For any other tunnel type, return noop to ignore * this check. */ - if (path->attr && path->attr->encap_tunneltype != - BGP_ENCAP_TYPE_VXLAN) + if (path->attr->encap_tunneltype != BGP_ENCAP_TYPE_VXLAN) return RMAP_NOOP; /* @@ -1470,7 +1469,7 @@ route_match_interface(void *rule, const struct prefix *prefix, if (type == RMAP_BGP) { path = object; - if (!path || !path->attr) + if (!path) return RMAP_NOMATCH; ifp = if_lookup_by_name_all_vrf((char *)rule); @@ -2690,7 +2689,7 @@ route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix, if (type == RMAP_BGP && prefix->family == AF_INET6) { path = (struct bgp_path_info *)object; - if (!path || !path->attr) + if (!path) return RMAP_NOMATCH; if (IPV6_ADDR_SAME(&path->attr->mp_nexthop_global, addr) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index dd880768b8..eae9db5a61 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1586,36 +1586,24 @@ DEFUN (no_bgp_update_delay, } -static int bgp_wpkt_quanta_config_vty(struct vty *vty, const char *num, - char set) +static int bgp_wpkt_quanta_config_vty(struct vty *vty, uint32_t quanta, + bool set) { VTY_DECLVAR_CONTEXT(bgp, bgp); - if (set) { - uint32_t quanta = strtoul(num, NULL, 10); - atomic_store_explicit(&bgp->wpkt_quanta, quanta, - memory_order_relaxed); - } else { - atomic_store_explicit(&bgp->wpkt_quanta, BGP_WRITE_PACKET_MAX, - memory_order_relaxed); - } + quanta = set ? quanta : BGP_WRITE_PACKET_MAX; + atomic_store_explicit(&bgp->wpkt_quanta, quanta, memory_order_relaxed); return CMD_SUCCESS; } -static int bgp_rpkt_quanta_config_vty(struct vty *vty, const char *num, - char set) +static int bgp_rpkt_quanta_config_vty(struct vty *vty, uint32_t quanta, + bool set) { VTY_DECLVAR_CONTEXT(bgp, bgp); - if (set) { - uint32_t quanta = strtoul(num, NULL, 10); - atomic_store_explicit(&bgp->rpkt_quanta, quanta, - memory_order_relaxed); - } else { - atomic_store_explicit(&bgp->rpkt_quanta, BGP_READ_PACKET_MAX, - memory_order_relaxed); - } + quanta = set ? quanta : BGP_READ_PACKET_MAX; + atomic_store_explicit(&bgp->rpkt_quanta, quanta, memory_order_relaxed); return CMD_SUCCESS; } @@ -1636,47 +1624,32 @@ void bgp_config_write_rpkt_quanta(struct vty *vty, struct bgp *bgp) vty_out(vty, " read-quanta %d\n", quanta); } -/* Packet quanta configuration */ -DEFUN (bgp_wpkt_quanta, +/* Packet quanta configuration + * + * XXX: The value set here controls the size of a stack buffer in the IO + * thread. When changing these limits be careful to prevent stack overflow. + * + * Furthermore, the maximums used here should correspond to + * BGP_WRITE_PACKET_MAX and BGP_READ_PACKET_MAX. + */ +DEFPY (bgp_wpkt_quanta, bgp_wpkt_quanta_cmd, - "write-quanta (1-10)", - "How many packets to write to peer socket per run\n" - "Number of packets\n") -{ - int idx_number = 1; - return bgp_wpkt_quanta_config_vty(vty, argv[idx_number]->arg, 1); -} - -DEFUN (no_bgp_wpkt_quanta, - no_bgp_wpkt_quanta_cmd, - "no write-quanta (1-10)", + "[no] write-quanta (1-64)$quanta", NO_STR - "How many packets to write to peer socket per I/O cycle\n" + "How many packets to write to peer socket per run\n" "Number of packets\n") { - int idx_number = 2; - return bgp_wpkt_quanta_config_vty(vty, argv[idx_number]->arg, 0); + return bgp_wpkt_quanta_config_vty(vty, quanta, !no); } -DEFUN (bgp_rpkt_quanta, +DEFPY (bgp_rpkt_quanta, bgp_rpkt_quanta_cmd, - "read-quanta (1-10)", - "How many packets to read from peer socket per I/O cycle\n" - "Number of packets\n") -{ - int idx_number = 1; - return bgp_rpkt_quanta_config_vty(vty, argv[idx_number]->arg, 1); -} - -DEFUN (no_bgp_rpkt_quanta, - no_bgp_rpkt_quanta_cmd, - "no read-quanta (1-10)", + "[no] read-quanta (1-10)$quanta", NO_STR "How many packets to read from peer socket per I/O cycle\n" "Number of packets\n") { - int idx_number = 2; - return bgp_rpkt_quanta_config_vty(vty, argv[idx_number]->arg, 0); + return bgp_rpkt_quanta_config_vty(vty, quanta, !no); } void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp) @@ -13072,9 +13045,7 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_update_delay_establish_wait_cmd); install_element(BGP_NODE, &bgp_wpkt_quanta_cmd); - install_element(BGP_NODE, &no_bgp_wpkt_quanta_cmd); install_element(BGP_NODE, &bgp_rpkt_quanta_cmd); - install_element(BGP_NODE, &no_bgp_rpkt_quanta_cmd); install_element(BGP_NODE, &bgp_coalesce_time_cmd); install_element(BGP_NODE, &no_bgp_coalesce_time_cmd); diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 0aa102feab..83b05ce536 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -388,15 +388,13 @@ void del_vnc_route(struct rfapi_descriptor *rfd, bpi = bpi->next) { vnc_zlog_debug_verbose( - "%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%u", + "%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%" PRIu64, __func__, bpi, bpi->peer, bpi->type, bpi->sub_type, (bpi->extra ? bpi->extra->vnc.export.rfapi_handle : NULL), - ((bpi->attr - && CHECK_FLAG(bpi->attr->flag, - ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) - ? bpi->attr->local_pref - : 0)); + CHECK_FLAG(bpi->attr->flag, + ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF) + ? bpi->attr->local_pref : 0)); if (bpi->peer == peer && bpi->type == type && bpi->sub_type == sub_type && bpi->extra diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 655cf747de..fe8e874440 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -484,8 +484,7 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr, new = info_make(type, sub_type, 0, peer, attr, NULL); - if (attr) - new->attr = bgp_attr_intern(attr); + new->attr = bgp_attr_intern(attr); bgp_path_info_extra_get(new); if (prd) { @@ -516,9 +515,8 @@ static void rfapiBgpInfoFree(struct bgp_path_info *goner) peer_unlock(goner->peer); } - if (goner->attr) { - bgp_attr_unintern(&goner->attr); - } + bgp_attr_unintern(&goner->attr); + if (goner->extra) bgp_path_info_extra_free(&goner->extra); XFREE(MTYPE_BGP_ROUTE, goner); @@ -1113,9 +1111,6 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1, if (!bpi1 || !bpi2) return 0; - if (!bpi1->attr || !bpi2->attr) - return 0; - /* * VN address comparisons */ @@ -1299,13 +1294,10 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, memcpy(&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet, ETH_ALEN); /* only low 3 bytes of this are significant */ - if (bpi->attr) { - (void)rfapiEcommunityGetLNI( - bpi->attr->ecommunity, - &vo->v.l2addr.logical_net_id); - (void)rfapiEcommunityGetEthernetTag( - bpi->attr->ecommunity, &vo->v.l2addr.tag_id); - } + (void)rfapiEcommunityGetLNI(bpi->attr->ecommunity, + &vo->v.l2addr.logical_net_id); + (void)rfapiEcommunityGetEthernetTag(bpi->attr->ecommunity, + &vo->v.l2addr.tag_id); /* local_nve_id comes from lower byte of RD type */ vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1]; @@ -1325,129 +1317,117 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, } } - if (bpi->attr) { - bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS; /*Default*/ - new->prefix.cost = rfapiRfpCost(bpi->attr); + bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS; /*Default*/ + new->prefix.cost = rfapiRfpCost(bpi->attr); - struct bgp_attr_encap_subtlv *pEncap; - - switch (BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len)) { - case AF_INET: - new->vn_address.addr_family = AF_INET; - new->vn_address.addr.v4 = - bpi->attr->mp_nexthop_global_in; - break; + struct bgp_attr_encap_subtlv *pEncap; - case AF_INET6: - new->vn_address.addr_family = AF_INET6; - new->vn_address.addr.v6 = bpi->attr->mp_nexthop_global; - break; + switch (BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len)) { + case AF_INET: + new->vn_address.addr_family = AF_INET; + new->vn_address.addr.v4 = bpi->attr->mp_nexthop_global_in; + break; - default: - zlog_warn("%s: invalid vpn nexthop length: %d", - __func__, bpi->attr->mp_nexthop_len); - rfapi_free_next_hop_list(new); - return NULL; - } + case AF_INET6: + new->vn_address.addr_family = AF_INET6; + new->vn_address.addr.v6 = bpi->attr->mp_nexthop_global; + break; - for (pEncap = bpi->attr->vnc_subtlvs; pEncap; - pEncap = pEncap->next) { - switch (pEncap->type) { - case BGP_VNC_SUBTLV_TYPE_LIFETIME: - /* use configured lifetime, not attr lifetime */ - break; + default: + zlog_warn("%s: invalid vpn nexthop length: %d", __func__, + bpi->attr->mp_nexthop_len); + rfapi_free_next_hop_list(new); + return NULL; + } - default: - zlog_warn("%s: unknown VNC option type %d", - __func__, pEncap->type); + for (pEncap = bpi->attr->vnc_subtlvs; pEncap; pEncap = pEncap->next) { + switch (pEncap->type) { + case BGP_VNC_SUBTLV_TYPE_LIFETIME: + /* use configured lifetime, not attr lifetime */ + break; + default: + zlog_warn("%s: unknown VNC option type %d", __func__, + pEncap->type); - break; - } + break; } + } - bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type); - if (tun_type == BGP_ENCAP_TYPE_MPLS) { - struct prefix p; - /* MPLS carries UN address in next hop */ - rfapiNexthop2Prefix(bpi->attr, &p); - if (p.family != 0) { - rfapiQprefix2Raddr(&p, &new->un_address); - have_vnc_tunnel_un = 1; - } + bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type); + if (tun_type == BGP_ENCAP_TYPE_MPLS) { + struct prefix p; + /* MPLS carries UN address in next hop */ + rfapiNexthop2Prefix(bpi->attr, &p); + if (p.family != 0) { + rfapiQprefix2Raddr(&p, &new->un_address); + have_vnc_tunnel_un = 1; } + } - for (pEncap = bpi->attr->encap_subtlvs; pEncap; - pEncap = pEncap->next) { - switch (pEncap->type) { - case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: - /* - * Overrides ENCAP UN address, if any - */ - switch (pEncap->length) { - - case 8: - new->un_address.addr_family = AF_INET; - memcpy(&new->un_address.addr.v4, - pEncap->value, 4); - have_vnc_tunnel_un = 1; - break; + for (pEncap = bpi->attr->encap_subtlvs; pEncap; pEncap = pEncap->next) { + switch (pEncap->type) { + case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT: + /* + * Overrides ENCAP UN address, if any + */ + switch (pEncap->length) { - case 20: - new->un_address.addr_family = AF_INET6; - memcpy(&new->un_address.addr.v6, - pEncap->value, 16); - have_vnc_tunnel_un = 1; - break; + case 8: + new->un_address.addr_family = AF_INET; + memcpy(&new->un_address.addr.v4, pEncap->value, + 4); + have_vnc_tunnel_un = 1; + break; - default: - zlog_warn( - "%s: invalid tunnel subtlv UN addr length (%d) for bpi %p", - __func__, pEncap->length, bpi); - } + case 20: + new->un_address.addr_family = AF_INET6; + memcpy(&new->un_address.addr.v6, pEncap->value, + 16); + have_vnc_tunnel_un = 1; break; default: zlog_warn( - "%s: unknown Encap Attribute option type %d", - __func__, pEncap->type); - - - break; + "%s: invalid tunnel subtlv UN addr length (%d) for bpi %p", + __func__, pEncap->length, bpi); } + break; + + default: + zlog_warn("%s: unknown Encap Attribute option type %d", + __func__, pEncap->type); + break; } + } - new->un_options = rfapi_encap_tlv_to_un_option(bpi->attr); + new->un_options = rfapi_encap_tlv_to_un_option(bpi->attr); #if DEBUG_ENCAP_MONITOR - vnc_zlog_debug_verbose("%s: line %d: have_vnc_tunnel_un=%d", - __func__, __LINE__, have_vnc_tunnel_un); + vnc_zlog_debug_verbose("%s: line %d: have_vnc_tunnel_un=%d", __func__, + __LINE__, have_vnc_tunnel_un); #endif - if (!have_vnc_tunnel_un && bpi->extra) { - /* - * use cached UN address from ENCAP route - */ - new->un_address.addr_family = - bpi->extra->vnc.import.un_family; - switch (new->un_address.addr_family) { - case AF_INET: - new->un_address.addr.v4 = - bpi->extra->vnc.import.un.addr4; - break; - case AF_INET6: - new->un_address.addr.v6 = - bpi->extra->vnc.import.un.addr6; - break; - default: - zlog_warn( - "%s: invalid UN addr family (%d) for bpi %p", - __func__, new->un_address.addr_family, - bpi); - rfapi_free_next_hop_list(new); - return NULL; - break; - } + if (!have_vnc_tunnel_un && bpi->extra) { + /* + * use cached UN address from ENCAP route + */ + new->un_address.addr_family = bpi->extra->vnc.import.un_family; + switch (new->un_address.addr_family) { + case AF_INET: + new->un_address.addr.v4 = + bpi->extra->vnc.import.un.addr4; + break; + case AF_INET6: + new->un_address.addr.v6 = + bpi->extra->vnc.import.un.addr6; + break; + default: + zlog_warn("%s: invalid UN addr family (%d) for bpi %p", + __func__, new->un_address.addr_family, bpi); + rfapi_free_next_hop_list(new); + return NULL; + break; } } @@ -2607,12 +2587,6 @@ static int rfapiAttrNexthopAddrDifferent(struct prefix *p1, struct prefix *p2) static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi, struct bgp_path_info *vpn_bpi) { - if (!encap_bpi->attr) { - zlog_warn("%s: no encap bpi attr/extra, can't copy UN address", - __func__); - return; - } - if (!vpn_bpi || !vpn_bpi->extra) { zlog_warn("%s: no vpn bpi attr/extra, can't copy UN address", __func__); @@ -4510,10 +4484,9 @@ static void rfapiDeleteRemotePrefixesIt( vnc_zlog_debug_verbose("%s: examining bpi %p", __func__, bpi); - if (bpi->attr) { - if (!rfapiGetNexthop(bpi->attr, &qpt)) - qpt_valid = 1; - } + if (!rfapiGetNexthop(bpi->attr, &qpt)) + qpt_valid = 1; + if (vn) { if (!qpt_valid || !prefix_match(vn, &qpt)) { diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 8e8acbfb91..39d4b3ee29 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -1647,11 +1647,6 @@ void rfapiRibUpdatePendingNode( struct rfapi_info *ri; struct prefix pfx_nh; - if (!bpi->attr) { - /* shouldn't happen */ - /* TBD increment error stats counter */ - continue; - } if (!bpi->extra) { /* shouldn't happen */ /* TBD increment error stats counter */ diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 46161b4f38..dc4a02e8b2 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -418,7 +418,7 @@ void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p, } } - if (bpi->attr && bpi->attr->ecommunity) { + if (bpi->attr->ecommunity) { s = ecommunity_ecom2str(bpi->attr->ecommunity, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); vty_out(vty, " EC{%s}", s); @@ -538,82 +538,78 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) * RFP option sizes (they are opaque values) * extended communities (RTs) */ - if (bpi->attr) { - uint32_t lifetime; - int printed_1st_gol = 0; - struct bgp_attr_encap_subtlv *pEncap; - struct prefix pfx_un; - int af = BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len); - - /* Nexthop */ - if (af == AF_INET) { - r = snprintf(p, REMAIN, "%s", - inet_ntop(AF_INET, - &bpi->attr->mp_nexthop_global_in, - buf, BUFSIZ)); - INCP; - } else if (af == AF_INET6) { - r = snprintf(p, REMAIN, "%s", - inet_ntop(AF_INET6, - &bpi->attr->mp_nexthop_global, - buf, BUFSIZ)); - INCP; - } else { - r = snprintf(p, REMAIN, "?"); - INCP; - } + uint32_t lifetime; + int printed_1st_gol = 0; + struct bgp_attr_encap_subtlv *pEncap; + struct prefix pfx_un; + int af = BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len); + + /* Nexthop */ + if (af == AF_INET) { + r = snprintf(p, REMAIN, "%s", + inet_ntop(AF_INET, + &bpi->attr->mp_nexthop_global_in, buf, + BUFSIZ)); + INCP; + } else if (af == AF_INET6) { + r = snprintf(p, REMAIN, "%s", + inet_ntop(AF_INET6, &bpi->attr->mp_nexthop_global, + buf, BUFSIZ)); + INCP; + } else { + r = snprintf(p, REMAIN, "?"); + INCP; + } - /* - * VNC tunnel subtlv, if present, contains UN address - */ - if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) { - r = snprintf(p, REMAIN, " un=%s", - inet_ntop(pfx_un.family, pfx_un.u.val, buf, - BUFSIZ)); - INCP; - } + /* + * VNC tunnel subtlv, if present, contains UN address + */ + if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) { + r = snprintf( + p, REMAIN, " un=%s", + inet_ntop(pfx_un.family, pfx_un.u.val, buf, BUFSIZ)); + INCP; + } - /* Lifetime */ - if (rfapiGetVncLifetime(bpi->attr, &lifetime)) { - r = snprintf(p, REMAIN, " nolife"); - INCP; - } else { - if (lifetime == 0xffffffff) - r = snprintf(p, REMAIN, " %6s", "infini"); - else - r = snprintf(p, REMAIN, " %6u", lifetime); - INCP; - } + /* Lifetime */ + if (rfapiGetVncLifetime(bpi->attr, &lifetime)) { + r = snprintf(p, REMAIN, " nolife"); + INCP; + } else { + if (lifetime == 0xffffffff) + r = snprintf(p, REMAIN, " %6s", "infini"); + else + r = snprintf(p, REMAIN, " %6u", lifetime); + INCP; + } - /* RFP option lengths */ - for (pEncap = bpi->attr->vnc_subtlvs; pEncap; - pEncap = pEncap->next) { + /* RFP option lengths */ + for (pEncap = bpi->attr->vnc_subtlvs; pEncap; pEncap = pEncap->next) { - if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) { - if (printed_1st_gol) { - r = snprintf(p, REMAIN, ","); - INCP; - } else { - r = snprintf(p, REMAIN, - " "); /* leading space */ - INCP; - } - r = snprintf(p, REMAIN, "%d", pEncap->length); + if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) { + if (printed_1st_gol) { + r = snprintf(p, REMAIN, ","); + INCP; + } else { + r = snprintf(p, REMAIN, + " "); /* leading space */ INCP; - printed_1st_gol = 1; } - } - - /* RT list */ - if (bpi->attr->ecommunity) { - s = ecommunity_ecom2str(bpi->attr->ecommunity, - ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - r = snprintf(p, REMAIN, " %s", s); + r = snprintf(p, REMAIN, "%d", pEncap->length); INCP; - XFREE(MTYPE_ECOMMUNITY_STR, s); + printed_1st_gol = 1; } } + /* RT list */ + if (bpi->attr->ecommunity) { + s = ecommunity_ecom2str(bpi->attr->ecommunity, + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + r = snprintf(p, REMAIN, " %s", s); + INCP; + XFREE(MTYPE_ECOMMUNITY_STR, s); + } + r = snprintf(p, REMAIN, " bpi@%p", bpi); INCP; @@ -628,21 +624,17 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) INCP; } - if (bpi->attr) { - - if (bpi->attr->weight) { - r = snprintf(p, REMAIN, " W=%d", bpi->attr->weight); - INCP; - } + if (bpi->attr->weight) { + r = snprintf(p, REMAIN, " W=%d", bpi->attr->weight); + INCP; + } - if (bpi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { - r = snprintf(p, REMAIN, " LP=%d", - bpi->attr->local_pref); - INCP; - } else { - r = snprintf(p, REMAIN, " LP=unset"); - INCP; - } + if (bpi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { + r = snprintf(p, REMAIN, " LP=%d", bpi->attr->local_pref); + INCP; + } else { + r = snprintf(p, REMAIN, " LP=unset"); + INCP; } r = snprintf(p, REMAIN, " %c:%u", zebra_route_char(bpi->type), @@ -1087,16 +1079,13 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, * See rfapi_import.c'rfapiRouteInfo2NextHopEntry() for conversion * back to cost. */ - if (bpi->attr) { - uint32_t local_pref; - if (bpi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) - local_pref = bpi->attr->local_pref; - else - local_pref = 0; - cost = (local_pref > 255) ? 0 : 255 - local_pref; - } else { - cost = 0; - } + uint32_t local_pref; + + if (bpi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) + local_pref = bpi->attr->local_pref; + else + local_pref = 0; + cost = (local_pref > 255) ? 0 : 255 - local_pref; fp(out, "%-20s ", buf_pfx); fp(out, "%-15s ", buf_vn); diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index eb2d0fd889..51ec999764 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -476,25 +476,21 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( plifetime = &lifetime; } - if (bpi->attr) { - encaptlvs = bpi->attr->vnc_subtlvs; - if (bpi->attr->encap_tunneltype != BGP_ENCAP_TYPE_RESERVED - && bpi->attr->encap_tunneltype != BGP_ENCAP_TYPE_MPLS) { - if (opt != NULL) - opt->next = &optary[cur_opt]; - opt = &optary[cur_opt++]; - memset(opt, 0, sizeof(struct rfapi_un_option)); - opt->type = RFAPI_UN_OPTION_TYPE_TUNNELTYPE; - opt->v.tunnel.type = bpi->attr->encap_tunneltype; - /* TBD parse bpi->attr->extra->encap_subtlvs */ - } - } else { - encaptlvs = NULL; + encaptlvs = bpi->attr->vnc_subtlvs; + if (bpi->attr->encap_tunneltype != BGP_ENCAP_TYPE_RESERVED + && bpi->attr->encap_tunneltype != BGP_ENCAP_TYPE_MPLS) { + if (opt != NULL) + opt->next = &optary[cur_opt]; + opt = &optary[cur_opt++]; + memset(opt, 0, sizeof(struct rfapi_un_option)); + opt->type = RFAPI_UN_OPTION_TYPE_TUNNELTYPE; + opt->v.tunnel.type = bpi->attr->encap_tunneltype; + /* TBD parse bpi->attr->extra->encap_subtlvs */ } struct ecommunity *new_ecom = ecommunity_dup(ecom); - if (bpi->attr && bpi->attr->ecommunity) + if (bpi->attr->ecommunity) ecommunity_merge(new_ecom, bpi->attr->ecommunity); if (bpi->extra) @@ -635,12 +631,8 @@ static void vnc_import_bgp_add_route_mode_resolve_nve( } local_pref = calc_local_pref(info->attr, info->peer); - if (info->attr - && (info->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) { - + if (info->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) med = &info->attr->med; - } - /* * At this point, we have allocated: @@ -1103,7 +1095,7 @@ static void vnc_import_bgp_del_route_mode_plain(struct bgp *bgp, * Compute VN address */ - if (info && info->attr) { + if (info) { rfapiUnicastNexthop2Prefix(afi, info->attr, &vn_pfx_space); } else { vnc_zlog_debug_verbose("%s: no attr, can't delete route", @@ -1489,12 +1481,9 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve( } local_pref = calc_local_pref(pb->ubpi->attr, pb->ubpi->peer); - if (pb->ubpi->attr - && (pb->ubpi->attr->flag - & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))) { - + if (pb->ubpi->attr->flag + & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) med = &pb->ubpi->attr->med; - } /* * Sanity check @@ -1729,11 +1718,6 @@ static void vnc_import_bgp_exterior_add_route_it( return; } - if (!info->attr) { - vnc_zlog_debug_verbose("%s: no info, skipping", __func__); - return; - } - /* * Extract nexthop from exterior route * @@ -1920,11 +1904,6 @@ void vnc_import_bgp_exterior_del_route( return; } - if (!info->attr) { - vnc_zlog_debug_verbose("%s: no info, skipping", __func__); - return; - } - /* * Extract nexthop from exterior route * diff --git a/configure.ac b/configure.ac index 730e2ae6f0..6147ebf0d8 100755 --- a/configure.ac +++ b/configure.ac @@ -536,6 +536,8 @@ AC_ARG_ENABLE([backtrace], AS_HELP_STRING([--disable-backtrace,], [disable crash backtraces (default autodetect)])) AC_ARG_ENABLE([time-check], AS_HELP_STRING([--disable-time-check], [disable slow thread warning messages])) +AC_ARG_ENABLE([cpu-time], + AS_HELP_STRING([--disable-cpu-time], [disable cpu usage data gathering])) AC_ARG_ENABLE([pcreposix], AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions])) AC_ARG_ENABLE([fpm], @@ -614,6 +616,14 @@ if test x"${enable_time_check}" != x"no" ; then fi fi +case "${enable_cpu_time}" in + "no") + AC_DEFINE([EXCLUDE_CPU_TIME], [1], [Exclude getrusage data gathering]) + ;; + "*") + ;; +esac + case "${enable_systemd}" in "no") ;; "yes") diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 5509fd5f0d..c7d722164a 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -451,7 +451,8 @@ Terminal Mode Commands This command displays system run statistics for all the different event types. If no options is specified all different run types are displayed together. Additionally you can ask to look at (r)ead, (w)rite, (t)imer, - (e)vent and e(x)ecute thread event types. + (e)vent and e(x)ecute thread event types. If you have compiled with + disable-cpu-time then this command will not show up. .. index:: show thread poll .. clicmd:: show thread poll diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index c99a5c49a3..b8c216ff82 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1063,6 +1063,13 @@ Configuring Peers on by default or not. This command defaults to on and is not displayed. The `no bgp default ipv4-unicast` form of the command is displayed. +.. index:: [no] neighbor PEER advertisement-interval (0-600) +.. clicmd:: [no] neighbor PEER advertisement-interval (0-600) + + Setup the minimum route advertisement interval(mrai) for the + peer in question. This number is between 0 and 600 seconds, + with the default advertisement interval being 0. + .. _bgp-peer-filtering: Peer Filtering @@ -2167,6 +2174,8 @@ Dumping Messages and Routing Tables Other BGP Commands ------------------ +The following are available in the top level *enable* mode: + .. index:: clear bgp \* .. clicmd:: clear bgp \* @@ -2202,6 +2211,24 @@ Other BGP Commands Clear peer using soft reconfiguration in this address-family and sub-address-family. +The following are available in the ``router bgp`` mode: + +.. index:: write-quanta (1-64) +.. clicmd:: write-quanta (1-64) + + BGP message Tx I/O is vectored. This means that multiple packets are written + to the peer socket at the same time each I/O cycle, in order to minimize + system call overhead. This value controls how many are written at a time. + Under certain load conditions, reducing this value could make peer traffic + less 'bursty'. In practice, leave this settings on the default (64) unless + you truly know what you are doing. + +.. index:: read-quanta (1-10) +.. clicmd:: read-quanta (1-10) + + Unlike Tx, BGP Rx traffic is not vectored. Packets are read off the wire one + at a time in a loop. This setting controls how many iterations the loop runs + for. As with write-quanta, it is best to leave this setting on the default. .. _bgp-displaying-bgp-information: diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 45549dccad..392a2dd784 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -302,6 +302,23 @@ options from the list below. Build the Sysrepo northbound plugin. +.. option:: --enable-time-check XXX + + When this is enabled with a XXX value in microseconds, any thread that + runs for over this value will cause a warning to be issued to the log. + If you do not specify any value or don't include this option then + the default time is 5 seconds. If --disable-time-check is specified + then no warning is issued for any thread run length. + +.. option:: --disable-cpu-time + + Disable cpu process accounting, this command also disables the `show thread cpu` + command. If this option is disabled, --enable-time-check is ignored. This + disabling of cpu time effectively means that the getrusage call is skipped. + Since this is a process switch into the kernel, systems with high FRR + load might see improvement in behavior. Be aware that `show thread cpu` + is considered a good data gathering tool from the perspective of developers. + You may specify any combination of the above options to the configure script. By default, the executables are placed in :file:`/usr/local/sbin` and the configuration files in :file:`/usr/local/etc`. The :file:`/usr/local/` diff --git a/lib/filter.c b/lib/filter.c index fe62ca1c13..8c210bd7ad 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -1915,6 +1915,7 @@ DEFUN (mac_access_list, argv_find(argv, argc, "X:X:X:X:X:X", &idx); if (idx) mac = argv[idx]->arg; + assert(mac); return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN, mac, 0, 1); @@ -1952,6 +1953,7 @@ DEFUN (no_mac_access_list, argv_find(argv, argc, "X:X:X:X:X:X", &idx); if (idx) mac = argv[idx]->arg; + assert(mac); return filter_set_zebra(vty, argv[2]->arg, seq, permit_deny, AFI_L2VPN, mac, 0, 0); @@ -2050,6 +2052,7 @@ DEFUN (access_list_exact, argv_find(argv, argc, "A.B.C.D/M", &idx); if (idx) prefix = argv[idx]->arg; + assert(prefix); idx = 0; if (argv_find(argv, argc, "exact-match", &idx)) @@ -2122,6 +2125,7 @@ DEFUN (no_access_list_exact, argv_find(argv, argc, "A.B.C.D/M", &idx); if (idx) prefix = argv[idx]->arg; + assert(prefix); idx = 0; if (argv_find(argv, argc, "exact-match", &idx)) @@ -2367,6 +2371,7 @@ DEFUN (no_ipv6_access_list_exact, argv_find(argv, argc, "X:X::X:X/M", &idx); if (idx) prefix = argv[idx]->arg; + assert(prefix); idx = 0; if (argv_find(argv, argc, "exact-match", &idx)) diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 61919f0229..d3e788d5d3 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -40,6 +40,7 @@ struct debug nb_dbg_cbs_state = {0, "Northbound callbacks: state"}; struct debug nb_dbg_cbs_rpc = {0, "Northbound callbacks: RPCs"}; struct debug nb_dbg_notif = {0, "Northbound notifications"}; struct debug nb_dbg_events = {0, "Northbound events"}; +struct debug nb_dbg_libyang = {0, "libyang debugging"}; struct nb_config *vty_shared_candidate_config; static struct thread_master *master; @@ -1581,7 +1582,7 @@ DEFPY (rollback_config, /* Debug CLI commands. */ static struct debug *nb_debugs[] = { &nb_dbg_cbs_config, &nb_dbg_cbs_state, &nb_dbg_cbs_rpc, - &nb_dbg_notif, &nb_dbg_events, + &nb_dbg_notif, &nb_dbg_events, &nb_dbg_libyang, }; static const char *const nb_debugs_conflines[] = { @@ -1590,6 +1591,7 @@ static const char *const nb_debugs_conflines[] = { "debug northbound callbacks rpc", "debug northbound notifications", "debug northbound events", + "debug northbound libyang", }; DEFINE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set)); @@ -1614,6 +1616,7 @@ DEFPY (debug_nb, callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc}]\ |notifications$notifications\ |events$events\ + |libyang$libyang\ >]", NO_STR DEBUG_STR @@ -1623,7 +1626,8 @@ DEFPY (debug_nb, "State\n" "RPC\n" "Notifications\n" - "Events\n") + "Events\n" + "libyang debugging\n") { uint32_t mode = DEBUG_NODE2MODE(vty->node); @@ -1641,10 +1645,16 @@ DEFPY (debug_nb, DEBUG_MODE_SET(&nb_dbg_notif, mode, !no); if (events) DEBUG_MODE_SET(&nb_dbg_events, mode, !no); + if (libyang) { + DEBUG_MODE_SET(&nb_dbg_libyang, mode, !no); + yang_debugging_set(!no); + } /* no specific debug --> act on all of them */ - if (strmatch(argv[argc - 1]->text, "northbound")) + if (strmatch(argv[argc - 1]->text, "northbound")) { nb_debug_set_all(mode, !no); + yang_debugging_set(!no); + } return CMD_SUCCESS; } diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index 218cae4e74..089899368d 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -616,6 +616,11 @@ class NorthboundImpl final : public frr::Northbound::Service return LYD_JSON; case frr::XML: return LYD_XML; + default: + flog_err(EC_LIB_DEVELOPMENT, + "%s: unknown data encoding format (%u)", + __func__, encoding); + exit(1); } } @@ -90,7 +90,7 @@ struct pbr_rule { uint32_t unique; struct pbr_filter filter; struct pbr_action action; - uint32_t ifindex; + ifindex_t ifindex; }; /* TCP flags value shared diff --git a/lib/thread.c b/lib/thread.c index 6669952ff4..649fe500cd 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -109,6 +109,7 @@ static void cpu_record_hash_free(void *a) XFREE(MTYPE_THREAD_STATS, hist); } +#ifndef EXCLUDE_CPU_TIME static void vty_out_cpu_thread_history(struct vty *vty, struct cpu_thread_history *a) { @@ -219,6 +220,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) if (tmp.total_calls > 0) vty_out_cpu_thread_history(vty, &tmp); } +#endif static void cpu_record_hash_clear(struct hash_bucket *bucket, void *args[]) { @@ -288,6 +290,7 @@ static uint8_t parse_filter(const char *filterstr) return filter; } +#ifndef EXCLUDE_CPU_TIME DEFUN (show_thread_cpu, show_thread_cpu_cmd, "show thread cpu [FILTER]", @@ -313,6 +316,7 @@ DEFUN (show_thread_cpu, cpu_record_print(vty, filter); return CMD_SUCCESS; } +#endif static void show_thread_poll_helper(struct vty *vty, struct thread_master *m) { @@ -403,7 +407,9 @@ DEFUN (clear_thread_cpu, void thread_cmd_init(void) { +#ifndef EXCLUDE_CPU_TIME install_element(VIEW_NODE, &show_thread_cpu_cmd); +#endif install_element(VIEW_NODE, &show_thread_poll_cmd); install_element(ENABLE_NODE, &clear_thread_cpu_cmd); } @@ -1511,7 +1517,9 @@ void thread_getrusage(RUSAGE_T *r) #define FRR_RUSAGE RUSAGE_SELF #endif monotime(&r->real); +#ifndef EXCLUDE_CPU_TIME getrusage(FRR_RUSAGE, &(r->cpu)); +#endif } /* @@ -1527,9 +1535,11 @@ void thread_getrusage(RUSAGE_T *r) */ void thread_call(struct thread *thread) { +#ifndef EXCLUDE_CPU_TIME _Atomic unsigned long realtime, cputime; unsigned long exp; unsigned long helper; +#endif RUSAGE_T before, after; GETRUSAGE(&before); @@ -1541,6 +1551,7 @@ void thread_call(struct thread *thread) GETRUSAGE(&after); +#ifndef EXCLUDE_CPU_TIME realtime = thread_consumed_time(&after, &before, &helper); cputime = helper; @@ -1585,6 +1596,7 @@ void thread_call(struct thread *thread) realtime / 1000, cputime / 1000); } #endif /* CONSUMED_TIME_CHECK */ +#endif /* Exclude CPU Time */ } /* Execute thread */ diff --git a/lib/yang.c b/lib/yang.c index 5470762ea6..d153f75530 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -616,6 +616,17 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path) zlog(priority, "libyang: %s", msg); } +void yang_debugging_set(bool enable) +{ + if (enable) { + ly_verb(LY_LLDBG); + ly_verb_dbg(0xFF); + } else { + ly_verb(LY_LLERR); + ly_verb_dbg(0); + } +} + struct ly_ctx *yang_ctx_new_setup(void) { struct ly_ctx *ctx; @@ -645,10 +656,6 @@ void yang_init(void) ly_set_log_clb(ly_log_cb, 1); ly_log_options(LY_LOLOG | LY_LOSTORE); - /* Let libyang log everything possible. */ - ly_verb(LY_LLDBG); - ly_verb_dbg(0xFF); - /* Initialize libyang container for native models. */ ly_native_ctx = yang_ctx_new_setup(); if (!ly_native_ctx) { diff --git a/lib/yang.h b/lib/yang.h index 322c74c76a..6892e36019 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -486,6 +486,14 @@ extern struct yang_data *yang_data_list_find(const struct list *list, extern struct ly_ctx *yang_ctx_new_setup(void); /* + * Enable or disable libyang verbose debugging. + * + * enable + * When set to true, enable libyang verbose debugging, otherwise disable it. + */ +extern void yang_debugging_set(bool enable); + +/* * Initialize the YANG subsystem. Should be called only once during the * daemon initialization process. */ diff --git a/tests/topotests/bgp_large_community/__init__.py b/tests/topotests/bgp_large_community/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_large_community/__init__.py diff --git a/tests/topotests/bgp_large_community/bgp_large_community_topo_1.json b/tests/topotests/bgp_large_community/bgp_large_community_topo_1.json new file mode 100644 index 0000000000..902c01bcbe --- /dev/null +++ b/tests/topotests/bgp_large_community/bgp_large_community_topo_1.json @@ -0,0 +1,262 @@ +{ + "ipv4base": "192.168.1.0", + "ipv4mask": 24, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "192.168.1.0", + "v4mask": 24, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:DB8:F::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {} + } + }, + "r3": { + "dest_link": { + "r1-link1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {} + } + }, + "r3": { + "dest_link": { + "r1-link1": {} + } + } + } + } + } + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "1000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {} + } + }, + "r4": { + "dest_link": { + "r2-link1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {} + } + }, + "r4": { + "dest_link": { + "r2-link1": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link1": {} + } + } + } + } + } + } + } + }, + "r4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r5-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "4000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4-link1": {} + } + }, + "r5": { + "dest_link": { + "r4-link1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4-link1": {} + } + }, + "r5": { + "dest_link": { + "r4-link1": {} + } + } + } + } + } + } + } + }, + "r5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r4-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "6000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r5-link1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r5-link1": {} + } + } + } + } + } + } + } + } + } +} diff --git a/tests/topotests/bgp_large_community/bgp_large_community_topo_2.json b/tests/topotests/bgp_large_community/bgp_large_community_topo_2.json new file mode 100644 index 0000000000..6f1ca90afb --- /dev/null +++ b/tests/topotests/bgp_large_community/bgp_large_community_topo_2.json @@ -0,0 +1,344 @@ +{ + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:DB8:F::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "1000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + } + } + } + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "1000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r4": { + "dest_link": { + "r2": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r4": { + "dest_link": { + "r2": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r5": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + }, + "r4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r6": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "4000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": {} + } + }, + "r6": { + "dest_link": { + "r4": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": {} + } + }, + "r6": { + "dest_link": { + "r4": {} + } + } + } + } + } + } + } + }, + "r5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r6": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "5000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + }, + "r6": { + "dest_link": { + "r5": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + }, + "r6": { + "dest_link": { + "r5": {} + } + } + } + } + } + } + } + }, + "r6": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r5": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "6000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": {} + } + }, + "r5": { + "dest_link": { + "r6": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": {} + } + }, + "r5": { + "dest_link": { + "r6": {} + } + } + } + } + } + } + } + } + } +} diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py new file mode 100755 index 0000000000..83ec1e784d --- /dev/null +++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py @@ -0,0 +1,1281 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + + +""" +Following tests are covered to test large-community/community functionality: +1. Verify if large community attribute can be configured only in correct + canonical format. +2. Verify that the community attribute value, which we have advertised are + received in correct format and values, at the receiving end. +3. Verify BGP Large Community attribute"s transitive property attribute. +4. Verify that BGP Large Communities attribute are malformed, if the length of + the BGP Large Communities Attribute value, expressed in octets, + is not a non-zero multiple of 12. +5. Verify if overriding large community values works fine. +6. Verify that large community values" aggregation works fine. +7. Standard community also work fine in conjunction with large-community. +8. Matching prefixes based on attributes other than prefix list and make use + of set clause (IPV6). +9. Matching prefixes based on attributes other than prefix list and make use + of set clause (IPV4). +10. Verify community and large-community list operations in route-map with all + clause (exact, all, any, regex) works. +11. Verify that any value in BGP Large communities for boundary values. +12. Clear BGP neighbor-ship and check if large community and community + attributes are getting re-populated. + +""" + +import pytest +import time +from os import path as os_path +import sys +from json import load as json_load + +# Required to instantiate the topology builder class. +from lib.topogen import Topogen, get_topogen +from mininet.topo import Topo + +from lib.common_config import ( + start_topology, write_test_header, + write_test_footer, reset_config_on_routers, + create_route_maps, create_bgp_community_lists, + create_prefix_lists, verify_bgp_community, step, + check_address_types +) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, create_router_bgp, + clear_bgp_and_verify +) +from lib.topojson import build_topo_from_json, build_config_from_json + +# Save the Current Working Directory to find configuration files. +CWD = os_path.dirname(os_path.realpath(__file__)) +sys.path.append(os_path.join(CWD, "../")) +sys.path.append(os_path.join(CWD, "../lib/")) + +# Reading the data from JSON File for topology and configuration creation +jsonFile = "{}/bgp_large_community_topo_1.json".format(CWD) +try: + with open(jsonFile, "r") as topoJson: + topo = json_load(topoJson) +except IOError: + logger.info("Could not read file:", jsonFile) + +# Global variables +bgp_convergence = False +NETWORK = { + "ipv4": ["200.50.2.0", "200.50.2.1", "200.50.2.0"], + "ipv6": ["1::1", "1::2", "1::0"] +} +MASK = {"ipv4": "32", "ipv6": "128"} +NET_MASK = {"ipv4": "24", "ipv6": "120"} +IPV4_NET = ["200.50.2.0"] +IPV6_NET = ["1::0"] +CONFIG_ROUTER_R1 = False +CONFIG_ROUTER_R2 = False +CONFIG_ROUTER_ADDITIVE = False +ADDR_TYPES = [] +LARGE_COMM = { + "r1": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1", + "r2": "2:1:1 2:2:1 2:3:1 2:4:1 2:5:1", + "mal_1": "1:1 1:2 1:3 1:4 1:5", + "pf_list_1": "0:0:1 0:0:10 0:0:100", + "pf_list_2": "0:0:2 0:0:20 0:0:200", + "agg_1": "0:0:1 0:0:2 0:0:10 0:0:20 0:0:100 0:0:200 2:1:1 " + "2:2:1 2:3:1 2:4:1 2:5:1", + "agg_2": "0:0:2 0:0:20 0:0:200 2:1:1 " + "2:2:1 2:3:1 2:4:1 2:5:1" +} +STANDARD_COMM = { + "r1": "1:1 1:2 1:3 1:4 1:5", + "r2": "2:1 2:2 2:3 2:4 2:5", + "mal_1": "1 2 3 4 5", + "pf_list_1": "0:1 0:10 0:100", + "pf_list_2": "0:2 0:20 0:200", + "agg_1": "0:1 0:2 0:10 0:20 0:100 0:200 2:1 2:2 2:3 2:4 2:5", + "agg_2": "0:2 0:20 0:200 2:1 2:2 2:3 2:4 2:5" +} + + +class CreateTopo(Topo): + """ + Test topology builder + + + * `Topo`: Topology object + """ + + def build(self, *_args, **_opts): + """Build function""" + tgen = get_topogen(self) + + # Building topology from json file + build_topo_from_json(tgen, topo) + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + global ADDR_TYPES + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + tgen = Topogen(CreateTopo, mod.__name__) + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Checking BGP convergence + global bgp_convergence + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + ##tgen.mininet_cli() + # Api call verify whether BGP is converged + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, ("setup_module :Failed \n Error:" + " {}".format(bgp_convergence)) + + ADDR_TYPES = check_address_types() + logger.info("Running setup_module() done") + + +def teardown_module(): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info("Testsuite end time: {}". + format(time.asctime(time.localtime(time.time())))) + logger.info("=" * 40) + + +def config_router_r1(tgen, topo, tc_name): + global CONFIG_ROUTER_R1 + + input_dict_1 = { + "r1": { + "route_maps": { + "LC1": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": LARGE_COMM["r1"] + }, + "community": { + "num": STANDARD_COMM["r1"] + } + } + } + ] + } + } + } + + step("Configuring LC1 on r1") + result = create_route_maps(tgen, input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + { + "network": "%s/%s" % ( + NETWORK["ipv4"][0], MASK["ipv4"]), + "no_of_network": 4 + } + ], + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": { + "route_maps": [{ + "name": "LC1", + "direction": "out" + }] + } + } + }, + "r3": { + "dest_link": { + "r1-link1": { + "route_maps": [{ + "name": "LC1", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "%s/%s" % ( + NETWORK["ipv6"][0], MASK["ipv6"]), + "no_of_network": 4 + } + ], + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": { + "route_maps": [{ + "name": "LC1", + "direction": "out" + }] + } + } + }, + "r3": { + "dest_link": { + "r1-link1": { + "route_maps": [{ + "name": "LC1", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + + step("Applying LC1 on r1 neighbors and advertising networks") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result) + + CONFIG_ROUTER_R1 = True + + +def config_router_r2(tgen, topo, tc_name): + global CONFIG_ROUTER_R2 + + input_dict = { + "r2": { + "route_maps": { + "LC2": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": LARGE_COMM["r2"] + }, + "community": { + "num": STANDARD_COMM["r2"] + } + } + } + ] + } + } + } + + step("Configuring route-maps LC2 on r2") + result = create_route_maps(tgen, input_dict) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + input_dict_1 = { + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2-link1": { + "route_maps": [{ + "name": "LC2", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2-link1": { + "route_maps": [{ + "name": "LC2", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + + step("Applying LC2 on r2 neighbors in out direction") + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + CONFIG_ROUTER_R2 = True + + +def config_router_additive(tgen, topo, tc_name): + global CONFIG_ROUTER_ADDITIVE + + input_dict = { + "r2": { + "route_maps": { + "LC2": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": LARGE_COMM["r2"], + "action": "additive" + }, + "community": { + "num": STANDARD_COMM["r2"], + "action": "additive" + } + } + } + ] + } + } + } + + step("Configuring LC2 with community attributes as additive") + result = create_route_maps(tgen, input_dict) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + # tgen.mininet_cli() + CONFIG_ROUTER_ADDITIVE = True + + +def config_for_as_path(tgen, topo, tc_name): + config_router_r1(tgen, topo, tc_name) + + config_router_r2(tgen, topo, tc_name) + + # Create ipv6 prefix list + input_dict_1 = { + "r1": { + "prefix_lists": { + "ipv4": { + "pf_list_1": [ + { + "seqid": "10", + "network": "%s/%s" % (NETWORK["ipv4"][0], + MASK["ipv4"]), + "action": "permit" + } + ], + "pf_list_2": [ + { + "seqid": "10", + "network": "%s/%s" % (NETWORK["ipv4"][1], + MASK["ipv4"]), + "action": "permit" + } + ] + }, + "ipv6": { + "pf_list_3": [ + { + "seqid": "10", + "network": "%s/%s" % (NETWORK["ipv6"][0], + MASK["ipv6"]), + "action": "permit" + } + ], + "pf_list_4": [ + { + "seqid": "10", + "network": "%s/%s" % (NETWORK["ipv6"][1], + MASK["ipv6"]), + "action": "permit" + } + ] + } + + } + } + } + + step("Configuring prefix-lists on r1 to filter networks") + result = create_prefix_lists(tgen, input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + input_dict_2 = { + "r1": { + "route_maps": { + "LC1": [ + { + "action": "permit", + "seq_id": 10, + "match": { + "ipv4": { + "prefix_lists": "pf_list_1" + } + }, + "set": { + "large_community": { + "num": LARGE_COMM["pf_list_1"] + }, + "community": { + "num": STANDARD_COMM["pf_list_1"] + } + } + }, + { + "action": "permit", + "seq_id": 20, + "match": { + "ipv6": { + "prefix_lists": "pf_list_3" + } + }, + "set": { + "large_community": { + "num": LARGE_COMM["pf_list_1"] + }, + "community": { + "num": STANDARD_COMM["pf_list_1"] + } + } + }, + { + "action": "permit", + "seq_id": 30, + "match": { + "ipv4": { + "prefix_lists": "pf_list_2" + } + }, + "set": { + "large_community": { + "num": LARGE_COMM["pf_list_2"] + }, + "community": { + "num": STANDARD_COMM["pf_list_2"] + } + } + }, + { + "action": "permit", + "seq_id": 40, + "match": { + "ipv6": { + "prefix_lists": "pf_list_4" + } + }, + "set": { + "large_community": { + "num": LARGE_COMM["pf_list_2"] + }, + "community": { + "num": STANDARD_COMM["pf_list_2"] + } + } + } + ] + } + } + } + + step("Applying prefix-lists match in route-map LC1 on r1. Setting" + " community attritbute for filtered networks") + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + config_router_additive(tgen, topo, tc_name) + + input_dict_3 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": LARGE_COMM["pf_list_1"], + "large": True + }, + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": STANDARD_COMM["pf_list_1"], + } + ] + } + } + + step("Configuring bgp community lists on r4") + result = create_bgp_community_lists(tgen, input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + input_dict_4 = { + "r4": { + "route_maps": { + "LC4": [ + { + "action": "permit", + "seq_id": "10", + "match": { + "large_community_list": {"id": "ANY"}, + "community_list": {"id": "ANY"} + }, + "set": { + "aspath": { + "as_num": "4000000", + "as_action": "prepend" + } + } + } + ] + } + } + } + + step("Applying community list on route-map on r4") + result = create_route_maps(tgen, input_dict_4) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + input_dict_5 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r4-link1": { + "route_maps": [{ + "name": "LC4", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r4-link1": { + "route_maps": [{ + "name": "LC4", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + + step("Applying route-map LC4 out from r4 to r5 ") + result = create_router_bgp(tgen, topo, input_dict_5) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + +##################################################### +# +# Test cases +# +##################################################### +def test_large_community_set(request): + """ + Verify if large community attribute can be configured only in correct + canonical format. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # API call to modify router id + # input_dict dictionary to be provided to configure route_map + input_dict = { + "r1": { + "route_maps": { + "LC1": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": {"num": LARGE_COMM["r1"]}, + "community": {"num": STANDARD_COMM["r1"]} + } + } + ] + } + } + } + + step("Trying to set bgp communities") + result = create_route_maps(tgen, input_dict) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_advertise(request): + """ + Verify that the community attribute value, which we have advertised are + received in correct format and values, at the receiving end. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_router_r1(tgen, topo, tc_name) + + input_dict = { + "largeCommunity": LARGE_COMM["r1"], + "community": STANDARD_COMM["r1"], + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r2", [NETWORK[adt][0]], + input_dict) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result) + + result = verify_bgp_community(tgen, adt, "r3", [NETWORK[adt][0]], + input_dict) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_transitive(request): + """ + Verify BGP Large Community attribute"s transitive property attribute. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + config_router_r1(tgen, topo, tc_name) + + input_dict_1 = { + "largeCommunity": LARGE_COMM["r1"], + "community": STANDARD_COMM["r1"] + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][0]], + input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_override(request): + """ + Verify if overriding large community values works fine. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_router_r1(tgen, topo, tc_name) + + config_router_r2(tgen, topo, tc_name) + + input_dict_3 = { + "largeCommunity": LARGE_COMM["r2"], + "community": STANDARD_COMM["r2"] + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][1]], + input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_additive(request): + """ + Verify that large community values" aggregation works fine. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_router_r1(tgen, topo, tc_name) + + config_router_r2(tgen, topo, tc_name) + + config_router_additive(tgen, topo, tc_name) + + input_dict_1 = { + "largeCommunity": "%s %s" % (LARGE_COMM["r1"], LARGE_COMM["r2"]), + "community": "%s %s" % (STANDARD_COMM["r1"], STANDARD_COMM["r2"]) + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][0]], + input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_match_as_path(request): + """ + Matching prefixes based on attributes other than prefix list and make use + of set clause. + """ + + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_for_as_path(tgen, topo, tc_name) + + input_dict = { + "largeCommunity": "%s %s" % ( + LARGE_COMM["pf_list_1"], LARGE_COMM["r2"]), + "community": "%s %s" % ( + STANDARD_COMM["pf_list_1"], STANDARD_COMM["r2"]), + } + + input_dict_1 = { + "largeCommunity": "%s %s" % ( + LARGE_COMM["pf_list_2"], LARGE_COMM["r2"]), + "community": "%s %s" % ( + STANDARD_COMM["pf_list_2"], STANDARD_COMM["r2"]), + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r5", [NETWORK[adt][0]], + input_dict) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + result = verify_bgp_community(tgen, adt, "r5", [NETWORK[adt][1]], + input_dict_1, expected=False) + + assert result is not True, "Test case {} : Should fail \n Error: {}". \ + format(tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_match_all(request): + """ + Verify community and large-community list operations in route-map with all + clause (exact, all, any, regex) works. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_router_r1(tgen, topo, tc_name) + + config_router_r2(tgen, topo, tc_name) + + config_router_additive(tgen, topo, tc_name) + + input_dict_1 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "1:1:1", + "large": True + }, + { + "community_type": "standard", + "action": "permit", + "name": "ALL", + "value": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1 2:1:1 2:2:1", + "large": True + }, + { + "community_type": "expanded", + "action": "permit", + "name": "EXP_ALL", + "value": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1 2:[1-5]:1", + "large": True + } + ] + } + } + + step("Create bgp community lists for ANY, EXACT and EXP_ALL match") + + result = create_bgp_community_lists(tgen, input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + input_dict_2 = { + "r4": { + "route_maps": { + "LC4": [ + { + "action": "permit", + "seq_id": "10", + "match": {"large-community-list": {"id": "ANY"}} + }, + { + "action": "permit", + "seq_id": "20", + "match": {"large-community-list": {"id": "EXACT"}} + }, + { + "action": "permit", + "seq_id": "30", + "match": {"large-community-list": {"id": "EXP_ALL"}} + } + ] + } + } + } + + step("Applying bgp community lits on LC4 route-map") + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + input_dict_3 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r4-link1": { + "route_maps": [{ + "name": "LC4", + "direction": "in" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r4-link1": { + "route_maps": [{ + "name": "LC4", + "direction": "in" + }] + } + } + } + } + } + } + } + } + } + } + + step("Apply route-mpa LC4 on r4 for r2 neighbor, direction 'in'") + + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + input_dict_4 = { + "largeCommunity": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1 2:1:1 2:2:1 2:3:1 " + "2:4:1 2:5:1" + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][0]], + input_dict_4) + assert result is True, "Test case {} : Should fail \n Error: {}". \ + format(tc_name, result) + + write_test_footer(tc_name) + + +#@pytest.mark.skip(reason="as-set not working for ipv6") +def test_large_community_aggregate_network(request): + """ + Restart router and check if large community and community + attributes are getting re-populated. + """ + + tc_name = request.node.name + write_test_header(tc_name) + + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + config_for_as_path(tgen, topo, tc_name) + + input_dict = { + "community": STANDARD_COMM["agg_1"], + "largeCommunity": LARGE_COMM["agg_1"] + } + + input_dict_1 = { + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "aggregate_address": [ + { + "network": "%s/%s" % ( + NETWORK["ipv4"][2], NET_MASK["ipv4"]), + "as_set": True + } + ] + } + }, + "ipv6": { + "unicast": { + "aggregate_address": [ + { + "network": "%s/%s" % ( + NETWORK["ipv6"][2], NET_MASK["ipv6"]), + "as_set": True + } + ] + } + } + } + } + } + } + + step("Configuring aggregate address as-set on r2") + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result) + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r4", + ["%s/%s" % (NETWORK[adt][2], + NET_MASK[adt])], + input_dict) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + { + "network": "%s/%s" % ( + NETWORK["ipv4"][0], MASK["ipv4"]), + "no_of_network": 1, + "delete": True + } + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "%s/%s" % ( + NETWORK["ipv6"][0], MASK["ipv6"]), + "no_of_network": 1, + "delete": True + } + ] + } + } + } + } + } + } + + step("Stop advertising one of the networks") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result) + + input_dict_3 = { + "community": STANDARD_COMM["agg_2"], + "largeCommunity": LARGE_COMM["agg_2"] + } + + for adt in ADDR_TYPES: + step("Verifying bgp community values on r5 is also modified") + result = verify_bgp_community(tgen, adt, "r4", + ["%s/%s" % (NETWORK[adt][2], + NET_MASK[adt])], + input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_boundary_values(request): + """ + Verify that any value in BGP Large communities for boundary values. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + input_dict = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "0:-1" + } + ] + } + } + + step("Checking boundary value for community 0:-1") + result = create_bgp_community_lists(tgen, input_dict) + assert result is not True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + step("Checking community attribute 0:65536") + input_dict_2 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "0:65536" + } + ] + } + } + + step("Checking boundary value for community 0:65536") + result = create_bgp_community_lists(tgen, input_dict_2) + assert result is not True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + step("Checking boundary value for community 0:4294967296") + input_dict_3 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "0:4294967296", + "large": True + } + ] + } + } + + result = create_bgp_community_lists(tgen, input_dict_3) + assert result is not True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + step("Checking boundary value for community 0:-1:1") + + input_dict_4 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "0:-1:1", + "large": True + } + ] + } + } + + result = create_bgp_community_lists(tgen, input_dict_4) + assert result is not True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + +def test_large_community_after_clear_bgp(request): + """ + Clear BGP neighbor-ship and check if large community and community + attributes are getting re-populated. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_router_r1(tgen, topo, tc_name) + + input_dict = { + "largeCommunity": LARGE_COMM["r1"], + "community": STANDARD_COMM["r1"] + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r2", [NETWORK[adt][0]], + input_dict) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + step("Clearing BGP on r1") + clear_bgp_and_verify(tgen, topo, "r1") + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r2", [NETWORK[adt][0]], + input_dict) + assert result is True, "Test case {} : Failed \n Error: {}". \ + format(tc_name, result) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py new file mode 100755 index 0000000000..cba20551cd --- /dev/null +++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py @@ -0,0 +1,2408 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +#Inc. ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bgp_large_community_topo_1.py: Test BGP large community. + +Following tests are covered: +1. Verify the standard large-community-lists can permit or deny + large community attribute only in the correct canonical format. +2. Verify the expanded large-community-lists can permit or deny + large community attribute both in the correct canonical format + as well as REG_EX. +3. Verify that we can modify a large-community-list is in use, + to add/remove attribute value and it takes immediate effect. +4. Verify that large community attribute gets advertised when + route-map is applied to a neighbor and cleared when route-map + is removed. +5. Verify that duplicate BGP Large Community values are NOT be transmitted. +6. Verify if we want to remove all the large-community attributes from a + set of prefix we can set the value as NONE. +7. Redistribute connected and static routes in BGP process with a route-map + appending/removing L-comm attributes. +8. Verify if we want to remove specific large-community values from + a set of prefix we can make use of DELETE operation based on L-comm list. +9. Verify that if community values are NOT be advertised to a specific + neighbour, we negate send-community command. + (Send-community all is enabled by default for all neighbors) +10. Verify that large-community lists can not be configured without providing + specific L-community values(for match/delete operation in a route-map). +11. Verify that Match_EXACT clause should pass only if all of the L-comm + values configured (horizontally) in the community list is present in + the prefix. There must be no additional L-communities in the prefix. +12. Verify that Match_ALL clause should pass only if ALL of the L-comm values + configured (horizontally) in the community list is present in the prefix. + There could be additional L-communities in the prefix that are not present + in the L-comm list. +13. Verify that Match_ANY clause should pass only if at-least any one L-comm + value configured(vertically) in large-community list, is present in prefixes. +14. Verify large-community lists operation in a route-map with match RegEx + statements. +""" + +import os +import sys +import json +import pytest +import time + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +# Import topoJson from lib, to create topology and initial configuration +from lib.topogen import Topogen, get_topogen +from mininet.topo import Topo + +from lib.common_config import ( + start_topology, write_test_header, + write_test_footer, reset_config_on_routers, + create_route_maps, create_bgp_community_lists, + create_prefix_lists, verify_bgp_community, step, + verify_create_community_list, delete_route_maps, + verify_route_maps, create_static_routes, + check_address_types +) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, create_router_bgp, + clear_bgp_and_verify +) +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology and configuration creation +jsonFile = "{}/bgp_large_community_topo_2.json".format(CWD) + +try: + with open(jsonFile, "r") as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) + +# Global variables +bgp_convergence = False + +NETWORKS = {"ipv4": ["200.50.2.0/32"], "ipv6": ["1::1/128"]} + + +class GenerateTopo(Topo): + """ + Test topology builder + + * `Topo`: Topology object + """ + + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Building topology from json file + build_topo_from_json(tgen, topo) + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("="*40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + tgen = Topogen(GenerateTopo, mod.__name__) + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Checking BGP convergence + global bgp_convergence, ADDR_TYPES + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + # Ipv4 + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, ("setup_module :Failed \n Error:" + " {}".format(bgp_convergence)) + ADDR_TYPES = check_address_types() + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info("Testsuite end time: {}".\ + format(time.asctime(time.localtime(time.time())))) + logger.info("="*40) + +##################################################### +# +# Testcases +# +##################################################### + + +def test_create_bgp_standard_large_community_list(request): + """ + Create standard large-community-list and verify it can permit + or deny large community attribute only in the correct canonical + format. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + step("Create srtandard large community list") + input_dict = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "LC_1_STD", + "value": "2:1:1 2:1:2 1:2:3", + "large": True + }, + { + "community_type": "standard", + "action": "permit", + "name": "LC_2_STD", + "value": "3:1:1 3:1:2", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create srtandard large community list with in-correct values") + input_dict = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "LC_1_STD_ERR", + "value": "0:0:0", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + ## TODO should fail + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_create_bgp_expanded_large_community_list(request): + """ + Create expanded large-community-list and verify it can permit + or deny large community attribute both in the correct canonical + format as well as REG_EX + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create expanded large community list") + input_dict = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "expanded", + "action": "permit", + "name": "LC_1_EXP", + "value": "1:1:200 1:2:* 3:2:1", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_modify_large_community_lists_referenced_by_rmap(request): + """ + This test is to verify that we can modify a large-community-list + is in use, add/remove attribute value and it takes immediate effect. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create standard large community list") + input_dict_1 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "LC_DEL", + "value": "1:2:1 1:3:1 2:1:1 2:2:2 3:3:3", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create route map") + input_dict_2 = { + "r1": { + "route_maps": { + "RM_R2_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "1:2:1 1:3:1 2:10:1 3:3:3 4:4:4 5:5:5", + "action": "additive" + } + } + } + ] + } + }, + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_comm_list": { + "id": "LC_DEL", + "delete": True + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.50.2.0/32"} + ], + "neighbor": { + "r2": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": "RM_R2_OUT", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "1::1/128"} + ], + "neighbor": { + "r2": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": "RM_R2_OUT", + "direction": "out" + }] + } + } + } + } + } + } + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify Community-list") + dut = "r4" + input_dict_4 = { + "largeCommunity": "2:10:1 4:4:4 5:5:5" + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_apply_and_remove(request): + """ + This test is to verify that large community attribute gets advertised when + route-map is applied to a neighbor and cleared when route-map is removed + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_1 = { + "r4": { + "route_maps": { + "RM_LC1": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "200:200:1 200:200:10 200:200:20000", + "action": "additive" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.50.2.0/32"} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "1::1/128"} + ] + } + } + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_LC1", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_LC1", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list") + dut = "r6" + input_dict_4 = { + "largeCommunity": "200:200:1 200:200:10 200:200:20000" + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Delete route map reference by community-list") + input_dict_3 = { + "r4": { + "route_maps": ["RM_LC1"] + } + } + result = delete_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify route map is deleted") + result = verify_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list") + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_4, expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_duplicate_large_community_list_attributes_not_transitive(request): + """ + This test is to verify that duplicate BGP Large Community values + are NOT be transmitted. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_1 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "0:0:1 0:0:10 0:0:100 2:0:1 2:0:2 2:0:3" + " 2:0:4 2:0:5", + "action": "additive" + } + } + } + ], + "RM_R4_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "0:0:1 0:0:10 0:0:10000 2:0:1 2:0:2", + "action": "additive" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.50.2.0/32"} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "1::1/128"} + ] + } + } + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + }, + "r6": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_OUT", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + }, + "r6": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_OUT", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list") + dut = "r6" + input_dict_4 = { + "largeCommunity": + "0:0:1 0:0:10 0:0:100 0:0:10000 2:0:1 2:0:2 2:0:3 2:0:4 2:0:5" + } + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_set_none(request): + """ + This test is to verify if we want to remove all the large-community + attributes from a set of prefix we can set the value as NONE. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_1 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "0:0:1 0:0:10 0:0:100 2:0:1 2:0:2 2:0:3" + " 2:0:4", + "action": "additive" + } + } + } + ] + } + }, + "r6": { + "route_maps": { + "RM_R6_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "none" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map") + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.50.2.0/32"} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "1::1/128"} + ] + } + } + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + } + } + } + }, + "r6": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": { + "route_maps": [{ + "name": "RM_R6_IN", + "direction": "in" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": { + "route_maps": [{ + "name": "RM_R6_IN", + "direction": "in" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify Community-list") + dut = "r6" + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_lcomm_lists_with_redistribute_static_connected_rmap(request): + """ + This test is to verify redistribute connected and static ipv4 routes + in BGP process with a route-map appending/removing L-comm attributes. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("create static routes") + input_dict = { + "r1": { + "static_routes": [ + { + "network": "200.50.2.0/32", + "next_hop": "10.0.0.6" + }, + { + "network": "1::1/128", + "next_hop": "fd00:0:0:1::2" + } + ] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("redistribute static routes") + input_dict_1 = { + "r1":{ + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + { + "redist_type": "static", + "attribute": "route-map RM_R2_OUT" + }, + { + "redist_type": "connected", + "attribute": "route-map RM_R2_OUT" + } + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + { + "redist_type": "static", + "attribute": "route-map RM_R2_OUT" + }, + { + "redist_type": "connected", + "attribute": "route-map RM_R2_OUT" + } + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create route map") + input_dict_3 = { + "r1": { + "route_maps": { + "RM_R2_OUT": [{ + "action": "permit", + "set": { + "large_community": {"num":"55:55:55 555:555:555"} + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list for static and connected ipv4 route on" + " r2") + + input_dict_5 = { + "largeCommunity": "55:55:55 555:555:555" + } + + if "ipv4" in ADDR_TYPES: + dut = "r2" + networks = ["200.50.2.0/32", "1.0.1.17/32"] + result = verify_bgp_community(tgen, "ipv4", dut, networks, + input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list for static and connected ipv4 route" + " on r4") + dut = "r4" + networks = ["200.50.2.0/32", "1.0.1.17/32"] + result = verify_bgp_community(tgen, "ipv4", dut, networks, + input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + if "ipv6" in ADDR_TYPES: + step("Verify large-community-list for static and connected ipv6 route" + " on r2") + dut = "r2" + networks = ["1::1/128", "2001:db8:f::1:17/128"] + result = verify_bgp_community(tgen, "ipv6", dut, networks, + input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list for static and connected ipv6 route" + " on r4") + dut = "r4" + networks = ["1::1/128", "2001:db8:f::1:17/128"] + result = verify_bgp_community(tgen, "ipv6", dut, networks, + input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_set_delete(request): + """ + This test is to verify if we want to remove specific large-community + values from a set of prefix we can make use of DELETE operation based + on L-comm list + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("configure route_map") + input_dict_2 = { + "r6": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "Test", + "value": "1:2:1 1:1:10 1:3:100", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create route map") + input_dict_3 = { + "r6": { + "route_maps": { + "RM_R6_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_comm_list": { + "id": "Test", + "delete": True + } + } + } + ] + } + }, + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "1:2:1 1:1:10 1:3:100 2:1:1 2:2:2 2:3:3" + " 2:4:4 2:5:5", + "action": "additive" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_4 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.50.2.0/32"} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "1::1/128"} + ] + } + } + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + } + } + } + }, + "r6": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": { + "route_maps": [{ + "name": "RM_R6_IN", + "direction": "in" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": { + "route_maps": [{ + "name": "RM_R6_IN", + "direction": "in" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list") + dut = "r6" + input_dict_5 = { + "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_no_send_community(request): + """ + This test is to verify if we want to remove specific large-community + values from a set of prefix we can make use of DELETE operation based + on L-comm list + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_2 = { + "r5": { + "route_maps": { + "RM_R6_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.50.2.0/32"} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "1::1/128"} + ] + } + } + } + } + }, + "r5": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r5": { + "route_maps": [{ + "name": "RM_R6_OUT", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r5": { + "route_maps": [{ + "name": "RM_R6_OUT", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list") + dut = "r6" + input_dict_4 = { + "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for no-send-community") + input_dict_5 = { + "r5": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r5": { + "no_send_community": "large" + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r5": { + "no_send_community": "large" + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify Community-list") + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_4, expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_create_large_community_lists_with_no_attribute_values(request): + """ + This test is to verify that large-community lists can not be + configured without providing specific L-community values + (for match/delete operation in a route-map). + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create standard large commumity-list") + input_dict_1 = { + "r5": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "Test1", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_1) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_match_exact(request): + """ + This test is to verify that Match_EXACT clause should pass + only if all of the L-comm values configured (horizontally) + in the community list is present in the prefix. There must + be no additional L-communities in the prefix. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_2 = { + "r2": { + "route_maps": { + "RM_R4_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.50.2.0/32"} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "1::1/128"} + ] + } + } + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [{ + "name": "RM_R4_OUT", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [{ + "name": "RM_R4_OUT", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create standard large commumity-list") + input_dict_4 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "EXACT", + "value": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create route map") + input_dict_5 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "match": { + "large-community-list": ["EXACT"], + "match_exact": True + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map") + input_dict_6 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_6) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list") + dut = "r4" + input_dict_4 = { + "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_match_all(request): + """ + This test is to verify that Match_ALL clause should pass + only if ALL of the L-comm values configured (horizontally) + in the community list are present in the prefix. There + could be additional L-communities in the prefix that are + not present in the L-comm list. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_2 = { + "r2": { + "route_maps": { + "RM_R4_OUT": [{ + "action": "permit", + "set": { + "large_community": { + "num": "1:1:1 1:2:3 2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.50.2.0/32"} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "1::1/128"} + ] + } + } + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [{ + "name": "RM_R4_OUT", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [{ + "name": "RM_R4_OUT", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create standard large commumity-list") + input_dict_4 = { + "r3": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ALL", + "value": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create route map") + input_dict_5 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "match": { + "large-community-list": { + "id": "ALL" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map") + input_dict_6 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_6) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list") + dut = "r4" + input_dict_4 = { + "largeCommunity": "1:1:1 1:2:3 2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_match_any(request): + """ + This test is to verify that Match_ANY clause should pass + only if at-least any one L-comm value configured(vertically) + in large-community list, is present in prefixes. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_2 = { + "r2": { + "route_maps": { + "RM_R4_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.50.2.0/32"} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "1::1/128"} + ] + } + } + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [{ + "name": "RM_R4_OUT", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [{ + "name": "RM_R4_OUT", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create standard large commumity-list") + input_dict_4 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "2:1:1", + "large": True + }, + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "2:2:1", + "large": True + }, + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "2:3:1", + "large": True + }, + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "2:4:1", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create route map") + input_dict_5 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "match": { + "large-community-list": { + "id": "ANY" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map") + input_dict_6 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_6) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list") + dut = "r4" + input_dict_7 = { + "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_7) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_match_regex(request): + """ + This test is to verify large-community lists" operation in a route-map + with match RegEx statements. Match clause should pass only if the + complete string of L-comm values are matched + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_2 = { + "r2": { + "route_maps": { + "RM_R4_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "1:1:1 1:1:2 2:1:3 2:1:4 2:1:5", + }, + "community": { + "num": "1:1 1:2 1:3 1:4 1:5" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.50.2.0/32"} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "1::1/128"} + ] + } + } + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [{ + "name": "RM_R4_OUT", + "direction": "out" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [{ + "name": "RM_R4_OUT", + "direction": "out" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo,input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create standard large commumity-list") + input_dict_4 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ALL", + "value": "1:1:1 2:1:3 2:1:4 2:1:5", + "large": True + }, + { + "community_type": "expanded", + "action": "permit", + "name": "EXP_ALL", + "value": "1:1:1 2:1:[3-5]", + "large": True + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create route map") + input_dict_5 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "match": { + "large_community_list": { + "id": "ALL", + }, + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure neighbor for route map") + input_dict_6 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [{ + "name": "RM_R4_IN", + "direction": "in" + }] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_6) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify large-community-list") + dut = "r4" + input_dict_7 = { + "largeCommunity": "1:1:1 1:1:2 2:1:3 2:1:4 2:1:5" + } + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_7) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Delete route map reference by community-list") + input_dict_3 = { + "r4": { + "route_maps": ["RM_R4_IN"] + } + } + result = delete_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + result = verify_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Create route map") + input_dict_5 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "20", + "match": { + "large_community_list": { + "id": "EXP_ALL", + }, + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("clear ip bgp") + result = clear_bgp_and_verify(tgen, topo, 'r4') + assert result is True, "Testcase {} :Failed \n Error: {}". \ + format(tc_name, result) + + step("Verify large-community-list") + dut = "r4" + input_dict_7 = { + "largeCommunity": "1:1:1 1:1:2 2:1:3 2:1:4 2:1:5" + } + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], + input_dict_7, expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".\ + format(tc_name, result) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 41d6a326cf..7ec584bf5f 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -200,29 +200,6 @@ def __create_bgp_global(tgen, input_dict, router, build=False): 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") - - if del_action: - cmd = "no {}".format(cmd) - - config_data.append(cmd) - return config_data @@ -300,15 +277,25 @@ def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, 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) + aggregate_addresses = addr_data.setdefault("aggregate_address", []) + for aggregate_address in aggregate_addresses: + network = aggregate_address.setdefault("network", None) + if not network: + logger.debug("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 = "{} as-set".format(cmd) + if summary: + cmd = "{} summary".format(cmd) + + if del_action: + cmd = "no {}".format(cmd) config_data.append(cmd) @@ -481,14 +468,20 @@ def __create_bgp_unicast_address_family(topo, input_dict, router, addr_type, send_community = peer.setdefault("send_community", None) prefix_lists = peer.setdefault("prefix_lists", {}) route_maps = peer.setdefault("route_maps", {}) + no_send_community = peer.setdefault("no_send_community", None) # next-hop-self if next_hop_self: config_data.append("{} next-hop-self".format(neigh_cxt)) - # no_send_community + # send_community if send_community: config_data.append("{} send-community".format(neigh_cxt)) + # no_send_community + if no_send_community: + config_data.append("no {} send-community {}".format( + neigh_cxt, no_send_community)) + if prefix_lists: for prefix_list in prefix_lists: name = prefix_list.setdefault("name", {}) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index c413bf45c7..38b97cba2d 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -44,7 +44,7 @@ from lib.topotest import interface_set_status FRRCFG_FILE = "frr_json.conf" FRRCFG_BKUP_FILE = "frr_json_initial.conf" -ERROR_LIST = ["Malformed", "Failure", "Unknown"] +ERROR_LIST = ["Malformed", "Failure", "Unknown", "Incomplete"] ROUTER_LIST = [] #### @@ -617,7 +617,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) + step("START -> Testcase : %s" % tc_name, reset=True) logger.info("*"*(len(tc_name)+count)) @@ -709,9 +709,9 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0): kwargs.pop('expected') ret = func(*args, **kwargs) logger.debug("Function returned %s" % ret) - if return_is_str and isinstance(ret, bool): + if return_is_str and isinstance(ret, bool) and _expected: return ret - elif return_is_str and _expected is False: + if isinstance(ret, str) and _expected is False: return ret if _attempts == i: @@ -732,6 +732,31 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0): return _retry +class Stepper: + """ + Prints step number for the test case step being executed + """ + count = 1 + + def __call__(self, msg, reset): + if reset: + Stepper.count = 1 + logger.info(msg) + else: + logger.info("STEP %s: '%s'", Stepper.count, msg) + Stepper.count += 1 + + +def step(msg, reset=False): + """ + Call Stepper to print test steps. Need to reset at the beginning of test. + * ` msg` : Step message body. + * `reset` : Reset step count to 1 when set to True. + """ + _step = Stepper() + _step(msg, reset) + + ############################################# # These APIs, will used by testcase ############################################# @@ -1949,3 +1974,61 @@ def verify_bgp_community(tgen, addr_type, router, network, input_dict=None): logger.debug("Exiting lib API: verify_bgp_community()") return True + + +def verify_create_community_list(tgen, input_dict): + """ + API is to verify if large community list is created for any given DUT in + input_dict by running "sh bgp large-community-list {"comm_name"} detail" + command. + Parameters + ---------- + * `tgen`: topogen object + * `input_dict`: having details like - for which router, large community + needs to be verified + Usage + ----- + input_dict = { + "r1": { + "large-community-list": { + "standard": { + "Test1": [{"action": "PERMIT", "attribute":\ + ""}] + }}}} + result = verify_create_community_list(tgen, input_dict) + Returns + ------- + errormsg(str) or True + """ + + logger.debug("Entering lib API: verify_create_community_list()") + + for router in input_dict.keys(): + if router not in tgen.routers(): + continue + + rnode = tgen.routers()[router] + + logger.info("Verifying large-community is created for dut %s:", + router) + + for comm_data in input_dict[router]["bgp_community_lists"]: + comm_name = comm_data["name"] + comm_type = comm_data["community_type"] + show_bgp_community = \ + run_frr_cmd(rnode, + "show bgp large-community-list {} detail". + format(comm_name)) + + # Verify community list and type + if comm_name in show_bgp_community and comm_type in \ + show_bgp_community: + logger.info("BGP %s large-community-list %s is" + " created", comm_type, comm_name) + else: + errormsg = "BGP {} large-community-list {} is not" \ + " created".format(comm_type, comm_name) + return errormsg + + logger.debug("Exiting lib API: verify_create_community_list()") + return True diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index b4049b55eb..819a06e99a 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -893,7 +893,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src, THREAD_OFF(r->t_adver_timer); thread_add_timer_msec( master, vrrp_adver_timer_expire, r, - r->vr->advertisement_interval * 10, + r->vr->advertisement_interval * CS2MS, &r->t_adver_timer); } else if (pkt->hdr.priority > r->priority || ((pkt->hdr.priority == r->priority) @@ -913,7 +913,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src, THREAD_OFF(r->t_master_down_timer); thread_add_timer_msec(master, vrrp_master_down_timer_expire, r, - r->master_down_interval * 10, + r->master_down_interval * CS2MS, &r->t_master_down_timer); vrrp_change_state(r, VRRP_STATE_BACKUP); } else { @@ -931,7 +931,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src, THREAD_OFF(r->t_master_down_timer); thread_add_timer_msec( master, vrrp_master_down_timer_expire, r, - r->skew_time * 10, &r->t_master_down_timer); + r->skew_time * CS2MS, &r->t_master_down_timer); } else if (r->vr->preempt_mode == false || pkt->hdr.priority >= r->priority) { if (r->vr->version == 3) { @@ -942,7 +942,7 @@ static int vrrp_recv_advertisement(struct vrrp_router *r, struct ipaddr *src, THREAD_OFF(r->t_master_down_timer); thread_add_timer_msec(master, vrrp_master_down_timer_expire, r, - r->master_down_interval * 10, + r->master_down_interval * CS2MS, &r->t_master_down_timer); } else if (r->vr->preempt_mode == true && pkt->hdr.priority < r->priority) { @@ -1456,7 +1456,7 @@ static int vrrp_adver_timer_expire(struct thread *thread) /* Reset the Adver_Timer to Advertisement_Interval */ thread_add_timer_msec(master, vrrp_adver_timer_expire, r, - r->vr->advertisement_interval * 10, + r->vr->advertisement_interval * CS2MS, &r->t_adver_timer); } else { zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM @@ -1480,7 +1480,7 @@ static int vrrp_master_down_timer_expire(struct thread *thread) r->vr->vrid, family2str(r->family)); thread_add_timer_msec(master, vrrp_adver_timer_expire, r, - r->vr->advertisement_interval * 10, + r->vr->advertisement_interval * CS2MS, &r->t_adver_timer); vrrp_change_state(r, VRRP_STATE_MASTER); @@ -1556,14 +1556,14 @@ static int vrrp_startup(struct vrrp_router *r) if (r->priority == VRRP_PRIO_MASTER) { thread_add_timer_msec(master, vrrp_adver_timer_expire, r, - r->vr->advertisement_interval * 10, + r->vr->advertisement_interval * CS2MS, &r->t_adver_timer); vrrp_change_state(r, VRRP_STATE_MASTER); } else { r->master_adver_interval = r->vr->advertisement_interval; vrrp_recalculate_timers(r); thread_add_timer_msec(master, vrrp_master_down_timer_expire, r, - r->master_down_interval * 10, + r->master_down_interval * CS2MS, &r->t_master_down_timer); vrrp_change_state(r, VRRP_STATE_BACKUP); } diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index f71b343140..239b02ee7f 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -145,10 +145,11 @@ DEFPY(vrrp_advertisement_interval, struct vrrp_vrouter *vr; uint16_t newadvint = - no ? vd.advertisement_interval * 10 : advertisement_interval; + no ? vd.advertisement_interval * CS2MS : advertisement_interval; - if (newadvint % 10 != 0) { - vty_out(vty, "%% Value must be a multiple of 10\n"); + if (newadvint % CS2MS != 0) { + vty_out(vty, "%% Value must be a multiple of %u\n", + (unsigned int)CS2MS); return CMD_WARNING_CONFIG_FAILED; } @@ -327,8 +328,9 @@ DEFPY(vrrp_default, "Force VRRP router into administrative shutdown\n") { if (adv) { - if (advint % 10 != 0) { - vty_out(vty, "%% Value must be a multiple of 10\n"); + if (advint % CS2MS != 0) { + vty_out(vty, "%% Value must be a multiple of %u\n", + (unsigned int)CS2MS); return CMD_WARNING_CONFIG_FAILED; } /* all internal computations are in centiseconds */ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 0c7a7471b1..643dcb7edc 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1339,7 +1339,7 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end", } DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd, - "router bgp [(1-4294967295)$instasn [<view|vrf> WORD]]", + "router bgp [(1-4294967295) [<view|vrf> WORD]]", ROUTER_STR BGP_STR AS_STR "BGP view\nBGP VRF\n" "View/VRF name\n") @@ -2255,6 +2255,7 @@ DEFUN (vtysh_show_poll, return ret; } +#ifndef EXCLUDE_CPU_TIME DEFUN (vtysh_show_thread, vtysh_show_thread_cmd, "show thread cpu [FILTER]", @@ -2281,6 +2282,7 @@ DEFUN (vtysh_show_thread, } return ret; } +#endif DEFUN (vtysh_show_work_queues, vtysh_show_work_queues_cmd, @@ -2427,10 +2429,10 @@ DEFUN (vtysh_show_error_code, /* Northbound. */ DEFUN (show_yang_operational_data, show_yang_operational_data_cmd, - "show yang operational-data XPATH$xpath\ + "show yang operational-data XPATH\ [{\ - format <json$json|xml$xml>\ - |translate WORD$translator_family\ + format <json|xml>\ + |translate WORD\ }]" DAEMONS_LIST, SHOW_STR "YANG information\n" @@ -2454,9 +2456,10 @@ DEFUNSH(VTYSH_ALL, debug_nb, debug_nb_cmd, "[no] debug northbound\ [<\ - callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc}]\ - |notifications$notifications\ - |events$events\ + callbacks [{configuration|state|rpc}]\ + |notifications\ + |events\ + |libyang\ >]", NO_STR DEBUG_STR @@ -2466,7 +2469,8 @@ DEFUNSH(VTYSH_ALL, debug_nb, "State\n" "RPC\n" "Notifications\n" - "Events\n") + "Events\n" + "libyang debugging\n") { return CMD_SUCCESS; } @@ -4077,7 +4081,9 @@ void vtysh_init_vty(void) install_element(VIEW_NODE, &vtysh_show_modules_cmd); install_element(VIEW_NODE, &vtysh_show_work_queues_cmd); install_element(VIEW_NODE, &vtysh_show_work_queues_daemon_cmd); +#ifndef EXCLUDE_CPU_TIME install_element(VIEW_NODE, &vtysh_show_thread_cmd); +#endif install_element(VIEW_NODE, &vtysh_show_poll_cmd); /* Logging */ diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 711c4e0877..2fdb215128 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -86,9 +86,8 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->rule.priority); /* interface on which applied */ - if (rule->ifp) - addattr_l(&req.n, sizeof(req), FRA_IFNAME, rule->ifp->name, - strlen(rule->ifp->name) + 1); + addattr_l(&req.n, sizeof(req), FRA_IFNAME, rule->ifname, + strlen(rule->ifname) + 1); /* source IP, if specified */ if (IS_RULE_FILTERING_ON_SRC_IP(rule)) { @@ -122,8 +121,7 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule) zlog_debug( "Tx %s family %s IF %s(%u) Pref %u Fwmark %u Src %s Dst %s Table %u", nl_msg_type_to_str(cmd), nl_family_to_str(family), - rule->ifp ? rule->ifp->name : "Unknown", - rule->ifp ? rule->ifp->ifindex : 0, rule->rule.priority, + rule->ifname, rule->rule.ifindex, rule->rule.priority, rule->rule.filter.fwmark, prefix2str(&rule->rule.filter.src_ip, buf1, sizeof(buf1)), @@ -227,13 +225,15 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (tb[FRA_IFNAME] == NULL) return 0; - /* If we don't know the interface, we don't care. */ ifname = (char *)RTA_DATA(tb[FRA_IFNAME]); zns = zebra_ns_lookup(ns_id); - rule.ifp = if_lookup_by_name_per_ns(zns, ifname); - if (!rule.ifp) + + /* If we don't know the interface, we don't care. */ + if (!if_lookup_by_name_per_ns(zns, ifname)) return 0; + strlcpy(rule.ifname, ifname, sizeof(rule.ifname)); + if (tb[FRA_PRIORITY]) rule.rule.priority = *(uint32_t *)RTA_DATA(tb[FRA_PRIORITY]); @@ -268,8 +268,8 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) zlog_debug( "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u", nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(frh->family), rule.ifp->name, - rule.ifp->ifindex, rule.rule.priority, + nl_family_to_str(frh->family), rule.ifname, + rule.rule.ifindex, rule.rule.priority, prefix2str(&rule.rule.filter.src_ip, buf1, sizeof(buf1)), prefix2str(&rule.rule.filter.dst_ip, buf2, diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index b0488b7559..e61e68b7fe 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -783,10 +783,7 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule, stream_putl(s, rule->rule.seq); stream_putl(s, rule->rule.priority); stream_putl(s, rule->rule.unique); - if (rule->ifp) - stream_putl(s, rule->ifp->ifindex); - else - stream_putl(s, 0); + stream_putl(s, rule->rule.ifindex); stream_putw_at(s, 0, stream_get_endp(s)); @@ -2294,7 +2291,6 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS) struct zebra_pbr_rule zpr; struct stream *s; uint32_t total, i; - ifindex_t ifindex; s = msg; STREAM_GETL(s, total); @@ -2319,17 +2315,20 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS) STREAM_GETW(s, zpr.rule.filter.dst_port); STREAM_GETL(s, zpr.rule.filter.fwmark); STREAM_GETL(s, zpr.rule.action.table); - STREAM_GETL(s, ifindex); + STREAM_GETL(s, zpr.rule.ifindex); - if (ifindex) { - zpr.ifp = if_lookup_by_index_per_ns( - zvrf->zns, - ifindex); - if (!zpr.ifp) { + if (zpr.rule.ifindex) { + struct interface *ifp; + + ifp = if_lookup_by_index_per_ns(zvrf->zns, + zpr.rule.ifindex); + if (!ifp) { zlog_debug("Failed to lookup ifindex: %u", - ifindex); + zpr.rule.ifindex); return; } + + strlcpy(zpr.ifname, ifp->name, sizeof(zpr.ifname)); } if (!is_default_prefix(&zpr.rule.filter.src_ip)) diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index f95a4ff950..e24d2e2b42 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -144,17 +144,12 @@ uint32_t zebra_pbr_rules_hash_key(const void *arg) key = jhash_3words(rule->rule.seq, rule->rule.priority, rule->rule.action.table, prefix_hash_key(&rule->rule.filter.src_ip)); - if (rule->ifp) - key = jhash_1word(rule->ifp->ifindex, key); - else - key = jhash_1word(0, key); if (rule->rule.filter.fwmark) - key = jhash_1word(rule->rule.filter.fwmark, key); + key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id, + rule->rule.ifindex, key); else - key = jhash_1word(0, key); - - key = jhash_1word(rule->vrf_id, key); + key = jhash_2words(rule->vrf_id, rule->rule.ifindex, key); return jhash_3words(rule->rule.filter.src_port, rule->rule.filter.dst_port, @@ -196,7 +191,7 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip)) return false; - if (r1->ifp != r2->ifp) + if (r1->rule.ifindex != r2->rule.ifindex) return false; if (r1->vrf_id != r2->vrf_id) @@ -208,7 +203,7 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) struct pbr_rule_unique_lookup { struct zebra_pbr_rule *rule; uint32_t unique; - struct interface *ifp; + ifindex_t ifindex; vrf_id_t vrf_id; }; @@ -218,7 +213,7 @@ static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data) struct zebra_pbr_rule *rule = b->data; if (pul->unique == rule->rule.unique - && pul->ifp == rule->ifp + && pul->ifindex == rule->rule.ifindex && pul->vrf_id == rule->vrf_id) { pul->rule = rule; return HASHWALK_ABORT; @@ -233,7 +228,7 @@ pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule) struct pbr_rule_unique_lookup pul; pul.unique = zrule->rule.unique; - pul.ifp = zrule->ifp; + pul.ifindex = zrule->rule.ifindex; pul.rule = NULL; pul.vrf_id = zrule->vrf_id; hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul); @@ -471,8 +466,12 @@ static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data) if (rule->sock == *sock) { (void)kernel_del_pbr_rule(rule); - hash_release(zrouter.rules_hash, rule); - XFREE(MTYPE_TMP, rule); + if (hash_release(zrouter.rules_hash, rule)) + XFREE(MTYPE_TMP, rule); + else + zlog_debug( + "%s: Rule seq: %u is being cleaned but we can't find it in our tables", + __func__, rule->rule.seq); } } diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index fcc9c5c39a..b7fbc9b7d5 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -41,7 +41,7 @@ struct zebra_pbr_rule { struct pbr_rule rule; - struct interface *ifp; + char ifname[INTERFACE_NAMSIZ]; vrf_id_t vrf_id; }; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 5ce9d3f293..92f8dd1ecc 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1025,10 +1025,9 @@ DEFPY (show_route_all_table_vrf, continue; if (zrt->afi != afi || zrt->safi != SAFI_UNICAST) continue; - if (zrt->table) - do_show_route_helper(vty, info->zvrf, zrt->table, afi, - false, 0, false, false, - 0, 0, !!json, zrt->tableid); + + do_show_route_helper(vty, info->zvrf, zrt->table, afi, false, 0, + false, false, 0, 0, !!json, zrt->tableid); } return CMD_SUCCESS; } |
