6 from framework import tag_fixme_vpp_workers
7 from framework import VppTestCase, VppTestRunner
8 from vpp_ip import DpoProto, INVALID_INDEX
9 from vpp_ip_route import (
27 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
28 from vpp_papi import VppEnum
31 from scapy.packet import Raw
32 from scapy.layers.l2 import Ether, ARP
33 from scapy.layers.inet import IP, UDP, ICMP, icmptypes, icmpcodes
34 from scapy.layers.inet6 import (
40 from scapy.contrib.mpls import MPLS
44 # scapy removed these attributes.
45 # we asked that they be restored: https://github.com/secdev/scapy/pull/1878
46 # semantic names have more meaning than numbers. so here they are.
51 def verify_filter(capture, sent):
52 if not len(capture) == len(sent):
53 # filter out any IPv6 RAs from the capture
60 def verify_mpls_stack(tst, rx, mpls_labels):
61 # the rx'd packet has the MPLS label popped
63 tst.assertEqual(eth.type, 0x8847)
67 for ii in range(len(mpls_labels)):
68 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
69 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
70 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
72 if ii == len(mpls_labels) - 1:
73 tst.assertEqual(rx_mpls.s, 1)
76 tst.assertEqual(rx_mpls.s, 0)
77 # pop the label to expose the next
78 rx_mpls = rx_mpls[MPLS].payload
81 @tag_fixme_vpp_workers
82 class TestMPLS(VppTestCase):
87 super(TestMPLS, cls).setUpClass()
90 def tearDownClass(cls):
91 super(TestMPLS, cls).tearDownClass()
94 super(TestMPLS, self).setUp()
96 # create 2 pg interfaces
97 self.create_pg_interfaces(range(4))
99 # setup both interfaces
100 # assign them different tables.
104 tbl = VppMplsTable(self, 0)
106 self.tables.append(tbl)
108 for i in self.pg_interfaces:
112 tbl = VppIpTable(self, table_id)
114 self.tables.append(tbl)
115 tbl = VppIpTable(self, table_id, is_ip6=1)
117 self.tables.append(tbl)
119 i.set_table_ip4(table_id)
120 i.set_table_ip6(table_id)
129 for i in self.pg_interfaces:
136 super(TestMPLS, self).tearDown()
138 # the default of 64 matches the IP packet TTL default
139 def create_stream_labelled_ip4(
150 self.reset_packet_infos()
152 for i in range(0, n):
153 info = self.create_packet_info(src_if, src_if)
154 payload = self.info_to_payload(info)
155 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
157 for ii in range(len(mpls_labels)):
159 label=mpls_labels[ii].value,
160 ttl=mpls_labels[ii].ttl,
161 cos=mpls_labels[ii].exp,
167 / IP(src=src_if.local_ip4, dst=src_if.remote_ip4, ttl=ip_ttl)
168 / UDP(sport=1234, dport=1234)
174 / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl)
175 / UDP(sport=1234, dport=1234)
181 / IP(src=ip_itf.remote_ip4, dst=ip_itf.local_ip4, ttl=ip_ttl)
186 p[IP].chksum = chksum
191 def create_stream_ip4(
192 self, src_if, dst_ip, ip_ttl=64, ip_dscp=0, payload_size=None
194 self.reset_packet_infos()
196 for i in range(0, 257):
197 info = self.create_packet_info(src_if, src_if)
198 payload = self.info_to_payload(info)
200 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
201 / IP(src=src_if.remote_ip4, dst=dst_ip, ttl=ip_ttl, tos=ip_dscp)
202 / UDP(sport=1234, dport=1234)
207 self.extend_packet(p, payload_size)
211 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
212 self.reset_packet_infos()
214 for i in range(0, 257):
215 info = self.create_packet_info(src_if, src_if)
216 payload = self.info_to_payload(info)
218 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
219 / IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=ip_ttl, tc=ip_dscp)
220 / UDP(sport=1234, dport=1234)
227 def create_stream_labelled_ip6(
228 self, src_if, mpls_labels, hlim=64, dst_ip=None, ping=0, ip_itf=None
231 dst_ip = src_if.remote_ip6
232 self.reset_packet_infos()
234 for i in range(0, 257):
235 info = self.create_packet_info(src_if, src_if)
236 payload = self.info_to_payload(info)
237 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
238 for l in mpls_labels:
239 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
243 IPv6(src=ip_itf.remote_ip6, dst=ip_itf.local_ip6)
244 / ICMPv6EchoRequest()
248 IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim)
249 / UDP(sport=1234, dport=1234)
256 def verify_capture_ip4(
257 self, src_if, capture, sent, ping_resp=0, ip_ttl=None, ip_dscp=0
260 capture = verify_filter(capture, sent)
262 self.assertEqual(len(capture), len(sent))
264 for i in range(len(capture)):
268 # the rx'd packet has the MPLS label popped
270 self.assertEqual(eth.type, 0x800)
276 self.assertEqual(rx_ip.src, tx_ip.src)
277 self.assertEqual(rx_ip.dst, tx_ip.dst)
278 self.assertEqual(rx_ip.tos, ip_dscp)
280 # IP processing post pop has decremented the TTL
281 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
283 self.assertEqual(rx_ip.ttl, ip_ttl)
285 self.assertEqual(rx_ip.src, tx_ip.dst)
286 self.assertEqual(rx_ip.dst, tx_ip.src)
291 def verify_capture_labelled_ip4(
292 self, src_if, capture, sent, mpls_labels, ip_ttl=None
295 capture = verify_filter(capture, sent)
297 self.assertEqual(len(capture), len(sent))
299 for i in range(len(capture)):
305 verify_mpls_stack(self, rx, mpls_labels)
307 self.assertEqual(rx_ip.src, tx_ip.src)
308 self.assertEqual(rx_ip.dst, tx_ip.dst)
310 # IP processing post pop has decremented the TTL
311 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
313 self.assertEqual(rx_ip.ttl, ip_ttl)
318 def verify_capture_labelled_ip6(
319 self, src_if, capture, sent, mpls_labels, ip_ttl=None
322 capture = verify_filter(capture, sent)
324 self.assertEqual(len(capture), len(sent))
326 for i in range(len(capture)):
332 verify_mpls_stack(self, rx, mpls_labels)
334 self.assertEqual(rx_ip.src, tx_ip.src)
335 self.assertEqual(rx_ip.dst, tx_ip.dst)
337 # IP processing post pop has decremented the TTL
338 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
340 self.assertEqual(rx_ip.hlim, ip_ttl)
345 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
347 capture = verify_filter(capture, sent)
349 self.assertEqual(len(capture), len(sent))
351 for i in range(len(capture)):
357 verify_mpls_stack(self, rx, mpls_labels)
359 self.assertEqual(rx_ip.src, tx_ip.src)
360 self.assertEqual(rx_ip.dst, tx_ip.dst)
361 # IP processing post pop has decremented the TTL
362 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
367 def verify_capture_labelled(self, src_if, capture, sent, mpls_labels):
369 capture = verify_filter(capture, sent)
371 self.assertEqual(len(capture), len(sent))
373 for i in range(len(capture)):
375 verify_mpls_stack(self, rx, mpls_labels)
379 def verify_capture_ip6(
380 self, src_if, capture, sent, ip_hlim=None, ip_dscp=0, ping_resp=0
383 self.assertEqual(len(capture), len(sent))
385 for i in range(len(capture)):
389 # the rx'd packet has the MPLS label popped
391 self.assertEqual(eth.type, 0x86DD)
397 self.assertEqual(rx_ip.src, tx_ip.src)
398 self.assertEqual(rx_ip.dst, tx_ip.dst)
399 self.assertEqual(rx_ip.tc, ip_dscp)
400 # IP processing post pop has decremented the TTL
402 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
404 self.assertEqual(rx_ip.hlim, ip_hlim)
406 self.assertEqual(rx_ip.src, tx_ip.dst)
407 self.assertEqual(rx_ip.dst, tx_ip.src)
411 def verify_capture_ip6_icmp(self, src_if, capture, sent):
414 self.assertTrue(len(capture) <= len(sent))
416 for i in range(len(capture)):
420 # the rx'd packet has the MPLS label popped
422 self.assertEqual(eth.type, 0x86DD)
427 self.assertEqual(rx_ip.dst, tx_ip.src)
428 # ICMP sourced from the interface's address
429 self.assertEqual(rx_ip.src, src_if.local_ip6)
430 # hop-limit reset to 255 for IMCP packet
431 self.assertEqual(rx_ip.hlim, 255)
433 icmp = rx[ICMPv6TimeExceeded]
438 def verify_capture_fragmented_labelled_ip4(
439 self, src_if, capture, sent, mpls_labels, ip_ttl=None
442 capture = verify_filter(capture, sent)
444 for i in range(len(capture)):
450 verify_mpls_stack(self, rx, mpls_labels)
452 self.assertEqual(rx_ip.src, tx_ip.src)
453 self.assertEqual(rx_ip.dst, tx_ip.dst)
455 # IP processing post pop has decremented the TTL
456 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
458 self.assertEqual(rx_ip.ttl, ip_ttl)
463 def verify_capture_fragmented_labelled_ip6(
464 self, src_if, capture, sent, mpls_labels, ip_ttl=None
467 capture = verify_filter(capture, sent)
469 for i in range(len(capture)):
474 rx_ip = IPv6(rx[MPLS].payload)
477 verify_mpls_stack(self, rx, mpls_labels)
479 self.assertEqual(rx_ip.src, tx_ip.src)
480 self.assertEqual(rx_ip.dst, tx_ip.dst)
482 # IP processing post pop has decremented the hop-limit
483 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
485 self.assertEqual(rx_ip.hlim, ip_ttl)
490 """MPLS label swap tests"""
493 # A simple MPLS xconnect - eos label in label out
495 route_32_eos = VppMplsRoute(
501 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(33)]
505 route_32_eos.add_vpp_config()
516 self.pg0.sw_if_index,
517 labels=[VppMplsLabel(33)],
524 # a stream that matches the route for 10.0.0.1
525 # PG0 is in the default table
527 tx = self.create_stream_labelled_ip4(
528 self.pg0, [VppMplsLabel(32, ttl=32, exp=1)]
530 rx = self.send_and_expect(self.pg0, tx, self.pg0)
531 self.verify_capture_labelled(
532 self.pg0, rx, tx, [VppMplsLabel(33, ttl=31, exp=1)]
535 self.assertEqual(route_32_eos.get_stats_to()["packets"], 257)
538 # A simple MPLS xconnect - non-eos label in label out
540 route_32_neos = VppMplsRoute(
546 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(33)]
550 route_32_neos.add_vpp_config()
553 # a stream that matches the route for 10.0.0.1
554 # PG0 is in the default table
556 tx = self.create_stream_labelled_ip4(
557 self.pg0, [VppMplsLabel(32, ttl=21, exp=7), VppMplsLabel(99)]
559 rx = self.send_and_expect(self.pg0, tx, self.pg0)
560 self.verify_capture_labelled(
561 self.pg0, rx, tx, [VppMplsLabel(33, ttl=20, exp=7), VppMplsLabel(99)]
563 self.assertEqual(route_32_neos.get_stats_to()["packets"], 257)
566 # A simple MPLS xconnect - non-eos label in label out, uniform mode
568 route_42_neos = VppMplsRoute(
575 self.pg0.sw_if_index,
576 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)],
580 route_42_neos.add_vpp_config()
582 tx = self.create_stream_labelled_ip4(
583 self.pg0, [VppMplsLabel(42, ttl=21, exp=7), VppMplsLabel(99)]
585 rx = self.send_and_expect(self.pg0, tx, self.pg0)
586 self.verify_capture_labelled(
587 self.pg0, rx, tx, [VppMplsLabel(43, ttl=20, exp=7), VppMplsLabel(99)]
591 # An MPLS xconnect - EOS label in IP out
593 route_33_eos = VppMplsRoute(
597 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[])],
599 route_33_eos.add_vpp_config()
601 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
602 rx = self.send_and_expect(self.pg0, tx, self.pg0)
603 self.verify_capture_ip4(self.pg0, rx, tx)
606 # disposed packets have an invalid IPv4 checksum
608 tx = self.create_stream_labelled_ip4(
609 self.pg0, [VppMplsLabel(33)], dst_ip=self.pg0.remote_ip4, n=65, chksum=1
611 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
614 # An MPLS xconnect - EOS label in IP out, uniform mode
616 route_3333_eos = VppMplsRoute(
623 self.pg0.sw_if_index,
624 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
628 route_3333_eos.add_vpp_config()
630 tx = self.create_stream_labelled_ip4(
631 self.pg0, [VppMplsLabel(3333, ttl=55, exp=3)]
633 rx = self.send_and_expect(self.pg0, tx, self.pg0)
634 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
635 tx = self.create_stream_labelled_ip4(
636 self.pg0, [VppMplsLabel(3333, ttl=66, exp=4)]
638 rx = self.send_and_expect(self.pg0, tx, self.pg0)
639 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
642 # An MPLS xconnect - EOS label in IPv6 out
644 route_333_eos = VppMplsRoute(
648 [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, labels=[])],
649 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
651 route_333_eos.add_vpp_config()
653 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
654 rx = self.send_and_expect(self.pg0, tx, self.pg0)
655 self.verify_capture_ip6(self.pg0, rx, tx)
658 # disposed packets have an TTL expired
660 tx = self.create_stream_labelled_ip6(
661 self.pg0, [VppMplsLabel(333, ttl=64)], dst_ip=self.pg1.remote_ip6, hlim=1
663 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
664 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
667 # An MPLS xconnect - EOS label in IPv6 out w imp-null
669 route_334_eos = VppMplsRoute(
675 self.pg0.remote_ip6, self.pg0.sw_if_index, labels=[VppMplsLabel(3)]
678 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
680 route_334_eos.add_vpp_config()
682 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334, ttl=64)])
683 rx = self.send_and_expect(self.pg0, tx, self.pg0)
684 self.verify_capture_ip6(self.pg0, rx, tx)
687 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
689 route_335_eos = VppMplsRoute(
696 self.pg0.sw_if_index,
697 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
700 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
702 route_335_eos.add_vpp_config()
704 tx = self.create_stream_labelled_ip6(
705 self.pg0, [VppMplsLabel(335, ttl=27, exp=4)]
707 rx = self.send_and_expect(self.pg0, tx, self.pg0)
708 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
711 # disposed packets have an TTL expired
713 tx = self.create_stream_labelled_ip6(
714 self.pg0, [VppMplsLabel(334)], dst_ip=self.pg1.remote_ip6, hlim=0
716 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
717 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
720 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
721 # so this traffic should be dropped.
723 route_33_neos = VppMplsRoute(
727 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[])],
729 route_33_neos.add_vpp_config()
731 tx = self.create_stream_labelled_ip4(
732 self.pg0, [VppMplsLabel(33), VppMplsLabel(99)]
734 self.send_and_assert_no_replies(
735 self.pg0, tx, "MPLS non-EOS packets popped and forwarded"
739 # A recursive EOS x-connect, which resolves through another x-connect
742 route_34_eos = VppMplsRoute(
751 labels=[VppMplsLabel(44), VppMplsLabel(45)],
755 route_34_eos.add_vpp_config()
756 self.logger.info(self.vapi.cli("sh mpls fib 34"))
758 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34, ttl=3)])
759 rx = self.send_and_expect(self.pg0, tx, self.pg0)
760 self.verify_capture_labelled(
764 [VppMplsLabel(33), VppMplsLabel(44), VppMplsLabel(45, ttl=2)],
767 self.assertEqual(route_34_eos.get_stats_to()["packets"], 257)
768 self.assertEqual(route_32_neos.get_stats_via()["packets"], 257)
771 # A recursive EOS x-connect, which resolves through another x-connect
774 route_35_eos = VppMplsRoute(
780 "0.0.0.0", 0xFFFFFFFF, nh_via_label=42, labels=[VppMplsLabel(44)]
784 route_35_eos.add_vpp_config()
786 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(35, ttl=3)])
787 rx = self.send_and_expect(self.pg0, tx, self.pg0)
788 self.verify_capture_labelled(
789 self.pg0, rx, tx, [VppMplsLabel(43, ttl=2), VppMplsLabel(44, ttl=2)]
793 # A recursive non-EOS x-connect, which resolves through another
796 route_34_neos = VppMplsRoute(
805 labels=[VppMplsLabel(44), VppMplsLabel(46)],
809 route_34_neos.add_vpp_config()
811 tx = self.create_stream_labelled_ip4(
812 self.pg0, [VppMplsLabel(34, ttl=45), VppMplsLabel(99)]
814 rx = self.send_and_expect(self.pg0, tx, self.pg0)
815 # it's the 2nd (counting from 0) label in the stack that is swapped
816 self.verify_capture_labelled(
823 VppMplsLabel(46, ttl=44),
829 # an recursive IP route that resolves through the recursive non-eos
832 ip_10_0_0_1 = VppIpRoute(
838 "0.0.0.0", 0xFFFFFFFF, nh_via_label=34, labels=[VppMplsLabel(55)]
842 ip_10_0_0_1.add_vpp_config()
844 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
845 rx = self.send_and_expect(self.pg0, tx, self.pg0)
846 self.verify_capture_labelled_ip4(
850 [VppMplsLabel(33), VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(55)],
852 self.assertEqual(ip_10_0_0_1.get_stats_to()["packets"], 257)
854 ip_10_0_0_1.remove_vpp_config()
855 route_34_neos.remove_vpp_config()
856 route_34_eos.remove_vpp_config()
857 route_33_neos.remove_vpp_config()
858 route_33_eos.remove_vpp_config()
859 route_32_neos.remove_vpp_config()
860 route_32_eos.remove_vpp_config()
863 """MPLS Local Label Binding test"""
866 # Add a non-recursive route with a single out label
868 route_10_0_0_1 = VppIpRoute(
874 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(45)]
878 route_10_0_0_1.add_vpp_config()
880 # bind a local label to the route
881 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
882 binding.add_vpp_config()
885 tx = self.create_stream_labelled_ip4(
886 self.pg0, [VppMplsLabel(44), VppMplsLabel(99)]
888 rx = self.send_and_expect(self.pg0, tx, self.pg0)
889 self.verify_capture_labelled(
890 self.pg0, rx, tx, [VppMplsLabel(45, ttl=63), VppMplsLabel(99)]
894 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
895 rx = self.send_and_expect(self.pg0, tx, self.pg0)
896 self.verify_capture_labelled(self.pg0, rx, tx, [VppMplsLabel(45, ttl=63)])
899 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
900 rx = self.send_and_expect(self.pg0, tx, self.pg0)
901 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
906 binding.remove_vpp_config()
907 route_10_0_0_1.remove_vpp_config()
909 def test_imposition(self):
910 """MPLS label imposition test"""
913 # Add a non-recursive route with a single out label
915 route_10_0_0_1 = VppIpRoute(
921 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(32)]
925 route_10_0_0_1.add_vpp_config()
928 # a stream that matches the route for 10.0.0.1
929 # PG0 is in the default table
931 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
932 rx = self.send_and_expect(self.pg0, tx, self.pg0)
933 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
936 # Add a non-recursive route with a 3 out labels
938 route_10_0_0_2 = VppIpRoute(
945 self.pg0.sw_if_index,
946 labels=[VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34)],
950 route_10_0_0_2.add_vpp_config()
952 tx = self.create_stream_ip4(self.pg0, "10.0.0.2", ip_ttl=44, ip_dscp=0xFF)
953 rx = self.send_and_expect(self.pg0, tx, self.pg0)
954 self.verify_capture_labelled_ip4(
958 [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34)],
963 # Add a non-recursive route with a single out label in uniform mode
965 route_10_0_0_3 = VppIpRoute(
972 self.pg0.sw_if_index,
973 labels=[VppMplsLabel(32, mode=MplsLspMode.UNIFORM)],
977 route_10_0_0_3.add_vpp_config()
979 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=54, ip_dscp=0xBE)
980 rx = self.send_and_expect(self.pg0, tx, self.pg0)
981 self.verify_capture_labelled_ip4(
982 self.pg0, rx, tx, [VppMplsLabel(32, ttl=53, exp=5)]
986 # Add a IPv6 non-recursive route with a single out label in
989 route_2001_3 = VppIpRoute(
996 self.pg0.sw_if_index,
997 labels=[VppMplsLabel(32, mode=MplsLspMode.UNIFORM)],
1001 route_2001_3.add_vpp_config()
1003 tx = self.create_stream_ip6(self.pg0, "2001::3", ip_ttl=54, ip_dscp=0xBE)
1004 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1005 self.verify_capture_labelled_ip6(
1006 self.pg0, rx, tx, [VppMplsLabel(32, ttl=53, exp=5)]
1010 # add a recursive path, with output label, via the 1 label route
1012 route_11_0_0_1 = VppIpRoute(
1016 [VppRoutePath("10.0.0.1", 0xFFFFFFFF, labels=[VppMplsLabel(44)])],
1018 route_11_0_0_1.add_vpp_config()
1021 # a stream that matches the route for 11.0.0.1, should pick up
1022 # the label stack for 11.0.0.1 and 10.0.0.1
1024 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
1025 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1026 self.verify_capture_labelled_ip4(
1027 self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(44)]
1030 self.assertEqual(route_11_0_0_1.get_stats_to()["packets"], 257)
1033 # add a recursive path, with 2 labels, via the 3 label route
1035 route_11_0_0_2 = VppIpRoute(
1041 "10.0.0.2", 0xFFFFFFFF, labels=[VppMplsLabel(44), VppMplsLabel(45)]
1045 route_11_0_0_2.add_vpp_config()
1048 # a stream that matches the route for 11.0.0.1, should pick up
1049 # the label stack for 11.0.0.1 and 10.0.0.1
1051 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
1052 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1053 self.verify_capture_labelled_ip4(
1066 self.assertEqual(route_11_0_0_2.get_stats_to()["packets"], 257)
1068 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1069 self.verify_capture_labelled_ip4(
1082 self.assertEqual(route_11_0_0_2.get_stats_to()["packets"], 514)
1087 route_11_0_0_2.remove_vpp_config()
1088 route_11_0_0_1.remove_vpp_config()
1089 route_10_0_0_2.remove_vpp_config()
1090 route_10_0_0_1.remove_vpp_config()
1092 def test_imposition_fragmentation(self):
1093 """MPLS label imposition fragmentation test"""
1096 # Add a ipv4 non-recursive route with a single out label
1098 route_10_0_0_1 = VppIpRoute(
1104 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(32)]
1108 route_10_0_0_1.add_vpp_config()
1109 route_1000_1 = VppIpRoute(
1115 self.pg0.remote_ip6, self.pg0.sw_if_index, labels=[VppMplsLabel(32)]
1119 route_1000_1.add_vpp_config()
1122 # a stream that matches the route for 10.0.0.1
1123 # PG0 is in the default table
1125 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
1126 for i in range(0, 257):
1127 self.extend_packet(tx[i], 10000)
1130 # 5 fragments per packet (257*5=1285)
1132 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
1133 self.verify_capture_fragmented_labelled_ip4(
1134 self.pg0, rx, tx, [VppMplsLabel(32)]
1137 # packets with DF bit set generate ICMP
1140 rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
1143 self.assertEqual(icmptypes[rx[ICMP].type], "dest-unreach")
1145 icmpcodes[rx[ICMP].type][rx[ICMP].code], "fragmentation-needed"
1147 # the link MTU is 9000, the MPLS over head is 4 bytes
1148 self.assertEqual(rx[ICMP].nexthopmtu, 9000 - 4)
1151 self.statistics.get_err_counter("/err/mpls-frag/dont_fragment_set"),
1155 # a stream that matches the route for 1000::1/128
1156 # PG0 is in the default table
1158 tx = self.create_stream_ip6(self.pg0, "1000::1")
1159 for i in range(0, 257):
1160 self.extend_packet(tx[i], 10000)
1162 rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
1164 self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 9000 - 4)
1169 route_10_0_0_1.remove_vpp_config()
1171 def test_tunnel_pipe(self):
1172 """MPLS Tunnel Tests - Pipe"""
1175 # Create a tunnel with two out labels
1177 mpls_tun = VppMPLSTunnelInterface(
1181 self.pg0.remote_ip4,
1182 self.pg0.sw_if_index,
1183 labels=[VppMplsLabel(44), VppMplsLabel(46)],
1187 mpls_tun.add_vpp_config()
1191 # add an unlabelled route through the new tunnel
1193 route_10_0_0_3 = VppIpRoute(
1194 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1196 route_10_0_0_3.add_vpp_config()
1198 self.vapi.cli("clear trace")
1199 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1200 self.pg0.add_stream(tx)
1202 self.pg_enable_capture(self.pg_interfaces)
1205 rx = self.pg0.get_capture()
1206 self.verify_capture_tunneled_ip4(
1207 self.pg0, rx, tx, [VppMplsLabel(44), VppMplsLabel(46)]
1211 # add a labelled route through the new tunnel
1213 route_10_0_0_4 = VppIpRoute(
1217 [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index, labels=[33])],
1219 route_10_0_0_4.add_vpp_config()
1221 self.vapi.cli("clear trace")
1222 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1223 self.pg0.add_stream(tx)
1225 self.pg_enable_capture(self.pg_interfaces)
1228 rx = self.pg0.get_capture()
1229 self.verify_capture_tunneled_ip4(
1233 [VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(33, ttl=255)],
1237 # change tunnel's MTU to a low value
1239 mpls_tun.set_l3_mtu(1200)
1241 # send IP into the tunnel to be fragmented
1242 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", payload_size=1500)
1243 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx) * 2)
1249 self.verify_capture_tunneled_ip4(
1250 self.pg0, rx, fake_tx, [VppMplsLabel(44), VppMplsLabel(46)]
1253 # send MPLS into the tunnel to be fragmented
1254 tx = self.create_stream_ip4(self.pg0, "10.0.0.4", payload_size=1500)
1255 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx) * 2)
1261 self.verify_capture_tunneled_ip4(
1265 [VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(33, ttl=255)],
1268 def test_tunnel_uniform(self):
1269 """MPLS Tunnel Tests - Uniform"""
1272 # Create a tunnel with a single out label
1273 # The label stack is specified here from outer to inner
1275 mpls_tun = VppMPLSTunnelInterface(
1279 self.pg0.remote_ip4,
1280 self.pg0.sw_if_index,
1282 VppMplsLabel(44, ttl=32),
1283 VppMplsLabel(46, MplsLspMode.UNIFORM),
1288 mpls_tun.add_vpp_config()
1292 # add an unlabelled route through the new tunnel
1294 route_10_0_0_3 = VppIpRoute(
1295 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1297 route_10_0_0_3.add_vpp_config()
1299 self.vapi.cli("clear trace")
1300 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1301 self.pg0.add_stream(tx)
1303 self.pg_enable_capture(self.pg_interfaces)
1306 rx = self.pg0.get_capture()
1307 self.verify_capture_tunneled_ip4(
1308 self.pg0, rx, tx, [VppMplsLabel(44, ttl=32), VppMplsLabel(46, ttl=23)]
1312 # add a labelled route through the new tunnel
1314 route_10_0_0_4 = VppIpRoute(
1320 "0.0.0.0", mpls_tun._sw_if_index, labels=[VppMplsLabel(33, ttl=47)]
1324 route_10_0_0_4.add_vpp_config()
1326 self.vapi.cli("clear trace")
1327 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1328 self.pg0.add_stream(tx)
1330 self.pg_enable_capture(self.pg_interfaces)
1333 rx = self.pg0.get_capture()
1334 self.verify_capture_tunneled_ip4(
1339 VppMplsLabel(44, ttl=32),
1340 VppMplsLabel(46, ttl=47),
1341 VppMplsLabel(33, ttl=47),
1345 def test_mpls_tunnel_many(self):
1346 """MPLS Multiple Tunnels"""
1348 for ii in range(100):
1349 mpls_tun = VppMPLSTunnelInterface(
1353 self.pg0.remote_ip4,
1354 self.pg0.sw_if_index,
1356 VppMplsLabel(44, ttl=32),
1357 VppMplsLabel(46, MplsLspMode.UNIFORM),
1362 mpls_tun.add_vpp_config()
1364 for ii in range(100):
1365 mpls_tun = VppMPLSTunnelInterface(
1369 self.pg0.remote_ip4,
1370 self.pg0.sw_if_index,
1372 VppMplsLabel(44, ttl=32),
1373 VppMplsLabel(46, MplsLspMode.UNIFORM),
1379 mpls_tun.add_vpp_config()
1382 def test_v4_exp_null(self):
1383 """MPLS V4 Explicit NULL test"""
1386 # The first test case has an MPLS TTL of 0
1387 # all packet should be dropped
1389 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0, ttl=0)])
1390 self.send_and_assert_no_replies(self.pg0, tx, "MPLS TTL=0 packets forwarded")
1393 # a stream with a non-zero MPLS TTL
1394 # PG0 is in the default table
1396 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1397 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1398 self.verify_capture_ip4(self.pg0, rx, tx)
1401 # a stream with a non-zero MPLS TTL
1403 # we are ensuring the post-pop lookup occurs in the VRF table
1405 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1406 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1407 self.verify_capture_ip4(self.pg1, rx, tx)
1409 def test_v6_exp_null(self):
1410 """MPLS V6 Explicit NULL test"""
1413 # a stream with a non-zero MPLS TTL
1414 # PG0 is in the default table
1416 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1417 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1418 self.verify_capture_ip6(self.pg0, rx, tx)
1421 # a stream with a non-zero MPLS TTL
1423 # we are ensuring the post-pop lookup occurs in the VRF table
1425 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1426 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1427 self.verify_capture_ip6(self.pg0, rx, tx)
1429 def test_deag(self):
1433 # A de-agg route - next-hop lookup in default table
1435 route_34_eos = VppMplsRoute(
1436 self, 34, 1, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)]
1438 route_34_eos.add_vpp_config()
1441 # ping an interface in the default table
1442 # PG0 is in the default table
1444 tx = self.create_stream_labelled_ip4(
1445 self.pg0, [VppMplsLabel(34)], ping=1, ip_itf=self.pg0
1447 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1448 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1451 # A de-agg route - next-hop lookup in non-default table
1453 route_35_eos = VppMplsRoute(
1454 self, 35, 1, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)]
1456 route_35_eos.add_vpp_config()
1457 route_356_eos = VppMplsRoute(
1461 [VppRoutePath("0::0", 0xFFFFFFFF, nh_table_id=1)],
1462 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1464 route_356_eos.add_vpp_config()
1467 # ping an interface in the non-default table
1468 # PG0 is in the default table. packet arrive labelled in the
1469 # default table and egress unlabelled in the non-default
1471 tx = self.create_stream_labelled_ip4(
1472 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1
1474 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1475 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1476 tx = self.create_stream_labelled_ip6(
1477 self.pg0, [VppMplsLabel(356)], ping=1, ip_itf=self.pg1
1479 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1480 self.verify_capture_ip6(self.pg1, rx, tx, ping_resp=1)
1485 route_36_neos = VppMplsRoute(self, 36, 0, [VppRoutePath("0.0.0.0", 0xFFFFFFFF)])
1486 route_36_neos.add_vpp_config()
1488 tx = self.create_stream_labelled_ip4(
1489 self.pg0, [VppMplsLabel(36), VppMplsLabel(35)], ping=1, ip_itf=self.pg1
1491 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1492 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1494 route_36_neos.remove_vpp_config()
1495 route_35_eos.remove_vpp_config()
1496 route_34_eos.remove_vpp_config()
1498 def test_interface_rx(self):
1499 """MPLS Interface Receive"""
1502 # Add a non-recursive route that will forward the traffic
1505 route_10_0_0_1 = VppIpRoute(
1510 paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
1512 route_10_0_0_1.add_vpp_config()
1515 # An interface receive label that maps traffic to RX on interface
1517 # by injecting the packet in on pg0, which is in table 0
1518 # doing an interface-rx on pg1 and matching a route in table 1
1519 # if the packet egresses, then we must have swapped to pg1
1520 # so as to have matched the route in table 1
1522 route_34_eos = VppMplsRoute(
1529 self.pg1.sw_if_index,
1530 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
1534 route_34_eos.add_vpp_config()
1537 # ping an interface in the default table
1538 # PG0 is in the default table
1540 tx = self.create_stream_labelled_ip4(
1541 self.pg0, [VppMplsLabel(34)], dst_ip="10.0.0.1"
1543 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1544 self.verify_capture_ip4(self.pg1, rx, tx)
1546 def test_mcast_mid_point(self):
1547 """MPLS Multicast Mid Point"""
1550 # Add a non-recursive route that will forward the traffic
1553 route_10_0_0_1 = VppIpRoute(
1558 paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
1560 route_10_0_0_1.add_vpp_config()
1563 # Add a mcast entry that replicate to pg2 and pg3
1564 # and replicate to a interface-rx (like a bud node would)
1566 route_3400_eos = VppMplsRoute(
1572 self.pg2.remote_ip4,
1573 self.pg2.sw_if_index,
1574 labels=[VppMplsLabel(3401)],
1577 self.pg3.remote_ip4,
1578 self.pg3.sw_if_index,
1579 labels=[VppMplsLabel(3402)],
1583 self.pg1.sw_if_index,
1584 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
1589 route_3400_eos.add_vpp_config()
1592 # ping an interface in the default table
1593 # PG0 is in the default table
1595 self.vapi.cli("clear trace")
1596 tx = self.create_stream_labelled_ip4(
1597 self.pg0, [VppMplsLabel(3400, ttl=64)], n=257, dst_ip="10.0.0.1"
1599 self.pg0.add_stream(tx)
1601 self.pg_enable_capture(self.pg_interfaces)
1604 rx = self.pg1.get_capture(257)
1605 self.verify_capture_ip4(self.pg1, rx, tx)
1607 rx = self.pg2.get_capture(257)
1608 self.verify_capture_labelled(self.pg2, rx, tx, [VppMplsLabel(3401, ttl=63)])
1609 rx = self.pg3.get_capture(257)
1610 self.verify_capture_labelled(self.pg3, rx, tx, [VppMplsLabel(3402, ttl=63)])
1612 def test_mcast_head(self):
1613 """MPLS Multicast Head-end"""
1615 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1616 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1619 # Create a multicast tunnel with two replications
1621 mpls_tun = VppMPLSTunnelInterface(
1625 self.pg2.remote_ip4, self.pg2.sw_if_index, labels=[VppMplsLabel(42)]
1628 self.pg3.remote_ip4, self.pg3.sw_if_index, labels=[VppMplsLabel(43)]
1633 mpls_tun.add_vpp_config()
1637 # add an unlabelled route through the new tunnel
1639 route_10_0_0_3 = VppIpRoute(
1640 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1642 route_10_0_0_3.add_vpp_config()
1644 self.vapi.cli("clear trace")
1645 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1646 self.pg0.add_stream(tx)
1648 self.pg_enable_capture(self.pg_interfaces)
1651 rx = self.pg2.get_capture(257)
1652 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1653 rx = self.pg3.get_capture(257)
1654 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1657 # An an IP multicast route via the tunnel
1659 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1661 route_232_1_1_1 = VppIpMRoute(
1666 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1669 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1672 mpls_tun._sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1676 route_232_1_1_1.add_vpp_config()
1677 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1679 self.vapi.cli("clear trace")
1680 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1681 self.pg0.add_stream(tx)
1683 self.pg_enable_capture(self.pg_interfaces)
1686 rx = self.pg2.get_capture(257)
1687 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1688 rx = self.pg3.get_capture(257)
1689 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1691 def test_mcast_ip4_tail(self):
1692 """MPLS IPv4 Multicast Tail"""
1694 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1695 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1698 # Add a multicast route that will forward the traffic
1701 route_232_1_1_1 = VppIpMRoute(
1706 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1710 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1714 route_232_1_1_1.add_vpp_config()
1717 # An interface receive label that maps traffic to RX on interface
1719 # by injecting the packet in on pg0, which is in table 0
1720 # doing an rpf-id and matching a route in table 1
1721 # if the packet egresses, then we must have matched the route in
1724 route_34_eos = VppMplsRoute(
1728 [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1, rpf_id=55)],
1730 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
1733 route_34_eos.add_vpp_config()
1736 # Drop due to interface lookup miss
1738 self.vapi.cli("clear trace")
1739 tx = self.create_stream_labelled_ip4(
1740 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1", n=1
1742 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1745 # set the RPF-ID of the entry to match the input packet's
1747 route_232_1_1_1.update_rpf_id(55)
1748 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1750 tx = self.create_stream_labelled_ip4(
1751 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1"
1753 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1754 self.verify_capture_ip4(self.pg1, rx, tx)
1757 # disposed packets have an invalid IPv4 checksum
1759 tx = self.create_stream_labelled_ip4(
1760 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1", n=65, chksum=1
1762 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1765 # set the RPF-ID of the entry to not match the input packet's
1767 route_232_1_1_1.update_rpf_id(56)
1768 tx = self.create_stream_labelled_ip4(
1769 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1"
1771 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1773 def test_mcast_ip6_tail(self):
1774 """MPLS IPv6 Multicast Tail"""
1776 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1777 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1780 # Add a multicast route that will forward the traffic
1783 route_ff = VppIpMRoute(
1788 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1792 self.pg1.sw_if_index,
1793 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1794 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1798 route_ff.add_vpp_config()
1801 # An interface receive label that maps traffic to RX on interface
1803 # by injecting the packet in on pg0, which is in table 0
1804 # doing an rpf-id and matching a route in table 1
1805 # if the packet egresses, then we must have matched the route in
1808 route_34_eos = VppMplsRoute(
1812 [VppRoutePath("::", 0xFFFFFFFF, nh_table_id=1, rpf_id=55)],
1814 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1817 route_34_eos.add_vpp_config()
1820 # Drop due to interface lookup miss
1822 tx = self.create_stream_labelled_ip6(
1823 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1825 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1828 # set the RPF-ID of the entry to match the input packet's
1830 route_ff.update_rpf_id(55)
1832 tx = self.create_stream_labelled_ip6(
1833 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1835 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1836 self.verify_capture_ip6(self.pg1, rx, tx)
1839 # disposed packets have hop-limit = 1
1841 tx = self.create_stream_labelled_ip6(
1842 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1", hlim=1
1844 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
1845 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1848 # set the RPF-ID of the entry to not match the input packet's
1850 route_ff.update_rpf_id(56)
1851 tx = self.create_stream_labelled_ip6(
1852 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1854 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1860 # Add a non-recursive route with a single out label
1862 route_10_0_0_1 = VppIpRoute(
1868 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(45)]
1872 route_10_0_0_1.add_vpp_config()
1874 # bind a local label to the route
1875 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1876 binding.add_vpp_config()
1879 # a labelled v6 route that resolves through the v4
1881 route_2001_3 = VppIpRoute(
1885 [VppRoutePath("10.0.0.1", INVALID_INDEX, labels=[VppMplsLabel(32)])],
1887 route_2001_3.add_vpp_config()
1889 tx = self.create_stream_ip6(self.pg0, "2001::3")
1890 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1892 self.verify_capture_labelled_ip6(
1893 self.pg0, rx, tx, [VppMplsLabel(45), VppMplsLabel(32)]
1897 # and a v4 recursive via the v6
1899 route_20_3 = VppIpRoute(
1903 [VppRoutePath("2001::3", INVALID_INDEX, labels=[VppMplsLabel(99)])],
1905 route_20_3.add_vpp_config()
1907 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1908 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1910 self.verify_capture_labelled_ip4(
1911 self.pg0, rx, tx, [VppMplsLabel(45), VppMplsLabel(32), VppMplsLabel(99)]
1914 def test_attached(self):
1915 """Attach Routes with Local Label"""
1918 # test that if a local label is associated with an attached/connected
1919 # prefix, that we can reach hosts in the prefix.
1921 binding = VppMplsIpBind(
1922 self, 44, self.pg0._local_ip4_subnet, self.pg0.local_ip4_prefix_len
1924 binding.add_vpp_config()
1927 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1928 / MPLS(label=44, ttl=64)
1929 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
1930 / UDP(sport=1234, dport=1234)
1931 / Raw(b"\xa5" * 100)
1933 rxs = self.send_and_expect(self.pg0, [tx], self.pg0)
1935 # if there's an ARP then the label is linked to the glean
1937 self.assertFalse(rx.haslayer(ARP))
1938 # it should be unicasted to the host
1939 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1940 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1943 class TestMPLSDisabled(VppTestCase):
1947 def setUpClass(cls):
1948 super(TestMPLSDisabled, cls).setUpClass()
1951 def tearDownClass(cls):
1952 super(TestMPLSDisabled, cls).tearDownClass()
1955 super(TestMPLSDisabled, self).setUp()
1957 # create 2 pg interfaces
1958 self.create_pg_interfaces(range(2))
1960 self.tbl = VppMplsTable(self, 0)
1961 self.tbl.add_vpp_config()
1963 # PG0 is MPLS enabled
1965 self.pg0.config_ip4()
1966 self.pg0.resolve_arp()
1967 self.pg0.enable_mpls()
1969 # PG 1 is not MPLS enabled
1973 for i in self.pg_interfaces:
1977 self.pg0.disable_mpls()
1978 super(TestMPLSDisabled, self).tearDown()
1980 def test_mpls_disabled(self):
1983 self.logger.info(self.vapi.cli("show mpls interface"))
1984 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1985 self.logger.info(self.vapi.cli("show mpls interface pg0"))
1988 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1989 / MPLS(label=32, ttl=64)
1990 / IPv6(src="2001::1", dst=self.pg0.remote_ip6)
1991 / UDP(sport=1234, dport=1234)
1992 / Raw(b"\xa5" * 100)
1996 # A simple MPLS xconnect - eos label in label out
1998 route_32_eos = VppMplsRoute(
2002 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[33])],
2004 route_32_eos.add_vpp_config()
2007 # PG1 does not forward IP traffic
2009 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
2014 self.pg1.enable_mpls()
2016 self.logger.info(self.vapi.cli("show mpls interface"))
2017 self.logger.info(self.vapi.cli("show mpls interface pg1"))
2020 # Now we get packets through
2022 self.pg1.add_stream(tx)
2023 self.pg_enable_capture(self.pg_interfaces)
2026 rx = self.pg0.get_capture(1)
2031 self.pg1.disable_mpls()
2034 # PG1 does not forward IP traffic
2036 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
2037 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
2040 class TestMPLSPIC(VppTestCase):
2041 """MPLS Prefix-Independent Convergence (PIC) edge convergence"""
2044 def setUpClass(cls):
2045 super(TestMPLSPIC, cls).setUpClass()
2048 def tearDownClass(cls):
2049 super(TestMPLSPIC, cls).tearDownClass()
2052 super(TestMPLSPIC, self).setUp()
2054 # create 2 pg interfaces
2055 self.create_pg_interfaces(range(4))
2057 mpls_tbl = VppMplsTable(self, 0)
2058 mpls_tbl.add_vpp_config()
2059 tbl4 = VppIpTable(self, 1)
2060 tbl4.add_vpp_config()
2061 tbl6 = VppIpTable(self, 1, is_ip6=1)
2062 tbl6.add_vpp_config()
2066 self.pg0.config_ip4()
2067 self.pg0.resolve_arp()
2068 self.pg0.enable_mpls()
2071 self.pg1.config_ip4()
2072 self.pg1.resolve_arp()
2073 self.pg1.enable_mpls()
2075 # VRF (customer facing) link
2077 self.pg2.set_table_ip4(1)
2078 self.pg2.config_ip4()
2079 self.pg2.resolve_arp()
2080 self.pg2.set_table_ip6(1)
2081 self.pg2.config_ip6()
2082 self.pg2.resolve_ndp()
2085 self.pg3.set_table_ip4(1)
2086 self.pg3.config_ip4()
2087 self.pg3.resolve_arp()
2088 self.pg3.set_table_ip6(1)
2089 self.pg3.config_ip6()
2090 self.pg3.resolve_ndp()
2093 self.pg0.disable_mpls()
2094 self.pg1.disable_mpls()
2095 for i in self.pg_interfaces:
2101 super(TestMPLSPIC, self).tearDown()
2103 def test_mpls_ibgp_pic(self):
2104 """MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
2106 1) setup many iBGP VPN routes via a pair of iBGP peers.
2107 2) Check EMCP forwarding to these peers
2108 3) withdraw the IGP route to one of these peers.
2109 4) check forwarding continues to the remaining peer
2113 # IGP+LDP core routes
2115 core_10_0_0_45 = VppIpRoute(
2119 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[45])],
2121 core_10_0_0_45.add_vpp_config()
2123 core_10_0_0_46 = VppIpRoute(
2127 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[46])],
2129 core_10_0_0_46.add_vpp_config()
2132 # Lot's of VPN routes. We need more the 64 so VPP will build
2133 # the fast convergence indirection
2137 for ii in range(NUM_PKTS):
2138 dst = "192.168.1.%d" % ii
2149 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST,
2155 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST,
2161 vpn_routes[ii].add_vpp_config()
2164 Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac)
2165 / IP(src=self.pg2.remote_ip4, dst=dst)
2166 / UDP(sport=1234, dport=1234)
2167 / Raw(b"\xa5" * 100)
2171 # Send the packet stream (one pkt to each VPN route)
2172 # - expect a 50-50 split of the traffic
2174 self.pg2.add_stream(pkts)
2175 self.pg_enable_capture(self.pg_interfaces)
2178 rx0 = self.pg0._get_capture(NUM_PKTS)
2179 rx1 = self.pg1._get_capture(NUM_PKTS)
2181 # not testing the LB hashing algorithm so we're not concerned
2182 # with the split ratio, just as long as neither is 0
2183 self.assertNotEqual(0, len(rx0))
2184 self.assertNotEqual(0, len(rx1))
2187 len(rx0) + len(rx1),
2188 "Expected all (%s) packets across both ECMP paths. "
2189 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2193 # use a test CLI command to stop the FIB walk process, this
2194 # will prevent the FIB converging the VPN routes and thus allow
2195 # us to probe the interim (post-fail, pre-converge) state
2197 self.vapi.ppcli("test fib-walk-process disable")
2200 # Withdraw one of the IGP routes
2202 core_10_0_0_46.remove_vpp_config()
2205 # now all packets should be forwarded through the remaining peer
2207 self.vapi.ppcli("clear trace")
2208 self.pg2.add_stream(pkts)
2209 self.pg_enable_capture(self.pg_interfaces)
2212 rx0 = self.pg0.get_capture(NUM_PKTS)
2216 "Expected all (%s) packets across single path. "
2217 "rx0: %s." % (len(pkts), len(rx0)),
2221 # enable the FIB walk process to converge the FIB
2223 self.vapi.ppcli("test fib-walk-process enable")
2226 # packets should still be forwarded through the remaining peer
2228 self.pg2.add_stream(pkts)
2229 self.pg_enable_capture(self.pg_interfaces)
2232 rx0 = self.pg0.get_capture(NUM_PKTS)
2236 "Expected all (%s) packets across single path. "
2237 "rx0: %s." % (len(pkts), len(rx0)),
2241 # Add the IGP route back and we return to load-balancing
2243 core_10_0_0_46.add_vpp_config()
2245 self.pg2.add_stream(pkts)
2246 self.pg_enable_capture(self.pg_interfaces)
2249 rx0 = self.pg0._get_capture(NUM_PKTS)
2250 rx1 = self.pg1._get_capture(NUM_PKTS)
2251 self.assertNotEqual(0, len(rx0))
2252 self.assertNotEqual(0, len(rx1))
2255 len(rx0) + len(rx1),
2256 "Expected all (%s) packets across both ECMP paths. "
2257 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2260 def test_mpls_ebgp_pic(self):
2261 """MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
2263 1) setup many eBGP VPN routes via a pair of eBGP peers.
2264 2) Check EMCP forwarding to these peers
2265 3) withdraw one eBGP path - expect LB across remaining eBGP
2269 # Lot's of VPN routes. We need more the 64 so VPP will build
2270 # the fast convergence indirection
2275 for ii in range(NUM_PKTS):
2276 dst = "192.168.1.%d" % ii
2277 local_label = 1600 + ii
2285 self.pg2.remote_ip4,
2288 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2291 self.pg3.remote_ip4,
2294 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2300 vpn_routes[ii].add_vpp_config()
2302 vpn_bindings.append(
2303 VppMplsIpBind(self, local_label, dst, 32, ip_table_id=1)
2305 vpn_bindings[ii].add_vpp_config()
2308 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2309 / MPLS(label=local_label, ttl=64)
2310 / IP(src=self.pg0.remote_ip4, dst=dst)
2311 / UDP(sport=1234, dport=1234)
2312 / Raw(b"\xa5" * 100)
2316 # Send the packet stream (one pkt to each VPN route)
2317 # - expect a 50-50 split of the traffic
2319 self.pg0.add_stream(pkts)
2320 self.pg_enable_capture(self.pg_interfaces)
2323 rx0 = self.pg2._get_capture(NUM_PKTS)
2324 rx1 = self.pg3._get_capture(NUM_PKTS)
2326 # not testing the LB hashing algorithm so we're not concerned
2327 # with the split ratio, just as long as neither is 0
2328 self.assertNotEqual(0, len(rx0))
2329 self.assertNotEqual(0, len(rx1))
2332 len(rx0) + len(rx1),
2333 "Expected all (%s) packets across both ECMP paths. "
2334 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2338 # use a test CLI command to stop the FIB walk process, this
2339 # will prevent the FIB converging the VPN routes and thus allow
2340 # us to probe the interim (post-fail, pre-converge) state
2342 self.vapi.ppcli("test fib-walk-process disable")
2345 # withdraw the connected prefix on the interface.
2347 self.pg2.unconfig_ip4()
2350 # now all packets should be forwarded through the remaining peer
2352 self.pg0.add_stream(pkts)
2353 self.pg_enable_capture(self.pg_interfaces)
2356 rx0 = self.pg3.get_capture(NUM_PKTS)
2360 "Expected all (%s) packets across single path. "
2361 "rx0: %s." % (len(pkts), len(rx0)),
2365 # enable the FIB walk process to converge the FIB
2367 self.vapi.ppcli("test fib-walk-process enable")
2370 # packets should still be forwarded through the remaining peer
2372 self.pg0.add_stream(pkts)
2373 self.pg_enable_capture(self.pg_interfaces)
2376 rx0 = self.pg3.get_capture(NUM_PKTS)
2380 "Expected all (%s) packets across single path. "
2381 "rx0: %s." % (len(pkts), len(rx0)),
2385 # put the connected routes back
2387 self.pg2.config_ip4()
2388 self.pg2.resolve_arp()
2390 self.pg0.add_stream(pkts)
2391 self.pg_enable_capture(self.pg_interfaces)
2394 rx0 = self.pg2._get_capture(NUM_PKTS)
2395 rx1 = self.pg3._get_capture(NUM_PKTS)
2396 self.assertNotEqual(0, len(rx0))
2397 self.assertNotEqual(0, len(rx1))
2400 len(rx0) + len(rx1),
2401 "Expected all (%s) packets across both ECMP paths. "
2402 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2405 def test_mpls_v6_ebgp_pic(self):
2406 """MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
2408 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
2409 2) Check EMCP forwarding to these peers
2410 3) withdraw one eBGP path - expect LB across remaining eBGP
2414 # Lot's of VPN routes. We need more the 64 so VPP will build
2415 # the fast convergence indirection
2420 for ii in range(NUM_PKTS):
2421 dst = "3000::%d" % ii
2422 local_label = 1600 + ii
2430 self.pg2.remote_ip6,
2433 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2436 self.pg3.remote_ip6,
2439 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2445 vpn_routes[ii].add_vpp_config()
2447 vpn_bindings.append(
2448 VppMplsIpBind(self, local_label, dst, 128, ip_table_id=1)
2450 vpn_bindings[ii].add_vpp_config()
2453 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2454 / MPLS(label=local_label, ttl=64)
2455 / IPv6(src=self.pg0.remote_ip6, dst=dst)
2456 / UDP(sport=1234, dport=1234)
2457 / Raw(b"\xa5" * 100)
2459 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2461 self.pg0.add_stream(pkts)
2462 self.pg_enable_capture(self.pg_interfaces)
2465 rx0 = self.pg2._get_capture(NUM_PKTS)
2466 rx1 = self.pg3._get_capture(NUM_PKTS)
2467 self.assertNotEqual(0, len(rx0))
2468 self.assertNotEqual(0, len(rx1))
2471 len(rx0) + len(rx1),
2472 "Expected all (%s) packets across both ECMP paths. "
2473 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2477 # use a test CLI command to stop the FIB walk process, this
2478 # will prevent the FIB converging the VPN routes and thus allow
2479 # us to probe the interim (post-fail, pre-converge) state
2481 self.vapi.ppcli("test fib-walk-process disable")
2484 # withdraw the connected prefix on the interface.
2485 # and shutdown the interface so the ND cache is flushed.
2487 self.pg2.unconfig_ip6()
2488 self.pg2.admin_down()
2491 # now all packets should be forwarded through the remaining peer
2493 self.pg0.add_stream(pkts)
2494 self.pg_enable_capture(self.pg_interfaces)
2497 rx0 = self.pg3.get_capture(NUM_PKTS)
2501 "Expected all (%s) packets across single path. "
2502 "rx0: %s." % (len(pkts), len(rx0)),
2506 # enable the FIB walk process to converge the FIB
2508 self.vapi.ppcli("test fib-walk-process enable")
2509 self.pg0.add_stream(pkts)
2510 self.pg_enable_capture(self.pg_interfaces)
2513 rx0 = self.pg3.get_capture(NUM_PKTS)
2517 "Expected all (%s) packets across single path. "
2518 "rx0: %s." % (len(pkts), len(rx0)),
2522 # put the connected routes back
2524 self.logger.info(self.vapi.cli("sh log"))
2526 self.pg2.config_ip6()
2527 self.pg2.resolve_ndp()
2529 self.pg0.add_stream(pkts)
2530 self.pg_enable_capture(self.pg_interfaces)
2533 rx0 = self.pg2._get_capture(NUM_PKTS)
2534 rx1 = self.pg3._get_capture(NUM_PKTS)
2535 self.assertNotEqual(0, len(rx0))
2536 self.assertNotEqual(0, len(rx1))
2539 len(rx0) + len(rx1),
2540 "Expected all (%s) packets across both ECMP paths. "
2541 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2545 class TestMPLSL2(VppTestCase):
2549 def setUpClass(cls):
2550 super(TestMPLSL2, cls).setUpClass()
2553 def tearDownClass(cls):
2554 super(TestMPLSL2, cls).tearDownClass()
2557 super(TestMPLSL2, self).setUp()
2559 # create 2 pg interfaces
2560 self.create_pg_interfaces(range(2))
2562 # create the default MPLS table
2564 tbl = VppMplsTable(self, 0)
2565 tbl.add_vpp_config()
2566 self.tables.append(tbl)
2568 # use pg0 as the core facing interface, don't resolve ARP
2570 self.pg0.config_ip4()
2571 self.pg0.enable_mpls()
2573 # use the other 2 for customer facing L2 links
2574 for i in self.pg_interfaces[1:]:
2578 for i in self.pg_interfaces[1:]:
2581 self.pg0.disable_mpls()
2582 self.pg0.unconfig_ip4()
2583 self.pg0.admin_down()
2584 super(TestMPLSL2, self).tearDown()
2586 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2587 capture = verify_filter(capture, sent)
2589 self.assertEqual(len(capture), len(sent))
2591 for i in range(len(capture)):
2595 # the MPLS TTL is 255 since it enters a new tunnel
2596 verify_mpls_stack(self, rx, mpls_labels)
2599 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2601 self.assertEqual(rx_eth.src, tx_eth.src)
2602 self.assertEqual(rx_eth.dst, tx_eth.dst)
2604 def verify_arp_req(self, rx, smac, sip, dip):
2606 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2607 self.assertEqual(ether.src, smac)
2610 self.assertEqual(arp.hwtype, 1)
2611 self.assertEqual(arp.ptype, 0x800)
2612 self.assertEqual(arp.hwlen, 6)
2613 self.assertEqual(arp.plen, 4)
2614 self.assertEqual(arp.op, ARP.who_has)
2615 self.assertEqual(arp.hwsrc, smac)
2616 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2617 self.assertEqual(arp.psrc, sip)
2618 self.assertEqual(arp.pdst, dip)
2620 def test_vpws(self):
2621 """Virtual Private Wire Service"""
2624 # Create an MPLS tunnel that pushes 1 label
2625 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2626 # information is not in the packet, but we test it works anyway
2628 mpls_tun_1 = VppMPLSTunnelInterface(
2632 self.pg0.remote_ip4,
2633 self.pg0.sw_if_index,
2634 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)],
2639 mpls_tun_1.add_vpp_config()
2640 mpls_tun_1.admin_up()
2643 # Create a label entry to for 55 that does L2 input to the tunnel
2645 route_55_eos = VppMplsRoute(
2652 mpls_tun_1.sw_if_index,
2653 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2654 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2657 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2659 route_55_eos.add_vpp_config()
2662 # Cross-connect the tunnel with one of the customers L2 interfaces
2664 self.vapi.sw_interface_set_l2_xconnect(
2665 self.pg1.sw_if_index, mpls_tun_1.sw_if_index, enable=1
2667 self.vapi.sw_interface_set_l2_xconnect(
2668 mpls_tun_1.sw_if_index, self.pg1.sw_if_index, enable=1
2672 # inject a packet from the core
2675 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2676 / MPLS(label=55, ttl=64)
2677 / Ether(dst="00:00:de:ad:ba:be", src="00:00:de:ad:be:ef")
2678 / IP(src="10.10.10.10", dst="11.11.11.11")
2679 / UDP(sport=1234, dport=1234)
2680 / Raw(b"\xa5" * 100)
2683 tx0 = pcore * NUM_PKTS
2684 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2685 payload = pcore[MPLS].payload
2687 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2688 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2691 # Inject a packet from the customer/L2 side
2692 # there's no resolved ARP entry so the first packet we see should be
2695 tx1 = pcore[MPLS].payload
2696 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2698 self.verify_arp_req(
2699 rx1[0], self.pg0.local_mac, self.pg0.local_ip4, self.pg0.remote_ip4
2703 # resolve the ARP entries and send again
2705 self.pg0.resolve_arp()
2706 tx1 = pcore[MPLS].payload * NUM_PKTS
2707 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2709 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2711 def test_vpls(self):
2712 """Virtual Private LAN Service"""
2714 # we skipped this in the setup
2715 self.pg0.resolve_arp()
2718 # Create a L2 MPLS tunnels
2720 mpls_tun1 = VppMPLSTunnelInterface(
2724 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(42)]
2729 mpls_tun1.add_vpp_config()
2730 mpls_tun1.admin_up()
2732 mpls_tun2 = VppMPLSTunnelInterface(
2736 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(43)]
2741 mpls_tun2.add_vpp_config()
2742 mpls_tun2.admin_up()
2745 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2746 # the latter includes a Psuedo Wire Control Word
2748 route_55_eos = VppMplsRoute(
2755 mpls_tun1.sw_if_index,
2756 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2757 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2760 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2763 route_56_eos = VppMplsRoute(
2770 mpls_tun2.sw_if_index,
2771 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2772 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2773 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2776 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2780 route_56_eos.add_vpp_config()
2781 route_55_eos.add_vpp_config()
2783 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2786 # add to tunnel to the customers bridge-domain
2788 self.vapi.sw_interface_set_l2_bridge(
2789 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1
2791 self.vapi.sw_interface_set_l2_bridge(
2792 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1
2794 self.vapi.sw_interface_set_l2_bridge(
2795 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1
2799 # Packet from host on the customer interface to each host
2800 # reachable over the core, and vice-versa
2803 Ether(dst="00:00:de:ad:ba:b1", src="00:00:de:ad:be:ef")
2804 / IP(src="10.10.10.10", dst="11.11.11.11")
2805 / UDP(sport=1234, dport=1234)
2806 / Raw(b"\xa5" * 100)
2809 Ether(dst="00:00:de:ad:ba:b2", src="00:00:de:ad:be:ef")
2810 / IP(src="10.10.10.10", dst="11.11.11.12")
2811 / UDP(sport=1234, dport=1234)
2812 / Raw(b"\xa5" * 100)
2815 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2816 / MPLS(label=55, ttl=64)
2817 / Ether(src="00:00:de:ad:ba:b1", dst="00:00:de:ad:be:ef")
2818 / IP(dst="10.10.10.10", src="11.11.11.11")
2819 / UDP(sport=1234, dport=1234)
2820 / Raw(b"\xa5" * 100)
2823 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2824 / MPLS(label=56, ttl=64)
2826 / Ether(src="00:00:de:ad:ba:b2", dst="00:00:de:ad:be:ef") # PW CW
2827 / IP(dst="10.10.10.10", src="11.11.11.12")
2828 / UDP(sport=1234, dport=1234)
2829 / Raw(b"\xa5" * 100)
2833 # The BD is learning, so send in one of each packet to learn
2836 # 2 packets due to BD flooding
2837 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2838 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2840 # we've learnt this so expect it be be forwarded not flooded
2841 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2842 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2843 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2845 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2846 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2847 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2850 # now a stream in each direction from each host
2852 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2853 self.verify_capture_tunneled_ethernet(
2854 rx, p_cust1 * NUM_PKTS, [VppMplsLabel(42)]
2857 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2858 self.verify_capture_tunneled_ethernet(
2859 rx, p_cust2 * NUM_PKTS, [VppMplsLabel(43)]
2862 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2863 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2866 # remove interfaces from customers bridge-domain
2868 self.vapi.sw_interface_set_l2_bridge(
2869 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0
2871 self.vapi.sw_interface_set_l2_bridge(
2872 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0
2874 self.vapi.sw_interface_set_l2_bridge(
2875 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0
2879 if __name__ == "__main__":
2880 unittest.main(testRunner=VppTestRunner)