summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alpine/APKBUILD.in23
-rw-r--r--bgpd/bgp_bmp.c8
-rw-r--r--bgpd/bgp_evpn.c123
-rw-r--r--bgpd/bgp_evpn.h1
-rw-r--r--bgpd/bgp_evpn_vty.c141
-rw-r--r--bgpd/bgp_flowspec_vty.c2
-rw-r--r--bgpd/bgp_io.c103
-rw-r--r--bgpd/bgp_io.h2
-rw-r--r--bgpd/bgp_pbr.c2
-rw-r--r--bgpd/bgp_route.c1981
-rw-r--r--bgpd/bgp_routemap.c9
-rw-r--r--bgpd/bgp_vpn.c75
-rw-r--r--bgpd/bgp_vty.c75
-rw-r--r--bgpd/rfapi/rfapi.c10
-rw-r--r--bgpd/rfapi/rfapi_import.c221
-rw-r--r--bgpd/rfapi/rfapi_rib.c5
-rw-r--r--bgpd/rfapi/rfapi_vty.c171
-rw-r--r--bgpd/rfapi/vnc_import_bgp.c51
-rwxr-xr-xconfigure.ac10
-rw-r--r--doc/user/basic.rst3
-rw-r--r--doc/user/bgp.rst27
-rw-r--r--doc/user/installation.rst17
-rw-r--r--lib/filter.c5
-rw-r--r--lib/northbound_cli.c16
-rw-r--r--lib/northbound_grpc.cpp5
-rw-r--r--lib/pbr.h2
-rw-r--r--lib/prefix.c47
-rw-r--r--lib/prefix.h2
-rw-r--r--lib/thread.c12
-rw-r--r--lib/yang.c16
-rw-r--r--lib/yang.h8
-rw-r--r--nhrpd/list.h9
-rw-r--r--nhrpd/nhrpd.h3
-rw-r--r--tests/topotests/bgp_large_community/__init__.py0
-rw-r--r--tests/topotests/bgp_large_community/bgp_large_community_topo_1.json262
-rw-r--r--tests/topotests/bgp_large_community/bgp_large_community_topo_2.json344
-rwxr-xr-xtests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py1281
-rwxr-xr-xtests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py2408
-rw-r--r--tests/topotests/lib/bgp.py59
-rw-r--r--tests/topotests/lib/common_config.py91
-rw-r--r--vrrpd/vrrp.c16
-rw-r--r--vrrpd/vrrp_vty.c12
-rw-r--r--vtysh/vtysh.c22
-rw-r--r--zebra/if_netlink.c10
-rw-r--r--zebra/rib.h7
-rw-r--r--zebra/rule_netlink.c20
-rw-r--r--zebra/zapi_msg.c23
-rw-r--r--zebra/zebra_nhg.c10
-rw-r--r--zebra/zebra_pbr.c27
-rw-r--r--zebra/zebra_pbr.h2
-rw-r--r--zebra/zebra_rib.c195
-rw-r--r--zebra/zebra_vty.c7
52 files changed, 6318 insertions, 1663 deletions
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in
index 60753c1227..1c579a8e72 100644
--- a/alpine/APKBUILD.in
+++ b/alpine/APKBUILD.in
@@ -8,18 +8,17 @@ arch="x86_64"
license="GPL-2.0"
depends="json-c c-ares ipsec-tools iproute2 python py-ipaddr bash"
makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
- acct autoconf automake bash
- binutils bison bsd-compat-headers build-base
- c-ares c-ares-dev ca-certificates cryptsetup-libs curl
- device-mapper-libs expat fakeroot flex fortify-headers gdbm
- git gmp isl json-c-dev kmod lddtree libacl libatomic libattr
- libblkid libburn libbz2 libc-dev libcap-dev libcurl libedit libffi libgcc
- libgomp libisoburn libisofs libltdl libressl libssh2
- libstdc++ libtool libuuid libyang-dev linux-headers lzip lzo m4 make mkinitfs mpc1
- mpfr3 mtools musl-dev ncurses-libs ncurses-terminfo ncurses-terminfo-base
- patch pax-utils pcre perl pkgconf python2 python2-dev readline
- readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs
- py-pip py-sphinx rtrlib rtrlib-dev"
+ acct autoconf automake bash binutils bison bsd-compat-headers build-base
+ c-ares c-ares-dev ca-certificates cryptsetup-libs curl device-mapper-libs
+ expat fakeroot flex fortify-headers gdbm git gmp isl json-c-dev kmod
+ lddtree libacl libatomic libattr libblkid libburn libbz2 libc-dev
+ libcap-dev libcurl libedit libffi libgcc libgomp libisoburn libisofs
+ libltdl libressl libssh2 libstdc++ libtool libuuid libyang-dev
+ linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr4 mtools musl-dev
+ ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre
+ perl pkgconf python2 python2-dev readline readline-dev sqlite-libs
+ squashfs-tools sudo tar texinfo xorriso xz-libs py-pip py-sphinx rtrlib
+ rtrlib-dev"
checkdepends="pytest py-setuptools"
install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall"
subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg"
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..3f2f11dbe2 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};
@@ -4695,59 +4697,60 @@ void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json)
{
char buf1[ETHER_ADDR_STRLEN];
char buf2[PREFIX2STR_BUFFER];
+ uint8_t family;
+ uint8_t prefixlen;
if (!json)
return;
- if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) {
- json_object_int_add(json, "routeType", p->prefix.route_type);
+ json_object_int_add(json, "routeType", p->prefix.route_type);
+
+ switch (p->prefix.route_type) {
+ case BGP_EVPN_MAC_IP_ROUTE:
json_object_int_add(json, "ethTag",
- p->prefix.imet_addr.eth_tag);
- json_object_int_add(json, "ipLen",
- is_evpn_prefix_ipaddr_v4(p)
- ? IPV4_MAX_BITLEN
- : IPV6_MAX_BITLEN);
- json_object_string_add(json, "ip",
- inet_ntoa(p->prefix.imet_addr.ip.ipaddr_v4));
- } else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
- if (is_evpn_prefix_ipaddr_none(p)) {
- json_object_int_add(json, "routeType",
- p->prefix.route_type);
- json_object_int_add(json, "ethTag",
- p->prefix.macip_addr.eth_tag);
- json_object_int_add(json, "macLen", 8 * ETH_ALEN);
- json_object_string_add(json, "mac",
- prefix_mac2str(&p->prefix.macip_addr.mac,
- buf1,
- sizeof(buf1)));
- } else {
- uint8_t family;
+ p->prefix.macip_addr.eth_tag);
+ json_object_int_add(json, "macLen", 8 * ETH_ALEN);
+ json_object_string_add(json, "mac",
+ prefix_mac2str(&p->prefix.macip_addr.mac, buf1,
+ sizeof(buf1)));
+
+ if (!is_evpn_prefix_ipaddr_none(p)) {
+ family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET :
+ AF_INET6;
+ prefixlen = (family == AF_INET) ?
+ IPV4_MAX_BITLEN : IPV6_MAX_BITLEN;
+ inet_ntop(family, &p->prefix.macip_addr.ip.ip.addr,
+ buf2, PREFIX2STR_BUFFER);
+ json_object_int_add(json, "ipLen", prefixlen);
+ json_object_string_add(json, "ip", buf2);
+ }
+ break;
- family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET
- : AF_INET6;
+ case BGP_EVPN_IMET_ROUTE:
+ json_object_int_add(json, "ethTag",
+ p->prefix.imet_addr.eth_tag);
+ family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET : AF_INET6;
+ prefixlen = (family == AF_INET) ? IPV4_MAX_BITLEN :
+ IPV6_MAX_BITLEN;
+ inet_ntop(family, &p->prefix.imet_addr.ip.ip.addr, buf2,
+ PREFIX2STR_BUFFER);
+ json_object_int_add(json, "ipLen", prefixlen);
+ json_object_string_add(json, "ip", buf2);
+ break;
- json_object_int_add(json, "routeType",
- p->prefix.route_type);
- json_object_int_add(json, "ethTag",
- p->prefix.macip_addr.eth_tag);
- json_object_int_add(json, "macLen", 8 * ETH_ALEN);
- json_object_string_add(json, "mac",
- prefix_mac2str(&p->prefix.macip_addr.mac,
- buf1,
- sizeof(buf1)));
- json_object_int_add(json, "ipLen",
- is_evpn_prefix_ipaddr_v4(p)
- ? IPV4_MAX_BITLEN
- : IPV6_MAX_BITLEN);
- json_object_string_add(
- json, "ip",
- inet_ntop(family,
- &p->prefix.macip_addr.ip.ip.addr,
- buf2,
- PREFIX2STR_BUFFER));
- }
- } else {
- /* Currently, this is to cater to other AF_ETHERNET code. */
+ case BGP_EVPN_IP_PREFIX_ROUTE:
+ json_object_int_add(json, "ethTag",
+ p->prefix.prefix_addr.eth_tag);
+ family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET : AF_INET6;
+ inet_ntop(family, &p->prefix.prefix_addr.ip.ip.addr,
+ buf2, sizeof(buf2));
+ json_object_int_add(json, "ipLen",
+ p->prefix.prefix_addr.ip_prefix_length);
+ json_object_string_add(json, "ip", buf2);
+ break;
+
+ default:
+ break;
}
}
@@ -6006,3 +6009,19 @@ void bgp_evpn_vrf_delete(struct bgp *bgp_vrf)
{
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
}
+
+/*
+ * Get the prefixlen of the ip prefix carried within the type5 evpn route.
+ */
+int bgp_evpn_get_type5_prefixlen(struct prefix *pfx)
+{
+ struct prefix_evpn *evp = (struct prefix_evpn *)pfx;
+
+ if (!pfx || pfx->family != AF_EVPN)
+ return 0;
+
+ if (evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE)
+ return 0;
+
+ return evp->prefix.prefix_addr.ip_prefix_length;
+}
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
index 4ad8e95bee..6d1e8cd31b 100644
--- a/bgpd/bgp_evpn.h
+++ b/bgpd/bgp_evpn.h
@@ -190,5 +190,6 @@ extern void bgp_evpn_flood_control_change(struct bgp *bgp);
extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp);
extern void bgp_evpn_cleanup(struct bgp *bgp);
extern void bgp_evpn_init(struct bgp *bgp);
+extern int bgp_evpn_get_type5_prefixlen(struct prefix *pfx);
#endif /* _QUAGGA_BGP_EVPN_H */
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 34308bd0db..55f85eeb83 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -275,42 +275,61 @@ static void show_import_rt_entry(struct hash_bucket *bucket, void *args[])
static void bgp_evpn_show_route_rd_header(struct vty *vty,
struct bgp_node *rd_rn,
- json_object *json)
+ json_object *json,
+ char *rd_str, int len)
{
uint16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
uint8_t *pnt;
- char rd_str[RD_ADDRSTRLEN];
pnt = rd_rn->p.u.val;
/* Decode RD type. */
type = decode_rd_type(pnt);
- if (json)
- return;
-
- vty_out(vty, "Route Distinguisher: ");
+ if (!json)
+ vty_out(vty, "Route Distinguisher: ");
switch (type) {
case RD_TYPE_AS:
decode_rd_as(pnt + 2, &rd_as);
- snprintf(rd_str, RD_ADDRSTRLEN, "%u:%d", rd_as.as, rd_as.val);
+ snprintf(rd_str, len, "%u:%d", rd_as.as, rd_as.val);
+ if (json)
+ json_object_string_add(json, "rd", rd_str);
+ else
+ vty_out(vty, "as2 %s\n", rd_str);
+ break;
+
+ case RD_TYPE_AS4:
+ decode_rd_as4(pnt + 2, &rd_as);
+ snprintf(rd_str, len, "%u:%d", rd_as.as, rd_as.val);
+ if (json)
+ json_object_string_add(json, "rd", rd_str);
+ else
+ vty_out(vty, "as4 %s\n", rd_str);
break;
case RD_TYPE_IP:
decode_rd_ip(pnt + 2, &rd_ip);
- snprintf(rd_str, RD_ADDRSTRLEN, "%s:%d", inet_ntoa(rd_ip.ip),
+ snprintf(rd_str, len, "%s:%d", inet_ntoa(rd_ip.ip),
rd_ip.val);
+ if (json)
+ json_object_string_add(json, "rd", rd_str);
+ else
+ vty_out(vty, "ip %s\n", rd_str);
break;
default:
- snprintf(rd_str, RD_ADDRSTRLEN, "Unknown RD type");
+ if (json) {
+ snprintf(rd_str, len, "Unknown");
+ json_object_string_add(json, "rd", rd_str);
+ } else {
+ snprintf(rd_str, len, "Unknown RD type");
+ vty_out(vty, "ip %s\n", rd_str);
+ }
break;
}
-
- vty_out(vty, "%s\n", rd_str);
}
static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
@@ -1057,18 +1076,17 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
struct bgp_path_info *pi;
int rd_header;
int header = 1;
- char rd_str[BUFSIZ];
+ char rd_str[RD_ADDRSTRLEN];
char buf[BUFSIZ];
int no_display;
unsigned long output_count = 0;
unsigned long total_count = 0;
json_object *json = NULL;
- json_object *json_nroute = NULL;
json_object *json_array = NULL;
json_object *json_prefix_info = NULL;
- memset(rd_str, 0, BUFSIZ);
+ memset(rd_str, 0, RD_ADDRSTRLEN);
bgp = bgp_get_evpn();
if (bgp == NULL) {
@@ -1085,6 +1103,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
for (rn = bgp_table_top(bgp->rib[afi][SAFI_EVPN]); rn;
rn = bgp_route_next(rn)) {
uint64_t tbl_ver;
+ json_object *json_nroute = NULL;
if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
continue;
@@ -1102,22 +1121,6 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
continue;
no_display = 0;
- if (use_json) {
- json_array = json_object_new_array();
- json_prefix_info = json_object_new_object();
-
- json_object_string_add(json_prefix_info,
- "prefix", bgp_evpn_route2str(
- (struct prefix_evpn *)&rm->p, buf,
- BUFSIZ));
-
- json_object_int_add(json_prefix_info,
- "prefixLen", rm->p.prefixlen);
-
- if (rd_header)
- json_nroute = json_object_new_object();
- }
-
for (; pi; pi = pi->next) {
total_count++;
if (type == bgp_show_type_neighbor) {
@@ -1191,60 +1194,16 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
header = 0;
}
if (rd_header) {
- uint16_t type;
- struct rd_as rd_as;
- struct rd_ip rd_ip;
- uint8_t *pnt;
-
- pnt = rn->p.u.val;
-
- /* Decode RD type. */
- type = decode_rd_type(pnt);
- /* Decode RD value. */
- if (type == RD_TYPE_AS)
- decode_rd_as(pnt + 2, &rd_as);
- else if (type == RD_TYPE_AS4)
- decode_rd_as4(pnt + 2, &rd_as);
- else if (type == RD_TYPE_IP)
- decode_rd_ip(pnt + 2, &rd_ip);
- if (use_json) {
- if (type == RD_TYPE_AS
- || type == RD_TYPE_AS4)
- sprintf(rd_str, "%u:%d",
- rd_as.as,
- rd_as.val);
- else if (type == RD_TYPE_IP)
- sprintf(rd_str, "%s:%d",
- inet_ntoa(
- rd_ip.ip),
- rd_ip.val);
- json_object_string_add(
- json_nroute,
- "rd",
- rd_str);
-
- } else {
- vty_out(vty,
- "Route Distinguisher: ");
- if (type == RD_TYPE_AS)
- vty_out(vty,
- "as2 %u:%d",
- rd_as.as,
- rd_as.val);
- else if (type == RD_TYPE_AS4)
- vty_out(vty,
- "as4 %u:%d",
- rd_as.as,
- rd_as.val);
- else if (type == RD_TYPE_IP)
- vty_out(vty, "ip %s:%d",
- inet_ntoa(
- rd_ip.ip),
- rd_ip.val);
- vty_out(vty, "\n\n");
- }
+ if (use_json)
+ json_nroute =
+ json_object_new_object();
+ bgp_evpn_show_route_rd_header(vty, rn,
+ json_nroute, rd_str,
+ RD_ADDRSTRLEN);
rd_header = 0;
}
+ if (use_json && !json_array)
+ json_array = json_object_new_array();
if (option == SHOW_DISPLAY_TAGS)
route_vty_out_tag(vty, &rm->p, pi,
@@ -1264,15 +1223,26 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
if (no_display)
output_count++;
- if (use_json) {
+ if (use_json && json_array) {
+ json_prefix_info = json_object_new_object();
+
+ json_object_string_add(json_prefix_info,
+ "prefix", bgp_evpn_route2str(
+ (struct prefix_evpn *)&rm->p, buf,
+ BUFSIZ));
+
+ json_object_int_add(json_prefix_info,
+ "prefixLen", rm->p.prefixlen);
+
json_object_object_add(json_prefix_info,
"paths", json_array);
json_object_object_add(json_nroute, buf,
json_prefix_info);
+ json_array = NULL;
}
}
- if (use_json)
+ if (use_json && json_nroute)
json_object_object_add(json, rd_str, json_nroute);
}
@@ -2689,7 +2659,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
/* RD header - per RD. */
if (rd_header) {
bgp_evpn_show_route_rd_header(
- vty, rd_rn, json);
+ vty, rd_rn, NULL, rd_str,
+ RD_ADDRSTRLEN);
rd_header = 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 2f73b001f1..de4f185ab2 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,
@@ -7529,7 +7515,7 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
json_object *json_status = NULL;
json_object *json_net = NULL;
char buff[BUFSIZ];
- char buf2[BUFSIZ];
+
/* Route status display. */
if (use_json) {
json_status = json_object_new_object();
@@ -7542,12 +7528,18 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
/* print prefix and mask */
if (use_json) {
- json_object_string_add(
- json_net, "addrPrefix",
- inet_ntop(p->family, &p->u.prefix, buff, BUFSIZ));
- json_object_int_add(json_net, "prefixLen", p->prefixlen);
- prefix2str(p, buf2, PREFIX_STRLEN);
- json_object_string_add(json_net, "network", buf2);
+ if (safi == SAFI_EVPN)
+ bgp_evpn_route2json((struct prefix_evpn *)p, json_net);
+ else if (p->family == AF_INET || p->family == AF_INET6) {
+ json_object_string_add(
+ json_net, "addrPrefix",
+ inet_ntop(p->family, &p->u.prefix, buff,
+ BUFSIZ));
+ json_object_int_add(json_net, "prefixLen",
+ p->prefixlen);
+ prefix2str(p, buff, PREFIX_STRLEN);
+ json_object_string_add(json_net, "network", buff);
+ }
} else
route_vty_out_route(p, vty, NULL);
@@ -7556,10 +7548,8 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
if (use_json) {
if (p->family == AF_INET
&& (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 (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
json_object_string_add(
json_net, "nextHop",
inet_ntoa(
@@ -7577,7 +7567,11 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
inet_ntop(AF_INET6,
&attr->mp_nexthop_global, buf,
BUFSIZ));
- }
+ } else if (p->family == AF_EVPN &&
+ !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+ json_object_string_add(json_net,
+ "nextHop", inet_ntoa(
+ attr->mp_nexthop_global_in));
if (attr->flag
& ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
@@ -7671,10 +7665,9 @@ void route_vty_out_tmp(struct vty *vty, struct prefix *p, struct attr *attr,
json_object_boolean_true_add(json_status, ">");
json_object_object_add(json_net, "appliedStatusSymbols",
json_status);
- char buf_cut[BUFSIZ];
- prefix2str(p, buf_cut, PREFIX_STRLEN);
- json_object_object_add(json_ar, buf_cut, json_net);
+ prefix2str(p, buff, PREFIX_STRLEN);
+ json_object_object_add(json_ar, buff, json_net);
} else
vty_out(vty, "\n");
}
@@ -7706,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);
}
}
@@ -7810,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);
}
}
@@ -7951,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");
}
@@ -8046,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");
}
@@ -8247,7 +8227,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
json_nexthop_global = json_object_new_object();
}
- if (!json_paths && path->extra) {
+ if (path->extra) {
char tag_buf[30];
buf2[0] = '\0';
@@ -8258,15 +8238,21 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
sizeof(tag_buf));
}
if (safi == SAFI_EVPN) {
- bgp_evpn_route2str((struct prefix_evpn *)&bn->p,
- buf2, sizeof(buf2));
- vty_out(vty, " Route %s", buf2);
- if (tag_buf[0] != '\0')
- vty_out(vty, " VNI %s", tag_buf);
- vty_out(vty, "\n");
+ if (!json_paths) {
+ bgp_evpn_route2str((struct prefix_evpn *)&bn->p,
+ buf2, sizeof(buf2));
+ vty_out(vty, " Route %s", buf2);
+ if (tag_buf[0] != '\0')
+ vty_out(vty, " VNI %s", tag_buf);
+ vty_out(vty, "\n");
+ } else {
+ if (tag_buf[0])
+ json_object_string_add(json_path, "VNI",
+ tag_buf);
+ }
}
- if (path->extra && path->extra->parent) {
+ if (path->extra && path->extra->parent && !json_paths) {
struct bgp_path_info *parent_ri;
struct bgp_node *rn, *prn;
@@ -8288,819 +8274,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
@@ -9124,8 +9030,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"
@@ -9642,37 +9547,47 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
if (has_valid_label)
label = label_pton(&rn->local_label);
- if (json) {
- if (has_valid_label)
- json_object_int_add(json, "localLabel", label);
+ if (safi == SAFI_EVPN) {
- json_object_string_add(
- json, "prefix",
- prefix2str(p, prefix_str, sizeof(prefix_str)));
- } else {
- if (safi == SAFI_EVPN)
+ if (!json) {
vty_out(vty, "BGP routing table entry for %s%s%s\n",
prd ? prefix_rd2str(prd, buf1, sizeof(buf1))
- : "",
- prd ? ":" : "",
+ : "", prd ? ":" : "",
bgp_evpn_route2str((struct prefix_evpn *)p,
- buf3, sizeof(buf3)));
- else
+ buf3, sizeof(buf3)));
+ } else {
+ json_object_string_add(json, "rd",
+ prd ? prefix_rd2str(prd, buf1, sizeof(buf1)) :
+ "");
+ bgp_evpn_route2json((struct prefix_evpn *)p, json);
+ }
+ } else {
+ if (!json) {
vty_out(vty, "BGP routing table entry for %s%s%s/%d\n",
((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
- ? prefix_rd2str(prd, buf1,
- sizeof(buf1))
- : ""),
+ ? prefix_rd2str(prd, buf1,
+ sizeof(buf1))
+ : ""),
safi == SAFI_MPLS_VPN ? ":" : "",
inet_ntop(p->family, &p->u.prefix, buf2,
- INET6_ADDRSTRLEN),
+ INET6_ADDRSTRLEN),
p->prefixlen);
- if (has_valid_label)
+ } else
+ json_object_string_add(json, "prefix",
+ prefix2str(p, prefix_str, sizeof(prefix_str)));
+ }
+
+ if (has_valid_label) {
+ if (json)
+ json_object_int_add(json, "localLabel", label);
+ else
vty_out(vty, "Local label: %d\n", label);
+ }
+
+ if (!json)
if (bgp_labeled_safi(safi) && safi != SAFI_EVPN)
vty_out(vty, "not allocated\n");
- }
for (pi = bgp_node_get_bgp_path_info(rn); pi; pi = pi->next) {
count++;
@@ -9804,6 +9719,58 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
}
}
+static void bgp_show_path_info(struct prefix_rd *pfx_rd,
+ struct bgp_node *bgp_node, struct vty *vty,
+ struct bgp *bgp, afi_t afi,
+ safi_t safi, json_object *json,
+ enum bgp_path_type pathtype, int *display)
+{
+ struct bgp_path_info *pi;
+ int header = 1;
+ char rdbuf[RD_ADDRSTRLEN];
+ json_object *json_header = NULL;
+ json_object *json_paths = NULL;
+
+ for (pi = bgp_node_get_bgp_path_info(bgp_node); pi;
+ pi = pi->next) {
+
+ if (json && !json_paths) {
+ /* Instantiate json_paths only if path is valid */
+ json_paths = json_object_new_array();
+ if (pfx_rd) {
+ prefix_rd2str(pfx_rd, rdbuf, sizeof(rdbuf));
+ json_header = json_object_new_object();
+ } else
+ json_header = json;
+ }
+
+ if (header) {
+ route_vty_out_detail_header(
+ vty, bgp, bgp_node, pfx_rd,
+ AFI_IP, safi, json_header);
+ header = 0;
+ }
+ (*display)++;
+
+ if (pathtype == BGP_PATH_SHOW_ALL
+ || (pathtype == BGP_PATH_SHOW_BESTPATH
+ && CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
+ || (pathtype == BGP_PATH_SHOW_MULTIPATH
+ && (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH)
+ || CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))))
+ route_vty_out_detail(vty, bgp, bgp_node,
+ pi, AFI_IP, safi,
+ json_paths);
+ }
+
+ if (json && json_paths) {
+ json_object_object_add(json_header, "paths", json_paths);
+
+ if (pfx_rd)
+ json_object_object_add(json, rdbuf, json_header);
+ }
+}
+
/* Display specified route of BGP table. */
static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
struct bgp_table *rib, const char *ip_str,
@@ -9812,12 +9779,10 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
enum bgp_path_type pathtype, bool use_json)
{
int ret;
- int header;
int display = 0;
struct prefix match;
struct bgp_node *rn;
struct bgp_node *rm;
- struct bgp_path_info *pi;
struct bgp_table *table;
json_object *json = NULL;
json_object *json_paths = NULL;
@@ -9831,12 +9796,10 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
match.family = afi2family(afi);
- if (use_json) {
+ if (use_json)
json = json_object_new_object();
- json_paths = json_object_new_array();
- }
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) {
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) {
for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
continue;
@@ -9844,8 +9807,6 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
if (!table)
continue;
- header = 1;
-
if ((rm = bgp_node_match(table, &match)) == NULL)
continue;
@@ -9855,73 +9816,83 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
continue;
}
- for (pi = bgp_node_get_bgp_path_info(rm); pi;
- pi = pi->next) {
- if (header) {
- route_vty_out_detail_header(
- vty, bgp, rm,
- (struct prefix_rd *)&rn->p,
- AFI_IP, safi, json);
- header = 0;
+ bgp_show_path_info((struct prefix_rd *)&rn->p, rm,
+ vty, bgp, afi, safi, json,
+ pathtype, &display);
+
+ bgp_unlock_node(rm);
+ }
+ } else if (safi == SAFI_EVPN) {
+ struct bgp_node *longest_pfx;
+ bool is_exact_pfxlen_match = FALSE;
+
+ for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
+ if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
+ continue;
+ table = bgp_node_get_bgp_table_info(rn);
+ if (!table)
+ continue;
+
+ longest_pfx = NULL;
+ is_exact_pfxlen_match = FALSE;
+ /*
+ * Search through all the prefixes for a match. The
+ * pfx's are enumerated in ascending order of pfxlens.
+ * So, the last pfx match is the longest match. Set
+ * is_exact_pfxlen_match when we get exact pfxlen match
+ */
+ for (rm = bgp_table_top(table); rm;
+ rm = bgp_route_next(rm)) {
+ /*
+ * Get prefixlen of the ip-prefix within type5
+ * evpn route
+ */
+ if (evpn_type5_prefix_match(&rm->p,
+ &match) && rm->info) {
+ longest_pfx = rm;
+ int type5_pfxlen =
+ bgp_evpn_get_type5_prefixlen(&rm->p);
+ if (type5_pfxlen == match.prefixlen) {
+ is_exact_pfxlen_match = TRUE;
+ bgp_unlock_node(rm);
+ break;
+ }
}
- display++;
-
- if (pathtype == BGP_PATH_SHOW_ALL
- || (pathtype == BGP_PATH_SHOW_BESTPATH
- && CHECK_FLAG(pi->flags,
- BGP_PATH_SELECTED))
- || (pathtype == BGP_PATH_SHOW_MULTIPATH
- && (CHECK_FLAG(pi->flags,
- BGP_PATH_MULTIPATH)
- || CHECK_FLAG(pi->flags,
- BGP_PATH_SELECTED))))
- route_vty_out_detail(vty, bgp, rm,
- pi, AFI_IP, safi,
- json_paths);
}
+ if (!longest_pfx)
+ continue;
+
+ if (prefix_check && !is_exact_pfxlen_match)
+ continue;
+
+ rm = longest_pfx;
+ bgp_lock_node(rm);
+
+ bgp_show_path_info((struct prefix_rd *)&rn->p, rm,
+ vty, bgp, afi, safi, json,
+ pathtype, &display);
+
bgp_unlock_node(rm);
}
} else if (safi == SAFI_FLOWSPEC) {
+ if (use_json)
+ json_paths = json_object_new_array();
+
display = bgp_flowspec_display_match_per_ip(afi, rib,
&match, prefix_check,
vty,
use_json,
json_paths);
+ if (use_json && display)
+ json_object_object_add(json, "paths", json_paths);
} else {
- header = 1;
-
if ((rn = bgp_node_match(rib, &match)) != NULL) {
if (!prefix_check
|| rn->p.prefixlen == match.prefixlen) {
- for (pi = bgp_node_get_bgp_path_info(rn); pi;
- pi = pi->next) {
- if (header) {
- route_vty_out_detail_header(
- vty, bgp, rn, NULL, afi,
- safi, json);
- header = 0;
- }
- display++;
-
- if (pathtype == BGP_PATH_SHOW_ALL
- || (pathtype
- == BGP_PATH_SHOW_BESTPATH
- && CHECK_FLAG(
- pi->flags,
- BGP_PATH_SELECTED))
- || (pathtype
- == BGP_PATH_SHOW_MULTIPATH
- && (CHECK_FLAG(
- pi->flags,
- BGP_PATH_MULTIPATH)
- || CHECK_FLAG(
- pi->flags,
- BGP_PATH_SELECTED))))
- route_vty_out_detail(
- vty, bgp, rn, pi,
- afi, safi, json_paths);
- }
+ bgp_show_path_info(NULL, rn, vty, bgp, afi,
+ safi, json,
+ pathtype, &display);
}
bgp_unlock_node(rn);
@@ -9929,11 +9900,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
}
if (use_json) {
- if (display)
- json_object_object_add(json, "paths", json_paths);
-
vty_out(vty, "%s\n", json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
+ json, JSON_C_TO_STRING_PRETTY |
+ JSON_C_TO_STRING_NOSLASHESCAPE));
json_object_free(json);
} else {
if (!display) {
@@ -10686,13 +10655,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);
@@ -11127,32 +11095,37 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix,
}
#endif /* KEEP_OLD_VPN_COMMANDS */
-DEFUN (show_ip_bgp_l2vpn_evpn_all_route_prefix,
- show_ip_bgp_l2vpn_evpn_all_route_prefix_cmd,
- "show [ip] bgp l2vpn evpn all <A.B.C.D|A.B.C.D/M> [json]",
+DEFUN (show_bgp_l2vpn_evpn_route_prefix,
+ show_bgp_l2vpn_evpn_route_prefix_cmd,
+ "show bgp l2vpn evpn <A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> [json]",
SHOW_STR
- IP_STR
BGP_STR
L2VPN_HELP_STR
EVPN_HELP_STR
- "Display information about all EVPN NLRIs\n"
+ "Network in the BGP routing table to display\n"
+ "Network in the BGP routing table to display\n"
"Network in the BGP routing table to display\n"
"Network in the BGP routing table to display\n"
JSON_STR)
{
int idx = 0;
char *network = NULL;
+ int prefix_check = 0;
- if (argv_find(argv, argc, "A.B.C.D", &idx))
+ if (argv_find(argv, argc, "A.B.C.D", &idx) ||
+ argv_find(argv, argc, "X:X::X:X", &idx))
network = argv[idx]->arg;
- else if (argv_find(argv, argc, "A.B.C.D/M", &idx))
+ else if (argv_find(argv, argc, "A.B.C.D/M", &idx) ||
+ argv_find(argv, argc, "A.B.C.D/M", &idx)) {
network = argv[idx]->arg;
- else {
+ prefix_check = 1;
+ } else {
vty_out(vty, "Unable to figure out Network\n");
return CMD_WARNING;
}
- return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, 0,
- BGP_PATH_SHOW_ALL, use_json(argc, argv));
+ return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL,
+ prefix_check, BGP_PATH_SHOW_ALL,
+ use_json(argc, argv));
}
static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
@@ -11263,7 +11236,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) {
@@ -12649,7 +12622,7 @@ void bgp_route_init(void)
#endif /* KEEP_OLD_VPN_COMMANDS */
install_element(VIEW_NODE, &show_bgp_afi_vpn_rd_route_cmd);
install_element(VIEW_NODE,
- &show_ip_bgp_l2vpn_evpn_all_route_prefix_cmd);
+ &show_bgp_l2vpn_evpn_route_prefix_cmd);
/* BGP dampening clear commands */
install_element(ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
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_vpn.c b/bgpd/bgp_vpn.c
index 09b1cb429b..e48eda7231 100644
--- a/bgpd/bgp_vpn.c
+++ b/bgpd/bgp_vpn.c
@@ -29,6 +29,7 @@
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_vpn.h"
+#include "bgpd/bgp_updgrp.h"
int show_adj_route_vpn(struct vty *vty, struct peer *peer,
struct prefix_rd *prd, afi_t afi, safi_t safi,
@@ -38,14 +39,15 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
struct bgp_table *table;
struct bgp_node *rn;
struct bgp_node *rm;
- struct bgp_path_info *path;
int rd_header;
int header = 1;
json_object *json = NULL;
json_object *json_scode = NULL;
json_object *json_ocode = NULL;
+ json_object *json_adv = NULL;
json_object *json_routes = NULL;
- json_object *json_array = NULL;
+ char rd_str[BUFSIZ];
+ unsigned long output_count = 0;
bgp = bgp_get_default();
if (bgp == NULL) {
@@ -59,8 +61,8 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
if (use_json) {
json_scode = json_object_new_object();
json_ocode = json_object_new_object();
- json_routes = json_object_new_object();
json = json_object_new_object();
+ json_adv = json_object_new_object();
json_object_string_add(json_scode, "suppressed", "s");
json_object_string_add(json_scode, "damped", "d");
@@ -83,16 +85,25 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
if (table == NULL)
continue;
- if (use_json)
- json_array = json_object_new_array();
- else
- json_array = NULL;
rd_header = 1;
+ memset(rd_str, 0, sizeof(rd_str));
for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) {
- path = bgp_node_get_bgp_path_info(rm);
- if (path == NULL)
+ struct bgp_adj_out *adj = NULL;
+ struct attr *attr = NULL;
+ struct peer_af *paf = NULL;
+
+ RB_FOREACH (adj, bgp_adj_out_rb, &rm->adj_out)
+ SUBGRP_FOREACH_PEER (adj->subgroup, paf) {
+ if (paf->peer != peer || !adj->attr)
+ continue;
+
+ attr = adj->attr;
+ break;
+ }
+
+ if (bgp_node_get_bgp_path_info(rm) == NULL)
continue;
if (header) {
@@ -102,6 +113,13 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
json_object_string_add(
json, "bgpLocalRouterId",
inet_ntoa(bgp->router_id));
+ json_object_int_add(
+ json,
+ "defaultLocPrf",
+ bgp->default_local_pref);
+ json_object_int_add(
+ json, "localAS",
+ bgp->as);
json_object_object_add(json,
"bgpStatusCodes",
json_scode);
@@ -112,6 +130,9 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
vty_out(vty,
"BGP table version is 0, local router ID is %s\n",
inet_ntoa(bgp->router_id));
+ vty_out(vty, "Default local pref %u, ",
+ bgp->default_local_pref);
+ vty_out(vty, "local AS %u\n", bgp->as);
vty_out(vty,
"Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n");
vty_out(vty,
@@ -146,18 +167,19 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
decode_rd_vnc_eth(pnt, &rd_vnc_eth);
#endif
if (use_json) {
- char buffer[BUFSIZ];
+ json_routes = json_object_new_object();
+
if (type == RD_TYPE_AS
|| type == RD_TYPE_AS4)
- sprintf(buffer, "%u:%d",
+ sprintf(rd_str, "%u:%d",
rd_as.as, rd_as.val);
else if (type == RD_TYPE_IP)
- sprintf(buffer, "%s:%d",
+ sprintf(rd_str, "%s:%d",
inet_ntoa(rd_ip.ip),
rd_ip.val);
json_object_string_add(
json_routes,
- "routeDistinguisher", buffer);
+ "rd", rd_str);
} else {
vty_out(vty, "Route Distinguisher: ");
@@ -192,24 +214,25 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
}
rd_header = 0;
}
- if (use_json) {
- char buf[BUFSIZ];
-
- prefix2str(&rm->p, buf, sizeof(buf));
- json_object_object_add(json_routes, buf,
- json_array);
- } else {
- route_vty_out_tmp(vty, &rm->p, path->attr,
- safi, use_json,
- json_array);
- }
+ route_vty_out_tmp(vty, &rm->p, attr,
+ safi, use_json,
+ json_routes);
+ output_count++;
}
+
+ if (use_json)
+ json_object_object_add(json_adv, rd_str, json_routes);
}
+
if (use_json) {
- json_object_object_add(json, "routes", json_routes);
+ json_object_object_add(json, "advertisedRoutes", json_adv);
+ json_object_int_add(json,
+ "totalPrefixCounter", output_count);
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
- }
+ } else
+ vty_out(vty, "\nTotal number of prefixes %ld\n", output_count);
+
return CMD_SUCCESS;
}
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 c81a19c03e..b916fcf413 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1101,6 +1101,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
@@ -2205,6 +2212,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 \*
@@ -2240,6 +2249,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);
}
}
diff --git a/lib/pbr.h b/lib/pbr.h
index ecd50447e5..cf6ac41d32 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -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/prefix.c b/lib/prefix.c
index aa6661d7fb..5071ca8201 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -601,6 +601,53 @@ int prefix_match(const struct prefix *n, const struct prefix *p)
if (np[offset] != pp[offset])
return 0;
return 1;
+
+}
+
+/*
+ * n is a type5 evpn prefix. This function tries to see if there is an
+ * ip-prefix within n which matches prefix p
+ * If n includes p prefix then return 1 else return 0.
+ */
+int evpn_type5_prefix_match(const struct prefix *n, const struct prefix *p)
+{
+ int offset;
+ int shift;
+ int prefixlen;
+ const uint8_t *np, *pp;
+ struct prefix_evpn *evp;
+
+ if (n->family != AF_EVPN)
+ return 0;
+
+ evp = (struct prefix_evpn *)n;
+ pp = p->u.val;
+
+ if ((evp->prefix.route_type != 5) ||
+ (p->family == AF_INET6 && !is_evpn_prefix_ipaddr_v6(evp)) ||
+ (p->family == AF_INET && !is_evpn_prefix_ipaddr_v4(evp)) ||
+ (is_evpn_prefix_ipaddr_none(evp)))
+ return 0;
+
+ prefixlen = evp->prefix.prefix_addr.ip_prefix_length;
+ np = &evp->prefix.prefix_addr.ip.ip.addr;
+
+ /* If n's prefix is longer than p's one return 0. */
+ if (prefixlen > p->prefixlen)
+ return 0;
+
+ offset = prefixlen / PNBBY;
+ shift = prefixlen % PNBBY;
+
+ if (shift)
+ if (maskbit[shift] & (np[offset] ^ pp[offset]))
+ return 0;
+
+ while (offset--)
+ if (np[offset] != pp[offset])
+ return 0;
+ return 1;
+
}
/* If n includes p then return 1 else return 0. Prefix mask is not considered */
diff --git a/lib/prefix.h b/lib/prefix.h
index 24c146e022..784927616a 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -407,6 +407,8 @@ extern void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
char *buf, int buf_size);
extern const char *prefix_sg2str(const struct prefix_sg *sg, char *str);
extern const char *prefix2str(union prefixconstptr, char *, int);
+extern int evpn_type5_prefix_match(const struct prefix *evpn_pfx,
+ const struct prefix *match_pfx);
extern int prefix_match(const struct prefix *, const struct prefix *);
extern int prefix_match_network_statement(const struct prefix *,
const struct prefix *);
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 674f3610d6..d153f75530 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -595,7 +595,7 @@ struct yang_data *yang_data_list_find(const struct list *list,
/* Make libyang log its errors using FRR logging infrastructure. */
static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
{
- int priority;
+ int priority = LOG_ERR;
switch (level) {
case LY_LLERR:
@@ -605,10 +605,9 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
priority = LOG_WARNING;
break;
case LY_LLVRB:
+ case LY_LLDBG:
priority = LOG_DEBUG;
break;
- default:
- return;
}
if (path)
@@ -617,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;
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/nhrpd/list.h b/nhrpd/list.h
index ee7f1c4403..a43687ac08 100644
--- a/nhrpd/list.h
+++ b/nhrpd/list.h
@@ -198,9 +198,12 @@ static inline int list_empty(const struct list_head *n)
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member), \
- n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
+ for (pos = ((head)->next != head ? \
+ list_entry((head)->next, typeof(*pos), member) : \
+ NULL), \
+ n = (pos ? \
+ list_entry(pos->member.next, typeof(*pos), member) : NULL); \
+ pos && (&pos->member != (head)); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif
diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h
index 50746d9ad5..cbee5951f3 100644
--- a/nhrpd/nhrpd.h
+++ b/nhrpd/nhrpd.h
@@ -76,8 +76,9 @@ static inline void notifier_del(struct notifier_block *n)
static inline void notifier_call(struct notifier_list *l, int cmd)
{
struct notifier_block *n, *nn;
- list_for_each_entry_safe(n, nn, &l->notifier_head, notifier_entry)
+ list_for_each_entry_safe(n, nn, &l->notifier_head, notifier_entry) {
n->action(n, cmd);
+ }
}
static inline int notifier_active(struct notifier_list *l)
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/if_netlink.c b/zebra/if_netlink.c
index 4e9b093610..d42f68cbe8 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -1104,6 +1104,14 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
NULL, ifa->ifa_prefixlen);
}
+
+ /*
+ * Linux kernel does not send route delete on interface down/addr del
+ * so we have to re-process routes it owns (i.e. kernel routes)
+ */
+ if (h->nlmsg_type != RTM_NEWADDR)
+ rib_update(RIB_UPDATE_KERNEL);
+
return 0;
}
@@ -1332,6 +1340,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
"Intf %s(%u) has gone DOWN",
name, ifp->ifindex);
if_down(ifp);
+ rib_update(RIB_UPDATE_KERNEL);
} else if (if_is_operative(ifp)) {
/* Must notify client daemons of new
* interface status. */
@@ -1371,6 +1380,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
"Intf %s(%u) has gone DOWN",
name, ifp->ifindex);
if_down(ifp);
+ rib_update(RIB_UPDATE_KERNEL);
}
}
diff --git a/zebra/rib.h b/zebra/rib.h
index b82428e54c..ee1df89c0e 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -301,8 +301,10 @@ typedef struct rib_tables_iter_t_ {
/* Events/reasons triggering a RIB update. */
typedef enum {
+ RIB_UPDATE_KERNEL,
RIB_UPDATE_RMAP_CHANGE,
- RIB_UPDATE_OTHER
+ RIB_UPDATE_OTHER,
+ RIB_UPDATE_MAX
} rib_update_event_t;
extern struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *re,
@@ -384,7 +386,8 @@ extern struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p,
vrf_id_t vrf_id);
-extern void rib_update(vrf_id_t vrf_id, rib_update_event_t event);
+extern void rib_update(rib_update_event_t event);
+extern void rib_update_vrf(vrf_id_t vrf_id, rib_update_event_t event);
extern void rib_update_table(struct route_table *table,
rib_update_event_t event);
extern int rib_sweep_route(struct thread *t);
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_nhg.c b/zebra/zebra_nhg.c
index 35df02a19a..4e696b39ac 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -177,10 +177,16 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
re->nexthop_mtu = 0;
/*
- * If the kernel has sent us a route, then
+ * If the kernel has sent us a NEW route, then
* by golly gee whiz it's a good route.
+ *
+ * If its an already INSTALLED route we have already handled, then the
+ * kernel route's nexthop might have became unreachable
+ * and we have to handle that.
*/
- if (re->type == ZEBRA_ROUTE_KERNEL || re->type == ZEBRA_ROUTE_SYSTEM)
+ if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
+ && (re->type == ZEBRA_ROUTE_KERNEL
+ || re->type == ZEBRA_ROUTE_SYSTEM))
return 1;
/*
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_rib.c b/zebra/zebra_rib.c
index 4a726b3e07..c2fa33f57d 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -58,6 +58,8 @@
#include "zebra/zebra_dplane.h"
#include "zebra/zebra_nhg.h"
+DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object");
+
/*
* Event, list, and mutex for delivery of dataplane results
*/
@@ -2961,11 +2963,66 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
return rib_add_multipath(afi, safi, p, src_p, re);
}
+static const char *rib_update_event2str(rib_update_event_t event)
+{
+ const char *ret = "UNKNOWN";
+
+ switch (event) {
+ case RIB_UPDATE_KERNEL:
+ ret = "RIB_UPDATE_KERNEL";
+ break;
+ case RIB_UPDATE_RMAP_CHANGE:
+ ret = "RIB_UPDATE_RMAP_CHANGE";
+ break;
+ case RIB_UPDATE_OTHER:
+ ret = "RIB_UPDATE_OTHER";
+ break;
+ case RIB_UPDATE_MAX:
+ break;
+ }
+
+ return ret;
+}
+
+
+/* Schedule route nodes to be processed if they match the type */
+static void rib_update_route_node(struct route_node *rn, int type)
+{
+ struct route_entry *re, *next;
+ bool re_changed = false;
+
+ RNODE_FOREACH_RE_SAFE (rn, re, next) {
+ if (type == ZEBRA_ROUTE_ALL || type == re->type) {
+ SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
+ re_changed = true;
+ }
+ }
+
+ if (re_changed)
+ rib_queue_add(rn);
+}
+
/* Schedule routes of a particular table (address-family) based on event. */
void rib_update_table(struct route_table *table, rib_update_event_t event)
{
struct route_node *rn;
- struct route_entry *re, *next;
+
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct zebra_vrf *zvrf;
+ struct vrf *vrf;
+
+ zvrf = table->info ? ((rib_table_info_t *)table->info)->zvrf
+ : NULL;
+ vrf = zvrf ? zvrf->vrf : NULL;
+
+ zlog_debug("%s: %s VRF %s Table %u event %s", __func__,
+ table->info ? afi2str(
+ ((rib_table_info_t *)table->info)->afi)
+ : "Unknown",
+ vrf ? vrf->name : "Unknown",
+ zvrf ? zvrf->table_id : 0,
+ rib_update_event2str(event));
+ }
/* Walk all routes and queue for processing, if appropriate for
* the trigger event.
@@ -2976,49 +3033,139 @@ void rib_update_table(struct route_table *table, rib_update_event_t event)
* has already been queued we don't
* need to queue it up again
*/
- if (rn->info && CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
- RIB_ROUTE_ANY_QUEUED))
+ if (rn->info
+ && CHECK_FLAG(rib_dest_from_rnode(rn)->flags,
+ RIB_ROUTE_ANY_QUEUED))
continue;
+
switch (event) {
+ case RIB_UPDATE_KERNEL:
+ rib_update_route_node(rn, ZEBRA_ROUTE_KERNEL);
+ break;
case RIB_UPDATE_RMAP_CHANGE:
case RIB_UPDATE_OTHER:
- /* Right now, examine all routes. Can restrict to a
- * protocol in
- * some cases (TODO).
- */
- if (rnode_to_ribs(rn)) {
- RNODE_FOREACH_RE_SAFE (rn, re, next)
- SET_FLAG(re->status,
- ROUTE_ENTRY_CHANGED);
- rib_queue_add(rn);
- }
+ rib_update_route_node(rn, ZEBRA_ROUTE_ALL);
break;
-
default:
break;
}
}
}
-/* RIB update function. */
-void rib_update(vrf_id_t vrf_id, rib_update_event_t event)
+static void rib_update_handle_vrf(vrf_id_t vrf_id, rib_update_event_t event)
{
struct route_table *table;
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: Handling VRF %s event %s", __func__,
+ vrf_id_to_name(vrf_id), rib_update_event2str(event));
+
/* Process routes of interested address-families. */
table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
- if (table) {
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%s : AFI_IP event %d", __func__, event);
+ if (table)
rib_update_table(table, event);
- }
table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, vrf_id);
- if (table) {
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%s : AFI_IP6 event %d", __func__, event);
+ if (table)
rib_update_table(table, event);
- }
+}
+
+static void rib_update_handle_vrf_all(rib_update_event_t event)
+{
+ struct zebra_router_table *zrt;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: Handling VRF (ALL) event %s", __func__,
+ rib_update_event2str(event));
+
+ /* Just iterate over all the route tables, rather than vrf lookups */
+ RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables)
+ rib_update_table(zrt->table, event);
+}
+
+struct rib_update_ctx {
+ rib_update_event_t event;
+ bool vrf_all;
+ vrf_id_t vrf_id;
+};
+
+static struct rib_update_ctx *rib_update_ctx_init(vrf_id_t vrf_id,
+ rib_update_event_t event)
+{
+ struct rib_update_ctx *ctx;
+
+ ctx = XCALLOC(MTYPE_RIB_UPDATE_CTX, sizeof(struct rib_update_ctx));
+
+ ctx->event = event;
+ ctx->vrf_id = vrf_id;
+
+ return ctx;
+}
+
+static void rib_update_ctx_fini(struct rib_update_ctx **ctx)
+{
+ XFREE(MTYPE_RIB_UPDATE_CTX, *ctx);
+
+ *ctx = NULL;
+}
+
+static int rib_update_handler(struct thread *thread)
+{
+ struct rib_update_ctx *ctx;
+
+ ctx = THREAD_ARG(thread);
+
+ if (ctx->vrf_all)
+ rib_update_handle_vrf_all(ctx->event);
+ else
+ rib_update_handle_vrf(ctx->vrf_id, ctx->event);
+
+ rib_update_ctx_fini(&ctx);
+
+ return 0;
+}
+
+/*
+ * Thread list to ensure we don't schedule a ton of events
+ * if interfaces are flapping for instance.
+ */
+static struct thread *t_rib_update_threads[RIB_UPDATE_MAX];
+
+/* Schedule a RIB update event for specific vrf */
+void rib_update_vrf(vrf_id_t vrf_id, rib_update_event_t event)
+{
+ struct rib_update_ctx *ctx;
+
+ ctx = rib_update_ctx_init(vrf_id, event);
+
+ /* Don't worry about making sure multiple rib updates for specific vrf
+ * are scheduled at once for now. If it becomes a problem, we can use a
+ * lookup of some sort to keep track of running threads via t_vrf_id
+ * like how we are doing it in t_rib_update_threads[].
+ */
+ thread_add_event(zrouter.master, rib_update_handler, ctx, 0, NULL);
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: Scheduled VRF %s, event %s", __func__,
+ vrf_id_to_name(ctx->vrf_id),
+ rib_update_event2str(event));
+}
+
+/* Schedule a RIB update event for all vrfs */
+void rib_update(rib_update_event_t event)
+{
+ struct rib_update_ctx *ctx;
+
+ ctx = rib_update_ctx_init(0, event);
+
+ ctx->vrf_all = true;
+
+ if (!thread_add_event(zrouter.master, rib_update_handler, ctx, 0,
+ &t_rib_update_threads[event]))
+ rib_update_ctx_fini(&ctx); /* Already scheduled */
+ else if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("%s: Schedued VRF (ALL), event %s", __func__,
+ rib_update_event2str(event));
}
/* Delete self installed routes after zebra is relaunched. */
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;
}