blob: eb4f4e32d1bcb3a70e900248385917d95096fdbe [file] [log] [blame]
Jan4af521d2016-11-15 17:05:00 +01001#!/usr/bin/env python
2"""L2 FIB Test Case HLD:
3
4**config 1**
5 - add 4 pg-l2 interfaces
6 - configure them into l2bd
7 - configure 100 MAC entries in L2 fib - 25 MACs per interface
8 - L2 MAC learning and unknown unicast flooding disabled in l2bd
9 - configure 100 MAC entries in L2 fib - 25 MACs per interface
10
11**test 1**
12 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 100 MAC \
13 entries in the FIB
14
15**verify 1**
16 - all packets received correctly
17
18**config 2**
19 - delete 12 MAC entries - 3 MACs per interface
20
21**test 2a**
22 - send L2 MAC frames between all 4 pg-l2 interfaces for non-deleted MAC \
23 entries
24
25**verify 2a**
26 - all packets received correctly
27
28**test 2b**
29 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 12 deleted \
30 MAC entries
31
32**verify 2b**
33 - no packet received on all 4 pg-l2 interfaces
34
35**config 3**
36 - configure new 100 MAC entries in L2 fib - 25 MACs per interface
37
38**test 3**
39 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 188 MAC \
40 entries in the FIB
41
42**verify 3**
43 - all packets received correctly
44
45**config 4**
46 - delete 160 MAC entries, 40 MACs per interface
47
48**test 4a**
49 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 28 \
50 non-deleted MAC entries
51
52**verify 4a**
53 - all packets received correctly
54
55**test 4b**
56 - try send L2 MAC frames between all 4 pg-l2 interfaces for all of 172 \
57 deleted MAC entries
58
59**verify 4b**
60 - no packet received on all 4 pg-l2 interfaces
61"""
62
63import unittest
64import random
65
66from scapy.packet import Raw
67from scapy.layers.l2 import Ether
68from scapy.layers.inet import IP, UDP
69
70from framework import VppTestCase, VppTestRunner
71from util import Host
72
73
74class TestL2fib(VppTestCase):
75 """ L2 FIB Test Case """
76
77 @classmethod
78 def setUpClass(cls):
79 """
80 Perform standard class setup (defined by class method setUpClass in
81 class VppTestCase) before running the test case, set test case related
82 variables and configure VPP.
83
84 :var int bd_id: Bridge domain ID.
85 :var int mac_entries_count: Number of MAC entries for bridge-domain.
86 """
87 super(TestL2fib, cls).setUpClass()
88
89 # Test variables
90 cls.bd_id = 1
91 cls.mac_entries_count = 200
92
93 try:
94 # Create 4 pg interfaces
95 cls.create_pg_interfaces(range(4))
96
97 # Packet flows mapping pg0 -> pg1, pg2, pg3 etc.
98 cls.flows = dict()
99 cls.flows[cls.pg0] = [cls.pg1, cls.pg2, cls.pg3]
100 cls.flows[cls.pg1] = [cls.pg0, cls.pg2, cls.pg3]
101 cls.flows[cls.pg2] = [cls.pg0, cls.pg1, cls.pg3]
102 cls.flows[cls.pg3] = [cls.pg0, cls.pg1, cls.pg2]
103
104 # Packet sizes
105 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
106
107 # Create BD with MAC learning and unknown unicast flooding disabled
108 # and put interfaces to this BD
109 cls.vapi.bridge_domain_add_del(bd_id=cls.bd_id, uu_flood=0, learn=0)
110 for pg_if in cls.pg_interfaces:
111 cls.vapi.sw_interface_set_l2_bridge(pg_if.sw_if_index,
112 bd_id=cls.bd_id)
113
114 # Set up all interfaces
115 for i in cls.pg_interfaces:
116 i.admin_up()
117
118 # Mapping between packet-generator index and lists of test hosts
119 cls.hosts_by_pg_idx = dict()
120 for pg_if in cls.pg_interfaces:
121 cls.hosts_by_pg_idx[pg_if.sw_if_index] = []
122
123 # Create list of deleted hosts
124 cls.deleted_hosts_by_pg_idx = dict()
125 for pg_if in cls.pg_interfaces:
126 cls.deleted_hosts_by_pg_idx[pg_if.sw_if_index] = []
127
128 except Exception:
129 super(TestL2fib, cls).tearDownClass()
130 raise
131
132 def setUp(self):
133 """
134 Clear trace and packet infos before running each test.
135 """
136 super(TestL2fib, self).setUp()
137 self.packet_infos = {}
138
139 def tearDown(self):
140 """
141 Show various debug prints after each test.
142 """
143 super(TestL2fib, self).tearDown()
144 if not self.vpp_dead:
145 self.logger.info(self.vapi.ppcli("show l2fib verbose"))
146 self.logger.info(self.vapi.ppcli("show bridge-domain %s detail"
147 % self.bd_id))
148
149 def create_hosts(self, count, start=0):
150 """
151 Create required number of host MAC addresses and distribute them among
152 interfaces. Create host IPv4 address for every host MAC address.
153
154 :param int count: Number of hosts to create MAC/IPv4 addresses for.
155 :param int start: Number to start numbering from.
156 """
157 n_int = len(self.pg_interfaces)
158 macs_per_if = count / n_int
159 i = -1
160 for pg_if in self.pg_interfaces:
161 i += 1
162 start_nr = macs_per_if * i + start
163 end_nr = count + start if i == (n_int - 1) \
164 else macs_per_if * (i + 1) + start
165 hosts = self.hosts_by_pg_idx[pg_if.sw_if_index]
166 for j in range(start_nr, end_nr):
167 host = Host(
168 "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j),
169 "172.17.1%02x.%u" % (pg_if.sw_if_index, j))
170 hosts.append(host)
171
172 def config_l2_fib_entries(self, count, start=0):
173 """
174 Create required number of L2 FIB entries.
175
176 :param int count: Number of L2 FIB entries to be created.
177 :param int start: Starting index of the host list. (Default value = 0)
178 """
179 n_int = len(self.pg_interfaces)
180 percent = 0
181 counter = 0.0
182 for pg_if in self.pg_interfaces:
183 end_nr = start + count / n_int
184 for j in range(start, end_nr):
185 host = self.hosts_by_pg_idx[pg_if.sw_if_index][j]
186 self.vapi.l2fib_add_del(host.mac, self.bd_id, pg_if.sw_if_index,
187 static_mac=1)
188 counter += 1
189 percentage = counter / count * 100
190 if percentage > percent:
191 self.logger.info("Configure %d L2 FIB entries .. %d%% done"
192 % (count, percentage))
193 percent += 1
194 self.logger.info(self.vapi.ppcli("show l2fib"))
195
196 def delete_l2_fib_entry(self, count):
197 """
198 Delete required number of L2 FIB entries.
199
200 :param int count: Number of L2 FIB entries to be created.
201 """
202 n_int = len(self.pg_interfaces)
203 percent = 0
204 counter = 0.0
205 for pg_if in self.pg_interfaces:
206 for j in range(count / n_int):
207 host = self.hosts_by_pg_idx[pg_if.sw_if_index][0]
208 self.vapi.l2fib_add_del(host.mac, self.bd_id, pg_if.sw_if_index,
209 is_add=0)
210 self.deleted_hosts_by_pg_idx[pg_if.sw_if_index].append(host)
211 del self.hosts_by_pg_idx[pg_if.sw_if_index][0]
212 counter += 1
213 percentage = counter / count * 100
214 if percentage > percent:
215 self.logger.info("Delete %d L2 FIB entries .. %d%% done"
216 % (count, percentage))
217 percent += 1
218 self.logger.info(self.vapi.ppcli("show l2fib"))
219
220 def create_stream(self, src_if, packet_sizes, deleted=False):
221 """
222 Create input packet stream for defined interface using hosts or
223 deleted_hosts list.
224
225 :param object src_if: Interface to create packet stream for.
226 :param list packet_sizes: List of required packet sizes.
227 :param boolean deleted: Set to True if deleted_hosts list required.
228 :return: Stream of packets.
229 """
230 pkts = []
231 src_hosts = self.hosts_by_pg_idx[src_if.sw_if_index]
232 for dst_if in self.flows[src_if]:
233 dst_hosts = self.deleted_hosts_by_pg_idx[dst_if.sw_if_index]\
234 if deleted else self.hosts_by_pg_idx[dst_if.sw_if_index]
235 n_int = len(dst_hosts)
236 for i in range(0, n_int):
237 dst_host = dst_hosts[i]
238 src_host = random.choice(src_hosts)
239 pkt_info = self.create_packet_info(
240 src_if.sw_if_index, dst_if.sw_if_index)
241 payload = self.info_to_payload(pkt_info)
242 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
243 IP(src=src_host.ip4, dst=dst_host.ip4) /
244 UDP(sport=1234, dport=1234) /
245 Raw(payload))
246 pkt_info.data = p.copy()
247 size = random.choice(packet_sizes)
248 self.extend_packet(p, size)
249 pkts.append(p)
250 return pkts
251
252 def verify_capture(self, pg_if, capture):
253 """
254 Verify captured input packet stream for defined interface.
255
256 :param object pg_if: Interface to verify captured packet stream for.
257 :param list capture: Captured packet stream.
258 """
259 last_info = dict()
260 for i in self.pg_interfaces:
261 last_info[i.sw_if_index] = None
262 dst_sw_if_index = pg_if.sw_if_index
263 for packet in capture:
264 payload_info = self.payload_to_info(str(packet[Raw]))
265 try:
266 ip = packet[IP]
267 udp = packet[UDP]
268 packet_index = payload_info.index
269 self.assertEqual(payload_info.dst, dst_sw_if_index)
270 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
271 (pg_if.name, payload_info.src, packet_index))
272 next_info = self.get_next_packet_info_for_interface2(
273 payload_info.src, dst_sw_if_index,
274 last_info[payload_info.src])
275 last_info[payload_info.src] = next_info
276 self.assertTrue(next_info is not None)
277 self.assertEqual(packet_index, next_info.index)
278 saved_packet = next_info.data
279 # Check standard fields
280 self.assertEqual(ip.src, saved_packet[IP].src)
281 self.assertEqual(ip.dst, saved_packet[IP].dst)
282 self.assertEqual(udp.sport, saved_packet[UDP].sport)
283 self.assertEqual(udp.dport, saved_packet[UDP].dport)
284 except:
285 self.logger.error("Unexpected or invalid packet:")
286 self.logger.error(packet.show())
287 raise
288 for i in self.pg_interfaces:
289 remaining_packet = self.get_next_packet_info_for_interface2(
290 i, dst_sw_if_index, last_info[i.sw_if_index])
291 self.assertTrue(
292 remaining_packet is None,
293 "Port %u: Packet expected from source %u didn't arrive" %
294 (dst_sw_if_index, i.sw_if_index))
295
296 def run_verify_test(self):
297 # Test
298 # Create incoming packet streams for packet-generator interfaces
299 for i in self.pg_interfaces:
300 pkts = self.create_stream(i, self.pg_if_packet_sizes)
301 i.add_stream(pkts)
302
303 # Enable packet capture and start packet sending
304 self.pg_enable_capture(self.pg_interfaces)
305 self.pg_start()
306
307 # Verify
308 # Verify outgoing packet streams per packet-generator interface
309 for i in self.pg_interfaces:
310 capture = i.get_capture()
311 self.logger.info("Verifying capture on interface %s" % i.name)
312 self.verify_capture(i, capture)
313
314 def run_verify_negat_test(self):
315 # Test
316 # Create incoming packet streams for packet-generator interfaces for
317 # deleted MAC addresses
318 self.packet_infos = {}
319 for i in self.pg_interfaces:
320 pkts = self.create_stream(i, self.pg_if_packet_sizes, deleted=True)
321 i.add_stream(pkts)
322
323 # Enable packet capture and start packet sending
324 self.pg_enable_capture(self.pg_interfaces)
325 self.pg_start()
326
327 # Verify
328 # Verify outgoing packet streams per packet-generator interface
329 for i in self.pg_interfaces:
330 capture = i.get_capture()
331 self.logger.info("Verifying capture on interface %s" % i.name)
332 try:
333 self.assertEqual(len(capture), 0)
334 except AssertionError:
335 self.logger.error("The capture on interface %s is not empty!"
336 % i.name)
337 raise AssertionError("%d != 0" % len(capture))
338
339 def test_l2_fib_01(self):
340 """ L2 FIB test 1 - program 100 MAC addresses
341 """
342 # Config 1
343 # Create test host entries
344 self.create_hosts(100)
345
346 # Add first 100 MAC entries to L2 FIB
347 self.config_l2_fib_entries(100)
348
349 # Test 1
350 self.run_verify_test()
351
352 def test_l2_fib_02(self):
353 """ L2 FIB test 2 - delete 12 MAC entries
354 """
355 # Config 2
356 # Delete 12 MAC entries (3 per interface) from L2 FIB
357 self.delete_l2_fib_entry(12)
358
359 # Test 2a
360 self.run_verify_test()
361
362 # Verify 2a
363 self.run_verify_negat_test()
364
365 def test_l2_fib_03(self):
366 """ L2 FIB test 3 - program new 100 MAC addresses
367 """
368 # Config 3
369 # Create new test host entries
370 self.create_hosts(100, start=100)
371
372 # Add new 100 MAC entries to L2 FIB
373 self.config_l2_fib_entries(100, start=22)
374
375 # Test 3
376 self.run_verify_test()
377
378 def test_l2_fib_04(self):
379 """ L2 FIB test 4 - delete 160 MAC entries
380 """
381 # Config 4
382 # Delete 160 MAC entries (40 per interface) from L2 FIB
383 self.delete_l2_fib_entry(160)
384
385 # Test 4a
386 self.run_verify_negat_test()
387
388
389if __name__ == '__main__':
390 unittest.main(testRunner=VppTestRunner)