From 8e73e0f7146d83d91aaa0cecf98e2765087f565b Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 25 Jun 2021 17:51:47 +0000 Subject: [PATCH 01/58] Adding BGP Benchmark testplan and test scripts --- ...ence-Testplan-for-Benchmark-Performance.md | 180 ++++++ docs/testplan/Img/Local_Link_Failure.png | Bin 0 -> 41025 bytes tests/ixia/bgp/files/__init__.py | 0 .../ixia/bgp/files/bgp_convergence_helper.py | 559 ++++++++++++++++++ .../ixia/bgp/test_bgp_local_link_failover.py | 56 ++ .../ixia/bgp/test_bgp_remote_link_failover.py | 55 ++ tests/ixia/bgp/test_bgp_rib_in_convergence.py | 55 ++ 7 files changed, 905 insertions(+) create mode 100644 docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md create mode 100644 docs/testplan/Img/Local_Link_Failure.png create mode 100644 tests/ixia/bgp/files/__init__.py create mode 100644 tests/ixia/bgp/files/bgp_convergence_helper.py create mode 100644 tests/ixia/bgp/test_bgp_local_link_failover.py create mode 100755 tests/ixia/bgp/test_bgp_remote_link_failover.py create mode 100644 tests/ixia/bgp/test_bgp_rib_in_convergence.py diff --git a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md new file mode 100644 index 00000000000..a2fca62157f --- /dev/null +++ b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md @@ -0,0 +1,180 @@ +# BGP convergence test plan for benchmark performance + +- [BGP convergence test plan for benchmark performance](#bgp-convergence-test-plan-for-benchmark-performance) + - [Overview](#Overview) + - [Scope](#Scope) + - [Testbed](#Keysight-Testbed) + - [Topology](#Topology) + - [SONiC switch as ToR](#SONiC-switch-as-ToR) + - [SONiC switch as Leaf](#SONiC-switch-as-Leaf) + - [Setup configuration](#Setup-configuration) + - [Test methodology](#Test-methodology) + - [Test cases](#Test-cases) + - [Test case # 1 – Convergence performance when remote link fails (route withdraw)](#test-case--1--convergence-performance-when-remote-link-fails-route-withdraw) + - [Test objective](#Test-objective) + - [Test steps](#Test-steps) + - [Test results](#Test-results) + - [Test case # 2 – RIB-IN Convergence](#Test-case--2--RIB-IN-Convergence) + - [Test objective](#Test-objective-1) + - [Test steps](#Test-steps-1) + - [Test results](#Test-results-1) + - [Test case # 3 - Failover convergence with local link failure](#Test-case--3--Failover-convergence-with-local-link-failure) + - [Test objective](#Test-objective-2) + - [Test steps](#Test-steps-2) + - [Test results](#Test-results-2) + - [Call for action](#Call-for-action) + +## Overview +The purpose of these tests is to test the overall convergence of a data center network by simulating multiple network devices such as ToR/Leafs and using SONiC switch DUT as one of the ToR/Leaf, closely resembling production environment. + +### Scope +These tests are targeted on fully functioning SONiC system. The purpose of these tests are to measure convergence when some unexpected failures such as remote link failure, local link failure, node failure or link faults etc occur and some expected failures such as maintenance or upgrade of devices occur in the SONiC system. + +### Keysight Testbed +The tests will run on following testbeds: +* t0 + +![Single DUT Topology ](Img/Single_DUT_Topology.png) + +## Topology +### SONiC switch as ToR + +![SONiC DUT as ToR ](Img/Switch_as_ToR.png) + +### SONiC switch as Leaf + +![SONiC DUT as ToR ](Img/Switch_acting_as_leaf.png) + +## Setup configuration +IPv4 EBGP neighborship will be configured between SONiC DUT and directly connected test ports. Test ports inturn will simulate the ToR's and Leafs by advertising IPv4/IPv6, dual-stack routes. + +## Test Methodology +Following test methodologies will be used for measuring convergence. +* Traffic generator will be used to configure ebgp peering between chassis ports and SONiC DUT by advertising IPv4/IPv6, dual-stack routes. +* Receiving ports will be advertising the same VIP(virtual IP) addresses. +* Data traffic will be sent from server to these VIP addresses. +* Depending on the test case, the faults will be generated. Local link failures can be simulated on the port by "simulating link down" event. +* Remote link failures can be simulated by withdrawing the routes. +* Control to data plane convergence will be measured by noting down the precise time of the control plane event and the data plane event. Convergence will be measured by taking the difference between contol and data plane events. Traffic generator will create those events and provide us with the control to data plane convergence value under statistics. +* RIB-IN Convergence is the time it takes to install the routes in its RIB and then in its FIB to forward the traffic without any loss. In order to measure RIB-IN convergence, initially IPv4/IPv6 routes will not be advertised. Once traffic is sent, IPv4/IPv6 routes will be advertised and the timestamp will be noted. Once the traffic received rate goes above the configured threshold value, it will note down the data plane above threshold timestamp. The difference between these two event timestamps will provide us with the RIB-IN convergence value. +* Route capacity can be measured by advertising routes in a linear search fashion. By doing this we can figure out the maximum routes a switch can learn and install in its RIB and then in its FIB to forward traffic without any loss. + +## Test cases +### Test case # 1 – Convergence performance when remote link fails (route withdraw) +#### Test objective +Measure the convergence time when remote link failure event happens with in the network. + +

+ + +

+ + +#### Test steps +* Configure IPv4 EBGP sessions between Keysight ports and the SONiC switch. +* Advertise IPv4 routes along with AS number via configured IPv4 BGP sessions. +* Configure and advertise same IPv4 routes from both the test ports. +* Configure another IPv4 session to send the traffic. This is the server port from which traffic will be sent to the VIP addresses. +* Start all protocols and verify that IPv4 BGP neighborship is established. +* Create a data traffic between the server port and receiver ports where the same VIP addresses are configured and enable tracking by "Destination Endpoint" and by "Destination session description". +* Set the desired threshold value for receiving traffic. By default we will be set to 90% of expected receiving rate. +* Apply and start the data traffic. +* Verify that traffic is equally distributed between the receiving ports without any loss. +* Simulate remote link failure by withdrawing the routes from one receiving port. +* Verify that the traffic is re-balanced and use the other available path to route the traffic. +* Drill down by "Destination Endpoint" under traffic statistics to get the control plane to data plane convergence value. +* In general the convergence value will fall in certain range. In order to achieve proper results, run the test multiple times and average out the test results. +* Set it back to default configuration. +#### Test results +| Event | Number Of IPv4 Routes | Convergence (ms) | +| :---: | :-: | :-: | +| Withdraw Routes | 1K | 388 | +| Withdraw Routes | 8K | 2870 | +| Withdraw Routes | 16K | 6188 | + +For above test case, below are the test results when multiple remote link fails. + +![Multiple link failure](Img/Multi_link_failure.png) + +| Event | Number Of IPv4 Routes | Convergence (ms) | +| :---: | :-: | :-: | +| Withdraw Routes | 1K | 438 | +| Withdraw Routes | 8K | 2800 | +| Withdraw Routes | 16K | 7176 | + +### Test case # 2 – RIB-IN Convergence +#### Test objective +Measure the convergence time to install the routes in its RIB and then in its FIB to forward the packets after the routes are advertised. + +

+ + +

+ +#### Test steps +* Configure IPv4 EBGP sessions between Keysight ports and the SONiC switch. +* Configure IPv4 routes via configured IPv4 BGP sessions. Initially disable the routes so that they don't get advertised after starting the protocols. +* Configure the same IPv4 routes from both the test receiving ports. +* Configure another IPv4 session to send the traffic. This is the server port from which traffic will be sent to the VIP addresses. +* Start all protocols and verify that IPv4 BGP neighborship is established. +* Create a data traffic between the server port and receiver ports where the same VIP addresses are configured and enable tracking by "Destination Endpoint" and by "Destination session description". +* Set the desired threshold value for receiving traffic. By default we will be set to 90% of expected receiving rate. +* Apply and start the data traffic. +* Verify that no traffic is being forwarded. +* Enable/advertise the routes which are already configured. +* Control plane event timestamp will be noted down and once the receiving traffic rate goes above the configured threshold value, it will note down the data plane threshold timestamp. +* The difference between these two event timestamp will provide us with the RIB-IN convergence time. +* In general the convergence value will fall in certain range. In order to achieve proper results, run the test multiple times and average out the test results. +* Set it back to default configuration. +#### Test results +| Event | Number Of IPv4 Routes | Convergence (ms) | +| :---: | :-: | :-: | +| Advertise Routes | 1K | 493 | +| Advertise Routes | 8K | 2953 | +| Advertise Routes | 64K | 28301 | +| Advertise Routes | 98K | 43109 | +| Advertise Routes | 196K | 90615 | + +In order to measure RIB-IN capacity of the switch, we can follow the same test methodology as RIB-IN convergence test. Below are the results for RIB-IN capacity test. + +| Event | Number Of IPv4 Routes | Convergence (ms) | Loss % | +| :---: | :-: | :-: | :-: | +| Advertise Routes | 256K | - | 25 | +| Advertise Routes | 198K | - | 0.50 | +| Advertise Routes | 196K | 85079 | 0 | +| Advertise Routes | 195K | 84487 | 0 | +| Advertise Routes | 194K | 83285 | 0 | + +### Test case # 3 - Failover convergence with local link failure +#### Test objective +Measure the convergence time when local link failure event happens with in the network. +

+ +

+ +#### Test steps +* Configure IPv4 EBGP sessions between Keysight ports and the SONiC switch. +* Advertise IPv4 routes along with AS number via configured IPv4 BGP sessions. +* Configure and advertise same IPv4 routes from both the test ports. +* Configure another IPv4 session to send the traffic. This is the server port from which traffic will be sent to the VIP addresses. +* Start all protocols and verify that IPv4 BGP neighborship is established. +* Create a data traffic between the server port and receiver ports where the same VIP addresses are configured and enable tracking by "Destination Endpoint" and by "Destination session description". +* Set the desired threshold value for receiving traffic. By default it will be set to 95% of expected receiving rate. +* Apply and start the data traffic. +* Verify that traffic is equally distributed between the receiving ports without any loss. +* Simulate local link failure by making port down on test tool. +* Verify that the traffic is re-balanced and use the other available path to route the traffic. +* Compute the failover convergence by the below formula +* Data Convergence Time(seconds) = (Tx Frames - Rx Frames) / Tx Frame Rate + +### Test Results +Below table is the result of 3 way ECMP for 4 link flap iterations +| Event Name | Iterations | Avg Calculated Data Convergence Time(ms) | +| :---: | :-: | :-: | +| Test_Port_2 Link Failure | 4 | 26.75 | +| Test_Port_3 Link Failure | 4 | 55 | +| Test_Port_4 Link Failure | 4 | 43 | + +### Call for action +* Solicit experience in multi-DUT system test scenarios. + diff --git a/docs/testplan/Img/Local_Link_Failure.png b/docs/testplan/Img/Local_Link_Failure.png new file mode 100644 index 0000000000000000000000000000000000000000..46195803622c7c250d8d74ae6eb7ee066ff95b1f GIT binary patch literal 41025 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 literal 0 HcmV?d00001 diff --git a/tests/ixia/bgp/files/__init__.py b/tests/ixia/bgp/files/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py new file mode 100644 index 00000000000..bc7b1cf026a --- /dev/null +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -0,0 +1,559 @@ +import pytest +import time +from tabulate import tabulate +from statistics import mean +from tests.common.utilities import wait +from tests.common.helpers.assertions import pytest_assert +logger = logging.getLogger(__name__) + +DUT_AS_NUM = 65100 +TGEN_AS_NUM = 65200 +TIMEOUT = 30 +BGP_TYPE = 'ebgp' +MAX_DP_CONVERGENCE = 100 +MAX_CPDP_CONVERGENCE = 3 +MAX_RIBIN_CONVERGENCE = 3 +def run_bgp_local_link_failover_test(cvg_api, + duthost, + tgen_ports, + iteration, + multipath, + number_of_ipv4_routes): + """ + Run BGP Convergence test + + Args: + cvg_api (pytest fixture): snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + iteration: number of iterations for running convergence test on a port + multipath: ecmp value for BGP config + number_of_ipv4_routes: Number of IPV4 Routes + """ + port_count = multipath+1 + # Create bgp config on dut + duthost_bgp_config(duthost, + tgen_ports, + port_count, + multipath) + + # Create bgp config on TGEN + tgen_bgp_config = __tgen_bgp_config(cvg_api, + tgen_ports, + port_count, + number_of_ipv4_routes) + + # Run the convergence test by flapping all the rx links one by one and calculate the convergence values + get_convergence_for_local_link_failover(cvg_api, + tgen_bgp_config, + iteration, + multipath, + number_of_ipv4_routes) + + # Cleanup the dut configs after getting the convergence numbers + cleanup_config(duthost, + tgen_ports, + port_count) + +def run_bgp_remote_link_failover_test(cvg_api, + duthost, + tgen_ports, + iteration, + multipath, + number_of_ipv4_routes): + """ + Run BGP Convergence test + + Args: + cvg_api (pytest fixture): snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + iteration: number of iterations for running convergence test on a port + multipath: ecmp value for BGP config + number_of_ipv4_routes: Number of IPV4 Routes + """ + port_count = multipath+1 + # Create bgp config on dut + duthost_bgp_config(duthost, + tgen_ports, + port_count, + multipath) + + # Create bgp config on TGEN + tgen_bgp_config = __tgen_bgp_config(cvg_api, + tgen_ports, + port_count, + number_of_ipv4_routes) + + # Run the convergence test by flapping all the rx links one by one and calculate the convergence values + get_convergence_for_remote_link_failover(cvg_api, + tgen_bgp_config, + iteration, + multipath, + number_of_ipv4_routes) + + # Cleanup the dut configs after getting the convergence numbers + cleanup_config(duthost, + tgen_ports, + port_count) + +def run_RIB_IN_convergence_test(cvg_api, + duthost, + tgen_ports, + iteration, + multipath, + number_of_ipv4_routes): + """ + Run BGP Convergence test + + Args: + cvg_api (pytest fixture): snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + iteration: number of iterations for running convergence test on a port + multipath: ecmp value for BGP config + number_of_ipv4_routes: Number of IPV4 Routes + """ + port_count = multipath+1 + # Create bgp config on dut + duthost_bgp_config(duthost, + tgen_ports, + port_count, + multipath) + + # Create bgp config on TGEN + tgen_bgp_config = __tgen_bgp_config(cvg_api, + tgen_ports, + port_count, + number_of_ipv4_routes) + + # Run the convergence test by flapping all the rx links one by one and calculate the convergence values + get_RIB_IN_convergence(cvg_api, + tgen_bgp_config, + iteration, + multipath, + number_of_ipv4_routes) + + # 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, + multipath): + """ + 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:multipath + 1 + multipath: ECMP value for BGP config + """ + 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']) + logger.info('Configuring IP Address %s' %tgen_ports[i]['ip']) + 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,multipath) + duthost.shell(bgp_config) + for i in range(1,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(cvg_api, + tgen_ports, + port_count, + number_of_ipv4_routes): + """ + Creating BGP config on TGEN + + Args: + cvg_api (pytest fixture): snappi API + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + port_count: multipath + 1 + number_of_ipv4_routes: Number of IPV4 Routes + """ + conv_config = cvg_api.convergence_config() + config = conv_config.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) + config.devices[i-1].container_name = config.ports[i-1].name + + config.options.port_options.location_preemption = True + layer1 = config.layer1.layer1()[-1] + layer1.name = 'port settings' + layer1.port_names = [port.name for port in config.ports] + layer1.ieee_media_defaults = False + layer1.auto_negotiation.rs_fec = True + layer1.auto_negotiation.link_training = False + layer1.speed = "speed_100_gbps" + layer1.auto_negotiate = False + + def create_topo(): + config.devices[0].ethernet.name = 'Ethernet 1' + config.devices[0].ethernet.ipv4.name = 'IPv4 1' + config.devices[0].ethernet.ipv4.address = tgen_ports[0]['ip'] + config.devices[0].ethernet.ipv4.gateway = tgen_ports[0]['peer_ip'] + config.devices[0].ethernet.ipv4.prefix = int(tgen_ports[0]['prefix']) + rx_flow_name = [] + for i in range(2,port_count+1): + ethernet_stack = config.devices[i-1].ethernet + ethernet_stack.name = 'Ethernet %d'%i + ipv4_stack = ethernet_stack.ipv4 + ipv4_stack.name = 'IPv4 %d'%i + ipv4_stack.address = tgen_ports[i-1]['ip'] + ipv4_stack.gateway = tgen_ports[i-1]['peer_ip'] + ipv4_stack.prefix = tgen_ports[i-1]['prefix'] + bgpv4_stack = ipv4_stack.bgpv4 + bgpv4_stack.name = 'BGP %d'%i + bgpv4_stack.as_type = BGP_TYPE + bgpv4_stack.dut_address = tgen_ports[i-1]['peer_ip'] + bgpv4_stack.as_number = int(TGEN_AS_NUM) + route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name = "Network Group %d"%i)[-1] + route_range.addresses.bgpv4routeaddress(address = '200.1.0.1', prefix = 32, count = number_of_ipv4_routes, step = 1) + rx_flow_name.append(route_range.name) + return rx_flow_name + + rx_flows = create_topo() + 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 + flow.rate.percentage = 100 + flow.metrics.enable = True + return conv_config,config,rx_flows + +def get_flow_stats(cvg_api): + """ + Args: + cvg_api (pytest fixture): Snappi API + """ + request = cvg_api.convergence_request() + request.metrics.flow_names = [] + return cvg_api.get_results(request).flow_metric + +def get_convergence_for_local_link_failover(cvg_api, + bgp_config, + iteration, + multipath, + number_of_ipv4_routes): + """ + Args: + cvg_api (pytest fixture): snappi API + bgp_config: __tgen_bgp_config + config: TGEN config + iteration: number of iterations for running convergence test on a port + number_of_ipv4_routes: Number of IPV4 Routes + """ + conv_config = bgp_config[0] + config = bgp_config[1] + rx_port_names = [] + conv_config.convergence_event = (conv_config.LINK_UP_DOWN) + cvg_api.set_config(conv_config) + for i in range(1,len(config.ports)): + rx_port_names.append(config.ports[i].name) + + def get_avg_dpdp_convergence_time(port_name, + rx_port_names): + """ + Args: + port_name: Name of the port + rx_port_names:List of rx port names + """ + + table,avg,tx_frate,rx_frate = [],[],[],[] + for i in range(0,iteration): + logger.info('|---- {} Link Flap Iteration : {} ----|'.format(port_name,i+1)) + + #Start Traffic + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT,"For Traffic To start") + flow_stats = get_flow_stats(cvg_api) + tx_frame_rate = flow_stats[0].frames_tx_rate + assert tx_frame_rate != 0,"Traffic has not started" + + #Link Flap + logger.info('Simulating Link Failure on {} link'.format(port_name)) + cs = cvg_api.convergence_state() + cs.link.port_names = [port_name] + cs.link.state = cs.link.DOWN + cvg_api.set_state(cs) + wait(TIMEOUT,"For Link to go down") + flows = get_flow_stats(cvg_api) + for flow in flows: + tx_frate.append(flow.frames_tx_rate) + rx_frate.append(flow.frames_tx_rate) + assert sum(tx_frate) == sum(rx_frate),"Traffic has not converged after link flap: TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate),sum(rx_frate)) + logger.info("Traffic has converged after link flap") + tx_frame_rate = flow_stats[0].frames_tx_rate + + # Stop traffic + logger.info('Stopping Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.STOP + cvg_api.set_state(cs) + wait(TIMEOUT,"For Traffic To Stop") + flow_stats = get_flow_stats(cvg_api) + assert flow_stats[0].frames_tx_rate == 0 + 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 Convergence Time: {} ms".format(int(dp_convergence))) + avg.append(int(dp_convergence)) + logger.info(dp_convergence) + assert dp_convergence < MAX_DP_CONVERGENCE,"DP Convergence is greater than 100 ms" + logger.info('Simulating Link Up on {} at the end of iteration {}'.format(port_name,i+1)) + + #Performing link up at the end of iteration + cs = cvg_api.convergence_state() + cs.link.port_names = [port_name] + cs.link.state = cs.link.UP + cvg_api.set_state(cs) + table.append('%s Link Failure'%port_name) + table.append(number_of_ipv4_routes) + table.append(iteration) + table.append(mean(avg)) + return table + table = [] + #Iterating link flap test on all the rx ports + for i,port_name in enumerate(rx_port_names): + table.append(get_avg_dpdp_convergence_time(port_name,rx_port_names)) + + columns = ['Event Name','No. of IPV4 Routes','Iterations','Avg Calculated Data Convergence Time (ms)'] + logger.info("\n%s" % tabulate(table,headers = columns,tablefmt = "psql")) + +def get_convergence_for_remote_link_failover(cvg_api, + bgp_config, + iteration, + multipath, + number_of_ipv4_routes): + """ + Args: + cvg_api (pytest fixture): snappi API + bgp_config: __tgen_bgp_config + config: TGEN config + iteration: number of iterations for running convergence test on a port + number_of_ipv4_routes: Number of IPV4 Routes + """ + route_names = [] + conv_config = bgp_config[0] + for device in bgp_config[1].devices: + if device.name not in ['Topology 1']: + for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: + route_names.append(route.name) + conv_config = bgp_config[0] + conv_config.rx_rate_threshold = 90/(multipath-1) + conv_config.convergence_event = (conv_config.ROUTE_ADVERTISE_WITHDRAW) + cvg_api.set_config(conv_config) + + + def get_avg_cpdp_convergence_time(route_name): + """ + Args: + route_name: name of the route + + """ + table,avg,tx_frate,rx_frate = [],[],[],[] + for i in range(0,iteration): + logger.info('|---- {} Route Withdraw Iteration : {} ----|'.format(route_name,i+1)) + + #Start Traffic + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT,"For Traffic To start") + flow_stats = get_flow_stats(cvg_api) + tx_frame_rate = flow_stats[0].frames_tx_rate + assert tx_frame_rate != 0,"Traffic has not started" + + #Withdraw routes from a BGP peer + logger.info('Withdrawing Routes from {}'.format(route_name)) + cs = cvg_api.convergence_state() + cs.route.names = [route_name] + cs.route.state = cs.route.WITHDRAW + cvg_api.set_state(cs) + wait(TIMEOUT,"For routes to be withdrawn") + flows = get_flow_stats(cvg_api) + for flow in flows: + tx_frate.append(flow.frames_tx_rate) + rx_frate.append(flow.frames_tx_rate) + assert sum(tx_frate) == sum(rx_frate),"Traffic has not converged after lroute withdraw TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate),sum(rx_frate)) + logger.info("Traffic has converged after route withdraw") + + #Get control plane to data plane convergence + request = cvg_api.convergence_request() + request.convergence.flow_names = [] + convergence_metrics = cvg_api.get_results(request).flow_convergence + for metrics in convergence_metrics: + logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) + assert metrics.control_plane_data_plane_convergence_us < MAX_CPDP_CONVERGENCE*1000000,"CP/DP Convergence is greater than 100s" + avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) + + #Advertise the routes back at the end of iteration + cs = cvg_api.convergence_state() + cs.route.names = [route_name] + cs.route.state = cs.route.ADVERTISE + cvg_api.set_state(cs) + logger.info('Readvertise {} routes back at the end of iteration {}'.format(route_name,i+1)) + + table.append('%s route withdraw'%route_name) + table.append(number_of_ipv4_routes) + table.append(iteration) + table.append(mean(avg)) + return table + table = [] + #Iterating route withdrawal on all BGP peers + for route in route_names: + table.append(get_avg_cpdp_convergence_time(route)) + + columns = ['Event Name','No. of IPV4 Routes','Iterations','Avg Control to Data Plane Convergence Time (ms)'] + logger.info("\n%s" % tabulate(table,headers = columns,tablefmt = "psql")) + +def get_RIB_IN_convergence(cvg_api, + bgp_config, + iteration, + multipath, + number_of_ipv4_routes): + """ + Args: + cvg_api (pytest fixture): snappi API + bgp_config: __tgen_bgp_config + config: TGEN config + iteration: number of iterations for running convergence test on a port + number_of_ipv4_routes: Number of IPV4 Routes + """ + + route_names = [] + conv_config = bgp_config[0] + for device in bgp_config[1].devices: + if device.name not in ['Topology 1']: + for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: + route_names.append(route.name) + conv_config.rx_rate_threshold = 90/(multipath-1) + conv_config.convergence_event = (conv_config.ROUTE_ADVERTISE_WITHDRAW) + cvg_api.set_config(conv_config) + + table,avg,tx_frate,rx_frate = [],[],[],[] + for i in range(0,iteration): + logger.info('|---- RIB-IN Convergence test, Iteration : {} ----|'.format(i+1)) + + #withdraw all routes before starting traffic + logger.info('Withdraw All Routes before starting traffic') + cs = cvg_api.convergence_state() + cs.route.names = route_names + cs.route.state = cs.route.WITHDRAW + cvg_api.set_state(cs) + wait(TIMEOUT,"For Routes to be withdrawn") + + #Start Traffic + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT,"For Traffic To start") + flow_stats = get_flow_stats(cvg_api) + tx_frame_rate = flow_stats[0].frames_tx_rate + rx_frame_rate = flow_stats[0].frames_rx_rate + assert tx_frame_rate != 0,"Traffic has not started" + assert rx_frame_rate == 0 + + #Advertise All Routes + logger.info('Advertising all Routes from {}'.format(route_names)) + cs = cvg_api.convergence_state() + cs.route.names = route_names + cs.route.state = cs.route.ADVERTISE + cvg_api.set_state(cs) + wait(TIMEOUT,"For all routes to be ADVERTISED") + flows = get_flow_stats(cvg_api) + for flow in flows: + tx_frate.append(flow.frames_tx_rate) + rx_frate.append(flow.frames_tx_rate) + assert sum(tx_frate) == sum(rx_frate),"Traffic has not convergedv, TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate),sum(rx_frate)) + logger.info("Traffic has converged after route advertisement") + + #Get RIB-IN convergence + request = cvg_api.convergence_request() + request.convergence.flow_names = [] + convergence_metrics = cvg_api.get_results(request).flow_convergence + for metrics in convergence_metrics: + logger.info('RIB-IN Convergence time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) + assert metrics.control_plane_data_plane_convergence_us < MAX_RIBIN_CONVERGENCE*1000000 + avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) + + #Stop traffic at the end of iteration + logger.info('Stopping Traffic at the end of iteration{}'.format(i+1)) + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.STOP + cvg_api.set_state(cs) + wait(TIMEOUT,"For Traffic To stop") + + table.append('Advertise All BGP Routes') + table.append(number_of_ipv4_routes) + table.append(iteration) + table.append(mean(avg)) + columns = ['Event Name','No. of IPV4 Routes','Iterations','Avg RIB-IN 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: + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + port_count:multipath + 1 + """ + 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') diff --git a/tests/ixia/bgp/test_bgp_local_link_failover.py b/tests/ixia/bgp/test_bgp_local_link_failover.py new file mode 100644 index 00000000000..b0c9130a816 --- /dev/null +++ b/tests/ixia/bgp/test_bgp_local_link_failover.py @@ -0,0 +1,56 @@ +#from tests.common.snappi.snappi_fixtures import snappi_api +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.bgp_convergence_helper import run_bgp_local_link_failover_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + +@pytest.mark.parametrize('multipath',[3]) +@pytest.mark.parametrize('convergence_test_iterations',[2]) +@pytest.mark.parametrize('number_of_ipv4_routes',[8000]) +def test_bgp_convergence_for_local_link_failover(cvg_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + multipath, + convergence_test_iterations, + number_of_ipv4_routes): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Create a flow from TGEN1 to (N-1) TGEN ports + 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range + 4) Simulate link failure by bringing down one of the (N-1) TGEN Ports + 5) Calculate the packet loss duration for convergence time + 6) Clean up the BGP config on the dut + + Verification: + 1) Send traffic without flapping any link + Result: Should not observe traffic loss + 2) Flap one of the N TGEN link + Result: The traffic must be routed via rest of the ECMP paths and should not observe traffic loss + + Args: + cvg_api (pytest fixture): Snappi Convergence API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + multipath: ECMP value + convergence_test_iterations: number of iterations the link failure test has to be run for a port + number_of_ipv4_routes: Number of IPV4 Routes + """ + #convergence_test_iterations and multipath values can be modified as per user preference + run_bgp_local_link_failover_test(cvg_api, + duthost, + tgen_ports, + convergence_test_iterations, + multipath, + number_of_ipv4_routes) diff --git a/tests/ixia/bgp/test_bgp_remote_link_failover.py b/tests/ixia/bgp/test_bgp_remote_link_failover.py new file mode 100755 index 00000000000..d13990b3243 --- /dev/null +++ b/tests/ixia/bgp/test_bgp_remote_link_failover.py @@ -0,0 +1,55 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.bgp_convergence_helper import run_bgp_remote_link_failover_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + +@pytest.mark.parametrize('multipath',[2]) +@pytest.mark.parametrize('convergence_test_iterations',[1]) +@pytest.mark.parametrize('number_of_ipv4_routes',[8000]) +def test_bgp_convergence_for_remote_link_failover(cvg_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + multipath, + convergence_test_iterations, + number_of_ipv4_routes): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Create a flow from TGEN1 to (N-1) TGEN ports + 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range + 4) Simulate link failure by bringing down one of the (N-1) TGEN Ports + 5) Calculate the packet loss duration for convergence time + 6) Clean up the BGP config on the dut + + Verification: + 1) Send traffic without flapping any link + Result: Should not observe traffic loss + 2) Flap one of the N TGEN link + Result: The traffic must be routed via rest of the ECMP paths and should not observe traffic loss + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + multipath: ECMP value + convergence_test_iterations: number of iterations the link failure test has to be run for a port + number_of_ipv4_routes: Number of IPV4 Routes + """ + #convergence_test_iterations and multipath values can be modified as per user preference + run_bgp_remote_link_failover_test(cvg_api, + duthost, + tgen_ports, + convergence_test_iterations, + multipath, + number_of_ipv4_routes) diff --git a/tests/ixia/bgp/test_bgp_rib_in_convergence.py b/tests/ixia/bgp/test_bgp_rib_in_convergence.py new file mode 100644 index 00000000000..67a501854d5 --- /dev/null +++ b/tests/ixia/bgp/test_bgp_rib_in_convergence.py @@ -0,0 +1,55 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.bgp_convergence_helper import run_RIB_IN_convergence_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + +@pytest.mark.parametrize('multipath',[3]) +@pytest.mark.parametrize('convergence_test_iterations',[2]) +@pytest.mark.parametrize('number_of_ipv4_routes',[8000]) +def test_RIB_IN_convergence(cvg_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + multipath, + convergence_test_iterations, + number_of_ipv4_routes): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Create a flow from TGEN1 to (N-1) TGEN ports + 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range + 4) Simulate link failure by bringing down one of the (N-1) TGEN Ports + 5) Calculate the packet loss duration for convergence time + 6) Clean up the BGP config on the dut + + Verification: + 1) Send traffic without flapping any link + Result: Should not observe traffic loss + 2) Flap one of the N TGEN link + Result: The traffic must be routed via rest of the ECMP paths and should not observe traffic loss + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + multipath: ECMP value + convergence_test_iterations: number of iterations the link failure test has to be run for a port + number_of_ipv4_routes: Number of IPV4 Routes + """ + #convergence_test_iterations and multipath values can be modified as per user preference + run_RIB_IN_convergence_test(cvg_api, + duthost, + tgen_ports, + convergence_test_iterations, + multipath, + number_of_ipv4_routes) From 914cc503c0c99a360e14159062da3e23307e050e Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 25 Jun 2021 20:11:24 +0000 Subject: [PATCH 02/58] snappi 4.12 changes --- tests/ixia/bgp/files/bgp_convergence_helper.py | 11 +++++++++-- tests/ixia/bgp/test_bgp_local_link_failover.py | 4 ++-- tests/ixia/bgp/test_bgp_rib_in_convergence.py | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index bc7b1cf026a..a6fd4a2c41c 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -219,23 +219,30 @@ def __tgen_bgp_config(cvg_api, def create_topo(): config.devices[0].ethernet.name = 'Ethernet 1' + config.devices[0].ethernet.mac = "00:00:00:00:00:01" config.devices[0].ethernet.ipv4.name = 'IPv4 1' config.devices[0].ethernet.ipv4.address = tgen_ports[0]['ip'] config.devices[0].ethernet.ipv4.gateway = tgen_ports[0]['peer_ip'] config.devices[0].ethernet.ipv4.prefix = int(tgen_ports[0]['prefix']) rx_flow_name = [] for i in range(2,port_count+1): + if len(str(hex(i).split('0x')[1]))==1: + m='0'+hex(i).split('0x')[1] + else: + m=hex(i).split('0x')[1] ethernet_stack = config.devices[i-1].ethernet ethernet_stack.name = 'Ethernet %d'%i + ethernet_stack.mac = "00:00:00:00:00:%s"%m ipv4_stack = ethernet_stack.ipv4 ipv4_stack.name = 'IPv4 %d'%i ipv4_stack.address = tgen_ports[i-1]['ip'] ipv4_stack.gateway = tgen_ports[i-1]['peer_ip'] - ipv4_stack.prefix = tgen_ports[i-1]['prefix'] + ipv4_stack.prefix = int(tgen_ports[i-1]['prefix']) bgpv4_stack = ipv4_stack.bgpv4 bgpv4_stack.name = 'BGP %d'%i bgpv4_stack.as_type = BGP_TYPE bgpv4_stack.dut_address = tgen_ports[i-1]['peer_ip'] + bgpv4_stack.local_address = tgen_ports[i-1]['ip'] bgpv4_stack.as_number = int(TGEN_AS_NUM) route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name = "Network Group %d"%i)[-1] route_range.addresses.bgpv4routeaddress(address = '200.1.0.1', prefix = 32, count = number_of_ipv4_routes, step = 1) @@ -249,7 +256,7 @@ def create_topo(): flow.size.fixed = 1024 flow.rate.percentage = 100 flow.metrics.enable = True - return conv_config,config,rx_flows + return conv_config,config def get_flow_stats(cvg_api): """ diff --git a/tests/ixia/bgp/test_bgp_local_link_failover.py b/tests/ixia/bgp/test_bgp_local_link_failover.py index b0c9130a816..3e2264c2e42 100644 --- a/tests/ixia/bgp/test_bgp_local_link_failover.py +++ b/tests/ixia/bgp/test_bgp_local_link_failover.py @@ -7,8 +7,8 @@ conn_graph_facts, fanout_graph_facts) import pytest -@pytest.mark.parametrize('multipath',[3]) -@pytest.mark.parametrize('convergence_test_iterations',[2]) +@pytest.mark.parametrize('multipath',[2]) +@pytest.mark.parametrize('convergence_test_iterations',[1]) @pytest.mark.parametrize('number_of_ipv4_routes',[8000]) def test_bgp_convergence_for_local_link_failover(cvg_api, duthost, diff --git a/tests/ixia/bgp/test_bgp_rib_in_convergence.py b/tests/ixia/bgp/test_bgp_rib_in_convergence.py index 67a501854d5..d75f87ee5c8 100644 --- a/tests/ixia/bgp/test_bgp_rib_in_convergence.py +++ b/tests/ixia/bgp/test_bgp_rib_in_convergence.py @@ -6,8 +6,8 @@ conn_graph_facts, fanout_graph_facts) import pytest -@pytest.mark.parametrize('multipath',[3]) -@pytest.mark.parametrize('convergence_test_iterations',[2]) +@pytest.mark.parametrize('multipath',[2]) +@pytest.mark.parametrize('convergence_test_iterations',[1]) @pytest.mark.parametrize('number_of_ipv4_routes',[8000]) def test_RIB_IN_convergence(cvg_api, duthost, From a7659d020e4c1799611f2cd1b465dfd60720bdd4 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 25 Jun 2021 21:52:26 +0000 Subject: [PATCH 03/58] Test steps --- tests/ixia/bgp/test_bgp_remote_link_failover.py | 10 +++++----- tests/ixia/bgp/test_bgp_rib_in_convergence.py | 15 ++++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/tests/ixia/bgp/test_bgp_remote_link_failover.py b/tests/ixia/bgp/test_bgp_remote_link_failover.py index d13990b3243..3f5381f8b2e 100755 --- a/tests/ixia/bgp/test_bgp_remote_link_failover.py +++ b/tests/ixia/bgp/test_bgp_remote_link_failover.py @@ -26,14 +26,14 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, 1) Create BGP config on DUT and TGEN respectively 2) Create a flow from TGEN1 to (N-1) TGEN ports 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range - 4) Simulate link failure by bringing down one of the (N-1) TGEN Ports - 5) Calculate the packet loss duration for convergence time + 4) Simulate route withdraw from one of the (N-1) BGP peers which is the equivalent of remote link failure + 5) Calculate the cp/dp for convergence time 6) Clean up the BGP config on the dut Verification: - 1) Send traffic without flapping any link + 1) Send traffic with all routes advertised by BGP peers Result: Should not observe traffic loss - 2) Flap one of the N TGEN link + 2) Withdraw all routes from one of the BGP peer Result: The traffic must be routed via rest of the ECMP paths and should not observe traffic loss Args: @@ -43,7 +43,7 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, conn_graph_facts (pytest fixture): connection graph fanout_graph_facts (pytest fixture): fanout graph multipath: ECMP value - convergence_test_iterations: number of iterations the link failure test has to be run for a port + convergence_test_iterations: number of iterations the cp/dp convergence test has to be run for a port number_of_ipv4_routes: Number of IPV4 Routes """ #convergence_test_iterations and multipath values can be modified as per user preference diff --git a/tests/ixia/bgp/test_bgp_rib_in_convergence.py b/tests/ixia/bgp/test_bgp_rib_in_convergence.py index d75f87ee5c8..d3433761e6c 100644 --- a/tests/ixia/bgp/test_bgp_rib_in_convergence.py +++ b/tests/ixia/bgp/test_bgp_rib_in_convergence.py @@ -25,16 +25,17 @@ def test_RIB_IN_convergence(cvg_api, Steps: 1) Create BGP config on DUT and TGEN respectively 2) Create a flow from TGEN1 to (N-1) TGEN ports - 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range - 4) Simulate link failure by bringing down one of the (N-1) TGEN Ports - 5) Calculate the packet loss duration for convergence time + 3) Withdraw the routes from all the BGP peers + 4) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range + 4) Advertise the routes when traffic is running + 5) Calculate the RIB-IN convergence time 6) Clean up the BGP config on the dut Verification: - 1) Send traffic without flapping any link - Result: Should not observe traffic loss - 2) Flap one of the N TGEN link - Result: The traffic must be routed via rest of the ECMP paths and should not observe traffic loss + 1) Send traffic after withdrawing routes from all BGP peers + Result: Should not observe any traffic in the receiving side + 2) Advertise the routes when the traffic is running + Result: The traffic must be routed via the ECMP paths and should not observe any traffic loss Args: snappi_api (pytest fixture): Snappi API From 33a7d0bd7cefedef0478894787045aa312abdf4a Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 29 Jun 2021 00:25:08 +0000 Subject: [PATCH 04/58] snappi-0.4.14 changes --- ...ence-Testplan-for-Benchmark-Performance.md | 10 +- .../ixia/bgp/files/bgp_convergence_helper.py | 93 ++++++++----------- .../ixia/bgp/test_bgp_local_link_failover.py | 10 +- .../ixia/bgp/test_bgp_remote_link_failover.py | 10 +- tests/ixia/bgp/test_bgp_rib_in_convergence.py | 10 +- 5 files changed, 60 insertions(+), 73 deletions(-) diff --git a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md index a2fca62157f..c650bf62234 100644 --- a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md +++ b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md @@ -169,11 +169,11 @@ Measure the convergence time when local link failure event happens with in the n ### Test Results Below table is the result of 3 way ECMP for 4 link flap iterations -| Event Name | Iterations | Avg Calculated Data Convergence Time(ms) | -| :---: | :-: | :-: | -| Test_Port_2 Link Failure | 4 | 26.75 | -| Test_Port_3 Link Failure | 4 | 55 | -| Test_Port_4 Link Failure | 4 | 43 | +| Event Name | No. of IPv4 Routes | Iterations | Avg Calculated Data Convergence Time(ms) | +| :---: | :-: | :-: | :-: | +| Test_Port_2 Link Failure | 1000 | 4 | 4.112 | +| Test_Port_3 Link Failure | 1000 | 4 | 4.336 | +| Test_Port_4 Link Failure | 1000 | 4 | 4.219 | ### Call for action * Solicit experience in multi-DUT system test scenarios. diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index a6fd4a2c41c..cc11fc66e45 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -10,15 +10,12 @@ TGEN_AS_NUM = 65200 TIMEOUT = 30 BGP_TYPE = 'ebgp' -MAX_DP_CONVERGENCE = 100 -MAX_CPDP_CONVERGENCE = 3 -MAX_RIBIN_CONVERGENCE = 3 def run_bgp_local_link_failover_test(cvg_api, duthost, tgen_ports, iteration, multipath, - number_of_ipv4_routes): + number_of_v4_routes,): """ Run BGP Convergence test @@ -28,7 +25,7 @@ def run_bgp_local_link_failover_test(cvg_api, tgen_ports (pytest fixture): Ports mapping info of T0 testbed iteration: number of iterations for running convergence test on a port multipath: ecmp value for BGP config - number_of_ipv4_routes: Number of IPV4 Routes + number_of_v4_routes: Number of IPV4 Routes """ port_count = multipath+1 # Create bgp config on dut @@ -41,14 +38,14 @@ def run_bgp_local_link_failover_test(cvg_api, tgen_bgp_config = __tgen_bgp_config(cvg_api, tgen_ports, port_count, - number_of_ipv4_routes) + number_of_v4_routes,) # Run the convergence test by flapping all the rx links one by one and calculate the convergence values get_convergence_for_local_link_failover(cvg_api, tgen_bgp_config, iteration, multipath, - number_of_ipv4_routes) + number_of_v4_routes,) # Cleanup the dut configs after getting the convergence numbers cleanup_config(duthost, @@ -60,7 +57,7 @@ def run_bgp_remote_link_failover_test(cvg_api, tgen_ports, iteration, multipath, - number_of_ipv4_routes): + number_of_v4_routes,): """ Run BGP Convergence test @@ -70,7 +67,6 @@ def run_bgp_remote_link_failover_test(cvg_api, tgen_ports (pytest fixture): Ports mapping info of T0 testbed iteration: number of iterations for running convergence test on a port multipath: ecmp value for BGP config - number_of_ipv4_routes: Number of IPV4 Routes """ port_count = multipath+1 # Create bgp config on dut @@ -83,14 +79,14 @@ def run_bgp_remote_link_failover_test(cvg_api, tgen_bgp_config = __tgen_bgp_config(cvg_api, tgen_ports, port_count, - number_of_ipv4_routes) + number_of_v4_routes,) # Run the convergence test by flapping all the rx links one by one and calculate the convergence values get_convergence_for_remote_link_failover(cvg_api, tgen_bgp_config, iteration, multipath, - number_of_ipv4_routes) + number_of_v4_routes,) # Cleanup the dut configs after getting the convergence numbers cleanup_config(duthost, @@ -102,7 +98,7 @@ def run_RIB_IN_convergence_test(cvg_api, tgen_ports, iteration, multipath, - number_of_ipv4_routes): + number_of_v4_routes,): """ Run BGP Convergence test @@ -112,7 +108,7 @@ def run_RIB_IN_convergence_test(cvg_api, tgen_ports (pytest fixture): Ports mapping info of T0 testbed iteration: number of iterations for running convergence test on a port multipath: ecmp value for BGP config - number_of_ipv4_routes: Number of IPV4 Routes + number_of_v4_routes: Number of IPV4 Routes """ port_count = multipath+1 # Create bgp config on dut @@ -125,14 +121,14 @@ def run_RIB_IN_convergence_test(cvg_api, tgen_bgp_config = __tgen_bgp_config(cvg_api, tgen_ports, port_count, - number_of_ipv4_routes) + number_of_v4_routes,) # Run the convergence test by flapping all the rx links one by one and calculate the convergence values get_RIB_IN_convergence(cvg_api, tgen_bgp_config, iteration, multipath, - number_of_ipv4_routes) + number_of_v4_routes,) # Cleanup the dut configs after getting the convergence numbers cleanup_config(duthost, @@ -190,7 +186,7 @@ def duthost_bgp_config(duthost, def __tgen_bgp_config(cvg_api, tgen_ports, port_count, - number_of_ipv4_routes): + number_of_v4_routes,): """ Creating BGP config on TGEN @@ -198,7 +194,7 @@ def __tgen_bgp_config(cvg_api, cvg_api (pytest fixture): snappi API tgen_ports (pytest fixture): Ports mapping info of T0 testbed port_count: multipath + 1 - number_of_ipv4_routes: Number of IPV4 Routes + number_of_v4_routes: Number of IPV4 Routes """ conv_config = cvg_api.convergence_config() config = conv_config.config @@ -245,7 +241,7 @@ def create_topo(): bgpv4_stack.local_address = tgen_ports[i-1]['ip'] bgpv4_stack.as_number = int(TGEN_AS_NUM) route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name = "Network Group %d"%i)[-1] - route_range.addresses.bgpv4routeaddress(address = '200.1.0.1', prefix = 32, count = number_of_ipv4_routes, step = 1) + route_range.addresses.bgpv4routeaddress(address = '200.1.0.1', prefix = 32, count = number_of_v4_routes, step = 1) rx_flow_name.append(route_range.name) return rx_flow_name @@ -256,7 +252,7 @@ def create_topo(): flow.size.fixed = 1024 flow.rate.percentage = 100 flow.metrics.enable = True - return conv_config,config + return conv_config def get_flow_stats(cvg_api): """ @@ -271,22 +267,20 @@ def get_convergence_for_local_link_failover(cvg_api, bgp_config, iteration, multipath, - number_of_ipv4_routes): + number_of_v4_routes,): """ Args: cvg_api (pytest fixture): snappi API bgp_config: __tgen_bgp_config config: TGEN config iteration: number of iterations for running convergence test on a port - number_of_ipv4_routes: Number of IPV4 Routes + number_of_v4_routes: Number of IPV4 Routes """ - conv_config = bgp_config[0] - config = bgp_config[1] rx_port_names = [] - conv_config.convergence_event = (conv_config.LINK_UP_DOWN) - cvg_api.set_config(conv_config) - for i in range(1,len(config.ports)): - rx_port_names.append(config.ports[i].name) + bgp_config.convergence_event = (bgp_config.LINK_UP_DOWN) + cvg_api.set_config(bgp_config) + for i in range(1,len(bgp_config.config.ports)): + rx_port_names.append(bgp_config.config.ports[i].name) def get_avg_dpdp_convergence_time(port_name, rx_port_names): @@ -338,10 +332,8 @@ def get_avg_dpdp_convergence_time(port_name, # Calculate DPDP Convergence dp_convergence = (tx_frames - rx_frames) * 1000 / tx_frame_rate - logger.info("DP Convergence Time: {} ms".format(int(dp_convergence))) - avg.append(int(dp_convergence)) - logger.info(dp_convergence) - assert dp_convergence < MAX_DP_CONVERGENCE,"DP Convergence is greater than 100 ms" + logger.info("DP Convergence Time: {} ms".format(round(dp_convergence,3))) + avg.append(round(dp_convergence,3)) logger.info('Simulating Link Up on {} at the end of iteration {}'.format(port_name,i+1)) #Performing link up at the end of iteration @@ -350,7 +342,7 @@ def get_avg_dpdp_convergence_time(port_name, cs.link.state = cs.link.UP cvg_api.set_state(cs) table.append('%s Link Failure'%port_name) - table.append(number_of_ipv4_routes) + table.append(number_of_v4_routes) table.append(iteration) table.append(mean(avg)) return table @@ -366,25 +358,23 @@ def get_convergence_for_remote_link_failover(cvg_api, bgp_config, iteration, multipath, - number_of_ipv4_routes): + number_of_v4_routes,): """ Args: cvg_api (pytest fixture): snappi API bgp_config: __tgen_bgp_config config: TGEN config iteration: number of iterations for running convergence test on a port - number_of_ipv4_routes: Number of IPV4 Routes + number_of_v4_routes: Number of IPV4 Routes """ route_names = [] - conv_config = bgp_config[0] - for device in bgp_config[1].devices: + for device in bgp_config.config.devices: if device.name not in ['Topology 1']: for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: route_names.append(route.name) - conv_config = bgp_config[0] - conv_config.rx_rate_threshold = 90/(multipath-1) - conv_config.convergence_event = (conv_config.ROUTE_ADVERTISE_WITHDRAW) - cvg_api.set_config(conv_config) + bgp_config.rx_rate_threshold = 90/(multipath-1) + bgp_config.convergence_event = (bgp_config.ROUTE_ADVERTISE_WITHDRAW) + cvg_api.set_config(bgp_config) def get_avg_cpdp_convergence_time(route_name): @@ -427,7 +417,6 @@ def get_avg_cpdp_convergence_time(route_name): convergence_metrics = cvg_api.get_results(request).flow_convergence for metrics in convergence_metrics: logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) - assert metrics.control_plane_data_plane_convergence_us < MAX_CPDP_CONVERGENCE*1000000,"CP/DP Convergence is greater than 100s" avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) #Advertise the routes back at the end of iteration @@ -438,7 +427,7 @@ def get_avg_cpdp_convergence_time(route_name): logger.info('Readvertise {} routes back at the end of iteration {}'.format(route_name,i+1)) table.append('%s route withdraw'%route_name) - table.append(number_of_ipv4_routes) + table.append(number_of_v4_routes) table.append(iteration) table.append(mean(avg)) return table @@ -454,25 +443,25 @@ def get_RIB_IN_convergence(cvg_api, bgp_config, iteration, multipath, - number_of_ipv4_routes): + number_of_v4_routes,): """ Args: cvg_api (pytest fixture): snappi API bgp_config: __tgen_bgp_config config: TGEN config iteration: number of iterations for running convergence test on a port - number_of_ipv4_routes: Number of IPV4 Routes + number_of_v4_routes: Number of IPV4 Routes """ route_names = [] - conv_config = bgp_config[0] - for device in bgp_config[1].devices: + #for device in bgp_config[1].devices: + for device in bgp_config.config.devices: if device.name not in ['Topology 1']: for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: route_names.append(route.name) - conv_config.rx_rate_threshold = 90/(multipath-1) - conv_config.convergence_event = (conv_config.ROUTE_ADVERTISE_WITHDRAW) - cvg_api.set_config(conv_config) + bgp_config.rx_rate_threshold = 90/(multipath) + bgp_config.convergence_event = (bgp_config.ROUTE_ADVERTISE_WITHDRAW) + cvg_api.set_config(bgp_config) table,avg,tx_frate,rx_frate = [],[],[],[] for i in range(0,iteration): @@ -518,9 +507,7 @@ def get_RIB_IN_convergence(cvg_api, convergence_metrics = cvg_api.get_results(request).flow_convergence for metrics in convergence_metrics: logger.info('RIB-IN Convergence time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) - assert metrics.control_plane_data_plane_convergence_us < MAX_RIBIN_CONVERGENCE*1000000 avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) - #Stop traffic at the end of iteration logger.info('Stopping Traffic at the end of iteration{}'.format(i+1)) cs = cvg_api.convergence_state() @@ -529,12 +516,12 @@ def get_RIB_IN_convergence(cvg_api, wait(TIMEOUT,"For Traffic To stop") table.append('Advertise All BGP Routes') - table.append(number_of_ipv4_routes) + table.append(number_of_v4_routes) table.append(iteration) table.append(mean(avg)) columns = ['Event Name','No. of IPV4 Routes','Iterations','Avg RIB-IN Convergence Time(ms)'] logger.info("\n%s" % tabulate([table],headers = columns,tablefmt = "psql")) - + def cleanup_config(duthost, tgen_ports, port_count): diff --git a/tests/ixia/bgp/test_bgp_local_link_failover.py b/tests/ixia/bgp/test_bgp_local_link_failover.py index 3e2264c2e42..cd630c41bb0 100644 --- a/tests/ixia/bgp/test_bgp_local_link_failover.py +++ b/tests/ixia/bgp/test_bgp_local_link_failover.py @@ -8,8 +8,8 @@ import pytest @pytest.mark.parametrize('multipath',[2]) -@pytest.mark.parametrize('convergence_test_iterations',[1]) -@pytest.mark.parametrize('number_of_ipv4_routes',[8000]) +@pytest.mark.parametrize('convergence_test_iterations',[2]) +@pytest.mark.parametrize('number_of_v4_routes',[4000]) def test_bgp_convergence_for_local_link_failover(cvg_api, duthost, tgen_ports, @@ -17,7 +17,7 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, fanout_graph_facts, multipath, convergence_test_iterations, - number_of_ipv4_routes): + number_of_v4_routes): """ Topo: @@ -45,7 +45,7 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, fanout_graph_facts (pytest fixture): fanout graph multipath: ECMP value convergence_test_iterations: number of iterations the link failure test has to be run for a port - number_of_ipv4_routes: Number of IPV4 Routes + number_of_v4_routes: Number of IPV4 Routes """ #convergence_test_iterations and multipath values can be modified as per user preference run_bgp_local_link_failover_test(cvg_api, @@ -53,4 +53,4 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, tgen_ports, convergence_test_iterations, multipath, - number_of_ipv4_routes) + number_of_v4_routes,) diff --git a/tests/ixia/bgp/test_bgp_remote_link_failover.py b/tests/ixia/bgp/test_bgp_remote_link_failover.py index 3f5381f8b2e..99c410f792d 100755 --- a/tests/ixia/bgp/test_bgp_remote_link_failover.py +++ b/tests/ixia/bgp/test_bgp_remote_link_failover.py @@ -7,8 +7,8 @@ import pytest @pytest.mark.parametrize('multipath',[2]) -@pytest.mark.parametrize('convergence_test_iterations',[1]) -@pytest.mark.parametrize('number_of_ipv4_routes',[8000]) +@pytest.mark.parametrize('convergence_test_iterations',[2]) +@pytest.mark.parametrize('number_of_v4_routes',[4000]) def test_bgp_convergence_for_remote_link_failover(cvg_api, duthost, tgen_ports, @@ -16,7 +16,7 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, fanout_graph_facts, multipath, convergence_test_iterations, - number_of_ipv4_routes): + number_of_v4_routes,): """ Topo: @@ -44,7 +44,7 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, fanout_graph_facts (pytest fixture): fanout graph multipath: ECMP value convergence_test_iterations: number of iterations the cp/dp convergence test has to be run for a port - number_of_ipv4_routes: Number of IPV4 Routes + number_of_v4_routes: Number of IPV4 Routes """ #convergence_test_iterations and multipath values can be modified as per user preference run_bgp_remote_link_failover_test(cvg_api, @@ -52,4 +52,4 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, tgen_ports, convergence_test_iterations, multipath, - number_of_ipv4_routes) + number_of_v4_routes,) diff --git a/tests/ixia/bgp/test_bgp_rib_in_convergence.py b/tests/ixia/bgp/test_bgp_rib_in_convergence.py index d3433761e6c..e34d05d7c6b 100644 --- a/tests/ixia/bgp/test_bgp_rib_in_convergence.py +++ b/tests/ixia/bgp/test_bgp_rib_in_convergence.py @@ -7,8 +7,8 @@ import pytest @pytest.mark.parametrize('multipath',[2]) -@pytest.mark.parametrize('convergence_test_iterations',[1]) -@pytest.mark.parametrize('number_of_ipv4_routes',[8000]) +@pytest.mark.parametrize('convergence_test_iterations',[2]) +@pytest.mark.parametrize('number_of_v4_routes',[4000]) def test_RIB_IN_convergence(cvg_api, duthost, tgen_ports, @@ -16,7 +16,7 @@ def test_RIB_IN_convergence(cvg_api, fanout_graph_facts, multipath, convergence_test_iterations, - number_of_ipv4_routes): + number_of_v4_routes): """ Topo: @@ -45,7 +45,7 @@ def test_RIB_IN_convergence(cvg_api, fanout_graph_facts (pytest fixture): fanout graph multipath: ECMP value convergence_test_iterations: number of iterations the link failure test has to be run for a port - number_of_ipv4_routes: Number of IPV4 Routes + number_of_v4_routes: Number of IPV4 Routes """ #convergence_test_iterations and multipath values can be modified as per user preference run_RIB_IN_convergence_test(cvg_api, @@ -53,4 +53,4 @@ def test_RIB_IN_convergence(cvg_api, tgen_ports, convergence_test_iterations, multipath, - number_of_ipv4_routes) + number_of_v4_routes) From 862973034cec338d6530dcbae8d5039b8655ffa4 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 29 Jun 2021 01:16:26 +0000 Subject: [PATCH 05/58] Adding snappi fixtures --- tests/common/snappi/__init__.py | 0 tests/common/snappi/common_helpers.py | 661 +++++++++++++++++++++++++ tests/common/snappi/snappi_fixtures.py | 107 ++++ tests/common/snappi/snappi_helpers.py | 202 ++++++++ 4 files changed, 970 insertions(+) create mode 100644 tests/common/snappi/__init__.py create mode 100644 tests/common/snappi/common_helpers.py create mode 100644 tests/common/snappi/snappi_fixtures.py create mode 100644 tests/common/snappi/snappi_helpers.py diff --git a/tests/common/snappi/__init__.py b/tests/common/snappi/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/common/snappi/common_helpers.py b/tests/common/snappi/common_helpers.py new file mode 100644 index 00000000000..4f47e913b72 --- /dev/null +++ b/tests/common/snappi/common_helpers.py @@ -0,0 +1,661 @@ +"""This module contains some auxiliary functions that are required +to support automation activities. These functions are used for various +secondary activities like convert the ansible Unicode STDOUT output +to string, get IP address in a subnet, increment an IP address, get +VLAN subnet etc. + +This file is also a placeholder for auxiliary function that are +required for supporting automation with Ixia devices in future: +like collecting diagnostics, uploading and downloading files +to/from API server, processing the statistics after obtaining them +in .csv format etc. +""" + +import ipaddr +from netaddr import IPNetwork +from tests.common.mellanox_data import is_mellanox_device as isMellanoxDevice + +def increment_ip_address(ip, incr=1) : + """ + Increment IP address by an integer number. + + Args: + ip (str): IP address in string format. + incr (int): Increment by the specified number. + + Return: + IP address in the argument incremented by the given integer. + """ + ipaddress = ipaddr.IPv4Address(ip) + ipaddress = ipaddress + incr + return_value = ipaddress._string_from_ip_int(ipaddress._ip) + return(return_value) + + +def ansible_stdout_to_str(ansible_stdout): + """ + The stdout of Ansible host is essentially a list of unicode characters. + This function converts it to a string. + + Args: + ansible_stdout: stdout of Ansible + + Returns: + Return a string + """ + result = "" + for x in ansible_stdout: + result += x.encode('UTF8') + return result + + +def get_vlan_subnet(host_ans): + """ + Get VLAN subnet of a T0 device + + Args: + host_ans: Ansible host instance of the device + + Returns: + VLAN subnet, e.g., "192.168.1.1/24" where 192.168.1.1 is gateway + and 24 is prefix length + """ + mg_facts = host_ans.minigraph_facts(host=host_ans.hostname)['ansible_facts'] + mg_vlans = mg_facts['minigraph_vlans'] + + if len(mg_vlans) != 1: + print 'There should be only one Vlan at the DUT' + return None + + mg_vlan_intfs = mg_facts['minigraph_vlan_interfaces'] + prefix_len = mg_vlan_intfs[0]['prefixlen'] + gw_addr = ansible_stdout_to_str(mg_vlan_intfs[0]['addr']) + return gw_addr + '/' + str(prefix_len) + +def get_egress_lossless_buffer_size(host_ans): + """ + Get egress lossless buffer size of a switch + + Args: + host_ans: Ansible host instance of the device + + Returns: + total switch buffer size in byte (int) + """ + config_facts = host_ans.config_facts(host=host_ans.hostname, + source="running")['ansible_facts'] + + if "BUFFER_POOL" not in config_facts.keys(): + return None + + buffer_pools = config_facts['BUFFER_POOL'] + profile_name = 'egress_lossless_pool' + + if profile_name not in buffer_pools.keys(): + return None + + egress_lossless_pool = buffer_pools[profile_name] + return int(egress_lossless_pool['size']) + +def get_addrs_in_subnet(subnet, number_of_ip): + """ + Get N IP addresses in a subnet. + + Args: + subnet (str): IPv4 subnet, e.g., '192.168.1.1/24' + number_of_ip (int): Number of IP addresses to get + + Return: + Return n IPv4 addresses in this subnet in a list. + """ + ip_addr = subnet.split('/')[0] + ip_addrs = [str(x) for x in list(IPNetwork(subnet))] + ip_addrs.remove(ip_addr) + + """ Try to avoid network and broadcast addresses """ + if len(ip_addrs) >= number_of_ip + 2: + del ip_addrs[0] + del ip_addrs[-1] + + return ip_addrs[:number_of_ip] + +def get_peer_snappi_chassis(conn_data, dut_hostname): + """ + Get the IXIA chassis connected to the DUT + Note that a DUT can only be connected to a IXIA chassis + + Args: + conn_data (dict): the dictionary returned by conn_graph_fact. + Example format of the conn_data is given below: + + { + u'device_conn': { + u'msr-s6100-dut-1': { + u'Ethernet0': { + u'peerdevice': u'msr-ixia-1', + u'peerport': u'Card12/Port5', + u'speed': u'40000' + }, + u'Ethernet1': { + u'peerdevice': u'msr-ixia-1', + u'peerport': u'Card12/Port6', + u'speed': u'40000' + }, + u'Ethernet2': { + u'peerdevice': u'msr-ixia-1', + u'peerport': u'Card12/Port7', + u'speed': u'40000' + } + } + }, + u'device_info': [{u'HwSku': u'Dell-S6100', u'Type': u'DevSonic'}], + u'device_port_vlans': [ + { + u'Ethernet0': { + u'mode': u'Access', + u'vlanids': u'', + u'vlanlist': [] + }, + u'Ethernet1': { + u'mode': u'Access', + u'vlanids': u'', + u'vlanlist': [] + }, + u'Ethernet2': { + u'mode': u'Access', + u'vlanids': u'', + u'vlanlist': [] + } + } + ], + u'device_vlan_list': [[]], + u'device_vlan_map_list': {u'msr-s6100-dut-1': []}, + u'device_vlan_range': [[]] + } + + dut_hostname (str): hostname of the DUT + + Returns: + The name of the peer IXIA chassis or None + """ + + device_conn = conn_data['device_conn'] + if dut_hostname not in device_conn: + return None + + dut_device_conn = device_conn[dut_hostname] + peer_devices = [dut_device_conn[port]['peerdevice'] for port in dut_device_conn] + peer_devices = list(set(peer_devices)) + + if len(peer_devices) == 1: + return peer_devices[0] + else: + return None + +def get_peer_port(conn_data, dut_hostname, dut_intf): + """ + Get the peer port of the DUT port + + Args: + conn_data (dict): the dictionary returned by conn_graph_fact. + Example format of the conn_data is given below: + + { + u'device_conn': { + u'msr-s6100-dut-1': { + u'Ethernet0': { + u'peerdevice': u'msr-ixia-1', + u'peerport': u'Card12/Port5', + u'speed': u'40000' + }, + u'Ethernet1': { + u'peerdevice': u'msr-ixia-1', + u'peerport': u'Card12/Port6', + u'speed': u'40000' + }, + u'Ethernet2': { + u'peerdevice': u'msr-ixia-1', + u'peerport': u'Card12/Port7', + u'speed': u'40000' + } + } + }, + u'device_info': [{u'HwSku': u'Dell-S6100', u'Type': u'DevSonic'}], + u'device_port_vlans': [ + { + u'Ethernet0': { + u'mode': u'Access', + u'vlanids': u'', + u'vlanlist': [] + }, + u'Ethernet1': { + u'mode': u'Access', + u'vlanids': u'', + u'vlanlist': [] + }, + u'Ethernet2': { + u'mode': u'Access', + u'vlanids': u'', + u'vlanlist': [] + } + } + ], + u'device_vlan_list': [[]], + u'device_vlan_map_list': {u'msr-s6100-dut-1': []}, + u'device_vlan_range': [[]] + } + + dut_hostname (str): hostname of the DUT + dut_intf (str): name of DUT interface + + Returns: + The name of the peer port or None + """ + device_conn = conn_data['device_conn'] + if dut_hostname not in device_conn: + return None + + dut_device_conn = device_conn[dut_hostname] + if dut_intf not in dut_device_conn: + return None + + return dut_device_conn[dut_intf]['peerport'] + + +def get_dut_intfs(conn_data, dut_hostname): + """ + Get DUT's interfaces + + Args: + conn_data (dict): the dictionary returned by conn_graph_fact. + Example format of the conn_data is given below: + + { + u'device_conn': { + u'msr-s6100-dut-1': { + u'Ethernet0': { + u'peerdevice': u'msr-ixia-1', + u'peerport': u'Card12/Port5', + u'speed': u'40000' + }, + u'Ethernet1': { + u'peerdevice': u'msr-ixia-1', + u'peerport': u'Card12/Port6', + u'speed': u'40000' + }, + u'Ethernet2': { + u'peerdevice': u'msr-ixia-1', + u'peerport': u'Card12/Port7', + u'speed': u'40000' + } + } + }, + u'device_info': [{u'HwSku': u'Dell-S6100', u'Type': u'DevSonic'}], + u'device_port_vlans': [ + { + u'Ethernet0': { + u'mode': u'Access', + u'vlanids': u'', + u'vlanlist': [] + }, + u'Ethernet1': { + u'mode': u'Access', + u'vlanids': u'', + u'vlanlist': [] + }, + u'Ethernet2': { + u'mode': u'Access', + u'vlanids': u'', + u'vlanlist': [] + } + } + ], + u'device_vlan_list': [[]], + u'device_vlan_map_list': {u'msr-s6100-dut-1': []}, + u'device_vlan_range': [[]] + } + + dut_hostname (str): hostname of the DUT + + Returns: + Return the list of interface names + """ + + device_conn = conn_data['device_conn'] + if dut_hostname not in device_conn: + return None + + dut_device_conn = device_conn[dut_hostname] + return list(dut_device_conn.keys()) + + +def pfc_class_enable_vector(prio_list): + """ + Calculate class-enable vector field in PFC PAUSE frames + + Args: + prio_list (list): list of priorities to pause, e.g., [3, 4] + + Returns: + Return class-enable vector + """ + vector = 0 + + for p in prio_list: + vector += (2**p) + + return "{:x}".format(vector) + +def get_wred_profiles(host_ans): + """ + Get all the WRED/ECN profiles of a SONiC switch + + Args: + host_ans: Ansible host instance of the device + + Returns: + WRED/ECN profiles (dictionary) or None. + Example format is given below: + + { + u'AZURE_LOSSLESS': { + u'ecn': u'ecn_all', + u'green_drop_probability': u'5', + u'green_max_threshold': u'2097152', + u'green_min_threshold': u'250000', + u'red_drop_probability': u'5', + u'red_max_threshold': u'2097152', + u'red_min_threshold': u'1048576', + u'wred_green_enable': u'true', + u'wred_red_enable': u'true', + u'wred_yellow_enable': u'true', + u'yellow_drop_probability': u'5', + u'yellow_max_threshold': u'2097152', + u'yellow_min_threshold': u'1048576' + } + } + """ + config_facts = host_ans.config_facts(host=host_ans.hostname, + source="running")['ansible_facts'] + + if "WRED_PROFILE" in config_facts.keys(): + return config_facts['WRED_PROFILE'] + else: + return None + +def config_wred(host_ans, kmin, kmax, pmax, profile=None): + """ + Config a WRED/ECN profile of a SONiC switch + + Args: + host_ans: Ansible host instance of the device + kmin (int): RED/ECN minimum threshold in bytes + kmax (int): RED/ECN maximum threshold in bytes + pmax (int): RED/ECN maximum marking probability in percentage + profile (str): name of profile to configure (None means any profile) + + Returns: + If configuration succeeds (bool) + """ + + if not isinstance(kmin, int) or \ + not isinstance(kmax, int) or \ + not isinstance(pmax, int): + return False + + if kmin < 0 or kmax < 0 or pmax < 0 or pmax > 100 or kmin > kmax: + return False + + profiles = get_wred_profiles(host_ans) + """ Cannot find any WRED/ECN profiles """ + if profiles is None: + return False + + """ Cannot find the profile to configure at the device """ + if profile is not None and profile not in profiles: + return False + + for p in profiles: + """ This is not the profile to configure """ + if profile is not None and profile != p: + continue + + kmin_old = int(profiles[p]['green_min_threshold']) + kmax_old = int(profiles[p]['green_max_threshold']) + + if kmin_old > kmax_old: + return False + + """ Ensure that Kmin is no larger than Kmax during the update """ + if kmin > kmin_old: + host_ans.shell('sudo ecnconfig -p {} -gmax {}'.format(p, kmax)) + host_ans.shell('sudo ecnconfig -p {} -gmin {}'.format(p, kmin)) + + else: + host_ans.shell('sudo ecnconfig -p {} -gmin {}'.format(p, kmin)) + host_ans.shell('sudo ecnconfig -p {} -gmax {}'.format(p, kmax)) + + return True + +def enable_ecn(host_ans, prio): + """ + Enable ECN marking on a priority + + Args: + host_ans: Ansible host instance of the device + prio (int): priority + + Returns: + N/A + """ + host_ans.shell('sudo ecnconfig -q {} on'.format(prio)) + +def disable_ecn(host_ans, prio): + """ + Disable ECN marking on a priority + + Args: + host_ans: Ansible host instance of the device + prio (int): priority + + Returns: + N/A + """ + host_ans.shell('sudo ecnconfig -q {} off'.format(prio)) + +def config_buffer_alpha(host_ans, profile, alpha_log2): + """ + Configure buffer threshold (a.k.a., alpha) + + Args: + host_ans: Ansible host instance of the device + profile (str): buffer profile name + alpha_log2 (int): set threshold to 2^alpha_log2 + + Returns: + N/A + """ + host_ans.shell('sudo mmuconfig -p {} -a {}'.format(profile, alpha_log2)) + +def config_ingress_lossless_buffer_alpha(host_ans, alpha_log2): + """ + Configure ingress buffer thresholds (a.k.a., alpha) of a device to 2^alpha_log2 + + Args: + host_ans: Ansible host instance of the device + alpha_log2 (int): set threshold to 2^alpha_log2 + + Returns: + If configuration succeeds (bool) + """ + if not isinstance(alpha_log2, int): + return False + + config_facts = host_ans.config_facts(host=host_ans.hostname, + source="running")['ansible_facts'] + + if "BUFFER_PROFILE" not in config_facts.keys(): + return False + + buffer_profiles = config_facts['BUFFER_PROFILE'] + ingress_profiles = [] + for profile in buffer_profiles: + if profile.startswith('ingress_lossless') or profile.startswith('pg_lossless'): + ingress_profiles.append(profile) + + for profile in ingress_profiles: + config_buffer_alpha(host_ans=host_ans, profile=profile, alpha_log2=alpha_log2) + + """ Check if configuration succeeds """ + config_facts = host_ans.config_facts(host=host_ans.hostname, + source="running")['ansible_facts'] + + for profile in ingress_profiles: + dynamic_th = config_facts['BUFFER_PROFILE'][profile]['dynamic_th'] + if int(dynamic_th) != alpha_log2: + return False + + return True + +def get_pfcwd_config_attr(host_ans, config_scope, attr): + """ + Get PFC watchdog configuration attribute + + Args: + host_ans: Ansible host instance of the device + config_scope (str): 'GLOBAL' or interface name + attr (str): config attribute name, e.g., 'detection_time' + + Returns: + config attribute (str) or None + """ + config_facts = host_ans.config_facts(host=host_ans.hostname, + source="running")['ansible_facts'] + + if 'PFC_WD' not in config_facts.keys(): + return None + + pfcwd_config = config_facts['PFC_WD'] + if config_scope not in pfcwd_config: + return None + + config = pfcwd_config[config_scope] + if attr in config: + return config[attr] + + return None + +def get_pfcwd_poll_interval(host_ans): + """ + Get PFC watchdog polling interval + + Args: + host_ans: Ansible host instance of the device + + Returns: + Polling interval in ms (int) or None + """ + val = get_pfcwd_config_attr(host_ans=host_ans, + config_scope='GLOBAL', + attr='POLL_INTERVAL') + + if val is not None: + return int(val) + + return None + +def get_pfcwd_detect_time(host_ans, intf): + """ + Get PFC watchdog detection time of a given interface + + Args: + host_ans: Ansible host instance of the device + intf (str): interface name + + Returns: + Detection time in ms (int) or None + """ + val = get_pfcwd_config_attr(host_ans=host_ans, + config_scope=intf, + attr='detection_time') + + if val is not None: + return int(val) + + return None + +def get_pfcwd_restore_time(host_ans, intf): + """ + Get PFC watchdog restoration time of a given interface + + Args: + host_ans: Ansible host instance of the device + intf (str): interface name + + Returns: + Restoration time in ms (int) or None + """ + val = get_pfcwd_config_attr(host_ans=host_ans, + config_scope=intf, + attr='restoration_time') + + if val is not None: + return int(val) + + return None + +def start_pfcwd(duthost): + """ + Start PFC watchdog with default setting + + Args: + duthost (AnsibleHost): Device Under Test (DUT) + + Returns: + N/A + """ + duthost.shell('sudo pfcwd start_default') + +def stop_pfcwd(duthost): + """ + Stop PFC watchdog + + Args: + duthost (AnsibleHost): Device Under Test (DUT) + + Returns: + N/A + """ + duthost.shell('sudo pfcwd stop') + +def disable_packet_aging(duthost): + """ + Disable packet aging feature (only on MLNX switches) + + Args: + duthost (AnsibleHost): Device Under Test (DUT) + + Returns: + N/A + """ + if isMellanoxDevice(duthost): + duthost.copy(src="qos/files/mellanox/packets_aging.py", dest="/tmp") + duthost.command("docker cp /tmp/packets_aging.py syncd:/") + duthost.command("docker exec syncd python /packets_aging.py disable") + duthost.command("docker exec syncd rm -rf /packets_aging.py") + +def enable_packet_aging(duthost): + """ + Enable packet aging feature (only on MLNX switches) + + Args: + duthost (AnsibleHost): Device Under Test (DUT) + + Returns: + N/A + """ + if isMellanoxDevice(duthost): + duthost.copy(src="qos/files/mellanox/packets_aging.py", dest="/tmp") + duthost.command("docker cp /tmp/packets_aging.py syncd:/") + duthost.command("docker exec syncd python /packets_aging.py enable") + duthost.command("docker exec syncd rm -rf /packets_aging.py") diff --git a/tests/common/snappi/snappi_fixtures.py b/tests/common/snappi/snappi_fixtures.py new file mode 100644 index 00000000000..cfc3063fc75 --- /dev/null +++ b/tests/common/snappi/snappi_fixtures.py @@ -0,0 +1,107 @@ +""" +This module contains the snappi fixture +""" +import pytest +import snappi_convergence +#from ipaddress import ip_address, IPv4Address +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +from tests.common.snappi.common_helpers import ( + get_vlan_subnet, get_addrs_in_subnet,get_peer_snappi_chassis) +from tests.common.snappi.snappi_helpers import SnappiFanoutManager, get_snappi_port_location + +@pytest.fixture(scope="module") +def snappi_api_serv_ip(tbinfo): + """ + In a Snappi testbed, there is no PTF docker. + Hence, we use ptf_ip field to store snappi API server. + This fixture returns the IP address of the snappi API server. + Args: + tbinfo (pytest fixture): fixture provides information about testbed + Returns: + snappi API server IP + """ + return tbinfo['ptf_ip'] + + + +@pytest.fixture(scope="module") +def snappi_api_serv_port(duthosts, rand_one_dut_hostname): + """ + This fixture returns the TCP Port of the Snappi API server. + Args: + duthost (pytest fixture): The duthost fixture. + Returns: + snappi API server port. + """ + duthost = duthosts[rand_one_dut_hostname] + return (duthost.host.options['variable_manager']. + _hostvars[duthost.hostname]['secret_group_vars'] + ['snappi_api_server']['rest_port']) + + +@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'} + snappi_fanout = get_peer_snappi_chassis(conn_data=conn_graph_facts,dut_hostname=duthost.hostname) + snappi_fanout_id = list(fanout_graph_facts.keys()).index(snappi_fanout) + snappi_fanout_list = SnappiFanoutManager(fanout_graph_facts) + snappi_fanout_list.get_fanout_device_details(device_number=snappi_fanout_id) + snappi_ports = snappi_fanout_list.get_ports(peer_device=duthost.hostname) + port_speed = None + for i in range(len(snappi_ports)): + if port_speed is None: + port_speed = int(snappi_ports[i]['speed']) + elif port_speed != int(snappi_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 snappi_ports: + port['location'] = get_snappi_port_location(port) + port['speed'] = speed_type[port['speed']] + for port in snappi_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 snappi_ports + +@pytest.fixture(scope='module') +def cvg_api(snappi_api_serv_ip, + snappi_api_serv_port): + #api = snappi_convergence.api(location=snappi_api_serv_ip + ':' + str(snappi_api_serv_port),ext='ixnetwork') + api = snappi_convergence.api(location='10.36.77.53' + ':' + '11009',ext='ixnetwork') + yield api + if getattr(api, 'assistant', None) is not None: + api.assistant.Session.remove() \ No newline at end of file diff --git a/tests/common/snappi/snappi_helpers.py b/tests/common/snappi/snappi_helpers.py new file mode 100644 index 00000000000..2da4b943116 --- /dev/null +++ b/tests/common/snappi/snappi_helpers.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- +""" +This module contains a definition of a simple helper class +"SnappiFanoutManager" which can be used to manage cards and ports of Snappi +chassis instead of reading it from fanout_graph_facts fixture. +""" +from copy import deepcopy + +from tests.common.helpers.assertions import pytest_assert +from tests.common.snappi.common_helpers import ansible_stdout_to_str, get_peer_snappi_chassis +from tests.common.reboot import logger + + +class SnappiFanoutManager(): + """Class for managing multiple chassis and extracting the information + like chassis IP, card, port etc. from fanout_graph_fact.""" + + def __init__(self, fanout_data): + """ When multiple chassis are available inside fanout_graph_facts + this method makes a list of chassis connection-details out of it. + So each chassis and details associated with it can be accessed by + a integer index (starting from 0) + Args: + fanout_data (dict): the dictionary returned by fanout_graph_fact. + Example format of the fanout_data is given below + {u'snappi-sonic': { + u'device_conn': { + u'Card9/Port1': { + u'peerdevice': u'sonic-s6100-dut', + u'peerport': u'Ethernet0', + u'speed': u'100000' + }, + u'Card9/Port2': { + u'peerdevice': u'sonic-s6100-dut', + u'peerport': u'Ethernet4', + u'speed': u'100000' + }, + u'Card9/Port3': { + u'peerdevice': u'sonic-s6100-dut', + u'peerport': u'Ethernet8', + u'speed': u'100000' + } + }, + u'device_info': { + u'HwSku': u'SNAPPI-tester', + u'ManagementGw': u'10.36.78.54', + u'ManagementIp': u'10.36.78.53/32', + u'Type': u'DevSnappiChassis', + u'mgmtip': u'10.36.78.53' + }, + u'device_port_vlans': { + u'Card9/Port1': { + u'mode': u'Access', + u'vlanids': u'300', + u'vlanlist': [300] + }, + u'Card9/Port2': { + u'mode': u'Access', + u'vlanids': u'301', + u'vlanlist': [301] + }, + u'Card9/Port3': { + u'mode': u'Access', + u'vlanids': u'302', + u'vlanlist': [302] + } + }, + u'device_vlan_list': [301, 302, 300, 302, 300, 301], + u'device_vlan_range': [u'300-302'] + } + } + """ + self.last_fanout_assessed = None + self.fanout_list = [] + self.last_device_connection_details = None + self.current_snappi_port_list = None + self.ip_address = '0.0.0.0' + + for fanout in fanout_data.keys(): + self.fanout_list.append(fanout_data[fanout]) + + def __parse_fanout_connections__(self): + device_conn = self.last_device_connection_details + retval = [] + for key in device_conn.keys(): + fanout_port = ansible_stdout_to_str(key) + peer_port = ansible_stdout_to_str(device_conn[key]['peerport']) + peer_device = ansible_stdout_to_str(device_conn[key]['peerdevice']) + speed = ansible_stdout_to_str(device_conn[key]['speed']) + string = "{}/{}/{}/{}/{}".\ + format(self.ip_address, fanout_port, peer_port, peer_device, speed) + retval.append(string) + + return(retval) + + def get_fanout_device_details(self, device_number): + """With the help of this function you can select the chassis you want + to access. For example get_fanout_device_details(0) selects the + first chassis. It just select the chassis but does not return + anything. The rest of the function then used to extract chassis + information like "get_chassis_ip()" will the return the ip address + of chassis 0 - the first chassis in the list. + Note: + Counting or indexing starts from 0. That is 0 = 1st chassis, + 1 = 2nd chassis ... + Args: + device_number (int): the chassis index (0 is the first) + Returns: + None + """ + + # Pointer to chassis info + self.last_fanout_assessed = device_number + + # Chassis connection details + self.last_device_connection_details = \ + self.fanout_list[self.last_fanout_assessed]['device_conn'] + + # Chassis ip details + chassis_ip = self.fanout_list[self.last_fanout_assessed]['device_info']['mgmtip'] + self.ip_address = ansible_stdout_to_str(chassis_ip) + + # List of chassis cards and ports + self.current_snappi_port_list = \ + self.__parse_fanout_connections__() + + def get_connection_details(self): + """This function returns all the details associated with a particular + chassis (selected earlier using get_fanout_device_details() function). + Details of the chassis will be available like chassis IP, card, ports, + peer port etc. in a dictionary format. + Note: If you have not used get_fanout_device_details(), by default 0th + (first) chassis remains selected. + Args: + This function takes no argument. + Returns: + Details of the chassis connection as dictionary format. + """ + return(self.last_device_connection_details) + + def get_chassis_ip(self): + """This function returns IP address of a particular chassis + (selected earlier using get_fanout_device_details() function). + Note: If you have not used get_fanout_device_details(), by default 0th + (first) chassis remains selected. + Args: + This function takes no argument. + Returns: + The IP address + """ + return self.ip_address + + def get_ports(self, peer_device=None): + """This function returns list of ports that are (1) associated with a + chassis (selected earlier using get_fanout_device_details() function) + and (2) connected to a peer device (SONiC DUT) as a list of dictionary. + Note: If you have not used get_fanout_device_details(), by default 0th + (first) chassis remains selected. If you do not specify peer_device, + this function will return all the ports of the chassis. + Args: + peer_device (str): hostname of the peer device + Returns: + Dictionary of chassis card port information. + """ + retval = [] + for port in self.current_snappi_port_list: + info_list = port.split('/') + dict_element = { + 'ip': info_list[0], + 'card_id': info_list[1].replace('Card', ''), + 'port_id': info_list[2].replace('Port', ''), + 'peer_port': info_list[3], + 'peer_device': info_list[4], + 'speed': info_list[5] + } + + if peer_device is None or info_list[4] == peer_device: + retval.append(dict_element) + + return retval + + +def get_snappi_port_location(intf): + """ + Extracting location from interface, since Snappi Api accepts location + in terms of chassis ip, card, and port in different format. + Note: Interface must have the keys 'ip', 'card_id' and 'port_id' + Args: + intf (dict) : intf must contain the keys 'ip', 'card_id', 'port_id'. + Example format : + {'ip': u'10.36.78.53', + 'port_id': u'1', + 'card_id': u'9', + 'speed': 100000, + 'peer_port': u'Ethernet0'} + Returns: location in string format. Example: '10.36.78.5;1;2' where + 1 is card_id and 2 is port_id. + """ + keys = set(['ip', 'card_id', 'port_id']) + pytest_assert(keys.issubset(set(intf.keys())), "intf does not have all the keys") + + return "{};{};{}".format(intf['ip'], intf['card_id'], intf['port_id']) \ No newline at end of file From 689d51ee5da1218d94b2e8577c6c6c7e76baa83d Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 29 Jun 2021 03:20:14 +0000 Subject: [PATCH 06/58] Resolving unused imports --- tests/common/snappi/snappi_fixtures.py | 2 +- tests/common/snappi/snappi_helpers.py | 4 +--- tests/ixia/bgp/files/bgp_convergence_helper.py | 3 --- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/common/snappi/snappi_fixtures.py b/tests/common/snappi/snappi_fixtures.py index cfc3063fc75..ff838da6e20 100644 --- a/tests/common/snappi/snappi_fixtures.py +++ b/tests/common/snappi/snappi_fixtures.py @@ -7,7 +7,7 @@ from tests.common.fixtures.conn_graph_facts import ( conn_graph_facts, fanout_graph_facts) from tests.common.snappi.common_helpers import ( - get_vlan_subnet, get_addrs_in_subnet,get_peer_snappi_chassis) + get_addrs_in_subnet,get_peer_snappi_chassis) from tests.common.snappi.snappi_helpers import SnappiFanoutManager, get_snappi_port_location @pytest.fixture(scope="module") diff --git a/tests/common/snappi/snappi_helpers.py b/tests/common/snappi/snappi_helpers.py index 2da4b943116..72046c2ccaa 100644 --- a/tests/common/snappi/snappi_helpers.py +++ b/tests/common/snappi/snappi_helpers.py @@ -4,10 +4,8 @@ "SnappiFanoutManager" which can be used to manage cards and ports of Snappi chassis instead of reading it from fanout_graph_facts fixture. """ -from copy import deepcopy - from tests.common.helpers.assertions import pytest_assert -from tests.common.snappi.common_helpers import ansible_stdout_to_str, get_peer_snappi_chassis +from tests.common.snappi.common_helpers import ansible_stdout_to_str from tests.common.reboot import logger diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index cc11fc66e45..c8a92bf8d8d 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -1,9 +1,6 @@ -import pytest -import time from tabulate import tabulate from statistics import mean from tests.common.utilities import wait -from tests.common.helpers.assertions import pytest_assert logger = logging.getLogger(__name__) DUT_AS_NUM = 65100 From 693a8fc6141daaf8716d0bf31b0e8fa6e3a0bab1 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 29 Jun 2021 18:53:49 +0000 Subject: [PATCH 07/58] using snappi_api_serv_* fixtures --- tests/common/snappi/snappi_fixtures.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/common/snappi/snappi_fixtures.py b/tests/common/snappi/snappi_fixtures.py index ff838da6e20..d80b029b536 100644 --- a/tests/common/snappi/snappi_fixtures.py +++ b/tests/common/snappi/snappi_fixtures.py @@ -100,8 +100,7 @@ def tgen_ports(duthost,conn_graph_facts,fanout_graph_facts): @pytest.fixture(scope='module') def cvg_api(snappi_api_serv_ip, snappi_api_serv_port): - #api = snappi_convergence.api(location=snappi_api_serv_ip + ':' + str(snappi_api_serv_port),ext='ixnetwork') - api = snappi_convergence.api(location='10.36.77.53' + ':' + '11009',ext='ixnetwork') + api = snappi_convergence.api(location=snappi_api_serv_ip + ':' + str(snappi_api_serv_port),ext='ixnetwork') yield api if getattr(api, 'assistant', None) is not None: api.assistant.Session.remove() \ No newline at end of file From b05bf49fb158cea36518ed94d75aeb1915084d62 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 2 Jul 2021 22:50:47 +0000 Subject: [PATCH 08/58] v6 routes support --- .../ixia/bgp/files/bgp_convergence_helper.py | 208 +++++++++++++----- .../ixia/bgp/test_bgp_local_link_failover.py | 14 +- .../ixia/bgp/test_bgp_remote_link_failover.py | 14 +- tests/ixia/bgp/test_bgp_rib_in_convergence.py | 14 +- 4 files changed, 181 insertions(+), 69 deletions(-) diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index c8a92bf8d8d..29d24881744 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -7,12 +7,14 @@ TGEN_AS_NUM = 65200 TIMEOUT = 30 BGP_TYPE = 'ebgp' + def run_bgp_local_link_failover_test(cvg_api, duthost, tgen_ports, iteration, multipath, - number_of_v4_routes,): + number_of_routes, + route_type,): """ Run BGP Convergence test @@ -22,39 +24,45 @@ def run_bgp_local_link_failover_test(cvg_api, tgen_ports (pytest fixture): Ports mapping info of T0 testbed iteration: number of iterations for running convergence test on a port multipath: ecmp value for BGP config - number_of_v4_routes: Number of IPV4 Routes + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes """ port_count = multipath+1 # Create bgp config on dut duthost_bgp_config(duthost, tgen_ports, port_count, - multipath) + multipath, + route_type) # Create bgp config on TGEN tgen_bgp_config = __tgen_bgp_config(cvg_api, tgen_ports, port_count, - number_of_v4_routes,) + number_of_routes, + route_type,) # Run the convergence test by flapping all the rx links one by one and calculate the convergence values get_convergence_for_local_link_failover(cvg_api, tgen_bgp_config, iteration, multipath, - number_of_v4_routes,) + number_of_routes, + route_type,) # Cleanup the dut configs after getting the convergence numbers cleanup_config(duthost, tgen_ports, - port_count) + port_count, + route_type,) def run_bgp_remote_link_failover_test(cvg_api, duthost, tgen_ports, iteration, multipath, - number_of_v4_routes,): + number_of_routes, + route_type,): """ Run BGP Convergence test @@ -64,38 +72,44 @@ def run_bgp_remote_link_failover_test(cvg_api, tgen_ports (pytest fixture): Ports mapping info of T0 testbed iteration: number of iterations for running convergence test on a port multipath: ecmp value for BGP config + route_type: IPv4 or IPv6 routes """ port_count = multipath+1 # Create bgp config on dut duthost_bgp_config(duthost, tgen_ports, port_count, - multipath) + multipath, + route_type,) # Create bgp config on TGEN tgen_bgp_config = __tgen_bgp_config(cvg_api, tgen_ports, port_count, - number_of_v4_routes,) + number_of_routes, + route_type,) # Run the convergence test by flapping all the rx links one by one and calculate the convergence values get_convergence_for_remote_link_failover(cvg_api, tgen_bgp_config, iteration, multipath, - number_of_v4_routes,) + number_of_routes, + route_type,) # Cleanup the dut configs after getting the convergence numbers cleanup_config(duthost, tgen_ports, - port_count) + port_count, + route_type,) def run_RIB_IN_convergence_test(cvg_api, duthost, tgen_ports, iteration, multipath, - number_of_v4_routes,): + number_of_routes, + route_type,): """ Run BGP Convergence test @@ -105,37 +119,43 @@ def run_RIB_IN_convergence_test(cvg_api, tgen_ports (pytest fixture): Ports mapping info of T0 testbed iteration: number of iterations for running convergence test on a port multipath: ecmp value for BGP config - number_of_v4_routes: Number of IPV4 Routes + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes """ port_count = multipath+1 # Create bgp config on dut duthost_bgp_config(duthost, tgen_ports, port_count, - multipath) + multipath, + route_type,) # Create bgp config on TGEN tgen_bgp_config = __tgen_bgp_config(cvg_api, tgen_ports, port_count, - number_of_v4_routes,) + number_of_routes, + route_type,) # Run the convergence test by flapping all the rx links one by one and calculate the convergence values get_RIB_IN_convergence(cvg_api, tgen_bgp_config, iteration, multipath, - number_of_v4_routes,) + number_of_routes, + route_type,) # Cleanup the dut configs after getting the convergence numbers cleanup_config(duthost, tgen_ports, - port_count) + port_count, + route_type,) def duthost_bgp_config(duthost, tgen_ports, port_count, - multipath): + multipath, + route_type,): """ Configures BGP on the DUT with N-1 ecmp @@ -144,16 +164,27 @@ def duthost_bgp_config(duthost, tgen_ports (pytest fixture): Ports mapping info of T0 testbed port_count:multipath + 1 multipath: ECMP value for BGP config + route_type: IPv4 or IPv6 routes """ + if route_type == 'IPv4': + peer_ip = 'peer_ip' + ip = 'ip' + prefix = 'prefix' + address_type = ['ip','ipv4'] + else: + peer_ip = 'peer_ipv6' + ip = 'ipv6' + prefix = 'ipv6_prefix' + address_type = ['ipv6','ipv6'] for i in range(0,port_count): intf_config = ( "vtysh " "-c 'configure terminal' " "-c 'interface %s' " - "-c 'ip address %s/%s' " + "-c '%s address %s/%s' " ) - intf_config %= (tgen_ports[i]['peer_port'],tgen_ports[i]['peer_ip'],tgen_ports[i]['prefix']) - logger.info('Configuring IP Address %s' %tgen_ports[i]['ip']) + intf_config %= (tgen_ports[i]['peer_port'],address_type[0],tgen_ports[i][peer_ip],tgen_ports[i][prefix]) + logger.info('Configuring IP Address %s' %tgen_ports[i][ip]) duthost.shell(intf_config) bgp_config = ( "vtysh " @@ -171,19 +202,20 @@ def duthost_bgp_config(duthost, "-c 'configure terminal' " "-c 'router bgp %s' " "-c 'neighbor %s remote-as %s' " - "-c 'address-family ipv4 unicast' " + "-c 'address-family %s 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']) + bgp_config_neighbor %= (DUT_AS_NUM,tgen_ports[i][ip],TGEN_AS_NUM,address_type[1],tgen_ports[i][ip]) + logger.info('Configuring BGP Neighbor %s' %tgen_ports[i][ip]) duthost.shell(bgp_config_neighbor) def __tgen_bgp_config(cvg_api, tgen_ports, port_count, - number_of_v4_routes,): + number_of_routes, + route_type,): """ Creating BGP config on TGEN @@ -191,7 +223,8 @@ def __tgen_bgp_config(cvg_api, cvg_api (pytest fixture): snappi API tgen_ports (pytest fixture): Ports mapping info of T0 testbed port_count: multipath + 1 - number_of_v4_routes: Number of IPV4 Routes + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes """ conv_config = cvg_api.convergence_config() config = conv_config.config @@ -210,7 +243,7 @@ def __tgen_bgp_config(cvg_api, layer1.speed = "speed_100_gbps" layer1.auto_negotiate = False - def create_topo(): + def create_v4_topo(): config.devices[0].ethernet.name = 'Ethernet 1' config.devices[0].ethernet.mac = "00:00:00:00:00:01" config.devices[0].ethernet.ipv4.name = 'IPv4 1' @@ -219,10 +252,10 @@ def create_topo(): config.devices[0].ethernet.ipv4.prefix = int(tgen_ports[0]['prefix']) rx_flow_name = [] for i in range(2,port_count+1): - if len(str(hex(i).split('0x')[1]))==1: - m='0'+hex(i).split('0x')[1] + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] else: - m=hex(i).split('0x')[1] + m = hex(i).split('0x')[1] ethernet_stack = config.devices[i-1].ethernet ethernet_stack.name = 'Ethernet %d'%i ethernet_stack.mac = "00:00:00:00:00:%s"%m @@ -238,12 +271,50 @@ def create_topo(): bgpv4_stack.local_address = tgen_ports[i-1]['ip'] bgpv4_stack.as_number = int(TGEN_AS_NUM) route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name = "Network Group %d"%i)[-1] - route_range.addresses.bgpv4routeaddress(address = '200.1.0.1', prefix = 32, count = number_of_v4_routes, step = 1) + route_range.addresses.bgpv4routeaddress(address = '200.1.0.1', prefix = 32, count = number_of_routes, step = 1) + rx_flow_name.append(route_range.name) + return rx_flow_name + + def create_v6_topo(): + config.devices[0].ethernet.name = 'Ethernet 1' + config.devices[0].ethernet.mac = "00:00:00:00:00:01" + config.devices[0].ethernet.ipv6.name = 'IPv6 1' + config.devices[0].ethernet.ipv6.address = tgen_ports[0]['ipv6'] + config.devices[0].ethernet.ipv6.gateway = tgen_ports[0]['peer_ipv6'] + config.devices[0].ethernet.ipv6.prefix = int(tgen_ports[0]['ipv6_prefix']) + rx_flow_name = [] + for i in range(2,port_count+1): + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] + else: + m = hex(i).split('0x')[1] + ethernet_stack = config.devices[i-1].ethernet + ethernet_stack.name = 'Ethernet %d'%i + ethernet_stack.mac = "00:00:00:00:00:%s"%m + ipv6_stack = ethernet_stack.ipv6 + ipv6_stack.name = 'IPv6 %d'%i + ipv6_stack.address = tgen_ports[i-1]['ipv6'] + ipv6_stack.gateway = tgen_ports[i-1]['peer_ipv6'] + ipv6_stack.prefix = int(tgen_ports[i-1]['ipv6_prefix']) + bgpv6_stack = ipv6_stack.bgpv6 + bgpv6_stack.name = r'BGP+ %d'%i + bgpv6_stack.as_type = BGP_TYPE + bgpv6_stack.dut_address = tgen_ports[i-1]['peer_ipv6'] + bgpv6_stack.local_address = tgen_ports[i-1]['ipv6'] + bgpv6_stack.as_number = int(TGEN_AS_NUM) + route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name = "Network Group %d"%i)[-1] + route_range.addresses.bgpv6routeaddress(address = '3000::1', prefix = 64, count = number_of_routes, step = 1) rx_flow_name.append(route_range.name) return rx_flow_name - rx_flows = create_topo() - flow = config.flows.flow(name = 'convergence_test')[-1] + if route_type == 'IPv4': + rx_flows = create_v4_topo() + flow = config.flows.flow(name = 'IPv4 Traffic')[-1] + elif route_type == 'IPv6': + rx_flows = create_v6_topo() + flow = config.flows.flow(name = 'IPv6 Traffic')[-1] + else: + raise Exception('Invalid route type given') flow.tx_rx.device.tx_names = [config.devices[0].name] flow.tx_rx.device.rx_names = rx_flows flow.size.fixed = 1024 @@ -264,14 +335,16 @@ def get_convergence_for_local_link_failover(cvg_api, bgp_config, iteration, multipath, - number_of_v4_routes,): + number_of_routes, + route_type,): """ Args: cvg_api (pytest fixture): snappi API bgp_config: __tgen_bgp_config config: TGEN config iteration: number of iterations for running convergence test on a port - number_of_v4_routes: Number of IPV4 Routes + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes """ rx_port_names = [] bgp_config.convergence_event = (bgp_config.LINK_UP_DOWN) @@ -339,7 +412,8 @@ def get_avg_dpdp_convergence_time(port_name, cs.link.state = cs.link.UP cvg_api.set_state(cs) table.append('%s Link Failure'%port_name) - table.append(number_of_v4_routes) + table.append(route_type) + table.append(number_of_routes) table.append(iteration) table.append(mean(avg)) return table @@ -348,27 +422,33 @@ def get_avg_dpdp_convergence_time(port_name, for i,port_name in enumerate(rx_port_names): table.append(get_avg_dpdp_convergence_time(port_name,rx_port_names)) - columns = ['Event Name','No. of IPV4 Routes','Iterations','Avg Calculated Data Convergence Time (ms)'] + columns = ['Event Name','Route Type','No. of Routes','Iterations','Avg Calculated Data Convergence Time (ms)'] logger.info("\n%s" % tabulate(table,headers = columns,tablefmt = "psql")) def get_convergence_for_remote_link_failover(cvg_api, bgp_config, iteration, multipath, - number_of_v4_routes,): + number_of_routes, + route_type,): """ Args: cvg_api (pytest fixture): snappi API bgp_config: __tgen_bgp_config config: TGEN config iteration: number of iterations for running convergence test on a port - number_of_v4_routes: Number of IPV4 Routes + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes """ route_names = [] for device in bgp_config.config.devices: if device.name not in ['Topology 1']: - for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: - route_names.append(route.name) + if route_type =='IPv4': + for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: + route_names.append(route.name) + else: + for route in device.ethernet.ipv6.bgpv6.bgpv6_routes: + route_names.append(route.name) bgp_config.rx_rate_threshold = 90/(multipath-1) bgp_config.convergence_event = (bgp_config.ROUTE_ADVERTISE_WITHDRAW) cvg_api.set_config(bgp_config) @@ -424,7 +504,8 @@ def get_avg_cpdp_convergence_time(route_name): logger.info('Readvertise {} routes back at the end of iteration {}'.format(route_name,i+1)) table.append('%s route withdraw'%route_name) - table.append(number_of_v4_routes) + table.append(route_type) + table.append(number_of_routes) table.append(iteration) table.append(mean(avg)) return table @@ -433,32 +514,40 @@ def get_avg_cpdp_convergence_time(route_name): for route in route_names: table.append(get_avg_cpdp_convergence_time(route)) - columns = ['Event Name','No. of IPV4 Routes','Iterations','Avg Control to Data Plane Convergence Time (ms)'] + columns = ['Event Name','Route Type','No. of Routes','Iterations','Avg Control to Data Plane Convergence Time (ms)'] logger.info("\n%s" % tabulate(table,headers = columns,tablefmt = "psql")) def get_RIB_IN_convergence(cvg_api, bgp_config, iteration, multipath, - number_of_v4_routes,): + number_of_routes, + route_type,): """ Args: cvg_api (pytest fixture): snappi API bgp_config: __tgen_bgp_config config: TGEN config iteration: number of iterations for running convergence test on a port - number_of_v4_routes: Number of IPV4 Routes + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes """ - + #anish route_names = [] - #for device in bgp_config[1].devices: for device in bgp_config.config.devices: if device.name not in ['Topology 1']: - for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: - route_names.append(route.name) + if route_type == 'IPv4': + for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: + route_names.append(route.name) + else: + for route in device.ethernet.ipv6.bgpv6.bgpv6_routes: + route_names.append(route.name) bgp_config.rx_rate_threshold = 90/(multipath) bgp_config.convergence_event = (bgp_config.ROUTE_ADVERTISE_WITHDRAW) + #anish + #cvg_api.set_config(cvg_api.config()) cvg_api.set_config(bgp_config) + table,avg,tx_frate,rx_frate = [],[],[],[] for i in range(0,iteration): @@ -513,15 +602,17 @@ def get_RIB_IN_convergence(cvg_api, wait(TIMEOUT,"For Traffic To stop") table.append('Advertise All BGP Routes') - table.append(number_of_v4_routes) + table.append(route_type) + table.append(number_of_routes) table.append(iteration) table.append(mean(avg)) - columns = ['Event Name','No. of IPV4 Routes','Iterations','Avg RIB-IN Convergence Time(ms)'] + columns = ['Event Name','Route Type','No. of Routes','Iterations','Avg RIB-IN Convergence Time(ms)'] logger.info("\n%s" % tabulate([table],headers = columns,tablefmt = "psql")) def cleanup_config(duthost, tgen_ports, - port_count): + port_count, + route_type,): """ Cleaning up dut config at the end of the test @@ -529,7 +620,16 @@ def cleanup_config(duthost, duthost (pytest fixture): duthost fixture tgen_ports (pytest fixture): Ports mapping info of T0 testbed port_count:multipath + 1 + route_type: IPv4 or IPv6 routes """ + if route_type == 'IPv4': + peer_ip = 'peer_ip' + ip = 'ip' + prefix = 'prefix' + else: + peer_ip = 'peer_ipv6' + ip = 'ipv6' + prefix = 'ipv6_prefix' logger.info('Cleaning Up Interface and BGP config') bgp_config_cleanup = ( "vtysh " @@ -543,8 +643,8 @@ def cleanup_config(duthost, "vtysh " "-c 'configure terminal' " "-c 'interface %s' " - "-c 'no ip address %s/%s' " + "-c 'no %s address %s/%s' " ) - intf_config_cleanup %= (tgen_ports[i]['peer_port'],tgen_ports[i]['peer_ip'],tgen_ports[i]['prefix']) + intf_config_cleanup %= (tgen_ports[i]['peer_port'],ip,tgen_ports[i][peer_ip],tgen_ports[i][prefix]) duthost.shell(intf_config_cleanup) logger.info('Convergence Test Completed') diff --git a/tests/ixia/bgp/test_bgp_local_link_failover.py b/tests/ixia/bgp/test_bgp_local_link_failover.py index cd630c41bb0..478f658275c 100644 --- a/tests/ixia/bgp/test_bgp_local_link_failover.py +++ b/tests/ixia/bgp/test_bgp_local_link_failover.py @@ -8,8 +8,9 @@ import pytest @pytest.mark.parametrize('multipath',[2]) -@pytest.mark.parametrize('convergence_test_iterations',[2]) -@pytest.mark.parametrize('number_of_v4_routes',[4000]) +@pytest.mark.parametrize('convergence_test_iterations',[1]) +@pytest.mark.parametrize('number_of_routes',[4000]) +@pytest.mark.parametrize('route_type',['IPv4','IPv6']) def test_bgp_convergence_for_local_link_failover(cvg_api, duthost, tgen_ports, @@ -17,7 +18,8 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, fanout_graph_facts, multipath, convergence_test_iterations, - number_of_v4_routes): + number_of_routes, + route_type,): """ Topo: @@ -45,7 +47,8 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, fanout_graph_facts (pytest fixture): fanout graph multipath: ECMP value convergence_test_iterations: number of iterations the link failure test has to be run for a port - number_of_v4_routes: Number of IPV4 Routes + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes """ #convergence_test_iterations and multipath values can be modified as per user preference run_bgp_local_link_failover_test(cvg_api, @@ -53,4 +56,5 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, tgen_ports, convergence_test_iterations, multipath, - number_of_v4_routes,) + number_of_routes, + route_type,) diff --git a/tests/ixia/bgp/test_bgp_remote_link_failover.py b/tests/ixia/bgp/test_bgp_remote_link_failover.py index 99c410f792d..98a38830041 100755 --- a/tests/ixia/bgp/test_bgp_remote_link_failover.py +++ b/tests/ixia/bgp/test_bgp_remote_link_failover.py @@ -7,8 +7,9 @@ import pytest @pytest.mark.parametrize('multipath',[2]) -@pytest.mark.parametrize('convergence_test_iterations',[2]) -@pytest.mark.parametrize('number_of_v4_routes',[4000]) +@pytest.mark.parametrize('convergence_test_iterations',[1]) +@pytest.mark.parametrize('number_of_routes',[4000]) +@pytest.mark.parametrize('route_type',['IPv4','IPv6']) def test_bgp_convergence_for_remote_link_failover(cvg_api, duthost, tgen_ports, @@ -16,7 +17,8 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, fanout_graph_facts, multipath, convergence_test_iterations, - number_of_v4_routes,): + number_of_routes, + route_type,): """ Topo: @@ -44,7 +46,8 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, fanout_graph_facts (pytest fixture): fanout graph multipath: ECMP value convergence_test_iterations: number of iterations the cp/dp convergence test has to be run for a port - number_of_v4_routes: Number of IPV4 Routes + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes """ #convergence_test_iterations and multipath values can be modified as per user preference run_bgp_remote_link_failover_test(cvg_api, @@ -52,4 +55,5 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, tgen_ports, convergence_test_iterations, multipath, - number_of_v4_routes,) + number_of_routes, + route_type,) diff --git a/tests/ixia/bgp/test_bgp_rib_in_convergence.py b/tests/ixia/bgp/test_bgp_rib_in_convergence.py index e34d05d7c6b..0e2061afb16 100644 --- a/tests/ixia/bgp/test_bgp_rib_in_convergence.py +++ b/tests/ixia/bgp/test_bgp_rib_in_convergence.py @@ -7,8 +7,9 @@ import pytest @pytest.mark.parametrize('multipath',[2]) -@pytest.mark.parametrize('convergence_test_iterations',[2]) -@pytest.mark.parametrize('number_of_v4_routes',[4000]) +@pytest.mark.parametrize('convergence_test_iterations',[1]) +@pytest.mark.parametrize('number_of_routes',[1000,2000]) +@pytest.mark.parametrize('route_type',['IPv4','IPv6']) def test_RIB_IN_convergence(cvg_api, duthost, tgen_ports, @@ -16,7 +17,8 @@ def test_RIB_IN_convergence(cvg_api, fanout_graph_facts, multipath, convergence_test_iterations, - number_of_v4_routes): + number_of_routes, + route_type,): """ Topo: @@ -45,7 +47,8 @@ def test_RIB_IN_convergence(cvg_api, fanout_graph_facts (pytest fixture): fanout graph multipath: ECMP value convergence_test_iterations: number of iterations the link failure test has to be run for a port - number_of_v4_routes: Number of IPV4 Routes + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes """ #convergence_test_iterations and multipath values can be modified as per user preference run_RIB_IN_convergence_test(cvg_api, @@ -53,4 +56,5 @@ def test_RIB_IN_convergence(cvg_api, tgen_ports, convergence_test_iterations, multipath, - number_of_v4_routes) + number_of_routes, + route_type,) From bcd03b782118434b83b1cd17c2ab2ed01b33d539 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 2 Jul 2021 22:57:25 +0000 Subject: [PATCH 09/58] v6 support --- tests/common/snappi/common_helpers.py | 24 +++++++++ tests/common/snappi/snappi_fixtures.py | 73 ++++++++++++++++++-------- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/tests/common/snappi/common_helpers.py b/tests/common/snappi/common_helpers.py index 4f47e913b72..5cbb8dc771b 100644 --- a/tests/common/snappi/common_helpers.py +++ b/tests/common/snappi/common_helpers.py @@ -13,6 +13,8 @@ import ipaddr from netaddr import IPNetwork +from ipaddress import IPv6Network, IPv6Address +from random import getrandbits from tests.common.mellanox_data import is_mellanox_device as isMellanoxDevice def increment_ip_address(ip, incr=1) : @@ -119,6 +121,28 @@ def get_addrs_in_subnet(subnet, number_of_ip): return ip_addrs[:number_of_ip] +def get_ipv6_addrs_in_subnet(subnet, number_of_ip): + """ + Get N IPv6 addresses in a subnet. + Args: + subnet (str): IPv6 subnet, e.g., '2001::1/64' + number_of_ip (int): Number of IP addresses to get + Return: + Return n IPv6 addresses in this subnet in a list. + """ + + subnet = str(IPNetwork(subnet).network) + "/" + str(subnet.split("/")[1]) + subnet = unicode(subnet, "utf-8") + ipv6_list = [] + for i in range(number_of_ip): + network = IPv6Network(subnet) + address = IPv6Address( + network.network_address + getrandbits( + network.max_prefixlen - network.prefixlen)) + ipv6_list.append(str(address)) + + return ipv6_list + def get_peer_snappi_chassis(conn_data, dut_hostname): """ Get the IXIA chassis connected to the DUT diff --git a/tests/common/snappi/snappi_fixtures.py b/tests/common/snappi/snappi_fixtures.py index d80b029b536..420b95116a2 100644 --- a/tests/common/snappi/snappi_fixtures.py +++ b/tests/common/snappi/snappi_fixtures.py @@ -7,7 +7,7 @@ from tests.common.fixtures.conn_graph_facts import ( conn_graph_facts, fanout_graph_facts) from tests.common.snappi.common_helpers import ( - get_addrs_in_subnet,get_peer_snappi_chassis) + get_addrs_in_subnet,get_ipv6_addrs_in_subnet,get_peer_snappi_chassis) from tests.common.snappi.snappi_helpers import SnappiFanoutManager, get_snappi_port_location @pytest.fixture(scope="module") @@ -40,8 +40,11 @@ def snappi_api_serv_port(duthosts, rand_one_dut_hostname): ['snappi_api_server']['rest_port']) -@pytest.fixture(scope="function") -def tgen_ports(duthost,conn_graph_facts,fanout_graph_facts): +@pytest.fixture(scope="module") +def tgen_ports(duthost, + conn_graph_facts, + fanout_graph_facts): + """ Populate tgen ports info of T0 testbed and returns as a list Args: @@ -49,54 +52,78 @@ def tgen_ports(duthost,conn_graph_facts,fanout_graph_facts): conn_graph_facts (pytest fixture): connection graph fanout_graph_facts (pytest fixture): fanout graph Return: - [{'card_id': '1', - 'ip': '21.1.1.2', + [{'card_id': '1', + 'ip': '22.1.1.2', + 'ipv6': '3001::2', + 'ipv6_prefix': u'64', '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', + 'peer_device': 'sonic-s6100-dut', + 'peer_ip': u'22.1.1.1', + 'peer_ipv6': u'3001::1', + 'peer_port': 'Ethernet8', 'port_id': '2', - 'speed': '400000'}, + 'prefix': u'24', + 'speed': 'speed_400_gbps'}, {'card_id': '1', - 'ip': '22.1.1.2', + 'ip': '21.1.1.2', + 'ipv6': '2001::2', + 'ipv6_prefix': u'64', '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', + 'peer_device': 'sonic-s6100-dut', + 'peer_ip': u'21.1.1.1', + 'peer_ipv6': u'2001::1', + 'peer_port': 'Ethernet0', 'port_id': '1', - 'speed': '400000'}] + 'prefix': u'24', + 'speed': 'speed_400_gbps'}] """ + speed_type = {'50000': 'speed_50_gbps', '100000': 'speed_100_gbps', '200000': 'speed_200_gbps', '400000': 'speed_400_gbps'} - snappi_fanout = get_peer_snappi_chassis(conn_data=conn_graph_facts,dut_hostname=duthost.hostname) + + snappi_fanout = get_peer_snappi_chassis(conn_data=conn_graph_facts, + dut_hostname=duthost.hostname) snappi_fanout_id = list(fanout_graph_facts.keys()).index(snappi_fanout) snappi_fanout_list = SnappiFanoutManager(fanout_graph_facts) snappi_fanout_list.get_fanout_device_details(device_number=snappi_fanout_id) snappi_ports = snappi_fanout_list.get_ports(peer_device=duthost.hostname) port_speed = None + for i in range(len(snappi_ports)): if port_speed is None: port_speed = int(snappi_ports[i]['speed']) + elif port_speed != int(snappi_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'] + + config_facts = duthost.config_facts(host=duthost.hostname, + source="running")['ansible_facts'] + for port in snappi_ports: port['location'] = get_snappi_port_location(port) port['speed'] = speed_type[port['speed']] + for port in snappi_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] + int_addrs = config_facts['INTERFACE'][peer_port].keys() + ipv4_subnet = [ele for ele in int_addrs if "." in ele][0] + if not ipv4_subnet: + raise Exception("IPv4 is not configured on the interface {}" + .format(peer_port)) + port['peer_ip'], port['prefix'] = ipv4_subnet.split("/") + port['ip'] = get_addrs_in_subnet(ipv4_subnet, 1)[0] + ipv6_subnet = [ele for ele in int_addrs if ":" in ele][0] + if not ipv6_subnet: + raise Exception("IPv6 is not configured on the interface {}" + .format(peer_port)) + port['peer_ipv6'], port['ipv6_prefix'] = ipv6_subnet.split("/") + port['ipv6'] = get_ipv6_addrs_in_subnet(ipv6_subnet, 1)[0] return snappi_ports + @pytest.fixture(scope='module') def cvg_api(snappi_api_serv_ip, snappi_api_serv_port): From 489fff15505b0f77d034c628e35aff12e1e2dc80 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 6 Jul 2021 22:20:50 +0000 Subject: [PATCH 10/58] try except block for interface configuration --- tests/common/snappi/snappi_fixtures.py | 38 ++++++++++++++------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/tests/common/snappi/snappi_fixtures.py b/tests/common/snappi/snappi_fixtures.py index 420b95116a2..5abb2366e34 100644 --- a/tests/common/snappi/snappi_fixtures.py +++ b/tests/common/snappi/snappi_fixtures.py @@ -3,7 +3,6 @@ """ import pytest import snappi_convergence -#from ipaddress import ip_address, IPv4Address from tests.common.fixtures.conn_graph_facts import ( conn_graph_facts, fanout_graph_facts) from tests.common.snappi.common_helpers import ( @@ -84,11 +83,11 @@ def tgen_ports(duthost, '400000': 'speed_400_gbps'} snappi_fanout = get_peer_snappi_chassis(conn_data=conn_graph_facts, - dut_hostname=duthost.hostname) + dut_hostname=duthost.hostname) snappi_fanout_id = list(fanout_graph_facts.keys()).index(snappi_fanout) snappi_fanout_list = SnappiFanoutManager(fanout_graph_facts) - snappi_fanout_list.get_fanout_device_details(device_number=snappi_fanout_id) - snappi_ports = snappi_fanout_list.get_ports(peer_device=duthost.hostname) + snappi_fanout_list.get_fanout_device_details(device_number = snappi_fanout_id) + snappi_ports = snappi_fanout_list.get_ports(peer_device = duthost.hostname) port_speed = None for i in range(len(snappi_ports)): @@ -109,25 +108,28 @@ def tgen_ports(duthost, for port in snappi_ports: peer_port = port['peer_port'] int_addrs = config_facts['INTERFACE'][peer_port].keys() - ipv4_subnet = [ele for ele in int_addrs if "." in ele][0] - if not ipv4_subnet: - raise Exception("IPv4 is not configured on the interface {}" - .format(peer_port)) - port['peer_ip'], port['prefix'] = ipv4_subnet.split("/") - port['ip'] = get_addrs_in_subnet(ipv4_subnet, 1)[0] - ipv6_subnet = [ele for ele in int_addrs if ":" in ele][0] - if not ipv6_subnet: - raise Exception("IPv6 is not configured on the interface {}" - .format(peer_port)) - port['peer_ipv6'], port['ipv6_prefix'] = ipv6_subnet.split("/") - port['ipv6'] = get_ipv6_addrs_in_subnet(ipv6_subnet, 1)[0] + try: + ipv4_subnet = [ele for ele in int_addrs if "." in ele][0] + if not ipv4_subnet: + raise Exception("IPv4 is not configured on the interface {}" + .format(peer_port)) + port['peer_ip'], port['prefix'] = ipv4_subnet.split("/") + port['ip'] = get_addrs_in_subnet(ipv4_subnet, 1)[0] + ipv6_subnet = [ele for ele in int_addrs if ":" in ele][0] + if not ipv6_subnet: + raise Exception("IPv6 is not configured on the interface {}" + .format(peer_port)) + port['peer_ipv6'], port['ipv6_prefix'] = ipv6_subnet.split("/") + port['ipv6'] = get_ipv6_addrs_in_subnet(ipv6_subnet, 1)[0] + except: + raise Exception('Configure IPv4 and IPv6 on DUT interfaces') return snappi_ports @pytest.fixture(scope='module') def cvg_api(snappi_api_serv_ip, - snappi_api_serv_port): + snappi_api_serv_port): api = snappi_convergence.api(location=snappi_api_serv_ip + ':' + str(snappi_api_serv_port),ext='ixnetwork') yield api if getattr(api, 'assistant', None) is not None: - api.assistant.Session.remove() \ No newline at end of file + api.assistant.Session.remove() From ec6020054c73c39927bd81c5db710ab8f9743664 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Mon, 12 Jul 2021 16:44:03 +0000 Subject: [PATCH 11/58] linter and snappi-0.4.16 changes --- ...ence-Testplan-for-Benchmark-Performance.md | 11 +- .../ixia/bgp/files/bgp_convergence_helper.py | 332 +++++++++--------- .../ixia/bgp/test_bgp_local_link_failover.py | 30 +- .../ixia/bgp/test_bgp_remote_link_failover.py | 6 +- tests/ixia/bgp/test_bgp_rib_in_convergence.py | 47 +-- 5 files changed, 226 insertions(+), 200 deletions(-) diff --git a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md index c650bf62234..f9b99950221 100644 --- a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md +++ b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md @@ -10,18 +10,21 @@ - [Setup configuration](#Setup-configuration) - [Test methodology](#Test-methodology) - [Test cases](#Test-cases) - - [Test case # 1 – Convergence performance when remote link fails (route withdraw)](#test-case--1--convergence-performance-when-remote-link-fails-route-withdraw) + - [Test case # 1 – Failover convergence with remote link failure (route withdraw)](#test-case--1--convergence-performance-when-remote-link-fails-route-withdraw) - [Test objective](#Test-objective) - [Test steps](#Test-steps) - [Test results](#Test-results) + - [Test case](#Test-case) - [Test case # 2 – RIB-IN Convergence](#Test-case--2--RIB-IN-Convergence) - [Test objective](#Test-objective-1) - [Test steps](#Test-steps-1) - [Test results](#Test-results-1) + - [Test case](#Test-case-1) - [Test case # 3 - Failover convergence with local link failure](#Test-case--3--Failover-convergence-with-local-link-failure) - [Test objective](#Test-objective-2) - [Test steps](#Test-steps-2) - [Test results](#Test-results-2) + - [Test case](#Test-case-2) - [Call for action](#Call-for-action) ## Overview @@ -102,6 +105,8 @@ For above test case, below are the test results when multiple remote link fails. | Withdraw Routes | 8K | 2800 | | Withdraw Routes | 16K | 7176 | +### Test Case +sonic-mgmt/tests/ixia/bgp/test_bgp_remote_link_failover.py ### Test case # 2 – RIB-IN Convergence #### Test objective Measure the convergence time to install the routes in its RIB and then in its FIB to forward the packets after the routes are advertised. @@ -145,6 +150,8 @@ In order to measure RIB-IN capacity of the switch, we can follow the same test m | Advertise Routes | 195K | 84487 | 0 | | Advertise Routes | 194K | 83285 | 0 | +### Test Case +sonic-mgmt/tests/ixia/bgp/test_bgp_rib_in_convergence.py ### Test case # 3 - Failover convergence with local link failure #### Test objective Measure the convergence time when local link failure event happens with in the network. @@ -175,6 +182,8 @@ Below table is the result of 3 way ECMP for 4 link flap iterations | Test_Port_3 Link Failure | 1000 | 4 | 4.336 | | Test_Port_4 Link Failure | 1000 | 4 | 4.219 | +### Test Case +sonic-mgmt/tests/ixia/bgp/test_bgp_local_link_failover.py ### Call for action * Solicit experience in multi-DUT system test scenarios. diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index 29d24881744..909d01aeb89 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -8,6 +8,7 @@ TIMEOUT = 30 BGP_TYPE = 'ebgp' + def run_bgp_local_link_failover_test(cvg_api, duthost, tgen_ports, @@ -16,8 +17,8 @@ def run_bgp_local_link_failover_test(cvg_api, number_of_routes, route_type,): """ - Run BGP Convergence test - + Run Local link failover test + Args: cvg_api (pytest fixture): snappi API duthost (pytest fixture): duthost fixture @@ -28,44 +29,49 @@ def run_bgp_local_link_failover_test(cvg_api, route_type: IPv4 or IPv6 routes """ port_count = multipath+1 - # Create bgp config on dut + + """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, port_count, multipath, - route_type) + route_type) - # Create bgp config on TGEN + """ Create bgp config on TGEN """ tgen_bgp_config = __tgen_bgp_config(cvg_api, tgen_ports, port_count, number_of_routes, route_type,) - # Run the convergence test by flapping all the rx links one by one and calculate the convergence values + """ + Run the convergence test by flapping all the rx + links one by one and calculate the convergence values + """ get_convergence_for_local_link_failover(cvg_api, - tgen_bgp_config, - iteration, - multipath, - number_of_routes, - route_type,) + tgen_bgp_config, + iteration, + multipath, + number_of_routes, + route_type,) - # Cleanup the dut configs after getting the convergence numbers + """ Cleanup the dut configs after getting the convergence numbers """ cleanup_config(duthost, tgen_ports, port_count, route_type,) + def run_bgp_remote_link_failover_test(cvg_api, - duthost, - tgen_ports, - iteration, - multipath, - number_of_routes, - route_type,): + duthost, + tgen_ports, + iteration, + multipath, + number_of_routes, + route_type,): """ - Run BGP Convergence test - + Run Remote link failover test + Args: cvg_api (pytest fixture): snappi API duthost (pytest fixture): duthost fixture @@ -75,21 +81,24 @@ def run_bgp_remote_link_failover_test(cvg_api, route_type: IPv4 or IPv6 routes """ port_count = multipath+1 - # Create bgp config on dut + """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, port_count, multipath, - route_type,) + route_type,) - # Create bgp config on TGEN + """ Create bgp config on TGEN """ tgen_bgp_config = __tgen_bgp_config(cvg_api, tgen_ports, port_count, number_of_routes, route_type,) - # Run the convergence test by flapping all the rx links one by one and calculate the convergence values + """ + Run the convergence test by withdrawing all the route ranges + one by one and calculate the convergence values + """ get_convergence_for_remote_link_failover(cvg_api, tgen_bgp_config, iteration, @@ -97,13 +106,14 @@ def run_bgp_remote_link_failover_test(cvg_api, number_of_routes, route_type,) - # Cleanup the dut configs after getting the convergence numbers + """ Cleanup the dut configs after getting the convergence numbers """ cleanup_config(duthost, tgen_ports, port_count, route_type,) -def run_RIB_IN_convergence_test(cvg_api, + +def run_rib_in_convergence_test(cvg_api, duthost, tgen_ports, iteration, @@ -111,8 +121,8 @@ def run_RIB_IN_convergence_test(cvg_api, number_of_routes, route_type,): """ - Run BGP Convergence test - + Run RIB-IN Convergence test + Args: cvg_api (pytest fixture): snappi API duthost (pytest fixture): duthost fixture @@ -123,33 +133,38 @@ def run_RIB_IN_convergence_test(cvg_api, route_type: IPv4 or IPv6 routes """ port_count = multipath+1 - # Create bgp config on dut + + """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, port_count, multipath, - route_type,) + route_type,) - # Create bgp config on TGEN + """ Create bgp config on TGEN """ tgen_bgp_config = __tgen_bgp_config(cvg_api, tgen_ports, port_count, number_of_routes, route_type,) - # Run the convergence test by flapping all the rx links one by one and calculate the convergence values - get_RIB_IN_convergence(cvg_api, - tgen_bgp_config, - iteration, - multipath, - number_of_routes, - route_type,) + """ + Run the convergence test by withdrawing all routes at once and + calculate the convergence values + """ + get_rib_in_convergence(cvg_api, + tgen_bgp_config, + iteration, + multipath, + number_of_routes, + route_type,) - # Cleanup the dut configs after getting the convergence numbers + """ Cleanup the dut configs after getting the convergence numbers """ cleanup_config(duthost, tgen_ports, port_count, - route_type,) + route_type,) + def duthost_bgp_config(duthost, tgen_ports, @@ -158,7 +173,7 @@ def duthost_bgp_config(duthost, route_type,): """ 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 @@ -170,21 +185,21 @@ def duthost_bgp_config(duthost, peer_ip = 'peer_ip' ip = 'ip' prefix = 'prefix' - address_type = ['ip','ipv4'] + address_type = ['ip', 'ipv4'] else: peer_ip = 'peer_ipv6' ip = 'ipv6' prefix = 'ipv6_prefix' - address_type = ['ipv6','ipv6'] - for i in range(0,port_count): + address_type = ['ipv6', 'ipv6'] + for i in range(0, port_count): intf_config = ( "vtysh " "-c 'configure terminal' " "-c 'interface %s' " "-c '%s address %s/%s' " ) - intf_config %= (tgen_ports[i]['peer_port'],address_type[0],tgen_ports[i][peer_ip],tgen_ports[i][prefix]) - logger.info('Configuring IP Address %s' %tgen_ports[i][ip]) + intf_config %= (tgen_ports[i]['peer_port'], address_type[0], tgen_ports[i][peer_ip], tgen_ports[i][prefix]) + logger.info('Configuring IP Address %s' % tgen_ports[i][ip]) duthost.shell(intf_config) bgp_config = ( "vtysh " @@ -194,9 +209,9 @@ def duthost_bgp_config(duthost, "-c 'maximum-paths %s' " "-c 'exit' " ) - bgp_config %= (DUT_AS_NUM,multipath) + bgp_config %= (DUT_AS_NUM, multipath) duthost.shell(bgp_config) - for i in range(1,port_count): + for i in range(1, port_count): bgp_config_neighbor = ( "vtysh " "-c 'configure terminal' " @@ -205,9 +220,9 @@ def duthost_bgp_config(duthost, "-c 'address-family %s unicast' " "-c 'neighbor %s activate' " "-c 'exit' " - ) - bgp_config_neighbor %= (DUT_AS_NUM,tgen_ports[i][ip],TGEN_AS_NUM,address_type[1],tgen_ports[i][ip]) - logger.info('Configuring BGP Neighbor %s' %tgen_ports[i][ip]) + ) + bgp_config_neighbor %= (DUT_AS_NUM, tgen_ports[i][ip], TGEN_AS_NUM, address_type[1], tgen_ports[i][ip]) + logger.info('Configuring BGP Neighbor %s' % tgen_ports[i][ip]) duthost.shell(bgp_config_neighbor) @@ -218,7 +233,7 @@ def __tgen_bgp_config(cvg_api, route_type,): """ Creating BGP config on TGEN - + Args: cvg_api (pytest fixture): snappi API tgen_ports (pytest fixture): Ports mapping info of T0 testbed @@ -228,9 +243,9 @@ def __tgen_bgp_config(cvg_api, """ conv_config = cvg_api.convergence_config() config = conv_config.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) + 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) config.devices[i-1].container_name = config.ports[i-1].name config.options.port_options.location_preemption = True @@ -251,30 +266,30 @@ def create_v4_topo(): config.devices[0].ethernet.ipv4.gateway = tgen_ports[0]['peer_ip'] config.devices[0].ethernet.ipv4.prefix = int(tgen_ports[0]['prefix']) rx_flow_name = [] - for i in range(2,port_count+1): + for i in range(2, port_count+1): if len(str(hex(i).split('0x')[1])) == 1: m = '0'+hex(i).split('0x')[1] else: m = hex(i).split('0x')[1] ethernet_stack = config.devices[i-1].ethernet - ethernet_stack.name = 'Ethernet %d'%i - ethernet_stack.mac = "00:00:00:00:00:%s"%m + ethernet_stack.name = 'Ethernet %d' % i + ethernet_stack.mac = "00:00:00:00:00:%s" % m ipv4_stack = ethernet_stack.ipv4 - ipv4_stack.name = 'IPv4 %d'%i + ipv4_stack.name = 'IPv4 %d' % i ipv4_stack.address = tgen_ports[i-1]['ip'] ipv4_stack.gateway = tgen_ports[i-1]['peer_ip'] ipv4_stack.prefix = int(tgen_ports[i-1]['prefix']) bgpv4_stack = ipv4_stack.bgpv4 - bgpv4_stack.name = 'BGP %d'%i + bgpv4_stack.name = 'BGP %d' % i bgpv4_stack.as_type = BGP_TYPE bgpv4_stack.dut_address = tgen_ports[i-1]['peer_ip'] bgpv4_stack.local_address = tgen_ports[i-1]['ip'] bgpv4_stack.as_number = int(TGEN_AS_NUM) - route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name = "Network Group %d"%i)[-1] - route_range.addresses.bgpv4routeaddress(address = '200.1.0.1', prefix = 32, count = number_of_routes, step = 1) + route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group %d" % i)[-1] + route_range.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=number_of_routes) rx_flow_name.append(route_range.name) return rx_flow_name - + def create_v6_topo(): config.devices[0].ethernet.name = 'Ethernet 1' config.devices[0].ethernet.mac = "00:00:00:00:00:01" @@ -283,36 +298,36 @@ def create_v6_topo(): config.devices[0].ethernet.ipv6.gateway = tgen_ports[0]['peer_ipv6'] config.devices[0].ethernet.ipv6.prefix = int(tgen_ports[0]['ipv6_prefix']) rx_flow_name = [] - for i in range(2,port_count+1): + for i in range(2, port_count+1): if len(str(hex(i).split('0x')[1])) == 1: m = '0'+hex(i).split('0x')[1] else: m = hex(i).split('0x')[1] ethernet_stack = config.devices[i-1].ethernet - ethernet_stack.name = 'Ethernet %d'%i - ethernet_stack.mac = "00:00:00:00:00:%s"%m + ethernet_stack.name = 'Ethernet %d' % i + ethernet_stack.mac = "00:00:00:00:00:%s" % m ipv6_stack = ethernet_stack.ipv6 - ipv6_stack.name = 'IPv6 %d'%i + ipv6_stack.name = 'IPv6 %d' % i ipv6_stack.address = tgen_ports[i-1]['ipv6'] ipv6_stack.gateway = tgen_ports[i-1]['peer_ipv6'] ipv6_stack.prefix = int(tgen_ports[i-1]['ipv6_prefix']) bgpv6_stack = ipv6_stack.bgpv6 - bgpv6_stack.name = r'BGP+ %d'%i + bgpv6_stack.name = r'BGP+ %d' % i bgpv6_stack.as_type = BGP_TYPE bgpv6_stack.dut_address = tgen_ports[i-1]['peer_ipv6'] bgpv6_stack.local_address = tgen_ports[i-1]['ipv6'] bgpv6_stack.as_number = int(TGEN_AS_NUM) - route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name = "Network Group %d"%i)[-1] - route_range.addresses.bgpv6routeaddress(address = '3000::1', prefix = 64, count = number_of_routes, step = 1) + route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group %d" % i)[-1] + route_range.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=number_of_routes) rx_flow_name.append(route_range.name) return rx_flow_name - + if route_type == 'IPv4': rx_flows = create_v4_topo() - flow = config.flows.flow(name = 'IPv4 Traffic')[-1] + flow = config.flows.flow(name='IPv4 Traffic')[-1] elif route_type == 'IPv6': rx_flows = create_v6_topo() - flow = config.flows.flow(name = 'IPv6 Traffic')[-1] + flow = config.flows.flow(name='IPv6 Traffic')[-1] else: raise Exception('Invalid route type given') flow.tx_rx.device.tx_names = [config.devices[0].name] @@ -321,15 +336,17 @@ def create_v6_topo(): flow.rate.percentage = 100 flow.metrics.enable = True return conv_config - + + def get_flow_stats(cvg_api): - """ - Args: - cvg_api (pytest fixture): Snappi API - """ - request = cvg_api.convergence_request() - request.metrics.flow_names = [] - return cvg_api.get_results(request).flow_metric + """ + Args: + cvg_api (pytest fixture): Snappi API + """ + request = cvg_api.convergence_request() + request.metrics.flow_names = [] + return cvg_api.get_results(request).flow_metric + def get_convergence_for_local_link_failover(cvg_api, bgp_config, @@ -347,9 +364,8 @@ def get_convergence_for_local_link_failover(cvg_api, route_type: IPv4 or IPv6 routes """ rx_port_names = [] - bgp_config.convergence_event = (bgp_config.LINK_UP_DOWN) cvg_api.set_config(bgp_config) - for i in range(1,len(bgp_config.config.ports)): + for i in range(1, len(bgp_config.config.ports)): rx_port_names.append(bgp_config.config.ports[i].name) def get_avg_dpdp_convergence_time(port_name, @@ -360,70 +376,74 @@ def get_avg_dpdp_convergence_time(port_name, rx_port_names:List of rx port names """ - table,avg,tx_frate,rx_frate = [],[],[],[] - for i in range(0,iteration): - logger.info('|---- {} Link Flap Iteration : {} ----|'.format(port_name,i+1)) + table, avg, tx_frate, rx_frate = [], [], [], [] + for i in range(0, iteration): + logger.info('|---- {} Link Flap Iteration : {} ----|'.format(port_name, i+1)) - #Start Traffic + """ Starting Traffic """ logger.info('Starting Traffic') cs = cvg_api.convergence_state() cs.transmit.state = cs.transmit.START cvg_api.set_state(cs) - wait(TIMEOUT,"For Traffic To start") + wait(TIMEOUT, "For Traffic To start") flow_stats = get_flow_stats(cvg_api) tx_frame_rate = flow_stats[0].frames_tx_rate - assert tx_frame_rate != 0,"Traffic has not started" + assert tx_frame_rate != 0, "Traffic has not started" - #Link Flap + """ Flapping Link """ logger.info('Simulating Link Failure on {} link'.format(port_name)) cs = cvg_api.convergence_state() cs.link.port_names = [port_name] cs.link.state = cs.link.DOWN cvg_api.set_state(cs) - wait(TIMEOUT,"For Link to go down") + wait(TIMEOUT, "For Link to go down") flows = get_flow_stats(cvg_api) for flow in flows: tx_frate.append(flow.frames_tx_rate) rx_frate.append(flow.frames_tx_rate) - assert sum(tx_frate) == sum(rx_frate),"Traffic has not converged after link flap: TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate),sum(rx_frate)) + assert sum(tx_frate) == sum(rx_frate), "Traffic has not converged after link flap: TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate)) logger.info("Traffic has converged after link flap") tx_frame_rate = flow_stats[0].frames_tx_rate - # Stop traffic + """ Stopping traffic """ logger.info('Stopping Traffic') cs = cvg_api.convergence_state() cs.transmit.state = cs.transmit.STOP cvg_api.set_state(cs) - wait(TIMEOUT,"For Traffic To Stop") + wait(TIMEOUT, "For Traffic To Stop") flow_stats = get_flow_stats(cvg_api) assert flow_stats[0].frames_tx_rate == 0 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 Convergence Time: {} ms".format(round(dp_convergence,3))) - avg.append(round(dp_convergence,3)) - logger.info('Simulating Link Up on {} at the end of iteration {}'.format(port_name,i+1)) - - #Performing link up at the end of iteration + + logger.info('Simulating Link Up on {} at the end of iteration {}'.format(port_name, i+1)) + """ Get control plane to data plane convergence value """ + request = cvg_api.convergence_request() + request.convergence.flow_names = [] + convergence_metrics = cvg_api.get_results(request).flow_convergence + for metrics in convergence_metrics: + logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) + avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) + + """ Performing link up at the end of iteration """ cs = cvg_api.convergence_state() cs.link.port_names = [port_name] cs.link.state = cs.link.UP cvg_api.set_state(cs) - table.append('%s Link Failure'%port_name) + table.append('%s Link Failure' % port_name) table.append(route_type) table.append(number_of_routes) table.append(iteration) table.append(mean(avg)) return table table = [] - #Iterating link flap test on all the rx ports - for i,port_name in enumerate(rx_port_names): - table.append(get_avg_dpdp_convergence_time(port_name,rx_port_names)) - - columns = ['Event Name','Route Type','No. of Routes','Iterations','Avg Calculated Data Convergence Time (ms)'] - logger.info("\n%s" % tabulate(table,headers = columns,tablefmt = "psql")) + """ Iterating link flap test on all the rx ports """ + for i, port_name in enumerate(rx_port_names): + table.append(get_avg_dpdp_convergence_time(port_name, rx_port_names)) + + columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Calculated Data Convergence Time (ms)'] + logger.info("\n%s" % tabulate(table, headers=columns, stablefmt="psql")) + def get_convergence_for_remote_link_failover(cvg_api, bgp_config, @@ -443,7 +463,7 @@ def get_convergence_for_remote_link_failover(cvg_api, route_names = [] for device in bgp_config.config.devices: if device.name not in ['Topology 1']: - if route_type =='IPv4': + if route_type == 'IPv4': for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: route_names.append(route.name) else: @@ -452,7 +472,7 @@ def get_convergence_for_remote_link_failover(cvg_api, bgp_config.rx_rate_threshold = 90/(multipath-1) bgp_config.convergence_event = (bgp_config.ROUTE_ADVERTISE_WITHDRAW) cvg_api.set_config(bgp_config) - + def get_avg_cpdp_convergence_time(route_name): """ @@ -460,35 +480,35 @@ def get_avg_cpdp_convergence_time(route_name): route_name: name of the route """ - table,avg,tx_frate,rx_frate = [],[],[],[] - for i in range(0,iteration): - logger.info('|---- {} Route Withdraw Iteration : {} ----|'.format(route_name,i+1)) + table, avg, tx_frate, rx_frate = [], [], [], [] + for i in range(0, iteration): + logger.info('|---- {} Route Withdraw Iteration : {} ----|'.format(route_name, i+1)) - #Start Traffic + """ Starting Traffic """ logger.info('Starting Traffic') cs = cvg_api.convergence_state() cs.transmit.state = cs.transmit.START cvg_api.set_state(cs) - wait(TIMEOUT,"For Traffic To start") + wait(TIMEOUT, "For Traffic To start") flow_stats = get_flow_stats(cvg_api) tx_frame_rate = flow_stats[0].frames_tx_rate - assert tx_frame_rate != 0,"Traffic has not started" + assert tx_frame_rate != 0, "Traffic has not started" - #Withdraw routes from a BGP peer + """ Withdrawing routes from a BGP peer """ logger.info('Withdrawing Routes from {}'.format(route_name)) cs = cvg_api.convergence_state() cs.route.names = [route_name] cs.route.state = cs.route.WITHDRAW cvg_api.set_state(cs) - wait(TIMEOUT,"For routes to be withdrawn") + wait(TIMEOUT, "For routes to be withdrawn") flows = get_flow_stats(cvg_api) for flow in flows: tx_frate.append(flow.frames_tx_rate) rx_frate.append(flow.frames_tx_rate) - assert sum(tx_frate) == sum(rx_frate),"Traffic has not converged after lroute withdraw TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate),sum(rx_frate)) + assert sum(tx_frate) == sum(rx_frate), "Traffic has not converged after lroute withdraw TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate)) logger.info("Traffic has converged after route withdraw") - - #Get control plane to data plane convergence + + """ Get control plane to data plane convergence value """ request = cvg_api.convergence_request() request.convergence.flow_names = [] convergence_metrics = cvg_api.get_results(request).flow_convergence @@ -496,28 +516,29 @@ def get_avg_cpdp_convergence_time(route_name): logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) - #Advertise the routes back at the end of iteration + """ Advertise the routes back at the end of iteration """ cs = cvg_api.convergence_state() cs.route.names = [route_name] cs.route.state = cs.route.ADVERTISE cvg_api.set_state(cs) - logger.info('Readvertise {} routes back at the end of iteration {}'.format(route_name,i+1)) - - table.append('%s route withdraw'%route_name) + logger.info('Readvertise {} routes back at the end of iteration {}'.format(route_name, i+1)) + + table.append('%s route withdraw' % route_name) table.append(route_type) table.append(number_of_routes) table.append(iteration) table.append(mean(avg)) return table table = [] - #Iterating route withdrawal on all BGP peers + """ Iterating route withdrawal on all BGP peers """ for route in route_names: table.append(get_avg_cpdp_convergence_time(route)) - - columns = ['Event Name','Route Type','No. of Routes','Iterations','Avg Control to Data Plane Convergence Time (ms)'] - logger.info("\n%s" % tabulate(table,headers = columns,tablefmt = "psql")) -def get_RIB_IN_convergence(cvg_api, + columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Control to Data Plane Convergence Time (ms)'] + logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) + + +def get_rib_in_convergence(cvg_api, bgp_config, iteration, multipath, @@ -532,7 +553,6 @@ def get_RIB_IN_convergence(cvg_api, number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes """ - #anish route_names = [] for device in bgp_config.config.devices: if device.name not in ['Topology 1']: @@ -543,79 +563,75 @@ def get_RIB_IN_convergence(cvg_api, for route in device.ethernet.ipv6.bgpv6.bgpv6_routes: route_names.append(route.name) bgp_config.rx_rate_threshold = 90/(multipath) - bgp_config.convergence_event = (bgp_config.ROUTE_ADVERTISE_WITHDRAW) - #anish - #cvg_api.set_config(cvg_api.config()) cvg_api.set_config(bgp_config) - - table,avg,tx_frate,rx_frate = [],[],[],[] - for i in range(0,iteration): + table, avg, tx_frate, rx_frate = [], [], [], [] + for i in range(0, iteration): logger.info('|---- RIB-IN Convergence test, Iteration : {} ----|'.format(i+1)) - - #withdraw all routes before starting traffic + """ withdraw all routes before starting traffic """ logger.info('Withdraw All Routes before starting traffic') cs = cvg_api.convergence_state() cs.route.names = route_names cs.route.state = cs.route.WITHDRAW cvg_api.set_state(cs) - wait(TIMEOUT,"For Routes to be withdrawn") + wait(TIMEOUT, "For Routes to be withdrawn") - #Start Traffic + """ Start Traffic """ logger.info('Starting Traffic') cs = cvg_api.convergence_state() cs.transmit.state = cs.transmit.START cvg_api.set_state(cs) - wait(TIMEOUT,"For Traffic To start") + wait(TIMEOUT, "For Traffic To start") flow_stats = get_flow_stats(cvg_api) tx_frame_rate = flow_stats[0].frames_tx_rate rx_frame_rate = flow_stats[0].frames_rx_rate - assert tx_frame_rate != 0,"Traffic has not started" + assert tx_frame_rate != 0, "Traffic has not started" assert rx_frame_rate == 0 - #Advertise All Routes + """ Advertise All Routes """ logger.info('Advertising all Routes from {}'.format(route_names)) cs = cvg_api.convergence_state() cs.route.names = route_names cs.route.state = cs.route.ADVERTISE cvg_api.set_state(cs) - wait(TIMEOUT,"For all routes to be ADVERTISED") + wait(TIMEOUT, "For all routes to be ADVERTISED") flows = get_flow_stats(cvg_api) for flow in flows: tx_frate.append(flow.frames_tx_rate) rx_frate.append(flow.frames_tx_rate) - assert sum(tx_frate) == sum(rx_frate),"Traffic has not convergedv, TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate),sum(rx_frate)) + assert sum(tx_frate) == sum(rx_frate), "Traffic has not convergedv, TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate)) logger.info("Traffic has converged after route advertisement") - - #Get RIB-IN convergence + + """ Get RIB-IN convergence """ request = cvg_api.convergence_request() request.convergence.flow_names = [] convergence_metrics = cvg_api.get_results(request).flow_convergence for metrics in convergence_metrics: logger.info('RIB-IN Convergence time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) - #Stop traffic at the end of iteration + + """ Stop traffic at the end of iteration """ logger.info('Stopping Traffic at the end of iteration{}'.format(i+1)) cs = cvg_api.convergence_state() cs.transmit.state = cs.transmit.STOP cvg_api.set_state(cs) - wait(TIMEOUT,"For Traffic To stop") - + wait(TIMEOUT, "For Traffic To stop") table.append('Advertise All BGP Routes') table.append(route_type) table.append(number_of_routes) table.append(iteration) table.append(mean(avg)) - columns = ['Event Name','Route Type','No. of Routes','Iterations','Avg RIB-IN Convergence Time(ms)'] - logger.info("\n%s" % tabulate([table],headers = columns,tablefmt = "psql")) - + columns = ['Event Name', 'Route Type', 'No. of Routes','Iterations', 'Avg RIB-IN Convergence Time(ms)'] + logger.info("\n%s" % tabulate([table], headers=columns, tablefmt="psql")) + + def cleanup_config(duthost, tgen_ports, port_count, route_type,): """ Cleaning up dut config at the end of the test - + Args: duthost (pytest fixture): duthost fixture tgen_ports (pytest fixture): Ports mapping info of T0 testbed @@ -638,13 +654,13 @@ def cleanup_config(duthost, ) bgp_config_cleanup %= (DUT_AS_NUM) duthost.shell(bgp_config_cleanup) - for i in range(0,port_count): + for i in range(0, port_count): intf_config_cleanup = ( "vtysh " "-c 'configure terminal' " "-c 'interface %s' " "-c 'no %s address %s/%s' " ) - intf_config_cleanup %= (tgen_ports[i]['peer_port'],ip,tgen_ports[i][peer_ip],tgen_ports[i][prefix]) + intf_config_cleanup %= (tgen_ports[i]['peer_port'], ip, tgen_ports[i][peer_ip], tgen_ports[i][prefix]) duthost.shell(intf_config_cleanup) logger.info('Convergence Test Completed') diff --git a/tests/ixia/bgp/test_bgp_local_link_failover.py b/tests/ixia/bgp/test_bgp_local_link_failover.py index 478f658275c..ad06d3963e4 100644 --- a/tests/ixia/bgp/test_bgp_local_link_failover.py +++ b/tests/ixia/bgp/test_bgp_local_link_failover.py @@ -1,4 +1,3 @@ -#from tests.common.snappi.snappi_fixtures import snappi_api from tests.common.snappi.snappi_fixtures import cvg_api from tests.common.snappi.snappi_fixtures import ( snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) @@ -7,10 +6,11 @@ conn_graph_facts, fanout_graph_facts) import pytest -@pytest.mark.parametrize('multipath',[2]) -@pytest.mark.parametrize('convergence_test_iterations',[1]) -@pytest.mark.parametrize('number_of_routes',[4000]) -@pytest.mark.parametrize('route_type',['IPv4','IPv6']) + +@pytest.mark.parametrize('multipath', [2]) +@pytest.mark.parametrize('convergence_test_iterations', [1]) +@pytest.mark.parametrize('number_of_routes', [1000]) +@pytest.mark.parametrize('route_type', ['IPv4']) def test_bgp_convergence_for_local_link_failover(cvg_api, duthost, tgen_ports, @@ -34,10 +34,10 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, 6) Clean up the BGP config on the dut Verification: - 1) Send traffic without flapping any link - Result: Should not observe traffic loss + 1) Send traffic without flapping any link + Result: Should not observe traffic loss 2) Flap one of the N TGEN link - Result: The traffic must be routed via rest of the ECMP paths and should not observe traffic loss + Result: The traffic must be routed via rest of the ECMP paths Args: cvg_api (pytest fixture): Snappi Convergence API @@ -50,11 +50,11 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes """ - #convergence_test_iterations and multipath values can be modified as per user preference + #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference run_bgp_local_link_failover_test(cvg_api, - duthost, - tgen_ports, - convergence_test_iterations, - multipath, - number_of_routes, - route_type,) + duthost, + tgen_ports, + convergence_test_iterations, + multipath, + number_of_routes, + route_type,) diff --git a/tests/ixia/bgp/test_bgp_remote_link_failover.py b/tests/ixia/bgp/test_bgp_remote_link_failover.py index 98a38830041..36fa383443b 100755 --- a/tests/ixia/bgp/test_bgp_remote_link_failover.py +++ b/tests/ixia/bgp/test_bgp_remote_link_failover.py @@ -8,8 +8,8 @@ @pytest.mark.parametrize('multipath',[2]) @pytest.mark.parametrize('convergence_test_iterations',[1]) -@pytest.mark.parametrize('number_of_routes',[4000]) -@pytest.mark.parametrize('route_type',['IPv4','IPv6']) +@pytest.mark.parametrize('number_of_routes',[1000]) +@pytest.mark.parametrize('route_type',['IPv4']) def test_bgp_convergence_for_remote_link_failover(cvg_api, duthost, tgen_ports, @@ -34,7 +34,7 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, Verification: 1) Send traffic with all routes advertised by BGP peers - Result: Should not observe traffic loss + Result: Should not observe traffic loss 2) Withdraw all routes from one of the BGP peer Result: The traffic must be routed via rest of the ECMP paths and should not observe traffic loss diff --git a/tests/ixia/bgp/test_bgp_rib_in_convergence.py b/tests/ixia/bgp/test_bgp_rib_in_convergence.py index 0e2061afb16..c4b07c3244d 100644 --- a/tests/ixia/bgp/test_bgp_rib_in_convergence.py +++ b/tests/ixia/bgp/test_bgp_rib_in_convergence.py @@ -1,24 +1,25 @@ from tests.common.snappi.snappi_fixtures import cvg_api from tests.common.snappi.snappi_fixtures import ( snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.bgp_convergence_helper import run_RIB_IN_convergence_test +from files.bgp_convergence_helper import run_rib_in_convergence_test from tests.common.fixtures.conn_graph_facts import ( conn_graph_facts, fanout_graph_facts) import pytest -@pytest.mark.parametrize('multipath',[2]) -@pytest.mark.parametrize('convergence_test_iterations',[1]) -@pytest.mark.parametrize('number_of_routes',[1000,2000]) -@pytest.mark.parametrize('route_type',['IPv4','IPv6']) -def test_RIB_IN_convergence(cvg_api, - duthost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - multipath, - convergence_test_iterations, - number_of_routes, - route_type,): + +@pytest.mark.parametrize('multipath', [2]) +@pytest.mark.parametrize('convergence_test_iterations', [1]) +@pytest.mark.parametrize('number_of_routes', [1000]) +@pytest.mark.parametrize('route_type', ['IPv4']) +def test_rib_in_convergence(cvg_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + multipath, + convergence_test_iterations, + number_of_routes, + route_type,): """ Topo: @@ -37,7 +38,7 @@ def test_RIB_IN_convergence(cvg_api, 1) Send traffic after withdrawing routes from all BGP peers Result: Should not observe any traffic in the receiving side 2) Advertise the routes when the traffic is running - Result: The traffic must be routed via the ECMP paths and should not observe any traffic loss + Result: The traffic must be routed via the ECMP paths Args: snappi_api (pytest fixture): Snappi API @@ -50,11 +51,11 @@ def test_RIB_IN_convergence(cvg_api, number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes """ - #convergence_test_iterations and multipath values can be modified as per user preference - run_RIB_IN_convergence_test(cvg_api, - duthost, - tgen_ports, - convergence_test_iterations, - multipath, - number_of_routes, - route_type,) + #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference + run_rib_in_convergence_test(cvg_api, + duthost, + tgen_ports, + convergence_test_iterations, + multipath, + number_of_routes, + route_type,) From 9f706807dfd3052a0d56c5ecfe9f32d56cda50f2 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Mon, 12 Jul 2021 21:25:56 +0000 Subject: [PATCH 12/58] removing unused variables --- tests/ixia/bgp/files/bgp_convergence_helper.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index 909d01aeb89..f0aa30b15c7 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -403,20 +403,6 @@ def get_avg_dpdp_convergence_time(port_name, rx_frate.append(flow.frames_tx_rate) assert sum(tx_frate) == sum(rx_frate), "Traffic has not converged after link flap: TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate)) logger.info("Traffic has converged after link flap") - tx_frame_rate = flow_stats[0].frames_tx_rate - - """ Stopping traffic """ - logger.info('Stopping Traffic') - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.STOP - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To Stop") - flow_stats = get_flow_stats(cvg_api) - assert flow_stats[0].frames_tx_rate == 0 - tx_frames = flow_stats[0].frames_tx - rx_frames = sum([fs.frames_rx for fs in flow_stats]) - - logger.info('Simulating Link Up on {} at the end of iteration {}'.format(port_name, i+1)) """ Get control plane to data plane convergence value """ request = cvg_api.convergence_request() request.convergence.flow_names = [] @@ -426,6 +412,7 @@ def get_avg_dpdp_convergence_time(port_name, avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) """ Performing link up at the end of iteration """ + logger.info('Simulating Link Up on {} at the end of iteration {}'.format(port_name, i+1)) cs = cvg_api.convergence_state() cs.link.port_names = [port_name] cs.link.state = cs.link.UP From 39da3fca7485c6d18471f04f626f692155344a6d Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 13 Jul 2021 19:50:03 +0000 Subject: [PATCH 13/58] Adding RIB-IN capacity test --- tests/ixia/bgp/test_bgp_rib_in_capacity.py | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 tests/ixia/bgp/test_bgp_rib_in_capacity.py diff --git a/tests/ixia/bgp/test_bgp_rib_in_capacity.py b/tests/ixia/bgp/test_bgp_rib_in_capacity.py new file mode 100644 index 00000000000..5af5447946e --- /dev/null +++ b/tests/ixia/bgp/test_bgp_rib_in_capacity.py @@ -0,0 +1,60 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.bgp_convergence_helper import run_RIB_IN_capacity_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('multipath', [2]) +@pytest.mark.parametrize('start_value', [10000]) +@pytest.mark.parametrize('step_value', [5000]) +@pytest.mark.parametrize('route_type', ['IPv4']) +def test_RIB_IN_capacity(cvg_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + multipath, + start_value, + step_value, + route_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create a BGP config on DUT and TGEN respectively + 2) Create a flow from TGEN1 to TGEN2 port + 3) Send Traffic from TGEN1 to TGEN2 port route range + 4) Check if there is any loss observed + 5) Increment the routes in terms of step_value and repeat test untill loss is observed + 6) Note down the number of routes upto which no loss was observed which is the RIB-IN capacity value + 7) Clean up the BGP config on the dut + Note: + confihgure DUT interfaces prior to running test + Verification: + 1) Send traffic and make sure there is no loss observed + 2) If loss is observed quit the test and note down the maximum routes upto which there was no loss + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + multipath: ECMP value + start_value: Start value of the number of BGP routes + step_value: Step value of the number of BGP routes to be incremented + route_type: IPv4 or IPv6 routes + """ + #multipath, start_value, step_value and route_type parameters can be modified as per user preference + run_RIB_IN_capacity_test(cvg_api, + duthost, + tgen_ports, + multipath, + start_value, + step_value, + route_type,) From 96f4c7caa3d611726095520343e2dff6c96727f8 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 13 Jul 2021 19:52:07 +0000 Subject: [PATCH 14/58] final changes --- .../ixia/bgp/files/bgp_convergence_helper.py | 186 ++++++++++++++++++ .../ixia/bgp/test_bgp_remote_link_failover.py | 2 +- 2 files changed, 187 insertions(+), 1 deletion(-) diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index f0aa30b15c7..ed8a8562ae9 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -166,6 +166,50 @@ def run_rib_in_convergence_test(cvg_api, route_type,) +def run_RIB_IN_capacity_test(cvg_api, + duthost, + tgen_ports, + multipath, + start_value, + step_value, + route_type,): + + """ + Run RIB-IN Capacity test + + Args: + cvg_api (pytest fixture): snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + multipath: ecmp value for BGP config + start_value: + step_value: + route_type: IPv4 or IPv6 routes + """ + port_count = multipath+1 + """ Create bgp config on dut """ + duthost_bgp_config(duthost, + tgen_ports, + port_count, + multipath, + route_type,) + + + """ Run the RIB-IN capacity test by increasig the route count step by step """ + get_RIB_IN_capacity(cvg_api, + tgen_ports, + multipath, + start_value, + step_value, + route_type,) + + """ Cleanup the dut configs after getting the convergence numbers """ + cleanup_config(duthost, + tgen_ports, + port_count, + route_type,) + + def duthost_bgp_config(duthost, tgen_ports, port_count, @@ -612,6 +656,148 @@ def get_rib_in_convergence(cvg_api, logger.info("\n%s" % tabulate([table], headers=columns, tablefmt="psql")) +def get_RIB_IN_capacity(cvg_api, + tgen_ports, + multipath, + start_value, + step_value, + route_type,): + """ + Args: + cvg_api (pytest fixture): snappi API + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + multipath: ecmp value for BGP config + start_value: Start value of the number of BGP routes + step_value: Step value of the number of BGP routes to be incremented + route_type: IPv4 or IPv6 routes + + """ + def tgen_capacity(routes): + conv_config = cvg_api.convergence_config() + config = conv_config.config + for i in range(1, 3): + config.ports.port(name='Test_Port_%d' % i, location=tgen_ports[i-1]['location']) + config.devices.device(name='Topology %d' % i) + config.devices[i-1].container_name = config.ports[i-1].name + + config.options.port_options.location_preemption = True + layer1 = config.layer1.layer1()[-1] + layer1.name = 'port settings' + layer1.port_names = [port.name for port in config.ports] + layer1.ieee_media_defaults = False + layer1.auto_negotiation.rs_fec = True + layer1.auto_negotiation.link_training = False + layer1.speed = "speed_100_gbps" + layer1.auto_negotiate = False + + def create_v4_topo(): + config.devices[0].ethernet.name = 'Ethernet 1_%d' % routes + config.devices[0].ethernet.mac = "00:00:00:00:00:01" + config.devices[0].ethernet.ipv4.name = 'IPv4 1_%d' % routes + config.devices[0].ethernet.ipv4.address = tgen_ports[0]['ip'] + config.devices[0].ethernet.ipv4.gateway = tgen_ports[0]['peer_ip'] + config.devices[0].ethernet.ipv4.prefix = int(tgen_ports[0]['prefix']) + rx_flow_name = [] + for i in range(2, 3): + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] + else: + m = hex(i).split('0x')[1] + ethernet_stack = config.devices[i-1].ethernet + ethernet_stack.name = 'Ethernet_%d_%d' % (i, routes) + ethernet_stack.mac = "00:00:00:00:00:%s" % m + ipv4_stack = ethernet_stack.ipv4 + ipv4_stack.name = 'IPv4_%d_%d' % (i, routes) + ipv4_stack.address = tgen_ports[i-1]['ip'] + ipv4_stack.gateway = tgen_ports[i-1]['peer_ip'] + ipv4_stack.prefix = int(tgen_ports[i-1]['prefix']) + bgpv4_stack = ipv4_stack.bgpv4 + bgpv4_stack.name = 'BGP_%d_%d' % (i, routes) + bgpv4_stack.as_type = BGP_TYPE + bgpv4_stack.dut_address = tgen_ports[i-1]['peer_ip'] + bgpv4_stack.local_address = tgen_ports[i-1]['ip'] + bgpv4_stack.as_number = int(TGEN_AS_NUM) + route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group %d_%d" % (i, routes))[-1] + route_range.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=routes) + rx_flow_name.append(route_range.name) + return rx_flow_name + + def create_v6_topo(): + config.devices[0].ethernet.name = 'Ethernet 1' + config.devices[0].ethernet.mac = "00:00:00:00:00:01" + config.devices[0].ethernet.ipv6.name = 'IPv6 1' + config.devices[0].ethernet.ipv6.address = tgen_ports[0]['ipv6'] + config.devices[0].ethernet.ipv6.gateway = tgen_ports[0]['peer_ipv6'] + config.devices[0].ethernet.ipv6.prefix = int(tgen_ports[0]['ipv6_prefix']) + rx_flow_name = [] + for i in range(2, 3): + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] + else: + m = hex(i).split('0x')[1] + ethernet_stack = config.devices[i-1].ethernet + ethernet_stack.name = 'Ethernet %d' % i + ethernet_stack.mac = "00:00:00:00:00:%s" % m + ipv6_stack = ethernet_stack.ipv6 + ipv6_stack.name = 'IPv6 %d' % i + ipv6_stack.address = tgen_ports[i-1]['ipv6'] + ipv6_stack.gateway = tgen_ports[i-1]['peer_ipv6'] + ipv6_stack.prefix = int(tgen_ports[i-1]['ipv6_prefix']) + bgpv6_stack = ipv6_stack.bgpv6 + bgpv6_stack.name = r'BGP+ %d' % i + bgpv6_stack.as_type = BGP_TYPE + bgpv6_stack.dut_address = tgen_ports[i-1]['peer_ipv6'] + bgpv6_stack.local_address = tgen_ports[i-1]['ipv6'] + bgpv6_stack.as_number = int(TGEN_AS_NUM) + route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group %d_%d" % (routes, i))[-1] + route_range.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=routes) + rx_flow_name.append(route_range.name) + return rx_flow_name + conv_config.rx_rate_threshold = 90/(multipath) + if route_type == 'IPv4': + rx_flows = create_v4_topo() + flow = config.flows.flow(name='IPv4_Traffic_%d' % routes)[-1] + elif route_type == 'IPv6': + rx_flows = create_v6_topo() + flow = config.flows.flow(name='IPv6_Traffic_%d' % routes)[-1] + else: + raise Exception('Invalid route type given') + flow.tx_rx.device.tx_names = [config.devices[0].name] + flow.tx_rx.device.rx_names = rx_flows + flow.size.fixed = 1024 + flow.rate.percentage = 100 + flow.metrics.enable = True + flow.metrics.loss = True + return conv_config + + for j in range(start_value, 100000000000, step_value): + logger.info('|-------------------- RIB-IN Capacity test, No.of Routes : {} ----|'.format(j)) + conv_config = tgen_capacity(j) + cvg_api.set_config(conv_config) + + """ Starting Traffic """ + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To start") + flow_stats = get_flow_stats(cvg_api) + logger.info('Loss% : {}'.format(flow_stats[0].loss)) + logger.info('Stopping Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.STOP + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To stop") + if float(flow_stats[0].loss)>0.1: + if start_value == j: + max_routes = 'N/A' + raise Exception('FAIL: Loss observed in start value itself, set the start value less than : {} !!!!!!!!!!!!'.format(start_value)) + else: + max_routes = j-step_value + logger.info('max_routes :{}'.format(max_routes)) + break + logger.info('|------------ Max Routes without loss (RIB-IN Capacity Value) : {} ----|'.format(max_routes)) + def cleanup_config(duthost, tgen_ports, port_count, diff --git a/tests/ixia/bgp/test_bgp_remote_link_failover.py b/tests/ixia/bgp/test_bgp_remote_link_failover.py index 36fa383443b..e1357f55d21 100755 --- a/tests/ixia/bgp/test_bgp_remote_link_failover.py +++ b/tests/ixia/bgp/test_bgp_remote_link_failover.py @@ -49,7 +49,7 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes """ - #convergence_test_iterations and multipath values can be modified as per user preference + #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference run_bgp_remote_link_failover_test(cvg_api, duthost, tgen_ports, From 20e20be0e2d91a92003106b7a21233ae83639de8 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 13 Jul 2021 19:57:45 +0000 Subject: [PATCH 15/58] Doc changes --- .../BGP-Convergence-Testplan-for-Benchmark-Performance.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md index f9b99950221..204816ff7fa 100644 --- a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md +++ b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md @@ -106,7 +106,7 @@ For above test case, below are the test results when multiple remote link fails. | Withdraw Routes | 16K | 7176 | ### Test Case -sonic-mgmt/tests/ixia/bgp/test_bgp_remote_link_failover.py +* sonic-mgmt/tests/ixia/bgp/test_bgp_remote_link_failover.py ### Test case # 2 – RIB-IN Convergence #### Test objective Measure the convergence time to install the routes in its RIB and then in its FIB to forward the packets after the routes are advertised. @@ -151,7 +151,8 @@ In order to measure RIB-IN capacity of the switch, we can follow the same test m | Advertise Routes | 194K | 83285 | 0 | ### Test Case -sonic-mgmt/tests/ixia/bgp/test_bgp_rib_in_convergence.py +* sonic-mgmt/tests/ixia/bgp/test_bgp_rib_in_convergence.py +* sonic-mgmt/tests/ixia/bgp/test_bgp_rib_in_capacity.py ### Test case # 3 - Failover convergence with local link failure #### Test objective Measure the convergence time when local link failure event happens with in the network. @@ -183,7 +184,7 @@ Below table is the result of 3 way ECMP for 4 link flap iterations | Test_Port_4 Link Failure | 1000 | 4 | 4.219 | ### Test Case -sonic-mgmt/tests/ixia/bgp/test_bgp_local_link_failover.py +* sonic-mgmt/tests/ixia/bgp/test_bgp_local_link_failover.py ### Call for action * Solicit experience in multi-DUT system test scenarios. From b1bcae538ae1121d7b9ef8045606de92f794771d Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 14 Jul 2021 18:26:13 +0000 Subject: [PATCH 16/58] thresholdixia/bgp/test_bgp_local_link_failover.py --- ...Convergence-Testplan-for-Benchmark-Performance.md | 6 +++--- tests/ixia/bgp/files/bgp_convergence_helper.py | 12 +++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md index 204816ff7fa..f15a9257fa3 100644 --- a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md +++ b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md @@ -179,9 +179,9 @@ Measure the convergence time when local link failure event happens with in the n Below table is the result of 3 way ECMP for 4 link flap iterations | Event Name | No. of IPv4 Routes | Iterations | Avg Calculated Data Convergence Time(ms) | | :---: | :-: | :-: | :-: | -| Test_Port_2 Link Failure | 1000 | 4 | 4.112 | -| Test_Port_3 Link Failure | 1000 | 4 | 4.336 | -| Test_Port_4 Link Failure | 1000 | 4 | 4.219 | +| Test_Port_2 Link Failure | 1000 | 4 | 14.112 | +| Test_Port_3 Link Failure | 1000 | 4 | 14.336 | +| Test_Port_4 Link Failure | 1000 | 4 | 14.219 | ### Test Case * sonic-mgmt/tests/ixia/bgp/test_bgp_local_link_failover.py diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index ed8a8562ae9..b271b80225a 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -408,16 +408,14 @@ def get_convergence_for_local_link_failover(cvg_api, route_type: IPv4 or IPv6 routes """ rx_port_names = [] - cvg_api.set_config(bgp_config) for i in range(1, len(bgp_config.config.ports)): rx_port_names.append(bgp_config.config.ports[i].name) - - def get_avg_dpdp_convergence_time(port_name, - rx_port_names): + bgp_config.rx_rate_threshold = 90/(multipath-1) + cvg_api.set_config(bgp_config) + def get_avg_dpdp_convergence_time(port_name): """ Args: port_name: Name of the port - rx_port_names:List of rx port names """ table, avg, tx_frate, rx_frate = [], [], [], [] @@ -470,8 +468,8 @@ def get_avg_dpdp_convergence_time(port_name, table = [] """ Iterating link flap test on all the rx ports """ for i, port_name in enumerate(rx_port_names): - table.append(get_avg_dpdp_convergence_time(port_name, rx_port_names)) - + #table.append(get_avg_dpdp_convergence_time(port_name, rx_port_names)) + table.append(get_avg_dpdp_convergence_time(port_name)) columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Calculated Data Convergence Time (ms)'] logger.info("\n%s" % tabulate(table, headers=columns, stablefmt="psql")) From 697d11bc700b6c2c8656a83be42d6b66d9d2ef4e Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 14 Jul 2021 18:33:52 +0000 Subject: [PATCH 17/58] comment removed --- tests/ixia/bgp/files/bgp_convergence_helper.py | 1 - tests/ixia/bgp/test_bgp_local_link_failover.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index b271b80225a..137da447990 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -468,7 +468,6 @@ def get_avg_dpdp_convergence_time(port_name): table = [] """ Iterating link flap test on all the rx ports """ for i, port_name in enumerate(rx_port_names): - #table.append(get_avg_dpdp_convergence_time(port_name, rx_port_names)) table.append(get_avg_dpdp_convergence_time(port_name)) columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Calculated Data Convergence Time (ms)'] logger.info("\n%s" % tabulate(table, headers=columns, stablefmt="psql")) diff --git a/tests/ixia/bgp/test_bgp_local_link_failover.py b/tests/ixia/bgp/test_bgp_local_link_failover.py index ad06d3963e4..0597555e415 100644 --- a/tests/ixia/bgp/test_bgp_local_link_failover.py +++ b/tests/ixia/bgp/test_bgp_local_link_failover.py @@ -7,9 +7,9 @@ import pytest -@pytest.mark.parametrize('multipath', [2]) +@pytest.mark.parametrize('multipath', [3]) @pytest.mark.parametrize('convergence_test_iterations', [1]) -@pytest.mark.parametrize('number_of_routes', [1000]) +@pytest.mark.parametrize('number_of_routes', [4000]) @pytest.mark.parametrize('route_type', ['IPv4']) def test_bgp_convergence_for_local_link_failover(cvg_api, duthost, From 38f57b0cba30bd3c331ded9d7b050dcce4801001 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 14 Jul 2021 18:44:29 +0000 Subject: [PATCH 18/58] testcase title change --- ...Convergence-Testplan-for-Benchmark-Performance.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md index f15a9257fa3..3df9347587a 100644 --- a/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md +++ b/docs/testplan/BGP-Convergence-Testplan-for-Benchmark-Performance.md @@ -10,17 +10,17 @@ - [Setup configuration](#Setup-configuration) - [Test methodology](#Test-methodology) - [Test cases](#Test-cases) - - [Test case # 1 – Failover convergence with remote link failure (route withdraw)](#test-case--1--convergence-performance-when-remote-link-fails-route-withdraw) + - [Test case # 1 – BGP Remote Link Failover Convergence (route withdraw)](#test-case--1--convergence-performance-when-remote-link-fails-route-withdraw) - [Test objective](#Test-objective) - [Test steps](#Test-steps) - [Test results](#Test-results) - [Test case](#Test-case) - - [Test case # 2 – RIB-IN Convergence](#Test-case--2--RIB-IN-Convergence) + - [Test case # 2 – BGP RIB-IN Convergence](#Test-case--2--RIB-IN-Convergence) - [Test objective](#Test-objective-1) - [Test steps](#Test-steps-1) - [Test results](#Test-results-1) - [Test case](#Test-case-1) - - [Test case # 3 - Failover convergence with local link failure](#Test-case--3--Failover-convergence-with-local-link-failure) + - [Test case # 3 - BGP Local Link Failover Convergence](#Test-case--3--Failover-convergence-with-local-link-failure) - [Test objective](#Test-objective-2) - [Test steps](#Test-steps-2) - [Test results](#Test-results-2) @@ -63,7 +63,7 @@ Following test methodologies will be used for measuring convergence. * Route capacity can be measured by advertising routes in a linear search fashion. By doing this we can figure out the maximum routes a switch can learn and install in its RIB and then in its FIB to forward traffic without any loss. ## Test cases -### Test case # 1 – Convergence performance when remote link fails (route withdraw) +### Test case # 1 – BGP Remote Link Failover Convergence (route withdraw) #### Test objective Measure the convergence time when remote link failure event happens with in the network. @@ -107,7 +107,7 @@ For above test case, below are the test results when multiple remote link fails. ### Test Case * sonic-mgmt/tests/ixia/bgp/test_bgp_remote_link_failover.py -### Test case # 2 – RIB-IN Convergence +### Test case # 2 – BGP RIB-IN Convergence #### Test objective Measure the convergence time to install the routes in its RIB and then in its FIB to forward the packets after the routes are advertised. @@ -153,7 +153,7 @@ In order to measure RIB-IN capacity of the switch, we can follow the same test m ### Test Case * sonic-mgmt/tests/ixia/bgp/test_bgp_rib_in_convergence.py * sonic-mgmt/tests/ixia/bgp/test_bgp_rib_in_capacity.py -### Test case # 3 - Failover convergence with local link failure +### Test case # 3 - BGP Local Link Failover Convergence #### Test objective Measure the convergence time when local link failure event happens with in the network.

From 9c56ec5eb334d2a617cd19a357575cc6bcf959c9 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 14 Jul 2021 19:17:02 +0000 Subject: [PATCH 19/58] resolving alert --- tests/ixia/bgp/files/bgp_convergence_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index 137da447990..6ca3ad352ff 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -788,7 +788,7 @@ def create_v6_topo(): if float(flow_stats[0].loss)>0.1: if start_value == j: max_routes = 'N/A' - raise Exception('FAIL: Loss observed in start value itself, set the start value less than : {} !!!!!!!!!!!!'.format(start_value)) + raise Exception('FAIL:Max Routes: {}, Loss observed in start value itself, set the start value less than : {} !!!!!!!!!!!!'.format(max_routes,start_value)) else: max_routes = j-step_value logger.info('max_routes :{}'.format(max_routes)) From e7390c7d3b50d11dd598e4937c2605a3fe264244 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 27 Jul 2021 05:39:23 +0000 Subject: [PATCH 20/58] resolving merge conflict --- tests/common/snappi/common_helpers.py | 291 ++++++++-------- tests/common/snappi/snappi_fixtures.py | 446 ++++++++++++++++++++----- tests/common/snappi/snappi_helpers.py | 22 +- 3 files changed, 514 insertions(+), 245 deletions(-) diff --git a/tests/common/snappi/common_helpers.py b/tests/common/snappi/common_helpers.py index 5cbb8dc771b..f8a6f48e078 100644 --- a/tests/common/snappi/common_helpers.py +++ b/tests/common/snappi/common_helpers.py @@ -5,7 +5,7 @@ VLAN subnet etc. This file is also a placeholder for auxiliary function that are -required for supporting automation with Ixia devices in future: +required for supporting automation with Snappi devices in future: like collecting diagnostics, uploading and downloading files to/from API server, processing the statistics after obtaining them in .csv format etc. @@ -13,11 +13,10 @@ import ipaddr from netaddr import IPNetwork -from ipaddress import IPv6Network, IPv6Address -from random import getrandbits from tests.common.mellanox_data import is_mellanox_device as isMellanoxDevice -def increment_ip_address(ip, incr=1) : + +def increment_ip_address(ip, incr=1): """ Increment IP address by an integer number. @@ -74,6 +73,7 @@ def get_vlan_subnet(host_ans): gw_addr = ansible_stdout_to_str(mg_vlan_intfs[0]['addr']) return gw_addr + '/' + str(prefix_len) + def get_egress_lossless_buffer_size(host_ans): """ Get egress lossless buffer size of a switch @@ -99,6 +99,7 @@ def get_egress_lossless_buffer_size(host_ans): egress_lossless_pool = buffer_pools[profile_name] return int(egress_lossless_pool['size']) + def get_addrs_in_subnet(subnet, number_of_ip): """ Get N IP addresses in a subnet. @@ -121,86 +122,57 @@ def get_addrs_in_subnet(subnet, number_of_ip): return ip_addrs[:number_of_ip] -def get_ipv6_addrs_in_subnet(subnet, number_of_ip): - """ - Get N IPv6 addresses in a subnet. - Args: - subnet (str): IPv6 subnet, e.g., '2001::1/64' - number_of_ip (int): Number of IP addresses to get - Return: - Return n IPv6 addresses in this subnet in a list. - """ - - subnet = str(IPNetwork(subnet).network) + "/" + str(subnet.split("/")[1]) - subnet = unicode(subnet, "utf-8") - ipv6_list = [] - for i in range(number_of_ip): - network = IPv6Network(subnet) - address = IPv6Address( - network.network_address + getrandbits( - network.max_prefixlen - network.prefixlen)) - ipv6_list.append(str(address)) - - return ipv6_list def get_peer_snappi_chassis(conn_data, dut_hostname): """ - Get the IXIA chassis connected to the DUT - Note that a DUT can only be connected to a IXIA chassis + Get the Snappi chassis connected to the DUT + Note that a DUT can only be connected to a Snappi chassis Args: conn_data (dict): the dictionary returned by conn_graph_fact. Example format of the conn_data is given below: - { - u'device_conn': { - u'msr-s6100-dut-1': { - u'Ethernet0': { - u'peerdevice': u'msr-ixia-1', - u'peerport': u'Card12/Port5', - u'speed': u'40000' - }, - u'Ethernet1': { - u'peerdevice': u'msr-ixia-1', - u'peerport': u'Card12/Port6', - u'speed': u'40000' - }, - u'Ethernet2': { - u'peerdevice': u'msr-ixia-1', - u'peerport': u'Card12/Port7', - u'speed': u'40000' - } - } - }, - u'device_info': [{u'HwSku': u'Dell-S6100', u'Type': u'DevSonic'}], - u'device_port_vlans': [ - { - u'Ethernet0': { - u'mode': u'Access', - u'vlanids': u'', - u'vlanlist': [] - }, - u'Ethernet1': { - u'mode': u'Access', - u'vlanids': u'', - u'vlanlist': [] - }, - u'Ethernet2': { - u'mode': u'Access', - u'vlanids': u'', - u'vlanlist': [] - } - } - ], - u'device_vlan_list': [[]], - u'device_vlan_map_list': {u'msr-s6100-dut-1': []}, - u'device_vlan_range': [[]] - } + {u'device_conn': {u'sonic-s6100-dut': + {u'Ethernet64': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port1', + u'speed': u'100000'}, + u'Ethernet68': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port2', + u'speed': u'100000'}, + u'Ethernet72': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port3', + u'speed': u'100000'}, + u'Ethernet76': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port4', + u'speed': u'100000'}}}, + u'device_console_info': {u'sonic-s6100-dut': {}}, + u'device_console_link': {u'sonic-s6100-dut': {}}, + u'device_info': {u'sonic-s6100-dut': + {u'HwSku': u'Arista-7060CX-32S-C32', + u'Type': u'DevSonic'}}, + u'device_pdu_info': {u'sonic-s6100-dut': {}}, + u'device_pdu_links': {u'sonic-s6100-dut': {}}, + u'device_port_vlans': {u'sonic-s6100-dut': + {u'Ethernet64': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}, + u'Ethernet68': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}, + u'Ethernet72': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}, + u'Ethernet76': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}}}, + u'device_vlan_list': {u'sonic-s6100-dut': [2, 2, 2, 2]}, + u'device_vlan_map_list': {u'sonic-s6100-dut': {u'19': 2}}, + u'device_vlan_range': {u'sonic-s6100-dut': [u'2']}} dut_hostname (str): hostname of the DUT Returns: - The name of the peer IXIA chassis or None + The name of the peer Snappi chassis or None """ device_conn = conn_data['device_conn'] @@ -216,6 +188,7 @@ def get_peer_snappi_chassis(conn_data, dut_hostname): else: return None + def get_peer_port(conn_data, dut_hostname, dut_intf): """ Get the peer port of the DUT port @@ -224,50 +197,42 @@ def get_peer_port(conn_data, dut_hostname, dut_intf): conn_data (dict): the dictionary returned by conn_graph_fact. Example format of the conn_data is given below: - { - u'device_conn': { - u'msr-s6100-dut-1': { - u'Ethernet0': { - u'peerdevice': u'msr-ixia-1', - u'peerport': u'Card12/Port5', - u'speed': u'40000' - }, - u'Ethernet1': { - u'peerdevice': u'msr-ixia-1', - u'peerport': u'Card12/Port6', - u'speed': u'40000' - }, - u'Ethernet2': { - u'peerdevice': u'msr-ixia-1', - u'peerport': u'Card12/Port7', - u'speed': u'40000' - } - } - }, - u'device_info': [{u'HwSku': u'Dell-S6100', u'Type': u'DevSonic'}], - u'device_port_vlans': [ - { - u'Ethernet0': { - u'mode': u'Access', - u'vlanids': u'', - u'vlanlist': [] - }, - u'Ethernet1': { - u'mode': u'Access', - u'vlanids': u'', - u'vlanlist': [] - }, - u'Ethernet2': { - u'mode': u'Access', - u'vlanids': u'', - u'vlanlist': [] - } - } - ], - u'device_vlan_list': [[]], - u'device_vlan_map_list': {u'msr-s6100-dut-1': []}, - u'device_vlan_range': [[]] - } + {u'device_conn': {u'sonic-s6100-dut': + {u'Ethernet64': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port1', + u'speed': u'100000'}, + u'Ethernet68': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port2', + u'speed': u'100000'}, + u'Ethernet72': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port3', + u'speed': u'100000'}, + u'Ethernet76': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port4', + u'speed': u'100000'}}}, + u'device_console_info': {u'sonic-s6100-dut': {}}, + u'device_console_link': {u'sonic-s6100-dut': {}}, + u'device_info': {u'sonic-s6100-dut': + {u'HwSku': u'Arista-7060CX-32S-C32', + u'Type': u'DevSonic'}}, + u'device_pdu_info': {u'sonic-s6100-dut': {}}, + u'device_pdu_links': {u'sonic-s6100-dut': {}}, + u'device_port_vlans': {u'sonic-s6100-dut': + {u'Ethernet64': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}, + u'Ethernet68': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}, + u'Ethernet72': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}, + u'Ethernet76': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}}}, + u'device_vlan_list': {u'sonic-s6100-dut': [2, 2, 2, 2]}, + u'device_vlan_map_list': {u'sonic-s6100-dut': {u'19': 2}}, + u'device_vlan_range': {u'sonic-s6100-dut': [u'2']}} dut_hostname (str): hostname of the DUT dut_intf (str): name of DUT interface @@ -294,50 +259,42 @@ def get_dut_intfs(conn_data, dut_hostname): conn_data (dict): the dictionary returned by conn_graph_fact. Example format of the conn_data is given below: - { - u'device_conn': { - u'msr-s6100-dut-1': { - u'Ethernet0': { - u'peerdevice': u'msr-ixia-1', - u'peerport': u'Card12/Port5', - u'speed': u'40000' - }, - u'Ethernet1': { - u'peerdevice': u'msr-ixia-1', - u'peerport': u'Card12/Port6', - u'speed': u'40000' - }, - u'Ethernet2': { - u'peerdevice': u'msr-ixia-1', - u'peerport': u'Card12/Port7', - u'speed': u'40000' - } - } - }, - u'device_info': [{u'HwSku': u'Dell-S6100', u'Type': u'DevSonic'}], - u'device_port_vlans': [ - { - u'Ethernet0': { - u'mode': u'Access', - u'vlanids': u'', - u'vlanlist': [] - }, - u'Ethernet1': { - u'mode': u'Access', - u'vlanids': u'', - u'vlanlist': [] - }, - u'Ethernet2': { - u'mode': u'Access', - u'vlanids': u'', - u'vlanlist': [] - } - } - ], - u'device_vlan_list': [[]], - u'device_vlan_map_list': {u'msr-s6100-dut-1': []}, - u'device_vlan_range': [[]] - } + {u'device_conn': {u'sonic-s6100-dut': + {u'Ethernet64': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port1', + u'speed': u'100000'}, + u'Ethernet68': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port2', + u'speed': u'100000'}, + u'Ethernet72': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port3', + u'speed': u'100000'}, + u'Ethernet76': {u'peerdevice': u'snappi-sonic', + u'peerport': u'Card4/Port4', + u'speed': u'100000'}}}, + u'device_console_info': {u'sonic-s6100-dut': {}}, + u'device_console_link': {u'sonic-s6100-dut': {}}, + u'device_info': {u'sonic-s6100-dut': + {u'HwSku': u'Arista-7060CX-32S-C32', + u'Type': u'DevSonic'}}, + u'device_pdu_info': {u'sonic-s6100-dut': {}}, + u'device_pdu_links': {u'sonic-s6100-dut': {}}, + u'device_port_vlans': {u'sonic-s6100-dut': + {u'Ethernet64': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}, + u'Ethernet68': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}, + u'Ethernet72': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}, + u'Ethernet76': {u'mode': u'Access', + u'vlanids': u'2', + u'vlanlist': [2]}}}, + u'device_vlan_list': {u'sonic-s6100-dut': [2, 2, 2, 2]}, + u'device_vlan_map_list': {u'sonic-s6100-dut': {u'19': 2}}, + u'device_vlan_range': {u'sonic-s6100-dut': [u'2']}} dut_hostname (str): hostname of the DUT @@ -370,6 +327,7 @@ def pfc_class_enable_vector(prio_list): return "{:x}".format(vector) + def get_wred_profiles(host_ans): """ Get all the WRED/ECN profiles of a SONiC switch @@ -407,6 +365,7 @@ def get_wred_profiles(host_ans): else: return None + def config_wred(host_ans, kmin, kmax, pmax, profile=None): """ Config a WRED/ECN profile of a SONiC switch @@ -461,6 +420,7 @@ def config_wred(host_ans, kmin, kmax, pmax, profile=None): return True + def enable_ecn(host_ans, prio): """ Enable ECN marking on a priority @@ -474,6 +434,7 @@ def enable_ecn(host_ans, prio): """ host_ans.shell('sudo ecnconfig -q {} on'.format(prio)) + def disable_ecn(host_ans, prio): """ Disable ECN marking on a priority @@ -487,6 +448,7 @@ def disable_ecn(host_ans, prio): """ host_ans.shell('sudo ecnconfig -q {} off'.format(prio)) + def config_buffer_alpha(host_ans, profile, alpha_log2): """ Configure buffer threshold (a.k.a., alpha) @@ -501,6 +463,7 @@ def config_buffer_alpha(host_ans, profile, alpha_log2): """ host_ans.shell('sudo mmuconfig -p {} -a {}'.format(profile, alpha_log2)) + def config_ingress_lossless_buffer_alpha(host_ans, alpha_log2): """ Configure ingress buffer thresholds (a.k.a., alpha) of a device to 2^alpha_log2 @@ -541,6 +504,7 @@ def config_ingress_lossless_buffer_alpha(host_ans, alpha_log2): return True + def get_pfcwd_config_attr(host_ans, config_scope, attr): """ Get PFC watchdog configuration attribute @@ -569,6 +533,7 @@ def get_pfcwd_config_attr(host_ans, config_scope, attr): return None + def get_pfcwd_poll_interval(host_ans): """ Get PFC watchdog polling interval @@ -588,6 +553,7 @@ def get_pfcwd_poll_interval(host_ans): return None + def get_pfcwd_detect_time(host_ans, intf): """ Get PFC watchdog detection time of a given interface @@ -608,6 +574,7 @@ def get_pfcwd_detect_time(host_ans, intf): return None + def get_pfcwd_restore_time(host_ans, intf): """ Get PFC watchdog restoration time of a given interface @@ -628,6 +595,7 @@ def get_pfcwd_restore_time(host_ans, intf): return None + def start_pfcwd(duthost): """ Start PFC watchdog with default setting @@ -640,6 +608,7 @@ def start_pfcwd(duthost): """ duthost.shell('sudo pfcwd start_default') + def stop_pfcwd(duthost): """ Stop PFC watchdog @@ -652,6 +621,7 @@ def stop_pfcwd(duthost): """ duthost.shell('sudo pfcwd stop') + def disable_packet_aging(duthost): """ Disable packet aging feature (only on MLNX switches) @@ -668,6 +638,7 @@ def disable_packet_aging(duthost): duthost.command("docker exec syncd python /packets_aging.py disable") duthost.command("docker exec syncd rm -rf /packets_aging.py") + def enable_packet_aging(duthost): """ Enable packet aging feature (only on MLNX switches) diff --git a/tests/common/snappi/snappi_fixtures.py b/tests/common/snappi/snappi_fixtures.py index 5abb2366e34..69103d828f3 100644 --- a/tests/common/snappi/snappi_fixtures.py +++ b/tests/common/snappi/snappi_fixtures.py @@ -2,12 +2,16 @@ This module contains the snappi fixture """ import pytest -import snappi_convergence -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -from tests.common.snappi.common_helpers import ( - get_addrs_in_subnet,get_ipv6_addrs_in_subnet,get_peer_snappi_chassis) +import snappi +from ipaddress import ip_address, IPv4Address +from tests.common.fixtures.conn_graph_facts import conn_graph_facts,\ + fanout_graph_facts +from tests.common.snappi.common_helpers import get_addrs_in_subnet,\ + get_peer_snappi_chassis from tests.common.snappi.snappi_helpers import SnappiFanoutManager, get_snappi_port_location +from tests.common.snappi.port import SnappiPortConfig, SnappiPortType +from tests.common.helpers.assertions import pytest_assert + @pytest.fixture(scope="module") def snappi_api_serv_ip(tbinfo): @@ -23,7 +27,6 @@ def snappi_api_serv_ip(tbinfo): return tbinfo['ptf_ip'] - @pytest.fixture(scope="module") def snappi_api_serv_port(duthosts, rand_one_dut_hostname): """ @@ -39,97 +42,372 @@ def snappi_api_serv_port(duthosts, rand_one_dut_hostname): ['snappi_api_server']['rest_port']) -@pytest.fixture(scope="module") -def tgen_ports(duthost, - conn_graph_facts, - fanout_graph_facts): +@pytest.fixture(scope='module') +def snappi_api(snappi_api_serv_ip, + snappi_api_serv_port): + """ + Fixture for session handle, + for creating snappi objects and making API calls. + Args: + snappi_api_serv_ip (pytest fixture): snappi_api_serv_ip fixture + snappi_api_serv_port (pytest fixture): snappi_api_serv_port fixture. + """ + location = "https://" + snappi_api_serv_ip + ":" + str(snappi_api_serv_port) + # TODO: Currently extension is defaulted to ixnetwork. + # Going forward, we should be able to specify extension + # from command line while running pytest. + api = snappi.api(location=location, ext="ixnetwork") + + yield api + + if getattr(api, 'assistant', None) is not None: + api.assistant.Session.remove() + +def __gen_mac(id): """ - Populate tgen ports info of T0 testbed and returns as a list + Generate a MAC address 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': '22.1.1.2', - 'ipv6': '3001::2', - 'ipv6_prefix': u'64', - 'location': '10.36.78.238;1;2', - 'peer_device': 'sonic-s6100-dut', - 'peer_ip': u'22.1.1.1', - 'peer_ipv6': u'3001::1', - 'peer_port': 'Ethernet8', - 'port_id': '2', - 'prefix': u'24', - 'speed': 'speed_400_gbps'}, - {'card_id': '1', - 'ip': '21.1.1.2', - 'ipv6': '2001::2', - 'ipv6_prefix': u'64', - 'location': '10.36.78.238;1;1', - 'peer_device': 'sonic-s6100-dut', - 'peer_ip': u'21.1.1.1', - 'peer_ipv6': u'2001::1', - 'peer_port': 'Ethernet0', - 'port_id': '1', - 'prefix': u'24', - 'speed': 'speed_400_gbps'}] - """ - - speed_type = {'50000': 'speed_50_gbps', - '100000': 'speed_100_gbps', - '200000': 'speed_200_gbps', - '400000': 'speed_400_gbps'} + id (int): Snappi port ID + Returns: + MAC address (string) + """ + return '00:11:22:33:44:{:02d}'.format(id) + + +def __valid_ipv4_addr(ip): + """ + Determine if a input string is a valid IPv4 address + Args: + ip (unicode str): input IP address + Returns: + True if the input is a valid IPv4 adress or False otherwise + """ + try: + return True if type(ip_address(ip)) is IPv4Address else False + except ValueError: + return False + + +def __l3_intf_config(config, port_config_list, duthost, snappi_ports): + """ + Generate Snappi configuration of layer 3 interfaces + Args: + config (obj): Snappi API config of the testbed + port_config_list (list): list of Snappi port configuration information + duthost (object): device under test + snappi_ports (list): list of Snappi port information + Returns: + True if we successfully generate configuration or False + """ + mg_facts = duthost.minigraph_facts(host=duthost.hostname)['ansible_facts'] + if 'minigraph_interfaces' in mg_facts: + l3_intf_facts = mg_facts['minigraph_interfaces'] + else: + return True + + if len(l3_intf_facts) == 0: + return True + + l3_intf = {} + for v in l3_intf_facts: + if __valid_ipv4_addr(v['addr']): + l3_intf[v['attachto']] = v + + dut_mac = str(duthost.facts['router_mac']) + + for k, v in l3_intf.items(): + intf = str(k) + gw_addr = str(v['addr']) + prefix = str(v['prefixlen']) + ip = str(v['peer_addr']) + + port_ids = [id for id, snappi_port in enumerate(snappi_ports) \ + if snappi_port['peer_port'] == intf] + if len(port_ids) != 1: + return False + + port_id = port_ids[0] + mac = __gen_mac(port_id) + + device = config.devices.device( + name='Device Port {}'.format(port_id), + container_name=config.ports[port_id].name)[-1] + + ethernet = device.ethernet + ethernet.name = 'Ethernet Port {}'.format(port_id) + ethernet.mac = mac + + ip_stack = ethernet.ipv4 + ip_stack.name = 'Ipv4 Port {}'.format(port_id) + ip_stack.address = ip + ip_stack.prefix = int(prefix) + ip_stack.gateway = gw_addr + + port_config = SnappiPortConfig(id=port_id, + ip=ip, + mac=mac, + gw=gw_addr, + gw_mac=dut_mac, + prefix_len=prefix, + port_type=SnappiPortType.IPInterface, + peer_port=intf) + + port_config_list.append(port_config) + + return True + + +def __vlan_intf_config(config, port_config_list, duthost, snappi_ports): + """ + Generate Snappi configuration of Vlan interfaces + Args: + config (obj): Snappi API config of the testbed + port_config_list (list): list of Snappi port configuration information + duthost (object): device under test + snappi_ports (list): list of Snappi port information + Returns: + True if we successfully generate configuration or False + """ + mg_facts = duthost.minigraph_facts(host=duthost.hostname)['ansible_facts'] + if 'minigraph_vlans' in mg_facts: + vlan_facts = mg_facts['minigraph_vlans'] + else: + return True + + if len(vlan_facts) == 0: + return True + + vlan_member = {} + for k, v in vlan_facts.items(): + vlan_member[k] = v['members'] + + vlan_intf_facts = mg_facts['minigraph_vlan_interfaces'] + vlan_intf = {} + for v in vlan_intf_facts: + if __valid_ipv4_addr(v['addr']): + vlan_intf[v['attachto']] = v + + dut_mac = str(duthost.facts['router_mac']) + + """ For each Vlan """ + for vlan in vlan_member: + phy_intfs = vlan_member[vlan] + gw_addr = str(vlan_intf[vlan]['addr']) + prefix = str(vlan_intf[vlan]['prefixlen']) + vlan_subnet = '{}/{}'.format(gw_addr, prefix) + vlan_ip_addrs = get_addrs_in_subnet(vlan_subnet, len(phy_intfs)) + + """ For each physical interface attached to this Vlan """ + for i in range(len(phy_intfs)): + phy_intf = phy_intfs[i] + vlan_ip_addr = vlan_ip_addrs[i] + port_ids = [id for id, snappi_port in enumerate(snappi_ports) \ + if snappi_port['peer_port'] == phy_intf] + if len(port_ids) != 1: + return False + + port_id = port_ids[0] + mac = __gen_mac(port_id) + device = config.devices.device( + name='Device Port {}'.format(port_id), + container_name=config.ports[port_id].name)[-1] + + ethernet = device.ethernet + ethernet.name = 'Ethernet Port {}'.format(port_id) + ethernet.mac = mac + + ip_stack = ethernet.ipv4 + ip_stack.name = 'Ipv4 Port {}'.format(port_id) + ip_stack.address = vlan_ip_addr + ip_stack.prefix = int(prefix) + ip_stack.gateway = gw_addr + + port_config = SnappiPortConfig(id=port_id, + ip=vlan_ip_addr, + mac=mac, + gw=gw_addr, + gw_mac=dut_mac, + prefix_len=prefix, + port_type=SnappiPortType.VlanMember, + peer_port=phy_intf) + + port_config_list.append(port_config) + + return True + + +def __portchannel_intf_config(config, port_config_list, duthost, snappi_ports): + """ + Generate Snappi configuration of portchannel interfaces + Args: + config (obj): Snappi API config of the testbed + port_config_list (list): list of Snappi port configuration information + duthost (object): device under test + snappi_ports (list): list of Snappi port information + Returns: + True if we successfully generate configuration or False + """ + mg_facts = duthost.minigraph_facts(host=duthost.hostname)['ansible_facts'] + if 'minigraph_portchannels' in mg_facts: + pc_facts = mg_facts['minigraph_portchannels'] + else: + return True + + if len(pc_facts) == 0: + return True + + pc_member = {} + for k, v in pc_facts.items(): + pc_member[k] = v['members'] + + pc_intf_facts = mg_facts['minigraph_portchannel_interfaces'] + pc_intf = {} + for v in pc_intf_facts: + if __valid_ipv4_addr(v['addr']): + pc_intf[v['attachto']] = v + + dut_mac = str(duthost.facts['router_mac']) + + """ For each port channel """ + for pc in pc_member: + phy_intfs = pc_member[pc] + gw_addr = str(pc_intf[pc]['addr']) + prefix = str(pc_intf[pc]['prefixlen']) + pc_ip_addr = str(pc_intf[pc]['peer_addr']) + + lag = config.lags.lag(name='Lag {}'.format(pc))[-1] + for i in range(len(phy_intfs)): + phy_intf = phy_intfs[i] + + port_ids = [id for id, snappi_port in enumerate(snappi_ports) \ + if snappi_port['peer_port'] == phy_intf] + if len(port_ids) != 1: + return False + + port_id = port_ids[0] + mac = __gen_mac(port_id) + + lp = lag.ports.port(port_name=config.ports[port_id].name)[-1] + lp.protocol.lacp.actor_system_id = '00:00:00:00:00:01' + lp.protocol.lacp.actor_system_priority = 1 + lp.protocol.lacp.actor_port_priority = 1 + lp.protocol.lacp.actor_port_number = 1 + lp.protocol.lacp.actor_key = 1 + + lp.ethernet.name = 'Ethernet Port {}'.format(port_id) + lp.ethernet.mac = mac + + port_config = SnappiPortConfig(id=port_id, + ip=pc_ip_addr, + mac=mac, + gw=gw_addr, + gw_mac=dut_mac, + prefix_len=prefix, + port_type=SnappiPortType.PortChannelMember, + peer_port=phy_intf) + + port_config_list.append(port_config) + + device = config.devices.device(name='Device {}'.format(pc), + container_name=lag.name)[-1] + + ip_stack = device.ethernet.ipv4 + ip_stack.address = pc_ip_addr + ip_stack.prefix = int(prefix) + ip_stack.gateway = gw_addr + + return True + + +@pytest.fixture(scope="function") +def snappi_testbed_config(conn_graph_facts, + fanout_graph_facts, + duthosts, + rand_one_dut_hostname, + snappi_api): + """ + Geenrate snappi API config and port config information for the testbed + Args: + conn_graph_facts (pytest fixture) + fanout_graph_facts (pytest fixture) + duthosts (pytest fixture): list of DUTs + rand_one_dut_hostname (pytest fixture): DUT hostname + snappi_api(pytest fixture): Snappi API fixture + Returns: + - config (obj): Snappi API config of the testbed + - port_config_list (list): list of port configuration information + """ + duthost = duthosts[rand_one_dut_hostname] + + """ Generate L1 config """ snappi_fanout = get_peer_snappi_chassis(conn_data=conn_graph_facts, dut_hostname=duthost.hostname) + + pytest_assert(snappi_fanout is not None, 'Fail to get snappi_fanout') + snappi_fanout_id = list(fanout_graph_facts.keys()).index(snappi_fanout) snappi_fanout_list = SnappiFanoutManager(fanout_graph_facts) - snappi_fanout_list.get_fanout_device_details(device_number = snappi_fanout_id) - snappi_ports = snappi_fanout_list.get_ports(peer_device = duthost.hostname) + snappi_fanout_list.get_fanout_device_details(device_number=snappi_fanout_id) + + snappi_ports = snappi_fanout_list.get_ports(peer_device=duthost.hostname) + port_speed = None + """ L1 config """ + config = snappi_api.config() for i in range(len(snappi_ports)): + config.ports.port(name='Port {}'.format(i), + location=get_snappi_port_location(snappi_ports[i])) + if port_speed is None: port_speed = int(snappi_ports[i]['speed']) - elif port_speed != int(snappi_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 snappi_ports: - port['location'] = get_snappi_port_location(port) - port['speed'] = speed_type[port['speed']] - - for port in snappi_ports: - peer_port = port['peer_port'] - int_addrs = config_facts['INTERFACE'][peer_port].keys() - try: - ipv4_subnet = [ele for ele in int_addrs if "." in ele][0] - if not ipv4_subnet: - raise Exception("IPv4 is not configured on the interface {}" - .format(peer_port)) - port['peer_ip'], port['prefix'] = ipv4_subnet.split("/") - port['ip'] = get_addrs_in_subnet(ipv4_subnet, 1)[0] - ipv6_subnet = [ele for ele in int_addrs if ":" in ele][0] - if not ipv6_subnet: - raise Exception("IPv6 is not configured on the interface {}" - .format(peer_port)) - port['peer_ipv6'], port['ipv6_prefix'] = ipv6_subnet.split("/") - port['ipv6'] = get_ipv6_addrs_in_subnet(ipv6_subnet, 1)[0] - except: - raise Exception('Configure IPv4 and IPv6 on DUT interfaces') - return snappi_ports + pytest_assert(port_speed == int(snappi_ports[i]['speed']), + 'Ports have different link speeds') + speed_gbps = int(port_speed/1000) -@pytest.fixture(scope='module') -def cvg_api(snappi_api_serv_ip, - snappi_api_serv_port): - api = snappi_convergence.api(location=snappi_api_serv_ip + ':' + str(snappi_api_serv_port),ext='ixnetwork') - yield api - if getattr(api, 'assistant', None) is not None: - api.assistant.Session.remove() + config.options.port_options.location_preemption = True + l1_config = config.layer1.layer1()[-1] + l1_config.name = 'L1 config' + l1_config.port_names = [port.name for port in config.ports] + l1_config.speed = 'speed_{}_gbps'.format(speed_gbps) + l1_config.ieee_media_defaults = False + l1_config.auto_negotiate = False + l1_config.auto_negotiation.link_training = True + l1_config.auto_negotiation.rs_fec = True + + pfc = l1_config.flow_control.ieee_802_1qbb + pfc.pfc_delay = 0 + pfc.pfc_class_0 = 0 + pfc.pfc_class_1 = 1 + pfc.pfc_class_2 = 2 + pfc.pfc_class_3 = 3 + pfc.pfc_class_4 = 4 + pfc.pfc_class_5 = 5 + pfc.pfc_class_6 = 6 + pfc.pfc_class_7 = 7 + + port_config_list = [] + + config_result = __vlan_intf_config(config=config, + port_config_list=port_config_list, + duthost=duthost, + snappi_ports=snappi_ports) + pytest_assert(config_result is True, 'Fail to configure Vlan interfaces') + + config_result = __portchannel_intf_config(config=config, + port_config_list=port_config_list, + duthost=duthost, + snappi_ports=snappi_ports) + pytest_assert(config_result is True, 'Fail to configure portchannel interfaces') + + config_result = __l3_intf_config(config=config, + port_config_list=port_config_list, + duthost=duthost, + snappi_ports=snappi_ports) + pytest_assert(config_result is True, 'Fail to configure L3 interfaces') + + return config, port_config_list \ No newline at end of file diff --git a/tests/common/snappi/snappi_helpers.py b/tests/common/snappi/snappi_helpers.py index 72046c2ccaa..0967c968b2e 100644 --- a/tests/common/snappi/snappi_helpers.py +++ b/tests/common/snappi/snappi_helpers.py @@ -4,6 +4,7 @@ "SnappiFanoutManager" which can be used to manage cards and ports of Snappi chassis instead of reading it from fanout_graph_facts fixture. """ + from tests.common.helpers.assertions import pytest_assert from tests.common.snappi.common_helpers import ansible_stdout_to_str from tests.common.reboot import logger @@ -18,9 +19,11 @@ def __init__(self, fanout_data): this method makes a list of chassis connection-details out of it. So each chassis and details associated with it can be accessed by a integer index (starting from 0) + Args: fanout_data (dict): the dictionary returned by fanout_graph_fact. Example format of the fanout_data is given below + {u'snappi-sonic': { u'device_conn': { u'Card9/Port1': { @@ -28,11 +31,13 @@ def __init__(self, fanout_data): u'peerport': u'Ethernet0', u'speed': u'100000' }, + u'Card9/Port2': { u'peerdevice': u'sonic-s6100-dut', u'peerport': u'Ethernet4', u'speed': u'100000' }, + u'Card9/Port3': { u'peerdevice': u'sonic-s6100-dut', u'peerport': u'Ethernet8', @@ -98,11 +103,14 @@ def get_fanout_device_details(self, device_number): anything. The rest of the function then used to extract chassis information like "get_chassis_ip()" will the return the ip address of chassis 0 - the first chassis in the list. + Note: Counting or indexing starts from 0. That is 0 = 1st chassis, 1 = 2nd chassis ... + Args: device_number (int): the chassis index (0 is the first) + Returns: None """ @@ -127,10 +135,13 @@ def get_connection_details(self): chassis (selected earlier using get_fanout_device_details() function). Details of the chassis will be available like chassis IP, card, ports, peer port etc. in a dictionary format. + Note: If you have not used get_fanout_device_details(), by default 0th (first) chassis remains selected. + Args: This function takes no argument. + Returns: Details of the chassis connection as dictionary format. """ @@ -139,10 +150,13 @@ def get_connection_details(self): def get_chassis_ip(self): """This function returns IP address of a particular chassis (selected earlier using get_fanout_device_details() function). + Note: If you have not used get_fanout_device_details(), by default 0th (first) chassis remains selected. + Args: This function takes no argument. + Returns: The IP address """ @@ -152,11 +166,14 @@ def get_ports(self, peer_device=None): """This function returns list of ports that are (1) associated with a chassis (selected earlier using get_fanout_device_details() function) and (2) connected to a peer device (SONiC DUT) as a list of dictionary. + Note: If you have not used get_fanout_device_details(), by default 0th (first) chassis remains selected. If you do not specify peer_device, this function will return all the ports of the chassis. + Args: peer_device (str): hostname of the peer device + Returns: Dictionary of chassis card port information. """ @@ -182,7 +199,9 @@ def get_snappi_port_location(intf): """ Extracting location from interface, since Snappi Api accepts location in terms of chassis ip, card, and port in different format. + Note: Interface must have the keys 'ip', 'card_id' and 'port_id' + Args: intf (dict) : intf must contain the keys 'ip', 'card_id', 'port_id'. Example format : @@ -191,10 +210,11 @@ def get_snappi_port_location(intf): 'card_id': u'9', 'speed': 100000, 'peer_port': u'Ethernet0'} + Returns: location in string format. Example: '10.36.78.5;1;2' where 1 is card_id and 2 is port_id. """ keys = set(['ip', 'card_id', 'port_id']) pytest_assert(keys.issubset(set(intf.keys())), "intf does not have all the keys") - return "{};{};{}".format(intf['ip'], intf['card_id'], intf['port_id']) \ No newline at end of file + return "{};{};{}".format(intf['ip'], intf['card_id'], intf['port_id']) From cef341bdb82cdde9c1a005da466f5323cf4b3d75 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 27 Jul 2021 05:53:51 +0000 Subject: [PATCH 21/58] updating merge conflict files --- tests/common/snappi/common_helpers.py | 22 ++++++ tests/common/snappi/snappi_fixtures.py | 100 ++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/tests/common/snappi/common_helpers.py b/tests/common/snappi/common_helpers.py index f8a6f48e078..f618b45205c 100644 --- a/tests/common/snappi/common_helpers.py +++ b/tests/common/snappi/common_helpers.py @@ -654,3 +654,25 @@ def enable_packet_aging(duthost): duthost.command("docker cp /tmp/packets_aging.py syncd:/") duthost.command("docker exec syncd python /packets_aging.py enable") duthost.command("docker exec syncd rm -rf /packets_aging.py") + +def get_ipv6_addrs_in_subnet(subnet, number_of_ip): + """ + Get N IPv6 addresses in a subnet. + Args: + subnet (str): IPv6 subnet, e.g., '2001::1/64' + number_of_ip (int): Number of IP addresses to get + Return: + Return n IPv6 addresses in this subnet in a list. + """ + + subnet = str(IPNetwork(subnet).network) + "/" + str(subnet.split("/")[1]) + subnet = unicode(subnet, "utf-8") + ipv6_list = [] + for i in range(number_of_ip): + network = IPv6Network(subnet) + address = IPv6Address( + network.network_address + getrandbits( + network.max_prefixlen - network.prefixlen)) + ipv6_list.append(str(address)) + + return ipv6_list \ No newline at end of file diff --git a/tests/common/snappi/snappi_fixtures.py b/tests/common/snappi/snappi_fixtures.py index 69103d828f3..0092e54ba38 100644 --- a/tests/common/snappi/snappi_fixtures.py +++ b/tests/common/snappi/snappi_fixtures.py @@ -3,11 +3,12 @@ """ import pytest import snappi +import snappi_convergence from ipaddress import ip_address, IPv4Address from tests.common.fixtures.conn_graph_facts import conn_graph_facts,\ fanout_graph_facts from tests.common.snappi.common_helpers import get_addrs_in_subnet,\ - get_peer_snappi_chassis + get_ipv6_addrs_in_subnet, get_peer_snappi_chassis from tests.common.snappi.snappi_helpers import SnappiFanoutManager, get_snappi_port_location from tests.common.snappi.port import SnappiPortConfig, SnappiPortType from tests.common.helpers.assertions import pytest_assert @@ -410,4 +411,99 @@ def snappi_testbed_config(conn_graph_facts, snappi_ports=snappi_ports) pytest_assert(config_result is True, 'Fail to configure L3 interfaces') - return config, port_config_list \ No newline at end of file + return config, port_config_list + +@pytest.fixture(scope="module") +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': '22.1.1.2', + 'ipv6': '3001::2', + 'ipv6_prefix': u'64', + 'location': '10.36.78.238;1;2', + 'peer_device': 'sonic-s6100-dut', + 'peer_ip': u'22.1.1.1', + 'peer_ipv6': u'3001::1', + 'peer_port': 'Ethernet8', + 'port_id': '2', + 'prefix': u'24', + 'speed': 'speed_400_gbps'}, + {'card_id': '1', + 'ip': '21.1.1.2', + 'ipv6': '2001::2', + 'ipv6_prefix': u'64', + 'location': '10.36.78.238;1;1', + 'peer_device': 'sonic-s6100-dut', + 'peer_ip': u'21.1.1.1', + 'peer_ipv6': u'2001::1', + 'peer_port': 'Ethernet0', + 'port_id': '1', + 'prefix': u'24', + 'speed': 'speed_400_gbps'}] + """ + + speed_type = {'50000': 'speed_50_gbps', + '100000': 'speed_100_gbps', + '200000': 'speed_200_gbps', + '400000': 'speed_400_gbps'} + + snappi_fanout = get_peer_snappi_chassis(conn_data=conn_graph_facts, + dut_hostname=duthost.hostname) + snappi_fanout_id = list(fanout_graph_facts.keys()).index(snappi_fanout) + snappi_fanout_list = SnappiFanoutManager(fanout_graph_facts) + snappi_fanout_list.get_fanout_device_details(device_number = snappi_fanout_id) + snappi_ports = snappi_fanout_list.get_ports(peer_device = duthost.hostname) + port_speed = None + + for i in range(len(snappi_ports)): + if port_speed is None: + port_speed = int(snappi_ports[i]['speed']) + + elif port_speed != int(snappi_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 snappi_ports: + port['location'] = get_snappi_port_location(port) + port['speed'] = speed_type[port['speed']] + + for port in snappi_ports: + peer_port = port['peer_port'] + int_addrs = config_facts['INTERFACE'][peer_port].keys() + try: + ipv4_subnet = [ele for ele in int_addrs if "." in ele][0] + if not ipv4_subnet: + raise Exception("IPv4 is not configured on the interface {}" + .format(peer_port)) + port['peer_ip'], port['prefix'] = ipv4_subnet.split("/") + port['ip'] = get_addrs_in_subnet(ipv4_subnet, 1)[0] + ipv6_subnet = [ele for ele in int_addrs if ":" in ele][0] + if not ipv6_subnet: + raise Exception("IPv6 is not configured on the interface {}" + .format(peer_port)) + port['peer_ipv6'], port['ipv6_prefix'] = ipv6_subnet.split("/") + port['ipv6'] = get_ipv6_addrs_in_subnet(ipv6_subnet, 1)[0] + except: + raise Exception('Configure IPv4 and IPv6 on DUT interfaces') + return snappi_ports + + +@pytest.fixture(scope='module') +def cvg_api(snappi_api_serv_ip, + snappi_api_serv_port): + api = snappi_convergence.api(location=snappi_api_serv_ip + ':' + str(snappi_api_serv_port),ext='ixnetwork') + yield api + if getattr(api, 'assistant', None) is not None: + api.assistant.Session.remove() \ No newline at end of file From 7f34351d911d6fdd74003cf191ed85e054412efe Mon Sep 17 00:00:00 2001 From: selldinesh Date: Thu, 5 Aug 2021 16:03:25 +0000 Subject: [PATCH 22/58] imports added --- tests/common/snappi/common_helpers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/common/snappi/common_helpers.py b/tests/common/snappi/common_helpers.py index f618b45205c..e9db1f1826e 100644 --- a/tests/common/snappi/common_helpers.py +++ b/tests/common/snappi/common_helpers.py @@ -14,7 +14,8 @@ import ipaddr from netaddr import IPNetwork from tests.common.mellanox_data import is_mellanox_device as isMellanoxDevice - +from ipaddress import IPv6Network, IPv6Address +from random import getrandbits def increment_ip_address(ip, incr=1): """ From 74b541bf1cc46f8651598f543c4210ffe81d42d0 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Thu, 5 Aug 2021 17:43:45 +0000 Subject: [PATCH 23/58] final changes --- tests/ixia/bgp/files/bgp_convergence_helper.py | 3 +-- tests/ixia/bgp/test_bgp_rib_in_capacity.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index 6ca3ad352ff..90d92924c4d 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -470,7 +470,7 @@ def get_avg_dpdp_convergence_time(port_name): for i, port_name in enumerate(rx_port_names): table.append(get_avg_dpdp_convergence_time(port_name)) columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Calculated Data Convergence Time (ms)'] - logger.info("\n%s" % tabulate(table, headers=columns, stablefmt="psql")) + logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) def get_convergence_for_remote_link_failover(cvg_api, @@ -498,7 +498,6 @@ def get_convergence_for_remote_link_failover(cvg_api, for route in device.ethernet.ipv6.bgpv6.bgpv6_routes: route_names.append(route.name) bgp_config.rx_rate_threshold = 90/(multipath-1) - bgp_config.convergence_event = (bgp_config.ROUTE_ADVERTISE_WITHDRAW) cvg_api.set_config(bgp_config) diff --git a/tests/ixia/bgp/test_bgp_rib_in_capacity.py b/tests/ixia/bgp/test_bgp_rib_in_capacity.py index 5af5447946e..9705b3c36a3 100644 --- a/tests/ixia/bgp/test_bgp_rib_in_capacity.py +++ b/tests/ixia/bgp/test_bgp_rib_in_capacity.py @@ -8,7 +8,7 @@ @pytest.mark.parametrize('multipath', [2]) -@pytest.mark.parametrize('start_value', [10000]) +@pytest.mark.parametrize('start_value', [5000]) @pytest.mark.parametrize('step_value', [5000]) @pytest.mark.parametrize('route_type', ['IPv4']) def test_RIB_IN_capacity(cvg_api, From c85d375be1cc0c6c997c8dc2d32fd0c44bea703f Mon Sep 17 00:00:00 2001 From: selldinesh Date: Thu, 9 Sep 2021 19:32:43 +0000 Subject: [PATCH 24/58] lag changes --- .../ixia/bgp/files/bgp_convergence_helper.py | 247 +++++++----------- 1 file changed, 99 insertions(+), 148 deletions(-) diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index 90d92924c4d..3a98d47d030 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -1,13 +1,13 @@ from tabulate import tabulate from statistics import mean from tests.common.utilities import wait +import json logger = logging.getLogger(__name__) -DUT_AS_NUM = 65100 TGEN_AS_NUM = 65200 -TIMEOUT = 30 +TIMEOUT = 40 BGP_TYPE = 'ebgp' - +temp_tg_port=dict() def run_bgp_local_link_failover_test(cvg_api, duthost, @@ -33,13 +33,10 @@ def run_bgp_local_link_failover_test(cvg_api, """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, - port_count, - multipath, - route_type) + port_count,) """ Create bgp config on TGEN """ tgen_bgp_config = __tgen_bgp_config(cvg_api, - tgen_ports, port_count, number_of_routes, route_type,) @@ -56,10 +53,7 @@ def run_bgp_local_link_failover_test(cvg_api, route_type,) """ Cleanup the dut configs after getting the convergence numbers """ - cleanup_config(duthost, - tgen_ports, - port_count, - route_type,) + cleanup_config(duthost) def run_bgp_remote_link_failover_test(cvg_api, @@ -84,13 +78,10 @@ def run_bgp_remote_link_failover_test(cvg_api, """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, - port_count, - multipath, - route_type,) + port_count,) """ Create bgp config on TGEN """ tgen_bgp_config = __tgen_bgp_config(cvg_api, - tgen_ports, port_count, number_of_routes, route_type,) @@ -107,10 +98,8 @@ def run_bgp_remote_link_failover_test(cvg_api, route_type,) """ Cleanup the dut configs after getting the convergence numbers """ - cleanup_config(duthost, - tgen_ports, - port_count, - route_type,) + cleanup_config(duthost) + def run_rib_in_convergence_test(cvg_api, @@ -137,13 +126,10 @@ def run_rib_in_convergence_test(cvg_api, """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, - port_count, - multipath, - route_type,) + port_count,) """ Create bgp config on TGEN """ tgen_bgp_config = __tgen_bgp_config(cvg_api, - tgen_ports, port_count, number_of_routes, route_type,) @@ -160,10 +146,7 @@ def run_rib_in_convergence_test(cvg_api, route_type,) """ Cleanup the dut configs after getting the convergence numbers """ - cleanup_config(duthost, - tgen_ports, - port_count, - route_type,) + cleanup_config(duthost) def run_RIB_IN_capacity_test(cvg_api, @@ -190,31 +173,23 @@ def run_RIB_IN_capacity_test(cvg_api, """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, - port_count, - multipath, - route_type,) + port_count,) """ Run the RIB-IN capacity test by increasig the route count step by step """ get_RIB_IN_capacity(cvg_api, - tgen_ports, multipath, start_value, step_value, route_type,) """ Cleanup the dut configs after getting the convergence numbers """ - cleanup_config(duthost, - tgen_ports, - port_count, - route_type,) + cleanup_config(duthost) def duthost_bgp_config(duthost, tgen_ports, - port_count, - multipath, - route_type,): + port_count,): """ Configures BGP on the DUT with N-1 ecmp @@ -223,55 +198,51 @@ def duthost_bgp_config(duthost, tgen_ports (pytest fixture): Ports mapping info of T0 testbed port_count:multipath + 1 multipath: ECMP value for BGP config - route_type: IPv4 or IPv6 routes """ - if route_type == 'IPv4': - peer_ip = 'peer_ip' - ip = 'ip' - prefix = 'prefix' - address_type = ['ip', 'ipv4'] - else: - peer_ip = 'peer_ipv6' - ip = 'ipv6' - prefix = 'ipv6_prefix' - address_type = ['ipv6', 'ipv6'] + duthost.command("sudo config save -y") + duthost.command("sudo cp {} {}".format("/etc/sonic/config_db.json", "/etc/sonic/config_db_backup.json")) + global temp_tg_port + temp_tg_port = tgen_ports for i in range(0, port_count): intf_config = ( - "vtysh " - "-c 'configure terminal' " - "-c 'interface %s' " - "-c '%s address %s/%s' " + "sudo config interface ip remove %s %s/%s \n" + "sudo config interface ip remove %s %s/%s \n" ) - intf_config %= (tgen_ports[i]['peer_port'], address_type[0], tgen_ports[i][peer_ip], tgen_ports[i][prefix]) - logger.info('Configuring IP Address %s' % tgen_ports[i][ip]) + intf_config %= (tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ipv6'], tgen_ports[i]['ipv6_prefix']) + logger.info('Removing configured IP and IPv6 Address from %s' % (tgen_ports[i]['peer_port'])) 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, multipath) - duthost.shell(bgp_config) - for i in range(1, port_count): - bgp_config_neighbor = ( - "vtysh " - "-c 'configure terminal' " - "-c 'router bgp %s' " - "-c 'neighbor %s remote-as %s' " - "-c 'address-family %s unicast' " - "-c 'neighbor %s activate' " - "-c 'exit' " + + for i in range(0, port_count): + portchannel_config = ( + "sudo config portchannel add PortChannel%s \n" + "sudo config portchannel member add PortChannel%s %s\n" + "sudo config interface ip add PortChannel%s %s/%s\n" + "sudo config interface ip add PortChannel%s %s/%s\n" ) - bgp_config_neighbor %= (DUT_AS_NUM, tgen_ports[i][ip], TGEN_AS_NUM, address_type[1], tgen_ports[i][ip]) - logger.info('Configuring BGP Neighbor %s' % tgen_ports[i][ip]) - duthost.shell(bgp_config_neighbor) + portchannel_config %= (i+1, i+1, tgen_ports[i]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], i+1, tgen_ports[i]['peer_ipv6'], 64) + logger.info('Configuring %s to PortChannel%s with IPs %s,%s' % (tgen_ports[1]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['peer_ipv6'])) + duthost.shell(portchannel_config) + logger.info('Configuring BGP in config_db.json') + bgp_neighbors = dict() + for i in range(1, port_count): + bgp_neighbors[tgen_ports[i]['ipv6']] = {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[i]['peer_ipv6'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"} + bgp_neighbors[tgen_ports[i]['ip']] = {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[i]['peer_ip'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"} + + cdf = json.loads(duthost.shell("sonic-cfggen -d --print-data")['stdout']) + for neighbor, neighbor_info in bgp_neighbors.items(): + cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info + + with open("/tmp/sconfig_db.json", 'w') as fp: + json.dump(cdf, fp, indent=4) + duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") + cdf = json.loads(duthost.shell("sonic-cfggen -j /tmp/config_db_temp.json --print-data")['stdout']) + duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json","/etc/sonic/config_db.json")) + logger.info('Reloading config to apply BGP config') + duthost.shell("sudo config reload -y \n") + wait(TIMEOUT+60,"For Config to reload \n") def __tgen_bgp_config(cvg_api, - tgen_ports, port_count, number_of_routes, route_type,): @@ -280,7 +251,6 @@ def __tgen_bgp_config(cvg_api, Args: cvg_api (pytest fixture): snappi API - tgen_ports (pytest fixture): Ports mapping info of T0 testbed port_count: multipath + 1 number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes @@ -288,9 +258,19 @@ def __tgen_bgp_config(cvg_api, conv_config = cvg_api.convergence_config() config = conv_config.config for i in range(1, port_count+1): - config.ports.port(name='Test_Port_%d' % i, location=tgen_ports[i-1]['location']) + config.ports.port(name='Test_Port_%d' % i, location=temp_tg_port[i-1]['location']) + c_lag = config.lags.lag(name="lag%d" % i)[-1] + lp = c_lag.ports.port(port_name='Test_Port_%d' % i)[-1] + lp.ethernet.name = 'lag_eth_%d' % i + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] + else: + m = hex(i).split('0x')[1] + lp.protocol.lacp.actor_system_id = "00:10:00:00:00:%s" % m + lp.ethernet.name = "lag_Ethernet %s" % i + lp.ethernet.mac = "00:10:01:00:00:%s" % m config.devices.device(name='Topology %d' % i) - config.devices[i-1].container_name = config.ports[i-1].name + config.devices[i-1].container_name = c_lag.name config.options.port_options.location_preemption = True layer1 = config.layer1.layer1()[-1] @@ -306,9 +286,9 @@ def create_v4_topo(): config.devices[0].ethernet.name = 'Ethernet 1' config.devices[0].ethernet.mac = "00:00:00:00:00:01" config.devices[0].ethernet.ipv4.name = 'IPv4 1' - config.devices[0].ethernet.ipv4.address = tgen_ports[0]['ip'] - config.devices[0].ethernet.ipv4.gateway = tgen_ports[0]['peer_ip'] - config.devices[0].ethernet.ipv4.prefix = int(tgen_ports[0]['prefix']) + config.devices[0].ethernet.ipv4.address = temp_tg_port[0]['ip'] + config.devices[0].ethernet.ipv4.gateway = temp_tg_port[0]['peer_ip'] + config.devices[0].ethernet.ipv4.prefix = int(temp_tg_port[0]['prefix']) rx_flow_name = [] for i in range(2, port_count+1): if len(str(hex(i).split('0x')[1])) == 1: @@ -320,14 +300,14 @@ def create_v4_topo(): ethernet_stack.mac = "00:00:00:00:00:%s" % m ipv4_stack = ethernet_stack.ipv4 ipv4_stack.name = 'IPv4 %d' % i - ipv4_stack.address = tgen_ports[i-1]['ip'] - ipv4_stack.gateway = tgen_ports[i-1]['peer_ip'] - ipv4_stack.prefix = int(tgen_ports[i-1]['prefix']) + ipv4_stack.address = temp_tg_port[i-1]['ip'] + ipv4_stack.gateway = temp_tg_port[i-1]['peer_ip'] + ipv4_stack.prefix = int(temp_tg_port[i-1]['prefix']) bgpv4_stack = ipv4_stack.bgpv4 bgpv4_stack.name = 'BGP %d' % i bgpv4_stack.as_type = BGP_TYPE - bgpv4_stack.dut_address = tgen_ports[i-1]['peer_ip'] - bgpv4_stack.local_address = tgen_ports[i-1]['ip'] + bgpv4_stack.dut_address = temp_tg_port[i-1]['peer_ip'] + bgpv4_stack.local_address = temp_tg_port[i-1]['ip'] bgpv4_stack.as_number = int(TGEN_AS_NUM) route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group %d" % i)[-1] route_range.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=number_of_routes) @@ -338,9 +318,9 @@ def create_v6_topo(): config.devices[0].ethernet.name = 'Ethernet 1' config.devices[0].ethernet.mac = "00:00:00:00:00:01" config.devices[0].ethernet.ipv6.name = 'IPv6 1' - config.devices[0].ethernet.ipv6.address = tgen_ports[0]['ipv6'] - config.devices[0].ethernet.ipv6.gateway = tgen_ports[0]['peer_ipv6'] - config.devices[0].ethernet.ipv6.prefix = int(tgen_ports[0]['ipv6_prefix']) + config.devices[0].ethernet.ipv6.address = temp_tg_port[0]['ipv6'] + config.devices[0].ethernet.ipv6.gateway = temp_tg_port[0]['peer_ipv6'] + config.devices[0].ethernet.ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix']) rx_flow_name = [] for i in range(2, port_count+1): if len(str(hex(i).split('0x')[1])) == 1: @@ -352,14 +332,14 @@ def create_v6_topo(): ethernet_stack.mac = "00:00:00:00:00:%s" % m ipv6_stack = ethernet_stack.ipv6 ipv6_stack.name = 'IPv6 %d' % i - ipv6_stack.address = tgen_ports[i-1]['ipv6'] - ipv6_stack.gateway = tgen_ports[i-1]['peer_ipv6'] - ipv6_stack.prefix = int(tgen_ports[i-1]['ipv6_prefix']) + ipv6_stack.address = temp_tg_port[i-1]['ipv6'] + ipv6_stack.gateway = temp_tg_port[i-1]['peer_ipv6'] + ipv6_stack.prefix = int(temp_tg_port[i-1]['ipv6_prefix']) bgpv6_stack = ipv6_stack.bgpv6 bgpv6_stack.name = r'BGP+ %d' % i bgpv6_stack.as_type = BGP_TYPE - bgpv6_stack.dut_address = tgen_ports[i-1]['peer_ipv6'] - bgpv6_stack.local_address = tgen_ports[i-1]['ipv6'] + bgpv6_stack.dut_address = temp_tg_port[i-1]['peer_ipv6'] + bgpv6_stack.local_address = temp_tg_port[i-1]['ipv6'] bgpv6_stack.as_number = int(TGEN_AS_NUM) route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group %d" % i)[-1] route_range.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=number_of_routes) @@ -653,7 +633,6 @@ def get_rib_in_convergence(cvg_api, def get_RIB_IN_capacity(cvg_api, - tgen_ports, multipath, start_value, step_value, @@ -661,7 +640,7 @@ def get_RIB_IN_capacity(cvg_api, """ Args: cvg_api (pytest fixture): snappi API - tgen_ports (pytest fixture): Ports mapping info of T0 testbed + temp_tg_port (pytest fixture): Ports mapping info of T0 testbed multipath: ecmp value for BGP config start_value: Start value of the number of BGP routes step_value: Step value of the number of BGP routes to be incremented @@ -672,7 +651,7 @@ def tgen_capacity(routes): conv_config = cvg_api.convergence_config() config = conv_config.config for i in range(1, 3): - config.ports.port(name='Test_Port_%d' % i, location=tgen_ports[i-1]['location']) + config.ports.port(name='Test_Port_%d' % i, location=temp_tg_port[i-1]['location']) config.devices.device(name='Topology %d' % i) config.devices[i-1].container_name = config.ports[i-1].name @@ -690,9 +669,9 @@ def create_v4_topo(): config.devices[0].ethernet.name = 'Ethernet 1_%d' % routes config.devices[0].ethernet.mac = "00:00:00:00:00:01" config.devices[0].ethernet.ipv4.name = 'IPv4 1_%d' % routes - config.devices[0].ethernet.ipv4.address = tgen_ports[0]['ip'] - config.devices[0].ethernet.ipv4.gateway = tgen_ports[0]['peer_ip'] - config.devices[0].ethernet.ipv4.prefix = int(tgen_ports[0]['prefix']) + config.devices[0].ethernet.ipv4.address = temp_tg_port[0]['ip'] + config.devices[0].ethernet.ipv4.gateway = temp_tg_port[0]['peer_ip'] + config.devices[0].ethernet.ipv4.prefix = int(temp_tg_port[0]['prefix']) rx_flow_name = [] for i in range(2, 3): if len(str(hex(i).split('0x')[1])) == 1: @@ -704,14 +683,14 @@ def create_v4_topo(): ethernet_stack.mac = "00:00:00:00:00:%s" % m ipv4_stack = ethernet_stack.ipv4 ipv4_stack.name = 'IPv4_%d_%d' % (i, routes) - ipv4_stack.address = tgen_ports[i-1]['ip'] - ipv4_stack.gateway = tgen_ports[i-1]['peer_ip'] - ipv4_stack.prefix = int(tgen_ports[i-1]['prefix']) + ipv4_stack.address = temp_tg_port[i-1]['ip'] + ipv4_stack.gateway = temp_tg_port[i-1]['peer_ip'] + ipv4_stack.prefix = int(temp_tg_port[i-1]['prefix']) bgpv4_stack = ipv4_stack.bgpv4 bgpv4_stack.name = 'BGP_%d_%d' % (i, routes) bgpv4_stack.as_type = BGP_TYPE - bgpv4_stack.dut_address = tgen_ports[i-1]['peer_ip'] - bgpv4_stack.local_address = tgen_ports[i-1]['ip'] + bgpv4_stack.dut_address = temp_tg_port[i-1]['peer_ip'] + bgpv4_stack.local_address = temp_tg_port[i-1]['ip'] bgpv4_stack.as_number = int(TGEN_AS_NUM) route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group %d_%d" % (i, routes))[-1] route_range.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=routes) @@ -722,9 +701,9 @@ def create_v6_topo(): config.devices[0].ethernet.name = 'Ethernet 1' config.devices[0].ethernet.mac = "00:00:00:00:00:01" config.devices[0].ethernet.ipv6.name = 'IPv6 1' - config.devices[0].ethernet.ipv6.address = tgen_ports[0]['ipv6'] - config.devices[0].ethernet.ipv6.gateway = tgen_ports[0]['peer_ipv6'] - config.devices[0].ethernet.ipv6.prefix = int(tgen_ports[0]['ipv6_prefix']) + config.devices[0].ethernet.ipv6.address = temp_tg_port[0]['ipv6'] + config.devices[0].ethernet.ipv6.gateway = temp_tg_port[0]['peer_ipv6'] + config.devices[0].ethernet.ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix']) rx_flow_name = [] for i in range(2, 3): if len(str(hex(i).split('0x')[1])) == 1: @@ -736,14 +715,14 @@ def create_v6_topo(): ethernet_stack.mac = "00:00:00:00:00:%s" % m ipv6_stack = ethernet_stack.ipv6 ipv6_stack.name = 'IPv6 %d' % i - ipv6_stack.address = tgen_ports[i-1]['ipv6'] - ipv6_stack.gateway = tgen_ports[i-1]['peer_ipv6'] - ipv6_stack.prefix = int(tgen_ports[i-1]['ipv6_prefix']) + ipv6_stack.address = temp_tg_port[i-1]['ipv6'] + ipv6_stack.gateway = temp_tg_port[i-1]['peer_ipv6'] + ipv6_stack.prefix = int(temp_tg_port[i-1]['ipv6_prefix']) bgpv6_stack = ipv6_stack.bgpv6 bgpv6_stack.name = r'BGP+ %d' % i bgpv6_stack.as_type = BGP_TYPE - bgpv6_stack.dut_address = tgen_ports[i-1]['peer_ipv6'] - bgpv6_stack.local_address = tgen_ports[i-1]['ipv6'] + bgpv6_stack.dut_address = temp_tg_port[i-1]['peer_ipv6'] + bgpv6_stack.local_address = temp_tg_port[i-1]['ipv6'] bgpv6_stack.as_number = int(TGEN_AS_NUM) route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group %d_%d" % (routes, i))[-1] route_range.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=routes) @@ -794,42 +773,14 @@ def create_v6_topo(): break logger.info('|------------ Max Routes without loss (RIB-IN Capacity Value) : {} ----|'.format(max_routes)) -def cleanup_config(duthost, - tgen_ports, - port_count, - route_type,): +def cleanup_config(duthost): """ Cleaning up dut config at the end of the test Args: duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of T0 testbed - port_count:multipath + 1 - route_type: IPv4 or IPv6 routes """ - if route_type == 'IPv4': - peer_ip = 'peer_ip' - ip = 'ip' - prefix = 'prefix' - else: - peer_ip = 'peer_ipv6' - ip = 'ipv6' - prefix = 'ipv6_prefix' - 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 %s address %s/%s' " - ) - intf_config_cleanup %= (tgen_ports[i]['peer_port'], ip, tgen_ports[i][peer_ip], tgen_ports[i][prefix]) - duthost.shell(intf_config_cleanup) + duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json","/etc/sonic/config_db.json")) + duthost.shell("sudo config reload -y \n") + wait(TIMEOUT+60,"For Cleanup to complete \n") logger.info('Convergence Test Completed') From 8f86a50da144eb9111308f4196bf50148c5a44eb Mon Sep 17 00:00:00 2001 From: selldinesh Date: Thu, 16 Sep 2021 21:06:24 +0000 Subject: [PATCH 25/58] resolving alert --- tests/ixia/bgp/files/bgp_convergence_helper.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py index 3a98d47d030..82dc09bf594 100644 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ b/tests/ixia/bgp/files/bgp_convergence_helper.py @@ -236,6 +236,7 @@ def duthost_bgp_config(duthost, json.dump(cdf, fp, indent=4) duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") cdf = json.loads(duthost.shell("sonic-cfggen -j /tmp/config_db_temp.json --print-data")['stdout']) + logger.info(cdf) duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json","/etc/sonic/config_db.json")) logger.info('Reloading config to apply BGP config') duthost.shell("sudo config reload -y \n") From 9dbb56d010c3eb056242a76bea58d2631747956c Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 17 Sep 2021 07:27:48 +0000 Subject: [PATCH 26/58] Adding reboot testcases --- tests/ixia/reboot/files/__init__.py | 0 tests/ixia/reboot/files/reboot_helper.py | 342 +++++++++++++++++++++++ tests/ixia/reboot/test_cold_reboot.py | 48 ++++ tests/ixia/reboot/test_fast_reboot.py | 48 ++++ tests/ixia/reboot/test_warm_reboot.py | 47 ++++ 5 files changed, 485 insertions(+) create mode 100755 tests/ixia/reboot/files/__init__.py create mode 100755 tests/ixia/reboot/files/reboot_helper.py create mode 100644 tests/ixia/reboot/test_cold_reboot.py create mode 100644 tests/ixia/reboot/test_fast_reboot.py create mode 100644 tests/ixia/reboot/test_warm_reboot.py diff --git a/tests/ixia/reboot/files/__init__.py b/tests/ixia/reboot/files/__init__.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/tests/ixia/reboot/files/reboot_helper.py b/tests/ixia/reboot/files/reboot_helper.py new file mode 100755 index 00000000000..148108a282e --- /dev/null +++ b/tests/ixia/reboot/files/reboot_helper.py @@ -0,0 +1,342 @@ +from tabulate import tabulate +from tests.common.utilities import (wait, wait_until) +from tests.common.helpers.assertions import pytest_assert +from tests.common.reboot import reboot +import json +import ipaddr +logger = logging.getLogger(__name__) + +DUT_AS_NUM = 65100 +TGEN_AS_NUM = 65200 +TIMEOUT = 30 +BGP_TYPE = 'ebgp' +temp_tg_port = dict() + + +def run_reboot_test(cvg_api, + duthost, + localhost, + tgen_ports, + reboot_type,): + """ + Run Local link failover test + + Args: + cvg_api (pytest fixture): snappi API + duthost (pytest fixture): duthost fixture + localhost (pytest fixture): localhost handle + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + reboot_type : Type of reboot + """ + + """ Create bgp config on dut """ + duthost_bgp_config(duthost, tgen_ports) + + """ Create bgp config on TGEN """ + tgen_bgp_config = __tgen_bgp_config(cvg_api) + + """ + Run the convergence test by flapping all the rx + links one by one and calculate the convergence valuess + """ + get_convergence_for_reboot_test(duthost, localhost, cvg_api, tgen_bgp_config, reboot_type,) + + cleanup_config(duthost) + + +def duthost_bgp_config(duthost, tgen_ports): + """ + 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 + """ + global temp_tg_port + duthost.command("sudo config save -y") + duthost.command("sudo cp {} {}".format("/etc/sonic/config_db.json", "/etc/sonic/config_db_backup.json")) + temp_tg_port = tgen_ports + for i in range(1, 4): + intf_config = ( + "sudo config interface ip remove %s %s/%s \n" + "sudo config interface ip remove %s %s/%s \n" + ) + intf_config %= (tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ipv6'], tgen_ports[i]['ipv6_prefix']) + logger.info('Removing configured IP and IPv6 Address from %s' % (tgen_ports[i]['peer_port'])) + duthost.shell(intf_config) + vlan_config=( + 'sudo config vlan add 1000\n' + 'sudo config vlan member add -u 1000 %s\n' + 'sudo config vlan member add -u 1000 %s\n' + 'sudo config interface ip add Vlan1000 192.168.1.1/16\n' + 'sudo config interface ip add Vlan1000 5001::1/64\n' + ) + vlan_config %= (tgen_ports[3]['peer_port'], tgen_ports[2]['peer_port']) + logger.info('Adding %s and %s to Vlan 1000' % (tgen_ports[3]['peer_port'], tgen_ports[2]['peer_port'])) + duthost.shell(vlan_config) + portchannel_config = ( + "sudo config portchannel add PortChannel1 \n" + "sudo config portchannel member add PortChannel1 %s\n" + "sudo config interface ip add PortChannel1 %s/%s\n" + "sudo config interface ip add PortChannel1 %s/%s\n" + ) + portchannel_config %= (tgen_ports[1]['peer_port'], tgen_ports[1]['peer_ip'], tgen_ports[1]['prefix'], tgen_ports[1]['peer_ipv6'], 64) + logger.info('Configuring %s to PortChannel1' % (tgen_ports[1]['peer_port'])) + logger.info('Portchannel1 (IPv4,IPv6) : ({},{})'.format(tgen_ports[1]['peer_ip'], tgen_ports[1]['peer_ipv6'])) + duthost.shell(portchannel_config) + loopback = ( + "sudo config interface ip add Loopback1 1.1.1.1/32\n" + ) + logger.info('Configuring 1.1.1.1/32 on the loopback interface') + duthost.shell(loopback) + logger.info('Configuring BGP in config_db.json') + bgp_neighbors = {tgen_ports[1]['ipv6']: {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[1]['peer_ipv6'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"},tgen_ports[1]['ip']: {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[1]['peer_ip'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"}} + cdf = json.loads(duthost.shell("sonic-cfggen -d --print-data")['stdout']) + for neighbor, neighbor_info in bgp_neighbors.items(): + cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info + + with open("/tmp/sconfig_db.json", 'w') as fp: + json.dump(cdf, fp, indent=4) + duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") + cdf = json.loads(duthost.shell("sonic-cfggen -j /tmp/config_db_temp.json --print-data")['stdout']) + print(cdf) + duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json", "/etc/sonic/config_db.json")) + logger.info('Reloading config to apply BGP config') + duthost.shell("sudo config reload -y \n") + wait(TIMEOUT+60, "For Config to reload \n") + + +def get_flow_stats(cvg_api, name): + """ + Args: + cvg_api (pytest fixture): Snappi API + """ + request = cvg_api.convergence_request() + request.metrics.flow_names = [name] + return cvg_api.get_results(request).flow_metric + + +def get_macs(mac, count, offset=1): + """ + Take mac as start mac returns the count of macs in a list + """ + mac_list = list() + for i in range(count): + mac_address = "{:012X}".format(int(mac, 16) + offset * i) + mac_address = ":".join( + format(s, "02x") for s in bytearray.fromhex(mac_address) + ) + mac_list.append(mac_address) + return mac_list + + +def get_ip_addresses(ip, count,type='ipv4'): + """ + Take ip as start ip returns the count of ips in a list + """ + ip_list = list() + for i in range(count): + if type == 'ipv6': + ipaddress = ipaddr.IPv6Address(ip) + else: + ipaddress = ipaddr.IPv4Address(ip) + ipaddress = ipaddress + i + value = ipaddress._string_from_ip_int(ipaddress._ip) + ip_list.append(value) + return ip_list + + +def __tgen_bgp_config(cvg_api,): + """ + Creating BGP config on TGEN + + Args: + cvg_api (pytest fixture): snappi API + """ + #temp_tg_port=[{'ip': '24.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet76', 'prefix': u'24', 'location': '10.36.78.53;4;4', 'ipv6': '2000:4::8', 'ipv6_prefix': u'124', 'port_id': '4', 'peer_ip': u'24.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:4::1'}, {'ip': '23.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet72', 'prefix': u'24', 'location': '10.36.78.53;4;3', 'ipv6': '2000:3::3', 'ipv6_prefix': u'124', 'port_id': '3', 'peer_ip': u'23.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:3::1'}, {'ip': '22.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet68', 'prefix': u'24', 'location': '10.36.78.53;4;2', 'ipv6': '2000:2::f', 'ipv6_prefix': u'124', 'port_id': '2', 'peer_ip': u'22.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:2::1'}, {'ip': '21.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet64', 'prefix': u'24', 'location': '10.36.78.53;4;1', 'ipv6': '2000:1::a', 'ipv6_prefix': u'124', 'port_id': '1', 'peer_ip': u'21.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:1::1'}] + conv_config = cvg_api.convergence_config() + cvg_api.enable_scaling(True) + config = conv_config.config + p1, p2, p3 = ( + config.ports.port(name="t1", location=temp_tg_port[1]['location']) + .port(name="server2", location=temp_tg_port[2]['location']) + .port(name="server1", location=temp_tg_port[3]['location']) + ) + lag3 = config.lags.lag(name="lag1")[-1] + lp3 = lag3.ports.port(port_name=p1.name)[-1] + lp3.protocol.lacp.actor_system_id = "00:11:03:00:00:03" + lp3.ethernet.name = "lag_Ethernet 3" + lp3.ethernet.mac = "00:13:01:00:00:01" + + config.options.port_options.location_preemption = True + layer1 = config.layer1.layer1()[-1] + layer1.name = 'port settings' + layer1.port_names = [port.name for port in config.ports] + layer1.ieee_media_defaults = False + layer1.auto_negotiation.rs_fec = True + layer1.auto_negotiation.link_training = False + layer1.speed = "speed_100_gbps" + layer1.auto_negotiate = False + + conf_values = dict() + num_of_devices = 1000 + conf_values['server_1_ipv4'] = get_ip_addresses("192.168.1.2", 2000)[::2] + conf_values['server_2_ipv4'] = get_ip_addresses("192.168.1.2", 2000)[1::2] + conf_values['server_1_ipv6'] = get_ip_addresses("5000::2", 2000, 'ipv6')[::2] + conf_values['server_2_ipv6'] = get_ip_addresses("5000::2", 2000, 'ipv6')[1::2] + conf_values['server_1_mac'] = get_macs("001700000011", num_of_devices) + conf_values['server_2_mac'] = get_macs("001600000011", num_of_devices) + for i in range(1, num_of_devices+1): + #server1 + d1 = config.devices.device(name='Server_1_{}'.format(i-1))[-1] + d1.container_name = p3.name + eth_1 = d1.ethernet + eth_1.name = 'Ethernet 1_{}'.format(i-1) + eth_1.mac = conf_values['server_1_mac'][i-1] + ipv4_1 = d1.ethernet.ipv4 + ipv4_1.name = 'IPv4 1_{}'.format(i-1) + ipv4_1.address = conf_values['server_1_ipv4'][i-1] + ipv4_1.gateway = '192.168.1.1' + ipv4_1.prefix = 16 + ipv6_1 = d1.ethernet.ipv6 + ipv6_1.name = 'IPv6 1_{}'.format(i-1) + ipv6_1.address = conf_values['server_1_ipv6'][i-1] + ipv6_1.gateway = '5001::1' + ipv6_1.prefix = 64 + #server2 + d2 = config.devices.device(name='Server_2_{}'.format(i-1))[-1] + d2.container_name = p2.name + eth_2 = d2.ethernet + eth_2.name = 'Ethernet 2_{}'.format(i-1) + eth_2.mac = conf_values['server_2_mac'][i-1] + ipv4_2 = d2.ethernet.ipv4 + ipv4_2.name = 'IPv4 2_{}'.format(i-1) + ipv4_2.address = conf_values['server_2_ipv4'][i-1] + ipv4_2.gateway = '192.168.1.1' + ipv4_2.prefix = 16 + ipv6_2 = d2.ethernet.ipv6 + ipv6_2.name = 'IPv6 2_{}'.format(i-1) + ipv6_2.address = conf_values['server_2_ipv6'][i-1] + ipv6_2.gateway = '5001::1' + ipv6_2.prefix = 64 + + #T1 + d3 = config.devices.device(name="T1")[-1] + d3.container_name = lag3.name + eth_3 = d3.ethernet + eth_3.name = 'Ethernet 3' + eth_3.mac = "00:14:01:00:00:01" + ipv4_3 = eth_3.ipv4 + ipv4_3.name = 'IPv4 3' + ipv4_3.address = temp_tg_port[1]['ip'] + ipv4_3.gateway = temp_tg_port[1]['peer_ip'] + ipv4_3.prefix = 24 + ipv6_3 = eth_3.ipv6 + ipv6_3.name = 'IPv6 3' + + ipv6_3.address = temp_tg_port[1]['ipv6'] + ipv6_3.gateway = temp_tg_port[1]['peer_ipv6'] + ipv6_3.prefix = 64 + bgpv4_stack = ipv4_3.bgpv4 + bgpv4_stack.name = 'BGP 3' + bgpv4_stack.as_type = BGP_TYPE + bgpv4_stack.dut_address = temp_tg_port[1]['peer_ip'] + bgpv4_stack.local_address = temp_tg_port[1]['ip'] + bgpv4_stack.as_number = int(TGEN_AS_NUM) + route_range1 = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group 1")[-1] + route_range1.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=1) + bgpv6_stack = ipv6_3.bgpv6 + bgpv6_stack.name = r'BGP+_3' + bgpv6_stack.as_type = BGP_TYPE + bgpv6_stack.dut_address = temp_tg_port[1]['peer_ipv6'] + bgpv6_stack.local_address = temp_tg_port[1]['ipv6'] + bgpv6_stack.as_number = int(TGEN_AS_NUM) + route_range2 = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group 2")[-1] + route_range2.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=1) + + def createTrafficItem(traffic_name, src, dest, rate=50): + flow1 = config.flows.flow(name=str(traffic_name))[-1] + flow1.tx_rx.device.tx_names = src + flow1.tx_rx.device.rx_names = dest + flow1.size.fixed = 1024 + flow1.rate.percentage = rate + flow1.metrics.enable = True + ipv4_1_names = ["IPv4 1_{}".format(i-1) for i in range(1, num_of_devices + 1)] + ipv4_2_names = ["IPv4 2_{}".format(i-1) for i in range(1, num_of_devices + 1)] + ipv6_1_names = ["IPv6 1_{}".format(i-1) for i in range(1, num_of_devices + 1)] + ipv6_2_names = ["IPv6 2_{}".format(i-1) for i in range(1, num_of_devices + 1)] + createTrafficItem("IPv4_1-IPv4_2", ipv4_1_names, ipv4_2_names) + createTrafficItem("IPv6_2-IPv6_1", ipv6_2_names, ipv6_1_names) + createTrafficItem("IPv4_1-T1", ipv4_1_names, [route_range1.name]) + createTrafficItem("IPv6_2-T1", ipv6_2_names, [route_range2.name]) + createTrafficItem("T1-IPv4_1", [route_range1.name], ipv4_1_names) + return conv_config + + +def get_convergence_for_reboot_test(duthost, + localhost, + cvg_api, + bgp_config, + reboot_type): + """ + Args: + duthost (pytest fixture): duthost fixture + localhost (pytest fixture): localhost handle + cvg_api (pytest fixture): snappi API + bgp_config: __tgen_bgp_config + reboot_type: Type of reboot + """ + table, dp = [], [] + bgp_config.rx_rate_threshold = 90 + cvg_api.set_config(bgp_config) + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + flow_names = ["IPv4_1-IPv4_2", "IPv6_2-IPv6_1", "IPv4_1-T1", "IPv6_2-T1", "T1-IPv4_1"] + cs.transmit.flow_names = flow_names + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT-10, "For Traffic To start") + req = cvg_api.ping_request() + p1 = req.endpoints.ipv4()[-1] + p1.src_name = 'IPv4 3' + p1.dst_ip = "1.1.1.1" + + logger.info("Issuing a {} reboot on the dut {}".format(reboot_type, duthost.hostname)) + reboot(duthost, localhost, reboot_type=reboot_type) + logger.info("Wait until the system is stable") + pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") + + responses = cvg_api.send_ping(req).responses + assert responses[-1].result == "success" + logger.info('Ping from IPv4 3 --> {} : {} after {} seconds after {}'.format(p1.dst_ip, responses[-1].result, 180, reboot_type)) + request = cvg_api.convergence_request() + for i in cs.transmit.flow_names: + request.metrics.flow_names = [i] + flow = cvg_api.get_results(request).flow_metric + assert int(flow[0].frames_tx_rate) != 0, "No Frames sent for traffic item: {}".format(i) + assert flow[0].frames_tx_rate == flow[0].frames_tx_rate, "Loss observed for Traffic Item: {}".format(i) + logger.info("No Loss Observed in Traffic Item {}".format(i)) + + request.convergence.flow_names = flow_names + convergence_metrics = cvg_api.get_results(request).flow_convergence + for metrics in convergence_metrics: + dp.append(metrics.data_plane_convergence_us/1000) + logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, metrics.data_plane_convergence_us/1000)) + + for j, i in enumerate(flow_names): + table.append([reboot_type, i, dp[j]]) + columns = ['Reboot Type', 'Traffic Item Name', 'Data Plane Convergence Time (ms)'] + logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) + +def cleanup_config(duthost): + """ + Cleaning up dut config at the end of the test + + Args: + duthost (pytest fixture): duthost fixture + """ + logger.info('Cleaning up config') + duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json", "/etc/sonic/config_db.json")) + duthost.shell("sudo config reload -y \n") + wait(TIMEOUT+30, "For Cleanup to complete \n") + logger.info('Convergence Test Completed') diff --git a/tests/ixia/reboot/test_cold_reboot.py b/tests/ixia/reboot/test_cold_reboot.py new file mode 100644 index 00000000000..af07e45e549 --- /dev/null +++ b/tests/ixia/reboot/test_cold_reboot.py @@ -0,0 +1,48 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.reboot_helper import run_reboot_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('reboot_type', ['cold']) +def test_reboot(cvg_api, + duthost, + localhost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + reboot_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create 2 servers and a T1 device with dual stack BGP + 2) Configure LAG for the T1 Device + 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 + 4) Make sure there is no loss observed while sending trafic + 5) Reboot the dut with cold-reboot command + 6) Make sure after reboot the traffic has converged + + Verification: + 1) Make sure the control plane is up after the reboot is complete and the dut is back up + 2) Traffic must have converged after the dut is back up + + Args: + cvg_api (pytest fixture): Snappi Convergence API + duthost (pytest fixture): duthost fixture + localhost (pytest fixture): localhost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + reboot_type (parameter): Reboot command + """ + run_reboot_test(cvg_api, + duthost, + localhost, + tgen_ports, + reboot_type,) diff --git a/tests/ixia/reboot/test_fast_reboot.py b/tests/ixia/reboot/test_fast_reboot.py new file mode 100644 index 00000000000..37e9087ae37 --- /dev/null +++ b/tests/ixia/reboot/test_fast_reboot.py @@ -0,0 +1,48 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.reboot_helper import run_reboot_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('reboot_type', ['fast']) +def test_reboot(cvg_api, + duthost, + localhost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + reboot_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create 2 servers and a T1 device with dual stack BGP + 2) Configure LAG for the T1 Device + 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 + 4) Make sure there is no loss observed while sending trafic + 5) Reboot the dut with fast-reboot command + 6) Make sure after reboot the traffic has converged + + Verification: + 1) Make sure the control plane is up after the reboot is complete and the dut is back up + 2) Traffic must have converged after the dut is back up + + Args: + cvg_api (pytest fixture): Snappi Convergence API + duthost (pytest fixture): duthost fixture + localhost (pytest fixture): localhost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + reboot_type (parameter): Reboot command + """ + run_reboot_test(cvg_api, + duthost, + localhost, + tgen_ports, + reboot_type,) diff --git a/tests/ixia/reboot/test_warm_reboot.py b/tests/ixia/reboot/test_warm_reboot.py new file mode 100644 index 00000000000..e0efa16156b --- /dev/null +++ b/tests/ixia/reboot/test_warm_reboot.py @@ -0,0 +1,47 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.reboot_helper import run_reboot_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('reboot_type', ['warm']) +def test_reboot(cvg_api, + duthost, + localhost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + reboot_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create 2 servers and a T1 device with dual stack BGP + 2) Configure LAG for the T1 Device + 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 + 4) Make sure there is no loss observed while sending trafic + 5) Reboot the dut with warm-reboot command + 6) Make sure after reboot the traffic has converged + + Verification: + 1) Make sure the control plane is up after the reboot is complete and the dut is back up + 2) Traffic must have converged after the dut is back up + + Args: + cvg_api (pytest fixture): Snappi Convergence API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + reboot_type (parameter): Reboot command + """ + run_reboot_test(cvg_api, + duthost, + localhost, + tgen_ports, + reboot_type,) From 4f818af298eaaeb71b3b20396faf74c4d97a14b7 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 17 Sep 2021 08:26:33 +0000 Subject: [PATCH 27/58] adding BGP convergence cases to tests/snappi folder --- tests/snappi/bgp/files/__init__.py | 0 .../bgp/files/bgp_convergence_helper.py | 787 ++++++++++++++++++ .../bgp/test_bgp_local_link_failover.py | 60 ++ .../bgp/test_bgp_remote_link_failover.py | 59 ++ tests/snappi/bgp/test_bgp_rib_in_capacity.py | 60 ++ .../snappi/bgp/test_bgp_rib_in_convergence.py | 61 ++ 6 files changed, 1027 insertions(+) create mode 100644 tests/snappi/bgp/files/__init__.py create mode 100644 tests/snappi/bgp/files/bgp_convergence_helper.py create mode 100644 tests/snappi/bgp/test_bgp_local_link_failover.py create mode 100755 tests/snappi/bgp/test_bgp_remote_link_failover.py create mode 100644 tests/snappi/bgp/test_bgp_rib_in_capacity.py create mode 100644 tests/snappi/bgp/test_bgp_rib_in_convergence.py diff --git a/tests/snappi/bgp/files/__init__.py b/tests/snappi/bgp/files/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py new file mode 100644 index 00000000000..82dc09bf594 --- /dev/null +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -0,0 +1,787 @@ +from tabulate import tabulate +from statistics import mean +from tests.common.utilities import wait +import json +logger = logging.getLogger(__name__) + +TGEN_AS_NUM = 65200 +TIMEOUT = 40 +BGP_TYPE = 'ebgp' +temp_tg_port=dict() + +def run_bgp_local_link_failover_test(cvg_api, + duthost, + tgen_ports, + iteration, + multipath, + number_of_routes, + route_type,): + """ + Run Local link failover test + + Args: + cvg_api (pytest fixture): snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + iteration: number of iterations for running convergence test on a port + multipath: ecmp value for BGP config + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes + """ + port_count = multipath+1 + + """ Create bgp config on dut """ + duthost_bgp_config(duthost, + tgen_ports, + port_count,) + + """ Create bgp config on TGEN """ + tgen_bgp_config = __tgen_bgp_config(cvg_api, + port_count, + number_of_routes, + route_type,) + + """ + Run the convergence test by flapping all the rx + links one by one and calculate the convergence values + """ + get_convergence_for_local_link_failover(cvg_api, + tgen_bgp_config, + iteration, + multipath, + number_of_routes, + route_type,) + + """ Cleanup the dut configs after getting the convergence numbers """ + cleanup_config(duthost) + + +def run_bgp_remote_link_failover_test(cvg_api, + duthost, + tgen_ports, + iteration, + multipath, + number_of_routes, + route_type,): + """ + Run Remote link failover test + + Args: + cvg_api (pytest fixture): snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + iteration: number of iterations for running convergence test on a port + multipath: ecmp value for BGP config + route_type: IPv4 or IPv6 routes + """ + port_count = multipath+1 + """ Create bgp config on dut """ + duthost_bgp_config(duthost, + tgen_ports, + port_count,) + + """ Create bgp config on TGEN """ + tgen_bgp_config = __tgen_bgp_config(cvg_api, + port_count, + number_of_routes, + route_type,) + + """ + Run the convergence test by withdrawing all the route ranges + one by one and calculate the convergence values + """ + get_convergence_for_remote_link_failover(cvg_api, + tgen_bgp_config, + iteration, + multipath, + number_of_routes, + route_type,) + + """ Cleanup the dut configs after getting the convergence numbers """ + cleanup_config(duthost) + + + +def run_rib_in_convergence_test(cvg_api, + duthost, + tgen_ports, + iteration, + multipath, + number_of_routes, + route_type,): + """ + Run RIB-IN Convergence test + + Args: + cvg_api (pytest fixture): snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + iteration: number of iterations for running convergence test on a port + multipath: ecmp value for BGP config + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes + """ + port_count = multipath+1 + + """ Create bgp config on dut """ + duthost_bgp_config(duthost, + tgen_ports, + port_count,) + + """ Create bgp config on TGEN """ + tgen_bgp_config = __tgen_bgp_config(cvg_api, + port_count, + number_of_routes, + route_type,) + + """ + Run the convergence test by withdrawing all routes at once and + calculate the convergence values + """ + get_rib_in_convergence(cvg_api, + tgen_bgp_config, + iteration, + multipath, + number_of_routes, + route_type,) + + """ Cleanup the dut configs after getting the convergence numbers """ + cleanup_config(duthost) + + +def run_RIB_IN_capacity_test(cvg_api, + duthost, + tgen_ports, + multipath, + start_value, + step_value, + route_type,): + + """ + Run RIB-IN Capacity test + + Args: + cvg_api (pytest fixture): snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + multipath: ecmp value for BGP config + start_value: + step_value: + route_type: IPv4 or IPv6 routes + """ + port_count = multipath+1 + """ Create bgp config on dut """ + duthost_bgp_config(duthost, + tgen_ports, + port_count,) + + + """ Run the RIB-IN capacity test by increasig the route count step by step """ + get_RIB_IN_capacity(cvg_api, + multipath, + start_value, + step_value, + route_type,) + + """ Cleanup the dut configs after getting the convergence numbers """ + cleanup_config(duthost) + + +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:multipath + 1 + multipath: ECMP value for BGP config + """ + duthost.command("sudo config save -y") + duthost.command("sudo cp {} {}".format("/etc/sonic/config_db.json", "/etc/sonic/config_db_backup.json")) + global temp_tg_port + temp_tg_port = tgen_ports + for i in range(0, port_count): + intf_config = ( + "sudo config interface ip remove %s %s/%s \n" + "sudo config interface ip remove %s %s/%s \n" + ) + intf_config %= (tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ipv6'], tgen_ports[i]['ipv6_prefix']) + logger.info('Removing configured IP and IPv6 Address from %s' % (tgen_ports[i]['peer_port'])) + duthost.shell(intf_config) + + for i in range(0, port_count): + portchannel_config = ( + "sudo config portchannel add PortChannel%s \n" + "sudo config portchannel member add PortChannel%s %s\n" + "sudo config interface ip add PortChannel%s %s/%s\n" + "sudo config interface ip add PortChannel%s %s/%s\n" + ) + portchannel_config %= (i+1, i+1, tgen_ports[i]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], i+1, tgen_ports[i]['peer_ipv6'], 64) + logger.info('Configuring %s to PortChannel%s with IPs %s,%s' % (tgen_ports[1]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['peer_ipv6'])) + duthost.shell(portchannel_config) + logger.info('Configuring BGP in config_db.json') + bgp_neighbors = dict() + for i in range(1, port_count): + bgp_neighbors[tgen_ports[i]['ipv6']] = {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[i]['peer_ipv6'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"} + bgp_neighbors[tgen_ports[i]['ip']] = {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[i]['peer_ip'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"} + + cdf = json.loads(duthost.shell("sonic-cfggen -d --print-data")['stdout']) + for neighbor, neighbor_info in bgp_neighbors.items(): + cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info + + with open("/tmp/sconfig_db.json", 'w') as fp: + json.dump(cdf, fp, indent=4) + duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") + cdf = json.loads(duthost.shell("sonic-cfggen -j /tmp/config_db_temp.json --print-data")['stdout']) + logger.info(cdf) + duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json","/etc/sonic/config_db.json")) + logger.info('Reloading config to apply BGP config') + duthost.shell("sudo config reload -y \n") + wait(TIMEOUT+60,"For Config to reload \n") + + +def __tgen_bgp_config(cvg_api, + port_count, + number_of_routes, + route_type,): + """ + Creating BGP config on TGEN + + Args: + cvg_api (pytest fixture): snappi API + port_count: multipath + 1 + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes + """ + conv_config = cvg_api.convergence_config() + config = conv_config.config + for i in range(1, port_count+1): + config.ports.port(name='Test_Port_%d' % i, location=temp_tg_port[i-1]['location']) + c_lag = config.lags.lag(name="lag%d" % i)[-1] + lp = c_lag.ports.port(port_name='Test_Port_%d' % i)[-1] + lp.ethernet.name = 'lag_eth_%d' % i + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] + else: + m = hex(i).split('0x')[1] + lp.protocol.lacp.actor_system_id = "00:10:00:00:00:%s" % m + lp.ethernet.name = "lag_Ethernet %s" % i + lp.ethernet.mac = "00:10:01:00:00:%s" % m + config.devices.device(name='Topology %d' % i) + config.devices[i-1].container_name = c_lag.name + + config.options.port_options.location_preemption = True + layer1 = config.layer1.layer1()[-1] + layer1.name = 'port settings' + layer1.port_names = [port.name for port in config.ports] + layer1.ieee_media_defaults = False + layer1.auto_negotiation.rs_fec = True + layer1.auto_negotiation.link_training = False + layer1.speed = "speed_100_gbps" + layer1.auto_negotiate = False + + def create_v4_topo(): + config.devices[0].ethernet.name = 'Ethernet 1' + config.devices[0].ethernet.mac = "00:00:00:00:00:01" + config.devices[0].ethernet.ipv4.name = 'IPv4 1' + config.devices[0].ethernet.ipv4.address = temp_tg_port[0]['ip'] + config.devices[0].ethernet.ipv4.gateway = temp_tg_port[0]['peer_ip'] + config.devices[0].ethernet.ipv4.prefix = int(temp_tg_port[0]['prefix']) + rx_flow_name = [] + for i in range(2, port_count+1): + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] + else: + m = hex(i).split('0x')[1] + ethernet_stack = config.devices[i-1].ethernet + ethernet_stack.name = 'Ethernet %d' % i + ethernet_stack.mac = "00:00:00:00:00:%s" % m + ipv4_stack = ethernet_stack.ipv4 + ipv4_stack.name = 'IPv4 %d' % i + ipv4_stack.address = temp_tg_port[i-1]['ip'] + ipv4_stack.gateway = temp_tg_port[i-1]['peer_ip'] + ipv4_stack.prefix = int(temp_tg_port[i-1]['prefix']) + bgpv4_stack = ipv4_stack.bgpv4 + bgpv4_stack.name = 'BGP %d' % i + bgpv4_stack.as_type = BGP_TYPE + bgpv4_stack.dut_address = temp_tg_port[i-1]['peer_ip'] + bgpv4_stack.local_address = temp_tg_port[i-1]['ip'] + bgpv4_stack.as_number = int(TGEN_AS_NUM) + route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group %d" % i)[-1] + route_range.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=number_of_routes) + rx_flow_name.append(route_range.name) + return rx_flow_name + + def create_v6_topo(): + config.devices[0].ethernet.name = 'Ethernet 1' + config.devices[0].ethernet.mac = "00:00:00:00:00:01" + config.devices[0].ethernet.ipv6.name = 'IPv6 1' + config.devices[0].ethernet.ipv6.address = temp_tg_port[0]['ipv6'] + config.devices[0].ethernet.ipv6.gateway = temp_tg_port[0]['peer_ipv6'] + config.devices[0].ethernet.ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix']) + rx_flow_name = [] + for i in range(2, port_count+1): + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] + else: + m = hex(i).split('0x')[1] + ethernet_stack = config.devices[i-1].ethernet + ethernet_stack.name = 'Ethernet %d' % i + ethernet_stack.mac = "00:00:00:00:00:%s" % m + ipv6_stack = ethernet_stack.ipv6 + ipv6_stack.name = 'IPv6 %d' % i + ipv6_stack.address = temp_tg_port[i-1]['ipv6'] + ipv6_stack.gateway = temp_tg_port[i-1]['peer_ipv6'] + ipv6_stack.prefix = int(temp_tg_port[i-1]['ipv6_prefix']) + bgpv6_stack = ipv6_stack.bgpv6 + bgpv6_stack.name = r'BGP+ %d' % i + bgpv6_stack.as_type = BGP_TYPE + bgpv6_stack.dut_address = temp_tg_port[i-1]['peer_ipv6'] + bgpv6_stack.local_address = temp_tg_port[i-1]['ipv6'] + bgpv6_stack.as_number = int(TGEN_AS_NUM) + route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group %d" % i)[-1] + route_range.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=number_of_routes) + rx_flow_name.append(route_range.name) + return rx_flow_name + + if route_type == 'IPv4': + rx_flows = create_v4_topo() + flow = config.flows.flow(name='IPv4 Traffic')[-1] + elif route_type == 'IPv6': + rx_flows = create_v6_topo() + flow = config.flows.flow(name='IPv6 Traffic')[-1] + else: + raise Exception('Invalid route type given') + flow.tx_rx.device.tx_names = [config.devices[0].name] + flow.tx_rx.device.rx_names = rx_flows + flow.size.fixed = 1024 + flow.rate.percentage = 100 + flow.metrics.enable = True + return conv_config + + +def get_flow_stats(cvg_api): + """ + Args: + cvg_api (pytest fixture): Snappi API + """ + request = cvg_api.convergence_request() + request.metrics.flow_names = [] + return cvg_api.get_results(request).flow_metric + + +def get_convergence_for_local_link_failover(cvg_api, + bgp_config, + iteration, + multipath, + number_of_routes, + route_type,): + """ + Args: + cvg_api (pytest fixture): snappi API + bgp_config: __tgen_bgp_config + config: TGEN config + iteration: number of iterations for running convergence test on a port + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes + """ + rx_port_names = [] + for i in range(1, len(bgp_config.config.ports)): + rx_port_names.append(bgp_config.config.ports[i].name) + bgp_config.rx_rate_threshold = 90/(multipath-1) + cvg_api.set_config(bgp_config) + def get_avg_dpdp_convergence_time(port_name): + """ + Args: + port_name: Name of the port + """ + + table, avg, tx_frate, rx_frate = [], [], [], [] + for i in range(0, iteration): + logger.info('|---- {} Link Flap Iteration : {} ----|'.format(port_name, i+1)) + + """ Starting Traffic """ + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To start") + flow_stats = get_flow_stats(cvg_api) + tx_frame_rate = flow_stats[0].frames_tx_rate + assert tx_frame_rate != 0, "Traffic has not started" + + """ Flapping Link """ + logger.info('Simulating Link Failure on {} link'.format(port_name)) + cs = cvg_api.convergence_state() + cs.link.port_names = [port_name] + cs.link.state = cs.link.DOWN + cvg_api.set_state(cs) + wait(TIMEOUT, "For Link to go down") + flows = get_flow_stats(cvg_api) + for flow in flows: + tx_frate.append(flow.frames_tx_rate) + rx_frate.append(flow.frames_tx_rate) + assert sum(tx_frate) == sum(rx_frate), "Traffic has not converged after link flap: TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate)) + logger.info("Traffic has converged after link flap") + """ Get control plane to data plane convergence value """ + request = cvg_api.convergence_request() + request.convergence.flow_names = [] + convergence_metrics = cvg_api.get_results(request).flow_convergence + for metrics in convergence_metrics: + logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) + avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) + + """ Performing link up at the end of iteration """ + logger.info('Simulating Link Up on {} at the end of iteration {}'.format(port_name, i+1)) + cs = cvg_api.convergence_state() + cs.link.port_names = [port_name] + cs.link.state = cs.link.UP + cvg_api.set_state(cs) + table.append('%s Link Failure' % port_name) + table.append(route_type) + table.append(number_of_routes) + table.append(iteration) + table.append(mean(avg)) + return table + table = [] + """ Iterating link flap test on all the rx ports """ + for i, port_name in enumerate(rx_port_names): + table.append(get_avg_dpdp_convergence_time(port_name)) + columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Calculated Data Convergence Time (ms)'] + logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) + + +def get_convergence_for_remote_link_failover(cvg_api, + bgp_config, + iteration, + multipath, + number_of_routes, + route_type,): + """ + Args: + cvg_api (pytest fixture): snappi API + bgp_config: __tgen_bgp_config + config: TGEN config + iteration: number of iterations for running convergence test on a port + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes + """ + route_names = [] + for device in bgp_config.config.devices: + if device.name not in ['Topology 1']: + if route_type == 'IPv4': + for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: + route_names.append(route.name) + else: + for route in device.ethernet.ipv6.bgpv6.bgpv6_routes: + route_names.append(route.name) + bgp_config.rx_rate_threshold = 90/(multipath-1) + cvg_api.set_config(bgp_config) + + + def get_avg_cpdp_convergence_time(route_name): + """ + Args: + route_name: name of the route + + """ + table, avg, tx_frate, rx_frate = [], [], [], [] + for i in range(0, iteration): + logger.info('|---- {} Route Withdraw Iteration : {} ----|'.format(route_name, i+1)) + + """ Starting Traffic """ + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To start") + flow_stats = get_flow_stats(cvg_api) + tx_frame_rate = flow_stats[0].frames_tx_rate + assert tx_frame_rate != 0, "Traffic has not started" + + """ Withdrawing routes from a BGP peer """ + logger.info('Withdrawing Routes from {}'.format(route_name)) + cs = cvg_api.convergence_state() + cs.route.names = [route_name] + cs.route.state = cs.route.WITHDRAW + cvg_api.set_state(cs) + wait(TIMEOUT, "For routes to be withdrawn") + flows = get_flow_stats(cvg_api) + for flow in flows: + tx_frate.append(flow.frames_tx_rate) + rx_frate.append(flow.frames_tx_rate) + assert sum(tx_frate) == sum(rx_frate), "Traffic has not converged after lroute withdraw TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate)) + logger.info("Traffic has converged after route withdraw") + + """ Get control plane to data plane convergence value """ + request = cvg_api.convergence_request() + request.convergence.flow_names = [] + convergence_metrics = cvg_api.get_results(request).flow_convergence + for metrics in convergence_metrics: + logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) + avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) + + """ Advertise the routes back at the end of iteration """ + cs = cvg_api.convergence_state() + cs.route.names = [route_name] + cs.route.state = cs.route.ADVERTISE + cvg_api.set_state(cs) + logger.info('Readvertise {} routes back at the end of iteration {}'.format(route_name, i+1)) + + table.append('%s route withdraw' % route_name) + table.append(route_type) + table.append(number_of_routes) + table.append(iteration) + table.append(mean(avg)) + return table + table = [] + """ Iterating route withdrawal on all BGP peers """ + for route in route_names: + table.append(get_avg_cpdp_convergence_time(route)) + + columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Control to Data Plane Convergence Time (ms)'] + logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) + + +def get_rib_in_convergence(cvg_api, + bgp_config, + iteration, + multipath, + number_of_routes, + route_type,): + """ + Args: + cvg_api (pytest fixture): snappi API + bgp_config: __tgen_bgp_config + config: TGEN config + iteration: number of iterations for running convergence test on a port + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes + """ + route_names = [] + for device in bgp_config.config.devices: + if device.name not in ['Topology 1']: + if route_type == 'IPv4': + for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: + route_names.append(route.name) + else: + for route in device.ethernet.ipv6.bgpv6.bgpv6_routes: + route_names.append(route.name) + bgp_config.rx_rate_threshold = 90/(multipath) + cvg_api.set_config(bgp_config) + + table, avg, tx_frate, rx_frate = [], [], [], [] + for i in range(0, iteration): + logger.info('|---- RIB-IN Convergence test, Iteration : {} ----|'.format(i+1)) + """ withdraw all routes before starting traffic """ + logger.info('Withdraw All Routes before starting traffic') + cs = cvg_api.convergence_state() + cs.route.names = route_names + cs.route.state = cs.route.WITHDRAW + cvg_api.set_state(cs) + wait(TIMEOUT, "For Routes to be withdrawn") + + """ Start Traffic """ + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To start") + flow_stats = get_flow_stats(cvg_api) + tx_frame_rate = flow_stats[0].frames_tx_rate + rx_frame_rate = flow_stats[0].frames_rx_rate + assert tx_frame_rate != 0, "Traffic has not started" + assert rx_frame_rate == 0 + + """ Advertise All Routes """ + logger.info('Advertising all Routes from {}'.format(route_names)) + cs = cvg_api.convergence_state() + cs.route.names = route_names + cs.route.state = cs.route.ADVERTISE + cvg_api.set_state(cs) + wait(TIMEOUT, "For all routes to be ADVERTISED") + flows = get_flow_stats(cvg_api) + for flow in flows: + tx_frate.append(flow.frames_tx_rate) + rx_frate.append(flow.frames_tx_rate) + assert sum(tx_frate) == sum(rx_frate), "Traffic has not convergedv, TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate)) + logger.info("Traffic has converged after route advertisement") + + """ Get RIB-IN convergence """ + request = cvg_api.convergence_request() + request.convergence.flow_names = [] + convergence_metrics = cvg_api.get_results(request).flow_convergence + for metrics in convergence_metrics: + logger.info('RIB-IN Convergence time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) + avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) + + """ Stop traffic at the end of iteration """ + logger.info('Stopping Traffic at the end of iteration{}'.format(i+1)) + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.STOP + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To stop") + table.append('Advertise All BGP Routes') + table.append(route_type) + table.append(number_of_routes) + table.append(iteration) + table.append(mean(avg)) + columns = ['Event Name', 'Route Type', 'No. of Routes','Iterations', 'Avg RIB-IN Convergence Time(ms)'] + logger.info("\n%s" % tabulate([table], headers=columns, tablefmt="psql")) + + +def get_RIB_IN_capacity(cvg_api, + multipath, + start_value, + step_value, + route_type,): + """ + Args: + cvg_api (pytest fixture): snappi API + temp_tg_port (pytest fixture): Ports mapping info of T0 testbed + multipath: ecmp value for BGP config + start_value: Start value of the number of BGP routes + step_value: Step value of the number of BGP routes to be incremented + route_type: IPv4 or IPv6 routes + + """ + def tgen_capacity(routes): + conv_config = cvg_api.convergence_config() + config = conv_config.config + for i in range(1, 3): + config.ports.port(name='Test_Port_%d' % i, location=temp_tg_port[i-1]['location']) + config.devices.device(name='Topology %d' % i) + config.devices[i-1].container_name = config.ports[i-1].name + + config.options.port_options.location_preemption = True + layer1 = config.layer1.layer1()[-1] + layer1.name = 'port settings' + layer1.port_names = [port.name for port in config.ports] + layer1.ieee_media_defaults = False + layer1.auto_negotiation.rs_fec = True + layer1.auto_negotiation.link_training = False + layer1.speed = "speed_100_gbps" + layer1.auto_negotiate = False + + def create_v4_topo(): + config.devices[0].ethernet.name = 'Ethernet 1_%d' % routes + config.devices[0].ethernet.mac = "00:00:00:00:00:01" + config.devices[0].ethernet.ipv4.name = 'IPv4 1_%d' % routes + config.devices[0].ethernet.ipv4.address = temp_tg_port[0]['ip'] + config.devices[0].ethernet.ipv4.gateway = temp_tg_port[0]['peer_ip'] + config.devices[0].ethernet.ipv4.prefix = int(temp_tg_port[0]['prefix']) + rx_flow_name = [] + for i in range(2, 3): + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] + else: + m = hex(i).split('0x')[1] + ethernet_stack = config.devices[i-1].ethernet + ethernet_stack.name = 'Ethernet_%d_%d' % (i, routes) + ethernet_stack.mac = "00:00:00:00:00:%s" % m + ipv4_stack = ethernet_stack.ipv4 + ipv4_stack.name = 'IPv4_%d_%d' % (i, routes) + ipv4_stack.address = temp_tg_port[i-1]['ip'] + ipv4_stack.gateway = temp_tg_port[i-1]['peer_ip'] + ipv4_stack.prefix = int(temp_tg_port[i-1]['prefix']) + bgpv4_stack = ipv4_stack.bgpv4 + bgpv4_stack.name = 'BGP_%d_%d' % (i, routes) + bgpv4_stack.as_type = BGP_TYPE + bgpv4_stack.dut_address = temp_tg_port[i-1]['peer_ip'] + bgpv4_stack.local_address = temp_tg_port[i-1]['ip'] + bgpv4_stack.as_number = int(TGEN_AS_NUM) + route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group %d_%d" % (i, routes))[-1] + route_range.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=routes) + rx_flow_name.append(route_range.name) + return rx_flow_name + + def create_v6_topo(): + config.devices[0].ethernet.name = 'Ethernet 1' + config.devices[0].ethernet.mac = "00:00:00:00:00:01" + config.devices[0].ethernet.ipv6.name = 'IPv6 1' + config.devices[0].ethernet.ipv6.address = temp_tg_port[0]['ipv6'] + config.devices[0].ethernet.ipv6.gateway = temp_tg_port[0]['peer_ipv6'] + config.devices[0].ethernet.ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix']) + rx_flow_name = [] + for i in range(2, 3): + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] + else: + m = hex(i).split('0x')[1] + ethernet_stack = config.devices[i-1].ethernet + ethernet_stack.name = 'Ethernet %d' % i + ethernet_stack.mac = "00:00:00:00:00:%s" % m + ipv6_stack = ethernet_stack.ipv6 + ipv6_stack.name = 'IPv6 %d' % i + ipv6_stack.address = temp_tg_port[i-1]['ipv6'] + ipv6_stack.gateway = temp_tg_port[i-1]['peer_ipv6'] + ipv6_stack.prefix = int(temp_tg_port[i-1]['ipv6_prefix']) + bgpv6_stack = ipv6_stack.bgpv6 + bgpv6_stack.name = r'BGP+ %d' % i + bgpv6_stack.as_type = BGP_TYPE + bgpv6_stack.dut_address = temp_tg_port[i-1]['peer_ipv6'] + bgpv6_stack.local_address = temp_tg_port[i-1]['ipv6'] + bgpv6_stack.as_number = int(TGEN_AS_NUM) + route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group %d_%d" % (routes, i))[-1] + route_range.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=routes) + rx_flow_name.append(route_range.name) + return rx_flow_name + conv_config.rx_rate_threshold = 90/(multipath) + if route_type == 'IPv4': + rx_flows = create_v4_topo() + flow = config.flows.flow(name='IPv4_Traffic_%d' % routes)[-1] + elif route_type == 'IPv6': + rx_flows = create_v6_topo() + flow = config.flows.flow(name='IPv6_Traffic_%d' % routes)[-1] + else: + raise Exception('Invalid route type given') + flow.tx_rx.device.tx_names = [config.devices[0].name] + flow.tx_rx.device.rx_names = rx_flows + flow.size.fixed = 1024 + flow.rate.percentage = 100 + flow.metrics.enable = True + flow.metrics.loss = True + return conv_config + + for j in range(start_value, 100000000000, step_value): + logger.info('|-------------------- RIB-IN Capacity test, No.of Routes : {} ----|'.format(j)) + conv_config = tgen_capacity(j) + cvg_api.set_config(conv_config) + + """ Starting Traffic """ + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To start") + flow_stats = get_flow_stats(cvg_api) + logger.info('Loss% : {}'.format(flow_stats[0].loss)) + logger.info('Stopping Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.STOP + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To stop") + if float(flow_stats[0].loss)>0.1: + if start_value == j: + max_routes = 'N/A' + raise Exception('FAIL:Max Routes: {}, Loss observed in start value itself, set the start value less than : {} !!!!!!!!!!!!'.format(max_routes,start_value)) + else: + max_routes = j-step_value + logger.info('max_routes :{}'.format(max_routes)) + break + logger.info('|------------ Max Routes without loss (RIB-IN Capacity Value) : {} ----|'.format(max_routes)) + +def cleanup_config(duthost): + """ + Cleaning up dut config at the end of the test + + Args: + duthost (pytest fixture): duthost fixture + """ + duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json","/etc/sonic/config_db.json")) + duthost.shell("sudo config reload -y \n") + wait(TIMEOUT+60,"For Cleanup to complete \n") + logger.info('Convergence Test Completed') diff --git a/tests/snappi/bgp/test_bgp_local_link_failover.py b/tests/snappi/bgp/test_bgp_local_link_failover.py new file mode 100644 index 00000000000..88610d988f7 --- /dev/null +++ b/tests/snappi/bgp/test_bgp_local_link_failover.py @@ -0,0 +1,60 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.bgp_convergence_helper2 import run_bgp_local_link_failover_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('multipath', [3]) +@pytest.mark.parametrize('convergence_test_iterations', [1]) +@pytest.mark.parametrize('number_of_routes', [1000]) +@pytest.mark.parametrize('route_type', ['IPv4']) +def test_bgp_convergence_for_local_link_failover(cvg_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + multipath, + convergence_test_iterations, + number_of_routes, + route_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Create a flow from TGEN1 to (N-1) TGEN ports + 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range + 4) Simulate link failure by bringing down one of the (N-1) TGEN Ports + 5) Calculate the packet loss duration for convergence time + 6) Clean up the BGP config on the dut + + Verification: + 1) Send traffic without flapping any link + Result: Should not observe traffic loss + 2) Flap one of the N TGEN link + Result: The traffic must be routed via rest of the ECMP paths + + Args: + cvg_api (pytest fixture): Snappi Convergence API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + multipath: ECMP value + convergence_test_iterations: number of iterations the link failure test has to be run for a port + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes + """ + #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference + run_bgp_local_link_failover_test(cvg_api, + duthost, + tgen_ports, + convergence_test_iterations, + multipath, + number_of_routes, + route_type,) diff --git a/tests/snappi/bgp/test_bgp_remote_link_failover.py b/tests/snappi/bgp/test_bgp_remote_link_failover.py new file mode 100755 index 00000000000..e1357f55d21 --- /dev/null +++ b/tests/snappi/bgp/test_bgp_remote_link_failover.py @@ -0,0 +1,59 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.bgp_convergence_helper import run_bgp_remote_link_failover_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + +@pytest.mark.parametrize('multipath',[2]) +@pytest.mark.parametrize('convergence_test_iterations',[1]) +@pytest.mark.parametrize('number_of_routes',[1000]) +@pytest.mark.parametrize('route_type',['IPv4']) +def test_bgp_convergence_for_remote_link_failover(cvg_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + multipath, + convergence_test_iterations, + number_of_routes, + route_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Create a flow from TGEN1 to (N-1) TGEN ports + 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range + 4) Simulate route withdraw from one of the (N-1) BGP peers which is the equivalent of remote link failure + 5) Calculate the cp/dp for convergence time + 6) Clean up the BGP config on the dut + + Verification: + 1) Send traffic with all routes advertised by BGP peers + Result: Should not observe traffic loss + 2) Withdraw all routes from one of the BGP peer + Result: The traffic must be routed via rest of the ECMP paths and should not observe traffic loss + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + multipath: ECMP value + convergence_test_iterations: number of iterations the cp/dp convergence test has to be run for a port + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes + """ + #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference + run_bgp_remote_link_failover_test(cvg_api, + duthost, + tgen_ports, + convergence_test_iterations, + multipath, + number_of_routes, + route_type,) diff --git a/tests/snappi/bgp/test_bgp_rib_in_capacity.py b/tests/snappi/bgp/test_bgp_rib_in_capacity.py new file mode 100644 index 00000000000..507fc2ed038 --- /dev/null +++ b/tests/snappi/bgp/test_bgp_rib_in_capacity.py @@ -0,0 +1,60 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.bgp_convergence_lag_helper import run_RIB_IN_capacity_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('multipath', [2]) +@pytest.mark.parametrize('start_value', [5000]) +@pytest.mark.parametrize('step_value', [5000]) +@pytest.mark.parametrize('route_type', ['IPv4']) +def test_RIB_IN_capacity(cvg_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + multipath, + start_value, + step_value, + route_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create a BGP config on DUT and TGEN respectively + 2) Create a flow from TGEN1 to TGEN2 port + 3) Send Traffic from TGEN1 to TGEN2 port route range + 4) Check if there is any loss observed + 5) Increment the routes in terms of step_value and repeat test untill loss is observed + 6) Note down the number of routes upto which no loss was observed which is the RIB-IN capacity value + 7) Clean up the BGP config on the dut + Note: + confihgure DUT interfaces prior to running test + Verification: + 1) Send traffic and make sure there is no loss observed + 2) If loss is observed quit the test and note down the maximum routes upto which there was no loss + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + multipath: ECMP value + start_value: Start value of the number of BGP routes + step_value: Step value of the number of BGP routes to be incremented + route_type: IPv4 or IPv6 routes + """ + #multipath, start_value, step_value and route_type parameters can be modified as per user preference + run_RIB_IN_capacity_test(cvg_api, + duthost, + tgen_ports, + multipath, + start_value, + step_value, + route_type,) diff --git a/tests/snappi/bgp/test_bgp_rib_in_convergence.py b/tests/snappi/bgp/test_bgp_rib_in_convergence.py new file mode 100644 index 00000000000..c4b07c3244d --- /dev/null +++ b/tests/snappi/bgp/test_bgp_rib_in_convergence.py @@ -0,0 +1,61 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.bgp_convergence_helper import run_rib_in_convergence_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('multipath', [2]) +@pytest.mark.parametrize('convergence_test_iterations', [1]) +@pytest.mark.parametrize('number_of_routes', [1000]) +@pytest.mark.parametrize('route_type', ['IPv4']) +def test_rib_in_convergence(cvg_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + multipath, + convergence_test_iterations, + number_of_routes, + route_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Create a flow from TGEN1 to (N-1) TGEN ports + 3) Withdraw the routes from all the BGP peers + 4) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range + 4) Advertise the routes when traffic is running + 5) Calculate the RIB-IN convergence time + 6) Clean up the BGP config on the dut + + Verification: + 1) Send traffic after withdrawing routes from all BGP peers + Result: Should not observe any traffic in the receiving side + 2) Advertise the routes when the traffic is running + Result: The traffic must be routed via the ECMP paths + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + multipath: ECMP value + convergence_test_iterations: number of iterations the link failure test has to be run for a port + number_of_routes: Number of IPv4/IPv6 Routes + route_type: IPv4 or IPv6 routes + """ + #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference + run_rib_in_convergence_test(cvg_api, + duthost, + tgen_ports, + convergence_test_iterations, + multipath, + number_of_routes, + route_type,) From 6bbfa44a3b2b555bf022134fcbc6449b572a697f Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 17 Sep 2021 08:27:54 +0000 Subject: [PATCH 28/58] adding Reboot cases to tests/snappi folder --- tests/snappi/reboot/files/__init__.py | 0 tests/snappi/reboot/files/reboot_helper.py | 352 +++++++++++++++++++++ tests/snappi/reboot/test_cold_reboot.py | 48 +++ tests/snappi/reboot/test_fast_reboot.py | 48 +++ tests/snappi/reboot/test_warm_reboot.py | 45 +++ 5 files changed, 493 insertions(+) create mode 100755 tests/snappi/reboot/files/__init__.py create mode 100755 tests/snappi/reboot/files/reboot_helper.py create mode 100644 tests/snappi/reboot/test_cold_reboot.py create mode 100644 tests/snappi/reboot/test_fast_reboot.py create mode 100644 tests/snappi/reboot/test_warm_reboot.py diff --git a/tests/snappi/reboot/files/__init__.py b/tests/snappi/reboot/files/__init__.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/tests/snappi/reboot/files/reboot_helper.py b/tests/snappi/reboot/files/reboot_helper.py new file mode 100755 index 00000000000..01c90700f82 --- /dev/null +++ b/tests/snappi/reboot/files/reboot_helper.py @@ -0,0 +1,352 @@ +from tabulate import tabulate +from tests.common.utilities import (wait, wait_until) +from tests.common.helpers.assertions import pytest_assert +from tests.common.reboot import reboot +import json +import ipaddr +logger = logging.getLogger(__name__) + +TGEN_AS_NUM = 65200 +TIMEOUT = 30 +BGP_TYPE = 'ebgp' +temp_tg_port = dict() + + +def run_reboot_test(cvg_api, + duthost, + localhost, + reboot_type,): + """ + Run Local link failover test + + Args: + cvg_api (pytest fixture): snappi API + duthost (pytest fixture): duthost fixture + localhost (pytest fixture): localhost handle + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + reboot_type : Type of reboot + """ + + """ Create bgp config on dut """ + #duthost_bgp_config(duthost, tgen_ports) + + """ Create bgp config on TGEN """ + tgen_bgp_config = __tgen_bgp_config(cvg_api) + + """ + Run the convergence test by flapping all the rx + links one by one and calculate the convergence valuess + """ + get_convergence_for_reboot_test(duthost, localhost, cvg_api, tgen_bgp_config, reboot_type,) + + #cleanup_config(duthost) + + +def duthost_bgp_config(duthost, tgen_ports): + """ + 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 + """ + global temp_tg_port + duthost.command("sudo config save -y") + duthost.command("sudo cp {} {}".format("/etc/sonic/config_db.json", "/etc/sonic/config_db_backup.json")) + temp_tg_port = tgen_ports + for i in range(1, 4): + intf_config = ( + "sudo config interface ip remove %s %s/%s \n" + "sudo config interface ip remove %s %s/%s \n" + ) + intf_config %= (tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ipv6'], tgen_ports[i]['ipv6_prefix']) + logger.info('Removing configured IP and IPv6 Address from %s' % (tgen_ports[i]['peer_port'])) + duthost.shell(intf_config) + vlan_config=( + 'sudo config vlan add 1000\n' + 'sudo config vlan member add -u 1000 %s\n' + 'sudo config vlan member add -u 1000 %s\n' + 'sudo config interface ip add Vlan1000 192.168.1.1/16\n' + 'sudo config interface ip add Vlan1000 5001::1/64\n' + ) + vlan_config %= (tgen_ports[3]['peer_port'], tgen_ports[2]['peer_port']) + logger.info('Adding %s and %s to Vlan 1000' % (tgen_ports[3]['peer_port'], tgen_ports[2]['peer_port'])) + duthost.shell(vlan_config) + portchannel_config = ( + "sudo config portchannel add PortChannel1 \n" + "sudo config portchannel member add PortChannel1 %s\n" + "sudo config interface ip add PortChannel1 %s/%s\n" + "sudo config interface ip add PortChannel1 %s/%s\n" + ) + portchannel_config %= (tgen_ports[1]['peer_port'], tgen_ports[1]['peer_ip'], tgen_ports[1]['prefix'], tgen_ports[1]['peer_ipv6'], 64) + logger.info('Configuring %s to PortChannel1' % (tgen_ports[1]['peer_port'])) + logger.info('Portchannel1 (IPv4,IPv6) : ({},{})'.format(tgen_ports[1]['peer_ip'], tgen_ports[1]['peer_ipv6'])) + duthost.shell(portchannel_config) + loopback = ( + "sudo config interface ip add Loopback1 1.1.1.1/32\n" + ) + logger.info('Configuring 1.1.1.1/32 on the loopback interface') + duthost.shell(loopback) + logger.info('Configuring BGP in config_db.json') + bgp_neighbors = {tgen_ports[1]['ipv6']: {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[1]['peer_ipv6'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"},tgen_ports[1]['ip']: {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[1]['peer_ip'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"}} + cdf = json.loads(duthost.shell("sonic-cfggen -d --print-data")['stdout']) + for neighbor, neighbor_info in bgp_neighbors.items(): + cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info + + with open("/tmp/sconfig_db.json", 'w') as fp: + json.dump(cdf, fp, indent=4) + duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") + cdf = json.loads(duthost.shell("sonic-cfggen -j /tmp/config_db_temp.json --print-data")['stdout']) + print(cdf) + duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json", "/etc/sonic/config_db.json")) + logger.info('Reloading config to apply BGP config') + duthost.shell("sudo config reload -y \n") + wait(TIMEOUT+60, "For Config to reload \n") + + +def get_flow_stats(cvg_api, name): + """ + Args: + cvg_api (pytest fixture): Snappi API + """ + request = cvg_api.convergence_request() + request.metrics.flow_names = [name] + return cvg_api.get_results(request).flow_metric + + +def get_macs(mac, count, offset=1): + """ + Take mac as start mac returns the count of macs in a list + """ + mac_list = list() + for i in range(count): + mac_address = "{:012X}".format(int(mac, 16) + offset * i) + mac_address = ":".join( + format(s, "02x") for s in bytearray.fromhex(mac_address) + ) + mac_list.append(mac_address) + return mac_list + + +def get_ip_addresses(ip, count,type='ipv4'): + """ + Take ip as start ip returns the count of ips in a list + """ + ip_list = list() + for i in range(count): + if type == 'ipv6': + ipaddress = ipaddr.IPv6Address(ip) + else: + ipaddress = ipaddr.IPv4Address(ip) + ipaddress = ipaddress + i + value = ipaddress._string_from_ip_int(ipaddress._ip) + ip_list.append(value) + return ip_list + + +def __tgen_bgp_config(cvg_api,): + """ + Creating BGP config on TGEN + + Args: + cvg_api (pytest fixture): snappi API + """ + temp_tg_port=[{'ip': '24.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet76', 'prefix': u'24', 'location': '10.36.78.53;4;4', 'ipv6': '2000:4::8', 'ipv6_prefix': u'124', 'port_id': '4', 'peer_ip': u'24.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:4::1'}, {'ip': '23.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet72', 'prefix': u'24', 'location': '10.36.78.53;4;3', 'ipv6': '2000:3::3', 'ipv6_prefix': u'124', 'port_id': '3', 'peer_ip': u'23.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:3::1'}, {'ip': '22.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet68', 'prefix': u'24', 'location': '10.36.78.53;4;2', 'ipv6': '2000:2::f', 'ipv6_prefix': u'124', 'port_id': '2', 'peer_ip': u'22.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:2::1'}, {'ip': '21.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet64', 'prefix': u'24', 'location': '10.36.78.53;4;1', 'ipv6': '2000:1::a', 'ipv6_prefix': u'124', 'port_id': '1', 'peer_ip': u'21.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:1::1'}] + conv_config = cvg_api.convergence_config() + cvg_api.enable_scaling(True) + config = conv_config.config + p1, p2, p3 = ( + config.ports.port(name="t1", location=temp_tg_port[1]['location']) + .port(name="server2", location=temp_tg_port[2]['location']) + .port(name="server1", location=temp_tg_port[3]['location']) + ) + lag3 = config.lags.lag(name="lag1")[-1] + lp3 = lag3.ports.port(port_name=p1.name)[-1] + lp3.protocol.lacp.actor_system_id = "00:11:03:00:00:03" + lp3.ethernet.name = "lag_Ethernet 3" + lp3.ethernet.mac = "00:13:01:00:00:01" + + config.options.port_options.location_preemption = True + layer1 = config.layer1.layer1()[-1] + layer1.name = 'port settings' + layer1.port_names = [port.name for port in config.ports] + layer1.ieee_media_defaults = False + layer1.auto_negotiation.rs_fec = True + layer1.auto_negotiation.link_training = False + layer1.speed = "speed_100_gbps" + layer1.auto_negotiate = False + + conf_values = dict() + num_of_devices = 1000 + conf_values['server_1_ipv4'] = get_ip_addresses("192.168.1.2", 2000)[::2] + conf_values['server_2_ipv4'] = get_ip_addresses("192.168.1.2", 2000)[1::2] + conf_values['server_1_ipv6'] = get_ip_addresses("5000::2", 2000, 'ipv6')[::2] + conf_values['server_2_ipv6'] = get_ip_addresses("5000::2", 2000, 'ipv6')[1::2] + conf_values['server_1_mac'] = get_macs("001700000011", num_of_devices) + conf_values['server_2_mac'] = get_macs("001600000011", num_of_devices) + for i in range(1, num_of_devices+1): + #server1 + d1 = config.devices.device(name='Server_1_{}'.format(i-1))[-1] + d1.container_name = p3.name + eth_1 = d1.ethernet + eth_1.name = 'Ethernet 1_{}'.format(i-1) + eth_1.mac = conf_values['server_1_mac'][i-1] + ipv4_1 = d1.ethernet.ipv4 + ipv4_1.name = 'IPv4 1_{}'.format(i-1) + ipv4_1.address = conf_values['server_1_ipv4'][i-1] + ipv4_1.gateway = '192.168.1.1' + ipv4_1.prefix = 16 + ipv6_1 = d1.ethernet.ipv6 + ipv6_1.name = 'IPv6 1_{}'.format(i-1) + ipv6_1.address = conf_values['server_1_ipv6'][i-1] + ipv6_1.gateway = '5001::1' + ipv6_1.prefix = 64 + #server2 + d2 = config.devices.device(name='Server_2_{}'.format(i-1))[-1] + d2.container_name = p2.name + eth_2 = d2.ethernet + eth_2.name = 'Ethernet 2_{}'.format(i-1) + eth_2.mac = conf_values['server_2_mac'][i-1] + ipv4_2 = d2.ethernet.ipv4 + ipv4_2.name = 'IPv4 2_{}'.format(i-1) + ipv4_2.address = conf_values['server_2_ipv4'][i-1] + ipv4_2.gateway = '192.168.1.1' + ipv4_2.prefix = 16 + ipv6_2 = d2.ethernet.ipv6 + ipv6_2.name = 'IPv6 2_{}'.format(i-1) + ipv6_2.address = conf_values['server_2_ipv6'][i-1] + ipv6_2.gateway = '5001::1' + ipv6_2.prefix = 64 + + #T1 + d3 = config.devices.device(name="T1")[-1] + d3.container_name = lag3.name + eth_3 = d3.ethernet + eth_3.name = 'Ethernet 3' + eth_3.mac = "00:14:01:00:00:01" + ipv4_3 = eth_3.ipv4 + ipv4_3.name = 'IPv4 3' + ipv4_3.address = temp_tg_port[1]['ip'] + ipv4_3.gateway = temp_tg_port[1]['peer_ip'] + ipv4_3.prefix = 24 + ipv6_3 = eth_3.ipv6 + ipv6_3.name = 'IPv6 3' + + ipv6_3.address = temp_tg_port[1]['ipv6'] + ipv6_3.gateway = temp_tg_port[1]['peer_ipv6'] + ipv6_3.prefix = 64 + bgpv4_stack = ipv4_3.bgpv4 + bgpv4_stack.name = 'BGP 3' + bgpv4_stack.as_type = BGP_TYPE + bgpv4_stack.dut_address = temp_tg_port[1]['peer_ip'] + bgpv4_stack.local_address = temp_tg_port[1]['ip'] + bgpv4_stack.as_number = int(TGEN_AS_NUM) + route_range1 = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group 1")[-1] + route_range1.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=1) + bgpv6_stack = ipv6_3.bgpv6 + bgpv6_stack.name = r'BGP+_3' + bgpv6_stack.as_type = BGP_TYPE + bgpv6_stack.dut_address = temp_tg_port[1]['peer_ipv6'] + bgpv6_stack.local_address = temp_tg_port[1]['ipv6'] + bgpv6_stack.as_number = int(TGEN_AS_NUM) + route_range2 = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group 2")[-1] + route_range2.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=1) + + def createTrafficItem(traffic_name, src, dest, rate=50): + flow1 = config.flows.flow(name=str(traffic_name))[-1] + flow1.tx_rx.device.tx_names = src + flow1.tx_rx.device.rx_names = dest + flow1.size.fixed = 1024 + flow1.rate.percentage = rate + flow1.metrics.enable = True + ipv4_1_names = ["IPv4 1_{}".format(i-1) for i in range(1, num_of_devices + 1)] + ipv4_2_names = ["IPv4 2_{}".format(i-1) for i in range(1, num_of_devices + 1)] + ipv6_1_names = ["IPv6 1_{}".format(i-1) for i in range(1, num_of_devices + 1)] + ipv6_2_names = ["IPv6 2_{}".format(i-1) for i in range(1, num_of_devices + 1)] + createTrafficItem("IPv4_1-IPv4_2", ipv4_1_names, ipv4_2_names) + createTrafficItem("IPv6_2-IPv6_1", ipv6_2_names, ipv6_1_names) + createTrafficItem("IPv4_1-T1", ipv4_1_names, [route_range1.name]) + createTrafficItem("IPv6_2-T1", ipv6_2_names, [route_range2.name]) + createTrafficItem("T1-IPv4_1", [route_range1.name], ipv4_1_names) + return conv_config + + +def get_convergence_for_reboot_test(duthost, + localhost, + cvg_api, + bgp_config, + reboot_type): + """ + Args: + duthost (pytest fixture): duthost fixture + localhost (pytest fixture): localhost handle + cvg_api (pytest fixture): snappi API + bgp_config: __tgen_bgp_config + reboot_type: Type of reboot + """ + table, dp = [], [] + bgp_config.rx_rate_threshold = 90 + cvg_api.set_config(bgp_config) + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + flow_names = ["IPv4_1-IPv4_2", "IPv6_2-IPv6_1", "IPv4_1-T1", "IPv6_2-T1", "T1-IPv4_1"] + cs.transmit.flow_names = flow_names + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT-10, "For Traffic To start") + + def check_bgp_state(): + req = cvg_api.convergence_request() + req.bgpv4.peer_names = [] + bgpv4_metrics = cvg_api.get_results(req).bgpv4_metrics + assert bgpv4_metrics[-1].session_state == "up", "BGP v4 Session State is not UP" + logger.info("BGP v4 Session State is UP") + req.bgpv6.peer_names = [] + bgpv6_metrics = cvg_api.get_results(req).bgpv6_metrics + assert bgpv6_metrics[-1].session_state == "up", "BGP v6 Session State is not UP" + logger.info("BGP v6 Session State is UP") + + check_bgp_state() + req = cvg_api.ping_request() + p1 = req.endpoints.ipv4()[-1] + p1.src_name = 'IPv4 3' + p1.dst_ip = "1.1.1.1" + logger.info("Issuing a {} reboot on the dut {}".format(reboot_type, duthost.hostname)) + reboot(duthost, localhost, reboot_type=reboot_type) + logger.info("Wait until the system is stable") + pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") + check_bgp_state() + responses = cvg_api.send_ping(req).responses + assert responses[-1].result == "success" + logger.info('Ping from IPv4 3 --> {} : {} after {} seconds after {}'.format(p1.dst_ip, responses[-1].result, 180, reboot_type)) + request = cvg_api.convergence_request() + for i in cs.transmit.flow_names: + request.metrics.flow_names = [i] + flow = cvg_api.get_results(request).flow_metric + assert int(flow[0].frames_tx_rate) != 0, "No Frames sent for traffic item: {}".format(i) + assert flow[0].frames_tx_rate == flow[0].frames_tx_rate, "Loss observed for Traffic Item: {}".format(i) + logger.info("No Loss Observed in Traffic Item {}".format(i)) + + request.convergence.flow_names = flow_names + convergence_metrics = cvg_api.get_results(request).flow_convergence + for metrics in convergence_metrics: + dp.append(metrics.data_plane_convergence_us/1000) + logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, metrics.data_plane_convergence_us/1000)) + + for j, i in enumerate(flow_names): + table.append([reboot_type, i, dp[j]]) + columns = ['Reboot Type', 'Traffic Item Name', 'Data Plane Convergence Time (ms)'] + logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) + +def cleanup_config(duthost): + """ + Cleaning up dut config at the end of the test + + Args: + duthost (pytest fixture): duthost fixture + """ + logger.info('Cleaning up config') + duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json", "/etc/sonic/config_db.json")) + duthost.shell("sudo config reload -y \n") + wait(TIMEOUT+30, "For Cleanup to complete \n") + logger.info('Convergence Test Completed') diff --git a/tests/snappi/reboot/test_cold_reboot.py b/tests/snappi/reboot/test_cold_reboot.py new file mode 100644 index 00000000000..af07e45e549 --- /dev/null +++ b/tests/snappi/reboot/test_cold_reboot.py @@ -0,0 +1,48 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.reboot_helper import run_reboot_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('reboot_type', ['cold']) +def test_reboot(cvg_api, + duthost, + localhost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + reboot_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create 2 servers and a T1 device with dual stack BGP + 2) Configure LAG for the T1 Device + 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 + 4) Make sure there is no loss observed while sending trafic + 5) Reboot the dut with cold-reboot command + 6) Make sure after reboot the traffic has converged + + Verification: + 1) Make sure the control plane is up after the reboot is complete and the dut is back up + 2) Traffic must have converged after the dut is back up + + Args: + cvg_api (pytest fixture): Snappi Convergence API + duthost (pytest fixture): duthost fixture + localhost (pytest fixture): localhost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + reboot_type (parameter): Reboot command + """ + run_reboot_test(cvg_api, + duthost, + localhost, + tgen_ports, + reboot_type,) diff --git a/tests/snappi/reboot/test_fast_reboot.py b/tests/snappi/reboot/test_fast_reboot.py new file mode 100644 index 00000000000..37e9087ae37 --- /dev/null +++ b/tests/snappi/reboot/test_fast_reboot.py @@ -0,0 +1,48 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.reboot_helper import run_reboot_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('reboot_type', ['fast']) +def test_reboot(cvg_api, + duthost, + localhost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + reboot_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create 2 servers and a T1 device with dual stack BGP + 2) Configure LAG for the T1 Device + 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 + 4) Make sure there is no loss observed while sending trafic + 5) Reboot the dut with fast-reboot command + 6) Make sure after reboot the traffic has converged + + Verification: + 1) Make sure the control plane is up after the reboot is complete and the dut is back up + 2) Traffic must have converged after the dut is back up + + Args: + cvg_api (pytest fixture): Snappi Convergence API + duthost (pytest fixture): duthost fixture + localhost (pytest fixture): localhost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + reboot_type (parameter): Reboot command + """ + run_reboot_test(cvg_api, + duthost, + localhost, + tgen_ports, + reboot_type,) diff --git a/tests/snappi/reboot/test_warm_reboot.py b/tests/snappi/reboot/test_warm_reboot.py new file mode 100644 index 00000000000..d8703c173b1 --- /dev/null +++ b/tests/snappi/reboot/test_warm_reboot.py @@ -0,0 +1,45 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.reboot_helper import run_reboot_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('reboot_type', ['warm']) +def test_reboot(cvg_api, + duthost, + localhost, + conn_graph_facts, + fanout_graph_facts, + reboot_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create 2 servers and a T1 device with dual stack BGP + 2) Configure LAG for the T1 Device + 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 + 4) Make sure there is no loss observed while sending trafic + 5) Reboot the dut with warm-reboot command + 6) Make sure after reboot the traffic has converged + + Verification: + 1) Make sure the control plane is up after the reboot is complete and the dut is back up + 2) Traffic must have converged after the dut is back up + + Args: + cvg_api (pytest fixture): Snappi Convergence API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + reboot_type (parameter): Reboot command + """ + run_reboot_test(cvg_api, + duthost, + localhost, + reboot_type,) From e29f3b4f94ec8938e15b1a11ac3dbb3d225b1350 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 17 Sep 2021 08:32:57 +0000 Subject: [PATCH 29/58] removing BGP files from test/ixia --- tests/ixia/bgp/files/__init__.py | 0 .../ixia/bgp/files/bgp_convergence_helper.py | 787 ------------------ .../ixia/bgp/test_bgp_local_link_failover.py | 60 -- .../ixia/bgp/test_bgp_remote_link_failover.py | 59 -- tests/ixia/bgp/test_bgp_rib_in_capacity.py | 60 -- tests/ixia/bgp/test_bgp_rib_in_convergence.py | 61 -- 6 files changed, 1027 deletions(-) delete mode 100644 tests/ixia/bgp/files/__init__.py delete mode 100644 tests/ixia/bgp/files/bgp_convergence_helper.py delete mode 100644 tests/ixia/bgp/test_bgp_local_link_failover.py delete mode 100755 tests/ixia/bgp/test_bgp_remote_link_failover.py delete mode 100644 tests/ixia/bgp/test_bgp_rib_in_capacity.py delete mode 100644 tests/ixia/bgp/test_bgp_rib_in_convergence.py diff --git a/tests/ixia/bgp/files/__init__.py b/tests/ixia/bgp/files/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/ixia/bgp/files/bgp_convergence_helper.py b/tests/ixia/bgp/files/bgp_convergence_helper.py deleted file mode 100644 index 82dc09bf594..00000000000 --- a/tests/ixia/bgp/files/bgp_convergence_helper.py +++ /dev/null @@ -1,787 +0,0 @@ -from tabulate import tabulate -from statistics import mean -from tests.common.utilities import wait -import json -logger = logging.getLogger(__name__) - -TGEN_AS_NUM = 65200 -TIMEOUT = 40 -BGP_TYPE = 'ebgp' -temp_tg_port=dict() - -def run_bgp_local_link_failover_test(cvg_api, - duthost, - tgen_ports, - iteration, - multipath, - number_of_routes, - route_type,): - """ - Run Local link failover test - - Args: - cvg_api (pytest fixture): snappi API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of T0 testbed - iteration: number of iterations for running convergence test on a port - multipath: ecmp value for BGP config - number_of_routes: Number of IPv4/IPv6 Routes - route_type: IPv4 or IPv6 routes - """ - port_count = multipath+1 - - """ Create bgp config on dut """ - duthost_bgp_config(duthost, - tgen_ports, - port_count,) - - """ Create bgp config on TGEN """ - tgen_bgp_config = __tgen_bgp_config(cvg_api, - port_count, - number_of_routes, - route_type,) - - """ - Run the convergence test by flapping all the rx - links one by one and calculate the convergence values - """ - get_convergence_for_local_link_failover(cvg_api, - tgen_bgp_config, - iteration, - multipath, - number_of_routes, - route_type,) - - """ Cleanup the dut configs after getting the convergence numbers """ - cleanup_config(duthost) - - -def run_bgp_remote_link_failover_test(cvg_api, - duthost, - tgen_ports, - iteration, - multipath, - number_of_routes, - route_type,): - """ - Run Remote link failover test - - Args: - cvg_api (pytest fixture): snappi API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of T0 testbed - iteration: number of iterations for running convergence test on a port - multipath: ecmp value for BGP config - route_type: IPv4 or IPv6 routes - """ - port_count = multipath+1 - """ Create bgp config on dut """ - duthost_bgp_config(duthost, - tgen_ports, - port_count,) - - """ Create bgp config on TGEN """ - tgen_bgp_config = __tgen_bgp_config(cvg_api, - port_count, - number_of_routes, - route_type,) - - """ - Run the convergence test by withdrawing all the route ranges - one by one and calculate the convergence values - """ - get_convergence_for_remote_link_failover(cvg_api, - tgen_bgp_config, - iteration, - multipath, - number_of_routes, - route_type,) - - """ Cleanup the dut configs after getting the convergence numbers """ - cleanup_config(duthost) - - - -def run_rib_in_convergence_test(cvg_api, - duthost, - tgen_ports, - iteration, - multipath, - number_of_routes, - route_type,): - """ - Run RIB-IN Convergence test - - Args: - cvg_api (pytest fixture): snappi API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of T0 testbed - iteration: number of iterations for running convergence test on a port - multipath: ecmp value for BGP config - number_of_routes: Number of IPv4/IPv6 Routes - route_type: IPv4 or IPv6 routes - """ - port_count = multipath+1 - - """ Create bgp config on dut """ - duthost_bgp_config(duthost, - tgen_ports, - port_count,) - - """ Create bgp config on TGEN """ - tgen_bgp_config = __tgen_bgp_config(cvg_api, - port_count, - number_of_routes, - route_type,) - - """ - Run the convergence test by withdrawing all routes at once and - calculate the convergence values - """ - get_rib_in_convergence(cvg_api, - tgen_bgp_config, - iteration, - multipath, - number_of_routes, - route_type,) - - """ Cleanup the dut configs after getting the convergence numbers """ - cleanup_config(duthost) - - -def run_RIB_IN_capacity_test(cvg_api, - duthost, - tgen_ports, - multipath, - start_value, - step_value, - route_type,): - - """ - Run RIB-IN Capacity test - - Args: - cvg_api (pytest fixture): snappi API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of T0 testbed - multipath: ecmp value for BGP config - start_value: - step_value: - route_type: IPv4 or IPv6 routes - """ - port_count = multipath+1 - """ Create bgp config on dut """ - duthost_bgp_config(duthost, - tgen_ports, - port_count,) - - - """ Run the RIB-IN capacity test by increasig the route count step by step """ - get_RIB_IN_capacity(cvg_api, - multipath, - start_value, - step_value, - route_type,) - - """ Cleanup the dut configs after getting the convergence numbers """ - cleanup_config(duthost) - - -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:multipath + 1 - multipath: ECMP value for BGP config - """ - duthost.command("sudo config save -y") - duthost.command("sudo cp {} {}".format("/etc/sonic/config_db.json", "/etc/sonic/config_db_backup.json")) - global temp_tg_port - temp_tg_port = tgen_ports - for i in range(0, port_count): - intf_config = ( - "sudo config interface ip remove %s %s/%s \n" - "sudo config interface ip remove %s %s/%s \n" - ) - intf_config %= (tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ipv6'], tgen_ports[i]['ipv6_prefix']) - logger.info('Removing configured IP and IPv6 Address from %s' % (tgen_ports[i]['peer_port'])) - duthost.shell(intf_config) - - for i in range(0, port_count): - portchannel_config = ( - "sudo config portchannel add PortChannel%s \n" - "sudo config portchannel member add PortChannel%s %s\n" - "sudo config interface ip add PortChannel%s %s/%s\n" - "sudo config interface ip add PortChannel%s %s/%s\n" - ) - portchannel_config %= (i+1, i+1, tgen_ports[i]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], i+1, tgen_ports[i]['peer_ipv6'], 64) - logger.info('Configuring %s to PortChannel%s with IPs %s,%s' % (tgen_ports[1]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['peer_ipv6'])) - duthost.shell(portchannel_config) - logger.info('Configuring BGP in config_db.json') - bgp_neighbors = dict() - for i in range(1, port_count): - bgp_neighbors[tgen_ports[i]['ipv6']] = {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[i]['peer_ipv6'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"} - bgp_neighbors[tgen_ports[i]['ip']] = {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[i]['peer_ip'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"} - - cdf = json.loads(duthost.shell("sonic-cfggen -d --print-data")['stdout']) - for neighbor, neighbor_info in bgp_neighbors.items(): - cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info - - with open("/tmp/sconfig_db.json", 'w') as fp: - json.dump(cdf, fp, indent=4) - duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") - cdf = json.loads(duthost.shell("sonic-cfggen -j /tmp/config_db_temp.json --print-data")['stdout']) - logger.info(cdf) - duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json","/etc/sonic/config_db.json")) - logger.info('Reloading config to apply BGP config') - duthost.shell("sudo config reload -y \n") - wait(TIMEOUT+60,"For Config to reload \n") - - -def __tgen_bgp_config(cvg_api, - port_count, - number_of_routes, - route_type,): - """ - Creating BGP config on TGEN - - Args: - cvg_api (pytest fixture): snappi API - port_count: multipath + 1 - number_of_routes: Number of IPv4/IPv6 Routes - route_type: IPv4 or IPv6 routes - """ - conv_config = cvg_api.convergence_config() - config = conv_config.config - for i in range(1, port_count+1): - config.ports.port(name='Test_Port_%d' % i, location=temp_tg_port[i-1]['location']) - c_lag = config.lags.lag(name="lag%d" % i)[-1] - lp = c_lag.ports.port(port_name='Test_Port_%d' % i)[-1] - lp.ethernet.name = 'lag_eth_%d' % i - if len(str(hex(i).split('0x')[1])) == 1: - m = '0'+hex(i).split('0x')[1] - else: - m = hex(i).split('0x')[1] - lp.protocol.lacp.actor_system_id = "00:10:00:00:00:%s" % m - lp.ethernet.name = "lag_Ethernet %s" % i - lp.ethernet.mac = "00:10:01:00:00:%s" % m - config.devices.device(name='Topology %d' % i) - config.devices[i-1].container_name = c_lag.name - - config.options.port_options.location_preemption = True - layer1 = config.layer1.layer1()[-1] - layer1.name = 'port settings' - layer1.port_names = [port.name for port in config.ports] - layer1.ieee_media_defaults = False - layer1.auto_negotiation.rs_fec = True - layer1.auto_negotiation.link_training = False - layer1.speed = "speed_100_gbps" - layer1.auto_negotiate = False - - def create_v4_topo(): - config.devices[0].ethernet.name = 'Ethernet 1' - config.devices[0].ethernet.mac = "00:00:00:00:00:01" - config.devices[0].ethernet.ipv4.name = 'IPv4 1' - config.devices[0].ethernet.ipv4.address = temp_tg_port[0]['ip'] - config.devices[0].ethernet.ipv4.gateway = temp_tg_port[0]['peer_ip'] - config.devices[0].ethernet.ipv4.prefix = int(temp_tg_port[0]['prefix']) - rx_flow_name = [] - for i in range(2, port_count+1): - if len(str(hex(i).split('0x')[1])) == 1: - m = '0'+hex(i).split('0x')[1] - else: - m = hex(i).split('0x')[1] - ethernet_stack = config.devices[i-1].ethernet - ethernet_stack.name = 'Ethernet %d' % i - ethernet_stack.mac = "00:00:00:00:00:%s" % m - ipv4_stack = ethernet_stack.ipv4 - ipv4_stack.name = 'IPv4 %d' % i - ipv4_stack.address = temp_tg_port[i-1]['ip'] - ipv4_stack.gateway = temp_tg_port[i-1]['peer_ip'] - ipv4_stack.prefix = int(temp_tg_port[i-1]['prefix']) - bgpv4_stack = ipv4_stack.bgpv4 - bgpv4_stack.name = 'BGP %d' % i - bgpv4_stack.as_type = BGP_TYPE - bgpv4_stack.dut_address = temp_tg_port[i-1]['peer_ip'] - bgpv4_stack.local_address = temp_tg_port[i-1]['ip'] - bgpv4_stack.as_number = int(TGEN_AS_NUM) - route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group %d" % i)[-1] - route_range.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=number_of_routes) - rx_flow_name.append(route_range.name) - return rx_flow_name - - def create_v6_topo(): - config.devices[0].ethernet.name = 'Ethernet 1' - config.devices[0].ethernet.mac = "00:00:00:00:00:01" - config.devices[0].ethernet.ipv6.name = 'IPv6 1' - config.devices[0].ethernet.ipv6.address = temp_tg_port[0]['ipv6'] - config.devices[0].ethernet.ipv6.gateway = temp_tg_port[0]['peer_ipv6'] - config.devices[0].ethernet.ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix']) - rx_flow_name = [] - for i in range(2, port_count+1): - if len(str(hex(i).split('0x')[1])) == 1: - m = '0'+hex(i).split('0x')[1] - else: - m = hex(i).split('0x')[1] - ethernet_stack = config.devices[i-1].ethernet - ethernet_stack.name = 'Ethernet %d' % i - ethernet_stack.mac = "00:00:00:00:00:%s" % m - ipv6_stack = ethernet_stack.ipv6 - ipv6_stack.name = 'IPv6 %d' % i - ipv6_stack.address = temp_tg_port[i-1]['ipv6'] - ipv6_stack.gateway = temp_tg_port[i-1]['peer_ipv6'] - ipv6_stack.prefix = int(temp_tg_port[i-1]['ipv6_prefix']) - bgpv6_stack = ipv6_stack.bgpv6 - bgpv6_stack.name = r'BGP+ %d' % i - bgpv6_stack.as_type = BGP_TYPE - bgpv6_stack.dut_address = temp_tg_port[i-1]['peer_ipv6'] - bgpv6_stack.local_address = temp_tg_port[i-1]['ipv6'] - bgpv6_stack.as_number = int(TGEN_AS_NUM) - route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group %d" % i)[-1] - route_range.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=number_of_routes) - rx_flow_name.append(route_range.name) - return rx_flow_name - - if route_type == 'IPv4': - rx_flows = create_v4_topo() - flow = config.flows.flow(name='IPv4 Traffic')[-1] - elif route_type == 'IPv6': - rx_flows = create_v6_topo() - flow = config.flows.flow(name='IPv6 Traffic')[-1] - else: - raise Exception('Invalid route type given') - flow.tx_rx.device.tx_names = [config.devices[0].name] - flow.tx_rx.device.rx_names = rx_flows - flow.size.fixed = 1024 - flow.rate.percentage = 100 - flow.metrics.enable = True - return conv_config - - -def get_flow_stats(cvg_api): - """ - Args: - cvg_api (pytest fixture): Snappi API - """ - request = cvg_api.convergence_request() - request.metrics.flow_names = [] - return cvg_api.get_results(request).flow_metric - - -def get_convergence_for_local_link_failover(cvg_api, - bgp_config, - iteration, - multipath, - number_of_routes, - route_type,): - """ - Args: - cvg_api (pytest fixture): snappi API - bgp_config: __tgen_bgp_config - config: TGEN config - iteration: number of iterations for running convergence test on a port - number_of_routes: Number of IPv4/IPv6 Routes - route_type: IPv4 or IPv6 routes - """ - rx_port_names = [] - for i in range(1, len(bgp_config.config.ports)): - rx_port_names.append(bgp_config.config.ports[i].name) - bgp_config.rx_rate_threshold = 90/(multipath-1) - cvg_api.set_config(bgp_config) - def get_avg_dpdp_convergence_time(port_name): - """ - Args: - port_name: Name of the port - """ - - table, avg, tx_frate, rx_frate = [], [], [], [] - for i in range(0, iteration): - logger.info('|---- {} Link Flap Iteration : {} ----|'.format(port_name, i+1)) - - """ Starting Traffic """ - logger.info('Starting Traffic') - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.START - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To start") - flow_stats = get_flow_stats(cvg_api) - tx_frame_rate = flow_stats[0].frames_tx_rate - assert tx_frame_rate != 0, "Traffic has not started" - - """ Flapping Link """ - logger.info('Simulating Link Failure on {} link'.format(port_name)) - cs = cvg_api.convergence_state() - cs.link.port_names = [port_name] - cs.link.state = cs.link.DOWN - cvg_api.set_state(cs) - wait(TIMEOUT, "For Link to go down") - flows = get_flow_stats(cvg_api) - for flow in flows: - tx_frate.append(flow.frames_tx_rate) - rx_frate.append(flow.frames_tx_rate) - assert sum(tx_frate) == sum(rx_frate), "Traffic has not converged after link flap: TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate)) - logger.info("Traffic has converged after link flap") - """ Get control plane to data plane convergence value """ - request = cvg_api.convergence_request() - request.convergence.flow_names = [] - convergence_metrics = cvg_api.get_results(request).flow_convergence - for metrics in convergence_metrics: - logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) - avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) - - """ Performing link up at the end of iteration """ - logger.info('Simulating Link Up on {} at the end of iteration {}'.format(port_name, i+1)) - cs = cvg_api.convergence_state() - cs.link.port_names = [port_name] - cs.link.state = cs.link.UP - cvg_api.set_state(cs) - table.append('%s Link Failure' % port_name) - table.append(route_type) - table.append(number_of_routes) - table.append(iteration) - table.append(mean(avg)) - return table - table = [] - """ Iterating link flap test on all the rx ports """ - for i, port_name in enumerate(rx_port_names): - table.append(get_avg_dpdp_convergence_time(port_name)) - columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Calculated Data Convergence Time (ms)'] - logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) - - -def get_convergence_for_remote_link_failover(cvg_api, - bgp_config, - iteration, - multipath, - number_of_routes, - route_type,): - """ - Args: - cvg_api (pytest fixture): snappi API - bgp_config: __tgen_bgp_config - config: TGEN config - iteration: number of iterations for running convergence test on a port - number_of_routes: Number of IPv4/IPv6 Routes - route_type: IPv4 or IPv6 routes - """ - route_names = [] - for device in bgp_config.config.devices: - if device.name not in ['Topology 1']: - if route_type == 'IPv4': - for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: - route_names.append(route.name) - else: - for route in device.ethernet.ipv6.bgpv6.bgpv6_routes: - route_names.append(route.name) - bgp_config.rx_rate_threshold = 90/(multipath-1) - cvg_api.set_config(bgp_config) - - - def get_avg_cpdp_convergence_time(route_name): - """ - Args: - route_name: name of the route - - """ - table, avg, tx_frate, rx_frate = [], [], [], [] - for i in range(0, iteration): - logger.info('|---- {} Route Withdraw Iteration : {} ----|'.format(route_name, i+1)) - - """ Starting Traffic """ - logger.info('Starting Traffic') - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.START - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To start") - flow_stats = get_flow_stats(cvg_api) - tx_frame_rate = flow_stats[0].frames_tx_rate - assert tx_frame_rate != 0, "Traffic has not started" - - """ Withdrawing routes from a BGP peer """ - logger.info('Withdrawing Routes from {}'.format(route_name)) - cs = cvg_api.convergence_state() - cs.route.names = [route_name] - cs.route.state = cs.route.WITHDRAW - cvg_api.set_state(cs) - wait(TIMEOUT, "For routes to be withdrawn") - flows = get_flow_stats(cvg_api) - for flow in flows: - tx_frate.append(flow.frames_tx_rate) - rx_frate.append(flow.frames_tx_rate) - assert sum(tx_frate) == sum(rx_frate), "Traffic has not converged after lroute withdraw TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate)) - logger.info("Traffic has converged after route withdraw") - - """ Get control plane to data plane convergence value """ - request = cvg_api.convergence_request() - request.convergence.flow_names = [] - convergence_metrics = cvg_api.get_results(request).flow_convergence - for metrics in convergence_metrics: - logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) - avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) - - """ Advertise the routes back at the end of iteration """ - cs = cvg_api.convergence_state() - cs.route.names = [route_name] - cs.route.state = cs.route.ADVERTISE - cvg_api.set_state(cs) - logger.info('Readvertise {} routes back at the end of iteration {}'.format(route_name, i+1)) - - table.append('%s route withdraw' % route_name) - table.append(route_type) - table.append(number_of_routes) - table.append(iteration) - table.append(mean(avg)) - return table - table = [] - """ Iterating route withdrawal on all BGP peers """ - for route in route_names: - table.append(get_avg_cpdp_convergence_time(route)) - - columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Control to Data Plane Convergence Time (ms)'] - logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) - - -def get_rib_in_convergence(cvg_api, - bgp_config, - iteration, - multipath, - number_of_routes, - route_type,): - """ - Args: - cvg_api (pytest fixture): snappi API - bgp_config: __tgen_bgp_config - config: TGEN config - iteration: number of iterations for running convergence test on a port - number_of_routes: Number of IPv4/IPv6 Routes - route_type: IPv4 or IPv6 routes - """ - route_names = [] - for device in bgp_config.config.devices: - if device.name not in ['Topology 1']: - if route_type == 'IPv4': - for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: - route_names.append(route.name) - else: - for route in device.ethernet.ipv6.bgpv6.bgpv6_routes: - route_names.append(route.name) - bgp_config.rx_rate_threshold = 90/(multipath) - cvg_api.set_config(bgp_config) - - table, avg, tx_frate, rx_frate = [], [], [], [] - for i in range(0, iteration): - logger.info('|---- RIB-IN Convergence test, Iteration : {} ----|'.format(i+1)) - """ withdraw all routes before starting traffic """ - logger.info('Withdraw All Routes before starting traffic') - cs = cvg_api.convergence_state() - cs.route.names = route_names - cs.route.state = cs.route.WITHDRAW - cvg_api.set_state(cs) - wait(TIMEOUT, "For Routes to be withdrawn") - - """ Start Traffic """ - logger.info('Starting Traffic') - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.START - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To start") - flow_stats = get_flow_stats(cvg_api) - tx_frame_rate = flow_stats[0].frames_tx_rate - rx_frame_rate = flow_stats[0].frames_rx_rate - assert tx_frame_rate != 0, "Traffic has not started" - assert rx_frame_rate == 0 - - """ Advertise All Routes """ - logger.info('Advertising all Routes from {}'.format(route_names)) - cs = cvg_api.convergence_state() - cs.route.names = route_names - cs.route.state = cs.route.ADVERTISE - cvg_api.set_state(cs) - wait(TIMEOUT, "For all routes to be ADVERTISED") - flows = get_flow_stats(cvg_api) - for flow in flows: - tx_frate.append(flow.frames_tx_rate) - rx_frate.append(flow.frames_tx_rate) - assert sum(tx_frate) == sum(rx_frate), "Traffic has not convergedv, TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate)) - logger.info("Traffic has converged after route advertisement") - - """ Get RIB-IN convergence """ - request = cvg_api.convergence_request() - request.convergence.flow_names = [] - convergence_metrics = cvg_api.get_results(request).flow_convergence - for metrics in convergence_metrics: - logger.info('RIB-IN Convergence time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) - avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) - - """ Stop traffic at the end of iteration """ - logger.info('Stopping Traffic at the end of iteration{}'.format(i+1)) - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.STOP - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To stop") - table.append('Advertise All BGP Routes') - table.append(route_type) - table.append(number_of_routes) - table.append(iteration) - table.append(mean(avg)) - columns = ['Event Name', 'Route Type', 'No. of Routes','Iterations', 'Avg RIB-IN Convergence Time(ms)'] - logger.info("\n%s" % tabulate([table], headers=columns, tablefmt="psql")) - - -def get_RIB_IN_capacity(cvg_api, - multipath, - start_value, - step_value, - route_type,): - """ - Args: - cvg_api (pytest fixture): snappi API - temp_tg_port (pytest fixture): Ports mapping info of T0 testbed - multipath: ecmp value for BGP config - start_value: Start value of the number of BGP routes - step_value: Step value of the number of BGP routes to be incremented - route_type: IPv4 or IPv6 routes - - """ - def tgen_capacity(routes): - conv_config = cvg_api.convergence_config() - config = conv_config.config - for i in range(1, 3): - config.ports.port(name='Test_Port_%d' % i, location=temp_tg_port[i-1]['location']) - config.devices.device(name='Topology %d' % i) - config.devices[i-1].container_name = config.ports[i-1].name - - config.options.port_options.location_preemption = True - layer1 = config.layer1.layer1()[-1] - layer1.name = 'port settings' - layer1.port_names = [port.name for port in config.ports] - layer1.ieee_media_defaults = False - layer1.auto_negotiation.rs_fec = True - layer1.auto_negotiation.link_training = False - layer1.speed = "speed_100_gbps" - layer1.auto_negotiate = False - - def create_v4_topo(): - config.devices[0].ethernet.name = 'Ethernet 1_%d' % routes - config.devices[0].ethernet.mac = "00:00:00:00:00:01" - config.devices[0].ethernet.ipv4.name = 'IPv4 1_%d' % routes - config.devices[0].ethernet.ipv4.address = temp_tg_port[0]['ip'] - config.devices[0].ethernet.ipv4.gateway = temp_tg_port[0]['peer_ip'] - config.devices[0].ethernet.ipv4.prefix = int(temp_tg_port[0]['prefix']) - rx_flow_name = [] - for i in range(2, 3): - if len(str(hex(i).split('0x')[1])) == 1: - m = '0'+hex(i).split('0x')[1] - else: - m = hex(i).split('0x')[1] - ethernet_stack = config.devices[i-1].ethernet - ethernet_stack.name = 'Ethernet_%d_%d' % (i, routes) - ethernet_stack.mac = "00:00:00:00:00:%s" % m - ipv4_stack = ethernet_stack.ipv4 - ipv4_stack.name = 'IPv4_%d_%d' % (i, routes) - ipv4_stack.address = temp_tg_port[i-1]['ip'] - ipv4_stack.gateway = temp_tg_port[i-1]['peer_ip'] - ipv4_stack.prefix = int(temp_tg_port[i-1]['prefix']) - bgpv4_stack = ipv4_stack.bgpv4 - bgpv4_stack.name = 'BGP_%d_%d' % (i, routes) - bgpv4_stack.as_type = BGP_TYPE - bgpv4_stack.dut_address = temp_tg_port[i-1]['peer_ip'] - bgpv4_stack.local_address = temp_tg_port[i-1]['ip'] - bgpv4_stack.as_number = int(TGEN_AS_NUM) - route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group %d_%d" % (i, routes))[-1] - route_range.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=routes) - rx_flow_name.append(route_range.name) - return rx_flow_name - - def create_v6_topo(): - config.devices[0].ethernet.name = 'Ethernet 1' - config.devices[0].ethernet.mac = "00:00:00:00:00:01" - config.devices[0].ethernet.ipv6.name = 'IPv6 1' - config.devices[0].ethernet.ipv6.address = temp_tg_port[0]['ipv6'] - config.devices[0].ethernet.ipv6.gateway = temp_tg_port[0]['peer_ipv6'] - config.devices[0].ethernet.ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix']) - rx_flow_name = [] - for i in range(2, 3): - if len(str(hex(i).split('0x')[1])) == 1: - m = '0'+hex(i).split('0x')[1] - else: - m = hex(i).split('0x')[1] - ethernet_stack = config.devices[i-1].ethernet - ethernet_stack.name = 'Ethernet %d' % i - ethernet_stack.mac = "00:00:00:00:00:%s" % m - ipv6_stack = ethernet_stack.ipv6 - ipv6_stack.name = 'IPv6 %d' % i - ipv6_stack.address = temp_tg_port[i-1]['ipv6'] - ipv6_stack.gateway = temp_tg_port[i-1]['peer_ipv6'] - ipv6_stack.prefix = int(temp_tg_port[i-1]['ipv6_prefix']) - bgpv6_stack = ipv6_stack.bgpv6 - bgpv6_stack.name = r'BGP+ %d' % i - bgpv6_stack.as_type = BGP_TYPE - bgpv6_stack.dut_address = temp_tg_port[i-1]['peer_ipv6'] - bgpv6_stack.local_address = temp_tg_port[i-1]['ipv6'] - bgpv6_stack.as_number = int(TGEN_AS_NUM) - route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group %d_%d" % (routes, i))[-1] - route_range.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=routes) - rx_flow_name.append(route_range.name) - return rx_flow_name - conv_config.rx_rate_threshold = 90/(multipath) - if route_type == 'IPv4': - rx_flows = create_v4_topo() - flow = config.flows.flow(name='IPv4_Traffic_%d' % routes)[-1] - elif route_type == 'IPv6': - rx_flows = create_v6_topo() - flow = config.flows.flow(name='IPv6_Traffic_%d' % routes)[-1] - else: - raise Exception('Invalid route type given') - flow.tx_rx.device.tx_names = [config.devices[0].name] - flow.tx_rx.device.rx_names = rx_flows - flow.size.fixed = 1024 - flow.rate.percentage = 100 - flow.metrics.enable = True - flow.metrics.loss = True - return conv_config - - for j in range(start_value, 100000000000, step_value): - logger.info('|-------------------- RIB-IN Capacity test, No.of Routes : {} ----|'.format(j)) - conv_config = tgen_capacity(j) - cvg_api.set_config(conv_config) - - """ Starting Traffic """ - logger.info('Starting Traffic') - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.START - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To start") - flow_stats = get_flow_stats(cvg_api) - logger.info('Loss% : {}'.format(flow_stats[0].loss)) - logger.info('Stopping Traffic') - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.STOP - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To stop") - if float(flow_stats[0].loss)>0.1: - if start_value == j: - max_routes = 'N/A' - raise Exception('FAIL:Max Routes: {}, Loss observed in start value itself, set the start value less than : {} !!!!!!!!!!!!'.format(max_routes,start_value)) - else: - max_routes = j-step_value - logger.info('max_routes :{}'.format(max_routes)) - break - logger.info('|------------ Max Routes without loss (RIB-IN Capacity Value) : {} ----|'.format(max_routes)) - -def cleanup_config(duthost): - """ - Cleaning up dut config at the end of the test - - Args: - duthost (pytest fixture): duthost fixture - """ - duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json","/etc/sonic/config_db.json")) - duthost.shell("sudo config reload -y \n") - wait(TIMEOUT+60,"For Cleanup to complete \n") - logger.info('Convergence Test Completed') diff --git a/tests/ixia/bgp/test_bgp_local_link_failover.py b/tests/ixia/bgp/test_bgp_local_link_failover.py deleted file mode 100644 index 0597555e415..00000000000 --- a/tests/ixia/bgp/test_bgp_local_link_failover.py +++ /dev/null @@ -1,60 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.bgp_convergence_helper import run_bgp_local_link_failover_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - - -@pytest.mark.parametrize('multipath', [3]) -@pytest.mark.parametrize('convergence_test_iterations', [1]) -@pytest.mark.parametrize('number_of_routes', [4000]) -@pytest.mark.parametrize('route_type', ['IPv4']) -def test_bgp_convergence_for_local_link_failover(cvg_api, - duthost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - multipath, - convergence_test_iterations, - number_of_routes, - route_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create BGP config on DUT and TGEN respectively - 2) Create a flow from TGEN1 to (N-1) TGEN ports - 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range - 4) Simulate link failure by bringing down one of the (N-1) TGEN Ports - 5) Calculate the packet loss duration for convergence time - 6) Clean up the BGP config on the dut - - Verification: - 1) Send traffic without flapping any link - Result: Should not observe traffic loss - 2) Flap one of the N TGEN link - Result: The traffic must be routed via rest of the ECMP paths - - Args: - cvg_api (pytest fixture): Snappi Convergence API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - multipath: ECMP value - convergence_test_iterations: number of iterations the link failure test has to be run for a port - number_of_routes: Number of IPv4/IPv6 Routes - route_type: IPv4 or IPv6 routes - """ - #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference - run_bgp_local_link_failover_test(cvg_api, - duthost, - tgen_ports, - convergence_test_iterations, - multipath, - number_of_routes, - route_type,) diff --git a/tests/ixia/bgp/test_bgp_remote_link_failover.py b/tests/ixia/bgp/test_bgp_remote_link_failover.py deleted file mode 100755 index e1357f55d21..00000000000 --- a/tests/ixia/bgp/test_bgp_remote_link_failover.py +++ /dev/null @@ -1,59 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.bgp_convergence_helper import run_bgp_remote_link_failover_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - -@pytest.mark.parametrize('multipath',[2]) -@pytest.mark.parametrize('convergence_test_iterations',[1]) -@pytest.mark.parametrize('number_of_routes',[1000]) -@pytest.mark.parametrize('route_type',['IPv4']) -def test_bgp_convergence_for_remote_link_failover(cvg_api, - duthost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - multipath, - convergence_test_iterations, - number_of_routes, - route_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create BGP config on DUT and TGEN respectively - 2) Create a flow from TGEN1 to (N-1) TGEN ports - 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range - 4) Simulate route withdraw from one of the (N-1) BGP peers which is the equivalent of remote link failure - 5) Calculate the cp/dp for convergence time - 6) Clean up the BGP config on the dut - - Verification: - 1) Send traffic with all routes advertised by BGP peers - Result: Should not observe traffic loss - 2) Withdraw all routes from one of the BGP peer - Result: The traffic must be routed via rest of the ECMP paths and should not observe traffic loss - - Args: - snappi_api (pytest fixture): Snappi API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - multipath: ECMP value - convergence_test_iterations: number of iterations the cp/dp convergence test has to be run for a port - number_of_routes: Number of IPv4/IPv6 Routes - route_type: IPv4 or IPv6 routes - """ - #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference - run_bgp_remote_link_failover_test(cvg_api, - duthost, - tgen_ports, - convergence_test_iterations, - multipath, - number_of_routes, - route_type,) diff --git a/tests/ixia/bgp/test_bgp_rib_in_capacity.py b/tests/ixia/bgp/test_bgp_rib_in_capacity.py deleted file mode 100644 index 9705b3c36a3..00000000000 --- a/tests/ixia/bgp/test_bgp_rib_in_capacity.py +++ /dev/null @@ -1,60 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.bgp_convergence_helper import run_RIB_IN_capacity_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - - -@pytest.mark.parametrize('multipath', [2]) -@pytest.mark.parametrize('start_value', [5000]) -@pytest.mark.parametrize('step_value', [5000]) -@pytest.mark.parametrize('route_type', ['IPv4']) -def test_RIB_IN_capacity(cvg_api, - duthost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - multipath, - start_value, - step_value, - route_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create a BGP config on DUT and TGEN respectively - 2) Create a flow from TGEN1 to TGEN2 port - 3) Send Traffic from TGEN1 to TGEN2 port route range - 4) Check if there is any loss observed - 5) Increment the routes in terms of step_value and repeat test untill loss is observed - 6) Note down the number of routes upto which no loss was observed which is the RIB-IN capacity value - 7) Clean up the BGP config on the dut - Note: - confihgure DUT interfaces prior to running test - Verification: - 1) Send traffic and make sure there is no loss observed - 2) If loss is observed quit the test and note down the maximum routes upto which there was no loss - - Args: - snappi_api (pytest fixture): Snappi API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - multipath: ECMP value - start_value: Start value of the number of BGP routes - step_value: Step value of the number of BGP routes to be incremented - route_type: IPv4 or IPv6 routes - """ - #multipath, start_value, step_value and route_type parameters can be modified as per user preference - run_RIB_IN_capacity_test(cvg_api, - duthost, - tgen_ports, - multipath, - start_value, - step_value, - route_type,) diff --git a/tests/ixia/bgp/test_bgp_rib_in_convergence.py b/tests/ixia/bgp/test_bgp_rib_in_convergence.py deleted file mode 100644 index c4b07c3244d..00000000000 --- a/tests/ixia/bgp/test_bgp_rib_in_convergence.py +++ /dev/null @@ -1,61 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.bgp_convergence_helper import run_rib_in_convergence_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - - -@pytest.mark.parametrize('multipath', [2]) -@pytest.mark.parametrize('convergence_test_iterations', [1]) -@pytest.mark.parametrize('number_of_routes', [1000]) -@pytest.mark.parametrize('route_type', ['IPv4']) -def test_rib_in_convergence(cvg_api, - duthost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - multipath, - convergence_test_iterations, - number_of_routes, - route_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create BGP config on DUT and TGEN respectively - 2) Create a flow from TGEN1 to (N-1) TGEN ports - 3) Withdraw the routes from all the BGP peers - 4) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range - 4) Advertise the routes when traffic is running - 5) Calculate the RIB-IN convergence time - 6) Clean up the BGP config on the dut - - Verification: - 1) Send traffic after withdrawing routes from all BGP peers - Result: Should not observe any traffic in the receiving side - 2) Advertise the routes when the traffic is running - Result: The traffic must be routed via the ECMP paths - - Args: - snappi_api (pytest fixture): Snappi API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - multipath: ECMP value - convergence_test_iterations: number of iterations the link failure test has to be run for a port - number_of_routes: Number of IPv4/IPv6 Routes - route_type: IPv4 or IPv6 routes - """ - #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference - run_rib_in_convergence_test(cvg_api, - duthost, - tgen_ports, - convergence_test_iterations, - multipath, - number_of_routes, - route_type,) From 7d7af080d671c6f422b06e36d0732b49f1ce63e1 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 17 Sep 2021 08:33:45 +0000 Subject: [PATCH 30/58] removing Reboot files from test/ixia --- tests/ixia/reboot/files/__init__.py | 0 tests/ixia/reboot/files/reboot_helper.py | 342 ----------------------- tests/ixia/reboot/test_cold_reboot.py | 48 ---- tests/ixia/reboot/test_fast_reboot.py | 48 ---- tests/ixia/reboot/test_warm_reboot.py | 47 ---- 5 files changed, 485 deletions(-) delete mode 100755 tests/ixia/reboot/files/__init__.py delete mode 100755 tests/ixia/reboot/files/reboot_helper.py delete mode 100644 tests/ixia/reboot/test_cold_reboot.py delete mode 100644 tests/ixia/reboot/test_fast_reboot.py delete mode 100644 tests/ixia/reboot/test_warm_reboot.py diff --git a/tests/ixia/reboot/files/__init__.py b/tests/ixia/reboot/files/__init__.py deleted file mode 100755 index e69de29bb2d..00000000000 diff --git a/tests/ixia/reboot/files/reboot_helper.py b/tests/ixia/reboot/files/reboot_helper.py deleted file mode 100755 index 148108a282e..00000000000 --- a/tests/ixia/reboot/files/reboot_helper.py +++ /dev/null @@ -1,342 +0,0 @@ -from tabulate import tabulate -from tests.common.utilities import (wait, wait_until) -from tests.common.helpers.assertions import pytest_assert -from tests.common.reboot import reboot -import json -import ipaddr -logger = logging.getLogger(__name__) - -DUT_AS_NUM = 65100 -TGEN_AS_NUM = 65200 -TIMEOUT = 30 -BGP_TYPE = 'ebgp' -temp_tg_port = dict() - - -def run_reboot_test(cvg_api, - duthost, - localhost, - tgen_ports, - reboot_type,): - """ - Run Local link failover test - - Args: - cvg_api (pytest fixture): snappi API - duthost (pytest fixture): duthost fixture - localhost (pytest fixture): localhost handle - tgen_ports (pytest fixture): Ports mapping info of T0 testbed - reboot_type : Type of reboot - """ - - """ Create bgp config on dut """ - duthost_bgp_config(duthost, tgen_ports) - - """ Create bgp config on TGEN """ - tgen_bgp_config = __tgen_bgp_config(cvg_api) - - """ - Run the convergence test by flapping all the rx - links one by one and calculate the convergence valuess - """ - get_convergence_for_reboot_test(duthost, localhost, cvg_api, tgen_bgp_config, reboot_type,) - - cleanup_config(duthost) - - -def duthost_bgp_config(duthost, tgen_ports): - """ - 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 - """ - global temp_tg_port - duthost.command("sudo config save -y") - duthost.command("sudo cp {} {}".format("/etc/sonic/config_db.json", "/etc/sonic/config_db_backup.json")) - temp_tg_port = tgen_ports - for i in range(1, 4): - intf_config = ( - "sudo config interface ip remove %s %s/%s \n" - "sudo config interface ip remove %s %s/%s \n" - ) - intf_config %= (tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ipv6'], tgen_ports[i]['ipv6_prefix']) - logger.info('Removing configured IP and IPv6 Address from %s' % (tgen_ports[i]['peer_port'])) - duthost.shell(intf_config) - vlan_config=( - 'sudo config vlan add 1000\n' - 'sudo config vlan member add -u 1000 %s\n' - 'sudo config vlan member add -u 1000 %s\n' - 'sudo config interface ip add Vlan1000 192.168.1.1/16\n' - 'sudo config interface ip add Vlan1000 5001::1/64\n' - ) - vlan_config %= (tgen_ports[3]['peer_port'], tgen_ports[2]['peer_port']) - logger.info('Adding %s and %s to Vlan 1000' % (tgen_ports[3]['peer_port'], tgen_ports[2]['peer_port'])) - duthost.shell(vlan_config) - portchannel_config = ( - "sudo config portchannel add PortChannel1 \n" - "sudo config portchannel member add PortChannel1 %s\n" - "sudo config interface ip add PortChannel1 %s/%s\n" - "sudo config interface ip add PortChannel1 %s/%s\n" - ) - portchannel_config %= (tgen_ports[1]['peer_port'], tgen_ports[1]['peer_ip'], tgen_ports[1]['prefix'], tgen_ports[1]['peer_ipv6'], 64) - logger.info('Configuring %s to PortChannel1' % (tgen_ports[1]['peer_port'])) - logger.info('Portchannel1 (IPv4,IPv6) : ({},{})'.format(tgen_ports[1]['peer_ip'], tgen_ports[1]['peer_ipv6'])) - duthost.shell(portchannel_config) - loopback = ( - "sudo config interface ip add Loopback1 1.1.1.1/32\n" - ) - logger.info('Configuring 1.1.1.1/32 on the loopback interface') - duthost.shell(loopback) - logger.info('Configuring BGP in config_db.json') - bgp_neighbors = {tgen_ports[1]['ipv6']: {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[1]['peer_ipv6'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"},tgen_ports[1]['ip']: {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[1]['peer_ip'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"}} - cdf = json.loads(duthost.shell("sonic-cfggen -d --print-data")['stdout']) - for neighbor, neighbor_info in bgp_neighbors.items(): - cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info - - with open("/tmp/sconfig_db.json", 'w') as fp: - json.dump(cdf, fp, indent=4) - duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") - cdf = json.loads(duthost.shell("sonic-cfggen -j /tmp/config_db_temp.json --print-data")['stdout']) - print(cdf) - duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json", "/etc/sonic/config_db.json")) - logger.info('Reloading config to apply BGP config') - duthost.shell("sudo config reload -y \n") - wait(TIMEOUT+60, "For Config to reload \n") - - -def get_flow_stats(cvg_api, name): - """ - Args: - cvg_api (pytest fixture): Snappi API - """ - request = cvg_api.convergence_request() - request.metrics.flow_names = [name] - return cvg_api.get_results(request).flow_metric - - -def get_macs(mac, count, offset=1): - """ - Take mac as start mac returns the count of macs in a list - """ - mac_list = list() - for i in range(count): - mac_address = "{:012X}".format(int(mac, 16) + offset * i) - mac_address = ":".join( - format(s, "02x") for s in bytearray.fromhex(mac_address) - ) - mac_list.append(mac_address) - return mac_list - - -def get_ip_addresses(ip, count,type='ipv4'): - """ - Take ip as start ip returns the count of ips in a list - """ - ip_list = list() - for i in range(count): - if type == 'ipv6': - ipaddress = ipaddr.IPv6Address(ip) - else: - ipaddress = ipaddr.IPv4Address(ip) - ipaddress = ipaddress + i - value = ipaddress._string_from_ip_int(ipaddress._ip) - ip_list.append(value) - return ip_list - - -def __tgen_bgp_config(cvg_api,): - """ - Creating BGP config on TGEN - - Args: - cvg_api (pytest fixture): snappi API - """ - #temp_tg_port=[{'ip': '24.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet76', 'prefix': u'24', 'location': '10.36.78.53;4;4', 'ipv6': '2000:4::8', 'ipv6_prefix': u'124', 'port_id': '4', 'peer_ip': u'24.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:4::1'}, {'ip': '23.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet72', 'prefix': u'24', 'location': '10.36.78.53;4;3', 'ipv6': '2000:3::3', 'ipv6_prefix': u'124', 'port_id': '3', 'peer_ip': u'23.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:3::1'}, {'ip': '22.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet68', 'prefix': u'24', 'location': '10.36.78.53;4;2', 'ipv6': '2000:2::f', 'ipv6_prefix': u'124', 'port_id': '2', 'peer_ip': u'22.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:2::1'}, {'ip': '21.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet64', 'prefix': u'24', 'location': '10.36.78.53;4;1', 'ipv6': '2000:1::a', 'ipv6_prefix': u'124', 'port_id': '1', 'peer_ip': u'21.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:1::1'}] - conv_config = cvg_api.convergence_config() - cvg_api.enable_scaling(True) - config = conv_config.config - p1, p2, p3 = ( - config.ports.port(name="t1", location=temp_tg_port[1]['location']) - .port(name="server2", location=temp_tg_port[2]['location']) - .port(name="server1", location=temp_tg_port[3]['location']) - ) - lag3 = config.lags.lag(name="lag1")[-1] - lp3 = lag3.ports.port(port_name=p1.name)[-1] - lp3.protocol.lacp.actor_system_id = "00:11:03:00:00:03" - lp3.ethernet.name = "lag_Ethernet 3" - lp3.ethernet.mac = "00:13:01:00:00:01" - - config.options.port_options.location_preemption = True - layer1 = config.layer1.layer1()[-1] - layer1.name = 'port settings' - layer1.port_names = [port.name for port in config.ports] - layer1.ieee_media_defaults = False - layer1.auto_negotiation.rs_fec = True - layer1.auto_negotiation.link_training = False - layer1.speed = "speed_100_gbps" - layer1.auto_negotiate = False - - conf_values = dict() - num_of_devices = 1000 - conf_values['server_1_ipv4'] = get_ip_addresses("192.168.1.2", 2000)[::2] - conf_values['server_2_ipv4'] = get_ip_addresses("192.168.1.2", 2000)[1::2] - conf_values['server_1_ipv6'] = get_ip_addresses("5000::2", 2000, 'ipv6')[::2] - conf_values['server_2_ipv6'] = get_ip_addresses("5000::2", 2000, 'ipv6')[1::2] - conf_values['server_1_mac'] = get_macs("001700000011", num_of_devices) - conf_values['server_2_mac'] = get_macs("001600000011", num_of_devices) - for i in range(1, num_of_devices+1): - #server1 - d1 = config.devices.device(name='Server_1_{}'.format(i-1))[-1] - d1.container_name = p3.name - eth_1 = d1.ethernet - eth_1.name = 'Ethernet 1_{}'.format(i-1) - eth_1.mac = conf_values['server_1_mac'][i-1] - ipv4_1 = d1.ethernet.ipv4 - ipv4_1.name = 'IPv4 1_{}'.format(i-1) - ipv4_1.address = conf_values['server_1_ipv4'][i-1] - ipv4_1.gateway = '192.168.1.1' - ipv4_1.prefix = 16 - ipv6_1 = d1.ethernet.ipv6 - ipv6_1.name = 'IPv6 1_{}'.format(i-1) - ipv6_1.address = conf_values['server_1_ipv6'][i-1] - ipv6_1.gateway = '5001::1' - ipv6_1.prefix = 64 - #server2 - d2 = config.devices.device(name='Server_2_{}'.format(i-1))[-1] - d2.container_name = p2.name - eth_2 = d2.ethernet - eth_2.name = 'Ethernet 2_{}'.format(i-1) - eth_2.mac = conf_values['server_2_mac'][i-1] - ipv4_2 = d2.ethernet.ipv4 - ipv4_2.name = 'IPv4 2_{}'.format(i-1) - ipv4_2.address = conf_values['server_2_ipv4'][i-1] - ipv4_2.gateway = '192.168.1.1' - ipv4_2.prefix = 16 - ipv6_2 = d2.ethernet.ipv6 - ipv6_2.name = 'IPv6 2_{}'.format(i-1) - ipv6_2.address = conf_values['server_2_ipv6'][i-1] - ipv6_2.gateway = '5001::1' - ipv6_2.prefix = 64 - - #T1 - d3 = config.devices.device(name="T1")[-1] - d3.container_name = lag3.name - eth_3 = d3.ethernet - eth_3.name = 'Ethernet 3' - eth_3.mac = "00:14:01:00:00:01" - ipv4_3 = eth_3.ipv4 - ipv4_3.name = 'IPv4 3' - ipv4_3.address = temp_tg_port[1]['ip'] - ipv4_3.gateway = temp_tg_port[1]['peer_ip'] - ipv4_3.prefix = 24 - ipv6_3 = eth_3.ipv6 - ipv6_3.name = 'IPv6 3' - - ipv6_3.address = temp_tg_port[1]['ipv6'] - ipv6_3.gateway = temp_tg_port[1]['peer_ipv6'] - ipv6_3.prefix = 64 - bgpv4_stack = ipv4_3.bgpv4 - bgpv4_stack.name = 'BGP 3' - bgpv4_stack.as_type = BGP_TYPE - bgpv4_stack.dut_address = temp_tg_port[1]['peer_ip'] - bgpv4_stack.local_address = temp_tg_port[1]['ip'] - bgpv4_stack.as_number = int(TGEN_AS_NUM) - route_range1 = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group 1")[-1] - route_range1.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=1) - bgpv6_stack = ipv6_3.bgpv6 - bgpv6_stack.name = r'BGP+_3' - bgpv6_stack.as_type = BGP_TYPE - bgpv6_stack.dut_address = temp_tg_port[1]['peer_ipv6'] - bgpv6_stack.local_address = temp_tg_port[1]['ipv6'] - bgpv6_stack.as_number = int(TGEN_AS_NUM) - route_range2 = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group 2")[-1] - route_range2.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=1) - - def createTrafficItem(traffic_name, src, dest, rate=50): - flow1 = config.flows.flow(name=str(traffic_name))[-1] - flow1.tx_rx.device.tx_names = src - flow1.tx_rx.device.rx_names = dest - flow1.size.fixed = 1024 - flow1.rate.percentage = rate - flow1.metrics.enable = True - ipv4_1_names = ["IPv4 1_{}".format(i-1) for i in range(1, num_of_devices + 1)] - ipv4_2_names = ["IPv4 2_{}".format(i-1) for i in range(1, num_of_devices + 1)] - ipv6_1_names = ["IPv6 1_{}".format(i-1) for i in range(1, num_of_devices + 1)] - ipv6_2_names = ["IPv6 2_{}".format(i-1) for i in range(1, num_of_devices + 1)] - createTrafficItem("IPv4_1-IPv4_2", ipv4_1_names, ipv4_2_names) - createTrafficItem("IPv6_2-IPv6_1", ipv6_2_names, ipv6_1_names) - createTrafficItem("IPv4_1-T1", ipv4_1_names, [route_range1.name]) - createTrafficItem("IPv6_2-T1", ipv6_2_names, [route_range2.name]) - createTrafficItem("T1-IPv4_1", [route_range1.name], ipv4_1_names) - return conv_config - - -def get_convergence_for_reboot_test(duthost, - localhost, - cvg_api, - bgp_config, - reboot_type): - """ - Args: - duthost (pytest fixture): duthost fixture - localhost (pytest fixture): localhost handle - cvg_api (pytest fixture): snappi API - bgp_config: __tgen_bgp_config - reboot_type: Type of reboot - """ - table, dp = [], [] - bgp_config.rx_rate_threshold = 90 - cvg_api.set_config(bgp_config) - logger.info('Starting Traffic') - cs = cvg_api.convergence_state() - flow_names = ["IPv4_1-IPv4_2", "IPv6_2-IPv6_1", "IPv4_1-T1", "IPv6_2-T1", "T1-IPv4_1"] - cs.transmit.flow_names = flow_names - cs.transmit.state = cs.transmit.START - cvg_api.set_state(cs) - wait(TIMEOUT-10, "For Traffic To start") - req = cvg_api.ping_request() - p1 = req.endpoints.ipv4()[-1] - p1.src_name = 'IPv4 3' - p1.dst_ip = "1.1.1.1" - - logger.info("Issuing a {} reboot on the dut {}".format(reboot_type, duthost.hostname)) - reboot(duthost, localhost, reboot_type=reboot_type) - logger.info("Wait until the system is stable") - pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") - - responses = cvg_api.send_ping(req).responses - assert responses[-1].result == "success" - logger.info('Ping from IPv4 3 --> {} : {} after {} seconds after {}'.format(p1.dst_ip, responses[-1].result, 180, reboot_type)) - request = cvg_api.convergence_request() - for i in cs.transmit.flow_names: - request.metrics.flow_names = [i] - flow = cvg_api.get_results(request).flow_metric - assert int(flow[0].frames_tx_rate) != 0, "No Frames sent for traffic item: {}".format(i) - assert flow[0].frames_tx_rate == flow[0].frames_tx_rate, "Loss observed for Traffic Item: {}".format(i) - logger.info("No Loss Observed in Traffic Item {}".format(i)) - - request.convergence.flow_names = flow_names - convergence_metrics = cvg_api.get_results(request).flow_convergence - for metrics in convergence_metrics: - dp.append(metrics.data_plane_convergence_us/1000) - logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, metrics.data_plane_convergence_us/1000)) - - for j, i in enumerate(flow_names): - table.append([reboot_type, i, dp[j]]) - columns = ['Reboot Type', 'Traffic Item Name', 'Data Plane Convergence Time (ms)'] - logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) - -def cleanup_config(duthost): - """ - Cleaning up dut config at the end of the test - - Args: - duthost (pytest fixture): duthost fixture - """ - logger.info('Cleaning up config') - duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json", "/etc/sonic/config_db.json")) - duthost.shell("sudo config reload -y \n") - wait(TIMEOUT+30, "For Cleanup to complete \n") - logger.info('Convergence Test Completed') diff --git a/tests/ixia/reboot/test_cold_reboot.py b/tests/ixia/reboot/test_cold_reboot.py deleted file mode 100644 index af07e45e549..00000000000 --- a/tests/ixia/reboot/test_cold_reboot.py +++ /dev/null @@ -1,48 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.reboot_helper import run_reboot_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - - -@pytest.mark.parametrize('reboot_type', ['cold']) -def test_reboot(cvg_api, - duthost, - localhost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - reboot_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create 2 servers and a T1 device with dual stack BGP - 2) Configure LAG for the T1 Device - 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 - 4) Make sure there is no loss observed while sending trafic - 5) Reboot the dut with cold-reboot command - 6) Make sure after reboot the traffic has converged - - Verification: - 1) Make sure the control plane is up after the reboot is complete and the dut is back up - 2) Traffic must have converged after the dut is back up - - Args: - cvg_api (pytest fixture): Snappi Convergence API - duthost (pytest fixture): duthost fixture - localhost (pytest fixture): localhost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - reboot_type (parameter): Reboot command - """ - run_reboot_test(cvg_api, - duthost, - localhost, - tgen_ports, - reboot_type,) diff --git a/tests/ixia/reboot/test_fast_reboot.py b/tests/ixia/reboot/test_fast_reboot.py deleted file mode 100644 index 37e9087ae37..00000000000 --- a/tests/ixia/reboot/test_fast_reboot.py +++ /dev/null @@ -1,48 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.reboot_helper import run_reboot_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - - -@pytest.mark.parametrize('reboot_type', ['fast']) -def test_reboot(cvg_api, - duthost, - localhost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - reboot_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create 2 servers and a T1 device with dual stack BGP - 2) Configure LAG for the T1 Device - 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 - 4) Make sure there is no loss observed while sending trafic - 5) Reboot the dut with fast-reboot command - 6) Make sure after reboot the traffic has converged - - Verification: - 1) Make sure the control plane is up after the reboot is complete and the dut is back up - 2) Traffic must have converged after the dut is back up - - Args: - cvg_api (pytest fixture): Snappi Convergence API - duthost (pytest fixture): duthost fixture - localhost (pytest fixture): localhost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - reboot_type (parameter): Reboot command - """ - run_reboot_test(cvg_api, - duthost, - localhost, - tgen_ports, - reboot_type,) diff --git a/tests/ixia/reboot/test_warm_reboot.py b/tests/ixia/reboot/test_warm_reboot.py deleted file mode 100644 index e0efa16156b..00000000000 --- a/tests/ixia/reboot/test_warm_reboot.py +++ /dev/null @@ -1,47 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.reboot_helper import run_reboot_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - - -@pytest.mark.parametrize('reboot_type', ['warm']) -def test_reboot(cvg_api, - duthost, - localhost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - reboot_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create 2 servers and a T1 device with dual stack BGP - 2) Configure LAG for the T1 Device - 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 - 4) Make sure there is no loss observed while sending trafic - 5) Reboot the dut with warm-reboot command - 6) Make sure after reboot the traffic has converged - - Verification: - 1) Make sure the control plane is up after the reboot is complete and the dut is back up - 2) Traffic must have converged after the dut is back up - - Args: - cvg_api (pytest fixture): Snappi Convergence API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - reboot_type (parameter): Reboot command - """ - run_reboot_test(cvg_api, - duthost, - localhost, - tgen_ports, - reboot_type,) From 7612f7437a47b78204bb6f5df6f117ed7d649557 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 17 Sep 2021 08:38:39 +0000 Subject: [PATCH 31/58] duthost config changes --- tests/snappi/reboot/files/reboot_helper.py | 6 +++--- tests/snappi/reboot/test_warm_reboot.py | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/snappi/reboot/files/reboot_helper.py b/tests/snappi/reboot/files/reboot_helper.py index 01c90700f82..ee255cecc26 100755 --- a/tests/snappi/reboot/files/reboot_helper.py +++ b/tests/snappi/reboot/files/reboot_helper.py @@ -15,6 +15,7 @@ def run_reboot_test(cvg_api, duthost, localhost, + tgen_ports, reboot_type,): """ Run Local link failover test @@ -28,7 +29,7 @@ def run_reboot_test(cvg_api, """ """ Create bgp config on dut """ - #duthost_bgp_config(duthost, tgen_ports) + duthost_bgp_config(duthost, tgen_ports) """ Create bgp config on TGEN """ tgen_bgp_config = __tgen_bgp_config(cvg_api) @@ -39,7 +40,7 @@ def run_reboot_test(cvg_api, """ get_convergence_for_reboot_test(duthost, localhost, cvg_api, tgen_bgp_config, reboot_type,) - #cleanup_config(duthost) + cleanup_config(duthost) def duthost_bgp_config(duthost, tgen_ports): @@ -151,7 +152,6 @@ def __tgen_bgp_config(cvg_api,): Args: cvg_api (pytest fixture): snappi API """ - temp_tg_port=[{'ip': '24.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet76', 'prefix': u'24', 'location': '10.36.78.53;4;4', 'ipv6': '2000:4::8', 'ipv6_prefix': u'124', 'port_id': '4', 'peer_ip': u'24.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:4::1'}, {'ip': '23.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet72', 'prefix': u'24', 'location': '10.36.78.53;4;3', 'ipv6': '2000:3::3', 'ipv6_prefix': u'124', 'port_id': '3', 'peer_ip': u'23.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:3::1'}, {'ip': '22.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet68', 'prefix': u'24', 'location': '10.36.78.53;4;2', 'ipv6': '2000:2::f', 'ipv6_prefix': u'124', 'port_id': '2', 'peer_ip': u'22.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:2::1'}, {'ip': '21.1.1.2', 'card_id': '4', 'peer_port': 'Ethernet64', 'prefix': u'24', 'location': '10.36.78.53;4;1', 'ipv6': '2000:1::a', 'ipv6_prefix': u'124', 'port_id': '1', 'peer_ip': u'21.1.1.1', 'speed': 'speed_100_gbps', 'peer_device': 'sonic-s6100-dut', 'peer_ipv6': u'2000:1::1'}] conv_config = cvg_api.convergence_config() cvg_api.enable_scaling(True) config = conv_config.config diff --git a/tests/snappi/reboot/test_warm_reboot.py b/tests/snappi/reboot/test_warm_reboot.py index d8703c173b1..e0efa16156b 100644 --- a/tests/snappi/reboot/test_warm_reboot.py +++ b/tests/snappi/reboot/test_warm_reboot.py @@ -11,6 +11,7 @@ def test_reboot(cvg_api, duthost, localhost, + tgen_ports, conn_graph_facts, fanout_graph_facts, reboot_type,): @@ -42,4 +43,5 @@ def test_reboot(cvg_api, run_reboot_test(cvg_api, duthost, localhost, + tgen_ports, reboot_type,) From 9345fd64cf29b94910eb20f5646f2ce0ad947d30 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 17 Sep 2021 19:59:43 +0000 Subject: [PATCH 32/58] adding soft reboot case --- tests/snappi/reboot/test_soft_reboot.py | 47 +++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tests/snappi/reboot/test_soft_reboot.py diff --git a/tests/snappi/reboot/test_soft_reboot.py b/tests/snappi/reboot/test_soft_reboot.py new file mode 100644 index 00000000000..0caf33d3618 --- /dev/null +++ b/tests/snappi/reboot/test_soft_reboot.py @@ -0,0 +1,47 @@ +from tests.common.snappi.snappi_fixtures import cvg_api +from tests.common.snappi.snappi_fixtures import ( + snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) +from files.reboot_helper import run_reboot_test +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +import pytest + + +@pytest.mark.parametrize('reboot_type', ['soft']) +def test_reboot(cvg_api, + duthost, + localhost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + reboot_type,): + + """ + Topo: + TGEN1 --- DUT --- TGEN(2..N) + + Steps: + 1) Create 2 servers and a T1 device with dual stack BGP + 2) Configure LAG for the T1 Device + 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 + 4) Make sure there is no loss observed while sending trafic + 5) Reboot the dut with soft-reboot command + 6) Make sure after reboot the traffic has converged + + Verification: + 1) Make sure the control plane is up after the reboot is complete and the dut is back up + 2) Traffic must have converged after the dut is back up + + Args: + cvg_api (pytest fixture): Snappi Convergence API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + reboot_type (parameter): Reboot command + """ + run_reboot_test(cvg_api, + duthost, + localhost, + tgen_ports, + reboot_type,) From 0df1594630350d784306d3c04d223fe50efb5496 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 17 Sep 2021 22:24:44 +0000 Subject: [PATCH 33/58] Added try finally block --- tests/snappi/reboot/files/reboot_helper.py | 57 ++++++++++++---------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/tests/snappi/reboot/files/reboot_helper.py b/tests/snappi/reboot/files/reboot_helper.py index ee255cecc26..e06ade9a6f9 100755 --- a/tests/snappi/reboot/files/reboot_helper.py +++ b/tests/snappi/reboot/files/reboot_helper.py @@ -312,31 +312,36 @@ def check_bgp_state(): p1.src_name = 'IPv4 3' p1.dst_ip = "1.1.1.1" logger.info("Issuing a {} reboot on the dut {}".format(reboot_type, duthost.hostname)) - reboot(duthost, localhost, reboot_type=reboot_type) - logger.info("Wait until the system is stable") - pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") - check_bgp_state() - responses = cvg_api.send_ping(req).responses - assert responses[-1].result == "success" - logger.info('Ping from IPv4 3 --> {} : {} after {} seconds after {}'.format(p1.dst_ip, responses[-1].result, 180, reboot_type)) - request = cvg_api.convergence_request() - for i in cs.transmit.flow_names: - request.metrics.flow_names = [i] - flow = cvg_api.get_results(request).flow_metric - assert int(flow[0].frames_tx_rate) != 0, "No Frames sent for traffic item: {}".format(i) - assert flow[0].frames_tx_rate == flow[0].frames_tx_rate, "Loss observed for Traffic Item: {}".format(i) - logger.info("No Loss Observed in Traffic Item {}".format(i)) - - request.convergence.flow_names = flow_names - convergence_metrics = cvg_api.get_results(request).flow_convergence - for metrics in convergence_metrics: - dp.append(metrics.data_plane_convergence_us/1000) - logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, metrics.data_plane_convergence_us/1000)) - - for j, i in enumerate(flow_names): - table.append([reboot_type, i, dp[j]]) - columns = ['Reboot Type', 'Traffic Item Name', 'Data Plane Convergence Time (ms)'] - logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) + try: + reboot(duthost, localhost, reboot_type=reboot_type) + logger.info("Wait until the system is stable") + pytest_assert(wait_until(300, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") + except Exception as e: + logger.info(e) + finally: + check_bgp_state() + responses = cvg_api.send_ping(req).responses + assert responses[-1].result == "success","Ping from IPv4 3 --> Loopback1 Failed" + logger.info('Ping from IPv4 3 --> {} : {} after {} seconds after {}'.format(p1.dst_ip, responses[-1].result, 180, reboot_type)) + request = cvg_api.convergence_request() + + for i in cs.transmit.flow_names: + request.metrics.flow_names = [i] + flow = cvg_api.get_results(request).flow_metric + assert int(flow[0].frames_tx_rate) != 0, "No Frames sent for traffic item: {}".format(i) + assert flow[0].frames_tx_rate == flow[0].frames_tx_rate, "Loss observed for Traffic Item: {}".format(i) + logger.info("No Loss Observed in Traffic Item {}".format(i)) + + request.convergence.flow_names = flow_names + convergence_metrics = cvg_api.get_results(request).flow_convergence + for metrics in convergence_metrics: + dp.append(metrics.data_plane_convergence_us/1000) + logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, metrics.data_plane_convergence_us/1000)) + + for j, i in enumerate(flow_names): + table.append([reboot_type, i, dp[j]]) + columns = ['Reboot Type', 'Traffic Item Name', 'Data Plane Convergence Time (ms)'] + logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) def cleanup_config(duthost): """ @@ -349,4 +354,4 @@ def cleanup_config(duthost): duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json", "/etc/sonic/config_db.json")) duthost.shell("sudo config reload -y \n") wait(TIMEOUT+30, "For Cleanup to complete \n") - logger.info('Convergence Test Completed') + logger.info('Reboot Test Completed') From adac26f7781d6e0e7d3f3974b86b71e66893a8d5 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 19 Oct 2021 17:22:51 +0000 Subject: [PATCH 34/58] adding wait_group --- tests/snappi/reboot/files/wait_group.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100755 tests/snappi/reboot/files/wait_group.py diff --git a/tests/snappi/reboot/files/wait_group.py b/tests/snappi/reboot/files/wait_group.py new file mode 100755 index 00000000000..034aac1b1e2 --- /dev/null +++ b/tests/snappi/reboot/files/wait_group.py @@ -0,0 +1,25 @@ +from threading import Condition + + +class WaitGroup: + wait_count = 0 + cv = Condition() + + def add(self, count): + self.cv.acquire() + self.wait_count += count + self.cv.release() + + def done(self): + self.cv.acquire() + if self.wait_count > 0: + self.wait_count -= 1 + if self.wait_count == 0: + self.cv.notify_all() + self.cv.release() + + def wait(self): + self.cv.acquire() + while self.wait_count > 0: + self.cv.wait() + self.cv.release() \ No newline at end of file From ce2791ed56a0c60cbd8143b38ff6e04255a5b33a Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 19 Oct 2021 17:24:10 +0000 Subject: [PATCH 35/58] modified reboot_helper --- tests/snappi/reboot/files/reboot_helper.py | 139 +++++++++++++-------- 1 file changed, 89 insertions(+), 50 deletions(-) diff --git a/tests/snappi/reboot/files/reboot_helper.py b/tests/snappi/reboot/files/reboot_helper.py index e06ade9a6f9..bbecc1bc979 100755 --- a/tests/snappi/reboot/files/reboot_helper.py +++ b/tests/snappi/reboot/files/reboot_helper.py @@ -2,8 +2,12 @@ from tests.common.utilities import (wait, wait_until) from tests.common.helpers.assertions import pytest_assert from tests.common.reboot import reboot +from wait_group import WaitGroup +from threading import Lock, Thread import json import ipaddr +import time +import re logger = logging.getLogger(__name__) TGEN_AS_NUM = 65200 @@ -11,15 +15,20 @@ BGP_TYPE = 'ebgp' temp_tg_port = dict() +bgp_down_start_timer = 0 +bgp_up_time = 0 +loopback_down_start_timer = 0 +loopback_up_time = 0 + def run_reboot_test(cvg_api, duthost, localhost, tgen_ports, - reboot_type,): + reboot_type, + ): """ Run Local link failover test - Args: cvg_api (pytest fixture): snappi API duthost (pytest fixture): duthost fixture @@ -46,11 +55,11 @@ def run_reboot_test(cvg_api, def duthost_bgp_config(duthost, tgen_ports): """ 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 """ + start = time.time() global temp_tg_port duthost.command("sudo config save -y") duthost.command("sudo cp {} {}".format("/etc/sonic/config_db.json", "/etc/sonic/config_db_backup.json")) @@ -60,10 +69,11 @@ def duthost_bgp_config(duthost, tgen_ports): "sudo config interface ip remove %s %s/%s \n" "sudo config interface ip remove %s %s/%s \n" ) - intf_config %= (tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ipv6'], tgen_ports[i]['ipv6_prefix']) + intf_config %= (tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], + tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ipv6'], tgen_ports[i]['ipv6_prefix']) logger.info('Removing configured IP and IPv6 Address from %s' % (tgen_ports[i]['peer_port'])) duthost.shell(intf_config) - vlan_config=( + vlan_config = ( 'sudo config vlan add 1000\n' 'sudo config vlan member add -u 1000 %s\n' 'sudo config vlan member add -u 1000 %s\n' @@ -79,7 +89,8 @@ def duthost_bgp_config(duthost, tgen_ports): "sudo config interface ip add PortChannel1 %s/%s\n" "sudo config interface ip add PortChannel1 %s/%s\n" ) - portchannel_config %= (tgen_ports[1]['peer_port'], tgen_ports[1]['peer_ip'], tgen_ports[1]['prefix'], tgen_ports[1]['peer_ipv6'], 64) + portchannel_config %= (tgen_ports[1]['peer_port'], tgen_ports[1]['peer_ip'], + tgen_ports[1]['prefix'], tgen_ports[1]['peer_ipv6'], 64) logger.info('Configuring %s to PortChannel1' % (tgen_ports[1]['peer_port'])) logger.info('Portchannel1 (IPv4,IPv6) : ({},{})'.format(tgen_ports[1]['peer_ip'], tgen_ports[1]['peer_ipv6'])) duthost.shell(portchannel_config) @@ -89,7 +100,12 @@ def duthost_bgp_config(duthost, tgen_ports): logger.info('Configuring 1.1.1.1/32 on the loopback interface') duthost.shell(loopback) logger.info('Configuring BGP in config_db.json') - bgp_neighbors = {tgen_ports[1]['ipv6']: {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[1]['peer_ipv6'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"},tgen_ports[1]['ip']: {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[1]['peer_ip'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"}} + bgp_neighbors = {tgen_ports[1]['ipv6']: {"rrclient": "0", "name": "ARISTA08T0", + "local_addr": tgen_ports[1]['peer_ipv6'], "nhopself": "0", + "holdtime": "90", "asn": TGEN_AS_NUM,"keepalive": "30"}, + tgen_ports[1]['ip']: {"rrclient": "0", "name": "ARISTA08T0", + "local_addr": tgen_ports[1]['peer_ip'], "nhopself": "0", + "holdtime": "90", "asn": TGEN_AS_NUM,"keepalive": "30"}} cdf = json.loads(duthost.shell("sonic-cfggen -d --print-data")['stdout']) for neighbor, neighbor_info in bgp_neighbors.items(): cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info @@ -103,6 +119,8 @@ def duthost_bgp_config(duthost, tgen_ports): logger.info('Reloading config to apply BGP config') duthost.shell("sudo config reload -y \n") wait(TIMEOUT+60, "For Config to reload \n") + end = time.time() + logger.info('duthost_bpg_config() took {}s to complete'.format(end-start)) def get_flow_stats(cvg_api, name): @@ -148,7 +166,6 @@ def get_ip_addresses(ip, count,type='ipv4'): def __tgen_bgp_config(cvg_api,): """ Creating BGP config on TGEN - Args: cvg_api (pytest fixture): snappi API """ @@ -268,14 +285,44 @@ def createTrafficItem(traffic_name, src, dest, rate=50): createTrafficItem("IPv4_1-T1", ipv4_1_names, [route_range1.name]) createTrafficItem("IPv6_2-T1", ipv6_2_names, [route_range2.name]) createTrafficItem("T1-IPv4_1", [route_range1.name], ipv4_1_names) + createTrafficItem("T1-IPv6_2", [route_range2.name],ipv6_2_names) return conv_config +def wait_for_bgp_downtime(cvg_api, duthost, wait_group): + """ + Ping the Loopback interface, while the reboot command is initialized wait for BGP to become inactive. + Once inactive capture timestamp to start a timer. + """ + global loopback_down_start_timer + global bgp_down_start_timer + + while True: + # Ping the Loopback interface + req = cvg_api.ping_request() + p1 = req.endpoints.ipv4()[-1] + p1.src_name = 'IPv4 3' + p1.dst_ip = "1.1.1.1" + responses = cvg_api.send_ping(req).responses + try: + bgp_facts = duthost.bgp_facts()['ansible_facts'] + for _, item in bgp_facts['bgp_neighbors'].items(): + if str(item['state']) not in 'active': + bgp_down_start_timer = time.time() + loopback_down_start_timer = time.time() + break + except: + loopback_down_start_timer = time.time() + break + wait_group.done() + + def get_convergence_for_reboot_test(duthost, localhost, cvg_api, bgp_config, - reboot_type): + reboot_type, + ): """ Args: duthost (pytest fixture): duthost fixture @@ -296,6 +343,7 @@ def get_convergence_for_reboot_test(duthost, wait(TIMEOUT-10, "For Traffic To start") def check_bgp_state(): + global bgp_up_time req = cvg_api.convergence_request() req.bgpv4.peer_names = [] bgpv4_metrics = cvg_api.get_results(req).bgpv4_metrics @@ -312,46 +360,37 @@ def check_bgp_state(): p1.src_name = 'IPv4 3' p1.dst_ip = "1.1.1.1" logger.info("Issuing a {} reboot on the dut {}".format(reboot_type, duthost.hostname)) - try: - reboot(duthost, localhost, reboot_type=reboot_type) - logger.info("Wait until the system is stable") - pytest_assert(wait_until(300, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") - except Exception as e: - logger.info(e) - finally: - check_bgp_state() - responses = cvg_api.send_ping(req).responses - assert responses[-1].result == "success","Ping from IPv4 3 --> Loopback1 Failed" - logger.info('Ping from IPv4 3 --> {} : {} after {} seconds after {}'.format(p1.dst_ip, responses[-1].result, 180, reboot_type)) - request = cvg_api.convergence_request() - - for i in cs.transmit.flow_names: + #reboot(duthost, localhost, reboot_type=reboot_type) + wait_group = WaitGroup() + wait_group.add(1) + t1 = Thread(target=wait_for_bgp_downtime, args=([cvg_api, duthost, wait_group])).start() + t2 = Thread(target=reboot, args=([duthost, localhost, reboot_type])).start() + wait_group.wait() + loopback_timer_start = time.time() + logger.info("Wait until the system is stable") + pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") + check_bgp_state() + bgp_up_time = time.time() - bgp_down_start_timer + responses = cvg_api.send_ping(req).responses + assert responses[-1].result == "success" + global loopback_up_time + loopback_up_time = time.time() - loopback_timer_start + #logger.info('Ping from IPv4 3 --> {} : {} after {} seconds after {}'.format(p1.dst_ip, responses[-1].result, 180, reboot_type)) + request = cvg_api.convergence_request() + request.convergence.flow_names = flow_names + convergence_metrics = cvg_api.get_results(request).flow_convergence + for i, metrics in cs.transmit.flow_names, convergence_metrics: + if reboot_type == "warm": request.metrics.flow_names = [i] flow = cvg_api.get_results(request).flow_metric - assert int(flow[0].frames_tx_rate) != 0, "No Frames sent for traffic item: {}".format(i) - assert flow[0].frames_tx_rate == flow[0].frames_tx_rate, "Loss observed for Traffic Item: {}".format(i) - logger.info("No Loss Observed in Traffic Item {}".format(i)) - - request.convergence.flow_names = flow_names - convergence_metrics = cvg_api.get_results(request).flow_convergence - for metrics in convergence_metrics: - dp.append(metrics.data_plane_convergence_us/1000) - logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, metrics.data_plane_convergence_us/1000)) - - for j, i in enumerate(flow_names): - table.append([reboot_type, i, dp[j]]) - columns = ['Reboot Type', 'Traffic Item Name', 'Data Plane Convergence Time (ms)'] - logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) - -def cleanup_config(duthost): - """ - Cleaning up dut config at the end of the test - - Args: - duthost (pytest fixture): duthost fixture - """ - logger.info('Cleaning up config') - duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json", "/etc/sonic/config_db.json")) - duthost.shell("sudo config reload -y \n") - wait(TIMEOUT+30, "For Cleanup to complete \n") - logger.info('Reboot Test Completed') + if flow[0].frames_tx_rate != flow[0].frames_tx_rate: + logger.info("Some Loss Observed in Traffic Item {}".format(i)) + dp.append(metrics.data_plane_convergence_us/1000) + logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, metrics.data_plane_convergence_us/1000)) + else: + dp.append(0) + logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, 0)) + else: + request.metrics.flow_names = [i] + flow = cvg_api.get_results(request).flow_metric + assert int(fl \ No newline at end of file From 15f4ad884cc478406760fdf4c51960b78bd8cf30 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Mon, 1 Nov 2021 16:32:17 +0000 Subject: [PATCH 36/58] resolving syntax err --- tests/snappi/reboot/files/reboot_helper.py | 31 ++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/snappi/reboot/files/reboot_helper.py b/tests/snappi/reboot/files/reboot_helper.py index bbecc1bc979..9307bee52c3 100755 --- a/tests/snappi/reboot/files/reboot_helper.py +++ b/tests/snappi/reboot/files/reboot_helper.py @@ -360,7 +360,7 @@ def check_bgp_state(): p1.src_name = 'IPv4 3' p1.dst_ip = "1.1.1.1" logger.info("Issuing a {} reboot on the dut {}".format(reboot_type, duthost.hostname)) - #reboot(duthost, localhost, reboot_type=reboot_type) + reboot(duthost, localhost, reboot_type=reboot_type) wait_group = WaitGroup() wait_group.add(1) t1 = Thread(target=wait_for_bgp_downtime, args=([cvg_api, duthost, wait_group])).start() @@ -393,4 +393,31 @@ def check_bgp_state(): else: request.metrics.flow_names = [i] flow = cvg_api.get_results(request).flow_metric - assert int(fl \ No newline at end of file + assert int(flow[0].frames_tx_rate) != 0, "No Frames sent for traffic item: {}".format(i) + assert flow[0].frames_tx_rate == flow[0].frames_tx_rate, "Loss observed for Traffic Item: {}".format(i) + logger.info("No Loss Observed in Traffic Item {}".format(i)) + dp.append(metrics.data_plane_convergence_us/1000) + logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, metrics.data_plane_convergence_us/1000)) + + flow_names_table_rows = ["Server IPv4_1 - Server IPv4_2", "Server IPv6_2 - Server IPv6_1", "Server IPv4_1 - T1", + "Server IPv6_2 - T1", "T1 - Server IPv4_1", "T1 - Server IPv6_2"] + for j, i in enumerate(flow_names_table_rows): + table.append([reboot_type, i, dp[j], float(0.0)]) + table.append([reboot_type, 'BGP Control Plane Up Time', float(0.0), float(bgp_up_time)*1000]) + table.append([reboot_type, ''.join('Loopback Up Time'.format(p1.dst_ip)), float(0.0), + float(loopback_up_time)*1000]) + columns = ['Reboot Type', 'Traffic Item Name', 'Data Plane Convergence Time (ms)', 'Time (ms)'] + logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) + + +def cleanup_config(duthost): + """ + Cleaning up dut config at the end of the test + Args: + duthost (pytest fixture): duthost fixture + """ + logger.info('Cleaning up config') + duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json", "/etc/sonic/config_db.json")) + duthost.shell("sudo config reload -y \n") + wait(TIMEOUT+30, "For Cleanup to complete \n") + logger.info('Convergence Test Completed') \ No newline at end of file From 341aefaae8733a70ac3df829c00999b04fdad706 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 2 Nov 2021 18:15:07 +0000 Subject: [PATCH 37/58] resolving alerts --- tests/snappi/reboot/files/reboot_helper.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/snappi/reboot/files/reboot_helper.py b/tests/snappi/reboot/files/reboot_helper.py index 9307bee52c3..4cf8a4fd51c 100755 --- a/tests/snappi/reboot/files/reboot_helper.py +++ b/tests/snappi/reboot/files/reboot_helper.py @@ -3,11 +3,10 @@ from tests.common.helpers.assertions import pytest_assert from tests.common.reboot import reboot from wait_group import WaitGroup -from threading import Lock, Thread +from threading import Thread import json import ipaddr import time -import re logger = logging.getLogger(__name__) TGEN_AS_NUM = 65200 @@ -303,7 +302,7 @@ def wait_for_bgp_downtime(cvg_api, duthost, wait_group): p1 = req.endpoints.ipv4()[-1] p1.src_name = 'IPv4 3' p1.dst_ip = "1.1.1.1" - responses = cvg_api.send_ping(req).responses + cvg_api.send_ping(req).responses try: bgp_facts = duthost.bgp_facts()['ansible_facts'] for _, item in bgp_facts['bgp_neighbors'].items(): @@ -311,8 +310,9 @@ def wait_for_bgp_downtime(cvg_api, duthost, wait_group): bgp_down_start_timer = time.time() loopback_down_start_timer = time.time() break - except: + except Exception as e: loopback_down_start_timer = time.time() + logger.info(e) break wait_group.done() @@ -363,12 +363,13 @@ def check_bgp_state(): reboot(duthost, localhost, reboot_type=reboot_type) wait_group = WaitGroup() wait_group.add(1) - t1 = Thread(target=wait_for_bgp_downtime, args=([cvg_api, duthost, wait_group])).start() - t2 = Thread(target=reboot, args=([duthost, localhost, reboot_type])).start() + Thread(target=wait_for_bgp_downtime, args=([cvg_api, duthost, wait_group])).start() + Thread(target=reboot, args=([duthost, localhost, reboot_type])).start() wait_group.wait() loopback_timer_start = time.time() logger.info("Wait until the system is stable") - pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") + pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), + "Not all critical services are fully started") check_bgp_state() bgp_up_time = time.time() - bgp_down_start_timer responses = cvg_api.send_ping(req).responses From aab8e1577268b284e26cf86943291c0dd734f5b6 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 2 Nov 2021 22:22:08 +0000 Subject: [PATCH 38/58] resolving alert --- tests/snappi/reboot/files/reboot_helper.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/snappi/reboot/files/reboot_helper.py b/tests/snappi/reboot/files/reboot_helper.py index 4cf8a4fd51c..d798de3ebc6 100755 --- a/tests/snappi/reboot/files/reboot_helper.py +++ b/tests/snappi/reboot/files/reboot_helper.py @@ -368,8 +368,7 @@ def check_bgp_state(): wait_group.wait() loopback_timer_start = time.time() logger.info("Wait until the system is stable") - pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), - "Not all critical services are fully started") + pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") check_bgp_state() bgp_up_time = time.time() - bgp_down_start_timer responses = cvg_api.send_ping(req).responses @@ -380,7 +379,7 @@ def check_bgp_state(): request = cvg_api.convergence_request() request.convergence.flow_names = flow_names convergence_metrics = cvg_api.get_results(request).flow_convergence - for i, metrics in cs.transmit.flow_names, convergence_metrics: + for i, metrics in zip(cs.transmit.flow_names, convergence_metrics): if reboot_type == "warm": request.metrics.flow_names = [i] flow = cvg_api.get_results(request).flow_metric From a53e4c8d76ffbbdb1c30a2c1fe1f20e497f6aa8c Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 3 Nov 2021 19:16:45 +0000 Subject: [PATCH 39/58] deleting reboot scripts --- tests/snappi/reboot/files/reboot_helper.py | 423 --------------------- tests/snappi/reboot/files/wait_group.py | 25 -- tests/snappi/reboot/test_cold_reboot.py | 48 --- tests/snappi/reboot/test_fast_reboot.py | 48 --- tests/snappi/reboot/test_soft_reboot.py | 47 --- tests/snappi/reboot/test_warm_reboot.py | 47 --- 6 files changed, 638 deletions(-) delete mode 100755 tests/snappi/reboot/files/reboot_helper.py delete mode 100755 tests/snappi/reboot/files/wait_group.py delete mode 100644 tests/snappi/reboot/test_cold_reboot.py delete mode 100644 tests/snappi/reboot/test_fast_reboot.py delete mode 100644 tests/snappi/reboot/test_soft_reboot.py delete mode 100644 tests/snappi/reboot/test_warm_reboot.py diff --git a/tests/snappi/reboot/files/reboot_helper.py b/tests/snappi/reboot/files/reboot_helper.py deleted file mode 100755 index d798de3ebc6..00000000000 --- a/tests/snappi/reboot/files/reboot_helper.py +++ /dev/null @@ -1,423 +0,0 @@ -from tabulate import tabulate -from tests.common.utilities import (wait, wait_until) -from tests.common.helpers.assertions import pytest_assert -from tests.common.reboot import reboot -from wait_group import WaitGroup -from threading import Thread -import json -import ipaddr -import time -logger = logging.getLogger(__name__) - -TGEN_AS_NUM = 65200 -TIMEOUT = 30 -BGP_TYPE = 'ebgp' -temp_tg_port = dict() - -bgp_down_start_timer = 0 -bgp_up_time = 0 -loopback_down_start_timer = 0 -loopback_up_time = 0 - - -def run_reboot_test(cvg_api, - duthost, - localhost, - tgen_ports, - reboot_type, - ): - """ - Run Local link failover test - Args: - cvg_api (pytest fixture): snappi API - duthost (pytest fixture): duthost fixture - localhost (pytest fixture): localhost handle - tgen_ports (pytest fixture): Ports mapping info of T0 testbed - reboot_type : Type of reboot - """ - - """ Create bgp config on dut """ - duthost_bgp_config(duthost, tgen_ports) - - """ Create bgp config on TGEN """ - tgen_bgp_config = __tgen_bgp_config(cvg_api) - - """ - Run the convergence test by flapping all the rx - links one by one and calculate the convergence valuess - """ - get_convergence_for_reboot_test(duthost, localhost, cvg_api, tgen_bgp_config, reboot_type,) - - cleanup_config(duthost) - - -def duthost_bgp_config(duthost, tgen_ports): - """ - 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 - """ - start = time.time() - global temp_tg_port - duthost.command("sudo config save -y") - duthost.command("sudo cp {} {}".format("/etc/sonic/config_db.json", "/etc/sonic/config_db_backup.json")) - temp_tg_port = tgen_ports - for i in range(1, 4): - intf_config = ( - "sudo config interface ip remove %s %s/%s \n" - "sudo config interface ip remove %s %s/%s \n" - ) - intf_config %= (tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], - tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ipv6'], tgen_ports[i]['ipv6_prefix']) - logger.info('Removing configured IP and IPv6 Address from %s' % (tgen_ports[i]['peer_port'])) - duthost.shell(intf_config) - vlan_config = ( - 'sudo config vlan add 1000\n' - 'sudo config vlan member add -u 1000 %s\n' - 'sudo config vlan member add -u 1000 %s\n' - 'sudo config interface ip add Vlan1000 192.168.1.1/16\n' - 'sudo config interface ip add Vlan1000 5001::1/64\n' - ) - vlan_config %= (tgen_ports[3]['peer_port'], tgen_ports[2]['peer_port']) - logger.info('Adding %s and %s to Vlan 1000' % (tgen_ports[3]['peer_port'], tgen_ports[2]['peer_port'])) - duthost.shell(vlan_config) - portchannel_config = ( - "sudo config portchannel add PortChannel1 \n" - "sudo config portchannel member add PortChannel1 %s\n" - "sudo config interface ip add PortChannel1 %s/%s\n" - "sudo config interface ip add PortChannel1 %s/%s\n" - ) - portchannel_config %= (tgen_ports[1]['peer_port'], tgen_ports[1]['peer_ip'], - tgen_ports[1]['prefix'], tgen_ports[1]['peer_ipv6'], 64) - logger.info('Configuring %s to PortChannel1' % (tgen_ports[1]['peer_port'])) - logger.info('Portchannel1 (IPv4,IPv6) : ({},{})'.format(tgen_ports[1]['peer_ip'], tgen_ports[1]['peer_ipv6'])) - duthost.shell(portchannel_config) - loopback = ( - "sudo config interface ip add Loopback1 1.1.1.1/32\n" - ) - logger.info('Configuring 1.1.1.1/32 on the loopback interface') - duthost.shell(loopback) - logger.info('Configuring BGP in config_db.json') - bgp_neighbors = {tgen_ports[1]['ipv6']: {"rrclient": "0", "name": "ARISTA08T0", - "local_addr": tgen_ports[1]['peer_ipv6'], "nhopself": "0", - "holdtime": "90", "asn": TGEN_AS_NUM,"keepalive": "30"}, - tgen_ports[1]['ip']: {"rrclient": "0", "name": "ARISTA08T0", - "local_addr": tgen_ports[1]['peer_ip'], "nhopself": "0", - "holdtime": "90", "asn": TGEN_AS_NUM,"keepalive": "30"}} - cdf = json.loads(duthost.shell("sonic-cfggen -d --print-data")['stdout']) - for neighbor, neighbor_info in bgp_neighbors.items(): - cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info - - with open("/tmp/sconfig_db.json", 'w') as fp: - json.dump(cdf, fp, indent=4) - duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") - cdf = json.loads(duthost.shell("sonic-cfggen -j /tmp/config_db_temp.json --print-data")['stdout']) - print(cdf) - duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json", "/etc/sonic/config_db.json")) - logger.info('Reloading config to apply BGP config') - duthost.shell("sudo config reload -y \n") - wait(TIMEOUT+60, "For Config to reload \n") - end = time.time() - logger.info('duthost_bpg_config() took {}s to complete'.format(end-start)) - - -def get_flow_stats(cvg_api, name): - """ - Args: - cvg_api (pytest fixture): Snappi API - """ - request = cvg_api.convergence_request() - request.metrics.flow_names = [name] - return cvg_api.get_results(request).flow_metric - - -def get_macs(mac, count, offset=1): - """ - Take mac as start mac returns the count of macs in a list - """ - mac_list = list() - for i in range(count): - mac_address = "{:012X}".format(int(mac, 16) + offset * i) - mac_address = ":".join( - format(s, "02x") for s in bytearray.fromhex(mac_address) - ) - mac_list.append(mac_address) - return mac_list - - -def get_ip_addresses(ip, count,type='ipv4'): - """ - Take ip as start ip returns the count of ips in a list - """ - ip_list = list() - for i in range(count): - if type == 'ipv6': - ipaddress = ipaddr.IPv6Address(ip) - else: - ipaddress = ipaddr.IPv4Address(ip) - ipaddress = ipaddress + i - value = ipaddress._string_from_ip_int(ipaddress._ip) - ip_list.append(value) - return ip_list - - -def __tgen_bgp_config(cvg_api,): - """ - Creating BGP config on TGEN - Args: - cvg_api (pytest fixture): snappi API - """ - conv_config = cvg_api.convergence_config() - cvg_api.enable_scaling(True) - config = conv_config.config - p1, p2, p3 = ( - config.ports.port(name="t1", location=temp_tg_port[1]['location']) - .port(name="server2", location=temp_tg_port[2]['location']) - .port(name="server1", location=temp_tg_port[3]['location']) - ) - lag3 = config.lags.lag(name="lag1")[-1] - lp3 = lag3.ports.port(port_name=p1.name)[-1] - lp3.protocol.lacp.actor_system_id = "00:11:03:00:00:03" - lp3.ethernet.name = "lag_Ethernet 3" - lp3.ethernet.mac = "00:13:01:00:00:01" - - config.options.port_options.location_preemption = True - layer1 = config.layer1.layer1()[-1] - layer1.name = 'port settings' - layer1.port_names = [port.name for port in config.ports] - layer1.ieee_media_defaults = False - layer1.auto_negotiation.rs_fec = True - layer1.auto_negotiation.link_training = False - layer1.speed = "speed_100_gbps" - layer1.auto_negotiate = False - - conf_values = dict() - num_of_devices = 1000 - conf_values['server_1_ipv4'] = get_ip_addresses("192.168.1.2", 2000)[::2] - conf_values['server_2_ipv4'] = get_ip_addresses("192.168.1.2", 2000)[1::2] - conf_values['server_1_ipv6'] = get_ip_addresses("5000::2", 2000, 'ipv6')[::2] - conf_values['server_2_ipv6'] = get_ip_addresses("5000::2", 2000, 'ipv6')[1::2] - conf_values['server_1_mac'] = get_macs("001700000011", num_of_devices) - conf_values['server_2_mac'] = get_macs("001600000011", num_of_devices) - for i in range(1, num_of_devices+1): - #server1 - d1 = config.devices.device(name='Server_1_{}'.format(i-1))[-1] - d1.container_name = p3.name - eth_1 = d1.ethernet - eth_1.name = 'Ethernet 1_{}'.format(i-1) - eth_1.mac = conf_values['server_1_mac'][i-1] - ipv4_1 = d1.ethernet.ipv4 - ipv4_1.name = 'IPv4 1_{}'.format(i-1) - ipv4_1.address = conf_values['server_1_ipv4'][i-1] - ipv4_1.gateway = '192.168.1.1' - ipv4_1.prefix = 16 - ipv6_1 = d1.ethernet.ipv6 - ipv6_1.name = 'IPv6 1_{}'.format(i-1) - ipv6_1.address = conf_values['server_1_ipv6'][i-1] - ipv6_1.gateway = '5001::1' - ipv6_1.prefix = 64 - #server2 - d2 = config.devices.device(name='Server_2_{}'.format(i-1))[-1] - d2.container_name = p2.name - eth_2 = d2.ethernet - eth_2.name = 'Ethernet 2_{}'.format(i-1) - eth_2.mac = conf_values['server_2_mac'][i-1] - ipv4_2 = d2.ethernet.ipv4 - ipv4_2.name = 'IPv4 2_{}'.format(i-1) - ipv4_2.address = conf_values['server_2_ipv4'][i-1] - ipv4_2.gateway = '192.168.1.1' - ipv4_2.prefix = 16 - ipv6_2 = d2.ethernet.ipv6 - ipv6_2.name = 'IPv6 2_{}'.format(i-1) - ipv6_2.address = conf_values['server_2_ipv6'][i-1] - ipv6_2.gateway = '5001::1' - ipv6_2.prefix = 64 - - #T1 - d3 = config.devices.device(name="T1")[-1] - d3.container_name = lag3.name - eth_3 = d3.ethernet - eth_3.name = 'Ethernet 3' - eth_3.mac = "00:14:01:00:00:01" - ipv4_3 = eth_3.ipv4 - ipv4_3.name = 'IPv4 3' - ipv4_3.address = temp_tg_port[1]['ip'] - ipv4_3.gateway = temp_tg_port[1]['peer_ip'] - ipv4_3.prefix = 24 - ipv6_3 = eth_3.ipv6 - ipv6_3.name = 'IPv6 3' - - ipv6_3.address = temp_tg_port[1]['ipv6'] - ipv6_3.gateway = temp_tg_port[1]['peer_ipv6'] - ipv6_3.prefix = 64 - bgpv4_stack = ipv4_3.bgpv4 - bgpv4_stack.name = 'BGP 3' - bgpv4_stack.as_type = BGP_TYPE - bgpv4_stack.dut_address = temp_tg_port[1]['peer_ip'] - bgpv4_stack.local_address = temp_tg_port[1]['ip'] - bgpv4_stack.as_number = int(TGEN_AS_NUM) - route_range1 = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group 1")[-1] - route_range1.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=1) - bgpv6_stack = ipv6_3.bgpv6 - bgpv6_stack.name = r'BGP+_3' - bgpv6_stack.as_type = BGP_TYPE - bgpv6_stack.dut_address = temp_tg_port[1]['peer_ipv6'] - bgpv6_stack.local_address = temp_tg_port[1]['ipv6'] - bgpv6_stack.as_number = int(TGEN_AS_NUM) - route_range2 = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group 2")[-1] - route_range2.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=1) - - def createTrafficItem(traffic_name, src, dest, rate=50): - flow1 = config.flows.flow(name=str(traffic_name))[-1] - flow1.tx_rx.device.tx_names = src - flow1.tx_rx.device.rx_names = dest - flow1.size.fixed = 1024 - flow1.rate.percentage = rate - flow1.metrics.enable = True - ipv4_1_names = ["IPv4 1_{}".format(i-1) for i in range(1, num_of_devices + 1)] - ipv4_2_names = ["IPv4 2_{}".format(i-1) for i in range(1, num_of_devices + 1)] - ipv6_1_names = ["IPv6 1_{}".format(i-1) for i in range(1, num_of_devices + 1)] - ipv6_2_names = ["IPv6 2_{}".format(i-1) for i in range(1, num_of_devices + 1)] - createTrafficItem("IPv4_1-IPv4_2", ipv4_1_names, ipv4_2_names) - createTrafficItem("IPv6_2-IPv6_1", ipv6_2_names, ipv6_1_names) - createTrafficItem("IPv4_1-T1", ipv4_1_names, [route_range1.name]) - createTrafficItem("IPv6_2-T1", ipv6_2_names, [route_range2.name]) - createTrafficItem("T1-IPv4_1", [route_range1.name], ipv4_1_names) - createTrafficItem("T1-IPv6_2", [route_range2.name],ipv6_2_names) - return conv_config - - -def wait_for_bgp_downtime(cvg_api, duthost, wait_group): - """ - Ping the Loopback interface, while the reboot command is initialized wait for BGP to become inactive. - Once inactive capture timestamp to start a timer. - """ - global loopback_down_start_timer - global bgp_down_start_timer - - while True: - # Ping the Loopback interface - req = cvg_api.ping_request() - p1 = req.endpoints.ipv4()[-1] - p1.src_name = 'IPv4 3' - p1.dst_ip = "1.1.1.1" - cvg_api.send_ping(req).responses - try: - bgp_facts = duthost.bgp_facts()['ansible_facts'] - for _, item in bgp_facts['bgp_neighbors'].items(): - if str(item['state']) not in 'active': - bgp_down_start_timer = time.time() - loopback_down_start_timer = time.time() - break - except Exception as e: - loopback_down_start_timer = time.time() - logger.info(e) - break - wait_group.done() - - -def get_convergence_for_reboot_test(duthost, - localhost, - cvg_api, - bgp_config, - reboot_type, - ): - """ - Args: - duthost (pytest fixture): duthost fixture - localhost (pytest fixture): localhost handle - cvg_api (pytest fixture): snappi API - bgp_config: __tgen_bgp_config - reboot_type: Type of reboot - """ - table, dp = [], [] - bgp_config.rx_rate_threshold = 90 - cvg_api.set_config(bgp_config) - logger.info('Starting Traffic') - cs = cvg_api.convergence_state() - flow_names = ["IPv4_1-IPv4_2", "IPv6_2-IPv6_1", "IPv4_1-T1", "IPv6_2-T1", "T1-IPv4_1"] - cs.transmit.flow_names = flow_names - cs.transmit.state = cs.transmit.START - cvg_api.set_state(cs) - wait(TIMEOUT-10, "For Traffic To start") - - def check_bgp_state(): - global bgp_up_time - req = cvg_api.convergence_request() - req.bgpv4.peer_names = [] - bgpv4_metrics = cvg_api.get_results(req).bgpv4_metrics - assert bgpv4_metrics[-1].session_state == "up", "BGP v4 Session State is not UP" - logger.info("BGP v4 Session State is UP") - req.bgpv6.peer_names = [] - bgpv6_metrics = cvg_api.get_results(req).bgpv6_metrics - assert bgpv6_metrics[-1].session_state == "up", "BGP v6 Session State is not UP" - logger.info("BGP v6 Session State is UP") - - check_bgp_state() - req = cvg_api.ping_request() - p1 = req.endpoints.ipv4()[-1] - p1.src_name = 'IPv4 3' - p1.dst_ip = "1.1.1.1" - logger.info("Issuing a {} reboot on the dut {}".format(reboot_type, duthost.hostname)) - reboot(duthost, localhost, reboot_type=reboot_type) - wait_group = WaitGroup() - wait_group.add(1) - Thread(target=wait_for_bgp_downtime, args=([cvg_api, duthost, wait_group])).start() - Thread(target=reboot, args=([duthost, localhost, reboot_type])).start() - wait_group.wait() - loopback_timer_start = time.time() - logger.info("Wait until the system is stable") - pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") - check_bgp_state() - bgp_up_time = time.time() - bgp_down_start_timer - responses = cvg_api.send_ping(req).responses - assert responses[-1].result == "success" - global loopback_up_time - loopback_up_time = time.time() - loopback_timer_start - #logger.info('Ping from IPv4 3 --> {} : {} after {} seconds after {}'.format(p1.dst_ip, responses[-1].result, 180, reboot_type)) - request = cvg_api.convergence_request() - request.convergence.flow_names = flow_names - convergence_metrics = cvg_api.get_results(request).flow_convergence - for i, metrics in zip(cs.transmit.flow_names, convergence_metrics): - if reboot_type == "warm": - request.metrics.flow_names = [i] - flow = cvg_api.get_results(request).flow_metric - if flow[0].frames_tx_rate != flow[0].frames_tx_rate: - logger.info("Some Loss Observed in Traffic Item {}".format(i)) - dp.append(metrics.data_plane_convergence_us/1000) - logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, metrics.data_plane_convergence_us/1000)) - else: - dp.append(0) - logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, 0)) - else: - request.metrics.flow_names = [i] - flow = cvg_api.get_results(request).flow_metric - assert int(flow[0].frames_tx_rate) != 0, "No Frames sent for traffic item: {}".format(i) - assert flow[0].frames_tx_rate == flow[0].frames_tx_rate, "Loss observed for Traffic Item: {}".format(i) - logger.info("No Loss Observed in Traffic Item {}".format(i)) - dp.append(metrics.data_plane_convergence_us/1000) - logger.info('DP/DP Convergence Time (ms) of {} : {}'.format(i, metrics.data_plane_convergence_us/1000)) - - flow_names_table_rows = ["Server IPv4_1 - Server IPv4_2", "Server IPv6_2 - Server IPv6_1", "Server IPv4_1 - T1", - "Server IPv6_2 - T1", "T1 - Server IPv4_1", "T1 - Server IPv6_2"] - for j, i in enumerate(flow_names_table_rows): - table.append([reboot_type, i, dp[j], float(0.0)]) - table.append([reboot_type, 'BGP Control Plane Up Time', float(0.0), float(bgp_up_time)*1000]) - table.append([reboot_type, ''.join('Loopback Up Time'.format(p1.dst_ip)), float(0.0), - float(loopback_up_time)*1000]) - columns = ['Reboot Type', 'Traffic Item Name', 'Data Plane Convergence Time (ms)', 'Time (ms)'] - logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) - - -def cleanup_config(duthost): - """ - Cleaning up dut config at the end of the test - Args: - duthost (pytest fixture): duthost fixture - """ - logger.info('Cleaning up config') - duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json", "/etc/sonic/config_db.json")) - duthost.shell("sudo config reload -y \n") - wait(TIMEOUT+30, "For Cleanup to complete \n") - logger.info('Convergence Test Completed') \ No newline at end of file diff --git a/tests/snappi/reboot/files/wait_group.py b/tests/snappi/reboot/files/wait_group.py deleted file mode 100755 index 034aac1b1e2..00000000000 --- a/tests/snappi/reboot/files/wait_group.py +++ /dev/null @@ -1,25 +0,0 @@ -from threading import Condition - - -class WaitGroup: - wait_count = 0 - cv = Condition() - - def add(self, count): - self.cv.acquire() - self.wait_count += count - self.cv.release() - - def done(self): - self.cv.acquire() - if self.wait_count > 0: - self.wait_count -= 1 - if self.wait_count == 0: - self.cv.notify_all() - self.cv.release() - - def wait(self): - self.cv.acquire() - while self.wait_count > 0: - self.cv.wait() - self.cv.release() \ No newline at end of file diff --git a/tests/snappi/reboot/test_cold_reboot.py b/tests/snappi/reboot/test_cold_reboot.py deleted file mode 100644 index af07e45e549..00000000000 --- a/tests/snappi/reboot/test_cold_reboot.py +++ /dev/null @@ -1,48 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.reboot_helper import run_reboot_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - - -@pytest.mark.parametrize('reboot_type', ['cold']) -def test_reboot(cvg_api, - duthost, - localhost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - reboot_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create 2 servers and a T1 device with dual stack BGP - 2) Configure LAG for the T1 Device - 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 - 4) Make sure there is no loss observed while sending trafic - 5) Reboot the dut with cold-reboot command - 6) Make sure after reboot the traffic has converged - - Verification: - 1) Make sure the control plane is up after the reboot is complete and the dut is back up - 2) Traffic must have converged after the dut is back up - - Args: - cvg_api (pytest fixture): Snappi Convergence API - duthost (pytest fixture): duthost fixture - localhost (pytest fixture): localhost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - reboot_type (parameter): Reboot command - """ - run_reboot_test(cvg_api, - duthost, - localhost, - tgen_ports, - reboot_type,) diff --git a/tests/snappi/reboot/test_fast_reboot.py b/tests/snappi/reboot/test_fast_reboot.py deleted file mode 100644 index 37e9087ae37..00000000000 --- a/tests/snappi/reboot/test_fast_reboot.py +++ /dev/null @@ -1,48 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.reboot_helper import run_reboot_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - - -@pytest.mark.parametrize('reboot_type', ['fast']) -def test_reboot(cvg_api, - duthost, - localhost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - reboot_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create 2 servers and a T1 device with dual stack BGP - 2) Configure LAG for the T1 Device - 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 - 4) Make sure there is no loss observed while sending trafic - 5) Reboot the dut with fast-reboot command - 6) Make sure after reboot the traffic has converged - - Verification: - 1) Make sure the control plane is up after the reboot is complete and the dut is back up - 2) Traffic must have converged after the dut is back up - - Args: - cvg_api (pytest fixture): Snappi Convergence API - duthost (pytest fixture): duthost fixture - localhost (pytest fixture): localhost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - reboot_type (parameter): Reboot command - """ - run_reboot_test(cvg_api, - duthost, - localhost, - tgen_ports, - reboot_type,) diff --git a/tests/snappi/reboot/test_soft_reboot.py b/tests/snappi/reboot/test_soft_reboot.py deleted file mode 100644 index 0caf33d3618..00000000000 --- a/tests/snappi/reboot/test_soft_reboot.py +++ /dev/null @@ -1,47 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.reboot_helper import run_reboot_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - - -@pytest.mark.parametrize('reboot_type', ['soft']) -def test_reboot(cvg_api, - duthost, - localhost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - reboot_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create 2 servers and a T1 device with dual stack BGP - 2) Configure LAG for the T1 Device - 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 - 4) Make sure there is no loss observed while sending trafic - 5) Reboot the dut with soft-reboot command - 6) Make sure after reboot the traffic has converged - - Verification: - 1) Make sure the control plane is up after the reboot is complete and the dut is back up - 2) Traffic must have converged after the dut is back up - - Args: - cvg_api (pytest fixture): Snappi Convergence API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - reboot_type (parameter): Reboot command - """ - run_reboot_test(cvg_api, - duthost, - localhost, - tgen_ports, - reboot_type,) diff --git a/tests/snappi/reboot/test_warm_reboot.py b/tests/snappi/reboot/test_warm_reboot.py deleted file mode 100644 index e0efa16156b..00000000000 --- a/tests/snappi/reboot/test_warm_reboot.py +++ /dev/null @@ -1,47 +0,0 @@ -from tests.common.snappi.snappi_fixtures import cvg_api -from tests.common.snappi.snappi_fixtures import ( - snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.reboot_helper import run_reboot_test -from tests.common.fixtures.conn_graph_facts import ( - conn_graph_facts, fanout_graph_facts) -import pytest - - -@pytest.mark.parametrize('reboot_type', ['warm']) -def test_reboot(cvg_api, - duthost, - localhost, - tgen_ports, - conn_graph_facts, - fanout_graph_facts, - reboot_type,): - - """ - Topo: - TGEN1 --- DUT --- TGEN(2..N) - - Steps: - 1) Create 2 servers and a T1 device with dual stack BGP - 2) Configure LAG for the T1 Device - 3) Send Traffic from Server1 to Server2, server2 to Server1, T1 to Server1, T1 to server2, Server1 to T1 and Server2 to T1 - 4) Make sure there is no loss observed while sending trafic - 5) Reboot the dut with warm-reboot command - 6) Make sure after reboot the traffic has converged - - Verification: - 1) Make sure the control plane is up after the reboot is complete and the dut is back up - 2) Traffic must have converged after the dut is back up - - Args: - cvg_api (pytest fixture): Snappi Convergence API - duthost (pytest fixture): duthost fixture - tgen_ports (pytest fixture): Ports mapping info of testbed - conn_graph_facts (pytest fixture): connection graph - fanout_graph_facts (pytest fixture): fanout graph - reboot_type (parameter): Reboot command - """ - run_reboot_test(cvg_api, - duthost, - localhost, - tgen_ports, - reboot_type,) From 4b820f8a56b3f124fb40deb436ffdc6e7c1df409 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 3 Nov 2021 19:18:25 +0000 Subject: [PATCH 40/58] deleting init --- tests/snappi/reboot/files/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 tests/snappi/reboot/files/__init__.py diff --git a/tests/snappi/reboot/files/__init__.py b/tests/snappi/reboot/files/__init__.py deleted file mode 100755 index e69de29bb2d..00000000000 From 2a2e4eec8cbb09201b4e72a2f9b0cd235f6305e1 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 10 Nov 2021 17:18:43 +0000 Subject: [PATCH 41/58] portname fix --- tests/snappi/bgp/files/bgp_convergence_helper.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 82dc09bf594..ac473476ce0 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -220,7 +220,7 @@ def duthost_bgp_config(duthost, "sudo config interface ip add PortChannel%s %s/%s\n" ) portchannel_config %= (i+1, i+1, tgen_ports[i]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], i+1, tgen_ports[i]['peer_ipv6'], 64) - logger.info('Configuring %s to PortChannel%s with IPs %s,%s' % (tgen_ports[1]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['peer_ipv6'])) + logger.info('Configuring %s to PortChannel%s with IPs %s,%s' % (tgen_ports[i]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['peer_ipv6'])) duthost.shell(portchannel_config) logger.info('Configuring BGP in config_db.json') bgp_neighbors = dict() @@ -236,7 +236,6 @@ def duthost_bgp_config(duthost, json.dump(cdf, fp, indent=4) duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") cdf = json.loads(duthost.shell("sonic-cfggen -j /tmp/config_db_temp.json --print-data")['stdout']) - logger.info(cdf) duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json","/etc/sonic/config_db.json")) logger.info('Reloading config to apply BGP config') duthost.shell("sudo config reload -y \n") @@ -523,7 +522,7 @@ def get_avg_cpdp_convergence_time(route_name): for metrics in convergence_metrics: logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) - + import pdb;pdb.set_trace() """ Advertise the routes back at the end of iteration """ cs = cvg_api.convergence_state() cs.route.names = [route_name] From da9a10ff55482f928409098d64e8187d04adcb32 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 10 Nov 2021 17:21:16 +0000 Subject: [PATCH 42/58] removed pdb --- tests/snappi/bgp/files/bgp_convergence_helper.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index ac473476ce0..1460073aba6 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -522,7 +522,6 @@ def get_avg_cpdp_convergence_time(route_name): for metrics in convergence_metrics: logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) - import pdb;pdb.set_trace() """ Advertise the routes back at the end of iteration """ cs = cvg_api.convergence_state() cs.route.names = [route_name] From 5bda7c3235799aa629a222160d3153916ef3fef9 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 12 Nov 2021 04:02:44 +0000 Subject: [PATCH 43/58] final changes --- .../bgp/files/bgp_convergence_helper.py | 65 +++++++++++-------- .../bgp/test_bgp_local_link_failover.py | 4 +- tests/snappi/bgp/test_bgp_rib_in_capacity.py | 4 +- 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 1460073aba6..4829e382c18 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -229,6 +229,7 @@ def duthost_bgp_config(duthost, bgp_neighbors[tgen_ports[i]['ip']] = {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[i]['peer_ip'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"} cdf = json.loads(duthost.shell("sonic-cfggen -d --print-data")['stdout']) + logger.info(cdf) for neighbor, neighbor_info in bgp_neighbors.items(): cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info @@ -651,8 +652,19 @@ def tgen_capacity(routes): config = conv_config.config for i in range(1, 3): config.ports.port(name='Test_Port_%d' % i, location=temp_tg_port[i-1]['location']) + c_lag = config.lags.lag(name="lag%d" % i)[-1] + lp = c_lag.ports.port(port_name='Test_Port_%d' % i)[-1] + lp.ethernet.name = 'lag_eth_%d' % i + if len(str(hex(i).split('0x')[1])) == 1: + m = '0'+hex(i).split('0x')[1] + else: + m = hex(i).split('0x')[1] + lp.protocol.lacp.actor_system_id = "00:10:00:00:00:%s" % m + lp.ethernet.name = "lag_Ethernet %s" % i + lp.ethernet.mac = "00:10:01:00:00:%s" % m config.devices.device(name='Topology %d' % i) - config.devices[i-1].container_name = config.ports[i-1].name + config.devices[i-1].container_name = c_lag.name + #config.devices[i-1].container_name = config.ports[i-1].name config.options.port_options.location_preemption = True layer1 = config.layer1.layer1()[-1] @@ -744,32 +756,33 @@ def create_v6_topo(): flow.metrics.loss = True return conv_config - for j in range(start_value, 100000000000, step_value): - logger.info('|-------------------- RIB-IN Capacity test, No.of Routes : {} ----|'.format(j)) - conv_config = tgen_capacity(j) - cvg_api.set_config(conv_config) - """ Starting Traffic """ - logger.info('Starting Traffic') - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.START - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To start") - flow_stats = get_flow_stats(cvg_api) - logger.info('Loss% : {}'.format(flow_stats[0].loss)) - logger.info('Stopping Traffic') - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.STOP - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To stop") - if float(flow_stats[0].loss)>0.1: - if start_value == j: - max_routes = 'N/A' - raise Exception('FAIL:Max Routes: {}, Loss observed in start value itself, set the start value less than : {} !!!!!!!!!!!!'.format(max_routes,start_value)) - else: - max_routes = j-step_value - logger.info('max_routes :{}'.format(max_routes)) - break + try: + for j in range(start_value, 100000000000, step_value): + logger.info('|-------------------- RIB-IN Capacity test, No.of Routes : {} ----|'.format(j)) + conv_config = tgen_capacity(j) + cvg_api.set_config(conv_config) + + """ Starting Traffic """ + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To start") + flow_stats = get_flow_stats(cvg_api) + logger.info('Loss% : {}'.format(flow_stats[0].loss)) + logger.info('Stopping Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.STOP + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To stop") + except: + if start_value == j: + max_routes = 'N/A' + raise Exception('FAIL:Max Routes: {}, unable to apply traffic, set the start value less than : {} !!!!!!!!!!!!'.format(max_routes,start_value)) + else: + max_routes = j-step_value + logger.info('max_routes :{}'.format(max_routes)) logger.info('|------------ Max Routes without loss (RIB-IN Capacity Value) : {} ----|'.format(max_routes)) def cleanup_config(duthost): diff --git a/tests/snappi/bgp/test_bgp_local_link_failover.py b/tests/snappi/bgp/test_bgp_local_link_failover.py index 88610d988f7..ad06d3963e4 100644 --- a/tests/snappi/bgp/test_bgp_local_link_failover.py +++ b/tests/snappi/bgp/test_bgp_local_link_failover.py @@ -1,13 +1,13 @@ from tests.common.snappi.snappi_fixtures import cvg_api from tests.common.snappi.snappi_fixtures import ( snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.bgp_convergence_helper2 import run_bgp_local_link_failover_test +from files.bgp_convergence_helper import run_bgp_local_link_failover_test from tests.common.fixtures.conn_graph_facts import ( conn_graph_facts, fanout_graph_facts) import pytest -@pytest.mark.parametrize('multipath', [3]) +@pytest.mark.parametrize('multipath', [2]) @pytest.mark.parametrize('convergence_test_iterations', [1]) @pytest.mark.parametrize('number_of_routes', [1000]) @pytest.mark.parametrize('route_type', ['IPv4']) diff --git a/tests/snappi/bgp/test_bgp_rib_in_capacity.py b/tests/snappi/bgp/test_bgp_rib_in_capacity.py index 507fc2ed038..5af5447946e 100644 --- a/tests/snappi/bgp/test_bgp_rib_in_capacity.py +++ b/tests/snappi/bgp/test_bgp_rib_in_capacity.py @@ -1,14 +1,14 @@ from tests.common.snappi.snappi_fixtures import cvg_api from tests.common.snappi.snappi_fixtures import ( snappi_api_serv_ip, snappi_api_serv_port, tgen_ports) -from files.bgp_convergence_lag_helper import run_RIB_IN_capacity_test +from files.bgp_convergence_helper import run_RIB_IN_capacity_test from tests.common.fixtures.conn_graph_facts import ( conn_graph_facts, fanout_graph_facts) import pytest @pytest.mark.parametrize('multipath', [2]) -@pytest.mark.parametrize('start_value', [5000]) +@pytest.mark.parametrize('start_value', [10000]) @pytest.mark.parametrize('step_value', [5000]) @pytest.mark.parametrize('route_type', ['IPv4']) def test_RIB_IN_capacity(cvg_api, From 970b65e2ba8e913851143f7ba6fdf8da8dbcc05f Mon Sep 17 00:00:00 2001 From: selldinesh Date: Mon, 22 Nov 2021 22:42:04 +0000 Subject: [PATCH 44/58] python exception block added --- .../bgp/files/bgp_convergence_helper.py | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 4829e382c18..0effcfd07fd 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -240,7 +240,7 @@ def duthost_bgp_config(duthost, duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json","/etc/sonic/config_db.json")) logger.info('Reloading config to apply BGP config') duthost.shell("sudo config reload -y \n") - wait(TIMEOUT+60,"For Config to reload \n") + wait(TIMEOUT,"For Config to reload \n") def __tgen_bgp_config(cvg_api, @@ -759,6 +759,7 @@ def create_v6_topo(): try: for j in range(start_value, 100000000000, step_value): + tx_frate, rx_frate = [], [] logger.info('|-------------------- RIB-IN Capacity test, No.of Routes : {} ----|'.format(j)) conv_config = tgen_capacity(j) cvg_api.set_config(conv_config) @@ -771,19 +772,27 @@ def create_v6_topo(): wait(TIMEOUT, "For Traffic To start") flow_stats = get_flow_stats(cvg_api) logger.info('Loss% : {}'.format(flow_stats[0].loss)) - logger.info('Stopping Traffic') - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.STOP - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To stop") + flows = get_flow_stats(cvg_api) + for flow in flows: + tx_frate.append(flow.frames_tx_rate) + rx_frate.append(flow.frames_tx_rate) + if sum(tx_frate) != sum(rx_frate): + raise Exception('Tx Frame rate not equal to Rx Frame rate for {} routes'.format(j)) + else: + logger.info('Stopping Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.STOP + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To stop") except: if start_value == j: max_routes = 'N/A' - raise Exception('FAIL:Max Routes: {}, unable to apply traffic, set the start value less than : {} !!!!!!!!!!!!'.format(max_routes,start_value)) + raise Exception('Set the start_value less than : {} !!!!!!!!!!!!'.format(start_value)) else: max_routes = j-step_value logger.info('max_routes :{}'.format(max_routes)) - logger.info('|------------ Max Routes without loss (RIB-IN Capacity Value) : {} ----|'.format(max_routes)) + finally: + logger.info('|------------ Max Routes without loss (RIB-IN Capacity Value) : {} ----|'.format(max_routes)) def cleanup_config(duthost): """ From 14b7cf694f343c78dde743f2c918588e01d5cec4 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 24 Nov 2021 03:50:32 +0000 Subject: [PATCH 45/58] bgp config --- tests/snappi/bgp/files/bgp_convergence_helper.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 0effcfd07fd..262338d2339 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -232,7 +232,7 @@ def duthost_bgp_config(duthost, logger.info(cdf) for neighbor, neighbor_info in bgp_neighbors.items(): cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info - + cdf["DEVICE_METADATA"]['localhost']['bgp_asn'] = DUT_AS_NUM with open("/tmp/sconfig_db.json", 'w') as fp: json.dump(cdf, fp, indent=4) duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") @@ -775,7 +775,7 @@ def create_v6_topo(): flows = get_flow_stats(cvg_api) for flow in flows: tx_frate.append(flow.frames_tx_rate) - rx_frate.append(flow.frames_tx_rate) + rx_frate.append(flow.frames_rx_rate) if sum(tx_frate) != sum(rx_frate): raise Exception('Tx Frame rate not equal to Rx Frame rate for {} routes'.format(j)) else: From 5de8993ad87e9e705f68232fd08b8cf27911bee3 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Mon, 29 Nov 2021 22:40:46 +0000 Subject: [PATCH 46/58] bgp config and port speed change --- .../bgp/files/bgp_convergence_helper.py | 119 ++++++++++++------ .../bgp/test_bgp_local_link_failover.py | 10 +- .../bgp/test_bgp_remote_link_failover.py | 8 +- tests/snappi/bgp/test_bgp_rib_in_capacity.py | 10 +- .../snappi/bgp/test_bgp_rib_in_convergence.py | 8 +- 5 files changed, 106 insertions(+), 49 deletions(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 262338d2339..978a88c45fe 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -5,7 +5,8 @@ logger = logging.getLogger(__name__) TGEN_AS_NUM = 65200 -TIMEOUT = 40 +DUT_AS_NUM = 65100 +TIMEOUT = 30 BGP_TYPE = 'ebgp' temp_tg_port=dict() @@ -15,7 +16,8 @@ def run_bgp_local_link_failover_test(cvg_api, iteration, multipath, number_of_routes, - route_type,): + route_type, + port_speed,): """ Run Local link failover test @@ -27,19 +29,22 @@ def run_bgp_local_link_failover_test(cvg_api, multipath: ecmp value for BGP config number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes + port_speed: speed of the port used for test """ port_count = multipath+1 """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, - port_count,) + port_count, + route_type,) """ Create bgp config on TGEN """ tgen_bgp_config = __tgen_bgp_config(cvg_api, port_count, number_of_routes, - route_type,) + route_type, + port_speed,) """ Run the convergence test by flapping all the rx @@ -62,7 +67,8 @@ def run_bgp_remote_link_failover_test(cvg_api, iteration, multipath, number_of_routes, - route_type,): + route_type, + port_speed,): """ Run Remote link failover test @@ -73,18 +79,21 @@ def run_bgp_remote_link_failover_test(cvg_api, iteration: number of iterations for running convergence test on a port multipath: ecmp value for BGP config route_type: IPv4 or IPv6 routes + port_speed: speed of the port used for test """ port_count = multipath+1 """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, - port_count,) + port_count, + route_type,) """ Create bgp config on TGEN """ tgen_bgp_config = __tgen_bgp_config(cvg_api, port_count, number_of_routes, - route_type,) + route_type, + port_speed,) """ Run the convergence test by withdrawing all the route ranges @@ -108,7 +117,8 @@ def run_rib_in_convergence_test(cvg_api, iteration, multipath, number_of_routes, - route_type,): + route_type, + port_speed,): """ Run RIB-IN Convergence test @@ -120,19 +130,22 @@ def run_rib_in_convergence_test(cvg_api, multipath: ecmp value for BGP config number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes + port_speed: speed of the port used for test """ port_count = multipath+1 """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, - port_count,) + port_count, + route_type,) """ Create bgp config on TGEN """ tgen_bgp_config = __tgen_bgp_config(cvg_api, port_count, number_of_routes, - route_type,) + route_type, + port_speed,) """ Run the convergence test by withdrawing all routes at once and @@ -165,15 +178,17 @@ def run_RIB_IN_capacity_test(cvg_api, duthost (pytest fixture): duthost fixture tgen_ports (pytest fixture): Ports mapping info of T0 testbed multipath: ecmp value for BGP config - start_value: - step_value: + start_value: start value of number of routes + step_value: step value of routes to be incremented at every iteration route_type: IPv4 or IPv6 routes + port_speed: speed of the port used for test """ port_count = multipath+1 """ Create bgp config on dut """ duthost_bgp_config(duthost, tgen_ports, - port_count,) + port_count, + route_type,) """ Run the RIB-IN capacity test by increasig the route count step by step """ @@ -181,7 +196,8 @@ def run_RIB_IN_capacity_test(cvg_api, multipath, start_value, step_value, - route_type,) + route_type, + port_speed,) """ Cleanup the dut configs after getting the convergence numbers """ cleanup_config(duthost) @@ -189,7 +205,8 @@ def run_RIB_IN_capacity_test(cvg_api, def duthost_bgp_config(duthost, tgen_ports, - port_count,): + port_count, + route_type,): """ Configures BGP on the DUT with N-1 ecmp @@ -198,6 +215,7 @@ def duthost_bgp_config(duthost, tgen_ports (pytest fixture): Ports mapping info of T0 testbed port_count:multipath + 1 multipath: ECMP value for BGP config + route_type: IPv4 or IPv6 routes """ duthost.command("sudo config save -y") duthost.command("sudo cp {} {}".format("/etc/sonic/config_db.json", "/etc/sonic/config_db_backup.json")) @@ -222,31 +240,52 @@ def duthost_bgp_config(duthost, portchannel_config %= (i+1, i+1, tgen_ports[i]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], i+1, tgen_ports[i]['peer_ipv6'], 64) logger.info('Configuring %s to PortChannel%s with IPs %s,%s' % (tgen_ports[i]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['peer_ipv6'])) duthost.shell(portchannel_config) - logger.info('Configuring BGP in config_db.json') - bgp_neighbors = dict() - for i in range(1, port_count): - bgp_neighbors[tgen_ports[i]['ipv6']] = {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[i]['peer_ipv6'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"} - bgp_neighbors[tgen_ports[i]['ip']] = {"rrclient": "0","name": "ARISTA08T0","local_addr": tgen_ports[i]['peer_ip'],"nhopself": "0","holdtime": "90","asn": TGEN_AS_NUM,"keepalive": "30"} - - cdf = json.loads(duthost.shell("sonic-cfggen -d --print-data")['stdout']) - logger.info(cdf) - for neighbor, neighbor_info in bgp_neighbors.items(): - cdf["BGP_NEIGHBOR"][neighbor] = neighbor_info - cdf["DEVICE_METADATA"]['localhost']['bgp_asn'] = DUT_AS_NUM - with open("/tmp/sconfig_db.json", 'w') as fp: - json.dump(cdf, fp, indent=4) - duthost.copy(src="/tmp/sconfig_db.json", dest="/tmp/config_db_temp.json") - cdf = json.loads(duthost.shell("sonic-cfggen -j /tmp/config_db_temp.json --print-data")['stdout']) - duthost.command("sudo cp {} {} \n".format("/tmp/config_db_temp.json","/etc/sonic/config_db.json")) - logger.info('Reloading config to apply BGP config') - duthost.shell("sudo config reload -y \n") - wait(TIMEOUT,"For Config to reload \n") + bgp_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'router bgp %s' " + "-c 'no bgp ebgp-requires-policy' " + "-c 'bgp bestpath as-path multipath-relax' " + "-c 'maximum-paths %s' " + "-c 'exit' " + ) + bgp_config %= (DUT_AS_NUM, port_count-1) + duthost.shell(bgp_config) + if route_type == 'IPv4': + for i in range(1, 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 v4 Neighbor %s' % tgen_ports[i]['ip']) + duthost.shell(bgp_config_neighbor) + else: + for i in range(1, port_count): + bgp_config_neighbor = ( + "vtysh " + "-c 'configure terminal' " + "-c 'router bgp %s' " + "-c 'neighbor %s remote-as %s' " + "-c 'address-family ipv6 unicast' " + "-c 'neighbor %s activate' " + "-c 'exit' " + ) + bgp_config_neighbor %= (DUT_AS_NUM, tgen_ports[i]['ipv6'], TGEN_AS_NUM, tgen_ports[i]['ipv6']) + logger.info('Configuring BGP v6 Neighbor %s' % tgen_ports[i]['ipv6']) + duthost.shell(bgp_config_neighbor) def __tgen_bgp_config(cvg_api, port_count, number_of_routes, - route_type,): + route_type, + port_speed,): """ Creating BGP config on TGEN @@ -255,6 +294,7 @@ def __tgen_bgp_config(cvg_api, port_count: multipath + 1 number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes + port_speed: speed of the port used for test """ conv_config = cvg_api.convergence_config() config = conv_config.config @@ -280,7 +320,7 @@ def __tgen_bgp_config(cvg_api, layer1.ieee_media_defaults = False layer1.auto_negotiation.rs_fec = True layer1.auto_negotiation.link_training = False - layer1.speed = "speed_100_gbps" + layer1.speed = port_speed layer1.auto_negotiate = False def create_v4_topo(): @@ -636,7 +676,8 @@ def get_RIB_IN_capacity(cvg_api, multipath, start_value, step_value, - route_type,): + route_type, + port_speed,): """ Args: cvg_api (pytest fixture): snappi API @@ -645,7 +686,7 @@ def get_RIB_IN_capacity(cvg_api, start_value: Start value of the number of BGP routes step_value: Step value of the number of BGP routes to be incremented route_type: IPv4 or IPv6 routes - + port_speed: speed of the port used in test """ def tgen_capacity(routes): conv_config = cvg_api.convergence_config() @@ -673,7 +714,7 @@ def tgen_capacity(routes): layer1.ieee_media_defaults = False layer1.auto_negotiation.rs_fec = True layer1.auto_negotiation.link_training = False - layer1.speed = "speed_100_gbps" + layer1.speed = port_speed layer1.auto_negotiate = False def create_v4_topo(): diff --git a/tests/snappi/bgp/test_bgp_local_link_failover.py b/tests/snappi/bgp/test_bgp_local_link_failover.py index ad06d3963e4..b4b9ea5aa91 100644 --- a/tests/snappi/bgp/test_bgp_local_link_failover.py +++ b/tests/snappi/bgp/test_bgp_local_link_failover.py @@ -7,10 +7,11 @@ import pytest -@pytest.mark.parametrize('multipath', [2]) +@pytest.mark.parametrize('multipath', [7]) @pytest.mark.parametrize('convergence_test_iterations', [1]) @pytest.mark.parametrize('number_of_routes', [1000]) @pytest.mark.parametrize('route_type', ['IPv4']) +@pytest.mark.parametrize('port_speed',['speed_400_gbps']) def test_bgp_convergence_for_local_link_failover(cvg_api, duthost, tgen_ports, @@ -19,7 +20,8 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, multipath, convergence_test_iterations, number_of_routes, - route_type,): + route_type, + port_speed,): """ Topo: @@ -49,6 +51,7 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, convergence_test_iterations: number of iterations the link failure test has to be run for a port number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes + port_speed: speed of the port used for test """ #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference run_bgp_local_link_failover_test(cvg_api, @@ -57,4 +60,5 @@ def test_bgp_convergence_for_local_link_failover(cvg_api, convergence_test_iterations, multipath, number_of_routes, - route_type,) + route_type, + port_speed,) diff --git a/tests/snappi/bgp/test_bgp_remote_link_failover.py b/tests/snappi/bgp/test_bgp_remote_link_failover.py index e1357f55d21..6f7ffc09e8a 100755 --- a/tests/snappi/bgp/test_bgp_remote_link_failover.py +++ b/tests/snappi/bgp/test_bgp_remote_link_failover.py @@ -10,6 +10,7 @@ @pytest.mark.parametrize('convergence_test_iterations',[1]) @pytest.mark.parametrize('number_of_routes',[1000]) @pytest.mark.parametrize('route_type',['IPv4']) +@pytest.mark.parametrize('port_speed',['speed_100_gbps']) def test_bgp_convergence_for_remote_link_failover(cvg_api, duthost, tgen_ports, @@ -18,7 +19,8 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, multipath, convergence_test_iterations, number_of_routes, - route_type,): + route_type, + port_speed,): """ Topo: @@ -48,6 +50,7 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, convergence_test_iterations: number of iterations the cp/dp convergence test has to be run for a port number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes + port_speed: speed of the port used for test """ #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference run_bgp_remote_link_failover_test(cvg_api, @@ -56,4 +59,5 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, convergence_test_iterations, multipath, number_of_routes, - route_type,) + route_type, + port_speed,) diff --git a/tests/snappi/bgp/test_bgp_rib_in_capacity.py b/tests/snappi/bgp/test_bgp_rib_in_capacity.py index 5af5447946e..c098455f802 100644 --- a/tests/snappi/bgp/test_bgp_rib_in_capacity.py +++ b/tests/snappi/bgp/test_bgp_rib_in_capacity.py @@ -9,8 +9,9 @@ @pytest.mark.parametrize('multipath', [2]) @pytest.mark.parametrize('start_value', [10000]) -@pytest.mark.parametrize('step_value', [5000]) +@pytest.mark.parametrize('step_value', [1000]) @pytest.mark.parametrize('route_type', ['IPv4']) +@pytest.mark.parametrize('port_speed',['speed_100_gbps']) def test_RIB_IN_capacity(cvg_api, duthost, tgen_ports, @@ -19,7 +20,8 @@ def test_RIB_IN_capacity(cvg_api, multipath, start_value, step_value, - route_type,): + route_type, + port_speed,): """ Topo: @@ -49,6 +51,7 @@ def test_RIB_IN_capacity(cvg_api, start_value: Start value of the number of BGP routes step_value: Step value of the number of BGP routes to be incremented route_type: IPv4 or IPv6 routes + port_speed: speed of the port used for test """ #multipath, start_value, step_value and route_type parameters can be modified as per user preference run_RIB_IN_capacity_test(cvg_api, @@ -57,4 +60,5 @@ def test_RIB_IN_capacity(cvg_api, multipath, start_value, step_value, - route_type,) + route_type, + port_speed,) diff --git a/tests/snappi/bgp/test_bgp_rib_in_convergence.py b/tests/snappi/bgp/test_bgp_rib_in_convergence.py index c4b07c3244d..36bd85d6544 100644 --- a/tests/snappi/bgp/test_bgp_rib_in_convergence.py +++ b/tests/snappi/bgp/test_bgp_rib_in_convergence.py @@ -11,6 +11,7 @@ @pytest.mark.parametrize('convergence_test_iterations', [1]) @pytest.mark.parametrize('number_of_routes', [1000]) @pytest.mark.parametrize('route_type', ['IPv4']) +@pytest.mark.parametrize('port_speed',['speed_100_gbps']) def test_rib_in_convergence(cvg_api, duthost, tgen_ports, @@ -19,7 +20,8 @@ def test_rib_in_convergence(cvg_api, multipath, convergence_test_iterations, number_of_routes, - route_type,): + route_type, + port_speed,): """ Topo: @@ -50,6 +52,7 @@ def test_rib_in_convergence(cvg_api, convergence_test_iterations: number of iterations the link failure test has to be run for a port number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes + port_speed: speed of the port used for test """ #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference run_rib_in_convergence_test(cvg_api, @@ -58,4 +61,5 @@ def test_rib_in_convergence(cvg_api, convergence_test_iterations, multipath, number_of_routes, - route_type,) + route_type, + port_speed,) From 6b5ceec708b4ebb96db64165e1d66bbef19a9c31 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Mon, 6 Dec 2021 23:45:00 +0000 Subject: [PATCH 47/58] resolving alerts --- tests/snappi/bgp/files/bgp_convergence_helper.py | 12 +++++++----- tests/snappi/bgp/test_bgp_local_link_failover.py | 4 ++-- tests/snappi/bgp/test_bgp_remote_link_failover.py | 2 +- tests/snappi/bgp/test_bgp_rib_in_capacity.py | 4 ++-- tests/snappi/bgp/test_bgp_rib_in_convergence.py | 2 +- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 978a88c45fe..958bc1df37d 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -1,7 +1,7 @@ from tabulate import tabulate from statistics import mean -from tests.common.utilities import wait -import json +from tests.common.utilities import (wait, wait_until) +from tests.common.helpers.assertions import pytest_assert logger = logging.getLogger(__name__) TGEN_AS_NUM = 65200 @@ -168,7 +168,8 @@ def run_RIB_IN_capacity_test(cvg_api, multipath, start_value, step_value, - route_type,): + route_type, + port_speed,): """ Run RIB-IN Capacity test @@ -844,5 +845,6 @@ def cleanup_config(duthost): """ duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json","/etc/sonic/config_db.json")) duthost.shell("sudo config reload -y \n") - wait(TIMEOUT+60,"For Cleanup to complete \n") - logger.info('Convergence Test Completed') + logger.info("Wait until all critical services are fully started") + pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") + logger.info('Convergence Test Completed') \ No newline at end of file diff --git a/tests/snappi/bgp/test_bgp_local_link_failover.py b/tests/snappi/bgp/test_bgp_local_link_failover.py index b4b9ea5aa91..e1e9b31c419 100644 --- a/tests/snappi/bgp/test_bgp_local_link_failover.py +++ b/tests/snappi/bgp/test_bgp_local_link_failover.py @@ -7,11 +7,11 @@ import pytest -@pytest.mark.parametrize('multipath', [7]) +@pytest.mark.parametrize('multipath', [2]) @pytest.mark.parametrize('convergence_test_iterations', [1]) @pytest.mark.parametrize('number_of_routes', [1000]) @pytest.mark.parametrize('route_type', ['IPv4']) -@pytest.mark.parametrize('port_speed',['speed_400_gbps']) +@pytest.mark.parametrize('port_speed',['speed_100_gbps']) def test_bgp_convergence_for_local_link_failover(cvg_api, duthost, tgen_ports, diff --git a/tests/snappi/bgp/test_bgp_remote_link_failover.py b/tests/snappi/bgp/test_bgp_remote_link_failover.py index 6f7ffc09e8a..c992b061d12 100755 --- a/tests/snappi/bgp/test_bgp_remote_link_failover.py +++ b/tests/snappi/bgp/test_bgp_remote_link_failover.py @@ -52,7 +52,7 @@ def test_bgp_convergence_for_remote_link_failover(cvg_api, route_type: IPv4 or IPv6 routes port_speed: speed of the port used for test """ - #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference + #convergence_test_iterations, multipath, number_of_routes, port_speed and route_type parameters can be modified as per user preference run_bgp_remote_link_failover_test(cvg_api, duthost, tgen_ports, diff --git a/tests/snappi/bgp/test_bgp_rib_in_capacity.py b/tests/snappi/bgp/test_bgp_rib_in_capacity.py index c098455f802..76d79104066 100644 --- a/tests/snappi/bgp/test_bgp_rib_in_capacity.py +++ b/tests/snappi/bgp/test_bgp_rib_in_capacity.py @@ -8,7 +8,7 @@ @pytest.mark.parametrize('multipath', [2]) -@pytest.mark.parametrize('start_value', [10000]) +@pytest.mark.parametrize('start_value', [1000]) @pytest.mark.parametrize('step_value', [1000]) @pytest.mark.parametrize('route_type', ['IPv4']) @pytest.mark.parametrize('port_speed',['speed_100_gbps']) @@ -53,7 +53,7 @@ def test_RIB_IN_capacity(cvg_api, route_type: IPv4 or IPv6 routes port_speed: speed of the port used for test """ - #multipath, start_value, step_value and route_type parameters can be modified as per user preference + #multipath, start_value, step_value and route_type, port_speed parameters can be modified as per user preference run_RIB_IN_capacity_test(cvg_api, duthost, tgen_ports, diff --git a/tests/snappi/bgp/test_bgp_rib_in_convergence.py b/tests/snappi/bgp/test_bgp_rib_in_convergence.py index 36bd85d6544..c6f71c114ae 100644 --- a/tests/snappi/bgp/test_bgp_rib_in_convergence.py +++ b/tests/snappi/bgp/test_bgp_rib_in_convergence.py @@ -54,7 +54,7 @@ def test_rib_in_convergence(cvg_api, route_type: IPv4 or IPv6 routes port_speed: speed of the port used for test """ - #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference + #convergence_test_iterations, multipath, number_of_routes port_speed and route_type parameters can be modified as per user preference run_rib_in_convergence_test(cvg_api, duthost, tgen_ports, From bcf739d9bc06d3b2df188a8bc92c1a204b94aee0 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 8 Dec 2021 16:57:25 +0000 Subject: [PATCH 48/58] resolving alert --- tests/snappi/bgp/files/bgp_convergence_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 958bc1df37d..d43c4059f22 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -846,5 +846,5 @@ def cleanup_config(duthost): duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json","/etc/sonic/config_db.json")) duthost.shell("sudo config reload -y \n") logger.info("Wait until all critical services are fully started") - pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") + pytest_assert(wait_until(360, 10, 1, duthost.critical_services_fully_started), "Not all critical services are fully started") logger.info('Convergence Test Completed') \ No newline at end of file From 189496065762d5ae682c9f7df66c24d4b07b9c47 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 8 Dec 2021 17:16:38 +0000 Subject: [PATCH 49/58] adding __init__.py --- tests/snappi/bgp/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/snappi/bgp/__init__.py diff --git a/tests/snappi/bgp/__init__.py b/tests/snappi/bgp/__init__.py new file mode 100644 index 00000000000..e69de29bb2d From 75fa26dcea180e89fa54fd750ec1616406c70475 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Thu, 9 Dec 2021 05:08:20 +0000 Subject: [PATCH 50/58] modified rib-in capacity case --- .../bgp/files/bgp_convergence_helper.py | 77 +++++++++++++------ 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index d43c4059f22..00ccc6de056 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -799,42 +799,71 @@ def create_v6_topo(): return conv_config + def run_traffic(routes): + logger.info('|-------------------- RIB-IN Capacity test, No.of Routes : {} ----|'.format(routes)) + conv_config = tgen_capacity(routes) + cvg_api.set_config(conv_config) + + """ Starting Traffic """ + logger.info('Starting Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Traffic To start") + try: for j in range(start_value, 100000000000, step_value): tx_frate, rx_frate = [], [] - logger.info('|-------------------- RIB-IN Capacity test, No.of Routes : {} ----|'.format(j)) - conv_config = tgen_capacity(j) - cvg_api.set_config(conv_config) - - """ Starting Traffic """ - logger.info('Starting Traffic') - cs = cvg_api.convergence_state() - cs.transmit.state = cs.transmit.START - cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To start") + run_traffic(j) flow_stats = get_flow_stats(cvg_api) logger.info('Loss% : {}'.format(flow_stats[0].loss)) - flows = get_flow_stats(cvg_api) - for flow in flows: + for flow in flow_stats: tx_frate.append(flow.frames_tx_rate) rx_frate.append(flow.frames_rx_rate) - if sum(tx_frate) != sum(rx_frate): - raise Exception('Tx Frame rate not equal to Rx Frame rate for {} routes'.format(j)) - else: + logger.info("Tx Frame Rate : {}".format(tx_frate)) + logger.info("Rx Frame Rate : {}".format(rx_frate)) + if float(flow_stats[0].loss) > 0.001: + if j == start_value: + raise Exception('Traffic Loss Encountered in first iteration, reduce the start value and run the test') + logger.info('Loss greater than 0.001 occured') + logger.info('Reducing the routes and running test') + b = j-step_value logger.info('Stopping Traffic') cs = cvg_api.convergence_state() cs.transmit.state = cs.transmit.STOP cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To stop") - except: - if start_value == j: - max_routes = 'N/A' - raise Exception('Set the start_value less than : {} !!!!!!!!!!!!'.format(start_value)) - else: - max_routes = j-step_value - logger.info('max_routes :{}'.format(max_routes)) + wait(TIMEOUT-20, "For Traffic To stop") + break + logger.info('Stopping Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.STOP + cvg_api.set_state(cs) + wait(TIMEOUT-20, "For Traffic To stop") + l = [] + l.append(b+int(step_value/8)) + l.append(b+int(step_value/4)) + l.append(b+int(step_value/2)) + l.append(b+step_value-int(step_value/4)) + l.append(b+step_value-int(step_value/8)) + for i in range(0,len(l)): + run_traffic(l[i]) + flow_stats = get_flow_stats(cvg_api) + logger.info('Loss% : {}'.format(flow_stats[0].loss)) + if float(flow_stats[0].loss) <= 0.001: + pass + else: + max_routes = l[i]-int(step_value/8) + break + logger.info('Stopping Traffic') + cs = cvg_api.convergence_state() + cs.transmit.state = cs.transmit.STOP + cvg_api.set_state(cs) + wait(TIMEOUT-20, "For Traffic To stop") + except Exception as e: + logger.info(e) finally: - logger.info('|------------ Max Routes without loss (RIB-IN Capacity Value) : {} ----|'.format(max_routes)) + columns = ['Test Name', 'Maximum no. of Routes'] + logger.info("\n%s" % tabulate([['RIB-IN Capacity Test',max_routes]], headers=columns, tablefmt="psql")) def cleanup_config(duthost): """ From 78e0c7e8ef5bec50e9f1f3b5e1fdd180c44dd34b Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 15 Dec 2021 21:16:16 +0000 Subject: [PATCH 51/58] adding delta frames --- .../bgp/files/bgp_convergence_helper.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 00ccc6de056..40ebf81765c 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -403,7 +403,6 @@ def create_v6_topo(): flow.metrics.enable = True return conv_config - def get_flow_stats(cvg_api): """ Args: @@ -413,7 +412,6 @@ def get_flow_stats(cvg_api): request.metrics.flow_names = [] return cvg_api.get_results(request).flow_metric - def get_convergence_for_local_link_failover(cvg_api, bgp_config, iteration, @@ -440,7 +438,7 @@ def get_avg_dpdp_convergence_time(port_name): port_name: Name of the port """ - table, avg, tx_frate, rx_frate = [], [], [], [] + table, avg, tx_frate, rx_frate, avg_delta = [], [], [], [], [] for i in range(0, iteration): logger.info('|---- {} Link Flap Iteration : {} ----|'.format(port_name, i+1)) @@ -453,7 +451,6 @@ def get_avg_dpdp_convergence_time(port_name): flow_stats = get_flow_stats(cvg_api) tx_frame_rate = flow_stats[0].frames_tx_rate assert tx_frame_rate != 0, "Traffic has not started" - """ Flapping Link """ logger.info('Simulating Link Failure on {} link'.format(port_name)) cs = cvg_api.convergence_state() @@ -474,7 +471,7 @@ def get_avg_dpdp_convergence_time(port_name): for metrics in convergence_metrics: logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) - + avg_delta.append(int(flows[0].frames_tx)-int(flows[0].frames_rx)) """ Performing link up at the end of iteration """ logger.info('Simulating Link Up on {} at the end of iteration {}'.format(port_name, i+1)) cs = cvg_api.convergence_state() @@ -485,13 +482,14 @@ def get_avg_dpdp_convergence_time(port_name): table.append(route_type) table.append(number_of_routes) table.append(iteration) + table.append(mean(avg_delta)) table.append(mean(avg)) return table table = [] """ Iterating link flap test on all the rx ports """ for i, port_name in enumerate(rx_port_names): table.append(get_avg_dpdp_convergence_time(port_name)) - columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Calculated Data Convergence Time (ms)'] + columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Delta Frames', 'Avg Calculated Data Convergence Time (ms)'] logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) @@ -529,7 +527,7 @@ def get_avg_cpdp_convergence_time(route_name): route_name: name of the route """ - table, avg, tx_frate, rx_frate = [], [], [], [] + table, avg, tx_frate, rx_frate, avg_delta = [], [], [], [], [] for i in range(0, iteration): logger.info('|---- {} Route Withdraw Iteration : {} ----|'.format(route_name, i+1)) @@ -564,6 +562,7 @@ def get_avg_cpdp_convergence_time(route_name): for metrics in convergence_metrics: logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) + avg_delta.append(int(flows[0].frames_tx)-int(flows[0].frames_rx)) """ Advertise the routes back at the end of iteration """ cs = cvg_api.convergence_state() cs.route.names = [route_name] @@ -575,6 +574,7 @@ def get_avg_cpdp_convergence_time(route_name): table.append(route_type) table.append(number_of_routes) table.append(iteration) + table.append(mean(avg_delta)) table.append(mean(avg)) return table table = [] @@ -582,7 +582,7 @@ def get_avg_cpdp_convergence_time(route_name): for route in route_names: table.append(get_avg_cpdp_convergence_time(route)) - columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Avg Control to Data Plane Convergence Time (ms)'] + columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Frames Delta', 'Avg Control to Data Plane Convergence Time (ms)'] logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql")) @@ -613,7 +613,7 @@ def get_rib_in_convergence(cvg_api, bgp_config.rx_rate_threshold = 90/(multipath) cvg_api.set_config(bgp_config) - table, avg, tx_frate, rx_frate = [], [], [], [] + table, avg, tx_frate, rx_frate, avg_delta = [], [], [], [], [] for i in range(0, iteration): logger.info('|---- RIB-IN Convergence test, Iteration : {} ----|'.format(i+1)) """ withdraw all routes before starting traffic """ @@ -657,7 +657,7 @@ def get_rib_in_convergence(cvg_api, for metrics in convergence_metrics: logger.info('RIB-IN Convergence time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000)) avg.append(int(metrics.control_plane_data_plane_convergence_us/1000)) - + avg_delta.append(int(flows[0].frames_tx)-int(flows[0].frames_rx)) """ Stop traffic at the end of iteration """ logger.info('Stopping Traffic at the end of iteration{}'.format(i+1)) cs = cvg_api.convergence_state() @@ -668,8 +668,9 @@ def get_rib_in_convergence(cvg_api, table.append(route_type) table.append(number_of_routes) table.append(iteration) + table.append(mean(avg_delta)) table.append(mean(avg)) - columns = ['Event Name', 'Route Type', 'No. of Routes','Iterations', 'Avg RIB-IN Convergence Time(ms)'] + columns = ['Event Name', 'Route Type', 'No. of Routes','Iterations', 'Frames Delta', 'Avg RIB-IN Convergence Time(ms)'] logger.info("\n%s" % tabulate([table], headers=columns, tablefmt="psql")) @@ -706,7 +707,6 @@ def tgen_capacity(routes): lp.ethernet.mac = "00:10:01:00:00:%s" % m config.devices.device(name='Topology %d' % i) config.devices[i-1].container_name = c_lag.name - #config.devices[i-1].container_name = config.ports[i-1].name config.options.port_options.location_preemption = True layer1 = config.layer1.layer1()[-1] From d86b7eb97836de19cd2ffc6008fec7151f43b388 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 5 Jan 2022 20:31:53 +0000 Subject: [PATCH 52/58] added test comment --- tests/snappi/bgp/files/bgp_convergence_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 40ebf81765c..92a126073d2 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -3,7 +3,7 @@ from tests.common.utilities import (wait, wait_until) from tests.common.helpers.assertions import pytest_assert logger = logging.getLogger(__name__) - +#test TGEN_AS_NUM = 65200 DUT_AS_NUM = 65100 TIMEOUT = 30 From bb2fe32714e1f44a690ef5d1cb2e993c7f63d348 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 5 Jan 2022 21:20:03 +0000 Subject: [PATCH 53/58] removed comment --- tests/snappi/bgp/files/bgp_convergence_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 92a126073d2..40ebf81765c 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -3,7 +3,7 @@ from tests.common.utilities import (wait, wait_until) from tests.common.helpers.assertions import pytest_assert logger = logging.getLogger(__name__) -#test + TGEN_AS_NUM = 65200 DUT_AS_NUM = 65100 TIMEOUT = 30 From 89ece91edcad5da38cfb5c81acc11c74657aeb88 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Tue, 8 Feb 2022 17:01:09 +0000 Subject: [PATCH 54/58] modified for snappi 0.7.12 version --- .../bgp/files/bgp_convergence_helper.py | 241 +++++++++++------- 1 file changed, 145 insertions(+), 96 deletions(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 40ebf81765c..ae8802d99d4 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -9,6 +9,7 @@ TIMEOUT = 30 BGP_TYPE = 'ebgp' temp_tg_port=dict() +NG_LIST = [] def run_bgp_local_link_failover_test(cvg_api, duthost, @@ -297,6 +298,7 @@ def __tgen_bgp_config(cvg_api, route_type: IPv4 or IPv6 routes port_speed: speed of the port used for test """ + global NG_LIST conv_config = cvg_api.convergence_config() config = conv_config.config for i in range(1, port_count+1): @@ -312,7 +314,6 @@ def __tgen_bgp_config(cvg_api, lp.ethernet.name = "lag_Ethernet %s" % i lp.ethernet.mac = "00:10:01:00:00:%s" % m config.devices.device(name='Topology %d' % i) - config.devices[i-1].container_name = c_lag.name config.options.port_options.location_preemption = True layer1 = config.layer1.layer1()[-1] @@ -325,66 +326,84 @@ def __tgen_bgp_config(cvg_api, layer1.auto_negotiate = False def create_v4_topo(): - config.devices[0].ethernet.name = 'Ethernet 1' - config.devices[0].ethernet.mac = "00:00:00:00:00:01" - config.devices[0].ethernet.ipv4.name = 'IPv4 1' - config.devices[0].ethernet.ipv4.address = temp_tg_port[0]['ip'] - config.devices[0].ethernet.ipv4.gateway = temp_tg_port[0]['peer_ip'] - config.devices[0].ethernet.ipv4.prefix = int(temp_tg_port[0]['prefix']) + eth = config.devices[0].ethernets.add() + eth.port_name = config.lags[0].name + eth.name = 'Ethernet 1' + eth.mac = "00:00:00:00:00:01" + ipv4 = eth.ipv4_addresses.add() + ipv4.name = 'IPv4 1' + ipv4.address = temp_tg_port[0]['ip'] + ipv4.gateway = temp_tg_port[0]['peer_ip'] + ipv4.prefix = int(temp_tg_port[0]['prefix']) rx_flow_name = [] for i in range(2, port_count+1): + NG_LIST.append('Network_Group%s'%i) if len(str(hex(i).split('0x')[1])) == 1: m = '0'+hex(i).split('0x')[1] else: m = hex(i).split('0x')[1] - ethernet_stack = config.devices[i-1].ethernet + + ethernet_stack = config.devices[i-1].ethernets.add() + ethernet_stack.port_name = config.lags[i-1].name ethernet_stack.name = 'Ethernet %d' % i ethernet_stack.mac = "00:00:00:00:00:%s" % m - ipv4_stack = ethernet_stack.ipv4 + ipv4_stack = ethernet_stack.ipv4_addresses.add() ipv4_stack.name = 'IPv4 %d' % i ipv4_stack.address = temp_tg_port[i-1]['ip'] ipv4_stack.gateway = temp_tg_port[i-1]['peer_ip'] ipv4_stack.prefix = int(temp_tg_port[i-1]['prefix']) - bgpv4_stack = ipv4_stack.bgpv4 - bgpv4_stack.name = 'BGP %d' % i - bgpv4_stack.as_type = BGP_TYPE - bgpv4_stack.dut_address = temp_tg_port[i-1]['peer_ip'] - bgpv4_stack.local_address = temp_tg_port[i-1]['ip'] - bgpv4_stack.as_number = int(TGEN_AS_NUM) - route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group %d" % i)[-1] - route_range.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=number_of_routes) + bgpv4 = config.devices[i-1].bgp + bgpv4.router_id = temp_tg_port[i-1]['peer_ip'] + bgpv4_int = bgpv4.ipv4_interfaces.add() + bgpv4_int.ipv4_name = ipv4_stack.name + bgpv4_peer = bgpv4_int.peers.add() + bgpv4_peer.name = 'BGP %d' % i + bgpv4_peer.as_type = BGP_TYPE + bgpv4_peer.peer_address = temp_tg_port[i-1]['peer_ip'] + bgpv4_peer.as_number = int(TGEN_AS_NUM) + route_range = bgpv4_peer.v4_routes.add(name=NG_LIST[-1]) #snappi object named Network Group 2 not found in internal db + route_range.addresses.add(address='200.1.0.1', prefix=32, count=number_of_routes) rx_flow_name.append(route_range.name) return rx_flow_name def create_v6_topo(): - config.devices[0].ethernet.name = 'Ethernet 1' - config.devices[0].ethernet.mac = "00:00:00:00:00:01" - config.devices[0].ethernet.ipv6.name = 'IPv6 1' - config.devices[0].ethernet.ipv6.address = temp_tg_port[0]['ipv6'] - config.devices[0].ethernet.ipv6.gateway = temp_tg_port[0]['peer_ipv6'] - config.devices[0].ethernet.ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix']) + eth = config.devices[0].ethernets.add() + eth.port_name = config.lags[0].name + eth.name = 'Ethernet 1' + eth.mac = "00:00:00:00:00:01" + ipv6 = eth.ipv6_addresses.add() + ipv6.name = 'IPv6 1' + ipv6.address = temp_tg_port[0]['ipv6'] + ipv6.gateway = temp_tg_port[0]['peer_ipv6'] + ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix']) rx_flow_name = [] for i in range(2, port_count+1): + NG_LIST.append('Network_Group%s'%i) if len(str(hex(i).split('0x')[1])) == 1: m = '0'+hex(i).split('0x')[1] else: m = hex(i).split('0x')[1] - ethernet_stack = config.devices[i-1].ethernet + ethernet_stack = config.devices[i-1].ethernets.add() + ethernet_stack.port_name = config.lags[i-1].name ethernet_stack.name = 'Ethernet %d' % i ethernet_stack.mac = "00:00:00:00:00:%s" % m - ipv6_stack = ethernet_stack.ipv6 + ipv6_stack = ethernet_stack.ipv6_addresses.add() ipv6_stack.name = 'IPv6 %d' % i ipv6_stack.address = temp_tg_port[i-1]['ipv6'] ipv6_stack.gateway = temp_tg_port[i-1]['peer_ipv6'] ipv6_stack.prefix = int(temp_tg_port[i-1]['ipv6_prefix']) - bgpv6_stack = ipv6_stack.bgpv6 - bgpv6_stack.name = r'BGP+ %d' % i - bgpv6_stack.as_type = BGP_TYPE - bgpv6_stack.dut_address = temp_tg_port[i-1]['peer_ipv6'] - bgpv6_stack.local_address = temp_tg_port[i-1]['ipv6'] - bgpv6_stack.as_number = int(TGEN_AS_NUM) - route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group %d" % i)[-1] - route_range.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=number_of_routes) + + bgpv6 = config.devices[i-1].bgp + bgpv6.router_id = temp_tg_port[i-1]['peer_ip'] + bgpv6_int = bgpv6.ipv6_interfaces.add() + bgpv6_int.ipv6_name = ipv6_stack.name + bgpv6_peer = bgpv6_int.peers.add() + bgpv6_peer.name = 'BGP+_%d' % i + bgpv6_peer.as_type = BGP_TYPE + bgpv6_peer.peer_address = temp_tg_port[i-1]['peer_ipv6'] + bgpv6_peer.as_number = int(TGEN_AS_NUM) + route_range = bgpv6_peer.v6_routes.add(name=NG_LIST[-1]) + route_range.addresses.add(address='3000::1', prefix=64, count=number_of_routes) rx_flow_name.append(route_range.name) return rx_flow_name @@ -432,6 +451,14 @@ def get_convergence_for_local_link_failover(cvg_api, rx_port_names.append(bgp_config.config.ports[i].name) bgp_config.rx_rate_threshold = 90/(multipath-1) cvg_api.set_config(bgp_config) + + """ Starting Protocols """ + logger.info("Starting all protocols ...") + cs = cvg_api.convergence_state() + cs.protocol.state = cs.protocol.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Protocols To start") + def get_avg_dpdp_convergence_time(port_name): """ Args: @@ -508,19 +535,9 @@ def get_convergence_for_remote_link_failover(cvg_api, number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes """ - route_names = [] - for device in bgp_config.config.devices: - if device.name not in ['Topology 1']: - if route_type == 'IPv4': - for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: - route_names.append(route.name) - else: - for route in device.ethernet.ipv6.bgpv6.bgpv6_routes: - route_names.append(route.name) + route_names = NG_LIST bgp_config.rx_rate_threshold = 90/(multipath-1) cvg_api.set_config(bgp_config) - - def get_avg_cpdp_convergence_time(route_name): """ Args: @@ -528,9 +545,14 @@ def get_avg_cpdp_convergence_time(route_name): """ table, avg, tx_frate, rx_frate, avg_delta = [], [], [], [], [] + """ Starting Protocols """ + logger.info("Starting all protocols ...") + cs = cvg_api.convergence_state() + cs.protocol.state = cs.protocol.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Protocols To start") for i in range(0, iteration): logger.info('|---- {} Route Withdraw Iteration : {} ----|'.format(route_name, i+1)) - """ Starting Traffic """ logger.info('Starting Traffic') cs = cvg_api.convergence_state() @@ -601,18 +623,9 @@ def get_rib_in_convergence(cvg_api, number_of_routes: Number of IPv4/IPv6 Routes route_type: IPv4 or IPv6 routes """ - route_names = [] - for device in bgp_config.config.devices: - if device.name not in ['Topology 1']: - if route_type == 'IPv4': - for route in device.ethernet.ipv4.bgpv4.bgpv4_routes: - route_names.append(route.name) - else: - for route in device.ethernet.ipv6.bgpv6.bgpv6_routes: - route_names.append(route.name) + route_names = NG_LIST bgp_config.rx_rate_threshold = 90/(multipath) cvg_api.set_config(bgp_config) - table, avg, tx_frate, rx_frate, avg_delta = [], [], [], [], [] for i in range(0, iteration): logger.info('|---- RIB-IN Convergence test, Iteration : {} ----|'.format(i+1)) @@ -622,8 +635,13 @@ def get_rib_in_convergence(cvg_api, cs.route.names = route_names cs.route.state = cs.route.WITHDRAW cvg_api.set_state(cs) - wait(TIMEOUT, "For Routes to be withdrawn") - + wait(TIMEOUT-25, "For Routes to be withdrawn") + """ Starting Protocols """ + logger.info("Starting all protocols ...") + cs = cvg_api.convergence_state() + cs.protocol.state = cs.protocol.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Protocols To start") """ Start Traffic """ logger.info('Starting Traffic') cs = cvg_api.convergence_state() @@ -642,7 +660,7 @@ def get_rib_in_convergence(cvg_api, cs.route.names = route_names cs.route.state = cs.route.ADVERTISE cvg_api.set_state(cs) - wait(TIMEOUT, "For all routes to be ADVERTISED") + wait(TIMEOUT-25, "For all routes to be ADVERTISED") flows = get_flow_stats(cvg_api) for flow in flows: tx_frate.append(flow.frames_tx_rate) @@ -663,7 +681,13 @@ def get_rib_in_convergence(cvg_api, cs = cvg_api.convergence_state() cs.transmit.state = cs.transmit.STOP cvg_api.set_state(cs) - wait(TIMEOUT, "For Traffic To stop") + wait(TIMEOUT-20, "For Traffic To stop") + """ Stopping Protocols """ + logger.info("Stopping all protocols ...") + cs = cvg_api.convergence_state() + cs.protocol.state = cs.protocol.STOP + cvg_api.set_state(cs) + wait(TIMEOUT-20, "For Protocols To STOP") table.append('Advertise All BGP Routes') table.append(route_type) table.append(number_of_routes) @@ -706,7 +730,6 @@ def tgen_capacity(routes): lp.ethernet.name = "lag_Ethernet %s" % i lp.ethernet.mac = "00:10:01:00:00:%s" % m config.devices.device(name='Topology %d' % i) - config.devices[i-1].container_name = c_lag.name config.options.port_options.location_preemption = True layer1 = config.layer1.layer1()[-1] @@ -719,66 +742,81 @@ def tgen_capacity(routes): layer1.auto_negotiate = False def create_v4_topo(): - config.devices[0].ethernet.name = 'Ethernet 1_%d' % routes - config.devices[0].ethernet.mac = "00:00:00:00:00:01" - config.devices[0].ethernet.ipv4.name = 'IPv4 1_%d' % routes - config.devices[0].ethernet.ipv4.address = temp_tg_port[0]['ip'] - config.devices[0].ethernet.ipv4.gateway = temp_tg_port[0]['peer_ip'] - config.devices[0].ethernet.ipv4.prefix = int(temp_tg_port[0]['prefix']) + eth = config.devices[0].ethernets.add() + eth.port_name = config.lags[0].name + eth.name = 'Ethernet 1' + eth.mac = "00:00:00:00:00:01" + ipv4 = eth.ipv4_addresses.add() + ipv4.name = 'IPv4 1' + ipv4.address = temp_tg_port[0]['ip'] + ipv4.gateway = temp_tg_port[0]['peer_ip'] + ipv4.prefix = int(temp_tg_port[0]['prefix']) rx_flow_name = [] for i in range(2, 3): if len(str(hex(i).split('0x')[1])) == 1: m = '0'+hex(i).split('0x')[1] else: m = hex(i).split('0x')[1] - ethernet_stack = config.devices[i-1].ethernet - ethernet_stack.name = 'Ethernet_%d_%d' % (i, routes) + ethernet_stack = config.devices[i-1].ethernets.add() + ethernet_stack.port_name = config.lags[i-1].name + ethernet_stack.name = 'Ethernet %d' % i ethernet_stack.mac = "00:00:00:00:00:%s" % m - ipv4_stack = ethernet_stack.ipv4 - ipv4_stack.name = 'IPv4_%d_%d' % (i, routes) + ipv4_stack = ethernet_stack.ipv4_addresses.add() + ipv4_stack.name = 'IPv4 %d' % i ipv4_stack.address = temp_tg_port[i-1]['ip'] ipv4_stack.gateway = temp_tg_port[i-1]['peer_ip'] ipv4_stack.prefix = int(temp_tg_port[i-1]['prefix']) - bgpv4_stack = ipv4_stack.bgpv4 - bgpv4_stack.name = 'BGP_%d_%d' % (i, routes) - bgpv4_stack.as_type = BGP_TYPE - bgpv4_stack.dut_address = temp_tg_port[i-1]['peer_ip'] - bgpv4_stack.local_address = temp_tg_port[i-1]['ip'] - bgpv4_stack.as_number = int(TGEN_AS_NUM) - route_range = bgpv4_stack.bgpv4_routes.bgpv4route(name="Network Group %d_%d" % (i, routes))[-1] - route_range.addresses.bgpv4routeaddress(address='200.1.0.1', prefix=32, count=routes) + bgpv4 = config.devices[i-1].bgp + bgpv4.router_id = temp_tg_port[i-1]['peer_ip'] + bgpv4_int = bgpv4.ipv4_interfaces.add() + bgpv4_int.ipv4_name = ipv4_stack.name + bgpv4_peer = bgpv4_int.peers.add() + bgpv4_peer.name = 'BGP %d' % i + bgpv4_peer.as_type = BGP_TYPE + bgpv4_peer.peer_address = temp_tg_port[i-1]['peer_ip'] + bgpv4_peer.as_number = int(TGEN_AS_NUM) + route_range = bgpv4_peer.v4_routes.add(name="Network_Group%d" % i) #snappi object named Network Group 2 not found in internal db + route_range.addresses.add(address='200.1.0.1', prefix=32, count=number_of_routes) rx_flow_name.append(route_range.name) return rx_flow_name def create_v6_topo(): - config.devices[0].ethernet.name = 'Ethernet 1' - config.devices[0].ethernet.mac = "00:00:00:00:00:01" - config.devices[0].ethernet.ipv6.name = 'IPv6 1' - config.devices[0].ethernet.ipv6.address = temp_tg_port[0]['ipv6'] - config.devices[0].ethernet.ipv6.gateway = temp_tg_port[0]['peer_ipv6'] - config.devices[0].ethernet.ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix']) + eth = config.devices[0].ethernets.add() + eth.port_name = config.lags[0].name + eth.name = 'Ethernet 1' + eth.mac = "00:00:00:00:00:01" + ipv6 = eth.ipv6_addresses.add() + ipv6.name = 'IPv6 1' + ipv6.address = temp_tg_port[0]['ipv6'] + ipv6.gateway = temp_tg_port[0]['peer_ipv6'] + ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix']) rx_flow_name = [] for i in range(2, 3): if len(str(hex(i).split('0x')[1])) == 1: m = '0'+hex(i).split('0x')[1] else: m = hex(i).split('0x')[1] - ethernet_stack = config.devices[i-1].ethernet + ethernet_stack = config.devices[i-1].ethernets.add() + ethernet_stack.port_name = config.lags[i-1].name ethernet_stack.name = 'Ethernet %d' % i ethernet_stack.mac = "00:00:00:00:00:%s" % m - ipv6_stack = ethernet_stack.ipv6 + ipv6_stack = ethernet_stack.ipv6_addresses.add() ipv6_stack.name = 'IPv6 %d' % i ipv6_stack.address = temp_tg_port[i-1]['ipv6'] ipv6_stack.gateway = temp_tg_port[i-1]['peer_ipv6'] ipv6_stack.prefix = int(temp_tg_port[i-1]['ipv6_prefix']) - bgpv6_stack = ipv6_stack.bgpv6 - bgpv6_stack.name = r'BGP+ %d' % i - bgpv6_stack.as_type = BGP_TYPE - bgpv6_stack.dut_address = temp_tg_port[i-1]['peer_ipv6'] - bgpv6_stack.local_address = temp_tg_port[i-1]['ipv6'] - bgpv6_stack.as_number = int(TGEN_AS_NUM) - route_range = bgpv6_stack.bgpv6_routes.bgpv6route(name="Network Group %d_%d" % (routes, i))[-1] - route_range.addresses.bgpv6routeaddress(address='3000::1', prefix=64, count=routes) + + bgpv6 = config.devices[i-1].bgp + bgpv6.router_id = temp_tg_port[i-1]['peer_ip'] + bgpv6_int = bgpv6.ipv6_interfaces.add() + bgpv6_int.ipv6_name = ipv6_stack.name + bgpv6_peer = bgpv6_int.peers.add() + bgpv6_peer.name = 'BGP+_%d' % i + bgpv6_peer.as_type = BGP_TYPE + bgpv6_peer.peer_address = temp_tg_port[i-1]['peer_ipv6'] + bgpv6_peer.as_number = int(TGEN_AS_NUM) + route_range = bgpv6_peer.v6_routes.add(name="Network Group %d" % i) + route_range.addresses.add(address='3000::1', prefix=64, count=number_of_routes) rx_flow_name.append(route_range.name) return rx_flow_name conv_config.rx_rate_threshold = 90/(multipath) @@ -798,12 +836,16 @@ def create_v6_topo(): flow.metrics.loss = True return conv_config - def run_traffic(routes): logger.info('|-------------------- RIB-IN Capacity test, No.of Routes : {} ----|'.format(routes)) conv_config = tgen_capacity(routes) cvg_api.set_config(conv_config) - + """ Starting Protocols """ + logger.info("Starting all protocols ...") + cs = cvg_api.convergence_state() + cs.protocol.state = cs.protocol.START + cvg_api.set_state(cs) + wait(TIMEOUT, "For Protocols To start") """ Starting Traffic """ logger.info('Starting Traffic') cs = cvg_api.convergence_state() @@ -850,6 +892,7 @@ def run_traffic(routes): flow_stats = get_flow_stats(cvg_api) logger.info('Loss% : {}'.format(flow_stats[0].loss)) if float(flow_stats[0].loss) <= 0.001: + max_routes = start_value pass else: max_routes = l[i]-int(step_value/8) @@ -859,6 +902,12 @@ def run_traffic(routes): cs.transmit.state = cs.transmit.STOP cvg_api.set_state(cs) wait(TIMEOUT-20, "For Traffic To stop") + """ Stopping Protocols """ + logger.info("Stopping all protocols ...") + cs = cvg_api.convergence_state() + cs.protocol.state = cs.protocol.STOP + cvg_api.set_state(cs) + wait(TIMEOUT-20, "For Protocols To STOP") except Exception as e: logger.info(e) finally: From c3ac9dec0057aa47b6f88c664d4cbda76918fc8b Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 11 Feb 2022 21:48:53 +0000 Subject: [PATCH 55/58] As-Path additions --- .../snappi/bgp/files/bgp_convergence_helper.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index ae8802d99d4..e5152d8b1ab 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -10,6 +10,7 @@ BGP_TYPE = 'ebgp' temp_tg_port=dict() NG_LIST = [] +aspaths = [65002, 65003] def run_bgp_local_link_failover_test(cvg_api, duthost, @@ -363,6 +364,10 @@ def create_v4_topo(): bgpv4_peer.as_number = int(TGEN_AS_NUM) route_range = bgpv4_peer.v4_routes.add(name=NG_LIST[-1]) #snappi object named Network Group 2 not found in internal db route_range.addresses.add(address='200.1.0.1', prefix=32, count=number_of_routes) + as_path = route_range.as_path + as_path_segment = as_path.segments.add() + as_path_segment.type = as_path_segment.AS_SEQ + as_path_segment.as_numbers = aspaths rx_flow_name.append(route_range.name) return rx_flow_name @@ -404,6 +409,10 @@ def create_v6_topo(): bgpv6_peer.as_number = int(TGEN_AS_NUM) route_range = bgpv6_peer.v6_routes.add(name=NG_LIST[-1]) route_range.addresses.add(address='3000::1', prefix=64, count=number_of_routes) + as_path = route_range.as_path + as_path_segment = as_path.segments.add() + as_path_segment.type = as_path_segment.AS_SEQ + as_path_segment.as_numbers = aspaths rx_flow_name.append(route_range.name) return rx_flow_name @@ -777,6 +786,10 @@ def create_v4_topo(): bgpv4_peer.as_number = int(TGEN_AS_NUM) route_range = bgpv4_peer.v4_routes.add(name="Network_Group%d" % i) #snappi object named Network Group 2 not found in internal db route_range.addresses.add(address='200.1.0.1', prefix=32, count=number_of_routes) + as_path = route_range.as_path + as_path_segment = as_path.segments.add() + as_path_segment.type = as_path_segment.AS_SEQ + as_path_segment.as_numbers = aspaths rx_flow_name.append(route_range.name) return rx_flow_name @@ -817,6 +830,10 @@ def create_v6_topo(): bgpv6_peer.as_number = int(TGEN_AS_NUM) route_range = bgpv6_peer.v6_routes.add(name="Network Group %d" % i) route_range.addresses.add(address='3000::1', prefix=64, count=number_of_routes) + as_path = route_range.as_path + as_path_segment = as_path.segments.add() + as_path_segment.type = as_path_segment.AS_SEQ + as_path_segment.as_numbers = aspaths rx_flow_name.append(route_range.name) return rx_flow_name conv_config.rx_rate_threshold = 90/(multipath) From 326464ef47e33f0c2a78721e88fd01f19ab44386 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Fri, 11 Feb 2022 22:14:43 +0000 Subject: [PATCH 56/58] snappi fixture modification --- tests/common/snappi/snappi_fixtures.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/tests/common/snappi/snappi_fixtures.py b/tests/common/snappi/snappi_fixtures.py index 0092e54ba38..477e1b7f7c4 100644 --- a/tests/common/snappi/snappi_fixtures.py +++ b/tests/common/snappi/snappi_fixtures.py @@ -13,7 +13,6 @@ from tests.common.snappi.port import SnappiPortConfig, SnappiPortType from tests.common.helpers.assertions import pytest_assert - @pytest.fixture(scope="module") def snappi_api_serv_ip(tbinfo): """ @@ -474,29 +473,26 @@ def tgen_ports(duthost, config_facts = duthost.config_facts(host=duthost.hostname, source="running")['ansible_facts'] - for port in snappi_ports: port['location'] = get_snappi_port_location(port) port['speed'] = speed_type[port['speed']] - - for port in snappi_ports: - peer_port = port['peer_port'] - int_addrs = config_facts['INTERFACE'][peer_port].keys() - try: + try: + for port in snappi_ports: + peer_port = port['peer_port'] + int_addrs = config_facts['INTERFACE'][peer_port].keys() ipv4_subnet = [ele for ele in int_addrs if "." in ele][0] if not ipv4_subnet: - raise Exception("IPv4 is not configured on the interface {}" - .format(peer_port)) + raise Exception("IPv4 is not configured on the interface {}".format(peer_port)) port['peer_ip'], port['prefix'] = ipv4_subnet.split("/") port['ip'] = get_addrs_in_subnet(ipv4_subnet, 1)[0] ipv6_subnet = [ele for ele in int_addrs if ":" in ele][0] if not ipv6_subnet: - raise Exception("IPv6 is not configured on the interface {}" - .format(peer_port)) + raise Exception("IPv6 is not configured on the interface {}".format(peer_port)) port['peer_ipv6'], port['ipv6_prefix'] = ipv6_subnet.split("/") port['ipv6'] = get_ipv6_addrs_in_subnet(ipv6_subnet, 1)[0] - except: - raise Exception('Configure IPv4 and IPv6 on DUT interfaces') + except: + raise Exception('Configure IPv4 and IPv6 on DUT interfaces') + return snappi_ports @@ -506,4 +502,5 @@ def cvg_api(snappi_api_serv_ip, api = snappi_convergence.api(location=snappi_api_serv_ip + ':' + str(snappi_api_serv_port),ext='ixnetwork') yield api if getattr(api, 'assistant', None) is not None: - api.assistant.Session.remove() \ No newline at end of file + api.assistant.Session.remove() + \ No newline at end of file From a4ec6a5a54549eca5a045d8c5fc044cb7d6a56d4 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 2 Mar 2022 23:29:02 +0000 Subject: [PATCH 57/58] changing wait_until arguments --- tests/snappi/bgp/files/bgp_convergence_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index e5152d8b1ab..49bfb2f9c88 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -941,5 +941,5 @@ def cleanup_config(duthost): duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json","/etc/sonic/config_db.json")) duthost.shell("sudo config reload -y \n") logger.info("Wait until all critical services are fully started") - pytest_assert(wait_until(360, 10, 1, duthost.critical_services_fully_started), "Not all critical services are fully started") + pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") logger.info('Convergence Test Completed') \ No newline at end of file From 2a47fcfff45213856d6ac8f0def4dee461f044f2 Mon Sep 17 00:00:00 2001 From: selldinesh Date: Wed, 16 Mar 2022 18:36:19 +0000 Subject: [PATCH 58/58] changing the arguments for wait_until function call --- tests/snappi/bgp/files/bgp_convergence_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py index 49bfb2f9c88..e5152d8b1ab 100644 --- a/tests/snappi/bgp/files/bgp_convergence_helper.py +++ b/tests/snappi/bgp/files/bgp_convergence_helper.py @@ -941,5 +941,5 @@ def cleanup_config(duthost): duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json","/etc/sonic/config_db.json")) duthost.shell("sudo config reload -y \n") logger.info("Wait until all critical services are fully started") - pytest_assert(wait_until(360, 10, duthost.critical_services_fully_started), "Not all critical services are fully started") + pytest_assert(wait_until(360, 10, 1, duthost.critical_services_fully_started), "Not all critical services are fully started") logger.info('Convergence Test Completed') \ No newline at end of file