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]
383 """ MPLS label swap tests """
386 # A simple MPLS xconnect - eos label in label out
388 route_32_eos = VppMplsRoute(self, 32, 1,
389 [VppRoutePath(self.pg0.remote_ip4,
390 self.pg0.sw_if_index,
391 labels=[VppMplsLabel(33)])])
392 route_32_eos.add_vpp_config()
395 find_mpls_route(self, 0, 32, 1,
396 [VppRoutePath(self.pg0.remote_ip4,
397 self.pg0.sw_if_index,
398 labels=[VppMplsLabel(33)])]))
401 # a stream that matches the route for 10.0.0.1
402 # PG0 is in the default table
404 tx = self.create_stream_labelled_ip4(self.pg0,
405 [VppMplsLabel(32, ttl=32, exp=1)])
406 rx = self.send_and_expect(self.pg0, tx, self.pg0)
407 self.verify_capture_labelled(self.pg0, rx, tx,
408 [VppMplsLabel(33, ttl=31, exp=1)])
410 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
413 # A simple MPLS xconnect - non-eos label in label out
415 route_32_neos = VppMplsRoute(self, 32, 0,
416 [VppRoutePath(self.pg0.remote_ip4,
417 self.pg0.sw_if_index,
418 labels=[VppMplsLabel(33)])])
419 route_32_neos.add_vpp_config()
422 # a stream that matches the route for 10.0.0.1
423 # PG0 is in the default table
425 tx = self.create_stream_labelled_ip4(self.pg0,
426 [VppMplsLabel(32, ttl=21, exp=7),
428 rx = self.send_and_expect(self.pg0, tx, self.pg0)
429 self.verify_capture_labelled(self.pg0, rx, tx,
430 [VppMplsLabel(33, ttl=20, exp=7),
432 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
435 # A simple MPLS xconnect - non-eos label in label out, uniform mode
437 route_42_neos = VppMplsRoute(
439 [VppRoutePath(self.pg0.remote_ip4,
440 self.pg0.sw_if_index,
441 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
442 route_42_neos.add_vpp_config()
444 tx = self.create_stream_labelled_ip4(self.pg0,
445 [VppMplsLabel(42, ttl=21, exp=7),
447 rx = self.send_and_expect(self.pg0, tx, self.pg0)
448 self.verify_capture_labelled(self.pg0, rx, tx,
449 [VppMplsLabel(43, ttl=20, exp=7),
453 # An MPLS xconnect - EOS label in IP out
455 route_33_eos = VppMplsRoute(self, 33, 1,
456 [VppRoutePath(self.pg0.remote_ip4,
457 self.pg0.sw_if_index,
459 route_33_eos.add_vpp_config()
461 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
462 rx = self.send_and_expect(self.pg0, tx, self.pg0)
463 self.verify_capture_ip4(self.pg0, rx, tx)
466 # disposed packets have an invalid IPv4 checksum
468 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
469 dst_ip=self.pg0.remote_ip4,
472 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
475 # An MPLS xconnect - EOS label in IP out, uniform mode
477 route_3333_eos = VppMplsRoute(
479 [VppRoutePath(self.pg0.remote_ip4,
480 self.pg0.sw_if_index,
481 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
482 route_3333_eos.add_vpp_config()
484 tx = self.create_stream_labelled_ip4(
486 [VppMplsLabel(3333, ttl=55, exp=3)])
487 rx = self.send_and_expect(self.pg0, tx, self.pg0)
488 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
489 tx = self.create_stream_labelled_ip4(
491 [VppMplsLabel(3333, ttl=66, exp=4)])
492 rx = self.send_and_expect(self.pg0, tx, self.pg0)
493 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
496 # An MPLS xconnect - EOS label in IPv6 out
498 route_333_eos = VppMplsRoute(
500 [VppRoutePath(self.pg0.remote_ip6,
501 self.pg0.sw_if_index,
503 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
504 route_333_eos.add_vpp_config()
506 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
507 rx = self.send_and_expect(self.pg0, tx, self.pg0)
508 self.verify_capture_ip6(self.pg0, rx, tx)
511 # disposed packets have an TTL expired
513 tx = self.create_stream_labelled_ip6(self.pg0,
514 [VppMplsLabel(333, ttl=64)],
515 dst_ip=self.pg1.remote_ip6,
517 rx = self.send_and_expect(self.pg0, tx, self.pg0)
518 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
521 # An MPLS xconnect - EOS label in IPv6 out w imp-null
523 route_334_eos = VppMplsRoute(
525 [VppRoutePath(self.pg0.remote_ip6,
526 self.pg0.sw_if_index,
527 labels=[VppMplsLabel(3)])],
528 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
529 route_334_eos.add_vpp_config()
531 tx = self.create_stream_labelled_ip6(self.pg0,
532 [VppMplsLabel(334, ttl=64)])
533 rx = self.send_and_expect(self.pg0, tx, self.pg0)
534 self.verify_capture_ip6(self.pg0, rx, tx)
537 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
539 route_335_eos = VppMplsRoute(
541 [VppRoutePath(self.pg0.remote_ip6,
542 self.pg0.sw_if_index,
543 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
544 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
545 route_335_eos.add_vpp_config()
547 tx = self.create_stream_labelled_ip6(
549 [VppMplsLabel(335, ttl=27, exp=4)])
550 rx = self.send_and_expect(self.pg0, tx, self.pg0)
551 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
554 # disposed packets have an TTL expired
556 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
557 dst_ip=self.pg1.remote_ip6,
559 rx = self.send_and_expect(self.pg0, tx, self.pg0)
560 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
563 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
564 # so this traffic should be dropped.
566 route_33_neos = VppMplsRoute(self, 33, 0,
567 [VppRoutePath(self.pg0.remote_ip4,
568 self.pg0.sw_if_index,
570 route_33_neos.add_vpp_config()
572 tx = self.create_stream_labelled_ip4(self.pg0,
575 self.send_and_assert_no_replies(
577 "MPLS non-EOS packets popped and forwarded")
580 # A recursive EOS x-connect, which resolves through another x-connect
583 route_34_eos = VppMplsRoute(self, 34, 1,
584 [VppRoutePath("0.0.0.0",
587 labels=[VppMplsLabel(44),
589 route_34_eos.add_vpp_config()
590 self.logger.info(self.vapi.cli("sh mpls fib 34"))
592 tx = self.create_stream_labelled_ip4(self.pg0,
593 [VppMplsLabel(34, ttl=3)])
594 rx = self.send_and_expect(self.pg0, tx, self.pg0)
595 self.verify_capture_labelled(self.pg0, rx, tx,
598 VppMplsLabel(45, ttl=2)])
600 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
601 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
604 # A recursive EOS x-connect, which resolves through another x-connect
607 route_35_eos = VppMplsRoute(
609 [VppRoutePath("0.0.0.0",
612 labels=[VppMplsLabel(44)])])
613 route_35_eos.add_vpp_config()
615 tx = self.create_stream_labelled_ip4(self.pg0,
616 [VppMplsLabel(35, ttl=3)])
617 rx = self.send_and_expect(self.pg0, tx, self.pg0)
618 self.verify_capture_labelled(self.pg0, rx, tx,
619 [VppMplsLabel(43, ttl=2),
620 VppMplsLabel(44, ttl=2)])
623 # A recursive non-EOS x-connect, which resolves through another
626 route_34_neos = VppMplsRoute(self, 34, 0,
627 [VppRoutePath("0.0.0.0",
630 labels=[VppMplsLabel(44),
632 route_34_neos.add_vpp_config()
634 tx = self.create_stream_labelled_ip4(self.pg0,
635 [VppMplsLabel(34, ttl=45),
637 rx = self.send_and_expect(self.pg0, tx, self.pg0)
638 # it's the 2nd (counting from 0) label in the stack that is swapped
639 self.verify_capture_labelled(self.pg0, rx, tx,
642 VppMplsLabel(46, ttl=44),
646 # an recursive IP route that resolves through the recursive non-eos
649 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
650 [VppRoutePath("0.0.0.0",
653 labels=[VppMplsLabel(55)])])
654 ip_10_0_0_1.add_vpp_config()
656 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
657 rx = self.send_and_expect(self.pg0, tx, self.pg0)
658 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
663 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
665 ip_10_0_0_1.remove_vpp_config()
666 route_34_neos.remove_vpp_config()
667 route_34_eos.remove_vpp_config()
668 route_33_neos.remove_vpp_config()
669 route_33_eos.remove_vpp_config()
670 route_32_neos.remove_vpp_config()
671 route_32_eos.remove_vpp_config()
674 """ MPLS Local Label Binding test """
677 # Add a non-recursive route with a single out label
679 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
680 [VppRoutePath(self.pg0.remote_ip4,
681 self.pg0.sw_if_index,
682 labels=[VppMplsLabel(45)])])
683 route_10_0_0_1.add_vpp_config()
685 # bind a local label to the route
686 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
687 binding.add_vpp_config()
690 tx = self.create_stream_labelled_ip4(self.pg0,
693 rx = self.send_and_expect(self.pg0, tx, self.pg0)
694 self.verify_capture_labelled(self.pg0, rx, tx,
695 [VppMplsLabel(45, ttl=63),
699 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
700 rx = self.send_and_expect(self.pg0, tx, self.pg0)
701 self.verify_capture_labelled(self.pg0, rx, tx,
702 [VppMplsLabel(45, ttl=63)])
705 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
706 rx = self.send_and_expect(self.pg0, tx, self.pg0)
707 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
712 binding.remove_vpp_config()
713 route_10_0_0_1.remove_vpp_config()
715 def test_imposition(self):
716 """ MPLS label imposition test """
719 # Add a non-recursive route with a single out label
721 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
722 [VppRoutePath(self.pg0.remote_ip4,
723 self.pg0.sw_if_index,
724 labels=[VppMplsLabel(32)])])
725 route_10_0_0_1.add_vpp_config()
728 # a stream that matches the route for 10.0.0.1
729 # PG0 is in the default table
731 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
732 rx = self.send_and_expect(self.pg0, tx, self.pg0)
733 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
736 # Add a non-recursive route with a 3 out labels
738 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
739 [VppRoutePath(self.pg0.remote_ip4,
740 self.pg0.sw_if_index,
741 labels=[VppMplsLabel(32),
744 route_10_0_0_2.add_vpp_config()
746 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
747 ip_ttl=44, ip_dscp=0xff)
748 rx = self.send_and_expect(self.pg0, tx, self.pg0)
749 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
756 # Add a non-recursive route with a single out label in uniform mode
758 route_10_0_0_3 = VppIpRoute(
759 self, "10.0.0.3", 32,
760 [VppRoutePath(self.pg0.remote_ip4,
761 self.pg0.sw_if_index,
762 labels=[VppMplsLabel(32,
763 mode=MplsLspMode.UNIFORM)])])
764 route_10_0_0_3.add_vpp_config()
766 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
767 ip_ttl=54, ip_dscp=0xbe)
768 rx = self.send_and_expect(self.pg0, tx, self.pg0)
769 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
770 [VppMplsLabel(32, ttl=53, exp=5)])
773 # Add a IPv6 non-recursive route with a single out label in
776 route_2001_3 = VppIpRoute(
777 self, "2001::3", 128,
778 [VppRoutePath(self.pg0.remote_ip6,
779 self.pg0.sw_if_index,
780 labels=[VppMplsLabel(32,
781 mode=MplsLspMode.UNIFORM)])])
782 route_2001_3.add_vpp_config()
784 tx = self.create_stream_ip6(self.pg0, "2001::3",
785 ip_ttl=54, ip_dscp=0xbe)
786 rx = self.send_and_expect(self.pg0, tx, self.pg0)
787 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
788 [VppMplsLabel(32, ttl=53, exp=5)])
791 # add a recursive path, with output label, via the 1 label route
793 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
794 [VppRoutePath("10.0.0.1",
796 labels=[VppMplsLabel(44)])])
797 route_11_0_0_1.add_vpp_config()
800 # a stream that matches the route for 11.0.0.1, should pick up
801 # the label stack for 11.0.0.1 and 10.0.0.1
803 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
804 rx = self.send_and_expect(self.pg0, tx, self.pg0)
805 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
809 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
812 # add a recursive path, with 2 labels, via the 3 label route
814 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
815 [VppRoutePath("10.0.0.2",
817 labels=[VppMplsLabel(44),
819 route_11_0_0_2.add_vpp_config()
822 # a stream that matches the route for 11.0.0.1, should pick up
823 # the label stack for 11.0.0.1 and 10.0.0.1
825 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
826 rx = self.send_and_expect(self.pg0, tx, self.pg0)
827 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
834 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
836 rx = self.send_and_expect(self.pg0, tx, self.pg0)
837 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
844 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
849 route_11_0_0_2.remove_vpp_config()
850 route_11_0_0_1.remove_vpp_config()
851 route_10_0_0_2.remove_vpp_config()
852 route_10_0_0_1.remove_vpp_config()
854 def test_tunnel_pipe(self):
855 """ MPLS Tunnel Tests - Pipe """
858 # Create a tunnel with a single out label
860 mpls_tun = VppMPLSTunnelInterface(
862 [VppRoutePath(self.pg0.remote_ip4,
863 self.pg0.sw_if_index,
864 labels=[VppMplsLabel(44),
866 mpls_tun.add_vpp_config()
870 # add an unlabelled route through the new tunnel
872 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
873 [VppRoutePath("0.0.0.0",
874 mpls_tun._sw_if_index)])
875 route_10_0_0_3.add_vpp_config()
877 self.vapi.cli("clear trace")
878 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
879 self.pg0.add_stream(tx)
881 self.pg_enable_capture(self.pg_interfaces)
884 rx = self.pg0.get_capture()
885 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
890 # add a labelled route through the new tunnel
892 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
893 [VppRoutePath("0.0.0.0",
894 mpls_tun._sw_if_index,
896 route_10_0_0_4.add_vpp_config()
898 self.vapi.cli("clear trace")
899 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
900 self.pg0.add_stream(tx)
902 self.pg_enable_capture(self.pg_interfaces)
905 rx = self.pg0.get_capture()
906 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
909 VppMplsLabel(33, ttl=255)])
911 def test_tunnel_uniform(self):
912 """ MPLS Tunnel Tests - Uniform """
915 # Create a tunnel with a single out label
916 # The label stack is specified here from outer to inner
918 mpls_tun = VppMPLSTunnelInterface(
920 [VppRoutePath(self.pg0.remote_ip4,
921 self.pg0.sw_if_index,
922 labels=[VppMplsLabel(44, ttl=32),
923 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
924 mpls_tun.add_vpp_config()
928 # add an unlabelled route through the new tunnel
930 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
931 [VppRoutePath("0.0.0.0",
932 mpls_tun._sw_if_index)])
933 route_10_0_0_3.add_vpp_config()
935 self.vapi.cli("clear trace")
936 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
937 self.pg0.add_stream(tx)
939 self.pg_enable_capture(self.pg_interfaces)
942 rx = self.pg0.get_capture()
943 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
944 [VppMplsLabel(44, ttl=32),
945 VppMplsLabel(46, ttl=23)])
948 # add a labelled route through the new tunnel
950 route_10_0_0_4 = VppIpRoute(
951 self, "10.0.0.4", 32,
952 [VppRoutePath("0.0.0.0",
953 mpls_tun._sw_if_index,
954 labels=[VppMplsLabel(33, ttl=47)])])
955 route_10_0_0_4.add_vpp_config()
957 self.vapi.cli("clear trace")
958 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
959 self.pg0.add_stream(tx)
961 self.pg_enable_capture(self.pg_interfaces)
964 rx = self.pg0.get_capture()
965 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
966 [VppMplsLabel(44, ttl=32),
967 VppMplsLabel(46, ttl=47),
968 VppMplsLabel(33, ttl=47)])
970 def test_mpls_tunnel_many(self):
971 """ MPLS Multiple Tunnels """
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()
983 def test_v4_exp_null(self):
984 """ MPLS V4 Explicit NULL test """
987 # The first test case has an MPLS TTL of 0
988 # all packet should be dropped
990 tx = self.create_stream_labelled_ip4(self.pg0,
991 [VppMplsLabel(0, ttl=0)])
992 self.send_and_assert_no_replies(self.pg0, tx,
993 "MPLS TTL=0 packets forwarded")
996 # a stream with a non-zero MPLS TTL
997 # PG0 is in the default table
999 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1000 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1001 self.verify_capture_ip4(self.pg0, rx, tx)
1004 # a stream with a non-zero MPLS TTL
1006 # we are ensuring the post-pop lookup occurs in the VRF table
1008 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1009 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1010 self.verify_capture_ip4(self.pg1, rx, tx)
1012 def test_v6_exp_null(self):
1013 """ MPLS V6 Explicit NULL test """
1016 # a stream with a non-zero MPLS TTL
1017 # PG0 is in the default table
1019 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1020 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1021 self.verify_capture_ip6(self.pg0, rx, tx)
1024 # a stream with a non-zero MPLS TTL
1026 # we are ensuring the post-pop lookup occurs in the VRF table
1028 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1029 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1030 self.verify_capture_ip6(self.pg0, rx, tx)
1032 def test_deag(self):
1036 # A de-agg route - next-hop lookup in default table
1038 route_34_eos = VppMplsRoute(self, 34, 1,
1039 [VppRoutePath("0.0.0.0",
1042 route_34_eos.add_vpp_config()
1045 # ping an interface in the default table
1046 # PG0 is in the default table
1048 tx = self.create_stream_labelled_ip4(self.pg0,
1052 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1053 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1056 # A de-agg route - next-hop lookup in non-default table
1058 route_35_eos = VppMplsRoute(self, 35, 1,
1059 [VppRoutePath("0.0.0.0",
1062 route_35_eos.add_vpp_config()
1065 # ping an interface in the non-default table
1066 # PG0 is in the default table. packet arrive labelled in the
1067 # default table and egress unlabelled in the non-default
1069 tx = self.create_stream_labelled_ip4(
1070 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1071 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1072 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1077 route_36_neos = VppMplsRoute(self, 36, 0,
1078 [VppRoutePath("0.0.0.0",
1080 route_36_neos.add_vpp_config()
1082 tx = self.create_stream_labelled_ip4(self.pg0,
1085 ping=1, ip_itf=self.pg1)
1086 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1087 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1089 route_36_neos.remove_vpp_config()
1090 route_35_eos.remove_vpp_config()
1091 route_34_eos.remove_vpp_config()
1093 def test_interface_rx(self):
1094 """ MPLS Interface Receive """
1097 # Add a non-recursive route that will forward the traffic
1100 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1102 paths=[VppRoutePath(self.pg1.remote_ip4,
1103 self.pg1.sw_if_index)])
1104 route_10_0_0_1.add_vpp_config()
1107 # An interface receive label that maps traffic to RX on interface
1109 # by injecting the packet in on pg0, which is in table 0
1110 # doing an interface-rx on pg1 and matching a route in table 1
1111 # if the packet egresses, then we must have swapped to pg1
1112 # so as to have matched the route in table 1
1114 route_34_eos = VppMplsRoute(
1116 [VppRoutePath("0.0.0.0",
1117 self.pg1.sw_if_index,
1118 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1119 route_34_eos.add_vpp_config()
1122 # ping an interface in the default table
1123 # PG0 is in the default table
1125 tx = self.create_stream_labelled_ip4(self.pg0,
1128 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1129 self.verify_capture_ip4(self.pg1, rx, tx)
1131 def test_mcast_mid_point(self):
1132 """ MPLS Multicast Mid Point """
1135 # Add a non-recursive route that will forward the traffic
1138 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1140 paths=[VppRoutePath(self.pg1.remote_ip4,
1141 self.pg1.sw_if_index)])
1142 route_10_0_0_1.add_vpp_config()
1145 # Add a mcast entry that replicate to pg2 and pg3
1146 # and replicate to a interface-rx (like a bud node would)
1148 route_3400_eos = VppMplsRoute(
1150 [VppRoutePath(self.pg2.remote_ip4,
1151 self.pg2.sw_if_index,
1152 labels=[VppMplsLabel(3401)]),
1153 VppRoutePath(self.pg3.remote_ip4,
1154 self.pg3.sw_if_index,
1155 labels=[VppMplsLabel(3402)]),
1156 VppRoutePath("0.0.0.0",
1157 self.pg1.sw_if_index,
1158 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1160 route_3400_eos.add_vpp_config()
1163 # ping an interface in the default table
1164 # PG0 is in the default table
1166 self.vapi.cli("clear trace")
1167 tx = self.create_stream_labelled_ip4(self.pg0,
1168 [VppMplsLabel(3400, ttl=64)],
1171 self.pg0.add_stream(tx)
1173 self.pg_enable_capture(self.pg_interfaces)
1176 rx = self.pg1.get_capture(257)
1177 self.verify_capture_ip4(self.pg1, rx, tx)
1179 rx = self.pg2.get_capture(257)
1180 self.verify_capture_labelled(self.pg2, rx, tx,
1181 [VppMplsLabel(3401, ttl=63)])
1182 rx = self.pg3.get_capture(257)
1183 self.verify_capture_labelled(self.pg3, rx, tx,
1184 [VppMplsLabel(3402, ttl=63)])
1186 def test_mcast_head(self):
1187 """ MPLS Multicast Head-end """
1190 # Create a multicast tunnel with two replications
1192 mpls_tun = VppMPLSTunnelInterface(
1194 [VppRoutePath(self.pg2.remote_ip4,
1195 self.pg2.sw_if_index,
1196 labels=[VppMplsLabel(42)]),
1197 VppRoutePath(self.pg3.remote_ip4,
1198 self.pg3.sw_if_index,
1199 labels=[VppMplsLabel(43)])],
1201 mpls_tun.add_vpp_config()
1205 # add an unlabelled route through the new tunnel
1207 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1208 [VppRoutePath("0.0.0.0",
1209 mpls_tun._sw_if_index)])
1210 route_10_0_0_3.add_vpp_config()
1212 self.vapi.cli("clear trace")
1213 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1214 self.pg0.add_stream(tx)
1216 self.pg_enable_capture(self.pg_interfaces)
1219 rx = self.pg2.get_capture(257)
1220 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1221 rx = self.pg3.get_capture(257)
1222 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1225 # An an IP multicast route via the tunnel
1227 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1229 route_232_1_1_1 = VppIpMRoute(
1233 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1234 [VppMRoutePath(self.pg0.sw_if_index,
1235 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1236 VppMRoutePath(mpls_tun._sw_if_index,
1237 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1238 route_232_1_1_1.add_vpp_config()
1239 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1241 self.vapi.cli("clear trace")
1242 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1243 self.pg0.add_stream(tx)
1245 self.pg_enable_capture(self.pg_interfaces)
1248 rx = self.pg2.get_capture(257)
1249 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1250 rx = self.pg3.get_capture(257)
1251 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1253 def test_mcast_ip4_tail(self):
1254 """ MPLS IPv4 Multicast Tail """
1257 # Add a multicast route that will forward the traffic
1260 route_232_1_1_1 = VppIpMRoute(
1264 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1266 paths=[VppMRoutePath(self.pg1.sw_if_index,
1267 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1268 route_232_1_1_1.add_vpp_config()
1271 # An interface receive label that maps traffic to RX on interface
1273 # by injecting the packet in on pg0, which is in table 0
1274 # doing an rpf-id and matching a route in table 1
1275 # if the packet egresses, then we must have matched the route in
1278 route_34_eos = VppMplsRoute(
1280 [VppRoutePath("0.0.0.0",
1285 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1287 route_34_eos.add_vpp_config()
1290 # Drop due to interface lookup miss
1292 self.vapi.cli("clear trace")
1293 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1294 dst_ip="232.1.1.1", n=1)
1295 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1298 # set the RPF-ID of the entry to match the input packet's
1300 route_232_1_1_1.update_rpf_id(55)
1301 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1303 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1305 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1306 self.verify_capture_ip4(self.pg1, rx, tx)
1309 # disposed packets have an invalid IPv4 checksum
1311 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1312 dst_ip="232.1.1.1", n=65,
1314 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1317 # set the RPF-ID of the entry to not match the input packet's
1319 route_232_1_1_1.update_rpf_id(56)
1320 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1322 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1324 def test_mcast_ip6_tail(self):
1325 """ MPLS IPv6 Multicast Tail """
1328 # Add a multicast route that will forward the traffic
1331 route_ff = VppIpMRoute(
1335 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1337 paths=[VppMRoutePath(self.pg1.sw_if_index,
1338 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD,
1339 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1340 route_ff.add_vpp_config()
1343 # An interface receive label that maps traffic to RX on interface
1345 # by injecting the packet in on pg0, which is in table 0
1346 # doing an rpf-id and matching a route in table 1
1347 # if the packet egresses, then we must have matched the route in
1350 route_34_eos = VppMplsRoute(
1357 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1359 route_34_eos.add_vpp_config()
1362 # Drop due to interface lookup miss
1364 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1366 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1369 # set the RPF-ID of the entry to match the input packet's
1371 route_ff.update_rpf_id(55)
1373 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1375 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1376 self.verify_capture_ip6(self.pg1, rx, tx)
1379 # disposed packets have hop-limit = 1
1381 tx = self.create_stream_labelled_ip6(self.pg0,
1385 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1386 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1389 # set the RPF-ID of the entry to not match the input packet's
1391 route_ff.update_rpf_id(56)
1392 tx = self.create_stream_labelled_ip6(self.pg0,
1395 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1401 # Add a non-recursive route with a single out label
1403 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1404 [VppRoutePath(self.pg0.remote_ip4,
1405 self.pg0.sw_if_index,
1406 labels=[VppMplsLabel(45)])])
1407 route_10_0_0_1.add_vpp_config()
1409 # bind a local label to the route
1410 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1411 binding.add_vpp_config()
1414 # a labelled v6 route that resolves through the v4
1416 route_2001_3 = VppIpRoute(
1417 self, "2001::3", 128,
1418 [VppRoutePath("10.0.0.1",
1420 labels=[VppMplsLabel(32)])])
1421 route_2001_3.add_vpp_config()
1423 tx = self.create_stream_ip6(self.pg0, "2001::3")
1424 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1426 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1431 # and a v4 recursive via the v6
1433 route_20_3 = VppIpRoute(
1434 self, "20.0.0.3", 32,
1435 [VppRoutePath("2001::3",
1437 labels=[VppMplsLabel(99)])])
1438 route_20_3.add_vpp_config()
1440 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1441 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1443 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1449 class TestMPLSDisabled(VppTestCase):
1450 """ MPLS disabled """
1453 def setUpClass(cls):
1454 super(TestMPLSDisabled, cls).setUpClass()
1457 def tearDownClass(cls):
1458 super(TestMPLSDisabled, cls).tearDownClass()
1461 super(TestMPLSDisabled, self).setUp()
1463 # create 2 pg interfaces
1464 self.create_pg_interfaces(range(2))
1466 self.tbl = VppMplsTable(self, 0)
1467 self.tbl.add_vpp_config()
1469 # PG0 is MPLS enabled
1471 self.pg0.config_ip4()
1472 self.pg0.resolve_arp()
1473 self.pg0.enable_mpls()
1475 # PG 1 is not MPLS enabled
1479 for i in self.pg_interfaces:
1483 self.pg0.disable_mpls()
1484 super(TestMPLSDisabled, self).tearDown()
1486 def test_mpls_disabled(self):
1487 """ MPLS Disabled """
1489 tx = (Ether(src=self.pg1.remote_mac,
1490 dst=self.pg1.local_mac) /
1491 MPLS(label=32, ttl=64) /
1492 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1493 UDP(sport=1234, dport=1234) /
1497 # A simple MPLS xconnect - eos label in label out
1499 route_32_eos = VppMplsRoute(self, 32, 1,
1500 [VppRoutePath(self.pg0.remote_ip4,
1501 self.pg0.sw_if_index,
1503 route_32_eos.add_vpp_config()
1506 # PG1 does not forward IP traffic
1508 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1513 self.pg1.enable_mpls()
1516 # Now we get packets through
1518 self.pg1.add_stream(tx)
1519 self.pg_enable_capture(self.pg_interfaces)
1522 rx = self.pg0.get_capture(1)
1527 self.pg1.disable_mpls()
1530 # PG1 does not forward IP traffic
1532 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1533 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1536 class TestMPLSPIC(VppTestCase):
1537 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1540 def setUpClass(cls):
1541 super(TestMPLSPIC, cls).setUpClass()
1544 def tearDownClass(cls):
1545 super(TestMPLSPIC, cls).tearDownClass()
1548 super(TestMPLSPIC, self).setUp()
1550 # create 2 pg interfaces
1551 self.create_pg_interfaces(range(4))
1553 mpls_tbl = VppMplsTable(self, 0)
1554 mpls_tbl.add_vpp_config()
1555 tbl4 = VppIpTable(self, 1)
1556 tbl4.add_vpp_config()
1557 tbl6 = VppIpTable(self, 1, is_ip6=1)
1558 tbl6.add_vpp_config()
1562 self.pg0.config_ip4()
1563 self.pg0.resolve_arp()
1564 self.pg0.enable_mpls()
1567 self.pg1.config_ip4()
1568 self.pg1.resolve_arp()
1569 self.pg1.enable_mpls()
1571 # VRF (customer facing) link
1573 self.pg2.set_table_ip4(1)
1574 self.pg2.config_ip4()
1575 self.pg2.resolve_arp()
1576 self.pg2.set_table_ip6(1)
1577 self.pg2.config_ip6()
1578 self.pg2.resolve_ndp()
1581 self.pg3.set_table_ip4(1)
1582 self.pg3.config_ip4()
1583 self.pg3.resolve_arp()
1584 self.pg3.set_table_ip6(1)
1585 self.pg3.config_ip6()
1586 self.pg3.resolve_ndp()
1589 self.pg0.disable_mpls()
1590 self.pg1.disable_mpls()
1591 for i in self.pg_interfaces:
1597 super(TestMPLSPIC, self).tearDown()
1599 def test_mpls_ibgp_pic(self):
1600 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1602 1) setup many iBGP VPN routes via a pair of iBGP peers.
1603 2) Check EMCP forwarding to these peers
1604 3) withdraw the IGP route to one of these peers.
1605 4) check forwarding continues to the remaining peer
1609 # IGP+LDP core routes
1611 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1612 [VppRoutePath(self.pg0.remote_ip4,
1613 self.pg0.sw_if_index,
1615 core_10_0_0_45.add_vpp_config()
1617 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1618 [VppRoutePath(self.pg1.remote_ip4,
1619 self.pg1.sw_if_index,
1621 core_10_0_0_46.add_vpp_config()
1624 # Lot's of VPN routes. We need more the 64 so VPP will build
1625 # the fast convergence indirection
1629 for ii in range(NUM_PKTS):
1630 dst = "192.168.1.%d" % ii
1631 vpn_routes.append(VppIpRoute(
1637 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1642 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1644 vpn_routes[ii].add_vpp_config()
1646 pkts.append(Ether(dst=self.pg2.local_mac,
1647 src=self.pg2.remote_mac) /
1648 IP(src=self.pg2.remote_ip4, dst=dst) /
1649 UDP(sport=1234, dport=1234) /
1653 # Send the packet stream (one pkt to each VPN route)
1654 # - expect a 50-50 split of the traffic
1656 self.pg2.add_stream(pkts)
1657 self.pg_enable_capture(self.pg_interfaces)
1660 rx0 = self.pg0._get_capture(NUM_PKTS)
1661 rx1 = self.pg1._get_capture(NUM_PKTS)
1663 # not testing the LB hashing algorithm so we're not concerned
1664 # with the split ratio, just as long as neither is 0
1665 self.assertNotEqual(0, len(rx0))
1666 self.assertNotEqual(0, len(rx1))
1667 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1668 "Expected all (%s) packets across both ECMP paths. "
1669 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1672 # use a test CLI command to stop the FIB walk process, this
1673 # will prevent the FIB converging the VPN routes and thus allow
1674 # us to probe the interim (post-fail, pre-converge) state
1676 self.vapi.ppcli("test fib-walk-process disable")
1679 # Withdraw one of the IGP routes
1681 core_10_0_0_46.remove_vpp_config()
1684 # now all packets should be forwarded through the remaining peer
1686 self.vapi.ppcli("clear trace")
1687 self.pg2.add_stream(pkts)
1688 self.pg_enable_capture(self.pg_interfaces)
1691 rx0 = self.pg0.get_capture(NUM_PKTS)
1692 self.assertEqual(len(pkts), len(rx0),
1693 "Expected all (%s) packets across single path. "
1694 "rx0: %s." % (len(pkts), len(rx0)))
1697 # enable the FIB walk process to converge the FIB
1699 self.vapi.ppcli("test fib-walk-process enable")
1702 # packets should still be forwarded through the remaining peer
1704 self.pg2.add_stream(pkts)
1705 self.pg_enable_capture(self.pg_interfaces)
1708 rx0 = self.pg0.get_capture(NUM_PKTS)
1709 self.assertEqual(len(pkts), len(rx0),
1710 "Expected all (%s) packets across single path. "
1711 "rx0: %s." % (len(pkts), len(rx0)))
1714 # Add the IGP route back and we return to load-balancing
1716 core_10_0_0_46.add_vpp_config()
1718 self.pg2.add_stream(pkts)
1719 self.pg_enable_capture(self.pg_interfaces)
1722 rx0 = self.pg0._get_capture(NUM_PKTS)
1723 rx1 = self.pg1._get_capture(NUM_PKTS)
1724 self.assertNotEqual(0, len(rx0))
1725 self.assertNotEqual(0, len(rx1))
1726 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1727 "Expected all (%s) packets across both ECMP paths. "
1728 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1730 def test_mpls_ebgp_pic(self):
1731 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1733 1) setup many eBGP VPN routes via a pair of eBGP peers.
1734 2) Check EMCP forwarding to these peers
1735 3) withdraw one eBGP path - expect LB across remaining eBGP
1739 # Lot's of VPN routes. We need more the 64 so VPP will build
1740 # the fast convergence indirection
1745 for ii in range(NUM_PKTS):
1746 dst = "192.168.1.%d" % ii
1747 local_label = 1600 + ii
1748 vpn_routes.append(VppIpRoute(
1751 self.pg2.remote_ip4,
1754 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1756 self.pg3.remote_ip4,
1759 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1761 vpn_routes[ii].add_vpp_config()
1763 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1765 vpn_bindings[ii].add_vpp_config()
1767 pkts.append(Ether(dst=self.pg0.local_mac,
1768 src=self.pg0.remote_mac) /
1769 MPLS(label=local_label, ttl=64) /
1770 IP(src=self.pg0.remote_ip4, dst=dst) /
1771 UDP(sport=1234, dport=1234) /
1775 # Send the packet stream (one pkt to each VPN route)
1776 # - expect a 50-50 split of the traffic
1778 self.pg0.add_stream(pkts)
1779 self.pg_enable_capture(self.pg_interfaces)
1782 rx0 = self.pg2._get_capture(NUM_PKTS)
1783 rx1 = self.pg3._get_capture(NUM_PKTS)
1785 # not testing the LB hashing algorithm so we're not concerned
1786 # with the split ratio, just as long as neither is 0
1787 self.assertNotEqual(0, len(rx0))
1788 self.assertNotEqual(0, len(rx1))
1789 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1790 "Expected all (%s) packets across both ECMP paths. "
1791 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1794 # use a test CLI command to stop the FIB walk process, this
1795 # will prevent the FIB converging the VPN routes and thus allow
1796 # us to probe the interim (post-fail, pre-converge) state
1798 self.vapi.ppcli("test fib-walk-process disable")
1801 # withdraw the connected prefix on the interface.
1803 self.pg2.unconfig_ip4()
1806 # now all packets should be forwarded through the remaining peer
1808 self.pg0.add_stream(pkts)
1809 self.pg_enable_capture(self.pg_interfaces)
1812 rx0 = self.pg3.get_capture(NUM_PKTS)
1813 self.assertEqual(len(pkts), len(rx0),
1814 "Expected all (%s) packets across single path. "
1815 "rx0: %s." % (len(pkts), len(rx0)))
1818 # enable the FIB walk process to converge the FIB
1820 self.vapi.ppcli("test fib-walk-process enable")
1823 # packets should still be forwarded through the remaining peer
1825 self.pg0.add_stream(pkts)
1826 self.pg_enable_capture(self.pg_interfaces)
1829 rx0 = self.pg3.get_capture(NUM_PKTS)
1830 self.assertEqual(len(pkts), len(rx0),
1831 "Expected all (%s) packets across single path. "
1832 "rx0: %s." % (len(pkts), len(rx0)))
1835 # put the connected routes back
1837 self.pg2.config_ip4()
1838 self.pg2.resolve_arp()
1840 self.pg0.add_stream(pkts)
1841 self.pg_enable_capture(self.pg_interfaces)
1844 rx0 = self.pg2._get_capture(NUM_PKTS)
1845 rx1 = self.pg3._get_capture(NUM_PKTS)
1846 self.assertNotEqual(0, len(rx0))
1847 self.assertNotEqual(0, len(rx1))
1848 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1849 "Expected all (%s) packets across both ECMP paths. "
1850 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1852 def test_mpls_v6_ebgp_pic(self):
1853 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1855 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1856 2) Check EMCP forwarding to these peers
1857 3) withdraw one eBGP path - expect LB across remaining eBGP
1861 # Lot's of VPN routes. We need more the 64 so VPP will build
1862 # the fast convergence indirection
1867 for ii in range(NUM_PKTS):
1868 dst = "3000::%d" % ii
1869 local_label = 1600 + ii
1870 vpn_routes.append(VppIpRoute(
1873 self.pg2.remote_ip6,
1876 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1878 self.pg3.remote_ip6,
1881 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1883 vpn_routes[ii].add_vpp_config()
1885 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1887 vpn_bindings[ii].add_vpp_config()
1889 pkts.append(Ether(dst=self.pg0.local_mac,
1890 src=self.pg0.remote_mac) /
1891 MPLS(label=local_label, ttl=64) /
1892 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1893 UDP(sport=1234, dport=1234) /
1895 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
1897 self.pg0.add_stream(pkts)
1898 self.pg_enable_capture(self.pg_interfaces)
1901 rx0 = self.pg2._get_capture(NUM_PKTS)
1902 rx1 = self.pg3._get_capture(NUM_PKTS)
1903 self.assertNotEqual(0, len(rx0))
1904 self.assertNotEqual(0, len(rx1))
1905 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1906 "Expected all (%s) packets across both ECMP paths. "
1907 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1910 # use a test CLI command to stop the FIB walk process, this
1911 # will prevent the FIB converging the VPN routes and thus allow
1912 # us to probe the interim (post-fail, pre-converge) state
1914 self.vapi.ppcli("test fib-walk-process disable")
1917 # withdraw the connected prefix on the interface.
1918 # and shutdown the interface so the ND cache is flushed.
1920 self.pg2.unconfig_ip6()
1921 self.pg2.admin_down()
1924 # now all packets should be forwarded through the remaining peer
1926 self.pg0.add_stream(pkts)
1927 self.pg_enable_capture(self.pg_interfaces)
1930 rx0 = self.pg3.get_capture(NUM_PKTS)
1931 self.assertEqual(len(pkts), len(rx0),
1932 "Expected all (%s) packets across single path. "
1933 "rx0: %s." % (len(pkts), len(rx0)))
1936 # enable the FIB walk process to converge the FIB
1938 self.vapi.ppcli("test fib-walk-process enable")
1939 self.pg0.add_stream(pkts)
1940 self.pg_enable_capture(self.pg_interfaces)
1943 rx0 = self.pg3.get_capture(NUM_PKTS)
1944 self.assertEqual(len(pkts), len(rx0),
1945 "Expected all (%s) packets across single path. "
1946 "rx0: %s." % (len(pkts), len(rx0)))
1949 # put the connected routes back
1952 self.pg2.config_ip6()
1953 self.pg2.resolve_ndp()
1955 self.pg0.add_stream(pkts)
1956 self.pg_enable_capture(self.pg_interfaces)
1959 rx0 = self.pg2._get_capture(NUM_PKTS)
1960 rx1 = self.pg3._get_capture(NUM_PKTS)
1961 self.assertNotEqual(0, len(rx0))
1962 self.assertNotEqual(0, len(rx1))
1963 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1964 "Expected all (%s) packets across both ECMP paths. "
1965 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1968 class TestMPLSL2(VppTestCase):
1972 def setUpClass(cls):
1973 super(TestMPLSL2, cls).setUpClass()
1976 def tearDownClass(cls):
1977 super(TestMPLSL2, cls).tearDownClass()
1980 super(TestMPLSL2, self).setUp()
1982 # create 2 pg interfaces
1983 self.create_pg_interfaces(range(2))
1985 # create the default MPLS table
1987 tbl = VppMplsTable(self, 0)
1988 tbl.add_vpp_config()
1989 self.tables.append(tbl)
1991 # use pg0 as the core facing interface
1993 self.pg0.config_ip4()
1994 self.pg0.resolve_arp()
1995 self.pg0.enable_mpls()
1997 # use the other 2 for customer facing L2 links
1998 for i in self.pg_interfaces[1:]:
2002 for i in self.pg_interfaces[1:]:
2005 self.pg0.disable_mpls()
2006 self.pg0.unconfig_ip4()
2007 self.pg0.admin_down()
2008 super(TestMPLSL2, self).tearDown()
2010 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2011 capture = verify_filter(capture, sent)
2013 self.assertEqual(len(capture), len(sent))
2015 for i in range(len(capture)):
2019 # the MPLS TTL is 255 since it enters a new tunnel
2020 verify_mpls_stack(self, rx, mpls_labels)
2023 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2025 self.assertEqual(rx_eth.src, tx_eth.src)
2026 self.assertEqual(rx_eth.dst, tx_eth.dst)
2028 def test_vpws(self):
2029 """ Virtual Private Wire Service """
2032 # Create an MPLS tunnel that pushes 1 label
2033 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2034 # information is not in the packet, but we test it works anyway
2036 mpls_tun_1 = VppMPLSTunnelInterface(
2038 [VppRoutePath(self.pg0.remote_ip4,
2039 self.pg0.sw_if_index,
2040 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2042 mpls_tun_1.add_vpp_config()
2043 mpls_tun_1.admin_up()
2046 # Create a label entry to for 55 that does L2 input to the tunnel
2048 route_55_eos = VppMplsRoute(
2050 [VppRoutePath("0.0.0.0",
2051 mpls_tun_1.sw_if_index,
2052 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2053 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2054 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2055 route_55_eos.add_vpp_config()
2058 # Cross-connect the tunnel with one of the customers L2 interfaces
2060 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2061 mpls_tun_1.sw_if_index,
2063 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2064 self.pg1.sw_if_index,
2068 # inject a packet from the core
2070 pcore = (Ether(dst=self.pg0.local_mac,
2071 src=self.pg0.remote_mac) /
2072 MPLS(label=55, ttl=64) /
2073 Ether(dst="00:00:de:ad:ba:be",
2074 src="00:00:de:ad:be:ef") /
2075 IP(src="10.10.10.10", dst="11.11.11.11") /
2076 UDP(sport=1234, dport=1234) /
2079 tx0 = pcore * NUM_PKTS
2080 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2081 payload = pcore[MPLS].payload
2083 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2084 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2087 # Inject a packet from the customer/L2 side
2089 tx1 = pcore[MPLS].payload * NUM_PKTS
2090 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2092 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2094 def test_vpls(self):
2095 """ Virtual Private LAN Service """
2097 # Create a L2 MPLS tunnels
2099 mpls_tun1 = VppMPLSTunnelInterface(
2101 [VppRoutePath(self.pg0.remote_ip4,
2102 self.pg0.sw_if_index,
2103 labels=[VppMplsLabel(42)])],
2105 mpls_tun1.add_vpp_config()
2106 mpls_tun1.admin_up()
2108 mpls_tun2 = VppMPLSTunnelInterface(
2110 [VppRoutePath(self.pg0.remote_ip4,
2111 self.pg0.sw_if_index,
2112 labels=[VppMplsLabel(43)])],
2114 mpls_tun2.add_vpp_config()
2115 mpls_tun2.admin_up()
2118 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2119 # the latter includes a Psuedo Wire Control Word
2121 route_55_eos = VppMplsRoute(
2123 [VppRoutePath("0.0.0.0",
2124 mpls_tun1.sw_if_index,
2125 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2126 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2127 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2129 route_56_eos = VppMplsRoute(
2131 [VppRoutePath("0.0.0.0",
2132 mpls_tun2.sw_if_index,
2133 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2134 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2135 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2136 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2139 route_56_eos.add_vpp_config()
2140 route_55_eos.add_vpp_config()
2142 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2145 # add to tunnel to the customers bridge-domain
2147 self.vapi.sw_interface_set_l2_bridge(
2148 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2149 self.vapi.sw_interface_set_l2_bridge(
2150 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2151 self.vapi.sw_interface_set_l2_bridge(
2152 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2155 # Packet from host on the customer interface to each host
2156 # reachable over the core, and vice-versa
2158 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2159 src="00:00:de:ad:be:ef") /
2160 IP(src="10.10.10.10", dst="11.11.11.11") /
2161 UDP(sport=1234, dport=1234) /
2163 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2164 src="00:00:de:ad:be:ef") /
2165 IP(src="10.10.10.10", dst="11.11.11.12") /
2166 UDP(sport=1234, dport=1234) /
2168 p_core1 = (Ether(dst=self.pg0.local_mac,
2169 src=self.pg0.remote_mac) /
2170 MPLS(label=55, ttl=64) /
2171 Ether(src="00:00:de:ad:ba:b1",
2172 dst="00:00:de:ad:be:ef") /
2173 IP(dst="10.10.10.10", src="11.11.11.11") /
2174 UDP(sport=1234, dport=1234) /
2176 p_core2 = (Ether(dst=self.pg0.local_mac,
2177 src=self.pg0.remote_mac) /
2178 MPLS(label=56, ttl=64) /
2179 Raw('\x01' * 4) / # PW CW
2180 Ether(src="00:00:de:ad:ba:b2",
2181 dst="00:00:de:ad:be:ef") /
2182 IP(dst="10.10.10.10", src="11.11.11.12") /
2183 UDP(sport=1234, dport=1234) /
2187 # The BD is learning, so send in one of each packet to learn
2190 # 2 packets due to BD flooding
2191 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2192 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2194 # we've learnt this so expect it be be forwarded not flooded
2195 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2196 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2197 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2199 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2200 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2201 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2204 # now a stream in each direction from each host
2206 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2207 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2210 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2211 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2214 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2215 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2218 # remove interfaces from customers bridge-domain
2220 self.vapi.sw_interface_set_l2_bridge(
2221 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2222 self.vapi.sw_interface_set_l2_bridge(
2223 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2224 self.vapi.sw_interface_set_l2_bridge(
2225 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2228 if __name__ == '__main__':
2229 unittest.main(testRunner=VppTestRunner)