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, ARP
18 from scapy.layers.inet import IP, UDP, ICMP
19 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
20 from scapy.contrib.mpls import MPLS
24 # scapy removed these attributes.
25 # we asked that they be restored: https://github.com/secdev/scapy/pull/1878
26 # semantic names have more meaning than numbers. so here they are.
31 def verify_filter(capture, sent):
32 if not len(capture) == len(sent):
33 # filter out any IPv6 RAs from the capture
40 def verify_mpls_stack(tst, rx, mpls_labels):
41 # the rx'd packet has the MPLS label popped
43 tst.assertEqual(eth.type, 0x8847)
47 for ii in range(len(mpls_labels)):
48 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
49 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
50 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
52 if ii == len(mpls_labels) - 1:
53 tst.assertEqual(rx_mpls.s, 1)
56 tst.assertEqual(rx_mpls.s, 0)
57 # pop the label to expose the next
58 rx_mpls = rx_mpls[MPLS].payload
61 class TestMPLS(VppTestCase):
62 """ MPLS Test Case """
66 super(TestMPLS, cls).setUpClass()
69 def tearDownClass(cls):
70 super(TestMPLS, cls).tearDownClass()
73 super(TestMPLS, self).setUp()
75 # create 2 pg interfaces
76 self.create_pg_interfaces(range(4))
78 # setup both interfaces
79 # assign them different tables.
83 tbl = VppMplsTable(self, 0)
85 self.tables.append(tbl)
87 for i in self.pg_interfaces:
91 tbl = VppIpTable(self, table_id)
93 self.tables.append(tbl)
94 tbl = VppIpTable(self, table_id, is_ip6=1)
96 self.tables.append(tbl)
98 i.set_table_ip4(table_id)
99 i.set_table_ip6(table_id)
108 for i in self.pg_interfaces:
116 super(TestMPLS, self).tearDown()
118 # the default of 64 matches the IP packet TTL default
119 def create_stream_labelled_ip4(
129 self.reset_packet_infos()
131 for i in range(0, n):
132 info = self.create_packet_info(src_if, src_if)
133 payload = self.info_to_payload(info)
134 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
136 for ii in range(len(mpls_labels)):
137 p = p / MPLS(label=mpls_labels[ii].value,
138 ttl=mpls_labels[ii].ttl,
139 cos=mpls_labels[ii].exp)
142 p = (p / IP(src=src_if.local_ip4,
143 dst=src_if.remote_ip4,
145 UDP(sport=1234, dport=1234) /
148 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
149 UDP(sport=1234, dport=1234) /
152 p = (p / IP(src=ip_itf.remote_ip4,
153 dst=ip_itf.local_ip4,
158 p[IP].chksum = chksum
163 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
164 self.reset_packet_infos()
166 for i in range(0, 257):
167 info = self.create_packet_info(src_if, src_if)
168 payload = self.info_to_payload(info)
169 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
170 IP(src=src_if.remote_ip4, dst=dst_ip,
171 ttl=ip_ttl, tos=ip_dscp) /
172 UDP(sport=1234, dport=1234) /
178 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
179 self.reset_packet_infos()
181 for i in range(0, 257):
182 info = self.create_packet_info(src_if, src_if)
183 payload = self.info_to_payload(info)
184 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
185 IPv6(src=src_if.remote_ip6, dst=dst_ip,
186 hlim=ip_ttl, tc=ip_dscp) /
187 UDP(sport=1234, dport=1234) /
193 def create_stream_labelled_ip6(self, src_if, mpls_labels,
194 hlim=64, dst_ip=None):
196 dst_ip = src_if.remote_ip6
197 self.reset_packet_infos()
199 for i in range(0, 257):
200 info = self.create_packet_info(src_if, src_if)
201 payload = self.info_to_payload(info)
202 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
203 for l in mpls_labels:
204 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
206 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
207 UDP(sport=1234, dport=1234) /
213 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
214 ip_ttl=None, ip_dscp=0):
216 capture = verify_filter(capture, sent)
218 self.assertEqual(len(capture), len(sent))
220 for i in range(len(capture)):
224 # the rx'd packet has the MPLS label popped
226 self.assertEqual(eth.type, 0x800)
232 self.assertEqual(rx_ip.src, tx_ip.src)
233 self.assertEqual(rx_ip.dst, tx_ip.dst)
234 self.assertEqual(rx_ip.tos, ip_dscp)
236 # IP processing post pop has decremented the TTL
237 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
239 self.assertEqual(rx_ip.ttl, ip_ttl)
241 self.assertEqual(rx_ip.src, tx_ip.dst)
242 self.assertEqual(rx_ip.dst, tx_ip.src)
247 def verify_capture_labelled_ip4(self, src_if, capture, sent,
248 mpls_labels, ip_ttl=None):
250 capture = verify_filter(capture, sent)
252 self.assertEqual(len(capture), len(sent))
254 for i in range(len(capture)):
260 verify_mpls_stack(self, rx, mpls_labels)
262 self.assertEqual(rx_ip.src, tx_ip.src)
263 self.assertEqual(rx_ip.dst, tx_ip.dst)
265 # IP processing post pop has decremented the TTL
266 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
268 self.assertEqual(rx_ip.ttl, ip_ttl)
273 def verify_capture_labelled_ip6(self, src_if, capture, sent,
274 mpls_labels, ip_ttl=None):
276 capture = verify_filter(capture, sent)
278 self.assertEqual(len(capture), len(sent))
280 for i in range(len(capture)):
286 verify_mpls_stack(self, rx, mpls_labels)
288 self.assertEqual(rx_ip.src, tx_ip.src)
289 self.assertEqual(rx_ip.dst, tx_ip.dst)
291 # IP processing post pop has decremented the TTL
292 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
294 self.assertEqual(rx_ip.hlim, ip_ttl)
299 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
301 capture = verify_filter(capture, sent)
303 self.assertEqual(len(capture), len(sent))
305 for i in range(len(capture)):
311 verify_mpls_stack(self, rx, mpls_labels)
313 self.assertEqual(rx_ip.src, tx_ip.src)
314 self.assertEqual(rx_ip.dst, tx_ip.dst)
315 # IP processing post pop has decremented the TTL
316 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
321 def verify_capture_labelled(self, src_if, capture, sent,
324 capture = verify_filter(capture, sent)
326 self.assertEqual(len(capture), len(sent))
328 for i in range(len(capture)):
330 verify_mpls_stack(self, rx, mpls_labels)
334 def verify_capture_ip6(self, src_if, capture, sent,
335 ip_hlim=None, ip_dscp=0):
337 self.assertEqual(len(capture), len(sent))
339 for i in range(len(capture)):
343 # the rx'd packet has the MPLS label popped
345 self.assertEqual(eth.type, 0x86DD)
350 self.assertEqual(rx_ip.src, tx_ip.src)
351 self.assertEqual(rx_ip.dst, tx_ip.dst)
352 self.assertEqual(rx_ip.tc, ip_dscp)
353 # IP processing post pop has decremented the TTL
355 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
357 self.assertEqual(rx_ip.hlim, ip_hlim)
362 def verify_capture_ip6_icmp(self, src_if, capture, sent):
364 self.assertEqual(len(capture), len(sent))
366 for i in range(len(capture)):
370 # the rx'd packet has the MPLS label popped
372 self.assertEqual(eth.type, 0x86DD)
377 self.assertEqual(rx_ip.dst, tx_ip.src)
378 # ICMP sourced from the interface's address
379 self.assertEqual(rx_ip.src, src_if.local_ip6)
380 # hop-limit reset to 255 for IMCP packet
381 self.assertEqual(rx_ip.hlim, 255)
383 icmp = rx[ICMPv6TimeExceeded]
388 def verify_capture_fragmented_labelled_ip4(self, src_if, capture, sent,
389 mpls_labels, ip_ttl=None):
391 capture = verify_filter(capture, sent)
393 for i in range(len(capture)):
399 verify_mpls_stack(self, rx, mpls_labels)
401 self.assertEqual(rx_ip.src, tx_ip.src)
402 self.assertEqual(rx_ip.dst, tx_ip.dst)
404 # IP processing post pop has decremented the TTL
405 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
407 self.assertEqual(rx_ip.ttl, ip_ttl)
413 """ MPLS label swap tests """
416 # A simple MPLS xconnect - eos label in label out
418 route_32_eos = VppMplsRoute(self, 32, 1,
419 [VppRoutePath(self.pg0.remote_ip4,
420 self.pg0.sw_if_index,
421 labels=[VppMplsLabel(33)])])
422 route_32_eos.add_vpp_config()
425 find_mpls_route(self, 0, 32, 1,
426 [VppRoutePath(self.pg0.remote_ip4,
427 self.pg0.sw_if_index,
428 labels=[VppMplsLabel(33)])]))
431 # a stream that matches the route for 10.0.0.1
432 # PG0 is in the default table
434 tx = self.create_stream_labelled_ip4(self.pg0,
435 [VppMplsLabel(32, ttl=32, exp=1)])
436 rx = self.send_and_expect(self.pg0, tx, self.pg0)
437 self.verify_capture_labelled(self.pg0, rx, tx,
438 [VppMplsLabel(33, ttl=31, exp=1)])
440 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
443 # A simple MPLS xconnect - non-eos label in label out
445 route_32_neos = VppMplsRoute(self, 32, 0,
446 [VppRoutePath(self.pg0.remote_ip4,
447 self.pg0.sw_if_index,
448 labels=[VppMplsLabel(33)])])
449 route_32_neos.add_vpp_config()
452 # a stream that matches the route for 10.0.0.1
453 # PG0 is in the default table
455 tx = self.create_stream_labelled_ip4(self.pg0,
456 [VppMplsLabel(32, ttl=21, exp=7),
458 rx = self.send_and_expect(self.pg0, tx, self.pg0)
459 self.verify_capture_labelled(self.pg0, rx, tx,
460 [VppMplsLabel(33, ttl=20, exp=7),
462 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
465 # A simple MPLS xconnect - non-eos label in label out, uniform mode
467 route_42_neos = VppMplsRoute(
469 [VppRoutePath(self.pg0.remote_ip4,
470 self.pg0.sw_if_index,
471 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
472 route_42_neos.add_vpp_config()
474 tx = self.create_stream_labelled_ip4(self.pg0,
475 [VppMplsLabel(42, ttl=21, exp=7),
477 rx = self.send_and_expect(self.pg0, tx, self.pg0)
478 self.verify_capture_labelled(self.pg0, rx, tx,
479 [VppMplsLabel(43, ttl=20, exp=7),
483 # An MPLS xconnect - EOS label in IP out
485 route_33_eos = VppMplsRoute(self, 33, 1,
486 [VppRoutePath(self.pg0.remote_ip4,
487 self.pg0.sw_if_index,
489 route_33_eos.add_vpp_config()
491 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
492 rx = self.send_and_expect(self.pg0, tx, self.pg0)
493 self.verify_capture_ip4(self.pg0, rx, tx)
496 # disposed packets have an invalid IPv4 checksum
498 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
499 dst_ip=self.pg0.remote_ip4,
502 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
505 # An MPLS xconnect - EOS label in IP out, uniform mode
507 route_3333_eos = VppMplsRoute(
509 [VppRoutePath(self.pg0.remote_ip4,
510 self.pg0.sw_if_index,
511 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
512 route_3333_eos.add_vpp_config()
514 tx = self.create_stream_labelled_ip4(
516 [VppMplsLabel(3333, ttl=55, exp=3)])
517 rx = self.send_and_expect(self.pg0, tx, self.pg0)
518 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
519 tx = self.create_stream_labelled_ip4(
521 [VppMplsLabel(3333, ttl=66, exp=4)])
522 rx = self.send_and_expect(self.pg0, tx, self.pg0)
523 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
526 # An MPLS xconnect - EOS label in IPv6 out
528 route_333_eos = VppMplsRoute(
530 [VppRoutePath(self.pg0.remote_ip6,
531 self.pg0.sw_if_index,
533 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
534 route_333_eos.add_vpp_config()
536 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
537 rx = self.send_and_expect(self.pg0, tx, self.pg0)
538 self.verify_capture_ip6(self.pg0, rx, tx)
541 # disposed packets have an TTL expired
543 tx = self.create_stream_labelled_ip6(self.pg0,
544 [VppMplsLabel(333, ttl=64)],
545 dst_ip=self.pg1.remote_ip6,
547 rx = self.send_and_expect(self.pg0, tx, self.pg0)
548 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
551 # An MPLS xconnect - EOS label in IPv6 out w imp-null
553 route_334_eos = VppMplsRoute(
555 [VppRoutePath(self.pg0.remote_ip6,
556 self.pg0.sw_if_index,
557 labels=[VppMplsLabel(3)])],
558 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
559 route_334_eos.add_vpp_config()
561 tx = self.create_stream_labelled_ip6(self.pg0,
562 [VppMplsLabel(334, ttl=64)])
563 rx = self.send_and_expect(self.pg0, tx, self.pg0)
564 self.verify_capture_ip6(self.pg0, rx, tx)
567 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
569 route_335_eos = VppMplsRoute(
571 [VppRoutePath(self.pg0.remote_ip6,
572 self.pg0.sw_if_index,
573 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
574 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
575 route_335_eos.add_vpp_config()
577 tx = self.create_stream_labelled_ip6(
579 [VppMplsLabel(335, ttl=27, exp=4)])
580 rx = self.send_and_expect(self.pg0, tx, self.pg0)
581 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
584 # disposed packets have an TTL expired
586 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
587 dst_ip=self.pg1.remote_ip6,
589 rx = self.send_and_expect(self.pg0, tx, self.pg0)
590 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
593 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
594 # so this traffic should be dropped.
596 route_33_neos = VppMplsRoute(self, 33, 0,
597 [VppRoutePath(self.pg0.remote_ip4,
598 self.pg0.sw_if_index,
600 route_33_neos.add_vpp_config()
602 tx = self.create_stream_labelled_ip4(self.pg0,
605 self.send_and_assert_no_replies(
607 "MPLS non-EOS packets popped and forwarded")
610 # A recursive EOS x-connect, which resolves through another x-connect
613 route_34_eos = VppMplsRoute(self, 34, 1,
614 [VppRoutePath("0.0.0.0",
617 labels=[VppMplsLabel(44),
619 route_34_eos.add_vpp_config()
620 self.logger.info(self.vapi.cli("sh mpls fib 34"))
622 tx = self.create_stream_labelled_ip4(self.pg0,
623 [VppMplsLabel(34, ttl=3)])
624 rx = self.send_and_expect(self.pg0, tx, self.pg0)
625 self.verify_capture_labelled(self.pg0, rx, tx,
628 VppMplsLabel(45, ttl=2)])
630 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
631 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
634 # A recursive EOS x-connect, which resolves through another x-connect
637 route_35_eos = VppMplsRoute(
639 [VppRoutePath("0.0.0.0",
642 labels=[VppMplsLabel(44)])])
643 route_35_eos.add_vpp_config()
645 tx = self.create_stream_labelled_ip4(self.pg0,
646 [VppMplsLabel(35, ttl=3)])
647 rx = self.send_and_expect(self.pg0, tx, self.pg0)
648 self.verify_capture_labelled(self.pg0, rx, tx,
649 [VppMplsLabel(43, ttl=2),
650 VppMplsLabel(44, ttl=2)])
653 # A recursive non-EOS x-connect, which resolves through another
656 route_34_neos = VppMplsRoute(self, 34, 0,
657 [VppRoutePath("0.0.0.0",
660 labels=[VppMplsLabel(44),
662 route_34_neos.add_vpp_config()
664 tx = self.create_stream_labelled_ip4(self.pg0,
665 [VppMplsLabel(34, ttl=45),
667 rx = self.send_and_expect(self.pg0, tx, self.pg0)
668 # it's the 2nd (counting from 0) label in the stack that is swapped
669 self.verify_capture_labelled(self.pg0, rx, tx,
672 VppMplsLabel(46, ttl=44),
676 # an recursive IP route that resolves through the recursive non-eos
679 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
680 [VppRoutePath("0.0.0.0",
683 labels=[VppMplsLabel(55)])])
684 ip_10_0_0_1.add_vpp_config()
686 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
687 rx = self.send_and_expect(self.pg0, tx, self.pg0)
688 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
693 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
695 ip_10_0_0_1.remove_vpp_config()
696 route_34_neos.remove_vpp_config()
697 route_34_eos.remove_vpp_config()
698 route_33_neos.remove_vpp_config()
699 route_33_eos.remove_vpp_config()
700 route_32_neos.remove_vpp_config()
701 route_32_eos.remove_vpp_config()
704 """ MPLS Local Label Binding test """
707 # Add a non-recursive route with a single out label
709 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
710 [VppRoutePath(self.pg0.remote_ip4,
711 self.pg0.sw_if_index,
712 labels=[VppMplsLabel(45)])])
713 route_10_0_0_1.add_vpp_config()
715 # bind a local label to the route
716 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
717 binding.add_vpp_config()
720 tx = self.create_stream_labelled_ip4(self.pg0,
723 rx = self.send_and_expect(self.pg0, tx, self.pg0)
724 self.verify_capture_labelled(self.pg0, rx, tx,
725 [VppMplsLabel(45, ttl=63),
729 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
730 rx = self.send_and_expect(self.pg0, tx, self.pg0)
731 self.verify_capture_labelled(self.pg0, rx, tx,
732 [VppMplsLabel(45, ttl=63)])
735 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
736 rx = self.send_and_expect(self.pg0, tx, self.pg0)
737 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
742 binding.remove_vpp_config()
743 route_10_0_0_1.remove_vpp_config()
745 def test_imposition(self):
746 """ MPLS label imposition test """
749 # Add a non-recursive route with a single out label
751 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
752 [VppRoutePath(self.pg0.remote_ip4,
753 self.pg0.sw_if_index,
754 labels=[VppMplsLabel(32)])])
755 route_10_0_0_1.add_vpp_config()
758 # a stream that matches the route for 10.0.0.1
759 # PG0 is in the default table
761 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
762 rx = self.send_and_expect(self.pg0, tx, self.pg0)
763 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
766 # Add a non-recursive route with a 3 out labels
768 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
769 [VppRoutePath(self.pg0.remote_ip4,
770 self.pg0.sw_if_index,
771 labels=[VppMplsLabel(32),
774 route_10_0_0_2.add_vpp_config()
776 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
777 ip_ttl=44, ip_dscp=0xff)
778 rx = self.send_and_expect(self.pg0, tx, self.pg0)
779 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
786 # Add a non-recursive route with a single out label in uniform mode
788 route_10_0_0_3 = VppIpRoute(
789 self, "10.0.0.3", 32,
790 [VppRoutePath(self.pg0.remote_ip4,
791 self.pg0.sw_if_index,
792 labels=[VppMplsLabel(32,
793 mode=MplsLspMode.UNIFORM)])])
794 route_10_0_0_3.add_vpp_config()
796 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
797 ip_ttl=54, ip_dscp=0xbe)
798 rx = self.send_and_expect(self.pg0, tx, self.pg0)
799 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
800 [VppMplsLabel(32, ttl=53, exp=5)])
803 # Add a IPv6 non-recursive route with a single out label in
806 route_2001_3 = VppIpRoute(
807 self, "2001::3", 128,
808 [VppRoutePath(self.pg0.remote_ip6,
809 self.pg0.sw_if_index,
810 labels=[VppMplsLabel(32,
811 mode=MplsLspMode.UNIFORM)])])
812 route_2001_3.add_vpp_config()
814 tx = self.create_stream_ip6(self.pg0, "2001::3",
815 ip_ttl=54, ip_dscp=0xbe)
816 rx = self.send_and_expect(self.pg0, tx, self.pg0)
817 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
818 [VppMplsLabel(32, ttl=53, exp=5)])
821 # add a recursive path, with output label, via the 1 label route
823 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
824 [VppRoutePath("10.0.0.1",
826 labels=[VppMplsLabel(44)])])
827 route_11_0_0_1.add_vpp_config()
830 # a stream that matches the route for 11.0.0.1, should pick up
831 # the label stack for 11.0.0.1 and 10.0.0.1
833 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
834 rx = self.send_and_expect(self.pg0, tx, self.pg0)
835 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
839 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
842 # add a recursive path, with 2 labels, via the 3 label route
844 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
845 [VppRoutePath("10.0.0.2",
847 labels=[VppMplsLabel(44),
849 route_11_0_0_2.add_vpp_config()
852 # a stream that matches the route for 11.0.0.1, should pick up
853 # the label stack for 11.0.0.1 and 10.0.0.1
855 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
856 rx = self.send_and_expect(self.pg0, tx, self.pg0)
857 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
864 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
866 rx = self.send_and_expect(self.pg0, tx, self.pg0)
867 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
874 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
879 route_11_0_0_2.remove_vpp_config()
880 route_11_0_0_1.remove_vpp_config()
881 route_10_0_0_2.remove_vpp_config()
882 route_10_0_0_1.remove_vpp_config()
884 def test_imposition_fragmentation(self):
885 """ MPLS label imposition fragmentation test """
888 # Add a ipv4 non-recursive route with a single out label
890 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
891 [VppRoutePath(self.pg0.remote_ip4,
892 self.pg0.sw_if_index,
893 labels=[VppMplsLabel(32)])])
894 route_10_0_0_1.add_vpp_config()
897 # a stream that matches the route for 10.0.0.1
898 # PG0 is in the default table
900 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
901 for i in range(0, 257):
902 self.extend_packet(tx[i], 10000)
905 # 5 fragments per packet (257*5=1285)
907 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
908 self.verify_capture_fragmented_labelled_ip4(self.pg0, rx, tx,
914 route_10_0_0_1.remove_vpp_config()
916 def test_tunnel_pipe(self):
917 """ MPLS Tunnel Tests - Pipe """
920 # Create a tunnel with a single out label
922 mpls_tun = VppMPLSTunnelInterface(
924 [VppRoutePath(self.pg0.remote_ip4,
925 self.pg0.sw_if_index,
926 labels=[VppMplsLabel(44),
928 mpls_tun.add_vpp_config()
932 # add an unlabelled route through the new tunnel
934 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
935 [VppRoutePath("0.0.0.0",
936 mpls_tun._sw_if_index)])
937 route_10_0_0_3.add_vpp_config()
939 self.vapi.cli("clear trace")
940 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
941 self.pg0.add_stream(tx)
943 self.pg_enable_capture(self.pg_interfaces)
946 rx = self.pg0.get_capture()
947 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
952 # add a labelled route through the new tunnel
954 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
955 [VppRoutePath("0.0.0.0",
956 mpls_tun._sw_if_index,
958 route_10_0_0_4.add_vpp_config()
960 self.vapi.cli("clear trace")
961 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
962 self.pg0.add_stream(tx)
964 self.pg_enable_capture(self.pg_interfaces)
967 rx = self.pg0.get_capture()
968 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
971 VppMplsLabel(33, ttl=255)])
973 def test_tunnel_uniform(self):
974 """ MPLS Tunnel Tests - Uniform """
977 # Create a tunnel with a single out label
978 # The label stack is specified here from outer to inner
980 mpls_tun = VppMPLSTunnelInterface(
982 [VppRoutePath(self.pg0.remote_ip4,
983 self.pg0.sw_if_index,
984 labels=[VppMplsLabel(44, ttl=32),
985 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
986 mpls_tun.add_vpp_config()
990 # add an unlabelled route through the new tunnel
992 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
993 [VppRoutePath("0.0.0.0",
994 mpls_tun._sw_if_index)])
995 route_10_0_0_3.add_vpp_config()
997 self.vapi.cli("clear trace")
998 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
999 self.pg0.add_stream(tx)
1001 self.pg_enable_capture(self.pg_interfaces)
1004 rx = self.pg0.get_capture()
1005 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1006 [VppMplsLabel(44, ttl=32),
1007 VppMplsLabel(46, ttl=23)])
1010 # add a labelled route through the new tunnel
1012 route_10_0_0_4 = VppIpRoute(
1013 self, "10.0.0.4", 32,
1014 [VppRoutePath("0.0.0.0",
1015 mpls_tun._sw_if_index,
1016 labels=[VppMplsLabel(33, ttl=47)])])
1017 route_10_0_0_4.add_vpp_config()
1019 self.vapi.cli("clear trace")
1020 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1021 self.pg0.add_stream(tx)
1023 self.pg_enable_capture(self.pg_interfaces)
1026 rx = self.pg0.get_capture()
1027 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1028 [VppMplsLabel(44, ttl=32),
1029 VppMplsLabel(46, ttl=47),
1030 VppMplsLabel(33, ttl=47)])
1032 def test_mpls_tunnel_many(self):
1033 """ MPLS Multiple Tunnels """
1035 for ii in range(10):
1036 mpls_tun = VppMPLSTunnelInterface(
1038 [VppRoutePath(self.pg0.remote_ip4,
1039 self.pg0.sw_if_index,
1040 labels=[VppMplsLabel(44, ttl=32),
1041 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1042 mpls_tun.add_vpp_config()
1045 def test_v4_exp_null(self):
1046 """ MPLS V4 Explicit NULL test """
1049 # The first test case has an MPLS TTL of 0
1050 # all packet should be dropped
1052 tx = self.create_stream_labelled_ip4(self.pg0,
1053 [VppMplsLabel(0, ttl=0)])
1054 self.send_and_assert_no_replies(self.pg0, tx,
1055 "MPLS TTL=0 packets forwarded")
1058 # a stream with a non-zero MPLS TTL
1059 # PG0 is in the default table
1061 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1062 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1063 self.verify_capture_ip4(self.pg0, rx, tx)
1066 # a stream with a non-zero MPLS TTL
1068 # we are ensuring the post-pop lookup occurs in the VRF table
1070 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1071 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1072 self.verify_capture_ip4(self.pg1, rx, tx)
1074 def test_v6_exp_null(self):
1075 """ MPLS V6 Explicit NULL test """
1078 # a stream with a non-zero MPLS TTL
1079 # PG0 is in the default table
1081 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1082 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1083 self.verify_capture_ip6(self.pg0, rx, tx)
1086 # a stream with a non-zero MPLS TTL
1088 # we are ensuring the post-pop lookup occurs in the VRF table
1090 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1091 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1092 self.verify_capture_ip6(self.pg0, rx, tx)
1094 def test_deag(self):
1098 # A de-agg route - next-hop lookup in default table
1100 route_34_eos = VppMplsRoute(self, 34, 1,
1101 [VppRoutePath("0.0.0.0",
1104 route_34_eos.add_vpp_config()
1107 # ping an interface in the default table
1108 # PG0 is in the default table
1110 tx = self.create_stream_labelled_ip4(self.pg0,
1114 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1115 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1118 # A de-agg route - next-hop lookup in non-default table
1120 route_35_eos = VppMplsRoute(self, 35, 1,
1121 [VppRoutePath("0.0.0.0",
1124 route_35_eos.add_vpp_config()
1127 # ping an interface in the non-default table
1128 # PG0 is in the default table. packet arrive labelled in the
1129 # default table and egress unlabelled in the non-default
1131 tx = self.create_stream_labelled_ip4(
1132 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1133 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1134 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1139 route_36_neos = VppMplsRoute(self, 36, 0,
1140 [VppRoutePath("0.0.0.0",
1142 route_36_neos.add_vpp_config()
1144 tx = self.create_stream_labelled_ip4(self.pg0,
1147 ping=1, ip_itf=self.pg1)
1148 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1149 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1151 route_36_neos.remove_vpp_config()
1152 route_35_eos.remove_vpp_config()
1153 route_34_eos.remove_vpp_config()
1155 def test_interface_rx(self):
1156 """ MPLS Interface Receive """
1159 # Add a non-recursive route that will forward the traffic
1162 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1164 paths=[VppRoutePath(self.pg1.remote_ip4,
1165 self.pg1.sw_if_index)])
1166 route_10_0_0_1.add_vpp_config()
1169 # An interface receive label that maps traffic to RX on interface
1171 # by injecting the packet in on pg0, which is in table 0
1172 # doing an interface-rx on pg1 and matching a route in table 1
1173 # if the packet egresses, then we must have swapped to pg1
1174 # so as to have matched the route in table 1
1176 route_34_eos = VppMplsRoute(
1178 [VppRoutePath("0.0.0.0",
1179 self.pg1.sw_if_index,
1180 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1181 route_34_eos.add_vpp_config()
1184 # ping an interface in the default table
1185 # PG0 is in the default table
1187 tx = self.create_stream_labelled_ip4(self.pg0,
1190 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1191 self.verify_capture_ip4(self.pg1, rx, tx)
1193 def test_mcast_mid_point(self):
1194 """ MPLS Multicast Mid Point """
1197 # Add a non-recursive route that will forward the traffic
1200 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1202 paths=[VppRoutePath(self.pg1.remote_ip4,
1203 self.pg1.sw_if_index)])
1204 route_10_0_0_1.add_vpp_config()
1207 # Add a mcast entry that replicate to pg2 and pg3
1208 # and replicate to a interface-rx (like a bud node would)
1210 route_3400_eos = VppMplsRoute(
1212 [VppRoutePath(self.pg2.remote_ip4,
1213 self.pg2.sw_if_index,
1214 labels=[VppMplsLabel(3401)]),
1215 VppRoutePath(self.pg3.remote_ip4,
1216 self.pg3.sw_if_index,
1217 labels=[VppMplsLabel(3402)]),
1218 VppRoutePath("0.0.0.0",
1219 self.pg1.sw_if_index,
1220 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1222 route_3400_eos.add_vpp_config()
1225 # ping an interface in the default table
1226 # PG0 is in the default table
1228 self.vapi.cli("clear trace")
1229 tx = self.create_stream_labelled_ip4(self.pg0,
1230 [VppMplsLabel(3400, ttl=64)],
1233 self.pg0.add_stream(tx)
1235 self.pg_enable_capture(self.pg_interfaces)
1238 rx = self.pg1.get_capture(257)
1239 self.verify_capture_ip4(self.pg1, rx, tx)
1241 rx = self.pg2.get_capture(257)
1242 self.verify_capture_labelled(self.pg2, rx, tx,
1243 [VppMplsLabel(3401, ttl=63)])
1244 rx = self.pg3.get_capture(257)
1245 self.verify_capture_labelled(self.pg3, rx, tx,
1246 [VppMplsLabel(3402, ttl=63)])
1248 def test_mcast_head(self):
1249 """ MPLS Multicast Head-end """
1252 # Create a multicast tunnel with two replications
1254 mpls_tun = VppMPLSTunnelInterface(
1256 [VppRoutePath(self.pg2.remote_ip4,
1257 self.pg2.sw_if_index,
1258 labels=[VppMplsLabel(42)]),
1259 VppRoutePath(self.pg3.remote_ip4,
1260 self.pg3.sw_if_index,
1261 labels=[VppMplsLabel(43)])],
1263 mpls_tun.add_vpp_config()
1267 # add an unlabelled route through the new tunnel
1269 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1270 [VppRoutePath("0.0.0.0",
1271 mpls_tun._sw_if_index)])
1272 route_10_0_0_3.add_vpp_config()
1274 self.vapi.cli("clear trace")
1275 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1276 self.pg0.add_stream(tx)
1278 self.pg_enable_capture(self.pg_interfaces)
1281 rx = self.pg2.get_capture(257)
1282 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1283 rx = self.pg3.get_capture(257)
1284 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1287 # An an IP multicast route via the tunnel
1289 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1291 route_232_1_1_1 = VppIpMRoute(
1295 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1296 [VppMRoutePath(self.pg0.sw_if_index,
1297 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1298 VppMRoutePath(mpls_tun._sw_if_index,
1299 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1300 route_232_1_1_1.add_vpp_config()
1301 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1303 self.vapi.cli("clear trace")
1304 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
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)])
1315 def test_mcast_ip4_tail(self):
1316 """ MPLS IPv4 Multicast Tail """
1319 # Add a multicast route that will forward the traffic
1322 route_232_1_1_1 = VppIpMRoute(
1326 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1328 paths=[VppMRoutePath(self.pg1.sw_if_index,
1329 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1330 route_232_1_1_1.add_vpp_config()
1333 # An interface receive label that maps traffic to RX on interface
1335 # by injecting the packet in on pg0, which is in table 0
1336 # doing an rpf-id and matching a route in table 1
1337 # if the packet egresses, then we must have matched the route in
1340 route_34_eos = VppMplsRoute(
1342 [VppRoutePath("0.0.0.0",
1347 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1349 route_34_eos.add_vpp_config()
1352 # Drop due to interface lookup miss
1354 self.vapi.cli("clear trace")
1355 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1356 dst_ip="232.1.1.1", n=1)
1357 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1360 # set the RPF-ID of the entry to match the input packet's
1362 route_232_1_1_1.update_rpf_id(55)
1363 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1365 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1367 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1368 self.verify_capture_ip4(self.pg1, rx, tx)
1371 # disposed packets have an invalid IPv4 checksum
1373 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1374 dst_ip="232.1.1.1", n=65,
1376 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1379 # set the RPF-ID of the entry to not match the input packet's
1381 route_232_1_1_1.update_rpf_id(56)
1382 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1384 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1386 def test_mcast_ip6_tail(self):
1387 """ MPLS IPv6 Multicast Tail """
1390 # Add a multicast route that will forward the traffic
1393 route_ff = VppIpMRoute(
1397 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1399 paths=[VppMRoutePath(self.pg1.sw_if_index,
1400 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
1401 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1402 route_ff.add_vpp_config()
1405 # An interface receive label that maps traffic to RX on interface
1407 # by injecting the packet in on pg0, which is in table 0
1408 # doing an rpf-id and matching a route in table 1
1409 # if the packet egresses, then we must have matched the route in
1412 route_34_eos = VppMplsRoute(
1419 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1421 route_34_eos.add_vpp_config()
1424 # Drop due to interface lookup miss
1426 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1428 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1431 # set the RPF-ID of the entry to match the input packet's
1433 route_ff.update_rpf_id(55)
1435 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1437 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1438 self.verify_capture_ip6(self.pg1, rx, tx)
1441 # disposed packets have hop-limit = 1
1443 tx = self.create_stream_labelled_ip6(self.pg0,
1447 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1448 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1451 # set the RPF-ID of the entry to not match the input packet's
1453 route_ff.update_rpf_id(56)
1454 tx = self.create_stream_labelled_ip6(self.pg0,
1457 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1463 # Add a non-recursive route with a single out label
1465 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1466 [VppRoutePath(self.pg0.remote_ip4,
1467 self.pg0.sw_if_index,
1468 labels=[VppMplsLabel(45)])])
1469 route_10_0_0_1.add_vpp_config()
1471 # bind a local label to the route
1472 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1473 binding.add_vpp_config()
1476 # a labelled v6 route that resolves through the v4
1478 route_2001_3 = VppIpRoute(
1479 self, "2001::3", 128,
1480 [VppRoutePath("10.0.0.1",
1482 labels=[VppMplsLabel(32)])])
1483 route_2001_3.add_vpp_config()
1485 tx = self.create_stream_ip6(self.pg0, "2001::3")
1486 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1488 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1493 # and a v4 recursive via the v6
1495 route_20_3 = VppIpRoute(
1496 self, "20.0.0.3", 32,
1497 [VppRoutePath("2001::3",
1499 labels=[VppMplsLabel(99)])])
1500 route_20_3.add_vpp_config()
1502 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1503 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1505 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1511 class TestMPLSDisabled(VppTestCase):
1512 """ MPLS disabled """
1515 def setUpClass(cls):
1516 super(TestMPLSDisabled, cls).setUpClass()
1519 def tearDownClass(cls):
1520 super(TestMPLSDisabled, cls).tearDownClass()
1523 super(TestMPLSDisabled, self).setUp()
1525 # create 2 pg interfaces
1526 self.create_pg_interfaces(range(2))
1528 self.tbl = VppMplsTable(self, 0)
1529 self.tbl.add_vpp_config()
1531 # PG0 is MPLS enabled
1533 self.pg0.config_ip4()
1534 self.pg0.resolve_arp()
1535 self.pg0.enable_mpls()
1537 # PG 1 is not MPLS enabled
1541 for i in self.pg_interfaces:
1545 self.pg0.disable_mpls()
1546 super(TestMPLSDisabled, self).tearDown()
1548 def test_mpls_disabled(self):
1549 """ MPLS Disabled """
1551 tx = (Ether(src=self.pg1.remote_mac,
1552 dst=self.pg1.local_mac) /
1553 MPLS(label=32, ttl=64) /
1554 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1555 UDP(sport=1234, dport=1234) /
1559 # A simple MPLS xconnect - eos label in label out
1561 route_32_eos = VppMplsRoute(self, 32, 1,
1562 [VppRoutePath(self.pg0.remote_ip4,
1563 self.pg0.sw_if_index,
1565 route_32_eos.add_vpp_config()
1568 # PG1 does not forward IP traffic
1570 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1575 self.pg1.enable_mpls()
1578 # Now we get packets through
1580 self.pg1.add_stream(tx)
1581 self.pg_enable_capture(self.pg_interfaces)
1584 rx = self.pg0.get_capture(1)
1589 self.pg1.disable_mpls()
1592 # PG1 does not forward IP traffic
1594 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1595 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1598 class TestMPLSPIC(VppTestCase):
1599 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1602 def setUpClass(cls):
1603 super(TestMPLSPIC, cls).setUpClass()
1606 def tearDownClass(cls):
1607 super(TestMPLSPIC, cls).tearDownClass()
1610 super(TestMPLSPIC, self).setUp()
1612 # create 2 pg interfaces
1613 self.create_pg_interfaces(range(4))
1615 mpls_tbl = VppMplsTable(self, 0)
1616 mpls_tbl.add_vpp_config()
1617 tbl4 = VppIpTable(self, 1)
1618 tbl4.add_vpp_config()
1619 tbl6 = VppIpTable(self, 1, is_ip6=1)
1620 tbl6.add_vpp_config()
1624 self.pg0.config_ip4()
1625 self.pg0.resolve_arp()
1626 self.pg0.enable_mpls()
1629 self.pg1.config_ip4()
1630 self.pg1.resolve_arp()
1631 self.pg1.enable_mpls()
1633 # VRF (customer facing) link
1635 self.pg2.set_table_ip4(1)
1636 self.pg2.config_ip4()
1637 self.pg2.resolve_arp()
1638 self.pg2.set_table_ip6(1)
1639 self.pg2.config_ip6()
1640 self.pg2.resolve_ndp()
1643 self.pg3.set_table_ip4(1)
1644 self.pg3.config_ip4()
1645 self.pg3.resolve_arp()
1646 self.pg3.set_table_ip6(1)
1647 self.pg3.config_ip6()
1648 self.pg3.resolve_ndp()
1651 self.pg0.disable_mpls()
1652 self.pg1.disable_mpls()
1653 for i in self.pg_interfaces:
1659 super(TestMPLSPIC, self).tearDown()
1661 def test_mpls_ibgp_pic(self):
1662 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1664 1) setup many iBGP VPN routes via a pair of iBGP peers.
1665 2) Check EMCP forwarding to these peers
1666 3) withdraw the IGP route to one of these peers.
1667 4) check forwarding continues to the remaining peer
1671 # IGP+LDP core routes
1673 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1674 [VppRoutePath(self.pg0.remote_ip4,
1675 self.pg0.sw_if_index,
1677 core_10_0_0_45.add_vpp_config()
1679 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1680 [VppRoutePath(self.pg1.remote_ip4,
1681 self.pg1.sw_if_index,
1683 core_10_0_0_46.add_vpp_config()
1686 # Lot's of VPN routes. We need more the 64 so VPP will build
1687 # the fast convergence indirection
1691 for ii in range(NUM_PKTS):
1692 dst = "192.168.1.%d" % ii
1693 vpn_routes.append(VppIpRoute(
1699 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1704 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1706 vpn_routes[ii].add_vpp_config()
1708 pkts.append(Ether(dst=self.pg2.local_mac,
1709 src=self.pg2.remote_mac) /
1710 IP(src=self.pg2.remote_ip4, dst=dst) /
1711 UDP(sport=1234, dport=1234) /
1715 # Send the packet stream (one pkt to each VPN route)
1716 # - expect a 50-50 split of the traffic
1718 self.pg2.add_stream(pkts)
1719 self.pg_enable_capture(self.pg_interfaces)
1722 rx0 = self.pg0._get_capture(NUM_PKTS)
1723 rx1 = self.pg1._get_capture(NUM_PKTS)
1725 # not testing the LB hashing algorithm so we're not concerned
1726 # with the split ratio, just as long as neither is 0
1727 self.assertNotEqual(0, len(rx0))
1728 self.assertNotEqual(0, len(rx1))
1729 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1730 "Expected all (%s) packets across both ECMP paths. "
1731 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1734 # use a test CLI command to stop the FIB walk process, this
1735 # will prevent the FIB converging the VPN routes and thus allow
1736 # us to probe the interim (post-fail, pre-converge) state
1738 self.vapi.ppcli("test fib-walk-process disable")
1741 # Withdraw one of the IGP routes
1743 core_10_0_0_46.remove_vpp_config()
1746 # now all packets should be forwarded through the remaining peer
1748 self.vapi.ppcli("clear trace")
1749 self.pg2.add_stream(pkts)
1750 self.pg_enable_capture(self.pg_interfaces)
1753 rx0 = self.pg0.get_capture(NUM_PKTS)
1754 self.assertEqual(len(pkts), len(rx0),
1755 "Expected all (%s) packets across single path. "
1756 "rx0: %s." % (len(pkts), len(rx0)))
1759 # enable the FIB walk process to converge the FIB
1761 self.vapi.ppcli("test fib-walk-process enable")
1764 # packets should still be forwarded through the remaining peer
1766 self.pg2.add_stream(pkts)
1767 self.pg_enable_capture(self.pg_interfaces)
1770 rx0 = self.pg0.get_capture(NUM_PKTS)
1771 self.assertEqual(len(pkts), len(rx0),
1772 "Expected all (%s) packets across single path. "
1773 "rx0: %s." % (len(pkts), len(rx0)))
1776 # Add the IGP route back and we return to load-balancing
1778 core_10_0_0_46.add_vpp_config()
1780 self.pg2.add_stream(pkts)
1781 self.pg_enable_capture(self.pg_interfaces)
1784 rx0 = self.pg0._get_capture(NUM_PKTS)
1785 rx1 = self.pg1._get_capture(NUM_PKTS)
1786 self.assertNotEqual(0, len(rx0))
1787 self.assertNotEqual(0, len(rx1))
1788 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1789 "Expected all (%s) packets across both ECMP paths. "
1790 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1792 def test_mpls_ebgp_pic(self):
1793 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1795 1) setup many eBGP VPN routes via a pair of eBGP peers.
1796 2) Check EMCP forwarding to these peers
1797 3) withdraw one eBGP path - expect LB across remaining eBGP
1801 # Lot's of VPN routes. We need more the 64 so VPP will build
1802 # the fast convergence indirection
1807 for ii in range(NUM_PKTS):
1808 dst = "192.168.1.%d" % ii
1809 local_label = 1600 + ii
1810 vpn_routes.append(VppIpRoute(
1813 self.pg2.remote_ip4,
1816 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1818 self.pg3.remote_ip4,
1821 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1823 vpn_routes[ii].add_vpp_config()
1825 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1827 vpn_bindings[ii].add_vpp_config()
1829 pkts.append(Ether(dst=self.pg0.local_mac,
1830 src=self.pg0.remote_mac) /
1831 MPLS(label=local_label, ttl=64) /
1832 IP(src=self.pg0.remote_ip4, dst=dst) /
1833 UDP(sport=1234, dport=1234) /
1837 # Send the packet stream (one pkt to each VPN route)
1838 # - expect a 50-50 split of the traffic
1840 self.pg0.add_stream(pkts)
1841 self.pg_enable_capture(self.pg_interfaces)
1844 rx0 = self.pg2._get_capture(NUM_PKTS)
1845 rx1 = self.pg3._get_capture(NUM_PKTS)
1847 # not testing the LB hashing algorithm so we're not concerned
1848 # with the split ratio, just as long as neither is 0
1849 self.assertNotEqual(0, len(rx0))
1850 self.assertNotEqual(0, len(rx1))
1851 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1852 "Expected all (%s) packets across both ECMP paths. "
1853 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1856 # use a test CLI command to stop the FIB walk process, this
1857 # will prevent the FIB converging the VPN routes and thus allow
1858 # us to probe the interim (post-fail, pre-converge) state
1860 self.vapi.ppcli("test fib-walk-process disable")
1863 # withdraw the connected prefix on the interface.
1865 self.pg2.unconfig_ip4()
1868 # now all packets should be forwarded through the remaining peer
1870 self.pg0.add_stream(pkts)
1871 self.pg_enable_capture(self.pg_interfaces)
1874 rx0 = self.pg3.get_capture(NUM_PKTS)
1875 self.assertEqual(len(pkts), len(rx0),
1876 "Expected all (%s) packets across single path. "
1877 "rx0: %s." % (len(pkts), len(rx0)))
1880 # enable the FIB walk process to converge the FIB
1882 self.vapi.ppcli("test fib-walk-process enable")
1885 # packets should still be forwarded through the remaining peer
1887 self.pg0.add_stream(pkts)
1888 self.pg_enable_capture(self.pg_interfaces)
1891 rx0 = self.pg3.get_capture(NUM_PKTS)
1892 self.assertEqual(len(pkts), len(rx0),
1893 "Expected all (%s) packets across single path. "
1894 "rx0: %s." % (len(pkts), len(rx0)))
1897 # put the connected routes back
1899 self.pg2.config_ip4()
1900 self.pg2.resolve_arp()
1902 self.pg0.add_stream(pkts)
1903 self.pg_enable_capture(self.pg_interfaces)
1906 rx0 = self.pg2._get_capture(NUM_PKTS)
1907 rx1 = self.pg3._get_capture(NUM_PKTS)
1908 self.assertNotEqual(0, len(rx0))
1909 self.assertNotEqual(0, len(rx1))
1910 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1911 "Expected all (%s) packets across both ECMP paths. "
1912 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1914 def test_mpls_v6_ebgp_pic(self):
1915 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1917 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1918 2) Check EMCP forwarding to these peers
1919 3) withdraw one eBGP path - expect LB across remaining eBGP
1923 # Lot's of VPN routes. We need more the 64 so VPP will build
1924 # the fast convergence indirection
1929 for ii in range(NUM_PKTS):
1930 dst = "3000::%d" % ii
1931 local_label = 1600 + ii
1932 vpn_routes.append(VppIpRoute(
1935 self.pg2.remote_ip6,
1938 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1940 self.pg3.remote_ip6,
1943 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1945 vpn_routes[ii].add_vpp_config()
1947 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1949 vpn_bindings[ii].add_vpp_config()
1951 pkts.append(Ether(dst=self.pg0.local_mac,
1952 src=self.pg0.remote_mac) /
1953 MPLS(label=local_label, ttl=64) /
1954 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1955 UDP(sport=1234, dport=1234) /
1957 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
1959 self.pg0.add_stream(pkts)
1960 self.pg_enable_capture(self.pg_interfaces)
1963 rx0 = self.pg2._get_capture(NUM_PKTS)
1964 rx1 = self.pg3._get_capture(NUM_PKTS)
1965 self.assertNotEqual(0, len(rx0))
1966 self.assertNotEqual(0, len(rx1))
1967 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1968 "Expected all (%s) packets across both ECMP paths. "
1969 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1972 # use a test CLI command to stop the FIB walk process, this
1973 # will prevent the FIB converging the VPN routes and thus allow
1974 # us to probe the interim (post-fail, pre-converge) state
1976 self.vapi.ppcli("test fib-walk-process disable")
1979 # withdraw the connected prefix on the interface.
1980 # and shutdown the interface so the ND cache is flushed.
1982 self.pg2.unconfig_ip6()
1983 self.pg2.admin_down()
1986 # now all packets should be forwarded through the remaining peer
1988 self.pg0.add_stream(pkts)
1989 self.pg_enable_capture(self.pg_interfaces)
1992 rx0 = self.pg3.get_capture(NUM_PKTS)
1993 self.assertEqual(len(pkts), len(rx0),
1994 "Expected all (%s) packets across single path. "
1995 "rx0: %s." % (len(pkts), len(rx0)))
1998 # enable the FIB walk process to converge the FIB
2000 self.vapi.ppcli("test fib-walk-process enable")
2001 self.pg0.add_stream(pkts)
2002 self.pg_enable_capture(self.pg_interfaces)
2005 rx0 = self.pg3.get_capture(NUM_PKTS)
2006 self.assertEqual(len(pkts), len(rx0),
2007 "Expected all (%s) packets across single path. "
2008 "rx0: %s." % (len(pkts), len(rx0)))
2011 # put the connected routes back
2014 self.pg2.config_ip6()
2015 self.pg2.resolve_ndp()
2017 self.pg0.add_stream(pkts)
2018 self.pg_enable_capture(self.pg_interfaces)
2021 rx0 = self.pg2._get_capture(NUM_PKTS)
2022 rx1 = self.pg3._get_capture(NUM_PKTS)
2023 self.assertNotEqual(0, len(rx0))
2024 self.assertNotEqual(0, len(rx1))
2025 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2026 "Expected all (%s) packets across both ECMP paths. "
2027 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2030 class TestMPLSL2(VppTestCase):
2034 def setUpClass(cls):
2035 super(TestMPLSL2, cls).setUpClass()
2038 def tearDownClass(cls):
2039 super(TestMPLSL2, cls).tearDownClass()
2042 super(TestMPLSL2, self).setUp()
2044 # create 2 pg interfaces
2045 self.create_pg_interfaces(range(2))
2047 # create the default MPLS table
2049 tbl = VppMplsTable(self, 0)
2050 tbl.add_vpp_config()
2051 self.tables.append(tbl)
2053 # use pg0 as the core facing interface, don't resolve ARP
2055 self.pg0.config_ip4()
2056 self.pg0.enable_mpls()
2058 # use the other 2 for customer facing L2 links
2059 for i in self.pg_interfaces[1:]:
2063 for i in self.pg_interfaces[1:]:
2066 self.pg0.disable_mpls()
2067 self.pg0.unconfig_ip4()
2068 self.pg0.admin_down()
2069 super(TestMPLSL2, self).tearDown()
2071 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2072 capture = verify_filter(capture, sent)
2074 self.assertEqual(len(capture), len(sent))
2076 for i in range(len(capture)):
2080 # the MPLS TTL is 255 since it enters a new tunnel
2081 verify_mpls_stack(self, rx, mpls_labels)
2084 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2086 self.assertEqual(rx_eth.src, tx_eth.src)
2087 self.assertEqual(rx_eth.dst, tx_eth.dst)
2089 def verify_arp_req(self, rx, smac, sip, dip):
2091 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2092 self.assertEqual(ether.src, smac)
2095 self.assertEqual(arp.hwtype, 1)
2096 self.assertEqual(arp.ptype, 0x800)
2097 self.assertEqual(arp.hwlen, 6)
2098 self.assertEqual(arp.plen, 4)
2099 self.assertEqual(arp.op, ARP.who_has)
2100 self.assertEqual(arp.hwsrc, smac)
2101 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2102 self.assertEqual(arp.psrc, sip)
2103 self.assertEqual(arp.pdst, dip)
2105 def test_vpws(self):
2106 """ Virtual Private Wire Service """
2109 # Create an MPLS tunnel that pushes 1 label
2110 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2111 # information is not in the packet, but we test it works anyway
2113 mpls_tun_1 = VppMPLSTunnelInterface(
2115 [VppRoutePath(self.pg0.remote_ip4,
2116 self.pg0.sw_if_index,
2117 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2119 mpls_tun_1.add_vpp_config()
2120 mpls_tun_1.admin_up()
2123 # Create a label entry to for 55 that does L2 input to the tunnel
2125 route_55_eos = VppMplsRoute(
2127 [VppRoutePath("0.0.0.0",
2128 mpls_tun_1.sw_if_index,
2129 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2130 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2131 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2132 route_55_eos.add_vpp_config()
2135 # Cross-connect the tunnel with one of the customers L2 interfaces
2137 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2138 mpls_tun_1.sw_if_index,
2140 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2141 self.pg1.sw_if_index,
2145 # inject a packet from the core
2147 pcore = (Ether(dst=self.pg0.local_mac,
2148 src=self.pg0.remote_mac) /
2149 MPLS(label=55, ttl=64) /
2150 Ether(dst="00:00:de:ad:ba:be",
2151 src="00:00:de:ad:be:ef") /
2152 IP(src="10.10.10.10", dst="11.11.11.11") /
2153 UDP(sport=1234, dport=1234) /
2156 tx0 = pcore * NUM_PKTS
2157 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2158 payload = pcore[MPLS].payload
2160 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2161 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2164 # Inject a packet from the customer/L2 side
2165 # there's no resolved ARP entry so the first packet we see should be
2168 tx1 = pcore[MPLS].payload
2169 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2171 self.verify_arp_req(rx1[0],
2174 self.pg0.remote_ip4)
2177 # resolve the ARP entries and send again
2179 self.pg0.resolve_arp()
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 # we skipped this in the setup
2189 self.pg0.resolve_arp()
2192 # Create a L2 MPLS tunnels
2194 mpls_tun1 = VppMPLSTunnelInterface(
2196 [VppRoutePath(self.pg0.remote_ip4,
2197 self.pg0.sw_if_index,
2198 labels=[VppMplsLabel(42)])],
2200 mpls_tun1.add_vpp_config()
2201 mpls_tun1.admin_up()
2203 mpls_tun2 = VppMPLSTunnelInterface(
2205 [VppRoutePath(self.pg0.remote_ip4,
2206 self.pg0.sw_if_index,
2207 labels=[VppMplsLabel(43)])],
2209 mpls_tun2.add_vpp_config()
2210 mpls_tun2.admin_up()
2213 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2214 # the latter includes a Psuedo Wire Control Word
2216 route_55_eos = VppMplsRoute(
2218 [VppRoutePath("0.0.0.0",
2219 mpls_tun1.sw_if_index,
2220 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2221 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2222 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2224 route_56_eos = VppMplsRoute(
2226 [VppRoutePath("0.0.0.0",
2227 mpls_tun2.sw_if_index,
2228 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2229 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2230 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2231 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2234 route_56_eos.add_vpp_config()
2235 route_55_eos.add_vpp_config()
2237 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2240 # add to tunnel to the customers bridge-domain
2242 self.vapi.sw_interface_set_l2_bridge(
2243 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2244 self.vapi.sw_interface_set_l2_bridge(
2245 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2246 self.vapi.sw_interface_set_l2_bridge(
2247 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2250 # Packet from host on the customer interface to each host
2251 # reachable over the core, and vice-versa
2253 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2254 src="00:00:de:ad:be:ef") /
2255 IP(src="10.10.10.10", dst="11.11.11.11") /
2256 UDP(sport=1234, dport=1234) /
2258 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2259 src="00:00:de:ad:be:ef") /
2260 IP(src="10.10.10.10", dst="11.11.11.12") /
2261 UDP(sport=1234, dport=1234) /
2263 p_core1 = (Ether(dst=self.pg0.local_mac,
2264 src=self.pg0.remote_mac) /
2265 MPLS(label=55, ttl=64) /
2266 Ether(src="00:00:de:ad:ba:b1",
2267 dst="00:00:de:ad:be:ef") /
2268 IP(dst="10.10.10.10", src="11.11.11.11") /
2269 UDP(sport=1234, dport=1234) /
2271 p_core2 = (Ether(dst=self.pg0.local_mac,
2272 src=self.pg0.remote_mac) /
2273 MPLS(label=56, ttl=64) /
2274 Raw('\x01' * 4) / # PW CW
2275 Ether(src="00:00:de:ad:ba:b2",
2276 dst="00:00:de:ad:be:ef") /
2277 IP(dst="10.10.10.10", src="11.11.11.12") /
2278 UDP(sport=1234, dport=1234) /
2282 # The BD is learning, so send in one of each packet to learn
2285 # 2 packets due to BD flooding
2286 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2287 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2289 # we've learnt this so expect it be be forwarded not flooded
2290 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2291 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2292 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2294 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2295 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2296 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2299 # now a stream in each direction from each host
2301 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2302 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2305 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2306 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2309 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2310 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2313 # remove interfaces from customers bridge-domain
2315 self.vapi.sw_interface_set_l2_bridge(
2316 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2317 self.vapi.sw_interface_set_l2_bridge(
2318 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2319 self.vapi.sw_interface_set_l2_bridge(
2320 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2323 if __name__ == '__main__':
2324 unittest.main(testRunner=VppTestRunner)