5 from framework import VppTestCase
6 from asfframework import VppTestRunner, tag_fixme_vpp_workers
7 from vpp_ip import INVALID_INDEX
8 from vpp_ip_route import (
26 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
27 from vpp_papi import VppEnum
30 from scapy.packet import Raw
31 from scapy.layers.l2 import Ether, ARP
32 from scapy.layers.inet import IP, UDP, ICMP, icmptypes, icmpcodes
33 from scapy.layers.inet6 import (
39 from scapy.contrib.mpls import MPLS
43 # scapy removed these attributes.
44 # we asked that they be restored: https://github.com/secdev/scapy/pull/1878
45 # semantic names have more meaning than numbers. so here they are.
50 def verify_filter(capture, sent):
51 if not len(capture) == len(sent):
52 # filter out any IPv6 RAs from the capture
59 def verify_mpls_stack(tst, rx, mpls_labels):
60 # the rx'd packet has the MPLS label popped
62 tst.assertEqual(eth.type, 0x8847)
66 for ii in range(len(mpls_labels)):
67 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
68 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
69 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
71 if ii == len(mpls_labels) - 1:
72 tst.assertEqual(rx_mpls.s, 1)
75 tst.assertEqual(rx_mpls.s, 0)
76 # pop the label to expose the next
77 rx_mpls = rx_mpls[MPLS].payload
80 @tag_fixme_vpp_workers
81 class TestMPLS(VppTestCase):
86 super(TestMPLS, cls).setUpClass()
89 def tearDownClass(cls):
90 super(TestMPLS, cls).tearDownClass()
93 super(TestMPLS, self).setUp()
95 # create 2 pg interfaces
96 self.create_pg_interfaces(range(4))
98 # setup both interfaces
99 # assign them different tables.
103 tbl = VppMplsTable(self, 0)
105 self.tables.append(tbl)
107 for i in self.pg_interfaces:
111 tbl = VppIpTable(self, table_id)
113 self.tables.append(tbl)
114 tbl = VppIpTable(self, table_id, is_ip6=1)
116 self.tables.append(tbl)
118 i.set_table_ip4(table_id)
119 i.set_table_ip6(table_id)
128 for i in self.pg_interfaces:
135 super(TestMPLS, self).tearDown()
137 # the default of 64 matches the IP packet TTL default
138 def create_stream_labelled_ip4(
149 self.reset_packet_infos()
151 for i in range(0, n):
152 info = self.create_packet_info(src_if, src_if)
153 payload = self.info_to_payload(info)
154 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
156 for ii in range(len(mpls_labels)):
158 label=mpls_labels[ii].value,
159 ttl=mpls_labels[ii].ttl,
160 cos=mpls_labels[ii].exp,
166 / IP(src=src_if.local_ip4, dst=src_if.remote_ip4, ttl=ip_ttl)
167 / UDP(sport=1234, dport=1234)
173 / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl)
174 / UDP(sport=1234, dport=1234)
180 / IP(src=ip_itf.remote_ip4, dst=ip_itf.local_ip4, ttl=ip_ttl)
185 p[IP].chksum = chksum
190 def create_stream_ip4(
191 self, src_if, dst_ip, ip_ttl=64, ip_dscp=0, payload_size=None, n=257
193 self.reset_packet_infos()
195 for i in range(0, n):
196 dst = dst_ip[i % len(dst_ip)] if isinstance(dst_ip, list) else dst_ip
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, 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, n=257):
212 self.reset_packet_infos()
214 for i in range(0, n):
215 dst = dst_ip[i % len(dst_ip)] if isinstance(dst_ip, list) else dst_ip
216 info = self.create_packet_info(src_if, src_if)
217 payload = self.info_to_payload(info)
219 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
220 / IPv6(src=src_if.remote_ip6, dst=dst, hlim=ip_ttl, tc=ip_dscp)
221 / UDP(sport=1234, dport=1234)
228 def create_stream_labelled_ip6(
229 self, src_if, mpls_labels, hlim=64, dst_ip=None, ping=0, ip_itf=None
232 dst_ip = src_if.remote_ip6
233 self.reset_packet_infos()
235 for i in range(0, 257):
236 info = self.create_packet_info(src_if, src_if)
237 payload = self.info_to_payload(info)
238 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
239 for l in mpls_labels:
240 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
244 IPv6(src=ip_itf.remote_ip6, dst=ip_itf.local_ip6)
245 / ICMPv6EchoRequest()
249 IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim)
250 / UDP(sport=1234, dport=1234)
257 def verify_capture_ip4(
258 self, src_if, capture, sent, ping_resp=0, ip_ttl=None, ip_dscp=0
261 capture = verify_filter(capture, sent)
263 self.assertEqual(len(capture), len(sent))
265 for i in range(len(capture)):
269 # the rx'd packet has the MPLS label popped
271 self.assertEqual(eth.type, 0x800)
277 self.assertEqual(rx_ip.src, tx_ip.src)
278 self.assertEqual(rx_ip.dst, tx_ip.dst)
279 self.assertEqual(rx_ip.tos, ip_dscp)
281 # IP processing post pop has decremented the TTL
282 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
284 self.assertEqual(rx_ip.ttl, ip_ttl)
286 self.assertEqual(rx_ip.src, tx_ip.dst)
287 self.assertEqual(rx_ip.dst, tx_ip.src)
292 def verify_capture_labelled_ip4(
293 self, src_if, capture, sent, mpls_labels, ip_ttl=None
296 capture = verify_filter(capture, sent)
298 self.assertEqual(len(capture), len(sent))
300 for i in range(len(capture)):
306 verify_mpls_stack(self, rx, mpls_labels)
308 self.assertEqual(rx_ip.src, tx_ip.src)
309 self.assertEqual(rx_ip.dst, tx_ip.dst)
311 # IP processing post pop has decremented the TTL
312 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
314 self.assertEqual(rx_ip.ttl, ip_ttl)
319 def verify_capture_labelled_ip6(
320 self, src_if, capture, sent, mpls_labels, ip_ttl=None
323 capture = verify_filter(capture, sent)
325 self.assertEqual(len(capture), len(sent))
327 for i in range(len(capture)):
333 verify_mpls_stack(self, rx, mpls_labels)
335 self.assertEqual(rx_ip.src, tx_ip.src)
336 self.assertEqual(rx_ip.dst, tx_ip.dst)
338 # IP processing post pop has decremented the TTL
339 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
341 self.assertEqual(rx_ip.hlim, ip_ttl)
346 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
348 capture = verify_filter(capture, sent)
350 self.assertEqual(len(capture), len(sent))
352 for i in range(len(capture)):
358 verify_mpls_stack(self, rx, mpls_labels)
360 self.assertEqual(rx_ip.src, tx_ip.src)
361 self.assertEqual(rx_ip.dst, tx_ip.dst)
362 # IP processing post pop has decremented the TTL
363 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
368 def verify_capture_labelled(self, src_if, capture, sent, mpls_labels):
370 capture = verify_filter(capture, sent)
372 self.assertEqual(len(capture), len(sent))
374 for i in range(len(capture)):
376 verify_mpls_stack(self, rx, mpls_labels)
380 def verify_capture_ip6(
381 self, src_if, capture, sent, ip_hlim=None, ip_dscp=0, ping_resp=0
384 self.assertEqual(len(capture), len(sent))
386 for i in range(len(capture)):
390 # the rx'd packet has the MPLS label popped
392 self.assertEqual(eth.type, 0x86DD)
398 self.assertEqual(rx_ip.src, tx_ip.src)
399 self.assertEqual(rx_ip.dst, tx_ip.dst)
400 self.assertEqual(rx_ip.tc, ip_dscp)
401 # IP processing post pop has decremented the TTL
403 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
405 self.assertEqual(rx_ip.hlim, ip_hlim)
407 self.assertEqual(rx_ip.src, tx_ip.dst)
408 self.assertEqual(rx_ip.dst, tx_ip.src)
412 def verify_capture_ip6_icmp(self, src_if, capture, sent):
415 self.assertTrue(len(capture) <= len(sent))
417 for i in range(len(capture)):
421 # the rx'd packet has the MPLS label popped
423 self.assertEqual(eth.type, 0x86DD)
428 self.assertEqual(rx_ip.dst, tx_ip.src)
429 # ICMP sourced from the interface's address
430 self.assertEqual(rx_ip.src, src_if.local_ip6)
431 # hop-limit reset to 255 for IMCP packet
432 self.assertEqual(rx_ip.hlim, 255)
434 icmp = rx[ICMPv6TimeExceeded]
439 def verify_capture_fragmented_labelled_ip4(
440 self, src_if, capture, sent, mpls_labels, ip_ttl=None
443 capture = verify_filter(capture, sent)
445 for i in range(len(capture)):
451 verify_mpls_stack(self, rx, mpls_labels)
453 self.assertEqual(rx_ip.src, tx_ip.src)
454 self.assertEqual(rx_ip.dst, tx_ip.dst)
456 # IP processing post pop has decremented the TTL
457 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
459 self.assertEqual(rx_ip.ttl, ip_ttl)
464 def verify_capture_fragmented_labelled_ip6(
465 self, src_if, capture, sent, mpls_labels, ip_ttl=None
468 capture = verify_filter(capture, sent)
470 for i in range(len(capture)):
475 rx_ip = IPv6(rx[MPLS].payload)
478 verify_mpls_stack(self, rx, mpls_labels)
480 self.assertEqual(rx_ip.src, tx_ip.src)
481 self.assertEqual(rx_ip.dst, tx_ip.dst)
483 # IP processing post pop has decremented the hop-limit
484 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
486 self.assertEqual(rx_ip.hlim, ip_ttl)
491 """MPLS label swap tests"""
494 # A simple MPLS xconnect - eos label in label out
496 route_32_eos = VppMplsRoute(
502 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(33)]
506 route_32_eos.add_vpp_config()
517 self.pg0.sw_if_index,
518 labels=[VppMplsLabel(33)],
525 # a stream that matches the route for 10.0.0.1
526 # PG0 is in the default table
528 tx = self.create_stream_labelled_ip4(
529 self.pg0, [VppMplsLabel(32, ttl=32, exp=1)]
531 rx = self.send_and_expect(self.pg0, tx, self.pg0)
532 self.verify_capture_labelled(
533 self.pg0, rx, tx, [VppMplsLabel(33, ttl=31, exp=1)]
536 self.assertEqual(route_32_eos.get_stats_to()["packets"], 257)
539 # A simple MPLS xconnect - non-eos label in label out
541 route_32_neos = VppMplsRoute(
547 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(33)]
551 route_32_neos.add_vpp_config()
554 # a stream that matches the route for 10.0.0.1
555 # PG0 is in the default table
557 tx = self.create_stream_labelled_ip4(
558 self.pg0, [VppMplsLabel(32, ttl=21, exp=7), VppMplsLabel(99)]
560 rx = self.send_and_expect(self.pg0, tx, self.pg0)
561 self.verify_capture_labelled(
562 self.pg0, rx, tx, [VppMplsLabel(33, ttl=20, exp=7), VppMplsLabel(99)]
564 self.assertEqual(route_32_neos.get_stats_to()["packets"], 257)
567 # A simple MPLS xconnect - non-eos label in label out, uniform mode
569 route_42_neos = VppMplsRoute(
576 self.pg0.sw_if_index,
577 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)],
581 route_42_neos.add_vpp_config()
583 tx = self.create_stream_labelled_ip4(
584 self.pg0, [VppMplsLabel(42, ttl=21, exp=7), VppMplsLabel(99)]
586 rx = self.send_and_expect(self.pg0, tx, self.pg0)
587 self.verify_capture_labelled(
588 self.pg0, rx, tx, [VppMplsLabel(43, ttl=20, exp=7), VppMplsLabel(99)]
592 # An MPLS xconnect - EOS label in IP out
594 route_33_eos = VppMplsRoute(
598 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[])],
600 route_33_eos.add_vpp_config()
602 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
603 rx = self.send_and_expect(self.pg0, tx, self.pg0)
604 self.verify_capture_ip4(self.pg0, rx, tx)
607 # disposed packets have an invalid IPv4 checksum
609 tx = self.create_stream_labelled_ip4(
610 self.pg0, [VppMplsLabel(33)], dst_ip=self.pg0.remote_ip4, n=65, chksum=1
612 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
615 # An MPLS xconnect - EOS label in IP out, uniform mode
617 route_3333_eos = VppMplsRoute(
624 self.pg0.sw_if_index,
625 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
629 route_3333_eos.add_vpp_config()
631 tx = self.create_stream_labelled_ip4(
632 self.pg0, [VppMplsLabel(3333, ttl=55, exp=3)]
634 rx = self.send_and_expect(self.pg0, tx, self.pg0)
635 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
636 tx = self.create_stream_labelled_ip4(
637 self.pg0, [VppMplsLabel(3333, ttl=66, exp=4)]
639 rx = self.send_and_expect(self.pg0, tx, self.pg0)
640 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
643 # An MPLS xconnect - EOS label in IPv6 out
645 route_333_eos = VppMplsRoute(
649 [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, labels=[])],
650 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
652 route_333_eos.add_vpp_config()
654 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
655 rx = self.send_and_expect(self.pg0, tx, self.pg0)
656 self.verify_capture_ip6(self.pg0, rx, tx)
659 # disposed packets have an TTL expired
661 tx = self.create_stream_labelled_ip6(
662 self.pg0, [VppMplsLabel(333, ttl=64)], dst_ip=self.pg1.remote_ip6, hlim=1
664 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
665 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
668 # An MPLS xconnect - EOS label in IPv6 out w imp-null
670 route_334_eos = VppMplsRoute(
676 self.pg0.remote_ip6, self.pg0.sw_if_index, labels=[VppMplsLabel(3)]
679 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
681 route_334_eos.add_vpp_config()
683 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334, ttl=64)])
684 rx = self.send_and_expect(self.pg0, tx, self.pg0)
685 self.verify_capture_ip6(self.pg0, rx, tx)
688 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
690 route_335_eos = VppMplsRoute(
697 self.pg0.sw_if_index,
698 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
701 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
703 route_335_eos.add_vpp_config()
705 tx = self.create_stream_labelled_ip6(
706 self.pg0, [VppMplsLabel(335, ttl=27, exp=4)]
708 rx = self.send_and_expect(self.pg0, tx, self.pg0)
709 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
712 # disposed packets have an TTL expired
714 tx = self.create_stream_labelled_ip6(
715 self.pg0, [VppMplsLabel(334)], dst_ip=self.pg1.remote_ip6, hlim=0
717 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
718 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
721 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
722 # so this traffic should be dropped.
724 route_33_neos = VppMplsRoute(
728 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[])],
730 route_33_neos.add_vpp_config()
732 tx = self.create_stream_labelled_ip4(
733 self.pg0, [VppMplsLabel(33), VppMplsLabel(99)]
735 self.send_and_assert_no_replies(
736 self.pg0, tx, "MPLS non-EOS packets popped and forwarded"
740 # A recursive EOS x-connect, which resolves through another x-connect
743 route_34_eos = VppMplsRoute(
752 labels=[VppMplsLabel(44), VppMplsLabel(45)],
756 route_34_eos.add_vpp_config()
757 self.logger.info(self.vapi.cli("sh mpls fib 34"))
759 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34, ttl=3)])
760 rx = self.send_and_expect(self.pg0, tx, self.pg0)
761 self.verify_capture_labelled(
765 [VppMplsLabel(33), VppMplsLabel(44), VppMplsLabel(45, ttl=2)],
768 self.assertEqual(route_34_eos.get_stats_to()["packets"], 257)
769 self.assertEqual(route_32_neos.get_stats_via()["packets"], 257)
772 # A recursive EOS x-connect, which resolves through another x-connect
775 route_35_eos = VppMplsRoute(
781 "0.0.0.0", 0xFFFFFFFF, nh_via_label=42, labels=[VppMplsLabel(44)]
785 route_35_eos.add_vpp_config()
787 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(35, ttl=3)])
788 rx = self.send_and_expect(self.pg0, tx, self.pg0)
789 self.verify_capture_labelled(
790 self.pg0, rx, tx, [VppMplsLabel(43, ttl=2), VppMplsLabel(44, ttl=2)]
794 # A recursive non-EOS x-connect, which resolves through another
797 route_34_neos = VppMplsRoute(
806 labels=[VppMplsLabel(44), VppMplsLabel(46)],
810 route_34_neos.add_vpp_config()
812 tx = self.create_stream_labelled_ip4(
813 self.pg0, [VppMplsLabel(34, ttl=45), VppMplsLabel(99)]
815 rx = self.send_and_expect(self.pg0, tx, self.pg0)
816 # it's the 2nd (counting from 0) label in the stack that is swapped
817 self.verify_capture_labelled(
824 VppMplsLabel(46, ttl=44),
830 # an recursive IP route that resolves through the recursive non-eos
833 ip_10_0_0_1 = VppIpRoute(
839 "0.0.0.0", 0xFFFFFFFF, nh_via_label=34, labels=[VppMplsLabel(55)]
843 ip_10_0_0_1.add_vpp_config()
845 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
846 rx = self.send_and_expect(self.pg0, tx, self.pg0)
847 self.verify_capture_labelled_ip4(
851 [VppMplsLabel(33), VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(55)],
853 self.assertEqual(ip_10_0_0_1.get_stats_to()["packets"], 257)
855 ip_10_0_0_1.remove_vpp_config()
856 route_34_neos.remove_vpp_config()
857 route_34_eos.remove_vpp_config()
858 route_33_neos.remove_vpp_config()
859 route_33_eos.remove_vpp_config()
860 route_32_neos.remove_vpp_config()
861 route_32_eos.remove_vpp_config()
864 """MPLS Local Label Binding test"""
867 # Add a non-recursive route with a single out label
869 route_10_0_0_1 = VppIpRoute(
875 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(45)]
879 route_10_0_0_1.add_vpp_config()
881 # bind a local label to the route
882 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
883 binding.add_vpp_config()
886 tx = self.create_stream_labelled_ip4(
887 self.pg0, [VppMplsLabel(44), VppMplsLabel(99)]
889 rx = self.send_and_expect(self.pg0, tx, self.pg0)
890 self.verify_capture_labelled(
891 self.pg0, rx, tx, [VppMplsLabel(45, ttl=63), VppMplsLabel(99)]
895 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
896 rx = self.send_and_expect(self.pg0, tx, self.pg0)
897 self.verify_capture_labelled(self.pg0, rx, tx, [VppMplsLabel(45, ttl=63)])
900 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
901 rx = self.send_and_expect(self.pg0, tx, self.pg0)
902 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
907 binding.remove_vpp_config()
908 route_10_0_0_1.remove_vpp_config()
910 def test_imposition(self):
911 """MPLS label imposition test"""
914 # Add a non-recursive route with a single out label
916 route_10_0_0_1 = VppIpRoute(
922 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(32)]
926 route_10_0_0_1.add_vpp_config()
929 # a stream that matches the route for 10.0.0.1
930 # PG0 is in the default table
932 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
933 rx = self.send_and_expect(self.pg0, tx, self.pg0)
934 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
937 # Add a non-recursive route with a 3 out labels
939 route_10_0_0_2 = VppIpRoute(
946 self.pg0.sw_if_index,
947 labels=[VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34)],
951 route_10_0_0_2.add_vpp_config()
953 tx = self.create_stream_ip4(self.pg0, "10.0.0.2", ip_ttl=44, ip_dscp=0xFF)
954 rx = self.send_and_expect(self.pg0, tx, self.pg0)
955 self.verify_capture_labelled_ip4(
959 [VppMplsLabel(32), VppMplsLabel(33), VppMplsLabel(34)],
964 # Add a non-recursive route with a single out label in uniform mode
966 route_10_0_0_3 = VppIpRoute(
973 self.pg0.sw_if_index,
974 labels=[VppMplsLabel(32, mode=MplsLspMode.UNIFORM)],
978 route_10_0_0_3.add_vpp_config()
980 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=54, ip_dscp=0xBE)
981 rx = self.send_and_expect(self.pg0, tx, self.pg0)
982 self.verify_capture_labelled_ip4(
983 self.pg0, rx, tx, [VppMplsLabel(32, ttl=53, exp=5)]
987 # Add a IPv6 non-recursive route with a single out label in
990 route_2001_3 = VppIpRoute(
997 self.pg0.sw_if_index,
998 labels=[VppMplsLabel(32, mode=MplsLspMode.UNIFORM)],
1002 route_2001_3.add_vpp_config()
1004 tx = self.create_stream_ip6(self.pg0, "2001::3", ip_ttl=54, ip_dscp=0xBE)
1005 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1006 self.verify_capture_labelled_ip6(
1007 self.pg0, rx, tx, [VppMplsLabel(32, ttl=53, exp=5)]
1011 # add a recursive path, with output label, via the 1 label route
1013 route_11_0_0_1 = VppIpRoute(
1017 [VppRoutePath("10.0.0.1", 0xFFFFFFFF, labels=[VppMplsLabel(44)])],
1019 route_11_0_0_1.add_vpp_config()
1022 # a stream that matches the route for 11.0.0.1, should pick up
1023 # the label stack for 11.0.0.1 and 10.0.0.1
1025 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
1026 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1027 self.verify_capture_labelled_ip4(
1028 self.pg0, rx, tx, [VppMplsLabel(32), VppMplsLabel(44)]
1031 self.assertEqual(route_11_0_0_1.get_stats_to()["packets"], 257)
1034 # add a recursive path, with 2 labels, via the 3 label route
1036 route_11_0_0_2 = VppIpRoute(
1042 "10.0.0.2", 0xFFFFFFFF, labels=[VppMplsLabel(44), VppMplsLabel(45)]
1046 route_11_0_0_2.add_vpp_config()
1049 # a stream that matches the route for 11.0.0.1, should pick up
1050 # the label stack for 11.0.0.1 and 10.0.0.1
1052 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
1053 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1054 self.verify_capture_labelled_ip4(
1067 self.assertEqual(route_11_0_0_2.get_stats_to()["packets"], 257)
1069 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1070 self.verify_capture_labelled_ip4(
1083 self.assertEqual(route_11_0_0_2.get_stats_to()["packets"], 514)
1088 route_11_0_0_2.remove_vpp_config()
1089 route_11_0_0_1.remove_vpp_config()
1090 route_10_0_0_2.remove_vpp_config()
1091 route_10_0_0_1.remove_vpp_config()
1093 def test_imposition_fragmentation(self):
1094 """MPLS label imposition fragmentation test"""
1097 # Add a ipv4 non-recursive route with a single out label
1099 route_10_0_0_1 = VppIpRoute(
1105 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(32)]
1109 route_10_0_0_1.add_vpp_config()
1110 route_1000_1 = VppIpRoute(
1116 self.pg0.remote_ip6, self.pg0.sw_if_index, labels=[VppMplsLabel(32)]
1120 route_1000_1.add_vpp_config()
1123 # a stream that matches the route for 10.0.0.1
1124 # PG0 is in the default table
1126 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
1127 for i in range(0, 257):
1128 self.extend_packet(tx[i], 10000)
1131 # 5 fragments per packet (257*5=1285)
1133 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
1134 self.verify_capture_fragmented_labelled_ip4(
1135 self.pg0, rx, tx, [VppMplsLabel(32)]
1138 # packets with DF bit set generate ICMP
1141 rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
1144 self.assertEqual(icmptypes[rx[ICMP].type], "dest-unreach")
1146 icmpcodes[rx[ICMP].type][rx[ICMP].code], "fragmentation-needed"
1148 # the link MTU is 9000, the MPLS over head is 4 bytes
1149 self.assertEqual(rx[ICMP].nexthopmtu, 9000 - 4)
1152 self.statistics.get_err_counter("/err/mpls-frag/dont_fragment_set"),
1156 # a stream that matches the route for 1000::1/128
1157 # PG0 is in the default table
1159 tx = self.create_stream_ip6(self.pg0, "1000::1")
1160 for i in range(0, 257):
1161 self.extend_packet(tx[i], 10000)
1163 rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
1165 self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 9000 - 4)
1170 route_10_0_0_1.remove_vpp_config()
1172 def test_tunnel_pipe(self):
1173 """MPLS Tunnel Tests - Pipe"""
1176 # Create a tunnel with two out labels
1178 mpls_tun = VppMPLSTunnelInterface(
1182 self.pg0.remote_ip4,
1183 self.pg0.sw_if_index,
1184 labels=[VppMplsLabel(44), VppMplsLabel(46)],
1188 mpls_tun.add_vpp_config()
1192 # add an unlabelled route through the new tunnel
1194 route_10_0_0_3 = VppIpRoute(
1195 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1197 route_10_0_0_3.add_vpp_config()
1199 self.vapi.cli("clear trace")
1200 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1201 self.pg0.add_stream(tx)
1203 self.pg_enable_capture(self.pg_interfaces)
1206 rx = self.pg0.get_capture()
1207 self.verify_capture_tunneled_ip4(
1208 self.pg0, rx, tx, [VppMplsLabel(44), VppMplsLabel(46)]
1212 # add a labelled route through the new tunnel
1214 route_10_0_0_4 = VppIpRoute(
1218 [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index, labels=[33])],
1220 route_10_0_0_4.add_vpp_config()
1222 self.vapi.cli("clear trace")
1223 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1224 self.pg0.add_stream(tx)
1226 self.pg_enable_capture(self.pg_interfaces)
1229 rx = self.pg0.get_capture()
1230 self.verify_capture_tunneled_ip4(
1234 [VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(33, ttl=255)],
1238 # change tunnel's MTU to a low value
1240 mpls_tun.set_l3_mtu(1200)
1242 # send IP into the tunnel to be fragmented
1243 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", payload_size=1500)
1244 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx) * 2)
1250 self.verify_capture_tunneled_ip4(
1251 self.pg0, rx, fake_tx, [VppMplsLabel(44), VppMplsLabel(46)]
1254 # send MPLS into the tunnel to be fragmented
1255 tx = self.create_stream_ip4(self.pg0, "10.0.0.4", payload_size=1500)
1256 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx) * 2)
1262 self.verify_capture_tunneled_ip4(
1266 [VppMplsLabel(44), VppMplsLabel(46), VppMplsLabel(33, ttl=255)],
1269 def test_tunnel_uniform(self):
1270 """MPLS Tunnel Tests - Uniform"""
1273 # Create a tunnel with a single out label
1274 # The label stack is specified here from outer to inner
1276 mpls_tun = VppMPLSTunnelInterface(
1280 self.pg0.remote_ip4,
1281 self.pg0.sw_if_index,
1283 VppMplsLabel(44, ttl=32),
1284 VppMplsLabel(46, MplsLspMode.UNIFORM),
1289 mpls_tun.add_vpp_config()
1293 # add an unlabelled route through the new tunnel
1295 route_10_0_0_3 = VppIpRoute(
1296 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1298 route_10_0_0_3.add_vpp_config()
1300 self.vapi.cli("clear trace")
1301 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1302 self.pg0.add_stream(tx)
1304 self.pg_enable_capture(self.pg_interfaces)
1307 rx = self.pg0.get_capture()
1308 self.verify_capture_tunneled_ip4(
1309 self.pg0, rx, tx, [VppMplsLabel(44, ttl=32), VppMplsLabel(46, ttl=23)]
1313 # add a labelled route through the new tunnel
1315 route_10_0_0_4 = VppIpRoute(
1321 "0.0.0.0", mpls_tun._sw_if_index, labels=[VppMplsLabel(33, ttl=47)]
1325 route_10_0_0_4.add_vpp_config()
1327 self.vapi.cli("clear trace")
1328 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1329 self.pg0.add_stream(tx)
1331 self.pg_enable_capture(self.pg_interfaces)
1334 rx = self.pg0.get_capture()
1335 self.verify_capture_tunneled_ip4(
1340 VppMplsLabel(44, ttl=32),
1341 VppMplsLabel(46, ttl=47),
1342 VppMplsLabel(33, ttl=47),
1346 def test_tunnel_ecmp(self):
1347 """MPLS Tunnel Tests - ECMP"""
1350 # Create a tunnel with multiple paths and labels
1352 self.pg0.generate_remote_hosts(2)
1353 self.pg0.configure_ipv4_neighbors()
1354 mpls_tun = VppMPLSTunnelInterface(
1358 self.pg0.remote_hosts[0].ip4,
1359 self.pg0.sw_if_index,
1360 labels=[VppMplsLabel(3)],
1363 self.pg0.remote_hosts[1].ip4,
1364 self.pg0.sw_if_index,
1365 labels=[VppMplsLabel(44)],
1369 mpls_tun.add_vpp_config()
1372 self.vapi.cli("clear trace")
1373 pkts = self.create_stream_ip4(
1374 self.pg0, ["10.0.0.%d" % i for i in range(NUM_PKTS)], n=NUM_PKTS
1377 def send_and_expect_mpls_lb(pkts, path_labels, min_ratio):
1378 self.pg0.add_stream(pkts)
1380 self.pg_enable_capture(self.pg_interfaces)
1383 rx = self.pg0.get_capture()
1388 self.assertEqual(eth.type, 0x8847)
1393 labels.append(mpls.label)
1396 mpls = mpls[MPLS].payload
1397 self.assertIn(labels, path_labels)
1399 key = "{}-{}".format(eth.dst, "-".join(str(i) for i in labels))
1400 paths[key] = paths.get(key, 0) + 1
1403 # Check distribution over multiple mpls paths
1405 self.assertEqual(len(paths), len(path_labels))
1406 for n in paths.values():
1407 self.assertGreaterEqual(n, NUM_PKTS / len(paths) * min_ratio)
1410 # Add labelled route through the new tunnel,
1411 # traffic should be balanced over all tunnel paths only.
1413 route_10_0_0_0 = VppIpRoute(
1417 [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index, labels=[33])],
1419 route_10_0_0_0.add_vpp_config()
1420 send_and_expect_mpls_lb(pkts, [[33], [44, 33]], 0.85)
1423 # Add labelled multipath route through the new tunnel,
1424 # traffic should be balanced over both paths first and
1425 # then over all tunnel paths.
1427 route_10_0_0_0 = VppIpRoute(
1432 VppRoutePath("0.0.0.1", mpls_tun._sw_if_index, labels=[33]),
1433 VppRoutePath("0.0.0.2", mpls_tun._sw_if_index, labels=[34]),
1436 route_10_0_0_0.add_vpp_config()
1437 send_and_expect_mpls_lb(pkts, [[33], [44, 33], [34], [44, 34]], 0.70)
1439 def test_mpls_tunnel_many(self):
1440 """MPLS Multiple Tunnels"""
1442 for ii in range(100):
1443 mpls_tun = VppMPLSTunnelInterface(
1447 self.pg0.remote_ip4,
1448 self.pg0.sw_if_index,
1450 VppMplsLabel(44, ttl=32),
1451 VppMplsLabel(46, MplsLspMode.UNIFORM),
1456 mpls_tun.add_vpp_config()
1458 for ii in range(100):
1459 mpls_tun = VppMPLSTunnelInterface(
1463 self.pg0.remote_ip4,
1464 self.pg0.sw_if_index,
1466 VppMplsLabel(44, ttl=32),
1467 VppMplsLabel(46, MplsLspMode.UNIFORM),
1473 mpls_tun.add_vpp_config()
1476 def test_v4_exp_null(self):
1477 """MPLS V4 Explicit NULL test"""
1480 # The first test case has an MPLS TTL of 0
1481 # all packet should be dropped
1483 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0, ttl=0)])
1484 self.send_and_assert_no_replies(self.pg0, tx, "MPLS TTL=0 packets forwarded")
1487 # a stream with a non-zero MPLS TTL
1488 # PG0 is in the default table
1490 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1491 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1492 self.verify_capture_ip4(self.pg0, rx, tx)
1495 # a stream with a non-zero MPLS TTL
1497 # we are ensuring the post-pop lookup occurs in the VRF table
1499 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1500 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1501 self.verify_capture_ip4(self.pg1, rx, tx)
1503 def test_v6_exp_null(self):
1504 """MPLS V6 Explicit NULL test"""
1507 # a stream with a non-zero MPLS TTL
1508 # PG0 is in the default table
1510 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1511 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1512 self.verify_capture_ip6(self.pg0, rx, tx)
1515 # a stream with a non-zero MPLS TTL
1517 # we are ensuring the post-pop lookup occurs in the VRF table
1519 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1520 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1521 self.verify_capture_ip6(self.pg0, rx, tx)
1523 def test_deag(self):
1527 # A de-agg route - next-hop lookup in default table
1529 route_34_eos = VppMplsRoute(
1530 self, 34, 1, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)]
1532 route_34_eos.add_vpp_config()
1535 # ping an interface in the default table
1536 # PG0 is in the default table
1538 tx = self.create_stream_labelled_ip4(
1539 self.pg0, [VppMplsLabel(34)], ping=1, ip_itf=self.pg0
1541 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1542 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1545 # A de-agg route - next-hop lookup in non-default table
1547 route_35_eos = VppMplsRoute(
1548 self, 35, 1, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)]
1550 route_35_eos.add_vpp_config()
1551 route_356_eos = VppMplsRoute(
1555 [VppRoutePath("0::0", 0xFFFFFFFF, nh_table_id=1)],
1556 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1558 route_356_eos.add_vpp_config()
1561 # ping an interface in the non-default table
1562 # PG0 is in the default table. packet arrive labelled in the
1563 # default table and egress unlabelled in the non-default
1565 tx = self.create_stream_labelled_ip4(
1566 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1
1568 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1569 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1570 tx = self.create_stream_labelled_ip6(
1571 self.pg0, [VppMplsLabel(356)], ping=1, ip_itf=self.pg1
1573 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1574 self.verify_capture_ip6(self.pg1, rx, tx, ping_resp=1)
1579 route_36_neos = VppMplsRoute(self, 36, 0, [VppRoutePath("0.0.0.0", 0xFFFFFFFF)])
1580 route_36_neos.add_vpp_config()
1582 tx = self.create_stream_labelled_ip4(
1583 self.pg0, [VppMplsLabel(36), VppMplsLabel(35)], ping=1, ip_itf=self.pg1
1585 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1586 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1588 route_36_neos.remove_vpp_config()
1589 route_35_eos.remove_vpp_config()
1590 route_34_eos.remove_vpp_config()
1592 def test_interface_rx(self):
1593 """MPLS Interface Receive"""
1596 # Add a non-recursive route that will forward the traffic
1599 route_10_0_0_1 = VppIpRoute(
1604 paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
1606 route_10_0_0_1.add_vpp_config()
1609 # An interface receive label that maps traffic to RX on interface
1611 # by injecting the packet in on pg0, which is in table 0
1612 # doing an interface-rx on pg1 and matching a route in table 1
1613 # if the packet egresses, then we must have swapped to pg1
1614 # so as to have matched the route in table 1
1616 route_34_eos = VppMplsRoute(
1623 self.pg1.sw_if_index,
1624 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
1628 route_34_eos.add_vpp_config()
1631 # ping an interface in the default table
1632 # PG0 is in the default table
1634 tx = self.create_stream_labelled_ip4(
1635 self.pg0, [VppMplsLabel(34)], dst_ip="10.0.0.1"
1637 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1638 self.verify_capture_ip4(self.pg1, rx, tx)
1640 def test_mcast_mid_point(self):
1641 """MPLS Multicast Mid Point"""
1644 # Add a non-recursive route that will forward the traffic
1647 route_10_0_0_1 = VppIpRoute(
1652 paths=[VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
1654 route_10_0_0_1.add_vpp_config()
1657 # Add a mcast entry that replicate to pg2 and pg3
1658 # and replicate to a interface-rx (like a bud node would)
1660 route_3400_eos = VppMplsRoute(
1666 self.pg2.remote_ip4,
1667 self.pg2.sw_if_index,
1668 labels=[VppMplsLabel(3401)],
1671 self.pg3.remote_ip4,
1672 self.pg3.sw_if_index,
1673 labels=[VppMplsLabel(3402)],
1677 self.pg1.sw_if_index,
1678 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
1683 route_3400_eos.add_vpp_config()
1686 # ping an interface in the default table
1687 # PG0 is in the default table
1689 self.vapi.cli("clear trace")
1690 tx = self.create_stream_labelled_ip4(
1691 self.pg0, [VppMplsLabel(3400, ttl=64)], n=257, dst_ip="10.0.0.1"
1693 self.pg0.add_stream(tx)
1695 self.pg_enable_capture(self.pg_interfaces)
1698 rx = self.pg1.get_capture(257)
1699 self.verify_capture_ip4(self.pg1, rx, tx)
1701 rx = self.pg2.get_capture(257)
1702 self.verify_capture_labelled(self.pg2, rx, tx, [VppMplsLabel(3401, ttl=63)])
1703 rx = self.pg3.get_capture(257)
1704 self.verify_capture_labelled(self.pg3, rx, tx, [VppMplsLabel(3402, ttl=63)])
1706 def test_mcast_head(self):
1707 """MPLS Multicast Head-end"""
1709 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1710 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1713 # Create a multicast tunnel with two replications
1715 mpls_tun = VppMPLSTunnelInterface(
1719 self.pg2.remote_ip4, self.pg2.sw_if_index, labels=[VppMplsLabel(42)]
1722 self.pg3.remote_ip4, self.pg3.sw_if_index, labels=[VppMplsLabel(43)]
1727 mpls_tun.add_vpp_config()
1731 # add an unlabelled route through the new tunnel
1733 route_10_0_0_3 = VppIpRoute(
1734 self, "10.0.0.3", 32, [VppRoutePath("0.0.0.0", mpls_tun._sw_if_index)]
1736 route_10_0_0_3.add_vpp_config()
1738 self.vapi.cli("clear trace")
1739 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1740 self.pg0.add_stream(tx)
1742 self.pg_enable_capture(self.pg_interfaces)
1745 rx = self.pg2.get_capture(257)
1746 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1747 rx = self.pg3.get_capture(257)
1748 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1751 # An an IP multicast route via the tunnel
1753 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1755 route_232_1_1_1 = VppIpMRoute(
1760 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1763 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
1766 mpls_tun._sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1770 route_232_1_1_1.add_vpp_config()
1771 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1773 self.vapi.cli("clear trace")
1774 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1775 self.pg0.add_stream(tx)
1777 self.pg_enable_capture(self.pg_interfaces)
1780 rx = self.pg2.get_capture(257)
1781 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1782 rx = self.pg3.get_capture(257)
1783 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1785 def test_mcast_ip4_tail(self):
1786 """MPLS IPv4 Multicast Tail"""
1788 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1789 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1792 # Add a multicast route that will forward the traffic
1795 route_232_1_1_1 = VppIpMRoute(
1800 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1804 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
1808 route_232_1_1_1.add_vpp_config()
1811 # An interface receive label that maps traffic to RX on interface
1813 # by injecting the packet in on pg0, which is in table 0
1814 # doing an rpf-id and matching a route in table 1
1815 # if the packet egresses, then we must have matched the route in
1818 route_34_eos = VppMplsRoute(
1822 [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1, rpf_id=55)],
1824 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
1827 route_34_eos.add_vpp_config()
1830 # Drop due to interface lookup miss
1832 self.vapi.cli("clear trace")
1833 tx = self.create_stream_labelled_ip4(
1834 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1", n=1
1836 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1839 # set the RPF-ID of the entry to match the input packet's
1841 route_232_1_1_1.update_rpf_id(55)
1842 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1844 tx = self.create_stream_labelled_ip4(
1845 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1"
1847 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1848 self.verify_capture_ip4(self.pg1, rx, tx)
1851 # disposed packets have an invalid IPv4 checksum
1853 tx = self.create_stream_labelled_ip4(
1854 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1", n=65, chksum=1
1856 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1859 # set the RPF-ID of the entry to not match the input packet's
1861 route_232_1_1_1.update_rpf_id(56)
1862 tx = self.create_stream_labelled_ip4(
1863 self.pg0, [VppMplsLabel(34)], dst_ip="232.1.1.1"
1865 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1867 def test_mcast_ip6_tail(self):
1868 """MPLS IPv6 Multicast Tail"""
1870 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1871 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1874 # Add a multicast route that will forward the traffic
1877 route_ff = VppIpMRoute(
1882 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1886 self.pg1.sw_if_index,
1887 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1888 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1892 route_ff.add_vpp_config()
1895 # An interface receive label that maps traffic to RX on interface
1897 # by injecting the packet in on pg0, which is in table 0
1898 # doing an rpf-id and matching a route in table 1
1899 # if the packet egresses, then we must have matched the route in
1902 route_34_eos = VppMplsRoute(
1906 [VppRoutePath("::", 0xFFFFFFFF, nh_table_id=1, rpf_id=55)],
1908 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1911 route_34_eos.add_vpp_config()
1914 # Drop due to interface lookup miss
1916 tx = self.create_stream_labelled_ip6(
1917 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1919 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1922 # set the RPF-ID of the entry to match the input packet's
1924 route_ff.update_rpf_id(55)
1926 tx = self.create_stream_labelled_ip6(
1927 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1929 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1930 self.verify_capture_ip6(self.pg1, rx, tx)
1933 # disposed packets have hop-limit = 1
1935 tx = self.create_stream_labelled_ip6(
1936 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1", hlim=1
1938 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
1939 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1942 # set the RPF-ID of the entry to not match the input packet's
1944 route_ff.update_rpf_id(56)
1945 tx = self.create_stream_labelled_ip6(
1946 self.pg0, [VppMplsLabel(34)], dst_ip="ff01::1"
1948 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1954 # Add a non-recursive route with a single out label
1956 route_10_0_0_1 = VppIpRoute(
1962 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(45)]
1966 route_10_0_0_1.add_vpp_config()
1968 # bind a local label to the route
1969 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1970 binding.add_vpp_config()
1973 # a labelled v6 route that resolves through the v4
1975 route_2001_3 = VppIpRoute(
1979 [VppRoutePath("10.0.0.1", INVALID_INDEX, labels=[VppMplsLabel(32)])],
1981 route_2001_3.add_vpp_config()
1983 tx = self.create_stream_ip6(self.pg0, "2001::3")
1984 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1986 self.verify_capture_labelled_ip6(
1987 self.pg0, rx, tx, [VppMplsLabel(45), VppMplsLabel(32)]
1991 # and a v4 recursive via the v6
1993 route_20_3 = VppIpRoute(
1997 [VppRoutePath("2001::3", INVALID_INDEX, labels=[VppMplsLabel(99)])],
1999 route_20_3.add_vpp_config()
2001 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
2002 rx = self.send_and_expect(self.pg0, tx, self.pg0)
2004 self.verify_capture_labelled_ip4(
2005 self.pg0, rx, tx, [VppMplsLabel(45), VppMplsLabel(32), VppMplsLabel(99)]
2008 def test_attached(self):
2009 """Attach Routes with Local Label"""
2012 # test that if a local label is associated with an attached/connected
2013 # prefix, that we can reach hosts in the prefix.
2015 binding = VppMplsIpBind(
2016 self, 44, self.pg0._local_ip4_subnet, self.pg0.local_ip4_prefix_len
2018 binding.add_vpp_config()
2021 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
2022 / MPLS(label=44, ttl=64)
2023 / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4)
2024 / UDP(sport=1234, dport=1234)
2025 / Raw(b"\xa5" * 100)
2027 rxs = self.send_and_expect(self.pg0, [tx], self.pg0)
2029 # if there's an ARP then the label is linked to the glean
2031 self.assertFalse(rx.haslayer(ARP))
2032 # it should be unicasted to the host
2033 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
2034 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
2037 class TestMPLSDisabled(VppTestCase):
2041 def setUpClass(cls):
2042 super(TestMPLSDisabled, cls).setUpClass()
2045 def tearDownClass(cls):
2046 super(TestMPLSDisabled, cls).tearDownClass()
2049 super(TestMPLSDisabled, self).setUp()
2051 # create 2 pg interfaces
2052 self.create_pg_interfaces(range(2))
2054 self.tbl = VppMplsTable(self, 0)
2055 self.tbl.add_vpp_config()
2057 # PG0 is MPLS enabled
2059 self.pg0.config_ip4()
2060 self.pg0.resolve_arp()
2061 self.pg0.enable_mpls()
2063 # PG 1 is not MPLS enabled
2067 for i in self.pg_interfaces:
2071 self.pg0.disable_mpls()
2072 super(TestMPLSDisabled, self).tearDown()
2074 def test_mpls_disabled(self):
2077 self.logger.info(self.vapi.cli("show mpls interface"))
2078 self.logger.info(self.vapi.cli("show mpls interface pg1"))
2079 self.logger.info(self.vapi.cli("show mpls interface pg0"))
2082 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
2083 / MPLS(label=32, ttl=64)
2084 / IPv6(src="2001::1", dst=self.pg0.remote_ip6)
2085 / UDP(sport=1234, dport=1234)
2086 / Raw(b"\xa5" * 100)
2090 # A simple MPLS xconnect - eos label in label out
2092 route_32_eos = VppMplsRoute(
2096 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[33])],
2098 route_32_eos.add_vpp_config()
2101 # PG1 does not forward IP traffic
2103 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
2108 self.pg1.enable_mpls()
2110 self.logger.info(self.vapi.cli("show mpls interface"))
2111 self.logger.info(self.vapi.cli("show mpls interface pg1"))
2114 # Now we get packets through
2116 self.pg1.add_stream(tx)
2117 self.pg_enable_capture(self.pg_interfaces)
2120 rx = self.pg0.get_capture(1)
2125 self.pg1.disable_mpls()
2128 # PG1 does not forward IP traffic
2130 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
2131 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
2134 class TestMPLSPIC(VppTestCase):
2135 """MPLS Prefix-Independent Convergence (PIC) edge convergence"""
2138 def setUpClass(cls):
2139 super(TestMPLSPIC, cls).setUpClass()
2142 def tearDownClass(cls):
2143 super(TestMPLSPIC, cls).tearDownClass()
2146 super(TestMPLSPIC, self).setUp()
2148 # create 2 pg interfaces
2149 self.create_pg_interfaces(range(4))
2151 mpls_tbl = VppMplsTable(self, 0)
2152 mpls_tbl.add_vpp_config()
2153 tbl4 = VppIpTable(self, 1)
2154 tbl4.add_vpp_config()
2155 tbl6 = VppIpTable(self, 1, is_ip6=1)
2156 tbl6.add_vpp_config()
2160 self.pg0.config_ip4()
2161 self.pg0.resolve_arp()
2162 self.pg0.enable_mpls()
2165 self.pg1.config_ip4()
2166 self.pg1.resolve_arp()
2167 self.pg1.enable_mpls()
2169 # VRF (customer facing) link
2171 self.pg2.set_table_ip4(1)
2172 self.pg2.config_ip4()
2173 self.pg2.resolve_arp()
2174 self.pg2.set_table_ip6(1)
2175 self.pg2.config_ip6()
2176 self.pg2.resolve_ndp()
2179 self.pg3.set_table_ip4(1)
2180 self.pg3.config_ip4()
2181 self.pg3.resolve_arp()
2182 self.pg3.set_table_ip6(1)
2183 self.pg3.config_ip6()
2184 self.pg3.resolve_ndp()
2187 self.pg0.disable_mpls()
2188 self.pg1.disable_mpls()
2189 for i in self.pg_interfaces:
2195 super(TestMPLSPIC, self).tearDown()
2197 def test_mpls_ibgp_pic(self):
2198 """MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
2200 1) setup many iBGP VPN routes via a pair of iBGP peers.
2201 2) Check EMCP forwarding to these peers
2202 3) withdraw the IGP route to one of these peers.
2203 4) check forwarding continues to the remaining peer
2207 # IGP+LDP core routes
2209 core_10_0_0_45 = VppIpRoute(
2213 [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[45])],
2215 core_10_0_0_45.add_vpp_config()
2217 core_10_0_0_46 = VppIpRoute(
2221 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[46])],
2223 core_10_0_0_46.add_vpp_config()
2226 # Lot's of VPN routes. We need more the 64 so VPP will build
2227 # the fast convergence indirection
2231 for ii in range(NUM_PKTS):
2232 dst = "192.168.1.%d" % ii
2243 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST,
2249 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST,
2255 vpn_routes[ii].add_vpp_config()
2258 Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac)
2259 / IP(src=self.pg2.remote_ip4, dst=dst)
2260 / UDP(sport=1234, dport=1234)
2261 / Raw(b"\xa5" * 100)
2265 # Send the packet stream (one pkt to each VPN route)
2266 # - expect a 50-50 split of the traffic
2268 self.pg2.add_stream(pkts)
2269 self.pg_enable_capture(self.pg_interfaces)
2272 rx0 = self.pg0._get_capture(NUM_PKTS)
2273 rx1 = self.pg1._get_capture(NUM_PKTS)
2275 # not testing the LB hashing algorithm so we're not concerned
2276 # with the split ratio, just as long as neither is 0
2277 self.assertNotEqual(0, len(rx0))
2278 self.assertNotEqual(0, len(rx1))
2281 len(rx0) + len(rx1),
2282 "Expected all (%s) packets across both ECMP paths. "
2283 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2287 # use a test CLI command to stop the FIB walk process, this
2288 # will prevent the FIB converging the VPN routes and thus allow
2289 # us to probe the interim (post-fail, pre-converge) state
2291 self.vapi.ppcli("test fib-walk-process disable")
2294 # Withdraw one of the IGP routes
2296 core_10_0_0_46.remove_vpp_config()
2299 # now all packets should be forwarded through the remaining peer
2301 self.vapi.ppcli("clear trace")
2302 self.pg2.add_stream(pkts)
2303 self.pg_enable_capture(self.pg_interfaces)
2306 rx0 = self.pg0.get_capture(NUM_PKTS)
2310 "Expected all (%s) packets across single path. "
2311 "rx0: %s." % (len(pkts), len(rx0)),
2315 # enable the FIB walk process to converge the FIB
2317 self.vapi.ppcli("test fib-walk-process enable")
2320 # packets should still be forwarded through the remaining peer
2322 self.pg2.add_stream(pkts)
2323 self.pg_enable_capture(self.pg_interfaces)
2326 rx0 = self.pg0.get_capture(NUM_PKTS)
2330 "Expected all (%s) packets across single path. "
2331 "rx0: %s." % (len(pkts), len(rx0)),
2335 # Add the IGP route back and we return to load-balancing
2337 core_10_0_0_46.add_vpp_config()
2339 self.pg2.add_stream(pkts)
2340 self.pg_enable_capture(self.pg_interfaces)
2343 rx0 = self.pg0._get_capture(NUM_PKTS)
2344 rx1 = self.pg1._get_capture(NUM_PKTS)
2345 self.assertNotEqual(0, len(rx0))
2346 self.assertNotEqual(0, len(rx1))
2349 len(rx0) + len(rx1),
2350 "Expected all (%s) packets across both ECMP paths. "
2351 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2354 def test_mpls_ebgp_pic(self):
2355 """MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
2357 1) setup many eBGP VPN routes via a pair of eBGP peers.
2358 2) Check EMCP forwarding to these peers
2359 3) withdraw one eBGP path - expect LB across remaining eBGP
2363 # Lot's of VPN routes. We need more the 64 so VPP will build
2364 # the fast convergence indirection
2369 for ii in range(NUM_PKTS):
2370 dst = "192.168.1.%d" % ii
2371 local_label = 1600 + ii
2379 self.pg2.remote_ip4,
2382 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2385 self.pg3.remote_ip4,
2388 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2394 vpn_routes[ii].add_vpp_config()
2396 vpn_bindings.append(
2397 VppMplsIpBind(self, local_label, dst, 32, ip_table_id=1)
2399 vpn_bindings[ii].add_vpp_config()
2402 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2403 / MPLS(label=local_label, ttl=64)
2404 / IP(src=self.pg0.remote_ip4, dst=dst)
2405 / UDP(sport=1234, dport=1234)
2406 / Raw(b"\xa5" * 100)
2410 # Send the packet stream (one pkt to each VPN route)
2411 # - expect a 50-50 split of the traffic
2413 self.pg0.add_stream(pkts)
2414 self.pg_enable_capture(self.pg_interfaces)
2417 rx0 = self.pg2._get_capture(NUM_PKTS)
2418 rx1 = self.pg3._get_capture(NUM_PKTS)
2420 # not testing the LB hashing algorithm so we're not concerned
2421 # with the split ratio, just as long as neither is 0
2422 self.assertNotEqual(0, len(rx0))
2423 self.assertNotEqual(0, len(rx1))
2426 len(rx0) + len(rx1),
2427 "Expected all (%s) packets across both ECMP paths. "
2428 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2432 # use a test CLI command to stop the FIB walk process, this
2433 # will prevent the FIB converging the VPN routes and thus allow
2434 # us to probe the interim (post-fail, pre-converge) state
2436 self.vapi.ppcli("test fib-walk-process disable")
2439 # withdraw the connected prefix on the interface.
2441 self.pg2.unconfig_ip4()
2444 # now all packets should be forwarded through the remaining peer
2446 self.pg0.add_stream(pkts)
2447 self.pg_enable_capture(self.pg_interfaces)
2450 rx0 = self.pg3.get_capture(NUM_PKTS)
2454 "Expected all (%s) packets across single path. "
2455 "rx0: %s." % (len(pkts), len(rx0)),
2459 # enable the FIB walk process to converge the FIB
2461 self.vapi.ppcli("test fib-walk-process enable")
2464 # packets should still be forwarded through the remaining peer
2466 self.pg0.add_stream(pkts)
2467 self.pg_enable_capture(self.pg_interfaces)
2470 rx0 = self.pg3.get_capture(NUM_PKTS)
2474 "Expected all (%s) packets across single path. "
2475 "rx0: %s." % (len(pkts), len(rx0)),
2479 # put the connected routes back
2481 self.pg2.config_ip4()
2482 self.pg2.resolve_arp()
2484 self.pg0.add_stream(pkts)
2485 self.pg_enable_capture(self.pg_interfaces)
2488 rx0 = self.pg2._get_capture(NUM_PKTS)
2489 rx1 = self.pg3._get_capture(NUM_PKTS)
2490 self.assertNotEqual(0, len(rx0))
2491 self.assertNotEqual(0, len(rx1))
2494 len(rx0) + len(rx1),
2495 "Expected all (%s) packets across both ECMP paths. "
2496 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2499 def test_mpls_v6_ebgp_pic(self):
2500 """MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
2502 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
2503 2) Check EMCP forwarding to these peers
2504 3) withdraw one eBGP path - expect LB across remaining eBGP
2508 # Lot's of VPN routes. We need more the 64 so VPP will build
2509 # the fast convergence indirection
2514 for ii in range(NUM_PKTS):
2515 dst = "3000::%d" % ii
2516 local_label = 1600 + ii
2524 self.pg2.remote_ip6,
2527 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2530 self.pg3.remote_ip6,
2533 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED,
2539 vpn_routes[ii].add_vpp_config()
2541 vpn_bindings.append(
2542 VppMplsIpBind(self, local_label, dst, 128, ip_table_id=1)
2544 vpn_bindings[ii].add_vpp_config()
2547 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2548 / MPLS(label=local_label, ttl=64)
2549 / IPv6(src=self.pg0.remote_ip6, dst=dst)
2550 / UDP(sport=1234, dport=1234)
2551 / Raw(b"\xa5" * 100)
2553 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2555 self.pg0.add_stream(pkts)
2556 self.pg_enable_capture(self.pg_interfaces)
2559 rx0 = self.pg2._get_capture(NUM_PKTS)
2560 rx1 = self.pg3._get_capture(NUM_PKTS)
2561 self.assertNotEqual(0, len(rx0))
2562 self.assertNotEqual(0, len(rx1))
2565 len(rx0) + len(rx1),
2566 "Expected all (%s) packets across both ECMP paths. "
2567 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2571 # use a test CLI command to stop the FIB walk process, this
2572 # will prevent the FIB converging the VPN routes and thus allow
2573 # us to probe the interim (post-fail, pre-converge) state
2575 self.vapi.ppcli("test fib-walk-process disable")
2578 # withdraw the connected prefix on the interface.
2579 # and shutdown the interface so the ND cache is flushed.
2581 self.pg2.unconfig_ip6()
2582 self.pg2.admin_down()
2585 # now all packets should be forwarded through the remaining peer
2587 self.pg0.add_stream(pkts)
2588 self.pg_enable_capture(self.pg_interfaces)
2591 rx0 = self.pg3.get_capture(NUM_PKTS)
2595 "Expected all (%s) packets across single path. "
2596 "rx0: %s." % (len(pkts), len(rx0)),
2600 # enable the FIB walk process to converge the FIB
2602 self.vapi.ppcli("test fib-walk-process enable")
2603 self.pg0.add_stream(pkts)
2604 self.pg_enable_capture(self.pg_interfaces)
2607 rx0 = self.pg3.get_capture(NUM_PKTS)
2611 "Expected all (%s) packets across single path. "
2612 "rx0: %s." % (len(pkts), len(rx0)),
2616 # put the connected routes back
2618 self.logger.info(self.vapi.cli("sh log"))
2620 self.pg2.config_ip6()
2621 self.pg2.resolve_ndp()
2623 self.pg0.add_stream(pkts)
2624 self.pg_enable_capture(self.pg_interfaces)
2627 rx0 = self.pg2._get_capture(NUM_PKTS)
2628 rx1 = self.pg3._get_capture(NUM_PKTS)
2629 self.assertNotEqual(0, len(rx0))
2630 self.assertNotEqual(0, len(rx1))
2633 len(rx0) + len(rx1),
2634 "Expected all (%s) packets across both ECMP paths. "
2635 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)),
2639 class TestMPLSL2(VppTestCase):
2643 def setUpClass(cls):
2644 super(TestMPLSL2, cls).setUpClass()
2647 def tearDownClass(cls):
2648 super(TestMPLSL2, cls).tearDownClass()
2651 super(TestMPLSL2, self).setUp()
2653 # create 2 pg interfaces
2654 self.create_pg_interfaces(range(2))
2656 # create the default MPLS table
2658 tbl = VppMplsTable(self, 0)
2659 tbl.add_vpp_config()
2660 self.tables.append(tbl)
2662 # use pg0 as the core facing interface, don't resolve ARP
2664 self.pg0.config_ip4()
2665 self.pg0.enable_mpls()
2667 # use the other 2 for customer facing L2 links
2668 for i in self.pg_interfaces[1:]:
2672 for i in self.pg_interfaces[1:]:
2675 self.pg0.disable_mpls()
2676 self.pg0.unconfig_ip4()
2677 self.pg0.admin_down()
2678 super(TestMPLSL2, self).tearDown()
2680 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2681 capture = verify_filter(capture, sent)
2683 self.assertEqual(len(capture), len(sent))
2685 for i in range(len(capture)):
2689 # the MPLS TTL is 255 since it enters a new tunnel
2690 verify_mpls_stack(self, rx, mpls_labels)
2693 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2695 self.assertEqual(rx_eth.src, tx_eth.src)
2696 self.assertEqual(rx_eth.dst, tx_eth.dst)
2698 def verify_arp_req(self, rx, smac, sip, dip):
2700 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2701 self.assertEqual(ether.src, smac)
2704 self.assertEqual(arp.hwtype, 1)
2705 self.assertEqual(arp.ptype, 0x800)
2706 self.assertEqual(arp.hwlen, 6)
2707 self.assertEqual(arp.plen, 4)
2708 self.assertEqual(arp.op, ARP.who_has)
2709 self.assertEqual(arp.hwsrc, smac)
2710 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2711 self.assertEqual(arp.psrc, sip)
2712 self.assertEqual(arp.pdst, dip)
2714 def test_vpws(self):
2715 """Virtual Private Wire Service"""
2718 # Create an MPLS tunnel that pushes 1 label
2719 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2720 # information is not in the packet, but we test it works anyway
2722 mpls_tun_1 = VppMPLSTunnelInterface(
2726 self.pg0.remote_ip4,
2727 self.pg0.sw_if_index,
2728 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)],
2733 mpls_tun_1.add_vpp_config()
2734 mpls_tun_1.admin_up()
2737 # Create a label entry to for 55 that does L2 input to the tunnel
2739 route_55_eos = VppMplsRoute(
2746 mpls_tun_1.sw_if_index,
2747 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2748 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2751 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2753 route_55_eos.add_vpp_config()
2756 # Cross-connect the tunnel with one of the customers L2 interfaces
2758 self.vapi.sw_interface_set_l2_xconnect(
2759 self.pg1.sw_if_index, mpls_tun_1.sw_if_index, enable=1
2761 self.vapi.sw_interface_set_l2_xconnect(
2762 mpls_tun_1.sw_if_index, self.pg1.sw_if_index, enable=1
2766 # inject a packet from the core
2769 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2770 / MPLS(label=55, ttl=64)
2771 / Ether(dst="00:00:de:ad:ba:be", src="00:00:de:ad:be:ef")
2772 / IP(src="10.10.10.10", dst="11.11.11.11")
2773 / UDP(sport=1234, dport=1234)
2774 / Raw(b"\xa5" * 100)
2777 tx0 = pcore * NUM_PKTS
2778 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2779 payload = pcore[MPLS].payload
2781 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2782 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2785 # Inject a packet from the customer/L2 side
2786 # there's no resolved ARP entry so the first packet we see should be
2789 tx1 = pcore[MPLS].payload
2790 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2792 self.verify_arp_req(
2793 rx1[0], self.pg0.local_mac, self.pg0.local_ip4, self.pg0.remote_ip4
2797 # resolve the ARP entries and send again
2799 self.pg0.resolve_arp()
2800 tx1 = pcore[MPLS].payload * NUM_PKTS
2801 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2803 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2805 def test_vpls(self):
2806 """Virtual Private LAN Service"""
2808 # we skipped this in the setup
2809 self.pg0.resolve_arp()
2812 # Create a L2 MPLS tunnels
2814 mpls_tun1 = VppMPLSTunnelInterface(
2818 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(42)]
2823 mpls_tun1.add_vpp_config()
2824 mpls_tun1.admin_up()
2826 mpls_tun2 = VppMPLSTunnelInterface(
2830 self.pg0.remote_ip4, self.pg0.sw_if_index, labels=[VppMplsLabel(43)]
2835 mpls_tun2.add_vpp_config()
2836 mpls_tun2.admin_up()
2839 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2840 # the latter includes a Psuedo Wire Control Word
2842 route_55_eos = VppMplsRoute(
2849 mpls_tun1.sw_if_index,
2850 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2851 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2854 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2857 route_56_eos = VppMplsRoute(
2864 mpls_tun2.sw_if_index,
2865 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2866 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2867 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2870 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET,
2874 route_56_eos.add_vpp_config()
2875 route_55_eos.add_vpp_config()
2877 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2880 # add to tunnel to the customers bridge-domain
2882 self.vapi.sw_interface_set_l2_bridge(
2883 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1
2885 self.vapi.sw_interface_set_l2_bridge(
2886 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1
2888 self.vapi.sw_interface_set_l2_bridge(
2889 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1
2893 # Packet from host on the customer interface to each host
2894 # reachable over the core, and vice-versa
2897 Ether(dst="00:00:de:ad:ba:b1", src="00:00:de:ad:be:ef")
2898 / IP(src="10.10.10.10", dst="11.11.11.11")
2899 / UDP(sport=1234, dport=1234)
2900 / Raw(b"\xa5" * 100)
2903 Ether(dst="00:00:de:ad:ba:b2", src="00:00:de:ad:be:ef")
2904 / IP(src="10.10.10.10", dst="11.11.11.12")
2905 / UDP(sport=1234, dport=1234)
2906 / Raw(b"\xa5" * 100)
2909 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2910 / MPLS(label=55, ttl=64)
2911 / Ether(src="00:00:de:ad:ba:b1", dst="00:00:de:ad:be:ef")
2912 / IP(dst="10.10.10.10", src="11.11.11.11")
2913 / UDP(sport=1234, dport=1234)
2914 / Raw(b"\xa5" * 100)
2917 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2918 / MPLS(label=56, ttl=64)
2920 / Ether(src="00:00:de:ad:ba:b2", dst="00:00:de:ad:be:ef") # PW CW
2921 / IP(dst="10.10.10.10", src="11.11.11.12")
2922 / UDP(sport=1234, dport=1234)
2923 / Raw(b"\xa5" * 100)
2927 # The BD is learning, so send in one of each packet to learn
2930 # 2 packets due to BD flooding
2931 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2932 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2934 # we've learnt this so expect it be be forwarded not flooded
2935 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2936 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2937 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2939 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2940 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2941 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2944 # now a stream in each direction from each host
2946 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2947 self.verify_capture_tunneled_ethernet(
2948 rx, p_cust1 * NUM_PKTS, [VppMplsLabel(42)]
2951 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2952 self.verify_capture_tunneled_ethernet(
2953 rx, p_cust2 * NUM_PKTS, [VppMplsLabel(43)]
2956 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2957 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2960 # remove interfaces from customers bridge-domain
2962 self.vapi.sw_interface_set_l2_bridge(
2963 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0
2965 self.vapi.sw_interface_set_l2_bridge(
2966 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0
2968 self.vapi.sw_interface_set_l2_bridge(
2969 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0
2973 if __name__ == "__main__":
2974 unittest.main(testRunner=VppTestRunner)