2 """L2 FIB Test Case HLD:
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
12 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 100 MAC \
16 - all packets received correctly
19 - delete 12 MAC entries - 3 MACs per interface
22 - send L2 MAC frames between all 4 pg-l2 interfaces for non-deleted MAC \
26 - all packets received correctly
29 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 12 deleted \
33 - no packet received on all 4 pg-l2 interfaces
36 - configure new 100 MAC entries in L2 fib - 25 MACs per interface
39 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 188 MAC \
43 - all packets received correctly
46 - delete 160 MAC entries, 40 MACs per interface
49 - send L2 MAC frames between all 4 pg-l2 interfaces for all of 28 \
50 non-deleted MAC entries
53 - all packets received correctly
56 - try send L2 MAC frames between all 4 pg-l2 interfaces for all of 172 \
60 - no packet received on all 4 pg-l2 interfaces
66 from scapy.packet import Raw
67 from scapy.layers.l2 import Ether
68 from scapy.layers.inet import IP, UDP
70 from framework import VppTestCase, VppTestRunner
71 from util import Host, ppp
74 class TestL2fib(VppTestCase):
75 """ L2 FIB Test Case """
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)
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.
88 :var int bd_id: Bridge domain ID.
90 super(TestL2fib, cls).setUpClass()
93 n_brs = cls.n_brs = range(1, 3)
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)
101 # Packet flows mapping pg0 -> pg1, pg2, pg3 etc.
102 ifs = cls.bd_ifs(bd_id)
104 cls.flows[cls.pg_interfaces[j]] = [
105 cls.pg_interfaces[x] for x in ifs if x != j]
108 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
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)]
117 cls.vapi.sw_interface_set_l2_bridge(pg_if.sw_if_index,
120 # Set up all interfaces
121 for i in cls.pg_interfaces:
124 # Mapping between packet-generator index and lists of test hosts
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] = []
134 super(TestL2fib, cls).tearDownClass()
138 super(TestL2fib, self).setUp()
139 self.reset_packet_infos()
143 Show various debug prints after each test.
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"
152 def create_hosts(self, n_hosts_per_if, subnet):
154 Create required number of host MAC addresses and distribute them among
155 interfaces. Create host IPv4 address for every host MAC address.
157 :param int n_hosts_per_if: Number of per interface hosts to
158 create MAC/IPv4 addresses for.
161 for pg_if in self.pg_interfaces:
162 swif = pg_if.sw_if_index
164 def mac(j): return "00:00:%02x:ff:%02x:%02x" % (subnet, swif, j)
166 def ip(j): return "172.%02u.1%02x.%u" % (subnet, swif, j)
168 def h(j): return Host(mac(j), ip(j))
169 self.hosts[swif] = [h(j) for j in range(n_hosts_per_if)]
171 def config_l2_fib_entries(self, bd_id, n_hosts_per_if):
173 Config required number of L2 FIB entries.
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)
179 ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
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):
186 self.vapi.l2fib_add_del(
187 host.mac, bd_id, swif, static_mac=1)
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"))
194 def delete_l2_fib_entry(self, bd_id, n_hosts_per_if):
196 Delete required number of L2 FIB entries.
198 :param int count: Number of L2 FIB entries to be created.
200 ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
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):
207 self.vapi.l2fib_add_del(
208 host.mac, bd_id, swif, is_add=0)
210 self.logger.info(self.vapi.ppcli("show l2fib"))
212 def flush_int(self, swif):
214 Flush swif L2 FIB entries.
216 :param int swif: sw if index.
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"))
224 def flush_bd(self, bd_id):
226 Flush bd_id L2 FIB entries.
228 :param int bd_id: Bridge Domain id.
230 self.vapi.l2fib_flush_bd(bd_id)
231 ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
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"))
241 Flush All L2 FIB entries.
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"))
251 def create_stream(self, src_if, packet_sizes, deleted=False):
253 Create input packet stream for defined interface using hosts or
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.
261 src_hosts = self.fib_hosts[src_if.sw_if_index]
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) /
277 pkt_info.data = p.copy()
278 size = random.choice(packet_sizes)
279 self.extend_packet(p, size)
283 def verify_capture(self, pg_if, capture):
285 Verify captured input packet stream for defined interface.
287 :param object pg_if: Interface to verify captured packet stream for.
288 :param list capture: Captured packet stream.
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]))
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)
316 self.logger.error(ppp("Unexpected or invalid packet:", packet))
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])
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))
326 def run_verify_test(self, bd_id):
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)]
332 pkts = self.create_stream(i, self.pg_if_packet_sizes)
335 # Enable packet capture and start packet sending
336 self.pg_enable_capture(ifs)
340 # Verify outgoing packet streams per packet-generator interface
342 capture = i.get_capture()
343 self.logger.info("Verifying capture on interface %s" % i.name)
344 self.verify_capture(i, capture)
346 def run_verify_negat_test(self, bd_id):
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)]
353 pkts = self.create_stream(i, self.pg_if_packet_sizes, deleted=True)
357 # Enable packet capture and start packet sending
358 self.pg_enable_capture(ifs)
362 # Verify outgoing packet streams per packet-generator interface
364 i.assert_nothing_captured(remark="outgoing interface")
366 def test_l2_fib_01(self):
367 """ L2 FIB test 1 - program 100 MAC addresses
370 # Create test host entries
371 self.create_hosts(100, subnet=17)
373 # Add first 100 MAC entries to L2 FIB
374 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=100)
377 self.run_verify_test(bd_id=1)
379 def test_l2_fib_02(self):
380 """ L2 FIB test 2 - delete 12 MAC entries
383 # Delete 12 MAC entries per interface from L2 FIB
384 self.delete_l2_fib_entry(bd_id=1, n_hosts_per_if=12)
387 self.run_verify_test(bd_id=1)
390 self.run_verify_negat_test(bd_id=1)
392 def test_l2_fib_03(self):
393 """ L2 FIB test 3 - program new 100 MAC addresses
396 # Create new test host entries
397 self.create_hosts(100, subnet=22)
399 # Add new 100 MAC entries to L2 FIB
400 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=100)
403 self.run_verify_test(bd_id=1)
405 def test_l2_fib_04(self):
406 """ L2 FIB test 4 - delete 160 MAC entries
409 # Delete 160 MAC entries per interface from L2 FIB
410 self.delete_l2_fib_entry(bd_id=1, n_hosts_per_if=160)
413 self.run_verify_negat_test(bd_id=1)
415 def test_l2_fib_05(self):
416 """ L2 FIB test 5 - flush first interface
418 self.flush_int(self.pg_interfaces[0].sw_if_index)
420 self.create_hosts(1, subnet=31)
421 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=1)
422 self.run_verify_test(bd_id=1)
423 self.run_verify_negat_test(bd_id=1)
425 def test_l2_fib_06(self):
426 """ L2 FIB test 6 - Program 20 new MAC entries
428 self.create_hosts(20, subnet=33)
430 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=20)
431 self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=20)
432 self.run_verify_test(bd_id=1)
433 self.run_verify_test(bd_id=2)
435 def test_l2_fib_07(self):
436 """ L2 FIB test 7 - flush bd_id
438 self.flush_bd(bd_id=1)
439 self.run_verify_negat_test(bd_id=1)
440 self.run_verify_test(bd_id=2)
442 def test_l2_fib_08(self):
443 """ L2 FIB test 8 - Program 20 new MAC entries
445 self.create_hosts(20, subnet=34)
447 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=20)
448 self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=20)
449 self.run_verify_test(bd_id=1)
450 self.run_verify_test(bd_id=2)
452 def test_l2_fib_09(self):
453 """ L2 FIB test 9 - flush all
457 self.run_verify_negat_test(bd_id=1)
458 self.run_verify_negat_test(bd_id=2)
460 def test_l2_fib_10(self):
461 """ L2 FIB test 10 - Program 20 new MAC entries
463 self.create_hosts(20, subnet=35)
465 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=20)
466 self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=20)
467 self.run_verify_test(bd_id=1)
468 self.run_verify_test(bd_id=2)
469 self.run_verify_negat_test(bd_id=1)
470 self.run_verify_negat_test(bd_id=2)
473 if __name__ == '__main__':
474 unittest.main(testRunner=VppTestRunner)