-
Notifications
You must be signed in to change notification settings - Fork 1k
VxLAN Automation: Adding all remaining testcases, and the required modifications. #5059
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
caad974
Adding all testcases, and the required modifications.
rraghav-cisco 962c002
Removed the skips.
rraghav-cisco 2c47f9d
Completed review comments.
rraghav-cisco 5528f35
Merge branch 'Azure:master' into rraghav-vxlan2
rraghav-cisco a7c803c
Final review comments, from Ihor Chekh, and roysr-nv
rraghav-cisco 85e3ffe
Merge branch 'rraghav-vxlan2' of https://github.com/rraghav-cisco/son…
rraghav-cisco 2c4d2f1
Adding calculated sleep after set or del routes, as per comment from …
rraghav-cisco a9f0aef
Adding back the supported topologies.
rraghav-cisco eb734fe
Merge branch 'Azure:master' into rraghav-vxlan2
rraghav-cisco 59ae8e1
Update the conditional skip criteria and revert the changes to get_et…
rraghav-cisco af025ec
Update the skip conditional.
rraghav-cisco 9432578
Restrict selected_interfaces to T0 facing only.
rraghav-cisco 9fb0a5c
Updating the traffic/ptf script to turn on ECN
rraghav-cisco f02fa5d
Merge branch 'Azure:master' into rraghav-vxlan2
rraghav-cisco 411bd24
Fixing bgp_established.
rraghav-cisco File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| # ptf --test-dir ptftests vxlan_traffic.VXLAN --platform-dir ptftests --qlen=1000 --platform remote \ | ||
| # -t 't2_ports=[16, 17, 0, 1, 4, 5, 21, 20];dut_mac=u"64:3a:ea:c1:73:f8";expect_encap_success=True; \ | ||
| # -t 't2_ports=[16, 17, 0, 1, 4, 5, 21, 20];dut_mac=u"64:3a:ea:c1:73:f8";expect_encap_success=True;packet_count=10; \ | ||
| # vxlan_port=4789;topo_file="/tmp/vxlan_topo_file.json";config_file="/tmp/vxlan-config-TC1-v6_in_v4.json";t0_ports=[u"Ethernet42"]' --relax --debug info \ | ||
| # --log-file /tmp/vxlan-tests.TC1.v6_in_v4.log | ||
|
|
||
|
|
@@ -17,26 +17,33 @@ | |
| import ptf.packet as scapy | ||
| from ptf.base_tests import BaseTest | ||
| from ptf import config | ||
| from ptf.testutils import * | ||
| from ptf.testutils import (simple_tcp_packet, simple_tcpv6_packet, simple_vxlan_packet, simple_vxlanv6_packet, | ||
| verify_packet_any_port, verify_no_packet_any, | ||
| send_packet, test_params_get) | ||
| from ptf.dataplane import match_exp_pkt | ||
| from ptf.mask import Mask | ||
| import datetime | ||
| import subprocess | ||
| import ipaddress | ||
| from pprint import pprint | ||
| import logging | ||
| from ipaddress import ip_address | ||
| import random | ||
|
|
||
| VARS = {} | ||
| VARS['tcp_sport'] = 1234 | ||
| VARS['tcp_dport'] = 5000 | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| # Some constants used in this code | ||
| TEST_ECN = False | ||
| MIN_PACKET_COUNT = 4 | ||
| MINIMUM_PACKETS_FOR_ECMP_VALIDATION = 300 | ||
| TEST_ECN = True | ||
|
|
||
| def get_incremental_value(key): | ||
|
|
||
| global VARS | ||
| VARS[key] = VARS[key] + 1 | ||
| # We would like to use the ports from 1234 to 65535 | ||
| VARS[key] = max(1234, (VARS[key] + 1) % 65535) | ||
| return VARS[key] | ||
|
|
||
| def read_ptf_macs(): | ||
|
|
@@ -59,6 +66,12 @@ def setUp(self): | |
| self.dut_mac = self.test_params['dut_mac'] | ||
| self.vxlan_port = self.test_params['vxlan_port'] | ||
| self.expect_encap_success = self.test_params['expect_encap_success'] | ||
| self.packet_count = self.test_params['packet_count'] | ||
| # The ECMP check fails occasionally if there is not enough packets. | ||
| # We should keep the packet count atleast MIN_PACKET_COUNT. | ||
| if self.packet_count < MIN_PACKET_COUNT: | ||
| logger.warning("Packet_count is below minimum, resetting to {}", MIN_PACKET_COUNT) | ||
| self.packet_count = MIN_PACKET_COUNT | ||
|
|
||
| self.random_mac = "00:aa:bb:cc:dd:ee" | ||
| self.ptf_mac_addrs = read_ptf_macs() | ||
rraghav-cisco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
@@ -122,6 +135,32 @@ def read_ptf_macs(self): | |
|
|
||
| return addrs | ||
|
|
||
| def verify_all_addresses_used_equally(self, nhs, returned_ip_addresses): | ||
| ''' | ||
| Verify the ECMP functionality using 2 checks. | ||
| Check 1 verifies every nexthop address has been used. | ||
| Check 2 verifies the distribution of number of packets among the nexthops. | ||
| Params: nhs: the nexthops that are configured. | ||
| returned_ip_addresses: The dict containing the nh addresses and corresponding packet counts. | ||
| ''' | ||
| # Check #1 : All addresses have been used. | ||
| if set(nhs) - set(returned_ip_addresses.keys()) == set([]): | ||
| logger.info(" Each address has been used") | ||
| logger.info("Packets sent:{} distribution:".format(self.packet_count)) | ||
| for nh_address in returned_ip_addresses.keys(): | ||
| logger.info(" {} : {}".format(nh_address, returned_ip_addresses[nh_address])) | ||
| # Check #2 : The packets are almost equally distributed. | ||
| # Every next-hop should have received within 1% of the packets that we sent per nexthop(which is self.packet_count). | ||
| # This check is valid only if there are large enough number of packets(300). Any lower number will need higher tolerance(more than 2%). | ||
| if self.packet_count > MINIMUM_PACKETS_FOR_ECMP_VALIDATION: | ||
| tolerance = 0.01 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rraghav-cisco please clarify what this 1% value is based on. Unfortunately I was not able to find it in feature requirement docs |
||
| for nh_address in returned_ip_addresses.keys(): | ||
| if (1.0-tolerance) * self.packet_count <= returned_ip_addresses[nh_address] <= (1.0+tolerance) * self.packet_count: | ||
| pass | ||
| else: | ||
| raise RuntimeError("ECMP nexthop address: {} received too less or too many of the " | ||
| "packets expected. Expected:{}, received on that address:{}".format(nh_address, self.packet_count, returned_ip_addresses[nh_address])) | ||
|
|
||
| def test_encap(self, ptf_port, vni, ptf_addr, destination, nhs, test_ecn=False, vlan=0): | ||
| rv = True | ||
| try: | ||
|
|
@@ -132,22 +171,21 @@ def test_encap(self, ptf_port, vni, ptf_addr, destination, nhs, test_ecn=False, | |
| else: | ||
| tagged = False | ||
|
|
||
|
|
||
| options = {'ip_tos' : 0} | ||
| options_v6 = {'ipv6_tc' : 0} | ||
| options = {'ip_ecn' : 0} | ||
| options_v6 = {'ipv6_ecn' : 0} | ||
| if test_ecn: | ||
| options = {'ip_tos' : random.randint(0, 3)} | ||
| options_v6 = {'ipv6_tos' : random.randint(0, 3)} | ||
| ecn = random.randint(0, 3) | ||
| options = {'ip_ecn' : ecn} | ||
| options_v6 = {'ipv6_ecn' : ecn} | ||
|
|
||
| # ECMP support, assume it is a string of comma seperated list of addresses. | ||
| returned_ip_addresses = {} | ||
| check_ecmp = False | ||
| for host_address in nhs: | ||
| check_ecmp = True | ||
| # This will ensure that every nh is used atleast once. | ||
| for i in range(4): | ||
| for i in range(self.packet_count): | ||
| tcp_sport = get_incremental_value('tcp_sport') | ||
rraghav-cisco marked this conversation as resolved.
Show resolved
Hide resolved
rraghav-cisco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| tcp_dport = 5000 | ||
| valid_combination = True | ||
| if isinstance(ip_address(destination), ipaddress.IPv4Address) and isinstance(ip_address(ptf_addr), ipaddress.IPv4Address): | ||
| pkt_opts = { | ||
|
|
@@ -159,7 +197,7 @@ def test_encap(self, ptf_port, vni, ptf_addr, destination, nhs, test_ecn=False, | |
| "ip_id":105, | ||
| "ip_ttl":64, | ||
| "tcp_sport":tcp_sport, | ||
| "tcp_dport":tcp_dport} | ||
| "tcp_dport":VARS['tcp_dport']} | ||
| pkt_opts.update(options) | ||
| pkt = simple_tcp_packet(**pkt_opts) | ||
| pkt_opts['ip_ttl'] = 63 | ||
|
|
@@ -174,16 +212,14 @@ def test_encap(self, ptf_port, vni, ptf_addr, destination, nhs, test_ecn=False, | |
| "ipv6_src":ptf_addr, | ||
| "ipv6_hlim":64, | ||
| "tcp_sport":tcp_sport, | ||
| "tcp_dport":tcp_dport} | ||
| "tcp_dport":VARS['tcp_dport']} | ||
| pkt_opts.update(options_v6) | ||
| pkt = simple_tcpv6_packet(**pkt_opts) | ||
| pkt_opts['ipv6_hlim'] = 63 | ||
| pkt_opts['eth_dst'] = self.dut_mac | ||
| pkt_opts['eth_src'] = self.dut_mac | ||
| exp_pkt = simple_tcpv6_packet(**pkt_opts) | ||
| else: | ||
| valid_combination = False | ||
| print("Unusable combination:src:{} and dst:{}".format(src, destination)) | ||
| udp_sport = 1234 # Use entropy_hash(pkt), it will be ignored in the test later. | ||
| udp_dport = self.vxlan_port | ||
| if isinstance(ip_address(host_address), ipaddress.IPv4Address): | ||
|
|
@@ -198,8 +234,9 @@ def test_encap(self, ptf_port, vni, ptf_addr, destination, nhs, test_ecn=False, | |
| udp_dport=udp_dport, | ||
| with_udp_chksum=False, | ||
| vxlan_vni=vni, | ||
| inner_frame=exp_pkt) | ||
| encap_pkt[IP].flags = 0x2 | ||
| inner_frame=exp_pkt, | ||
| **options) | ||
| encap_pkt[scapy.IP].flags = 0x2 | ||
| elif isinstance(ip_address(host_address), ipaddress.IPv6Address): | ||
| encap_pkt = simple_vxlanv6_packet( | ||
| eth_src=self.dut_mac, | ||
|
|
@@ -210,8 +247,9 @@ def test_encap(self, ptf_port, vni, ptf_addr, destination, nhs, test_ecn=False, | |
| udp_dport=udp_dport, | ||
| with_udp_chksum=False, | ||
| vxlan_vni=vni, | ||
| inner_frame=exp_pkt) | ||
| send_packet(self, ptf_port, str(pkt), count=2) | ||
| inner_frame=exp_pkt, | ||
| **options_v6) | ||
| send_packet(self, ptf_port, str(pkt)) | ||
|
|
||
| masked_exp_pkt = Mask(encap_pkt) | ||
| masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "src") | ||
|
|
@@ -227,11 +265,11 @@ def test_encap(self, ptf_port, vni, ptf_addr, destination, nhs, test_ecn=False, | |
| masked_exp_pkt.set_do_not_care_scapy(scapy.UDP, "sport") | ||
| masked_exp_pkt.set_do_not_care_scapy(scapy.UDP, "chksum") | ||
|
|
||
| logging.info("Sending packet from port " + str(ptf_port) + " to " + destination) | ||
| logger.info("Sending packet from port " + str(ptf_port) + " to " + destination) | ||
|
|
||
| if self.expect_encap_success: | ||
| status, received_pkt = verify_packet_any_port(self, masked_exp_pkt, self.t2_ports) | ||
| scapy_pkt = Ether(received_pkt) | ||
| _, received_pkt = verify_packet_any_port(self, masked_exp_pkt, self.t2_ports) | ||
| scapy_pkt = scapy.Ether(received_pkt) | ||
| # Store every destination that was received. | ||
| if isinstance(ip_address(host_address), ipaddress.IPv6Address): | ||
| dest_ip = scapy_pkt['IPv6'].dst | ||
|
|
@@ -244,20 +282,15 @@ def test_encap(self, ptf_port, vni, ptf_addr, destination, nhs, test_ecn=False, | |
|
|
||
| else: | ||
| check_ecmp = False | ||
| print ("Verifying no packet") | ||
| logger.info("Verifying no packet") | ||
| verify_no_packet_any(self, masked_exp_pkt, self.t2_ports) | ||
|
|
||
| # Verify ECMP: | ||
| if check_ecmp: | ||
| if set(nhs) - set(returned_ip_addresses.keys()) == set([]): | ||
| print ("Each address has been used") | ||
| else: | ||
| raise RuntimeError('''ECMP might have failed for:{}, we expected every ip address in the nexthop group({} of them) | ||
| to be used, but only {} are used:\nUsed addresses:{}\nUnused Addresses:{}'''.format(destination, | ||
| len(nhs), len(returned_ip_addresses.keys()), | ||
| returned_ip_addresses.keys(), set(nhs)-set(returned_ip_addresses.keys()))) | ||
| self.verify_all_addresses_used_equally(nhs, returned_ip_addresses) | ||
|
|
||
| pkt.load = '0' * 60 + str(len(self.packets)) | ||
| self.packets.append((ptf_port, str(pkt).encode("base64"))) | ||
|
|
||
| finally: | ||
| logger.info("") | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.