Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding bgp_test for DPDP convergence case #1

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
101 changes: 100 additions & 1 deletion tests/common/ixia/ixia_fixtures.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from tests.common.ixia.common_helpers import get_vlan_subnet, get_addrs_in_subnet,\
get_peer_ixia_chassis
from tests.common.ixia.ixia_helpers import IxiaFanoutManager, get_tgen_location

import snappi
try:
from abstract_open_traffic_generator.port import Port
from abstract_open_traffic_generator.config import Options, Config
Expand Down Expand Up @@ -294,3 +294,102 @@ def ixia_testbed(conn_graph_facts,
config.devices.append(device)

return config

@pytest.fixture(scope = "module")
def ixia_api_serv_ip(tbinfo):
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
"""
In an Ixia testbed, there is no PTF docker.
Hence, we use ptf_ip field to store Ixia API server.
This fixture returns the IP address of the Ixia API server.
Args:
tbinfo (pytest fixture): fixture provides information about testbed
Returns:
Ixia API server IP
"""
return tbinfo['ptf_ip']

@pytest.fixture(scope = "module")
def ixia_api_serv_port(duthosts, rand_one_dut_hostname):
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
"""
This fixture returns the TCP port for REST API of the ixia API server.
Args:
duthost (pytest fixture): The duthost fixture.
Returns:
Ixia API server REST port.
"""
duthost = duthosts[rand_one_dut_hostname]
return duthost.host.options['variable_manager']._hostvars[duthost.hostname]['secret_group_vars']['ixia_api_server']['rest_port']

@pytest.fixture(scope='module')
def snappi_api(ixia_api_serv_ip,
ixia_api_serv_port):
"""
Snappi session fixture for snappi Tgen API
Args:
ixia_api_serv_ip (pytest fixture): ixia_api_serv_ip fixture
ixia_api_serv_port (pytest fixture): ixia_api_serv_port fixture.
"""
host = "https://" + str(ixia_api_serv_ip) + ":" + str(ixia_api_serv_port)
api = snappi.api(host=host, ext="ixnetwork")
yield api
if api.assistant is not None:
api.assistant.Session.remove()


@pytest.fixture(scope="function")
def tgen_ports(duthost,conn_graph_facts,fanout_graph_facts):
"""
Populate tgen ports info of T0 testbed and returns as a list
Args:
duthost (pytest fixture): duthost fixture
conn_graph_facts (pytest fixture): connection graph
fanout_graph_facts (pytest fixture): fanout graph
Return:
[{'card_id': '1',
'ip': '21.1.1.2',
'location': '10.36.78.238;1;2',
'prefix': u'24',
'peer_ip': u'21.1.1.1',
'peer_device': 'example-s6100-dut-1',
'peer_port': 'Ethernet0',
'port_id': '2',
'speed': '400000'},
{'card_id': '1',
'ip': '22.1.1.2',
'location': '10.36.78.238;1;1',
'prefix': u'24',
'peer_ip': u'22.1.1.1',
'peer_device': 'example-s6100-dut-1',
'peer_port': 'Ethernet8',
'port_id': '1',
'speed': '400000'}]
"""
speed_type = {'50000': 'speed_50_gbps',
'100000': 'speed_100_gbps',
'200000': 'speed_200_gbps',
'400000': 'speed_400_gbps'}
ixia_fanout = get_peer_ixia_chassis(conn_data=conn_graph_facts,dut_hostname=duthost.hostname)
ixia_fanout_id = list(fanout_graph_facts.keys()).index(ixia_fanout)
ixia_fanout_list = IxiaFanoutManager(fanout_graph_facts)
ixia_fanout_list.get_fanout_device_details(device_number=ixia_fanout_id)
ixia_ports = ixia_fanout_list.get_ports(peer_device=duthost.hostname)
port_speed = None
for i in range(len(ixia_ports)):
if port_speed is None:
port_speed = int(ixia_ports[i]['speed'])
elif port_speed != int(ixia_ports[i]['speed']):
""" All the ports should have the same bandwidth """
return None
config_facts = duthost.config_facts(host=duthost.hostname,source="running")['ansible_facts']
for port in ixia_ports:
port['location'] = get_tgen_location(port)
port['speed'] = speed_type[port['speed']]
for port in ixia_ports:
peer_port = port['peer_port']
subnet = config_facts['INTERFACE'][peer_port].keys()[0]
if not subnet:
raise Exception("IP is not configured on the interface {}".format(peer_port))
port['peer_ip'], port['prefix'] = subnet.split("/")
port['ip'] = get_addrs_in_subnet(subnet, 1)[0]
return ixia_ports

255 changes: 255 additions & 0 deletions tests/ixia/bgp/helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
import pytest
import time
from tabulate import tabulate
from statistics import mean
from tests.common.utilities import wait_until
logger = logging.getLogger(__name__)

DUT_AS_NUM = 65100
TGEN_AS_NUM = 65200
BGP_TYPE = 'ebgp'

def run_bgp_convergence_test(snappi_api,duthost,tgen_ports):
"""
Run BGP Convergence test
Args:
snappi_api (pytest fixture): Snappi API
duthost (pytest fixture): duthost fixture
tgen_ports (pytest fixture): Ports mapping info of T0 testbed
"""
port_count=len(tgen_ports)

# Create bgp config on dut
duthost_bgp_config(duthost,tgen_ports,port_count)

# Create bgp config on TGEN
tgen_bgp_config=__tgen_bgp_config(snappi_api,tgen_ports,port_count)

#Run the convergence test by flapping all the rx links and calculate the convergence values
tgen_getConvergenceTime(snappi_api,tgen_bgp_config)
selldinesh marked this conversation as resolved.
Show resolved Hide resolved

# Cleanup the dut configs after getting the convergence numbers
cleanup_config(duthost,tgen_ports,port_count)


def duthost_bgp_config(duthost,tgen_ports,port_count):
"""
Configures BGP on the DUT with N-1 ecmp
Args:
duthost (pytest fixture): duthost fixture
tgen_ports (pytest fixture): Ports mapping info of T0 testbed
port_count:len(tgen_ports)
"""
MPATH=port_count-1
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
for i in range(0,port_count):
intf_config = (
"vtysh "
"-c 'configure terminal' "
"-c 'interface %s' "
"-c 'ip address %s/%s' "
)
intf_config %= (tgen_ports[i]['peer_port'],tgen_ports[i]['peer_ip'],tgen_ports[i]['prefix'])
duthost.shell(intf_config)
bgp_config = (
"vtysh "
"-c 'configure terminal' "
"-c 'router bgp %s' "
"-c 'bgp bestpath as-path multipath-relax' "
"-c 'maximum-paths %s' "
"-c 'exit' "
)
bgp_config %= (DUT_AS_NUM,MPATH)
duthost.shell(bgp_config)
for i in range(0,port_count):
bgp_config_neighbor = (
"vtysh "
"-c 'configure terminal' "
"-c 'router bgp %s' "
"-c 'neighbor %s remote-as %s' "
"-c 'address-family ipv4 unicast' "
"-c 'neighbor %s activate' "
"-c 'exit' "
)
bgp_config_neighbor %= (DUT_AS_NUM,tgen_ports[i]['ip'],TGEN_AS_NUM,tgen_ports[i]['ip'])
logger.info('Configuring BGP Neighbor %s' %tgen_ports[i]['ip'])
duthost.shell(bgp_config_neighbor)


def __tgen_bgp_config(snappi_api,tgen_ports,port_count):
"""
Creating BGP config on TGEN
Args:
snappi_api (pytest fixture): Snappi API
tgen_ports (pytest fixture): Ports mapping info of T0 testbed
port_count:len(tgen_ports)
"""
config = snappi_api.config()
for i in range(1,port_count+1):
config.ports.port(name='Test Port %d'%i,location=tgen_ports[i-1]['location'])
config.devices.device(name='Topology %d'%i,container_name=config.ports[i-1].name,device_count=1)

config.options.port_options.location_preemption = True
for i in range(1,port_count+1):
layer1 = config.layer1.layer1()[-1]
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
layer1.name = '%s port settings'%config.ports[i-1].name
layer1.port_names = [config.ports[i-1].name]
layer1.ieee_media_defaults = False
layer1.auto_negotiation.rs_fec = False
layer1.auto_negotiation.link_training = False
layer1.speed= "speed_100_gbps"
layer1.auto_negotiate = False

def createTopo():
config.devices[0].ethernet.name='Ethernet 1'
config.devices[0].ethernet.ipv4.name='IPv4 1'
config.devices[0].ethernet.ipv4.address.value=tgen_ports[0]['ip']
config.devices[0].ethernet.ipv4.gateway.value=tgen_ports[0]['peer_ip']
config.devices[0].ethernet.ipv4.prefix.value=24
rx_flow_name=[]
for i in range(2,port_count+1):
Ethernet=config.devices[i-1].ethernet
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
Ethernet.name='Ethernet %d'%i
IPv4=Ethernet.ipv4
IPv4.name='IPv4 %d'%i
IPv4.address.value=tgen_ports[i-1]['ip']
IPv4.gateway.value=tgen_ports[i-1]['peer_ip']
IPv4.prefix.value=31
BGPv4=IPv4.bgpv4
BGPv4.name='BGP %d'%i
BGPv4.as_type=BGP_TYPE
BGPv4.dut_ipv4_address.value=tgen_ports[i-1]['peer_ip']
BGPv4.as_number.value=TGEN_AS_NUM
RouteRange=BGPv4.bgpv4_route_ranges.bgpv4routerange()[-1]
RouteRange.name="Network Group %d"%i
RouteRange.address_count="1000"
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
RouteRange.address.value="200.1.0.1"
RouteRange.prefix.value="32"
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
rx_flow_name.append(RouteRange.name)
return rx_flow_name

rx_flows=createTopo()
flow = config.flows.flow(name='convergence_test')[-1]
flow.tx_rx.device.tx_names = [config.devices[0].name]
flow.tx_rx.device.rx_names = rx_flows
flow.size.fixed = "1024"
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
flow.rate.percentage = "100"
snappi_api.set_config(config)
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
return config

def tgen_getConvergenceTime(snappi_api,config):
rx_port_names=[]
snappi_api.set_config(config)
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
for i in range(1,len(config.ports)):
rx_port_names.append(config.ports[i].name)

def get_flow_stats(snappi_api):
"""
Args:
snappi_api (pytest fixture): Snappi API
"""
request = snappi_api.metrics_request()
request.flow.flow_names = []
return snappi_api.get_metrics(request).flow_metrics

def is_port_rx_stopped(snappi_api, port_name):
"""
Returns true if port is down
"""
req = snappi_api.metrics_request()
req.port.port_names = [port_name]
port_stats = snappi_api.get_metrics(req).port_metrics
if int(port_stats[0].frames_rx_rate) == 0:
return True
return False

def getAvgDPDPConvergenceTime(portName,iter):
table,avg=[],[]
for i in range(0,iter):
logger.info('|---- {} Link Flap Iteration : {} ----|'.format(portName,i+1))

#Start Traffic
logger.info('Starting Traffic')
ts = snappi_api.transmit_state()
ts.state = ts.START
response=snappi_api.set_transmit_state(ts)
assert(len(response.errors)) == 0
time.sleep(30)
flow_stats=get_flow_stats(snappi_api)
tx_frame_rate = flow_stats[0].frames_tx_rate
assert tx_frame_rate != 0

#Link Flap
logger.info('Simulating Link Failure on {} link'.format(portName))
ls = snappi_api.link_state()
ls.port_names = [portName]
ls.state = ls.DOWN
response=snappi_api.set_link_state(ls)
assert(len(response.errors)) == 0
time.sleep(15)
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
assert is_port_rx_stopped(snappi_api,portName) == True
flow_stats=get_flow_stats(snappi_api)
tx_frame_rate = flow_stats[0].frames_tx_rate
assert tx_frame_rate != 0
logger.info(tx_frame_rate)

# Stop traffic
logger.info('Stopping Traffic')
ts = snappi_api.transmit_state()
ts.state = ts.STOP
response=snappi_api.set_transmit_state(ts)
assert(len(response.errors)) == 0
time.sleep(5)
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
flow_stats=get_flow_stats(snappi_api)
tx_frames = flow_stats[0].frames_tx
rx_frames = sum([fs.frames_rx for fs in flow_stats])

# Calculate DPDP Convergence
dp_convergence = (tx_frames - rx_frames) * 1000 / tx_frame_rate
logger.info("DP/DP Convergence Time: {} ms".format(int(dp_convergence)))
avg.append(int(dp_convergence))
logger.info('Simulating Link Up on {} at the end of iteration {}'.format(portName,i+1))

#Link up at the end of iteration
ls.state = ls.UP
response=snappi_api.set_link_state(ls)
assert(len(response.errors)) == 0
table.append('%s Link Failure'%portName)
table.append(iter)
table.append(mean(avg))
return table
table=[]
flap_iterations=1
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
#Iterating link flap test on all the rx ports
#flap_iterations can be modified as per preference
for i in range(0,len(rx_port_names)):
table.append(getAvgDPDPConvergenceTime(rx_port_names[i],flap_iterations))
columns=['Event Name','Iterations','Avg Calculated DP/DP Convergence Time(ms)']
logger.info("\n%s" % tabulate(table,headers=columns,tablefmt="psql"))

def cleanup_config(duthost,tgen_ports,port_count):
"""
Cleaning up dut config at the end of the test
Args:
snappi_api (pytest fixture): Snappi API
selldinesh marked this conversation as resolved.
Show resolved Hide resolved
duthost (pytest fixture): duthost fixture
tgen_ports (pytest fixture): Ports mapping info of T0 testbed
port_count:len(tgen_ports)
"""
logger.info('Cleaning Up Interface and BGP config')
bgp_config_cleanup = (
"vtysh "
"-c 'configure terminal' "
"-c 'no router bgp %s' "
)
bgp_config_cleanup %= (DUT_AS_NUM)
duthost.shell(bgp_config_cleanup)
for i in range(0,port_count):
intf_config_cleanup = (
"vtysh "
"-c 'configure terminal' "
"-c 'interface %s' "
"-c 'no ip address %s/%s' "
)
intf_config_cleanup %= (tgen_ports[i]['peer_port'],tgen_ports[i]['peer_ip'],tgen_ports[i]['prefix'])
duthost.shell(intf_config_cleanup)
logger.info('Convergence Test Completed')
Loading