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.learned_hosts = dict()
127 cls.fib_hosts = dict()
128 cls.deleted_hosts = dict()
129 for pg_if in cls.pg_interfaces:
130 swif = pg_if.sw_if_index
132 cls.learned_hosts[swif] = []
133 cls.fib_hosts[swif] = []
134 cls.deleted_hosts[swif] = []
137 super(TestL2fib, cls).tearDownClass()
141 super(TestL2fib, self).setUp()
142 self.reset_packet_infos()
146 Show various debug prints after each test.
148 super(TestL2fib, self).tearDown()
149 if not self.vpp_dead:
150 self.logger.info(self.vapi.ppcli("show l2fib verbose"))
151 for bd_id in self.n_brs:
152 self.logger.info(self.vapi.ppcli("show bridge-domain %s detail"
155 def create_hosts(self, n_hosts_per_if, subnet):
157 Create required number of host MAC addresses and distribute them among
158 interfaces. Create host IPv4 address for every host MAC address.
160 :param int n_hosts_per_if: Number of per interface hosts to
161 create MAC/IPv4 addresses for.
164 for pg_if in self.pg_interfaces:
165 swif = pg_if.sw_if_index
167 def mac(j): return "00:00:%02x:ff:%02x:%02x" % (subnet, swif, j)
169 def ip(j): return "172.%02u.1%02x.%u" % (subnet, swif, j)
171 def h(j): return Host(mac(j), ip(j))
172 self.hosts[swif] = [h(j) for j in range(n_hosts_per_if)]
174 def learn_hosts(self, bd_id, n_hosts_per_if):
176 Create L2 MAC packet stream with host MAC addresses per interface to
177 let the bridge domain learn these MAC addresses.
179 :param int bd_id: BD to teach
180 :param int n_hosts_per_if: number of hosts
182 self.vapi.bridge_flags(bd_id, 1, 1)
183 ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
185 swif = pg_if.sw_if_index
186 hosts = self.hosts[swif]
187 lhosts = self.learned_hosts[swif]
189 for j in range(n_hosts_per_if):
192 packet = (Ether(dst="ff:ff:ff:ff:ff:ff", src=host.mac))
193 packets.append(packet)
194 pg_if.add_stream(packets)
195 self.logger.info("Sending broadcast eth frames for MAC learning")
198 def config_l2_fib_entries(self, bd_id, n_hosts_per_if):
200 Config required number of L2 FIB entries.
202 :param int bd_id: BD's id
203 :param int count: Number of L2 FIB entries to be created.
204 :param int start: Starting index of the host list. (Default value = 0)
206 ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
208 swif = pg_if.sw_if_index
209 hosts = self.hosts[swif]
210 fhosts = self.fib_hosts[swif]
211 for j in range(n_hosts_per_if):
213 self.vapi.l2fib_add_del(
214 host.mac, bd_id, swif, static_mac=1)
217 self.logger.info("Configure %d L2 FIB entries .." %
218 len(self.pg_interfaces) * n_hosts_per_if)
219 self.logger.info(self.vapi.ppcli("show l2fib"))
221 def delete_l2_fib_entry(self, bd_id, n_hosts_per_if):
223 Delete required number of L2 FIB entries.
225 :param int count: Number of L2 FIB entries to be created.
227 ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
229 swif = pg_if.sw_if_index
230 hosts = self.fib_hosts[swif]
231 dhosts = self.deleted_hosts[swif]
232 for j in range(n_hosts_per_if):
234 self.vapi.l2fib_add_del(
235 host.mac, bd_id, swif, is_add=0)
237 self.logger.info(self.vapi.ppcli("show l2fib"))
239 def flush_int(self, swif):
241 Flush swif L2 FIB entries.
243 :param int swif: sw if index.
246 self.vapi.l2fib_flush_int(swif)
247 self.deleted_hosts[swif] = self.learned_hosts[swif] + \
248 self.deleted_hosts[swif]
249 flushed[swif] = self.learned_hosts[swif]
250 self.learned_hosts[swif] = []
251 self.logger.info(self.vapi.ppcli("show l2fib"))
254 def flush_bd(self, bd_id):
256 Flush bd_id L2 FIB entries.
258 :param int bd_id: Bridge Domain id.
260 self.vapi.l2fib_flush_bd(bd_id)
262 ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
264 swif = pg_if.sw_if_index
265 self.deleted_hosts[swif] = self.learned_hosts[swif] + \
266 self.deleted_hosts[swif]
267 flushed[swif] = self.learned_hosts[swif]
268 self.learned_hosts[swif] = []
269 self.logger.info(self.vapi.ppcli("show l2fib"))
274 Flush All L2 FIB entries.
276 self.vapi.l2fib_flush_all()
278 for pg_if in self.pg_interfaces:
279 swif = pg_if.sw_if_index
280 self.deleted_hosts[swif] = self.learned_hosts[swif] + \
281 self.deleted_hosts[swif]
282 flushed[swif] = self.learned_hosts[swif]
283 self.learned_hosts[swif] = []
284 self.logger.info(self.vapi.ppcli("show l2fib"))
287 def create_stream(self, src_if, packet_sizes, if_src_hosts=None,
290 Create input packet stream for defined interface using hosts or
293 :param object src_if: Interface to create packet stream for.
294 :param list packet_sizes: List of required packet sizes.
295 :param boolean deleted: Set to True if deleted_hosts list required.
296 :return: Stream of packets.
299 if_src_hosts = self.fib_hosts
301 if_dst_hosts = self.fib_hosts
302 src_hosts = if_src_hosts[src_if.sw_if_index]
306 for dst_if in self.flows[src_if]:
307 dst_swif = dst_if.sw_if_index
308 if dst_swif not in if_dst_hosts:
310 dst_hosts = if_dst_hosts[dst_swif]
311 for i in range(0, len(dst_hosts)):
312 dst_host = dst_hosts[i]
313 src_host = random.choice(src_hosts)
314 pkt_info = self.create_packet_info(src_if, dst_if)
315 payload = self.info_to_payload(pkt_info)
316 p = (Ether(dst=dst_host.mac, src=src_host.mac) /
317 IP(src=src_host.ip4, dst=dst_host.ip4) /
318 UDP(sport=1234, dport=1234) /
320 pkt_info.data = p.copy()
321 size = random.choice(packet_sizes)
322 self.extend_packet(p, size)
326 def verify_capture(self, pg_if, capture):
328 Verify captured input packet stream for defined interface.
330 :param object pg_if: Interface to verify captured packet stream for.
331 :param list capture: Captured packet stream.
334 for i in self.pg_interfaces:
335 last_info[i.sw_if_index] = None
336 dst_sw_if_index = pg_if.sw_if_index
337 for packet in capture:
338 payload_info = self.payload_to_info(str(packet[Raw]))
342 packet_index = payload_info.index
343 self.assertEqual(payload_info.dst, dst_sw_if_index)
344 self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
345 (pg_if.name, payload_info.src, packet_index))
346 next_info = self.get_next_packet_info_for_interface2(
347 payload_info.src, dst_sw_if_index,
348 last_info[payload_info.src])
349 last_info[payload_info.src] = next_info
350 self.assertTrue(next_info is not None)
351 self.assertEqual(packet_index, next_info.index)
352 saved_packet = next_info.data
353 # Check standard fields
354 self.assertEqual(ip.src, saved_packet[IP].src)
355 self.assertEqual(ip.dst, saved_packet[IP].dst)
356 self.assertEqual(udp.sport, saved_packet[UDP].sport)
357 self.assertEqual(udp.dport, saved_packet[UDP].dport)
359 self.logger.error(ppp("Unexpected or invalid packet:", packet))
361 for i in self.pg_interfaces:
362 remaining_packet = self.get_next_packet_info_for_interface2(
363 i, dst_sw_if_index, last_info[i.sw_if_index])
365 remaining_packet is None,
366 "Port %u: Packet expected from source %u didn't arrive" %
367 (dst_sw_if_index, i.sw_if_index))
369 def run_verify_test(self, bd_id, dst_hosts=None):
371 # Create incoming packet streams for packet-generator interfaces
373 dst_hosts = self.fib_hosts
374 self.reset_packet_infos()
375 ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
377 pkts = self.create_stream(
378 i, self.pg_if_packet_sizes, if_dst_hosts=dst_hosts)
381 self.vapi.bridge_flags(bd_id, 0, 1)
382 # Enable packet capture and start packet sending
383 self.pg_enable_capture(ifs)
387 # Verify outgoing packet streams per packet-generator interface
389 if not dst_hosts[i.sw_if_index]:
391 capture = i.get_capture()
392 self.logger.info("Verifying capture on interface %s" % i.name)
393 self.verify_capture(i, capture)
395 def run_verify_negat_test(self, bd_id, dst_hosts=None):
397 # Create incoming packet streams for packet-generator interfaces for
398 # deleted MAC addresses
400 dst_hosts = self.deleted_hosts
401 self.reset_packet_infos()
402 ifs = [self.pg_interfaces[i] for i in self.bd_ifs(bd_id)]
404 pkts = self.create_stream(
405 i, self.pg_if_packet_sizes, if_dst_hosts=dst_hosts)
409 self.vapi.bridge_flags(bd_id, 0, 1)
410 # Enable packet capture and start packet sending
411 self.pg_enable_capture(ifs)
415 # Verify outgoing packet streams per packet-generator interface
418 i.get_capture(0, timeout=timeout)
419 i.assert_nothing_captured(remark="outgoing interface")
422 def test_l2_fib_01(self):
423 """ L2 FIB test 1 - program 100 MAC addresses
426 # Create test host entries
427 self.create_hosts(100, subnet=17)
429 # Add first 100 MAC entries to L2 FIB
430 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=100)
433 self.run_verify_test(bd_id=1)
435 def test_l2_fib_02(self):
436 """ L2 FIB test 2 - delete 12 MAC entries
439 # Delete 12 MAC entries per interface from L2 FIB
440 self.delete_l2_fib_entry(bd_id=1, n_hosts_per_if=12)
443 self.run_verify_test(bd_id=1)
446 self.run_verify_negat_test(bd_id=1)
448 def test_l2_fib_03(self):
449 """ L2 FIB test 3 - program new 100 MAC addresses
452 # Create new test host entries
453 self.create_hosts(100, subnet=22)
455 # Add new 100 MAC entries to L2 FIB
456 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=100)
459 self.run_verify_test(bd_id=1)
461 def test_l2_fib_04(self):
462 """ L2 FIB test 4 - delete 160 MAC entries
465 # Delete 160 MAC entries per interface from L2 FIB
466 self.delete_l2_fib_entry(bd_id=1, n_hosts_per_if=160)
469 self.run_verify_negat_test(bd_id=1)
471 def test_l2_fib_05(self):
472 """ L2 FIB test 5 - Program 10 new MAC entries, learn 10
474 self.create_hosts(20, subnet=35)
476 self.learn_hosts(bd_id=1, n_hosts_per_if=10)
477 self.learn_hosts(bd_id=2, n_hosts_per_if=10)
478 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10)
479 self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10)
480 self.run_verify_test(bd_id=1, dst_hosts=self.learned_hosts)
481 self.run_verify_test(bd_id=2, dst_hosts=self.learned_hosts)
483 def test_l2_fib_06(self):
484 """ L2 FIB test 6 - flush first interface
486 self.create_hosts(20, subnet=36)
488 self.learn_hosts(bd_id=1, n_hosts_per_if=10)
489 self.learn_hosts(bd_id=2, n_hosts_per_if=10)
490 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10)
491 self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10)
492 flushed = self.flush_int(self.pg_interfaces[0].sw_if_index)
493 self.run_verify_test(bd_id=1, dst_hosts=self.learned_hosts)
494 self.run_verify_negat_test(bd_id=1, dst_hosts=flushed)
496 def test_l2_fib_07(self):
497 """ L2 FIB test 7 - flush bd_id
499 self.create_hosts(20, subnet=37)
501 self.learn_hosts(bd_id=1, n_hosts_per_if=10)
502 self.learn_hosts(bd_id=2, n_hosts_per_if=10)
503 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10)
504 self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10)
505 flushed = self.flush_bd(bd_id=1)
506 self.run_verify_negat_test(bd_id=1, dst_hosts=flushed)
507 self.run_verify_test(bd_id=2, dst_hosts=self.learned_hosts)
509 def test_l2_fib_08(self):
510 """ L2 FIB test 8 - flush all
512 self.create_hosts(20, subnet=38)
514 self.learn_hosts(bd_id=1, n_hosts_per_if=10)
515 self.learn_hosts(bd_id=2, n_hosts_per_if=10)
516 self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10)
517 self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10)
518 flushed = self.flush_all()
519 self.run_verify_negat_test(bd_id=1, dst_hosts=flushed)
520 self.run_verify_negat_test(bd_id=2, dst_hosts=flushed)
523 if __name__ == '__main__':
524 unittest.main(testRunner=VppTestRunner)