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
12 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
14 from scapy.packet import Raw
15 from scapy.layers.l2 import Ether
16 from scapy.layers.inet import IP, UDP, ICMP
17 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
18 from scapy.contrib.mpls import MPLS
21 def verify_filter(capture, sent):
22 if not len(capture) == len(sent):
23 # filter out any IPv6 RAs from the capture
30 def verify_mpls_stack(tst, rx, mpls_labels):
31 # the rx'd packet has the MPLS label popped
33 tst.assertEqual(eth.type, 0x8847)
37 for ii in range(len(mpls_labels)):
38 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
39 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
40 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
42 if ii == len(mpls_labels) - 1:
43 tst.assertEqual(rx_mpls.s, 1)
46 tst.assertEqual(rx_mpls.s, 0)
47 # pop the label to expose the next
48 rx_mpls = rx_mpls[MPLS].payload
51 class TestMPLS(VppTestCase):
52 """ MPLS Test Case """
55 super(TestMPLS, self).setUp()
57 # create 2 pg interfaces
58 self.create_pg_interfaces(range(4))
60 # setup both interfaces
61 # assign them different tables.
65 tbl = VppMplsTable(self, 0)
67 self.tables.append(tbl)
69 for i in self.pg_interfaces:
73 tbl = VppIpTable(self, table_id)
75 self.tables.append(tbl)
76 tbl = VppIpTable(self, table_id, is_ip6=1)
78 self.tables.append(tbl)
80 i.set_table_ip4(table_id)
81 i.set_table_ip6(table_id)
90 for i in self.pg_interfaces:
98 super(TestMPLS, self).tearDown()
100 # the default of 64 matches the IP packet TTL default
101 def create_stream_labelled_ip4(
111 self.reset_packet_infos()
113 for i in range(0, n):
114 info = self.create_packet_info(src_if, src_if)
115 payload = self.info_to_payload(info)
116 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
118 for ii in range(len(mpls_labels)):
119 p = p / MPLS(label=mpls_labels[ii].value,
120 ttl=mpls_labels[ii].ttl,
121 cos=mpls_labels[ii].exp)
124 p = (p / IP(src=src_if.local_ip4,
125 dst=src_if.remote_ip4,
127 UDP(sport=1234, dport=1234) /
130 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
131 UDP(sport=1234, dport=1234) /
134 p = (p / IP(src=ip_itf.remote_ip4,
135 dst=ip_itf.local_ip4,
140 p[IP].chksum = chksum
145 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
146 self.reset_packet_infos()
148 for i in range(0, 257):
149 info = self.create_packet_info(src_if, src_if)
150 payload = self.info_to_payload(info)
151 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
152 IP(src=src_if.remote_ip4, dst=dst_ip,
153 ttl=ip_ttl, tos=ip_dscp) /
154 UDP(sport=1234, dport=1234) /
160 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
161 self.reset_packet_infos()
163 for i in range(0, 257):
164 info = self.create_packet_info(src_if, src_if)
165 payload = self.info_to_payload(info)
166 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
167 IPv6(src=src_if.remote_ip6, dst=dst_ip,
168 hlim=ip_ttl, tc=ip_dscp) /
169 UDP(sport=1234, dport=1234) /
175 def create_stream_labelled_ip6(self, src_if, mpls_labels,
176 hlim=64, dst_ip=None):
178 dst_ip = src_if.remote_ip6
179 self.reset_packet_infos()
181 for i in range(0, 257):
182 info = self.create_packet_info(src_if, src_if)
183 payload = self.info_to_payload(info)
184 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
185 for l in mpls_labels:
186 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
188 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
189 UDP(sport=1234, dport=1234) /
195 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
196 ip_ttl=None, ip_dscp=0):
198 capture = verify_filter(capture, sent)
200 self.assertEqual(len(capture), len(sent))
202 for i in range(len(capture)):
206 # the rx'd packet has the MPLS label popped
208 self.assertEqual(eth.type, 0x800)
214 self.assertEqual(rx_ip.src, tx_ip.src)
215 self.assertEqual(rx_ip.dst, tx_ip.dst)
216 self.assertEqual(rx_ip.tos, ip_dscp)
218 # IP processing post pop has decremented the TTL
219 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
221 self.assertEqual(rx_ip.ttl, ip_ttl)
223 self.assertEqual(rx_ip.src, tx_ip.dst)
224 self.assertEqual(rx_ip.dst, tx_ip.src)
229 def verify_capture_labelled_ip4(self, src_if, capture, sent,
230 mpls_labels, ip_ttl=None):
232 capture = verify_filter(capture, sent)
234 self.assertEqual(len(capture), len(sent))
236 for i in range(len(capture)):
242 verify_mpls_stack(self, rx, mpls_labels)
244 self.assertEqual(rx_ip.src, tx_ip.src)
245 self.assertEqual(rx_ip.dst, tx_ip.dst)
247 # IP processing post pop has decremented the TTL
248 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
250 self.assertEqual(rx_ip.ttl, ip_ttl)
255 def verify_capture_labelled_ip6(self, src_if, capture, sent,
256 mpls_labels, ip_ttl=None):
258 capture = verify_filter(capture, sent)
260 self.assertEqual(len(capture), len(sent))
262 for i in range(len(capture)):
268 verify_mpls_stack(self, rx, mpls_labels)
270 self.assertEqual(rx_ip.src, tx_ip.src)
271 self.assertEqual(rx_ip.dst, tx_ip.dst)
273 # IP processing post pop has decremented the TTL
274 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
276 self.assertEqual(rx_ip.hlim, ip_ttl)
281 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
283 capture = verify_filter(capture, sent)
285 self.assertEqual(len(capture), len(sent))
287 for i in range(len(capture)):
293 verify_mpls_stack(self, rx, mpls_labels)
295 self.assertEqual(rx_ip.src, tx_ip.src)
296 self.assertEqual(rx_ip.dst, tx_ip.dst)
297 # IP processing post pop has decremented the TTL
298 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
303 def verify_capture_labelled(self, src_if, capture, sent,
306 capture = verify_filter(capture, sent)
308 self.assertEqual(len(capture), len(sent))
310 for i in range(len(capture)):
312 verify_mpls_stack(self, rx, mpls_labels)
316 def verify_capture_ip6(self, src_if, capture, sent,
317 ip_hlim=None, ip_dscp=0):
319 self.assertEqual(len(capture), len(sent))
321 for i in range(len(capture)):
325 # the rx'd packet has the MPLS label popped
327 self.assertEqual(eth.type, 0x86DD)
332 self.assertEqual(rx_ip.src, tx_ip.src)
333 self.assertEqual(rx_ip.dst, tx_ip.dst)
334 self.assertEqual(rx_ip.tc, ip_dscp)
335 # IP processing post pop has decremented the TTL
337 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
339 self.assertEqual(rx_ip.hlim, ip_hlim)
344 def verify_capture_ip6_icmp(self, src_if, capture, sent):
346 self.assertEqual(len(capture), len(sent))
348 for i in range(len(capture)):
352 # the rx'd packet has the MPLS label popped
354 self.assertEqual(eth.type, 0x86DD)
359 self.assertEqual(rx_ip.dst, tx_ip.src)
360 # ICMP sourced from the interface's address
361 self.assertEqual(rx_ip.src, src_if.local_ip6)
362 # hop-limit reset to 255 for IMCP packet
363 self.assertEqual(rx_ip.hlim, 254)
365 icmp = rx[ICMPv6TimeExceeded]
371 """ MPLS label swap tests """
374 # A simple MPLS xconnect - eos label in label out
376 route_32_eos = VppMplsRoute(self, 32, 1,
377 [VppRoutePath(self.pg0.remote_ip4,
378 self.pg0.sw_if_index,
379 labels=[VppMplsLabel(33)])])
380 route_32_eos.add_vpp_config()
383 # a stream that matches the route for 10.0.0.1
384 # PG0 is in the default table
386 tx = self.create_stream_labelled_ip4(self.pg0,
387 [VppMplsLabel(32, ttl=32, exp=1)])
388 rx = self.send_and_expect(self.pg0, tx, self.pg0)
389 self.verify_capture_labelled(self.pg0, rx, tx,
390 [VppMplsLabel(33, ttl=31, exp=1)])
393 # A simple MPLS xconnect - non-eos label in label out
395 route_32_neos = VppMplsRoute(self, 32, 0,
396 [VppRoutePath(self.pg0.remote_ip4,
397 self.pg0.sw_if_index,
398 labels=[VppMplsLabel(33)])])
399 route_32_neos.add_vpp_config()
402 # a stream that matches the route for 10.0.0.1
403 # PG0 is in the default table
405 tx = self.create_stream_labelled_ip4(self.pg0,
406 [VppMplsLabel(32, ttl=21, exp=7),
408 rx = self.send_and_expect(self.pg0, tx, self.pg0)
409 self.verify_capture_labelled(self.pg0, rx, tx,
410 [VppMplsLabel(33, ttl=20, exp=7),
414 # A simple MPLS xconnect - non-eos label in label out, uniform mode
416 route_42_neos = VppMplsRoute(
418 [VppRoutePath(self.pg0.remote_ip4,
419 self.pg0.sw_if_index,
420 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
421 route_42_neos.add_vpp_config()
423 tx = self.create_stream_labelled_ip4(self.pg0,
424 [VppMplsLabel(42, ttl=21, exp=7),
426 rx = self.send_and_expect(self.pg0, tx, self.pg0)
427 self.verify_capture_labelled(self.pg0, rx, tx,
428 [VppMplsLabel(43, ttl=20, exp=7),
432 # An MPLS xconnect - EOS label in IP out
434 route_33_eos = VppMplsRoute(self, 33, 1,
435 [VppRoutePath(self.pg0.remote_ip4,
436 self.pg0.sw_if_index,
438 route_33_eos.add_vpp_config()
440 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
441 rx = self.send_and_expect(self.pg0, tx, self.pg0)
442 self.verify_capture_ip4(self.pg0, rx, tx)
445 # disposed packets have an invalid IPv4 checkusm
447 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
448 dst_ip=self.pg0.remote_ip4,
451 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
454 # An MPLS xconnect - EOS label in IP out, uniform mode
456 route_3333_eos = VppMplsRoute(
458 [VppRoutePath(self.pg0.remote_ip4,
459 self.pg0.sw_if_index,
460 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
461 route_3333_eos.add_vpp_config()
463 tx = self.create_stream_labelled_ip4(
465 [VppMplsLabel(3333, ttl=55, exp=3)])
466 rx = self.send_and_expect(self.pg0, tx, self.pg0)
467 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
468 tx = self.create_stream_labelled_ip4(
470 [VppMplsLabel(3333, ttl=66, exp=4)])
471 rx = self.send_and_expect(self.pg0, tx, self.pg0)
472 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
475 # An MPLS xconnect - EOS label in IPv6 out
477 route_333_eos = VppMplsRoute(
479 [VppRoutePath(self.pg0.remote_ip6,
480 self.pg0.sw_if_index,
482 proto=DpoProto.DPO_PROTO_IP6)])
483 route_333_eos.add_vpp_config()
485 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
486 rx = self.send_and_expect(self.pg0, tx, self.pg0)
487 self.verify_capture_ip6(self.pg0, rx, tx)
490 # disposed packets have an TTL expired
492 tx = self.create_stream_labelled_ip6(self.pg0,
493 [VppMplsLabel(333, ttl=64)],
494 dst_ip=self.pg1.remote_ip6,
496 rx = self.send_and_expect(self.pg0, tx, self.pg0)
497 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
500 # An MPLS xconnect - EOS label in IPv6 out w imp-null
502 route_334_eos = VppMplsRoute(
504 [VppRoutePath(self.pg0.remote_ip6,
505 self.pg0.sw_if_index,
506 labels=[VppMplsLabel(3)],
507 proto=DpoProto.DPO_PROTO_IP6)])
508 route_334_eos.add_vpp_config()
510 tx = self.create_stream_labelled_ip6(self.pg0,
511 [VppMplsLabel(334, ttl=64)])
512 rx = self.send_and_expect(self.pg0, tx, self.pg0)
513 self.verify_capture_ip6(self.pg0, rx, tx)
516 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
518 route_335_eos = VppMplsRoute(
520 [VppRoutePath(self.pg0.remote_ip6,
521 self.pg0.sw_if_index,
522 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
523 proto=DpoProto.DPO_PROTO_IP6)])
524 route_335_eos.add_vpp_config()
526 tx = self.create_stream_labelled_ip6(
528 [VppMplsLabel(335, ttl=27, exp=4)])
529 rx = self.send_and_expect(self.pg0, tx, self.pg0)
530 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
533 # disposed packets have an TTL expired
535 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
536 dst_ip=self.pg1.remote_ip6,
538 rx = self.send_and_expect(self.pg0, tx, self.pg0)
539 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
542 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
543 # so this traffic should be dropped.
545 route_33_neos = VppMplsRoute(self, 33, 0,
546 [VppRoutePath(self.pg0.remote_ip4,
547 self.pg0.sw_if_index,
549 route_33_neos.add_vpp_config()
551 tx = self.create_stream_labelled_ip4(self.pg0,
554 self.send_and_assert_no_replies(
556 "MPLS non-EOS packets popped and forwarded")
559 # A recursive EOS x-connect, which resolves through another x-connect
562 route_34_eos = VppMplsRoute(self, 34, 1,
563 [VppRoutePath("0.0.0.0",
566 labels=[VppMplsLabel(44),
568 route_34_eos.add_vpp_config()
570 tx = self.create_stream_labelled_ip4(self.pg0,
571 [VppMplsLabel(34, ttl=3)])
572 rx = self.send_and_expect(self.pg0, tx, self.pg0)
573 self.verify_capture_labelled(self.pg0, rx, tx,
576 VppMplsLabel(45, ttl=2)])
579 # A recursive EOS x-connect, which resolves through another x-connect
582 route_35_eos = VppMplsRoute(
584 [VppRoutePath("0.0.0.0",
587 labels=[VppMplsLabel(44)])])
588 route_35_eos.add_vpp_config()
590 tx = self.create_stream_labelled_ip4(self.pg0,
591 [VppMplsLabel(35, ttl=3)])
592 rx = self.send_and_expect(self.pg0, tx, self.pg0)
593 self.verify_capture_labelled(self.pg0, rx, tx,
594 [VppMplsLabel(43, ttl=2),
595 VppMplsLabel(44, ttl=2)])
598 # A recursive non-EOS x-connect, which resolves through another
601 route_34_neos = VppMplsRoute(self, 34, 0,
602 [VppRoutePath("0.0.0.0",
605 labels=[VppMplsLabel(44),
607 route_34_neos.add_vpp_config()
609 tx = self.create_stream_labelled_ip4(self.pg0,
610 [VppMplsLabel(34, ttl=45),
612 rx = self.send_and_expect(self.pg0, tx, self.pg0)
613 # it's the 2nd (counting from 0) label in the stack that is swapped
614 self.verify_capture_labelled(self.pg0, rx, tx,
617 VppMplsLabel(46, ttl=44),
621 # an recursive IP route that resolves through the recursive non-eos
624 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
625 [VppRoutePath("0.0.0.0",
628 labels=[VppMplsLabel(55)])])
629 ip_10_0_0_1.add_vpp_config()
631 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
632 rx = self.send_and_expect(self.pg0, tx, self.pg0)
633 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
639 ip_10_0_0_1.remove_vpp_config()
640 route_34_neos.remove_vpp_config()
641 route_34_eos.remove_vpp_config()
642 route_33_neos.remove_vpp_config()
643 route_33_eos.remove_vpp_config()
644 route_32_neos.remove_vpp_config()
645 route_32_eos.remove_vpp_config()
648 """ MPLS Local Label Binding test """
651 # Add a non-recursive route with a single out label
653 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
654 [VppRoutePath(self.pg0.remote_ip4,
655 self.pg0.sw_if_index,
656 labels=[VppMplsLabel(45)])])
657 route_10_0_0_1.add_vpp_config()
659 # bind a local label to the route
660 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
661 binding.add_vpp_config()
664 tx = self.create_stream_labelled_ip4(self.pg0,
667 rx = self.send_and_expect(self.pg0, tx, self.pg0)
668 self.verify_capture_labelled(self.pg0, rx, tx,
669 [VppMplsLabel(45, ttl=63),
673 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
674 rx = self.send_and_expect(self.pg0, tx, self.pg0)
675 self.verify_capture_labelled(self.pg0, rx, tx,
676 [VppMplsLabel(45, ttl=63)])
679 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
680 rx = self.send_and_expect(self.pg0, tx, self.pg0)
681 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
686 binding.remove_vpp_config()
687 route_10_0_0_1.remove_vpp_config()
689 def test_imposition(self):
690 """ MPLS label imposition test """
693 # Add a non-recursive route with a single out label
695 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
696 [VppRoutePath(self.pg0.remote_ip4,
697 self.pg0.sw_if_index,
698 labels=[VppMplsLabel(32)])])
699 route_10_0_0_1.add_vpp_config()
702 # a stream that matches the route for 10.0.0.1
703 # PG0 is in the default table
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(32)])
710 # Add a non-recursive route with a 3 out labels
712 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
713 [VppRoutePath(self.pg0.remote_ip4,
714 self.pg0.sw_if_index,
715 labels=[VppMplsLabel(32),
718 route_10_0_0_2.add_vpp_config()
720 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
721 ip_ttl=44, ip_dscp=0xff)
722 rx = self.send_and_expect(self.pg0, tx, self.pg0)
723 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
730 # Add a non-recursive route with a single out label in uniform mode
732 route_10_0_0_3 = VppIpRoute(
733 self, "10.0.0.3", 32,
734 [VppRoutePath(self.pg0.remote_ip4,
735 self.pg0.sw_if_index,
736 labels=[VppMplsLabel(32,
737 mode=MplsLspMode.UNIFORM)])])
738 route_10_0_0_3.add_vpp_config()
740 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
741 ip_ttl=54, ip_dscp=0xbe)
742 rx = self.send_and_expect(self.pg0, tx, self.pg0)
743 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
744 [VppMplsLabel(32, ttl=53, exp=5)])
747 # Add a IPv6 non-recursive route with a single out label in
750 route_2001_3 = VppIpRoute(
751 self, "2001::3", 128,
752 [VppRoutePath(self.pg0.remote_ip6,
753 self.pg0.sw_if_index,
754 proto=DpoProto.DPO_PROTO_IP6,
755 labels=[VppMplsLabel(32,
756 mode=MplsLspMode.UNIFORM)])],
758 route_2001_3.add_vpp_config()
760 tx = self.create_stream_ip6(self.pg0, "2001::3",
761 ip_ttl=54, ip_dscp=0xbe)
762 rx = self.send_and_expect(self.pg0, tx, self.pg0)
763 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
764 [VppMplsLabel(32, ttl=53, exp=5)])
767 # add a recursive path, with output label, via the 1 label route
769 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
770 [VppRoutePath("10.0.0.1",
772 labels=[VppMplsLabel(44)])])
773 route_11_0_0_1.add_vpp_config()
776 # a stream that matches the route for 11.0.0.1, should pick up
777 # the label stack for 11.0.0.1 and 10.0.0.1
779 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
780 rx = self.send_and_expect(self.pg0, tx, self.pg0)
781 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
786 # add a recursive path, with 2 labels, via the 3 label route
788 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
789 [VppRoutePath("10.0.0.2",
791 labels=[VppMplsLabel(44),
793 route_11_0_0_2.add_vpp_config()
796 # a stream that matches the route for 11.0.0.1, should pick up
797 # the label stack for 11.0.0.1 and 10.0.0.1
799 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
800 rx = self.send_and_expect(self.pg0, tx, self.pg0)
801 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
811 route_11_0_0_2.remove_vpp_config()
812 route_11_0_0_1.remove_vpp_config()
813 route_10_0_0_2.remove_vpp_config()
814 route_10_0_0_1.remove_vpp_config()
816 def test_tunnel_pipe(self):
817 """ MPLS Tunnel Tests - Pipe """
820 # Create a tunnel with a single out label
822 mpls_tun = VppMPLSTunnelInterface(
824 [VppRoutePath(self.pg0.remote_ip4,
825 self.pg0.sw_if_index,
826 labels=[VppMplsLabel(44),
828 mpls_tun.add_vpp_config()
832 # add an unlabelled route through the new tunnel
834 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
835 [VppRoutePath("0.0.0.0",
836 mpls_tun._sw_if_index)])
837 route_10_0_0_3.add_vpp_config()
839 self.vapi.cli("clear trace")
840 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
841 self.pg0.add_stream(tx)
843 self.pg_enable_capture(self.pg_interfaces)
846 rx = self.pg0.get_capture()
847 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
852 # add a labelled route through the new tunnel
854 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
855 [VppRoutePath("0.0.0.0",
856 mpls_tun._sw_if_index,
858 route_10_0_0_4.add_vpp_config()
860 self.vapi.cli("clear trace")
861 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
862 self.pg0.add_stream(tx)
864 self.pg_enable_capture(self.pg_interfaces)
867 rx = self.pg0.get_capture()
868 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
871 VppMplsLabel(33, ttl=255)])
873 def test_tunnel_uniform(self):
874 """ MPLS Tunnel Tests - Uniform """
877 # Create a tunnel with a single out label
878 # The label stack is specified here from outer to inner
880 mpls_tun = VppMPLSTunnelInterface(
882 [VppRoutePath(self.pg0.remote_ip4,
883 self.pg0.sw_if_index,
884 labels=[VppMplsLabel(44, ttl=32),
885 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
886 mpls_tun.add_vpp_config()
890 # add an unlabelled route through the new tunnel
892 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
893 [VppRoutePath("0.0.0.0",
894 mpls_tun._sw_if_index)])
895 route_10_0_0_3.add_vpp_config()
897 self.vapi.cli("clear trace")
898 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
899 self.pg0.add_stream(tx)
901 self.pg_enable_capture(self.pg_interfaces)
904 rx = self.pg0.get_capture()
905 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
906 [VppMplsLabel(44, ttl=32),
907 VppMplsLabel(46, ttl=23)])
910 # add a labelled route through the new tunnel
912 route_10_0_0_4 = VppIpRoute(
913 self, "10.0.0.4", 32,
914 [VppRoutePath("0.0.0.0",
915 mpls_tun._sw_if_index,
916 labels=[VppMplsLabel(33, ttl=47)])])
917 route_10_0_0_4.add_vpp_config()
919 self.vapi.cli("clear trace")
920 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
921 self.pg0.add_stream(tx)
923 self.pg_enable_capture(self.pg_interfaces)
926 rx = self.pg0.get_capture()
927 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
928 [VppMplsLabel(44, ttl=32),
929 VppMplsLabel(46, ttl=47),
930 VppMplsLabel(33, ttl=47)])
932 def test_v4_exp_null(self):
933 """ MPLS V4 Explicit NULL test """
936 # The first test case has an MPLS TTL of 0
937 # all packet should be dropped
939 tx = self.create_stream_labelled_ip4(self.pg0,
940 [VppMplsLabel(0, ttl=0)])
941 self.send_and_assert_no_replies(self.pg0, tx,
942 "MPLS TTL=0 packets forwarded")
945 # a stream with a non-zero MPLS TTL
946 # PG0 is in the default table
948 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
949 rx = self.send_and_expect(self.pg0, tx, self.pg0)
950 self.verify_capture_ip4(self.pg0, rx, tx)
953 # a stream with a non-zero MPLS TTL
955 # we are ensuring the post-pop lookup occurs in the VRF table
957 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
958 rx = self.send_and_expect(self.pg1, tx, self.pg1)
959 self.verify_capture_ip4(self.pg1, rx, tx)
961 def test_v6_exp_null(self):
962 """ MPLS V6 Explicit NULL test """
965 # a stream with a non-zero MPLS TTL
966 # PG0 is in the default table
968 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
969 rx = self.send_and_expect(self.pg0, tx, self.pg0)
970 self.verify_capture_ip6(self.pg0, rx, tx)
973 # a stream with a non-zero MPLS TTL
975 # we are ensuring the post-pop lookup occurs in the VRF table
977 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
978 rx = self.send_and_expect(self.pg1, tx, self.pg1)
979 self.verify_capture_ip6(self.pg0, rx, tx)
985 # A de-agg route - next-hop lookup in default table
987 route_34_eos = VppMplsRoute(self, 34, 1,
988 [VppRoutePath("0.0.0.0",
991 route_34_eos.add_vpp_config()
994 # ping an interface in the default table
995 # PG0 is in the default table
997 tx = self.create_stream_labelled_ip4(self.pg0,
1001 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1002 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1005 # A de-agg route - next-hop lookup in non-default table
1007 route_35_eos = VppMplsRoute(self, 35, 1,
1008 [VppRoutePath("0.0.0.0",
1011 route_35_eos.add_vpp_config()
1014 # ping an interface in the non-default table
1015 # PG0 is in the default table. packet arrive labelled in the
1016 # default table and egress unlabelled in the non-default
1018 tx = self.create_stream_labelled_ip4(
1019 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1020 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1021 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1026 route_36_neos = VppMplsRoute(self, 36, 0,
1027 [VppRoutePath("0.0.0.0",
1029 route_36_neos.add_vpp_config()
1031 tx = self.create_stream_labelled_ip4(self.pg0,
1034 ping=1, ip_itf=self.pg1)
1035 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1036 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1038 route_36_neos.remove_vpp_config()
1039 route_35_eos.remove_vpp_config()
1040 route_34_eos.remove_vpp_config()
1042 def test_interface_rx(self):
1043 """ MPLS Interface Receive """
1046 # Add a non-recursive route that will forward the traffic
1049 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1051 paths=[VppRoutePath(self.pg1.remote_ip4,
1052 self.pg1.sw_if_index)])
1053 route_10_0_0_1.add_vpp_config()
1056 # An interface receive label that maps traffic to RX on interface
1058 # by injecting the packet in on pg0, which is in table 0
1059 # doing an interface-rx on pg1 and matching a route in table 1
1060 # if the packet egresses, then we must have swapped to pg1
1061 # so as to have matched the route in table 1
1063 route_34_eos = VppMplsRoute(self, 34, 1,
1064 [VppRoutePath("0.0.0.0",
1065 self.pg1.sw_if_index,
1066 is_interface_rx=1)])
1067 route_34_eos.add_vpp_config()
1070 # ping an interface in the default table
1071 # PG0 is in the default table
1073 tx = self.create_stream_labelled_ip4(self.pg0,
1076 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1077 self.verify_capture_ip4(self.pg1, rx, tx)
1079 def test_mcast_mid_point(self):
1080 """ MPLS Multicast Mid Point """
1083 # Add a non-recursive route that will forward the traffic
1086 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1088 paths=[VppRoutePath(self.pg1.remote_ip4,
1089 self.pg1.sw_if_index)])
1090 route_10_0_0_1.add_vpp_config()
1093 # Add a mcast entry that replicate to pg2 and pg3
1094 # and replicate to a interface-rx (like a bud node would)
1096 route_3400_eos = VppMplsRoute(
1098 [VppRoutePath(self.pg2.remote_ip4,
1099 self.pg2.sw_if_index,
1100 labels=[VppMplsLabel(3401)]),
1101 VppRoutePath(self.pg3.remote_ip4,
1102 self.pg3.sw_if_index,
1103 labels=[VppMplsLabel(3402)]),
1104 VppRoutePath("0.0.0.0",
1105 self.pg1.sw_if_index,
1106 is_interface_rx=1)],
1108 route_3400_eos.add_vpp_config()
1111 # ping an interface in the default table
1112 # PG0 is in the default table
1114 self.vapi.cli("clear trace")
1115 tx = self.create_stream_labelled_ip4(self.pg0,
1116 [VppMplsLabel(3400, ttl=64)],
1119 self.pg0.add_stream(tx)
1121 self.pg_enable_capture(self.pg_interfaces)
1124 rx = self.pg1.get_capture(257)
1125 self.verify_capture_ip4(self.pg1, rx, tx)
1127 rx = self.pg2.get_capture(257)
1128 self.verify_capture_labelled(self.pg2, rx, tx,
1129 [VppMplsLabel(3401, ttl=63)])
1130 rx = self.pg3.get_capture(257)
1131 self.verify_capture_labelled(self.pg3, rx, tx,
1132 [VppMplsLabel(3402, ttl=63)])
1134 def test_mcast_head(self):
1135 """ MPLS Multicast Head-end """
1138 # Create a multicast tunnel with two replications
1140 mpls_tun = VppMPLSTunnelInterface(
1142 [VppRoutePath(self.pg2.remote_ip4,
1143 self.pg2.sw_if_index,
1144 labels=[VppMplsLabel(42)]),
1145 VppRoutePath(self.pg3.remote_ip4,
1146 self.pg3.sw_if_index,
1147 labels=[VppMplsLabel(43)])],
1149 mpls_tun.add_vpp_config()
1153 # add an unlabelled route through the new tunnel
1155 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1156 [VppRoutePath("0.0.0.0",
1157 mpls_tun._sw_if_index)])
1158 route_10_0_0_3.add_vpp_config()
1160 self.vapi.cli("clear trace")
1161 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1162 self.pg0.add_stream(tx)
1164 self.pg_enable_capture(self.pg_interfaces)
1167 rx = self.pg2.get_capture(257)
1168 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1169 rx = self.pg3.get_capture(257)
1170 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1173 # An an IP multicast route via the tunnel
1175 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1177 route_232_1_1_1 = VppIpMRoute(
1181 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1182 [VppMRoutePath(self.pg0.sw_if_index,
1183 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1184 VppMRoutePath(mpls_tun._sw_if_index,
1185 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1186 route_232_1_1_1.add_vpp_config()
1188 self.vapi.cli("clear trace")
1189 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1190 self.pg0.add_stream(tx)
1192 self.pg_enable_capture(self.pg_interfaces)
1195 rx = self.pg2.get_capture(257)
1196 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1197 rx = self.pg3.get_capture(257)
1198 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1200 def test_mcast_ip4_tail(self):
1201 """ MPLS IPv4 Multicast Tail """
1204 # Add a multicast route that will forward the traffic
1207 route_232_1_1_1 = VppIpMRoute(
1211 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1213 paths=[VppMRoutePath(self.pg1.sw_if_index,
1214 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1215 route_232_1_1_1.add_vpp_config()
1218 # An interface receive label that maps traffic to RX on interface
1220 # by injecting the packet in on pg0, which is in table 0
1221 # doing an rpf-id and matching a route in table 1
1222 # if the packet egresses, then we must have matched the route in
1225 route_34_eos = VppMplsRoute(self, 34, 1,
1226 [VppRoutePath("0.0.0.0",
1227 self.pg1.sw_if_index,
1232 route_34_eos.add_vpp_config()
1235 # Drop due to interface lookup miss
1237 self.vapi.cli("clear trace")
1238 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1239 dst_ip="232.1.1.1", n=1)
1240 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1243 # set the RPF-ID of the enrtry to match the input packet's
1245 route_232_1_1_1.update_rpf_id(55)
1247 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1249 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1250 self.verify_capture_ip4(self.pg1, rx, tx)
1253 # disposed packets have an invalid IPv4 checkusm
1255 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1256 dst_ip="232.1.1.1", n=65,
1258 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1261 # set the RPF-ID of the entry to not match the input packet's
1263 route_232_1_1_1.update_rpf_id(56)
1264 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1266 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1268 def test_mcast_ip6_tail(self):
1269 """ MPLS IPv6 Multicast Tail """
1272 # Add a multicast route that will forward the traffic
1275 route_ff = VppIpMRoute(
1279 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1281 paths=[VppMRoutePath(self.pg1.sw_if_index,
1282 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
1284 route_ff.add_vpp_config()
1287 # An interface receive label that maps traffic to RX on interface
1289 # by injecting the packet in on pg0, which is in table 0
1290 # doing an rpf-id and matching a route in table 1
1291 # if the packet egresses, then we must have matched the route in
1294 route_34_eos = VppMplsRoute(
1297 self.pg1.sw_if_index,
1300 proto=DpoProto.DPO_PROTO_IP6)],
1303 route_34_eos.add_vpp_config()
1306 # Drop due to interface lookup miss
1308 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1310 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1313 # set the RPF-ID of the enrtry to match the input packet's
1315 route_ff.update_rpf_id(55)
1317 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1319 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1320 self.verify_capture_ip6(self.pg1, rx, tx)
1323 # disposed packets have hop-limit = 1
1325 tx = self.create_stream_labelled_ip6(self.pg0,
1329 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1330 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1333 # set the RPF-ID of the enrtry to not match the input packet's
1335 route_ff.update_rpf_id(56)
1336 tx = self.create_stream_labelled_ip6(self.pg0,
1339 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1342 class TestMPLSDisabled(VppTestCase):
1343 """ MPLS disabled """
1346 super(TestMPLSDisabled, self).setUp()
1348 # create 2 pg interfaces
1349 self.create_pg_interfaces(range(2))
1351 self.tbl = VppMplsTable(self, 0)
1352 self.tbl.add_vpp_config()
1354 # PG0 is MPLS enalbed
1356 self.pg0.config_ip4()
1357 self.pg0.resolve_arp()
1358 self.pg0.enable_mpls()
1360 # PG 1 is not MPLS enabled
1364 for i in self.pg_interfaces:
1368 self.pg0.disable_mpls()
1369 super(TestMPLSDisabled, self).tearDown()
1371 def test_mpls_disabled(self):
1372 """ MPLS Disabled """
1374 tx = (Ether(src=self.pg1.remote_mac,
1375 dst=self.pg1.local_mac) /
1376 MPLS(label=32, ttl=64) /
1377 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1378 UDP(sport=1234, dport=1234) /
1382 # A simple MPLS xconnect - eos label in label out
1384 route_32_eos = VppMplsRoute(self, 32, 1,
1385 [VppRoutePath(self.pg0.remote_ip4,
1386 self.pg0.sw_if_index,
1388 route_32_eos.add_vpp_config()
1391 # PG1 does not forward IP traffic
1393 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1398 self.pg1.enable_mpls()
1401 # Now we get packets through
1403 self.pg1.add_stream(tx)
1404 self.pg_enable_capture(self.pg_interfaces)
1407 rx = self.pg0.get_capture(1)
1412 self.pg1.disable_mpls()
1415 # PG1 does not forward IP traffic
1417 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1418 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1421 class TestMPLSPIC(VppTestCase):
1422 """ MPLS PIC edge convergence """
1425 super(TestMPLSPIC, self).setUp()
1427 # create 2 pg interfaces
1428 self.create_pg_interfaces(range(4))
1430 mpls_tbl = VppMplsTable(self, 0)
1431 mpls_tbl.add_vpp_config()
1432 tbl4 = VppIpTable(self, 1)
1433 tbl4.add_vpp_config()
1434 tbl6 = VppIpTable(self, 1, is_ip6=1)
1435 tbl6.add_vpp_config()
1439 self.pg0.config_ip4()
1440 self.pg0.resolve_arp()
1441 self.pg0.enable_mpls()
1443 self.pg1.config_ip4()
1444 self.pg1.resolve_arp()
1445 self.pg1.enable_mpls()
1447 # VRF (customer facing) link
1449 self.pg2.set_table_ip4(1)
1450 self.pg2.config_ip4()
1451 self.pg2.resolve_arp()
1452 self.pg2.set_table_ip6(1)
1453 self.pg2.config_ip6()
1454 self.pg2.resolve_ndp()
1456 self.pg3.set_table_ip4(1)
1457 self.pg3.config_ip4()
1458 self.pg3.resolve_arp()
1459 self.pg3.set_table_ip6(1)
1460 self.pg3.config_ip6()
1461 self.pg3.resolve_ndp()
1464 self.pg0.disable_mpls()
1465 self.pg1.disable_mpls()
1466 for i in self.pg_interfaces:
1472 super(TestMPLSPIC, self).tearDown()
1474 def test_mpls_ibgp_pic(self):
1475 """ MPLS iBGP PIC edge convergence
1477 1) setup many iBGP VPN routes via a pair of iBGP peers.
1478 2) Check EMCP forwarding to these peers
1479 3) withdraw the IGP route to one of these peers.
1480 4) check forwarding continues to the remaining peer
1484 # IGP+LDP core routes
1486 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1487 [VppRoutePath(self.pg0.remote_ip4,
1488 self.pg0.sw_if_index,
1490 core_10_0_0_45.add_vpp_config()
1492 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1493 [VppRoutePath(self.pg1.remote_ip4,
1494 self.pg1.sw_if_index,
1496 core_10_0_0_46.add_vpp_config()
1499 # Lot's of VPN routes. We need more the 64 so VPP will build
1500 # the fast convergence indirection
1504 for ii in range(64):
1505 dst = "192.168.1.%d" % ii
1506 vpn_routes.append(VppIpRoute(self, dst, 32,
1507 [VppRoutePath("10.0.0.45",
1511 VppRoutePath("10.0.0.46",
1514 is_resolve_host=1)],
1516 vpn_routes[ii].add_vpp_config()
1518 pkts.append(Ether(dst=self.pg2.local_mac,
1519 src=self.pg2.remote_mac) /
1520 IP(src=self.pg2.remote_ip4, dst=dst) /
1521 UDP(sport=1234, dport=1234) /
1525 # Send the packet stream (one pkt to each VPN route)
1526 # - expect a 50-50 split of the traffic
1528 self.pg2.add_stream(pkts)
1529 self.pg_enable_capture(self.pg_interfaces)
1532 rx0 = self.pg0._get_capture(1)
1533 rx1 = self.pg1._get_capture(1)
1535 # not testig the LB hashing algorithm so we're not concerned
1536 # with the split ratio, just as long as neither is 0
1537 self.assertNotEqual(0, len(rx0))
1538 self.assertNotEqual(0, len(rx1))
1541 # use a test CLI command to stop the FIB walk process, this
1542 # will prevent the FIB converging the VPN routes and thus allow
1543 # us to probe the interim (psot-fail, pre-converge) state
1545 self.vapi.ppcli("test fib-walk-process disable")
1548 # Withdraw one of the IGP routes
1550 core_10_0_0_46.remove_vpp_config()
1553 # now all packets should be forwarded through the remaining peer
1555 self.vapi.ppcli("clear trace")
1556 self.pg2.add_stream(pkts)
1557 self.pg_enable_capture(self.pg_interfaces)
1560 rx0 = self.pg0.get_capture(len(pkts))
1563 # enable the FIB walk process to converge the FIB
1565 self.vapi.ppcli("test fib-walk-process enable")
1568 # packets should still be forwarded through the remaining peer
1570 self.pg2.add_stream(pkts)
1571 self.pg_enable_capture(self.pg_interfaces)
1574 rx0 = self.pg0.get_capture(64)
1577 # Add the IGP route back and we return to load-balancing
1579 core_10_0_0_46.add_vpp_config()
1581 self.pg2.add_stream(pkts)
1582 self.pg_enable_capture(self.pg_interfaces)
1585 rx0 = self.pg0._get_capture(1)
1586 rx1 = self.pg1._get_capture(1)
1587 self.assertNotEqual(0, len(rx0))
1588 self.assertNotEqual(0, len(rx1))
1590 def test_mpls_ebgp_pic(self):
1591 """ MPLS eBGP PIC edge convergence
1593 1) setup many eBGP VPN routes via a pair of eBGP peers
1594 2) Check EMCP forwarding to these peers
1595 3) withdraw one eBGP path - expect LB across remaining eBGP
1599 # Lot's of VPN routes. We need more the 64 so VPP will build
1600 # the fast convergence indirection
1605 for ii in range(64):
1606 dst = "192.168.1.%d" % ii
1607 local_label = 1600 + ii
1608 vpn_routes.append(VppIpRoute(self, dst, 32,
1609 [VppRoutePath(self.pg2.remote_ip4,
1612 is_resolve_attached=1),
1613 VppRoutePath(self.pg3.remote_ip4,
1616 is_resolve_attached=1)],
1618 vpn_routes[ii].add_vpp_config()
1620 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1622 vpn_bindings[ii].add_vpp_config()
1624 pkts.append(Ether(dst=self.pg0.local_mac,
1625 src=self.pg0.remote_mac) /
1626 MPLS(label=local_label, ttl=64) /
1627 IP(src=self.pg0.remote_ip4, dst=dst) /
1628 UDP(sport=1234, dport=1234) /
1631 self.pg0.add_stream(pkts)
1632 self.pg_enable_capture(self.pg_interfaces)
1635 rx0 = self.pg2._get_capture(1)
1636 rx1 = self.pg3._get_capture(1)
1637 self.assertNotEqual(0, len(rx0))
1638 self.assertNotEqual(0, len(rx1))
1641 # use a test CLI command to stop the FIB walk process, this
1642 # will prevent the FIB converging the VPN routes and thus allow
1643 # us to probe the interim (psot-fail, pre-converge) state
1645 self.vapi.ppcli("test fib-walk-process disable")
1648 # withdraw the connected prefix on the interface.
1650 self.pg2.unconfig_ip4()
1653 # now all packets should be forwarded through the remaining peer
1655 self.pg0.add_stream(pkts)
1656 self.pg_enable_capture(self.pg_interfaces)
1659 rx0 = self.pg3.get_capture(len(pkts))
1662 # enable the FIB walk process to converge the FIB
1664 self.vapi.ppcli("test fib-walk-process enable")
1665 self.pg0.add_stream(pkts)
1666 self.pg_enable_capture(self.pg_interfaces)
1669 rx0 = self.pg3.get_capture(len(pkts))
1672 # put the connecteds back
1674 self.pg2.config_ip4()
1676 self.pg0.add_stream(pkts)
1677 self.pg_enable_capture(self.pg_interfaces)
1680 rx0 = self.pg2._get_capture(1)
1681 rx1 = self.pg3._get_capture(1)
1682 self.assertNotEqual(0, len(rx0))
1683 self.assertNotEqual(0, len(rx1))
1685 def test_mpls_v6_ebgp_pic(self):
1686 """ MPLSv6 eBGP PIC edge convergence
1688 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1689 2) Check EMCP forwarding to these peers
1690 3) withdraw one eBGP path - expect LB across remaining eBGP
1694 # Lot's of VPN routes. We need more the 64 so VPP will build
1695 # the fast convergence indirection
1700 for ii in range(64):
1701 dst = "3000::%d" % ii
1702 local_label = 1600 + ii
1703 vpn_routes.append(VppIpRoute(
1705 [VppRoutePath(self.pg2.remote_ip6,
1708 is_resolve_attached=1,
1709 proto=DpoProto.DPO_PROTO_IP6),
1710 VppRoutePath(self.pg3.remote_ip6,
1713 proto=DpoProto.DPO_PROTO_IP6,
1714 is_resolve_attached=1)],
1717 vpn_routes[ii].add_vpp_config()
1719 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1722 vpn_bindings[ii].add_vpp_config()
1724 pkts.append(Ether(dst=self.pg0.local_mac,
1725 src=self.pg0.remote_mac) /
1726 MPLS(label=local_label, ttl=64) /
1727 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1728 UDP(sport=1234, dport=1234) /
1731 self.pg0.add_stream(pkts)
1732 self.pg_enable_capture(self.pg_interfaces)
1735 rx0 = self.pg2._get_capture(1)
1736 rx1 = self.pg3._get_capture(1)
1737 self.assertNotEqual(0, len(rx0))
1738 self.assertNotEqual(0, len(rx1))
1741 # use a test CLI command to stop the FIB walk process, this
1742 # will prevent the FIB converging the VPN routes and thus allow
1743 # us to probe the interim (psot-fail, pre-converge) state
1745 self.vapi.ppcli("test fib-walk-process disable")
1748 # withdraw the connected prefix on the interface.
1749 # and shutdown the interface so the ND cache is flushed.
1751 self.pg2.unconfig_ip6()
1752 self.pg2.admin_down()
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(len(pkts))
1764 # enable the FIB walk process to converge the FIB
1766 self.vapi.ppcli("test fib-walk-process enable")
1767 self.pg0.add_stream(pkts)
1768 self.pg_enable_capture(self.pg_interfaces)
1771 rx0 = self.pg3.get_capture(len(pkts))
1774 # put the connecteds back
1777 self.pg2.config_ip6()
1779 self.pg0.add_stream(pkts)
1780 self.pg_enable_capture(self.pg_interfaces)
1783 rx0 = self.pg2._get_capture(1)
1784 rx1 = self.pg3._get_capture(1)
1785 self.assertNotEqual(0, len(rx0))
1786 self.assertNotEqual(0, len(rx1))
1789 class TestMPLSL2(VppTestCase):
1793 super(TestMPLSL2, self).setUp()
1795 # create 2 pg interfaces
1796 self.create_pg_interfaces(range(2))
1798 # create the default MPLS table
1800 tbl = VppMplsTable(self, 0)
1801 tbl.add_vpp_config()
1802 self.tables.append(tbl)
1804 # use pg0 as the core facing interface
1806 self.pg0.config_ip4()
1807 self.pg0.resolve_arp()
1808 self.pg0.enable_mpls()
1810 # use the other 2 for customer facing L2 links
1811 for i in self.pg_interfaces[1:]:
1815 for i in self.pg_interfaces[1:]:
1818 self.pg0.disable_mpls()
1819 self.pg0.unconfig_ip4()
1820 self.pg0.admin_down()
1821 super(TestMPLSL2, self).tearDown()
1823 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
1824 capture = verify_filter(capture, sent)
1826 self.assertEqual(len(capture), len(sent))
1828 for i in range(len(capture)):
1832 # the MPLS TTL is 255 since it enters a new tunnel
1833 verify_mpls_stack(self, rx, mpls_labels)
1836 rx_eth = Ether(str(rx[MPLS].payload))
1838 self.assertEqual(rx_eth.src, tx_eth.src)
1839 self.assertEqual(rx_eth.dst, tx_eth.dst)
1841 def test_vpws(self):
1842 """ Virtual Private Wire Service """
1845 # Create an MPLS tunnel that pushes 1 label
1846 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
1847 # information is not in the packet, but we test it works anyway
1849 mpls_tun_1 = VppMPLSTunnelInterface(
1851 [VppRoutePath(self.pg0.remote_ip4,
1852 self.pg0.sw_if_index,
1853 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
1855 mpls_tun_1.add_vpp_config()
1856 mpls_tun_1.admin_up()
1859 # Create a label entry to for 55 that does L2 input to the tunnel
1861 route_55_eos = VppMplsRoute(
1863 [VppRoutePath("0.0.0.0",
1864 mpls_tun_1.sw_if_index,
1866 proto=DpoProto.DPO_PROTO_ETHERNET)])
1867 route_55_eos.add_vpp_config()
1870 # Cross-connect the tunnel with one of the customers L2 interfaces
1872 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
1873 mpls_tun_1.sw_if_index,
1875 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
1876 self.pg1.sw_if_index,
1880 # inject a packet from the core
1882 pcore = (Ether(dst=self.pg0.local_mac,
1883 src=self.pg0.remote_mac) /
1884 MPLS(label=55, ttl=64) /
1885 Ether(dst="00:00:de:ad:ba:be",
1886 src="00:00:de:ad:be:ef") /
1887 IP(src="10.10.10.10", dst="11.11.11.11") /
1888 UDP(sport=1234, dport=1234) /
1892 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
1893 payload = pcore[MPLS].payload
1895 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
1896 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
1899 # Inject a packet from the custoer/L2 side
1901 tx1 = pcore[MPLS].payload * 65
1902 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
1904 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
1906 def test_vpls(self):
1907 """ Virtual Private LAN Service """
1909 # Create an L2 MPLS tunnel
1911 mpls_tun = VppMPLSTunnelInterface(
1913 [VppRoutePath(self.pg0.remote_ip4,
1914 self.pg0.sw_if_index,
1915 labels=[VppMplsLabel(42)])],
1917 mpls_tun.add_vpp_config()
1921 # Create a label entry to for 55 that does L2 input to the tunnel
1923 route_55_eos = VppMplsRoute(
1925 [VppRoutePath("0.0.0.0",
1926 mpls_tun.sw_if_index,
1928 proto=DpoProto.DPO_PROTO_ETHERNET)])
1929 route_55_eos.add_vpp_config()
1932 # add to tunnel to the customers bridge-domain
1934 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
1936 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
1940 # Packet from the customer interface and from the core
1942 p_cust = (Ether(dst="00:00:de:ad:ba:be",
1943 src="00:00:de:ad:be:ef") /
1944 IP(src="10.10.10.10", dst="11.11.11.11") /
1945 UDP(sport=1234, dport=1234) /
1947 p_core = (Ether(src="00:00:de:ad:ba:be",
1948 dst="00:00:de:ad:be:ef") /
1949 IP(dst="10.10.10.10", src="11.11.11.11") /
1950 UDP(sport=1234, dport=1234) /
1954 # The BD is learning, so send in one of each packet to learn
1956 p_core_encap = (Ether(dst=self.pg0.local_mac,
1957 src=self.pg0.remote_mac) /
1958 MPLS(label=55, ttl=64) /
1961 self.pg1.add_stream(p_cust)
1962 self.pg_enable_capture(self.pg_interfaces)
1964 self.pg0.add_stream(p_core_encap)
1965 self.pg_enable_capture(self.pg_interfaces)
1968 # we've learnt this so expect it be be forwarded
1969 rx0 = self.pg1.get_capture(1)
1971 self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst)
1972 self.assertEqual(rx0[0][Ether].src, p_core[Ether].src)
1975 # now a stream in each direction
1977 self.pg1.add_stream(p_cust * 65)
1978 self.pg_enable_capture(self.pg_interfaces)
1981 rx0 = self.pg0.get_capture(65)
1983 self.verify_capture_tunneled_ethernet(rx0, p_cust*65,
1987 # remove interfaces from customers bridge-domain
1989 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
1992 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
1996 if __name__ == '__main__':
1997 unittest.main(testRunner=VppTestRunner)