blob: bc653f0b4fb833b57f74675f971a65ed6d5e4af0 [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):
15 """ L2XC Test Case """
16
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(
55 cls.pg0.sw_if_index, cls.pg1.sw_if_index, enable=1)
56 cls.vapi.sw_interface_set_l2_xconnect(
57 cls.pg1.sw_if_index, cls.pg0.sw_if_index, enable=1)
58
59 # Create bi-directional cross-connects between pg2 and pg3
60 cls.vapi.sw_interface_set_l2_xconnect(
61 cls.pg2.sw_if_index, cls.pg3.sw_if_index, enable=1)
62 cls.vapi.sw_interface_set_l2_xconnect(
63 cls.pg3.sw_if_index, cls.pg2.sw_if_index, enable=1)
64
65 # mapping between packet-generator index and lists of test hosts
66 cls.hosts_by_pg_idx = dict()
67
68 # Create host MAC and IPv4 lists
69 cls.create_host_lists(cls.hosts_nr)
70
71 # setup all interfaces
72 for i in cls.interfaces:
73 i.admin_up()
74
75 except Exception:
76 super(TestL2xc, cls).tearDownClass()
77 raise
78
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -070079 @classmethod
80 def tearDownClass(cls):
81 super(TestL2xc, cls).tearDownClass()
82
Klement Sekeraf62ae122016-10-11 11:47:09 +020083 def setUp(self):
84 super(TestL2xc, self).setUp()
Klement Sekeradab231a2016-12-21 08:50:14 +010085 self.reset_packet_infos()
Klement Sekeraf62ae122016-10-11 11:47:09 +020086
Damjan Marionf56b77a2016-10-03 19:44:57 +020087 def tearDown(self):
Jan49c0fca2016-10-26 15:44:27 +020088 """
89 Show various debug prints after each test.
90 """
Klement Sekeraf62ae122016-10-11 11:47:09 +020091 super(TestL2xc, self).tearDown()
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -070092
93 def show_commands_at_teardown(self):
94 self.logger.info(self.vapi.ppcli("show l2patch"))
Damjan Marionf56b77a2016-10-03 19:44:57 +020095
Jan49c0fca2016-10-26 15:44:27 +020096 @classmethod
97 def create_host_lists(cls, count):
98 """
99 Method to create required number of MAC and IPv4 addresses.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200100 Create required number of host MAC addresses and distribute them among
101 interfaces. Create host IPv4 address for every host MAC address too.
102
103 :param count: Number of hosts to create MAC and IPv4 addresses for.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200104 """
Jan49c0fca2016-10-26 15:44:27 +0200105 for pg_if in cls.pg_interfaces:
106 cls.hosts_by_pg_idx[pg_if.sw_if_index] = []
107 hosts = cls.hosts_by_pg_idx[pg_if.sw_if_index]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200108 for j in range(0, count):
Matej Klotton0178d522016-11-04 11:11:44 +0100109 host = Host(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200110 "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j),
111 "172.17.1%02x.%u" % (pg_if.sw_if_index, j))
112 hosts.append(host)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200113
Jan49c0fca2016-10-26 15:44:27 +0200114 def create_stream(self, src_if, packet_sizes, packets_per_burst):
115 """
116 Create input packet stream for defined interface.
117
118 :param object src_if: Interface to create packet stream for.
119 :param list packet_sizes: List of required packet sizes.
120 :param int packets_per_burst: Number of packets in burst.
121 :return: Stream of packets.
122 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200123 pkts = []
Jan49c0fca2016-10-26 15:44:27 +0200124 for i in range(0, packets_per_burst):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200125 dst_if = self.flows[src_if][0]
126 dst_host = random.choice(self.hosts_by_pg_idx[dst_if.sw_if_index])
127 src_host = random.choice(self.hosts_by_pg_idx[src_if.sw_if_index])
Klement Sekeradab231a2016-12-21 08:50:14 +0100128 pkt_info = self.create_packet_info(src_if, dst_if)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200129 payload = self.info_to_payload(pkt_info)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200130 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
131 IP(src=src_host.ip4, dst=dst_host.ip4) /
Damjan Marionf56b77a2016-10-03 19:44:57 +0200132 UDP(sport=1234, dport=1234) /
133 Raw(payload))
134 pkt_info.data = p.copy()
Jan49c0fca2016-10-26 15:44:27 +0200135 size = random.choice(packet_sizes)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200136 self.extend_packet(p, size)
137 pkts.append(p)
138 return pkts
Damjan Marionf56b77a2016-10-03 19:44:57 +0200139
Klement Sekeraf62ae122016-10-11 11:47:09 +0200140 def verify_capture(self, pg_if, capture):
Jan49c0fca2016-10-26 15:44:27 +0200141 """
142 Verify captured input packet stream for defined interface.
143
144 :param object pg_if: Interface to verify captured packet stream for.
145 :param list capture: Captured packet stream.
146 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200147 last_info = dict()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200148 for i in self.interfaces:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200149 last_info[i.sw_if_index] = None
150 dst_sw_if_index = pg_if.sw_if_index
Damjan Marionf56b77a2016-10-03 19:44:57 +0200151 for packet in capture:
152 try:
153 ip = packet[IP]
154 udp = packet[UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -0800155 payload_info = self.payload_to_info(packet[Raw])
Klement Sekeraf62ae122016-10-11 11:47:09 +0200156 packet_index = payload_info.index
157 self.assertEqual(payload_info.dst, dst_sw_if_index)
Jan49c0fca2016-10-26 15:44:27 +0200158 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
159 (pg_if.name, payload_info.src, packet_index))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200160 next_info = self.get_next_packet_info_for_interface2(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200161 payload_info.src, dst_sw_if_index,
Damjan Marionf56b77a2016-10-03 19:44:57 +0200162 last_info[payload_info.src])
163 last_info[payload_info.src] = next_info
164 self.assertTrue(next_info is not None)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200165 self.assertEqual(packet_index, next_info.index)
166 saved_packet = next_info.data
Damjan Marionf56b77a2016-10-03 19:44:57 +0200167 # Check standard fields
Klement Sekeraf62ae122016-10-11 11:47:09 +0200168 self.assertEqual(ip.src, saved_packet[IP].src)
169 self.assertEqual(ip.dst, saved_packet[IP].dst)
170 self.assertEqual(udp.sport, saved_packet[UDP].sport)
171 self.assertEqual(udp.dport, saved_packet[UDP].dport)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200172 except:
Klement Sekera7bb873a2016-11-18 07:38:42 +0100173 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200174 raise
175 for i in self.interfaces:
176 remaining_packet = self.get_next_packet_info_for_interface2(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200177 i, dst_sw_if_index, last_info[i.sw_if_index])
Damjan Marionf56b77a2016-10-03 19:44:57 +0200178 self.assertTrue(remaining_packet is None,
179 "Port %u: Packet expected from source %u didn't"
Klement Sekeraf62ae122016-10-11 11:47:09 +0200180 " arrive" % (dst_sw_if_index, i.sw_if_index))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200181
Jan49c0fca2016-10-26 15:44:27 +0200182 def run_l2xc_test(self, pkts_per_burst):
183 """ L2XC test """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200184
Klement Sekeraf62ae122016-10-11 11:47:09 +0200185 # Create incoming packet streams for packet-generator interfaces
Damjan Marionf56b77a2016-10-03 19:44:57 +0200186 for i in self.interfaces:
Jan49c0fca2016-10-26 15:44:27 +0200187 pkts = self.create_stream(i, self.pg_if_packet_sizes,
188 pkts_per_burst)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200189 i.add_stream(pkts)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200190
Klement Sekeraf62ae122016-10-11 11:47:09 +0200191 # Enable packet capturing and start packet sending
192 self.pg_enable_capture(self.pg_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200193 self.pg_start()
194
Klement Sekeraf62ae122016-10-11 11:47:09 +0200195 # Verify outgoing packet streams per packet-generator interface
196 for i in self.pg_interfaces:
197 capture = i.get_capture()
Jan49c0fca2016-10-26 15:44:27 +0200198 self.logger.info("Verifying capture on interface %s" % i.name)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200199 self.verify_capture(i, capture)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200200
Jan49c0fca2016-10-26 15:44:27 +0200201 def test_l2xc_sl(self):
202 """ L2XC single-loop test
203
204 Test scenario:
205 1. config
206 2 pairs of 2 interfaces, l2xconnected
207
208 2. sending l2 eth packets between 4 interfaces
209 64B, 512B, 1518B, 9018B (ether_size)
210 burst of 2 packets per interface
211 """
212
213 self.run_l2xc_test(self.sl_pkts_per_burst)
214
215 def test_l2xc_dl(self):
216 """ L2XC dual-loop test
217
218 Test scenario:
219 1. config
220 2 pairs of 2 interfaces, l2xconnected
221
222 2. sending l2 eth packets between 4 interfaces
223 64B, 512B, 1518B, 9018B (ether_size)
224 burst of 257 packets per interface
225 """
226
227 self.run_l2xc_test(self.dl_pkts_per_burst)
228
Damjan Marionf56b77a2016-10-03 19:44:57 +0200229
230if __name__ == '__main__':
Klement Sekeraf62ae122016-10-11 11:47:09 +0200231 unittest.main(testRunner=VppTestRunner)