blob: eba349a2a0f56cfe106bcb826d54bc0d5c25a39c [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
10from framework import VppTestCase, VppTestRunner
Klement Sekera7bb873a2016-11-18 07:38:42 +010011from util import Host, ppp
Damjan Marionf56b77a2016-10-03 19:44:57 +020012
13
Damjan Marionf56b77a2016-10-03 19:44:57 +020014class TestL2xc(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020015 """L2XC Test Case"""
Damjan Marionf56b77a2016-10-03 19:44:57 +020016
Damjan Marionf56b77a2016-10-03 19:44:57 +020017 @classmethod
18 def setUpClass(cls):
Jan49c0fca2016-10-26 15:44:27 +020019 """
20 Perform standard class setup (defined by class method setUpClass in
21 class VppTestCase) before running the test case, set test case related
22 variables and configure VPP.
23
24 :var int hosts_nr: Number of hosts to be created.
25 :var int dl_pkts_per_burst: Number of packets in burst for dual-loop
26 test.
27 :var int sl_pkts_per_burst: Number of packets in burst for single-loop
28 test.
29 """
Damjan Marionf56b77a2016-10-03 19:44:57 +020030 super(TestL2xc, cls).setUpClass()
31
Jan49c0fca2016-10-26 15:44:27 +020032 # Test variables
33 cls.hosts_nr = 10
34 cls.dl_pkts_per_burst = 257
35 cls.sl_pkts_per_burst = 2
36
37 try:
38 # create 4 pg interfaces
39 cls.create_pg_interfaces(range(4))
40
41 # packet flows mapping pg0 -> pg1, pg2 -> pg3, etc.
42 cls.flows = dict()
43 cls.flows[cls.pg0] = [cls.pg1]
44 cls.flows[cls.pg1] = [cls.pg0]
45 cls.flows[cls.pg2] = [cls.pg3]
46 cls.flows[cls.pg3] = [cls.pg2]
47
48 # packet sizes
49 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
50
51 cls.interfaces = list(cls.pg_interfaces)
52
53 # Create bi-directional cross-connects between pg0 and pg1
54 cls.vapi.sw_interface_set_l2_xconnect(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020055 cls.pg0.sw_if_index, cls.pg1.sw_if_index, enable=1
56 )
Jan49c0fca2016-10-26 15:44:27 +020057 cls.vapi.sw_interface_set_l2_xconnect(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020058 cls.pg1.sw_if_index, cls.pg0.sw_if_index, enable=1
59 )
Jan49c0fca2016-10-26 15:44:27 +020060
61 # Create bi-directional cross-connects between pg2 and pg3
62 cls.vapi.sw_interface_set_l2_xconnect(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020063 cls.pg2.sw_if_index, cls.pg3.sw_if_index, enable=1
64 )
Jan49c0fca2016-10-26 15:44:27 +020065 cls.vapi.sw_interface_set_l2_xconnect(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020066 cls.pg3.sw_if_index, cls.pg2.sw_if_index, enable=1
67 )
Jan49c0fca2016-10-26 15:44:27 +020068
69 # mapping between packet-generator index and lists of test hosts
70 cls.hosts_by_pg_idx = dict()
71
72 # Create host MAC and IPv4 lists
73 cls.create_host_lists(cls.hosts_nr)
74
75 # setup all interfaces
76 for i in cls.interfaces:
77 i.admin_up()
78
79 except Exception:
80 super(TestL2xc, cls).tearDownClass()
81 raise
82
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070083 @classmethod
84 def tearDownClass(cls):
85 super(TestL2xc, cls).tearDownClass()
86
Klement Sekeraf62ae122016-10-11 11:47:09 +020087 def setUp(self):
88 super(TestL2xc, self).setUp()
Klement Sekeradab231a2016-12-21 08:50:14 +010089 self.reset_packet_infos()
Klement Sekeraf62ae122016-10-11 11:47:09 +020090
Damjan Marionf56b77a2016-10-03 19:44:57 +020091 def tearDown(self):
Jan49c0fca2016-10-26 15:44:27 +020092 """
93 Show various debug prints after each test.
94 """
Klement Sekeraf62ae122016-10-11 11:47:09 +020095 super(TestL2xc, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -070096
97 def show_commands_at_teardown(self):
98 self.logger.info(self.vapi.ppcli("show l2patch"))
Damjan Marionf56b77a2016-10-03 19:44:57 +020099
Jan49c0fca2016-10-26 15:44:27 +0200100 @classmethod
101 def create_host_lists(cls, count):
102 """
103 Method to create required number of MAC and IPv4 addresses.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200104 Create required number of host MAC addresses and distribute them among
105 interfaces. Create host IPv4 address for every host MAC address too.
106
107 :param count: Number of hosts to create MAC and IPv4 addresses for.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200108 """
Jan49c0fca2016-10-26 15:44:27 +0200109 for pg_if in cls.pg_interfaces:
110 cls.hosts_by_pg_idx[pg_if.sw_if_index] = []
111 hosts = cls.hosts_by_pg_idx[pg_if.sw_if_index]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200112 for j in range(0, count):
Matej Klotton0178d522016-11-04 11:11:44 +0100113 host = Host(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200114 "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200115 "172.17.1%02x.%u" % (pg_if.sw_if_index, j),
116 )
Klement Sekeraf62ae122016-10-11 11:47:09 +0200117 hosts.append(host)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200118
Jan49c0fca2016-10-26 15:44:27 +0200119 def create_stream(self, src_if, packet_sizes, packets_per_burst):
120 """
121 Create input packet stream for defined interface.
122
123 :param object src_if: Interface to create packet stream for.
124 :param list packet_sizes: List of required packet sizes.
125 :param int packets_per_burst: Number of packets in burst.
126 :return: Stream of packets.
127 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200128 pkts = []
Jan49c0fca2016-10-26 15:44:27 +0200129 for i in range(0, packets_per_burst):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200130 dst_if = self.flows[src_if][0]
131 dst_host = random.choice(self.hosts_by_pg_idx[dst_if.sw_if_index])
132 src_host = random.choice(self.hosts_by_pg_idx[src_if.sw_if_index])
Klement Sekeradab231a2016-12-21 08:50:14 +0100133 pkt_info = self.create_packet_info(src_if, dst_if)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200134 payload = self.info_to_payload(pkt_info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200135 p = (
136 Ether(dst=dst_host.mac, src=src_host.mac)
137 / IP(src=src_host.ip4, dst=dst_host.ip4)
138 / UDP(sport=1234, dport=1234)
139 / Raw(payload)
140 )
Damjan Marionf56b77a2016-10-03 19:44:57 +0200141 pkt_info.data = p.copy()
Jan49c0fca2016-10-26 15:44:27 +0200142 size = random.choice(packet_sizes)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200143 self.extend_packet(p, size)
144 pkts.append(p)
145 return pkts
Damjan Marionf56b77a2016-10-03 19:44:57 +0200146
Klement Sekeraf62ae122016-10-11 11:47:09 +0200147 def verify_capture(self, pg_if, capture):
Jan49c0fca2016-10-26 15:44:27 +0200148 """
149 Verify captured input packet stream for defined interface.
150
151 :param object pg_if: Interface to verify captured packet stream for.
152 :param list capture: Captured packet stream.
153 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200154 last_info = dict()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200155 for i in self.interfaces:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200156 last_info[i.sw_if_index] = None
157 dst_sw_if_index = pg_if.sw_if_index
Damjan Marionf56b77a2016-10-03 19:44:57 +0200158 for packet in capture:
159 try:
160 ip = packet[IP]
161 udp = packet[UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -0800162 payload_info = self.payload_to_info(packet[Raw])
Klement Sekeraf62ae122016-10-11 11:47:09 +0200163 packet_index = payload_info.index
164 self.assertEqual(payload_info.dst, dst_sw_if_index)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200165 self.logger.debug(
166 "Got packet on port %s: src=%u (id=%u)"
167 % (pg_if.name, payload_info.src, packet_index)
168 )
Damjan Marionf56b77a2016-10-03 19:44:57 +0200169 next_info = self.get_next_packet_info_for_interface2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200170 payload_info.src, dst_sw_if_index, last_info[payload_info.src]
171 )
Damjan Marionf56b77a2016-10-03 19:44:57 +0200172 last_info[payload_info.src] = next_info
173 self.assertTrue(next_info is not None)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200174 self.assertEqual(packet_index, next_info.index)
175 saved_packet = next_info.data
Damjan Marionf56b77a2016-10-03 19:44:57 +0200176 # Check standard fields
Klement Sekeraf62ae122016-10-11 11:47:09 +0200177 self.assertEqual(ip.src, saved_packet[IP].src)
178 self.assertEqual(ip.dst, saved_packet[IP].dst)
179 self.assertEqual(udp.sport, saved_packet[UDP].sport)
180 self.assertEqual(udp.dport, saved_packet[UDP].dport)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200181 except:
Klement Sekera7bb873a2016-11-18 07:38:42 +0100182 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200183 raise
184 for i in self.interfaces:
185 remaining_packet = self.get_next_packet_info_for_interface2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200186 i, dst_sw_if_index, last_info[i.sw_if_index]
187 )
188 self.assertTrue(
189 remaining_packet is None,
190 "Port %u: Packet expected from source %u didn't"
191 " arrive" % (dst_sw_if_index, i.sw_if_index),
192 )
Damjan Marionf56b77a2016-10-03 19:44:57 +0200193
Jan49c0fca2016-10-26 15:44:27 +0200194 def run_l2xc_test(self, pkts_per_burst):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200195 """L2XC test"""
Damjan Marionf56b77a2016-10-03 19:44:57 +0200196
Klement Sekeraf62ae122016-10-11 11:47:09 +0200197 # Create incoming packet streams for packet-generator interfaces
Damjan Marionf56b77a2016-10-03 19:44:57 +0200198 for i in self.interfaces:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200199 pkts = self.create_stream(i, self.pg_if_packet_sizes, pkts_per_burst)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200200 i.add_stream(pkts)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200201
Klement Sekeraf62ae122016-10-11 11:47:09 +0200202 # Enable packet capturing and start packet sending
203 self.pg_enable_capture(self.pg_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200204 self.pg_start()
205
Klement Sekeraf62ae122016-10-11 11:47:09 +0200206 # Verify outgoing packet streams per packet-generator interface
207 for i in self.pg_interfaces:
208 capture = i.get_capture()
Jan49c0fca2016-10-26 15:44:27 +0200209 self.logger.info("Verifying capture on interface %s" % i.name)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200210 self.verify_capture(i, capture)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200211
Jan49c0fca2016-10-26 15:44:27 +0200212 def test_l2xc_sl(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200213 """L2XC single-loop test
Jan49c0fca2016-10-26 15:44:27 +0200214
215 Test scenario:
216 1. config
217 2 pairs of 2 interfaces, l2xconnected
218
219 2. sending l2 eth packets between 4 interfaces
220 64B, 512B, 1518B, 9018B (ether_size)
221 burst of 2 packets per interface
222 """
223
224 self.run_l2xc_test(self.sl_pkts_per_burst)
225
226 def test_l2xc_dl(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200227 """L2XC dual-loop test
Jan49c0fca2016-10-26 15:44:27 +0200228
229 Test scenario:
230 1. config
231 2 pairs of 2 interfaces, l2xconnected
232
233 2. sending l2 eth packets between 4 interfaces
234 64B, 512B, 1518B, 9018B (ether_size)
235 burst of 257 packets per interface
236 """
237
238 self.run_l2xc_test(self.dl_pkts_per_burst)
239
Damjan Marionf56b77a2016-10-03 19:44:57 +0200240
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200241if __name__ == "__main__":
Klement Sekeraf62ae122016-10-11 11:47:09 +0200242 unittest.main(testRunner=VppTestRunner)