blob: a29b7d210286aa3c3d25014de7cb8accc0794746 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Damjan Marionf56b77a2016-10-03 19:44:57 +02002
3import unittest
4import random
Klement Sekeraf62ae122016-10-11 11:47:09 +02005
6from scapy.packet import Raw
7from scapy.layers.l2 import Ether
Damjan Marionf56b77a2016-10-03 19:44:57 +02008from scapy.layers.inet import IP, UDP
Klement Sekeraf62ae122016-10-11 11:47:09 +02009
Dave Wallace8800f732023-08-31 00:47:44 -040010from framework import VppTestCase
11from asfframework import VppTestRunner
Klement Sekera7bb873a2016-11-18 07:38:42 +010012from util import Host, ppp
Damjan Marionf56b77a2016-10-03 19:44:57 +020013
14
Damjan Marionf56b77a2016-10-03 19:44:57 +020015class TestL2xc(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020016 """L2XC Test Case"""
Damjan Marionf56b77a2016-10-03 19:44:57 +020017
Damjan Marionf56b77a2016-10-03 19:44:57 +020018 @classmethod
19 def setUpClass(cls):
Jan49c0fca2016-10-26 15:44:27 +020020 """
21 Perform standard class setup (defined by class method setUpClass in
22 class VppTestCase) before running the test case, set test case related
23 variables and configure VPP.
24
25 :var int hosts_nr: Number of hosts to be created.
26 :var int dl_pkts_per_burst: Number of packets in burst for dual-loop
27 test.
28 :var int sl_pkts_per_burst: Number of packets in burst for single-loop
29 test.
30 """
Damjan Marionf56b77a2016-10-03 19:44:57 +020031 super(TestL2xc, cls).setUpClass()
32
Jan49c0fca2016-10-26 15:44:27 +020033 # Test variables
34 cls.hosts_nr = 10
35 cls.dl_pkts_per_burst = 257
36 cls.sl_pkts_per_burst = 2
37
38 try:
39 # create 4 pg interfaces
40 cls.create_pg_interfaces(range(4))
41
42 # packet flows mapping pg0 -> pg1, pg2 -> pg3, etc.
43 cls.flows = dict()
44 cls.flows[cls.pg0] = [cls.pg1]
45 cls.flows[cls.pg1] = [cls.pg0]
46 cls.flows[cls.pg2] = [cls.pg3]
47 cls.flows[cls.pg3] = [cls.pg2]
48
49 # packet sizes
50 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
51
52 cls.interfaces = list(cls.pg_interfaces)
53
54 # Create bi-directional cross-connects between pg0 and pg1
55 cls.vapi.sw_interface_set_l2_xconnect(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020056 cls.pg0.sw_if_index, cls.pg1.sw_if_index, enable=1
57 )
Jan49c0fca2016-10-26 15:44:27 +020058 cls.vapi.sw_interface_set_l2_xconnect(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020059 cls.pg1.sw_if_index, cls.pg0.sw_if_index, enable=1
60 )
Jan49c0fca2016-10-26 15:44:27 +020061
62 # Create bi-directional cross-connects between pg2 and pg3
63 cls.vapi.sw_interface_set_l2_xconnect(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020064 cls.pg2.sw_if_index, cls.pg3.sw_if_index, enable=1
65 )
Jan49c0fca2016-10-26 15:44:27 +020066 cls.vapi.sw_interface_set_l2_xconnect(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020067 cls.pg3.sw_if_index, cls.pg2.sw_if_index, enable=1
68 )
Jan49c0fca2016-10-26 15:44:27 +020069
70 # mapping between packet-generator index and lists of test hosts
71 cls.hosts_by_pg_idx = dict()
72
73 # Create host MAC and IPv4 lists
74 cls.create_host_lists(cls.hosts_nr)
75
76 # setup all interfaces
77 for i in cls.interfaces:
78 i.admin_up()
79
80 except Exception:
81 super(TestL2xc, cls).tearDownClass()
82 raise
83
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070084 @classmethod
85 def tearDownClass(cls):
86 super(TestL2xc, cls).tearDownClass()
87
Klement Sekeraf62ae122016-10-11 11:47:09 +020088 def setUp(self):
89 super(TestL2xc, self).setUp()
Klement Sekeradab231a2016-12-21 08:50:14 +010090 self.reset_packet_infos()
Klement Sekeraf62ae122016-10-11 11:47:09 +020091
Damjan Marionf56b77a2016-10-03 19:44:57 +020092 def tearDown(self):
Jan49c0fca2016-10-26 15:44:27 +020093 """
94 Show various debug prints after each test.
95 """
Klement Sekeraf62ae122016-10-11 11:47:09 +020096 super(TestL2xc, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -070097
98 def show_commands_at_teardown(self):
99 self.logger.info(self.vapi.ppcli("show l2patch"))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200100
Jan49c0fca2016-10-26 15:44:27 +0200101 @classmethod
102 def create_host_lists(cls, count):
103 """
104 Method to create required number of MAC and IPv4 addresses.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200105 Create required number of host MAC addresses and distribute them among
106 interfaces. Create host IPv4 address for every host MAC address too.
107
108 :param count: Number of hosts to create MAC and IPv4 addresses for.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200109 """
Jan49c0fca2016-10-26 15:44:27 +0200110 for pg_if in cls.pg_interfaces:
111 cls.hosts_by_pg_idx[pg_if.sw_if_index] = []
112 hosts = cls.hosts_by_pg_idx[pg_if.sw_if_index]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200113 for j in range(0, count):
Matej Klotton0178d522016-11-04 11:11:44 +0100114 host = Host(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200115 "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200116 "172.17.1%02x.%u" % (pg_if.sw_if_index, j),
117 )
Klement Sekeraf62ae122016-10-11 11:47:09 +0200118 hosts.append(host)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200119
Jan49c0fca2016-10-26 15:44:27 +0200120 def create_stream(self, src_if, packet_sizes, packets_per_burst):
121 """
122 Create input packet stream for defined interface.
123
124 :param object src_if: Interface to create packet stream for.
125 :param list packet_sizes: List of required packet sizes.
126 :param int packets_per_burst: Number of packets in burst.
127 :return: Stream of packets.
128 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200129 pkts = []
Jan49c0fca2016-10-26 15:44:27 +0200130 for i in range(0, packets_per_burst):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200131 dst_if = self.flows[src_if][0]
132 dst_host = random.choice(self.hosts_by_pg_idx[dst_if.sw_if_index])
133 src_host = random.choice(self.hosts_by_pg_idx[src_if.sw_if_index])
Klement Sekeradab231a2016-12-21 08:50:14 +0100134 pkt_info = self.create_packet_info(src_if, dst_if)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200135 payload = self.info_to_payload(pkt_info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200136 p = (
137 Ether(dst=dst_host.mac, src=src_host.mac)
138 / IP(src=src_host.ip4, dst=dst_host.ip4)
139 / UDP(sport=1234, dport=1234)
140 / Raw(payload)
141 )
Damjan Marionf56b77a2016-10-03 19:44:57 +0200142 pkt_info.data = p.copy()
Jan49c0fca2016-10-26 15:44:27 +0200143 size = random.choice(packet_sizes)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200144 self.extend_packet(p, size)
145 pkts.append(p)
146 return pkts
Damjan Marionf56b77a2016-10-03 19:44:57 +0200147
Klement Sekeraf62ae122016-10-11 11:47:09 +0200148 def verify_capture(self, pg_if, capture):
Jan49c0fca2016-10-26 15:44:27 +0200149 """
150 Verify captured input packet stream for defined interface.
151
152 :param object pg_if: Interface to verify captured packet stream for.
153 :param list capture: Captured packet stream.
154 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200155 last_info = dict()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200156 for i in self.interfaces:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200157 last_info[i.sw_if_index] = None
158 dst_sw_if_index = pg_if.sw_if_index
Damjan Marionf56b77a2016-10-03 19:44:57 +0200159 for packet in capture:
160 try:
161 ip = packet[IP]
162 udp = packet[UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -0800163 payload_info = self.payload_to_info(packet[Raw])
Klement Sekeraf62ae122016-10-11 11:47:09 +0200164 packet_index = payload_info.index
165 self.assertEqual(payload_info.dst, dst_sw_if_index)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200166 self.logger.debug(
167 "Got packet on port %s: src=%u (id=%u)"
168 % (pg_if.name, payload_info.src, packet_index)
169 )
Damjan Marionf56b77a2016-10-03 19:44:57 +0200170 next_info = self.get_next_packet_info_for_interface2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200171 payload_info.src, dst_sw_if_index, last_info[payload_info.src]
172 )
Damjan Marionf56b77a2016-10-03 19:44:57 +0200173 last_info[payload_info.src] = next_info
174 self.assertTrue(next_info is not None)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200175 self.assertEqual(packet_index, next_info.index)
176 saved_packet = next_info.data
Damjan Marionf56b77a2016-10-03 19:44:57 +0200177 # Check standard fields
Klement Sekeraf62ae122016-10-11 11:47:09 +0200178 self.assertEqual(ip.src, saved_packet[IP].src)
179 self.assertEqual(ip.dst, saved_packet[IP].dst)
180 self.assertEqual(udp.sport, saved_packet[UDP].sport)
181 self.assertEqual(udp.dport, saved_packet[UDP].dport)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200182 except:
Klement Sekera7bb873a2016-11-18 07:38:42 +0100183 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200184 raise
185 for i in self.interfaces:
186 remaining_packet = self.get_next_packet_info_for_interface2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200187 i, dst_sw_if_index, last_info[i.sw_if_index]
188 )
189 self.assertTrue(
190 remaining_packet is None,
191 "Port %u: Packet expected from source %u didn't"
192 " arrive" % (dst_sw_if_index, i.sw_if_index),
193 )
Damjan Marionf56b77a2016-10-03 19:44:57 +0200194
Jan49c0fca2016-10-26 15:44:27 +0200195 def run_l2xc_test(self, pkts_per_burst):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200196 """L2XC test"""
Damjan Marionf56b77a2016-10-03 19:44:57 +0200197
Klement Sekeraf62ae122016-10-11 11:47:09 +0200198 # Create incoming packet streams for packet-generator interfaces
Damjan Marionf56b77a2016-10-03 19:44:57 +0200199 for i in self.interfaces:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200200 pkts = self.create_stream(i, self.pg_if_packet_sizes, pkts_per_burst)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200201 i.add_stream(pkts)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200202
Klement Sekeraf62ae122016-10-11 11:47:09 +0200203 # Enable packet capturing and start packet sending
204 self.pg_enable_capture(self.pg_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200205 self.pg_start()
206
Klement Sekeraf62ae122016-10-11 11:47:09 +0200207 # Verify outgoing packet streams per packet-generator interface
208 for i in self.pg_interfaces:
209 capture = i.get_capture()
Jan49c0fca2016-10-26 15:44:27 +0200210 self.logger.info("Verifying capture on interface %s" % i.name)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200211 self.verify_capture(i, capture)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200212
Jan49c0fca2016-10-26 15:44:27 +0200213 def test_l2xc_sl(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 """L2XC single-loop test
Jan49c0fca2016-10-26 15:44:27 +0200215
216 Test scenario:
217 1. config
218 2 pairs of 2 interfaces, l2xconnected
219
220 2. sending l2 eth packets between 4 interfaces
221 64B, 512B, 1518B, 9018B (ether_size)
222 burst of 2 packets per interface
223 """
224
225 self.run_l2xc_test(self.sl_pkts_per_burst)
226
227 def test_l2xc_dl(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200228 """L2XC dual-loop test
Jan49c0fca2016-10-26 15:44:27 +0200229
230 Test scenario:
231 1. config
232 2 pairs of 2 interfaces, l2xconnected
233
234 2. sending l2 eth packets between 4 interfaces
235 64B, 512B, 1518B, 9018B (ether_size)
236 burst of 257 packets per interface
237 """
238
239 self.run_l2xc_test(self.dl_pkts_per_burst)
240
Damjan Marionf56b77a2016-10-03 19:44:57 +0200241
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200242if __name__ == "__main__":
Klement Sekeraf62ae122016-10-11 11:47:09 +0200243 unittest.main(testRunner=VppTestRunner)