6 from framework import VppTestCase, VppTestRunner
7 from vpp_ip import DpoProto, INVALID_INDEX
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
9 VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
10 MRouteItfFlags, MRouteEntryFlags, VppIpTable, VppMplsTable, \
11 VppMplsLabel, MplsLspMode, find_mpls_route, \
12 FibPathProto, FibPathType, FibPathFlags, VppMplsLabel, MplsLspMode
13 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
16 from scapy.packet import Raw
17 from scapy.layers.l2 import Ether
18 from scapy.layers.inet import IP, UDP, ICMP
19 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
20 from scapy.contrib.mpls import MPLS
25 def verify_filter(capture, sent):
26 if not len(capture) == len(sent):
27 # filter out any IPv6 RAs from the capture
34 def verify_mpls_stack(tst, rx, mpls_labels):
35 # the rx'd packet has the MPLS label popped
37 tst.assertEqual(eth.type, 0x8847)
41 for ii in range(len(mpls_labels)):
42 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
43 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
44 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
46 if ii == len(mpls_labels) - 1:
47 tst.assertEqual(rx_mpls.s, 1)
50 tst.assertEqual(rx_mpls.s, 0)
51 # pop the label to expose the next
52 rx_mpls = rx_mpls[MPLS].payload
55 class TestMPLS(VppTestCase):
56 """ MPLS Test Case """
60 super(TestMPLS, cls).setUpClass()
63 def tearDownClass(cls):
64 super(TestMPLS, cls).tearDownClass()
67 super(TestMPLS, self).setUp()
69 # create 2 pg interfaces
70 self.create_pg_interfaces(range(4))
72 # setup both interfaces
73 # assign them different tables.
77 tbl = VppMplsTable(self, 0)
79 self.tables.append(tbl)
81 for i in self.pg_interfaces:
85 tbl = VppIpTable(self, table_id)
87 self.tables.append(tbl)
88 tbl = VppIpTable(self, table_id, is_ip6=1)
90 self.tables.append(tbl)
92 i.set_table_ip4(table_id)
93 i.set_table_ip6(table_id)
102 for i in self.pg_interfaces:
110 super(TestMPLS, self).tearDown()
112 # the default of 64 matches the IP packet TTL default
113 def create_stream_labelled_ip4(
123 self.reset_packet_infos()
125 for i in range(0, n):
126 info = self.create_packet_info(src_if, src_if)
127 payload = self.info_to_payload(info)
128 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
130 for ii in range(len(mpls_labels)):
131 p = p / MPLS(label=mpls_labels[ii].value,
132 ttl=mpls_labels[ii].ttl,
133 cos=mpls_labels[ii].exp)
136 p = (p / IP(src=src_if.local_ip4,
137 dst=src_if.remote_ip4,
139 UDP(sport=1234, dport=1234) /
142 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
143 UDP(sport=1234, dport=1234) /
146 p = (p / IP(src=ip_itf.remote_ip4,
147 dst=ip_itf.local_ip4,
152 p[IP].chksum = chksum
157 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64,
158 ip_dscp=0, payload_size=None):
159 self.reset_packet_infos()
161 for i in range(0, 257):
162 info = self.create_packet_info(src_if, src_if)
163 payload = self.info_to_payload(info)
164 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
165 IP(src=src_if.remote_ip4, dst=dst_ip,
166 ttl=ip_ttl, tos=ip_dscp) /
167 UDP(sport=1234, dport=1234) /
171 self.extend_packet(p, payload_size)
175 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
176 self.reset_packet_infos()
178 for i in range(0, 257):
179 info = self.create_packet_info(src_if, src_if)
180 payload = self.info_to_payload(info)
181 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
182 IPv6(src=src_if.remote_ip6, dst=dst_ip,
183 hlim=ip_ttl, tc=ip_dscp) /
184 UDP(sport=1234, dport=1234) /
190 def create_stream_labelled_ip6(self, src_if, mpls_labels,
191 hlim=64, dst_ip=None):
193 dst_ip = src_if.remote_ip6
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)
199 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
200 for l in mpls_labels:
201 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
203 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
204 UDP(sport=1234, dport=1234) /
210 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
211 ip_ttl=None, ip_dscp=0):
213 capture = verify_filter(capture, sent)
215 self.assertEqual(len(capture), len(sent))
217 for i in range(len(capture)):
221 # the rx'd packet has the MPLS label popped
223 self.assertEqual(eth.type, 0x800)
229 self.assertEqual(rx_ip.src, tx_ip.src)
230 self.assertEqual(rx_ip.dst, tx_ip.dst)
231 self.assertEqual(rx_ip.tos, ip_dscp)
233 # IP processing post pop has decremented the TTL
234 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
236 self.assertEqual(rx_ip.ttl, ip_ttl)
238 self.assertEqual(rx_ip.src, tx_ip.dst)
239 self.assertEqual(rx_ip.dst, tx_ip.src)
244 def verify_capture_labelled_ip4(self, src_if, capture, sent,
245 mpls_labels, ip_ttl=None):
247 capture = verify_filter(capture, sent)
249 self.assertEqual(len(capture), len(sent))
251 for i in range(len(capture)):
257 verify_mpls_stack(self, rx, mpls_labels)
259 self.assertEqual(rx_ip.src, tx_ip.src)
260 self.assertEqual(rx_ip.dst, tx_ip.dst)
262 # IP processing post pop has decremented the TTL
263 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
265 self.assertEqual(rx_ip.ttl, ip_ttl)
270 def verify_capture_labelled_ip6(self, src_if, capture, sent,
271 mpls_labels, ip_ttl=None):
273 capture = verify_filter(capture, sent)
275 self.assertEqual(len(capture), len(sent))
277 for i in range(len(capture)):
283 verify_mpls_stack(self, rx, mpls_labels)
285 self.assertEqual(rx_ip.src, tx_ip.src)
286 self.assertEqual(rx_ip.dst, tx_ip.dst)
288 # IP processing post pop has decremented the TTL
289 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
291 self.assertEqual(rx_ip.hlim, ip_ttl)
296 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
298 capture = verify_filter(capture, sent)
300 self.assertEqual(len(capture), len(sent))
302 for i in range(len(capture)):
308 verify_mpls_stack(self, rx, mpls_labels)
310 self.assertEqual(rx_ip.src, tx_ip.src)
311 self.assertEqual(rx_ip.dst, tx_ip.dst)
312 # IP processing post pop has decremented the TTL
313 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
318 def verify_capture_labelled(self, src_if, capture, sent,
321 capture = verify_filter(capture, sent)
323 self.assertEqual(len(capture), len(sent))
325 for i in range(len(capture)):
327 verify_mpls_stack(self, rx, mpls_labels)
331 def verify_capture_ip6(self, src_if, capture, sent,
332 ip_hlim=None, ip_dscp=0):
334 self.assertEqual(len(capture), len(sent))
336 for i in range(len(capture)):
340 # the rx'd packet has the MPLS label popped
342 self.assertEqual(eth.type, 0x86DD)
347 self.assertEqual(rx_ip.src, tx_ip.src)
348 self.assertEqual(rx_ip.dst, tx_ip.dst)
349 self.assertEqual(rx_ip.tc, ip_dscp)
350 # IP processing post pop has decremented the TTL
352 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
354 self.assertEqual(rx_ip.hlim, ip_hlim)
359 def verify_capture_ip6_icmp(self, src_if, capture, sent):
361 self.assertEqual(len(capture), len(sent))
363 for i in range(len(capture)):
367 # the rx'd packet has the MPLS label popped
369 self.assertEqual(eth.type, 0x86DD)
374 self.assertEqual(rx_ip.dst, tx_ip.src)
375 # ICMP sourced from the interface's address
376 self.assertEqual(rx_ip.src, src_if.local_ip6)
377 # hop-limit reset to 255 for IMCP packet
378 self.assertEqual(rx_ip.hlim, 255)
380 icmp = rx[ICMPv6TimeExceeded]
385 def verify_capture_fragmented_labelled_ip4(self, src_if, capture, sent,
386 mpls_labels, ip_ttl=None):
388 capture = verify_filter(capture, sent)
390 for i in range(len(capture)):
396 verify_mpls_stack(self, rx, mpls_labels)
398 self.assertEqual(rx_ip.src, tx_ip.src)
399 self.assertEqual(rx_ip.dst, tx_ip.dst)
401 # IP processing post pop has decremented the TTL
402 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
404 self.assertEqual(rx_ip.ttl, ip_ttl)
410 """ MPLS label swap tests """
413 # A simple MPLS xconnect - eos label in label out
415 route_32_eos = VppMplsRoute(self, 32, 1,
416 [VppRoutePath(self.pg0.remote_ip4,
417 self.pg0.sw_if_index,
418 labels=[VppMplsLabel(33)])])
419 route_32_eos.add_vpp_config()
422 find_mpls_route(self, 0, 32, 1,
423 [VppRoutePath(self.pg0.remote_ip4,
424 self.pg0.sw_if_index,
425 labels=[VppMplsLabel(33)])]))
428 # a stream that matches the route for 10.0.0.1
429 # PG0 is in the default table
431 tx = self.create_stream_labelled_ip4(self.pg0,
432 [VppMplsLabel(32, ttl=32, exp=1)])
433 rx = self.send_and_expect(self.pg0, tx, self.pg0)
434 self.verify_capture_labelled(self.pg0, rx, tx,
435 [VppMplsLabel(33, ttl=31, exp=1)])
437 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
440 # A simple MPLS xconnect - non-eos label in label out
442 route_32_neos = VppMplsRoute(self, 32, 0,
443 [VppRoutePath(self.pg0.remote_ip4,
444 self.pg0.sw_if_index,
445 labels=[VppMplsLabel(33)])])
446 route_32_neos.add_vpp_config()
449 # a stream that matches the route for 10.0.0.1
450 # PG0 is in the default table
452 tx = self.create_stream_labelled_ip4(self.pg0,
453 [VppMplsLabel(32, ttl=21, exp=7),
455 rx = self.send_and_expect(self.pg0, tx, self.pg0)
456 self.verify_capture_labelled(self.pg0, rx, tx,
457 [VppMplsLabel(33, ttl=20, exp=7),
459 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
462 # A simple MPLS xconnect - non-eos label in label out, uniform mode
464 route_42_neos = VppMplsRoute(
466 [VppRoutePath(self.pg0.remote_ip4,
467 self.pg0.sw_if_index,
468 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
469 route_42_neos.add_vpp_config()
471 tx = self.create_stream_labelled_ip4(self.pg0,
472 [VppMplsLabel(42, ttl=21, exp=7),
474 rx = self.send_and_expect(self.pg0, tx, self.pg0)
475 self.verify_capture_labelled(self.pg0, rx, tx,
476 [VppMplsLabel(43, ttl=20, exp=7),
480 # An MPLS xconnect - EOS label in IP out
482 route_33_eos = VppMplsRoute(self, 33, 1,
483 [VppRoutePath(self.pg0.remote_ip4,
484 self.pg0.sw_if_index,
486 route_33_eos.add_vpp_config()
488 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
489 rx = self.send_and_expect(self.pg0, tx, self.pg0)
490 self.verify_capture_ip4(self.pg0, rx, tx)
493 # disposed packets have an invalid IPv4 checksum
495 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
496 dst_ip=self.pg0.remote_ip4,
499 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
502 # An MPLS xconnect - EOS label in IP out, uniform mode
504 route_3333_eos = VppMplsRoute(
506 [VppRoutePath(self.pg0.remote_ip4,
507 self.pg0.sw_if_index,
508 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
509 route_3333_eos.add_vpp_config()
511 tx = self.create_stream_labelled_ip4(
513 [VppMplsLabel(3333, ttl=55, exp=3)])
514 rx = self.send_and_expect(self.pg0, tx, self.pg0)
515 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
516 tx = self.create_stream_labelled_ip4(
518 [VppMplsLabel(3333, ttl=66, exp=4)])
519 rx = self.send_and_expect(self.pg0, tx, self.pg0)
520 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
523 # An MPLS xconnect - EOS label in IPv6 out
525 route_333_eos = VppMplsRoute(
527 [VppRoutePath(self.pg0.remote_ip6,
528 self.pg0.sw_if_index,
530 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
531 route_333_eos.add_vpp_config()
533 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
534 rx = self.send_and_expect(self.pg0, tx, self.pg0)
535 self.verify_capture_ip6(self.pg0, rx, tx)
538 # disposed packets have an TTL expired
540 tx = self.create_stream_labelled_ip6(self.pg0,
541 [VppMplsLabel(333, ttl=64)],
542 dst_ip=self.pg1.remote_ip6,
544 rx = self.send_and_expect(self.pg0, tx, self.pg0)
545 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
548 # An MPLS xconnect - EOS label in IPv6 out w imp-null
550 route_334_eos = VppMplsRoute(
552 [VppRoutePath(self.pg0.remote_ip6,
553 self.pg0.sw_if_index,
554 labels=[VppMplsLabel(3)])],
555 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
556 route_334_eos.add_vpp_config()
558 tx = self.create_stream_labelled_ip6(self.pg0,
559 [VppMplsLabel(334, ttl=64)])
560 rx = self.send_and_expect(self.pg0, tx, self.pg0)
561 self.verify_capture_ip6(self.pg0, rx, tx)
564 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
566 route_335_eos = VppMplsRoute(
568 [VppRoutePath(self.pg0.remote_ip6,
569 self.pg0.sw_if_index,
570 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
571 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
572 route_335_eos.add_vpp_config()
574 tx = self.create_stream_labelled_ip6(
576 [VppMplsLabel(335, ttl=27, exp=4)])
577 rx = self.send_and_expect(self.pg0, tx, self.pg0)
578 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
581 # disposed packets have an TTL expired
583 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
584 dst_ip=self.pg1.remote_ip6,
586 rx = self.send_and_expect(self.pg0, tx, self.pg0)
587 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
590 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
591 # so this traffic should be dropped.
593 route_33_neos = VppMplsRoute(self, 33, 0,
594 [VppRoutePath(self.pg0.remote_ip4,
595 self.pg0.sw_if_index,
597 route_33_neos.add_vpp_config()
599 tx = self.create_stream_labelled_ip4(self.pg0,
602 self.send_and_assert_no_replies(
604 "MPLS non-EOS packets popped and forwarded")
607 # A recursive EOS x-connect, which resolves through another x-connect
610 route_34_eos = VppMplsRoute(self, 34, 1,
611 [VppRoutePath("0.0.0.0",
614 labels=[VppMplsLabel(44),
616 route_34_eos.add_vpp_config()
617 self.logger.info(self.vapi.cli("sh mpls fib 34"))
619 tx = self.create_stream_labelled_ip4(self.pg0,
620 [VppMplsLabel(34, ttl=3)])
621 rx = self.send_and_expect(self.pg0, tx, self.pg0)
622 self.verify_capture_labelled(self.pg0, rx, tx,
625 VppMplsLabel(45, ttl=2)])
627 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
628 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
631 # A recursive EOS x-connect, which resolves through another x-connect
634 route_35_eos = VppMplsRoute(
636 [VppRoutePath("0.0.0.0",
639 labels=[VppMplsLabel(44)])])
640 route_35_eos.add_vpp_config()
642 tx = self.create_stream_labelled_ip4(self.pg0,
643 [VppMplsLabel(35, ttl=3)])
644 rx = self.send_and_expect(self.pg0, tx, self.pg0)
645 self.verify_capture_labelled(self.pg0, rx, tx,
646 [VppMplsLabel(43, ttl=2),
647 VppMplsLabel(44, ttl=2)])
650 # A recursive non-EOS x-connect, which resolves through another
653 route_34_neos = VppMplsRoute(self, 34, 0,
654 [VppRoutePath("0.0.0.0",
657 labels=[VppMplsLabel(44),
659 route_34_neos.add_vpp_config()
661 tx = self.create_stream_labelled_ip4(self.pg0,
662 [VppMplsLabel(34, ttl=45),
664 rx = self.send_and_expect(self.pg0, tx, self.pg0)
665 # it's the 2nd (counting from 0) label in the stack that is swapped
666 self.verify_capture_labelled(self.pg0, rx, tx,
669 VppMplsLabel(46, ttl=44),
673 # an recursive IP route that resolves through the recursive non-eos
676 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
677 [VppRoutePath("0.0.0.0",
680 labels=[VppMplsLabel(55)])])
681 ip_10_0_0_1.add_vpp_config()
683 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
684 rx = self.send_and_expect(self.pg0, tx, self.pg0)
685 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
690 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
692 ip_10_0_0_1.remove_vpp_config()
693 route_34_neos.remove_vpp_config()
694 route_34_eos.remove_vpp_config()
695 route_33_neos.remove_vpp_config()
696 route_33_eos.remove_vpp_config()
697 route_32_neos.remove_vpp_config()
698 route_32_eos.remove_vpp_config()
701 """ MPLS Local Label Binding test """
704 # Add a non-recursive route with a single out label
706 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
707 [VppRoutePath(self.pg0.remote_ip4,
708 self.pg0.sw_if_index,
709 labels=[VppMplsLabel(45)])])
710 route_10_0_0_1.add_vpp_config()
712 # bind a local label to the route
713 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
714 binding.add_vpp_config()
717 tx = self.create_stream_labelled_ip4(self.pg0,
720 rx = self.send_and_expect(self.pg0, tx, self.pg0)
721 self.verify_capture_labelled(self.pg0, rx, tx,
722 [VppMplsLabel(45, ttl=63),
726 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
727 rx = self.send_and_expect(self.pg0, tx, self.pg0)
728 self.verify_capture_labelled(self.pg0, rx, tx,
729 [VppMplsLabel(45, ttl=63)])
732 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
733 rx = self.send_and_expect(self.pg0, tx, self.pg0)
734 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
739 binding.remove_vpp_config()
740 route_10_0_0_1.remove_vpp_config()
742 def test_imposition(self):
743 """ MPLS label imposition test """
746 # Add a non-recursive route with a single out label
748 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
749 [VppRoutePath(self.pg0.remote_ip4,
750 self.pg0.sw_if_index,
751 labels=[VppMplsLabel(32)])])
752 route_10_0_0_1.add_vpp_config()
755 # a stream that matches the route for 10.0.0.1
756 # PG0 is in the default table
758 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
759 rx = self.send_and_expect(self.pg0, tx, self.pg0)
760 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
763 # Add a non-recursive route with a 3 out labels
765 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
766 [VppRoutePath(self.pg0.remote_ip4,
767 self.pg0.sw_if_index,
768 labels=[VppMplsLabel(32),
771 route_10_0_0_2.add_vpp_config()
773 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
774 ip_ttl=44, ip_dscp=0xff)
775 rx = self.send_and_expect(self.pg0, tx, self.pg0)
776 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
783 # Add a non-recursive route with a single out label in uniform mode
785 route_10_0_0_3 = VppIpRoute(
786 self, "10.0.0.3", 32,
787 [VppRoutePath(self.pg0.remote_ip4,
788 self.pg0.sw_if_index,
789 labels=[VppMplsLabel(32,
790 mode=MplsLspMode.UNIFORM)])])
791 route_10_0_0_3.add_vpp_config()
793 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
794 ip_ttl=54, ip_dscp=0xbe)
795 rx = self.send_and_expect(self.pg0, tx, self.pg0)
796 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
797 [VppMplsLabel(32, ttl=53, exp=5)])
800 # Add a IPv6 non-recursive route with a single out label in
803 route_2001_3 = VppIpRoute(
804 self, "2001::3", 128,
805 [VppRoutePath(self.pg0.remote_ip6,
806 self.pg0.sw_if_index,
807 labels=[VppMplsLabel(32,
808 mode=MplsLspMode.UNIFORM)])])
809 route_2001_3.add_vpp_config()
811 tx = self.create_stream_ip6(self.pg0, "2001::3",
812 ip_ttl=54, ip_dscp=0xbe)
813 rx = self.send_and_expect(self.pg0, tx, self.pg0)
814 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
815 [VppMplsLabel(32, ttl=53, exp=5)])
818 # add a recursive path, with output label, via the 1 label route
820 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
821 [VppRoutePath("10.0.0.1",
823 labels=[VppMplsLabel(44)])])
824 route_11_0_0_1.add_vpp_config()
827 # a stream that matches the route for 11.0.0.1, should pick up
828 # the label stack for 11.0.0.1 and 10.0.0.1
830 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
831 rx = self.send_and_expect(self.pg0, tx, self.pg0)
832 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
836 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
839 # add a recursive path, with 2 labels, via the 3 label route
841 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
842 [VppRoutePath("10.0.0.2",
844 labels=[VppMplsLabel(44),
846 route_11_0_0_2.add_vpp_config()
849 # a stream that matches the route for 11.0.0.1, should pick up
850 # the label stack for 11.0.0.1 and 10.0.0.1
852 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
853 rx = self.send_and_expect(self.pg0, tx, self.pg0)
854 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
861 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
863 rx = self.send_and_expect(self.pg0, tx, self.pg0)
864 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
871 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
876 route_11_0_0_2.remove_vpp_config()
877 route_11_0_0_1.remove_vpp_config()
878 route_10_0_0_2.remove_vpp_config()
879 route_10_0_0_1.remove_vpp_config()
881 def test_imposition_fragmentation(self):
882 """ MPLS label imposition fragmentation test """
885 # Add a ipv4 non-recursive route with a single out label
887 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
888 [VppRoutePath(self.pg0.remote_ip4,
889 self.pg0.sw_if_index,
890 labels=[VppMplsLabel(32)])])
891 route_10_0_0_1.add_vpp_config()
894 # a stream that matches the route for 10.0.0.1
895 # PG0 is in the default table
897 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
898 for i in range(0, 257):
899 self.extend_packet(tx[i], 10000)
902 # 5 fragments per packet (257*5=1285)
904 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
905 self.verify_capture_fragmented_labelled_ip4(self.pg0, rx, tx,
911 route_10_0_0_1.remove_vpp_config()
913 def test_tunnel_pipe(self):
914 """ MPLS Tunnel Tests - Pipe """
917 # Create a tunnel with two out labels
919 mpls_tun = VppMPLSTunnelInterface(
921 [VppRoutePath(self.pg0.remote_ip4,
922 self.pg0.sw_if_index,
923 labels=[VppMplsLabel(44),
925 mpls_tun.add_vpp_config()
929 # add an unlabelled route through the new tunnel
931 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
932 [VppRoutePath("0.0.0.0",
933 mpls_tun._sw_if_index)])
934 route_10_0_0_3.add_vpp_config()
936 self.vapi.cli("clear trace")
937 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
938 self.pg0.add_stream(tx)
940 self.pg_enable_capture(self.pg_interfaces)
943 rx = self.pg0.get_capture()
944 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
949 # add a labelled route through the new tunnel
951 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
952 [VppRoutePath("0.0.0.0",
953 mpls_tun._sw_if_index,
955 route_10_0_0_4.add_vpp_config()
957 self.vapi.cli("clear trace")
958 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
959 self.pg0.add_stream(tx)
961 self.pg_enable_capture(self.pg_interfaces)
964 rx = self.pg0.get_capture()
965 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
968 VppMplsLabel(33, ttl=255)])
971 # change tunnel's MTU to a low value
973 mpls_tun.set_l3_mtu(1200)
975 # send IP into the tunnel to be fragmented
976 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
978 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
984 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
988 # send MPLS into the tunnel to be fragmented
989 tx = self.create_stream_ip4(self.pg0, "10.0.0.4",
991 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
997 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1000 VppMplsLabel(33, ttl=255)])
1002 def test_tunnel_uniform(self):
1003 """ MPLS Tunnel Tests - Uniform """
1006 # Create a tunnel with a single out label
1007 # The label stack is specified here from outer to inner
1009 mpls_tun = VppMPLSTunnelInterface(
1011 [VppRoutePath(self.pg0.remote_ip4,
1012 self.pg0.sw_if_index,
1013 labels=[VppMplsLabel(44, ttl=32),
1014 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1015 mpls_tun.add_vpp_config()
1019 # add an unlabelled route through the new tunnel
1021 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1022 [VppRoutePath("0.0.0.0",
1023 mpls_tun._sw_if_index)])
1024 route_10_0_0_3.add_vpp_config()
1026 self.vapi.cli("clear trace")
1027 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1028 self.pg0.add_stream(tx)
1030 self.pg_enable_capture(self.pg_interfaces)
1033 rx = self.pg0.get_capture()
1034 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1035 [VppMplsLabel(44, ttl=32),
1036 VppMplsLabel(46, ttl=23)])
1039 # add a labelled route through the new tunnel
1041 route_10_0_0_4 = VppIpRoute(
1042 self, "10.0.0.4", 32,
1043 [VppRoutePath("0.0.0.0",
1044 mpls_tun._sw_if_index,
1045 labels=[VppMplsLabel(33, ttl=47)])])
1046 route_10_0_0_4.add_vpp_config()
1048 self.vapi.cli("clear trace")
1049 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1050 self.pg0.add_stream(tx)
1052 self.pg_enable_capture(self.pg_interfaces)
1055 rx = self.pg0.get_capture()
1056 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1057 [VppMplsLabel(44, ttl=32),
1058 VppMplsLabel(46, ttl=47),
1059 VppMplsLabel(33, ttl=47)])
1061 def test_mpls_tunnel_many(self):
1062 """ MPLS Multiple Tunnels """
1064 for ii in range(10):
1065 mpls_tun = VppMPLSTunnelInterface(
1067 [VppRoutePath(self.pg0.remote_ip4,
1068 self.pg0.sw_if_index,
1069 labels=[VppMplsLabel(44, ttl=32),
1070 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1071 mpls_tun.add_vpp_config()
1074 def test_v4_exp_null(self):
1075 """ MPLS V4 Explicit NULL test """
1078 # The first test case has an MPLS TTL of 0
1079 # all packet should be dropped
1081 tx = self.create_stream_labelled_ip4(self.pg0,
1082 [VppMplsLabel(0, ttl=0)])
1083 self.send_and_assert_no_replies(self.pg0, tx,
1084 "MPLS TTL=0 packets forwarded")
1087 # a stream with a non-zero MPLS TTL
1088 # PG0 is in the default table
1090 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1091 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1092 self.verify_capture_ip4(self.pg0, rx, tx)
1095 # a stream with a non-zero MPLS TTL
1097 # we are ensuring the post-pop lookup occurs in the VRF table
1099 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1100 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1101 self.verify_capture_ip4(self.pg1, rx, tx)
1103 def test_v6_exp_null(self):
1104 """ MPLS V6 Explicit NULL test """
1107 # a stream with a non-zero MPLS TTL
1108 # PG0 is in the default table
1110 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1111 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1112 self.verify_capture_ip6(self.pg0, rx, tx)
1115 # a stream with a non-zero MPLS TTL
1117 # we are ensuring the post-pop lookup occurs in the VRF table
1119 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1120 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1121 self.verify_capture_ip6(self.pg0, rx, tx)
1123 def test_deag(self):
1127 # A de-agg route - next-hop lookup in default table
1129 route_34_eos = VppMplsRoute(self, 34, 1,
1130 [VppRoutePath("0.0.0.0",
1133 route_34_eos.add_vpp_config()
1136 # ping an interface in the default table
1137 # PG0 is in the default table
1139 tx = self.create_stream_labelled_ip4(self.pg0,
1143 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1144 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1147 # A de-agg route - next-hop lookup in non-default table
1149 route_35_eos = VppMplsRoute(self, 35, 1,
1150 [VppRoutePath("0.0.0.0",
1153 route_35_eos.add_vpp_config()
1156 # ping an interface in the non-default table
1157 # PG0 is in the default table. packet arrive labelled in the
1158 # default table and egress unlabelled in the non-default
1160 tx = self.create_stream_labelled_ip4(
1161 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1162 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1163 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1168 route_36_neos = VppMplsRoute(self, 36, 0,
1169 [VppRoutePath("0.0.0.0",
1171 route_36_neos.add_vpp_config()
1173 tx = self.create_stream_labelled_ip4(self.pg0,
1176 ping=1, ip_itf=self.pg1)
1177 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1178 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1180 route_36_neos.remove_vpp_config()
1181 route_35_eos.remove_vpp_config()
1182 route_34_eos.remove_vpp_config()
1184 def test_interface_rx(self):
1185 """ MPLS Interface Receive """
1188 # Add a non-recursive route that will forward the traffic
1191 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1193 paths=[VppRoutePath(self.pg1.remote_ip4,
1194 self.pg1.sw_if_index)])
1195 route_10_0_0_1.add_vpp_config()
1198 # An interface receive label that maps traffic to RX on interface
1200 # by injecting the packet in on pg0, which is in table 0
1201 # doing an interface-rx on pg1 and matching a route in table 1
1202 # if the packet egresses, then we must have swapped to pg1
1203 # so as to have matched the route in table 1
1205 route_34_eos = VppMplsRoute(
1207 [VppRoutePath("0.0.0.0",
1208 self.pg1.sw_if_index,
1209 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1210 route_34_eos.add_vpp_config()
1213 # ping an interface in the default table
1214 # PG0 is in the default table
1216 tx = self.create_stream_labelled_ip4(self.pg0,
1219 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1220 self.verify_capture_ip4(self.pg1, rx, tx)
1222 def test_mcast_mid_point(self):
1223 """ MPLS Multicast Mid Point """
1226 # Add a non-recursive route that will forward the traffic
1229 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1231 paths=[VppRoutePath(self.pg1.remote_ip4,
1232 self.pg1.sw_if_index)])
1233 route_10_0_0_1.add_vpp_config()
1236 # Add a mcast entry that replicate to pg2 and pg3
1237 # and replicate to a interface-rx (like a bud node would)
1239 route_3400_eos = VppMplsRoute(
1241 [VppRoutePath(self.pg2.remote_ip4,
1242 self.pg2.sw_if_index,
1243 labels=[VppMplsLabel(3401)]),
1244 VppRoutePath(self.pg3.remote_ip4,
1245 self.pg3.sw_if_index,
1246 labels=[VppMplsLabel(3402)]),
1247 VppRoutePath("0.0.0.0",
1248 self.pg1.sw_if_index,
1249 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1251 route_3400_eos.add_vpp_config()
1254 # ping an interface in the default table
1255 # PG0 is in the default table
1257 self.vapi.cli("clear trace")
1258 tx = self.create_stream_labelled_ip4(self.pg0,
1259 [VppMplsLabel(3400, ttl=64)],
1262 self.pg0.add_stream(tx)
1264 self.pg_enable_capture(self.pg_interfaces)
1267 rx = self.pg1.get_capture(257)
1268 self.verify_capture_ip4(self.pg1, rx, tx)
1270 rx = self.pg2.get_capture(257)
1271 self.verify_capture_labelled(self.pg2, rx, tx,
1272 [VppMplsLabel(3401, ttl=63)])
1273 rx = self.pg3.get_capture(257)
1274 self.verify_capture_labelled(self.pg3, rx, tx,
1275 [VppMplsLabel(3402, ttl=63)])
1277 def test_mcast_head(self):
1278 """ MPLS Multicast Head-end """
1281 # Create a multicast tunnel with two replications
1283 mpls_tun = VppMPLSTunnelInterface(
1285 [VppRoutePath(self.pg2.remote_ip4,
1286 self.pg2.sw_if_index,
1287 labels=[VppMplsLabel(42)]),
1288 VppRoutePath(self.pg3.remote_ip4,
1289 self.pg3.sw_if_index,
1290 labels=[VppMplsLabel(43)])],
1292 mpls_tun.add_vpp_config()
1296 # add an unlabelled route through the new tunnel
1298 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1299 [VppRoutePath("0.0.0.0",
1300 mpls_tun._sw_if_index)])
1301 route_10_0_0_3.add_vpp_config()
1303 self.vapi.cli("clear trace")
1304 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1305 self.pg0.add_stream(tx)
1307 self.pg_enable_capture(self.pg_interfaces)
1310 rx = self.pg2.get_capture(257)
1311 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1312 rx = self.pg3.get_capture(257)
1313 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1316 # An an IP multicast route via the tunnel
1318 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1320 route_232_1_1_1 = VppIpMRoute(
1324 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1325 [VppMRoutePath(self.pg0.sw_if_index,
1326 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1327 VppMRoutePath(mpls_tun._sw_if_index,
1328 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1329 route_232_1_1_1.add_vpp_config()
1330 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1332 self.vapi.cli("clear trace")
1333 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1334 self.pg0.add_stream(tx)
1336 self.pg_enable_capture(self.pg_interfaces)
1339 rx = self.pg2.get_capture(257)
1340 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1341 rx = self.pg3.get_capture(257)
1342 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1344 def test_mcast_ip4_tail(self):
1345 """ MPLS IPv4 Multicast Tail """
1348 # Add a multicast route that will forward the traffic
1351 route_232_1_1_1 = VppIpMRoute(
1355 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1357 paths=[VppMRoutePath(self.pg1.sw_if_index,
1358 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1359 route_232_1_1_1.add_vpp_config()
1362 # An interface receive label that maps traffic to RX on interface
1364 # by injecting the packet in on pg0, which is in table 0
1365 # doing an rpf-id and matching a route in table 1
1366 # if the packet egresses, then we must have matched the route in
1369 route_34_eos = VppMplsRoute(
1371 [VppRoutePath("0.0.0.0",
1376 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1378 route_34_eos.add_vpp_config()
1381 # Drop due to interface lookup miss
1383 self.vapi.cli("clear trace")
1384 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1385 dst_ip="232.1.1.1", n=1)
1386 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1389 # set the RPF-ID of the entry to match the input packet's
1391 route_232_1_1_1.update_rpf_id(55)
1392 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1394 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1396 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1397 self.verify_capture_ip4(self.pg1, rx, tx)
1400 # disposed packets have an invalid IPv4 checksum
1402 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1403 dst_ip="232.1.1.1", n=65,
1405 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1408 # set the RPF-ID of the entry to not match the input packet's
1410 route_232_1_1_1.update_rpf_id(56)
1411 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1413 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1415 def test_mcast_ip6_tail(self):
1416 """ MPLS IPv6 Multicast Tail """
1419 # Add a multicast route that will forward the traffic
1422 route_ff = VppIpMRoute(
1426 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1428 paths=[VppMRoutePath(self.pg1.sw_if_index,
1429 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
1430 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1431 route_ff.add_vpp_config()
1434 # An interface receive label that maps traffic to RX on interface
1436 # by injecting the packet in on pg0, which is in table 0
1437 # doing an rpf-id and matching a route in table 1
1438 # if the packet egresses, then we must have matched the route in
1441 route_34_eos = VppMplsRoute(
1448 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1450 route_34_eos.add_vpp_config()
1453 # Drop due to interface lookup miss
1455 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1457 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1460 # set the RPF-ID of the entry to match the input packet's
1462 route_ff.update_rpf_id(55)
1464 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1466 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1467 self.verify_capture_ip6(self.pg1, rx, tx)
1470 # disposed packets have hop-limit = 1
1472 tx = self.create_stream_labelled_ip6(self.pg0,
1476 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1477 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1480 # set the RPF-ID of the entry to not match the input packet's
1482 route_ff.update_rpf_id(56)
1483 tx = self.create_stream_labelled_ip6(self.pg0,
1486 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1492 # Add a non-recursive route with a single out label
1494 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1495 [VppRoutePath(self.pg0.remote_ip4,
1496 self.pg0.sw_if_index,
1497 labels=[VppMplsLabel(45)])])
1498 route_10_0_0_1.add_vpp_config()
1500 # bind a local label to the route
1501 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1502 binding.add_vpp_config()
1505 # a labelled v6 route that resolves through the v4
1507 route_2001_3 = VppIpRoute(
1508 self, "2001::3", 128,
1509 [VppRoutePath("10.0.0.1",
1511 labels=[VppMplsLabel(32)])])
1512 route_2001_3.add_vpp_config()
1514 tx = self.create_stream_ip6(self.pg0, "2001::3")
1515 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1517 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1522 # and a v4 recursive via the v6
1524 route_20_3 = VppIpRoute(
1525 self, "20.0.0.3", 32,
1526 [VppRoutePath("2001::3",
1528 labels=[VppMplsLabel(99)])])
1529 route_20_3.add_vpp_config()
1531 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1532 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1534 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1540 class TestMPLSDisabled(VppTestCase):
1541 """ MPLS disabled """
1544 def setUpClass(cls):
1545 super(TestMPLSDisabled, cls).setUpClass()
1548 def tearDownClass(cls):
1549 super(TestMPLSDisabled, cls).tearDownClass()
1552 super(TestMPLSDisabled, self).setUp()
1554 # create 2 pg interfaces
1555 self.create_pg_interfaces(range(2))
1557 self.tbl = VppMplsTable(self, 0)
1558 self.tbl.add_vpp_config()
1560 # PG0 is MPLS enabled
1562 self.pg0.config_ip4()
1563 self.pg0.resolve_arp()
1564 self.pg0.enable_mpls()
1566 # PG 1 is not MPLS enabled
1570 for i in self.pg_interfaces:
1574 self.pg0.disable_mpls()
1575 super(TestMPLSDisabled, self).tearDown()
1577 def test_mpls_disabled(self):
1578 """ MPLS Disabled """
1580 tx = (Ether(src=self.pg1.remote_mac,
1581 dst=self.pg1.local_mac) /
1582 MPLS(label=32, ttl=64) /
1583 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1584 UDP(sport=1234, dport=1234) /
1588 # A simple MPLS xconnect - eos label in label out
1590 route_32_eos = VppMplsRoute(self, 32, 1,
1591 [VppRoutePath(self.pg0.remote_ip4,
1592 self.pg0.sw_if_index,
1594 route_32_eos.add_vpp_config()
1597 # PG1 does not forward IP traffic
1599 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1604 self.pg1.enable_mpls()
1607 # Now we get packets through
1609 self.pg1.add_stream(tx)
1610 self.pg_enable_capture(self.pg_interfaces)
1613 rx = self.pg0.get_capture(1)
1618 self.pg1.disable_mpls()
1621 # PG1 does not forward IP traffic
1623 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1624 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1627 class TestMPLSPIC(VppTestCase):
1628 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1631 def setUpClass(cls):
1632 super(TestMPLSPIC, cls).setUpClass()
1635 def tearDownClass(cls):
1636 super(TestMPLSPIC, cls).tearDownClass()
1639 super(TestMPLSPIC, self).setUp()
1641 # create 2 pg interfaces
1642 self.create_pg_interfaces(range(4))
1644 mpls_tbl = VppMplsTable(self, 0)
1645 mpls_tbl.add_vpp_config()
1646 tbl4 = VppIpTable(self, 1)
1647 tbl4.add_vpp_config()
1648 tbl6 = VppIpTable(self, 1, is_ip6=1)
1649 tbl6.add_vpp_config()
1653 self.pg0.config_ip4()
1654 self.pg0.resolve_arp()
1655 self.pg0.enable_mpls()
1658 self.pg1.config_ip4()
1659 self.pg1.resolve_arp()
1660 self.pg1.enable_mpls()
1662 # VRF (customer facing) link
1664 self.pg2.set_table_ip4(1)
1665 self.pg2.config_ip4()
1666 self.pg2.resolve_arp()
1667 self.pg2.set_table_ip6(1)
1668 self.pg2.config_ip6()
1669 self.pg2.resolve_ndp()
1672 self.pg3.set_table_ip4(1)
1673 self.pg3.config_ip4()
1674 self.pg3.resolve_arp()
1675 self.pg3.set_table_ip6(1)
1676 self.pg3.config_ip6()
1677 self.pg3.resolve_ndp()
1680 self.pg0.disable_mpls()
1681 self.pg1.disable_mpls()
1682 for i in self.pg_interfaces:
1688 super(TestMPLSPIC, self).tearDown()
1690 def test_mpls_ibgp_pic(self):
1691 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1693 1) setup many iBGP VPN routes via a pair of iBGP peers.
1694 2) Check EMCP forwarding to these peers
1695 3) withdraw the IGP route to one of these peers.
1696 4) check forwarding continues to the remaining peer
1700 # IGP+LDP core routes
1702 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1703 [VppRoutePath(self.pg0.remote_ip4,
1704 self.pg0.sw_if_index,
1706 core_10_0_0_45.add_vpp_config()
1708 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1709 [VppRoutePath(self.pg1.remote_ip4,
1710 self.pg1.sw_if_index,
1712 core_10_0_0_46.add_vpp_config()
1715 # Lot's of VPN routes. We need more the 64 so VPP will build
1716 # the fast convergence indirection
1720 for ii in range(NUM_PKTS):
1721 dst = "192.168.1.%d" % ii
1722 vpn_routes.append(VppIpRoute(
1728 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1733 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1735 vpn_routes[ii].add_vpp_config()
1737 pkts.append(Ether(dst=self.pg2.local_mac,
1738 src=self.pg2.remote_mac) /
1739 IP(src=self.pg2.remote_ip4, dst=dst) /
1740 UDP(sport=1234, dport=1234) /
1744 # Send the packet stream (one pkt to each VPN route)
1745 # - expect a 50-50 split of the traffic
1747 self.pg2.add_stream(pkts)
1748 self.pg_enable_capture(self.pg_interfaces)
1751 rx0 = self.pg0._get_capture(NUM_PKTS)
1752 rx1 = self.pg1._get_capture(NUM_PKTS)
1754 # not testing the LB hashing algorithm so we're not concerned
1755 # with the split ratio, just as long as neither is 0
1756 self.assertNotEqual(0, len(rx0))
1757 self.assertNotEqual(0, len(rx1))
1758 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1759 "Expected all (%s) packets across both ECMP paths. "
1760 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1763 # use a test CLI command to stop the FIB walk process, this
1764 # will prevent the FIB converging the VPN routes and thus allow
1765 # us to probe the interim (post-fail, pre-converge) state
1767 self.vapi.ppcli("test fib-walk-process disable")
1770 # Withdraw one of the IGP routes
1772 core_10_0_0_46.remove_vpp_config()
1775 # now all packets should be forwarded through the remaining peer
1777 self.vapi.ppcli("clear trace")
1778 self.pg2.add_stream(pkts)
1779 self.pg_enable_capture(self.pg_interfaces)
1782 rx0 = self.pg0.get_capture(NUM_PKTS)
1783 self.assertEqual(len(pkts), len(rx0),
1784 "Expected all (%s) packets across single path. "
1785 "rx0: %s." % (len(pkts), len(rx0)))
1788 # enable the FIB walk process to converge the FIB
1790 self.vapi.ppcli("test fib-walk-process enable")
1793 # packets should still be forwarded through the remaining peer
1795 self.pg2.add_stream(pkts)
1796 self.pg_enable_capture(self.pg_interfaces)
1799 rx0 = self.pg0.get_capture(NUM_PKTS)
1800 self.assertEqual(len(pkts), len(rx0),
1801 "Expected all (%s) packets across single path. "
1802 "rx0: %s." % (len(pkts), len(rx0)))
1805 # Add the IGP route back and we return to load-balancing
1807 core_10_0_0_46.add_vpp_config()
1809 self.pg2.add_stream(pkts)
1810 self.pg_enable_capture(self.pg_interfaces)
1813 rx0 = self.pg0._get_capture(NUM_PKTS)
1814 rx1 = self.pg1._get_capture(NUM_PKTS)
1815 self.assertNotEqual(0, len(rx0))
1816 self.assertNotEqual(0, len(rx1))
1817 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1818 "Expected all (%s) packets across both ECMP paths. "
1819 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1821 def test_mpls_ebgp_pic(self):
1822 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1824 1) setup many eBGP VPN routes via a pair of eBGP peers.
1825 2) Check EMCP forwarding to these peers
1826 3) withdraw one eBGP path - expect LB across remaining eBGP
1830 # Lot's of VPN routes. We need more the 64 so VPP will build
1831 # the fast convergence indirection
1836 for ii in range(NUM_PKTS):
1837 dst = "192.168.1.%d" % ii
1838 local_label = 1600 + ii
1839 vpn_routes.append(VppIpRoute(
1842 self.pg2.remote_ip4,
1845 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1847 self.pg3.remote_ip4,
1850 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1852 vpn_routes[ii].add_vpp_config()
1854 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1856 vpn_bindings[ii].add_vpp_config()
1858 pkts.append(Ether(dst=self.pg0.local_mac,
1859 src=self.pg0.remote_mac) /
1860 MPLS(label=local_label, ttl=64) /
1861 IP(src=self.pg0.remote_ip4, dst=dst) /
1862 UDP(sport=1234, dport=1234) /
1866 # Send the packet stream (one pkt to each VPN route)
1867 # - expect a 50-50 split of the traffic
1869 self.pg0.add_stream(pkts)
1870 self.pg_enable_capture(self.pg_interfaces)
1873 rx0 = self.pg2._get_capture(NUM_PKTS)
1874 rx1 = self.pg3._get_capture(NUM_PKTS)
1876 # not testing the LB hashing algorithm so we're not concerned
1877 # with the split ratio, just as long as neither is 0
1878 self.assertNotEqual(0, len(rx0))
1879 self.assertNotEqual(0, len(rx1))
1880 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1881 "Expected all (%s) packets across both ECMP paths. "
1882 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1885 # use a test CLI command to stop the FIB walk process, this
1886 # will prevent the FIB converging the VPN routes and thus allow
1887 # us to probe the interim (post-fail, pre-converge) state
1889 self.vapi.ppcli("test fib-walk-process disable")
1892 # withdraw the connected prefix on the interface.
1894 self.pg2.unconfig_ip4()
1897 # now all packets should be forwarded through the remaining peer
1899 self.pg0.add_stream(pkts)
1900 self.pg_enable_capture(self.pg_interfaces)
1903 rx0 = self.pg3.get_capture(NUM_PKTS)
1904 self.assertEqual(len(pkts), len(rx0),
1905 "Expected all (%s) packets across single path. "
1906 "rx0: %s." % (len(pkts), len(rx0)))
1909 # enable the FIB walk process to converge the FIB
1911 self.vapi.ppcli("test fib-walk-process enable")
1914 # packets should still be forwarded through the remaining peer
1916 self.pg0.add_stream(pkts)
1917 self.pg_enable_capture(self.pg_interfaces)
1920 rx0 = self.pg3.get_capture(NUM_PKTS)
1921 self.assertEqual(len(pkts), len(rx0),
1922 "Expected all (%s) packets across single path. "
1923 "rx0: %s." % (len(pkts), len(rx0)))
1926 # put the connected routes back
1928 self.pg2.config_ip4()
1929 self.pg2.resolve_arp()
1931 self.pg0.add_stream(pkts)
1932 self.pg_enable_capture(self.pg_interfaces)
1935 rx0 = self.pg2._get_capture(NUM_PKTS)
1936 rx1 = self.pg3._get_capture(NUM_PKTS)
1937 self.assertNotEqual(0, len(rx0))
1938 self.assertNotEqual(0, len(rx1))
1939 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1940 "Expected all (%s) packets across both ECMP paths. "
1941 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1943 def test_mpls_v6_ebgp_pic(self):
1944 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1946 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1947 2) Check EMCP forwarding to these peers
1948 3) withdraw one eBGP path - expect LB across remaining eBGP
1952 # Lot's of VPN routes. We need more the 64 so VPP will build
1953 # the fast convergence indirection
1958 for ii in range(NUM_PKTS):
1959 dst = "3000::%d" % ii
1960 local_label = 1600 + ii
1961 vpn_routes.append(VppIpRoute(
1964 self.pg2.remote_ip6,
1967 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1969 self.pg3.remote_ip6,
1972 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1974 vpn_routes[ii].add_vpp_config()
1976 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1978 vpn_bindings[ii].add_vpp_config()
1980 pkts.append(Ether(dst=self.pg0.local_mac,
1981 src=self.pg0.remote_mac) /
1982 MPLS(label=local_label, ttl=64) /
1983 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1984 UDP(sport=1234, dport=1234) /
1986 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
1988 self.pg0.add_stream(pkts)
1989 self.pg_enable_capture(self.pg_interfaces)
1992 rx0 = self.pg2._get_capture(NUM_PKTS)
1993 rx1 = self.pg3._get_capture(NUM_PKTS)
1994 self.assertNotEqual(0, len(rx0))
1995 self.assertNotEqual(0, len(rx1))
1996 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1997 "Expected all (%s) packets across both ECMP paths. "
1998 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2001 # use a test CLI command to stop the FIB walk process, this
2002 # will prevent the FIB converging the VPN routes and thus allow
2003 # us to probe the interim (post-fail, pre-converge) state
2005 self.vapi.ppcli("test fib-walk-process disable")
2008 # withdraw the connected prefix on the interface.
2009 # and shutdown the interface so the ND cache is flushed.
2011 self.pg2.unconfig_ip6()
2012 self.pg2.admin_down()
2015 # now all packets should be forwarded through the remaining peer
2017 self.pg0.add_stream(pkts)
2018 self.pg_enable_capture(self.pg_interfaces)
2021 rx0 = self.pg3.get_capture(NUM_PKTS)
2022 self.assertEqual(len(pkts), len(rx0),
2023 "Expected all (%s) packets across single path. "
2024 "rx0: %s." % (len(pkts), len(rx0)))
2027 # enable the FIB walk process to converge the FIB
2029 self.vapi.ppcli("test fib-walk-process enable")
2030 self.pg0.add_stream(pkts)
2031 self.pg_enable_capture(self.pg_interfaces)
2034 rx0 = self.pg3.get_capture(NUM_PKTS)
2035 self.assertEqual(len(pkts), len(rx0),
2036 "Expected all (%s) packets across single path. "
2037 "rx0: %s." % (len(pkts), len(rx0)))
2040 # put the connected routes back
2043 self.pg2.config_ip6()
2044 self.pg2.resolve_ndp()
2046 self.pg0.add_stream(pkts)
2047 self.pg_enable_capture(self.pg_interfaces)
2050 rx0 = self.pg2._get_capture(NUM_PKTS)
2051 rx1 = self.pg3._get_capture(NUM_PKTS)
2052 self.assertNotEqual(0, len(rx0))
2053 self.assertNotEqual(0, len(rx1))
2054 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2055 "Expected all (%s) packets across both ECMP paths. "
2056 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2059 class TestMPLSL2(VppTestCase):
2063 def setUpClass(cls):
2064 super(TestMPLSL2, cls).setUpClass()
2067 def tearDownClass(cls):
2068 super(TestMPLSL2, cls).tearDownClass()
2071 super(TestMPLSL2, self).setUp()
2073 # create 2 pg interfaces
2074 self.create_pg_interfaces(range(2))
2076 # create the default MPLS table
2078 tbl = VppMplsTable(self, 0)
2079 tbl.add_vpp_config()
2080 self.tables.append(tbl)
2082 # use pg0 as the core facing interface
2084 self.pg0.config_ip4()
2085 self.pg0.resolve_arp()
2086 self.pg0.enable_mpls()
2088 # use the other 2 for customer facing L2 links
2089 for i in self.pg_interfaces[1:]:
2093 for i in self.pg_interfaces[1:]:
2096 self.pg0.disable_mpls()
2097 self.pg0.unconfig_ip4()
2098 self.pg0.admin_down()
2099 super(TestMPLSL2, self).tearDown()
2101 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2102 capture = verify_filter(capture, sent)
2104 self.assertEqual(len(capture), len(sent))
2106 for i in range(len(capture)):
2110 # the MPLS TTL is 255 since it enters a new tunnel
2111 verify_mpls_stack(self, rx, mpls_labels)
2114 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2116 self.assertEqual(rx_eth.src, tx_eth.src)
2117 self.assertEqual(rx_eth.dst, tx_eth.dst)
2119 def test_vpws(self):
2120 """ Virtual Private Wire Service """
2123 # Create an MPLS tunnel that pushes 1 label
2124 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2125 # information is not in the packet, but we test it works anyway
2127 mpls_tun_1 = VppMPLSTunnelInterface(
2129 [VppRoutePath(self.pg0.remote_ip4,
2130 self.pg0.sw_if_index,
2131 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2133 mpls_tun_1.add_vpp_config()
2134 mpls_tun_1.admin_up()
2137 # Create a label entry to for 55 that does L2 input to the tunnel
2139 route_55_eos = VppMplsRoute(
2141 [VppRoutePath("0.0.0.0",
2142 mpls_tun_1.sw_if_index,
2143 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2144 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2145 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2146 route_55_eos.add_vpp_config()
2149 # Cross-connect the tunnel with one of the customers L2 interfaces
2151 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2152 mpls_tun_1.sw_if_index,
2154 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2155 self.pg1.sw_if_index,
2159 # inject a packet from the core
2161 pcore = (Ether(dst=self.pg0.local_mac,
2162 src=self.pg0.remote_mac) /
2163 MPLS(label=55, ttl=64) /
2164 Ether(dst="00:00:de:ad:ba:be",
2165 src="00:00:de:ad:be:ef") /
2166 IP(src="10.10.10.10", dst="11.11.11.11") /
2167 UDP(sport=1234, dport=1234) /
2170 tx0 = pcore * NUM_PKTS
2171 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2172 payload = pcore[MPLS].payload
2174 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2175 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2178 # Inject a packet from the customer/L2 side
2180 tx1 = pcore[MPLS].payload * NUM_PKTS
2181 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2183 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2185 def test_vpls(self):
2186 """ Virtual Private LAN Service """
2188 # Create a L2 MPLS tunnels
2190 mpls_tun1 = VppMPLSTunnelInterface(
2192 [VppRoutePath(self.pg0.remote_ip4,
2193 self.pg0.sw_if_index,
2194 labels=[VppMplsLabel(42)])],
2196 mpls_tun1.add_vpp_config()
2197 mpls_tun1.admin_up()
2199 mpls_tun2 = VppMPLSTunnelInterface(
2201 [VppRoutePath(self.pg0.remote_ip4,
2202 self.pg0.sw_if_index,
2203 labels=[VppMplsLabel(43)])],
2205 mpls_tun2.add_vpp_config()
2206 mpls_tun2.admin_up()
2209 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2210 # the latter includes a Psuedo Wire Control Word
2212 route_55_eos = VppMplsRoute(
2214 [VppRoutePath("0.0.0.0",
2215 mpls_tun1.sw_if_index,
2216 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2217 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2218 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2220 route_56_eos = VppMplsRoute(
2222 [VppRoutePath("0.0.0.0",
2223 mpls_tun2.sw_if_index,
2224 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2225 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2226 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2227 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2230 route_56_eos.add_vpp_config()
2231 route_55_eos.add_vpp_config()
2233 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2236 # add to tunnel to the customers bridge-domain
2238 self.vapi.sw_interface_set_l2_bridge(
2239 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2240 self.vapi.sw_interface_set_l2_bridge(
2241 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2242 self.vapi.sw_interface_set_l2_bridge(
2243 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2246 # Packet from host on the customer interface to each host
2247 # reachable over the core, and vice-versa
2249 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2250 src="00:00:de:ad:be:ef") /
2251 IP(src="10.10.10.10", dst="11.11.11.11") /
2252 UDP(sport=1234, dport=1234) /
2254 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2255 src="00:00:de:ad:be:ef") /
2256 IP(src="10.10.10.10", dst="11.11.11.12") /
2257 UDP(sport=1234, dport=1234) /
2259 p_core1 = (Ether(dst=self.pg0.local_mac,
2260 src=self.pg0.remote_mac) /
2261 MPLS(label=55, ttl=64) /
2262 Ether(src="00:00:de:ad:ba:b1",
2263 dst="00:00:de:ad:be:ef") /
2264 IP(dst="10.10.10.10", src="11.11.11.11") /
2265 UDP(sport=1234, dport=1234) /
2267 p_core2 = (Ether(dst=self.pg0.local_mac,
2268 src=self.pg0.remote_mac) /
2269 MPLS(label=56, ttl=64) /
2270 Raw(b'\x01' * 4) / # PW CW
2271 Ether(src="00:00:de:ad:ba:b2",
2272 dst="00:00:de:ad:be:ef") /
2273 IP(dst="10.10.10.10", src="11.11.11.12") /
2274 UDP(sport=1234, dport=1234) /
2278 # The BD is learning, so send in one of each packet to learn
2281 # 2 packets due to BD flooding
2282 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2283 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2285 # we've learnt this so expect it be be forwarded not flooded
2286 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2287 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2288 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2290 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2291 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2292 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2295 # now a stream in each direction from each host
2297 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2298 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2301 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2302 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2305 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2306 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2309 # remove interfaces from customers bridge-domain
2311 self.vapi.sw_interface_set_l2_bridge(
2312 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2313 self.vapi.sw_interface_set_l2_bridge(
2314 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2315 self.vapi.sw_interface_set_l2_bridge(
2316 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2319 if __name__ == '__main__':
2320 unittest.main(testRunner=VppTestRunner)