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:
115 super(TestMPLS, self).tearDown()
117 # the default of 64 matches the IP packet TTL default
118 def create_stream_labelled_ip4(
128 self.reset_packet_infos()
130 for i in range(0, n):
131 info = self.create_packet_info(src_if, src_if)
132 payload = self.info_to_payload(info)
133 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
135 for ii in range(len(mpls_labels)):
136 p = p / MPLS(label=mpls_labels[ii].value,
137 ttl=mpls_labels[ii].ttl,
138 cos=mpls_labels[ii].exp)
141 p = (p / IP(src=src_if.local_ip4,
142 dst=src_if.remote_ip4,
144 UDP(sport=1234, dport=1234) /
147 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
148 UDP(sport=1234, dport=1234) /
151 p = (p / IP(src=ip_itf.remote_ip4,
152 dst=ip_itf.local_ip4,
157 p[IP].chksum = chksum
162 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64,
163 ip_dscp=0, payload_size=None):
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) /
176 self.extend_packet(p, payload_size)
180 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
181 self.reset_packet_infos()
183 for i in range(0, 257):
184 info = self.create_packet_info(src_if, src_if)
185 payload = self.info_to_payload(info)
186 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
187 IPv6(src=src_if.remote_ip6, dst=dst_ip,
188 hlim=ip_ttl, tc=ip_dscp) /
189 UDP(sport=1234, dport=1234) /
195 def create_stream_labelled_ip6(self, src_if, mpls_labels,
196 hlim=64, dst_ip=None):
198 dst_ip = src_if.remote_ip6
199 self.reset_packet_infos()
201 for i in range(0, 257):
202 info = self.create_packet_info(src_if, src_if)
203 payload = self.info_to_payload(info)
204 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
205 for l in mpls_labels:
206 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
208 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
209 UDP(sport=1234, dport=1234) /
215 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
216 ip_ttl=None, ip_dscp=0):
218 capture = verify_filter(capture, sent)
220 self.assertEqual(len(capture), len(sent))
222 for i in range(len(capture)):
226 # the rx'd packet has the MPLS label popped
228 self.assertEqual(eth.type, 0x800)
234 self.assertEqual(rx_ip.src, tx_ip.src)
235 self.assertEqual(rx_ip.dst, tx_ip.dst)
236 self.assertEqual(rx_ip.tos, ip_dscp)
238 # IP processing post pop has decremented the TTL
239 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
241 self.assertEqual(rx_ip.ttl, ip_ttl)
243 self.assertEqual(rx_ip.src, tx_ip.dst)
244 self.assertEqual(rx_ip.dst, tx_ip.src)
249 def verify_capture_labelled_ip4(self, src_if, capture, sent,
250 mpls_labels, ip_ttl=None):
252 capture = verify_filter(capture, sent)
254 self.assertEqual(len(capture), len(sent))
256 for i in range(len(capture)):
262 verify_mpls_stack(self, rx, mpls_labels)
264 self.assertEqual(rx_ip.src, tx_ip.src)
265 self.assertEqual(rx_ip.dst, tx_ip.dst)
267 # IP processing post pop has decremented the TTL
268 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
270 self.assertEqual(rx_ip.ttl, ip_ttl)
275 def verify_capture_labelled_ip6(self, src_if, capture, sent,
276 mpls_labels, ip_ttl=None):
278 capture = verify_filter(capture, sent)
280 self.assertEqual(len(capture), len(sent))
282 for i in range(len(capture)):
288 verify_mpls_stack(self, rx, mpls_labels)
290 self.assertEqual(rx_ip.src, tx_ip.src)
291 self.assertEqual(rx_ip.dst, tx_ip.dst)
293 # IP processing post pop has decremented the TTL
294 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
296 self.assertEqual(rx_ip.hlim, ip_ttl)
301 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
303 capture = verify_filter(capture, sent)
305 self.assertEqual(len(capture), len(sent))
307 for i in range(len(capture)):
313 verify_mpls_stack(self, rx, mpls_labels)
315 self.assertEqual(rx_ip.src, tx_ip.src)
316 self.assertEqual(rx_ip.dst, tx_ip.dst)
317 # IP processing post pop has decremented the TTL
318 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
323 def verify_capture_labelled(self, src_if, capture, sent,
326 capture = verify_filter(capture, sent)
328 self.assertEqual(len(capture), len(sent))
330 for i in range(len(capture)):
332 verify_mpls_stack(self, rx, mpls_labels)
336 def verify_capture_ip6(self, src_if, capture, sent,
337 ip_hlim=None, ip_dscp=0):
339 self.assertEqual(len(capture), len(sent))
341 for i in range(len(capture)):
345 # the rx'd packet has the MPLS label popped
347 self.assertEqual(eth.type, 0x86DD)
352 self.assertEqual(rx_ip.src, tx_ip.src)
353 self.assertEqual(rx_ip.dst, tx_ip.dst)
354 self.assertEqual(rx_ip.tc, ip_dscp)
355 # IP processing post pop has decremented the TTL
357 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
359 self.assertEqual(rx_ip.hlim, ip_hlim)
364 def verify_capture_ip6_icmp(self, src_if, capture, sent):
366 self.assertEqual(len(capture), len(sent))
368 for i in range(len(capture)):
372 # the rx'd packet has the MPLS label popped
374 self.assertEqual(eth.type, 0x86DD)
379 self.assertEqual(rx_ip.dst, tx_ip.src)
380 # ICMP sourced from the interface's address
381 self.assertEqual(rx_ip.src, src_if.local_ip6)
382 # hop-limit reset to 255 for IMCP packet
383 self.assertEqual(rx_ip.hlim, 255)
385 icmp = rx[ICMPv6TimeExceeded]
390 def verify_capture_fragmented_labelled_ip4(self, src_if, capture, sent,
391 mpls_labels, ip_ttl=None):
393 capture = verify_filter(capture, sent)
395 for i in range(len(capture)):
401 verify_mpls_stack(self, rx, mpls_labels)
403 self.assertEqual(rx_ip.src, tx_ip.src)
404 self.assertEqual(rx_ip.dst, tx_ip.dst)
406 # IP processing post pop has decremented the TTL
407 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
409 self.assertEqual(rx_ip.ttl, ip_ttl)
415 """ MPLS label swap tests """
418 # A simple MPLS xconnect - eos label in label out
420 route_32_eos = VppMplsRoute(self, 32, 1,
421 [VppRoutePath(self.pg0.remote_ip4,
422 self.pg0.sw_if_index,
423 labels=[VppMplsLabel(33)])])
424 route_32_eos.add_vpp_config()
427 find_mpls_route(self, 0, 32, 1,
428 [VppRoutePath(self.pg0.remote_ip4,
429 self.pg0.sw_if_index,
430 labels=[VppMplsLabel(33)])]))
433 # a stream that matches the route for 10.0.0.1
434 # PG0 is in the default table
436 tx = self.create_stream_labelled_ip4(self.pg0,
437 [VppMplsLabel(32, ttl=32, exp=1)])
438 rx = self.send_and_expect(self.pg0, tx, self.pg0)
439 self.verify_capture_labelled(self.pg0, rx, tx,
440 [VppMplsLabel(33, ttl=31, exp=1)])
442 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
445 # A simple MPLS xconnect - non-eos label in label out
447 route_32_neos = VppMplsRoute(self, 32, 0,
448 [VppRoutePath(self.pg0.remote_ip4,
449 self.pg0.sw_if_index,
450 labels=[VppMplsLabel(33)])])
451 route_32_neos.add_vpp_config()
454 # a stream that matches the route for 10.0.0.1
455 # PG0 is in the default table
457 tx = self.create_stream_labelled_ip4(self.pg0,
458 [VppMplsLabel(32, ttl=21, exp=7),
460 rx = self.send_and_expect(self.pg0, tx, self.pg0)
461 self.verify_capture_labelled(self.pg0, rx, tx,
462 [VppMplsLabel(33, ttl=20, exp=7),
464 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
467 # A simple MPLS xconnect - non-eos label in label out, uniform mode
469 route_42_neos = VppMplsRoute(
471 [VppRoutePath(self.pg0.remote_ip4,
472 self.pg0.sw_if_index,
473 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
474 route_42_neos.add_vpp_config()
476 tx = self.create_stream_labelled_ip4(self.pg0,
477 [VppMplsLabel(42, ttl=21, exp=7),
479 rx = self.send_and_expect(self.pg0, tx, self.pg0)
480 self.verify_capture_labelled(self.pg0, rx, tx,
481 [VppMplsLabel(43, ttl=20, exp=7),
485 # An MPLS xconnect - EOS label in IP out
487 route_33_eos = VppMplsRoute(self, 33, 1,
488 [VppRoutePath(self.pg0.remote_ip4,
489 self.pg0.sw_if_index,
491 route_33_eos.add_vpp_config()
493 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
494 rx = self.send_and_expect(self.pg0, tx, self.pg0)
495 self.verify_capture_ip4(self.pg0, rx, tx)
498 # disposed packets have an invalid IPv4 checksum
500 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
501 dst_ip=self.pg0.remote_ip4,
504 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
507 # An MPLS xconnect - EOS label in IP out, uniform mode
509 route_3333_eos = VppMplsRoute(
511 [VppRoutePath(self.pg0.remote_ip4,
512 self.pg0.sw_if_index,
513 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
514 route_3333_eos.add_vpp_config()
516 tx = self.create_stream_labelled_ip4(
518 [VppMplsLabel(3333, ttl=55, exp=3)])
519 rx = self.send_and_expect(self.pg0, tx, self.pg0)
520 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
521 tx = self.create_stream_labelled_ip4(
523 [VppMplsLabel(3333, ttl=66, exp=4)])
524 rx = self.send_and_expect(self.pg0, tx, self.pg0)
525 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
528 # An MPLS xconnect - EOS label in IPv6 out
530 route_333_eos = VppMplsRoute(
532 [VppRoutePath(self.pg0.remote_ip6,
533 self.pg0.sw_if_index,
535 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
536 route_333_eos.add_vpp_config()
538 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
539 rx = self.send_and_expect(self.pg0, tx, self.pg0)
540 self.verify_capture_ip6(self.pg0, rx, tx)
543 # disposed packets have an TTL expired
545 tx = self.create_stream_labelled_ip6(self.pg0,
546 [VppMplsLabel(333, ttl=64)],
547 dst_ip=self.pg1.remote_ip6,
549 rx = self.send_and_expect(self.pg0, tx, self.pg0)
550 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
553 # An MPLS xconnect - EOS label in IPv6 out w imp-null
555 route_334_eos = VppMplsRoute(
557 [VppRoutePath(self.pg0.remote_ip6,
558 self.pg0.sw_if_index,
559 labels=[VppMplsLabel(3)])],
560 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
561 route_334_eos.add_vpp_config()
563 tx = self.create_stream_labelled_ip6(self.pg0,
564 [VppMplsLabel(334, ttl=64)])
565 rx = self.send_and_expect(self.pg0, tx, self.pg0)
566 self.verify_capture_ip6(self.pg0, rx, tx)
569 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
571 route_335_eos = VppMplsRoute(
573 [VppRoutePath(self.pg0.remote_ip6,
574 self.pg0.sw_if_index,
575 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
576 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
577 route_335_eos.add_vpp_config()
579 tx = self.create_stream_labelled_ip6(
581 [VppMplsLabel(335, ttl=27, exp=4)])
582 rx = self.send_and_expect(self.pg0, tx, self.pg0)
583 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
586 # disposed packets have an TTL expired
588 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
589 dst_ip=self.pg1.remote_ip6,
591 rx = self.send_and_expect(self.pg0, tx, self.pg0)
592 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
595 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
596 # so this traffic should be dropped.
598 route_33_neos = VppMplsRoute(self, 33, 0,
599 [VppRoutePath(self.pg0.remote_ip4,
600 self.pg0.sw_if_index,
602 route_33_neos.add_vpp_config()
604 tx = self.create_stream_labelled_ip4(self.pg0,
607 self.send_and_assert_no_replies(
609 "MPLS non-EOS packets popped and forwarded")
612 # A recursive EOS x-connect, which resolves through another x-connect
615 route_34_eos = VppMplsRoute(self, 34, 1,
616 [VppRoutePath("0.0.0.0",
619 labels=[VppMplsLabel(44),
621 route_34_eos.add_vpp_config()
622 self.logger.info(self.vapi.cli("sh mpls fib 34"))
624 tx = self.create_stream_labelled_ip4(self.pg0,
625 [VppMplsLabel(34, ttl=3)])
626 rx = self.send_and_expect(self.pg0, tx, self.pg0)
627 self.verify_capture_labelled(self.pg0, rx, tx,
630 VppMplsLabel(45, ttl=2)])
632 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
633 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
636 # A recursive EOS x-connect, which resolves through another x-connect
639 route_35_eos = VppMplsRoute(
641 [VppRoutePath("0.0.0.0",
644 labels=[VppMplsLabel(44)])])
645 route_35_eos.add_vpp_config()
647 tx = self.create_stream_labelled_ip4(self.pg0,
648 [VppMplsLabel(35, ttl=3)])
649 rx = self.send_and_expect(self.pg0, tx, self.pg0)
650 self.verify_capture_labelled(self.pg0, rx, tx,
651 [VppMplsLabel(43, ttl=2),
652 VppMplsLabel(44, ttl=2)])
655 # A recursive non-EOS x-connect, which resolves through another
658 route_34_neos = VppMplsRoute(self, 34, 0,
659 [VppRoutePath("0.0.0.0",
662 labels=[VppMplsLabel(44),
664 route_34_neos.add_vpp_config()
666 tx = self.create_stream_labelled_ip4(self.pg0,
667 [VppMplsLabel(34, ttl=45),
669 rx = self.send_and_expect(self.pg0, tx, self.pg0)
670 # it's the 2nd (counting from 0) label in the stack that is swapped
671 self.verify_capture_labelled(self.pg0, rx, tx,
674 VppMplsLabel(46, ttl=44),
678 # an recursive IP route that resolves through the recursive non-eos
681 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
682 [VppRoutePath("0.0.0.0",
685 labels=[VppMplsLabel(55)])])
686 ip_10_0_0_1.add_vpp_config()
688 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
689 rx = self.send_and_expect(self.pg0, tx, self.pg0)
690 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
695 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
697 ip_10_0_0_1.remove_vpp_config()
698 route_34_neos.remove_vpp_config()
699 route_34_eos.remove_vpp_config()
700 route_33_neos.remove_vpp_config()
701 route_33_eos.remove_vpp_config()
702 route_32_neos.remove_vpp_config()
703 route_32_eos.remove_vpp_config()
706 """ MPLS Local Label Binding test """
709 # Add a non-recursive route with a single out label
711 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
712 [VppRoutePath(self.pg0.remote_ip4,
713 self.pg0.sw_if_index,
714 labels=[VppMplsLabel(45)])])
715 route_10_0_0_1.add_vpp_config()
717 # bind a local label to the route
718 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
719 binding.add_vpp_config()
722 tx = self.create_stream_labelled_ip4(self.pg0,
725 rx = self.send_and_expect(self.pg0, tx, self.pg0)
726 self.verify_capture_labelled(self.pg0, rx, tx,
727 [VppMplsLabel(45, ttl=63),
731 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
732 rx = self.send_and_expect(self.pg0, tx, self.pg0)
733 self.verify_capture_labelled(self.pg0, rx, tx,
734 [VppMplsLabel(45, ttl=63)])
737 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
738 rx = self.send_and_expect(self.pg0, tx, self.pg0)
739 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
744 binding.remove_vpp_config()
745 route_10_0_0_1.remove_vpp_config()
747 def test_imposition(self):
748 """ MPLS label imposition test """
751 # Add a non-recursive route with a single out label
753 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
754 [VppRoutePath(self.pg0.remote_ip4,
755 self.pg0.sw_if_index,
756 labels=[VppMplsLabel(32)])])
757 route_10_0_0_1.add_vpp_config()
760 # a stream that matches the route for 10.0.0.1
761 # PG0 is in the default table
763 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
764 rx = self.send_and_expect(self.pg0, tx, self.pg0)
765 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
768 # Add a non-recursive route with a 3 out labels
770 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
771 [VppRoutePath(self.pg0.remote_ip4,
772 self.pg0.sw_if_index,
773 labels=[VppMplsLabel(32),
776 route_10_0_0_2.add_vpp_config()
778 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
779 ip_ttl=44, ip_dscp=0xff)
780 rx = self.send_and_expect(self.pg0, tx, self.pg0)
781 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
788 # Add a non-recursive route with a single out label in uniform mode
790 route_10_0_0_3 = VppIpRoute(
791 self, "10.0.0.3", 32,
792 [VppRoutePath(self.pg0.remote_ip4,
793 self.pg0.sw_if_index,
794 labels=[VppMplsLabel(32,
795 mode=MplsLspMode.UNIFORM)])])
796 route_10_0_0_3.add_vpp_config()
798 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
799 ip_ttl=54, ip_dscp=0xbe)
800 rx = self.send_and_expect(self.pg0, tx, self.pg0)
801 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
802 [VppMplsLabel(32, ttl=53, exp=5)])
805 # Add a IPv6 non-recursive route with a single out label in
808 route_2001_3 = VppIpRoute(
809 self, "2001::3", 128,
810 [VppRoutePath(self.pg0.remote_ip6,
811 self.pg0.sw_if_index,
812 labels=[VppMplsLabel(32,
813 mode=MplsLspMode.UNIFORM)])])
814 route_2001_3.add_vpp_config()
816 tx = self.create_stream_ip6(self.pg0, "2001::3",
817 ip_ttl=54, ip_dscp=0xbe)
818 rx = self.send_and_expect(self.pg0, tx, self.pg0)
819 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
820 [VppMplsLabel(32, ttl=53, exp=5)])
823 # add a recursive path, with output label, via the 1 label route
825 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
826 [VppRoutePath("10.0.0.1",
828 labels=[VppMplsLabel(44)])])
829 route_11_0_0_1.add_vpp_config()
832 # a stream that matches the route for 11.0.0.1, should pick up
833 # the label stack for 11.0.0.1 and 10.0.0.1
835 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
836 rx = self.send_and_expect(self.pg0, tx, self.pg0)
837 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
841 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
844 # add a recursive path, with 2 labels, via the 3 label route
846 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
847 [VppRoutePath("10.0.0.2",
849 labels=[VppMplsLabel(44),
851 route_11_0_0_2.add_vpp_config()
854 # a stream that matches the route for 11.0.0.1, should pick up
855 # the label stack for 11.0.0.1 and 10.0.0.1
857 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
858 rx = self.send_and_expect(self.pg0, tx, self.pg0)
859 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
866 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
868 rx = self.send_and_expect(self.pg0, tx, self.pg0)
869 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
876 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
881 route_11_0_0_2.remove_vpp_config()
882 route_11_0_0_1.remove_vpp_config()
883 route_10_0_0_2.remove_vpp_config()
884 route_10_0_0_1.remove_vpp_config()
886 def test_imposition_fragmentation(self):
887 """ MPLS label imposition fragmentation test """
890 # Add a ipv4 non-recursive route with a single out label
892 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
893 [VppRoutePath(self.pg0.remote_ip4,
894 self.pg0.sw_if_index,
895 labels=[VppMplsLabel(32)])])
896 route_10_0_0_1.add_vpp_config()
899 # a stream that matches the route for 10.0.0.1
900 # PG0 is in the default table
902 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
903 for i in range(0, 257):
904 self.extend_packet(tx[i], 10000)
907 # 5 fragments per packet (257*5=1285)
909 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
910 self.verify_capture_fragmented_labelled_ip4(self.pg0, rx, tx,
916 route_10_0_0_1.remove_vpp_config()
918 def test_tunnel_pipe(self):
919 """ MPLS Tunnel Tests - Pipe """
922 # Create a tunnel with two out labels
924 mpls_tun = VppMPLSTunnelInterface(
926 [VppRoutePath(self.pg0.remote_ip4,
927 self.pg0.sw_if_index,
928 labels=[VppMplsLabel(44),
930 mpls_tun.add_vpp_config()
934 # add an unlabelled route through the new tunnel
936 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
937 [VppRoutePath("0.0.0.0",
938 mpls_tun._sw_if_index)])
939 route_10_0_0_3.add_vpp_config()
941 self.vapi.cli("clear trace")
942 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
943 self.pg0.add_stream(tx)
945 self.pg_enable_capture(self.pg_interfaces)
948 rx = self.pg0.get_capture()
949 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
954 # add a labelled route through the new tunnel
956 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
957 [VppRoutePath("0.0.0.0",
958 mpls_tun._sw_if_index,
960 route_10_0_0_4.add_vpp_config()
962 self.vapi.cli("clear trace")
963 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
964 self.pg0.add_stream(tx)
966 self.pg_enable_capture(self.pg_interfaces)
969 rx = self.pg0.get_capture()
970 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
973 VppMplsLabel(33, ttl=255)])
976 # change tunnel's MTU to a low value
978 mpls_tun.set_l3_mtu(1200)
980 # send IP into the tunnel to be fragmented
981 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
983 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
989 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
993 # send MPLS into the tunnel to be fragmented
994 tx = self.create_stream_ip4(self.pg0, "10.0.0.4",
996 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1002 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1005 VppMplsLabel(33, ttl=255)])
1007 def test_tunnel_uniform(self):
1008 """ MPLS Tunnel Tests - Uniform """
1011 # Create a tunnel with a single out label
1012 # The label stack is specified here from outer to inner
1014 mpls_tun = VppMPLSTunnelInterface(
1016 [VppRoutePath(self.pg0.remote_ip4,
1017 self.pg0.sw_if_index,
1018 labels=[VppMplsLabel(44, ttl=32),
1019 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1020 mpls_tun.add_vpp_config()
1024 # add an unlabelled route through the new tunnel
1026 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1027 [VppRoutePath("0.0.0.0",
1028 mpls_tun._sw_if_index)])
1029 route_10_0_0_3.add_vpp_config()
1031 self.vapi.cli("clear trace")
1032 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1033 self.pg0.add_stream(tx)
1035 self.pg_enable_capture(self.pg_interfaces)
1038 rx = self.pg0.get_capture()
1039 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1040 [VppMplsLabel(44, ttl=32),
1041 VppMplsLabel(46, ttl=23)])
1044 # add a labelled route through the new tunnel
1046 route_10_0_0_4 = VppIpRoute(
1047 self, "10.0.0.4", 32,
1048 [VppRoutePath("0.0.0.0",
1049 mpls_tun._sw_if_index,
1050 labels=[VppMplsLabel(33, ttl=47)])])
1051 route_10_0_0_4.add_vpp_config()
1053 self.vapi.cli("clear trace")
1054 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1055 self.pg0.add_stream(tx)
1057 self.pg_enable_capture(self.pg_interfaces)
1060 rx = self.pg0.get_capture()
1061 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1062 [VppMplsLabel(44, ttl=32),
1063 VppMplsLabel(46, ttl=47),
1064 VppMplsLabel(33, ttl=47)])
1066 def test_mpls_tunnel_many(self):
1067 """ MPLS Multiple Tunnels """
1069 for ii in range(10):
1070 mpls_tun = VppMPLSTunnelInterface(
1072 [VppRoutePath(self.pg0.remote_ip4,
1073 self.pg0.sw_if_index,
1074 labels=[VppMplsLabel(44, ttl=32),
1075 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1076 mpls_tun.add_vpp_config()
1079 def test_v4_exp_null(self):
1080 """ MPLS V4 Explicit NULL test """
1083 # The first test case has an MPLS TTL of 0
1084 # all packet should be dropped
1086 tx = self.create_stream_labelled_ip4(self.pg0,
1087 [VppMplsLabel(0, ttl=0)])
1088 self.send_and_assert_no_replies(self.pg0, tx,
1089 "MPLS TTL=0 packets forwarded")
1092 # a stream with a non-zero MPLS TTL
1093 # PG0 is in the default table
1095 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1096 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1097 self.verify_capture_ip4(self.pg0, rx, tx)
1100 # a stream with a non-zero MPLS TTL
1102 # we are ensuring the post-pop lookup occurs in the VRF table
1104 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1105 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1106 self.verify_capture_ip4(self.pg1, rx, tx)
1108 def test_v6_exp_null(self):
1109 """ MPLS V6 Explicit NULL test """
1112 # a stream with a non-zero MPLS TTL
1113 # PG0 is in the default table
1115 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1116 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1117 self.verify_capture_ip6(self.pg0, rx, tx)
1120 # a stream with a non-zero MPLS TTL
1122 # we are ensuring the post-pop lookup occurs in the VRF table
1124 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1125 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1126 self.verify_capture_ip6(self.pg0, rx, tx)
1128 def test_deag(self):
1132 # A de-agg route - next-hop lookup in default table
1134 route_34_eos = VppMplsRoute(self, 34, 1,
1135 [VppRoutePath("0.0.0.0",
1138 route_34_eos.add_vpp_config()
1141 # ping an interface in the default table
1142 # PG0 is in the default table
1144 tx = self.create_stream_labelled_ip4(self.pg0,
1148 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1149 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1152 # A de-agg route - next-hop lookup in non-default table
1154 route_35_eos = VppMplsRoute(self, 35, 1,
1155 [VppRoutePath("0.0.0.0",
1158 route_35_eos.add_vpp_config()
1161 # ping an interface in the non-default table
1162 # PG0 is in the default table. packet arrive labelled in the
1163 # default table and egress unlabelled in the non-default
1165 tx = self.create_stream_labelled_ip4(
1166 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1167 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1168 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1173 route_36_neos = VppMplsRoute(self, 36, 0,
1174 [VppRoutePath("0.0.0.0",
1176 route_36_neos.add_vpp_config()
1178 tx = self.create_stream_labelled_ip4(self.pg0,
1181 ping=1, ip_itf=self.pg1)
1182 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1183 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1185 route_36_neos.remove_vpp_config()
1186 route_35_eos.remove_vpp_config()
1187 route_34_eos.remove_vpp_config()
1189 def test_interface_rx(self):
1190 """ MPLS Interface Receive """
1193 # Add a non-recursive route that will forward the traffic
1196 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1198 paths=[VppRoutePath(self.pg1.remote_ip4,
1199 self.pg1.sw_if_index)])
1200 route_10_0_0_1.add_vpp_config()
1203 # An interface receive label that maps traffic to RX on interface
1205 # by injecting the packet in on pg0, which is in table 0
1206 # doing an interface-rx on pg1 and matching a route in table 1
1207 # if the packet egresses, then we must have swapped to pg1
1208 # so as to have matched the route in table 1
1210 route_34_eos = VppMplsRoute(
1212 [VppRoutePath("0.0.0.0",
1213 self.pg1.sw_if_index,
1214 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1215 route_34_eos.add_vpp_config()
1218 # ping an interface in the default table
1219 # PG0 is in the default table
1221 tx = self.create_stream_labelled_ip4(self.pg0,
1224 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1225 self.verify_capture_ip4(self.pg1, rx, tx)
1227 def test_mcast_mid_point(self):
1228 """ MPLS Multicast Mid Point """
1231 # Add a non-recursive route that will forward the traffic
1234 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1236 paths=[VppRoutePath(self.pg1.remote_ip4,
1237 self.pg1.sw_if_index)])
1238 route_10_0_0_1.add_vpp_config()
1241 # Add a mcast entry that replicate to pg2 and pg3
1242 # and replicate to a interface-rx (like a bud node would)
1244 route_3400_eos = VppMplsRoute(
1246 [VppRoutePath(self.pg2.remote_ip4,
1247 self.pg2.sw_if_index,
1248 labels=[VppMplsLabel(3401)]),
1249 VppRoutePath(self.pg3.remote_ip4,
1250 self.pg3.sw_if_index,
1251 labels=[VppMplsLabel(3402)]),
1252 VppRoutePath("0.0.0.0",
1253 self.pg1.sw_if_index,
1254 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1256 route_3400_eos.add_vpp_config()
1259 # ping an interface in the default table
1260 # PG0 is in the default table
1262 self.vapi.cli("clear trace")
1263 tx = self.create_stream_labelled_ip4(self.pg0,
1264 [VppMplsLabel(3400, ttl=64)],
1267 self.pg0.add_stream(tx)
1269 self.pg_enable_capture(self.pg_interfaces)
1272 rx = self.pg1.get_capture(257)
1273 self.verify_capture_ip4(self.pg1, rx, tx)
1275 rx = self.pg2.get_capture(257)
1276 self.verify_capture_labelled(self.pg2, rx, tx,
1277 [VppMplsLabel(3401, ttl=63)])
1278 rx = self.pg3.get_capture(257)
1279 self.verify_capture_labelled(self.pg3, rx, tx,
1280 [VppMplsLabel(3402, ttl=63)])
1282 def test_mcast_head(self):
1283 """ MPLS Multicast Head-end """
1286 # Create a multicast tunnel with two replications
1288 mpls_tun = VppMPLSTunnelInterface(
1290 [VppRoutePath(self.pg2.remote_ip4,
1291 self.pg2.sw_if_index,
1292 labels=[VppMplsLabel(42)]),
1293 VppRoutePath(self.pg3.remote_ip4,
1294 self.pg3.sw_if_index,
1295 labels=[VppMplsLabel(43)])],
1297 mpls_tun.add_vpp_config()
1301 # add an unlabelled route through the new tunnel
1303 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1304 [VppRoutePath("0.0.0.0",
1305 mpls_tun._sw_if_index)])
1306 route_10_0_0_3.add_vpp_config()
1308 self.vapi.cli("clear trace")
1309 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1310 self.pg0.add_stream(tx)
1312 self.pg_enable_capture(self.pg_interfaces)
1315 rx = self.pg2.get_capture(257)
1316 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1317 rx = self.pg3.get_capture(257)
1318 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1321 # An an IP multicast route via the tunnel
1323 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1325 route_232_1_1_1 = VppIpMRoute(
1329 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1330 [VppMRoutePath(self.pg0.sw_if_index,
1331 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1332 VppMRoutePath(mpls_tun._sw_if_index,
1333 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1334 route_232_1_1_1.add_vpp_config()
1335 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1337 self.vapi.cli("clear trace")
1338 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1339 self.pg0.add_stream(tx)
1341 self.pg_enable_capture(self.pg_interfaces)
1344 rx = self.pg2.get_capture(257)
1345 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1346 rx = self.pg3.get_capture(257)
1347 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1349 def test_mcast_ip4_tail(self):
1350 """ MPLS IPv4 Multicast Tail """
1353 # Add a multicast route that will forward the traffic
1356 route_232_1_1_1 = VppIpMRoute(
1360 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1362 paths=[VppMRoutePath(self.pg1.sw_if_index,
1363 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1364 route_232_1_1_1.add_vpp_config()
1367 # An interface receive label that maps traffic to RX on interface
1369 # by injecting the packet in on pg0, which is in table 0
1370 # doing an rpf-id and matching a route in table 1
1371 # if the packet egresses, then we must have matched the route in
1374 route_34_eos = VppMplsRoute(
1376 [VppRoutePath("0.0.0.0",
1381 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1383 route_34_eos.add_vpp_config()
1386 # Drop due to interface lookup miss
1388 self.vapi.cli("clear trace")
1389 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1390 dst_ip="232.1.1.1", n=1)
1391 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1394 # set the RPF-ID of the entry to match the input packet's
1396 route_232_1_1_1.update_rpf_id(55)
1397 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1399 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1401 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1402 self.verify_capture_ip4(self.pg1, rx, tx)
1405 # disposed packets have an invalid IPv4 checksum
1407 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1408 dst_ip="232.1.1.1", n=65,
1410 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1413 # set the RPF-ID of the entry to not match the input packet's
1415 route_232_1_1_1.update_rpf_id(56)
1416 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1418 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1420 def test_mcast_ip6_tail(self):
1421 """ MPLS IPv6 Multicast Tail """
1424 # Add a multicast route that will forward the traffic
1427 route_ff = VppIpMRoute(
1431 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1433 paths=[VppMRoutePath(self.pg1.sw_if_index,
1434 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
1435 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1436 route_ff.add_vpp_config()
1439 # An interface receive label that maps traffic to RX on interface
1441 # by injecting the packet in on pg0, which is in table 0
1442 # doing an rpf-id and matching a route in table 1
1443 # if the packet egresses, then we must have matched the route in
1446 route_34_eos = VppMplsRoute(
1453 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1455 route_34_eos.add_vpp_config()
1458 # Drop due to interface lookup miss
1460 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1462 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1465 # set the RPF-ID of the entry to match the input packet's
1467 route_ff.update_rpf_id(55)
1469 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1471 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1472 self.verify_capture_ip6(self.pg1, rx, tx)
1475 # disposed packets have hop-limit = 1
1477 tx = self.create_stream_labelled_ip6(self.pg0,
1481 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1482 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1485 # set the RPF-ID of the entry to not match the input packet's
1487 route_ff.update_rpf_id(56)
1488 tx = self.create_stream_labelled_ip6(self.pg0,
1491 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1497 # Add a non-recursive route with a single out label
1499 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1500 [VppRoutePath(self.pg0.remote_ip4,
1501 self.pg0.sw_if_index,
1502 labels=[VppMplsLabel(45)])])
1503 route_10_0_0_1.add_vpp_config()
1505 # bind a local label to the route
1506 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1507 binding.add_vpp_config()
1510 # a labelled v6 route that resolves through the v4
1512 route_2001_3 = VppIpRoute(
1513 self, "2001::3", 128,
1514 [VppRoutePath("10.0.0.1",
1516 labels=[VppMplsLabel(32)])])
1517 route_2001_3.add_vpp_config()
1519 tx = self.create_stream_ip6(self.pg0, "2001::3")
1520 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1522 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1527 # and a v4 recursive via the v6
1529 route_20_3 = VppIpRoute(
1530 self, "20.0.0.3", 32,
1531 [VppRoutePath("2001::3",
1533 labels=[VppMplsLabel(99)])])
1534 route_20_3.add_vpp_config()
1536 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1537 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1539 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1545 class TestMPLSDisabled(VppTestCase):
1546 """ MPLS disabled """
1549 def setUpClass(cls):
1550 super(TestMPLSDisabled, cls).setUpClass()
1553 def tearDownClass(cls):
1554 super(TestMPLSDisabled, cls).tearDownClass()
1557 super(TestMPLSDisabled, self).setUp()
1559 # create 2 pg interfaces
1560 self.create_pg_interfaces(range(2))
1562 self.tbl = VppMplsTable(self, 0)
1563 self.tbl.add_vpp_config()
1565 # PG0 is MPLS enabled
1567 self.pg0.config_ip4()
1568 self.pg0.resolve_arp()
1569 self.pg0.enable_mpls()
1571 # PG 1 is not MPLS enabled
1575 for i in self.pg_interfaces:
1579 self.pg0.disable_mpls()
1580 super(TestMPLSDisabled, self).tearDown()
1582 def test_mpls_disabled(self):
1583 """ MPLS Disabled """
1585 tx = (Ether(src=self.pg1.remote_mac,
1586 dst=self.pg1.local_mac) /
1587 MPLS(label=32, ttl=64) /
1588 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1589 UDP(sport=1234, dport=1234) /
1593 # A simple MPLS xconnect - eos label in label out
1595 route_32_eos = VppMplsRoute(self, 32, 1,
1596 [VppRoutePath(self.pg0.remote_ip4,
1597 self.pg0.sw_if_index,
1599 route_32_eos.add_vpp_config()
1602 # PG1 does not forward IP traffic
1604 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1609 self.pg1.enable_mpls()
1612 # Now we get packets through
1614 self.pg1.add_stream(tx)
1615 self.pg_enable_capture(self.pg_interfaces)
1618 rx = self.pg0.get_capture(1)
1623 self.pg1.disable_mpls()
1626 # PG1 does not forward IP traffic
1628 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1629 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1632 class TestMPLSPIC(VppTestCase):
1633 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1636 def setUpClass(cls):
1637 super(TestMPLSPIC, cls).setUpClass()
1640 def tearDownClass(cls):
1641 super(TestMPLSPIC, cls).tearDownClass()
1644 super(TestMPLSPIC, self).setUp()
1646 # create 2 pg interfaces
1647 self.create_pg_interfaces(range(4))
1649 mpls_tbl = VppMplsTable(self, 0)
1650 mpls_tbl.add_vpp_config()
1651 tbl4 = VppIpTable(self, 1)
1652 tbl4.add_vpp_config()
1653 tbl6 = VppIpTable(self, 1, is_ip6=1)
1654 tbl6.add_vpp_config()
1658 self.pg0.config_ip4()
1659 self.pg0.resolve_arp()
1660 self.pg0.enable_mpls()
1663 self.pg1.config_ip4()
1664 self.pg1.resolve_arp()
1665 self.pg1.enable_mpls()
1667 # VRF (customer facing) link
1669 self.pg2.set_table_ip4(1)
1670 self.pg2.config_ip4()
1671 self.pg2.resolve_arp()
1672 self.pg2.set_table_ip6(1)
1673 self.pg2.config_ip6()
1674 self.pg2.resolve_ndp()
1677 self.pg3.set_table_ip4(1)
1678 self.pg3.config_ip4()
1679 self.pg3.resolve_arp()
1680 self.pg3.set_table_ip6(1)
1681 self.pg3.config_ip6()
1682 self.pg3.resolve_ndp()
1685 self.pg0.disable_mpls()
1686 self.pg1.disable_mpls()
1687 for i in self.pg_interfaces:
1693 super(TestMPLSPIC, self).tearDown()
1695 def test_mpls_ibgp_pic(self):
1696 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1698 1) setup many iBGP VPN routes via a pair of iBGP peers.
1699 2) Check EMCP forwarding to these peers
1700 3) withdraw the IGP route to one of these peers.
1701 4) check forwarding continues to the remaining peer
1705 # IGP+LDP core routes
1707 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1708 [VppRoutePath(self.pg0.remote_ip4,
1709 self.pg0.sw_if_index,
1711 core_10_0_0_45.add_vpp_config()
1713 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1714 [VppRoutePath(self.pg1.remote_ip4,
1715 self.pg1.sw_if_index,
1717 core_10_0_0_46.add_vpp_config()
1720 # Lot's of VPN routes. We need more the 64 so VPP will build
1721 # the fast convergence indirection
1725 for ii in range(NUM_PKTS):
1726 dst = "192.168.1.%d" % ii
1727 vpn_routes.append(VppIpRoute(
1733 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1738 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1740 vpn_routes[ii].add_vpp_config()
1742 pkts.append(Ether(dst=self.pg2.local_mac,
1743 src=self.pg2.remote_mac) /
1744 IP(src=self.pg2.remote_ip4, dst=dst) /
1745 UDP(sport=1234, dport=1234) /
1749 # Send the packet stream (one pkt to each VPN route)
1750 # - expect a 50-50 split of the traffic
1752 self.pg2.add_stream(pkts)
1753 self.pg_enable_capture(self.pg_interfaces)
1756 rx0 = self.pg0._get_capture(NUM_PKTS)
1757 rx1 = self.pg1._get_capture(NUM_PKTS)
1759 # not testing the LB hashing algorithm so we're not concerned
1760 # with the split ratio, just as long as neither is 0
1761 self.assertNotEqual(0, len(rx0))
1762 self.assertNotEqual(0, len(rx1))
1763 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1764 "Expected all (%s) packets across both ECMP paths. "
1765 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1768 # use a test CLI command to stop the FIB walk process, this
1769 # will prevent the FIB converging the VPN routes and thus allow
1770 # us to probe the interim (post-fail, pre-converge) state
1772 self.vapi.ppcli("test fib-walk-process disable")
1775 # Withdraw one of the IGP routes
1777 core_10_0_0_46.remove_vpp_config()
1780 # now all packets should be forwarded through the remaining peer
1782 self.vapi.ppcli("clear trace")
1783 self.pg2.add_stream(pkts)
1784 self.pg_enable_capture(self.pg_interfaces)
1787 rx0 = self.pg0.get_capture(NUM_PKTS)
1788 self.assertEqual(len(pkts), len(rx0),
1789 "Expected all (%s) packets across single path. "
1790 "rx0: %s." % (len(pkts), len(rx0)))
1793 # enable the FIB walk process to converge the FIB
1795 self.vapi.ppcli("test fib-walk-process enable")
1798 # packets should still be forwarded through the remaining peer
1800 self.pg2.add_stream(pkts)
1801 self.pg_enable_capture(self.pg_interfaces)
1804 rx0 = self.pg0.get_capture(NUM_PKTS)
1805 self.assertEqual(len(pkts), len(rx0),
1806 "Expected all (%s) packets across single path. "
1807 "rx0: %s." % (len(pkts), len(rx0)))
1810 # Add the IGP route back and we return to load-balancing
1812 core_10_0_0_46.add_vpp_config()
1814 self.pg2.add_stream(pkts)
1815 self.pg_enable_capture(self.pg_interfaces)
1818 rx0 = self.pg0._get_capture(NUM_PKTS)
1819 rx1 = self.pg1._get_capture(NUM_PKTS)
1820 self.assertNotEqual(0, len(rx0))
1821 self.assertNotEqual(0, len(rx1))
1822 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1823 "Expected all (%s) packets across both ECMP paths. "
1824 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1826 def test_mpls_ebgp_pic(self):
1827 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1829 1) setup many eBGP VPN routes via a pair of eBGP peers.
1830 2) Check EMCP forwarding to these peers
1831 3) withdraw one eBGP path - expect LB across remaining eBGP
1835 # Lot's of VPN routes. We need more the 64 so VPP will build
1836 # the fast convergence indirection
1841 for ii in range(NUM_PKTS):
1842 dst = "192.168.1.%d" % ii
1843 local_label = 1600 + ii
1844 vpn_routes.append(VppIpRoute(
1847 self.pg2.remote_ip4,
1850 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1852 self.pg3.remote_ip4,
1855 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1857 vpn_routes[ii].add_vpp_config()
1859 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1861 vpn_bindings[ii].add_vpp_config()
1863 pkts.append(Ether(dst=self.pg0.local_mac,
1864 src=self.pg0.remote_mac) /
1865 MPLS(label=local_label, ttl=64) /
1866 IP(src=self.pg0.remote_ip4, dst=dst) /
1867 UDP(sport=1234, dport=1234) /
1871 # Send the packet stream (one pkt to each VPN route)
1872 # - expect a 50-50 split of the traffic
1874 self.pg0.add_stream(pkts)
1875 self.pg_enable_capture(self.pg_interfaces)
1878 rx0 = self.pg2._get_capture(NUM_PKTS)
1879 rx1 = self.pg3._get_capture(NUM_PKTS)
1881 # not testing the LB hashing algorithm so we're not concerned
1882 # with the split ratio, just as long as neither is 0
1883 self.assertNotEqual(0, len(rx0))
1884 self.assertNotEqual(0, len(rx1))
1885 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1886 "Expected all (%s) packets across both ECMP paths. "
1887 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1890 # use a test CLI command to stop the FIB walk process, this
1891 # will prevent the FIB converging the VPN routes and thus allow
1892 # us to probe the interim (post-fail, pre-converge) state
1894 self.vapi.ppcli("test fib-walk-process disable")
1897 # withdraw the connected prefix on the interface.
1899 self.pg2.unconfig_ip4()
1902 # now all packets should be forwarded through the remaining peer
1904 self.pg0.add_stream(pkts)
1905 self.pg_enable_capture(self.pg_interfaces)
1908 rx0 = self.pg3.get_capture(NUM_PKTS)
1909 self.assertEqual(len(pkts), len(rx0),
1910 "Expected all (%s) packets across single path. "
1911 "rx0: %s." % (len(pkts), len(rx0)))
1914 # enable the FIB walk process to converge the FIB
1916 self.vapi.ppcli("test fib-walk-process enable")
1919 # packets should still be forwarded through the remaining peer
1921 self.pg0.add_stream(pkts)
1922 self.pg_enable_capture(self.pg_interfaces)
1925 rx0 = self.pg3.get_capture(NUM_PKTS)
1926 self.assertEqual(len(pkts), len(rx0),
1927 "Expected all (%s) packets across single path. "
1928 "rx0: %s." % (len(pkts), len(rx0)))
1931 # put the connected routes back
1933 self.pg2.config_ip4()
1934 self.pg2.resolve_arp()
1936 self.pg0.add_stream(pkts)
1937 self.pg_enable_capture(self.pg_interfaces)
1940 rx0 = self.pg2._get_capture(NUM_PKTS)
1941 rx1 = self.pg3._get_capture(NUM_PKTS)
1942 self.assertNotEqual(0, len(rx0))
1943 self.assertNotEqual(0, len(rx1))
1944 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1945 "Expected all (%s) packets across both ECMP paths. "
1946 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1948 def test_mpls_v6_ebgp_pic(self):
1949 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1951 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1952 2) Check EMCP forwarding to these peers
1953 3) withdraw one eBGP path - expect LB across remaining eBGP
1957 # Lot's of VPN routes. We need more the 64 so VPP will build
1958 # the fast convergence indirection
1963 for ii in range(NUM_PKTS):
1964 dst = "3000::%d" % ii
1965 local_label = 1600 + ii
1966 vpn_routes.append(VppIpRoute(
1969 self.pg2.remote_ip6,
1972 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1974 self.pg3.remote_ip6,
1977 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1979 vpn_routes[ii].add_vpp_config()
1981 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1983 vpn_bindings[ii].add_vpp_config()
1985 pkts.append(Ether(dst=self.pg0.local_mac,
1986 src=self.pg0.remote_mac) /
1987 MPLS(label=local_label, ttl=64) /
1988 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1989 UDP(sport=1234, dport=1234) /
1991 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
1993 self.pg0.add_stream(pkts)
1994 self.pg_enable_capture(self.pg_interfaces)
1997 rx0 = self.pg2._get_capture(NUM_PKTS)
1998 rx1 = self.pg3._get_capture(NUM_PKTS)
1999 self.assertNotEqual(0, len(rx0))
2000 self.assertNotEqual(0, len(rx1))
2001 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2002 "Expected all (%s) packets across both ECMP paths. "
2003 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2006 # use a test CLI command to stop the FIB walk process, this
2007 # will prevent the FIB converging the VPN routes and thus allow
2008 # us to probe the interim (post-fail, pre-converge) state
2010 self.vapi.ppcli("test fib-walk-process disable")
2013 # withdraw the connected prefix on the interface.
2014 # and shutdown the interface so the ND cache is flushed.
2016 self.pg2.unconfig_ip6()
2017 self.pg2.admin_down()
2020 # now all packets should be forwarded through the remaining peer
2022 self.pg0.add_stream(pkts)
2023 self.pg_enable_capture(self.pg_interfaces)
2026 rx0 = self.pg3.get_capture(NUM_PKTS)
2027 self.assertEqual(len(pkts), len(rx0),
2028 "Expected all (%s) packets across single path. "
2029 "rx0: %s." % (len(pkts), len(rx0)))
2032 # enable the FIB walk process to converge the FIB
2034 self.vapi.ppcli("test fib-walk-process enable")
2035 self.pg0.add_stream(pkts)
2036 self.pg_enable_capture(self.pg_interfaces)
2039 rx0 = self.pg3.get_capture(NUM_PKTS)
2040 self.assertEqual(len(pkts), len(rx0),
2041 "Expected all (%s) packets across single path. "
2042 "rx0: %s." % (len(pkts), len(rx0)))
2045 # put the connected routes back
2047 self.logger.info(self.vapi.cli("sh log"))
2049 self.pg2.config_ip6()
2050 self.pg2.resolve_ndp()
2052 self.pg0.add_stream(pkts)
2053 self.pg_enable_capture(self.pg_interfaces)
2056 rx0 = self.pg2._get_capture(NUM_PKTS)
2057 rx1 = self.pg3._get_capture(NUM_PKTS)
2058 self.assertNotEqual(0, len(rx0))
2059 self.assertNotEqual(0, len(rx1))
2060 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2061 "Expected all (%s) packets across both ECMP paths. "
2062 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2065 class TestMPLSL2(VppTestCase):
2069 def setUpClass(cls):
2070 super(TestMPLSL2, cls).setUpClass()
2073 def tearDownClass(cls):
2074 super(TestMPLSL2, cls).tearDownClass()
2077 super(TestMPLSL2, self).setUp()
2079 # create 2 pg interfaces
2080 self.create_pg_interfaces(range(2))
2082 # create the default MPLS table
2084 tbl = VppMplsTable(self, 0)
2085 tbl.add_vpp_config()
2086 self.tables.append(tbl)
2088 # use pg0 as the core facing interface, don't resolve ARP
2090 self.pg0.config_ip4()
2091 self.pg0.enable_mpls()
2093 # use the other 2 for customer facing L2 links
2094 for i in self.pg_interfaces[1:]:
2098 for i in self.pg_interfaces[1:]:
2101 self.pg0.disable_mpls()
2102 self.pg0.unconfig_ip4()
2103 self.pg0.admin_down()
2104 super(TestMPLSL2, self).tearDown()
2106 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2107 capture = verify_filter(capture, sent)
2109 self.assertEqual(len(capture), len(sent))
2111 for i in range(len(capture)):
2115 # the MPLS TTL is 255 since it enters a new tunnel
2116 verify_mpls_stack(self, rx, mpls_labels)
2119 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2121 self.assertEqual(rx_eth.src, tx_eth.src)
2122 self.assertEqual(rx_eth.dst, tx_eth.dst)
2124 def verify_arp_req(self, rx, smac, sip, dip):
2126 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2127 self.assertEqual(ether.src, smac)
2130 self.assertEqual(arp.hwtype, 1)
2131 self.assertEqual(arp.ptype, 0x800)
2132 self.assertEqual(arp.hwlen, 6)
2133 self.assertEqual(arp.plen, 4)
2134 self.assertEqual(arp.op, ARP.who_has)
2135 self.assertEqual(arp.hwsrc, smac)
2136 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2137 self.assertEqual(arp.psrc, sip)
2138 self.assertEqual(arp.pdst, dip)
2140 def test_vpws(self):
2141 """ Virtual Private Wire Service """
2144 # Create an MPLS tunnel that pushes 1 label
2145 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2146 # information is not in the packet, but we test it works anyway
2148 mpls_tun_1 = VppMPLSTunnelInterface(
2150 [VppRoutePath(self.pg0.remote_ip4,
2151 self.pg0.sw_if_index,
2152 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2154 mpls_tun_1.add_vpp_config()
2155 mpls_tun_1.admin_up()
2158 # Create a label entry to for 55 that does L2 input to the tunnel
2160 route_55_eos = VppMplsRoute(
2162 [VppRoutePath("0.0.0.0",
2163 mpls_tun_1.sw_if_index,
2164 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2165 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2166 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2167 route_55_eos.add_vpp_config()
2170 # Cross-connect the tunnel with one of the customers L2 interfaces
2172 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2173 mpls_tun_1.sw_if_index,
2175 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2176 self.pg1.sw_if_index,
2180 # inject a packet from the core
2182 pcore = (Ether(dst=self.pg0.local_mac,
2183 src=self.pg0.remote_mac) /
2184 MPLS(label=55, ttl=64) /
2185 Ether(dst="00:00:de:ad:ba:be",
2186 src="00:00:de:ad:be:ef") /
2187 IP(src="10.10.10.10", dst="11.11.11.11") /
2188 UDP(sport=1234, dport=1234) /
2191 tx0 = pcore * NUM_PKTS
2192 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2193 payload = pcore[MPLS].payload
2195 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2196 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2199 # Inject a packet from the customer/L2 side
2200 # there's no resolved ARP entry so the first packet we see should be
2203 tx1 = pcore[MPLS].payload
2204 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2206 self.verify_arp_req(rx1[0],
2209 self.pg0.remote_ip4)
2212 # resolve the ARP entries and send again
2214 self.pg0.resolve_arp()
2215 tx1 = pcore[MPLS].payload * NUM_PKTS
2216 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2218 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2220 def test_vpls(self):
2221 """ Virtual Private LAN Service """
2223 # we skipped this in the setup
2224 self.pg0.resolve_arp()
2227 # Create a L2 MPLS tunnels
2229 mpls_tun1 = VppMPLSTunnelInterface(
2231 [VppRoutePath(self.pg0.remote_ip4,
2232 self.pg0.sw_if_index,
2233 labels=[VppMplsLabel(42)])],
2235 mpls_tun1.add_vpp_config()
2236 mpls_tun1.admin_up()
2238 mpls_tun2 = VppMPLSTunnelInterface(
2240 [VppRoutePath(self.pg0.remote_ip4,
2241 self.pg0.sw_if_index,
2242 labels=[VppMplsLabel(43)])],
2244 mpls_tun2.add_vpp_config()
2245 mpls_tun2.admin_up()
2248 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2249 # the latter includes a Psuedo Wire Control Word
2251 route_55_eos = VppMplsRoute(
2253 [VppRoutePath("0.0.0.0",
2254 mpls_tun1.sw_if_index,
2255 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2256 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2257 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2259 route_56_eos = VppMplsRoute(
2261 [VppRoutePath("0.0.0.0",
2262 mpls_tun2.sw_if_index,
2263 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2264 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2265 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2266 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2269 route_56_eos.add_vpp_config()
2270 route_55_eos.add_vpp_config()
2272 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2275 # add to tunnel to the customers bridge-domain
2277 self.vapi.sw_interface_set_l2_bridge(
2278 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2279 self.vapi.sw_interface_set_l2_bridge(
2280 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2281 self.vapi.sw_interface_set_l2_bridge(
2282 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2285 # Packet from host on the customer interface to each host
2286 # reachable over the core, and vice-versa
2288 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2289 src="00:00:de:ad:be:ef") /
2290 IP(src="10.10.10.10", dst="11.11.11.11") /
2291 UDP(sport=1234, dport=1234) /
2293 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2294 src="00:00:de:ad:be:ef") /
2295 IP(src="10.10.10.10", dst="11.11.11.12") /
2296 UDP(sport=1234, dport=1234) /
2298 p_core1 = (Ether(dst=self.pg0.local_mac,
2299 src=self.pg0.remote_mac) /
2300 MPLS(label=55, ttl=64) /
2301 Ether(src="00:00:de:ad:ba:b1",
2302 dst="00:00:de:ad:be:ef") /
2303 IP(dst="10.10.10.10", src="11.11.11.11") /
2304 UDP(sport=1234, dport=1234) /
2306 p_core2 = (Ether(dst=self.pg0.local_mac,
2307 src=self.pg0.remote_mac) /
2308 MPLS(label=56, ttl=64) /
2309 Raw(b'\x01' * 4) / # PW CW
2310 Ether(src="00:00:de:ad:ba:b2",
2311 dst="00:00:de:ad:be:ef") /
2312 IP(dst="10.10.10.10", src="11.11.11.12") /
2313 UDP(sport=1234, dport=1234) /
2317 # The BD is learning, so send in one of each packet to learn
2320 # 2 packets due to BD flooding
2321 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2322 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2324 # we've learnt this so expect it be be forwarded not flooded
2325 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2326 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2327 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2329 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2330 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2331 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2334 # now a stream in each direction from each host
2336 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2337 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2340 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2341 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2344 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2345 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2348 # remove interfaces from customers bridge-domain
2350 self.vapi.sw_interface_set_l2_bridge(
2351 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2352 self.vapi.sw_interface_set_l2_bridge(
2353 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2354 self.vapi.sw_interface_set_l2_bridge(
2355 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2358 if __name__ == '__main__':
2359 unittest.main(testRunner=VppTestRunner)