5 from framework import VppTestCase
6 from asfframework import VppTestRunner, tag_fixme_vpp_workers
7 from vpp_ip import INVALID_INDEX
8 from vpp_ip_route import (
26 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
27 from vpp_papi import VppEnum
30 from scapy.packet import Raw
31 from scapy.layers.l2 import Ether, ARP
32 from scapy.layers.inet import IP, UDP, ICMP, icmptypes, icmpcodes
33 from scapy.layers.inet6 import (
39 from scapy.contrib.mpls import MPLS
43 # scapy removed these attributes.
44 # we asked that they be restored: https://github.com/secdev/scapy/pull/1878
45 # semantic names have more meaning than numbers. so here they are.
50 def verify_filter(capture, sent):
51 if not len(capture) == len(sent):
52 # filter out any IPv6 RAs from the capture
59 def verify_mpls_stack(tst, rx, mpls_labels):
60 # the rx'd packet has the MPLS label popped
62 tst.assertEqual(eth.type, 0x8847)
66 for ii in range(len(mpls_labels)):
67 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
68 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
69 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
71 if ii == len(mpls_labels) - 1:
72 tst.assertEqual(rx_mpls.s, 1)
75 tst.assertEqual(rx_mpls.s, 0)
76 # pop the label to expose the next
77 rx_mpls = rx_mpls[MPLS].payload
80 @tag_fixme_vpp_workers
81 class TestMPLS(VppTestCase):
86 super(TestMPLS, cls).setUpClass()
89 def tearDownClass(cls):
90 super(TestMPLS, cls).tearDownClass()
93 super(TestMPLS, self).setUp()
95 # create 2 pg interfaces
96 self.create_pg_interfaces(range(4))
98 # setup both interfaces
99 # assign them different tables.
103 tbl = VppMplsTable(self, 0)
105 self.tables.append(tbl)
107 for i in self.pg_interfaces:
111 tbl = VppIpTable(self, table_id)
113 self.tables.append(tbl)
114 tbl = VppIpTable(self, table_id, is_ip6=1)
116 self.tables.append(tbl)
118 i.set_table_ip4(table_id)
119 i.set_table_ip6(table_id)
128 for i in self.pg_interfaces:
135 super(TestMPLS, self).tearDown()
137 # the default of 64 matches the IP packet TTL default
138 def create_stream_labelled_ip4(
149 self.reset_packet_infos()
151 for i in range(0, n):
152 info = self.create_packet_info(src_if, src_if)
153 payload = self.info_to_payload(info)
154 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
156 for ii in range(len(mpls_labels)):
158 label=mpls_labels[ii].value,
159 ttl=mpls_labels[ii].ttl,
160 cos=mpls_labels[ii].exp,
166 / IP(src=src_if.local_ip4, dst=src_if.remote_ip4, ttl=ip_ttl)
167 / UDP(sport=1234, dport=1234)
173 / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl)
174 / UDP(sport=1234, dport=1234)
180 / IP(src=ip_itf.remote_ip4, dst=ip_itf.local_ip4, ttl=ip_ttl)
185 p[IP].chksum = chksum
190 def create_stream_ip4(
191 self, src_if, dst_ip, ip_ttl=64, ip_dscp=0, payload_size=None
193 self.reset_packet_infos()
195 for i in range(0, 257):
196 info = self.create_packet_info(src_if, src_if)
197 payload = self.info_to_payload(info)
199 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
200 / IP(src=src_if.remote_ip4, dst=dst_ip, ttl=ip_ttl, tos=ip_dscp)
201 / UDP(sport=1234, dport=1234)
206 self.extend_packet(p, payload_size)
210 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
211 self.reset_packet_infos()
213 for i in range(0, 257):
214 info = self.create_packet_info(src_if, src_if)
215 payload = self.info_to_payload(info)
217 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
218 / IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=ip_ttl, tc=ip_dscp)
219 / UDP(sport=1234, dport=1234)
226 def create_stream_labelled_ip6(
227 self, src_if, mpls_labels, hlim=64, dst_ip=None, ping=0, ip_itf=None
230 dst_ip = src_if.remote_ip6
231 self.reset_packet_infos()
233 for i in range(0, 257):
234 info = self.create_packet_info(src_if, src_if)
235 payload = self.info_to_payload(info)
236 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
237 for l in mpls_labels:
238 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
242 IPv6(src=ip_itf.remote_ip6, dst=ip_itf.local_ip6)
243 / ICMPv6EchoRequest()
247 IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim)
248 / UDP(sport=1234, dport=1234)
255 def verify_capture_ip4(
256 self, src_if, capture, sent, ping_resp=0, ip_ttl=None, ip_dscp=0
259 capture = verify_filter(capture, sent)
261 self.assertEqual(len(capture), len(sent))
263 for i in range(len(capture)):
267 # the rx'd packet has the MPLS label popped
269 self.assertEqual(eth.type, 0x800)
275 self.assertEqual(rx_ip.src, tx_ip.src)
276 self.assertEqual(rx_ip.dst, tx_ip.dst)
277 self.assertEqual(rx_ip.tos, ip_dscp)
279 # IP processing post pop has decremented the TTL
280 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
282 self.assertEqual(rx_ip.ttl, ip_ttl)
284 self.assertEqual(rx_ip.src, tx_ip.dst)
285 self.assertEqual(rx_ip.dst, tx_ip.src)
290 def verify_capture_labelled_ip4(
291 self, src_if, capture, sent, mpls_labels, ip_ttl=None
294 capture = verify_filter(capture, sent)
296 self.assertEqual(len(capture), len(sent))
298 for i in range(len(capture)):
304 verify_mpls_stack(self, rx, mpls_labels)
306 self.assertEqual(rx_ip.src, tx_ip.src)
307 self.assertEqual(rx_ip.dst, tx_ip.dst)
309 # IP processing post pop has decremented the TTL
310 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
312 self.assertEqual(rx_ip.ttl, ip_ttl)
317 def verify_capture_labelled_ip6(
318 self, src_if, capture, sent, mpls_labels, ip_ttl=None
321 capture = verify_filter(capture, sent)
323 self.assertEqual(len(capture), len(sent))
325 for i in range(len(capture)):
331 verify_mpls_stack(self, rx, mpls_labels)
333 self.assertEqual(rx_ip.src, tx_ip.src)
334 self.assertEqual(rx_ip.dst, tx_ip.dst)
336 # IP processing post pop has decremented the TTL
337 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
339 self.assertEqual(rx_ip.hlim, ip_ttl)
344 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
346 capture = verify_filter(capture, sent)
348 self.assertEqual(len(capture), len(sent))
350 for i in range(len(capture)):
356 verify_mpls_stack(self, rx, mpls_labels)
358 self.assertEqual(rx_ip.src, tx_ip.src)
359 self.assertEqual(rx_ip.dst, tx_ip.dst)
360 # IP processing post pop has decremented the TTL
361 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
366 def verify_capture_labelled(self, src_if, capture, sent, mpls_labels):
368 capture = verify_filter(capture, sent)
370 self.assertEqual(len(capture), len(sent))
372 for i in range(len(capture)):
374 verify_mpls_stack(self, rx, mpls_labels)
378 def verify_capture_ip6(
379 self, src_if, capture, sent, ip_hlim=None, ip_dscp=0, ping_resp=0
382 self.assertEqual(len(capture), len(sent))
384 for i in range(len(capture)):
388 # the rx'd packet has the MPLS label popped
390 self.assertEqual(eth.type, 0x86DD)
396 self.assertEqual(rx_ip.src, tx_ip.src)
397 self.assertEqual(rx_ip.dst, tx_ip.dst)
398 self.assertEqual(rx_ip.tc, ip_dscp)
399 # IP processing post pop has decremented the TTL
401 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
403 self.assertEqual(rx_ip.hlim, ip_hlim)
405 self.assertEqual(rx_ip.src, tx_ip.dst)
406 self.assertEqual(rx_ip.dst, tx_ip.src)
410 def verify_capture_ip6_icmp(self, src_if, capture, sent):
413 self.assertTrue(len(capture) <= len(sent))
415 for i in range(len(capture)):
419 # the rx'd packet has the MPLS label popped
421 self.assertEqual(eth.type, 0x86DD)
426 self.assertEqual(rx_ip.dst, tx_ip.src)
427 # ICMP sourced from the interface's address
428 self.assertEqual(rx_ip.src, src_if.local_ip6)
429 # hop-limit reset to 255 for IMCP packet
430 self.assertEqual(rx_ip.hlim, 255)
432 icmp = rx[ICMPv6TimeExceeded]
437 def verify_capture_fragmented_labelled_ip4(
438 self, src_if, capture, sent, mpls_labels, ip_ttl=None
441 capture = verify_filter(capture, sent)
443 for i in range(len(capture)):
449 verify_mpls_stack(self, rx, mpls_labels)
451 self.assertEqual(rx_ip.src, tx_ip.src)
452 self.assertEqual(rx_ip.dst, tx_ip.dst)
454 # IP processing post pop has decremented the TTL
455 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
457 self.assertEqual(rx_ip.ttl, ip_ttl)
462 def verify_capture_fragmented_labelled_ip6(
463 self, src_if, capture, sent, mpls_labels, ip_ttl=None
466 capture = verify_filter(capture, sent)
468 for i in range(len(capture)):
473 rx_ip = IPv6(rx[MPLS].payload)
476 verify_mpls_stack(self, rx, mpls_labels)
478 self.assertEqual(rx_ip.src, tx_ip.src)
479 self.assertEqual(rx_ip.dst, tx_ip.dst)
481 # IP processing post pop has decremented the hop-limit
482 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
484 self.assertEqual(rx_ip.hlim, ip_ttl)
489 """MPLS label swap tests"""
492 # A simple MPLS xconnect - eos label in label out
494 route_32_eos = VppMplsRoute(
500 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(33)]
504 route_32_eos.add_vpp_config()
515 self.pg0.sw_if_index,
516 labels=[VppMplsLabel(33)],
523 # a stream that matches the route for 10.0.0.1
524 # PG0 is in the default table
526 tx = self.create_stream_labelled_ip4(
527 self.pg0, [VppMplsLabel(32, ttl=32, exp=1)]
529 rx = self.send_and_expect(self.pg0, tx, self.pg0)
530 self.verify_capture_labelled(
531 self.pg0, rx, tx, [VppMplsLabel(33, ttl=31, exp=1)]
534 self.assertEqual(route_32_eos.get_stats_to()["packets"], 257)
537 # A simple MPLS xconnect - non-eos label in label out
539 route_32_neos = VppMplsRoute(
545 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(33)]
549 route_32_neos.add_vpp_config()
552 # a stream that matches the route for 10.0.0.1
553 # PG0 is in the default table
555 tx = self.create_stream_labelled_ip4(
556 self.pg0, [VppMplsLabel(32, ttl=21, exp=7), VppMplsLabel(99)]
558 rx = self.send_and_expect(self.pg0, tx, self.pg0)
559 self.verify_capture_labelled(
560 self.pg0, rx, tx, [VppMplsLabel(33, ttl=20, exp=7), VppMplsLabel(99)]
562 self.assertEqual(route_32_neos.get_stats_to()["packets"], 257)
565 # A simple MPLS xconnect - non-eos label in label out, uniform mode
567 route_42_neos = VppMplsRoute(
574 self.pg0.sw_if_index,
575 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)],
579 route_42_neos.add_vpp_config()
581 tx = self.create_stream_labelled_ip4(
582 self.pg0, [VppMplsLabel(42, ttl=21, exp=7), VppMplsLabel(99)]
584 rx = self.send_and_expect(self.pg0, tx, self.pg0)
585 self.verify_capture_labelled(
586 self.pg0, rx, tx, [VppMplsLabel(43, ttl=20, exp=7), VppMplsLabel(99)]
590 # An MPLS xconnect - EOS label in IP out
592 route_33_eos = VppMplsRoute(
596 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[])],
598 route_33_eos.add_vpp_config()
600 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
601 rx = self.send_and_expect(self.pg0, tx, self.pg0)
602 self.verify_capture_ip4(self.pg0, rx, tx)
605 # disposed packets have an invalid IPv4 checksum
607 tx = self.create_stream_labelled_ip4(
608 self.pg0, [VppMplsLabel(33)], dst_ip=self.pg0.remote_ip4, n=65, chksum=1
610 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
613 # An MPLS xconnect - EOS label in IP out, uniform mode
615 route_3333_eos = VppMplsRoute(
622 self.pg0.sw_if_index,
623 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
627 route_3333_eos.add_vpp_config()
629 tx = self.create_stream_labelled_ip4(
630 self.pg0, [VppMplsLabel(3333, ttl=55, exp=3)]
632 rx = self.send_and_expect(self.pg0, tx, self.pg0)
633 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
634 tx = self.create_stream_labelled_ip4(
635 self.pg0, [VppMplsLabel(3333, ttl=66, exp=4)]
637 rx = self.send_and_expect(self.pg0, tx, self.pg0)
638 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
641 # An MPLS xconnect - EOS label in IPv6 out
643 route_333_eos = VppMplsRoute(
647 [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, labels=[])],
648 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
650 route_333_eos.add_vpp_config()
652 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
653 rx = self.send_and_expect(self.pg0, tx, self.pg0)
654 self.verify_capture_ip6(self.pg0, rx, tx)
657 # disposed packets have an TTL expired
659 tx = self.create_stream_labelled_ip6(
660 self.pg0, [VppMplsLabel(333, ttl=64)], dst_ip=self.pg1.remote_ip6, hlim=1
662 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
663 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
666 # An MPLS xconnect - EOS label in IPv6 out w imp-null
668 route_334_eos = VppMplsRoute(
674 self.pg0.remote_ip6, self.pg0.sw_if_index, labels=[VppMplsLabel(3)]
677 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
679 route_334_eos.add_vpp_config()
681 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334, ttl=64)])
682 rx = self.send_and_expect(self.pg0, tx, self.pg0)
683 self.verify_capture_ip6(self.pg0, rx, tx)
686 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
688 route_335_eos = VppMplsRoute(
695 self.pg0.sw_if_index,
696 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
699 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
701 route_335_eos.add_vpp_config()
703 tx = self.create_stream_labelled_ip6(
704 self.pg0, [VppMplsLabel(335, ttl=27, exp=4)]
706 rx = self.send_and_expect(self.pg0, tx, self.pg0)
707 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
710 # disposed packets have an TTL expired
712 tx = self.create_stream_labelled_ip6(
713 self.pg0, [VppMplsLabel(334)], dst_ip=self.pg1.remote_ip6, hlim=0
715 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
716 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
719 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
720 # so this traffic should be dropped.
722 route_33_neos = VppMplsRoute(
726 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[])],
728 route_33_neos.add_vpp_config()
730 tx = self.create_stream_labelled_ip4(
731 self.pg0, [VppMplsLabel(33), VppMplsLabel(99)]
733 self.send_and_assert_no_replies(
734 self.pg0, tx, "MPLS non-EOS packets popped and forwarded"
738 # A recursive EOS x-connect, which resolves through another x-connect
741 route_34_eos = VppMplsRoute(
750 labels=[VppMplsLabel(44), VppMplsLabel(45)],
754 route_34_eos.add_vpp_config()
755 self.logger.info(self.vapi.cli("sh mpls fib 34"))
757 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34, ttl=3)])
758 rx = self.send_and_expect(self.pg0, tx, self.pg0)
759 self.verify_capture_labelled(
763 [VppMplsLabel(33), VppMplsLabel(44), VppMplsLabel(45, ttl=2)],
766 self.assertEqual(route_34_eos.get_stats_to()["packets"], 257)
767 self.assertEqual(route_32_neos.get_stats_via()["packets"], 257)
770 # A recursive EOS x-connect, which resolves through another x-connect
773 route_35_eos = VppMplsRoute(
779 "0.0.0.0", 0xFFFFFFFF, nh_via_label=42, labels=[VppMplsLabel(44)]
783 route_35_eos.add_vpp_config()
785 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(35, ttl=3)])
786 rx = self.send_and_expect(self.pg0, tx, self.pg0)
787 self.verify_capture_labelled(
788 self.pg0, rx, tx, [VppMplsLabel(43, ttl=2), VppMplsLabel(44, ttl=2)]
792 # A recursive non-EOS x-connect, which resolves through another
795 route_34_neos = VppMplsRoute(
804 labels=[VppMplsLabel(44), VppMplsLabel(46)],
808 route_34_neos.add_vpp_config()
810 tx = self.create_stream_labelled_ip4(
811 self.pg0, [VppMplsLabel(34, ttl=45), VppMplsLabel(99)]
813 rx = self.send_and_expect(self.pg0, tx, self.pg0)
814 # it's the 2nd (counting from 0) label in the stack that is swapped
815 self.verify_capture_labelled(
822 VppMplsLabel(46, ttl=44),
828 # an recursive IP route that resolves through the recursive non-eos
831 ip_10_0_0_1 = VppIpRoute(
837 "0.0.0.0", 0xFFFFFFFF, nh_via_label=34, labels=[VppMplsLabel(55)]
841 ip_10_0_0_1.add_vpp_config()
843 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
844 rx = self.send_and_expect(self.pg0, tx, self.pg0)
845 self.verify_capture_labelled_ip4(
849 [VppMplsLabel(33), VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(55)],
851 self.assertEqual(ip_10_0_0_1.get_stats_to()["packets"], 257)
853 ip_10_0_0_1.remove_vpp_config()
854 route_34_neos.remove_vpp_config()
855 route_34_eos.remove_vpp_config()
856 route_33_neos.remove_vpp_config()
857 route_33_eos.remove_vpp_config()
858 route_32_neos.remove_vpp_config()
859 route_32_eos.remove_vpp_config()
862 """MPLS Local Label Binding test"""
865 # Add a non-recursive route with a single out label
867 route_10_0_0_1 = VppIpRoute(
873 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(45)]
877 route_10_0_0_1.add_vpp_config()
879 # bind a local label to the route
880 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
881 binding.add_vpp_config()
884 tx = self.create_stream_labelled_ip4(
885 self.pg0, [VppMplsLabel(44), VppMplsLabel(99)]
887 rx = self.send_and_expect(self.pg0, tx, self.pg0)
888 self.verify_capture_labelled(
889 self.pg0, rx, tx, [VppMplsLabel(45, ttl=63), VppMplsLabel(99)]
893 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
894 rx = self.send_and_expect(self.pg0, tx, self.pg0)
895 self.verify_capture_labelled(self.pg0, rx, tx, [VppMplsLabel(45, ttl=63)])
898 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
899 rx = self.send_and_expect(self.pg0, tx, self.pg0)
900 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
905 binding.remove_vpp_config()
906 route_10_0_0_1.remove_vpp_config()
908 def test_imposition(self):
909 """MPLS label imposition test"""
912 # Add a non-recursive route with a single out label
914 route_10_0_0_1 = VppIpRoute(
920 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(32)]
924 route_10_0_0_1.add_vpp_config()
927 # a stream that matches the route for 10.0.0.1
928 # PG0 is in the default table
930 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
931 rx = self.send_and_expect(self.pg0, tx, self.pg0)
932 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
935 # Add a non-recursive route with a 3 out labels
937 route_10_0_0_2 = VppIpRoute(
944 self.pg0.sw_if_index,
945 labels=[VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34)],
949 route_10_0_0_2.add_vpp_config()
951 tx = self.create_stream_ip4(self.pg0, "10.0.0.2", ip_ttl=44, ip_dscp=0xFF)
952 rx = self.send_and_expect(self.pg0, tx, self.pg0)
953 self.verify_capture_labelled_ip4(
957 [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34)],
962 # Add a non-recursive route with a single out label in uniform mode
964 route_10_0_0_3 = VppIpRoute(
971 self.pg0.sw_if_index,
972 labels=[VppMplsLabel(32, mode=MplsLspMode.UNIFORM)],
976 route_10_0_0_3.add_vpp_config()
978 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=54, ip_dscp=0xBE)
979 rx = self.send_and_expect(self.pg0, tx, self.pg0)
980 self.verify_capture_labelled_ip4(
981 self.pg0, rx, tx, [VppMplsLabel(32, ttl=53, exp=5)]
985 # Add a IPv6 non-recursive route with a single out label in
988 route_2001_3 = VppIpRoute(
995 self.pg0.sw_if_index,
996 labels=[VppMplsLabel(32, mode=MplsLspMode.UNIFORM)],
1000 route_2001_3.add_vpp_config()
1002 tx = self.create_stream_ip6(self.pg0, "2001::3", ip_ttl=54, ip_dscp=0xBE)
1003 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1004 self.verify_capture_labelled_ip6(
1005 self.pg0, rx, tx, [VppMplsLabel(32, ttl=53, exp=5)]
1009 # add a recursive path, with output label, via the 1 label route
1011 route_11_0_0_1 = VppIpRoute(
1015 [VppRoutePath("10.0.0.1", 0xFFFFFFFF, labels=[VppMplsLabel(44)])],
1017 route_11_0_0_1.add_vpp_config()
1020 # a stream that matches the route for 11.0.0.1, should pick up
1021 # the label stack for 11.0.0.1 and 10.0.0.1
1023 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
1024 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1025 self.verify_capture_labelled_ip4(
1026 self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(44)]
1029 self.assertEqual(route_11_0_0_1.get_stats_to()["packets"], 257)
1032 # add a recursive path, with 2 labels, via the 3 label route
1034 route_11_0_0_2 = VppIpRoute(
1040 "10.0.0.2", 0xFFFFFFFF, labels=[VppMplsLabel(44), VppMplsLabel(45)]
1044 route_11_0_0_2.add_vpp_config()
1047 # a stream that matches the route for 11.0.0.1, should pick up
1048 # the label stack for 11.0.0.1 and 10.0.0.1
1050 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
1051 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1052 self.verify_capture_labelled_ip4(
1065 self.assertEqual(route_11_0_0_2.get_stats_to()["packets"], 257)
1067 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1068 self.verify_capture_labelled_ip4(
1081 self.assertEqual(route_11_0_0_2.get_stats_to()["packets"], 514)
1086 route_11_0_0_2.remove_vpp_config()
1087 route_11_0_0_1.remove_vpp_config()
1088 route_10_0_0_2.remove_vpp_config()
1089 route_10_0_0_1.remove_vpp_config()
1091 def test_imposition_fragmentation(self):
1092 """MPLS label imposition fragmentation test"""
1095 # Add a ipv4 non-recursive route with a single out label
1097 route_10_0_0_1 = VppIpRoute(
1103 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(32)]
1107 route_10_0_0_1.add_vpp_config()
1108 route_1000_1 = VppIpRoute(
1114 self.pg0.remote_ip6, self.pg0.sw_if_index, labels=[VppMplsLabel(32)]
1118 route_1000_1.add_vpp_config()
1121 # a stream that matches the route for 10.0.0.1
1122 # PG0 is in the default table
1124 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
1125 for i in range(0, 257):
1126 self.extend_packet(tx[i], 10000)
1129 # 5 fragments per packet (257*5=1285)
1131 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
1132 self.verify_capture_fragmented_labelled_ip4(
1133 self.pg0, rx, tx, [VppMplsLabel(32)]
1136 # packets with DF bit set generate ICMP
1139 rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
1142 self.assertEqual(icmptypes[rx[ICMP].type], "dest-unreach")
1144 icmpcodes[rx[ICMP].type][rx[ICMP].code], "fragmentation-needed"
1146 # the link MTU is 9000, the MPLS over head is 4 bytes
1147 self.assertEqual(rx[ICMP].nexthopmtu, 9000 - 4)
1150 self.statistics.get_err_counter("/err/mpls-frag/dont_fragment_set"),
1154 # a stream that matches the route for 1000::1/128
1155 # PG0 is in the default table
1157 tx = self.create_stream_ip6(self.pg0, "1000::1")
1158 for i in range(0, 257):
1159 self.extend_packet(tx[i], 10000)
1161 rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
1163 self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 9000 - 4)
1168 route_10_0_0_1.remove_vpp_config()
1170 def test_tunnel_pipe(self):
1171 """MPLS Tunnel Tests - Pipe"""
1174 # Create a tunnel with two out labels
1176 mpls_tun = VppMPLSTunnelInterface(
1180 self.pg0.remote_ip4,
1181 self.pg0.sw_if_index,
1182 labels=[VppMplsLabel(44), VppMplsLabel(46)],
1186 mpls_tun.add_vpp_config()
1190 # add an unlabelled route through the new tunnel
1192 route_10_0_0_3 = VppIpRoute(
1193 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1195 route_10_0_0_3.add_vpp_config()
1197 self.vapi.cli("clear trace")
1198 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1199 self.pg0.add_stream(tx)
1201 self.pg_enable_capture(self.pg_interfaces)
1204 rx = self.pg0.get_capture()
1205 self.verify_capture_tunneled_ip4(
1206 self.pg0, rx, tx, [VppMplsLabel(44), VppMplsLabel(46)]
1210 # add a labelled route through the new tunnel
1212 route_10_0_0_4 = VppIpRoute(
1216 [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index, labels=[33])],
1218 route_10_0_0_4.add_vpp_config()
1220 self.vapi.cli("clear trace")
1221 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1222 self.pg0.add_stream(tx)
1224 self.pg_enable_capture(self.pg_interfaces)
1227 rx = self.pg0.get_capture()
1228 self.verify_capture_tunneled_ip4(
1232 [VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(33, ttl=255)],
1236 # change tunnel's MTU to a low value
1238 mpls_tun.set_l3_mtu(1200)
1240 # send IP into the tunnel to be fragmented
1241 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", payload_size=1500)
1242 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx) * 2)
1248 self.verify_capture_tunneled_ip4(
1249 self.pg0, rx, fake_tx, [VppMplsLabel(44), VppMplsLabel(46)]
1252 # send MPLS into the tunnel to be fragmented
1253 tx = self.create_stream_ip4(self.pg0, "10.0.0.4", payload_size=1500)
1254 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx) * 2)
1260 self.verify_capture_tunneled_ip4(
1264 [VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(33, ttl=255)],
1267 def test_tunnel_uniform(self):
1268 """MPLS Tunnel Tests - Uniform"""
1271 # Create a tunnel with a single out label
1272 # The label stack is specified here from outer to inner
1274 mpls_tun = VppMPLSTunnelInterface(
1278 self.pg0.remote_ip4,
1279 self.pg0.sw_if_index,
1281 VppMplsLabel(44, ttl=32),
1282 VppMplsLabel(46, MplsLspMode.UNIFORM),
1287 mpls_tun.add_vpp_config()
1291 # add an unlabelled route through the new tunnel
1293 route_10_0_0_3 = VppIpRoute(
1294 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1296 route_10_0_0_3.add_vpp_config()
1298 self.vapi.cli("clear trace")
1299 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1300 self.pg0.add_stream(tx)
1302 self.pg_enable_capture(self.pg_interfaces)
1305 rx = self.pg0.get_capture()
1306 self.verify_capture_tunneled_ip4(
1307 self.pg0, rx, tx, [VppMplsLabel(44, ttl=32), VppMplsLabel(46, ttl=23)]
1311 # add a labelled route through the new tunnel
1313 route_10_0_0_4 = VppIpRoute(
1319 "0.0.0.0", mpls_tun._sw_if_index, labels=[VppMplsLabel(33, ttl=47)]
1323 route_10_0_0_4.add_vpp_config()
1325 self.vapi.cli("clear trace")
1326 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1327 self.pg0.add_stream(tx)
1329 self.pg_enable_capture(self.pg_interfaces)
1332 rx = self.pg0.get_capture()
1333 self.verify_capture_tunneled_ip4(
1338 VppMplsLabel(44, ttl=32),
1339 VppMplsLabel(46, ttl=47),
1340 VppMplsLabel(33, ttl=47),
1344 def test_mpls_tunnel_many(self):
1345 """MPLS Multiple Tunnels"""
1347 for ii in range(100):
1348 mpls_tun = VppMPLSTunnelInterface(
1352 self.pg0.remote_ip4,
1353 self.pg0.sw_if_index,
1355 VppMplsLabel(44, ttl=32),
1356 VppMplsLabel(46, MplsLspMode.UNIFORM),
1361 mpls_tun.add_vpp_config()
1363 for ii in range(100):
1364 mpls_tun = VppMPLSTunnelInterface(
1368 self.pg0.remote_ip4,
1369 self.pg0.sw_if_index,
1371 VppMplsLabel(44, ttl=32),
1372 VppMplsLabel(46, MplsLspMode.UNIFORM),
1378 mpls_tun.add_vpp_config()
1381 def test_v4_exp_null(self):
1382 """MPLS V4 Explicit NULL test"""
1385 # The first test case has an MPLS TTL of 0
1386 # all packet should be dropped
1388 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0, ttl=0)])
1389 self.send_and_assert_no_replies(self.pg0, tx, "MPLS TTL=0 packets forwarded")
1392 # a stream with a non-zero MPLS TTL
1393 # PG0 is in the default table
1395 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1396 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1397 self.verify_capture_ip4(self.pg0, rx, tx)
1400 # a stream with a non-zero MPLS TTL
1402 # we are ensuring the post-pop lookup occurs in the VRF table
1404 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1405 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1406 self.verify_capture_ip4(self.pg1, rx, tx)
1408 def test_v6_exp_null(self):
1409 """MPLS V6 Explicit NULL test"""
1412 # a stream with a non-zero MPLS TTL
1413 # PG0 is in the default table
1415 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1416 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1417 self.verify_capture_ip6(self.pg0, rx, tx)
1420 # a stream with a non-zero MPLS TTL
1422 # we are ensuring the post-pop lookup occurs in the VRF table
1424 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1425 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1426 self.verify_capture_ip6(self.pg0, rx, tx)
1428 def test_deag(self):
1432 # A de-agg route - next-hop lookup in default table
1434 route_34_eos = VppMplsRoute(
1435 self, 34, 1, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)]
1437 route_34_eos.add_vpp_config()
1440 # ping an interface in the default table
1441 # PG0 is in the default table
1443 tx = self.create_stream_labelled_ip4(
1444 self.pg0, [VppMplsLabel(34)], ping=1, ip_itf=self.pg0
1446 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1447 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1450 # A de-agg route - next-hop lookup in non-default table
1452 route_35_eos = VppMplsRoute(
1453 self, 35, 1, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)]
1455 route_35_eos.add_vpp_config()
1456 route_356_eos = VppMplsRoute(
1460 [VppRoutePath("0::0", 0xFFFFFFFF, nh_table_id=1)],
1461 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1463 route_356_eos.add_vpp_config()
1466 # ping an interface in the non-default table
1467 # PG0 is in the default table. packet arrive labelled in the
1468 # default table and egress unlabelled in the non-default
1470 tx = self.create_stream_labelled_ip4(
1471 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1
1473 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1474 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1475 tx = self.create_stream_labelled_ip6(
1476 self.pg0, [VppMplsLabel(356)], ping=1, ip_itf=self.pg1
1478 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1479 self.verify_capture_ip6(self.pg1, rx, tx, ping_resp=1)
1484 route_36_neos = VppMplsRoute(self, 36, 0, [VppRoutePath("0.0.0.0", 0xFFFFFFFF)])
1485 route_36_neos.add_vpp_config()
1487 tx = self.create_stream_labelled_ip4(
1488 self.pg0, [VppMplsLabel(36), VppMplsLabel(35)], ping=1, ip_itf=self.pg1
1490 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1491 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1493 route_36_neos.remove_vpp_config()
1494 route_35_eos.remove_vpp_config()
1495 route_34_eos.remove_vpp_config()
1497 def test_interface_rx(self):
1498 """MPLS Interface Receive"""
1501 # Add a non-recursive route that will forward the traffic
1504 route_10_0_0_1 = VppIpRoute(
1509 paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
1511 route_10_0_0_1.add_vpp_config()
1514 # An interface receive label that maps traffic to RX on interface
1516 # by injecting the packet in on pg0, which is in table 0
1517 # doing an interface-rx on pg1 and matching a route in table 1
1518 # if the packet egresses, then we must have swapped to pg1
1519 # so as to have matched the route in table 1
1521 route_34_eos = VppMplsRoute(
1528 self.pg1.sw_if_index,
1529 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
1533 route_34_eos.add_vpp_config()
1536 # ping an interface in the default table
1537 # PG0 is in the default table
1539 tx = self.create_stream_labelled_ip4(
1540 self.pg0, [VppMplsLabel(34)], dst_ip="10.0.0.1"
1542 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1543 self.verify_capture_ip4(self.pg1, rx, tx)
1545 def test_mcast_mid_point(self):
1546 """MPLS Multicast Mid Point"""
1549 # Add a non-recursive route that will forward the traffic
1552 route_10_0_0_1 = VppIpRoute(
1557 paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
1559 route_10_0_0_1.add_vpp_config()
1562 # Add a mcast entry that replicate to pg2 and pg3
1563 # and replicate to a interface-rx (like a bud node would)
1565 route_3400_eos = VppMplsRoute(
1571 self.pg2.remote_ip4,
1572 self.pg2.sw_if_index,
1573 labels=[VppMplsLabel(3401)],
1576 self.pg3.remote_ip4,
1577 self.pg3.sw_if_index,
1578 labels=[VppMplsLabel(3402)],
1582 self.pg1.sw_if_index,
1583 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
1588 route_3400_eos.add_vpp_config()
1591 # ping an interface in the default table
1592 # PG0 is in the default table
1594 self.vapi.cli("clear trace")
1595 tx = self.create_stream_labelled_ip4(
1596 self.pg0, [VppMplsLabel(3400, ttl=64)], n=257, dst_ip="10.0.0.1"
1598 self.pg0.add_stream(tx)
1600 self.pg_enable_capture(self.pg_interfaces)
1603 rx = self.pg1.get_capture(257)
1604 self.verify_capture_ip4(self.pg1, rx, tx)
1606 rx = self.pg2.get_capture(257)
1607 self.verify_capture_labelled(self.pg2, rx, tx, [VppMplsLabel(3401, ttl=63)])
1608 rx = self.pg3.get_capture(257)
1609 self.verify_capture_labelled(self.pg3, rx, tx, [VppMplsLabel(3402, ttl=63)])
1611 def test_mcast_head(self):
1612 """MPLS Multicast Head-end"""
1614 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1615 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1618 # Create a multicast tunnel with two replications
1620 mpls_tun = VppMPLSTunnelInterface(
1624 self.pg2.remote_ip4, self.pg2.sw_if_index, labels=[VppMplsLabel(42)]
1627 self.pg3.remote_ip4, self.pg3.sw_if_index, labels=[VppMplsLabel(43)]
1632 mpls_tun.add_vpp_config()
1636 # add an unlabelled route through the new tunnel
1638 route_10_0_0_3 = VppIpRoute(
1639 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1641 route_10_0_0_3.add_vpp_config()
1643 self.vapi.cli("clear trace")
1644 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1645 self.pg0.add_stream(tx)
1647 self.pg_enable_capture(self.pg_interfaces)
1650 rx = self.pg2.get_capture(257)
1651 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1652 rx = self.pg3.get_capture(257)
1653 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1656 # An an IP multicast route via the tunnel
1658 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1660 route_232_1_1_1 = VppIpMRoute(
1665 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1668 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1671 mpls_tun._sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1675 route_232_1_1_1.add_vpp_config()
1676 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1678 self.vapi.cli("clear trace")
1679 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1680 self.pg0.add_stream(tx)
1682 self.pg_enable_capture(self.pg_interfaces)
1685 rx = self.pg2.get_capture(257)
1686 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1687 rx = self.pg3.get_capture(257)
1688 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1690 def test_mcast_ip4_tail(self):
1691 """MPLS IPv4 Multicast Tail"""
1693 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1694 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1697 # Add a multicast route that will forward the traffic
1700 route_232_1_1_1 = VppIpMRoute(
1705 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1709 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1713 route_232_1_1_1.add_vpp_config()
1716 # An interface receive label that maps traffic to RX on interface
1718 # by injecting the packet in on pg0, which is in table 0
1719 # doing an rpf-id and matching a route in table 1
1720 # if the packet egresses, then we must have matched the route in
1723 route_34_eos = VppMplsRoute(
1727 [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1, rpf_id=55)],
1729 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
1732 route_34_eos.add_vpp_config()
1735 # Drop due to interface lookup miss
1737 self.vapi.cli("clear trace")
1738 tx = self.create_stream_labelled_ip4(
1739 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1", n=1
1741 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1744 # set the RPF-ID of the entry to match the input packet's
1746 route_232_1_1_1.update_rpf_id(55)
1747 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1749 tx = self.create_stream_labelled_ip4(
1750 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1"
1752 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1753 self.verify_capture_ip4(self.pg1, rx, tx)
1756 # disposed packets have an invalid IPv4 checksum
1758 tx = self.create_stream_labelled_ip4(
1759 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1", n=65, chksum=1
1761 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1764 # set the RPF-ID of the entry to not match the input packet's
1766 route_232_1_1_1.update_rpf_id(56)
1767 tx = self.create_stream_labelled_ip4(
1768 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1"
1770 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1772 def test_mcast_ip6_tail(self):
1773 """MPLS IPv6 Multicast Tail"""
1775 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1776 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1779 # Add a multicast route that will forward the traffic
1782 route_ff = VppIpMRoute(
1787 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1791 self.pg1.sw_if_index,
1792 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1793 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1797 route_ff.add_vpp_config()
1800 # An interface receive label that maps traffic to RX on interface
1802 # by injecting the packet in on pg0, which is in table 0
1803 # doing an rpf-id and matching a route in table 1
1804 # if the packet egresses, then we must have matched the route in
1807 route_34_eos = VppMplsRoute(
1811 [VppRoutePath("::", 0xFFFFFFFF, nh_table_id=1, rpf_id=55)],
1813 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1816 route_34_eos.add_vpp_config()
1819 # Drop due to interface lookup miss
1821 tx = self.create_stream_labelled_ip6(
1822 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1824 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1827 # set the RPF-ID of the entry to match the input packet's
1829 route_ff.update_rpf_id(55)
1831 tx = self.create_stream_labelled_ip6(
1832 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1834 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1835 self.verify_capture_ip6(self.pg1, rx, tx)
1838 # disposed packets have hop-limit = 1
1840 tx = self.create_stream_labelled_ip6(
1841 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1", hlim=1
1843 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
1844 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1847 # set the RPF-ID of the entry to not match the input packet's
1849 route_ff.update_rpf_id(56)
1850 tx = self.create_stream_labelled_ip6(
1851 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1853 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1859 # Add a non-recursive route with a single out label
1861 route_10_0_0_1 = VppIpRoute(
1867 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(45)]
1871 route_10_0_0_1.add_vpp_config()
1873 # bind a local label to the route
1874 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1875 binding.add_vpp_config()
1878 # a labelled v6 route that resolves through the v4
1880 route_2001_3 = VppIpRoute(
1884 [VppRoutePath("10.0.0.1", INVALID_INDEX, labels=[VppMplsLabel(32)])],
1886 route_2001_3.add_vpp_config()
1888 tx = self.create_stream_ip6(self.pg0, "2001::3")
1889 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1891 self.verify_capture_labelled_ip6(
1892 self.pg0, rx, tx, [VppMplsLabel(45), VppMplsLabel(32)]
1896 # and a v4 recursive via the v6
1898 route_20_3 = VppIpRoute(
1902 [VppRoutePath("2001::3", INVALID_INDEX, labels=[VppMplsLabel(99)])],
1904 route_20_3.add_vpp_config()
1906 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1907 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1909 self.verify_capture_labelled_ip4(
1910 self.pg0, rx, tx, [VppMplsLabel(45), VppMplsLabel(32), VppMplsLabel(99)]
1913 def test_attached(self):
1914 """Attach Routes with Local Label"""
1917 # test that if a local label is associated with an attached/connected
1918 # prefix, that we can reach hosts in the prefix.
1920 binding = VppMplsIpBind(
1921 self, 44, self.pg0._local_ip4_subnet, self.pg0.local_ip4_prefix_len
1923 binding.add_vpp_config()
1926 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1927 / MPLS(label=44, ttl=64)
1928 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
1929 / UDP(sport=1234, dport=1234)
1930 / Raw(b"\xa5" * 100)
1932 rxs = self.send_and_expect(self.pg0, [tx], self.pg0)
1934 # if there's an ARP then the label is linked to the glean
1936 self.assertFalse(rx.haslayer(ARP))
1937 # it should be unicasted to the host
1938 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1939 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1942 class TestMPLSDisabled(VppTestCase):
1946 def setUpClass(cls):
1947 super(TestMPLSDisabled, cls).setUpClass()
1950 def tearDownClass(cls):
1951 super(TestMPLSDisabled, cls).tearDownClass()
1954 super(TestMPLSDisabled, self).setUp()
1956 # create 2 pg interfaces
1957 self.create_pg_interfaces(range(2))
1959 self.tbl = VppMplsTable(self, 0)
1960 self.tbl.add_vpp_config()
1962 # PG0 is MPLS enabled
1964 self.pg0.config_ip4()
1965 self.pg0.resolve_arp()
1966 self.pg0.enable_mpls()
1968 # PG 1 is not MPLS enabled
1972 for i in self.pg_interfaces:
1976 self.pg0.disable_mpls()
1977 super(TestMPLSDisabled, self).tearDown()
1979 def test_mpls_disabled(self):
1982 self.logger.info(self.vapi.cli("show mpls interface"))
1983 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1984 self.logger.info(self.vapi.cli("show mpls interface pg0"))
1987 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1988 / MPLS(label=32, ttl=64)
1989 / IPv6(src="2001::1", dst=self.pg0.remote_ip6)
1990 / UDP(sport=1234, dport=1234)
1991 / Raw(b"\xa5" * 100)
1995 # A simple MPLS xconnect - eos label in label out
1997 route_32_eos = VppMplsRoute(
2001 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[33])],
2003 route_32_eos.add_vpp_config()
2006 # PG1 does not forward IP traffic
2008 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
2013 self.pg1.enable_mpls()
2015 self.logger.info(self.vapi.cli("show mpls interface"))
2016 self.logger.info(self.vapi.cli("show mpls interface pg1"))
2019 # Now we get packets through
2021 self.pg1.add_stream(tx)
2022 self.pg_enable_capture(self.pg_interfaces)
2025 rx = self.pg0.get_capture(1)
2030 self.pg1.disable_mpls()
2033 # PG1 does not forward IP traffic
2035 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
2036 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
2039 class TestMPLSPIC(VppTestCase):
2040 """MPLS Prefix-Independent Convergence (PIC) edge convergence"""
2043 def setUpClass(cls):
2044 super(TestMPLSPIC, cls).setUpClass()
2047 def tearDownClass(cls):
2048 super(TestMPLSPIC, cls).tearDownClass()
2051 super(TestMPLSPIC, self).setUp()
2053 # create 2 pg interfaces
2054 self.create_pg_interfaces(range(4))
2056 mpls_tbl = VppMplsTable(self, 0)
2057 mpls_tbl.add_vpp_config()
2058 tbl4 = VppIpTable(self, 1)
2059 tbl4.add_vpp_config()
2060 tbl6 = VppIpTable(self, 1, is_ip6=1)
2061 tbl6.add_vpp_config()
2065 self.pg0.config_ip4()
2066 self.pg0.resolve_arp()
2067 self.pg0.enable_mpls()
2070 self.pg1.config_ip4()
2071 self.pg1.resolve_arp()
2072 self.pg1.enable_mpls()
2074 # VRF (customer facing) link
2076 self.pg2.set_table_ip4(1)
2077 self.pg2.config_ip4()
2078 self.pg2.resolve_arp()
2079 self.pg2.set_table_ip6(1)
2080 self.pg2.config_ip6()
2081 self.pg2.resolve_ndp()
2084 self.pg3.set_table_ip4(1)
2085 self.pg3.config_ip4()
2086 self.pg3.resolve_arp()
2087 self.pg3.set_table_ip6(1)
2088 self.pg3.config_ip6()
2089 self.pg3.resolve_ndp()
2092 self.pg0.disable_mpls()
2093 self.pg1.disable_mpls()
2094 for i in self.pg_interfaces:
2100 super(TestMPLSPIC, self).tearDown()
2102 def test_mpls_ibgp_pic(self):
2103 """MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
2105 1) setup many iBGP VPN routes via a pair of iBGP peers.
2106 2) Check EMCP forwarding to these peers
2107 3) withdraw the IGP route to one of these peers.
2108 4) check forwarding continues to the remaining peer
2112 # IGP+LDP core routes
2114 core_10_0_0_45 = VppIpRoute(
2118 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[45])],
2120 core_10_0_0_45.add_vpp_config()
2122 core_10_0_0_46 = VppIpRoute(
2126 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[46])],
2128 core_10_0_0_46.add_vpp_config()
2131 # Lot's of VPN routes. We need more the 64 so VPP will build
2132 # the fast convergence indirection
2136 for ii in range(NUM_PKTS):
2137 dst = "192.168.1.%d" % ii
2148 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST,
2154 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST,
2160 vpn_routes[ii].add_vpp_config()
2163 Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac)
2164 / IP(src=self.pg2.remote_ip4, dst=dst)
2165 / UDP(sport=1234, dport=1234)
2166 / Raw(b"\xa5" * 100)
2170 # Send the packet stream (one pkt to each VPN route)
2171 # - expect a 50-50 split of the traffic
2173 self.pg2.add_stream(pkts)
2174 self.pg_enable_capture(self.pg_interfaces)
2177 rx0 = self.pg0._get_capture(NUM_PKTS)
2178 rx1 = self.pg1._get_capture(NUM_PKTS)
2180 # not testing the LB hashing algorithm so we're not concerned
2181 # with the split ratio, just as long as neither is 0
2182 self.assertNotEqual(0, len(rx0))
2183 self.assertNotEqual(0, len(rx1))
2186 len(rx0) + len(rx1),
2187 "Expected all (%s) packets across both ECMP paths. "
2188 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2192 # use a test CLI command to stop the FIB walk process, this
2193 # will prevent the FIB converging the VPN routes and thus allow
2194 # us to probe the interim (post-fail, pre-converge) state
2196 self.vapi.ppcli("test fib-walk-process disable")
2199 # Withdraw one of the IGP routes
2201 core_10_0_0_46.remove_vpp_config()
2204 # now all packets should be forwarded through the remaining peer
2206 self.vapi.ppcli("clear trace")
2207 self.pg2.add_stream(pkts)
2208 self.pg_enable_capture(self.pg_interfaces)
2211 rx0 = self.pg0.get_capture(NUM_PKTS)
2215 "Expected all (%s) packets across single path. "
2216 "rx0: %s." % (len(pkts), len(rx0)),
2220 # enable the FIB walk process to converge the FIB
2222 self.vapi.ppcli("test fib-walk-process enable")
2225 # packets should still be forwarded through the remaining peer
2227 self.pg2.add_stream(pkts)
2228 self.pg_enable_capture(self.pg_interfaces)
2231 rx0 = self.pg0.get_capture(NUM_PKTS)
2235 "Expected all (%s) packets across single path. "
2236 "rx0: %s." % (len(pkts), len(rx0)),
2240 # Add the IGP route back and we return to load-balancing
2242 core_10_0_0_46.add_vpp_config()
2244 self.pg2.add_stream(pkts)
2245 self.pg_enable_capture(self.pg_interfaces)
2248 rx0 = self.pg0._get_capture(NUM_PKTS)
2249 rx1 = self.pg1._get_capture(NUM_PKTS)
2250 self.assertNotEqual(0, len(rx0))
2251 self.assertNotEqual(0, len(rx1))
2254 len(rx0) + len(rx1),
2255 "Expected all (%s) packets across both ECMP paths. "
2256 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2259 def test_mpls_ebgp_pic(self):
2260 """MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
2262 1) setup many eBGP VPN routes via a pair of eBGP peers.
2263 2) Check EMCP forwarding to these peers
2264 3) withdraw one eBGP path - expect LB across remaining eBGP
2268 # Lot's of VPN routes. We need more the 64 so VPP will build
2269 # the fast convergence indirection
2274 for ii in range(NUM_PKTS):
2275 dst = "192.168.1.%d" % ii
2276 local_label = 1600 + ii
2284 self.pg2.remote_ip4,
2287 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2290 self.pg3.remote_ip4,
2293 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2299 vpn_routes[ii].add_vpp_config()
2301 vpn_bindings.append(
2302 VppMplsIpBind(self, local_label, dst, 32, ip_table_id=1)
2304 vpn_bindings[ii].add_vpp_config()
2307 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2308 / MPLS(label=local_label, ttl=64)
2309 / IP(src=self.pg0.remote_ip4, dst=dst)
2310 / UDP(sport=1234, dport=1234)
2311 / Raw(b"\xa5" * 100)
2315 # Send the packet stream (one pkt to each VPN route)
2316 # - expect a 50-50 split of the traffic
2318 self.pg0.add_stream(pkts)
2319 self.pg_enable_capture(self.pg_interfaces)
2322 rx0 = self.pg2._get_capture(NUM_PKTS)
2323 rx1 = self.pg3._get_capture(NUM_PKTS)
2325 # not testing the LB hashing algorithm so we're not concerned
2326 # with the split ratio, just as long as neither is 0
2327 self.assertNotEqual(0, len(rx0))
2328 self.assertNotEqual(0, len(rx1))
2331 len(rx0) + len(rx1),
2332 "Expected all (%s) packets across both ECMP paths. "
2333 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2337 # use a test CLI command to stop the FIB walk process, this
2338 # will prevent the FIB converging the VPN routes and thus allow
2339 # us to probe the interim (post-fail, pre-converge) state
2341 self.vapi.ppcli("test fib-walk-process disable")
2344 # withdraw the connected prefix on the interface.
2346 self.pg2.unconfig_ip4()
2349 # now all packets should be forwarded through the remaining peer
2351 self.pg0.add_stream(pkts)
2352 self.pg_enable_capture(self.pg_interfaces)
2355 rx0 = self.pg3.get_capture(NUM_PKTS)
2359 "Expected all (%s) packets across single path. "
2360 "rx0: %s." % (len(pkts), len(rx0)),
2364 # enable the FIB walk process to converge the FIB
2366 self.vapi.ppcli("test fib-walk-process enable")
2369 # packets should still be forwarded through the remaining peer
2371 self.pg0.add_stream(pkts)
2372 self.pg_enable_capture(self.pg_interfaces)
2375 rx0 = self.pg3.get_capture(NUM_PKTS)
2379 "Expected all (%s) packets across single path. "
2380 "rx0: %s." % (len(pkts), len(rx0)),
2384 # put the connected routes back
2386 self.pg2.config_ip4()
2387 self.pg2.resolve_arp()
2389 self.pg0.add_stream(pkts)
2390 self.pg_enable_capture(self.pg_interfaces)
2393 rx0 = self.pg2._get_capture(NUM_PKTS)
2394 rx1 = self.pg3._get_capture(NUM_PKTS)
2395 self.assertNotEqual(0, len(rx0))
2396 self.assertNotEqual(0, len(rx1))
2399 len(rx0) + len(rx1),
2400 "Expected all (%s) packets across both ECMP paths. "
2401 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2404 def test_mpls_v6_ebgp_pic(self):
2405 """MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
2407 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
2408 2) Check EMCP forwarding to these peers
2409 3) withdraw one eBGP path - expect LB across remaining eBGP
2413 # Lot's of VPN routes. We need more the 64 so VPP will build
2414 # the fast convergence indirection
2419 for ii in range(NUM_PKTS):
2420 dst = "3000::%d" % ii
2421 local_label = 1600 + ii
2429 self.pg2.remote_ip6,
2432 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2435 self.pg3.remote_ip6,
2438 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2444 vpn_routes[ii].add_vpp_config()
2446 vpn_bindings.append(
2447 VppMplsIpBind(self, local_label, dst, 128, ip_table_id=1)
2449 vpn_bindings[ii].add_vpp_config()
2452 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2453 / MPLS(label=local_label, ttl=64)
2454 / IPv6(src=self.pg0.remote_ip6, dst=dst)
2455 / UDP(sport=1234, dport=1234)
2456 / Raw(b"\xa5" * 100)
2458 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2460 self.pg0.add_stream(pkts)
2461 self.pg_enable_capture(self.pg_interfaces)
2464 rx0 = self.pg2._get_capture(NUM_PKTS)
2465 rx1 = self.pg3._get_capture(NUM_PKTS)
2466 self.assertNotEqual(0, len(rx0))
2467 self.assertNotEqual(0, len(rx1))
2470 len(rx0) + len(rx1),
2471 "Expected all (%s) packets across both ECMP paths. "
2472 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2476 # use a test CLI command to stop the FIB walk process, this
2477 # will prevent the FIB converging the VPN routes and thus allow
2478 # us to probe the interim (post-fail, pre-converge) state
2480 self.vapi.ppcli("test fib-walk-process disable")
2483 # withdraw the connected prefix on the interface.
2484 # and shutdown the interface so the ND cache is flushed.
2486 self.pg2.unconfig_ip6()
2487 self.pg2.admin_down()
2490 # now all packets should be forwarded through the remaining peer
2492 self.pg0.add_stream(pkts)
2493 self.pg_enable_capture(self.pg_interfaces)
2496 rx0 = self.pg3.get_capture(NUM_PKTS)
2500 "Expected all (%s) packets across single path. "
2501 "rx0: %s." % (len(pkts), len(rx0)),
2505 # enable the FIB walk process to converge the FIB
2507 self.vapi.ppcli("test fib-walk-process enable")
2508 self.pg0.add_stream(pkts)
2509 self.pg_enable_capture(self.pg_interfaces)
2512 rx0 = self.pg3.get_capture(NUM_PKTS)
2516 "Expected all (%s) packets across single path. "
2517 "rx0: %s." % (len(pkts), len(rx0)),
2521 # put the connected routes back
2523 self.logger.info(self.vapi.cli("sh log"))
2525 self.pg2.config_ip6()
2526 self.pg2.resolve_ndp()
2528 self.pg0.add_stream(pkts)
2529 self.pg_enable_capture(self.pg_interfaces)
2532 rx0 = self.pg2._get_capture(NUM_PKTS)
2533 rx1 = self.pg3._get_capture(NUM_PKTS)
2534 self.assertNotEqual(0, len(rx0))
2535 self.assertNotEqual(0, len(rx1))
2538 len(rx0) + len(rx1),
2539 "Expected all (%s) packets across both ECMP paths. "
2540 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2544 class TestMPLSL2(VppTestCase):
2548 def setUpClass(cls):
2549 super(TestMPLSL2, cls).setUpClass()
2552 def tearDownClass(cls):
2553 super(TestMPLSL2, cls).tearDownClass()
2556 super(TestMPLSL2, self).setUp()
2558 # create 2 pg interfaces
2559 self.create_pg_interfaces(range(2))
2561 # create the default MPLS table
2563 tbl = VppMplsTable(self, 0)
2564 tbl.add_vpp_config()
2565 self.tables.append(tbl)
2567 # use pg0 as the core facing interface, don't resolve ARP
2569 self.pg0.config_ip4()
2570 self.pg0.enable_mpls()
2572 # use the other 2 for customer facing L2 links
2573 for i in self.pg_interfaces[1:]:
2577 for i in self.pg_interfaces[1:]:
2580 self.pg0.disable_mpls()
2581 self.pg0.unconfig_ip4()
2582 self.pg0.admin_down()
2583 super(TestMPLSL2, self).tearDown()
2585 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2586 capture = verify_filter(capture, sent)
2588 self.assertEqual(len(capture), len(sent))
2590 for i in range(len(capture)):
2594 # the MPLS TTL is 255 since it enters a new tunnel
2595 verify_mpls_stack(self, rx, mpls_labels)
2598 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2600 self.assertEqual(rx_eth.src, tx_eth.src)
2601 self.assertEqual(rx_eth.dst, tx_eth.dst)
2603 def verify_arp_req(self, rx, smac, sip, dip):
2605 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2606 self.assertEqual(ether.src, smac)
2609 self.assertEqual(arp.hwtype, 1)
2610 self.assertEqual(arp.ptype, 0x800)
2611 self.assertEqual(arp.hwlen, 6)
2612 self.assertEqual(arp.plen, 4)
2613 self.assertEqual(arp.op, ARP.who_has)
2614 self.assertEqual(arp.hwsrc, smac)
2615 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2616 self.assertEqual(arp.psrc, sip)
2617 self.assertEqual(arp.pdst, dip)
2619 def test_vpws(self):
2620 """Virtual Private Wire Service"""
2623 # Create an MPLS tunnel that pushes 1 label
2624 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2625 # information is not in the packet, but we test it works anyway
2627 mpls_tun_1 = VppMPLSTunnelInterface(
2631 self.pg0.remote_ip4,
2632 self.pg0.sw_if_index,
2633 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)],
2638 mpls_tun_1.add_vpp_config()
2639 mpls_tun_1.admin_up()
2642 # Create a label entry to for 55 that does L2 input to the tunnel
2644 route_55_eos = VppMplsRoute(
2651 mpls_tun_1.sw_if_index,
2652 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2653 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2656 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2658 route_55_eos.add_vpp_config()
2661 # Cross-connect the tunnel with one of the customers L2 interfaces
2663 self.vapi.sw_interface_set_l2_xconnect(
2664 self.pg1.sw_if_index, mpls_tun_1.sw_if_index, enable=1
2666 self.vapi.sw_interface_set_l2_xconnect(
2667 mpls_tun_1.sw_if_index, self.pg1.sw_if_index, enable=1
2671 # inject a packet from the core
2674 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2675 / MPLS(label=55, ttl=64)
2676 / Ether(dst="00:00:de:ad:ba:be", src="00:00:de:ad:be:ef")
2677 / IP(src="10.10.10.10", dst="11.11.11.11")
2678 / UDP(sport=1234, dport=1234)
2679 / Raw(b"\xa5" * 100)
2682 tx0 = pcore * NUM_PKTS
2683 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2684 payload = pcore[MPLS].payload
2686 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2687 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2690 # Inject a packet from the customer/L2 side
2691 # there's no resolved ARP entry so the first packet we see should be
2694 tx1 = pcore[MPLS].payload
2695 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2697 self.verify_arp_req(
2698 rx1[0], self.pg0.local_mac, self.pg0.local_ip4, self.pg0.remote_ip4
2702 # resolve the ARP entries and send again
2704 self.pg0.resolve_arp()
2705 tx1 = pcore[MPLS].payload * NUM_PKTS
2706 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2708 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2710 def test_vpls(self):
2711 """Virtual Private LAN Service"""
2713 # we skipped this in the setup
2714 self.pg0.resolve_arp()
2717 # Create a L2 MPLS tunnels
2719 mpls_tun1 = VppMPLSTunnelInterface(
2723 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(42)]
2728 mpls_tun1.add_vpp_config()
2729 mpls_tun1.admin_up()
2731 mpls_tun2 = VppMPLSTunnelInterface(
2735 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(43)]
2740 mpls_tun2.add_vpp_config()
2741 mpls_tun2.admin_up()
2744 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2745 # the latter includes a Psuedo Wire Control Word
2747 route_55_eos = VppMplsRoute(
2754 mpls_tun1.sw_if_index,
2755 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2756 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2759 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2762 route_56_eos = VppMplsRoute(
2769 mpls_tun2.sw_if_index,
2770 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2771 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2772 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2775 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2779 route_56_eos.add_vpp_config()
2780 route_55_eos.add_vpp_config()
2782 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2785 # add to tunnel to the customers bridge-domain
2787 self.vapi.sw_interface_set_l2_bridge(
2788 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1
2790 self.vapi.sw_interface_set_l2_bridge(
2791 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1
2793 self.vapi.sw_interface_set_l2_bridge(
2794 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1
2798 # Packet from host on the customer interface to each host
2799 # reachable over the core, and vice-versa
2802 Ether(dst="00:00:de:ad:ba:b1", src="00:00:de:ad:be:ef")
2803 / IP(src="10.10.10.10", dst="11.11.11.11")
2804 / UDP(sport=1234, dport=1234)
2805 / Raw(b"\xa5" * 100)
2808 Ether(dst="00:00:de:ad:ba:b2", src="00:00:de:ad:be:ef")
2809 / IP(src="10.10.10.10", dst="11.11.11.12")
2810 / UDP(sport=1234, dport=1234)
2811 / Raw(b"\xa5" * 100)
2814 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2815 / MPLS(label=55, ttl=64)
2816 / Ether(src="00:00:de:ad:ba:b1", dst="00:00:de:ad:be:ef")
2817 / IP(dst="10.10.10.10", src="11.11.11.11")
2818 / UDP(sport=1234, dport=1234)
2819 / Raw(b"\xa5" * 100)
2822 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2823 / MPLS(label=56, ttl=64)
2825 / Ether(src="00:00:de:ad:ba:b2", dst="00:00:de:ad:be:ef") # PW CW
2826 / IP(dst="10.10.10.10", src="11.11.11.12")
2827 / UDP(sport=1234, dport=1234)
2828 / Raw(b"\xa5" * 100)
2832 # The BD is learning, so send in one of each packet to learn
2835 # 2 packets due to BD flooding
2836 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2837 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2839 # we've learnt this so expect it be be forwarded not flooded
2840 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2841 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2842 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2844 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2845 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2846 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2849 # now a stream in each direction from each host
2851 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2852 self.verify_capture_tunneled_ethernet(
2853 rx, p_cust1 * NUM_PKTS, [VppMplsLabel(42)]
2856 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2857 self.verify_capture_tunneled_ethernet(
2858 rx, p_cust2 * NUM_PKTS, [VppMplsLabel(43)]
2861 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2862 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2865 # remove interfaces from customers bridge-domain
2867 self.vapi.sw_interface_set_l2_bridge(
2868 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0
2870 self.vapi.sw_interface_set_l2_bridge(
2871 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0
2873 self.vapi.sw_interface_set_l2_bridge(
2874 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0
2878 if __name__ == "__main__":
2879 unittest.main(testRunner=VppTestRunner)