blob: 845579b037b61ddac8734ee4660634261deb10cd [file] [log] [blame]
Damjan Marionf56b77a2016-10-03 19:44:57 +02001#!/usr/bin/env python
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()
92 if not self.vpp_dead:
Jan49c0fca2016-10-26 15:44:27 +020093 self.logger.info(self.vapi.ppcli("show l2patch"))
Damjan Marionf56b77a2016-10-03 19:44:57 +020094
Jan49c0fca2016-10-26 15:44:27 +020095 @classmethod
96 def create_host_lists(cls, count):
97 """
98 Method to create required number of MAC and IPv4 addresses.
Klement Sekeraf62ae122016-10-11 11:47:09 +020099 Create required number of host MAC addresses and distribute them among
100 interfaces. Create host IPv4 address for every host MAC address too.
101
102 :param count: Number of hosts to create MAC and IPv4 addresses for.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200103 """
Jan49c0fca2016-10-26 15:44:27 +0200104 for pg_if in cls.pg_interfaces:
105 cls.hosts_by_pg_idx[pg_if.sw_if_index] = []
106 hosts = cls.hosts_by_pg_idx[pg_if.sw_if_index]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200107 for j in range(0, count):
Matej Klotton0178d522016-11-04 11:11:44 +0100108 host = Host(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200109 "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j),
110 "172.17.1%02x.%u" % (pg_if.sw_if_index, j))
111 hosts.append(host)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200112
Jan49c0fca2016-10-26 15:44:27 +0200113 def create_stream(self, src_if, packet_sizes, packets_per_burst):
114 """
115 Create input packet stream for defined interface.
116
117 :param object src_if: Interface to create packet stream for.
118 :param list packet_sizes: List of required packet sizes.
119 :param int packets_per_burst: Number of packets in burst.
120 :return: Stream of packets.
121 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200122 pkts = []
Jan49c0fca2016-10-26 15:44:27 +0200123 for i in range(0, packets_per_burst):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200124 dst_if = self.flows[src_if][0]
125 dst_host = random.choice(self.hosts_by_pg_idx[dst_if.sw_if_index])
126 src_host = random.choice(self.hosts_by_pg_idx[src_if.sw_if_index])
Klement Sekeradab231a2016-12-21 08:50:14 +0100127 pkt_info = self.create_packet_info(src_if, dst_if)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200128 payload = self.info_to_payload(pkt_info)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200129 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
130 IP(src=src_host.ip4, dst=dst_host.ip4) /
Damjan Marionf56b77a2016-10-03 19:44:57 +0200131 UDP(sport=1234, dport=1234) /
132 Raw(payload))
133 pkt_info.data = p.copy()
Jan49c0fca2016-10-26 15:44:27 +0200134 size = random.choice(packet_sizes)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200135 self.extend_packet(p, size)
136 pkts.append(p)
137 return pkts
Damjan Marionf56b77a2016-10-03 19:44:57 +0200138
Klement Sekeraf62ae122016-10-11 11:47:09 +0200139 def verify_capture(self, pg_if, capture):
Jan49c0fca2016-10-26 15:44:27 +0200140 """
141 Verify captured input packet stream for defined interface.
142
143 :param object pg_if: Interface to verify captured packet stream for.
144 :param list capture: Captured packet stream.
145 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200146 last_info = dict()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200147 for i in self.interfaces:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200148 last_info[i.sw_if_index] = None
149 dst_sw_if_index = pg_if.sw_if_index
Damjan Marionf56b77a2016-10-03 19:44:57 +0200150 for packet in capture:
151 try:
152 ip = packet[IP]
153 udp = packet[UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -0800154 payload_info = self.payload_to_info(packet[Raw])
Klement Sekeraf62ae122016-10-11 11:47:09 +0200155 packet_index = payload_info.index
156 self.assertEqual(payload_info.dst, dst_sw_if_index)
Jan49c0fca2016-10-26 15:44:27 +0200157 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
158 (pg_if.name, payload_info.src, packet_index))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200159 next_info = self.get_next_packet_info_for_interface2(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200160 payload_info.src, dst_sw_if_index,
Damjan Marionf56b77a2016-10-03 19:44:57 +0200161 last_info[payload_info.src])
162 last_info[payload_info.src] = next_info
163 self.assertTrue(next_info is not None)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200164 self.assertEqual(packet_index, next_info.index)
165 saved_packet = next_info.data
Damjan Marionf56b77a2016-10-03 19:44:57 +0200166 # Check standard fields
Klement Sekeraf62ae122016-10-11 11:47:09 +0200167 self.assertEqual(ip.src, saved_packet[IP].src)
168 self.assertEqual(ip.dst, saved_packet[IP].dst)
169 self.assertEqual(udp.sport, saved_packet[UDP].sport)
170 self.assertEqual(udp.dport, saved_packet[UDP].dport)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200171 except:
Klement Sekera7bb873a2016-11-18 07:38:42 +0100172 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200173 raise
174 for i in self.interfaces:
175 remaining_packet = self.get_next_packet_info_for_interface2(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200176 i, dst_sw_if_index, last_info[i.sw_if_index])
Damjan Marionf56b77a2016-10-03 19:44:57 +0200177 self.assertTrue(remaining_packet is None,
178 "Port %u: Packet expected from source %u didn't"
Klement Sekeraf62ae122016-10-11 11:47:09 +0200179 " arrive" % (dst_sw_if_index, i.sw_if_index))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200180
Jan49c0fca2016-10-26 15:44:27 +0200181 def run_l2xc_test(self, pkts_per_burst):
182 """ L2XC test """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200183
Klement Sekeraf62ae122016-10-11 11:47:09 +0200184 # Create incoming packet streams for packet-generator interfaces
Damjan Marionf56b77a2016-10-03 19:44:57 +0200185 for i in self.interfaces:
Jan49c0fca2016-10-26 15:44:27 +0200186 pkts = self.create_stream(i, self.pg_if_packet_sizes,
187 pkts_per_burst)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200188 i.add_stream(pkts)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200189
Klement Sekeraf62ae122016-10-11 11:47:09 +0200190 # Enable packet capturing and start packet sending
191 self.pg_enable_capture(self.pg_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200192 self.pg_start()
193
Klement Sekeraf62ae122016-10-11 11:47:09 +0200194 # Verify outgoing packet streams per packet-generator interface
195 for i in self.pg_interfaces:
196 capture = i.get_capture()
Jan49c0fca2016-10-26 15:44:27 +0200197 self.logger.info("Verifying capture on interface %s" % i.name)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200198 self.verify_capture(i, capture)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200199
Jan49c0fca2016-10-26 15:44:27 +0200200 def test_l2xc_sl(self):
201 """ L2XC single-loop test
202
203 Test scenario:
204 1. config
205 2 pairs of 2 interfaces, l2xconnected
206
207 2. sending l2 eth packets between 4 interfaces
208 64B, 512B, 1518B, 9018B (ether_size)
209 burst of 2 packets per interface
210 """
211
212 self.run_l2xc_test(self.sl_pkts_per_burst)
213
214 def test_l2xc_dl(self):
215 """ L2XC dual-loop test
216
217 Test scenario:
218 1. config
219 2 pairs of 2 interfaces, l2xconnected
220
221 2. sending l2 eth packets between 4 interfaces
222 64B, 512B, 1518B, 9018B (ether_size)
223 burst of 257 packets per interface
224 """
225
226 self.run_l2xc_test(self.dl_pkts_per_burst)
227
Damjan Marionf56b77a2016-10-03 19:44:57 +0200228
229if __name__ == '__main__':
Klement Sekeraf62ae122016-10-11 11:47:09 +0200230 unittest.main(testRunner=VppTestRunner)