blob: 49ca99684f1611ebdb2bb776bb5de181472787a0 [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
Matej Klotton0178d522016-11-04 11:11:44 +010011from util import Host
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
Klement Sekeraf62ae122016-10-11 11:47:09 +020079 def setUp(self):
Jan49c0fca2016-10-26 15:44:27 +020080 """
81 Clear trace and packet infos before running each test.
82 """
Klement Sekeraf62ae122016-10-11 11:47:09 +020083 super(TestL2xc, self).setUp()
Jan49c0fca2016-10-26 15:44:27 +020084 self.packet_infos = {}
Klement Sekeraf62ae122016-10-11 11:47:09 +020085
Damjan Marionf56b77a2016-10-03 19:44:57 +020086 def tearDown(self):
Jan49c0fca2016-10-26 15:44:27 +020087 """
88 Show various debug prints after each test.
89 """
Klement Sekeraf62ae122016-10-11 11:47:09 +020090 super(TestL2xc, self).tearDown()
91 if not self.vpp_dead:
Jan49c0fca2016-10-26 15:44:27 +020092 self.logger.info(self.vapi.ppcli("show l2patch"))
Damjan Marionf56b77a2016-10-03 19:44:57 +020093
Jan49c0fca2016-10-26 15:44:27 +020094 @classmethod
95 def create_host_lists(cls, count):
96 """
97 Method to create required number of MAC and IPv4 addresses.
Klement Sekeraf62ae122016-10-11 11:47:09 +020098 Create required number of host MAC addresses and distribute them among
99 interfaces. Create host IPv4 address for every host MAC address too.
100
101 :param count: Number of hosts to create MAC and IPv4 addresses for.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200102 """
Jan49c0fca2016-10-26 15:44:27 +0200103 for pg_if in cls.pg_interfaces:
104 cls.hosts_by_pg_idx[pg_if.sw_if_index] = []
105 hosts = cls.hosts_by_pg_idx[pg_if.sw_if_index]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200106 for j in range(0, count):
Matej Klotton0178d522016-11-04 11:11:44 +0100107 host = Host(
Klement Sekeraf62ae122016-10-11 11:47:09 +0200108 "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j),
109 "172.17.1%02x.%u" % (pg_if.sw_if_index, j))
110 hosts.append(host)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200111
Jan49c0fca2016-10-26 15:44:27 +0200112 def create_stream(self, src_if, packet_sizes, packets_per_burst):
113 """
114 Create input packet stream for defined interface.
115
116 :param object src_if: Interface to create packet stream for.
117 :param list packet_sizes: List of required packet sizes.
118 :param int packets_per_burst: Number of packets in burst.
119 :return: Stream of packets.
120 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200121 pkts = []
Jan49c0fca2016-10-26 15:44:27 +0200122 for i in range(0, packets_per_burst):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200123 dst_if = self.flows[src_if][0]
124 dst_host = random.choice(self.hosts_by_pg_idx[dst_if.sw_if_index])
125 src_host = random.choice(self.hosts_by_pg_idx[src_if.sw_if_index])
126 pkt_info = self.create_packet_info(
127 src_if.sw_if_index, dst_if.sw_if_index)
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]
154 payload_info = self.payload_to_info(str(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:
Jan49c0fca2016-10-26 15:44:27 +0200172 self.logger.error("Unexpected or invalid packet:")
173 self.logger.error(packet.show())
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)