mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-06-06 01:59:57 +00:00
bgpd: Add "bgp bestpath peer-type multipath-relax"
This new BGP configuration is akin to "bgp bestpath aspath multipath-relax". When applied, paths learned from different peer types will be eligible to be considered for multipath (ECMP). Paths from all of eBGP, iBGP, and confederation peers may be included in multipaths if they are otherwise equal cost. This change preserves the existing bestpath behavior of step 10's result being returned, not the result from steps 8 and 9, in the case where both 8+9 and 10 determine a winner. Signed-off-by: Joanne Mikkelson <jmmikkel@arista.com>
This commit is contained in:
parent
8baa41e571
commit
ee88563ac2
@ -565,6 +565,8 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
int internal_as_route;
|
||||
int confed_as_route;
|
||||
int ret = 0;
|
||||
int igp_metric_ret = 0;
|
||||
int peer_sort_ret = -1;
|
||||
char new_buf[PATH_ADDPATH_STR_BUFFER];
|
||||
char exist_buf[PATH_ADDPATH_STR_BUFFER];
|
||||
uint32_t new_mm_seq;
|
||||
@ -971,7 +973,9 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
zlog_debug(
|
||||
"%s: %s wins over %s due to eBGP peer > iBGP peer",
|
||||
pfx_buf, new_buf, exist_buf);
|
||||
if (!CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX))
|
||||
return 1;
|
||||
peer_sort_ret = 1;
|
||||
}
|
||||
|
||||
if (exist_sort == BGP_PEER_EBGP
|
||||
@ -981,7 +985,9 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
zlog_debug(
|
||||
"%s: %s loses to %s due to iBGP peer < eBGP peer",
|
||||
pfx_buf, new_buf, exist_buf);
|
||||
if (!CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX))
|
||||
return 0;
|
||||
peer_sort_ret = 0;
|
||||
}
|
||||
|
||||
/* 8. IGP metric check. */
|
||||
@ -993,19 +999,19 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
existm = exist->extra->igpmetric;
|
||||
|
||||
if (newm < existm) {
|
||||
if (debug)
|
||||
if (debug && peer_sort_ret < 0)
|
||||
zlog_debug(
|
||||
"%s: %s wins over %s due to IGP metric %u < %u",
|
||||
pfx_buf, new_buf, exist_buf, newm, existm);
|
||||
ret = 1;
|
||||
igp_metric_ret = 1;
|
||||
}
|
||||
|
||||
if (newm > existm) {
|
||||
if (debug)
|
||||
if (debug && peer_sort_ret < 0)
|
||||
zlog_debug(
|
||||
"%s: %s loses to %s due to IGP metric %u > %u",
|
||||
pfx_buf, new_buf, exist_buf, newm, existm);
|
||||
ret = 0;
|
||||
igp_metric_ret = 0;
|
||||
}
|
||||
|
||||
/* 9. Same IGP metric. Compare the cluster list length as
|
||||
@ -1023,21 +1029,21 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
existm = BGP_CLUSTER_LIST_LENGTH(exist->attr);
|
||||
|
||||
if (newm < existm) {
|
||||
if (debug)
|
||||
if (debug && peer_sort_ret < 0)
|
||||
zlog_debug(
|
||||
"%s: %s wins over %s due to CLUSTER_LIST length %u < %u",
|
||||
pfx_buf, new_buf, exist_buf,
|
||||
newm, existm);
|
||||
ret = 1;
|
||||
igp_metric_ret = 1;
|
||||
}
|
||||
|
||||
if (newm > existm) {
|
||||
if (debug)
|
||||
if (debug && peer_sort_ret < 0)
|
||||
zlog_debug(
|
||||
"%s: %s loses to %s due to CLUSTER_LIST length %u > %u",
|
||||
pfx_buf, new_buf, exist_buf,
|
||||
newm, existm);
|
||||
ret = 0;
|
||||
igp_metric_ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1051,7 +1057,10 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
zlog_debug(
|
||||
"%s: %s wins over %s due to confed-external peer > confed-internal peer",
|
||||
pfx_buf, new_buf, exist_buf);
|
||||
if (!CHECK_FLAG(bgp->flags,
|
||||
BGP_FLAG_PEERTYPE_MULTIPATH_RELAX))
|
||||
return 1;
|
||||
peer_sort_ret = 1;
|
||||
}
|
||||
|
||||
if (exist_sort == BGP_PEER_CONFED
|
||||
@ -1061,7 +1070,10 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
zlog_debug(
|
||||
"%s: %s loses to %s due to confed-internal peer < confed-external peer",
|
||||
pfx_buf, new_buf, exist_buf);
|
||||
if (!CHECK_FLAG(bgp->flags,
|
||||
BGP_FLAG_PEERTYPE_MULTIPATH_RELAX))
|
||||
return 0;
|
||||
peer_sort_ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1122,6 +1134,17 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
* TODO: If unequal cost ibgp multipath is enabled we can
|
||||
* mark the paths as equal here instead of returning
|
||||
*/
|
||||
|
||||
/* Prior to the addition of BGP_FLAG_PEERTYPE_MULTIPATH_RELAX,
|
||||
* if either step 7 or 10 (peer type checks) yielded a winner,
|
||||
* that result was returned immediately. Returning from step 10
|
||||
* ignored the return value computed in steps 8 and 9 (IGP
|
||||
* metric checks). In order to preserve that behavior, if
|
||||
* peer_sort_ret is set, return that rather than igp_metric_ret.
|
||||
*/
|
||||
ret = peer_sort_ret;
|
||||
if (peer_sort_ret < 0) {
|
||||
ret = igp_metric_ret;
|
||||
if (debug) {
|
||||
if (ret == 1)
|
||||
zlog_debug(
|
||||
@ -1133,9 +1156,18 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
|
||||
pfx_buf, new_buf, exist_buf);
|
||||
}
|
||||
*reason = bgp_path_selection_igp_metric;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, the decision whether to set *paths_eq = 1 has been
|
||||
* completed. If we deferred returning because of bestpath peer-type
|
||||
* relax configuration, return now.
|
||||
*/
|
||||
if (peer_sort_ret >= 0)
|
||||
return peer_sort_ret;
|
||||
|
||||
/* 12. If both paths are external, prefer the path that was received
|
||||
first (the oldest one). This step minimizes route-flap, since a
|
||||
newer path won't displace an older one, even if it was the
|
||||
|
@ -3571,6 +3571,37 @@ DEFUN_YANG (no_bgp_bestpath_aspath_multipath_relax,
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
/* "bgp bestpath peer-type multipath-relax" configuration. */
|
||||
DEFUN(bgp_bestpath_peer_type_multipath_relax,
|
||||
bgp_bestpath_peer_type_multipath_relax_cmd,
|
||||
"bgp bestpath peer-type multipath-relax",
|
||||
BGP_STR
|
||||
"Change the default bestpath selection\n"
|
||||
"Peer type\n"
|
||||
"Allow load sharing across routes learned from different peer types\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||
SET_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX);
|
||||
bgp_recalculate_all_bestpaths(bgp);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(no_bgp_bestpath_peer_type_multipath_relax,
|
||||
no_bgp_bestpath_peer_type_multipath_relax_cmd,
|
||||
"no bgp bestpath peer-type multipath-relax",
|
||||
NO_STR BGP_STR
|
||||
"Change the default bestpath selection\n"
|
||||
"Peer type\n"
|
||||
"Allow load sharing across routes learned from different peer types\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||
UNSET_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX);
|
||||
bgp_recalculate_all_bestpaths(bgp);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* "bgp log-neighbor-changes" configuration. */
|
||||
DEFUN_YANG(bgp_log_neighbor_changes,
|
||||
bgp_log_neighbor_changes_cmd,
|
||||
@ -10496,6 +10527,9 @@ static void bgp_show_bestpath_json(struct bgp *bgp, json_object *json)
|
||||
} else
|
||||
json_object_string_add(bestpath, "multiPathRelax", "false");
|
||||
|
||||
if (CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX))
|
||||
json_object_boolean_true_add(bestpath, "peerTypeRelax");
|
||||
|
||||
if (CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_ROUTER_ID))
|
||||
json_object_string_add(bestpath, "compareRouterId", "true");
|
||||
if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_CONFED)
|
||||
@ -17656,6 +17690,10 @@ int bgp_config_write(struct vty *vty)
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX))
|
||||
vty_out(vty,
|
||||
" bgp bestpath peer-type multipath-relax\n");
|
||||
|
||||
/* Link bandwidth handling. */
|
||||
if (bgp->lb_handling == BGP_LINK_BW_IGNORE_BW)
|
||||
vty_out(vty, " bgp bestpath bandwidth ignore\n");
|
||||
@ -18140,6 +18178,11 @@ void bgp_vty_init(void)
|
||||
install_element(BGP_NODE, &bgp_bestpath_aspath_multipath_relax_cmd);
|
||||
install_element(BGP_NODE, &no_bgp_bestpath_aspath_multipath_relax_cmd);
|
||||
|
||||
/* "bgp bestpath peer-type multipath-relax" commands */
|
||||
install_element(BGP_NODE, &bgp_bestpath_peer_type_multipath_relax_cmd);
|
||||
install_element(BGP_NODE,
|
||||
&no_bgp_bestpath_peer_type_multipath_relax_cmd);
|
||||
|
||||
/* "bgp log-neighbor-changes" commands */
|
||||
install_element(BGP_NODE, &bgp_log_neighbor_changes_cmd);
|
||||
install_element(BGP_NODE, &no_bgp_log_neighbor_changes_cmd);
|
||||
|
@ -478,6 +478,7 @@ struct bgp {
|
||||
#define BGP_FLAG_SUPPRESS_FIB_PENDING (1 << 28)
|
||||
#define BGP_FLAG_SUPPRESS_DUPLICATES (1 << 29)
|
||||
#define BGP_FLAG_DEFAULT_IPV6 (1 << 30)
|
||||
#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1 << 31)
|
||||
|
||||
enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE]
|
||||
[BGP_GLOBAL_GR_EVENT_CMD];
|
||||
|
@ -394,6 +394,13 @@ Route Selection
|
||||
other measures were taken to avoid these. The exact behaviour will be
|
||||
sensitive to the iBGP and reflection topology.
|
||||
|
||||
.. clicmd:: bgp bestpath peer-type multipath-relax
|
||||
|
||||
This command specifies that BGP decision process should consider paths
|
||||
from all peers for multipath computation. If this option is enabled,
|
||||
paths learned from any of eBGP, iBGP, or confederation neighbors will
|
||||
be multipath if they are otherwise considered equal cost.
|
||||
|
||||
.. _bgp-distance:
|
||||
|
||||
Administrative Distance Metrics
|
||||
|
53
tests/topotests/bgp_peer-type_multipath-relax/exabgp.env
Normal file
53
tests/topotests/bgp_peer-type_multipath-relax/exabgp.env
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
[exabgp.api]
|
||||
encoder = text
|
||||
highres = false
|
||||
respawn = false
|
||||
socket = ''
|
||||
|
||||
[exabgp.bgp]
|
||||
openwait = 60
|
||||
|
||||
[exabgp.cache]
|
||||
attributes = true
|
||||
nexthops = true
|
||||
|
||||
[exabgp.daemon]
|
||||
daemonize = true
|
||||
pid = '/var/run/exabgp/exabgp.pid'
|
||||
user = 'exabgp'
|
||||
|
||||
[exabgp.log]
|
||||
all = false
|
||||
configuration = true
|
||||
daemon = true
|
||||
destination = '/var/log/exabgp.log'
|
||||
enable = true
|
||||
level = INFO
|
||||
message = false
|
||||
network = true
|
||||
packets = false
|
||||
parser = false
|
||||
processes = true
|
||||
reactor = true
|
||||
rib = false
|
||||
routes = false
|
||||
short = false
|
||||
timers = false
|
||||
|
||||
[exabgp.pdb]
|
||||
enable = false
|
||||
|
||||
[exabgp.profile]
|
||||
enable = false
|
||||
file = ''
|
||||
|
||||
[exabgp.reactor]
|
||||
speed = 1.0
|
||||
|
||||
[exabgp.tcp]
|
||||
acl = false
|
||||
bind = ''
|
||||
delay = 0
|
||||
once = false
|
||||
port = 179
|
38
tests/topotests/bgp_peer-type_multipath-relax/peer1/exa-receive.py
Executable file
38
tests/topotests/bgp_peer-type_multipath-relax/peer1/exa-receive.py
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
exa-receive.py: Save received routes form ExaBGP into file
|
||||
"""
|
||||
|
||||
from sys import stdin, argv
|
||||
from datetime import datetime
|
||||
|
||||
# 1st arg is peer number
|
||||
peer = int(argv[1])
|
||||
|
||||
# When the parent dies we are seeing continual newlines, so we only access so many before stopping
|
||||
counter = 0
|
||||
|
||||
routesavefile = open("/tmp/peer%s-received.log" % peer, "w")
|
||||
|
||||
while True:
|
||||
try:
|
||||
line = stdin.readline()
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H:%M:%S - ")
|
||||
routesavefile.write(timestamp + line)
|
||||
routesavefile.flush()
|
||||
|
||||
if line == "":
|
||||
counter += 1
|
||||
if counter > 100:
|
||||
break
|
||||
continue
|
||||
|
||||
counter = 0
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except IOError:
|
||||
# most likely a signal during readline
|
||||
pass
|
||||
|
||||
routesavefile.close()
|
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
"Helper script to read api commands from a pipe and feed them to ExaBGP"
|
||||
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
sys.exit(1)
|
||||
fifo = sys.argv[1]
|
||||
|
||||
while True:
|
||||
pipe = open(fifo, "r")
|
||||
with pipe:
|
||||
line = pipe.readline().strip()
|
||||
if line != "":
|
||||
sys.stdout.write("{}\n".format(line))
|
||||
sys.stdout.flush()
|
||||
pipe.close()
|
||||
|
||||
sys.exit(0)
|
@ -0,0 +1,21 @@
|
||||
group controller {
|
||||
|
||||
process announce-routes {
|
||||
run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer1.in";
|
||||
encoder text;
|
||||
}
|
||||
|
||||
process receive-routes {
|
||||
run "/etc/exabgp/exa-receive.py 1";
|
||||
receive-routes;
|
||||
encoder text;
|
||||
}
|
||||
|
||||
neighbor 10.0.1.1 {
|
||||
router-id 10.0.1.2;
|
||||
local-address 10.0.1.2;
|
||||
local-as 64510;
|
||||
peer-as 64510;
|
||||
}
|
||||
|
||||
}
|
38
tests/topotests/bgp_peer-type_multipath-relax/peer2/exa-receive.py
Executable file
38
tests/topotests/bgp_peer-type_multipath-relax/peer2/exa-receive.py
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
exa-receive.py: Save received routes form ExaBGP into file
|
||||
"""
|
||||
|
||||
from sys import stdin, argv
|
||||
from datetime import datetime
|
||||
|
||||
# 1st arg is peer number
|
||||
peer = int(argv[1])
|
||||
|
||||
# When the parent dies we are seeing continual newlines, so we only access so many before stopping
|
||||
counter = 0
|
||||
|
||||
routesavefile = open("/tmp/peer%s-received.log" % peer, "w")
|
||||
|
||||
while True:
|
||||
try:
|
||||
line = stdin.readline()
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H:%M:%S - ")
|
||||
routesavefile.write(timestamp + line)
|
||||
routesavefile.flush()
|
||||
|
||||
if line == "":
|
||||
counter += 1
|
||||
if counter > 100:
|
||||
break
|
||||
continue
|
||||
|
||||
counter = 0
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except IOError:
|
||||
# most likely a signal during readline
|
||||
pass
|
||||
|
||||
routesavefile.close()
|
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
"Helper script to read api commands from a pipe and feed them to ExaBGP"
|
||||
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
sys.exit(1)
|
||||
fifo = sys.argv[1]
|
||||
|
||||
while True:
|
||||
pipe = open(fifo, "r")
|
||||
with pipe:
|
||||
line = pipe.readline().strip()
|
||||
if line != "":
|
||||
sys.stdout.write("{}\n".format(line))
|
||||
sys.stdout.flush()
|
||||
pipe.close()
|
||||
|
||||
sys.exit(0)
|
@ -0,0 +1,21 @@
|
||||
group controller {
|
||||
|
||||
process announce-routes {
|
||||
run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer2.in";
|
||||
encoder text;
|
||||
}
|
||||
|
||||
process receive-routes {
|
||||
run "/etc/exabgp/exa-receive.py 2";
|
||||
receive-routes;
|
||||
encoder text;
|
||||
}
|
||||
|
||||
neighbor 10.0.2.1 {
|
||||
router-id 10.0.2.2;
|
||||
local-address 10.0.2.2;
|
||||
local-as 64511;
|
||||
peer-as 64511;
|
||||
}
|
||||
|
||||
}
|
38
tests/topotests/bgp_peer-type_multipath-relax/peer3/exa-receive.py
Executable file
38
tests/topotests/bgp_peer-type_multipath-relax/peer3/exa-receive.py
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
exa-receive.py: Save received routes form ExaBGP into file
|
||||
"""
|
||||
|
||||
from sys import stdin, argv
|
||||
from datetime import datetime
|
||||
|
||||
# 1st arg is peer number
|
||||
peer = int(argv[1])
|
||||
|
||||
# When the parent dies we are seeing continual newlines, so we only access so many before stopping
|
||||
counter = 0
|
||||
|
||||
routesavefile = open("/tmp/peer%s-received.log" % peer, "w")
|
||||
|
||||
while True:
|
||||
try:
|
||||
line = stdin.readline()
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H:%M:%S - ")
|
||||
routesavefile.write(timestamp + line)
|
||||
routesavefile.flush()
|
||||
|
||||
if line == "":
|
||||
counter += 1
|
||||
if counter > 100:
|
||||
break
|
||||
continue
|
||||
|
||||
counter = 0
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except IOError:
|
||||
# most likely a signal during readline
|
||||
pass
|
||||
|
||||
routesavefile.close()
|
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
"Helper script to read api commands from a pipe and feed them to ExaBGP"
|
||||
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
sys.exit(1)
|
||||
fifo = sys.argv[1]
|
||||
|
||||
while True:
|
||||
pipe = open(fifo, "r")
|
||||
with pipe:
|
||||
line = pipe.readline().strip()
|
||||
if line != "":
|
||||
sys.stdout.write("{}\n".format(line))
|
||||
sys.stdout.flush()
|
||||
pipe.close()
|
||||
|
||||
sys.exit(0)
|
@ -0,0 +1,21 @@
|
||||
group controller {
|
||||
|
||||
process announce-routes {
|
||||
run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer3.in";
|
||||
encoder text;
|
||||
}
|
||||
|
||||
process receive-routes {
|
||||
run "/etc/exabgp/exa-receive.py 3";
|
||||
receive-routes;
|
||||
encoder text;
|
||||
}
|
||||
|
||||
neighbor 10.0.3.1 {
|
||||
router-id 10.0.3.2;
|
||||
local-address 10.0.3.2;
|
||||
local-as 64502;
|
||||
peer-as 64501;
|
||||
}
|
||||
|
||||
}
|
38
tests/topotests/bgp_peer-type_multipath-relax/peer4/exa-receive.py
Executable file
38
tests/topotests/bgp_peer-type_multipath-relax/peer4/exa-receive.py
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
exa-receive.py: Save received routes form ExaBGP into file
|
||||
"""
|
||||
|
||||
from sys import stdin, argv
|
||||
from datetime import datetime
|
||||
|
||||
# 1st arg is peer number
|
||||
peer = int(argv[1])
|
||||
|
||||
# When the parent dies we are seeing continual newlines, so we only access so many before stopping
|
||||
counter = 0
|
||||
|
||||
routesavefile = open("/tmp/peer%s-received.log" % peer, "w")
|
||||
|
||||
while True:
|
||||
try:
|
||||
line = stdin.readline()
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H:%M:%S - ")
|
||||
routesavefile.write(timestamp + line)
|
||||
routesavefile.flush()
|
||||
|
||||
if line == "":
|
||||
counter += 1
|
||||
if counter > 100:
|
||||
break
|
||||
continue
|
||||
|
||||
counter = 0
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except IOError:
|
||||
# most likely a signal during readline
|
||||
pass
|
||||
|
||||
routesavefile.close()
|
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
"Helper script to read api commands from a pipe and feed them to ExaBGP"
|
||||
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
sys.exit(1)
|
||||
fifo = sys.argv[1]
|
||||
|
||||
while True:
|
||||
pipe = open(fifo, "r")
|
||||
with pipe:
|
||||
line = pipe.readline().strip()
|
||||
if line != "":
|
||||
sys.stdout.write("{}\n".format(line))
|
||||
sys.stdout.flush()
|
||||
pipe.close()
|
||||
|
||||
sys.exit(0)
|
@ -0,0 +1,21 @@
|
||||
group controller {
|
||||
|
||||
process announce-routes {
|
||||
run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer4.in";
|
||||
encoder text;
|
||||
}
|
||||
|
||||
process receive-routes {
|
||||
run "/etc/exabgp/exa-receive.py 4";
|
||||
receive-routes;
|
||||
encoder text;
|
||||
}
|
||||
|
||||
neighbor 10.0.4.1 {
|
||||
router-id 10.0.4.2;
|
||||
local-address 10.0.4.2;
|
||||
local-as 64503;
|
||||
peer-as 64501;
|
||||
}
|
||||
|
||||
}
|
16
tests/topotests/bgp_peer-type_multipath-relax/r1/bgpd.conf
Normal file
16
tests/topotests/bgp_peer-type_multipath-relax/r1/bgpd.conf
Normal file
@ -0,0 +1,16 @@
|
||||
!
|
||||
router bgp 64510
|
||||
bgp router-id 10.0.1.1
|
||||
no bgp ebgp-requires-policy
|
||||
bgp confederation identifier 64501
|
||||
bgp confederation peers 64511
|
||||
bgp bestpath as-path multipath-relax
|
||||
bgp bestpath compare-routerid
|
||||
bgp bestpath peer-type multipath-relax
|
||||
neighbor 10.0.1.2 remote-as 64510
|
||||
neighbor 10.0.3.2 remote-as 64502
|
||||
neighbor 10.0.4.2 remote-as 64503
|
||||
neighbor 10.0.5.2 remote-as 64511
|
||||
!
|
||||
line vty
|
||||
!
|
@ -0,0 +1,50 @@
|
||||
{
|
||||
"routes": { "203.0.113.0/30": [
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"pathFrom":"external",
|
||||
"peerId":"10.0.5.2"
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"Peer Type",
|
||||
"pathFrom":"external",
|
||||
"peerId":"10.0.4.2"
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"pathFrom":"internal",
|
||||
"peerId":"10.0.1.2"
|
||||
}
|
||||
],"203.0.113.4/30": [
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"Confed Peer Type",
|
||||
"pathFrom":"external",
|
||||
"peerId":"10.0.5.2"
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"pathFrom":"internal",
|
||||
"peerId":"10.0.1.2"
|
||||
}
|
||||
],"203.0.113.8/30": [
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"pathFrom":"external",
|
||||
"peerId":"10.0.4.2"
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"Router ID",
|
||||
"pathFrom":"external",
|
||||
"peerId":"10.0.3.2"
|
||||
}
|
||||
] } }
|
@ -0,0 +1,50 @@
|
||||
{
|
||||
"routes": { "203.0.113.0/30": [
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":null,
|
||||
"pathFrom":"external",
|
||||
"peerId":"10.0.5.2"
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"Peer Type",
|
||||
"pathFrom":"external",
|
||||
"peerId":"10.0.4.2"
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":null,
|
||||
"pathFrom":"internal",
|
||||
"peerId":"10.0.1.2"
|
||||
}
|
||||
],"203.0.113.4/30": [
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"Confed Peer Type",
|
||||
"pathFrom":"external",
|
||||
"peerId":"10.0.5.2"
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":null,
|
||||
"pathFrom":"internal",
|
||||
"peerId":"10.0.1.2"
|
||||
}
|
||||
],"203.0.113.8/30": [
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"pathFrom":"external",
|
||||
"peerId":"10.0.4.2"
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"bestpath":true,
|
||||
"selectionReason":"Router ID",
|
||||
"pathFrom":"external",
|
||||
"peerId":"10.0.3.2"
|
||||
}
|
||||
] } }
|
@ -0,0 +1,33 @@
|
||||
{
|
||||
"203.0.113.0\/30":[
|
||||
{
|
||||
"prefix":"203.0.113.0\/30",
|
||||
"protocol":"bgp",
|
||||
"installed":true,
|
||||
"internalNextHopNum":4,
|
||||
"internalNextHopActiveNum":4,
|
||||
"nexthops":[
|
||||
{
|
||||
"ip":"198.51.100.2",
|
||||
"active":true,
|
||||
"recursive":true
|
||||
},
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.3.2",
|
||||
"active":true
|
||||
},
|
||||
{
|
||||
"ip":"198.51.100.10",
|
||||
"active":true,
|
||||
"recursive":true
|
||||
},
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.3.2",
|
||||
"active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
{
|
||||
"203.0.113.0\/30":[
|
||||
{
|
||||
"prefix":"203.0.113.0\/30",
|
||||
"protocol":"bgp",
|
||||
"installed":true,
|
||||
"internalNextHopNum":4,
|
||||
"internalNextHopActiveNum":4,
|
||||
"nexthops":[
|
||||
{
|
||||
"ip":"198.51.100.1",
|
||||
"active":true,
|
||||
"recursive":true
|
||||
},
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.3.2",
|
||||
"active":true
|
||||
},
|
||||
{
|
||||
"ip":"198.51.100.10",
|
||||
"active":true,
|
||||
"recursive":true
|
||||
},
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.3.2",
|
||||
"active":true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
{
|
||||
"prefix":"203.0.113.0\/30",
|
||||
"paths":[
|
||||
{
|
||||
"valid":false,
|
||||
"peer":{
|
||||
"peerId":"10.0.4.2",
|
||||
"routerId":"10.0.4.2",
|
||||
"type":"external"
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"bestpath":{
|
||||
"overall":true,
|
||||
"selectionReason":"Confed Peer Type"
|
||||
},
|
||||
"peer":{
|
||||
"peerId":"10.0.5.2",
|
||||
"routerId":"10.0.5.2",
|
||||
"type":"confed-external"
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"peer":{
|
||||
"peerId":"10.0.1.2",
|
||||
"routerId":"10.0.1.2",
|
||||
"type":"confed-internal"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
{
|
||||
"prefix":"203.0.113.0\/30",
|
||||
"paths":[
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"bestpath":{
|
||||
"overall":true,
|
||||
"selectionReason":"Peer Type"
|
||||
},
|
||||
"peer":{
|
||||
"peerId":"10.0.4.2",
|
||||
"routerId":"10.0.4.2",
|
||||
"type":"external"
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"peer":{
|
||||
"peerId":"10.0.5.2",
|
||||
"routerId":"10.0.5.2",
|
||||
"type":"confed-external"
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"peer":{
|
||||
"peerId":"10.0.1.2",
|
||||
"routerId":"10.0.1.2",
|
||||
"type":"confed-internal"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
{
|
||||
"prefix":"203.0.113.0\/30",
|
||||
"paths":[
|
||||
{
|
||||
"multipath":true,
|
||||
"peer":{
|
||||
"peerId":"10.0.5.2",
|
||||
"routerId":"10.0.5.2",
|
||||
"type":"confed-external"
|
||||
}
|
||||
},
|
||||
{
|
||||
"multipath":true,
|
||||
"bestpath":{
|
||||
"overall":true,
|
||||
"selectionReason":"Peer Type"
|
||||
},
|
||||
"peer":{
|
||||
"peerId":"10.0.4.2",
|
||||
"routerId":"10.0.4.2",
|
||||
"type":"external"
|
||||
}
|
||||
},
|
||||
{
|
||||
"multipath":true,
|
||||
"peer":{
|
||||
"peerId":"10.0.1.2",
|
||||
"routerId":"10.0.1.2",
|
||||
"type":"confed-internal"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"203.0.113.8\/30":[
|
||||
{
|
||||
"prefix":"203.0.113.8\/30",
|
||||
"protocol":"bgp",
|
||||
"installed":true,
|
||||
"internalNextHopNum":2,
|
||||
"internalNextHopActiveNum":1,
|
||||
"nexthops":[
|
||||
{
|
||||
"fib":true,
|
||||
"ip":"10.0.3.2",
|
||||
"active":true
|
||||
},
|
||||
{
|
||||
"fib":null,
|
||||
"ip":"198.51.100.10",
|
||||
"active":null
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"prefix":"203.0.113.8\/30",
|
||||
"paths":[
|
||||
{
|
||||
"valid":false,
|
||||
"peer":{
|
||||
"peerId":"10.0.4.2",
|
||||
"routerId":"10.0.4.2",
|
||||
"type":"external"
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"peer":{
|
||||
"peerId":"10.0.3.2",
|
||||
"routerId":"10.0.3.2",
|
||||
"type":"external"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"prefix":"203.0.113.8\/30",
|
||||
"paths":[
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"peer":{
|
||||
"peerId":"10.0.4.2",
|
||||
"routerId":"10.0.4.2",
|
||||
"type":"external"
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid":true,
|
||||
"multipath":true,
|
||||
"peer":{
|
||||
"peerId":"10.0.3.2",
|
||||
"routerId":"10.0.3.2",
|
||||
"type":"external"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
27
tests/topotests/bgp_peer-type_multipath-relax/r1/zebra.conf
Normal file
27
tests/topotests/bgp_peer-type_multipath-relax/r1/zebra.conf
Normal file
@ -0,0 +1,27 @@
|
||||
!
|
||||
hostname r1
|
||||
!
|
||||
interface r1-eth0
|
||||
description ExaBGP iBGP peer1
|
||||
ip address 10.0.1.1/24
|
||||
no link-detect
|
||||
!
|
||||
interface r1-eth1
|
||||
description ExaBGP peer3
|
||||
ip address 10.0.3.1/24
|
||||
no link-detect
|
||||
!
|
||||
interface r1-eth2
|
||||
description ExaBGP peer4
|
||||
ip address 10.0.4.1/24
|
||||
no link-detect
|
||||
!
|
||||
interface r1-eth3
|
||||
description r2 confed peer
|
||||
ip address 10.0.5.1/24
|
||||
no link-detect
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
19
tests/topotests/bgp_peer-type_multipath-relax/r2/bgpd.conf
Normal file
19
tests/topotests/bgp_peer-type_multipath-relax/r2/bgpd.conf
Normal file
@ -0,0 +1,19 @@
|
||||
!
|
||||
!log file bgpd.log
|
||||
!
|
||||
router bgp 64511
|
||||
bgp confederation identifier 64501
|
||||
bgp confederation peers 64510
|
||||
bgp router-id 10.0.5.2
|
||||
no bgp ebgp-requires-policy
|
||||
neighbor 10.0.2.2 remote-as 64511
|
||||
neighbor 10.0.5.1 remote-as 64510
|
||||
!
|
||||
address-family ipv4 unicast
|
||||
neighbor 10.0.5.1 route-map dropall in
|
||||
exit-address-family
|
||||
!
|
||||
route-map dropall deny 10
|
||||
!
|
||||
line vty
|
||||
!
|
@ -0,0 +1,4 @@
|
||||
hostname r2
|
||||
!
|
||||
ip route 198.51.100.0/24 10.0.2.2
|
||||
!
|
19
tests/topotests/bgp_peer-type_multipath-relax/r2/zebra.conf
Normal file
19
tests/topotests/bgp_peer-type_multipath-relax/r2/zebra.conf
Normal file
@ -0,0 +1,19 @@
|
||||
!
|
||||
!
|
||||
hostname r2
|
||||
!
|
||||
interface r2-eth0
|
||||
description ExaBGP peer
|
||||
ip address 10.0.2.1/24
|
||||
no link-detect
|
||||
!
|
||||
interface r2-eth1
|
||||
description r1 confed peer
|
||||
ip address 10.0.5.2/24
|
||||
no link-detect
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
!
|
||||
line vty
|
||||
!
|
@ -0,0 +1,258 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Part of NetDEF Topology Tests
|
||||
#
|
||||
# Copyright (c) 2021 Arista Networks, Inc.
|
||||
#
|
||||
# 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 Arista Networks DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
"""
|
||||
test_bgp_peer-type_multipath-relax.py:
|
||||
|
||||
Test the effects of the "bgp bestpath peer-type multipath-relax" command
|
||||
|
||||
- enabling the command allows eBGP, iBGP, and confed routes to be multipath
|
||||
- the choice of best path is not affected
|
||||
- disabling the command removes iBGP/confed routes from multipath
|
||||
|
||||
Topology used by the test:
|
||||
|
||||
eBGP +------+ iBGP
|
||||
peer1 ---- | r1 | ---- peer3
|
||||
| |
|
||||
peer2 ---- r2 ---- | | ---- peer4
|
||||
iBGP confed +------+ eBGP
|
||||
|
||||
r2 is present in this topology because ExaBGP does not currently support
|
||||
confederations so we use FRR to advertise the required AS_CONFED_SEQUENCE.
|
||||
|
||||
Routes are advertised from different peers to form interesting multipaths.
|
||||
|
||||
peer1 peer2 peer3 peer4 multipath on r1
|
||||
|
||||
203.0.113.0/30 x x x all 3
|
||||
203.0.113.4/30 x x confed-iBGP
|
||||
203.0.113.8/30 x x eBGP-only
|
||||
|
||||
There is also a BGP-advertised route used only for recursively resolving
|
||||
next hops.
|
||||
"""
|
||||
|
||||
import functools
|
||||
import json
|
||||
import os
|
||||
import pytest
|
||||
import sys
|
||||
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, "../"))
|
||||
|
||||
# pylint: disable=C0413
|
||||
from lib import topotest
|
||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||
from lib.topolog import logger
|
||||
from mininet.topo import Topo
|
||||
|
||||
|
||||
class PeerTypeRelaxTopo(Topo):
|
||||
def build(self, *_args, **_opts):
|
||||
"Build function"
|
||||
tgen = get_topogen(self)
|
||||
|
||||
# Set up routers
|
||||
tgen.add_router("r1") # DUT
|
||||
tgen.add_router("r2")
|
||||
|
||||
# Set up peers
|
||||
for peern in range(1, 5):
|
||||
peer = tgen.add_exabgp_peer(
|
||||
"peer{}".format(peern),
|
||||
ip="10.0.{}.2/24".format(peern),
|
||||
defaultRoute="via 10.0.{}.1".format(peern),
|
||||
)
|
||||
if peern == 2:
|
||||
tgen.add_link(tgen.gears["r2"], peer)
|
||||
else:
|
||||
tgen.add_link(tgen.gears["r1"], peer)
|
||||
tgen.add_link(tgen.gears["r1"], tgen.gears["r2"])
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
"Sets up the pytest environment"
|
||||
tgen = Topogen(PeerTypeRelaxTopo, mod.__name__)
|
||||
tgen.start_topology()
|
||||
|
||||
# For all registered routers, load the zebra configuration file
|
||||
for rname, router in tgen.routers().items():
|
||||
router.run("/bin/bash {}/setup_vrfs".format(CWD))
|
||||
router.load_config(
|
||||
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
|
||||
)
|
||||
router.load_config(
|
||||
TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname))
|
||||
)
|
||||
router.load_config(
|
||||
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
|
||||
)
|
||||
|
||||
# After loading the configurations, this function loads configured daemons.
|
||||
tgen.start_router()
|
||||
|
||||
# Start up exabgp peers
|
||||
peers = tgen.exabgp_peers()
|
||||
for peer in peers:
|
||||
fifo_in = "/var/run/exabgp_{}.in".format(peer)
|
||||
if os.path.exists(fifo_in):
|
||||
os.remove(fifo_in)
|
||||
os.mkfifo(fifo_in, 0o777)
|
||||
logger.info("Starting ExaBGP on peer {}".format(peer))
|
||||
peer_dir = os.path.join(CWD, peer)
|
||||
env_file = os.path.join(CWD, "exabgp.env")
|
||||
peers[peer].start(peer_dir, env_file)
|
||||
|
||||
|
||||
def teardown_module(mod):
|
||||
"Teardown the pytest environment"
|
||||
tgen = get_topogen()
|
||||
|
||||
# This function tears down the whole topology.
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def test_bgp_peer_type_multipath_relax():
|
||||
tgen = get_topogen()
|
||||
|
||||
# Don't run this test if we have any failure.
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
def exabgp_cmd(peer, cmd):
|
||||
pipe = open("/run/exabgp_{}.in".format(peer), "w")
|
||||
with pipe:
|
||||
pipe.write(cmd)
|
||||
pipe.close()
|
||||
|
||||
# Prefixes used in the test
|
||||
prefix1 = "203.0.113.0/30"
|
||||
prefix2 = "203.0.113.4/30"
|
||||
prefix3 = "203.0.113.8/30"
|
||||
# Next hops used for iBGP/confed routes
|
||||
resolved_nh1 = "198.51.100.1"
|
||||
resolved_nh2 = "198.51.100.2"
|
||||
# BGP route used for recursive resolution
|
||||
bgp_resolving_prefix = "198.51.100.0/24"
|
||||
# Next hop that will require non-connected recursive resolution
|
||||
ebgp_resolved_nh = "198.51.100.10"
|
||||
|
||||
# Send a non-connected route to resolve others
|
||||
exabgp_cmd(
|
||||
"peer3", "announce route {} next-hop self\n".format(bgp_resolving_prefix)
|
||||
)
|
||||
router = tgen.gears["r1"]
|
||||
|
||||
# It seems that if you write to the exabgp socket too quickly in
|
||||
# succession, requests get lost. So verify prefix1 now instead of
|
||||
# after all the prefixes are advertised.
|
||||
logger.info("Create and verify mixed-type multipaths")
|
||||
exabgp_cmd(
|
||||
"peer1",
|
||||
"announce route {} next-hop {} as-path [ 64499 ]\n".format(
|
||||
prefix1, resolved_nh1
|
||||
),
|
||||
)
|
||||
exabgp_cmd(
|
||||
"peer2",
|
||||
"announce route {} next-hop {} as-path [ 64499 ]\n".format(
|
||||
prefix1, resolved_nh2
|
||||
),
|
||||
)
|
||||
exabgp_cmd("peer4", "announce route {} next-hop self\n".format(prefix1))
|
||||
reffile = os.path.join(CWD, "r1/prefix1.json")
|
||||
expected = json.loads(open(reffile).read())
|
||||
test_func = functools.partial(
|
||||
topotest.router_json_cmp,
|
||||
router,
|
||||
"show ip bgp {} json".format(prefix1),
|
||||
expected,
|
||||
)
|
||||
_, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
|
||||
assertMsg = "Mixed-type multipath not found"
|
||||
assert res is None, assertMsg
|
||||
|
||||
logger.info("Create and verify eBGP and iBGP+confed multipaths")
|
||||
exabgp_cmd(
|
||||
"peer1",
|
||||
"announce route {} next-hop {} as-path [ 64499 ]\n".format(
|
||||
prefix2, resolved_nh1
|
||||
),
|
||||
)
|
||||
exabgp_cmd(
|
||||
"peer2",
|
||||
"announce route {} next-hop {} as-path [ 64499 ]\n".format(
|
||||
prefix2, resolved_nh2
|
||||
),
|
||||
)
|
||||
exabgp_cmd("peer3", "announce route {} next-hop self".format(prefix3))
|
||||
exabgp_cmd("peer4", "announce route {} next-hop self".format(prefix3))
|
||||
reffile = os.path.join(CWD, "r1/multipath.json")
|
||||
expected = json.loads(open(reffile).read())
|
||||
test_func = functools.partial(
|
||||
topotest.router_json_cmp, router, "show ip bgp json", expected
|
||||
)
|
||||
_, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
|
||||
assertMsg = "Not all expected multipaths found"
|
||||
assert res is None, assertMsg
|
||||
|
||||
logger.info("Toggle peer-type multipath-relax and verify the changes")
|
||||
router.vtysh_cmd(
|
||||
"conf\n router bgp 64510\n no bgp bestpath peer-type multipath-relax\n"
|
||||
)
|
||||
# This file verifies "multipath" is not set
|
||||
reffile = os.path.join(CWD, "r1/not-multipath.json")
|
||||
expected = json.loads(open(reffile).read())
|
||||
test_func = functools.partial(
|
||||
topotest.router_json_cmp, router, "show ip bgp json", expected
|
||||
)
|
||||
_, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
|
||||
assertMsg = "Disabling peer-type multipath-relax did not take effect"
|
||||
assert res is None, assertMsg
|
||||
|
||||
router.vtysh_cmd(
|
||||
"conf\n router bgp 64510\n bgp bestpath peer-type multipath-relax\n"
|
||||
)
|
||||
reffile = os.path.join(CWD, "r1/multipath.json")
|
||||
expected = json.loads(open(reffile).read())
|
||||
test_func = functools.partial(
|
||||
topotest.router_json_cmp, router, "show ip bgp json", expected
|
||||
)
|
||||
_, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
|
||||
assertMsg = "Reenabling peer-type multipath-relax did not take effect"
|
||||
assert res is None, assertMsg
|
||||
|
||||
|
||||
def test_memory_leak():
|
||||
"Run the memory leak test and report results."
|
||||
tgen = get_topogen()
|
||||
if not tgen.is_memleak_enabled():
|
||||
pytest.skip("Memory leak test/report is disabled")
|
||||
|
||||
tgen.report_memory_leaks()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
Loading…
Reference in New Issue
Block a user