Skip L2 FIB flush tests
[vpp.git] / test / test_l2_fib.py
1 #!/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
63 import unittest
64 import random
65
66 from scapy.packet import Raw
67 from scapy.layers.l2 import Ether
68 from scapy.layers.inet import IP, UDP
69
70 from framework import VppTestCase, VppTestRunner
71 from util import Host, ppp
72
73
74 class TestL2fib(VppTestCase):
75     """ L2 FIB Test Case """
76
77     @classmethod
78     def bd_ifs(cls, bd_id):
79         return range((bd_id - 1) * cls.n_ifs_per_bd, bd_id * cls.n_ifs_per_bd)
80
81     @classmethod
82     def setUpClass(cls):
83         """
84         Perform standard class setup (defined by class method setUpClass in
85         class VppTestCase) before running the test case, set test case related
86         variables and configure VPP.
87
88         :var int bd_id: Bridge domain ID.
89         """
90         super(TestL2fib, cls).setUpClass()
91
92         try:
93             n_brs = cls.n_brs = range(1, 3)
94             cls.n_ifs_per_bd = 4
95             n_ifs = range(cls.n_ifs_per_bd * len(cls.n_brs))
96             # Create 4 pg interfaces
97             cls.create_pg_interfaces(n_ifs)
98
99             cls.flows = dict()
100             for bd_id in n_brs:
101                 # Packet flows mapping pg0 -> pg1, pg2, pg3 etc.
102                 ifs = cls.bd_ifs(bd_id)
103                 for j in ifs:
104                     cls.flows[cls.pg_interfaces[j]] = [
105                         cls.pg_interfaces[x] for x in ifs if x != j]
106
107             # Packet sizes
108             cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
109
110             for bd_id in n_brs:
111                 # Create BD with MAC learning and unknown unicast flooding
112                 # disabled and put interfaces to this BD
113                 cls.vapi.bridge_domain_add_del(
114                     bd_id=bd_id, uu_flood=0, learn=0)
115                 ifs = [cls.pg_interfaces[i] for i in cls.bd_ifs(bd_id)]
116                 for pg_if in ifs:
117                     cls.vapi.sw_interface_set_l2_bridge(pg_if.sw_if_index,
118                                                         bd_id=bd_id)
119
120             # Set up all interfaces
121             for i in cls.pg_interfaces:
122                 i.admin_up()
123
124             # Mapping between packet-generator index and lists of test hosts
125             cls.hosts = dict()
126             cls.fib_hosts = dict()
127             cls.deleted_hosts = dict()
128             for pg_if in cls.pg_interfaces:
129                 cls.hosts[pg_if.sw_if_index] = []
130                 cls.fib_hosts[pg_if.sw_if_index] = []
131                 cls.deleted_hosts[pg_if.sw_if_index] = []
132
133         except Exception:
134             super(TestL2fib, cls).tearDownClass()
135             raise
136
137     def setUp(self):
138         super(TestL2fib, self).setUp()
139         self.reset_packet_infos()
140
141     def tearDown(self):
142         """
143         Show various debug prints after each test.
144         """
145         super(TestL2fib, self).tearDown()
146         if not self.vpp_dead:
147             self.logger.info(self.vapi.ppcli("show l2fib verbose"))
148             for bd_id in self.n_brs:
149                 self.logger.info(self.vapi.ppcli("show bridge-domain %s detail"
150                                                  % bd_id))
151
152     def create_hosts(self, n_hosts_per_if, subnet):
153         """
154         Create required number of host MAC addresses and distribute them among
155         interfaces. Create host IPv4 address for every host MAC address.
156
157         :param int n_hosts_per_if: Number of per interface hosts to
158         create MAC/IPv4 addresses for.
159         """
160
161         for pg_if in self.pg_interfaces:
162             swif = pg_if.sw_if_index
163
164             def mac(j): return "00:00:%02x:ff:%02x:%02x" % (subnet, swif, j)
165
166             def ip(j): return "172.%02u.1%02x.%u" % (subnet, swif, j)
167
168             def h(j): return Host(mac(j), ip(j))
169             self.hosts[swif] = [h(j) for j in range(n_hosts_per_if)]
170
171     def config_l2_fib_entries(self, bd_id, n_hosts_per_if):
172         """
173         Config required number of L2 FIB entries.
174
175         :param int bd_id: BD's id
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         ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
180         for pg_if in ifs:
181             swif = pg_if.sw_if_index
182             hosts = self.hosts[swif]
183             fhosts = self.fib_hosts[swif]
184             for j in range(n_hosts_per_if):
185                 host = hosts.pop()
186                 self.vapi.l2fib_add_del(
187                     host.mac, bd_id, swif, static_mac=1)
188                 fhosts.append(host)
189         #        del hosts[0]
190         self.logger.info("Configure %d L2 FIB entries .." %
191                          len(self.pg_interfaces) * n_hosts_per_if)
192         self.logger.info(self.vapi.ppcli("show l2fib"))
193
194     def delete_l2_fib_entry(self, bd_id, n_hosts_per_if):
195         """
196         Delete required number of L2 FIB entries.
197
198         :param int count: Number of L2 FIB entries to be created.
199         """
200         ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
201         for pg_if in ifs:
202             swif = pg_if.sw_if_index
203             hosts = self.fib_hosts[swif]
204             dhosts = self.deleted_hosts[swif]
205             for j in range(n_hosts_per_if):
206                 host = hosts.pop()
207                 self.vapi.l2fib_add_del(
208                     host.mac, bd_id, swif, is_add=0)
209                 dhosts.append(host)
210         self.logger.info(self.vapi.ppcli("show l2fib"))
211
212     def flush_int(self, swif):
213         """
214         Flush swif L2 FIB entries.
215
216         :param int swif: sw if index.
217         """
218         self.vapi.l2fib_flush_int(swif)
219         self.deleted_hosts[swif] = self.fib_hosts[swif] + \
220             self.deleted_hosts[swif]
221         self.fib_hosts[swif] = []
222         self.logger.info(self.vapi.ppcli("show l2fib"))
223
224     def flush_bd(self, bd_id):
225         """
226         Flush bd_id L2 FIB entries.
227
228         :param int bd_id: Bridge Domain id.
229         """
230         self.vapi.l2fib_flush_bd(bd_id)
231         ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
232         for pg_if in ifs:
233             swif = pg_if.sw_if_index
234             self.deleted_hosts[swif] = self.fib_hosts[swif] + \
235                 self.deleted_hosts[swif]
236             self.fib_hosts[swif] = []
237         self.logger.info(self.vapi.ppcli("show l2fib"))
238
239     def flush_all(self):
240         """
241         Flush All L2 FIB entries.
242         """
243         self.vapi.l2fib_flush_all()
244         for pg_if in self.pg_interfaces:
245             swif = pg_if.sw_if_index
246             self.deleted_hosts[swif] = self.fib_hosts[swif] + \
247                 self.deleted_hosts[swif]
248             self.fib_hosts[swif] = []
249         self.logger.info(self.vapi.ppcli("show l2fib"))
250
251     def create_stream(self, src_if, packet_sizes, deleted=False):
252         """
253         Create input packet stream for defined interface using hosts or
254         deleted_hosts list.
255
256         :param object src_if: Interface to create packet stream for.
257         :param list packet_sizes: List of required packet sizes.
258         :param boolean deleted: Set to True if deleted_hosts list required.
259         :return: Stream of packets.
260         """
261         src_hosts = self.fib_hosts[src_if.sw_if_index]
262         if not src_hosts:
263             return []
264         pkts = []
265         for dst_if in self.flows[src_if]:
266             dst_hosts = self.deleted_hosts[dst_if.sw_if_index]\
267                 if deleted else self.fib_hosts[dst_if.sw_if_index]
268             for i in range(0, len(dst_hosts)):
269                 dst_host = dst_hosts[i]
270                 src_host = random.choice(src_hosts)
271                 pkt_info = self.create_packet_info(src_if, dst_if)
272                 payload = self.info_to_payload(pkt_info)
273                 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
274                      IP(src=src_host.ip4, dst=dst_host.ip4) /
275                      UDP(sport=1234, dport=1234) /
276                      Raw(payload))
277                 pkt_info.data = p.copy()
278                 size = random.choice(packet_sizes)
279                 self.extend_packet(p, size)
280                 pkts.append(p)
281         return pkts
282
283     def verify_capture(self, pg_if, capture):
284         """
285         Verify captured input packet stream for defined interface.
286
287         :param object pg_if: Interface to verify captured packet stream for.
288         :param list capture: Captured packet stream.
289         """
290         last_info = dict()
291         for i in self.pg_interfaces:
292             last_info[i.sw_if_index] = None
293         dst_sw_if_index = pg_if.sw_if_index
294         for packet in capture:
295             payload_info = self.payload_to_info(str(packet[Raw]))
296             try:
297                 ip = packet[IP]
298                 udp = packet[UDP]
299                 packet_index = payload_info.index
300                 self.assertEqual(payload_info.dst, dst_sw_if_index)
301                 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
302                                   (pg_if.name, payload_info.src, packet_index))
303                 next_info = self.get_next_packet_info_for_interface2(
304                     payload_info.src, dst_sw_if_index,
305                     last_info[payload_info.src])
306                 last_info[payload_info.src] = next_info
307                 self.assertTrue(next_info is not None)
308                 self.assertEqual(packet_index, next_info.index)
309                 saved_packet = next_info.data
310                 # Check standard fields
311                 self.assertEqual(ip.src, saved_packet[IP].src)
312                 self.assertEqual(ip.dst, saved_packet[IP].dst)
313                 self.assertEqual(udp.sport, saved_packet[UDP].sport)
314                 self.assertEqual(udp.dport, saved_packet[UDP].dport)
315             except:
316                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
317                 raise
318         for i in self.pg_interfaces:
319             remaining_packet = self.get_next_packet_info_for_interface2(
320                 i, dst_sw_if_index, last_info[i.sw_if_index])
321             self.assertTrue(
322                 remaining_packet is None,
323                 "Port %u: Packet expected from source %u didn't arrive" %
324                 (dst_sw_if_index, i.sw_if_index))
325
326     def run_verify_test(self, bd_id):
327         # Test
328         # Create incoming packet streams for packet-generator interfaces
329         self.reset_packet_infos()
330         ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
331         for i in ifs:
332             pkts = self.create_stream(i, self.pg_if_packet_sizes)
333             i.add_stream(pkts)
334
335         # Enable packet capture and start packet sending
336         self.pg_enable_capture(ifs)
337         self.pg_start()
338
339         # Verify
340         # Verify outgoing packet streams per packet-generator interface
341         for i in ifs:
342             capture = i.get_capture()
343             self.logger.info("Verifying capture on interface %s" % i.name)
344             self.verify_capture(i, capture)
345
346     def run_verify_negat_test(self, bd_id):
347         # Test
348         # Create incoming packet streams for packet-generator interfaces for
349         # deleted MAC addresses
350         self.reset_packet_infos()
351         ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
352         for i in ifs:
353             pkts = self.create_stream(i, self.pg_if_packet_sizes, deleted=True)
354             if pkts:
355                 i.add_stream(pkts)
356
357         # Enable packet capture and start packet sending
358         self.pg_enable_capture(ifs)
359         self.pg_start()
360
361         # Verify
362         # Verify outgoing packet streams per packet-generator interface
363         timeout = 1
364         for i in ifs:
365             i.get_capture(0, timeout=timeout)
366             i.assert_nothing_captured(remark="outgoing interface")
367             timeout = 0.1
368
369     def test_l2_fib_01(self):
370         """ L2 FIB test 1 - program 100 MAC addresses
371         """
372         # Config 1
373         # Create test host entries
374         self.create_hosts(100, subnet=17)
375
376         # Add first 100 MAC entries to L2 FIB
377         self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=100)
378
379         # Test 1
380         self.run_verify_test(bd_id=1)
381
382     def test_l2_fib_02(self):
383         """ L2 FIB test 2 - delete 12 MAC entries
384         """
385         # Config 2
386         # Delete 12 MAC entries per interface from L2 FIB
387         self.delete_l2_fib_entry(bd_id=1, n_hosts_per_if=12)
388
389         # Test 2a
390         self.run_verify_test(bd_id=1)
391
392         # Verify 2a
393         self.run_verify_negat_test(bd_id=1)
394
395     def test_l2_fib_03(self):
396         """ L2 FIB test 3 - program new 100 MAC addresses
397         """
398         # Config 3
399         # Create new test host entries
400         self.create_hosts(100, subnet=22)
401
402         # Add new 100 MAC entries to L2 FIB
403         self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=100)
404
405         # Test 3
406         self.run_verify_test(bd_id=1)
407
408     def test_l2_fib_04(self):
409         """ L2 FIB test 4 - delete 160 MAC entries
410         """
411         # Config 4
412         # Delete 160 MAC entries per interface from L2 FIB
413         self.delete_l2_fib_entry(bd_id=1, n_hosts_per_if=160)
414
415         # Test 4a
416         self.run_verify_negat_test(bd_id=1)
417
418     @unittest.skip("can't flush static entries")
419     def test_l2_fib_05(self):
420         """ L2 FIB test 5 - flush first interface
421         """
422         self.flush_int(self.pg_interfaces[0].sw_if_index)
423         self.sleep(3)
424         self.create_hosts(1, subnet=31)
425         self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=1)
426         self.run_verify_test(bd_id=1)
427         self.run_verify_negat_test(bd_id=1)
428
429     @unittest.skip("can't flush static entries")
430     def test_l2_fib_06(self):
431         """ L2 FIB test 6 - Program 20 new MAC entries
432         """
433         self.create_hosts(20, subnet=33)
434
435         self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=20)
436         self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=20)
437         self.run_verify_test(bd_id=1)
438         self.run_verify_test(bd_id=2)
439
440     @unittest.skip("can't flush static entries")
441     def test_l2_fib_07(self):
442         """ L2 FIB test 7 - flush bd_id
443         """
444         self.flush_bd(bd_id=1)
445         self.run_verify_negat_test(bd_id=1)
446         self.run_verify_test(bd_id=2)
447
448     @unittest.skip("can't flush static entries")
449     def test_l2_fib_08(self):
450         """ L2 FIB test 8 - Program 20 new MAC entries
451         """
452         self.create_hosts(20, subnet=34)
453
454         self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=20)
455         self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=20)
456         self.run_verify_test(bd_id=1)
457         self.run_verify_test(bd_id=2)
458
459     @unittest.skip("can't flush static entries")
460     def test_l2_fib_09(self):
461         """ L2 FIB test 9 - flush all
462         """
463         self.flush_all()
464         self.sleep(3)
465         self.run_verify_negat_test(bd_id=1)
466         self.run_verify_negat_test(bd_id=2)
467
468     @unittest.skip("can't flush static entries")
469     def test_l2_fib_10(self):
470         """ L2 FIB test 10 - Program 20 new MAC entries
471         """
472         self.create_hosts(20, subnet=35)
473
474         self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=20)
475         self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=20)
476         self.run_verify_test(bd_id=1)
477         self.run_verify_test(bd_id=2)
478         self.run_verify_negat_test(bd_id=1)
479         self.run_verify_negat_test(bd_id=2)
480
481
482 if __name__ == '__main__':
483     unittest.main(testRunner=VppTestRunner)