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("/err/ip4-input/rpf_failure")
226 self.assertEqual(count, len(tx))
230 # one accepting interface, pg0, 7 forwarding interfaces
231 # many forwarding interfaces test the case where the replicate DPO
232 # needs to use extra cache lines for the buckets.
234 route_232_1_1_1 = VppIpMRoute(
239 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
242 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
245 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
248 self.pg2.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
251 self.pg3.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
254 self.pg4.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
257 self.pg5.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
260 self.pg6.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
263 self.pg7.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
267 route_232_1_1_1.add_vpp_config()
271 # one accepting interface, pg0, 2 forwarding interfaces
273 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
277 27, # any grp-len is ok when src is set
278 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
281 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
284 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
287 self.pg2.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
291 route_1_1_1_1_232_1_1_1.add_vpp_config()
295 # one accepting interface, pg0, 2 forwarding interfaces
296 # that use unicast next-hops
298 route_1_1_1_1_232_1_1_2 = VppIpMRoute(
303 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
306 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
309 self.pg1.sw_if_index,
310 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
311 nh=self.pg1.remote_ip4,
314 self.pg2.sw_if_index,
315 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
316 nh=self.pg2.remote_ip4,
320 route_1_1_1_1_232_1_1_2.add_vpp_config()
324 # one accepting interface, pg0, 1 forwarding interfaces
326 route_232 = VppIpMRoute(
331 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
334 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
337 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
341 route_232.add_vpp_config()
344 # a stream that matches the route for (1.1.1.1,232.1.1.1)
347 self.vapi.cli("clear trace")
348 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
349 self.pg0.add_stream(tx)
351 self.pg_enable_capture(self.pg_interfaces)
354 self.assertEqual(route_1_1_1_1_232_1_1_1.get_stats()["packets"], len(tx))
356 # We expect replications on Pg1->7
357 self.verify_capture_ip4(self.pg1, tx)
358 self.verify_capture_ip4(self.pg2, tx)
360 # no replications on Pg0
361 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
362 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
365 # a stream that matches the route for (1.1.1.1,232.1.1.1)
368 self.vapi.cli("clear trace")
369 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1", payload_size=1024)
370 self.pg0.add_stream(tx)
372 self.pg_enable_capture(self.pg_interfaces)
375 # We expect replications on Pg1->7
376 self.verify_capture_ip4(self.pg1, tx)
377 self.verify_capture_ip4(self.pg2, tx)
379 self.assertEqual(route_1_1_1_1_232_1_1_1.get_stats()["packets"], 2 * len(tx))
381 # no replications on Pg0
382 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
383 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
386 # a stream to the unicast next-hops
388 self.vapi.cli("clear trace")
389 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.2")
390 self.pg0.add_stream(tx)
392 self.pg_enable_capture(self.pg_interfaces)
395 # We expect replications on Pg1->7
396 self.verify_capture_ip4(self.pg1, tx, dst_mac=self.pg1.remote_mac)
397 self.verify_capture_ip4(self.pg2, tx, dst_mac=self.pg2.remote_mac)
399 # no replications on Pg0 nor pg3
400 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
401 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
404 # a stream that matches the route for (*,232.0.0.0/8)
405 # Send packets with the 9th bit set so we test the correct clearing
406 # of that bit in the mac rewrite
408 self.vapi.cli("clear trace")
409 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.255.255.255")
410 self.pg0.add_stream(tx)
412 self.pg_enable_capture(self.pg_interfaces)
415 # We expect replications on Pg1 only
416 self.verify_capture_ip4(self.pg1, tx)
417 self.assertEqual(route_232.get_stats()["packets"], len(tx))
419 # no replications on Pg0, Pg2 not Pg3
420 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
421 self.pg2.assert_nothing_captured(remark="IP multicast packets forwarded on PG2")
422 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
425 # a stream that matches the route for (*,232.1.1.1)
427 self.vapi.cli("clear trace")
428 tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "232.1.1.1")
429 self.pg0.add_stream(tx)
431 self.pg_enable_capture(self.pg_interfaces)
434 # We expect replications on Pg1->7
435 self.verify_capture_ip4(self.pg1, tx)
436 self.verify_capture_ip4(self.pg2, tx)
437 self.verify_capture_ip4(self.pg3, tx)
438 self.verify_capture_ip4(self.pg4, tx)
439 self.verify_capture_ip4(self.pg5, tx)
440 self.verify_capture_ip4(self.pg6, tx)
441 self.verify_capture_ip4(self.pg7, tx)
443 # no replications on Pg0
444 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
446 self.vapi.cli("packet mac-filter pg0 off")
447 self.vapi.cli("packet mac-filter pg1 off")
448 self.vapi.cli("packet mac-filter pg2 off")
449 self.vapi.cli("packet mac-filter pg4 off")
450 self.vapi.cli("packet mac-filter pg5 off")
451 self.vapi.cli("packet mac-filter pg6 off")
452 self.vapi.cli("packet mac-filter pg7 off")
454 def test_ip6_mcast(self):
455 """IPv6 Multicast Replication"""
457 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
458 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
460 self.vapi.cli("packet mac-filter pg0 on")
461 self.vapi.cli("packet mac-filter pg1 on")
462 self.vapi.cli("packet mac-filter pg2 on")
463 self.vapi.cli("packet mac-filter pg4 on")
464 self.vapi.cli("packet mac-filter pg5 on")
465 self.vapi.cli("packet mac-filter pg6 on")
466 self.vapi.cli("packet mac-filter pg7 on")
468 # a stream that matches the default route. gets dropped.
470 self.vapi.cli("clear trace")
471 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
472 self.pg0.add_stream(tx)
474 self.pg_enable_capture(self.pg_interfaces)
477 self.pg0.assert_nothing_captured(
478 remark="IPv6 multicast packets forwarded on default route"
483 # one accepting interface, pg0, 3 forwarding interfaces
485 route_ff01_1 = VppIpMRoute(
490 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
493 self.pg0.sw_if_index,
494 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
495 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
498 self.pg1.sw_if_index,
499 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
500 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
503 self.pg2.sw_if_index,
504 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
505 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
508 self.pg3.sw_if_index,
509 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
510 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
514 route_ff01_1.add_vpp_config()
518 # one accepting interface, pg0, 2 forwarding interfaces
520 route_2001_ff01_1 = VppIpMRoute(
524 0, # any grp-len is ok when src is set
525 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
528 self.pg0.sw_if_index,
529 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
530 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
533 self.pg1.sw_if_index,
534 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
535 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
538 self.pg2.sw_if_index,
539 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
540 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
544 route_2001_ff01_1.add_vpp_config()
548 # one accepting interface, pg0, 1 forwarding interface
550 route_ff01 = VppIpMRoute(
555 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
558 self.pg0.sw_if_index,
559 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
560 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
563 self.pg1.sw_if_index,
564 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
565 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
569 route_ff01.add_vpp_config()
572 # a stream that matches the route for (*, ff01::/16)
573 # sent on the non-accepting interface
575 self.vapi.cli("clear trace")
576 tx = self.create_stream_ip6(self.pg1, "2002::1", "ff01:2::255")
577 self.send_and_assert_no_replies(self.pg1, tx, "RPF miss")
578 count = self.statistics.get_err_counter("/err/ip6-input/rpf_failure")
579 self.assertEqual(count, 2 * len(tx))
582 # a stream that matches the route for (*, ff01::/16)
583 # sent on the accepting interface
585 self.vapi.cli("clear trace")
586 tx = self.create_stream_ip6(self.pg0, "2002::1", "ff01:2::255")
587 self.pg0.add_stream(tx)
589 self.pg_enable_capture(self.pg_interfaces)
592 # We expect replications on Pg1
593 self.verify_capture_ip6(self.pg1, tx)
595 # no replications on Pg0, Pg3
596 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
597 self.pg2.assert_nothing_captured(remark="IP multicast packets forwarded on PG2")
598 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
601 # Bounce the interface and it should still work
603 self.pg1.admin_down()
604 self.pg0.add_stream(tx)
605 self.pg_enable_capture(self.pg_interfaces)
607 self.pg1.assert_nothing_captured(
608 remark="IP multicast packets forwarded on down PG1"
612 self.pg0.add_stream(tx)
613 self.pg_enable_capture(self.pg_interfaces)
615 self.verify_capture_ip6(self.pg1, tx)
618 # a stream that matches the route for (*,ff01::1)
620 self.vapi.cli("clear trace")
621 tx = self.create_stream_ip6(self.pg0, "2002::2", "ff01::1")
622 self.pg0.add_stream(tx)
624 self.pg_enable_capture(self.pg_interfaces)
627 # We expect replications on Pg1, 2, 3.
628 self.verify_capture_ip6(self.pg1, tx)
629 self.verify_capture_ip6(self.pg2, tx)
630 self.verify_capture_ip6(self.pg3, tx)
632 # no replications on Pg0
633 self.pg0.assert_nothing_captured(
634 remark="IPv6 multicast packets forwarded on PG0"
638 # a stream that matches the route for (2001::1, ff00::1)
640 self.vapi.cli("clear trace")
641 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
642 self.pg0.add_stream(tx)
644 self.pg_enable_capture(self.pg_interfaces)
647 # We expect replications on Pg1, 2,
648 self.verify_capture_ip6(self.pg1, tx)
649 self.verify_capture_ip6(self.pg2, tx)
651 # no replications on Pg0, Pg3
652 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
653 self.pg3.assert_nothing_captured(remark="IP multicast packets forwarded on PG3")
655 self.vapi.cli("packet mac-filter pg0 off")
656 self.vapi.cli("packet mac-filter pg1 off")
657 self.vapi.cli("packet mac-filter pg2 off")
658 self.vapi.cli("packet mac-filter pg4 off")
659 self.vapi.cli("packet mac-filter pg5 off")
660 self.vapi.cli("packet mac-filter pg6 off")
661 self.vapi.cli("packet mac-filter pg7 off")
663 def _mcast_connected_send_stream(self, dst_ip):
664 self.vapi.cli("clear trace")
665 tx = self.create_stream_ip4(self.pg0, self.pg0.remote_ip4, dst_ip)
666 self.pg0.add_stream(tx)
668 self.pg_enable_capture(self.pg_interfaces)
671 # We expect replications on Pg1.
672 self.verify_capture_ip4(self.pg1, tx)
676 def test_ip_mcast_connected(self):
677 """IP Multicast Connected Source check"""
679 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
680 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
684 # one accepting interface, pg0, 1 forwarding interfaces
686 route_232_1_1_1 = VppIpMRoute(
691 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
694 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
697 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
702 route_232_1_1_1.add_vpp_config()
703 route_232_1_1_1.update_entry_flags(
704 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_CONNECTED
708 # Now the (*,G) is present, send from connected source
710 tx = self._mcast_connected_send_stream("232.1.1.1")
713 # Constrct a representation of the signal we expect on pg0
715 signal_232_1_1_1_itf_0 = VppMFibSignal(
716 self, route_232_1_1_1, self.pg0.sw_if_index, tx[0]
720 # read the only expected signal
722 signals = self.vapi.mfib_signal_dump()
724 self.assertEqual(1, len(signals))
726 signal_232_1_1_1_itf_0.compare(signals[0])
729 # reading the signal allows for the generation of another
730 # so send more packets and expect the next signal
732 tx = self._mcast_connected_send_stream("232.1.1.1")
734 signals = self.vapi.mfib_signal_dump()
735 self.assertEqual(1, len(signals))
736 signal_232_1_1_1_itf_0.compare(signals[0])
739 # A Second entry with connected check
740 # one accepting interface, pg0, 1 forwarding interfaces
742 route_232_1_1_2 = VppIpMRoute(
747 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
750 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
753 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
758 route_232_1_1_2.add_vpp_config()
759 route_232_1_1_2.update_entry_flags(
760 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_CONNECTED
764 # Send traffic to both entries. One read should net us two signals
766 signal_232_1_1_2_itf_0 = VppMFibSignal(
767 self, route_232_1_1_2, self.pg0.sw_if_index, tx[0]
769 tx = self._mcast_connected_send_stream("232.1.1.1")
770 tx2 = self._mcast_connected_send_stream("232.1.1.2")
773 # read the only expected signal
775 signals = self.vapi.mfib_signal_dump()
777 self.assertEqual(2, len(signals))
779 signal_232_1_1_1_itf_0.compare(signals[1])
780 signal_232_1_1_2_itf_0.compare(signals[0])
782 route_232_1_1_1.update_entry_flags(MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE)
783 route_232_1_1_2.update_entry_flags(MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE)
785 def test_ip_mcast_signal(self):
786 """IP Multicast Signal"""
788 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
789 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
793 # one accepting interface, pg0, 1 forwarding interfaces
795 route_232_1_1_1 = VppIpMRoute(
800 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
803 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
806 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
811 route_232_1_1_1.add_vpp_config()
813 route_232_1_1_1.update_entry_flags(MRouteEntryFlags.MFIB_API_ENTRY_FLAG_SIGNAL)
816 # Now the (*,G) is present, send from connected source
818 tx = self._mcast_connected_send_stream("232.1.1.1")
821 # Constrct a representation of the signal we expect on pg0
823 signal_232_1_1_1_itf_0 = VppMFibSignal(
824 self, route_232_1_1_1, self.pg0.sw_if_index, tx[0]
828 # read the only expected signal
830 signals = self.vapi.mfib_signal_dump()
832 self.assertEqual(1, len(signals))
834 signal_232_1_1_1_itf_0.compare(signals[0])
837 # reading the signal allows for the generation of another
838 # so send more packets and expect the next signal
840 tx = self._mcast_connected_send_stream("232.1.1.1")
842 signals = self.vapi.mfib_signal_dump()
843 self.assertEqual(1, len(signals))
844 signal_232_1_1_1_itf_0.compare(signals[0])
847 # Set the negate-signal on the accepting interval - the signals
850 route_232_1_1_1.update_path_flags(
851 self.pg0.sw_if_index,
853 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
854 | MRouteItfFlags.MFIB_API_ITF_FLAG_NEGATE_SIGNAL
858 self.vapi.cli("clear trace")
859 tx = self._mcast_connected_send_stream("232.1.1.1")
861 signals = self.vapi.mfib_signal_dump()
862 self.assertEqual(0, len(signals))
865 # Clear the SIGNAL flag on the entry and the signals should
866 # come back since the interface is still NEGATE-SIGNAL
868 route_232_1_1_1.update_entry_flags(MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE)
870 tx = self._mcast_connected_send_stream("232.1.1.1")
872 signals = self.vapi.mfib_signal_dump()
873 self.assertEqual(1, len(signals))
874 signal_232_1_1_1_itf_0.compare(signals[0])
877 # Lastly remove the NEGATE-SIGNAL from the interface and the
878 # signals should stop
880 route_232_1_1_1.update_path_flags(
881 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
884 tx = self._mcast_connected_send_stream("232.1.1.1")
885 signals = self.vapi.mfib_signal_dump()
886 self.assertEqual(0, len(signals))
888 def test_ip_mcast_vrf(self):
889 """IP Multicast Replication in non-default table"""
891 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
892 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
896 # one accepting interface, pg0, 2 forwarding interfaces
898 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
903 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
906 self.pg8.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
909 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
912 self.pg2.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
917 route_1_1_1_1_232_1_1_1.add_vpp_config()
920 # a stream that matches the route for (1.1.1.1,232.1.1.1)
923 self.vapi.cli("clear trace")
924 tx = self.create_stream_ip4(self.pg8, "1.1.1.1", "232.1.1.1")
925 self.pg8.add_stream(tx)
927 self.pg_enable_capture(self.pg_interfaces)
930 # We expect replications on Pg1 & 2
931 self.verify_capture_ip4(self.pg1, tx)
932 self.verify_capture_ip4(self.pg2, tx)
935 # An (S,G). for for-us
937 route_0_0_0_0_224_0_0_5 = VppIpMRoute(
942 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
945 self.pg8.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
949 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
950 type=FibPathType.FIB_PATH_TYPE_LOCAL,
955 route_0_0_0_0_224_0_0_5.add_vpp_config()
958 # a stream that matches the route for (0.0.0.0, 224.0.0.5)
961 self.vapi.cli("clear trace")
962 self.pg8.resolve_arp()
965 # send a ping to mcast address from peer on pg8
970 icmp_load = b"\x0a" * 18
972 Ether(dst=getmacbyip("224.0.0.5"), src=self.pg8.remote_mac)
973 / IP(src=self.pg8.remote_ip4, dst="224.0.0.5")
974 / ICMP(id=icmp_id, seq=icmp_seq)
975 / Raw(load=icmp_load)
978 self.send_and_expect(self.pg8, tx, self.pg8)
980 def test_ip_mcast_gre(self):
981 """IP Multicast Replication over GRE"""
983 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
984 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
986 gre_if_1 = VppGreInterface(
987 self, self.pg1.local_ip4, self.pg1.remote_ip4
989 gre_if_2 = VppGreInterface(
990 self, self.pg2.local_ip4, self.pg2.remote_ip4
992 gre_if_3 = VppGreInterface(
993 self, self.pg3.local_ip4, self.pg3.remote_ip4
997 gre_if_1.config_ip4()
999 gre_if_2.config_ip4()
1001 gre_if_3.config_ip4()
1005 # one accepting interface, pg0, 2 forwarding interfaces
1007 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
1012 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1015 gre_if_1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1018 gre_if_2.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1021 gre_if_3.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1025 route_1_1_1_1_232_1_1_1.add_vpp_config()
1028 # a stream that matches the route for (1.1.1.1,232.2.2.2)
1032 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1033 / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4)
1035 / IP(src="1.1.1.1", dst="232.2.2.2")
1036 / UDP(sport=1234, dport=1234)
1040 self.vapi.cli("clear trace")
1041 self.pg1.add_stream(tx)
1043 self.pg_enable_capture(self.pg_interfaces)
1046 # We expect replications on Pg2 & 3
1047 # check the encap headers are as expected based on the egress tunnel
1048 rxs = self.pg2.get_capture(len(tx))
1050 self.assertEqual(rx[IP].src, gre_if_2.t_src)
1051 self.assertEqual(rx[IP].dst, gre_if_2.t_dst)
1052 self.assert_packet_checksums_valid(rx)
1054 rxs = self.pg3.get_capture(len(tx))
1056 self.assertEqual(rx[IP].src, gre_if_3.t_src)
1057 self.assertEqual(rx[IP].dst, gre_if_3.t_dst)
1058 self.assert_packet_checksums_valid(rx)
1060 def test_ip6_mcast_gre(self):
1061 """IP6 Multicast Replication over GRE"""
1063 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1064 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1066 gre_if_1 = VppGreInterface(
1067 self, self.pg1.local_ip4, self.pg1.remote_ip4
1069 gre_if_2 = VppGreInterface(
1070 self, self.pg2.local_ip4, self.pg2.remote_ip4
1072 gre_if_3 = VppGreInterface(
1073 self, self.pg3.local_ip4, self.pg3.remote_ip4
1077 gre_if_1.config_ip6()
1079 gre_if_2.config_ip6()
1081 gre_if_3.config_ip6()
1085 # one accepting interface, pg0, 2 forwarding interfaces
1087 route_1_1_FF_1 = VppIpMRoute(
1092 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1095 gre_if_1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1098 gre_if_2.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1101 gre_if_3.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1105 route_1_1_FF_1.add_vpp_config()
1108 # a stream that matches the route for (1::1, FF::1)
1112 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1113 / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4)
1115 / IPv6(src="1::1", dst="FF00::1")
1116 / UDP(sport=1234, dport=1234)
1120 self.vapi.cli("clear trace")
1121 self.pg1.add_stream(tx)
1123 self.pg_enable_capture(self.pg_interfaces)
1126 # We expect replications on Pg2 & 3
1127 # check the encap headers are as expected based on the egress tunnel
1128 rxs = self.pg2.get_capture(len(tx))
1130 self.assertEqual(rx[IP].src, gre_if_2.t_src)
1131 self.assertEqual(rx[IP].dst, gre_if_2.t_dst)
1132 self.assert_packet_checksums_valid(rx)
1134 rxs = self.pg3.get_capture(len(tx))
1136 self.assertEqual(rx[IP].src, gre_if_3.t_src)
1137 self.assertEqual(rx[IP].dst, gre_if_3.t_dst)
1138 self.assert_packet_checksums_valid(rx)
1140 def test_ip6_mcast_vrf(self):
1141 """IPv6 Multicast Replication in non-default table"""
1143 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1144 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1148 # one accepting interface, pg0, 2 forwarding interfaces
1150 route_2001_ff01_1 = VppIpMRoute(
1155 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1158 self.pg8.sw_if_index,
1159 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
1160 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1163 self.pg1.sw_if_index,
1164 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1165 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1168 self.pg2.sw_if_index,
1169 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1170 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1175 route_2001_ff01_1.add_vpp_config()
1178 # a stream that matches the route for (2001::1, ff00::1)
1180 self.vapi.cli("clear trace")
1181 tx = self.create_stream_ip6(self.pg8, "2001::1", "ff01::1")
1182 self.pg8.add_stream(tx)
1184 self.pg_enable_capture(self.pg_interfaces)
1187 # We expect replications on Pg1, 2,
1188 self.verify_capture_ip6(self.pg1, tx)
1189 self.verify_capture_ip6(self.pg2, tx)
1191 def test_bidir(self):
1192 """IP Multicast Bi-directional"""
1194 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1195 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1198 # A (*,G). The set of accepting interfaces matching the forwarding
1200 route_232_1_1_1 = VppIpMRoute(
1205 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1208 self.pg0.sw_if_index,
1209 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1210 | MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1213 self.pg1.sw_if_index,
1214 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1215 | MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1218 self.pg2.sw_if_index,
1219 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1220 | MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1223 self.pg3.sw_if_index,
1224 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1225 | MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1229 route_232_1_1_1.add_vpp_config()
1231 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
1232 self.pg0.add_stream(tx)
1234 self.pg_enable_capture(self.pg_interfaces)
1237 # We expect replications on Pg1, 2, 3, but not on pg0
1238 self.verify_capture_ip4(self.pg1, tx)
1239 self.verify_capture_ip4(self.pg2, tx)
1240 self.verify_capture_ip4(self.pg3, tx)
1241 self.pg0.assert_nothing_captured(remark="IP multicast packets forwarded on PG0")
1244 if __name__ == "__main__":
1245 unittest.main(testRunner=VppTestRunner)