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, icmptypes, icmpcodes
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 self.assertEqual(icmptypes[rx[ICMP].type], "dest-unreach")
965 self.assertEqual(icmpcodes[rx[ICMP].type][rx[ICMP].code],
966 "fragmentation-needed")
967 # the link MTU is 9000, the MPLS over head is 4 bytes
968 self.assertEqual(rx[ICMP].nexthopmtu, 9000 - 4)
970 self.assertEqual(self.statistics.get_err_counter(
971 "/err/mpls-frag/can't fragment this packet"),
974 # a stream that matches the route for 1000::1/128
975 # PG0 is in the default table
977 tx = self.create_stream_ip6(self.pg0, "1000::1")
978 for i in range(0, 257):
979 self.extend_packet(tx[i], 10000)
981 rxs = self.send_and_expect_some(self.pg0, tx, self.pg0)
983 self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 9000 - 4)
988 route_10_0_0_1.remove_vpp_config()
990 def test_tunnel_pipe(self):
991 """ MPLS Tunnel Tests - Pipe """
994 # Create a tunnel with two out labels
996 mpls_tun = VppMPLSTunnelInterface(
998 [VppRoutePath(self.pg0.remote_ip4,
999 self.pg0.sw_if_index,
1000 labels=[VppMplsLabel(44),
1001 VppMplsLabel(46)])])
1002 mpls_tun.add_vpp_config()
1006 # add an unlabelled route through the new tunnel
1008 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1009 [VppRoutePath("0.0.0.0",
1010 mpls_tun._sw_if_index)])
1011 route_10_0_0_3.add_vpp_config()
1013 self.vapi.cli("clear trace")
1014 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1015 self.pg0.add_stream(tx)
1017 self.pg_enable_capture(self.pg_interfaces)
1020 rx = self.pg0.get_capture()
1021 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1026 # add a labelled route through the new tunnel
1028 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
1029 [VppRoutePath("0.0.0.0",
1030 mpls_tun._sw_if_index,
1032 route_10_0_0_4.add_vpp_config()
1034 self.vapi.cli("clear trace")
1035 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1036 self.pg0.add_stream(tx)
1038 self.pg_enable_capture(self.pg_interfaces)
1041 rx = self.pg0.get_capture()
1042 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1045 VppMplsLabel(33, ttl=255)])
1048 # change tunnel's MTU to a low value
1050 mpls_tun.set_l3_mtu(1200)
1052 # send IP into the tunnel to be fragmented
1053 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
1055 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1061 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1065 # send MPLS into the tunnel to be fragmented
1066 tx = self.create_stream_ip4(self.pg0, "10.0.0.4",
1068 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1074 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1077 VppMplsLabel(33, ttl=255)])
1079 def test_tunnel_uniform(self):
1080 """ MPLS Tunnel Tests - Uniform """
1083 # Create a tunnel with a single out label
1084 # The label stack is specified here from outer to inner
1086 mpls_tun = VppMPLSTunnelInterface(
1088 [VppRoutePath(self.pg0.remote_ip4,
1089 self.pg0.sw_if_index,
1090 labels=[VppMplsLabel(44, ttl=32),
1091 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1092 mpls_tun.add_vpp_config()
1096 # add an unlabelled route through the new tunnel
1098 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1099 [VppRoutePath("0.0.0.0",
1100 mpls_tun._sw_if_index)])
1101 route_10_0_0_3.add_vpp_config()
1103 self.vapi.cli("clear trace")
1104 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1105 self.pg0.add_stream(tx)
1107 self.pg_enable_capture(self.pg_interfaces)
1110 rx = self.pg0.get_capture()
1111 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1112 [VppMplsLabel(44, ttl=32),
1113 VppMplsLabel(46, ttl=23)])
1116 # add a labelled route through the new tunnel
1118 route_10_0_0_4 = VppIpRoute(
1119 self, "10.0.0.4", 32,
1120 [VppRoutePath("0.0.0.0",
1121 mpls_tun._sw_if_index,
1122 labels=[VppMplsLabel(33, ttl=47)])])
1123 route_10_0_0_4.add_vpp_config()
1125 self.vapi.cli("clear trace")
1126 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1127 self.pg0.add_stream(tx)
1129 self.pg_enable_capture(self.pg_interfaces)
1132 rx = self.pg0.get_capture()
1133 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1134 [VppMplsLabel(44, ttl=32),
1135 VppMplsLabel(46, ttl=47),
1136 VppMplsLabel(33, ttl=47)])
1138 def test_mpls_tunnel_many(self):
1139 """ MPLS Multiple Tunnels """
1141 for ii in range(100):
1142 mpls_tun = VppMPLSTunnelInterface(
1144 [VppRoutePath(self.pg0.remote_ip4,
1145 self.pg0.sw_if_index,
1146 labels=[VppMplsLabel(44, ttl=32),
1147 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1148 mpls_tun.add_vpp_config()
1150 for ii in range(100):
1151 mpls_tun = VppMPLSTunnelInterface(
1153 [VppRoutePath(self.pg0.remote_ip4,
1154 self.pg0.sw_if_index,
1155 labels=[VppMplsLabel(44, ttl=32),
1156 VppMplsLabel(46, MplsLspMode.UNIFORM)])],
1158 mpls_tun.add_vpp_config()
1161 def test_v4_exp_null(self):
1162 """ MPLS V4 Explicit NULL test """
1165 # The first test case has an MPLS TTL of 0
1166 # all packet should be dropped
1168 tx = self.create_stream_labelled_ip4(self.pg0,
1169 [VppMplsLabel(0, ttl=0)])
1170 self.send_and_assert_no_replies(self.pg0, tx,
1171 "MPLS TTL=0 packets forwarded")
1174 # a stream with a non-zero MPLS TTL
1175 # PG0 is in the default table
1177 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1178 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1179 self.verify_capture_ip4(self.pg0, rx, tx)
1182 # a stream with a non-zero MPLS TTL
1184 # we are ensuring the post-pop lookup occurs in the VRF table
1186 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1187 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1188 self.verify_capture_ip4(self.pg1, rx, tx)
1190 def test_v6_exp_null(self):
1191 """ MPLS V6 Explicit NULL test """
1194 # a stream with a non-zero MPLS TTL
1195 # PG0 is in the default table
1197 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1198 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1199 self.verify_capture_ip6(self.pg0, rx, tx)
1202 # a stream with a non-zero MPLS TTL
1204 # we are ensuring the post-pop lookup occurs in the VRF table
1206 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1207 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1208 self.verify_capture_ip6(self.pg0, rx, tx)
1210 def test_deag(self):
1214 # A de-agg route - next-hop lookup in default table
1216 route_34_eos = VppMplsRoute(self, 34, 1,
1217 [VppRoutePath("0.0.0.0",
1220 route_34_eos.add_vpp_config()
1223 # ping an interface in the default table
1224 # PG0 is in the default table
1226 tx = self.create_stream_labelled_ip4(self.pg0,
1230 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1231 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1234 # A de-agg route - next-hop lookup in non-default table
1236 route_35_eos = VppMplsRoute(self, 35, 1,
1237 [VppRoutePath("0.0.0.0",
1240 route_35_eos.add_vpp_config()
1241 route_356_eos = VppMplsRoute(
1243 [VppRoutePath("0::0",
1246 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1247 route_356_eos.add_vpp_config()
1250 # ping an interface in the non-default table
1251 # PG0 is in the default table. packet arrive labelled in the
1252 # default table and egress unlabelled in the non-default
1254 tx = self.create_stream_labelled_ip4(
1255 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1256 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1257 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1258 tx = self.create_stream_labelled_ip6(
1259 self.pg0, [VppMplsLabel(356)], ping=1, ip_itf=self.pg1)
1260 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1261 self.verify_capture_ip6(self.pg1, rx, tx, ping_resp=1)
1266 route_36_neos = VppMplsRoute(self, 36, 0,
1267 [VppRoutePath("0.0.0.0",
1269 route_36_neos.add_vpp_config()
1271 tx = self.create_stream_labelled_ip4(self.pg0,
1274 ping=1, ip_itf=self.pg1)
1275 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1276 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1278 route_36_neos.remove_vpp_config()
1279 route_35_eos.remove_vpp_config()
1280 route_34_eos.remove_vpp_config()
1282 def test_interface_rx(self):
1283 """ MPLS Interface Receive """
1286 # Add a non-recursive route that will forward the traffic
1289 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1291 paths=[VppRoutePath(self.pg1.remote_ip4,
1292 self.pg1.sw_if_index)])
1293 route_10_0_0_1.add_vpp_config()
1296 # An interface receive label that maps traffic to RX on interface
1298 # by injecting the packet in on pg0, which is in table 0
1299 # doing an interface-rx on pg1 and matching a route in table 1
1300 # if the packet egresses, then we must have swapped to pg1
1301 # so as to have matched the route in table 1
1303 route_34_eos = VppMplsRoute(
1305 [VppRoutePath("0.0.0.0",
1306 self.pg1.sw_if_index,
1307 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1308 route_34_eos.add_vpp_config()
1311 # ping an interface in the default table
1312 # PG0 is in the default table
1314 tx = self.create_stream_labelled_ip4(self.pg0,
1317 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1318 self.verify_capture_ip4(self.pg1, rx, tx)
1320 def test_mcast_mid_point(self):
1321 """ MPLS Multicast Mid Point """
1324 # Add a non-recursive route that will forward the traffic
1327 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1329 paths=[VppRoutePath(self.pg1.remote_ip4,
1330 self.pg1.sw_if_index)])
1331 route_10_0_0_1.add_vpp_config()
1334 # Add a mcast entry that replicate to pg2 and pg3
1335 # and replicate to a interface-rx (like a bud node would)
1337 route_3400_eos = VppMplsRoute(
1339 [VppRoutePath(self.pg2.remote_ip4,
1340 self.pg2.sw_if_index,
1341 labels=[VppMplsLabel(3401)]),
1342 VppRoutePath(self.pg3.remote_ip4,
1343 self.pg3.sw_if_index,
1344 labels=[VppMplsLabel(3402)]),
1345 VppRoutePath("0.0.0.0",
1346 self.pg1.sw_if_index,
1347 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1349 route_3400_eos.add_vpp_config()
1352 # ping an interface in the default table
1353 # PG0 is in the default table
1355 self.vapi.cli("clear trace")
1356 tx = self.create_stream_labelled_ip4(self.pg0,
1357 [VppMplsLabel(3400, ttl=64)],
1360 self.pg0.add_stream(tx)
1362 self.pg_enable_capture(self.pg_interfaces)
1365 rx = self.pg1.get_capture(257)
1366 self.verify_capture_ip4(self.pg1, rx, tx)
1368 rx = self.pg2.get_capture(257)
1369 self.verify_capture_labelled(self.pg2, rx, tx,
1370 [VppMplsLabel(3401, ttl=63)])
1371 rx = self.pg3.get_capture(257)
1372 self.verify_capture_labelled(self.pg3, rx, tx,
1373 [VppMplsLabel(3402, ttl=63)])
1375 def test_mcast_head(self):
1376 """ MPLS Multicast Head-end """
1378 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1379 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1382 # Create a multicast tunnel with two replications
1384 mpls_tun = VppMPLSTunnelInterface(
1386 [VppRoutePath(self.pg2.remote_ip4,
1387 self.pg2.sw_if_index,
1388 labels=[VppMplsLabel(42)]),
1389 VppRoutePath(self.pg3.remote_ip4,
1390 self.pg3.sw_if_index,
1391 labels=[VppMplsLabel(43)])],
1393 mpls_tun.add_vpp_config()
1397 # add an unlabelled route through the new tunnel
1399 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1400 [VppRoutePath("0.0.0.0",
1401 mpls_tun._sw_if_index)])
1402 route_10_0_0_3.add_vpp_config()
1404 self.vapi.cli("clear trace")
1405 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1406 self.pg0.add_stream(tx)
1408 self.pg_enable_capture(self.pg_interfaces)
1411 rx = self.pg2.get_capture(257)
1412 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1413 rx = self.pg3.get_capture(257)
1414 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1417 # An an IP multicast route via the tunnel
1419 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1421 route_232_1_1_1 = VppIpMRoute(
1425 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1426 [VppMRoutePath(self.pg0.sw_if_index,
1427 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT),
1428 VppMRoutePath(mpls_tun._sw_if_index,
1429 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1430 route_232_1_1_1.add_vpp_config()
1431 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1433 self.vapi.cli("clear trace")
1434 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1435 self.pg0.add_stream(tx)
1437 self.pg_enable_capture(self.pg_interfaces)
1440 rx = self.pg2.get_capture(257)
1441 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1442 rx = self.pg3.get_capture(257)
1443 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1445 def test_mcast_ip4_tail(self):
1446 """ MPLS IPv4 Multicast Tail """
1448 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1449 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1452 # Add a multicast route that will forward the traffic
1455 route_232_1_1_1 = VppIpMRoute(
1459 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1461 paths=[VppMRoutePath(self.pg1.sw_if_index,
1462 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1463 route_232_1_1_1.add_vpp_config()
1466 # An interface receive label that maps traffic to RX on interface
1468 # by injecting the packet in on pg0, which is in table 0
1469 # doing an rpf-id and matching a route in table 1
1470 # if the packet egresses, then we must have matched the route in
1473 route_34_eos = VppMplsRoute(
1475 [VppRoutePath("0.0.0.0",
1480 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1482 route_34_eos.add_vpp_config()
1485 # Drop due to interface lookup miss
1487 self.vapi.cli("clear trace")
1488 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1489 dst_ip="232.1.1.1", n=1)
1490 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1493 # set the RPF-ID of the entry to match the input packet's
1495 route_232_1_1_1.update_rpf_id(55)
1496 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1498 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1500 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1501 self.verify_capture_ip4(self.pg1, rx, tx)
1504 # disposed packets have an invalid IPv4 checksum
1506 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1507 dst_ip="232.1.1.1", n=65,
1509 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1512 # set the RPF-ID of the entry to not match the input packet's
1514 route_232_1_1_1.update_rpf_id(56)
1515 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1517 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1519 def test_mcast_ip6_tail(self):
1520 """ MPLS IPv6 Multicast Tail """
1522 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1523 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1526 # Add a multicast route that will forward the traffic
1529 route_ff = VppIpMRoute(
1533 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1535 paths=[VppMRoutePath(self.pg1.sw_if_index,
1536 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1537 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1538 route_ff.add_vpp_config()
1541 # An interface receive label that maps traffic to RX on interface
1543 # by injecting the packet in on pg0, which is in table 0
1544 # doing an rpf-id and matching a route in table 1
1545 # if the packet egresses, then we must have matched the route in
1548 route_34_eos = VppMplsRoute(
1555 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1557 route_34_eos.add_vpp_config()
1560 # Drop due to interface lookup miss
1562 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1564 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1567 # set the RPF-ID of the entry to match the input packet's
1569 route_ff.update_rpf_id(55)
1571 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1573 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1574 self.verify_capture_ip6(self.pg1, rx, tx)
1577 # disposed packets have hop-limit = 1
1579 tx = self.create_stream_labelled_ip6(self.pg0,
1583 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
1584 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1587 # set the RPF-ID of the entry to not match the input packet's
1589 route_ff.update_rpf_id(56)
1590 tx = self.create_stream_labelled_ip6(self.pg0,
1593 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1599 # Add a non-recursive route with a single out label
1601 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1602 [VppRoutePath(self.pg0.remote_ip4,
1603 self.pg0.sw_if_index,
1604 labels=[VppMplsLabel(45)])])
1605 route_10_0_0_1.add_vpp_config()
1607 # bind a local label to the route
1608 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1609 binding.add_vpp_config()
1612 # a labelled v6 route that resolves through the v4
1614 route_2001_3 = VppIpRoute(
1615 self, "2001::3", 128,
1616 [VppRoutePath("10.0.0.1",
1618 labels=[VppMplsLabel(32)])])
1619 route_2001_3.add_vpp_config()
1621 tx = self.create_stream_ip6(self.pg0, "2001::3")
1622 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1624 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1629 # and a v4 recursive via the v6
1631 route_20_3 = VppIpRoute(
1632 self, "20.0.0.3", 32,
1633 [VppRoutePath("2001::3",
1635 labels=[VppMplsLabel(99)])])
1636 route_20_3.add_vpp_config()
1638 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1639 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1641 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1646 def test_attached(self):
1647 """ Attach Routes with Local Label """
1650 # test that if a local label is associated with an attached/connected
1651 # prefix, that we can reach hosts in the prefix.
1653 binding = VppMplsIpBind(self, 44,
1654 self.pg0._local_ip4_subnet,
1655 self.pg0.local_ip4_prefix_len)
1656 binding.add_vpp_config()
1658 tx = (Ether(src=self.pg1.remote_mac,
1659 dst=self.pg1.local_mac) /
1660 MPLS(label=44, ttl=64) /
1661 IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) /
1662 UDP(sport=1234, dport=1234) /
1664 rxs = self.send_and_expect(self.pg0, [tx], self.pg0)
1666 # if there's an ARP then the label is linked to the glean
1668 self.assertFalse(rx.haslayer(ARP))
1669 # it should be unicasted to the host
1670 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1671 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1674 class TestMPLSDisabled(VppTestCase):
1675 """ MPLS disabled """
1678 def setUpClass(cls):
1679 super(TestMPLSDisabled, cls).setUpClass()
1682 def tearDownClass(cls):
1683 super(TestMPLSDisabled, cls).tearDownClass()
1686 super(TestMPLSDisabled, self).setUp()
1688 # create 2 pg interfaces
1689 self.create_pg_interfaces(range(2))
1691 self.tbl = VppMplsTable(self, 0)
1692 self.tbl.add_vpp_config()
1694 # PG0 is MPLS enabled
1696 self.pg0.config_ip4()
1697 self.pg0.resolve_arp()
1698 self.pg0.enable_mpls()
1700 # PG 1 is not MPLS enabled
1704 for i in self.pg_interfaces:
1708 self.pg0.disable_mpls()
1709 super(TestMPLSDisabled, self).tearDown()
1711 def test_mpls_disabled(self):
1712 """ MPLS Disabled """
1714 self.logger.info(self.vapi.cli("show mpls interface"))
1715 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1716 self.logger.info(self.vapi.cli("show mpls interface pg0"))
1718 tx = (Ether(src=self.pg1.remote_mac,
1719 dst=self.pg1.local_mac) /
1720 MPLS(label=32, ttl=64) /
1721 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1722 UDP(sport=1234, dport=1234) /
1726 # A simple MPLS xconnect - eos label in label out
1728 route_32_eos = VppMplsRoute(self, 32, 1,
1729 [VppRoutePath(self.pg0.remote_ip4,
1730 self.pg0.sw_if_index,
1732 route_32_eos.add_vpp_config()
1735 # PG1 does not forward IP traffic
1737 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1742 self.pg1.enable_mpls()
1744 self.logger.info(self.vapi.cli("show mpls interface"))
1745 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1748 # Now we get packets through
1750 self.pg1.add_stream(tx)
1751 self.pg_enable_capture(self.pg_interfaces)
1754 rx = self.pg0.get_capture(1)
1759 self.pg1.disable_mpls()
1762 # PG1 does not forward IP traffic
1764 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1765 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1768 class TestMPLSPIC(VppTestCase):
1769 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1772 def setUpClass(cls):
1773 super(TestMPLSPIC, cls).setUpClass()
1776 def tearDownClass(cls):
1777 super(TestMPLSPIC, cls).tearDownClass()
1780 super(TestMPLSPIC, self).setUp()
1782 # create 2 pg interfaces
1783 self.create_pg_interfaces(range(4))
1785 mpls_tbl = VppMplsTable(self, 0)
1786 mpls_tbl.add_vpp_config()
1787 tbl4 = VppIpTable(self, 1)
1788 tbl4.add_vpp_config()
1789 tbl6 = VppIpTable(self, 1, is_ip6=1)
1790 tbl6.add_vpp_config()
1794 self.pg0.config_ip4()
1795 self.pg0.resolve_arp()
1796 self.pg0.enable_mpls()
1799 self.pg1.config_ip4()
1800 self.pg1.resolve_arp()
1801 self.pg1.enable_mpls()
1803 # VRF (customer facing) link
1805 self.pg2.set_table_ip4(1)
1806 self.pg2.config_ip4()
1807 self.pg2.resolve_arp()
1808 self.pg2.set_table_ip6(1)
1809 self.pg2.config_ip6()
1810 self.pg2.resolve_ndp()
1813 self.pg3.set_table_ip4(1)
1814 self.pg3.config_ip4()
1815 self.pg3.resolve_arp()
1816 self.pg3.set_table_ip6(1)
1817 self.pg3.config_ip6()
1818 self.pg3.resolve_ndp()
1821 self.pg0.disable_mpls()
1822 self.pg1.disable_mpls()
1823 for i in self.pg_interfaces:
1829 super(TestMPLSPIC, self).tearDown()
1831 def test_mpls_ibgp_pic(self):
1832 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1834 1) setup many iBGP VPN routes via a pair of iBGP peers.
1835 2) Check EMCP forwarding to these peers
1836 3) withdraw the IGP route to one of these peers.
1837 4) check forwarding continues to the remaining peer
1841 # IGP+LDP core routes
1843 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1844 [VppRoutePath(self.pg0.remote_ip4,
1845 self.pg0.sw_if_index,
1847 core_10_0_0_45.add_vpp_config()
1849 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1850 [VppRoutePath(self.pg1.remote_ip4,
1851 self.pg1.sw_if_index,
1853 core_10_0_0_46.add_vpp_config()
1856 # Lot's of VPN routes. We need more the 64 so VPP will build
1857 # the fast convergence indirection
1861 for ii in range(NUM_PKTS):
1862 dst = "192.168.1.%d" % ii
1863 vpn_routes.append(VppIpRoute(
1869 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1874 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1876 vpn_routes[ii].add_vpp_config()
1878 pkts.append(Ether(dst=self.pg2.local_mac,
1879 src=self.pg2.remote_mac) /
1880 IP(src=self.pg2.remote_ip4, dst=dst) /
1881 UDP(sport=1234, dport=1234) /
1885 # Send the packet stream (one pkt to each VPN route)
1886 # - expect a 50-50 split of the traffic
1888 self.pg2.add_stream(pkts)
1889 self.pg_enable_capture(self.pg_interfaces)
1892 rx0 = self.pg0._get_capture(NUM_PKTS)
1893 rx1 = self.pg1._get_capture(NUM_PKTS)
1895 # not testing the LB hashing algorithm so we're not concerned
1896 # with the split ratio, just as long as neither is 0
1897 self.assertNotEqual(0, len(rx0))
1898 self.assertNotEqual(0, len(rx1))
1899 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1900 "Expected all (%s) packets across both ECMP paths. "
1901 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1904 # use a test CLI command to stop the FIB walk process, this
1905 # will prevent the FIB converging the VPN routes and thus allow
1906 # us to probe the interim (post-fail, pre-converge) state
1908 self.vapi.ppcli("test fib-walk-process disable")
1911 # Withdraw one of the IGP routes
1913 core_10_0_0_46.remove_vpp_config()
1916 # now all packets should be forwarded through the remaining peer
1918 self.vapi.ppcli("clear trace")
1919 self.pg2.add_stream(pkts)
1920 self.pg_enable_capture(self.pg_interfaces)
1923 rx0 = self.pg0.get_capture(NUM_PKTS)
1924 self.assertEqual(len(pkts), len(rx0),
1925 "Expected all (%s) packets across single path. "
1926 "rx0: %s." % (len(pkts), len(rx0)))
1929 # enable the FIB walk process to converge the FIB
1931 self.vapi.ppcli("test fib-walk-process enable")
1934 # packets should still be forwarded through the remaining peer
1936 self.pg2.add_stream(pkts)
1937 self.pg_enable_capture(self.pg_interfaces)
1940 rx0 = self.pg0.get_capture(NUM_PKTS)
1941 self.assertEqual(len(pkts), len(rx0),
1942 "Expected all (%s) packets across single path. "
1943 "rx0: %s." % (len(pkts), len(rx0)))
1946 # Add the IGP route back and we return to load-balancing
1948 core_10_0_0_46.add_vpp_config()
1950 self.pg2.add_stream(pkts)
1951 self.pg_enable_capture(self.pg_interfaces)
1954 rx0 = self.pg0._get_capture(NUM_PKTS)
1955 rx1 = self.pg1._get_capture(NUM_PKTS)
1956 self.assertNotEqual(0, len(rx0))
1957 self.assertNotEqual(0, len(rx1))
1958 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1959 "Expected all (%s) packets across both ECMP paths. "
1960 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1962 def test_mpls_ebgp_pic(self):
1963 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1965 1) setup many eBGP VPN routes via a pair of eBGP peers.
1966 2) Check EMCP forwarding to these peers
1967 3) withdraw one eBGP path - expect LB across remaining eBGP
1971 # Lot's of VPN routes. We need more the 64 so VPP will build
1972 # the fast convergence indirection
1977 for ii in range(NUM_PKTS):
1978 dst = "192.168.1.%d" % ii
1979 local_label = 1600 + ii
1980 vpn_routes.append(VppIpRoute(
1983 self.pg2.remote_ip4,
1986 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1988 self.pg3.remote_ip4,
1991 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1993 vpn_routes[ii].add_vpp_config()
1995 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1997 vpn_bindings[ii].add_vpp_config()
1999 pkts.append(Ether(dst=self.pg0.local_mac,
2000 src=self.pg0.remote_mac) /
2001 MPLS(label=local_label, ttl=64) /
2002 IP(src=self.pg0.remote_ip4, dst=dst) /
2003 UDP(sport=1234, dport=1234) /
2007 # Send the packet stream (one pkt to each VPN route)
2008 # - expect a 50-50 split of the traffic
2010 self.pg0.add_stream(pkts)
2011 self.pg_enable_capture(self.pg_interfaces)
2014 rx0 = self.pg2._get_capture(NUM_PKTS)
2015 rx1 = self.pg3._get_capture(NUM_PKTS)
2017 # not testing the LB hashing algorithm so we're not concerned
2018 # with the split ratio, just as long as neither is 0
2019 self.assertNotEqual(0, len(rx0))
2020 self.assertNotEqual(0, len(rx1))
2021 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2022 "Expected all (%s) packets across both ECMP paths. "
2023 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2026 # use a test CLI command to stop the FIB walk process, this
2027 # will prevent the FIB converging the VPN routes and thus allow
2028 # us to probe the interim (post-fail, pre-converge) state
2030 self.vapi.ppcli("test fib-walk-process disable")
2033 # withdraw the connected prefix on the interface.
2035 self.pg2.unconfig_ip4()
2038 # now all packets should be forwarded through the remaining peer
2040 self.pg0.add_stream(pkts)
2041 self.pg_enable_capture(self.pg_interfaces)
2044 rx0 = self.pg3.get_capture(NUM_PKTS)
2045 self.assertEqual(len(pkts), len(rx0),
2046 "Expected all (%s) packets across single path. "
2047 "rx0: %s." % (len(pkts), len(rx0)))
2050 # enable the FIB walk process to converge the FIB
2052 self.vapi.ppcli("test fib-walk-process enable")
2055 # packets should still be forwarded through the remaining peer
2057 self.pg0.add_stream(pkts)
2058 self.pg_enable_capture(self.pg_interfaces)
2061 rx0 = self.pg3.get_capture(NUM_PKTS)
2062 self.assertEqual(len(pkts), len(rx0),
2063 "Expected all (%s) packets across single path. "
2064 "rx0: %s." % (len(pkts), len(rx0)))
2067 # put the connected routes back
2069 self.pg2.config_ip4()
2070 self.pg2.resolve_arp()
2072 self.pg0.add_stream(pkts)
2073 self.pg_enable_capture(self.pg_interfaces)
2076 rx0 = self.pg2._get_capture(NUM_PKTS)
2077 rx1 = self.pg3._get_capture(NUM_PKTS)
2078 self.assertNotEqual(0, len(rx0))
2079 self.assertNotEqual(0, len(rx1))
2080 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2081 "Expected all (%s) packets across both ECMP paths. "
2082 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2084 def test_mpls_v6_ebgp_pic(self):
2085 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
2087 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
2088 2) Check EMCP forwarding to these peers
2089 3) withdraw one eBGP path - expect LB across remaining eBGP
2093 # Lot's of VPN routes. We need more the 64 so VPP will build
2094 # the fast convergence indirection
2099 for ii in range(NUM_PKTS):
2100 dst = "3000::%d" % ii
2101 local_label = 1600 + ii
2102 vpn_routes.append(VppIpRoute(
2105 self.pg2.remote_ip6,
2108 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
2110 self.pg3.remote_ip6,
2113 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
2115 vpn_routes[ii].add_vpp_config()
2117 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
2119 vpn_bindings[ii].add_vpp_config()
2121 pkts.append(Ether(dst=self.pg0.local_mac,
2122 src=self.pg0.remote_mac) /
2123 MPLS(label=local_label, ttl=64) /
2124 IPv6(src=self.pg0.remote_ip6, dst=dst) /
2125 UDP(sport=1234, dport=1234) /
2127 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2129 self.pg0.add_stream(pkts)
2130 self.pg_enable_capture(self.pg_interfaces)
2133 rx0 = self.pg2._get_capture(NUM_PKTS)
2134 rx1 = self.pg3._get_capture(NUM_PKTS)
2135 self.assertNotEqual(0, len(rx0))
2136 self.assertNotEqual(0, len(rx1))
2137 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2138 "Expected all (%s) packets across both ECMP paths. "
2139 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2142 # use a test CLI command to stop the FIB walk process, this
2143 # will prevent the FIB converging the VPN routes and thus allow
2144 # us to probe the interim (post-fail, pre-converge) state
2146 self.vapi.ppcli("test fib-walk-process disable")
2149 # withdraw the connected prefix on the interface.
2150 # and shutdown the interface so the ND cache is flushed.
2152 self.pg2.unconfig_ip6()
2153 self.pg2.admin_down()
2156 # now all packets should be forwarded through the remaining peer
2158 self.pg0.add_stream(pkts)
2159 self.pg_enable_capture(self.pg_interfaces)
2162 rx0 = self.pg3.get_capture(NUM_PKTS)
2163 self.assertEqual(len(pkts), len(rx0),
2164 "Expected all (%s) packets across single path. "
2165 "rx0: %s." % (len(pkts), len(rx0)))
2168 # enable the FIB walk process to converge the FIB
2170 self.vapi.ppcli("test fib-walk-process enable")
2171 self.pg0.add_stream(pkts)
2172 self.pg_enable_capture(self.pg_interfaces)
2175 rx0 = self.pg3.get_capture(NUM_PKTS)
2176 self.assertEqual(len(pkts), len(rx0),
2177 "Expected all (%s) packets across single path. "
2178 "rx0: %s." % (len(pkts), len(rx0)))
2181 # put the connected routes back
2183 self.logger.info(self.vapi.cli("sh log"))
2185 self.pg2.config_ip6()
2186 self.pg2.resolve_ndp()
2188 self.pg0.add_stream(pkts)
2189 self.pg_enable_capture(self.pg_interfaces)
2192 rx0 = self.pg2._get_capture(NUM_PKTS)
2193 rx1 = self.pg3._get_capture(NUM_PKTS)
2194 self.assertNotEqual(0, len(rx0))
2195 self.assertNotEqual(0, len(rx1))
2196 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2197 "Expected all (%s) packets across both ECMP paths. "
2198 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2201 class TestMPLSL2(VppTestCase):
2205 def setUpClass(cls):
2206 super(TestMPLSL2, cls).setUpClass()
2209 def tearDownClass(cls):
2210 super(TestMPLSL2, cls).tearDownClass()
2213 super(TestMPLSL2, self).setUp()
2215 # create 2 pg interfaces
2216 self.create_pg_interfaces(range(2))
2218 # create the default MPLS table
2220 tbl = VppMplsTable(self, 0)
2221 tbl.add_vpp_config()
2222 self.tables.append(tbl)
2224 # use pg0 as the core facing interface, don't resolve ARP
2226 self.pg0.config_ip4()
2227 self.pg0.enable_mpls()
2229 # use the other 2 for customer facing L2 links
2230 for i in self.pg_interfaces[1:]:
2234 for i in self.pg_interfaces[1:]:
2237 self.pg0.disable_mpls()
2238 self.pg0.unconfig_ip4()
2239 self.pg0.admin_down()
2240 super(TestMPLSL2, self).tearDown()
2242 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2243 capture = verify_filter(capture, sent)
2245 self.assertEqual(len(capture), len(sent))
2247 for i in range(len(capture)):
2251 # the MPLS TTL is 255 since it enters a new tunnel
2252 verify_mpls_stack(self, rx, mpls_labels)
2255 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2257 self.assertEqual(rx_eth.src, tx_eth.src)
2258 self.assertEqual(rx_eth.dst, tx_eth.dst)
2260 def verify_arp_req(self, rx, smac, sip, dip):
2262 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2263 self.assertEqual(ether.src, smac)
2266 self.assertEqual(arp.hwtype, 1)
2267 self.assertEqual(arp.ptype, 0x800)
2268 self.assertEqual(arp.hwlen, 6)
2269 self.assertEqual(arp.plen, 4)
2270 self.assertEqual(arp.op, ARP.who_has)
2271 self.assertEqual(arp.hwsrc, smac)
2272 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2273 self.assertEqual(arp.psrc, sip)
2274 self.assertEqual(arp.pdst, dip)
2276 def test_vpws(self):
2277 """ Virtual Private Wire Service """
2280 # Create an MPLS tunnel that pushes 1 label
2281 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2282 # information is not in the packet, but we test it works anyway
2284 mpls_tun_1 = VppMPLSTunnelInterface(
2286 [VppRoutePath(self.pg0.remote_ip4,
2287 self.pg0.sw_if_index,
2288 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2290 mpls_tun_1.add_vpp_config()
2291 mpls_tun_1.admin_up()
2294 # Create a label entry to for 55 that does L2 input to the tunnel
2296 route_55_eos = VppMplsRoute(
2298 [VppRoutePath("0.0.0.0",
2299 mpls_tun_1.sw_if_index,
2300 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2301 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2302 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2303 route_55_eos.add_vpp_config()
2306 # Cross-connect the tunnel with one of the customers L2 interfaces
2308 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2309 mpls_tun_1.sw_if_index,
2311 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2312 self.pg1.sw_if_index,
2316 # inject a packet from the core
2318 pcore = (Ether(dst=self.pg0.local_mac,
2319 src=self.pg0.remote_mac) /
2320 MPLS(label=55, ttl=64) /
2321 Ether(dst="00:00:de:ad:ba:be",
2322 src="00:00:de:ad:be:ef") /
2323 IP(src="10.10.10.10", dst="11.11.11.11") /
2324 UDP(sport=1234, dport=1234) /
2327 tx0 = pcore * NUM_PKTS
2328 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2329 payload = pcore[MPLS].payload
2331 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2332 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2335 # Inject a packet from the customer/L2 side
2336 # there's no resolved ARP entry so the first packet we see should be
2339 tx1 = pcore[MPLS].payload
2340 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2342 self.verify_arp_req(rx1[0],
2345 self.pg0.remote_ip4)
2348 # resolve the ARP entries and send again
2350 self.pg0.resolve_arp()
2351 tx1 = pcore[MPLS].payload * NUM_PKTS
2352 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2354 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2356 def test_vpls(self):
2357 """ Virtual Private LAN Service """
2359 # we skipped this in the setup
2360 self.pg0.resolve_arp()
2363 # Create a L2 MPLS tunnels
2365 mpls_tun1 = VppMPLSTunnelInterface(
2367 [VppRoutePath(self.pg0.remote_ip4,
2368 self.pg0.sw_if_index,
2369 labels=[VppMplsLabel(42)])],
2371 mpls_tun1.add_vpp_config()
2372 mpls_tun1.admin_up()
2374 mpls_tun2 = VppMPLSTunnelInterface(
2376 [VppRoutePath(self.pg0.remote_ip4,
2377 self.pg0.sw_if_index,
2378 labels=[VppMplsLabel(43)])],
2380 mpls_tun2.add_vpp_config()
2381 mpls_tun2.admin_up()
2384 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2385 # the latter includes a Psuedo Wire Control Word
2387 route_55_eos = VppMplsRoute(
2389 [VppRoutePath("0.0.0.0",
2390 mpls_tun1.sw_if_index,
2391 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2392 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2393 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2395 route_56_eos = VppMplsRoute(
2397 [VppRoutePath("0.0.0.0",
2398 mpls_tun2.sw_if_index,
2399 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2400 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2401 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2402 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2405 route_56_eos.add_vpp_config()
2406 route_55_eos.add_vpp_config()
2408 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2411 # add to tunnel to the customers bridge-domain
2413 self.vapi.sw_interface_set_l2_bridge(
2414 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2415 self.vapi.sw_interface_set_l2_bridge(
2416 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2417 self.vapi.sw_interface_set_l2_bridge(
2418 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2421 # Packet from host on the customer interface to each host
2422 # reachable over the core, and vice-versa
2424 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2425 src="00:00:de:ad:be:ef") /
2426 IP(src="10.10.10.10", dst="11.11.11.11") /
2427 UDP(sport=1234, dport=1234) /
2429 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2430 src="00:00:de:ad:be:ef") /
2431 IP(src="10.10.10.10", dst="11.11.11.12") /
2432 UDP(sport=1234, dport=1234) /
2434 p_core1 = (Ether(dst=self.pg0.local_mac,
2435 src=self.pg0.remote_mac) /
2436 MPLS(label=55, ttl=64) /
2437 Ether(src="00:00:de:ad:ba:b1",
2438 dst="00:00:de:ad:be:ef") /
2439 IP(dst="10.10.10.10", src="11.11.11.11") /
2440 UDP(sport=1234, dport=1234) /
2442 p_core2 = (Ether(dst=self.pg0.local_mac,
2443 src=self.pg0.remote_mac) /
2444 MPLS(label=56, ttl=64) /
2445 Raw(b'\x01' * 4) / # PW CW
2446 Ether(src="00:00:de:ad:ba:b2",
2447 dst="00:00:de:ad:be:ef") /
2448 IP(dst="10.10.10.10", src="11.11.11.12") /
2449 UDP(sport=1234, dport=1234) /
2453 # The BD is learning, so send in one of each packet to learn
2456 # 2 packets due to BD flooding
2457 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2458 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2460 # we've learnt this so expect it be be forwarded not flooded
2461 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2462 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2463 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2465 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2466 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2467 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2470 # now a stream in each direction from each host
2472 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2473 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2476 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2477 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2480 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2481 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2484 # remove interfaces from customers bridge-domain
2486 self.vapi.sw_interface_set_l2_bridge(
2487 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2488 self.vapi.sw_interface_set_l2_bridge(
2489 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2490 self.vapi.sw_interface_set_l2_bridge(
2491 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2494 if __name__ == '__main__':
2495 unittest.main(testRunner=VppTestRunner)