aboutsummaryrefslogtreecommitdiffstats
path: root/tests/vpp/perf/l2/10ge2p1x710-dot1ad-l2xcbase-ndrpdr.robot
blob: e3dba2f5e8bf1610c67f5a10e8c37b914f63ec02 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# Copyright (c) 2019 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

*** Settings ***
| Resource | resources/libraries/robot/shared/default.robot
| Resource | resources/libraries/robot/l2/tagging.robot
| ...
| Force Tags | 3_NODE_SINGLE_LINK_TOPO | PERFTEST | HW_ENV | NDRPDR
| ... | NIC_Intel-X710 | L2XCFWD | BASE | DOT1AD
| ...
| Suite Setup | Setup suite single link | performance
| Suite Teardown | Tear down suite | performance
| Test Setup | Setup test
| Test Teardown | Tear down test | performance
| ...
| Test Template | Local Template
| ...
| Documentation | *RFC2544: Pkt throughput L2XC with 802.1ad test cases*
| ...
| ... | *[Top] Network Topologies:* TG-DUT1-DUT2-TG 3-node circular topology
| ... | with single links between nodes.
| ... | *[Enc] Packet Encapsulations:* Eth-IPv4 for L2 xconnect.
| ... | 802.1ad tagging is applied on link between DUT1 and DUT2 with inner 4B
| ... | vlan tag (id=100) and outer 4B vlan tag (id=200).
| ... | *[Cfg] DUT configuration:* DUT1 and DUT2 are configured with L2 cross-
| ... | connect. DUT1 and DUT2 tested with ${nic_name}.\
| ... | *[Ver] TG verification:* TG finds and reports throughput NDR (Non Drop\
| ... | Rate) with zero packet loss tolerance and throughput PDR (Partial Drop\
| ... | Rate) with non-zero packet loss tolerance (LT) expressed in percentage\
| ... | of packets transmitted. NDR and PDR are discovered for different\
| ... | Ethernet L2 frame sizes using MLRsearch library.\
| ... | Test packets are generated by TG on
| ... | links to DUTs. TG traffic profile contains two L3 flow-groups
| ... | (flow-group per direction, 253 flows per flow-group) with all packets
| ... | containing Ethernet header, IPv4 header with IP protocol=61 and
| ... | static payload. MAC addresses are matching MAC addresses of the TG
| ... | node interfaces.
| ... | *[Ref] Applicable standard specifications:* RFC2544.

*** Variables ***
| @{plugins_to_enable}= | dpdk_plugin.so
| ${osi_layer}= | L2
| ${nic_name}= | Intel-X710
| ${overhead}= | ${8}
| ${subid}= | 10
| ${outer_vlan_id}= | 100
| ${inner_vlan_id}= | 200
| ${type_subif}= | two_tags
| ${tag_rewrite}= | pop-2
# Traffic profile:
| ${traffic_profile}= | trex-sl-3n-ethip4-ip4src254

*** Keywords ***
| Local Template
| | [Documentation]
| | ... | [Cfg] DUT runs L2XC forwarding config.
| | ... | Each DUT uses ${phy_cores} physical core(s) for worker threads.
| | ... | [Ver] Measure NDR and PDR values using MLRsearch algorithm.\
| | ...
| | ... | *Arguments:*
| | ... | - frame_size - Framesize in Bytes in integer or string (IMIX_v4_1).
| | ... | Type: integer, string
| | ... | - phy_cores - Number of physical cores. Type: integer
| | ... | - rxq - Number of RX queues, default value: ${None}. Type: integer
| | ...
| | [Arguments] | ${frame_size} | ${phy_cores} | ${rxq}=${None}
| | ...
| | Set Test Variable | \${frame_size}
| | ...
| | Given Add worker threads and rxqueues to all DUTs | ${phy_cores} | ${rxq}
| | And Add PCI devices to all DUTs
| | And Set Max Rate And Jumbo And Handle Multi Seg
| | And Apply startup configuration on all VPP DUTs
| | And Set interfaces in path up
| | When Initialize VLAN sub-interfaces in 3-node circular topology
| | ... | ${dut1} | ${dut1_if2} | ${dut2} | ${dut2_if1} | ${subid}
| | ... | ${outer_vlan_id} | ${inner_vlan_id} | ${type_subif}
| | And Configure L2 tag rewrite method on interfaces
| | ... | ${dut1} | ${subif_index_1} | ${dut2} | ${subif_index_2}
| | ... | ${tag_rewrite}
| | And Configure L2XC
| | ... | ${dut1} | ${dut1_if1} | ${subif_index_1}
| | And Configure L2XC
| | ... | ${dut2} | ${dut2_if2} | ${subif_index_2}
| | Then Find NDR and PDR intervals using optimized search

*** Test Cases ***
| tc01-64B-1c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | 64B | 1C
| | frame_size=${64} | phy_cores=${1}

| tc02-64B-2c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | 64B | 2C
| | frame_size=${64} | phy_cores=${2}

| tc03-64B-4c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | 64B | 4C
| | frame_size=${64} | phy_cores=${4}

| tc04-1518B-1c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | 1518B | 1C
| | frame_size=${1518} | phy_cores=${1}

| tc05-1518B-2c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | 1518B | 2C
| | frame_size=${1518} | phy_cores=${2}

| tc06-1518B-4c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | 1518B | 4C
| | frame_size=${1518} | phy_cores=${4}

| tc07-9000B-1c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | 9000B | 1C
| | frame_size=${9000} | phy_cores=${1}

| tc08-9000B-2c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | 9000B | 2C
| | frame_size=${9000} | phy_cores=${2}

| tc09-9000B-4c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | 9000B | 4C
| | frame_size=${9000} | phy_cores=${4}

| tc10-IMIX-1c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | IMIX | 1C
| | frame_size=IMIX_v4_1 | phy_cores=${1}

| tc11-IMIX-2c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | IMIX | 2C
| | frame_size=IMIX_v4_1 | phy_cores=${2}

| tc12-IMIX-4c-dot1ad-l2xcbase-ndrpdr
| | [Tags] | IMIX | 4C
| | frame_size=IMIX_v4_1 | phy_cores=${4}
).tearDownClass() raise def setUp(self): """ Clear trace and packet infos before running each test. """ super(TestIP6VrfMultiInst, self).setUp() self.reset_packet_infos() def tearDown(self): """ Show various debug prints after each test. """ super(TestIP6VrfMultiInst, self).tearDown() if not self.vpp_dead: self.logger.info(self.vapi.ppcli("show ip6 fib")) self.logger.info(self.vapi.ppcli("show ip6 neighbors")) def create_vrf_and_assign_interfaces(self, count, start=1): """ Create required number of FIB tables / VRFs, put 3 l2-pg interfaces to every FIB table / VRF. :param int count: Number of FIB tables / VRFs to be created. :param int start: Starting number of the FIB table / VRF ID. \ (Default value = 1) """ for i in range(count): vrf_id = i + start pg_if = self.pg_if_by_vrf_id[vrf_id][0] dest_addr = pg_if.remote_hosts[0].ip6n dest_addr_len = 64 self.vapi.ip_table_add_del(vrf_id, is_add=1, is_ipv6=1) self.vapi.ip_add_del_route( dest_addr, dest_addr_len, pg_if.local_ip6n, is_ipv6=1, table_id=vrf_id, is_multipath=1) self.logger.info("IPv6 VRF ID %d created" % vrf_id) if vrf_id not in self.vrf_list: self.vrf_list.append(vrf_id) if vrf_id in self.vrf_reset_list: self.vrf_reset_list.remove(vrf_id) for j in range(self.pg_ifs_per_vrf): pg_if = self.pg_if_by_vrf_id[vrf_id][j] pg_if.set_table_ip6(vrf_id) self.logger.info("pg-interface %s added to IPv6 VRF ID %d" % (pg_if.name, vrf_id)) if pg_if not in self.pg_in_vrf: self.pg_in_vrf.append(pg_if) if pg_if in self.pg_not_in_vrf: self.pg_not_in_vrf.remove(pg_if) pg_if.config_ip6() pg_if.disable_ipv6_ra() pg_if.configure_ipv6_neighbors() self.logger.debug(self.vapi.ppcli("show ip6 fib")) self.logger.debug(self.vapi.ppcli("show ip6 neighbors")) def reset_vrf(self, vrf_id): """ Reset required FIB table / VRF. :param int vrf_id: The FIB table / VRF ID to be reset. """ # self.vapi.reset_vrf(vrf_id, is_ipv6=1) self.vapi.reset_fib(vrf_id, is_ipv6=1) if vrf_id in self.vrf_list: self.vrf_list.remove(vrf_id) if vrf_id not in self.vrf_reset_list: self.vrf_reset_list.append(vrf_id) for j in range(self.pg_ifs_per_vrf): pg_if = self.pg_if_by_vrf_id[vrf_id][j] pg_if.unconfig_ip6() if pg_if in self.pg_in_vrf: self.pg_in_vrf.remove(pg_if) if pg_if not in self.pg_not_in_vrf: self.pg_not_in_vrf.append(pg_if) self.logger.info("IPv6 VRF ID %d reset" % vrf_id) self.logger.debug(self.vapi.ppcli("show ip6 fib")) self.logger.debug(self.vapi.ppcli("show ip6 neighbors")) self.vapi.ip_table_add_del(vrf_id, is_add=0, is_ipv6=1) def create_stream(self, src_if, packet_sizes): """ Create input packet stream for defined interface using hosts list. :param object src_if: Interface to create packet stream for. :param list packet_sizes: List of required packet sizes. :return: Stream of packets. """ pkts = [] src_hosts = src_if.remote_hosts for dst_if in self.flows[src_if]: for dst_host in dst_if.remote_hosts: src_host = random.choice(src_hosts) pkt_info = self.create_packet_info(src_if, dst_if) payload = self.info_to_payload(pkt_info) p = (Ether(dst=src_if.local_mac, src=src_host.mac) / IPv6(src=src_host.ip6, dst=dst_host.ip6) / UDP(sport=1234, dport=1234) / Raw(payload)) pkt_info.data = p.copy() size = random.choice(packet_sizes) self.extend_packet(p, size) pkts.append(p) self.logger.debug("Input stream created for port %s. Length: %u pkt(s)" % (src_if.name, len(pkts))) return pkts def verify_capture(self, pg_if, capture): """ Verify captured input packet stream for defined interface. :param object pg_if: Interface to verify captured packet stream for. :param list capture: Captured packet stream. """ last_info = dict() for i in self.pg_interfaces: last_info[i.sw_if_index] = None dst_sw_if_index = pg_if.sw_if_index for packet in capture: try: ip = packet[IPv6] udp = packet[UDP] payload_info = self.payload_to_info(str(packet[Raw])) packet_index = payload_info.index self.assertEqual(payload_info.dst, dst_sw_if_index) self.logger.debug("Got packet on port %s: src=%u (id=%u)" % (pg_if.name, payload_info.src, packet_index)) next_info = self.get_next_packet_info_for_interface2( payload_info.src, dst_sw_if_index, last_info[payload_info.src]) last_info[payload_info.src] = next_info self.assertIsNotNone(next_info) self.assertEqual(packet_index, next_info.index) saved_packet = next_info.data # Check standard fields self.assertEqual(ip.src, saved_packet[IPv6].src) self.assertEqual(ip.dst, saved_packet[IPv6].dst) self.assertEqual(udp.sport, saved_packet[UDP].sport) self.assertEqual(udp.dport, saved_packet[UDP].dport) except: self.logger.error(ppp("Unexpected or invalid packet:", packet)) raise for i in self.pg_interfaces: remaining_packet = self.get_next_packet_info_for_interface2( i, dst_sw_if_index, last_info[i.sw_if_index]) self.assertIsNone( remaining_packet, "Port %u: Packet expected from source %u didn't arrive" % (dst_sw_if_index, i.sw_if_index)) def verify_vrf(self, vrf_id): """ Check if the FIB table / VRF ID is configured. :param int vrf_id: The FIB table / VRF ID to be verified. :return: 1 if the FIB table / VRF ID is configured, otherwise return 0. """ ip6_fib_dump = self.vapi.ip6_fib_dump() vrf_exist = False vrf_count = 0 for ip6_fib_details in ip6_fib_dump: if ip6_fib_details.table_id == vrf_id: if not vrf_exist: vrf_exist = True addr = inet_ntop(socket.AF_INET6, ip6_fib_details.address) addrtype = in6_getAddrType(addr) vrf_count += 1 if addrtype == IPV6_ADDR_UNICAST else 0 if not vrf_exist and vrf_count == 0: self.logger.info("IPv6 VRF ID %d is not configured" % vrf_id) return VRF_NOT_CONFIGURED elif vrf_exist and vrf_count == 0: self.logger.info("IPv6 VRF ID %d has been reset" % vrf_id) return VRF_RESET else: self.logger.info("IPv6 VRF ID %d is configured" % vrf_id) return VRF_CONFIGURED def run_verify_test(self): """ Create packet streams for all configured l2-pg interfaces, send all \ prepared packet streams and verify that: - all packets received correctly on all pg-l2 interfaces assigned to bridge domains - no packet received on all pg-l2 interfaces not assigned to bridge domains :raise RuntimeError: If no packet captured on l2-pg interface assigned to the bridge domain or if any packet is captured on l2-pg interface not assigned to the bridge domain. """ # Test # Create incoming packet streams for packet-generator interfaces for pg_if in self.pg_interfaces: pkts = self.create_stream(pg_if, self.pg_if_packet_sizes) pg_if.add_stream(pkts) # Enable packet capture and start packet sending self.pg_enable_capture(self.pg_interfaces) self.pg_start() # Verify # Verify outgoing packet streams per packet-generator interface for pg_if in self.pg_interfaces: if pg_if in self.pg_in_vrf: capture = pg_if.get_capture(remark="interface is in VRF") self.verify_capture(pg_if, capture) elif pg_if in self.pg_not_in_vrf: pg_if.assert_nothing_captured(remark="interface is not in VRF", filter_out_fn=is_ipv6_misc_ext) self.logger.debug("No capture for interface %s" % pg_if.name) else: raise Exception("Unknown interface: %s" % pg_if.name) def test_ip6_vrf_01(self): """ IP6 VRF Multi-instance test 1 - create 4 VRFs """ # Config 1 # Create 4 VRFs self.create_vrf_and_assign_interfaces(4) # Verify 1 for vrf_id in self.vrf_list: self.assertEqual(self.verify_vrf(vrf_id), VRF_CONFIGURED) # Test 1 self.run_verify_test() def test_ip6_vrf_02(self): """ IP6 VRF Multi-instance test 2 - reset 2 VRFs """ # Config 2 # Delete 2 VRFs self.reset_vrf(1) self.reset_vrf(2) # Verify 2 for vrf_id in self.vrf_reset_list: self.assertEqual(self.verify_vrf(vrf_id), VRF_RESET) for vrf_id in self.vrf_list: self.assertEqual(self.verify_vrf(vrf_id), VRF_CONFIGURED) # Test 2 self.run_verify_test() # Reset routes learned from ICMPv6 Neighbor Discovery for vrf_id in self.vrf_reset_list: self.reset_vrf(vrf_id) def test_ip6_vrf_03(self): """ IP6 VRF Multi-instance 3 - add 2 VRFs """ # Config 3 # Add 1 of reset VRFs and 1 new VRF self.create_vrf_and_assign_interfaces(1) self.create_vrf_and_assign_interfaces(1, start=5) # Verify 3 for vrf_id in self.vrf_reset_list: self.assertEqual(self.verify_vrf(vrf_id), VRF_RESET) for vrf_id in self.vrf_list: self.assertEqual(self.verify_vrf(vrf_id), VRF_CONFIGURED) # Test 3 self.run_verify_test() # Reset routes learned from ICMPv6 Neighbor Discovery for vrf_id in self.vrf_reset_list: self.reset_vrf(vrf_id) def test_ip6_vrf_04(self): """ IP6 VRF Multi-instance test 4 - reset 4 VRFs """ # Config 4 # Reset all VRFs (i.e. no VRF except VRF=0 created) for i in range(len(self.vrf_list)): self.reset_vrf(self.vrf_list[0]) # Verify 4 for vrf_id in self.vrf_reset_list: self.assertEqual(self.verify_vrf(vrf_id), VRF_RESET) for vrf_id in self.vrf_list: self.assertEqual(self.verify_vrf(vrf_id), VRF_CONFIGURED) # Test 4 self.run_verify_test() if __name__ == '__main__': unittest.main(testRunner=VppTestRunner)