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(
1152 "/err/mpls-frag/can't fragment this packet"
1157 # a stream that matches the route for 1000::1/128
1158 # PG0 is in the default table
1160 tx = self.create_stream_ip6(self.pg0, "1000::1")
1161 for i in range(0, 257):
1162 self.extend_packet(tx[i], 10000)
1164 rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
1166 self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 9000 - 4)
1171 route_10_0_0_1.remove_vpp_config()
1173 def test_tunnel_pipe(self):
1174 """MPLS Tunnel Tests - Pipe"""
1177 # Create a tunnel with two out labels
1179 mpls_tun = VppMPLSTunnelInterface(
1183 self.pg0.remote_ip4,
1184 self.pg0.sw_if_index,
1185 labels=[VppMplsLabel(44), VppMplsLabel(46)],
1189 mpls_tun.add_vpp_config()
1193 # add an unlabelled route through the new tunnel
1195 route_10_0_0_3 = VppIpRoute(
1196 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1198 route_10_0_0_3.add_vpp_config()
1200 self.vapi.cli("clear trace")
1201 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1202 self.pg0.add_stream(tx)
1204 self.pg_enable_capture(self.pg_interfaces)
1207 rx = self.pg0.get_capture()
1208 self.verify_capture_tunneled_ip4(
1209 self.pg0, rx, tx, [VppMplsLabel(44), VppMplsLabel(46)]
1213 # add a labelled route through the new tunnel
1215 route_10_0_0_4 = VppIpRoute(
1219 [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index, labels=[33])],
1221 route_10_0_0_4.add_vpp_config()
1223 self.vapi.cli("clear trace")
1224 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1225 self.pg0.add_stream(tx)
1227 self.pg_enable_capture(self.pg_interfaces)
1230 rx = self.pg0.get_capture()
1231 self.verify_capture_tunneled_ip4(
1235 [VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(33, ttl=255)],
1239 # change tunnel's MTU to a low value
1241 mpls_tun.set_l3_mtu(1200)
1243 # send IP into the tunnel to be fragmented
1244 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", payload_size=1500)
1245 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx) * 2)
1251 self.verify_capture_tunneled_ip4(
1252 self.pg0, rx, fake_tx, [VppMplsLabel(44), VppMplsLabel(46)]
1255 # send MPLS into the tunnel to be fragmented
1256 tx = self.create_stream_ip4(self.pg0, "10.0.0.4", payload_size=1500)
1257 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx) * 2)
1263 self.verify_capture_tunneled_ip4(
1267 [VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(33, ttl=255)],
1270 def test_tunnel_uniform(self):
1271 """MPLS Tunnel Tests - Uniform"""
1274 # Create a tunnel with a single out label
1275 # The label stack is specified here from outer to inner
1277 mpls_tun = VppMPLSTunnelInterface(
1281 self.pg0.remote_ip4,
1282 self.pg0.sw_if_index,
1284 VppMplsLabel(44, ttl=32),
1285 VppMplsLabel(46, MplsLspMode.UNIFORM),
1290 mpls_tun.add_vpp_config()
1294 # add an unlabelled route through the new tunnel
1296 route_10_0_0_3 = VppIpRoute(
1297 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1299 route_10_0_0_3.add_vpp_config()
1301 self.vapi.cli("clear trace")
1302 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1303 self.pg0.add_stream(tx)
1305 self.pg_enable_capture(self.pg_interfaces)
1308 rx = self.pg0.get_capture()
1309 self.verify_capture_tunneled_ip4(
1310 self.pg0, rx, tx, [VppMplsLabel(44, ttl=32), VppMplsLabel(46, ttl=23)]
1314 # add a labelled route through the new tunnel
1316 route_10_0_0_4 = VppIpRoute(
1322 "0.0.0.0", mpls_tun._sw_if_index, labels=[VppMplsLabel(33, ttl=47)]
1326 route_10_0_0_4.add_vpp_config()
1328 self.vapi.cli("clear trace")
1329 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1330 self.pg0.add_stream(tx)
1332 self.pg_enable_capture(self.pg_interfaces)
1335 rx = self.pg0.get_capture()
1336 self.verify_capture_tunneled_ip4(
1341 VppMplsLabel(44, ttl=32),
1342 VppMplsLabel(46, ttl=47),
1343 VppMplsLabel(33, ttl=47),
1347 def test_mpls_tunnel_many(self):
1348 """MPLS Multiple Tunnels"""
1350 for ii in range(100):
1351 mpls_tun = VppMPLSTunnelInterface(
1355 self.pg0.remote_ip4,
1356 self.pg0.sw_if_index,
1358 VppMplsLabel(44, ttl=32),
1359 VppMplsLabel(46, MplsLspMode.UNIFORM),
1364 mpls_tun.add_vpp_config()
1366 for ii in range(100):
1367 mpls_tun = VppMPLSTunnelInterface(
1371 self.pg0.remote_ip4,
1372 self.pg0.sw_if_index,
1374 VppMplsLabel(44, ttl=32),
1375 VppMplsLabel(46, MplsLspMode.UNIFORM),
1381 mpls_tun.add_vpp_config()
1384 def test_v4_exp_null(self):
1385 """MPLS V4 Explicit NULL test"""
1388 # The first test case has an MPLS TTL of 0
1389 # all packet should be dropped
1391 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0, ttl=0)])
1392 self.send_and_assert_no_replies(self.pg0, tx, "MPLS TTL=0 packets forwarded")
1395 # a stream with a non-zero MPLS TTL
1396 # PG0 is in the default table
1398 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1399 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1400 self.verify_capture_ip4(self.pg0, rx, tx)
1403 # a stream with a non-zero MPLS TTL
1405 # we are ensuring the post-pop lookup occurs in the VRF table
1407 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1408 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1409 self.verify_capture_ip4(self.pg1, rx, tx)
1411 def test_v6_exp_null(self):
1412 """MPLS V6 Explicit NULL test"""
1415 # a stream with a non-zero MPLS TTL
1416 # PG0 is in the default table
1418 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1419 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1420 self.verify_capture_ip6(self.pg0, rx, tx)
1423 # a stream with a non-zero MPLS TTL
1425 # we are ensuring the post-pop lookup occurs in the VRF table
1427 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1428 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1429 self.verify_capture_ip6(self.pg0, rx, tx)
1431 def test_deag(self):
1435 # A de-agg route - next-hop lookup in default table
1437 route_34_eos = VppMplsRoute(
1438 self, 34, 1, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)]
1440 route_34_eos.add_vpp_config()
1443 # ping an interface in the default table
1444 # PG0 is in the default table
1446 tx = self.create_stream_labelled_ip4(
1447 self.pg0, [VppMplsLabel(34)], ping=1, ip_itf=self.pg0
1449 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1450 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1453 # A de-agg route - next-hop lookup in non-default table
1455 route_35_eos = VppMplsRoute(
1456 self, 35, 1, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)]
1458 route_35_eos.add_vpp_config()
1459 route_356_eos = VppMplsRoute(
1463 [VppRoutePath("0::0", 0xFFFFFFFF, nh_table_id=1)],
1464 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1466 route_356_eos.add_vpp_config()
1469 # ping an interface in the non-default table
1470 # PG0 is in the default table. packet arrive labelled in the
1471 # default table and egress unlabelled in the non-default
1473 tx = self.create_stream_labelled_ip4(
1474 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1
1476 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1477 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1478 tx = self.create_stream_labelled_ip6(
1479 self.pg0, [VppMplsLabel(356)], ping=1, ip_itf=self.pg1
1481 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1482 self.verify_capture_ip6(self.pg1, rx, tx, ping_resp=1)
1487 route_36_neos = VppMplsRoute(self, 36, 0, [VppRoutePath("0.0.0.0", 0xFFFFFFFF)])
1488 route_36_neos.add_vpp_config()
1490 tx = self.create_stream_labelled_ip4(
1491 self.pg0, [VppMplsLabel(36), VppMplsLabel(35)], ping=1, ip_itf=self.pg1
1493 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1494 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1496 route_36_neos.remove_vpp_config()
1497 route_35_eos.remove_vpp_config()
1498 route_34_eos.remove_vpp_config()
1500 def test_interface_rx(self):
1501 """MPLS Interface Receive"""
1504 # Add a non-recursive route that will forward the traffic
1507 route_10_0_0_1 = VppIpRoute(
1512 paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
1514 route_10_0_0_1.add_vpp_config()
1517 # An interface receive label that maps traffic to RX on interface
1519 # by injecting the packet in on pg0, which is in table 0
1520 # doing an interface-rx on pg1 and matching a route in table 1
1521 # if the packet egresses, then we must have swapped to pg1
1522 # so as to have matched the route in table 1
1524 route_34_eos = VppMplsRoute(
1531 self.pg1.sw_if_index,
1532 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
1536 route_34_eos.add_vpp_config()
1539 # ping an interface in the default table
1540 # PG0 is in the default table
1542 tx = self.create_stream_labelled_ip4(
1543 self.pg0, [VppMplsLabel(34)], dst_ip="10.0.0.1"
1545 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1546 self.verify_capture_ip4(self.pg1, rx, tx)
1548 def test_mcast_mid_point(self):
1549 """MPLS Multicast Mid Point"""
1552 # Add a non-recursive route that will forward the traffic
1555 route_10_0_0_1 = VppIpRoute(
1560 paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
1562 route_10_0_0_1.add_vpp_config()
1565 # Add a mcast entry that replicate to pg2 and pg3
1566 # and replicate to a interface-rx (like a bud node would)
1568 route_3400_eos = VppMplsRoute(
1574 self.pg2.remote_ip4,
1575 self.pg2.sw_if_index,
1576 labels=[VppMplsLabel(3401)],
1579 self.pg3.remote_ip4,
1580 self.pg3.sw_if_index,
1581 labels=[VppMplsLabel(3402)],
1585 self.pg1.sw_if_index,
1586 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
1591 route_3400_eos.add_vpp_config()
1594 # ping an interface in the default table
1595 # PG0 is in the default table
1597 self.vapi.cli("clear trace")
1598 tx = self.create_stream_labelled_ip4(
1599 self.pg0, [VppMplsLabel(3400, ttl=64)], n=257, dst_ip="10.0.0.1"
1601 self.pg0.add_stream(tx)
1603 self.pg_enable_capture(self.pg_interfaces)
1606 rx = self.pg1.get_capture(257)
1607 self.verify_capture_ip4(self.pg1, rx, tx)
1609 rx = self.pg2.get_capture(257)
1610 self.verify_capture_labelled(self.pg2, rx, tx, [VppMplsLabel(3401, ttl=63)])
1611 rx = self.pg3.get_capture(257)
1612 self.verify_capture_labelled(self.pg3, rx, tx, [VppMplsLabel(3402, ttl=63)])
1614 def test_mcast_head(self):
1615 """MPLS Multicast Head-end"""
1617 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1618 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1621 # Create a multicast tunnel with two replications
1623 mpls_tun = VppMPLSTunnelInterface(
1627 self.pg2.remote_ip4, self.pg2.sw_if_index, labels=[VppMplsLabel(42)]
1630 self.pg3.remote_ip4, self.pg3.sw_if_index, labels=[VppMplsLabel(43)]
1635 mpls_tun.add_vpp_config()
1639 # add an unlabelled route through the new tunnel
1641 route_10_0_0_3 = VppIpRoute(
1642 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1644 route_10_0_0_3.add_vpp_config()
1646 self.vapi.cli("clear trace")
1647 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1648 self.pg0.add_stream(tx)
1650 self.pg_enable_capture(self.pg_interfaces)
1653 rx = self.pg2.get_capture(257)
1654 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1655 rx = self.pg3.get_capture(257)
1656 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1659 # An an IP multicast route via the tunnel
1661 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1663 route_232_1_1_1 = VppIpMRoute(
1668 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1671 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1674 mpls_tun._sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1678 route_232_1_1_1.add_vpp_config()
1679 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1681 self.vapi.cli("clear trace")
1682 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1683 self.pg0.add_stream(tx)
1685 self.pg_enable_capture(self.pg_interfaces)
1688 rx = self.pg2.get_capture(257)
1689 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1690 rx = self.pg3.get_capture(257)
1691 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1693 def test_mcast_ip4_tail(self):
1694 """MPLS IPv4 Multicast Tail"""
1696 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1697 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1700 # Add a multicast route that will forward the traffic
1703 route_232_1_1_1 = VppIpMRoute(
1708 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1712 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1716 route_232_1_1_1.add_vpp_config()
1719 # An interface receive label that maps traffic to RX on interface
1721 # by injecting the packet in on pg0, which is in table 0
1722 # doing an rpf-id and matching a route in table 1
1723 # if the packet egresses, then we must have matched the route in
1726 route_34_eos = VppMplsRoute(
1730 [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1, rpf_id=55)],
1732 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
1735 route_34_eos.add_vpp_config()
1738 # Drop due to interface lookup miss
1740 self.vapi.cli("clear trace")
1741 tx = self.create_stream_labelled_ip4(
1742 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1", n=1
1744 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1747 # set the RPF-ID of the entry to match the input packet's
1749 route_232_1_1_1.update_rpf_id(55)
1750 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1752 tx = self.create_stream_labelled_ip4(
1753 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1"
1755 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1756 self.verify_capture_ip4(self.pg1, rx, tx)
1759 # disposed packets have an invalid IPv4 checksum
1761 tx = self.create_stream_labelled_ip4(
1762 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1", n=65, chksum=1
1764 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1767 # set the RPF-ID of the entry to not match the input packet's
1769 route_232_1_1_1.update_rpf_id(56)
1770 tx = self.create_stream_labelled_ip4(
1771 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1"
1773 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1775 def test_mcast_ip6_tail(self):
1776 """MPLS IPv6 Multicast Tail"""
1778 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1779 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1782 # Add a multicast route that will forward the traffic
1785 route_ff = VppIpMRoute(
1790 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1794 self.pg1.sw_if_index,
1795 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1796 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1800 route_ff.add_vpp_config()
1803 # An interface receive label that maps traffic to RX on interface
1805 # by injecting the packet in on pg0, which is in table 0
1806 # doing an rpf-id and matching a route in table 1
1807 # if the packet egresses, then we must have matched the route in
1810 route_34_eos = VppMplsRoute(
1814 [VppRoutePath("::", 0xFFFFFFFF, nh_table_id=1, rpf_id=55)],
1816 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1819 route_34_eos.add_vpp_config()
1822 # Drop due to interface lookup miss
1824 tx = self.create_stream_labelled_ip6(
1825 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1827 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1830 # set the RPF-ID of the entry to match the input packet's
1832 route_ff.update_rpf_id(55)
1834 tx = self.create_stream_labelled_ip6(
1835 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1837 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1838 self.verify_capture_ip6(self.pg1, rx, tx)
1841 # disposed packets have hop-limit = 1
1843 tx = self.create_stream_labelled_ip6(
1844 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1", hlim=1
1846 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
1847 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1850 # set the RPF-ID of the entry to not match the input packet's
1852 route_ff.update_rpf_id(56)
1853 tx = self.create_stream_labelled_ip6(
1854 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1856 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1862 # Add a non-recursive route with a single out label
1864 route_10_0_0_1 = VppIpRoute(
1870 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(45)]
1874 route_10_0_0_1.add_vpp_config()
1876 # bind a local label to the route
1877 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1878 binding.add_vpp_config()
1881 # a labelled v6 route that resolves through the v4
1883 route_2001_3 = VppIpRoute(
1887 [VppRoutePath("10.0.0.1", INVALID_INDEX, labels=[VppMplsLabel(32)])],
1889 route_2001_3.add_vpp_config()
1891 tx = self.create_stream_ip6(self.pg0, "2001::3")
1892 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1894 self.verify_capture_labelled_ip6(
1895 self.pg0, rx, tx, [VppMplsLabel(45), VppMplsLabel(32)]
1899 # and a v4 recursive via the v6
1901 route_20_3 = VppIpRoute(
1905 [VppRoutePath("2001::3", INVALID_INDEX, labels=[VppMplsLabel(99)])],
1907 route_20_3.add_vpp_config()
1909 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1910 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1912 self.verify_capture_labelled_ip4(
1913 self.pg0, rx, tx, [VppMplsLabel(45), VppMplsLabel(32), VppMplsLabel(99)]
1916 def test_attached(self):
1917 """Attach Routes with Local Label"""
1920 # test that if a local label is associated with an attached/connected
1921 # prefix, that we can reach hosts in the prefix.
1923 binding = VppMplsIpBind(
1924 self, 44, self.pg0._local_ip4_subnet, self.pg0.local_ip4_prefix_len
1926 binding.add_vpp_config()
1929 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1930 / MPLS(label=44, ttl=64)
1931 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
1932 / UDP(sport=1234, dport=1234)
1933 / Raw(b"\xa5" * 100)
1935 rxs = self.send_and_expect(self.pg0, [tx], self.pg0)
1937 # if there's an ARP then the label is linked to the glean
1939 self.assertFalse(rx.haslayer(ARP))
1940 # it should be unicasted to the host
1941 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1942 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1945 class TestMPLSDisabled(VppTestCase):
1949 def setUpClass(cls):
1950 super(TestMPLSDisabled, cls).setUpClass()
1953 def tearDownClass(cls):
1954 super(TestMPLSDisabled, cls).tearDownClass()
1957 super(TestMPLSDisabled, self).setUp()
1959 # create 2 pg interfaces
1960 self.create_pg_interfaces(range(2))
1962 self.tbl = VppMplsTable(self, 0)
1963 self.tbl.add_vpp_config()
1965 # PG0 is MPLS enabled
1967 self.pg0.config_ip4()
1968 self.pg0.resolve_arp()
1969 self.pg0.enable_mpls()
1971 # PG 1 is not MPLS enabled
1975 for i in self.pg_interfaces:
1979 self.pg0.disable_mpls()
1980 super(TestMPLSDisabled, self).tearDown()
1982 def test_mpls_disabled(self):
1985 self.logger.info(self.vapi.cli("show mpls interface"))
1986 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1987 self.logger.info(self.vapi.cli("show mpls interface pg0"))
1990 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1991 / MPLS(label=32, ttl=64)
1992 / IPv6(src="2001::1", dst=self.pg0.remote_ip6)
1993 / UDP(sport=1234, dport=1234)
1994 / Raw(b"\xa5" * 100)
1998 # A simple MPLS xconnect - eos label in label out
2000 route_32_eos = VppMplsRoute(
2004 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[33])],
2006 route_32_eos.add_vpp_config()
2009 # PG1 does not forward IP traffic
2011 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
2016 self.pg1.enable_mpls()
2018 self.logger.info(self.vapi.cli("show mpls interface"))
2019 self.logger.info(self.vapi.cli("show mpls interface pg1"))
2022 # Now we get packets through
2024 self.pg1.add_stream(tx)
2025 self.pg_enable_capture(self.pg_interfaces)
2028 rx = self.pg0.get_capture(1)
2033 self.pg1.disable_mpls()
2036 # PG1 does not forward IP traffic
2038 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
2039 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
2042 class TestMPLSPIC(VppTestCase):
2043 """MPLS Prefix-Independent Convergence (PIC) edge convergence"""
2046 def setUpClass(cls):
2047 super(TestMPLSPIC, cls).setUpClass()
2050 def tearDownClass(cls):
2051 super(TestMPLSPIC, cls).tearDownClass()
2054 super(TestMPLSPIC, self).setUp()
2056 # create 2 pg interfaces
2057 self.create_pg_interfaces(range(4))
2059 mpls_tbl = VppMplsTable(self, 0)
2060 mpls_tbl.add_vpp_config()
2061 tbl4 = VppIpTable(self, 1)
2062 tbl4.add_vpp_config()
2063 tbl6 = VppIpTable(self, 1, is_ip6=1)
2064 tbl6.add_vpp_config()
2068 self.pg0.config_ip4()
2069 self.pg0.resolve_arp()
2070 self.pg0.enable_mpls()
2073 self.pg1.config_ip4()
2074 self.pg1.resolve_arp()
2075 self.pg1.enable_mpls()
2077 # VRF (customer facing) link
2079 self.pg2.set_table_ip4(1)
2080 self.pg2.config_ip4()
2081 self.pg2.resolve_arp()
2082 self.pg2.set_table_ip6(1)
2083 self.pg2.config_ip6()
2084 self.pg2.resolve_ndp()
2087 self.pg3.set_table_ip4(1)
2088 self.pg3.config_ip4()
2089 self.pg3.resolve_arp()
2090 self.pg3.set_table_ip6(1)
2091 self.pg3.config_ip6()
2092 self.pg3.resolve_ndp()
2095 self.pg0.disable_mpls()
2096 self.pg1.disable_mpls()
2097 for i in self.pg_interfaces:
2103 super(TestMPLSPIC, self).tearDown()
2105 def test_mpls_ibgp_pic(self):
2106 """MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
2108 1) setup many iBGP VPN routes via a pair of iBGP peers.
2109 2) Check EMCP forwarding to these peers
2110 3) withdraw the IGP route to one of these peers.
2111 4) check forwarding continues to the remaining peer
2115 # IGP+LDP core routes
2117 core_10_0_0_45 = VppIpRoute(
2121 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[45])],
2123 core_10_0_0_45.add_vpp_config()
2125 core_10_0_0_46 = VppIpRoute(
2129 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[46])],
2131 core_10_0_0_46.add_vpp_config()
2134 # Lot's of VPN routes. We need more the 64 so VPP will build
2135 # the fast convergence indirection
2139 for ii in range(NUM_PKTS):
2140 dst = "192.168.1.%d" % ii
2151 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST,
2157 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST,
2163 vpn_routes[ii].add_vpp_config()
2166 Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac)
2167 / IP(src=self.pg2.remote_ip4, dst=dst)
2168 / UDP(sport=1234, dport=1234)
2169 / Raw(b"\xa5" * 100)
2173 # Send the packet stream (one pkt to each VPN route)
2174 # - expect a 50-50 split of the traffic
2176 self.pg2.add_stream(pkts)
2177 self.pg_enable_capture(self.pg_interfaces)
2180 rx0 = self.pg0._get_capture(NUM_PKTS)
2181 rx1 = self.pg1._get_capture(NUM_PKTS)
2183 # not testing the LB hashing algorithm so we're not concerned
2184 # with the split ratio, just as long as neither is 0
2185 self.assertNotEqual(0, len(rx0))
2186 self.assertNotEqual(0, len(rx1))
2189 len(rx0) + len(rx1),
2190 "Expected all (%s) packets across both ECMP paths. "
2191 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2195 # use a test CLI command to stop the FIB walk process, this
2196 # will prevent the FIB converging the VPN routes and thus allow
2197 # us to probe the interim (post-fail, pre-converge) state
2199 self.vapi.ppcli("test fib-walk-process disable")
2202 # Withdraw one of the IGP routes
2204 core_10_0_0_46.remove_vpp_config()
2207 # now all packets should be forwarded through the remaining peer
2209 self.vapi.ppcli("clear trace")
2210 self.pg2.add_stream(pkts)
2211 self.pg_enable_capture(self.pg_interfaces)
2214 rx0 = self.pg0.get_capture(NUM_PKTS)
2218 "Expected all (%s) packets across single path. "
2219 "rx0: %s." % (len(pkts), len(rx0)),
2223 # enable the FIB walk process to converge the FIB
2225 self.vapi.ppcli("test fib-walk-process enable")
2228 # packets should still be forwarded through the remaining peer
2230 self.pg2.add_stream(pkts)
2231 self.pg_enable_capture(self.pg_interfaces)
2234 rx0 = self.pg0.get_capture(NUM_PKTS)
2238 "Expected all (%s) packets across single path. "
2239 "rx0: %s." % (len(pkts), len(rx0)),
2243 # Add the IGP route back and we return to load-balancing
2245 core_10_0_0_46.add_vpp_config()
2247 self.pg2.add_stream(pkts)
2248 self.pg_enable_capture(self.pg_interfaces)
2251 rx0 = self.pg0._get_capture(NUM_PKTS)
2252 rx1 = self.pg1._get_capture(NUM_PKTS)
2253 self.assertNotEqual(0, len(rx0))
2254 self.assertNotEqual(0, len(rx1))
2257 len(rx0) + len(rx1),
2258 "Expected all (%s) packets across both ECMP paths. "
2259 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2262 def test_mpls_ebgp_pic(self):
2263 """MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
2265 1) setup many eBGP VPN routes via a pair of eBGP peers.
2266 2) Check EMCP forwarding to these peers
2267 3) withdraw one eBGP path - expect LB across remaining eBGP
2271 # Lot's of VPN routes. We need more the 64 so VPP will build
2272 # the fast convergence indirection
2277 for ii in range(NUM_PKTS):
2278 dst = "192.168.1.%d" % ii
2279 local_label = 1600 + ii
2287 self.pg2.remote_ip4,
2290 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2293 self.pg3.remote_ip4,
2296 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2302 vpn_routes[ii].add_vpp_config()
2304 vpn_bindings.append(
2305 VppMplsIpBind(self, local_label, dst, 32, ip_table_id=1)
2307 vpn_bindings[ii].add_vpp_config()
2310 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2311 / MPLS(label=local_label, ttl=64)
2312 / IP(src=self.pg0.remote_ip4, dst=dst)
2313 / UDP(sport=1234, dport=1234)
2314 / Raw(b"\xa5" * 100)
2318 # Send the packet stream (one pkt to each VPN route)
2319 # - expect a 50-50 split of the traffic
2321 self.pg0.add_stream(pkts)
2322 self.pg_enable_capture(self.pg_interfaces)
2325 rx0 = self.pg2._get_capture(NUM_PKTS)
2326 rx1 = self.pg3._get_capture(NUM_PKTS)
2328 # not testing the LB hashing algorithm so we're not concerned
2329 # with the split ratio, just as long as neither is 0
2330 self.assertNotEqual(0, len(rx0))
2331 self.assertNotEqual(0, len(rx1))
2334 len(rx0) + len(rx1),
2335 "Expected all (%s) packets across both ECMP paths. "
2336 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2340 # use a test CLI command to stop the FIB walk process, this
2341 # will prevent the FIB converging the VPN routes and thus allow
2342 # us to probe the interim (post-fail, pre-converge) state
2344 self.vapi.ppcli("test fib-walk-process disable")
2347 # withdraw the connected prefix on the interface.
2349 self.pg2.unconfig_ip4()
2352 # now all packets should be forwarded through the remaining peer
2354 self.pg0.add_stream(pkts)
2355 self.pg_enable_capture(self.pg_interfaces)
2358 rx0 = self.pg3.get_capture(NUM_PKTS)
2362 "Expected all (%s) packets across single path. "
2363 "rx0: %s." % (len(pkts), len(rx0)),
2367 # enable the FIB walk process to converge the FIB
2369 self.vapi.ppcli("test fib-walk-process enable")
2372 # packets should still be forwarded through the remaining peer
2374 self.pg0.add_stream(pkts)
2375 self.pg_enable_capture(self.pg_interfaces)
2378 rx0 = self.pg3.get_capture(NUM_PKTS)
2382 "Expected all (%s) packets across single path. "
2383 "rx0: %s." % (len(pkts), len(rx0)),
2387 # put the connected routes back
2389 self.pg2.config_ip4()
2390 self.pg2.resolve_arp()
2392 self.pg0.add_stream(pkts)
2393 self.pg_enable_capture(self.pg_interfaces)
2396 rx0 = self.pg2._get_capture(NUM_PKTS)
2397 rx1 = self.pg3._get_capture(NUM_PKTS)
2398 self.assertNotEqual(0, len(rx0))
2399 self.assertNotEqual(0, len(rx1))
2402 len(rx0) + len(rx1),
2403 "Expected all (%s) packets across both ECMP paths. "
2404 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2407 def test_mpls_v6_ebgp_pic(self):
2408 """MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
2410 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
2411 2) Check EMCP forwarding to these peers
2412 3) withdraw one eBGP path - expect LB across remaining eBGP
2416 # Lot's of VPN routes. We need more the 64 so VPP will build
2417 # the fast convergence indirection
2422 for ii in range(NUM_PKTS):
2423 dst = "3000::%d" % ii
2424 local_label = 1600 + ii
2432 self.pg2.remote_ip6,
2435 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2438 self.pg3.remote_ip6,
2441 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2447 vpn_routes[ii].add_vpp_config()
2449 vpn_bindings.append(
2450 VppMplsIpBind(self, local_label, dst, 128, ip_table_id=1)
2452 vpn_bindings[ii].add_vpp_config()
2455 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2456 / MPLS(label=local_label, ttl=64)
2457 / IPv6(src=self.pg0.remote_ip6, dst=dst)
2458 / UDP(sport=1234, dport=1234)
2459 / Raw(b"\xa5" * 100)
2461 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2463 self.pg0.add_stream(pkts)
2464 self.pg_enable_capture(self.pg_interfaces)
2467 rx0 = self.pg2._get_capture(NUM_PKTS)
2468 rx1 = self.pg3._get_capture(NUM_PKTS)
2469 self.assertNotEqual(0, len(rx0))
2470 self.assertNotEqual(0, len(rx1))
2473 len(rx0) + len(rx1),
2474 "Expected all (%s) packets across both ECMP paths. "
2475 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2479 # use a test CLI command to stop the FIB walk process, this
2480 # will prevent the FIB converging the VPN routes and thus allow
2481 # us to probe the interim (post-fail, pre-converge) state
2483 self.vapi.ppcli("test fib-walk-process disable")
2486 # withdraw the connected prefix on the interface.
2487 # and shutdown the interface so the ND cache is flushed.
2489 self.pg2.unconfig_ip6()
2490 self.pg2.admin_down()
2493 # now all packets should be forwarded through the remaining peer
2495 self.pg0.add_stream(pkts)
2496 self.pg_enable_capture(self.pg_interfaces)
2499 rx0 = self.pg3.get_capture(NUM_PKTS)
2503 "Expected all (%s) packets across single path. "
2504 "rx0: %s." % (len(pkts), len(rx0)),
2508 # enable the FIB walk process to converge the FIB
2510 self.vapi.ppcli("test fib-walk-process enable")
2511 self.pg0.add_stream(pkts)
2512 self.pg_enable_capture(self.pg_interfaces)
2515 rx0 = self.pg3.get_capture(NUM_PKTS)
2519 "Expected all (%s) packets across single path. "
2520 "rx0: %s." % (len(pkts), len(rx0)),
2524 # put the connected routes back
2526 self.logger.info(self.vapi.cli("sh log"))
2528 self.pg2.config_ip6()
2529 self.pg2.resolve_ndp()
2531 self.pg0.add_stream(pkts)
2532 self.pg_enable_capture(self.pg_interfaces)
2535 rx0 = self.pg2._get_capture(NUM_PKTS)
2536 rx1 = self.pg3._get_capture(NUM_PKTS)
2537 self.assertNotEqual(0, len(rx0))
2538 self.assertNotEqual(0, len(rx1))
2541 len(rx0) + len(rx1),
2542 "Expected all (%s) packets across both ECMP paths. "
2543 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2547 class TestMPLSL2(VppTestCase):
2551 def setUpClass(cls):
2552 super(TestMPLSL2, cls).setUpClass()
2555 def tearDownClass(cls):
2556 super(TestMPLSL2, cls).tearDownClass()
2559 super(TestMPLSL2, self).setUp()
2561 # create 2 pg interfaces
2562 self.create_pg_interfaces(range(2))
2564 # create the default MPLS table
2566 tbl = VppMplsTable(self, 0)
2567 tbl.add_vpp_config()
2568 self.tables.append(tbl)
2570 # use pg0 as the core facing interface, don't resolve ARP
2572 self.pg0.config_ip4()
2573 self.pg0.enable_mpls()
2575 # use the other 2 for customer facing L2 links
2576 for i in self.pg_interfaces[1:]:
2580 for i in self.pg_interfaces[1:]:
2583 self.pg0.disable_mpls()
2584 self.pg0.unconfig_ip4()
2585 self.pg0.admin_down()
2586 super(TestMPLSL2, self).tearDown()
2588 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2589 capture = verify_filter(capture, sent)
2591 self.assertEqual(len(capture), len(sent))
2593 for i in range(len(capture)):
2597 # the MPLS TTL is 255 since it enters a new tunnel
2598 verify_mpls_stack(self, rx, mpls_labels)
2601 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2603 self.assertEqual(rx_eth.src, tx_eth.src)
2604 self.assertEqual(rx_eth.dst, tx_eth.dst)
2606 def verify_arp_req(self, rx, smac, sip, dip):
2608 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2609 self.assertEqual(ether.src, smac)
2612 self.assertEqual(arp.hwtype, 1)
2613 self.assertEqual(arp.ptype, 0x800)
2614 self.assertEqual(arp.hwlen, 6)
2615 self.assertEqual(arp.plen, 4)
2616 self.assertEqual(arp.op, ARP.who_has)
2617 self.assertEqual(arp.hwsrc, smac)
2618 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2619 self.assertEqual(arp.psrc, sip)
2620 self.assertEqual(arp.pdst, dip)
2622 def test_vpws(self):
2623 """Virtual Private Wire Service"""
2626 # Create an MPLS tunnel that pushes 1 label
2627 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2628 # information is not in the packet, but we test it works anyway
2630 mpls_tun_1 = VppMPLSTunnelInterface(
2634 self.pg0.remote_ip4,
2635 self.pg0.sw_if_index,
2636 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)],
2641 mpls_tun_1.add_vpp_config()
2642 mpls_tun_1.admin_up()
2645 # Create a label entry to for 55 that does L2 input to the tunnel
2647 route_55_eos = VppMplsRoute(
2654 mpls_tun_1.sw_if_index,
2655 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2656 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2659 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2661 route_55_eos.add_vpp_config()
2664 # Cross-connect the tunnel with one of the customers L2 interfaces
2666 self.vapi.sw_interface_set_l2_xconnect(
2667 self.pg1.sw_if_index, mpls_tun_1.sw_if_index, enable=1
2669 self.vapi.sw_interface_set_l2_xconnect(
2670 mpls_tun_1.sw_if_index, self.pg1.sw_if_index, enable=1
2674 # inject a packet from the core
2677 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2678 / MPLS(label=55, ttl=64)
2679 / Ether(dst="00:00:de:ad:ba:be", src="00:00:de:ad:be:ef")
2680 / IP(src="10.10.10.10", dst="11.11.11.11")
2681 / UDP(sport=1234, dport=1234)
2682 / Raw(b"\xa5" * 100)
2685 tx0 = pcore * NUM_PKTS
2686 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2687 payload = pcore[MPLS].payload
2689 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2690 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2693 # Inject a packet from the customer/L2 side
2694 # there's no resolved ARP entry so the first packet we see should be
2697 tx1 = pcore[MPLS].payload
2698 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2700 self.verify_arp_req(
2701 rx1[0], self.pg0.local_mac, self.pg0.local_ip4, self.pg0.remote_ip4
2705 # resolve the ARP entries and send again
2707 self.pg0.resolve_arp()
2708 tx1 = pcore[MPLS].payload * NUM_PKTS
2709 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2711 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2713 def test_vpls(self):
2714 """Virtual Private LAN Service"""
2716 # we skipped this in the setup
2717 self.pg0.resolve_arp()
2720 # Create a L2 MPLS tunnels
2722 mpls_tun1 = VppMPLSTunnelInterface(
2726 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(42)]
2731 mpls_tun1.add_vpp_config()
2732 mpls_tun1.admin_up()
2734 mpls_tun2 = VppMPLSTunnelInterface(
2738 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(43)]
2743 mpls_tun2.add_vpp_config()
2744 mpls_tun2.admin_up()
2747 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2748 # the latter includes a Psuedo Wire Control Word
2750 route_55_eos = VppMplsRoute(
2757 mpls_tun1.sw_if_index,
2758 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2759 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2762 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2765 route_56_eos = VppMplsRoute(
2772 mpls_tun2.sw_if_index,
2773 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2774 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2775 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2778 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2782 route_56_eos.add_vpp_config()
2783 route_55_eos.add_vpp_config()
2785 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2788 # add to tunnel to the customers bridge-domain
2790 self.vapi.sw_interface_set_l2_bridge(
2791 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1
2793 self.vapi.sw_interface_set_l2_bridge(
2794 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1
2796 self.vapi.sw_interface_set_l2_bridge(
2797 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1
2801 # Packet from host on the customer interface to each host
2802 # reachable over the core, and vice-versa
2805 Ether(dst="00:00:de:ad:ba:b1", src="00:00:de:ad:be:ef")
2806 / IP(src="10.10.10.10", dst="11.11.11.11")
2807 / UDP(sport=1234, dport=1234)
2808 / Raw(b"\xa5" * 100)
2811 Ether(dst="00:00:de:ad:ba:b2", src="00:00:de:ad:be:ef")
2812 / IP(src="10.10.10.10", dst="11.11.11.12")
2813 / UDP(sport=1234, dport=1234)
2814 / Raw(b"\xa5" * 100)
2817 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2818 / MPLS(label=55, ttl=64)
2819 / Ether(src="00:00:de:ad:ba:b1", dst="00:00:de:ad:be:ef")
2820 / IP(dst="10.10.10.10", src="11.11.11.11")
2821 / UDP(sport=1234, dport=1234)
2822 / Raw(b"\xa5" * 100)
2825 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2826 / MPLS(label=56, ttl=64)
2828 / Ether(src="00:00:de:ad:ba:b2", dst="00:00:de:ad:be:ef") # PW CW
2829 / IP(dst="10.10.10.10", src="11.11.11.12")
2830 / UDP(sport=1234, dport=1234)
2831 / Raw(b"\xa5" * 100)
2835 # The BD is learning, so send in one of each packet to learn
2838 # 2 packets due to BD flooding
2839 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2840 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2842 # we've learnt this so expect it be be forwarded not flooded
2843 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2844 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2845 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2847 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2848 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2849 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2852 # now a stream in each direction from each host
2854 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2855 self.verify_capture_tunneled_ethernet(
2856 rx, p_cust1 * NUM_PKTS, [VppMplsLabel(42)]
2859 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2860 self.verify_capture_tunneled_ethernet(
2861 rx, p_cust2 * NUM_PKTS, [VppMplsLabel(43)]
2864 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2865 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2868 # remove interfaces from customers bridge-domain
2870 self.vapi.sw_interface_set_l2_bridge(
2871 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0
2873 self.vapi.sw_interface_set_l2_bridge(
2874 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0
2876 self.vapi.sw_interface_set_l2_bridge(
2877 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0
2881 if __name__ == "__main__":
2882 unittest.main(testRunner=VppTestRunner)