mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-31 08:35:45 +00:00
Merge pull request #9610 from iqras23/best_path
bgpd: VRF-Lite fix best path selection
This commit is contained in:
commit
f1f6716d4a
@ -181,6 +181,20 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If both nexthops are same then check
|
||||
* if they belong to same VRF
|
||||
*/
|
||||
if (!compare && bpi1->attr->nh_type != NEXTHOP_TYPE_BLACKHOLE) {
|
||||
if (bpi1->extra && bpi1->extra->bgp_orig && bpi2->extra
|
||||
&& bpi2->extra->bgp_orig) {
|
||||
if (bpi1->extra->bgp_orig->vrf_id
|
||||
!= bpi2->extra->bgp_orig->vrf_id) {
|
||||
compare = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return compare;
|
||||
}
|
||||
|
||||
|
@ -779,10 +779,7 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
|
||||
* schemes that could be implemented in the future.
|
||||
*
|
||||
*/
|
||||
for (bpi_ultimate = source_bpi;
|
||||
bpi_ultimate->extra && bpi_ultimate->extra->parent;
|
||||
bpi_ultimate = bpi_ultimate->extra->parent)
|
||||
;
|
||||
bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi);
|
||||
|
||||
/*
|
||||
* match parent
|
||||
@ -1619,10 +1616,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */
|
||||
if (!CHECK_FLAG(bgp_vrf->af_flags[afi][safi],
|
||||
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
|
||||
/* work back to original route */
|
||||
for (bpi_ultimate = path_vpn;
|
||||
bpi_ultimate->extra && bpi_ultimate->extra->parent;
|
||||
bpi_ultimate = bpi_ultimate->extra->parent)
|
||||
;
|
||||
bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
|
||||
|
||||
/*
|
||||
* if original route was unicast,
|
||||
|
@ -548,6 +548,25 @@ void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf,
|
||||
snprintf(buf, buf_len, "path %s", pi->peer->host);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the ultimate path info.
|
||||
*/
|
||||
struct bgp_path_info *bgp_get_imported_bpi_ultimate(struct bgp_path_info *info)
|
||||
{
|
||||
struct bgp_path_info *bpi_ultimate;
|
||||
|
||||
if (info->sub_type != BGP_ROUTE_IMPORTED)
|
||||
return info;
|
||||
|
||||
for (bpi_ultimate = info;
|
||||
bpi_ultimate->extra && bpi_ultimate->extra->parent;
|
||||
bpi_ultimate = bpi_ultimate->extra->parent)
|
||||
;
|
||||
|
||||
return bpi_ultimate;
|
||||
}
|
||||
|
||||
/* Compare two bgp route entity. If 'new' is preferable over 'exist' return 1.
|
||||
*/
|
||||
static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
@ -587,6 +606,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
bool old_proxy;
|
||||
bool new_proxy;
|
||||
bool new_origin, exist_origin;
|
||||
struct bgp_path_info *bpi_ultimate;
|
||||
|
||||
*paths_eq = 0;
|
||||
|
||||
@ -598,9 +618,11 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
bgp_path_info_path_with_addpath_rx_str(new, new_buf,
|
||||
if (debug) {
|
||||
bpi_ultimate = bgp_get_imported_bpi_ultimate(new);
|
||||
bgp_path_info_path_with_addpath_rx_str(bpi_ultimate, new_buf,
|
||||
sizeof(new_buf));
|
||||
}
|
||||
|
||||
if (exist == NULL) {
|
||||
*reason = bgp_path_selection_first;
|
||||
@ -611,7 +633,8 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
bgp_path_info_path_with_addpath_rx_str(exist, exist_buf,
|
||||
bpi_ultimate = bgp_get_imported_bpi_ultimate(exist);
|
||||
bgp_path_info_path_with_addpath_rx_str(bpi_ultimate, exist_buf,
|
||||
sizeof(exist_buf));
|
||||
zlog_debug("%s(%s): Comparing %s flags 0x%x with %s flags 0x%x",
|
||||
pfx_buf, bgp->name_pretty, new_buf, new->flags,
|
||||
@ -859,6 +882,14 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Here if these are imported routes then get ultimate pi for
|
||||
* path compare.
|
||||
*/
|
||||
new = bgp_get_imported_bpi_ultimate(new);
|
||||
exist = bgp_get_imported_bpi_ultimate(exist);
|
||||
newattr = new->attr;
|
||||
existattr = exist->attr;
|
||||
|
||||
/* 4. AS path length check. */
|
||||
if (!CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE)) {
|
||||
int exist_hops = aspath_count_hops(existattr->aspath);
|
||||
|
@ -633,6 +633,8 @@ extern struct bgp_dest *bgp_afi_node_get(struct bgp_table *table, afi_t afi,
|
||||
struct prefix_rd *prd);
|
||||
extern struct bgp_path_info *bgp_path_info_lock(struct bgp_path_info *path);
|
||||
extern struct bgp_path_info *bgp_path_info_unlock(struct bgp_path_info *path);
|
||||
extern struct bgp_path_info *
|
||||
bgp_get_imported_bpi_ultimate(struct bgp_path_info *info);
|
||||
extern void bgp_path_info_add(struct bgp_dest *dest, struct bgp_path_info *pi);
|
||||
extern void bgp_path_info_extra_free(struct bgp_path_info_extra **extra);
|
||||
extern void bgp_path_info_reap(struct bgp_dest *dest, struct bgp_path_info *pi);
|
||||
|
@ -1199,7 +1199,7 @@ route_match_vrl_source_vrf(void *rule, const struct prefix *prefix,
|
||||
if (strncmp(vrf_name, "n/a", VRF_NAMSIZ) == 0)
|
||||
return RMAP_NOMATCH;
|
||||
|
||||
if (path->extra == NULL)
|
||||
if (path->extra == NULL || path->extra->bgp_orig == NULL)
|
||||
return RMAP_NOMATCH;
|
||||
|
||||
if (strncmp(vrf_name, vrf_id_to_name(path->extra->bgp_orig->vrf_id),
|
||||
|
@ -1252,6 +1252,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
|
||||
uint8_t distance;
|
||||
struct peer *peer;
|
||||
struct bgp_path_info *mpinfo;
|
||||
struct bgp *bgp_orig;
|
||||
uint32_t metric;
|
||||
struct attr local_attr;
|
||||
struct bgp_path_info local_info;
|
||||
@ -1415,13 +1416,13 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
|
||||
}
|
||||
}
|
||||
|
||||
BGP_ORIGINAL_UPDATE(bgp_orig, mpinfo, bgp);
|
||||
|
||||
if (nh_family == AF_INET) {
|
||||
nh_updated = update_ipv4nh_for_route_install(
|
||||
nh_othervrf,
|
||||
nh_othervrf ?
|
||||
info->extra->bgp_orig : bgp,
|
||||
&mpinfo_cp->attr->nexthop,
|
||||
mpinfo_cp->attr, is_evpn, api_nh);
|
||||
nh_othervrf, bgp_orig,
|
||||
&mpinfo_cp->attr->nexthop, mpinfo_cp->attr,
|
||||
is_evpn, api_nh);
|
||||
} else {
|
||||
ifindex_t ifindex = IFINDEX_INTERNAL;
|
||||
struct in6_addr *nexthop;
|
||||
@ -1431,18 +1432,13 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
|
||||
|
||||
if (!nexthop)
|
||||
nh_updated = update_ipv4nh_for_route_install(
|
||||
nh_othervrf,
|
||||
nh_othervrf ? info->extra->bgp_orig
|
||||
: bgp,
|
||||
nh_othervrf, bgp_orig,
|
||||
&mpinfo_cp->attr->nexthop,
|
||||
mpinfo_cp->attr, is_evpn, api_nh);
|
||||
else
|
||||
nh_updated = update_ipv6nh_for_route_install(
|
||||
nh_othervrf,
|
||||
nh_othervrf ? info->extra->bgp_orig
|
||||
: bgp,
|
||||
nexthop, ifindex, mpinfo, info, is_evpn,
|
||||
api_nh);
|
||||
nh_othervrf, bgp_orig, nexthop, ifindex,
|
||||
mpinfo, info, is_evpn, api_nh);
|
||||
}
|
||||
|
||||
/* Did we get proper nexthop info to update zebra? */
|
||||
|
@ -23,6 +23,13 @@
|
||||
|
||||
#include "vxlan.h"
|
||||
|
||||
/* Macro to update bgp_original based on bpg_path_info */
|
||||
#define BGP_ORIGINAL_UPDATE(_bgp_orig, _mpinfo, _bgp) \
|
||||
((_mpinfo->extra && _mpinfo->extra->bgp_orig \
|
||||
&& _mpinfo->sub_type == BGP_ROUTE_IMPORTED) \
|
||||
? (_bgp_orig = _mpinfo->extra->bgp_orig) \
|
||||
: (_bgp_orig = _bgp))
|
||||
|
||||
/* Default weight for next hop, if doing weighted ECMP. */
|
||||
#define BGP_ZEBRA_DEFAULT_NHOP_WEIGHT 1
|
||||
|
||||
|
@ -294,16 +294,16 @@ luCommand(
|
||||
"1 available, best",
|
||||
"wait",
|
||||
"Ensure 99.0.0.4 shows up",
|
||||
10
|
||||
)
|
||||
10,
|
||||
)
|
||||
luCommand(
|
||||
"r1",
|
||||
'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.1.0.0/24"',
|
||||
"2 available, best",
|
||||
"wait",
|
||||
"Ensure 5.1.0.0 shows up",
|
||||
10
|
||||
)
|
||||
10,
|
||||
)
|
||||
want_r1_remote_cust1_routes = [
|
||||
{"p": "5.1.0.0/24", "n": "3.3.3.3", "bp": False},
|
||||
{"p": "5.1.0.0/24", "n": "99.0.0.1", "bp": True},
|
||||
@ -316,9 +316,9 @@ want_r1_remote_cust1_routes = [
|
||||
{"p": "6.0.1.0/24", "n": "3.3.3.3", "bp": False},
|
||||
{"p": "6.0.1.0/24", "n": "4.4.4.4", "bp": False},
|
||||
{"p": "6.0.1.0/24", "n": "99.0.0.1", "bp": True},
|
||||
{"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": True},
|
||||
{"p": "6.0.2.0/24", "n": "4.4.4.4", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "99.0.0.1", "bp": True},
|
||||
{"p": "6.0.2.0/24", "n": "99.0.0.1", "bp": False},
|
||||
{"p": "99.0.0.1/32", "n": "192.168.1.2", "bp": True},
|
||||
{"p": "99.0.0.2/32", "n": "3.3.3.3"},
|
||||
{"p": "99.0.0.3/32", "n": "4.4.4.4"},
|
||||
@ -338,16 +338,16 @@ luCommand(
|
||||
"1 available, best",
|
||||
"wait",
|
||||
"Ensure 99.0.0.4 shows up",
|
||||
10
|
||||
)
|
||||
10,
|
||||
)
|
||||
luCommand(
|
||||
"r3",
|
||||
'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.1.0.0/24"',
|
||||
"2 available, best",
|
||||
"wait",
|
||||
"Ensure 5.1.0.0 shows up",
|
||||
10
|
||||
)
|
||||
10,
|
||||
)
|
||||
want_r3_remote_cust1_routes = [
|
||||
{"p": "5.1.0.0/24", "n": "1.1.1.1", "bp": True},
|
||||
{"p": "5.1.0.0/24", "n": "99.0.0.2", "bp": False},
|
||||
@ -360,9 +360,9 @@ want_r3_remote_cust1_routes = [
|
||||
{"p": "6.0.1.0/24", "n": "1.1.1.1", "bp": True},
|
||||
{"p": "6.0.1.0/24", "n": "4.4.4.4", "bp": False},
|
||||
{"p": "6.0.1.0/24", "n": "99.0.0.2", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": True},
|
||||
{"p": "6.0.2.0/24", "n": "4.4.4.4", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "99.0.0.2", "bp": True},
|
||||
{"p": "6.0.2.0/24", "n": "99.0.0.2", "bp": False},
|
||||
{"p": "99.0.0.1/32", "n": "1.1.1.1", "bp": True},
|
||||
{"p": "99.0.0.3/32", "n": "4.4.4.4", "bp": True},
|
||||
{"p": "99.0.0.4/32", "n": "4.4.4.4", "bp": True},
|
||||
@ -382,24 +382,24 @@ luCommand(
|
||||
"1 available, best",
|
||||
"wait",
|
||||
"Ensure 99.0.0.4 shows up",
|
||||
10
|
||||
)
|
||||
10,
|
||||
)
|
||||
luCommand(
|
||||
"r4",
|
||||
'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 5.1.0.0/24"',
|
||||
"2 available, best",
|
||||
"wait",
|
||||
"Ensure 5.1.0.0 shows up",
|
||||
10
|
||||
)
|
||||
10,
|
||||
)
|
||||
luCommand(
|
||||
"r4",
|
||||
'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 99.0.0.2/32"',
|
||||
"1 available, best",
|
||||
"wait",
|
||||
"Ensure 99.0.0.2 shows up",
|
||||
10
|
||||
)
|
||||
10,
|
||||
)
|
||||
want_r4_remote_cust1_routes = [
|
||||
{"p": "5.1.0.0/24", "n": "1.1.1.1", "bp": True},
|
||||
{"p": "5.1.0.0/24", "n": "3.3.3.3", "bp": False},
|
||||
@ -409,10 +409,10 @@ want_r4_remote_cust1_routes = [
|
||||
{"p": "6.0.1.0/24", "n": "3.3.3.3", "bp": False},
|
||||
{"p": "6.0.1.0/24", "n": "99.0.0.3", "bp": False},
|
||||
{"p": "6.0.1.0/24", "n": "99.0.0.4", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": True},
|
||||
{"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "99.0.0.4", "bp": True},
|
||||
{"p": "6.0.2.0/24", "n": "99.0.0.4", "bp": False},
|
||||
{"p": "99.0.0.1/32", "n": "1.1.1.1", "bp": True},
|
||||
{"p": "99.0.0.2/32", "n": "3.3.3.3", "bp": True},
|
||||
{"p": "99.0.0.3/32", "n": "192.168.1.2", "bp": True},
|
||||
@ -436,9 +436,9 @@ want_r4_remote_cust2_routes = [
|
||||
{"p": "6.0.1.0/24", "n": "3.3.3.3", "bp": False},
|
||||
{"p": "6.0.1.0/24", "n": "99.0.0.3", "bp": False},
|
||||
{"p": "6.0.1.0/24", "n": "99.0.0.4", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": True},
|
||||
{"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": True},
|
||||
{"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": False},
|
||||
{"p": "6.0.2.0/24", "n": "99.0.0.4", "bp": False},
|
||||
{"p": "99.0.0.1/32", "n": "1.1.1.1", "bp": True},
|
||||
{"p": "99.0.0.2/32", "n": "3.3.3.3", "bp": True},
|
||||
@ -632,8 +632,8 @@ luCommand(
|
||||
luCommand(
|
||||
"ce1",
|
||||
'vtysh -c "show bgp ipv4 uni 6.0.2.0"',
|
||||
"1 available, best .*192.168.1.1.* Local.* 99.0.0.1 from 0.0.0.0 .99.0.0.1"
|
||||
+ ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .First path received"
|
||||
"2 available, best .*192.168.1.1.* Local.* 99.0.0.1 from 0.0.0.0 .99.0.0.1"
|
||||
+ ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .Weight"
|
||||
+ ".* Community: 0:67.* Extended Community: RT:89:123.* Large Community: 12:34:11",
|
||||
"pass",
|
||||
"Redundant route 2 details",
|
||||
@ -641,8 +641,8 @@ luCommand(
|
||||
luCommand(
|
||||
"ce2",
|
||||
'vtysh -c "show bgp ipv4 uni 6.0.2.0"',
|
||||
"1 available, best .*192.168.1.1.* Local.* 99.0.0.2 from 0.0.0.0 .99.0.0.2"
|
||||
+ ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .First path received"
|
||||
"2 available, best .*192.168.1.1.* Local.* 99.0.0.2 from 0.0.0.0 .99.0.0.2"
|
||||
+ ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .Weight"
|
||||
+ ".* Community: 0:67.* Extended Community: RT:89:123.* Large Community: 12:34:12",
|
||||
"pass",
|
||||
"Redundant route 2 details",
|
||||
@ -661,7 +661,7 @@ luCommand(
|
||||
'vtysh -c "show bgp ipv4 uni 6.0.2.0"',
|
||||
"2 available, best .*192.168.1.1.* Local.* 192.168.1.1 from 192.168.1.1 .192.168.1.1"
|
||||
+ ".* Origin IGP, metric 100, localpref 100, valid, internal"
|
||||
+ ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:14",
|
||||
+ ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:11",
|
||||
"pass",
|
||||
"Redundant route 2 details",
|
||||
)
|
||||
@ -670,7 +670,7 @@ luCommand(
|
||||
'vtysh -c "show bgp vrf ce4-cust2 ipv4 6.0.2.0"',
|
||||
"2 available, best .*192.168.2.1.* Local.* 192.168.2.1 from 192.168.2.1 .192.168.2.1"
|
||||
+ ".* Origin IGP, metric 100, localpref 100, valid, internal"
|
||||
+ ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:13",
|
||||
+ ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:11",
|
||||
"pass",
|
||||
"Redundant route 2 details",
|
||||
)
|
||||
|
@ -0,0 +1,563 @@
|
||||
{
|
||||
"address_types": ["ipv4","ipv6"],
|
||||
"ipv4base": "10.0.0.0",
|
||||
"ipv4mask": 30,
|
||||
"ipv6base": "fd00::",
|
||||
"ipv6mask": 64,
|
||||
"link_ip_start": {
|
||||
"ipv4": "10.0.0.0",
|
||||
"v4mask": 30,
|
||||
"ipv6": "fd00::",
|
||||
"v6mask": 64
|
||||
},
|
||||
"lo_prefix": {
|
||||
"ipv4": "1.0.",
|
||||
"v4mask": 32,
|
||||
"ipv6": "2001:db8:f::",
|
||||
"v6mask": 128
|
||||
},
|
||||
"routers": {
|
||||
"r1": {
|
||||
"links": {
|
||||
"r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"},
|
||||
"r3-link1": {"ipv4": "auto", "ipv6": "auto"},
|
||||
"r4-link1": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"vrfs":[
|
||||
{
|
||||
"name": "ISR",
|
||||
"id": "1"
|
||||
}
|
||||
],
|
||||
"bgp":
|
||||
[
|
||||
{
|
||||
"local_as": "100",
|
||||
"vrf": "ISR",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"next_hop_self": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"next_hop_self": true,
|
||||
"route_maps": [{
|
||||
"name": "rmap_global",
|
||||
"direction": "in"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"route_maps": [{
|
||||
"name": "rmap_global",
|
||||
"direction": "in"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r4": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r4": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"route_maps": [{
|
||||
"name": "rmap_global",
|
||||
"direction": "in"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"static_routes":[
|
||||
{
|
||||
"network": ["11.11.11.1/32", "11.11.11.11/32"],
|
||||
"next_hop":"Null0",
|
||||
"vrf": "ISR"
|
||||
},
|
||||
{
|
||||
"network": ["11:11::1/128", "11:11::11/128"],
|
||||
"next_hop":"Null0",
|
||||
"vrf": "ISR"
|
||||
},
|
||||
{
|
||||
"network": ["10.10.10.10/32", "10.10.10.100/32"],
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network": ["10:10::10/128", "10:10::100/128"],
|
||||
"next_hop":"Null0"
|
||||
}
|
||||
],
|
||||
"route_maps": {
|
||||
"rmap_global": [{
|
||||
"action": "permit",
|
||||
"set": {
|
||||
"ipv6": {
|
||||
"nexthop": "prefer-global"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"r2": {
|
||||
"links": {
|
||||
"r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"},
|
||||
"r3-link1": {"ipv4": "auto", "ipv6": "auto"},
|
||||
"r4-link1": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"vrfs":[
|
||||
{
|
||||
"name": "ISR",
|
||||
"id": "1"
|
||||
}
|
||||
],
|
||||
"bgp":
|
||||
[
|
||||
{
|
||||
"local_as": "100",
|
||||
"vrf": "ISR",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"next_hop_self": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"next_hop_self": true,
|
||||
"route_maps": [{
|
||||
"name": "rmap_global",
|
||||
"direction": "in"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"route_maps": [{
|
||||
"name": "rmap_global",
|
||||
"direction": "in"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r4": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r4": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"route_maps": [{
|
||||
"name": "rmap_global",
|
||||
"direction": "in"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"static_routes":[
|
||||
{
|
||||
"network": ["22.22.22.2/32", "22.22.22.22/32"],
|
||||
"next_hop":"Null0",
|
||||
"vrf": "ISR"
|
||||
},
|
||||
{
|
||||
"network": ["22:22::2/128", "22:22::22/128"],
|
||||
"next_hop":"Null0",
|
||||
"vrf": "ISR"
|
||||
},
|
||||
{
|
||||
"network": ["20.20.20.20/32", "20.20.20.200/32"],
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network": ["20:20::20/128", "20:20::200/128"],
|
||||
"next_hop":"Null0"
|
||||
}
|
||||
],
|
||||
"route_maps": {
|
||||
"rmap_global": [{
|
||||
"action": "permit",
|
||||
"set": {
|
||||
"ipv6": {
|
||||
"nexthop": "prefer-global"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"r3": {
|
||||
"links": {
|
||||
"r1-link1": {"ipv4": "auto", "ipv6": "auto"},
|
||||
"r2-link1": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"bgp":
|
||||
[
|
||||
{
|
||||
"local_as": "300",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r3-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r3-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"route_maps": [{
|
||||
"name": "rmap_global",
|
||||
"direction": "in"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"local_as": "300",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"route_maps": [{
|
||||
"name": "rmap_global",
|
||||
"direction": "in"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"static_routes":[
|
||||
{
|
||||
"network": ["30.30.30.3/32", "30.30.30.30/32"],
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network": ["30:30::3/128", "30:30::30/128"],
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network": ["50.50.50.5/32", "50.50.50.50/32"],
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network": ["50:50::5/128", "50:50::50/128"],
|
||||
"next_hop":"Null0"
|
||||
}
|
||||
],
|
||||
"route_maps": {
|
||||
"rmap_global": [{
|
||||
"action": "permit",
|
||||
"set": {
|
||||
"ipv6": {
|
||||
"nexthop": "prefer-global"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"r4": {
|
||||
"links": {
|
||||
"r1-link1": {"ipv4": "auto", "ipv6": "auto"},
|
||||
"r2-link1": {"ipv4": "auto", "ipv6": "auto"}
|
||||
},
|
||||
"bgp":
|
||||
[
|
||||
{
|
||||
"local_as": "400",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r4-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r4-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"route_maps": [{
|
||||
"name": "rmap_global",
|
||||
"direction": "in"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"local_as": "400",
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r4-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r4-link1": {
|
||||
"keepalivetimer": 1,
|
||||
"holddowntimer": 3,
|
||||
"route_maps": [{
|
||||
"name": "rmap_global",
|
||||
"direction": "in"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"static_routes":[
|
||||
{
|
||||
"network": ["40.40.40.4/32", "40.40.40.40/32"],
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network": ["40:40::4/128", "40:40::40/128"],
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network": ["50.50.50.5/32", "50.50.50.50/32"],
|
||||
"next_hop":"Null0"
|
||||
},
|
||||
{
|
||||
"network": ["50:50::5/128", "50:50::50/128"],
|
||||
"next_hop":"Null0"
|
||||
}
|
||||
],
|
||||
"route_maps": {
|
||||
"rmap_global": [{
|
||||
"action": "permit",
|
||||
"set": {
|
||||
"ipv6": {
|
||||
"nexthop": "prefer-global"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,916 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Copyright (c) 2020 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 BGP VRF Lite:
|
||||
|
||||
1. Verify BGP best path selection algorithm works fine when
|
||||
routes are imported from ISR to default vrf and vice versa.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import pytest
|
||||
import platform
|
||||
|
||||
# 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/"))
|
||||
|
||||
# Required to instantiate the topology builder class.
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib.topogen import Topogen, get_topogen
|
||||
from lib.topotest import version_cmp
|
||||
|
||||
from lib.common_config import (
|
||||
start_topology,
|
||||
write_test_header,
|
||||
check_address_types,
|
||||
write_test_footer,
|
||||
step,
|
||||
create_route_maps,
|
||||
create_prefix_lists,
|
||||
check_router_status,
|
||||
get_frr_ipv6_linklocal,
|
||||
shutdown_bringup_interface,
|
||||
)
|
||||
|
||||
from lib.topolog import logger
|
||||
from lib.bgp import (
|
||||
verify_bgp_convergence,
|
||||
create_router_bgp,
|
||||
verify_bgp_community,
|
||||
verify_bgp_rib,
|
||||
clear_bgp,
|
||||
verify_best_path_as_per_bgp_attribute
|
||||
)
|
||||
from lib.topojson import build_config_from_json
|
||||
|
||||
|
||||
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
|
||||
|
||||
# Global variables
|
||||
NETWORK1_1 = {"ipv4": "11.11.11.1/32", "ipv6": "11:11::1/128"}
|
||||
NETWORK1_2 = {"ipv4": "11.11.11.11/32", "ipv6": "11:11::11/128"}
|
||||
NETWORK1_3 = {"ipv4": "10.10.10.10/32", "ipv6": "10:10::10/128"}
|
||||
NETWORK1_4 = {"ipv4": "10.10.10.100/32", "ipv6": "10:10::100/128"}
|
||||
|
||||
NETWORK2_1 = {"ipv4": "22.22.22.2/32", "ipv6": "22:22::2/128"}
|
||||
NETWORK2_2 = {"ipv4": "22.22.22.22/32", "ipv6": "22:22::22/128"}
|
||||
NETWORK2_3 = {"ipv4": "20.20.20.20/32", "ipv6": "20:20::20/128"}
|
||||
NETWORK2_4 = {"ipv4": "20.20.20.200/32", "ipv6": "20:20::200/128"}
|
||||
|
||||
NETWORK3_1 = {"ipv4": "30.30.30.3/32", "ipv6": "30:30::3/128"}
|
||||
NETWORK3_2 = {"ipv4": "30.30.30.30/32", "ipv6": "30:30::30/128"}
|
||||
NETWORK3_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"}
|
||||
NETWORK3_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"}
|
||||
|
||||
NETWORK4_1 = {"ipv4": "40.40.40.4/32", "ipv6": "40:40::4/128"}
|
||||
NETWORK4_2 = {"ipv4": "40.40.40.40/32", "ipv6": "40:40::40/128"}
|
||||
NETWORK4_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"}
|
||||
NETWORK4_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"}
|
||||
NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
|
||||
LOOPBACK_1 = {
|
||||
"ipv4": "10.0.0.7/24",
|
||||
"ipv6": "fd00:0:0:1::7/64",
|
||||
"ipv4_mask": "255.255.255.0",
|
||||
"ipv6_mask": None,
|
||||
}
|
||||
LOOPBACK_2 = {
|
||||
"ipv4": "10.0.0.16/24",
|
||||
"ipv6": "fd00:0:0:3::5/64",
|
||||
"ipv4_mask": "255.255.255.0",
|
||||
"ipv6_mask": None,
|
||||
}
|
||||
PREFERRED_NEXT_HOP = "global"
|
||||
|
||||
|
||||
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...
|
||||
json_file = "{}/bgp_vrf_lite_best_path_topo1.json".format(CWD)
|
||||
tgen = Topogen(json_file, mod.__name__)
|
||||
global topo
|
||||
topo = tgen.json_topo
|
||||
# ... and here it calls Mininet initialization functions.
|
||||
|
||||
# Starting topology, create tmp files which are loaded to routers
|
||||
# to start deamons and then start routers
|
||||
start_topology(tgen)
|
||||
|
||||
# Run these tests for kernel version 4.19 or above
|
||||
if version_cmp(platform.release(), "4.19") < 0:
|
||||
error_msg = (
|
||||
"BGP vrf dynamic route leak tests will not run "
|
||||
'(have kernel "{}", but it requires >= 4.19)'.format(platform.release())
|
||||
)
|
||||
pytest.skip(error_msg)
|
||||
|
||||
# Creating configuration from JSON
|
||||
build_config_from_json(tgen, topo)
|
||||
|
||||
global BGP_CONVERGENCE
|
||||
global ADDR_TYPES
|
||||
ADDR_TYPES = check_address_types()
|
||||
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format(
|
||||
BGP_CONVERGENCE
|
||||
)
|
||||
|
||||
logger.info("Running setup_module() done")
|
||||
|
||||
|
||||
def teardown_module():
|
||||
"""Teardown the pytest environment"""
|
||||
|
||||
logger.info("Running teardown_module to delete topology")
|
||||
|
||||
tgen = get_topogen()
|
||||
|
||||
# Stop toplogy and Remove tmp files
|
||||
tgen.stop_topology()
|
||||
|
||||
logger.info(
|
||||
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
|
||||
)
|
||||
logger.info("=" * 40)
|
||||
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# Testcases
|
||||
#
|
||||
#####################################################
|
||||
|
||||
|
||||
def disable_route_map_to_prefer_global_next_hop(tgen, topo):
|
||||
"""
|
||||
This API is to remove prefer global route-map applied on neighbors
|
||||
|
||||
Parameter:
|
||||
----------
|
||||
* `tgen` : Topogen object
|
||||
* `topo` : Input JSON data
|
||||
|
||||
Returns:
|
||||
--------
|
||||
True/errormsg
|
||||
|
||||
"""
|
||||
|
||||
logger.info("Remove prefer-global rmap applied on neighbors")
|
||||
input_dict = {
|
||||
"r1": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "100",
|
||||
"vrf": "ISR",
|
||||
"address_family": {
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_global",
|
||||
"direction": "in",
|
||||
"delete": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_global",
|
||||
"direction": "in",
|
||||
"delete": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r4": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_global",
|
||||
"direction": "in",
|
||||
"delete": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
"r2": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "100",
|
||||
"vrf": "ISR",
|
||||
"address_family": {
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_global",
|
||||
"direction": "in",
|
||||
"delete": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_global",
|
||||
"direction": "in",
|
||||
"delete": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r4": {
|
||||
"dest_link": {
|
||||
"r2-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_global",
|
||||
"direction": "in",
|
||||
"delete": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
"r3": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "300",
|
||||
"address_family": {
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r3-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_global",
|
||||
"direction": "in",
|
||||
"delete": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"local_as": "300",
|
||||
"address_family": {
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r3-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_global",
|
||||
"direction": "in",
|
||||
"delete": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
"r4": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "400",
|
||||
"address_family": {
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r1": {
|
||||
"dest_link": {
|
||||
"r4-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_global",
|
||||
"direction": "in",
|
||||
"delete": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"local_as": "400",
|
||||
"address_family": {
|
||||
"ipv6": {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r2": {
|
||||
"dest_link": {
|
||||
"r4-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_global",
|
||||
"direction": "in",
|
||||
"delete": True,
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
result = create_router_bgp(tgen, topo, input_dict)
|
||||
assert result is True, "Testcase :Failed \n Error: {}".format(result)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def test_bgp_best_path_with_dynamic_import_p0(request):
|
||||
"""
|
||||
1.5.6. Verify BGP best path selection algorithm works fine when
|
||||
routes are imported from ISR to default vrf and vice versa.
|
||||
"""
|
||||
|
||||
tgen = get_topogen()
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
build_config_from_json(tgen, topo)
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
check_router_status(tgen)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
step(
|
||||
"Redistribute configured static routes into BGP process" " on R1/R2 and R3"
|
||||
)
|
||||
|
||||
input_dict_1 = {}
|
||||
DUT = ["r1", "r2", "r3", "r4"]
|
||||
VRFS = ["ISR", "ISR", "default", "default"]
|
||||
AS_NUM = [100, 100, 300, 400]
|
||||
|
||||
for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
|
||||
temp = {dut: {"bgp": []}}
|
||||
input_dict_1.update(temp)
|
||||
|
||||
temp[dut]["bgp"].append(
|
||||
{
|
||||
"local_as": as_num,
|
||||
"vrf": vrf,
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {"redistribute": [{"redist_type": "static"}]}
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
result = create_router_bgp(tgen, topo, input_dict_1)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
step("Import from default vrf into vrf ISR on R1 and R2 as below")
|
||||
|
||||
input_dict_vrf = {}
|
||||
DUT = ["r1", "r2"]
|
||||
VRFS = ["ISR", "ISR"]
|
||||
AS_NUM = [100, 100]
|
||||
|
||||
for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
|
||||
temp = {dut: {"bgp": []}}
|
||||
input_dict_vrf.update(temp)
|
||||
|
||||
temp[dut]["bgp"].append(
|
||||
{
|
||||
"local_as": as_num,
|
||||
"vrf": vrf,
|
||||
"address_family": {
|
||||
addr_type: {"unicast": {"import": {"vrf": "default"}}}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
result = create_router_bgp(tgen, topo, input_dict_vrf)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
input_dict_default = {}
|
||||
DUT = ["r1", "r2"]
|
||||
VRFS = ["default", "default"]
|
||||
AS_NUM = [100, 100]
|
||||
|
||||
for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
|
||||
temp = {dut: {"bgp": []}}
|
||||
input_dict_default.update(temp)
|
||||
|
||||
temp[dut]["bgp"].append(
|
||||
{
|
||||
"local_as": as_num,
|
||||
"vrf": vrf,
|
||||
"address_family": {
|
||||
addr_type: {"unicast": {"import": {"vrf": "ISR"}}}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
result = create_router_bgp(tgen, topo, input_dict_default)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step(
|
||||
"Verify ECMP/Next-hop/Imported routes Vs Locally originated "
|
||||
"routes/eBGP routes vs iBGP routes --already covered in almost"
|
||||
" all tests"
|
||||
)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
step("Verify Pre-emption")
|
||||
|
||||
input_routes_r3 = {
|
||||
"r3": {"static_routes": [{"network": [NETWORK3_3[addr_type]]}]}
|
||||
}
|
||||
|
||||
intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"]
|
||||
intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"]
|
||||
|
||||
if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
|
||||
nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1)
|
||||
nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1)
|
||||
else:
|
||||
nh_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"][addr_type].split("/")[
|
||||
0
|
||||
]
|
||||
nh_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"][addr_type].split("/")[
|
||||
0
|
||||
]
|
||||
|
||||
result = verify_bgp_rib(
|
||||
tgen, addr_type, "r1", input_routes_r3, next_hop=[nh_r4_r1]
|
||||
)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Shutdown interface connected to r1 from r4:")
|
||||
shutdown_bringup_interface(tgen, "r4", intf_r4_r1, False)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
input_routes_r3 = {
|
||||
"r3": {"static_routes": [{"network": [NETWORK3_3[addr_type]]}]}
|
||||
}
|
||||
|
||||
intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"]
|
||||
intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"]
|
||||
|
||||
if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
|
||||
nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1)
|
||||
nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1)
|
||||
else:
|
||||
nh_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"][addr_type].split("/")[
|
||||
0
|
||||
]
|
||||
nh_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"][addr_type].split("/")[
|
||||
0
|
||||
]
|
||||
|
||||
step("Verify next-hop is changed")
|
||||
result = verify_bgp_rib(
|
||||
tgen, addr_type, "r1", input_routes_r3, next_hop=[nh_r3_r1]
|
||||
)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Bringup interface connected to r1 from r4:")
|
||||
shutdown_bringup_interface(tgen, "r4", intf_r4_r1, True)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
input_routes_r3 = {
|
||||
"r3": {"static_routes": [{"network": [NETWORK3_3[addr_type]]}]}
|
||||
}
|
||||
|
||||
intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"]
|
||||
intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"]
|
||||
|
||||
if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
|
||||
nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1)
|
||||
nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1)
|
||||
else:
|
||||
nh_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"][addr_type].split("/")[
|
||||
0
|
||||
]
|
||||
nh_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"][addr_type].split("/")[
|
||||
0
|
||||
]
|
||||
|
||||
step("Verify next-hop is not chnaged aftr shutdown:")
|
||||
result = verify_bgp_rib(
|
||||
tgen, addr_type, "r1", input_routes_r3, next_hop=[nh_r3_r1]
|
||||
)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Active-Standby scenario(as-path prepend and Local pref)")
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
step("Create prefix-list")
|
||||
|
||||
input_dict_pf = {
|
||||
"r1": {
|
||||
"prefix_lists": {
|
||||
addr_type: {
|
||||
"pf_ls_{}".format(addr_type): [
|
||||
{
|
||||
"seqid": 10,
|
||||
"network": NETWORK3_4[addr_type],
|
||||
"action": "permit",
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result = create_prefix_lists(tgen, input_dict_pf)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
step("Create route-map to match prefix-list and set localpref 500")
|
||||
|
||||
input_dict_rm = {
|
||||
"r1": {
|
||||
"route_maps": {
|
||||
"rmap_PATH1_{}".format(addr_type): [
|
||||
{
|
||||
"action": "permit",
|
||||
"seq_id": 10,
|
||||
"match": {
|
||||
addr_type: {
|
||||
"prefix_lists": "pf_ls_{}".format(addr_type)
|
||||
}
|
||||
},
|
||||
"set": {"locPrf": 500},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = create_route_maps(tgen, input_dict_rm)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step("Create route-map to match prefix-list and set localpref 600")
|
||||
|
||||
input_dict_rm = {
|
||||
"r1": {
|
||||
"route_maps": {
|
||||
"rmap_PATH2_{}".format(addr_type): [
|
||||
{
|
||||
"action": "permit",
|
||||
"seq_id": 20,
|
||||
"match": {
|
||||
addr_type: {
|
||||
"prefix_lists": "pf_ls_{}".format(addr_type)
|
||||
}
|
||||
},
|
||||
"set": {"locPrf": 600},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = create_route_maps(tgen, input_dict_rm)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
input_dict_rma = {
|
||||
"r1": {
|
||||
"bgp": [
|
||||
{
|
||||
"local_as": "100",
|
||||
"address_family": {
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"neighbor": {
|
||||
"r3": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_PATH1_{}".format(
|
||||
addr_type
|
||||
),
|
||||
"direction": "in",
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"r4": {
|
||||
"dest_link": {
|
||||
"r1-link1": {
|
||||
"route_maps": [
|
||||
{
|
||||
"name": "rmap_PATH2_{}".format(
|
||||
addr_type
|
||||
),
|
||||
"direction": "in",
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = create_router_bgp(tgen, topo, input_dict_rma)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
dut = "r1"
|
||||
attribute = "locPrf"
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
step("Verify bestpath is installed as per highest localpref")
|
||||
|
||||
input_routes_r3 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{"network": [NETWORK3_3[addr_type], NETWORK3_4[addr_type]]}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = verify_best_path_as_per_bgp_attribute(
|
||||
tgen, addr_type, dut, input_routes_r3, attribute
|
||||
)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
step("Create route-map to match prefix-list and set localpref 700")
|
||||
|
||||
input_dict_rm = {
|
||||
"r1": {
|
||||
"route_maps": {
|
||||
"rmap_PATH1_{}".format(addr_type): [
|
||||
{
|
||||
"action": "permit",
|
||||
"seq_id": 10,
|
||||
"match": {
|
||||
addr_type: {
|
||||
"prefix_lists": "pf_ls_{}".format(addr_type)
|
||||
}
|
||||
},
|
||||
"set": {"locPrf": 700},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = create_route_maps(tgen, input_dict_rm)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
step("Verify bestpath is changed as per highest localpref")
|
||||
|
||||
input_routes_r3 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{"network": [NETWORK3_3[addr_type], NETWORK3_4[addr_type]]}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = verify_best_path_as_per_bgp_attribute(
|
||||
tgen, addr_type, dut, input_routes_r3, attribute
|
||||
)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
step("Create route-map to match prefix-list and set as-path prepend")
|
||||
|
||||
input_dict_rm = {
|
||||
"r1": {
|
||||
"route_maps": {
|
||||
"rmap_PATH2_{}".format(addr_type): [
|
||||
{
|
||||
"action": "permit",
|
||||
"seq_id": 20,
|
||||
"match": {
|
||||
addr_type: {
|
||||
"prefix_lists": "pf_ls_{}".format(addr_type)
|
||||
}
|
||||
},
|
||||
"set": {
|
||||
"localpref": 700,
|
||||
"path": {"as_num": "111", "as_action": "prepend"},
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = create_route_maps(tgen, input_dict_rm)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
attribute = "path"
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
|
||||
step("Verify bestpath is changed as per shortest as-path")
|
||||
|
||||
input_routes_r3 = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{"network": [NETWORK3_3[addr_type], NETWORK3_4[addr_type]]}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = verify_best_path_as_per_bgp_attribute(
|
||||
tgen, addr_type, dut, input_routes_r3, attribute
|
||||
)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
@ -0,0 +1,539 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Copyright (c) 2021 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 BGP VRF Lite:
|
||||
1. Verify that locally imported routes are selected as best path over eBGP imported routes
|
||||
peers.
|
||||
2. Verify ECMP for imported routes from different VRFs.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import pytest
|
||||
import platform
|
||||
from time import sleep
|
||||
|
||||
# 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/"))
|
||||
|
||||
# Required to instantiate the topology builder class.
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib.topogen import Topogen, get_topogen
|
||||
from lib.topotest import version_cmp
|
||||
|
||||
from lib.common_config import (
|
||||
start_topology,
|
||||
write_test_header,
|
||||
check_address_types,
|
||||
write_test_footer,
|
||||
reset_config_on_routers,
|
||||
verify_rib,
|
||||
step,
|
||||
create_static_routes,
|
||||
check_router_status,
|
||||
apply_raw_config
|
||||
)
|
||||
|
||||
from lib.topolog import logger
|
||||
from lib.bgp import (
|
||||
verify_bgp_convergence,
|
||||
create_router_bgp,
|
||||
verify_bgp_rib,
|
||||
verify_bgp_bestpath
|
||||
)
|
||||
from lib.topojson import build_config_from_json
|
||||
|
||||
pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
|
||||
|
||||
# Global variables
|
||||
NETWORK1_1 = {"ipv4": "11.11.11.1/32", "ipv6": "11:11::1/128"}
|
||||
NETWORK1_2 = {"ipv4": "11.11.11.11/32", "ipv6": "11:11::11/128"}
|
||||
NETWORK1_3 = {"ipv4": "10.10.10.1/32", "ipv6": "10:10::1/128"}
|
||||
NETWORK1_4 = {"ipv4": "10.10.10.100/32", "ipv6": "10:10::100/128"}
|
||||
NETWORK1_5 = {"ipv4": "110.110.110.1/32", "ipv6": "110:110::1/128"}
|
||||
NETWORK1_6 = {"ipv4": "110.110.110.100/32", "ipv6": "110:110::100/128"}
|
||||
|
||||
NETWORK2_1 = {"ipv4": "22.22.22.2/32", "ipv6": "22:22::2/128"}
|
||||
NETWORK2_2 = {"ipv4": "22.22.22.22/32", "ipv6": "22:22::22/128"}
|
||||
NETWORK2_3 = {"ipv4": "20.20.20.20/32", "ipv6": "20:20::20/128"}
|
||||
NETWORK2_4 = {"ipv4": "20.20.20.200/32", "ipv6": "20:20::200/128"}
|
||||
NETWORK2_5 = {"ipv4": "220.220.220.20/32", "ipv6": "220:220::20/128"}
|
||||
NETWORK2_6 = {"ipv4": "220.220.220.200/32", "ipv6": "220:220::200/128"}
|
||||
|
||||
NETWORK3_1 = {"ipv4": "30.30.30.3/32", "ipv6": "30:30::3/128"}
|
||||
NETWORK3_2 = {"ipv4": "30.30.30.30/32", "ipv6": "30:30::30/128"}
|
||||
|
||||
PREFIX_LIST = {
|
||||
"ipv4": ["11.11.11.1", "22.22.22.2", "22.22.22.22"],
|
||||
"ipv6": ["11:11::1", "22:22::2", "22:22::22"],
|
||||
}
|
||||
PREFERRED_NEXT_HOP = "global"
|
||||
VRF_LIST = ["RED", "BLUE", "GREEN"]
|
||||
COMM_VAL_1 = "100:100"
|
||||
COMM_VAL_2 = "500:500"
|
||||
COMM_VAL_3 = "600:600"
|
||||
BESTPATH = {
|
||||
"ipv4": "0.0.0.0",
|
||||
"ipv6": "::"
|
||||
}
|
||||
|
||||
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...
|
||||
json_file = "{}/bgp_vrf_lite_best_path_topo2.json".format(CWD)
|
||||
tgen = Topogen(json_file, mod.__name__)
|
||||
global topo
|
||||
topo = tgen.json_topo
|
||||
# ... and here it calls Mininet initialization functions.
|
||||
|
||||
# Starting topology, create tmp files which are loaded to routers
|
||||
# to start deamons and then start routers
|
||||
start_topology(tgen)
|
||||
|
||||
# Run these tests for kernel version 4.19 or above
|
||||
if version_cmp(platform.release(), "4.19") < 0:
|
||||
error_msg = (
|
||||
"BGP vrf dynamic route leak tests will not run "
|
||||
'(have kernel "{}", but it requires >= 4.19)'.format(platform.release())
|
||||
)
|
||||
pytest.skip(error_msg)
|
||||
|
||||
# Creating configuration from JSON
|
||||
build_config_from_json(tgen, topo)
|
||||
|
||||
global BGP_CONVERGENCE
|
||||
global ADDR_TYPES
|
||||
ADDR_TYPES = check_address_types()
|
||||
|
||||
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
||||
assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format(
|
||||
BGP_CONVERGENCE
|
||||
)
|
||||
|
||||
logger.info("Running setup_module() done")
|
||||
|
||||
|
||||
def teardown_module():
|
||||
"""Teardown the pytest environment"""
|
||||
|
||||
logger.info("Running teardown_module to delete topology")
|
||||
|
||||
tgen = get_topogen()
|
||||
|
||||
# Stop toplogy and Remove tmp files
|
||||
tgen.stop_topology()
|
||||
|
||||
logger.info(
|
||||
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
|
||||
)
|
||||
logger.info("=" * 40)
|
||||
|
||||
|
||||
#####################################################
|
||||
#
|
||||
# Testcases
|
||||
#
|
||||
#####################################################
|
||||
|
||||
def test_dynamic_import_ecmp_imported_routed_diffrent_vrfs_p0(request):
|
||||
"""
|
||||
Verify ECMP for imported routes from different VRFs.
|
||||
"""
|
||||
|
||||
tgen = get_topogen()
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
if tgen.routers_have_failure():
|
||||
check_router_status(tgen)
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
step("Configure same static routes in tenant vrfs RED and GREEN on router "
|
||||
"R3 and redistribute in respective BGP process")
|
||||
|
||||
for vrf_name in ["RED", "GREEN"]:
|
||||
for addr_type in ADDR_TYPES:
|
||||
if vrf_name == "GREEN":
|
||||
next_hop_vrf = topo["routers"]["r1"]["links"][
|
||||
"r3-link3"][addr_type].split("/")[0]
|
||||
else:
|
||||
next_hop_vrf = topo["routers"]["r2"]["links"][
|
||||
"r3-link1"][addr_type].split("/")[0]
|
||||
static_routes = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": [NETWORK1_1[addr_type]],
|
||||
"next_hop": next_hop_vrf,
|
||||
"vrf": vrf_name
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = create_static_routes(tgen, static_routes)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
step("Redistribute static route on BGP VRF : {}".format(vrf_name))
|
||||
temp = {}
|
||||
for addr_type in ADDR_TYPES:
|
||||
temp.update({
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static"
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
redist_dict = {"r3": {"bgp": [{
|
||||
"vrf": vrf_name, "local_as": 3, "address_family": temp
|
||||
}]}}
|
||||
|
||||
result = create_router_bgp(tgen, topo, redist_dict)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
step("Verify that configured static routes are installed in respective "
|
||||
"BGP table for vrf RED & GREEN")
|
||||
for vrf_name in ["RED", "GREEN"]:
|
||||
for addr_type in ADDR_TYPES:
|
||||
if vrf_name == "GREEN":
|
||||
next_hop_vrf = topo["routers"]["r1"]["links"][
|
||||
"r3-link3"][addr_type].split("/")[0]
|
||||
else:
|
||||
next_hop_vrf = topo["routers"]["r2"]["links"][
|
||||
"r3-link1"][addr_type].split("/")[0]
|
||||
static_routes = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": [NETWORK1_1[addr_type]],
|
||||
"vrf": vrf_name
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = verify_bgp_rib(tgen, addr_type, "r3", static_routes,
|
||||
next_hop=next_hop_vrf)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
result = verify_rib(tgen, addr_type, "r3", static_routes,
|
||||
next_hop=next_hop_vrf)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
step("Import vrf RED and GREEN into default vrf and Configure ECMP")
|
||||
bgp_val = []
|
||||
for vrf_name in ["RED", "GREEN"]:
|
||||
temp = {}
|
||||
for addr_type in ADDR_TYPES:
|
||||
temp.update({
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"import": {
|
||||
"vrf": vrf_name
|
||||
},
|
||||
"maximum_paths": {
|
||||
"ebgp": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
bgp_val.append({
|
||||
"local_as": 3, "address_family": temp
|
||||
})
|
||||
|
||||
import_dict = {"r3": {"bgp": bgp_val}}
|
||||
|
||||
result = create_router_bgp(tgen, topo, import_dict)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
step("Configure bgp bestpath on router r3")
|
||||
r3_raw_config = {
|
||||
"r3": {
|
||||
"raw_config": [
|
||||
"router bgp 3",
|
||||
"bgp bestpath as-path multipath-relax"
|
||||
]
|
||||
}
|
||||
}
|
||||
result = apply_raw_config(tgen, r3_raw_config)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
step("Verify that routes are imported with two different next-hop vrfs "
|
||||
"and IPs. Additionally R3 must do ECMP for both the routes.")
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
next_hop_vrf = [
|
||||
topo["routers"]["r2"]["links"]["r3-link1"][addr_type]. \
|
||||
split("/")[0],
|
||||
topo["routers"]["r1"]["links"]["r3-link3"][addr_type]. \
|
||||
split("/")[0]
|
||||
]
|
||||
static_routes = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": [NETWORK1_1[addr_type]],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = verify_bgp_rib(tgen, addr_type, "r3", static_routes,
|
||||
next_hop=next_hop_vrf)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
result = verify_rib(tgen, addr_type, "r3", static_routes,
|
||||
next_hop=next_hop_vrf)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
step("Now change the next-hop of static routes in vrf RED and GREEN to "
|
||||
"same IP address")
|
||||
for addr_type in ADDR_TYPES:
|
||||
next_hop_vrf = topo["routers"]["r1"]["links"][
|
||||
"r3-link3"][addr_type].split("/")[0]
|
||||
static_routes = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": [NETWORK1_1[addr_type]],
|
||||
"next_hop": next_hop_vrf,
|
||||
"vrf": "RED"
|
||||
},
|
||||
{
|
||||
"network": [NETWORK1_1[addr_type]],
|
||||
"next_hop": topo["routers"]["r2"]["links"][
|
||||
"r3-link1"][addr_type].split("/")[0],
|
||||
"vrf": "RED",
|
||||
"delete": True
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = create_static_routes(tgen, static_routes)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
step("Verify that now routes are imported with two different next-hop "
|
||||
"vrfs but same IPs. Additionally R3 must do ECMP for both the routes")
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
next_hop_vrf = [
|
||||
topo["routers"]["r1"]["links"]["r3-link3"][addr_type].\
|
||||
split("/")[0],
|
||||
topo["routers"]["r1"]["links"]["r3-link3"][addr_type]. \
|
||||
split("/")[0]
|
||||
]
|
||||
static_routes = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": [NETWORK1_1[addr_type]],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = verify_bgp_rib(tgen, addr_type, "r3", static_routes,
|
||||
next_hop=next_hop_vrf)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
result = verify_rib(tgen, addr_type, "r3", static_routes,
|
||||
next_hop=next_hop_vrf)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_locally_imported_routes_selected_as_bestpath_over_ebgp_imported_routes_p0(request):
|
||||
"""
|
||||
Verify ECMP for imported routes from different VRFs.
|
||||
"""
|
||||
|
||||
tgen = get_topogen()
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
if tgen.routers_have_failure():
|
||||
check_router_status(tgen)
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
step("Configure same static routes on R2 and R3 vrfs and redistribute in BGP "
|
||||
"for GREEN and RED vrf instances")
|
||||
for dut, network in zip(["r2", "r3"], [
|
||||
[NETWORK1_1, NETWORK1_2], [NETWORK1_1, NETWORK1_2]]):
|
||||
for vrf_name, network_vrf in zip(["RED", "GREEN"], network):
|
||||
step("Configure static route for VRF : {} on {}".format(vrf_name,
|
||||
dut))
|
||||
for addr_type in ADDR_TYPES:
|
||||
static_routes = {
|
||||
dut: {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": [network_vrf[addr_type]],
|
||||
"next_hop": "blackhole",
|
||||
"vrf": vrf_name
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = create_static_routes(tgen, static_routes)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
for dut, as_num in zip(["r2", "r3"], ["2", "3"]):
|
||||
for vrf_name in ["RED", "GREEN"]:
|
||||
step("Redistribute static route on BGP VRF : {}".format(vrf_name))
|
||||
temp = {}
|
||||
for addr_type in ADDR_TYPES:
|
||||
temp.update({
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"redistribute": [{
|
||||
"redist_type": "static"
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
redist_dict = {dut: {"bgp": [{
|
||||
"vrf": vrf_name, "local_as": as_num, "address_family": temp
|
||||
}]}}
|
||||
|
||||
result = create_router_bgp(tgen, topo, redist_dict)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
step("Verify that R2 and R3 has installed redistributed routes in default "
|
||||
"and RED vrfs and GREEN respectively:")
|
||||
for dut, network in zip(["r2", "r3"],
|
||||
[[NETWORK1_1, NETWORK1_2],
|
||||
[NETWORK1_1, NETWORK1_2]]):
|
||||
for vrf_name, network_vrf in zip(["RED", "GREEN"], network):
|
||||
for addr_type in ADDR_TYPES:
|
||||
static_routes = {
|
||||
dut: {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": [network_vrf[addr_type]],
|
||||
"next_hop": "blackhole",
|
||||
"vrf": vrf_name
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = verify_bgp_rib(tgen, addr_type, dut, static_routes)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
step("Import vrf RED's route in vrf GREEN on R3")
|
||||
temp = {}
|
||||
for addr_type in ADDR_TYPES:
|
||||
temp.update({
|
||||
addr_type: {
|
||||
"unicast": {
|
||||
"import": {
|
||||
"vrf": "RED"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
import_dict = {"r3": {"bgp": [{
|
||||
"vrf": "GREEN", "local_as": 3, "address_family": temp
|
||||
}]}}
|
||||
|
||||
result = create_router_bgp(tgen, topo, import_dict)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
step("Verify that locally imported routes are installed over eBGP imported"
|
||||
" routes from VRF RED into VRF GREEN")
|
||||
for addr_type in ADDR_TYPES:
|
||||
static_routes = {
|
||||
"r3": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": [NETWORK1_2[addr_type]],
|
||||
"next_hop": "blackhole",
|
||||
"vrf": "GREEN"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
input_routes = {
|
||||
"r3": {
|
||||
addr_type: [
|
||||
{
|
||||
"network": NETWORK1_2[addr_type],
|
||||
"bestpath": BESTPATH[addr_type],
|
||||
"vrf": "GREEN"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
result = verify_bgp_bestpath(tgen, addr_type, input_routes)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
result = verify_rib(tgen, addr_type, "r3", static_routes)
|
||||
assert result is True, "Testcase {} : Failed \n Error {}". \
|
||||
format(tc_name, result)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
@ -989,6 +989,14 @@ def __create_bgp_unicast_address_family(
|
||||
if "no_allowas_in" in peer:
|
||||
allow_as_in = peer["no_allowas_in"]
|
||||
config_data.append("no {} allowas-in {}".format(neigh_cxt, allow_as_in))
|
||||
|
||||
if "shutdown" in peer:
|
||||
shut_val = peer["shutdown"]
|
||||
if shut_val is True:
|
||||
config_data.append("{} shutdown".format(neigh_cxt))
|
||||
elif shut_val is False:
|
||||
config_data.append("no {} shutdown".format(neigh_cxt))
|
||||
|
||||
if prefix_lists:
|
||||
for prefix_list in prefix_lists:
|
||||
name = prefix_list.setdefault("name", {})
|
||||
@ -2221,6 +2229,7 @@ def verify_bgp_attributes(
|
||||
rmap_name=None,
|
||||
input_dict=None,
|
||||
seq_id=None,
|
||||
vrf=None,
|
||||
nexthop=None,
|
||||
expected=True,
|
||||
):
|
||||
@ -2275,7 +2284,10 @@ def verify_bgp_attributes(
|
||||
logger.info("Verifying BGP set attributes for dut {}:".format(router))
|
||||
|
||||
for static_route in static_routes:
|
||||
cmd = "show bgp {} {} json".format(addr_type, static_route)
|
||||
if vrf:
|
||||
cmd = "show bgp vrf {} {} {} json".format(vrf, addr_type, static_route)
|
||||
else:
|
||||
cmd = "show bgp {} {} json".format(addr_type, static_route)
|
||||
show_bgp_json = run_frr_cmd(rnode, cmd, isjson=True)
|
||||
|
||||
dict_to_test = []
|
||||
@ -2821,7 +2833,6 @@ def verify_bgp_rib(
|
||||
st_rt,
|
||||
dut,
|
||||
)
|
||||
return errormsg
|
||||
else:
|
||||
nh_found = True
|
||||
|
||||
@ -4428,6 +4439,83 @@ def verify_evpn_routes(
|
||||
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@retry(retry_timeout=10)
|
||||
def verify_bgp_bestpath(tgen, addr_type, input_dict):
|
||||
"""
|
||||
Verifies bgp next hop values in best-path output
|
||||
|
||||
* `dut` : device under test
|
||||
* `addr_type` : Address type ipv4/ipv6
|
||||
* `input_dict`: having details like multipath and bestpath
|
||||
|
||||
Usage
|
||||
-----
|
||||
input_dict_1 = {
|
||||
"r1": {
|
||||
"ipv4" : {
|
||||
"bestpath": "50.0.0.1",
|
||||
"multipath": ["50.0.0.1", "50.0.0.2"],
|
||||
"network": "100.0.0.0/24"
|
||||
}
|
||||
"ipv6" : {
|
||||
"bestpath": "1000::1",
|
||||
"multipath": ["1000::1", "1000::2"]
|
||||
"network": "2000::1/128"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = verify_bgp_bestpath(tgen, input_dict)
|
||||
|
||||
"""
|
||||
|
||||
result = False
|
||||
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
|
||||
for dut in input_dict.keys():
|
||||
rnode = tgen.routers()[dut]
|
||||
|
||||
logger.info("[DUT: %s]: Verifying bgp bestpath and multipath " "routes:", dut)
|
||||
result = False
|
||||
for network_dict in input_dict[dut][addr_type]:
|
||||
nw_addr = network_dict.setdefault("network", None)
|
||||
vrf = network_dict.setdefault("vrf", None)
|
||||
bestpath = network_dict.setdefault("bestpath", None)
|
||||
|
||||
if vrf:
|
||||
cmd = "show bgp vrf {} {} {} bestpath json".format(
|
||||
vrf, addr_type, nw_addr
|
||||
)
|
||||
else:
|
||||
cmd = "show bgp {} {} bestpath json".format(addr_type, nw_addr)
|
||||
|
||||
data = run_frr_cmd(rnode, cmd, isjson=True)
|
||||
route = data["paths"][0]
|
||||
|
||||
if "bestpath" in route:
|
||||
if route["bestpath"]["overall"] is True:
|
||||
_bestpath = route["nexthops"][0]["ip"]
|
||||
|
||||
if _bestpath != bestpath:
|
||||
return (
|
||||
"DUT:[{}] Bestpath do not match for"
|
||||
" network: {}, Expected "
|
||||
" {} as bgp bestpath found {}".format(
|
||||
dut, nw_addr, bestpath, _bestpath
|
||||
)
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"DUT:[{}] Found expected bestpath: "
|
||||
" {} for network: {}".format(dut, _bestpath, nw_addr)
|
||||
)
|
||||
result = True
|
||||
|
||||
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
|
||||
return result
|
||||
|
||||
|
||||
def verify_tcp_mss(tgen, dut, neighbour, configured_tcp_mss, vrf=None):
|
||||
"""
|
||||
This api is used to verify the tcp-mss value assigned to a neigbour of DUT
|
||||
|
Loading…
Reference in New Issue
Block a user