5 from framework import tag_fixme_vpp_workers
6 from framework import VppTestCase, VppTestRunner
7 from vpp_ip import DpoProto
8 from vpp_ip_route import (
16 from vpp_gre_interface import VppGreInterface
17 from vpp_papi import VppEnum
19 from scapy.packet import Raw
20 from scapy.layers.l2 import Ether, GRE
21 from scapy.layers.inet import IP, UDP, getmacbyip, ICMP
22 from scapy.layers.inet6 import IPv6, getmacbyip6
25 # The number of packets sent is set to 91 so that when we replicate more than 3
26 # times, which we do for some entries, we will generate more than 256 packets
27 # to the next node in the VLIB graph. Thus we are testing the code's
28 # correctness handling this over-flow.
29 # It's also an odd number so we hit any single loops.
34 class TestMFIB(VppTestCase):
39 super(TestMFIB, cls).setUpClass()
42 def tearDownClass(cls):
43 super(TestMFIB, cls).tearDownClass()
46 super(TestMFIB, self).setUp()
50 error = self.vapi.cli("test mfib")
53 self.logger.critical(error)
54 self.assertNotIn("Failed", error)
57 @tag_fixme_vpp_workers
58 class TestIPMcast(VppTestCase):
59 """IP Multicast Test Case"""
63 super(TestIPMcast, cls).setUpClass()
66 def tearDownClass(cls):
67 super(TestIPMcast, cls).tearDownClass()
70 super(TestIPMcast, self).setUp()
72 # create 8 pg interfaces
73 self.create_pg_interfaces(range(9))
76 for i in self.pg_interfaces[:8]:
84 tbl4 = VppIpTable(self, 10)
86 self.pg8.set_table_ip4(10)
89 tbl6 = VppIpTable(self, 10, is_ip6=1)
91 self.pg8.set_table_ip6(10)
95 for i in self.pg_interfaces:
100 self.pg8.set_table_ip4(0)
101 self.pg8.set_table_ip6(0)
102 super(TestIPMcast, self).tearDown()
104 def create_stream_ip4(self, src_if, src_ip, dst_ip, payload_size=0):
106 # default to small packet sizes
108 Ether(dst=getmacbyip(dst_ip), src=src_if.remote_mac)
109 / IP(src=src_ip, dst=dst_ip)
110 / UDP(sport=1234, dport=1234)
113 payload_size = 64 - len(p)
114 p = p / Raw(b"\xa5" * payload_size)
116 for i in range(0, N_PKTS_IN_STREAM):
120 def create_stream_ip6(self, src_if, src_ip, dst_ip):
122 for i in range(0, N_PKTS_IN_STREAM):
123 info = self.create_packet_info(src_if, src_if)
124 payload = self.info_to_payload(info)
126 Ether(dst=getmacbyip6(dst_ip), src=src_if.remote_mac)
127 / IPv6(src=src_ip, dst=dst_ip)
128 / UDP(sport=1234, dport=1234)
135 def verify_filter(self, capture, sent):
136 if not len(capture) == len(sent):
137 # filter out any IPv6 RAs from the capture
143 def verify_capture_ip4(self, rx_if, sent, dst_mac=None):
144 rxd = rx_if.get_capture(len(sent))
147 capture = self.verify_filter(rxd, sent)
149 self.assertEqual(len(capture), len(sent))
151 for i in range(len(capture)):
156 self.assertEqual(eth.type, 0x800)
162 dst_mac = getmacbyip(rx_ip.dst)
164 # check the MAC address on the RX'd packet is correctly formed
165 self.assertEqual(eth.dst, dst_mac)
167 self.assertEqual(rx_ip.src, tx_ip.src)
168 self.assertEqual(rx_ip.dst, tx_ip.dst)
169 # IP processing post pop has decremented the TTL
170 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
175 def verify_capture_ip6(self, rx_if, sent):
176 capture = rx_if.get_capture(len(sent))
178 self.assertEqual(len(capture), len(sent))
180 for i in range(len(capture)):
185 self.assertEqual(eth.type, 0x86DD)
190 # check the MAC address on the RX'd packet is correctly formed
191 self.assertEqual(eth.dst, getmacbyip6(rx_ip.dst))
193 self.assertEqual(rx_ip.src, tx_ip.src)
194 self.assertEqual(rx_ip.dst, tx_ip.dst)
195 # IP processing post pop has decremented the TTL
196 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
198 def test_ip_mcast(self):
199 """IP Multicast Replication"""
201 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
202 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
205 # a stream that matches the default route. gets dropped.
207 self.vapi.cli("clear trace")
208 self.vapi.cli("packet mac-filter pg0 on")
209 self.vapi.cli("packet mac-filter pg1 on")
210 self.vapi.cli("packet mac-filter pg2 on")
211 self.vapi.cli("packet mac-filter pg4 on")
212 self.vapi.cli("packet mac-filter pg5 on")
213 self.vapi.cli("packet mac-filter pg6 on")
214 self.vapi.cli("packet mac-filter pg7 on")
216 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
217 self.pg0.add_stream(tx)
219 self.pg_enable_capture(self.pg_interfaces)
222 self.pg0.assert_nothing_captured(
223 remark="IP multicast packets forwarded on default route"
225 count = self.statistics.get_err_counter(
226 "/err/ip4-input/Multicast RPF check failed"
228 self.assertEqual(count, len(tx))
232 # one accepting interface, pg0, 7 forwarding interfaces
233 # many forwarding interfaces test the case where the replicate DPO
234 # needs to use extra cache lines for the buckets.
236 route_232_1_1_1 = VppIpMRoute(
241 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
244 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
247 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
250 self.pg2.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
253 self.pg3.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
256 self.pg4.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
259 self.pg5.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
262 self.pg6.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
265 self.pg7.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
269 route_232_1_1_1.add_vpp_config()
273 # one accepting interface, pg0, 2 forwarding interfaces
275 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
279 27, # any grp-len is ok when src is set
280 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
283 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
286 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
289 self.pg2.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
293 route_1_1_1_1_232_1_1_1.add_vpp_config()
297 # one accepting interface, pg0, 2 forwarding interfaces
298 # that use unicast next-hops
300 route_1_1_1_1_232_1_1_2 = VppIpMRoute(
305 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
308 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
311 self.pg1.sw_if_index,
312 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
313 nh=self.pg1.remote_ip4,
316 self.pg2.sw_if_index,
317 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
318 nh=self.pg2.remote_ip4,
322 route_1_1_1_1_232_1_1_2.add_vpp_config()
326 # one accepting interface, pg0, 1 forwarding interfaces
328 route_232 = VppIpMRoute(
333 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
336 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
339 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
343 route_232.add_vpp_config()
346 # a stream that matches the route for (1.1.1.1,232.1.1.1)
349 self.vapi.cli("clear trace")
350 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
351 self.pg0.add_stream(tx)
353 self.pg_enable_capture(self.pg_interfaces)
356 self.assertEqual(route_1_1_1_1_232_1_1_1.get_stats()["packets"], len(tx))
358 # We expect replications on Pg1->7
359 self.verify_capture_ip4(self.pg1, tx)
360 self.verify_capture_ip4(self.pg2, tx)
362 # no replications on Pg0
363 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
364 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
367 # a stream that matches the route for (1.1.1.1,232.1.1.1)
370 self.vapi.cli("clear trace")
371 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1", payload_size=1024)
372 self.pg0.add_stream(tx)
374 self.pg_enable_capture(self.pg_interfaces)
377 # We expect replications on Pg1->7
378 self.verify_capture_ip4(self.pg1, tx)
379 self.verify_capture_ip4(self.pg2, tx)
381 self.assertEqual(route_1_1_1_1_232_1_1_1.get_stats()["packets"], 2 * len(tx))
383 # no replications on Pg0
384 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
385 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
388 # a stream to the unicast next-hops
390 self.vapi.cli("clear trace")
391 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.2")
392 self.pg0.add_stream(tx)
394 self.pg_enable_capture(self.pg_interfaces)
397 # We expect replications on Pg1->7
398 self.verify_capture_ip4(self.pg1, tx, dst_mac=self.pg1.remote_mac)
399 self.verify_capture_ip4(self.pg2, tx, dst_mac=self.pg2.remote_mac)
401 # no replications on Pg0 nor pg3
402 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
403 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
406 # a stream that matches the route for (*,232.0.0.0/8)
407 # Send packets with the 9th bit set so we test the correct clearing
408 # of that bit in the mac rewrite
410 self.vapi.cli("clear trace")
411 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.255.255.255")
412 self.pg0.add_stream(tx)
414 self.pg_enable_capture(self.pg_interfaces)
417 # We expect replications on Pg1 only
418 self.verify_capture_ip4(self.pg1, tx)
419 self.assertEqual(route_232.get_stats()["packets"], len(tx))
421 # no replications on Pg0, Pg2 not Pg3
422 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
423 self.pg2.assert_nothing_captured(remark="IP multicast packets forwarded on PG2")
424 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
427 # a stream that matches the route for (*,232.1.1.1)
429 self.vapi.cli("clear trace")
430 tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "232.1.1.1")
431 self.pg0.add_stream(tx)
433 self.pg_enable_capture(self.pg_interfaces)
436 # We expect replications on Pg1->7
437 self.verify_capture_ip4(self.pg1, tx)
438 self.verify_capture_ip4(self.pg2, tx)
439 self.verify_capture_ip4(self.pg3, tx)
440 self.verify_capture_ip4(self.pg4, tx)
441 self.verify_capture_ip4(self.pg5, tx)
442 self.verify_capture_ip4(self.pg6, tx)
443 self.verify_capture_ip4(self.pg7, tx)
445 # no replications on Pg0
446 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
448 self.vapi.cli("packet mac-filter pg0 off")
449 self.vapi.cli("packet mac-filter pg1 off")
450 self.vapi.cli("packet mac-filter pg2 off")
451 self.vapi.cli("packet mac-filter pg4 off")
452 self.vapi.cli("packet mac-filter pg5 off")
453 self.vapi.cli("packet mac-filter pg6 off")
454 self.vapi.cli("packet mac-filter pg7 off")
456 def test_ip6_mcast(self):
457 """IPv6 Multicast Replication"""
459 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
460 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
462 self.vapi.cli("packet mac-filter pg0 on")
463 self.vapi.cli("packet mac-filter pg1 on")
464 self.vapi.cli("packet mac-filter pg2 on")
465 self.vapi.cli("packet mac-filter pg4 on")
466 self.vapi.cli("packet mac-filter pg5 on")
467 self.vapi.cli("packet mac-filter pg6 on")
468 self.vapi.cli("packet mac-filter pg7 on")
470 # a stream that matches the default route. gets dropped.
472 self.vapi.cli("clear trace")
473 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
474 self.pg0.add_stream(tx)
476 self.pg_enable_capture(self.pg_interfaces)
479 self.pg0.assert_nothing_captured(
480 remark="IPv6 multicast packets forwarded on default route"
485 # one accepting interface, pg0, 3 forwarding interfaces
487 route_ff01_1 = VppIpMRoute(
492 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
495 self.pg0.sw_if_index,
496 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
497 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
500 self.pg1.sw_if_index,
501 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
502 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
505 self.pg2.sw_if_index,
506 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
507 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
510 self.pg3.sw_if_index,
511 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
512 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
516 route_ff01_1.add_vpp_config()
520 # one accepting interface, pg0, 2 forwarding interfaces
522 route_2001_ff01_1 = VppIpMRoute(
526 0, # any grp-len is ok when src is set
527 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
530 self.pg0.sw_if_index,
531 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
532 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
535 self.pg1.sw_if_index,
536 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
537 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
540 self.pg2.sw_if_index,
541 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
542 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
546 route_2001_ff01_1.add_vpp_config()
550 # one accepting interface, pg0, 1 forwarding interface
552 route_ff01 = VppIpMRoute(
557 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
560 self.pg0.sw_if_index,
561 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
562 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
565 self.pg1.sw_if_index,
566 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
567 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
571 route_ff01.add_vpp_config()
574 # a stream that matches the route for (*, ff01::/16)
575 # sent on the non-accepting interface
577 self.vapi.cli("clear trace")
578 tx = self.create_stream_ip6(self.pg1, "2002::1", "ff01:2::255")
579 self.send_and_assert_no_replies(self.pg1, tx, "RPF miss")
580 count = self.statistics.get_err_counter(
581 "/err/ip6-input/Multicast RPF check failed"
583 self.assertEqual(count, 2 * len(tx))
586 # a stream that matches the route for (*, ff01::/16)
587 # sent on the accepting interface
589 self.vapi.cli("clear trace")
590 tx = self.create_stream_ip6(self.pg0, "2002::1", "ff01:2::255")
591 self.pg0.add_stream(tx)
593 self.pg_enable_capture(self.pg_interfaces)
596 # We expect replications on Pg1
597 self.verify_capture_ip6(self.pg1, tx)
599 # no replications on Pg0, Pg3
600 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
601 self.pg2.assert_nothing_captured(remark="IP multicast packets forwarded on PG2")
602 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
605 # Bounce the interface and it should still work
607 self.pg1.admin_down()
608 self.pg0.add_stream(tx)
609 self.pg_enable_capture(self.pg_interfaces)
611 self.pg1.assert_nothing_captured(
612 remark="IP multicast packets forwarded on down PG1"
616 self.pg0.add_stream(tx)
617 self.pg_enable_capture(self.pg_interfaces)
619 self.verify_capture_ip6(self.pg1, tx)
622 # a stream that matches the route for (*,ff01::1)
624 self.vapi.cli("clear trace")
625 tx = self.create_stream_ip6(self.pg0, "2002::2", "ff01::1")
626 self.pg0.add_stream(tx)
628 self.pg_enable_capture(self.pg_interfaces)
631 # We expect replications on Pg1, 2, 3.
632 self.verify_capture_ip6(self.pg1, tx)
633 self.verify_capture_ip6(self.pg2, tx)
634 self.verify_capture_ip6(self.pg3, tx)
636 # no replications on Pg0
637 self.pg0.assert_nothing_captured(
638 remark="IPv6 multicast packets forwarded on PG0"
642 # a stream that matches the route for (2001::1, ff00::1)
644 self.vapi.cli("clear trace")
645 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
646 self.pg0.add_stream(tx)
648 self.pg_enable_capture(self.pg_interfaces)
651 # We expect replications on Pg1, 2,
652 self.verify_capture_ip6(self.pg1, tx)
653 self.verify_capture_ip6(self.pg2, tx)
655 # no replications on Pg0, Pg3
656 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
657 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
659 self.vapi.cli("packet mac-filter pg0 off")
660 self.vapi.cli("packet mac-filter pg1 off")
661 self.vapi.cli("packet mac-filter pg2 off")
662 self.vapi.cli("packet mac-filter pg4 off")
663 self.vapi.cli("packet mac-filter pg5 off")
664 self.vapi.cli("packet mac-filter pg6 off")
665 self.vapi.cli("packet mac-filter pg7 off")
667 def _mcast_connected_send_stream(self, dst_ip):
668 self.vapi.cli("clear trace")
669 tx = self.create_stream_ip4(self.pg0, self.pg0.remote_ip4, dst_ip)
670 self.pg0.add_stream(tx)
672 self.pg_enable_capture(self.pg_interfaces)
675 # We expect replications on Pg1.
676 self.verify_capture_ip4(self.pg1, tx)
680 def test_ip_mcast_connected(self):
681 """IP Multicast Connected Source check"""
683 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
684 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
688 # one accepting interface, pg0, 1 forwarding interfaces
690 route_232_1_1_1 = VppIpMRoute(
695 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
698 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
701 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
706 route_232_1_1_1.add_vpp_config()
707 route_232_1_1_1.update_entry_flags(
708 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_CONNECTED
712 # Now the (*,G) is present, send from connected source
714 tx = self._mcast_connected_send_stream("232.1.1.1")
717 # Constrct a representation of the signal we expect on pg0
719 signal_232_1_1_1_itf_0 = VppMFibSignal(
720 self, route_232_1_1_1, self.pg0.sw_if_index, tx[0]
724 # read the only expected signal
726 signals = self.vapi.mfib_signal_dump()
728 self.assertEqual(1, len(signals))
730 signal_232_1_1_1_itf_0.compare(signals[0])
733 # reading the signal allows for the generation of another
734 # so send more packets and expect the next signal
736 tx = self._mcast_connected_send_stream("232.1.1.1")
738 signals = self.vapi.mfib_signal_dump()
739 self.assertEqual(1, len(signals))
740 signal_232_1_1_1_itf_0.compare(signals[0])
743 # A Second entry with connected check
744 # one accepting interface, pg0, 1 forwarding interfaces
746 route_232_1_1_2 = VppIpMRoute(
751 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
754 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
757 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
762 route_232_1_1_2.add_vpp_config()
763 route_232_1_1_2.update_entry_flags(
764 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_CONNECTED
768 # Send traffic to both entries. One read should net us two signals
770 signal_232_1_1_2_itf_0 = VppMFibSignal(
771 self, route_232_1_1_2, self.pg0.sw_if_index, tx[0]
773 tx = self._mcast_connected_send_stream("232.1.1.1")
774 tx2 = self._mcast_connected_send_stream("232.1.1.2")
777 # read the only expected signal
779 signals = self.vapi.mfib_signal_dump()
781 self.assertEqual(2, len(signals))
783 signal_232_1_1_1_itf_0.compare(signals[1])
784 signal_232_1_1_2_itf_0.compare(signals[0])
786 route_232_1_1_1.update_entry_flags(MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE)
787 route_232_1_1_2.update_entry_flags(MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE)
789 def test_ip_mcast_signal(self):
790 """IP Multicast Signal"""
792 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
793 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
797 # one accepting interface, pg0, 1 forwarding interfaces
799 route_232_1_1_1 = VppIpMRoute(
804 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
807 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
810 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
815 route_232_1_1_1.add_vpp_config()
817 route_232_1_1_1.update_entry_flags(MRouteEntryFlags.MFIB_API_ENTRY_FLAG_SIGNAL)
820 # Now the (*,G) is present, send from connected source
822 tx = self._mcast_connected_send_stream("232.1.1.1")
825 # Constrct a representation of the signal we expect on pg0
827 signal_232_1_1_1_itf_0 = VppMFibSignal(
828 self, route_232_1_1_1, self.pg0.sw_if_index, tx[0]
832 # read the only expected signal
834 signals = self.vapi.mfib_signal_dump()
836 self.assertEqual(1, len(signals))
838 signal_232_1_1_1_itf_0.compare(signals[0])
841 # reading the signal allows for the generation of another
842 # so send more packets and expect the next signal
844 tx = self._mcast_connected_send_stream("232.1.1.1")
846 signals = self.vapi.mfib_signal_dump()
847 self.assertEqual(1, len(signals))
848 signal_232_1_1_1_itf_0.compare(signals[0])
851 # Set the negate-signal on the accepting interval - the signals
854 route_232_1_1_1.update_path_flags(
855 self.pg0.sw_if_index,
857 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
858 | MRouteItfFlags.MFIB_API_ITF_FLAG_NEGATE_SIGNAL
862 self.vapi.cli("clear trace")
863 tx = self._mcast_connected_send_stream("232.1.1.1")
865 signals = self.vapi.mfib_signal_dump()
866 self.assertEqual(0, len(signals))
869 # Clear the SIGNAL flag on the entry and the signals should
870 # come back since the interface is still NEGATE-SIGNAL
872 route_232_1_1_1.update_entry_flags(MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE)
874 tx = self._mcast_connected_send_stream("232.1.1.1")
876 signals = self.vapi.mfib_signal_dump()
877 self.assertEqual(1, len(signals))
878 signal_232_1_1_1_itf_0.compare(signals[0])
881 # Lastly remove the NEGATE-SIGNAL from the interface and the
882 # signals should stop
884 route_232_1_1_1.update_path_flags(
885 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
888 tx = self._mcast_connected_send_stream("232.1.1.1")
889 signals = self.vapi.mfib_signal_dump()
890 self.assertEqual(0, len(signals))
892 def test_ip_mcast_vrf(self):
893 """IP Multicast Replication in non-default table"""
895 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
896 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
900 # one accepting interface, pg0, 2 forwarding interfaces
902 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
907 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
910 self.pg8.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
913 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
916 self.pg2.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
921 route_1_1_1_1_232_1_1_1.add_vpp_config()
924 # a stream that matches the route for (1.1.1.1,232.1.1.1)
927 self.vapi.cli("clear trace")
928 tx = self.create_stream_ip4(self.pg8, "1.1.1.1", "232.1.1.1")
929 self.pg8.add_stream(tx)
931 self.pg_enable_capture(self.pg_interfaces)
934 # We expect replications on Pg1 & 2
935 self.verify_capture_ip4(self.pg1, tx)
936 self.verify_capture_ip4(self.pg2, tx)
939 # An (S,G). for for-us
941 route_0_0_0_0_224_0_0_5 = VppIpMRoute(
946 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
949 self.pg8.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
953 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
954 type=FibPathType.FIB_PATH_TYPE_LOCAL,
959 route_0_0_0_0_224_0_0_5.add_vpp_config()
962 # a stream that matches the route for (0.0.0.0, 224.0.0.5)
965 self.vapi.cli("clear trace")
966 self.pg8.resolve_arp()
969 # send a ping to mcast address from peer on pg8
974 icmp_load = b"\x0a" * 18
976 Ether(dst=getmacbyip("224.0.0.5"), src=self.pg8.remote_mac)
977 / IP(src=self.pg8.remote_ip4, dst="224.0.0.5")
978 / ICMP(id=icmp_id, seq=icmp_seq)
979 / Raw(load=icmp_load)
982 self.send_and_expect(self.pg8, tx, self.pg8)
984 def test_ip_mcast_gre(self):
985 """IP Multicast Replication over GRE"""
987 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
988 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
990 gre_if_1 = VppGreInterface(
991 self, self.pg1.local_ip4, self.pg1.remote_ip4
993 gre_if_2 = VppGreInterface(
994 self, self.pg2.local_ip4, self.pg2.remote_ip4
996 gre_if_3 = VppGreInterface(
997 self, self.pg3.local_ip4, self.pg3.remote_ip4
1001 gre_if_1.config_ip4()
1003 gre_if_2.config_ip4()
1005 gre_if_3.config_ip4()
1009 # one accepting interface, pg0, 2 forwarding interfaces
1011 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
1016 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1019 gre_if_1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1022 gre_if_2.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1025 gre_if_3.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1029 route_1_1_1_1_232_1_1_1.add_vpp_config()
1032 # a stream that matches the route for (1.1.1.1,232.2.2.2)
1036 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1037 / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4)
1039 / IP(src="1.1.1.1", dst="232.2.2.2")
1040 / UDP(sport=1234, dport=1234)
1044 self.vapi.cli("clear trace")
1045 self.pg1.add_stream(tx)
1047 self.pg_enable_capture(self.pg_interfaces)
1050 # We expect replications on Pg2 & 3
1051 # check the encap headers are as expected based on the egress tunnel
1052 rxs = self.pg2.get_capture(len(tx))
1054 self.assertEqual(rx[IP].src, gre_if_2.t_src)
1055 self.assertEqual(rx[IP].dst, gre_if_2.t_dst)
1056 self.assert_packet_checksums_valid(rx)
1058 rxs = self.pg3.get_capture(len(tx))
1060 self.assertEqual(rx[IP].src, gre_if_3.t_src)
1061 self.assertEqual(rx[IP].dst, gre_if_3.t_dst)
1062 self.assert_packet_checksums_valid(rx)
1064 def test_ip6_mcast_gre(self):
1065 """IP6 Multicast Replication over GRE"""
1067 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1068 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1070 gre_if_1 = VppGreInterface(
1071 self, self.pg1.local_ip4, self.pg1.remote_ip4
1073 gre_if_2 = VppGreInterface(
1074 self, self.pg2.local_ip4, self.pg2.remote_ip4
1076 gre_if_3 = VppGreInterface(
1077 self, self.pg3.local_ip4, self.pg3.remote_ip4
1081 gre_if_1.config_ip6()
1083 gre_if_2.config_ip6()
1085 gre_if_3.config_ip6()
1089 # one accepting interface, pg0, 2 forwarding interfaces
1091 route_1_1_FF_1 = VppIpMRoute(
1096 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1099 gre_if_1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1102 gre_if_2.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1105 gre_if_3.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1109 route_1_1_FF_1.add_vpp_config()
1112 # a stream that matches the route for (1::1, FF::1)
1116 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1117 / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4)
1119 / IPv6(src="1::1", dst="FF00::1")
1120 / UDP(sport=1234, dport=1234)
1124 self.vapi.cli("clear trace")
1125 self.pg1.add_stream(tx)
1127 self.pg_enable_capture(self.pg_interfaces)
1130 # We expect replications on Pg2 & 3
1131 # check the encap headers are as expected based on the egress tunnel
1132 rxs = self.pg2.get_capture(len(tx))
1134 self.assertEqual(rx[IP].src, gre_if_2.t_src)
1135 self.assertEqual(rx[IP].dst, gre_if_2.t_dst)
1136 self.assert_packet_checksums_valid(rx)
1138 rxs = self.pg3.get_capture(len(tx))
1140 self.assertEqual(rx[IP].src, gre_if_3.t_src)
1141 self.assertEqual(rx[IP].dst, gre_if_3.t_dst)
1142 self.assert_packet_checksums_valid(rx)
1144 def test_ip6_mcast_vrf(self):
1145 """IPv6 Multicast Replication in non-default table"""
1147 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1148 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1152 # one accepting interface, pg0, 2 forwarding interfaces
1154 route_2001_ff01_1 = VppIpMRoute(
1159 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1162 self.pg8.sw_if_index,
1163 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
1164 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1167 self.pg1.sw_if_index,
1168 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1169 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1172 self.pg2.sw_if_index,
1173 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1174 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1179 route_2001_ff01_1.add_vpp_config()
1182 # a stream that matches the route for (2001::1, ff00::1)
1184 self.vapi.cli("clear trace")
1185 tx = self.create_stream_ip6(self.pg8, "2001::1", "ff01::1")
1186 self.pg8.add_stream(tx)
1188 self.pg_enable_capture(self.pg_interfaces)
1191 # We expect replications on Pg1, 2,
1192 self.verify_capture_ip6(self.pg1, tx)
1193 self.verify_capture_ip6(self.pg2, tx)
1195 def test_bidir(self):
1196 """IP Multicast Bi-directional"""
1198 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1199 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1202 # A (*,G). The set of accepting interfaces matching the forwarding
1204 route_232_1_1_1 = VppIpMRoute(
1209 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1212 self.pg0.sw_if_index,
1213 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1214 | MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1217 self.pg1.sw_if_index,
1218 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1219 | MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1222 self.pg2.sw_if_index,
1223 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1224 | MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1227 self.pg3.sw_if_index,
1228 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1229 | MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1233 route_232_1_1_1.add_vpp_config()
1235 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
1236 self.pg0.add_stream(tx)
1238 self.pg_enable_capture(self.pg_interfaces)
1241 # We expect replications on Pg1, 2, 3, but not on pg0
1242 self.verify_capture_ip4(self.pg1, tx)
1243 self.verify_capture_ip4(self.pg2, tx)
1244 self.verify_capture_ip4(self.pg3, tx)
1245 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
1248 if __name__ == "__main__":
1249 unittest.main(testRunner=VppTestRunner)