5 from framework import VppTestCase, VppTestRunner
6 from vpp_ip import DpoProto
7 from vpp_ip_route import VppIpMRoute, VppMRoutePath, VppMFibSignal, \
8 MRouteItfFlags, MRouteEntryFlags, VppIpTable
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether
12 from scapy.layers.inet import IP, UDP, getmacbyip
13 from scapy.layers.inet6 import IPv6, getmacbyip6
16 # The number of packets sent is set to 91 so that when we replicate more than 3
17 # times, which we do for some entries, we will generate more than 256 packets
18 # to the next node in the VLIB graph. Thus we are testing the code's
19 # correctness handling this over-flow.
20 # It's also an odd number so we hit any single loops.
25 class TestMFIB(VppTestCase):
26 """ MFIB Test Case """
29 super(TestMFIB, self).setUp()
32 """ MFIB Unit Tests """
33 error = self.vapi.cli("test mfib")
36 self.logger.critical(error)
37 self.assertEqual(error.find("Failed"), -1)
40 class TestIPMcast(VppTestCase):
41 """ IP Multicast Test Case """
44 super(TestIPMcast, self).setUp()
46 # create 8 pg interfaces
47 self.create_pg_interfaces(range(9))
50 for i in self.pg_interfaces[:8]:
58 tbl4 = VppIpTable(self, 10)
60 self.pg8.set_table_ip4(10)
63 tbl6 = VppIpTable(self, 10, is_ip6=1)
65 self.pg8.set_table_ip6(10)
69 for i in self.pg_interfaces:
74 self.pg8.set_table_ip4(0)
75 self.pg8.set_table_ip6(0)
76 super(TestIPMcast, self).tearDown()
78 def create_stream_ip4(self, src_if, src_ip, dst_ip, payload_size=0):
80 # default to small packet sizes
81 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
82 IP(src=src_ip, dst=dst_ip) /
83 UDP(sport=1234, dport=1234))
85 payload_size = 64 - len(p)
86 p = p / Raw('\xa5' * payload_size)
88 for i in range(0, N_PKTS_IN_STREAM):
92 def create_stream_ip6(self, src_if, src_ip, dst_ip):
94 for i in range(0, N_PKTS_IN_STREAM):
95 info = self.create_packet_info(src_if, src_if)
96 payload = self.info_to_payload(info)
97 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
98 IPv6(src=src_ip, dst=dst_ip) /
99 UDP(sport=1234, dport=1234) /
105 def verify_filter(self, capture, sent):
106 if not len(capture) == len(sent):
107 # filter out any IPv6 RAs from the captur
109 if (p.haslayer(IPv6)):
113 def verify_capture_ip4(self, rx_if, sent, dst_mac=None):
114 rxd = rx_if.get_capture(len(sent))
117 capture = self.verify_filter(rxd, sent)
119 self.assertEqual(len(capture), len(sent))
121 for i in range(len(capture)):
126 self.assertEqual(eth.type, 0x800)
132 dst_mac = getmacbyip(rx_ip.dst)
134 # check the MAC address on the RX'd packet is correctly formed
135 self.assertEqual(eth.dst, dst_mac)
137 self.assertEqual(rx_ip.src, tx_ip.src)
138 self.assertEqual(rx_ip.dst, tx_ip.dst)
139 # IP processing post pop has decremented the TTL
140 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
145 def verify_capture_ip6(self, rx_if, sent):
146 capture = rx_if.get_capture(len(sent))
148 self.assertEqual(len(capture), len(sent))
150 for i in range(len(capture)):
155 self.assertEqual(eth.type, 0x86DD)
160 # check the MAC address on the RX'd packet is correctly formed
161 self.assertEqual(eth.dst, getmacbyip6(rx_ip.dst))
163 self.assertEqual(rx_ip.src, tx_ip.src)
164 self.assertEqual(rx_ip.dst, tx_ip.dst)
165 # IP processing post pop has decremented the TTL
166 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
168 def test_ip_mcast(self):
169 """ IP Multicast Replication """
172 # a stream that matches the default route. gets dropped.
174 self.vapi.cli("clear trace")
175 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
176 self.pg0.add_stream(tx)
178 self.pg_enable_capture(self.pg_interfaces)
181 self.pg0.assert_nothing_captured(
182 remark="IP multicast packets forwarded on default route")
186 # one accepting interface, pg0, 7 forwarding interfaces
187 # many forwarding interfaces test the case where the replicare DPO
188 # needs to use extra cache lines for the buckets.
190 route_232_1_1_1 = VppIpMRoute(
194 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
195 [VppMRoutePath(self.pg0.sw_if_index,
196 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
197 VppMRoutePath(self.pg1.sw_if_index,
198 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
199 VppMRoutePath(self.pg2.sw_if_index,
200 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
201 VppMRoutePath(self.pg3.sw_if_index,
202 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
203 VppMRoutePath(self.pg4.sw_if_index,
204 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
205 VppMRoutePath(self.pg5.sw_if_index,
206 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
207 VppMRoutePath(self.pg6.sw_if_index,
208 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
209 VppMRoutePath(self.pg7.sw_if_index,
210 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
211 route_232_1_1_1.add_vpp_config()
215 # one accepting interface, pg0, 2 forwarding interfaces
217 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
221 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
222 [VppMRoutePath(self.pg0.sw_if_index,
223 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
224 VppMRoutePath(self.pg1.sw_if_index,
225 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
226 VppMRoutePath(self.pg2.sw_if_index,
227 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
228 route_1_1_1_1_232_1_1_1.add_vpp_config()
232 # one accepting interface, pg0, 2 forwarding interfaces
233 # that use unicast next-hops
235 route_1_1_1_1_232_1_1_2 = VppIpMRoute(
239 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
240 [VppMRoutePath(self.pg0.sw_if_index,
241 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
242 VppMRoutePath(self.pg1.sw_if_index,
243 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
244 nh=self.pg1.remote_ip4),
245 VppMRoutePath(self.pg2.sw_if_index,
246 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
247 nh=self.pg2.remote_ip4)])
248 route_1_1_1_1_232_1_1_2.add_vpp_config()
252 # one accepting interface, pg0, 1 forwarding interfaces
254 route_232 = VppIpMRoute(
258 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
259 [VppMRoutePath(self.pg0.sw_if_index,
260 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
261 VppMRoutePath(self.pg1.sw_if_index,
262 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
263 route_232.add_vpp_config()
266 # a stream that matches the route for (1.1.1.1,232.1.1.1)
269 self.vapi.cli("clear trace")
270 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
271 self.pg0.add_stream(tx)
273 self.pg_enable_capture(self.pg_interfaces)
276 # We expect replications on Pg1->7
277 self.verify_capture_ip4(self.pg1, tx)
278 self.verify_capture_ip4(self.pg2, tx)
280 # no replications on Pg0
281 self.pg0.assert_nothing_captured(
282 remark="IP multicast packets forwarded on PG0")
283 self.pg3.assert_nothing_captured(
284 remark="IP multicast packets forwarded on PG3")
287 # a stream that matches the route for (1.1.1.1,232.1.1.1)
290 self.vapi.cli("clear trace")
291 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1",
293 self.pg0.add_stream(tx)
295 self.pg_enable_capture(self.pg_interfaces)
298 # We expect replications on Pg1->7
299 self.verify_capture_ip4(self.pg1, tx)
300 self.verify_capture_ip4(self.pg2, tx)
302 # no replications on Pg0
303 self.pg0.assert_nothing_captured(
304 remark="IP multicast packets forwarded on PG0")
305 self.pg3.assert_nothing_captured(
306 remark="IP multicast packets forwarded on PG3")
309 # a stream to the unicast next-hops
311 self.vapi.cli("clear trace")
312 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.2")
313 self.pg0.add_stream(tx)
315 self.pg_enable_capture(self.pg_interfaces)
318 # We expect replications on Pg1->7
319 self.verify_capture_ip4(self.pg1, tx, dst_mac=self.pg1.remote_mac)
320 self.verify_capture_ip4(self.pg2, tx, dst_mac=self.pg2.remote_mac)
322 # no replications on Pg0 nor pg3
323 self.pg0.assert_nothing_captured(
324 remark="IP multicast packets forwarded on PG0")
325 self.pg3.assert_nothing_captured(
326 remark="IP multicast packets forwarded on PG3")
329 # a stream that matches the route for (*,232.0.0.0/8)
330 # Send packets with the 9th bit set so we test the correct clearing
331 # of that bit in the mac rewrite
333 self.vapi.cli("clear trace")
334 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.255.255.255")
335 self.pg0.add_stream(tx)
337 self.pg_enable_capture(self.pg_interfaces)
340 # We expect replications on Pg1 only
341 self.verify_capture_ip4(self.pg1, tx)
343 # no replications on Pg0, Pg2 not Pg3
344 self.pg0.assert_nothing_captured(
345 remark="IP multicast packets forwarded on PG0")
346 self.pg2.assert_nothing_captured(
347 remark="IP multicast packets forwarded on PG2")
348 self.pg3.assert_nothing_captured(
349 remark="IP multicast packets forwarded on PG3")
352 # a stream that matches the route for (*,232.1.1.1)
354 self.vapi.cli("clear trace")
355 tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "232.1.1.1")
356 self.pg0.add_stream(tx)
358 self.pg_enable_capture(self.pg_interfaces)
361 # We expect replications on Pg1->7
362 self.verify_capture_ip4(self.pg1, tx)
363 self.verify_capture_ip4(self.pg2, tx)
364 self.verify_capture_ip4(self.pg3, tx)
365 self.verify_capture_ip4(self.pg4, tx)
366 self.verify_capture_ip4(self.pg5, tx)
367 self.verify_capture_ip4(self.pg6, tx)
368 self.verify_capture_ip4(self.pg7, tx)
370 # no replications on Pg0
371 self.pg0.assert_nothing_captured(
372 remark="IP multicast packets forwarded on PG0")
374 def test_ip6_mcast(self):
375 """ IPv6 Multicast Replication """
378 # a stream that matches the default route. gets dropped.
380 self.vapi.cli("clear trace")
381 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
382 self.pg0.add_stream(tx)
384 self.pg_enable_capture(self.pg_interfaces)
387 self.pg0.assert_nothing_captured(
388 remark="IPv6 multicast packets forwarded on default route")
392 # one accepting interface, pg0, 3 forwarding interfaces
394 route_ff01_1 = VppIpMRoute(
398 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
399 [VppMRoutePath(self.pg0.sw_if_index,
400 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
401 proto=DpoProto.DPO_PROTO_IP6),
402 VppMRoutePath(self.pg1.sw_if_index,
403 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
404 proto=DpoProto.DPO_PROTO_IP6),
405 VppMRoutePath(self.pg2.sw_if_index,
406 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
407 proto=DpoProto.DPO_PROTO_IP6),
408 VppMRoutePath(self.pg3.sw_if_index,
409 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
410 proto=DpoProto.DPO_PROTO_IP6)],
412 route_ff01_1.add_vpp_config()
416 # one accepting interface, pg0, 2 forwarding interfaces
418 route_2001_ff01_1 = VppIpMRoute(
422 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
423 [VppMRoutePath(self.pg0.sw_if_index,
424 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
425 proto=DpoProto.DPO_PROTO_IP6),
426 VppMRoutePath(self.pg1.sw_if_index,
427 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
428 proto=DpoProto.DPO_PROTO_IP6),
429 VppMRoutePath(self.pg2.sw_if_index,
430 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
431 proto=DpoProto.DPO_PROTO_IP6)],
433 route_2001_ff01_1.add_vpp_config()
437 # one accepting interface, pg0, 1 forwarding interface
439 route_ff01 = VppIpMRoute(
443 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
444 [VppMRoutePath(self.pg0.sw_if_index,
445 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
446 proto=DpoProto.DPO_PROTO_IP6),
447 VppMRoutePath(self.pg1.sw_if_index,
448 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
449 proto=DpoProto.DPO_PROTO_IP6)],
451 route_ff01.add_vpp_config()
454 # a stream that matches the route for (*, ff01::/16)
455 # sent on the non-accepting interface
457 self.vapi.cli("clear trace")
458 tx = self.create_stream_ip6(self.pg1, "2002::1", "ff01:2::255")
459 self.send_and_assert_no_replies(self.pg1, tx, "RPF miss")
462 # a stream that matches the route for (*, ff01::/16)
463 # sent on the accepting interface
465 self.vapi.cli("clear trace")
466 tx = self.create_stream_ip6(self.pg0, "2002::1", "ff01:2::255")
467 self.pg0.add_stream(tx)
469 self.pg_enable_capture(self.pg_interfaces)
472 # We expect replications on Pg1
473 self.verify_capture_ip6(self.pg1, tx)
475 # no replications on Pg0, Pg3
476 self.pg0.assert_nothing_captured(
477 remark="IP multicast packets forwarded on PG0")
478 self.pg2.assert_nothing_captured(
479 remark="IP multicast packets forwarded on PG2")
480 self.pg3.assert_nothing_captured(
481 remark="IP multicast packets forwarded on PG3")
484 # Bounce the interface and it should still work
486 self.pg1.admin_down()
487 self.pg0.add_stream(tx)
488 self.pg_enable_capture(self.pg_interfaces)
490 self.pg1.assert_nothing_captured(
491 remark="IP multicast packets forwarded on down PG1")
494 self.pg0.add_stream(tx)
495 self.pg_enable_capture(self.pg_interfaces)
497 self.verify_capture_ip6(self.pg1, tx)
500 # a stream that matches the route for (*,ff01::1)
502 self.vapi.cli("clear trace")
503 tx = self.create_stream_ip6(self.pg0, "2002::2", "ff01::1")
504 self.pg0.add_stream(tx)
506 self.pg_enable_capture(self.pg_interfaces)
509 # We expect replications on Pg1, 2, 3.
510 self.verify_capture_ip6(self.pg1, tx)
511 self.verify_capture_ip6(self.pg2, tx)
512 self.verify_capture_ip6(self.pg3, tx)
514 # no replications on Pg0
515 self.pg0.assert_nothing_captured(
516 remark="IPv6 multicast packets forwarded on PG0")
519 # a stream that matches the route for (2001::1, ff00::1)
521 self.vapi.cli("clear trace")
522 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
523 self.pg0.add_stream(tx)
525 self.pg_enable_capture(self.pg_interfaces)
528 # We expect replications on Pg1, 2,
529 self.verify_capture_ip6(self.pg1, tx)
530 self.verify_capture_ip6(self.pg2, tx)
532 # no replications on Pg0, Pg3
533 self.pg0.assert_nothing_captured(
534 remark="IP multicast packets forwarded on PG0")
535 self.pg3.assert_nothing_captured(
536 remark="IP multicast packets forwarded on PG3")
538 def _mcast_connected_send_stream(self, dst_ip):
539 self.vapi.cli("clear trace")
540 tx = self.create_stream_ip4(self.pg0,
543 self.pg0.add_stream(tx)
545 self.pg_enable_capture(self.pg_interfaces)
548 # We expect replications on Pg1.
549 self.verify_capture_ip4(self.pg1, tx)
553 def test_ip_mcast_connected(self):
554 """ IP Multicast Connected Source check """
558 # one accepting interface, pg0, 1 forwarding interfaces
560 route_232_1_1_1 = VppIpMRoute(
564 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
565 [VppMRoutePath(self.pg0.sw_if_index,
566 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
567 VppMRoutePath(self.pg1.sw_if_index,
568 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
570 route_232_1_1_1.add_vpp_config()
571 route_232_1_1_1.update_entry_flags(
572 MRouteEntryFlags.MFIB_ENTRY_FLAG_CONNECTED)
575 # Now the (*,G) is present, send from connected source
577 tx = self._mcast_connected_send_stream("232.1.1.1")
580 # Constrct a representation of the signal we expect on pg0
582 signal_232_1_1_1_itf_0 = VppMFibSignal(self,
584 self.pg0.sw_if_index,
588 # read the only expected signal
590 signals = self.vapi.mfib_signal_dump()
592 self.assertEqual(1, len(signals))
594 signal_232_1_1_1_itf_0.compare(signals[0])
597 # reading the signal allows for the generation of another
598 # so send more packets and expect the next signal
600 tx = self._mcast_connected_send_stream("232.1.1.1")
602 signals = self.vapi.mfib_signal_dump()
603 self.assertEqual(1, len(signals))
604 signal_232_1_1_1_itf_0.compare(signals[0])
607 # A Second entry with connected check
608 # one accepting interface, pg0, 1 forwarding interfaces
610 route_232_1_1_2 = VppIpMRoute(
614 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
615 [VppMRoutePath(self.pg0.sw_if_index,
616 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
617 VppMRoutePath(self.pg1.sw_if_index,
618 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
620 route_232_1_1_2.add_vpp_config()
621 route_232_1_1_2.update_entry_flags(
622 MRouteEntryFlags.MFIB_ENTRY_FLAG_CONNECTED)
625 # Send traffic to both entries. One read should net us two signals
627 signal_232_1_1_2_itf_0 = VppMFibSignal(self,
629 self.pg0.sw_if_index,
631 tx = self._mcast_connected_send_stream("232.1.1.1")
632 tx2 = self._mcast_connected_send_stream("232.1.1.2")
635 # read the only expected signal
637 signals = self.vapi.mfib_signal_dump()
639 self.assertEqual(2, len(signals))
641 signal_232_1_1_1_itf_0.compare(signals[1])
642 signal_232_1_1_2_itf_0.compare(signals[0])
644 route_232_1_1_1.update_entry_flags(
645 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
646 route_232_1_1_2.update_entry_flags(
647 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
649 def test_ip_mcast_signal(self):
650 """ IP Multicast Signal """
654 # one accepting interface, pg0, 1 forwarding interfaces
656 route_232_1_1_1 = VppIpMRoute(
660 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
661 [VppMRoutePath(self.pg0.sw_if_index,
662 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
663 VppMRoutePath(self.pg1.sw_if_index,
664 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
666 route_232_1_1_1.add_vpp_config()
667 route_232_1_1_1.update_entry_flags(
668 MRouteEntryFlags.MFIB_ENTRY_FLAG_SIGNAL)
671 # Now the (*,G) is present, send from connected source
673 tx = self._mcast_connected_send_stream("232.1.1.1")
676 # Constrct a representation of the signal we expect on pg0
678 signal_232_1_1_1_itf_0 = VppMFibSignal(self,
680 self.pg0.sw_if_index,
684 # read the only expected signal
686 signals = self.vapi.mfib_signal_dump()
688 self.assertEqual(1, len(signals))
690 signal_232_1_1_1_itf_0.compare(signals[0])
693 # reading the signal allows for the generation of another
694 # so send more packets and expect the next signal
696 tx = self._mcast_connected_send_stream("232.1.1.1")
698 signals = self.vapi.mfib_signal_dump()
699 self.assertEqual(1, len(signals))
700 signal_232_1_1_1_itf_0.compare(signals[0])
703 # Set the negate-signal on the accepting interval - the signals
706 route_232_1_1_1.update_path_flags(
707 self.pg0.sw_if_index,
708 (MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
709 MRouteItfFlags.MFIB_ITF_FLAG_NEGATE_SIGNAL))
711 self.vapi.cli("clear trace")
712 tx = self._mcast_connected_send_stream("232.1.1.1")
714 signals = self.vapi.mfib_signal_dump()
715 self.assertEqual(0, len(signals))
718 # Clear the SIGNAL flag on the entry and the signals should
719 # come back since the interface is still NEGATE-SIGNAL
721 route_232_1_1_1.update_entry_flags(
722 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
724 tx = self._mcast_connected_send_stream("232.1.1.1")
726 signals = self.vapi.mfib_signal_dump()
727 self.assertEqual(1, len(signals))
728 signal_232_1_1_1_itf_0.compare(signals[0])
731 # Lastly remove the NEGATE-SIGNAL from the interface and the
732 # signals should stop
734 route_232_1_1_1.update_path_flags(self.pg0.sw_if_index,
735 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT)
737 tx = self._mcast_connected_send_stream("232.1.1.1")
738 signals = self.vapi.mfib_signal_dump()
739 self.assertEqual(0, len(signals))
741 def test_ip_mcast_vrf(self):
742 """ IP Multicast Replication in non-default table"""
746 # one accepting interface, pg0, 2 forwarding interfaces
748 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
752 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
753 [VppMRoutePath(self.pg8.sw_if_index,
754 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
755 VppMRoutePath(self.pg1.sw_if_index,
756 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
757 VppMRoutePath(self.pg2.sw_if_index,
758 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
760 route_1_1_1_1_232_1_1_1.add_vpp_config()
763 # a stream that matches the route for (1.1.1.1,232.1.1.1)
766 self.vapi.cli("clear trace")
767 tx = self.create_stream_ip4(self.pg8, "1.1.1.1", "232.1.1.1")
768 self.pg8.add_stream(tx)
770 self.pg_enable_capture(self.pg_interfaces)
773 # We expect replications on Pg1 & 2
774 self.verify_capture_ip4(self.pg1, tx)
775 self.verify_capture_ip4(self.pg2, tx)
777 def test_ip6_mcast_vrf(self):
778 """ IPv6 Multicast Replication in non-default table"""
782 # one accepting interface, pg0, 2 forwarding interfaces
784 route_2001_ff01_1 = VppIpMRoute(
788 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
789 [VppMRoutePath(self.pg8.sw_if_index,
790 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
791 proto=DpoProto.DPO_PROTO_IP6),
792 VppMRoutePath(self.pg1.sw_if_index,
793 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
794 proto=DpoProto.DPO_PROTO_IP6),
795 VppMRoutePath(self.pg2.sw_if_index,
796 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
797 proto=DpoProto.DPO_PROTO_IP6)],
800 route_2001_ff01_1.add_vpp_config()
803 # a stream that matches the route for (2001::1, ff00::1)
805 self.vapi.cli("clear trace")
806 tx = self.create_stream_ip6(self.pg8, "2001::1", "ff01::1")
807 self.pg8.add_stream(tx)
809 self.pg_enable_capture(self.pg_interfaces)
812 # We expect replications on Pg1, 2,
813 self.verify_capture_ip6(self.pg1, tx)
814 self.verify_capture_ip6(self.pg2, tx)
816 def test_bidir(self):
817 """ IP Multicast Bi-directional """
820 # A (*,G). The set of accepting interfaces matching the forwarding
822 route_232_1_1_1 = VppIpMRoute(
826 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
827 [VppMRoutePath(self.pg0.sw_if_index,
828 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
829 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
830 VppMRoutePath(self.pg1.sw_if_index,
831 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
832 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
833 VppMRoutePath(self.pg2.sw_if_index,
834 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
835 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
836 VppMRoutePath(self.pg3.sw_if_index,
837 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
838 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
839 route_232_1_1_1.add_vpp_config()
841 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
842 self.pg0.add_stream(tx)
844 self.pg_enable_capture(self.pg_interfaces)
847 # We expect replications on Pg1, 2, 3, but not on pg0
848 self.verify_capture_ip4(self.pg1, tx)
849 self.verify_capture_ip4(self.pg2, tx)
850 self.verify_capture_ip4(self.pg3, tx)
851 self.pg0.assert_nothing_captured(
852 remark="IP multicast packets forwarded on PG0")
855 if __name__ == '__main__':
856 unittest.main(testRunner=VppTestRunner)