Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 215 additions & 0 deletions tests/bgp/bgp_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import json
import pytest
import yaml
import random
import logging
import requests
from natsort import natsorted
Expand Down Expand Up @@ -45,6 +46,13 @@
ALLOW_LIST_PREFIX_JSON_FILE = '/tmp/allow_list.json'
DROP_COMMUNITY = ''
DEFAULT_ACTION = ''
ANNOUNCE = 'announce'
DEFAULT = "default"
IP_VER = 4
QUEUED = "queued"
ACTION_IN = "in"
ACTION_NOT_IN = "not"
ACTION_STOP = "stop"


def apply_bgp_config(duthost, template_name):
Expand Down Expand Up @@ -514,3 +522,210 @@ def get_default_action():
Since the value of this constant has been changed in the helper, it cannot be directly imported
"""
return DEFAULT_ACTION


def restart_bgp_session(duthost):
"""
Restart bgp session
"""
logging.info("Restart all BGP sessions")
duthost.shell('vtysh -c "clear bgp *"')


def get_ptf_recv_port(duthost, vm_name, tbinfo):
"""
Get ptf receive port
"""
port = duthost.shell("show lldp table | grep -w {} | awk '{{print $1}}'".format(vm_name))['stdout']
mg_facts = duthost.get_extended_minigraph_facts(tbinfo)
return mg_facts['minigraph_ptf_indices'][port]


def get_eth_port(duthost, tbinfo):
"""
Get ethernet port that connects to T0 VM
"""
mg_facts = duthost.get_extended_minigraph_facts(tbinfo)
t0_vm = [vm_name for vm_name in mg_facts['minigraph_devices'].keys() if vm_name.endswith('T0')][0]
port = duthost.shell("show ip interface | grep -w {} | awk '{{print $1}}'".format(t0_vm))['stdout']
return port


def get_vm_offset(duthost, nbrhosts, tbinfo):
"""
Get port offset of exabgp and ptf receive port
"""
logging.info("get_vm_offset ---------")
vm_name = random.choice([vm_name for vm_name in nbrhosts.keys() if vm_name.endswith('T0')])
ptf_recv_port = get_ptf_recv_port(duthost, vm_name, tbinfo)
port_offset = tbinfo['topo']['properties']['topology']['VMs'][vm_name]['vm_offset']
logging.info("vm_offset of {} is: {}".format(vm_name, port_offset))
return port_offset, ptf_recv_port


def get_exabgp_port(duthost, nbrhosts, tbinfo, exabgp_base_port):
"""
Get exabgp port and ptf receive port
"""
port_offset, ptf_recv_port = get_vm_offset(duthost, nbrhosts, tbinfo)
return exabgp_base_port + port_offset, ptf_recv_port


def get_vm_name(tbinfo, vm_level='T2'):
"""
Get vm name, default return value would be T2 VM name
"""
for vm in tbinfo['topo']['properties']['topology']['VMs'].keys():
if vm[-2:] == vm_level:
return vm


def get_t2_ptf_intfs(mg_facts):
"""
Get ptf interface list that connect with T2 VMs
"""
t2_ethernets = []
for k, v in mg_facts["minigraph_neighbors"].items():
if v['name'][-2:] == 'T2':
t2_ethernets.append(k)

ptf_interfaces = []
for port in t2_ethernets:
ptf_interfaces.append(mg_facts['minigraph_ptf_indices'][port])
return ptf_interfaces


def get_bgp_neighbor_ip(duthost, vm_name, vrf=DEFAULT):
"""
Get ipv4 and ipv6 bgp neighbor ip addresses
"""
if vrf == DEFAULT:
cmd_v4 = "show ip interface | grep -w {} | awk '{{print $5}}'"
cmd_v6 = "show ipv6 interface | grep -w {} | awk '{{print $5}}'"
bgp_neighbor_ip = duthost.shell(cmd_v4.format(vm_name))['stdout']
bgp_neighbor_ipv6 = duthost.shell(cmd_v6.format(vm_name))['stdout']
else:
cmd_v4 = "show ip interface | grep -w {} | awk '{{print $7}}' | sed 's/)//g'"
cmd_v6 = "show ipv6 interface | grep -w {} | awk '{{print $7}}' | sed 's/)//g'"
bgp_neighbor_ip = duthost.shell(cmd_v4.format(vm_name))['stdout'][1:-1]
bgp_neighbor_ipv6 = duthost.shell(cmd_v6.format(vm_name))['stdout'][1:-1]
logging.info("BGP neighbor of {} is {}".format(vm_name, bgp_neighbor_ip))
logging.info("IPv6 BGP neighbor of {} is {}".format(vm_name, bgp_neighbor_ipv6))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a function to get bgp neighbor ips, something like:
bgp_facts = duthost.bgp_facts()['ansible_facts']
bgp_facts['bgp_neighbors']

Would this method can be use in your case ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jcaiMR ,
Checked with this method, it could not list the bgp neighbors under user defined vrf:
(Pdb) duthost.bgp_facts()
Thursday 25 May 2023 12:56:05 +0300 (0:01:45.335) 0:24:46.708 **********
{u'invocation': {u'module_args': {u'instance_id': None, u'num_npus': 1}}, 'failed': False, 'changed': False, '_ansible_no_log': False, u'ansible_facts': {u'bgp_statistics': {u'ipv4_idle': 0, u'ipv6_idle': 0, u'ipv4_admin_down': 0, u'ipv6_admin_down': 0, u'ipv6': 0, u'ipv4': 0}, u'bgp_neighbors': {}}}

c-panther-01# show ip bgp vrf Vrf1 summary

IPv4 Unicast Summary (VRF Vrf1):
BGP router identifier 10.0.0.62, local AS number 65100 vrf-id 417
BGP table version 11346
RIB entries 12853, using 2310 KiB of memory
Peers 48, using 34 MiB of memory
Peer groups 2, using 128 bytes of memory

Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
10.0.0.1 4 65200 3262 78 0 0 0 00:03:38 6370 4 ARISTA01T2
10.0.0.5 4 65200 3262 79 0 0 0 00:03:38 6370 4 ARISTA03T2
10.0.0.9 4 65200 3262 79 0 0 0 00:03:39 6370 4 ARISTA05T2
10.0.0.13 4 65200 3262 78 0 0 0 00:03:37 6370 4 ARISTA07T2
10.0.0.17 4 65200 3262 78 0 0 0 00:03:38 6370 4 ARISTA09T2
10.0.0.21 4 65200 3262 81 0 0 0 00:03:37 6370 4 ARISTA11T2
10.0.0.25 4 65200 3262 78 0 0 0 00:03:38 6370 4 ARISTA13T2
10.0.0.29 4 65200 3262 78 0 0 0 00:03:38 6370 4 ARISTA15T2
10.0.0.33 4 64001 80 79 0 0 0 00:03:39 4 4 ARISTA01T0
10.0.0.35 4 64002 78 78 0 0 0 00:03:38 3 4 ARISTA02T0
10.0.0.37 4 64003 79 78 0 0 0 00:03:38 4 4 ARISTA03T0
10.0.0.39 4 64004 78 78 0 0 0 00:03:38 3 4 ARISTA04T0
10.0.0.41 4 64005 78 78 0 0 0 00:03:38 3 4 ARISTA05T0
10.0.0.43 4 64006 78 79 0 0 0 00:03:39 3 4 ARISTA06T0
10.0.0.45 4 64007 78 78 0 0 0 00:03:37 3 4 ARISTA07T0
10.0.0.47 4 64008 78 78 0 0 0 00:03:38 3 4 ARISTA08T0
10.0.0.49 4 64009 78 78 0 0 0 00:03:38 3 4 ARISTA09T0
10.0.0.51 4 64010 78 78 0 0 0 00:03:37 3 4 ARISTA10T0
10.0.0.53 4 64011 78 78 0 0 0 00:03:38 3 4 ARISTA11T0
10.0.0.55 4 64012 80 78 0 0 0 00:03:38 5 4 ARISTA12T0
10.0.0.57 4 64013 78 78 0 0 0 00:03:38 3 4 ARISTA13T0
10.0.0.59 4 64014 78 78 0 0 0 00:03:38 3 4 ARISTA14T0
10.0.0.61 4 64015 78 78 0 0 0 00:03:38 3 4 ARISTA15T0
10.0.0.63 4 64016 78 78 0 0 0 00:03:38 3 4 ARISTA16T0
fc00::2 4 65200 3260 129 0 0 0 00:03:30 NoNeg NoNeg ARISTA01T2
fc00::a 4 65200 3263 190 0 0 0 00:03:39 NoNeg NoNeg ARISTA03T2
fc00::12 4 65200 3260 129 0 0 0 00:03:30 NoNeg NoNeg ARISTA05T2
fc00::1a 4 65200 3260 129 0 0 0 00:03:31 NoNeg NoNeg ARISTA07T2
fc00::22 4 65200 3260 129 0 0 0 00:03:32 NoNeg NoNeg ARISTA09T2
fc00::2a 4 65200 3260 130 0 0 0 00:03:32 NoNeg NoNeg ARISTA11T2
fc00::32 4 65200 3260 129 0 0 0 00:03:31 NoNeg NoNeg ARISTA13T2
fc00::3a 4 65200 3262 189 0 0 0 00:03:38 NoNeg NoNeg ARISTA15T2
fc00::42 4 64001 75 123 0 0 0 00:03:28 NoNeg NoNeg ARISTA01T0
fc00::46 4 64002 76 129 0 0 0 00:03:30 NoNeg NoNeg ARISTA02T0
fc00::4a 4 64003 75 128 0 0 0 00:03:29 NoNeg NoNeg ARISTA03T0
fc00::4e 4 64004 75 128 0 0 0 00:03:29 NoNeg NoNeg ARISTA04T0
fc00::52 4 64005 75 128 0 0 0 00:03:29 NoNeg NoNeg ARISTA05T0
fc00::56 4 64006 75 123 0 0 0 00:03:28 NoNeg NoNeg ARISTA06T0
fc00::5a 4 64007 75 123 0 0 0 00:03:29 NoNeg NoNeg ARISTA07T0
fc00::5e 4 64008 75 128 0 0 0 00:03:29 NoNeg NoNeg ARISTA08T0
fc00::62 4 64009 76 129 0 0 0 00:03:30 NoNeg NoNeg ARISTA09T0
fc00::66 4 64010 75 123 0 0 0 00:03:29 NoNeg NoNeg ARISTA10T0
fc00::6a 4 64011 76 129 0 0 0 00:03:30 NoNeg NoNeg ARISTA11T0
fc00::6e 4 64012 75 128 0 0 0 00:03:29 NoNeg NoNeg ARISTA12T0
fc00::72 4 64013 75 128 0 0 0 00:03:29 NoNeg NoNeg ARISTA13T0
fc00::76 4 64014 76 129 0 0 0 00:03:30 NoNeg NoNeg ARISTA14T0
fc00::7a 4 64015 76 129 0 0 0 00:03:30 NoNeg NoNeg ARISTA15T0
fc00::7e 4 64016 76 129 0 0 0 00:03:30 NoNeg NoNeg ARISTA16T0

Total number of neighbors 48

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks for the information.

return bgp_neighbor_ip, bgp_neighbor_ipv6


def get_vrf_route_json(duthost, route, vrf=DEFAULT, ip_ver=IP_VER):
"""
Get output of 'show ip route vrf xxx xxx json' or 'show ipv6 route vrf xxx xxx json'
"""
if ip_ver == IP_VER:
logging.info('Execute command - vtysh -c "show ip route vrf {} {} json"'.format(vrf, route))
out = json.loads(duthost.shell('vtysh -c "show ip route vrf {} {} json"'.
format(vrf, route), verbose=False)['stdout'])
else:
logging.info('Execute command - vtysh -c "show ipv6 route vrf {} {} json"'.format(vrf, route))
out = json.loads(duthost.shell('vtysh -c "show ipv6 route vrf {} {} json"'.
format(vrf, route), verbose=False)['stdout'])

logging.info('Command output:\n {}'.format(out))
return out


def check_route_status(duthost, route, check_field, vrf=DEFAULT, ip_ver=IP_VER, expect_status=True):
"""
Get 'offloaded' or 'queu' value of specific route
"""
out = get_vrf_route_json(duthost, route, vrf, ip_ver)
check_field_status = out[route][0].get(check_field, None)
if check_field_status:
logging.info("Route:{} - {} status:{} - expect status:{}"
.format(route, check_field, check_field_status, expect_status))
return True is expect_status
else:
logging.info("No {} value found in route:{}".format(check_field, out))
return False is expect_status


def check_route_install_status(duthost, route, vrf=DEFAULT, ip_ver=IP_VER, check_point=QUEUED, action=ACTION_IN):
"""
Verify route install status
"""
if check_point == QUEUED:
if action == ACTION_IN:
pytest_assert(wait_until(60, 2, 0, check_route_status, duthost, route, check_point, vrf, ip_ver),
"Vrf:{} - route:{} is not in {} state".format(vrf, route, check_point))
else:
pytest_assert(wait_until(60, 2, 0, check_route_status, duthost, route, check_point, vrf, ip_ver, False),
"Vrf:{} - route:{} is in {} state".format(vrf, route, check_point))
else:
if action == ACTION_IN:
pytest_assert(wait_until(60, 2, 0, check_route_status, duthost, route, check_point, vrf, ip_ver),
"Vrf:{} - route:{} is not installed into FIB".format(vrf, route))
else:
pytest_assert(wait_until(60, 2, 0, check_route_status, duthost, route, check_point, vrf, ip_ver, False),
"Vrf:{} - route:{} is installed into FIB".format(vrf, route))


def check_propagate_route(duthost, route, bgp_neighbor, vrf=DEFAULT, ip_ver=IP_VER, action=ACTION_IN):
"""
Check whether ipv4 or ipv6 route is advertised to T2 VM
"""
if ip_ver == IP_VER:
logging.info('Execute command - vtysh -c "show ip bgp vrf {} neighbors {} advertised-routes"'
.format(vrf, bgp_neighbor))
out = duthost.shell('vtysh -c "show ip bgp vrf {} neighbors {} advertised-routes"'.format(vrf, bgp_neighbor),
verbose=False)['stdout']
else:
logging.info('Execute command - vtysh -c "show ip bgp vrf {} ipv6 neighbors {} advertised-routes"'
.format(vrf, bgp_neighbor))
out = duthost.shell('vtysh -c "show ip bgp vrf {} ipv6 neighbors {} advertised-routes"'.
format(vrf, bgp_neighbor), verbose=False)['stdout']
logging.debug('Command output:\n {}'.format(out))

if action == ACTION_IN:
if route in out:
logging.info("Route:{} found - action:{}".format(route, action))
return True
else:
logging.info("Route:{} not found - action:{}".format(route, action))
return False
else:
if route in out:
logging.info("Route:{} found - action:{}".format(route, action))
return False
else:
logging.info("Route:{} not found - action:{}".format(route, action))
return True


def validate_route_propagate_status(duthost, route, bgp_neighbor, vrf=DEFAULT, ip_ver=IP_VER, exist=True):
"""
Verify ipv4 or ipv6 route propagate status
:param duthost: duthost fixture
:param route: ipv4 or ipv6 route
:param bgp_neighbor: ipv4 or ipv6 bgp neighbor address
:param vrf: vrf name
:param ip_ver: ip version number
:param exist: route expected status
"""
if exist:
pytest_assert(wait_until(30, 2, 0, check_propagate_route, duthost, route, bgp_neighbor, vrf, ip_ver),
"Vrf:{} - route:{} is not propagated to {}".format(vrf, route, bgp_neighbor))
else:
pytest_assert(wait_until(30, 2, 0, check_propagate_route, duthost, route, bgp_neighbor, vrf, ip_ver,
ACTION_NOT_IN),
"Vrf:{} - route:{} is propagated to {}".format(vrf, route, bgp_neighbor))


def operate_orchagent(duthost, action=ACTION_STOP):
"""
Stop or Continue orchagent process
"""
if action == ACTION_STOP:
logging.info('Suspend orchagent process to simulate a delay')
cmd = 'sudo kill -SIGSTOP $(pidof orchagent)'
else:
logging.info('Recover orchagent process')
cmd = 'sudo kill -SIGCONT $(pidof orchagent)'
duthost.shell(cmd)
49 changes: 49 additions & 0 deletions tests/bgp/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,3 +596,52 @@ def bgpmon_setup_teardown(ptfhost, duthosts, enum_rand_one_per_hwsku_frontend_ho
# Remove the route to DUT loopback IP and the interface router mac
ptfhost.shell("ip route del %s" % dut_lo_addr + "/32")
ptfhost.shell("ip neigh flush to %s nud permanent" % dut_lo_addr)


def pytest_addoption(parser):
"""
Adds options to pytest that are used by bgp suppress fib pending test
"""

parser.addoption(
"--bgp_suppress_fib_pending",
action="store_true",
dest="bgp_suppress_fib_pending",
default=False,
help="enable bgp suppress fib pending function, by default it will not enable bgp suppress fib pending function"
)
parser.addoption(
"--bgp_suppress_fib_reboot_type",
action="store",
dest="bgp_suppress_fib_reboot_type",
type=str,
choices=["reload", "fast", "warm", "cold", "random"],
default="reload",
help="reboot type such as reload, fast, warm, cold, random"
)


@pytest.fixture(scope="module", autouse=True)
def config_bgp_suppress_fib(duthosts, rand_one_dut_hostname, request):
"""
Enable or disable bgp suppress-fib-pending function
"""
duthost = duthosts[rand_one_dut_hostname]
config = request.config.getoption("--bgp_suppress_fib_pending")
logger.info("--bgp_suppress_fib_pending:{}".format(config))

if config:
logger.info("Check if bgp suppress fib pending is supported")
res = duthost.command("show suppress-fib-pending", module_ignore_errors=True)
if res['rc'] != 0:
pytest.skip('BGP suppress fib pending function is not supported')
logger.info('Enable BGP suppress fib pending function')
duthost.shell('sudo config suppress-fib-pending enabled')
duthost.shell('sudo config save -y')

yield

if config:
logger.info('Disable BGP suppress fib pending function')
duthost.shell('sudo config suppress-fib-pending disabled')
duthost.shell('sudo config save -y')
Loading