5 from framework import VppTestCase, VppTestRunner
6 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
7 from vpp_ip_route import VppIpMRoute, VppMRoutePath, VppMFibSignal, \
8 MRouteItfFlags, MRouteEntryFlags, VppIpTable, DpoProto
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether
12 from scapy.layers.inet import IP, UDP, getmacbyip, ICMP
13 from scapy.layers.inet6 import IPv6, getmacbyip6
17 # The number of packets sent is set to 91 so that when we replicate more than 3
18 # times, which we do for some entries, we will generate more than 256 packets
19 # to the next node in the VLIB graph. Thus we are testing the code's
20 # correctness handling this over-flow.
21 # It's also an odd number so we hit any single loops.
26 class TestMFIB(VppTestCase):
27 """ MFIB Test Case """
30 super(TestMFIB, self).setUp()
33 """ MFIB Unit Tests """
34 error = self.vapi.cli("test mfib")
37 self.logger.critical(error)
38 self.assertEqual(error.find("Failed"), -1)
41 class TestIPMcast(VppTestCase):
42 """ IP Multicast Test Case """
45 super(TestIPMcast, self).setUp()
47 # create 8 pg interfaces
48 self.create_pg_interfaces(range(9))
51 for i in self.pg_interfaces[:8]:
59 tbl4 = VppIpTable(self, 10)
61 self.pg8.set_table_ip4(10)
64 tbl6 = VppIpTable(self, 10, is_ip6=1)
66 self.pg8.set_table_ip6(10)
70 for i in self.pg_interfaces:
75 self.pg8.set_table_ip4(0)
76 self.pg8.set_table_ip6(0)
77 super(TestIPMcast, self).tearDown()
79 def create_stream_ip4(self, src_if, src_ip, dst_ip, payload_size=0):
81 # default to small packet sizes
82 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
83 IP(src=src_ip, dst=dst_ip) /
84 UDP(sport=1234, dport=1234))
86 payload_size = 64 - len(p)
87 p = p / Raw('\xa5' * payload_size)
89 for i in range(0, N_PKTS_IN_STREAM):
93 def create_stream_ip6(self, src_if, src_ip, dst_ip):
95 for i in range(0, N_PKTS_IN_STREAM):
96 info = self.create_packet_info(src_if, src_if)
97 payload = self.info_to_payload(info)
98 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
99 IPv6(src=src_ip, dst=dst_ip) /
100 UDP(sport=1234, dport=1234) /
106 def verify_filter(self, capture, sent):
107 if not len(capture) == len(sent):
108 # filter out any IPv6 RAs from the captur
110 if (p.haslayer(IPv6)):
114 def verify_capture_ip4(self, rx_if, sent, dst_mac=None):
115 rxd = rx_if.get_capture(len(sent))
118 capture = self.verify_filter(rxd, sent)
120 self.assertEqual(len(capture), len(sent))
122 for i in range(len(capture)):
127 self.assertEqual(eth.type, 0x800)
133 dst_mac = getmacbyip(rx_ip.dst)
135 # check the MAC address on the RX'd packet is correctly formed
136 self.assertEqual(eth.dst, dst_mac)
138 self.assertEqual(rx_ip.src, tx_ip.src)
139 self.assertEqual(rx_ip.dst, tx_ip.dst)
140 # IP processing post pop has decremented the TTL
141 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
146 def verify_capture_ip6(self, rx_if, sent):
147 capture = rx_if.get_capture(len(sent))
149 self.assertEqual(len(capture), len(sent))
151 for i in range(len(capture)):
156 self.assertEqual(eth.type, 0x86DD)
161 # check the MAC address on the RX'd packet is correctly formed
162 self.assertEqual(eth.dst, getmacbyip6(rx_ip.dst))
164 self.assertEqual(rx_ip.src, tx_ip.src)
165 self.assertEqual(rx_ip.dst, tx_ip.dst)
166 # IP processing post pop has decremented the TTL
167 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
169 def test_ip_mcast(self):
170 """ IP Multicast Replication """
173 # a stream that matches the default route. gets dropped.
175 self.vapi.cli("clear trace")
176 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
177 self.pg0.add_stream(tx)
179 self.pg_enable_capture(self.pg_interfaces)
182 self.pg0.assert_nothing_captured(
183 remark="IP multicast packets forwarded on default route")
187 # one accepting interface, pg0, 7 forwarding interfaces
188 # many forwarding interfaces test the case where the replicare DPO
189 # needs to use extra cache lines for the buckets.
191 route_232_1_1_1 = VppIpMRoute(
195 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
196 [VppMRoutePath(self.pg0.sw_if_index,
197 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
198 VppMRoutePath(self.pg1.sw_if_index,
199 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
200 VppMRoutePath(self.pg2.sw_if_index,
201 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
202 VppMRoutePath(self.pg3.sw_if_index,
203 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
204 VppMRoutePath(self.pg4.sw_if_index,
205 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
206 VppMRoutePath(self.pg5.sw_if_index,
207 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
208 VppMRoutePath(self.pg6.sw_if_index,
209 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
210 VppMRoutePath(self.pg7.sw_if_index,
211 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
212 route_232_1_1_1.add_vpp_config()
216 # one accepting interface, pg0, 2 forwarding interfaces
218 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
222 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
223 [VppMRoutePath(self.pg0.sw_if_index,
224 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
225 VppMRoutePath(self.pg1.sw_if_index,
226 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
227 VppMRoutePath(self.pg2.sw_if_index,
228 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
229 route_1_1_1_1_232_1_1_1.add_vpp_config()
233 # one accepting interface, pg0, 2 forwarding interfaces
234 # that use unicast next-hops
236 route_1_1_1_1_232_1_1_2 = VppIpMRoute(
240 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
241 [VppMRoutePath(self.pg0.sw_if_index,
242 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
243 VppMRoutePath(self.pg1.sw_if_index,
244 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
245 nh=self.pg1.remote_ip4),
246 VppMRoutePath(self.pg2.sw_if_index,
247 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
248 nh=self.pg2.remote_ip4)])
249 route_1_1_1_1_232_1_1_2.add_vpp_config()
253 # one accepting interface, pg0, 1 forwarding interfaces
255 route_232 = VppIpMRoute(
259 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
260 [VppMRoutePath(self.pg0.sw_if_index,
261 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
262 VppMRoutePath(self.pg1.sw_if_index,
263 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
264 route_232.add_vpp_config()
267 # a stream that matches the route for (1.1.1.1,232.1.1.1)
270 self.vapi.cli("clear trace")
271 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
272 self.pg0.add_stream(tx)
274 self.pg_enable_capture(self.pg_interfaces)
277 # We expect replications on Pg1->7
278 self.verify_capture_ip4(self.pg1, tx)
279 self.verify_capture_ip4(self.pg2, tx)
281 # no replications on Pg0
282 self.pg0.assert_nothing_captured(
283 remark="IP multicast packets forwarded on PG0")
284 self.pg3.assert_nothing_captured(
285 remark="IP multicast packets forwarded on PG3")
288 # a stream that matches the route for (1.1.1.1,232.1.1.1)
291 self.vapi.cli("clear trace")
292 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1",
294 self.pg0.add_stream(tx)
296 self.pg_enable_capture(self.pg_interfaces)
299 # We expect replications on Pg1->7
300 self.verify_capture_ip4(self.pg1, tx)
301 self.verify_capture_ip4(self.pg2, tx)
303 # no replications on Pg0
304 self.pg0.assert_nothing_captured(
305 remark="IP multicast packets forwarded on PG0")
306 self.pg3.assert_nothing_captured(
307 remark="IP multicast packets forwarded on PG3")
310 # a stream to the unicast next-hops
312 self.vapi.cli("clear trace")
313 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.2")
314 self.pg0.add_stream(tx)
316 self.pg_enable_capture(self.pg_interfaces)
319 # We expect replications on Pg1->7
320 self.verify_capture_ip4(self.pg1, tx, dst_mac=self.pg1.remote_mac)
321 self.verify_capture_ip4(self.pg2, tx, dst_mac=self.pg2.remote_mac)
323 # no replications on Pg0 nor pg3
324 self.pg0.assert_nothing_captured(
325 remark="IP multicast packets forwarded on PG0")
326 self.pg3.assert_nothing_captured(
327 remark="IP multicast packets forwarded on PG3")
330 # a stream that matches the route for (*,232.0.0.0/8)
331 # Send packets with the 9th bit set so we test the correct clearing
332 # of that bit in the mac rewrite
334 self.vapi.cli("clear trace")
335 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.255.255.255")
336 self.pg0.add_stream(tx)
338 self.pg_enable_capture(self.pg_interfaces)
341 # We expect replications on Pg1 only
342 self.verify_capture_ip4(self.pg1, tx)
344 # no replications on Pg0, Pg2 not Pg3
345 self.pg0.assert_nothing_captured(
346 remark="IP multicast packets forwarded on PG0")
347 self.pg2.assert_nothing_captured(
348 remark="IP multicast packets forwarded on PG2")
349 self.pg3.assert_nothing_captured(
350 remark="IP multicast packets forwarded on PG3")
353 # a stream that matches the route for (*,232.1.1.1)
355 self.vapi.cli("clear trace")
356 tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "232.1.1.1")
357 self.pg0.add_stream(tx)
359 self.pg_enable_capture(self.pg_interfaces)
362 # We expect replications on Pg1->7
363 self.verify_capture_ip4(self.pg1, tx)
364 self.verify_capture_ip4(self.pg2, tx)
365 self.verify_capture_ip4(self.pg3, tx)
366 self.verify_capture_ip4(self.pg4, tx)
367 self.verify_capture_ip4(self.pg5, tx)
368 self.verify_capture_ip4(self.pg6, tx)
369 self.verify_capture_ip4(self.pg7, tx)
371 # no replications on Pg0
372 self.pg0.assert_nothing_captured(
373 remark="IP multicast packets forwarded on PG0")
375 def test_ip6_mcast(self):
376 """ IPv6 Multicast Replication """
379 # a stream that matches the default route. gets dropped.
381 self.vapi.cli("clear trace")
382 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
383 self.pg0.add_stream(tx)
385 self.pg_enable_capture(self.pg_interfaces)
388 self.pg0.assert_nothing_captured(
389 remark="IPv6 multicast packets forwarded on default route")
393 # one accepting interface, pg0, 3 forwarding interfaces
395 route_ff01_1 = VppIpMRoute(
399 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
400 [VppMRoutePath(self.pg0.sw_if_index,
401 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
402 proto=DpoProto.DPO_PROTO_IP6),
403 VppMRoutePath(self.pg1.sw_if_index,
404 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
405 proto=DpoProto.DPO_PROTO_IP6),
406 VppMRoutePath(self.pg2.sw_if_index,
407 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
408 proto=DpoProto.DPO_PROTO_IP6),
409 VppMRoutePath(self.pg3.sw_if_index,
410 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
411 proto=DpoProto.DPO_PROTO_IP6)],
413 route_ff01_1.add_vpp_config()
417 # one accepting interface, pg0, 2 forwarding interfaces
419 route_2001_ff01_1 = VppIpMRoute(
423 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
424 [VppMRoutePath(self.pg0.sw_if_index,
425 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
426 proto=DpoProto.DPO_PROTO_IP6),
427 VppMRoutePath(self.pg1.sw_if_index,
428 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
429 proto=DpoProto.DPO_PROTO_IP6),
430 VppMRoutePath(self.pg2.sw_if_index,
431 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
432 proto=DpoProto.DPO_PROTO_IP6)],
434 route_2001_ff01_1.add_vpp_config()
438 # one accepting interface, pg0, 1 forwarding interface
440 route_ff01 = VppIpMRoute(
444 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
445 [VppMRoutePath(self.pg0.sw_if_index,
446 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
447 proto=DpoProto.DPO_PROTO_IP6),
448 VppMRoutePath(self.pg1.sw_if_index,
449 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
450 proto=DpoProto.DPO_PROTO_IP6)],
452 route_ff01.add_vpp_config()
455 # a stream that matches the route for (*, ff01::/16)
456 # sent on the non-accepting interface
458 self.vapi.cli("clear trace")
459 tx = self.create_stream_ip6(self.pg1, "2002::1", "ff01:2::255")
460 self.send_and_assert_no_replies(self.pg1, tx, "RPF miss")
463 # a stream that matches the route for (*, ff01::/16)
464 # sent on the accepting interface
466 self.vapi.cli("clear trace")
467 tx = self.create_stream_ip6(self.pg0, "2002::1", "ff01:2::255")
468 self.pg0.add_stream(tx)
470 self.pg_enable_capture(self.pg_interfaces)
473 # We expect replications on Pg1
474 self.verify_capture_ip6(self.pg1, tx)
476 # no replications on Pg0, Pg3
477 self.pg0.assert_nothing_captured(
478 remark="IP multicast packets forwarded on PG0")
479 self.pg2.assert_nothing_captured(
480 remark="IP multicast packets forwarded on PG2")
481 self.pg3.assert_nothing_captured(
482 remark="IP multicast packets forwarded on PG3")
485 # Bounce the interface and it should still work
487 self.pg1.admin_down()
488 self.pg0.add_stream(tx)
489 self.pg_enable_capture(self.pg_interfaces)
491 self.pg1.assert_nothing_captured(
492 remark="IP multicast packets forwarded on down PG1")
495 self.pg0.add_stream(tx)
496 self.pg_enable_capture(self.pg_interfaces)
498 self.verify_capture_ip6(self.pg1, tx)
501 # a stream that matches the route for (*,ff01::1)
503 self.vapi.cli("clear trace")
504 tx = self.create_stream_ip6(self.pg0, "2002::2", "ff01::1")
505 self.pg0.add_stream(tx)
507 self.pg_enable_capture(self.pg_interfaces)
510 # We expect replications on Pg1, 2, 3.
511 self.verify_capture_ip6(self.pg1, tx)
512 self.verify_capture_ip6(self.pg2, tx)
513 self.verify_capture_ip6(self.pg3, tx)
515 # no replications on Pg0
516 self.pg0.assert_nothing_captured(
517 remark="IPv6 multicast packets forwarded on PG0")
520 # a stream that matches the route for (2001::1, ff00::1)
522 self.vapi.cli("clear trace")
523 tx = self.create_stream_ip6(self.pg0, "2001::1", "ff01::1")
524 self.pg0.add_stream(tx)
526 self.pg_enable_capture(self.pg_interfaces)
529 # We expect replications on Pg1, 2,
530 self.verify_capture_ip6(self.pg1, tx)
531 self.verify_capture_ip6(self.pg2, tx)
533 # no replications on Pg0, Pg3
534 self.pg0.assert_nothing_captured(
535 remark="IP multicast packets forwarded on PG0")
536 self.pg3.assert_nothing_captured(
537 remark="IP multicast packets forwarded on PG3")
539 def _mcast_connected_send_stream(self, dst_ip):
540 self.vapi.cli("clear trace")
541 tx = self.create_stream_ip4(self.pg0,
544 self.pg0.add_stream(tx)
546 self.pg_enable_capture(self.pg_interfaces)
549 # We expect replications on Pg1.
550 self.verify_capture_ip4(self.pg1, tx)
554 def test_ip_mcast_connected(self):
555 """ IP Multicast Connected Source check """
559 # one accepting interface, pg0, 1 forwarding interfaces
561 route_232_1_1_1 = VppIpMRoute(
565 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
566 [VppMRoutePath(self.pg0.sw_if_index,
567 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
568 VppMRoutePath(self.pg1.sw_if_index,
569 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
571 route_232_1_1_1.add_vpp_config()
572 route_232_1_1_1.update_entry_flags(
573 MRouteEntryFlags.MFIB_ENTRY_FLAG_CONNECTED)
576 # Now the (*,G) is present, send from connected source
578 tx = self._mcast_connected_send_stream("232.1.1.1")
581 # Constrct a representation of the signal we expect on pg0
583 signal_232_1_1_1_itf_0 = VppMFibSignal(self,
585 self.pg0.sw_if_index,
589 # read the only expected signal
591 signals = self.vapi.mfib_signal_dump()
593 self.assertEqual(1, len(signals))
595 signal_232_1_1_1_itf_0.compare(signals[0])
598 # reading the signal allows for the generation of another
599 # so send more packets and expect the next signal
601 tx = self._mcast_connected_send_stream("232.1.1.1")
603 signals = self.vapi.mfib_signal_dump()
604 self.assertEqual(1, len(signals))
605 signal_232_1_1_1_itf_0.compare(signals[0])
608 # A Second entry with connected check
609 # one accepting interface, pg0, 1 forwarding interfaces
611 route_232_1_1_2 = VppIpMRoute(
615 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
616 [VppMRoutePath(self.pg0.sw_if_index,
617 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
618 VppMRoutePath(self.pg1.sw_if_index,
619 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
621 route_232_1_1_2.add_vpp_config()
622 route_232_1_1_2.update_entry_flags(
623 MRouteEntryFlags.MFIB_ENTRY_FLAG_CONNECTED)
626 # Send traffic to both entries. One read should net us two signals
628 signal_232_1_1_2_itf_0 = VppMFibSignal(self,
630 self.pg0.sw_if_index,
632 tx = self._mcast_connected_send_stream("232.1.1.1")
633 tx2 = self._mcast_connected_send_stream("232.1.1.2")
636 # read the only expected signal
638 signals = self.vapi.mfib_signal_dump()
640 self.assertEqual(2, len(signals))
642 signal_232_1_1_1_itf_0.compare(signals[1])
643 signal_232_1_1_2_itf_0.compare(signals[0])
645 route_232_1_1_1.update_entry_flags(
646 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
647 route_232_1_1_2.update_entry_flags(
648 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
650 def test_ip_mcast_signal(self):
651 """ IP Multicast Signal """
655 # one accepting interface, pg0, 1 forwarding interfaces
657 route_232_1_1_1 = VppIpMRoute(
661 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
662 [VppMRoutePath(self.pg0.sw_if_index,
663 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
664 VppMRoutePath(self.pg1.sw_if_index,
665 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
667 route_232_1_1_1.add_vpp_config()
668 route_232_1_1_1.update_entry_flags(
669 MRouteEntryFlags.MFIB_ENTRY_FLAG_SIGNAL)
672 # Now the (*,G) is present, send from connected source
674 tx = self._mcast_connected_send_stream("232.1.1.1")
677 # Constrct a representation of the signal we expect on pg0
679 signal_232_1_1_1_itf_0 = VppMFibSignal(self,
681 self.pg0.sw_if_index,
685 # read the only expected signal
687 signals = self.vapi.mfib_signal_dump()
689 self.assertEqual(1, len(signals))
691 signal_232_1_1_1_itf_0.compare(signals[0])
694 # reading the signal allows for the generation of another
695 # so send more packets and expect the next signal
697 tx = self._mcast_connected_send_stream("232.1.1.1")
699 signals = self.vapi.mfib_signal_dump()
700 self.assertEqual(1, len(signals))
701 signal_232_1_1_1_itf_0.compare(signals[0])
704 # Set the negate-signal on the accepting interval - the signals
707 route_232_1_1_1.update_path_flags(
708 self.pg0.sw_if_index,
709 (MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
710 MRouteItfFlags.MFIB_ITF_FLAG_NEGATE_SIGNAL))
712 self.vapi.cli("clear trace")
713 tx = self._mcast_connected_send_stream("232.1.1.1")
715 signals = self.vapi.mfib_signal_dump()
716 self.assertEqual(0, len(signals))
719 # Clear the SIGNAL flag on the entry and the signals should
720 # come back since the interface is still NEGATE-SIGNAL
722 route_232_1_1_1.update_entry_flags(
723 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE)
725 tx = self._mcast_connected_send_stream("232.1.1.1")
727 signals = self.vapi.mfib_signal_dump()
728 self.assertEqual(1, len(signals))
729 signal_232_1_1_1_itf_0.compare(signals[0])
732 # Lastly remove the NEGATE-SIGNAL from the interface and the
733 # signals should stop
735 route_232_1_1_1.update_path_flags(self.pg0.sw_if_index,
736 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT)
738 tx = self._mcast_connected_send_stream("232.1.1.1")
739 signals = self.vapi.mfib_signal_dump()
740 self.assertEqual(0, len(signals))
742 def test_ip_mcast_vrf(self):
743 """ IP Multicast Replication in non-default table"""
747 # one accepting interface, pg0, 2 forwarding interfaces
749 route_1_1_1_1_232_1_1_1 = VppIpMRoute(
753 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
754 [VppMRoutePath(self.pg8.sw_if_index,
755 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
756 VppMRoutePath(self.pg1.sw_if_index,
757 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
758 VppMRoutePath(self.pg2.sw_if_index,
759 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
761 route_1_1_1_1_232_1_1_1.add_vpp_config()
764 # a stream that matches the route for (1.1.1.1,232.1.1.1)
767 self.vapi.cli("clear trace")
768 tx = self.create_stream_ip4(self.pg8, "1.1.1.1", "232.1.1.1")
769 self.pg8.add_stream(tx)
771 self.pg_enable_capture(self.pg_interfaces)
774 # We expect replications on Pg1 & 2
775 self.verify_capture_ip4(self.pg1, tx)
776 self.verify_capture_ip4(self.pg2, tx)
778 def test_ip6_mcast_vrf(self):
779 """ IPv6 Multicast Replication in non-default table"""
783 # one accepting interface, pg0, 2 forwarding interfaces
785 route_2001_ff01_1 = VppIpMRoute(
789 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
790 [VppMRoutePath(self.pg8.sw_if_index,
791 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT,
792 proto=DpoProto.DPO_PROTO_IP6),
793 VppMRoutePath(self.pg1.sw_if_index,
794 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
795 proto=DpoProto.DPO_PROTO_IP6),
796 VppMRoutePath(self.pg2.sw_if_index,
797 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
798 proto=DpoProto.DPO_PROTO_IP6)],
801 route_2001_ff01_1.add_vpp_config()
804 # a stream that matches the route for (2001::1, ff00::1)
806 self.vapi.cli("clear trace")
807 tx = self.create_stream_ip6(self.pg8, "2001::1", "ff01::1")
808 self.pg8.add_stream(tx)
810 self.pg_enable_capture(self.pg_interfaces)
813 # We expect replications on Pg1, 2,
814 self.verify_capture_ip6(self.pg1, tx)
815 self.verify_capture_ip6(self.pg2, tx)
817 def test_bidir(self):
818 """ IP Multicast Bi-directional """
821 # A (*,G). The set of accepting interfaces matching the forwarding
823 route_232_1_1_1 = VppIpMRoute(
827 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
828 [VppMRoutePath(self.pg0.sw_if_index,
829 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
830 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
831 VppMRoutePath(self.pg1.sw_if_index,
832 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
833 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
834 VppMRoutePath(self.pg2.sw_if_index,
835 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
836 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD),
837 VppMRoutePath(self.pg3.sw_if_index,
838 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
839 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
840 route_232_1_1_1.add_vpp_config()
842 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "232.1.1.1")
843 self.pg0.add_stream(tx)
845 self.pg_enable_capture(self.pg_interfaces)
848 # We expect replications on Pg1, 2, 3, but not on pg0
849 self.verify_capture_ip4(self.pg1, tx)
850 self.verify_capture_ip4(self.pg2, tx)
851 self.verify_capture_ip4(self.pg3, tx)
852 self.pg0.assert_nothing_captured(
853 remark="IP multicast packets forwarded on PG0")
856 if __name__ == '__main__':
857 unittest.main(testRunner=VppTestRunner)