6 from framework import VppTestCase, VppTestRunner
7 from vpp_ip import DpoProto
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")
1398 class TestMPLSDisabled(VppTestCase):
1399 """ MPLS disabled """
1402 def setUpClass(cls):
1403 super(TestMPLSDisabled, cls).setUpClass()
1406 def tearDownClass(cls):
1407 super(TestMPLSDisabled, cls).tearDownClass()
1410 super(TestMPLSDisabled, self).setUp()
1412 # create 2 pg interfaces
1413 self.create_pg_interfaces(range(2))
1415 self.tbl = VppMplsTable(self, 0)
1416 self.tbl.add_vpp_config()
1418 # PG0 is MPLS enabled
1420 self.pg0.config_ip4()
1421 self.pg0.resolve_arp()
1422 self.pg0.enable_mpls()
1424 # PG 1 is not MPLS enabled
1428 for i in self.pg_interfaces:
1432 self.pg0.disable_mpls()
1433 super(TestMPLSDisabled, self).tearDown()
1435 def test_mpls_disabled(self):
1436 """ MPLS Disabled """
1438 tx = (Ether(src=self.pg1.remote_mac,
1439 dst=self.pg1.local_mac) /
1440 MPLS(label=32, ttl=64) /
1441 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1442 UDP(sport=1234, dport=1234) /
1446 # A simple MPLS xconnect - eos label in label out
1448 route_32_eos = VppMplsRoute(self, 32, 1,
1449 [VppRoutePath(self.pg0.remote_ip4,
1450 self.pg0.sw_if_index,
1452 route_32_eos.add_vpp_config()
1455 # PG1 does not forward IP traffic
1457 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1462 self.pg1.enable_mpls()
1465 # Now we get packets through
1467 self.pg1.add_stream(tx)
1468 self.pg_enable_capture(self.pg_interfaces)
1471 rx = self.pg0.get_capture(1)
1476 self.pg1.disable_mpls()
1479 # PG1 does not forward IP traffic
1481 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1482 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1485 class TestMPLSPIC(VppTestCase):
1486 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1489 def setUpClass(cls):
1490 super(TestMPLSPIC, cls).setUpClass()
1493 def tearDownClass(cls):
1494 super(TestMPLSPIC, cls).tearDownClass()
1497 super(TestMPLSPIC, self).setUp()
1499 # create 2 pg interfaces
1500 self.create_pg_interfaces(range(4))
1502 mpls_tbl = VppMplsTable(self, 0)
1503 mpls_tbl.add_vpp_config()
1504 tbl4 = VppIpTable(self, 1)
1505 tbl4.add_vpp_config()
1506 tbl6 = VppIpTable(self, 1, is_ip6=1)
1507 tbl6.add_vpp_config()
1511 self.pg0.config_ip4()
1512 self.pg0.resolve_arp()
1513 self.pg0.enable_mpls()
1516 self.pg1.config_ip4()
1517 self.pg1.resolve_arp()
1518 self.pg1.enable_mpls()
1520 # VRF (customer facing) link
1522 self.pg2.set_table_ip4(1)
1523 self.pg2.config_ip4()
1524 self.pg2.resolve_arp()
1525 self.pg2.set_table_ip6(1)
1526 self.pg2.config_ip6()
1527 self.pg2.resolve_ndp()
1530 self.pg3.set_table_ip4(1)
1531 self.pg3.config_ip4()
1532 self.pg3.resolve_arp()
1533 self.pg3.set_table_ip6(1)
1534 self.pg3.config_ip6()
1535 self.pg3.resolve_ndp()
1538 self.pg0.disable_mpls()
1539 self.pg1.disable_mpls()
1540 for i in self.pg_interfaces:
1546 super(TestMPLSPIC, self).tearDown()
1548 def test_mpls_ibgp_pic(self):
1549 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1551 1) setup many iBGP VPN routes via a pair of iBGP peers.
1552 2) Check EMCP forwarding to these peers
1553 3) withdraw the IGP route to one of these peers.
1554 4) check forwarding continues to the remaining peer
1558 # IGP+LDP core routes
1560 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1561 [VppRoutePath(self.pg0.remote_ip4,
1562 self.pg0.sw_if_index,
1564 core_10_0_0_45.add_vpp_config()
1566 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1567 [VppRoutePath(self.pg1.remote_ip4,
1568 self.pg1.sw_if_index,
1570 core_10_0_0_46.add_vpp_config()
1573 # Lot's of VPN routes. We need more the 64 so VPP will build
1574 # the fast convergence indirection
1578 for ii in range(NUM_PKTS):
1579 dst = "192.168.1.%d" % ii
1580 vpn_routes.append(VppIpRoute(
1586 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1591 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1593 vpn_routes[ii].add_vpp_config()
1595 pkts.append(Ether(dst=self.pg2.local_mac,
1596 src=self.pg2.remote_mac) /
1597 IP(src=self.pg2.remote_ip4, dst=dst) /
1598 UDP(sport=1234, dport=1234) /
1602 # Send the packet stream (one pkt to each VPN route)
1603 # - expect a 50-50 split of the traffic
1605 self.pg2.add_stream(pkts)
1606 self.pg_enable_capture(self.pg_interfaces)
1609 rx0 = self.pg0._get_capture(NUM_PKTS)
1610 rx1 = self.pg1._get_capture(NUM_PKTS)
1612 # not testing the LB hashing algorithm so we're not concerned
1613 # with the split ratio, just as long as neither is 0
1614 self.assertNotEqual(0, len(rx0))
1615 self.assertNotEqual(0, len(rx1))
1616 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1617 "Expected all (%s) packets across both ECMP paths. "
1618 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1621 # use a test CLI command to stop the FIB walk process, this
1622 # will prevent the FIB converging the VPN routes and thus allow
1623 # us to probe the interim (post-fail, pre-converge) state
1625 self.vapi.ppcli("test fib-walk-process disable")
1628 # Withdraw one of the IGP routes
1630 core_10_0_0_46.remove_vpp_config()
1633 # now all packets should be forwarded through the remaining peer
1635 self.vapi.ppcli("clear trace")
1636 self.pg2.add_stream(pkts)
1637 self.pg_enable_capture(self.pg_interfaces)
1640 rx0 = self.pg0.get_capture(NUM_PKTS)
1641 self.assertEqual(len(pkts), len(rx0),
1642 "Expected all (%s) packets across single path. "
1643 "rx0: %s." % (len(pkts), len(rx0)))
1646 # enable the FIB walk process to converge the FIB
1648 self.vapi.ppcli("test fib-walk-process enable")
1651 # packets should still be forwarded through the remaining peer
1653 self.pg2.add_stream(pkts)
1654 self.pg_enable_capture(self.pg_interfaces)
1657 rx0 = self.pg0.get_capture(NUM_PKTS)
1658 self.assertEqual(len(pkts), len(rx0),
1659 "Expected all (%s) packets across single path. "
1660 "rx0: %s." % (len(pkts), len(rx0)))
1663 # Add the IGP route back and we return to load-balancing
1665 core_10_0_0_46.add_vpp_config()
1667 self.pg2.add_stream(pkts)
1668 self.pg_enable_capture(self.pg_interfaces)
1671 rx0 = self.pg0._get_capture(NUM_PKTS)
1672 rx1 = self.pg1._get_capture(NUM_PKTS)
1673 self.assertNotEqual(0, len(rx0))
1674 self.assertNotEqual(0, len(rx1))
1675 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1676 "Expected all (%s) packets across both ECMP paths. "
1677 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1679 def test_mpls_ebgp_pic(self):
1680 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1682 1) setup many eBGP VPN routes via a pair of eBGP peers.
1683 2) Check EMCP forwarding to these peers
1684 3) withdraw one eBGP path - expect LB across remaining eBGP
1688 # Lot's of VPN routes. We need more the 64 so VPP will build
1689 # the fast convergence indirection
1694 for ii in range(NUM_PKTS):
1695 dst = "192.168.1.%d" % ii
1696 local_label = 1600 + ii
1697 vpn_routes.append(VppIpRoute(
1700 self.pg2.remote_ip4,
1703 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1705 self.pg3.remote_ip4,
1708 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1710 vpn_routes[ii].add_vpp_config()
1712 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1714 vpn_bindings[ii].add_vpp_config()
1716 pkts.append(Ether(dst=self.pg0.local_mac,
1717 src=self.pg0.remote_mac) /
1718 MPLS(label=local_label, ttl=64) /
1719 IP(src=self.pg0.remote_ip4, dst=dst) /
1720 UDP(sport=1234, dport=1234) /
1724 # Send the packet stream (one pkt to each VPN route)
1725 # - expect a 50-50 split of the traffic
1727 self.pg0.add_stream(pkts)
1728 self.pg_enable_capture(self.pg_interfaces)
1731 rx0 = self.pg2._get_capture(NUM_PKTS)
1732 rx1 = self.pg3._get_capture(NUM_PKTS)
1734 # not testing the LB hashing algorithm so we're not concerned
1735 # with the split ratio, just as long as neither is 0
1736 self.assertNotEqual(0, len(rx0))
1737 self.assertNotEqual(0, len(rx1))
1738 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1739 "Expected all (%s) packets across both ECMP paths. "
1740 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1743 # use a test CLI command to stop the FIB walk process, this
1744 # will prevent the FIB converging the VPN routes and thus allow
1745 # us to probe the interim (post-fail, pre-converge) state
1747 self.vapi.ppcli("test fib-walk-process disable")
1750 # withdraw the connected prefix on the interface.
1752 self.pg2.unconfig_ip4()
1755 # now all packets should be forwarded through the remaining peer
1757 self.pg0.add_stream(pkts)
1758 self.pg_enable_capture(self.pg_interfaces)
1761 rx0 = self.pg3.get_capture(NUM_PKTS)
1762 self.assertEqual(len(pkts), len(rx0),
1763 "Expected all (%s) packets across single path. "
1764 "rx0: %s." % (len(pkts), len(rx0)))
1767 # enable the FIB walk process to converge the FIB
1769 self.vapi.ppcli("test fib-walk-process enable")
1772 # packets should still be forwarded through the remaining peer
1774 self.pg0.add_stream(pkts)
1775 self.pg_enable_capture(self.pg_interfaces)
1778 rx0 = self.pg3.get_capture(NUM_PKTS)
1779 self.assertEqual(len(pkts), len(rx0),
1780 "Expected all (%s) packets across single path. "
1781 "rx0: %s." % (len(pkts), len(rx0)))
1784 # put the connected routes back
1786 self.pg2.config_ip4()
1787 self.pg2.resolve_arp()
1789 self.pg0.add_stream(pkts)
1790 self.pg_enable_capture(self.pg_interfaces)
1793 rx0 = self.pg2._get_capture(NUM_PKTS)
1794 rx1 = self.pg3._get_capture(NUM_PKTS)
1795 self.assertNotEqual(0, len(rx0))
1796 self.assertNotEqual(0, len(rx1))
1797 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1798 "Expected all (%s) packets across both ECMP paths. "
1799 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1801 def test_mpls_v6_ebgp_pic(self):
1802 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1804 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1805 2) Check EMCP forwarding to these peers
1806 3) withdraw one eBGP path - expect LB across remaining eBGP
1810 # Lot's of VPN routes. We need more the 64 so VPP will build
1811 # the fast convergence indirection
1816 for ii in range(NUM_PKTS):
1817 dst = "3000::%d" % ii
1818 local_label = 1600 + ii
1819 vpn_routes.append(VppIpRoute(
1822 self.pg2.remote_ip6,
1825 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1827 self.pg3.remote_ip6,
1830 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1832 vpn_routes[ii].add_vpp_config()
1834 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1836 vpn_bindings[ii].add_vpp_config()
1838 pkts.append(Ether(dst=self.pg0.local_mac,
1839 src=self.pg0.remote_mac) /
1840 MPLS(label=local_label, ttl=64) /
1841 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1842 UDP(sport=1234, dport=1234) /
1844 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
1846 self.pg0.add_stream(pkts)
1847 self.pg_enable_capture(self.pg_interfaces)
1850 rx0 = self.pg2._get_capture(NUM_PKTS)
1851 rx1 = self.pg3._get_capture(NUM_PKTS)
1852 self.assertNotEqual(0, len(rx0))
1853 self.assertNotEqual(0, len(rx1))
1854 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1855 "Expected all (%s) packets across both ECMP paths. "
1856 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1859 # use a test CLI command to stop the FIB walk process, this
1860 # will prevent the FIB converging the VPN routes and thus allow
1861 # us to probe the interim (post-fail, pre-converge) state
1863 self.vapi.ppcli("test fib-walk-process disable")
1866 # withdraw the connected prefix on the interface.
1867 # and shutdown the interface so the ND cache is flushed.
1869 self.pg2.unconfig_ip6()
1870 self.pg2.admin_down()
1873 # now all packets should be forwarded through the remaining peer
1875 self.pg0.add_stream(pkts)
1876 self.pg_enable_capture(self.pg_interfaces)
1879 rx0 = self.pg3.get_capture(NUM_PKTS)
1880 self.assertEqual(len(pkts), len(rx0),
1881 "Expected all (%s) packets across single path. "
1882 "rx0: %s." % (len(pkts), len(rx0)))
1885 # enable the FIB walk process to converge the FIB
1887 self.vapi.ppcli("test fib-walk-process enable")
1888 self.pg0.add_stream(pkts)
1889 self.pg_enable_capture(self.pg_interfaces)
1892 rx0 = self.pg3.get_capture(NUM_PKTS)
1893 self.assertEqual(len(pkts), len(rx0),
1894 "Expected all (%s) packets across single path. "
1895 "rx0: %s." % (len(pkts), len(rx0)))
1898 # put the connected routes back
1901 self.pg2.config_ip6()
1902 self.pg2.resolve_ndp()
1904 self.pg0.add_stream(pkts)
1905 self.pg_enable_capture(self.pg_interfaces)
1908 rx0 = self.pg2._get_capture(NUM_PKTS)
1909 rx1 = self.pg3._get_capture(NUM_PKTS)
1910 self.assertNotEqual(0, len(rx0))
1911 self.assertNotEqual(0, len(rx1))
1912 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1913 "Expected all (%s) packets across both ECMP paths. "
1914 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1917 class TestMPLSL2(VppTestCase):
1921 def setUpClass(cls):
1922 super(TestMPLSL2, cls).setUpClass()
1925 def tearDownClass(cls):
1926 super(TestMPLSL2, cls).tearDownClass()
1929 super(TestMPLSL2, self).setUp()
1931 # create 2 pg interfaces
1932 self.create_pg_interfaces(range(2))
1934 # create the default MPLS table
1936 tbl = VppMplsTable(self, 0)
1937 tbl.add_vpp_config()
1938 self.tables.append(tbl)
1940 # use pg0 as the core facing interface
1942 self.pg0.config_ip4()
1943 self.pg0.resolve_arp()
1944 self.pg0.enable_mpls()
1946 # use the other 2 for customer facing L2 links
1947 for i in self.pg_interfaces[1:]:
1951 for i in self.pg_interfaces[1:]:
1954 self.pg0.disable_mpls()
1955 self.pg0.unconfig_ip4()
1956 self.pg0.admin_down()
1957 super(TestMPLSL2, self).tearDown()
1959 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
1960 capture = verify_filter(capture, sent)
1962 self.assertEqual(len(capture), len(sent))
1964 for i in range(len(capture)):
1968 # the MPLS TTL is 255 since it enters a new tunnel
1969 verify_mpls_stack(self, rx, mpls_labels)
1972 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
1974 self.assertEqual(rx_eth.src, tx_eth.src)
1975 self.assertEqual(rx_eth.dst, tx_eth.dst)
1977 def test_vpws(self):
1978 """ Virtual Private Wire Service """
1981 # Create an MPLS tunnel that pushes 1 label
1982 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
1983 # information is not in the packet, but we test it works anyway
1985 mpls_tun_1 = VppMPLSTunnelInterface(
1987 [VppRoutePath(self.pg0.remote_ip4,
1988 self.pg0.sw_if_index,
1989 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
1991 mpls_tun_1.add_vpp_config()
1992 mpls_tun_1.admin_up()
1995 # Create a label entry to for 55 that does L2 input to the tunnel
1997 route_55_eos = VppMplsRoute(
1999 [VppRoutePath("0.0.0.0",
2000 mpls_tun_1.sw_if_index,
2001 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2002 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2003 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2004 route_55_eos.add_vpp_config()
2007 # Cross-connect the tunnel with one of the customers L2 interfaces
2009 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2010 mpls_tun_1.sw_if_index,
2012 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2013 self.pg1.sw_if_index,
2017 # inject a packet from the core
2019 pcore = (Ether(dst=self.pg0.local_mac,
2020 src=self.pg0.remote_mac) /
2021 MPLS(label=55, ttl=64) /
2022 Ether(dst="00:00:de:ad:ba:be",
2023 src="00:00:de:ad:be:ef") /
2024 IP(src="10.10.10.10", dst="11.11.11.11") /
2025 UDP(sport=1234, dport=1234) /
2028 tx0 = pcore * NUM_PKTS
2029 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2030 payload = pcore[MPLS].payload
2032 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2033 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2036 # Inject a packet from the customer/L2 side
2038 tx1 = pcore[MPLS].payload * NUM_PKTS
2039 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2041 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2043 def test_vpls(self):
2044 """ Virtual Private LAN Service """
2046 # Create an L2 MPLS tunnel
2048 mpls_tun = VppMPLSTunnelInterface(
2050 [VppRoutePath(self.pg0.remote_ip4,
2051 self.pg0.sw_if_index,
2052 labels=[VppMplsLabel(42)])],
2054 mpls_tun.add_vpp_config()
2058 # Create a label entry to for 55 that does L2 input to the tunnel
2060 route_55_eos = VppMplsRoute(
2062 [VppRoutePath("0.0.0.0",
2063 mpls_tun.sw_if_index,
2064 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2065 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2066 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2067 route_55_eos.add_vpp_config()
2070 # add to tunnel to the customers bridge-domain
2072 self.vapi.sw_interface_set_l2_bridge(
2073 rx_sw_if_index=mpls_tun.sw_if_index, bd_id=1)
2074 self.vapi.sw_interface_set_l2_bridge(
2075 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2078 # Packet from the customer interface and from the core
2080 p_cust = (Ether(dst="00:00:de:ad:ba:be",
2081 src="00:00:de:ad:be:ef") /
2082 IP(src="10.10.10.10", dst="11.11.11.11") /
2083 UDP(sport=1234, dport=1234) /
2085 p_core = (Ether(src="00:00:de:ad:ba:be",
2086 dst="00:00:de:ad:be:ef") /
2087 IP(dst="10.10.10.10", src="11.11.11.11") /
2088 UDP(sport=1234, dport=1234) /
2092 # The BD is learning, so send in one of each packet to learn
2094 p_core_encap = (Ether(dst=self.pg0.local_mac,
2095 src=self.pg0.remote_mac) /
2096 MPLS(label=55, ttl=64) /
2099 self.pg1.add_stream(p_cust)
2100 self.pg_enable_capture(self.pg_interfaces)
2102 self.pg0.add_stream(p_core_encap)
2103 self.pg_enable_capture(self.pg_interfaces)
2106 # we've learnt this so expect it be be forwarded
2107 rx0 = self.pg1.get_capture(1)
2109 self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst)
2110 self.assertEqual(rx0[0][Ether].src, p_core[Ether].src)
2113 # now a stream in each direction
2115 self.pg1.add_stream(p_cust * NUM_PKTS)
2116 self.pg_enable_capture(self.pg_interfaces)
2119 rx0 = self.pg0.get_capture(NUM_PKTS)
2121 self.verify_capture_tunneled_ethernet(rx0, p_cust*NUM_PKTS,
2125 # remove interfaces from customers bridge-domain
2127 self.vapi.sw_interface_set_l2_bridge(
2128 rx_sw_if_index=mpls_tun.sw_if_index, bd_id=1, enable=0)
2129 self.vapi.sw_interface_set_l2_bridge(
2130 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2133 if __name__ == '__main__':
2134 unittest.main(testRunner=VppTestRunner)