6 from framework import VppTestCase, VppTestRunner
7 from vpp_ip import DpoProto, INVALID_INDEX
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
9 VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
10 MRouteItfFlags, MRouteEntryFlags, VppIpTable, VppMplsTable, \
11 VppMplsLabel, MplsLspMode, find_mpls_route, \
12 FibPathProto, FibPathType, FibPathFlags, VppMplsLabel, MplsLspMode
13 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
16 from scapy.packet import Raw
17 from scapy.layers.l2 import Ether
18 from scapy.layers.inet import IP, UDP, ICMP
19 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
20 from scapy.contrib.mpls import MPLS
25 def verify_filter(capture, sent):
26 if not len(capture) == len(sent):
27 # filter out any IPv6 RAs from the capture
34 def verify_mpls_stack(tst, rx, mpls_labels):
35 # the rx'd packet has the MPLS label popped
37 tst.assertEqual(eth.type, 0x8847)
41 for ii in range(len(mpls_labels)):
42 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
43 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
44 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
46 if ii == len(mpls_labels) - 1:
47 tst.assertEqual(rx_mpls.s, 1)
50 tst.assertEqual(rx_mpls.s, 0)
51 # pop the label to expose the next
52 rx_mpls = rx_mpls[MPLS].payload
55 class TestMPLS(VppTestCase):
56 """ MPLS Test Case """
60 super(TestMPLS, cls).setUpClass()
63 def tearDownClass(cls):
64 super(TestMPLS, cls).tearDownClass()
67 super(TestMPLS, self).setUp()
69 # create 2 pg interfaces
70 self.create_pg_interfaces(range(4))
72 # setup both interfaces
73 # assign them different tables.
77 tbl = VppMplsTable(self, 0)
79 self.tables.append(tbl)
81 for i in self.pg_interfaces:
85 tbl = VppIpTable(self, table_id)
87 self.tables.append(tbl)
88 tbl = VppIpTable(self, table_id, is_ip6=1)
90 self.tables.append(tbl)
92 i.set_table_ip4(table_id)
93 i.set_table_ip6(table_id)
102 for i in self.pg_interfaces:
110 super(TestMPLS, self).tearDown()
112 # the default of 64 matches the IP packet TTL default
113 def create_stream_labelled_ip4(
123 self.reset_packet_infos()
125 for i in range(0, n):
126 info = self.create_packet_info(src_if, src_if)
127 payload = self.info_to_payload(info)
128 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
130 for ii in range(len(mpls_labels)):
131 p = p / MPLS(label=mpls_labels[ii].value,
132 ttl=mpls_labels[ii].ttl,
133 cos=mpls_labels[ii].exp)
136 p = (p / IP(src=src_if.local_ip4,
137 dst=src_if.remote_ip4,
139 UDP(sport=1234, dport=1234) /
142 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
143 UDP(sport=1234, dport=1234) /
146 p = (p / IP(src=ip_itf.remote_ip4,
147 dst=ip_itf.local_ip4,
152 p[IP].chksum = chksum
157 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
158 self.reset_packet_infos()
160 for i in range(0, 257):
161 info = self.create_packet_info(src_if, src_if)
162 payload = self.info_to_payload(info)
163 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
164 IP(src=src_if.remote_ip4, dst=dst_ip,
165 ttl=ip_ttl, tos=ip_dscp) /
166 UDP(sport=1234, dport=1234) /
172 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
173 self.reset_packet_infos()
175 for i in range(0, 257):
176 info = self.create_packet_info(src_if, src_if)
177 payload = self.info_to_payload(info)
178 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
179 IPv6(src=src_if.remote_ip6, dst=dst_ip,
180 hlim=ip_ttl, tc=ip_dscp) /
181 UDP(sport=1234, dport=1234) /
187 def create_stream_labelled_ip6(self, src_if, mpls_labels,
188 hlim=64, dst_ip=None):
190 dst_ip = src_if.remote_ip6
191 self.reset_packet_infos()
193 for i in range(0, 257):
194 info = self.create_packet_info(src_if, src_if)
195 payload = self.info_to_payload(info)
196 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
197 for l in mpls_labels:
198 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
200 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
201 UDP(sport=1234, dport=1234) /
207 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
208 ip_ttl=None, ip_dscp=0):
210 capture = verify_filter(capture, sent)
212 self.assertEqual(len(capture), len(sent))
214 for i in range(len(capture)):
218 # the rx'd packet has the MPLS label popped
220 self.assertEqual(eth.type, 0x800)
226 self.assertEqual(rx_ip.src, tx_ip.src)
227 self.assertEqual(rx_ip.dst, tx_ip.dst)
228 self.assertEqual(rx_ip.tos, ip_dscp)
230 # IP processing post pop has decremented the TTL
231 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
233 self.assertEqual(rx_ip.ttl, ip_ttl)
235 self.assertEqual(rx_ip.src, tx_ip.dst)
236 self.assertEqual(rx_ip.dst, tx_ip.src)
241 def verify_capture_labelled_ip4(self, src_if, capture, sent,
242 mpls_labels, ip_ttl=None):
244 capture = verify_filter(capture, sent)
246 self.assertEqual(len(capture), len(sent))
248 for i in range(len(capture)):
254 verify_mpls_stack(self, rx, mpls_labels)
256 self.assertEqual(rx_ip.src, tx_ip.src)
257 self.assertEqual(rx_ip.dst, tx_ip.dst)
259 # IP processing post pop has decremented the TTL
260 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
262 self.assertEqual(rx_ip.ttl, ip_ttl)
267 def verify_capture_labelled_ip6(self, src_if, capture, sent,
268 mpls_labels, ip_ttl=None):
270 capture = verify_filter(capture, sent)
272 self.assertEqual(len(capture), len(sent))
274 for i in range(len(capture)):
280 verify_mpls_stack(self, rx, mpls_labels)
282 self.assertEqual(rx_ip.src, tx_ip.src)
283 self.assertEqual(rx_ip.dst, tx_ip.dst)
285 # IP processing post pop has decremented the TTL
286 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
288 self.assertEqual(rx_ip.hlim, ip_ttl)
293 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
295 capture = verify_filter(capture, sent)
297 self.assertEqual(len(capture), len(sent))
299 for i in range(len(capture)):
305 verify_mpls_stack(self, rx, mpls_labels)
307 self.assertEqual(rx_ip.src, tx_ip.src)
308 self.assertEqual(rx_ip.dst, tx_ip.dst)
309 # IP processing post pop has decremented the TTL
310 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
315 def verify_capture_labelled(self, src_if, capture, sent,
318 capture = verify_filter(capture, sent)
320 self.assertEqual(len(capture), len(sent))
322 for i in range(len(capture)):
324 verify_mpls_stack(self, rx, mpls_labels)
328 def verify_capture_ip6(self, src_if, capture, sent,
329 ip_hlim=None, ip_dscp=0):
331 self.assertEqual(len(capture), len(sent))
333 for i in range(len(capture)):
337 # the rx'd packet has the MPLS label popped
339 self.assertEqual(eth.type, 0x86DD)
344 self.assertEqual(rx_ip.src, tx_ip.src)
345 self.assertEqual(rx_ip.dst, tx_ip.dst)
346 self.assertEqual(rx_ip.tc, ip_dscp)
347 # IP processing post pop has decremented the TTL
349 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
351 self.assertEqual(rx_ip.hlim, ip_hlim)
356 def verify_capture_ip6_icmp(self, src_if, capture, sent):
358 self.assertEqual(len(capture), len(sent))
360 for i in range(len(capture)):
364 # the rx'd packet has the MPLS label popped
366 self.assertEqual(eth.type, 0x86DD)
371 self.assertEqual(rx_ip.dst, tx_ip.src)
372 # ICMP sourced from the interface's address
373 self.assertEqual(rx_ip.src, src_if.local_ip6)
374 # hop-limit reset to 255 for IMCP packet
375 self.assertEqual(rx_ip.hlim, 255)
377 icmp = rx[ICMPv6TimeExceeded]
382 def verify_capture_fragmented_labelled_ip4(self, src_if, capture, sent,
383 mpls_labels, ip_ttl=None):
385 capture = verify_filter(capture, sent)
387 for i in range(len(capture)):
393 verify_mpls_stack(self, rx, mpls_labels)
395 self.assertEqual(rx_ip.src, tx_ip.src)
396 self.assertEqual(rx_ip.dst, tx_ip.dst)
398 # IP processing post pop has decremented the TTL
399 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
401 self.assertEqual(rx_ip.ttl, ip_ttl)
407 """ MPLS label swap tests """
410 # A simple MPLS xconnect - eos label in label out
412 route_32_eos = VppMplsRoute(self, 32, 1,
413 [VppRoutePath(self.pg0.remote_ip4,
414 self.pg0.sw_if_index,
415 labels=[VppMplsLabel(33)])])
416 route_32_eos.add_vpp_config()
419 find_mpls_route(self, 0, 32, 1,
420 [VppRoutePath(self.pg0.remote_ip4,
421 self.pg0.sw_if_index,
422 labels=[VppMplsLabel(33)])]))
425 # a stream that matches the route for 10.0.0.1
426 # PG0 is in the default table
428 tx = self.create_stream_labelled_ip4(self.pg0,
429 [VppMplsLabel(32, ttl=32, exp=1)])
430 rx = self.send_and_expect(self.pg0, tx, self.pg0)
431 self.verify_capture_labelled(self.pg0, rx, tx,
432 [VppMplsLabel(33, ttl=31, exp=1)])
434 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
437 # A simple MPLS xconnect - non-eos label in label out
439 route_32_neos = VppMplsRoute(self, 32, 0,
440 [VppRoutePath(self.pg0.remote_ip4,
441 self.pg0.sw_if_index,
442 labels=[VppMplsLabel(33)])])
443 route_32_neos.add_vpp_config()
446 # a stream that matches the route for 10.0.0.1
447 # PG0 is in the default table
449 tx = self.create_stream_labelled_ip4(self.pg0,
450 [VppMplsLabel(32, ttl=21, exp=7),
452 rx = self.send_and_expect(self.pg0, tx, self.pg0)
453 self.verify_capture_labelled(self.pg0, rx, tx,
454 [VppMplsLabel(33, ttl=20, exp=7),
456 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
459 # A simple MPLS xconnect - non-eos label in label out, uniform mode
461 route_42_neos = VppMplsRoute(
463 [VppRoutePath(self.pg0.remote_ip4,
464 self.pg0.sw_if_index,
465 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
466 route_42_neos.add_vpp_config()
468 tx = self.create_stream_labelled_ip4(self.pg0,
469 [VppMplsLabel(42, ttl=21, exp=7),
471 rx = self.send_and_expect(self.pg0, tx, self.pg0)
472 self.verify_capture_labelled(self.pg0, rx, tx,
473 [VppMplsLabel(43, ttl=20, exp=7),
477 # An MPLS xconnect - EOS label in IP out
479 route_33_eos = VppMplsRoute(self, 33, 1,
480 [VppRoutePath(self.pg0.remote_ip4,
481 self.pg0.sw_if_index,
483 route_33_eos.add_vpp_config()
485 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
486 rx = self.send_and_expect(self.pg0, tx, self.pg0)
487 self.verify_capture_ip4(self.pg0, rx, tx)
490 # disposed packets have an invalid IPv4 checksum
492 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
493 dst_ip=self.pg0.remote_ip4,
496 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
499 # An MPLS xconnect - EOS label in IP out, uniform mode
501 route_3333_eos = VppMplsRoute(
503 [VppRoutePath(self.pg0.remote_ip4,
504 self.pg0.sw_if_index,
505 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
506 route_3333_eos.add_vpp_config()
508 tx = self.create_stream_labelled_ip4(
510 [VppMplsLabel(3333, ttl=55, exp=3)])
511 rx = self.send_and_expect(self.pg0, tx, self.pg0)
512 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
513 tx = self.create_stream_labelled_ip4(
515 [VppMplsLabel(3333, ttl=66, exp=4)])
516 rx = self.send_and_expect(self.pg0, tx, self.pg0)
517 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
520 # An MPLS xconnect - EOS label in IPv6 out
522 route_333_eos = VppMplsRoute(
524 [VppRoutePath(self.pg0.remote_ip6,
525 self.pg0.sw_if_index,
527 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
528 route_333_eos.add_vpp_config()
530 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
531 rx = self.send_and_expect(self.pg0, tx, self.pg0)
532 self.verify_capture_ip6(self.pg0, rx, tx)
535 # disposed packets have an TTL expired
537 tx = self.create_stream_labelled_ip6(self.pg0,
538 [VppMplsLabel(333, ttl=64)],
539 dst_ip=self.pg1.remote_ip6,
541 rx = self.send_and_expect(self.pg0, tx, self.pg0)
542 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
545 # An MPLS xconnect - EOS label in IPv6 out w imp-null
547 route_334_eos = VppMplsRoute(
549 [VppRoutePath(self.pg0.remote_ip6,
550 self.pg0.sw_if_index,
551 labels=[VppMplsLabel(3)])],
552 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
553 route_334_eos.add_vpp_config()
555 tx = self.create_stream_labelled_ip6(self.pg0,
556 [VppMplsLabel(334, ttl=64)])
557 rx = self.send_and_expect(self.pg0, tx, self.pg0)
558 self.verify_capture_ip6(self.pg0, rx, tx)
561 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
563 route_335_eos = VppMplsRoute(
565 [VppRoutePath(self.pg0.remote_ip6,
566 self.pg0.sw_if_index,
567 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
568 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
569 route_335_eos.add_vpp_config()
571 tx = self.create_stream_labelled_ip6(
573 [VppMplsLabel(335, ttl=27, exp=4)])
574 rx = self.send_and_expect(self.pg0, tx, self.pg0)
575 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
578 # disposed packets have an TTL expired
580 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
581 dst_ip=self.pg1.remote_ip6,
583 rx = self.send_and_expect(self.pg0, tx, self.pg0)
584 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
587 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
588 # so this traffic should be dropped.
590 route_33_neos = VppMplsRoute(self, 33, 0,
591 [VppRoutePath(self.pg0.remote_ip4,
592 self.pg0.sw_if_index,
594 route_33_neos.add_vpp_config()
596 tx = self.create_stream_labelled_ip4(self.pg0,
599 self.send_and_assert_no_replies(
601 "MPLS non-EOS packets popped and forwarded")
604 # A recursive EOS x-connect, which resolves through another x-connect
607 route_34_eos = VppMplsRoute(self, 34, 1,
608 [VppRoutePath("0.0.0.0",
611 labels=[VppMplsLabel(44),
613 route_34_eos.add_vpp_config()
614 self.logger.info(self.vapi.cli("sh mpls fib 34"))
616 tx = self.create_stream_labelled_ip4(self.pg0,
617 [VppMplsLabel(34, ttl=3)])
618 rx = self.send_and_expect(self.pg0, tx, self.pg0)
619 self.verify_capture_labelled(self.pg0, rx, tx,
622 VppMplsLabel(45, ttl=2)])
624 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
625 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
628 # A recursive EOS x-connect, which resolves through another x-connect
631 route_35_eos = VppMplsRoute(
633 [VppRoutePath("0.0.0.0",
636 labels=[VppMplsLabel(44)])])
637 route_35_eos.add_vpp_config()
639 tx = self.create_stream_labelled_ip4(self.pg0,
640 [VppMplsLabel(35, ttl=3)])
641 rx = self.send_and_expect(self.pg0, tx, self.pg0)
642 self.verify_capture_labelled(self.pg0, rx, tx,
643 [VppMplsLabel(43, ttl=2),
644 VppMplsLabel(44, ttl=2)])
647 # A recursive non-EOS x-connect, which resolves through another
650 route_34_neos = VppMplsRoute(self, 34, 0,
651 [VppRoutePath("0.0.0.0",
654 labels=[VppMplsLabel(44),
656 route_34_neos.add_vpp_config()
658 tx = self.create_stream_labelled_ip4(self.pg0,
659 [VppMplsLabel(34, ttl=45),
661 rx = self.send_and_expect(self.pg0, tx, self.pg0)
662 # it's the 2nd (counting from 0) label in the stack that is swapped
663 self.verify_capture_labelled(self.pg0, rx, tx,
666 VppMplsLabel(46, ttl=44),
670 # an recursive IP route that resolves through the recursive non-eos
673 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
674 [VppRoutePath("0.0.0.0",
677 labels=[VppMplsLabel(55)])])
678 ip_10_0_0_1.add_vpp_config()
680 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
681 rx = self.send_and_expect(self.pg0, tx, self.pg0)
682 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
687 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
689 ip_10_0_0_1.remove_vpp_config()
690 route_34_neos.remove_vpp_config()
691 route_34_eos.remove_vpp_config()
692 route_33_neos.remove_vpp_config()
693 route_33_eos.remove_vpp_config()
694 route_32_neos.remove_vpp_config()
695 route_32_eos.remove_vpp_config()
698 """ MPLS Local Label Binding test """
701 # Add a non-recursive route with a single out label
703 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
704 [VppRoutePath(self.pg0.remote_ip4,
705 self.pg0.sw_if_index,
706 labels=[VppMplsLabel(45)])])
707 route_10_0_0_1.add_vpp_config()
709 # bind a local label to the route
710 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
711 binding.add_vpp_config()
714 tx = self.create_stream_labelled_ip4(self.pg0,
717 rx = self.send_and_expect(self.pg0, tx, self.pg0)
718 self.verify_capture_labelled(self.pg0, rx, tx,
719 [VppMplsLabel(45, ttl=63),
723 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
724 rx = self.send_and_expect(self.pg0, tx, self.pg0)
725 self.verify_capture_labelled(self.pg0, rx, tx,
726 [VppMplsLabel(45, ttl=63)])
729 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
730 rx = self.send_and_expect(self.pg0, tx, self.pg0)
731 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
736 binding.remove_vpp_config()
737 route_10_0_0_1.remove_vpp_config()
739 def test_imposition(self):
740 """ MPLS label imposition test """
743 # Add a non-recursive route with a single out label
745 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
746 [VppRoutePath(self.pg0.remote_ip4,
747 self.pg0.sw_if_index,
748 labels=[VppMplsLabel(32)])])
749 route_10_0_0_1.add_vpp_config()
752 # a stream that matches the route for 10.0.0.1
753 # PG0 is in the default table
755 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
756 rx = self.send_and_expect(self.pg0, tx, self.pg0)
757 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
760 # Add a non-recursive route with a 3 out labels
762 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
763 [VppRoutePath(self.pg0.remote_ip4,
764 self.pg0.sw_if_index,
765 labels=[VppMplsLabel(32),
768 route_10_0_0_2.add_vpp_config()
770 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
771 ip_ttl=44, ip_dscp=0xff)
772 rx = self.send_and_expect(self.pg0, tx, self.pg0)
773 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
780 # Add a non-recursive route with a single out label in uniform mode
782 route_10_0_0_3 = VppIpRoute(
783 self, "10.0.0.3", 32,
784 [VppRoutePath(self.pg0.remote_ip4,
785 self.pg0.sw_if_index,
786 labels=[VppMplsLabel(32,
787 mode=MplsLspMode.UNIFORM)])])
788 route_10_0_0_3.add_vpp_config()
790 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
791 ip_ttl=54, ip_dscp=0xbe)
792 rx = self.send_and_expect(self.pg0, tx, self.pg0)
793 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
794 [VppMplsLabel(32, ttl=53, exp=5)])
797 # Add a IPv6 non-recursive route with a single out label in
800 route_2001_3 = VppIpRoute(
801 self, "2001::3", 128,
802 [VppRoutePath(self.pg0.remote_ip6,
803 self.pg0.sw_if_index,
804 labels=[VppMplsLabel(32,
805 mode=MplsLspMode.UNIFORM)])])
806 route_2001_3.add_vpp_config()
808 tx = self.create_stream_ip6(self.pg0, "2001::3",
809 ip_ttl=54, ip_dscp=0xbe)
810 rx = self.send_and_expect(self.pg0, tx, self.pg0)
811 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
812 [VppMplsLabel(32, ttl=53, exp=5)])
815 # add a recursive path, with output label, via the 1 label route
817 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
818 [VppRoutePath("10.0.0.1",
820 labels=[VppMplsLabel(44)])])
821 route_11_0_0_1.add_vpp_config()
824 # a stream that matches the route for 11.0.0.1, should pick up
825 # the label stack for 11.0.0.1 and 10.0.0.1
827 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
828 rx = self.send_and_expect(self.pg0, tx, self.pg0)
829 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
833 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
836 # add a recursive path, with 2 labels, via the 3 label route
838 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
839 [VppRoutePath("10.0.0.2",
841 labels=[VppMplsLabel(44),
843 route_11_0_0_2.add_vpp_config()
846 # a stream that matches the route for 11.0.0.1, should pick up
847 # the label stack for 11.0.0.1 and 10.0.0.1
849 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
850 rx = self.send_and_expect(self.pg0, tx, self.pg0)
851 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
858 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
860 rx = self.send_and_expect(self.pg0, tx, self.pg0)
861 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
868 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
873 route_11_0_0_2.remove_vpp_config()
874 route_11_0_0_1.remove_vpp_config()
875 route_10_0_0_2.remove_vpp_config()
876 route_10_0_0_1.remove_vpp_config()
878 def test_imposition_fragmentation(self):
879 """ MPLS label imposition fragmentation test """
882 # Add a ipv4 non-recursive route with a single out label
884 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
885 [VppRoutePath(self.pg0.remote_ip4,
886 self.pg0.sw_if_index,
887 labels=[VppMplsLabel(32)])])
888 route_10_0_0_1.add_vpp_config()
891 # a stream that matches the route for 10.0.0.1
892 # PG0 is in the default table
894 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
895 for i in range(0, 257):
896 self.extend_packet(tx[i], 10000)
899 # 5 fragments per packet (257*5=1285)
901 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
902 self.verify_capture_fragmented_labelled_ip4(self.pg0, rx, tx,
908 route_10_0_0_1.remove_vpp_config()
910 def test_tunnel_pipe(self):
911 """ MPLS Tunnel Tests - Pipe """
914 # Create a tunnel with a single out label
916 mpls_tun = VppMPLSTunnelInterface(
918 [VppRoutePath(self.pg0.remote_ip4,
919 self.pg0.sw_if_index,
920 labels=[VppMplsLabel(44),
922 mpls_tun.add_vpp_config()
926 # add an unlabelled route through the new tunnel
928 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
929 [VppRoutePath("0.0.0.0",
930 mpls_tun._sw_if_index)])
931 route_10_0_0_3.add_vpp_config()
933 self.vapi.cli("clear trace")
934 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
935 self.pg0.add_stream(tx)
937 self.pg_enable_capture(self.pg_interfaces)
940 rx = self.pg0.get_capture()
941 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
946 # add a labelled route through the new tunnel
948 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
949 [VppRoutePath("0.0.0.0",
950 mpls_tun._sw_if_index,
952 route_10_0_0_4.add_vpp_config()
954 self.vapi.cli("clear trace")
955 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
956 self.pg0.add_stream(tx)
958 self.pg_enable_capture(self.pg_interfaces)
961 rx = self.pg0.get_capture()
962 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
965 VppMplsLabel(33, ttl=255)])
967 def test_tunnel_uniform(self):
968 """ MPLS Tunnel Tests - Uniform """
971 # Create a tunnel with a single out label
972 # The label stack is specified here from outer to inner
974 mpls_tun = VppMPLSTunnelInterface(
976 [VppRoutePath(self.pg0.remote_ip4,
977 self.pg0.sw_if_index,
978 labels=[VppMplsLabel(44, ttl=32),
979 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
980 mpls_tun.add_vpp_config()
984 # add an unlabelled route through the new tunnel
986 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
987 [VppRoutePath("0.0.0.0",
988 mpls_tun._sw_if_index)])
989 route_10_0_0_3.add_vpp_config()
991 self.vapi.cli("clear trace")
992 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
993 self.pg0.add_stream(tx)
995 self.pg_enable_capture(self.pg_interfaces)
998 rx = self.pg0.get_capture()
999 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1000 [VppMplsLabel(44, ttl=32),
1001 VppMplsLabel(46, ttl=23)])
1004 # add a labelled route through the new tunnel
1006 route_10_0_0_4 = VppIpRoute(
1007 self, "10.0.0.4", 32,
1008 [VppRoutePath("0.0.0.0",
1009 mpls_tun._sw_if_index,
1010 labels=[VppMplsLabel(33, ttl=47)])])
1011 route_10_0_0_4.add_vpp_config()
1013 self.vapi.cli("clear trace")
1014 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
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,
1022 [VppMplsLabel(44, ttl=32),
1023 VppMplsLabel(46, ttl=47),
1024 VppMplsLabel(33, ttl=47)])
1026 def test_mpls_tunnel_many(self):
1027 """ MPLS Multiple Tunnels """
1029 for ii in range(10):
1030 mpls_tun = VppMPLSTunnelInterface(
1032 [VppRoutePath(self.pg0.remote_ip4,
1033 self.pg0.sw_if_index,
1034 labels=[VppMplsLabel(44, ttl=32),
1035 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1036 mpls_tun.add_vpp_config()
1039 def test_v4_exp_null(self):
1040 """ MPLS V4 Explicit NULL test """
1043 # The first test case has an MPLS TTL of 0
1044 # all packet should be dropped
1046 tx = self.create_stream_labelled_ip4(self.pg0,
1047 [VppMplsLabel(0, ttl=0)])
1048 self.send_and_assert_no_replies(self.pg0, tx,
1049 "MPLS TTL=0 packets forwarded")
1052 # a stream with a non-zero MPLS TTL
1053 # PG0 is in the default table
1055 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1056 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1057 self.verify_capture_ip4(self.pg0, rx, tx)
1060 # a stream with a non-zero MPLS TTL
1062 # we are ensuring the post-pop lookup occurs in the VRF table
1064 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1065 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1066 self.verify_capture_ip4(self.pg1, rx, tx)
1068 def test_v6_exp_null(self):
1069 """ MPLS V6 Explicit NULL test """
1072 # a stream with a non-zero MPLS TTL
1073 # PG0 is in the default table
1075 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1076 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1077 self.verify_capture_ip6(self.pg0, rx, tx)
1080 # a stream with a non-zero MPLS TTL
1082 # we are ensuring the post-pop lookup occurs in the VRF table
1084 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1085 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1086 self.verify_capture_ip6(self.pg0, rx, tx)
1088 def test_deag(self):
1092 # A de-agg route - next-hop lookup in default table
1094 route_34_eos = VppMplsRoute(self, 34, 1,
1095 [VppRoutePath("0.0.0.0",
1098 route_34_eos.add_vpp_config()
1101 # ping an interface in the default table
1102 # PG0 is in the default table
1104 tx = self.create_stream_labelled_ip4(self.pg0,
1108 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1109 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1112 # A de-agg route - next-hop lookup in non-default table
1114 route_35_eos = VppMplsRoute(self, 35, 1,
1115 [VppRoutePath("0.0.0.0",
1118 route_35_eos.add_vpp_config()
1121 # ping an interface in the non-default table
1122 # PG0 is in the default table. packet arrive labelled in the
1123 # default table and egress unlabelled in the non-default
1125 tx = self.create_stream_labelled_ip4(
1126 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1127 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1128 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1133 route_36_neos = VppMplsRoute(self, 36, 0,
1134 [VppRoutePath("0.0.0.0",
1136 route_36_neos.add_vpp_config()
1138 tx = self.create_stream_labelled_ip4(self.pg0,
1141 ping=1, ip_itf=self.pg1)
1142 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1143 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1145 route_36_neos.remove_vpp_config()
1146 route_35_eos.remove_vpp_config()
1147 route_34_eos.remove_vpp_config()
1149 def test_interface_rx(self):
1150 """ MPLS Interface Receive """
1153 # Add a non-recursive route that will forward the traffic
1156 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1158 paths=[VppRoutePath(self.pg1.remote_ip4,
1159 self.pg1.sw_if_index)])
1160 route_10_0_0_1.add_vpp_config()
1163 # An interface receive label that maps traffic to RX on interface
1165 # by injecting the packet in on pg0, which is in table 0
1166 # doing an interface-rx on pg1 and matching a route in table 1
1167 # if the packet egresses, then we must have swapped to pg1
1168 # so as to have matched the route in table 1
1170 route_34_eos = VppMplsRoute(
1172 [VppRoutePath("0.0.0.0",
1173 self.pg1.sw_if_index,
1174 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1175 route_34_eos.add_vpp_config()
1178 # ping an interface in the default table
1179 # PG0 is in the default table
1181 tx = self.create_stream_labelled_ip4(self.pg0,
1184 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1185 self.verify_capture_ip4(self.pg1, rx, tx)
1187 def test_mcast_mid_point(self):
1188 """ MPLS Multicast Mid Point """
1191 # Add a non-recursive route that will forward the traffic
1194 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1196 paths=[VppRoutePath(self.pg1.remote_ip4,
1197 self.pg1.sw_if_index)])
1198 route_10_0_0_1.add_vpp_config()
1201 # Add a mcast entry that replicate to pg2 and pg3
1202 # and replicate to a interface-rx (like a bud node would)
1204 route_3400_eos = VppMplsRoute(
1206 [VppRoutePath(self.pg2.remote_ip4,
1207 self.pg2.sw_if_index,
1208 labels=[VppMplsLabel(3401)]),
1209 VppRoutePath(self.pg3.remote_ip4,
1210 self.pg3.sw_if_index,
1211 labels=[VppMplsLabel(3402)]),
1212 VppRoutePath("0.0.0.0",
1213 self.pg1.sw_if_index,
1214 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1216 route_3400_eos.add_vpp_config()
1219 # ping an interface in the default table
1220 # PG0 is in the default table
1222 self.vapi.cli("clear trace")
1223 tx = self.create_stream_labelled_ip4(self.pg0,
1224 [VppMplsLabel(3400, ttl=64)],
1227 self.pg0.add_stream(tx)
1229 self.pg_enable_capture(self.pg_interfaces)
1232 rx = self.pg1.get_capture(257)
1233 self.verify_capture_ip4(self.pg1, rx, tx)
1235 rx = self.pg2.get_capture(257)
1236 self.verify_capture_labelled(self.pg2, rx, tx,
1237 [VppMplsLabel(3401, ttl=63)])
1238 rx = self.pg3.get_capture(257)
1239 self.verify_capture_labelled(self.pg3, rx, tx,
1240 [VppMplsLabel(3402, ttl=63)])
1242 def test_mcast_head(self):
1243 """ MPLS Multicast Head-end """
1246 # Create a multicast tunnel with two replications
1248 mpls_tun = VppMPLSTunnelInterface(
1250 [VppRoutePath(self.pg2.remote_ip4,
1251 self.pg2.sw_if_index,
1252 labels=[VppMplsLabel(42)]),
1253 VppRoutePath(self.pg3.remote_ip4,
1254 self.pg3.sw_if_index,
1255 labels=[VppMplsLabel(43)])],
1257 mpls_tun.add_vpp_config()
1261 # add an unlabelled route through the new tunnel
1263 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1264 [VppRoutePath("0.0.0.0",
1265 mpls_tun._sw_if_index)])
1266 route_10_0_0_3.add_vpp_config()
1268 self.vapi.cli("clear trace")
1269 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1270 self.pg0.add_stream(tx)
1272 self.pg_enable_capture(self.pg_interfaces)
1275 rx = self.pg2.get_capture(257)
1276 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1277 rx = self.pg3.get_capture(257)
1278 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1281 # An an IP multicast route via the tunnel
1283 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1285 route_232_1_1_1 = VppIpMRoute(
1289 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1290 [VppMRoutePath(self.pg0.sw_if_index,
1291 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1292 VppMRoutePath(mpls_tun._sw_if_index,
1293 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1294 route_232_1_1_1.add_vpp_config()
1295 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1297 self.vapi.cli("clear trace")
1298 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1299 self.pg0.add_stream(tx)
1301 self.pg_enable_capture(self.pg_interfaces)
1304 rx = self.pg2.get_capture(257)
1305 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1306 rx = self.pg3.get_capture(257)
1307 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1309 def test_mcast_ip4_tail(self):
1310 """ MPLS IPv4 Multicast Tail """
1313 # Add a multicast route that will forward the traffic
1316 route_232_1_1_1 = VppIpMRoute(
1320 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1322 paths=[VppMRoutePath(self.pg1.sw_if_index,
1323 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1324 route_232_1_1_1.add_vpp_config()
1327 # An interface receive label that maps traffic to RX on interface
1329 # by injecting the packet in on pg0, which is in table 0
1330 # doing an rpf-id and matching a route in table 1
1331 # if the packet egresses, then we must have matched the route in
1334 route_34_eos = VppMplsRoute(
1336 [VppRoutePath("0.0.0.0",
1341 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1343 route_34_eos.add_vpp_config()
1346 # Drop due to interface lookup miss
1348 self.vapi.cli("clear trace")
1349 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1350 dst_ip="232.1.1.1", n=1)
1351 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1354 # set the RPF-ID of the entry to match the input packet's
1356 route_232_1_1_1.update_rpf_id(55)
1357 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1359 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1361 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1362 self.verify_capture_ip4(self.pg1, rx, tx)
1365 # disposed packets have an invalid IPv4 checksum
1367 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1368 dst_ip="232.1.1.1", n=65,
1370 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1373 # set the RPF-ID of the entry to not match the input packet's
1375 route_232_1_1_1.update_rpf_id(56)
1376 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1378 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1380 def test_mcast_ip6_tail(self):
1381 """ MPLS IPv6 Multicast Tail """
1384 # Add a multicast route that will forward the traffic
1387 route_ff = VppIpMRoute(
1391 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1393 paths=[VppMRoutePath(self.pg1.sw_if_index,
1394 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
1395 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1396 route_ff.add_vpp_config()
1399 # An interface receive label that maps traffic to RX on interface
1401 # by injecting the packet in on pg0, which is in table 0
1402 # doing an rpf-id and matching a route in table 1
1403 # if the packet egresses, then we must have matched the route in
1406 route_34_eos = VppMplsRoute(
1413 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1415 route_34_eos.add_vpp_config()
1418 # Drop due to interface lookup miss
1420 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1422 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1425 # set the RPF-ID of the entry to match the input packet's
1427 route_ff.update_rpf_id(55)
1429 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1431 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1432 self.verify_capture_ip6(self.pg1, rx, tx)
1435 # disposed packets have hop-limit = 1
1437 tx = self.create_stream_labelled_ip6(self.pg0,
1441 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1442 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1445 # set the RPF-ID of the entry to not match the input packet's
1447 route_ff.update_rpf_id(56)
1448 tx = self.create_stream_labelled_ip6(self.pg0,
1451 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1457 # Add a non-recursive route with a single out label
1459 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1460 [VppRoutePath(self.pg0.remote_ip4,
1461 self.pg0.sw_if_index,
1462 labels=[VppMplsLabel(45)])])
1463 route_10_0_0_1.add_vpp_config()
1465 # bind a local label to the route
1466 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1467 binding.add_vpp_config()
1470 # a labelled v6 route that resolves through the v4
1472 route_2001_3 = VppIpRoute(
1473 self, "2001::3", 128,
1474 [VppRoutePath("10.0.0.1",
1476 labels=[VppMplsLabel(32)])])
1477 route_2001_3.add_vpp_config()
1479 tx = self.create_stream_ip6(self.pg0, "2001::3")
1480 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1482 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1487 # and a v4 recursive via the v6
1489 route_20_3 = VppIpRoute(
1490 self, "20.0.0.3", 32,
1491 [VppRoutePath("2001::3",
1493 labels=[VppMplsLabel(99)])])
1494 route_20_3.add_vpp_config()
1496 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1497 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1499 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1505 class TestMPLSDisabled(VppTestCase):
1506 """ MPLS disabled """
1509 def setUpClass(cls):
1510 super(TestMPLSDisabled, cls).setUpClass()
1513 def tearDownClass(cls):
1514 super(TestMPLSDisabled, cls).tearDownClass()
1517 super(TestMPLSDisabled, self).setUp()
1519 # create 2 pg interfaces
1520 self.create_pg_interfaces(range(2))
1522 self.tbl = VppMplsTable(self, 0)
1523 self.tbl.add_vpp_config()
1525 # PG0 is MPLS enabled
1527 self.pg0.config_ip4()
1528 self.pg0.resolve_arp()
1529 self.pg0.enable_mpls()
1531 # PG 1 is not MPLS enabled
1535 for i in self.pg_interfaces:
1539 self.pg0.disable_mpls()
1540 super(TestMPLSDisabled, self).tearDown()
1542 def test_mpls_disabled(self):
1543 """ MPLS Disabled """
1545 tx = (Ether(src=self.pg1.remote_mac,
1546 dst=self.pg1.local_mac) /
1547 MPLS(label=32, ttl=64) /
1548 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1549 UDP(sport=1234, dport=1234) /
1553 # A simple MPLS xconnect - eos label in label out
1555 route_32_eos = VppMplsRoute(self, 32, 1,
1556 [VppRoutePath(self.pg0.remote_ip4,
1557 self.pg0.sw_if_index,
1559 route_32_eos.add_vpp_config()
1562 # PG1 does not forward IP traffic
1564 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1569 self.pg1.enable_mpls()
1572 # Now we get packets through
1574 self.pg1.add_stream(tx)
1575 self.pg_enable_capture(self.pg_interfaces)
1578 rx = self.pg0.get_capture(1)
1583 self.pg1.disable_mpls()
1586 # PG1 does not forward IP traffic
1588 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1589 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1592 class TestMPLSPIC(VppTestCase):
1593 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1596 def setUpClass(cls):
1597 super(TestMPLSPIC, cls).setUpClass()
1600 def tearDownClass(cls):
1601 super(TestMPLSPIC, cls).tearDownClass()
1604 super(TestMPLSPIC, self).setUp()
1606 # create 2 pg interfaces
1607 self.create_pg_interfaces(range(4))
1609 mpls_tbl = VppMplsTable(self, 0)
1610 mpls_tbl.add_vpp_config()
1611 tbl4 = VppIpTable(self, 1)
1612 tbl4.add_vpp_config()
1613 tbl6 = VppIpTable(self, 1, is_ip6=1)
1614 tbl6.add_vpp_config()
1618 self.pg0.config_ip4()
1619 self.pg0.resolve_arp()
1620 self.pg0.enable_mpls()
1623 self.pg1.config_ip4()
1624 self.pg1.resolve_arp()
1625 self.pg1.enable_mpls()
1627 # VRF (customer facing) link
1629 self.pg2.set_table_ip4(1)
1630 self.pg2.config_ip4()
1631 self.pg2.resolve_arp()
1632 self.pg2.set_table_ip6(1)
1633 self.pg2.config_ip6()
1634 self.pg2.resolve_ndp()
1637 self.pg3.set_table_ip4(1)
1638 self.pg3.config_ip4()
1639 self.pg3.resolve_arp()
1640 self.pg3.set_table_ip6(1)
1641 self.pg3.config_ip6()
1642 self.pg3.resolve_ndp()
1645 self.pg0.disable_mpls()
1646 self.pg1.disable_mpls()
1647 for i in self.pg_interfaces:
1653 super(TestMPLSPIC, self).tearDown()
1655 def test_mpls_ibgp_pic(self):
1656 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1658 1) setup many iBGP VPN routes via a pair of iBGP peers.
1659 2) Check EMCP forwarding to these peers
1660 3) withdraw the IGP route to one of these peers.
1661 4) check forwarding continues to the remaining peer
1665 # IGP+LDP core routes
1667 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1668 [VppRoutePath(self.pg0.remote_ip4,
1669 self.pg0.sw_if_index,
1671 core_10_0_0_45.add_vpp_config()
1673 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1674 [VppRoutePath(self.pg1.remote_ip4,
1675 self.pg1.sw_if_index,
1677 core_10_0_0_46.add_vpp_config()
1680 # Lot's of VPN routes. We need more the 64 so VPP will build
1681 # the fast convergence indirection
1685 for ii in range(NUM_PKTS):
1686 dst = "192.168.1.%d" % ii
1687 vpn_routes.append(VppIpRoute(
1693 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1698 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1700 vpn_routes[ii].add_vpp_config()
1702 pkts.append(Ether(dst=self.pg2.local_mac,
1703 src=self.pg2.remote_mac) /
1704 IP(src=self.pg2.remote_ip4, dst=dst) /
1705 UDP(sport=1234, dport=1234) /
1709 # Send the packet stream (one pkt to each VPN route)
1710 # - expect a 50-50 split of the traffic
1712 self.pg2.add_stream(pkts)
1713 self.pg_enable_capture(self.pg_interfaces)
1716 rx0 = self.pg0._get_capture(NUM_PKTS)
1717 rx1 = self.pg1._get_capture(NUM_PKTS)
1719 # not testing the LB hashing algorithm so we're not concerned
1720 # with the split ratio, just as long as neither is 0
1721 self.assertNotEqual(0, len(rx0))
1722 self.assertNotEqual(0, len(rx1))
1723 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1724 "Expected all (%s) packets across both ECMP paths. "
1725 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1728 # use a test CLI command to stop the FIB walk process, this
1729 # will prevent the FIB converging the VPN routes and thus allow
1730 # us to probe the interim (post-fail, pre-converge) state
1732 self.vapi.ppcli("test fib-walk-process disable")
1735 # Withdraw one of the IGP routes
1737 core_10_0_0_46.remove_vpp_config()
1740 # now all packets should be forwarded through the remaining peer
1742 self.vapi.ppcli("clear trace")
1743 self.pg2.add_stream(pkts)
1744 self.pg_enable_capture(self.pg_interfaces)
1747 rx0 = self.pg0.get_capture(NUM_PKTS)
1748 self.assertEqual(len(pkts), len(rx0),
1749 "Expected all (%s) packets across single path. "
1750 "rx0: %s." % (len(pkts), len(rx0)))
1753 # enable the FIB walk process to converge the FIB
1755 self.vapi.ppcli("test fib-walk-process enable")
1758 # packets should still be forwarded through the remaining peer
1760 self.pg2.add_stream(pkts)
1761 self.pg_enable_capture(self.pg_interfaces)
1764 rx0 = self.pg0.get_capture(NUM_PKTS)
1765 self.assertEqual(len(pkts), len(rx0),
1766 "Expected all (%s) packets across single path. "
1767 "rx0: %s." % (len(pkts), len(rx0)))
1770 # Add the IGP route back and we return to load-balancing
1772 core_10_0_0_46.add_vpp_config()
1774 self.pg2.add_stream(pkts)
1775 self.pg_enable_capture(self.pg_interfaces)
1778 rx0 = self.pg0._get_capture(NUM_PKTS)
1779 rx1 = self.pg1._get_capture(NUM_PKTS)
1780 self.assertNotEqual(0, len(rx0))
1781 self.assertNotEqual(0, len(rx1))
1782 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1783 "Expected all (%s) packets across both ECMP paths. "
1784 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1786 def test_mpls_ebgp_pic(self):
1787 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1789 1) setup many eBGP VPN routes via a pair of eBGP peers.
1790 2) Check EMCP forwarding to these peers
1791 3) withdraw one eBGP path - expect LB across remaining eBGP
1795 # Lot's of VPN routes. We need more the 64 so VPP will build
1796 # the fast convergence indirection
1801 for ii in range(NUM_PKTS):
1802 dst = "192.168.1.%d" % ii
1803 local_label = 1600 + ii
1804 vpn_routes.append(VppIpRoute(
1807 self.pg2.remote_ip4,
1810 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1812 self.pg3.remote_ip4,
1815 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1817 vpn_routes[ii].add_vpp_config()
1819 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1821 vpn_bindings[ii].add_vpp_config()
1823 pkts.append(Ether(dst=self.pg0.local_mac,
1824 src=self.pg0.remote_mac) /
1825 MPLS(label=local_label, ttl=64) /
1826 IP(src=self.pg0.remote_ip4, dst=dst) /
1827 UDP(sport=1234, dport=1234) /
1831 # Send the packet stream (one pkt to each VPN route)
1832 # - expect a 50-50 split of the traffic
1834 self.pg0.add_stream(pkts)
1835 self.pg_enable_capture(self.pg_interfaces)
1838 rx0 = self.pg2._get_capture(NUM_PKTS)
1839 rx1 = self.pg3._get_capture(NUM_PKTS)
1841 # not testing the LB hashing algorithm so we're not concerned
1842 # with the split ratio, just as long as neither is 0
1843 self.assertNotEqual(0, len(rx0))
1844 self.assertNotEqual(0, len(rx1))
1845 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1846 "Expected all (%s) packets across both ECMP paths. "
1847 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1850 # use a test CLI command to stop the FIB walk process, this
1851 # will prevent the FIB converging the VPN routes and thus allow
1852 # us to probe the interim (post-fail, pre-converge) state
1854 self.vapi.ppcli("test fib-walk-process disable")
1857 # withdraw the connected prefix on the interface.
1859 self.pg2.unconfig_ip4()
1862 # now all packets should be forwarded through the remaining peer
1864 self.pg0.add_stream(pkts)
1865 self.pg_enable_capture(self.pg_interfaces)
1868 rx0 = self.pg3.get_capture(NUM_PKTS)
1869 self.assertEqual(len(pkts), len(rx0),
1870 "Expected all (%s) packets across single path. "
1871 "rx0: %s." % (len(pkts), len(rx0)))
1874 # enable the FIB walk process to converge the FIB
1876 self.vapi.ppcli("test fib-walk-process enable")
1879 # packets should still be forwarded through the remaining peer
1881 self.pg0.add_stream(pkts)
1882 self.pg_enable_capture(self.pg_interfaces)
1885 rx0 = self.pg3.get_capture(NUM_PKTS)
1886 self.assertEqual(len(pkts), len(rx0),
1887 "Expected all (%s) packets across single path. "
1888 "rx0: %s." % (len(pkts), len(rx0)))
1891 # put the connected routes back
1893 self.pg2.config_ip4()
1894 self.pg2.resolve_arp()
1896 self.pg0.add_stream(pkts)
1897 self.pg_enable_capture(self.pg_interfaces)
1900 rx0 = self.pg2._get_capture(NUM_PKTS)
1901 rx1 = self.pg3._get_capture(NUM_PKTS)
1902 self.assertNotEqual(0, len(rx0))
1903 self.assertNotEqual(0, len(rx1))
1904 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1905 "Expected all (%s) packets across both ECMP paths. "
1906 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1908 def test_mpls_v6_ebgp_pic(self):
1909 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1911 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1912 2) Check EMCP forwarding to these peers
1913 3) withdraw one eBGP path - expect LB across remaining eBGP
1917 # Lot's of VPN routes. We need more the 64 so VPP will build
1918 # the fast convergence indirection
1923 for ii in range(NUM_PKTS):
1924 dst = "3000::%d" % ii
1925 local_label = 1600 + ii
1926 vpn_routes.append(VppIpRoute(
1929 self.pg2.remote_ip6,
1932 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1934 self.pg3.remote_ip6,
1937 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1939 vpn_routes[ii].add_vpp_config()
1941 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1943 vpn_bindings[ii].add_vpp_config()
1945 pkts.append(Ether(dst=self.pg0.local_mac,
1946 src=self.pg0.remote_mac) /
1947 MPLS(label=local_label, ttl=64) /
1948 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1949 UDP(sport=1234, dport=1234) /
1951 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
1953 self.pg0.add_stream(pkts)
1954 self.pg_enable_capture(self.pg_interfaces)
1957 rx0 = self.pg2._get_capture(NUM_PKTS)
1958 rx1 = self.pg3._get_capture(NUM_PKTS)
1959 self.assertNotEqual(0, len(rx0))
1960 self.assertNotEqual(0, len(rx1))
1961 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1962 "Expected all (%s) packets across both ECMP paths. "
1963 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1966 # use a test CLI command to stop the FIB walk process, this
1967 # will prevent the FIB converging the VPN routes and thus allow
1968 # us to probe the interim (post-fail, pre-converge) state
1970 self.vapi.ppcli("test fib-walk-process disable")
1973 # withdraw the connected prefix on the interface.
1974 # and shutdown the interface so the ND cache is flushed.
1976 self.pg2.unconfig_ip6()
1977 self.pg2.admin_down()
1980 # now all packets should be forwarded through the remaining peer
1982 self.pg0.add_stream(pkts)
1983 self.pg_enable_capture(self.pg_interfaces)
1986 rx0 = self.pg3.get_capture(NUM_PKTS)
1987 self.assertEqual(len(pkts), len(rx0),
1988 "Expected all (%s) packets across single path. "
1989 "rx0: %s." % (len(pkts), len(rx0)))
1992 # enable the FIB walk process to converge the FIB
1994 self.vapi.ppcli("test fib-walk-process enable")
1995 self.pg0.add_stream(pkts)
1996 self.pg_enable_capture(self.pg_interfaces)
1999 rx0 = self.pg3.get_capture(NUM_PKTS)
2000 self.assertEqual(len(pkts), len(rx0),
2001 "Expected all (%s) packets across single path. "
2002 "rx0: %s." % (len(pkts), len(rx0)))
2005 # put the connected routes back
2008 self.pg2.config_ip6()
2009 self.pg2.resolve_ndp()
2011 self.pg0.add_stream(pkts)
2012 self.pg_enable_capture(self.pg_interfaces)
2015 rx0 = self.pg2._get_capture(NUM_PKTS)
2016 rx1 = self.pg3._get_capture(NUM_PKTS)
2017 self.assertNotEqual(0, len(rx0))
2018 self.assertNotEqual(0, len(rx1))
2019 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2020 "Expected all (%s) packets across both ECMP paths. "
2021 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2024 class TestMPLSL2(VppTestCase):
2028 def setUpClass(cls):
2029 super(TestMPLSL2, cls).setUpClass()
2032 def tearDownClass(cls):
2033 super(TestMPLSL2, cls).tearDownClass()
2036 super(TestMPLSL2, self).setUp()
2038 # create 2 pg interfaces
2039 self.create_pg_interfaces(range(2))
2041 # create the default MPLS table
2043 tbl = VppMplsTable(self, 0)
2044 tbl.add_vpp_config()
2045 self.tables.append(tbl)
2047 # use pg0 as the core facing interface
2049 self.pg0.config_ip4()
2050 self.pg0.resolve_arp()
2051 self.pg0.enable_mpls()
2053 # use the other 2 for customer facing L2 links
2054 for i in self.pg_interfaces[1:]:
2058 for i in self.pg_interfaces[1:]:
2061 self.pg0.disable_mpls()
2062 self.pg0.unconfig_ip4()
2063 self.pg0.admin_down()
2064 super(TestMPLSL2, self).tearDown()
2066 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2067 capture = verify_filter(capture, sent)
2069 self.assertEqual(len(capture), len(sent))
2071 for i in range(len(capture)):
2075 # the MPLS TTL is 255 since it enters a new tunnel
2076 verify_mpls_stack(self, rx, mpls_labels)
2079 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2081 self.assertEqual(rx_eth.src, tx_eth.src)
2082 self.assertEqual(rx_eth.dst, tx_eth.dst)
2084 def test_vpws(self):
2085 """ Virtual Private Wire Service """
2088 # Create an MPLS tunnel that pushes 1 label
2089 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2090 # information is not in the packet, but we test it works anyway
2092 mpls_tun_1 = VppMPLSTunnelInterface(
2094 [VppRoutePath(self.pg0.remote_ip4,
2095 self.pg0.sw_if_index,
2096 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2098 mpls_tun_1.add_vpp_config()
2099 mpls_tun_1.admin_up()
2102 # Create a label entry to for 55 that does L2 input to the tunnel
2104 route_55_eos = VppMplsRoute(
2106 [VppRoutePath("0.0.0.0",
2107 mpls_tun_1.sw_if_index,
2108 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2109 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2110 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2111 route_55_eos.add_vpp_config()
2114 # Cross-connect the tunnel with one of the customers L2 interfaces
2116 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2117 mpls_tun_1.sw_if_index,
2119 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2120 self.pg1.sw_if_index,
2124 # inject a packet from the core
2126 pcore = (Ether(dst=self.pg0.local_mac,
2127 src=self.pg0.remote_mac) /
2128 MPLS(label=55, ttl=64) /
2129 Ether(dst="00:00:de:ad:ba:be",
2130 src="00:00:de:ad:be:ef") /
2131 IP(src="10.10.10.10", dst="11.11.11.11") /
2132 UDP(sport=1234, dport=1234) /
2135 tx0 = pcore * NUM_PKTS
2136 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2137 payload = pcore[MPLS].payload
2139 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2140 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2143 # Inject a packet from the customer/L2 side
2145 tx1 = pcore[MPLS].payload * NUM_PKTS
2146 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2148 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2150 def test_vpls(self):
2151 """ Virtual Private LAN Service """
2153 # Create a L2 MPLS tunnels
2155 mpls_tun1 = VppMPLSTunnelInterface(
2157 [VppRoutePath(self.pg0.remote_ip4,
2158 self.pg0.sw_if_index,
2159 labels=[VppMplsLabel(42)])],
2161 mpls_tun1.add_vpp_config()
2162 mpls_tun1.admin_up()
2164 mpls_tun2 = VppMPLSTunnelInterface(
2166 [VppRoutePath(self.pg0.remote_ip4,
2167 self.pg0.sw_if_index,
2168 labels=[VppMplsLabel(43)])],
2170 mpls_tun2.add_vpp_config()
2171 mpls_tun2.admin_up()
2174 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2175 # the latter includes a Psuedo Wire Control Word
2177 route_55_eos = VppMplsRoute(
2179 [VppRoutePath("0.0.0.0",
2180 mpls_tun1.sw_if_index,
2181 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2182 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2183 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2185 route_56_eos = VppMplsRoute(
2187 [VppRoutePath("0.0.0.0",
2188 mpls_tun2.sw_if_index,
2189 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2190 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2191 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2192 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2195 route_56_eos.add_vpp_config()
2196 route_55_eos.add_vpp_config()
2198 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2201 # add to tunnel to the customers bridge-domain
2203 self.vapi.sw_interface_set_l2_bridge(
2204 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2205 self.vapi.sw_interface_set_l2_bridge(
2206 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2207 self.vapi.sw_interface_set_l2_bridge(
2208 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2211 # Packet from host on the customer interface to each host
2212 # reachable over the core, and vice-versa
2214 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2215 src="00:00:de:ad:be:ef") /
2216 IP(src="10.10.10.10", dst="11.11.11.11") /
2217 UDP(sport=1234, dport=1234) /
2219 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2220 src="00:00:de:ad:be:ef") /
2221 IP(src="10.10.10.10", dst="11.11.11.12") /
2222 UDP(sport=1234, dport=1234) /
2224 p_core1 = (Ether(dst=self.pg0.local_mac,
2225 src=self.pg0.remote_mac) /
2226 MPLS(label=55, ttl=64) /
2227 Ether(src="00:00:de:ad:ba:b1",
2228 dst="00:00:de:ad:be:ef") /
2229 IP(dst="10.10.10.10", src="11.11.11.11") /
2230 UDP(sport=1234, dport=1234) /
2232 p_core2 = (Ether(dst=self.pg0.local_mac,
2233 src=self.pg0.remote_mac) /
2234 MPLS(label=56, ttl=64) /
2235 Raw('\x01' * 4) / # PW CW
2236 Ether(src="00:00:de:ad:ba:b2",
2237 dst="00:00:de:ad:be:ef") /
2238 IP(dst="10.10.10.10", src="11.11.11.12") /
2239 UDP(sport=1234, dport=1234) /
2243 # The BD is learning, so send in one of each packet to learn
2246 # 2 packets due to BD flooding
2247 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2248 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2250 # we've learnt this so expect it be be forwarded not flooded
2251 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2252 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2253 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2255 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2256 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2257 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2260 # now a stream in each direction from each host
2262 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2263 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2266 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2267 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2270 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2271 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2274 # remove interfaces from customers bridge-domain
2276 self.vapi.sw_interface_set_l2_bridge(
2277 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2278 self.vapi.sw_interface_set_l2_bridge(
2279 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2280 self.vapi.sw_interface_set_l2_bridge(
2281 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2284 if __name__ == '__main__':
2285 unittest.main(testRunner=VppTestRunner)