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,
164 ip_dscp=0, payload_size=None):
165 self.reset_packet_infos()
167 for i in range(0, 257):
168 info = self.create_packet_info(src_if, src_if)
169 payload = self.info_to_payload(info)
170 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
171 IP(src=src_if.remote_ip4, dst=dst_ip,
172 ttl=ip_ttl, tos=ip_dscp) /
173 UDP(sport=1234, dport=1234) /
177 self.extend_packet(p, payload_size)
181 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
182 self.reset_packet_infos()
184 for i in range(0, 257):
185 info = self.create_packet_info(src_if, src_if)
186 payload = self.info_to_payload(info)
187 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
188 IPv6(src=src_if.remote_ip6, dst=dst_ip,
189 hlim=ip_ttl, tc=ip_dscp) /
190 UDP(sport=1234, dport=1234) /
196 def create_stream_labelled_ip6(self, src_if, mpls_labels,
197 hlim=64, dst_ip=None):
199 dst_ip = src_if.remote_ip6
200 self.reset_packet_infos()
202 for i in range(0, 257):
203 info = self.create_packet_info(src_if, src_if)
204 payload = self.info_to_payload(info)
205 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
206 for l in mpls_labels:
207 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
209 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
210 UDP(sport=1234, dport=1234) /
216 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
217 ip_ttl=None, ip_dscp=0):
219 capture = verify_filter(capture, sent)
221 self.assertEqual(len(capture), len(sent))
223 for i in range(len(capture)):
227 # the rx'd packet has the MPLS label popped
229 self.assertEqual(eth.type, 0x800)
235 self.assertEqual(rx_ip.src, tx_ip.src)
236 self.assertEqual(rx_ip.dst, tx_ip.dst)
237 self.assertEqual(rx_ip.tos, ip_dscp)
239 # IP processing post pop has decremented the TTL
240 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
242 self.assertEqual(rx_ip.ttl, ip_ttl)
244 self.assertEqual(rx_ip.src, tx_ip.dst)
245 self.assertEqual(rx_ip.dst, tx_ip.src)
250 def verify_capture_labelled_ip4(self, src_if, capture, sent,
251 mpls_labels, ip_ttl=None):
253 capture = verify_filter(capture, sent)
255 self.assertEqual(len(capture), len(sent))
257 for i in range(len(capture)):
263 verify_mpls_stack(self, rx, mpls_labels)
265 self.assertEqual(rx_ip.src, tx_ip.src)
266 self.assertEqual(rx_ip.dst, tx_ip.dst)
268 # IP processing post pop has decremented the TTL
269 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
271 self.assertEqual(rx_ip.ttl, ip_ttl)
276 def verify_capture_labelled_ip6(self, src_if, capture, sent,
277 mpls_labels, ip_ttl=None):
279 capture = verify_filter(capture, sent)
281 self.assertEqual(len(capture), len(sent))
283 for i in range(len(capture)):
289 verify_mpls_stack(self, rx, mpls_labels)
291 self.assertEqual(rx_ip.src, tx_ip.src)
292 self.assertEqual(rx_ip.dst, tx_ip.dst)
294 # IP processing post pop has decremented the TTL
295 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
297 self.assertEqual(rx_ip.hlim, ip_ttl)
302 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
304 capture = verify_filter(capture, sent)
306 self.assertEqual(len(capture), len(sent))
308 for i in range(len(capture)):
314 verify_mpls_stack(self, rx, mpls_labels)
316 self.assertEqual(rx_ip.src, tx_ip.src)
317 self.assertEqual(rx_ip.dst, tx_ip.dst)
318 # IP processing post pop has decremented the TTL
319 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
324 def verify_capture_labelled(self, src_if, capture, sent,
327 capture = verify_filter(capture, sent)
329 self.assertEqual(len(capture), len(sent))
331 for i in range(len(capture)):
333 verify_mpls_stack(self, rx, mpls_labels)
337 def verify_capture_ip6(self, src_if, capture, sent,
338 ip_hlim=None, ip_dscp=0):
340 self.assertEqual(len(capture), len(sent))
342 for i in range(len(capture)):
346 # the rx'd packet has the MPLS label popped
348 self.assertEqual(eth.type, 0x86DD)
353 self.assertEqual(rx_ip.src, tx_ip.src)
354 self.assertEqual(rx_ip.dst, tx_ip.dst)
355 self.assertEqual(rx_ip.tc, ip_dscp)
356 # IP processing post pop has decremented the TTL
358 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
360 self.assertEqual(rx_ip.hlim, ip_hlim)
365 def verify_capture_ip6_icmp(self, src_if, capture, sent):
367 self.assertEqual(len(capture), len(sent))
369 for i in range(len(capture)):
373 # the rx'd packet has the MPLS label popped
375 self.assertEqual(eth.type, 0x86DD)
380 self.assertEqual(rx_ip.dst, tx_ip.src)
381 # ICMP sourced from the interface's address
382 self.assertEqual(rx_ip.src, src_if.local_ip6)
383 # hop-limit reset to 255 for IMCP packet
384 self.assertEqual(rx_ip.hlim, 255)
386 icmp = rx[ICMPv6TimeExceeded]
391 def verify_capture_fragmented_labelled_ip4(self, src_if, capture, sent,
392 mpls_labels, ip_ttl=None):
394 capture = verify_filter(capture, sent)
396 for i in range(len(capture)):
402 verify_mpls_stack(self, rx, mpls_labels)
404 self.assertEqual(rx_ip.src, tx_ip.src)
405 self.assertEqual(rx_ip.dst, tx_ip.dst)
407 # IP processing post pop has decremented the TTL
408 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
410 self.assertEqual(rx_ip.ttl, ip_ttl)
416 """ MPLS label swap tests """
419 # A simple MPLS xconnect - eos label in label out
421 route_32_eos = VppMplsRoute(self, 32, 1,
422 [VppRoutePath(self.pg0.remote_ip4,
423 self.pg0.sw_if_index,
424 labels=[VppMplsLabel(33)])])
425 route_32_eos.add_vpp_config()
428 find_mpls_route(self, 0, 32, 1,
429 [VppRoutePath(self.pg0.remote_ip4,
430 self.pg0.sw_if_index,
431 labels=[VppMplsLabel(33)])]))
434 # a stream that matches the route for 10.0.0.1
435 # PG0 is in the default table
437 tx = self.create_stream_labelled_ip4(self.pg0,
438 [VppMplsLabel(32, ttl=32, exp=1)])
439 rx = self.send_and_expect(self.pg0, tx, self.pg0)
440 self.verify_capture_labelled(self.pg0, rx, tx,
441 [VppMplsLabel(33, ttl=31, exp=1)])
443 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
446 # A simple MPLS xconnect - non-eos label in label out
448 route_32_neos = VppMplsRoute(self, 32, 0,
449 [VppRoutePath(self.pg0.remote_ip4,
450 self.pg0.sw_if_index,
451 labels=[VppMplsLabel(33)])])
452 route_32_neos.add_vpp_config()
455 # a stream that matches the route for 10.0.0.1
456 # PG0 is in the default table
458 tx = self.create_stream_labelled_ip4(self.pg0,
459 [VppMplsLabel(32, ttl=21, exp=7),
461 rx = self.send_and_expect(self.pg0, tx, self.pg0)
462 self.verify_capture_labelled(self.pg0, rx, tx,
463 [VppMplsLabel(33, ttl=20, exp=7),
465 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
468 # A simple MPLS xconnect - non-eos label in label out, uniform mode
470 route_42_neos = VppMplsRoute(
472 [VppRoutePath(self.pg0.remote_ip4,
473 self.pg0.sw_if_index,
474 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
475 route_42_neos.add_vpp_config()
477 tx = self.create_stream_labelled_ip4(self.pg0,
478 [VppMplsLabel(42, ttl=21, exp=7),
480 rx = self.send_and_expect(self.pg0, tx, self.pg0)
481 self.verify_capture_labelled(self.pg0, rx, tx,
482 [VppMplsLabel(43, ttl=20, exp=7),
486 # An MPLS xconnect - EOS label in IP out
488 route_33_eos = VppMplsRoute(self, 33, 1,
489 [VppRoutePath(self.pg0.remote_ip4,
490 self.pg0.sw_if_index,
492 route_33_eos.add_vpp_config()
494 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
495 rx = self.send_and_expect(self.pg0, tx, self.pg0)
496 self.verify_capture_ip4(self.pg0, rx, tx)
499 # disposed packets have an invalid IPv4 checksum
501 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
502 dst_ip=self.pg0.remote_ip4,
505 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
508 # An MPLS xconnect - EOS label in IP out, uniform mode
510 route_3333_eos = VppMplsRoute(
512 [VppRoutePath(self.pg0.remote_ip4,
513 self.pg0.sw_if_index,
514 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
515 route_3333_eos.add_vpp_config()
517 tx = self.create_stream_labelled_ip4(
519 [VppMplsLabel(3333, ttl=55, exp=3)])
520 rx = self.send_and_expect(self.pg0, tx, self.pg0)
521 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
522 tx = self.create_stream_labelled_ip4(
524 [VppMplsLabel(3333, ttl=66, exp=4)])
525 rx = self.send_and_expect(self.pg0, tx, self.pg0)
526 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
529 # An MPLS xconnect - EOS label in IPv6 out
531 route_333_eos = VppMplsRoute(
533 [VppRoutePath(self.pg0.remote_ip6,
534 self.pg0.sw_if_index,
536 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
537 route_333_eos.add_vpp_config()
539 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
540 rx = self.send_and_expect(self.pg0, tx, self.pg0)
541 self.verify_capture_ip6(self.pg0, rx, tx)
544 # disposed packets have an TTL expired
546 tx = self.create_stream_labelled_ip6(self.pg0,
547 [VppMplsLabel(333, ttl=64)],
548 dst_ip=self.pg1.remote_ip6,
550 rx = self.send_and_expect(self.pg0, tx, self.pg0)
551 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
554 # An MPLS xconnect - EOS label in IPv6 out w imp-null
556 route_334_eos = VppMplsRoute(
558 [VppRoutePath(self.pg0.remote_ip6,
559 self.pg0.sw_if_index,
560 labels=[VppMplsLabel(3)])],
561 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
562 route_334_eos.add_vpp_config()
564 tx = self.create_stream_labelled_ip6(self.pg0,
565 [VppMplsLabel(334, ttl=64)])
566 rx = self.send_and_expect(self.pg0, tx, self.pg0)
567 self.verify_capture_ip6(self.pg0, rx, tx)
570 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
572 route_335_eos = VppMplsRoute(
574 [VppRoutePath(self.pg0.remote_ip6,
575 self.pg0.sw_if_index,
576 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
577 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
578 route_335_eos.add_vpp_config()
580 tx = self.create_stream_labelled_ip6(
582 [VppMplsLabel(335, ttl=27, exp=4)])
583 rx = self.send_and_expect(self.pg0, tx, self.pg0)
584 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
587 # disposed packets have an TTL expired
589 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
590 dst_ip=self.pg1.remote_ip6,
592 rx = self.send_and_expect(self.pg0, tx, self.pg0)
593 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
596 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
597 # so this traffic should be dropped.
599 route_33_neos = VppMplsRoute(self, 33, 0,
600 [VppRoutePath(self.pg0.remote_ip4,
601 self.pg0.sw_if_index,
603 route_33_neos.add_vpp_config()
605 tx = self.create_stream_labelled_ip4(self.pg0,
608 self.send_and_assert_no_replies(
610 "MPLS non-EOS packets popped and forwarded")
613 # A recursive EOS x-connect, which resolves through another x-connect
616 route_34_eos = VppMplsRoute(self, 34, 1,
617 [VppRoutePath("0.0.0.0",
620 labels=[VppMplsLabel(44),
622 route_34_eos.add_vpp_config()
623 self.logger.info(self.vapi.cli("sh mpls fib 34"))
625 tx = self.create_stream_labelled_ip4(self.pg0,
626 [VppMplsLabel(34, ttl=3)])
627 rx = self.send_and_expect(self.pg0, tx, self.pg0)
628 self.verify_capture_labelled(self.pg0, rx, tx,
631 VppMplsLabel(45, ttl=2)])
633 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
634 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
637 # A recursive EOS x-connect, which resolves through another x-connect
640 route_35_eos = VppMplsRoute(
642 [VppRoutePath("0.0.0.0",
645 labels=[VppMplsLabel(44)])])
646 route_35_eos.add_vpp_config()
648 tx = self.create_stream_labelled_ip4(self.pg0,
649 [VppMplsLabel(35, ttl=3)])
650 rx = self.send_and_expect(self.pg0, tx, self.pg0)
651 self.verify_capture_labelled(self.pg0, rx, tx,
652 [VppMplsLabel(43, ttl=2),
653 VppMplsLabel(44, ttl=2)])
656 # A recursive non-EOS x-connect, which resolves through another
659 route_34_neos = VppMplsRoute(self, 34, 0,
660 [VppRoutePath("0.0.0.0",
663 labels=[VppMplsLabel(44),
665 route_34_neos.add_vpp_config()
667 tx = self.create_stream_labelled_ip4(self.pg0,
668 [VppMplsLabel(34, ttl=45),
670 rx = self.send_and_expect(self.pg0, tx, self.pg0)
671 # it's the 2nd (counting from 0) label in the stack that is swapped
672 self.verify_capture_labelled(self.pg0, rx, tx,
675 VppMplsLabel(46, ttl=44),
679 # an recursive IP route that resolves through the recursive non-eos
682 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
683 [VppRoutePath("0.0.0.0",
686 labels=[VppMplsLabel(55)])])
687 ip_10_0_0_1.add_vpp_config()
689 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
690 rx = self.send_and_expect(self.pg0, tx, self.pg0)
691 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
696 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
698 ip_10_0_0_1.remove_vpp_config()
699 route_34_neos.remove_vpp_config()
700 route_34_eos.remove_vpp_config()
701 route_33_neos.remove_vpp_config()
702 route_33_eos.remove_vpp_config()
703 route_32_neos.remove_vpp_config()
704 route_32_eos.remove_vpp_config()
707 """ MPLS Local Label Binding test """
710 # Add a non-recursive route with a single out label
712 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
713 [VppRoutePath(self.pg0.remote_ip4,
714 self.pg0.sw_if_index,
715 labels=[VppMplsLabel(45)])])
716 route_10_0_0_1.add_vpp_config()
718 # bind a local label to the route
719 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
720 binding.add_vpp_config()
723 tx = self.create_stream_labelled_ip4(self.pg0,
726 rx = self.send_and_expect(self.pg0, tx, self.pg0)
727 self.verify_capture_labelled(self.pg0, rx, tx,
728 [VppMplsLabel(45, ttl=63),
732 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
733 rx = self.send_and_expect(self.pg0, tx, self.pg0)
734 self.verify_capture_labelled(self.pg0, rx, tx,
735 [VppMplsLabel(45, ttl=63)])
738 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
739 rx = self.send_and_expect(self.pg0, tx, self.pg0)
740 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
745 binding.remove_vpp_config()
746 route_10_0_0_1.remove_vpp_config()
748 def test_imposition(self):
749 """ MPLS label imposition test """
752 # Add a non-recursive route with a single out label
754 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
755 [VppRoutePath(self.pg0.remote_ip4,
756 self.pg0.sw_if_index,
757 labels=[VppMplsLabel(32)])])
758 route_10_0_0_1.add_vpp_config()
761 # a stream that matches the route for 10.0.0.1
762 # PG0 is in the default table
764 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
765 rx = self.send_and_expect(self.pg0, tx, self.pg0)
766 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
769 # Add a non-recursive route with a 3 out labels
771 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
772 [VppRoutePath(self.pg0.remote_ip4,
773 self.pg0.sw_if_index,
774 labels=[VppMplsLabel(32),
777 route_10_0_0_2.add_vpp_config()
779 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
780 ip_ttl=44, ip_dscp=0xff)
781 rx = self.send_and_expect(self.pg0, tx, self.pg0)
782 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
789 # Add a non-recursive route with a single out label in uniform mode
791 route_10_0_0_3 = VppIpRoute(
792 self, "10.0.0.3", 32,
793 [VppRoutePath(self.pg0.remote_ip4,
794 self.pg0.sw_if_index,
795 labels=[VppMplsLabel(32,
796 mode=MplsLspMode.UNIFORM)])])
797 route_10_0_0_3.add_vpp_config()
799 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
800 ip_ttl=54, ip_dscp=0xbe)
801 rx = self.send_and_expect(self.pg0, tx, self.pg0)
802 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
803 [VppMplsLabel(32, ttl=53, exp=5)])
806 # Add a IPv6 non-recursive route with a single out label in
809 route_2001_3 = VppIpRoute(
810 self, "2001::3", 128,
811 [VppRoutePath(self.pg0.remote_ip6,
812 self.pg0.sw_if_index,
813 labels=[VppMplsLabel(32,
814 mode=MplsLspMode.UNIFORM)])])
815 route_2001_3.add_vpp_config()
817 tx = self.create_stream_ip6(self.pg0, "2001::3",
818 ip_ttl=54, ip_dscp=0xbe)
819 rx = self.send_and_expect(self.pg0, tx, self.pg0)
820 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
821 [VppMplsLabel(32, ttl=53, exp=5)])
824 # add a recursive path, with output label, via the 1 label route
826 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
827 [VppRoutePath("10.0.0.1",
829 labels=[VppMplsLabel(44)])])
830 route_11_0_0_1.add_vpp_config()
833 # a stream that matches the route for 11.0.0.1, should pick up
834 # the label stack for 11.0.0.1 and 10.0.0.1
836 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
837 rx = self.send_and_expect(self.pg0, tx, self.pg0)
838 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
842 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
845 # add a recursive path, with 2 labels, via the 3 label route
847 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
848 [VppRoutePath("10.0.0.2",
850 labels=[VppMplsLabel(44),
852 route_11_0_0_2.add_vpp_config()
855 # a stream that matches the route for 11.0.0.1, should pick up
856 # the label stack for 11.0.0.1 and 10.0.0.1
858 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
859 rx = self.send_and_expect(self.pg0, tx, self.pg0)
860 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
867 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
869 rx = self.send_and_expect(self.pg0, tx, self.pg0)
870 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
877 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
882 route_11_0_0_2.remove_vpp_config()
883 route_11_0_0_1.remove_vpp_config()
884 route_10_0_0_2.remove_vpp_config()
885 route_10_0_0_1.remove_vpp_config()
887 def test_imposition_fragmentation(self):
888 """ MPLS label imposition fragmentation test """
891 # Add a ipv4 non-recursive route with a single out label
893 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
894 [VppRoutePath(self.pg0.remote_ip4,
895 self.pg0.sw_if_index,
896 labels=[VppMplsLabel(32)])])
897 route_10_0_0_1.add_vpp_config()
900 # a stream that matches the route for 10.0.0.1
901 # PG0 is in the default table
903 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
904 for i in range(0, 257):
905 self.extend_packet(tx[i], 10000)
908 # 5 fragments per packet (257*5=1285)
910 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
911 self.verify_capture_fragmented_labelled_ip4(self.pg0, rx, tx,
917 route_10_0_0_1.remove_vpp_config()
919 def test_tunnel_pipe(self):
920 """ MPLS Tunnel Tests - Pipe """
923 # Create a tunnel with two out labels
925 mpls_tun = VppMPLSTunnelInterface(
927 [VppRoutePath(self.pg0.remote_ip4,
928 self.pg0.sw_if_index,
929 labels=[VppMplsLabel(44),
931 mpls_tun.add_vpp_config()
935 # add an unlabelled route through the new tunnel
937 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
938 [VppRoutePath("0.0.0.0",
939 mpls_tun._sw_if_index)])
940 route_10_0_0_3.add_vpp_config()
942 self.vapi.cli("clear trace")
943 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
944 self.pg0.add_stream(tx)
946 self.pg_enable_capture(self.pg_interfaces)
949 rx = self.pg0.get_capture()
950 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
955 # add a labelled route through the new tunnel
957 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
958 [VppRoutePath("0.0.0.0",
959 mpls_tun._sw_if_index,
961 route_10_0_0_4.add_vpp_config()
963 self.vapi.cli("clear trace")
964 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
965 self.pg0.add_stream(tx)
967 self.pg_enable_capture(self.pg_interfaces)
970 rx = self.pg0.get_capture()
971 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
974 VppMplsLabel(33, ttl=255)])
977 # change tunnel's MTU to a low value
979 mpls_tun.set_l3_mtu(1200)
981 # send IP into the tunnel to be fragmented
982 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
984 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
990 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
994 # send MPLS into the tunnel to be fragmented
995 tx = self.create_stream_ip4(self.pg0, "10.0.0.4",
997 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1003 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1006 VppMplsLabel(33, ttl=255)])
1008 def test_tunnel_uniform(self):
1009 """ MPLS Tunnel Tests - Uniform """
1012 # Create a tunnel with a single out label
1013 # The label stack is specified here from outer to inner
1015 mpls_tun = VppMPLSTunnelInterface(
1017 [VppRoutePath(self.pg0.remote_ip4,
1018 self.pg0.sw_if_index,
1019 labels=[VppMplsLabel(44, ttl=32),
1020 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1021 mpls_tun.add_vpp_config()
1025 # add an unlabelled route through the new tunnel
1027 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1028 [VppRoutePath("0.0.0.0",
1029 mpls_tun._sw_if_index)])
1030 route_10_0_0_3.add_vpp_config()
1032 self.vapi.cli("clear trace")
1033 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1034 self.pg0.add_stream(tx)
1036 self.pg_enable_capture(self.pg_interfaces)
1039 rx = self.pg0.get_capture()
1040 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1041 [VppMplsLabel(44, ttl=32),
1042 VppMplsLabel(46, ttl=23)])
1045 # add a labelled route through the new tunnel
1047 route_10_0_0_4 = VppIpRoute(
1048 self, "10.0.0.4", 32,
1049 [VppRoutePath("0.0.0.0",
1050 mpls_tun._sw_if_index,
1051 labels=[VppMplsLabel(33, ttl=47)])])
1052 route_10_0_0_4.add_vpp_config()
1054 self.vapi.cli("clear trace")
1055 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1056 self.pg0.add_stream(tx)
1058 self.pg_enable_capture(self.pg_interfaces)
1061 rx = self.pg0.get_capture()
1062 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1063 [VppMplsLabel(44, ttl=32),
1064 VppMplsLabel(46, ttl=47),
1065 VppMplsLabel(33, ttl=47)])
1067 def test_mpls_tunnel_many(self):
1068 """ MPLS Multiple Tunnels """
1070 for ii in range(10):
1071 mpls_tun = VppMPLSTunnelInterface(
1073 [VppRoutePath(self.pg0.remote_ip4,
1074 self.pg0.sw_if_index,
1075 labels=[VppMplsLabel(44, ttl=32),
1076 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1077 mpls_tun.add_vpp_config()
1080 def test_v4_exp_null(self):
1081 """ MPLS V4 Explicit NULL test """
1084 # The first test case has an MPLS TTL of 0
1085 # all packet should be dropped
1087 tx = self.create_stream_labelled_ip4(self.pg0,
1088 [VppMplsLabel(0, ttl=0)])
1089 self.send_and_assert_no_replies(self.pg0, tx,
1090 "MPLS TTL=0 packets forwarded")
1093 # a stream with a non-zero MPLS TTL
1094 # PG0 is in the default table
1096 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1097 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1098 self.verify_capture_ip4(self.pg0, rx, tx)
1101 # a stream with a non-zero MPLS TTL
1103 # we are ensuring the post-pop lookup occurs in the VRF table
1105 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1106 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1107 self.verify_capture_ip4(self.pg1, rx, tx)
1109 def test_v6_exp_null(self):
1110 """ MPLS V6 Explicit NULL test """
1113 # a stream with a non-zero MPLS TTL
1114 # PG0 is in the default table
1116 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1117 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1118 self.verify_capture_ip6(self.pg0, rx, tx)
1121 # a stream with a non-zero MPLS TTL
1123 # we are ensuring the post-pop lookup occurs in the VRF table
1125 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1126 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1127 self.verify_capture_ip6(self.pg0, rx, tx)
1129 def test_deag(self):
1133 # A de-agg route - next-hop lookup in default table
1135 route_34_eos = VppMplsRoute(self, 34, 1,
1136 [VppRoutePath("0.0.0.0",
1139 route_34_eos.add_vpp_config()
1142 # ping an interface in the default table
1143 # PG0 is in the default table
1145 tx = self.create_stream_labelled_ip4(self.pg0,
1149 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1150 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1153 # A de-agg route - next-hop lookup in non-default table
1155 route_35_eos = VppMplsRoute(self, 35, 1,
1156 [VppRoutePath("0.0.0.0",
1159 route_35_eos.add_vpp_config()
1162 # ping an interface in the non-default table
1163 # PG0 is in the default table. packet arrive labelled in the
1164 # default table and egress unlabelled in the non-default
1166 tx = self.create_stream_labelled_ip4(
1167 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1168 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1169 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1174 route_36_neos = VppMplsRoute(self, 36, 0,
1175 [VppRoutePath("0.0.0.0",
1177 route_36_neos.add_vpp_config()
1179 tx = self.create_stream_labelled_ip4(self.pg0,
1182 ping=1, ip_itf=self.pg1)
1183 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1184 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1186 route_36_neos.remove_vpp_config()
1187 route_35_eos.remove_vpp_config()
1188 route_34_eos.remove_vpp_config()
1190 def test_interface_rx(self):
1191 """ MPLS Interface Receive """
1194 # Add a non-recursive route that will forward the traffic
1197 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1199 paths=[VppRoutePath(self.pg1.remote_ip4,
1200 self.pg1.sw_if_index)])
1201 route_10_0_0_1.add_vpp_config()
1204 # An interface receive label that maps traffic to RX on interface
1206 # by injecting the packet in on pg0, which is in table 0
1207 # doing an interface-rx on pg1 and matching a route in table 1
1208 # if the packet egresses, then we must have swapped to pg1
1209 # so as to have matched the route in table 1
1211 route_34_eos = VppMplsRoute(
1213 [VppRoutePath("0.0.0.0",
1214 self.pg1.sw_if_index,
1215 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1216 route_34_eos.add_vpp_config()
1219 # ping an interface in the default table
1220 # PG0 is in the default table
1222 tx = self.create_stream_labelled_ip4(self.pg0,
1225 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1226 self.verify_capture_ip4(self.pg1, rx, tx)
1228 def test_mcast_mid_point(self):
1229 """ MPLS Multicast Mid Point """
1232 # Add a non-recursive route that will forward the traffic
1235 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1237 paths=[VppRoutePath(self.pg1.remote_ip4,
1238 self.pg1.sw_if_index)])
1239 route_10_0_0_1.add_vpp_config()
1242 # Add a mcast entry that replicate to pg2 and pg3
1243 # and replicate to a interface-rx (like a bud node would)
1245 route_3400_eos = VppMplsRoute(
1247 [VppRoutePath(self.pg2.remote_ip4,
1248 self.pg2.sw_if_index,
1249 labels=[VppMplsLabel(3401)]),
1250 VppRoutePath(self.pg3.remote_ip4,
1251 self.pg3.sw_if_index,
1252 labels=[VppMplsLabel(3402)]),
1253 VppRoutePath("0.0.0.0",
1254 self.pg1.sw_if_index,
1255 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1257 route_3400_eos.add_vpp_config()
1260 # ping an interface in the default table
1261 # PG0 is in the default table
1263 self.vapi.cli("clear trace")
1264 tx = self.create_stream_labelled_ip4(self.pg0,
1265 [VppMplsLabel(3400, ttl=64)],
1268 self.pg0.add_stream(tx)
1270 self.pg_enable_capture(self.pg_interfaces)
1273 rx = self.pg1.get_capture(257)
1274 self.verify_capture_ip4(self.pg1, rx, tx)
1276 rx = self.pg2.get_capture(257)
1277 self.verify_capture_labelled(self.pg2, rx, tx,
1278 [VppMplsLabel(3401, ttl=63)])
1279 rx = self.pg3.get_capture(257)
1280 self.verify_capture_labelled(self.pg3, rx, tx,
1281 [VppMplsLabel(3402, ttl=63)])
1283 def test_mcast_head(self):
1284 """ MPLS Multicast Head-end """
1287 # Create a multicast tunnel with two replications
1289 mpls_tun = VppMPLSTunnelInterface(
1291 [VppRoutePath(self.pg2.remote_ip4,
1292 self.pg2.sw_if_index,
1293 labels=[VppMplsLabel(42)]),
1294 VppRoutePath(self.pg3.remote_ip4,
1295 self.pg3.sw_if_index,
1296 labels=[VppMplsLabel(43)])],
1298 mpls_tun.add_vpp_config()
1302 # add an unlabelled route through the new tunnel
1304 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1305 [VppRoutePath("0.0.0.0",
1306 mpls_tun._sw_if_index)])
1307 route_10_0_0_3.add_vpp_config()
1309 self.vapi.cli("clear trace")
1310 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1311 self.pg0.add_stream(tx)
1313 self.pg_enable_capture(self.pg_interfaces)
1316 rx = self.pg2.get_capture(257)
1317 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1318 rx = self.pg3.get_capture(257)
1319 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1322 # An an IP multicast route via the tunnel
1324 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1326 route_232_1_1_1 = VppIpMRoute(
1330 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1331 [VppMRoutePath(self.pg0.sw_if_index,
1332 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1333 VppMRoutePath(mpls_tun._sw_if_index,
1334 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1335 route_232_1_1_1.add_vpp_config()
1336 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1338 self.vapi.cli("clear trace")
1339 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1340 self.pg0.add_stream(tx)
1342 self.pg_enable_capture(self.pg_interfaces)
1345 rx = self.pg2.get_capture(257)
1346 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1347 rx = self.pg3.get_capture(257)
1348 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1350 def test_mcast_ip4_tail(self):
1351 """ MPLS IPv4 Multicast Tail """
1354 # Add a multicast route that will forward the traffic
1357 route_232_1_1_1 = VppIpMRoute(
1361 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1363 paths=[VppMRoutePath(self.pg1.sw_if_index,
1364 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1365 route_232_1_1_1.add_vpp_config()
1368 # An interface receive label that maps traffic to RX on interface
1370 # by injecting the packet in on pg0, which is in table 0
1371 # doing an rpf-id and matching a route in table 1
1372 # if the packet egresses, then we must have matched the route in
1375 route_34_eos = VppMplsRoute(
1377 [VppRoutePath("0.0.0.0",
1382 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1384 route_34_eos.add_vpp_config()
1387 # Drop due to interface lookup miss
1389 self.vapi.cli("clear trace")
1390 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1391 dst_ip="232.1.1.1", n=1)
1392 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1395 # set the RPF-ID of the entry to match the input packet's
1397 route_232_1_1_1.update_rpf_id(55)
1398 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1400 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1402 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1403 self.verify_capture_ip4(self.pg1, rx, tx)
1406 # disposed packets have an invalid IPv4 checksum
1408 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1409 dst_ip="232.1.1.1", n=65,
1411 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1414 # set the RPF-ID of the entry to not match the input packet's
1416 route_232_1_1_1.update_rpf_id(56)
1417 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1419 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1421 def test_mcast_ip6_tail(self):
1422 """ MPLS IPv6 Multicast Tail """
1425 # Add a multicast route that will forward the traffic
1428 route_ff = VppIpMRoute(
1432 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1434 paths=[VppMRoutePath(self.pg1.sw_if_index,
1435 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
1436 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1437 route_ff.add_vpp_config()
1440 # An interface receive label that maps traffic to RX on interface
1442 # by injecting the packet in on pg0, which is in table 0
1443 # doing an rpf-id and matching a route in table 1
1444 # if the packet egresses, then we must have matched the route in
1447 route_34_eos = VppMplsRoute(
1454 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1456 route_34_eos.add_vpp_config()
1459 # Drop due to interface lookup miss
1461 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1463 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1466 # set the RPF-ID of the entry to match the input packet's
1468 route_ff.update_rpf_id(55)
1470 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1472 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1473 self.verify_capture_ip6(self.pg1, rx, tx)
1476 # disposed packets have hop-limit = 1
1478 tx = self.create_stream_labelled_ip6(self.pg0,
1482 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1483 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1486 # set the RPF-ID of the entry to not match the input packet's
1488 route_ff.update_rpf_id(56)
1489 tx = self.create_stream_labelled_ip6(self.pg0,
1492 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1498 # Add a non-recursive route with a single out label
1500 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1501 [VppRoutePath(self.pg0.remote_ip4,
1502 self.pg0.sw_if_index,
1503 labels=[VppMplsLabel(45)])])
1504 route_10_0_0_1.add_vpp_config()
1506 # bind a local label to the route
1507 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1508 binding.add_vpp_config()
1511 # a labelled v6 route that resolves through the v4
1513 route_2001_3 = VppIpRoute(
1514 self, "2001::3", 128,
1515 [VppRoutePath("10.0.0.1",
1517 labels=[VppMplsLabel(32)])])
1518 route_2001_3.add_vpp_config()
1520 tx = self.create_stream_ip6(self.pg0, "2001::3")
1521 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1523 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1528 # and a v4 recursive via the v6
1530 route_20_3 = VppIpRoute(
1531 self, "20.0.0.3", 32,
1532 [VppRoutePath("2001::3",
1534 labels=[VppMplsLabel(99)])])
1535 route_20_3.add_vpp_config()
1537 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1538 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1540 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1546 class TestMPLSDisabled(VppTestCase):
1547 """ MPLS disabled """
1550 def setUpClass(cls):
1551 super(TestMPLSDisabled, cls).setUpClass()
1554 def tearDownClass(cls):
1555 super(TestMPLSDisabled, cls).tearDownClass()
1558 super(TestMPLSDisabled, self).setUp()
1560 # create 2 pg interfaces
1561 self.create_pg_interfaces(range(2))
1563 self.tbl = VppMplsTable(self, 0)
1564 self.tbl.add_vpp_config()
1566 # PG0 is MPLS enabled
1568 self.pg0.config_ip4()
1569 self.pg0.resolve_arp()
1570 self.pg0.enable_mpls()
1572 # PG 1 is not MPLS enabled
1576 for i in self.pg_interfaces:
1580 self.pg0.disable_mpls()
1581 super(TestMPLSDisabled, self).tearDown()
1583 def test_mpls_disabled(self):
1584 """ MPLS Disabled """
1586 tx = (Ether(src=self.pg1.remote_mac,
1587 dst=self.pg1.local_mac) /
1588 MPLS(label=32, ttl=64) /
1589 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1590 UDP(sport=1234, dport=1234) /
1594 # A simple MPLS xconnect - eos label in label out
1596 route_32_eos = VppMplsRoute(self, 32, 1,
1597 [VppRoutePath(self.pg0.remote_ip4,
1598 self.pg0.sw_if_index,
1600 route_32_eos.add_vpp_config()
1603 # PG1 does not forward IP traffic
1605 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1610 self.pg1.enable_mpls()
1613 # Now we get packets through
1615 self.pg1.add_stream(tx)
1616 self.pg_enable_capture(self.pg_interfaces)
1619 rx = self.pg0.get_capture(1)
1624 self.pg1.disable_mpls()
1627 # PG1 does not forward IP traffic
1629 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1630 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1633 class TestMPLSPIC(VppTestCase):
1634 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1637 def setUpClass(cls):
1638 super(TestMPLSPIC, cls).setUpClass()
1641 def tearDownClass(cls):
1642 super(TestMPLSPIC, cls).tearDownClass()
1645 super(TestMPLSPIC, self).setUp()
1647 # create 2 pg interfaces
1648 self.create_pg_interfaces(range(4))
1650 mpls_tbl = VppMplsTable(self, 0)
1651 mpls_tbl.add_vpp_config()
1652 tbl4 = VppIpTable(self, 1)
1653 tbl4.add_vpp_config()
1654 tbl6 = VppIpTable(self, 1, is_ip6=1)
1655 tbl6.add_vpp_config()
1659 self.pg0.config_ip4()
1660 self.pg0.resolve_arp()
1661 self.pg0.enable_mpls()
1664 self.pg1.config_ip4()
1665 self.pg1.resolve_arp()
1666 self.pg1.enable_mpls()
1668 # VRF (customer facing) link
1670 self.pg2.set_table_ip4(1)
1671 self.pg2.config_ip4()
1672 self.pg2.resolve_arp()
1673 self.pg2.set_table_ip6(1)
1674 self.pg2.config_ip6()
1675 self.pg2.resolve_ndp()
1678 self.pg3.set_table_ip4(1)
1679 self.pg3.config_ip4()
1680 self.pg3.resolve_arp()
1681 self.pg3.set_table_ip6(1)
1682 self.pg3.config_ip6()
1683 self.pg3.resolve_ndp()
1686 self.pg0.disable_mpls()
1687 self.pg1.disable_mpls()
1688 for i in self.pg_interfaces:
1694 super(TestMPLSPIC, self).tearDown()
1696 def test_mpls_ibgp_pic(self):
1697 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1699 1) setup many iBGP VPN routes via a pair of iBGP peers.
1700 2) Check EMCP forwarding to these peers
1701 3) withdraw the IGP route to one of these peers.
1702 4) check forwarding continues to the remaining peer
1706 # IGP+LDP core routes
1708 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1709 [VppRoutePath(self.pg0.remote_ip4,
1710 self.pg0.sw_if_index,
1712 core_10_0_0_45.add_vpp_config()
1714 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1715 [VppRoutePath(self.pg1.remote_ip4,
1716 self.pg1.sw_if_index,
1718 core_10_0_0_46.add_vpp_config()
1721 # Lot's of VPN routes. We need more the 64 so VPP will build
1722 # the fast convergence indirection
1726 for ii in range(NUM_PKTS):
1727 dst = "192.168.1.%d" % ii
1728 vpn_routes.append(VppIpRoute(
1734 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1739 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1741 vpn_routes[ii].add_vpp_config()
1743 pkts.append(Ether(dst=self.pg2.local_mac,
1744 src=self.pg2.remote_mac) /
1745 IP(src=self.pg2.remote_ip4, dst=dst) /
1746 UDP(sport=1234, dport=1234) /
1750 # Send the packet stream (one pkt to each VPN route)
1751 # - expect a 50-50 split of the traffic
1753 self.pg2.add_stream(pkts)
1754 self.pg_enable_capture(self.pg_interfaces)
1757 rx0 = self.pg0._get_capture(NUM_PKTS)
1758 rx1 = self.pg1._get_capture(NUM_PKTS)
1760 # not testing the LB hashing algorithm so we're not concerned
1761 # with the split ratio, just as long as neither is 0
1762 self.assertNotEqual(0, len(rx0))
1763 self.assertNotEqual(0, len(rx1))
1764 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1765 "Expected all (%s) packets across both ECMP paths. "
1766 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1769 # use a test CLI command to stop the FIB walk process, this
1770 # will prevent the FIB converging the VPN routes and thus allow
1771 # us to probe the interim (post-fail, pre-converge) state
1773 self.vapi.ppcli("test fib-walk-process disable")
1776 # Withdraw one of the IGP routes
1778 core_10_0_0_46.remove_vpp_config()
1781 # now all packets should be forwarded through the remaining peer
1783 self.vapi.ppcli("clear trace")
1784 self.pg2.add_stream(pkts)
1785 self.pg_enable_capture(self.pg_interfaces)
1788 rx0 = self.pg0.get_capture(NUM_PKTS)
1789 self.assertEqual(len(pkts), len(rx0),
1790 "Expected all (%s) packets across single path. "
1791 "rx0: %s." % (len(pkts), len(rx0)))
1794 # enable the FIB walk process to converge the FIB
1796 self.vapi.ppcli("test fib-walk-process enable")
1799 # packets should still be forwarded through the remaining peer
1801 self.pg2.add_stream(pkts)
1802 self.pg_enable_capture(self.pg_interfaces)
1805 rx0 = self.pg0.get_capture(NUM_PKTS)
1806 self.assertEqual(len(pkts), len(rx0),
1807 "Expected all (%s) packets across single path. "
1808 "rx0: %s." % (len(pkts), len(rx0)))
1811 # Add the IGP route back and we return to load-balancing
1813 core_10_0_0_46.add_vpp_config()
1815 self.pg2.add_stream(pkts)
1816 self.pg_enable_capture(self.pg_interfaces)
1819 rx0 = self.pg0._get_capture(NUM_PKTS)
1820 rx1 = self.pg1._get_capture(NUM_PKTS)
1821 self.assertNotEqual(0, len(rx0))
1822 self.assertNotEqual(0, len(rx1))
1823 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1824 "Expected all (%s) packets across both ECMP paths. "
1825 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1827 def test_mpls_ebgp_pic(self):
1828 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1830 1) setup many eBGP VPN routes via a pair of eBGP peers.
1831 2) Check EMCP forwarding to these peers
1832 3) withdraw one eBGP path - expect LB across remaining eBGP
1836 # Lot's of VPN routes. We need more the 64 so VPP will build
1837 # the fast convergence indirection
1842 for ii in range(NUM_PKTS):
1843 dst = "192.168.1.%d" % ii
1844 local_label = 1600 + ii
1845 vpn_routes.append(VppIpRoute(
1848 self.pg2.remote_ip4,
1851 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1853 self.pg3.remote_ip4,
1856 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1858 vpn_routes[ii].add_vpp_config()
1860 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1862 vpn_bindings[ii].add_vpp_config()
1864 pkts.append(Ether(dst=self.pg0.local_mac,
1865 src=self.pg0.remote_mac) /
1866 MPLS(label=local_label, ttl=64) /
1867 IP(src=self.pg0.remote_ip4, dst=dst) /
1868 UDP(sport=1234, dport=1234) /
1872 # Send the packet stream (one pkt to each VPN route)
1873 # - expect a 50-50 split of the traffic
1875 self.pg0.add_stream(pkts)
1876 self.pg_enable_capture(self.pg_interfaces)
1879 rx0 = self.pg2._get_capture(NUM_PKTS)
1880 rx1 = self.pg3._get_capture(NUM_PKTS)
1882 # not testing the LB hashing algorithm so we're not concerned
1883 # with the split ratio, just as long as neither is 0
1884 self.assertNotEqual(0, len(rx0))
1885 self.assertNotEqual(0, len(rx1))
1886 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1887 "Expected all (%s) packets across both ECMP paths. "
1888 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1891 # use a test CLI command to stop the FIB walk process, this
1892 # will prevent the FIB converging the VPN routes and thus allow
1893 # us to probe the interim (post-fail, pre-converge) state
1895 self.vapi.ppcli("test fib-walk-process disable")
1898 # withdraw the connected prefix on the interface.
1900 self.pg2.unconfig_ip4()
1903 # now all packets should be forwarded through the remaining peer
1905 self.pg0.add_stream(pkts)
1906 self.pg_enable_capture(self.pg_interfaces)
1909 rx0 = self.pg3.get_capture(NUM_PKTS)
1910 self.assertEqual(len(pkts), len(rx0),
1911 "Expected all (%s) packets across single path. "
1912 "rx0: %s." % (len(pkts), len(rx0)))
1915 # enable the FIB walk process to converge the FIB
1917 self.vapi.ppcli("test fib-walk-process enable")
1920 # packets should still be forwarded through the remaining peer
1922 self.pg0.add_stream(pkts)
1923 self.pg_enable_capture(self.pg_interfaces)
1926 rx0 = self.pg3.get_capture(NUM_PKTS)
1927 self.assertEqual(len(pkts), len(rx0),
1928 "Expected all (%s) packets across single path. "
1929 "rx0: %s." % (len(pkts), len(rx0)))
1932 # put the connected routes back
1934 self.pg2.config_ip4()
1935 self.pg2.resolve_arp()
1937 self.pg0.add_stream(pkts)
1938 self.pg_enable_capture(self.pg_interfaces)
1941 rx0 = self.pg2._get_capture(NUM_PKTS)
1942 rx1 = self.pg3._get_capture(NUM_PKTS)
1943 self.assertNotEqual(0, len(rx0))
1944 self.assertNotEqual(0, len(rx1))
1945 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1946 "Expected all (%s) packets across both ECMP paths. "
1947 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1949 def test_mpls_v6_ebgp_pic(self):
1950 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1952 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1953 2) Check EMCP forwarding to these peers
1954 3) withdraw one eBGP path - expect LB across remaining eBGP
1958 # Lot's of VPN routes. We need more the 64 so VPP will build
1959 # the fast convergence indirection
1964 for ii in range(NUM_PKTS):
1965 dst = "3000::%d" % ii
1966 local_label = 1600 + ii
1967 vpn_routes.append(VppIpRoute(
1970 self.pg2.remote_ip6,
1973 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1975 self.pg3.remote_ip6,
1978 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1980 vpn_routes[ii].add_vpp_config()
1982 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1984 vpn_bindings[ii].add_vpp_config()
1986 pkts.append(Ether(dst=self.pg0.local_mac,
1987 src=self.pg0.remote_mac) /
1988 MPLS(label=local_label, ttl=64) /
1989 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1990 UDP(sport=1234, dport=1234) /
1992 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
1994 self.pg0.add_stream(pkts)
1995 self.pg_enable_capture(self.pg_interfaces)
1998 rx0 = self.pg2._get_capture(NUM_PKTS)
1999 rx1 = self.pg3._get_capture(NUM_PKTS)
2000 self.assertNotEqual(0, len(rx0))
2001 self.assertNotEqual(0, len(rx1))
2002 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2003 "Expected all (%s) packets across both ECMP paths. "
2004 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2007 # use a test CLI command to stop the FIB walk process, this
2008 # will prevent the FIB converging the VPN routes and thus allow
2009 # us to probe the interim (post-fail, pre-converge) state
2011 self.vapi.ppcli("test fib-walk-process disable")
2014 # withdraw the connected prefix on the interface.
2015 # and shutdown the interface so the ND cache is flushed.
2017 self.pg2.unconfig_ip6()
2018 self.pg2.admin_down()
2021 # now all packets should be forwarded through the remaining peer
2023 self.pg0.add_stream(pkts)
2024 self.pg_enable_capture(self.pg_interfaces)
2027 rx0 = self.pg3.get_capture(NUM_PKTS)
2028 self.assertEqual(len(pkts), len(rx0),
2029 "Expected all (%s) packets across single path. "
2030 "rx0: %s." % (len(pkts), len(rx0)))
2033 # enable the FIB walk process to converge the FIB
2035 self.vapi.ppcli("test fib-walk-process enable")
2036 self.pg0.add_stream(pkts)
2037 self.pg_enable_capture(self.pg_interfaces)
2040 rx0 = self.pg3.get_capture(NUM_PKTS)
2041 self.assertEqual(len(pkts), len(rx0),
2042 "Expected all (%s) packets across single path. "
2043 "rx0: %s." % (len(pkts), len(rx0)))
2046 # put the connected routes back
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)