6 from framework import tag_fixme_vpp_workers
7 from framework import VppTestCase, VppTestRunner
8 from vpp_ip import DpoProto, INVALID_INDEX
9 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
10 VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
11 VppIpTable, VppMplsTable, \
12 VppMplsLabel, MplsLspMode, find_mpls_route, \
13 FibPathProto, FibPathType, FibPathFlags, VppMplsLabel, MplsLspMode
14 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
15 from vpp_papi import VppEnum
18 from scapy.packet import Raw
19 from scapy.layers.l2 import Ether, ARP
20 from scapy.layers.inet import IP, UDP, ICMP
21 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded, ICMPv6EchoRequest, \
23 from scapy.contrib.mpls import MPLS
27 # scapy removed these attributes.
28 # we asked that they be restored: https://github.com/secdev/scapy/pull/1878
29 # semantic names have more meaning than numbers. so here they are.
34 def verify_filter(capture, sent):
35 if not len(capture) == len(sent):
36 # filter out any IPv6 RAs from the capture
43 def verify_mpls_stack(tst, rx, mpls_labels):
44 # the rx'd packet has the MPLS label popped
46 tst.assertEqual(eth.type, 0x8847)
50 for ii in range(len(mpls_labels)):
51 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
52 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
53 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
55 if ii == len(mpls_labels) - 1:
56 tst.assertEqual(rx_mpls.s, 1)
59 tst.assertEqual(rx_mpls.s, 0)
60 # pop the label to expose the next
61 rx_mpls = rx_mpls[MPLS].payload
64 @tag_fixme_vpp_workers
65 class TestMPLS(VppTestCase):
66 """ MPLS Test Case """
70 super(TestMPLS, cls).setUpClass()
73 def tearDownClass(cls):
74 super(TestMPLS, cls).tearDownClass()
77 super(TestMPLS, self).setUp()
79 # create 2 pg interfaces
80 self.create_pg_interfaces(range(4))
82 # setup both interfaces
83 # assign them different tables.
87 tbl = VppMplsTable(self, 0)
89 self.tables.append(tbl)
91 for i in self.pg_interfaces:
95 tbl = VppIpTable(self, table_id)
97 self.tables.append(tbl)
98 tbl = VppIpTable(self, table_id, is_ip6=1)
100 self.tables.append(tbl)
102 i.set_table_ip4(table_id)
103 i.set_table_ip6(table_id)
112 for i in self.pg_interfaces:
119 super(TestMPLS, self).tearDown()
121 # the default of 64 matches the IP packet TTL default
122 def create_stream_labelled_ip4(
132 self.reset_packet_infos()
134 for i in range(0, n):
135 info = self.create_packet_info(src_if, src_if)
136 payload = self.info_to_payload(info)
137 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
139 for ii in range(len(mpls_labels)):
140 p = p / MPLS(label=mpls_labels[ii].value,
141 ttl=mpls_labels[ii].ttl,
142 cos=mpls_labels[ii].exp)
145 p = (p / IP(src=src_if.local_ip4,
146 dst=src_if.remote_ip4,
148 UDP(sport=1234, dport=1234) /
151 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
152 UDP(sport=1234, dport=1234) /
155 p = (p / IP(src=ip_itf.remote_ip4,
156 dst=ip_itf.local_ip4,
161 p[IP].chksum = chksum
166 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64,
167 ip_dscp=0, payload_size=None):
168 self.reset_packet_infos()
170 for i in range(0, 257):
171 info = self.create_packet_info(src_if, src_if)
172 payload = self.info_to_payload(info)
173 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
174 IP(src=src_if.remote_ip4, dst=dst_ip,
175 ttl=ip_ttl, tos=ip_dscp) /
176 UDP(sport=1234, dport=1234) /
180 self.extend_packet(p, payload_size)
184 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
185 self.reset_packet_infos()
187 for i in range(0, 257):
188 info = self.create_packet_info(src_if, src_if)
189 payload = self.info_to_payload(info)
190 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
191 IPv6(src=src_if.remote_ip6, dst=dst_ip,
192 hlim=ip_ttl, tc=ip_dscp) /
193 UDP(sport=1234, dport=1234) /
199 def create_stream_labelled_ip6(self, src_if, mpls_labels,
200 hlim=64, dst_ip=None,
201 ping=0, ip_itf=None):
203 dst_ip = src_if.remote_ip6
204 self.reset_packet_infos()
206 for i in range(0, 257):
207 info = self.create_packet_info(src_if, src_if)
208 payload = self.info_to_payload(info)
209 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
210 for l in mpls_labels:
211 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
214 p = p / (IPv6(src=ip_itf.remote_ip6,
215 dst=ip_itf.local_ip6) /
218 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
219 UDP(sport=1234, dport=1234) /
225 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
226 ip_ttl=None, ip_dscp=0):
228 capture = verify_filter(capture, sent)
230 self.assertEqual(len(capture), len(sent))
232 for i in range(len(capture)):
236 # the rx'd packet has the MPLS label popped
238 self.assertEqual(eth.type, 0x800)
244 self.assertEqual(rx_ip.src, tx_ip.src)
245 self.assertEqual(rx_ip.dst, tx_ip.dst)
246 self.assertEqual(rx_ip.tos, ip_dscp)
248 # IP processing post pop has decremented the TTL
249 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
251 self.assertEqual(rx_ip.ttl, ip_ttl)
253 self.assertEqual(rx_ip.src, tx_ip.dst)
254 self.assertEqual(rx_ip.dst, tx_ip.src)
259 def verify_capture_labelled_ip4(self, src_if, capture, sent,
260 mpls_labels, ip_ttl=None):
262 capture = verify_filter(capture, sent)
264 self.assertEqual(len(capture), len(sent))
266 for i in range(len(capture)):
272 verify_mpls_stack(self, rx, mpls_labels)
274 self.assertEqual(rx_ip.src, tx_ip.src)
275 self.assertEqual(rx_ip.dst, tx_ip.dst)
277 # IP processing post pop has decremented the TTL
278 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
280 self.assertEqual(rx_ip.ttl, ip_ttl)
285 def verify_capture_labelled_ip6(self, src_if, capture, sent,
286 mpls_labels, ip_ttl=None):
288 capture = verify_filter(capture, sent)
290 self.assertEqual(len(capture), len(sent))
292 for i in range(len(capture)):
298 verify_mpls_stack(self, rx, mpls_labels)
300 self.assertEqual(rx_ip.src, tx_ip.src)
301 self.assertEqual(rx_ip.dst, tx_ip.dst)
303 # IP processing post pop has decremented the TTL
304 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
306 self.assertEqual(rx_ip.hlim, ip_ttl)
311 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
313 capture = verify_filter(capture, sent)
315 self.assertEqual(len(capture), len(sent))
317 for i in range(len(capture)):
323 verify_mpls_stack(self, rx, mpls_labels)
325 self.assertEqual(rx_ip.src, tx_ip.src)
326 self.assertEqual(rx_ip.dst, tx_ip.dst)
327 # IP processing post pop has decremented the TTL
328 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
333 def verify_capture_labelled(self, src_if, capture, sent,
336 capture = verify_filter(capture, sent)
338 self.assertEqual(len(capture), len(sent))
340 for i in range(len(capture)):
342 verify_mpls_stack(self, rx, mpls_labels)
346 def verify_capture_ip6(self, src_if, capture, sent,
347 ip_hlim=None, ip_dscp=0,
350 self.assertEqual(len(capture), len(sent))
352 for i in range(len(capture)):
356 # the rx'd packet has the MPLS label popped
358 self.assertEqual(eth.type, 0x86DD)
364 self.assertEqual(rx_ip.src, tx_ip.src)
365 self.assertEqual(rx_ip.dst, tx_ip.dst)
366 self.assertEqual(rx_ip.tc, ip_dscp)
367 # IP processing post pop has decremented the TTL
369 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
371 self.assertEqual(rx_ip.hlim, ip_hlim)
373 self.assertEqual(rx_ip.src, tx_ip.dst)
374 self.assertEqual(rx_ip.dst, tx_ip.src)
378 def verify_capture_ip6_icmp(self, src_if, capture, sent):
381 self.assertTrue(len(capture) <= len(sent))
383 for i in range(len(capture)):
387 # the rx'd packet has the MPLS label popped
389 self.assertEqual(eth.type, 0x86DD)
394 self.assertEqual(rx_ip.dst, tx_ip.src)
395 # ICMP sourced from the interface's address
396 self.assertEqual(rx_ip.src, src_if.local_ip6)
397 # hop-limit reset to 255 for IMCP packet
398 self.assertEqual(rx_ip.hlim, 255)
400 icmp = rx[ICMPv6TimeExceeded]
405 def verify_capture_fragmented_labelled_ip4(self, src_if, capture, sent,
406 mpls_labels, ip_ttl=None):
408 capture = verify_filter(capture, sent)
410 for i in range(len(capture)):
416 verify_mpls_stack(self, rx, mpls_labels)
418 self.assertEqual(rx_ip.src, tx_ip.src)
419 self.assertEqual(rx_ip.dst, tx_ip.dst)
421 # IP processing post pop has decremented the TTL
422 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
424 self.assertEqual(rx_ip.ttl, ip_ttl)
429 def verify_capture_fragmented_labelled_ip6(self, src_if, capture, sent,
430 mpls_labels, ip_ttl=None):
432 capture = verify_filter(capture, sent)
434 for i in range(len(capture)):
439 rx_ip = IPv6(rx[MPLS].payload)
442 verify_mpls_stack(self, rx, mpls_labels)
444 self.assertEqual(rx_ip.src, tx_ip.src)
445 self.assertEqual(rx_ip.dst, tx_ip.dst)
447 # IP processing post pop has decremented the hop-limit
448 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
450 self.assertEqual(rx_ip.hlim, ip_ttl)
455 """ MPLS label swap tests """
458 # A simple MPLS xconnect - eos label in label out
460 route_32_eos = VppMplsRoute(self, 32, 1,
461 [VppRoutePath(self.pg0.remote_ip4,
462 self.pg0.sw_if_index,
463 labels=[VppMplsLabel(33)])])
464 route_32_eos.add_vpp_config()
467 find_mpls_route(self, 0, 32, 1,
468 [VppRoutePath(self.pg0.remote_ip4,
469 self.pg0.sw_if_index,
470 labels=[VppMplsLabel(33)])]))
473 # a stream that matches the route for 10.0.0.1
474 # PG0 is in the default table
476 tx = self.create_stream_labelled_ip4(self.pg0,
477 [VppMplsLabel(32, ttl=32, exp=1)])
478 rx = self.send_and_expect(self.pg0, tx, self.pg0)
479 self.verify_capture_labelled(self.pg0, rx, tx,
480 [VppMplsLabel(33, ttl=31, exp=1)])
482 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
485 # A simple MPLS xconnect - non-eos label in label out
487 route_32_neos = VppMplsRoute(self, 32, 0,
488 [VppRoutePath(self.pg0.remote_ip4,
489 self.pg0.sw_if_index,
490 labels=[VppMplsLabel(33)])])
491 route_32_neos.add_vpp_config()
494 # a stream that matches the route for 10.0.0.1
495 # PG0 is in the default table
497 tx = self.create_stream_labelled_ip4(self.pg0,
498 [VppMplsLabel(32, ttl=21, exp=7),
500 rx = self.send_and_expect(self.pg0, tx, self.pg0)
501 self.verify_capture_labelled(self.pg0, rx, tx,
502 [VppMplsLabel(33, ttl=20, exp=7),
504 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
507 # A simple MPLS xconnect - non-eos label in label out, uniform mode
509 route_42_neos = VppMplsRoute(
511 [VppRoutePath(self.pg0.remote_ip4,
512 self.pg0.sw_if_index,
513 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
514 route_42_neos.add_vpp_config()
516 tx = self.create_stream_labelled_ip4(self.pg0,
517 [VppMplsLabel(42, ttl=21, exp=7),
519 rx = self.send_and_expect(self.pg0, tx, self.pg0)
520 self.verify_capture_labelled(self.pg0, rx, tx,
521 [VppMplsLabel(43, ttl=20, exp=7),
525 # An MPLS xconnect - EOS label in IP out
527 route_33_eos = VppMplsRoute(self, 33, 1,
528 [VppRoutePath(self.pg0.remote_ip4,
529 self.pg0.sw_if_index,
531 route_33_eos.add_vpp_config()
533 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
534 rx = self.send_and_expect(self.pg0, tx, self.pg0)
535 self.verify_capture_ip4(self.pg0, rx, tx)
538 # disposed packets have an invalid IPv4 checksum
540 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
541 dst_ip=self.pg0.remote_ip4,
544 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
547 # An MPLS xconnect - EOS label in IP out, uniform mode
549 route_3333_eos = VppMplsRoute(
551 [VppRoutePath(self.pg0.remote_ip4,
552 self.pg0.sw_if_index,
553 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
554 route_3333_eos.add_vpp_config()
556 tx = self.create_stream_labelled_ip4(
558 [VppMplsLabel(3333, ttl=55, exp=3)])
559 rx = self.send_and_expect(self.pg0, tx, self.pg0)
560 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
561 tx = self.create_stream_labelled_ip4(
563 [VppMplsLabel(3333, ttl=66, exp=4)])
564 rx = self.send_and_expect(self.pg0, tx, self.pg0)
565 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
568 # An MPLS xconnect - EOS label in IPv6 out
570 route_333_eos = VppMplsRoute(
572 [VppRoutePath(self.pg0.remote_ip6,
573 self.pg0.sw_if_index,
575 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
576 route_333_eos.add_vpp_config()
578 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
579 rx = self.send_and_expect(self.pg0, tx, self.pg0)
580 self.verify_capture_ip6(self.pg0, rx, tx)
583 # disposed packets have an TTL expired
585 tx = self.create_stream_labelled_ip6(self.pg0,
586 [VppMplsLabel(333, ttl=64)],
587 dst_ip=self.pg1.remote_ip6,
589 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
590 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
593 # An MPLS xconnect - EOS label in IPv6 out w imp-null
595 route_334_eos = VppMplsRoute(
597 [VppRoutePath(self.pg0.remote_ip6,
598 self.pg0.sw_if_index,
599 labels=[VppMplsLabel(3)])],
600 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
601 route_334_eos.add_vpp_config()
603 tx = self.create_stream_labelled_ip6(self.pg0,
604 [VppMplsLabel(334, ttl=64)])
605 rx = self.send_and_expect(self.pg0, tx, self.pg0)
606 self.verify_capture_ip6(self.pg0, rx, tx)
609 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
611 route_335_eos = VppMplsRoute(
613 [VppRoutePath(self.pg0.remote_ip6,
614 self.pg0.sw_if_index,
615 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
616 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
617 route_335_eos.add_vpp_config()
619 tx = self.create_stream_labelled_ip6(
621 [VppMplsLabel(335, ttl=27, exp=4)])
622 rx = self.send_and_expect(self.pg0, tx, self.pg0)
623 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
626 # disposed packets have an TTL expired
628 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
629 dst_ip=self.pg1.remote_ip6,
631 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
632 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
635 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
636 # so this traffic should be dropped.
638 route_33_neos = VppMplsRoute(self, 33, 0,
639 [VppRoutePath(self.pg0.remote_ip4,
640 self.pg0.sw_if_index,
642 route_33_neos.add_vpp_config()
644 tx = self.create_stream_labelled_ip4(self.pg0,
647 self.send_and_assert_no_replies(
649 "MPLS non-EOS packets popped and forwarded")
652 # A recursive EOS x-connect, which resolves through another x-connect
655 route_34_eos = VppMplsRoute(self, 34, 1,
656 [VppRoutePath("0.0.0.0",
659 labels=[VppMplsLabel(44),
661 route_34_eos.add_vpp_config()
662 self.logger.info(self.vapi.cli("sh mpls fib 34"))
664 tx = self.create_stream_labelled_ip4(self.pg0,
665 [VppMplsLabel(34, ttl=3)])
666 rx = self.send_and_expect(self.pg0, tx, self.pg0)
667 self.verify_capture_labelled(self.pg0, rx, tx,
670 VppMplsLabel(45, ttl=2)])
672 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
673 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
676 # A recursive EOS x-connect, which resolves through another x-connect
679 route_35_eos = VppMplsRoute(
681 [VppRoutePath("0.0.0.0",
684 labels=[VppMplsLabel(44)])])
685 route_35_eos.add_vpp_config()
687 tx = self.create_stream_labelled_ip4(self.pg0,
688 [VppMplsLabel(35, ttl=3)])
689 rx = self.send_and_expect(self.pg0, tx, self.pg0)
690 self.verify_capture_labelled(self.pg0, rx, tx,
691 [VppMplsLabel(43, ttl=2),
692 VppMplsLabel(44, ttl=2)])
695 # A recursive non-EOS x-connect, which resolves through another
698 route_34_neos = VppMplsRoute(self, 34, 0,
699 [VppRoutePath("0.0.0.0",
702 labels=[VppMplsLabel(44),
704 route_34_neos.add_vpp_config()
706 tx = self.create_stream_labelled_ip4(self.pg0,
707 [VppMplsLabel(34, ttl=45),
709 rx = self.send_and_expect(self.pg0, tx, self.pg0)
710 # it's the 2nd (counting from 0) label in the stack that is swapped
711 self.verify_capture_labelled(self.pg0, rx, tx,
714 VppMplsLabel(46, ttl=44),
718 # an recursive IP route that resolves through the recursive non-eos
721 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
722 [VppRoutePath("0.0.0.0",
725 labels=[VppMplsLabel(55)])])
726 ip_10_0_0_1.add_vpp_config()
728 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
729 rx = self.send_and_expect(self.pg0, tx, self.pg0)
730 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
735 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
737 ip_10_0_0_1.remove_vpp_config()
738 route_34_neos.remove_vpp_config()
739 route_34_eos.remove_vpp_config()
740 route_33_neos.remove_vpp_config()
741 route_33_eos.remove_vpp_config()
742 route_32_neos.remove_vpp_config()
743 route_32_eos.remove_vpp_config()
746 """ MPLS Local Label Binding test """
749 # Add a non-recursive route with a single out label
751 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
752 [VppRoutePath(self.pg0.remote_ip4,
753 self.pg0.sw_if_index,
754 labels=[VppMplsLabel(45)])])
755 route_10_0_0_1.add_vpp_config()
757 # bind a local label to the route
758 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
759 binding.add_vpp_config()
762 tx = self.create_stream_labelled_ip4(self.pg0,
765 rx = self.send_and_expect(self.pg0, tx, self.pg0)
766 self.verify_capture_labelled(self.pg0, rx, tx,
767 [VppMplsLabel(45, ttl=63),
771 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
772 rx = self.send_and_expect(self.pg0, tx, self.pg0)
773 self.verify_capture_labelled(self.pg0, rx, tx,
774 [VppMplsLabel(45, ttl=63)])
777 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
778 rx = self.send_and_expect(self.pg0, tx, self.pg0)
779 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
784 binding.remove_vpp_config()
785 route_10_0_0_1.remove_vpp_config()
787 def test_imposition(self):
788 """ MPLS label imposition test """
791 # Add a non-recursive route with a single out label
793 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
794 [VppRoutePath(self.pg0.remote_ip4,
795 self.pg0.sw_if_index,
796 labels=[VppMplsLabel(32)])])
797 route_10_0_0_1.add_vpp_config()
800 # a stream that matches the route for 10.0.0.1
801 # PG0 is in the default table
803 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
804 rx = self.send_and_expect(self.pg0, tx, self.pg0)
805 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
808 # Add a non-recursive route with a 3 out labels
810 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
811 [VppRoutePath(self.pg0.remote_ip4,
812 self.pg0.sw_if_index,
813 labels=[VppMplsLabel(32),
816 route_10_0_0_2.add_vpp_config()
818 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
819 ip_ttl=44, ip_dscp=0xff)
820 rx = self.send_and_expect(self.pg0, tx, self.pg0)
821 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
828 # Add a non-recursive route with a single out label in uniform mode
830 route_10_0_0_3 = VppIpRoute(
831 self, "10.0.0.3", 32,
832 [VppRoutePath(self.pg0.remote_ip4,
833 self.pg0.sw_if_index,
834 labels=[VppMplsLabel(32,
835 mode=MplsLspMode.UNIFORM)])])
836 route_10_0_0_3.add_vpp_config()
838 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
839 ip_ttl=54, ip_dscp=0xbe)
840 rx = self.send_and_expect(self.pg0, tx, self.pg0)
841 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
842 [VppMplsLabel(32, ttl=53, exp=5)])
845 # Add a IPv6 non-recursive route with a single out label in
848 route_2001_3 = VppIpRoute(
849 self, "2001::3", 128,
850 [VppRoutePath(self.pg0.remote_ip6,
851 self.pg0.sw_if_index,
852 labels=[VppMplsLabel(32,
853 mode=MplsLspMode.UNIFORM)])])
854 route_2001_3.add_vpp_config()
856 tx = self.create_stream_ip6(self.pg0, "2001::3",
857 ip_ttl=54, ip_dscp=0xbe)
858 rx = self.send_and_expect(self.pg0, tx, self.pg0)
859 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
860 [VppMplsLabel(32, ttl=53, exp=5)])
863 # add a recursive path, with output label, via the 1 label route
865 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
866 [VppRoutePath("10.0.0.1",
868 labels=[VppMplsLabel(44)])])
869 route_11_0_0_1.add_vpp_config()
872 # a stream that matches the route for 11.0.0.1, should pick up
873 # the label stack for 11.0.0.1 and 10.0.0.1
875 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
876 rx = self.send_and_expect(self.pg0, tx, self.pg0)
877 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
881 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
884 # add a recursive path, with 2 labels, via the 3 label route
886 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
887 [VppRoutePath("10.0.0.2",
889 labels=[VppMplsLabel(44),
891 route_11_0_0_2.add_vpp_config()
894 # a stream that matches the route for 11.0.0.1, should pick up
895 # the label stack for 11.0.0.1 and 10.0.0.1
897 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
898 rx = self.send_and_expect(self.pg0, tx, self.pg0)
899 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
906 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
908 rx = self.send_and_expect(self.pg0, tx, self.pg0)
909 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
916 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
921 route_11_0_0_2.remove_vpp_config()
922 route_11_0_0_1.remove_vpp_config()
923 route_10_0_0_2.remove_vpp_config()
924 route_10_0_0_1.remove_vpp_config()
926 def test_imposition_fragmentation(self):
927 """ MPLS label imposition fragmentation test """
930 # Add a ipv4 non-recursive route with a single out label
932 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
933 [VppRoutePath(self.pg0.remote_ip4,
934 self.pg0.sw_if_index,
935 labels=[VppMplsLabel(32)])])
936 route_10_0_0_1.add_vpp_config()
937 route_1000_1 = VppIpRoute(self, "1000::1", 128,
938 [VppRoutePath(self.pg0.remote_ip6,
939 self.pg0.sw_if_index,
940 labels=[VppMplsLabel(32)])])
941 route_1000_1.add_vpp_config()
944 # a stream that matches the route for 10.0.0.1
945 # PG0 is in the default table
947 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
948 for i in range(0, 257):
949 self.extend_packet(tx[i], 10000)
952 # 5 fragments per packet (257*5=1285)
954 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
955 self.verify_capture_fragmented_labelled_ip4(self.pg0, rx, tx,
958 # packets with DF bit set generate ICMP
961 rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
964 rx[ICMP].code = "fragmentation-needed"
966 self.assertEqual(self.statistics.get_err_counter(
967 "/err/mpls-frag/can't fragment this packet"),
970 # a stream that matches the route for 1000::1/128
971 # PG0 is in the default table
973 tx = self.create_stream_ip6(self.pg0, "1000::1")
974 for i in range(0, 257):
975 self.extend_packet(tx[i], 10000)
977 rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
979 rx[ICMPv6PacketTooBig].mtu = 9000
984 route_10_0_0_1.remove_vpp_config()
986 def test_tunnel_pipe(self):
987 """ MPLS Tunnel Tests - Pipe """
990 # Create a tunnel with two out labels
992 mpls_tun = VppMPLSTunnelInterface(
994 [VppRoutePath(self.pg0.remote_ip4,
995 self.pg0.sw_if_index,
996 labels=[VppMplsLabel(44),
998 mpls_tun.add_vpp_config()
1002 # add an unlabelled route through the new tunnel
1004 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1005 [VppRoutePath("0.0.0.0",
1006 mpls_tun._sw_if_index)])
1007 route_10_0_0_3.add_vpp_config()
1009 self.vapi.cli("clear trace")
1010 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1011 self.pg0.add_stream(tx)
1013 self.pg_enable_capture(self.pg_interfaces)
1016 rx = self.pg0.get_capture()
1017 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1022 # add a labelled route through the new tunnel
1024 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
1025 [VppRoutePath("0.0.0.0",
1026 mpls_tun._sw_if_index,
1028 route_10_0_0_4.add_vpp_config()
1030 self.vapi.cli("clear trace")
1031 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1032 self.pg0.add_stream(tx)
1034 self.pg_enable_capture(self.pg_interfaces)
1037 rx = self.pg0.get_capture()
1038 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1041 VppMplsLabel(33, ttl=255)])
1044 # change tunnel's MTU to a low value
1046 mpls_tun.set_l3_mtu(1200)
1048 # send IP into the tunnel to be fragmented
1049 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
1051 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1057 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1061 # send MPLS into the tunnel to be fragmented
1062 tx = self.create_stream_ip4(self.pg0, "10.0.0.4",
1064 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1070 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1073 VppMplsLabel(33, ttl=255)])
1075 def test_tunnel_uniform(self):
1076 """ MPLS Tunnel Tests - Uniform """
1079 # Create a tunnel with a single out label
1080 # The label stack is specified here from outer to inner
1082 mpls_tun = VppMPLSTunnelInterface(
1084 [VppRoutePath(self.pg0.remote_ip4,
1085 self.pg0.sw_if_index,
1086 labels=[VppMplsLabel(44, ttl=32),
1087 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1088 mpls_tun.add_vpp_config()
1092 # add an unlabelled route through the new tunnel
1094 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1095 [VppRoutePath("0.0.0.0",
1096 mpls_tun._sw_if_index)])
1097 route_10_0_0_3.add_vpp_config()
1099 self.vapi.cli("clear trace")
1100 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1101 self.pg0.add_stream(tx)
1103 self.pg_enable_capture(self.pg_interfaces)
1106 rx = self.pg0.get_capture()
1107 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1108 [VppMplsLabel(44, ttl=32),
1109 VppMplsLabel(46, ttl=23)])
1112 # add a labelled route through the new tunnel
1114 route_10_0_0_4 = VppIpRoute(
1115 self, "10.0.0.4", 32,
1116 [VppRoutePath("0.0.0.0",
1117 mpls_tun._sw_if_index,
1118 labels=[VppMplsLabel(33, ttl=47)])])
1119 route_10_0_0_4.add_vpp_config()
1121 self.vapi.cli("clear trace")
1122 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1123 self.pg0.add_stream(tx)
1125 self.pg_enable_capture(self.pg_interfaces)
1128 rx = self.pg0.get_capture()
1129 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1130 [VppMplsLabel(44, ttl=32),
1131 VppMplsLabel(46, ttl=47),
1132 VppMplsLabel(33, ttl=47)])
1134 def test_mpls_tunnel_many(self):
1135 """ MPLS Multiple Tunnels """
1137 for ii in range(100):
1138 mpls_tun = VppMPLSTunnelInterface(
1140 [VppRoutePath(self.pg0.remote_ip4,
1141 self.pg0.sw_if_index,
1142 labels=[VppMplsLabel(44, ttl=32),
1143 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1144 mpls_tun.add_vpp_config()
1146 for ii in range(100):
1147 mpls_tun = VppMPLSTunnelInterface(
1149 [VppRoutePath(self.pg0.remote_ip4,
1150 self.pg0.sw_if_index,
1151 labels=[VppMplsLabel(44, ttl=32),
1152 VppMplsLabel(46, MplsLspMode.UNIFORM)])],
1154 mpls_tun.add_vpp_config()
1157 def test_v4_exp_null(self):
1158 """ MPLS V4 Explicit NULL test """
1161 # The first test case has an MPLS TTL of 0
1162 # all packet should be dropped
1164 tx = self.create_stream_labelled_ip4(self.pg0,
1165 [VppMplsLabel(0, ttl=0)])
1166 self.send_and_assert_no_replies(self.pg0, tx,
1167 "MPLS TTL=0 packets forwarded")
1170 # a stream with a non-zero MPLS TTL
1171 # PG0 is in the default table
1173 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1174 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1175 self.verify_capture_ip4(self.pg0, rx, tx)
1178 # a stream with a non-zero MPLS TTL
1180 # we are ensuring the post-pop lookup occurs in the VRF table
1182 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1183 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1184 self.verify_capture_ip4(self.pg1, rx, tx)
1186 def test_v6_exp_null(self):
1187 """ MPLS V6 Explicit NULL test """
1190 # a stream with a non-zero MPLS TTL
1191 # PG0 is in the default table
1193 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1194 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1195 self.verify_capture_ip6(self.pg0, rx, tx)
1198 # a stream with a non-zero MPLS TTL
1200 # we are ensuring the post-pop lookup occurs in the VRF table
1202 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1203 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1204 self.verify_capture_ip6(self.pg0, rx, tx)
1206 def test_deag(self):
1210 # A de-agg route - next-hop lookup in default table
1212 route_34_eos = VppMplsRoute(self, 34, 1,
1213 [VppRoutePath("0.0.0.0",
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,
1226 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1227 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1230 # A de-agg route - next-hop lookup in non-default table
1232 route_35_eos = VppMplsRoute(self, 35, 1,
1233 [VppRoutePath("0.0.0.0",
1236 route_35_eos.add_vpp_config()
1237 route_356_eos = VppMplsRoute(
1239 [VppRoutePath("0::0",
1242 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1243 route_356_eos.add_vpp_config()
1246 # ping an interface in the non-default table
1247 # PG0 is in the default table. packet arrive labelled in the
1248 # default table and egress unlabelled in the non-default
1250 tx = self.create_stream_labelled_ip4(
1251 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1252 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1253 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1254 tx = self.create_stream_labelled_ip6(
1255 self.pg0, [VppMplsLabel(356)], ping=1, ip_itf=self.pg1)
1256 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1257 self.verify_capture_ip6(self.pg1, rx, tx, ping_resp=1)
1262 route_36_neos = VppMplsRoute(self, 36, 0,
1263 [VppRoutePath("0.0.0.0",
1265 route_36_neos.add_vpp_config()
1267 tx = self.create_stream_labelled_ip4(self.pg0,
1270 ping=1, ip_itf=self.pg1)
1271 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1272 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1274 route_36_neos.remove_vpp_config()
1275 route_35_eos.remove_vpp_config()
1276 route_34_eos.remove_vpp_config()
1278 def test_interface_rx(self):
1279 """ MPLS Interface Receive """
1282 # Add a non-recursive route that will forward the traffic
1285 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1287 paths=[VppRoutePath(self.pg1.remote_ip4,
1288 self.pg1.sw_if_index)])
1289 route_10_0_0_1.add_vpp_config()
1292 # An interface receive label that maps traffic to RX on interface
1294 # by injecting the packet in on pg0, which is in table 0
1295 # doing an interface-rx on pg1 and matching a route in table 1
1296 # if the packet egresses, then we must have swapped to pg1
1297 # so as to have matched the route in table 1
1299 route_34_eos = VppMplsRoute(
1301 [VppRoutePath("0.0.0.0",
1302 self.pg1.sw_if_index,
1303 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1304 route_34_eos.add_vpp_config()
1307 # ping an interface in the default table
1308 # PG0 is in the default table
1310 tx = self.create_stream_labelled_ip4(self.pg0,
1313 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1314 self.verify_capture_ip4(self.pg1, rx, tx)
1316 def test_mcast_mid_point(self):
1317 """ MPLS Multicast Mid Point """
1320 # Add a non-recursive route that will forward the traffic
1323 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1325 paths=[VppRoutePath(self.pg1.remote_ip4,
1326 self.pg1.sw_if_index)])
1327 route_10_0_0_1.add_vpp_config()
1330 # Add a mcast entry that replicate to pg2 and pg3
1331 # and replicate to a interface-rx (like a bud node would)
1333 route_3400_eos = VppMplsRoute(
1335 [VppRoutePath(self.pg2.remote_ip4,
1336 self.pg2.sw_if_index,
1337 labels=[VppMplsLabel(3401)]),
1338 VppRoutePath(self.pg3.remote_ip4,
1339 self.pg3.sw_if_index,
1340 labels=[VppMplsLabel(3402)]),
1341 VppRoutePath("0.0.0.0",
1342 self.pg1.sw_if_index,
1343 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1345 route_3400_eos.add_vpp_config()
1348 # ping an interface in the default table
1349 # PG0 is in the default table
1351 self.vapi.cli("clear trace")
1352 tx = self.create_stream_labelled_ip4(self.pg0,
1353 [VppMplsLabel(3400, ttl=64)],
1356 self.pg0.add_stream(tx)
1358 self.pg_enable_capture(self.pg_interfaces)
1361 rx = self.pg1.get_capture(257)
1362 self.verify_capture_ip4(self.pg1, rx, tx)
1364 rx = self.pg2.get_capture(257)
1365 self.verify_capture_labelled(self.pg2, rx, tx,
1366 [VppMplsLabel(3401, ttl=63)])
1367 rx = self.pg3.get_capture(257)
1368 self.verify_capture_labelled(self.pg3, rx, tx,
1369 [VppMplsLabel(3402, ttl=63)])
1371 def test_mcast_head(self):
1372 """ MPLS Multicast Head-end """
1374 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1375 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1378 # Create a multicast tunnel with two replications
1380 mpls_tun = VppMPLSTunnelInterface(
1382 [VppRoutePath(self.pg2.remote_ip4,
1383 self.pg2.sw_if_index,
1384 labels=[VppMplsLabel(42)]),
1385 VppRoutePath(self.pg3.remote_ip4,
1386 self.pg3.sw_if_index,
1387 labels=[VppMplsLabel(43)])],
1389 mpls_tun.add_vpp_config()
1393 # add an unlabelled route through the new tunnel
1395 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1396 [VppRoutePath("0.0.0.0",
1397 mpls_tun._sw_if_index)])
1398 route_10_0_0_3.add_vpp_config()
1400 self.vapi.cli("clear trace")
1401 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1402 self.pg0.add_stream(tx)
1404 self.pg_enable_capture(self.pg_interfaces)
1407 rx = self.pg2.get_capture(257)
1408 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1409 rx = self.pg3.get_capture(257)
1410 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1413 # An an IP multicast route via the tunnel
1415 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1417 route_232_1_1_1 = VppIpMRoute(
1421 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1422 [VppMRoutePath(self.pg0.sw_if_index,
1423 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT),
1424 VppMRoutePath(mpls_tun._sw_if_index,
1425 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1426 route_232_1_1_1.add_vpp_config()
1427 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1429 self.vapi.cli("clear trace")
1430 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1431 self.pg0.add_stream(tx)
1433 self.pg_enable_capture(self.pg_interfaces)
1436 rx = self.pg2.get_capture(257)
1437 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1438 rx = self.pg3.get_capture(257)
1439 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1441 def test_mcast_ip4_tail(self):
1442 """ MPLS IPv4 Multicast Tail """
1444 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1445 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1448 # Add a multicast route that will forward the traffic
1451 route_232_1_1_1 = VppIpMRoute(
1455 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1457 paths=[VppMRoutePath(self.pg1.sw_if_index,
1458 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1459 route_232_1_1_1.add_vpp_config()
1462 # An interface receive label that maps traffic to RX on interface
1464 # by injecting the packet in on pg0, which is in table 0
1465 # doing an rpf-id and matching a route in table 1
1466 # if the packet egresses, then we must have matched the route in
1469 route_34_eos = VppMplsRoute(
1471 [VppRoutePath("0.0.0.0",
1476 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1478 route_34_eos.add_vpp_config()
1481 # Drop due to interface lookup miss
1483 self.vapi.cli("clear trace")
1484 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1485 dst_ip="232.1.1.1", n=1)
1486 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1489 # set the RPF-ID of the entry to match the input packet's
1491 route_232_1_1_1.update_rpf_id(55)
1492 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1494 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1496 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1497 self.verify_capture_ip4(self.pg1, rx, tx)
1500 # disposed packets have an invalid IPv4 checksum
1502 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1503 dst_ip="232.1.1.1", n=65,
1505 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1508 # set the RPF-ID of the entry to not match the input packet's
1510 route_232_1_1_1.update_rpf_id(56)
1511 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1513 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1515 def test_mcast_ip6_tail(self):
1516 """ MPLS IPv6 Multicast Tail """
1518 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1519 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1522 # Add a multicast route that will forward the traffic
1525 route_ff = VppIpMRoute(
1529 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1531 paths=[VppMRoutePath(self.pg1.sw_if_index,
1532 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1533 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1534 route_ff.add_vpp_config()
1537 # An interface receive label that maps traffic to RX on interface
1539 # by injecting the packet in on pg0, which is in table 0
1540 # doing an rpf-id and matching a route in table 1
1541 # if the packet egresses, then we must have matched the route in
1544 route_34_eos = VppMplsRoute(
1551 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1553 route_34_eos.add_vpp_config()
1556 # Drop due to interface lookup miss
1558 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1560 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1563 # set the RPF-ID of the entry to match the input packet's
1565 route_ff.update_rpf_id(55)
1567 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1569 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1570 self.verify_capture_ip6(self.pg1, rx, tx)
1573 # disposed packets have hop-limit = 1
1575 tx = self.create_stream_labelled_ip6(self.pg0,
1579 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
1580 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1583 # set the RPF-ID of the entry to not match the input packet's
1585 route_ff.update_rpf_id(56)
1586 tx = self.create_stream_labelled_ip6(self.pg0,
1589 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1595 # Add a non-recursive route with a single out label
1597 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1598 [VppRoutePath(self.pg0.remote_ip4,
1599 self.pg0.sw_if_index,
1600 labels=[VppMplsLabel(45)])])
1601 route_10_0_0_1.add_vpp_config()
1603 # bind a local label to the route
1604 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1605 binding.add_vpp_config()
1608 # a labelled v6 route that resolves through the v4
1610 route_2001_3 = VppIpRoute(
1611 self, "2001::3", 128,
1612 [VppRoutePath("10.0.0.1",
1614 labels=[VppMplsLabel(32)])])
1615 route_2001_3.add_vpp_config()
1617 tx = self.create_stream_ip6(self.pg0, "2001::3")
1618 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1620 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1625 # and a v4 recursive via the v6
1627 route_20_3 = VppIpRoute(
1628 self, "20.0.0.3", 32,
1629 [VppRoutePath("2001::3",
1631 labels=[VppMplsLabel(99)])])
1632 route_20_3.add_vpp_config()
1634 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1635 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1637 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1642 def test_attached(self):
1643 """ Attach Routes with Local Label """
1646 # test that if a local label is associated with an attached/connected
1647 # prefix, that we can reach hosts in the prefix.
1649 binding = VppMplsIpBind(self, 44,
1650 self.pg0._local_ip4_subnet,
1651 self.pg0.local_ip4_prefix_len)
1652 binding.add_vpp_config()
1654 tx = (Ether(src=self.pg1.remote_mac,
1655 dst=self.pg1.local_mac) /
1656 MPLS(label=44, ttl=64) /
1657 IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) /
1658 UDP(sport=1234, dport=1234) /
1660 rxs = self.send_and_expect(self.pg0, [tx], self.pg0)
1662 # if there's an ARP then the label is linked to the glean
1664 self.assertFalse(rx.haslayer(ARP))
1665 # it should be unicasted to the host
1666 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1667 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1670 class TestMPLSDisabled(VppTestCase):
1671 """ MPLS disabled """
1674 def setUpClass(cls):
1675 super(TestMPLSDisabled, cls).setUpClass()
1678 def tearDownClass(cls):
1679 super(TestMPLSDisabled, cls).tearDownClass()
1682 super(TestMPLSDisabled, self).setUp()
1684 # create 2 pg interfaces
1685 self.create_pg_interfaces(range(2))
1687 self.tbl = VppMplsTable(self, 0)
1688 self.tbl.add_vpp_config()
1690 # PG0 is MPLS enabled
1692 self.pg0.config_ip4()
1693 self.pg0.resolve_arp()
1694 self.pg0.enable_mpls()
1696 # PG 1 is not MPLS enabled
1700 for i in self.pg_interfaces:
1704 self.pg0.disable_mpls()
1705 super(TestMPLSDisabled, self).tearDown()
1707 def test_mpls_disabled(self):
1708 """ MPLS Disabled """
1710 self.logger.info(self.vapi.cli("show mpls interface"))
1711 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1712 self.logger.info(self.vapi.cli("show mpls interface pg0"))
1714 tx = (Ether(src=self.pg1.remote_mac,
1715 dst=self.pg1.local_mac) /
1716 MPLS(label=32, ttl=64) /
1717 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1718 UDP(sport=1234, dport=1234) /
1722 # A simple MPLS xconnect - eos label in label out
1724 route_32_eos = VppMplsRoute(self, 32, 1,
1725 [VppRoutePath(self.pg0.remote_ip4,
1726 self.pg0.sw_if_index,
1728 route_32_eos.add_vpp_config()
1731 # PG1 does not forward IP traffic
1733 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1738 self.pg1.enable_mpls()
1740 self.logger.info(self.vapi.cli("show mpls interface"))
1741 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1744 # Now we get packets through
1746 self.pg1.add_stream(tx)
1747 self.pg_enable_capture(self.pg_interfaces)
1750 rx = self.pg0.get_capture(1)
1755 self.pg1.disable_mpls()
1758 # PG1 does not forward IP traffic
1760 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1761 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1764 class TestMPLSPIC(VppTestCase):
1765 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1768 def setUpClass(cls):
1769 super(TestMPLSPIC, cls).setUpClass()
1772 def tearDownClass(cls):
1773 super(TestMPLSPIC, cls).tearDownClass()
1776 super(TestMPLSPIC, self).setUp()
1778 # create 2 pg interfaces
1779 self.create_pg_interfaces(range(4))
1781 mpls_tbl = VppMplsTable(self, 0)
1782 mpls_tbl.add_vpp_config()
1783 tbl4 = VppIpTable(self, 1)
1784 tbl4.add_vpp_config()
1785 tbl6 = VppIpTable(self, 1, is_ip6=1)
1786 tbl6.add_vpp_config()
1790 self.pg0.config_ip4()
1791 self.pg0.resolve_arp()
1792 self.pg0.enable_mpls()
1795 self.pg1.config_ip4()
1796 self.pg1.resolve_arp()
1797 self.pg1.enable_mpls()
1799 # VRF (customer facing) link
1801 self.pg2.set_table_ip4(1)
1802 self.pg2.config_ip4()
1803 self.pg2.resolve_arp()
1804 self.pg2.set_table_ip6(1)
1805 self.pg2.config_ip6()
1806 self.pg2.resolve_ndp()
1809 self.pg3.set_table_ip4(1)
1810 self.pg3.config_ip4()
1811 self.pg3.resolve_arp()
1812 self.pg3.set_table_ip6(1)
1813 self.pg3.config_ip6()
1814 self.pg3.resolve_ndp()
1817 self.pg0.disable_mpls()
1818 self.pg1.disable_mpls()
1819 for i in self.pg_interfaces:
1825 super(TestMPLSPIC, self).tearDown()
1827 def test_mpls_ibgp_pic(self):
1828 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1830 1) setup many iBGP VPN routes via a pair of iBGP peers.
1831 2) Check EMCP forwarding to these peers
1832 3) withdraw the IGP route to one of these peers.
1833 4) check forwarding continues to the remaining peer
1837 # IGP+LDP core routes
1839 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1840 [VppRoutePath(self.pg0.remote_ip4,
1841 self.pg0.sw_if_index,
1843 core_10_0_0_45.add_vpp_config()
1845 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1846 [VppRoutePath(self.pg1.remote_ip4,
1847 self.pg1.sw_if_index,
1849 core_10_0_0_46.add_vpp_config()
1852 # Lot's of VPN routes. We need more the 64 so VPP will build
1853 # the fast convergence indirection
1857 for ii in range(NUM_PKTS):
1858 dst = "192.168.1.%d" % ii
1859 vpn_routes.append(VppIpRoute(
1865 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1870 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1872 vpn_routes[ii].add_vpp_config()
1874 pkts.append(Ether(dst=self.pg2.local_mac,
1875 src=self.pg2.remote_mac) /
1876 IP(src=self.pg2.remote_ip4, dst=dst) /
1877 UDP(sport=1234, dport=1234) /
1881 # Send the packet stream (one pkt to each VPN route)
1882 # - expect a 50-50 split of the traffic
1884 self.pg2.add_stream(pkts)
1885 self.pg_enable_capture(self.pg_interfaces)
1888 rx0 = self.pg0._get_capture(NUM_PKTS)
1889 rx1 = self.pg1._get_capture(NUM_PKTS)
1891 # not testing the LB hashing algorithm so we're not concerned
1892 # with the split ratio, just as long as neither is 0
1893 self.assertNotEqual(0, len(rx0))
1894 self.assertNotEqual(0, len(rx1))
1895 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1896 "Expected all (%s) packets across both ECMP paths. "
1897 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1900 # use a test CLI command to stop the FIB walk process, this
1901 # will prevent the FIB converging the VPN routes and thus allow
1902 # us to probe the interim (post-fail, pre-converge) state
1904 self.vapi.ppcli("test fib-walk-process disable")
1907 # Withdraw one of the IGP routes
1909 core_10_0_0_46.remove_vpp_config()
1912 # now all packets should be forwarded through the remaining peer
1914 self.vapi.ppcli("clear trace")
1915 self.pg2.add_stream(pkts)
1916 self.pg_enable_capture(self.pg_interfaces)
1919 rx0 = self.pg0.get_capture(NUM_PKTS)
1920 self.assertEqual(len(pkts), len(rx0),
1921 "Expected all (%s) packets across single path. "
1922 "rx0: %s." % (len(pkts), len(rx0)))
1925 # enable the FIB walk process to converge the FIB
1927 self.vapi.ppcli("test fib-walk-process enable")
1930 # packets should still be forwarded through the remaining peer
1932 self.pg2.add_stream(pkts)
1933 self.pg_enable_capture(self.pg_interfaces)
1936 rx0 = self.pg0.get_capture(NUM_PKTS)
1937 self.assertEqual(len(pkts), len(rx0),
1938 "Expected all (%s) packets across single path. "
1939 "rx0: %s." % (len(pkts), len(rx0)))
1942 # Add the IGP route back and we return to load-balancing
1944 core_10_0_0_46.add_vpp_config()
1946 self.pg2.add_stream(pkts)
1947 self.pg_enable_capture(self.pg_interfaces)
1950 rx0 = self.pg0._get_capture(NUM_PKTS)
1951 rx1 = self.pg1._get_capture(NUM_PKTS)
1952 self.assertNotEqual(0, len(rx0))
1953 self.assertNotEqual(0, len(rx1))
1954 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1955 "Expected all (%s) packets across both ECMP paths. "
1956 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1958 def test_mpls_ebgp_pic(self):
1959 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1961 1) setup many eBGP VPN routes via a pair of eBGP peers.
1962 2) Check EMCP forwarding to these peers
1963 3) withdraw one eBGP path - expect LB across remaining eBGP
1967 # Lot's of VPN routes. We need more the 64 so VPP will build
1968 # the fast convergence indirection
1973 for ii in range(NUM_PKTS):
1974 dst = "192.168.1.%d" % ii
1975 local_label = 1600 + ii
1976 vpn_routes.append(VppIpRoute(
1979 self.pg2.remote_ip4,
1982 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1984 self.pg3.remote_ip4,
1987 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1989 vpn_routes[ii].add_vpp_config()
1991 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1993 vpn_bindings[ii].add_vpp_config()
1995 pkts.append(Ether(dst=self.pg0.local_mac,
1996 src=self.pg0.remote_mac) /
1997 MPLS(label=local_label, ttl=64) /
1998 IP(src=self.pg0.remote_ip4, dst=dst) /
1999 UDP(sport=1234, dport=1234) /
2003 # Send the packet stream (one pkt to each VPN route)
2004 # - expect a 50-50 split of the traffic
2006 self.pg0.add_stream(pkts)
2007 self.pg_enable_capture(self.pg_interfaces)
2010 rx0 = self.pg2._get_capture(NUM_PKTS)
2011 rx1 = self.pg3._get_capture(NUM_PKTS)
2013 # not testing the LB hashing algorithm so we're not concerned
2014 # with the split ratio, just as long as neither is 0
2015 self.assertNotEqual(0, len(rx0))
2016 self.assertNotEqual(0, len(rx1))
2017 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2018 "Expected all (%s) packets across both ECMP paths. "
2019 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2022 # use a test CLI command to stop the FIB walk process, this
2023 # will prevent the FIB converging the VPN routes and thus allow
2024 # us to probe the interim (post-fail, pre-converge) state
2026 self.vapi.ppcli("test fib-walk-process disable")
2029 # withdraw the connected prefix on the interface.
2031 self.pg2.unconfig_ip4()
2034 # now all packets should be forwarded through the remaining peer
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 # enable the FIB walk process to converge the FIB
2048 self.vapi.ppcli("test fib-walk-process enable")
2051 # packets should still be forwarded through the remaining peer
2053 self.pg0.add_stream(pkts)
2054 self.pg_enable_capture(self.pg_interfaces)
2057 rx0 = self.pg3.get_capture(NUM_PKTS)
2058 self.assertEqual(len(pkts), len(rx0),
2059 "Expected all (%s) packets across single path. "
2060 "rx0: %s." % (len(pkts), len(rx0)))
2063 # put the connected routes back
2065 self.pg2.config_ip4()
2066 self.pg2.resolve_arp()
2068 self.pg0.add_stream(pkts)
2069 self.pg_enable_capture(self.pg_interfaces)
2072 rx0 = self.pg2._get_capture(NUM_PKTS)
2073 rx1 = self.pg3._get_capture(NUM_PKTS)
2074 self.assertNotEqual(0, len(rx0))
2075 self.assertNotEqual(0, len(rx1))
2076 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2077 "Expected all (%s) packets across both ECMP paths. "
2078 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2080 def test_mpls_v6_ebgp_pic(self):
2081 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
2083 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
2084 2) Check EMCP forwarding to these peers
2085 3) withdraw one eBGP path - expect LB across remaining eBGP
2089 # Lot's of VPN routes. We need more the 64 so VPP will build
2090 # the fast convergence indirection
2095 for ii in range(NUM_PKTS):
2096 dst = "3000::%d" % ii
2097 local_label = 1600 + ii
2098 vpn_routes.append(VppIpRoute(
2101 self.pg2.remote_ip6,
2104 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
2106 self.pg3.remote_ip6,
2109 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
2111 vpn_routes[ii].add_vpp_config()
2113 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
2115 vpn_bindings[ii].add_vpp_config()
2117 pkts.append(Ether(dst=self.pg0.local_mac,
2118 src=self.pg0.remote_mac) /
2119 MPLS(label=local_label, ttl=64) /
2120 IPv6(src=self.pg0.remote_ip6, dst=dst) /
2121 UDP(sport=1234, dport=1234) /
2123 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2125 self.pg0.add_stream(pkts)
2126 self.pg_enable_capture(self.pg_interfaces)
2129 rx0 = self.pg2._get_capture(NUM_PKTS)
2130 rx1 = self.pg3._get_capture(NUM_PKTS)
2131 self.assertNotEqual(0, len(rx0))
2132 self.assertNotEqual(0, len(rx1))
2133 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2134 "Expected all (%s) packets across both ECMP paths. "
2135 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2138 # use a test CLI command to stop the FIB walk process, this
2139 # will prevent the FIB converging the VPN routes and thus allow
2140 # us to probe the interim (post-fail, pre-converge) state
2142 self.vapi.ppcli("test fib-walk-process disable")
2145 # withdraw the connected prefix on the interface.
2146 # and shutdown the interface so the ND cache is flushed.
2148 self.pg2.unconfig_ip6()
2149 self.pg2.admin_down()
2152 # now all packets should be forwarded through the remaining peer
2154 self.pg0.add_stream(pkts)
2155 self.pg_enable_capture(self.pg_interfaces)
2158 rx0 = self.pg3.get_capture(NUM_PKTS)
2159 self.assertEqual(len(pkts), len(rx0),
2160 "Expected all (%s) packets across single path. "
2161 "rx0: %s." % (len(pkts), len(rx0)))
2164 # enable the FIB walk process to converge the FIB
2166 self.vapi.ppcli("test fib-walk-process enable")
2167 self.pg0.add_stream(pkts)
2168 self.pg_enable_capture(self.pg_interfaces)
2171 rx0 = self.pg3.get_capture(NUM_PKTS)
2172 self.assertEqual(len(pkts), len(rx0),
2173 "Expected all (%s) packets across single path. "
2174 "rx0: %s." % (len(pkts), len(rx0)))
2177 # put the connected routes back
2179 self.logger.info(self.vapi.cli("sh log"))
2181 self.pg2.config_ip6()
2182 self.pg2.resolve_ndp()
2184 self.pg0.add_stream(pkts)
2185 self.pg_enable_capture(self.pg_interfaces)
2188 rx0 = self.pg2._get_capture(NUM_PKTS)
2189 rx1 = self.pg3._get_capture(NUM_PKTS)
2190 self.assertNotEqual(0, len(rx0))
2191 self.assertNotEqual(0, len(rx1))
2192 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2193 "Expected all (%s) packets across both ECMP paths. "
2194 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2197 class TestMPLSL2(VppTestCase):
2201 def setUpClass(cls):
2202 super(TestMPLSL2, cls).setUpClass()
2205 def tearDownClass(cls):
2206 super(TestMPLSL2, cls).tearDownClass()
2209 super(TestMPLSL2, self).setUp()
2211 # create 2 pg interfaces
2212 self.create_pg_interfaces(range(2))
2214 # create the default MPLS table
2216 tbl = VppMplsTable(self, 0)
2217 tbl.add_vpp_config()
2218 self.tables.append(tbl)
2220 # use pg0 as the core facing interface, don't resolve ARP
2222 self.pg0.config_ip4()
2223 self.pg0.enable_mpls()
2225 # use the other 2 for customer facing L2 links
2226 for i in self.pg_interfaces[1:]:
2230 for i in self.pg_interfaces[1:]:
2233 self.pg0.disable_mpls()
2234 self.pg0.unconfig_ip4()
2235 self.pg0.admin_down()
2236 super(TestMPLSL2, self).tearDown()
2238 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2239 capture = verify_filter(capture, sent)
2241 self.assertEqual(len(capture), len(sent))
2243 for i in range(len(capture)):
2247 # the MPLS TTL is 255 since it enters a new tunnel
2248 verify_mpls_stack(self, rx, mpls_labels)
2251 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2253 self.assertEqual(rx_eth.src, tx_eth.src)
2254 self.assertEqual(rx_eth.dst, tx_eth.dst)
2256 def verify_arp_req(self, rx, smac, sip, dip):
2258 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2259 self.assertEqual(ether.src, smac)
2262 self.assertEqual(arp.hwtype, 1)
2263 self.assertEqual(arp.ptype, 0x800)
2264 self.assertEqual(arp.hwlen, 6)
2265 self.assertEqual(arp.plen, 4)
2266 self.assertEqual(arp.op, ARP.who_has)
2267 self.assertEqual(arp.hwsrc, smac)
2268 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2269 self.assertEqual(arp.psrc, sip)
2270 self.assertEqual(arp.pdst, dip)
2272 def test_vpws(self):
2273 """ Virtual Private Wire Service """
2276 # Create an MPLS tunnel that pushes 1 label
2277 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2278 # information is not in the packet, but we test it works anyway
2280 mpls_tun_1 = VppMPLSTunnelInterface(
2282 [VppRoutePath(self.pg0.remote_ip4,
2283 self.pg0.sw_if_index,
2284 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2286 mpls_tun_1.add_vpp_config()
2287 mpls_tun_1.admin_up()
2290 # Create a label entry to for 55 that does L2 input to the tunnel
2292 route_55_eos = VppMplsRoute(
2294 [VppRoutePath("0.0.0.0",
2295 mpls_tun_1.sw_if_index,
2296 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2297 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2298 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2299 route_55_eos.add_vpp_config()
2302 # Cross-connect the tunnel with one of the customers L2 interfaces
2304 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2305 mpls_tun_1.sw_if_index,
2307 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2308 self.pg1.sw_if_index,
2312 # inject a packet from the core
2314 pcore = (Ether(dst=self.pg0.local_mac,
2315 src=self.pg0.remote_mac) /
2316 MPLS(label=55, ttl=64) /
2317 Ether(dst="00:00:de:ad:ba:be",
2318 src="00:00:de:ad:be:ef") /
2319 IP(src="10.10.10.10", dst="11.11.11.11") /
2320 UDP(sport=1234, dport=1234) /
2323 tx0 = pcore * NUM_PKTS
2324 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2325 payload = pcore[MPLS].payload
2327 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2328 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2331 # Inject a packet from the customer/L2 side
2332 # there's no resolved ARP entry so the first packet we see should be
2335 tx1 = pcore[MPLS].payload
2336 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2338 self.verify_arp_req(rx1[0],
2341 self.pg0.remote_ip4)
2344 # resolve the ARP entries and send again
2346 self.pg0.resolve_arp()
2347 tx1 = pcore[MPLS].payload * NUM_PKTS
2348 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2350 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2352 def test_vpls(self):
2353 """ Virtual Private LAN Service """
2355 # we skipped this in the setup
2356 self.pg0.resolve_arp()
2359 # Create a L2 MPLS tunnels
2361 mpls_tun1 = VppMPLSTunnelInterface(
2363 [VppRoutePath(self.pg0.remote_ip4,
2364 self.pg0.sw_if_index,
2365 labels=[VppMplsLabel(42)])],
2367 mpls_tun1.add_vpp_config()
2368 mpls_tun1.admin_up()
2370 mpls_tun2 = VppMPLSTunnelInterface(
2372 [VppRoutePath(self.pg0.remote_ip4,
2373 self.pg0.sw_if_index,
2374 labels=[VppMplsLabel(43)])],
2376 mpls_tun2.add_vpp_config()
2377 mpls_tun2.admin_up()
2380 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2381 # the latter includes a Psuedo Wire Control Word
2383 route_55_eos = VppMplsRoute(
2385 [VppRoutePath("0.0.0.0",
2386 mpls_tun1.sw_if_index,
2387 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2388 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2389 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2391 route_56_eos = VppMplsRoute(
2393 [VppRoutePath("0.0.0.0",
2394 mpls_tun2.sw_if_index,
2395 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2396 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2397 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2398 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2401 route_56_eos.add_vpp_config()
2402 route_55_eos.add_vpp_config()
2404 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2407 # add to tunnel to the customers bridge-domain
2409 self.vapi.sw_interface_set_l2_bridge(
2410 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2411 self.vapi.sw_interface_set_l2_bridge(
2412 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2413 self.vapi.sw_interface_set_l2_bridge(
2414 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2417 # Packet from host on the customer interface to each host
2418 # reachable over the core, and vice-versa
2420 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2421 src="00:00:de:ad:be:ef") /
2422 IP(src="10.10.10.10", dst="11.11.11.11") /
2423 UDP(sport=1234, dport=1234) /
2425 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2426 src="00:00:de:ad:be:ef") /
2427 IP(src="10.10.10.10", dst="11.11.11.12") /
2428 UDP(sport=1234, dport=1234) /
2430 p_core1 = (Ether(dst=self.pg0.local_mac,
2431 src=self.pg0.remote_mac) /
2432 MPLS(label=55, ttl=64) /
2433 Ether(src="00:00:de:ad:ba:b1",
2434 dst="00:00:de:ad:be:ef") /
2435 IP(dst="10.10.10.10", src="11.11.11.11") /
2436 UDP(sport=1234, dport=1234) /
2438 p_core2 = (Ether(dst=self.pg0.local_mac,
2439 src=self.pg0.remote_mac) /
2440 MPLS(label=56, ttl=64) /
2441 Raw(b'\x01' * 4) / # PW CW
2442 Ether(src="00:00:de:ad:ba:b2",
2443 dst="00:00:de:ad:be:ef") /
2444 IP(dst="10.10.10.10", src="11.11.11.12") /
2445 UDP(sport=1234, dport=1234) /
2449 # The BD is learning, so send in one of each packet to learn
2452 # 2 packets due to BD flooding
2453 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2454 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2456 # we've learnt this so expect it be be forwarded not flooded
2457 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2458 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2459 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2461 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2462 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2463 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2466 # now a stream in each direction from each host
2468 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2469 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2472 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2473 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2476 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2477 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2480 # remove interfaces from customers bridge-domain
2482 self.vapi.sw_interface_set_l2_bridge(
2483 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2484 self.vapi.sw_interface_set_l2_bridge(
2485 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2486 self.vapi.sw_interface_set_l2_bridge(
2487 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2490 if __name__ == '__main__':
2491 unittest.main(testRunner=VppTestRunner)