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 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, 255)
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 find_mpls_route(self, 0, 32, 1,
384 [VppRoutePath(self.pg0.remote_ip4,
385 self.pg0.sw_if_index,
386 labels=[VppMplsLabel(33)])]))
389 # a stream that matches the route for 10.0.0.1
390 # PG0 is in the default table
392 tx = self.create_stream_labelled_ip4(self.pg0,
393 [VppMplsLabel(32, ttl=32, exp=1)])
394 rx = self.send_and_expect(self.pg0, tx, self.pg0)
395 self.verify_capture_labelled(self.pg0, rx, tx,
396 [VppMplsLabel(33, ttl=31, exp=1)])
398 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
401 # A simple MPLS xconnect - non-eos label in label out
403 route_32_neos = VppMplsRoute(self, 32, 0,
404 [VppRoutePath(self.pg0.remote_ip4,
405 self.pg0.sw_if_index,
406 labels=[VppMplsLabel(33)])])
407 route_32_neos.add_vpp_config()
410 # a stream that matches the route for 10.0.0.1
411 # PG0 is in the default table
413 tx = self.create_stream_labelled_ip4(self.pg0,
414 [VppMplsLabel(32, ttl=21, exp=7),
416 rx = self.send_and_expect(self.pg0, tx, self.pg0)
417 self.verify_capture_labelled(self.pg0, rx, tx,
418 [VppMplsLabel(33, ttl=20, exp=7),
420 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
423 # A simple MPLS xconnect - non-eos label in label out, uniform mode
425 route_42_neos = VppMplsRoute(
427 [VppRoutePath(self.pg0.remote_ip4,
428 self.pg0.sw_if_index,
429 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
430 route_42_neos.add_vpp_config()
432 tx = self.create_stream_labelled_ip4(self.pg0,
433 [VppMplsLabel(42, ttl=21, exp=7),
435 rx = self.send_and_expect(self.pg0, tx, self.pg0)
436 self.verify_capture_labelled(self.pg0, rx, tx,
437 [VppMplsLabel(43, ttl=20, exp=7),
441 # An MPLS xconnect - EOS label in IP out
443 route_33_eos = VppMplsRoute(self, 33, 1,
444 [VppRoutePath(self.pg0.remote_ip4,
445 self.pg0.sw_if_index,
447 route_33_eos.add_vpp_config()
449 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
450 rx = self.send_and_expect(self.pg0, tx, self.pg0)
451 self.verify_capture_ip4(self.pg0, rx, tx)
454 # disposed packets have an invalid IPv4 checkusm
456 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
457 dst_ip=self.pg0.remote_ip4,
460 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
463 # An MPLS xconnect - EOS label in IP out, uniform mode
465 route_3333_eos = VppMplsRoute(
467 [VppRoutePath(self.pg0.remote_ip4,
468 self.pg0.sw_if_index,
469 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
470 route_3333_eos.add_vpp_config()
472 tx = self.create_stream_labelled_ip4(
474 [VppMplsLabel(3333, ttl=55, exp=3)])
475 rx = self.send_and_expect(self.pg0, tx, self.pg0)
476 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
477 tx = self.create_stream_labelled_ip4(
479 [VppMplsLabel(3333, ttl=66, exp=4)])
480 rx = self.send_and_expect(self.pg0, tx, self.pg0)
481 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
484 # An MPLS xconnect - EOS label in IPv6 out
486 route_333_eos = VppMplsRoute(
488 [VppRoutePath(self.pg0.remote_ip6,
489 self.pg0.sw_if_index,
491 proto=DpoProto.DPO_PROTO_IP6)])
492 route_333_eos.add_vpp_config()
494 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
495 rx = self.send_and_expect(self.pg0, tx, self.pg0)
496 self.verify_capture_ip6(self.pg0, rx, tx)
499 # disposed packets have an TTL expired
501 tx = self.create_stream_labelled_ip6(self.pg0,
502 [VppMplsLabel(333, ttl=64)],
503 dst_ip=self.pg1.remote_ip6,
505 rx = self.send_and_expect(self.pg0, tx, self.pg0)
506 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
509 # An MPLS xconnect - EOS label in IPv6 out w imp-null
511 route_334_eos = VppMplsRoute(
513 [VppRoutePath(self.pg0.remote_ip6,
514 self.pg0.sw_if_index,
515 labels=[VppMplsLabel(3)],
516 proto=DpoProto.DPO_PROTO_IP6)])
517 route_334_eos.add_vpp_config()
519 tx = self.create_stream_labelled_ip6(self.pg0,
520 [VppMplsLabel(334, ttl=64)])
521 rx = self.send_and_expect(self.pg0, tx, self.pg0)
522 self.verify_capture_ip6(self.pg0, rx, tx)
525 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
527 route_335_eos = VppMplsRoute(
529 [VppRoutePath(self.pg0.remote_ip6,
530 self.pg0.sw_if_index,
531 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
532 proto=DpoProto.DPO_PROTO_IP6)])
533 route_335_eos.add_vpp_config()
535 tx = self.create_stream_labelled_ip6(
537 [VppMplsLabel(335, ttl=27, exp=4)])
538 rx = self.send_and_expect(self.pg0, tx, self.pg0)
539 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
542 # disposed packets have an TTL expired
544 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
545 dst_ip=self.pg1.remote_ip6,
547 rx = self.send_and_expect(self.pg0, tx, self.pg0)
548 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
551 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
552 # so this traffic should be dropped.
554 route_33_neos = VppMplsRoute(self, 33, 0,
555 [VppRoutePath(self.pg0.remote_ip4,
556 self.pg0.sw_if_index,
558 route_33_neos.add_vpp_config()
560 tx = self.create_stream_labelled_ip4(self.pg0,
563 self.send_and_assert_no_replies(
565 "MPLS non-EOS packets popped and forwarded")
568 # A recursive EOS x-connect, which resolves through another x-connect
571 route_34_eos = VppMplsRoute(self, 34, 1,
572 [VppRoutePath("0.0.0.0",
575 labels=[VppMplsLabel(44),
577 route_34_eos.add_vpp_config()
579 tx = self.create_stream_labelled_ip4(self.pg0,
580 [VppMplsLabel(34, ttl=3)])
581 rx = self.send_and_expect(self.pg0, tx, self.pg0)
582 self.verify_capture_labelled(self.pg0, rx, tx,
585 VppMplsLabel(45, ttl=2)])
587 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
588 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
591 # A recursive EOS x-connect, which resolves through another x-connect
594 route_35_eos = VppMplsRoute(
596 [VppRoutePath("0.0.0.0",
599 labels=[VppMplsLabel(44)])])
600 route_35_eos.add_vpp_config()
602 tx = self.create_stream_labelled_ip4(self.pg0,
603 [VppMplsLabel(35, ttl=3)])
604 rx = self.send_and_expect(self.pg0, tx, self.pg0)
605 self.verify_capture_labelled(self.pg0, rx, tx,
606 [VppMplsLabel(43, ttl=2),
607 VppMplsLabel(44, ttl=2)])
610 # A recursive non-EOS x-connect, which resolves through another
613 route_34_neos = VppMplsRoute(self, 34, 0,
614 [VppRoutePath("0.0.0.0",
617 labels=[VppMplsLabel(44),
619 route_34_neos.add_vpp_config()
621 tx = self.create_stream_labelled_ip4(self.pg0,
622 [VppMplsLabel(34, ttl=45),
624 rx = self.send_and_expect(self.pg0, tx, self.pg0)
625 # it's the 2nd (counting from 0) label in the stack that is swapped
626 self.verify_capture_labelled(self.pg0, rx, tx,
629 VppMplsLabel(46, ttl=44),
633 # an recursive IP route that resolves through the recursive non-eos
636 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
637 [VppRoutePath("0.0.0.0",
640 labels=[VppMplsLabel(55)])])
641 ip_10_0_0_1.add_vpp_config()
643 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
644 rx = self.send_and_expect(self.pg0, tx, self.pg0)
645 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
650 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
652 ip_10_0_0_1.remove_vpp_config()
653 route_34_neos.remove_vpp_config()
654 route_34_eos.remove_vpp_config()
655 route_33_neos.remove_vpp_config()
656 route_33_eos.remove_vpp_config()
657 route_32_neos.remove_vpp_config()
658 route_32_eos.remove_vpp_config()
661 """ MPLS Local Label Binding test """
664 # Add a non-recursive route with a single out label
666 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
667 [VppRoutePath(self.pg0.remote_ip4,
668 self.pg0.sw_if_index,
669 labels=[VppMplsLabel(45)])])
670 route_10_0_0_1.add_vpp_config()
672 # bind a local label to the route
673 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
674 binding.add_vpp_config()
677 tx = self.create_stream_labelled_ip4(self.pg0,
680 rx = self.send_and_expect(self.pg0, tx, self.pg0)
681 self.verify_capture_labelled(self.pg0, rx, tx,
682 [VppMplsLabel(45, ttl=63),
686 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
687 rx = self.send_and_expect(self.pg0, tx, self.pg0)
688 self.verify_capture_labelled(self.pg0, rx, tx,
689 [VppMplsLabel(45, ttl=63)])
692 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
693 rx = self.send_and_expect(self.pg0, tx, self.pg0)
694 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
699 binding.remove_vpp_config()
700 route_10_0_0_1.remove_vpp_config()
702 def test_imposition(self):
703 """ MPLS label imposition test """
706 # Add a non-recursive route with a single out label
708 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
709 [VppRoutePath(self.pg0.remote_ip4,
710 self.pg0.sw_if_index,
711 labels=[VppMplsLabel(32)])])
712 route_10_0_0_1.add_vpp_config()
715 # a stream that matches the route for 10.0.0.1
716 # PG0 is in the default table
718 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
719 rx = self.send_and_expect(self.pg0, tx, self.pg0)
720 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
723 # Add a non-recursive route with a 3 out labels
725 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
726 [VppRoutePath(self.pg0.remote_ip4,
727 self.pg0.sw_if_index,
728 labels=[VppMplsLabel(32),
731 route_10_0_0_2.add_vpp_config()
733 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
734 ip_ttl=44, ip_dscp=0xff)
735 rx = self.send_and_expect(self.pg0, tx, self.pg0)
736 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
743 # Add a non-recursive route with a single out label in uniform mode
745 route_10_0_0_3 = VppIpRoute(
746 self, "10.0.0.3", 32,
747 [VppRoutePath(self.pg0.remote_ip4,
748 self.pg0.sw_if_index,
749 labels=[VppMplsLabel(32,
750 mode=MplsLspMode.UNIFORM)])])
751 route_10_0_0_3.add_vpp_config()
753 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
754 ip_ttl=54, ip_dscp=0xbe)
755 rx = self.send_and_expect(self.pg0, tx, self.pg0)
756 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
757 [VppMplsLabel(32, ttl=53, exp=5)])
760 # Add a IPv6 non-recursive route with a single out label in
763 route_2001_3 = VppIpRoute(
764 self, "2001::3", 128,
765 [VppRoutePath(self.pg0.remote_ip6,
766 self.pg0.sw_if_index,
767 proto=DpoProto.DPO_PROTO_IP6,
768 labels=[VppMplsLabel(32,
769 mode=MplsLspMode.UNIFORM)])],
771 route_2001_3.add_vpp_config()
773 tx = self.create_stream_ip6(self.pg0, "2001::3",
774 ip_ttl=54, ip_dscp=0xbe)
775 rx = self.send_and_expect(self.pg0, tx, self.pg0)
776 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
777 [VppMplsLabel(32, ttl=53, exp=5)])
780 # add a recursive path, with output label, via the 1 label route
782 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
783 [VppRoutePath("10.0.0.1",
785 labels=[VppMplsLabel(44)])])
786 route_11_0_0_1.add_vpp_config()
789 # a stream that matches the route for 11.0.0.1, should pick up
790 # the label stack for 11.0.0.1 and 10.0.0.1
792 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
793 rx = self.send_and_expect(self.pg0, tx, self.pg0)
794 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
798 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
801 # add a recursive path, with 2 labels, via the 3 label route
803 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
804 [VppRoutePath("10.0.0.2",
806 labels=[VppMplsLabel(44),
808 route_11_0_0_2.add_vpp_config()
811 # a stream that matches the route for 11.0.0.1, should pick up
812 # the label stack for 11.0.0.1 and 10.0.0.1
814 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
815 rx = self.send_and_expect(self.pg0, tx, self.pg0)
816 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
823 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
825 rx = self.send_and_expect(self.pg0, tx, self.pg0)
826 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
833 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
838 route_11_0_0_2.remove_vpp_config()
839 route_11_0_0_1.remove_vpp_config()
840 route_10_0_0_2.remove_vpp_config()
841 route_10_0_0_1.remove_vpp_config()
843 def test_tunnel_pipe(self):
844 """ MPLS Tunnel Tests - Pipe """
847 # Create a tunnel with a single out label
849 mpls_tun = VppMPLSTunnelInterface(
851 [VppRoutePath(self.pg0.remote_ip4,
852 self.pg0.sw_if_index,
853 labels=[VppMplsLabel(44),
855 mpls_tun.add_vpp_config()
859 # add an unlabelled route through the new tunnel
861 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
862 [VppRoutePath("0.0.0.0",
863 mpls_tun._sw_if_index)])
864 route_10_0_0_3.add_vpp_config()
866 self.vapi.cli("clear trace")
867 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
868 self.pg0.add_stream(tx)
870 self.pg_enable_capture(self.pg_interfaces)
873 rx = self.pg0.get_capture()
874 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
879 # add a labelled route through the new tunnel
881 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
882 [VppRoutePath("0.0.0.0",
883 mpls_tun._sw_if_index,
885 route_10_0_0_4.add_vpp_config()
887 self.vapi.cli("clear trace")
888 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
889 self.pg0.add_stream(tx)
891 self.pg_enable_capture(self.pg_interfaces)
894 rx = self.pg0.get_capture()
895 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
898 VppMplsLabel(33, ttl=255)])
900 def test_tunnel_uniform(self):
901 """ MPLS Tunnel Tests - Uniform """
904 # Create a tunnel with a single out label
905 # The label stack is specified here from outer to inner
907 mpls_tun = VppMPLSTunnelInterface(
909 [VppRoutePath(self.pg0.remote_ip4,
910 self.pg0.sw_if_index,
911 labels=[VppMplsLabel(44, ttl=32),
912 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
913 mpls_tun.add_vpp_config()
917 # add an unlabelled route through the new tunnel
919 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
920 [VppRoutePath("0.0.0.0",
921 mpls_tun._sw_if_index)])
922 route_10_0_0_3.add_vpp_config()
924 self.vapi.cli("clear trace")
925 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
926 self.pg0.add_stream(tx)
928 self.pg_enable_capture(self.pg_interfaces)
931 rx = self.pg0.get_capture()
932 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
933 [VppMplsLabel(44, ttl=32),
934 VppMplsLabel(46, ttl=23)])
937 # add a labelled route through the new tunnel
939 route_10_0_0_4 = VppIpRoute(
940 self, "10.0.0.4", 32,
941 [VppRoutePath("0.0.0.0",
942 mpls_tun._sw_if_index,
943 labels=[VppMplsLabel(33, ttl=47)])])
944 route_10_0_0_4.add_vpp_config()
946 self.vapi.cli("clear trace")
947 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
948 self.pg0.add_stream(tx)
950 self.pg_enable_capture(self.pg_interfaces)
953 rx = self.pg0.get_capture()
954 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
955 [VppMplsLabel(44, ttl=32),
956 VppMplsLabel(46, ttl=47),
957 VppMplsLabel(33, ttl=47)])
959 def test_mpls_tunnel_many(self):
960 """ Multiple Tunnels """
963 mpls_tun = VppMPLSTunnelInterface(
965 [VppRoutePath(self.pg0.remote_ip4,
966 self.pg0.sw_if_index,
967 labels=[VppMplsLabel(44, ttl=32),
968 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
969 mpls_tun.add_vpp_config()
972 def test_v4_exp_null(self):
973 """ MPLS V4 Explicit NULL test """
976 # The first test case has an MPLS TTL of 0
977 # all packet should be dropped
979 tx = self.create_stream_labelled_ip4(self.pg0,
980 [VppMplsLabel(0, ttl=0)])
981 self.send_and_assert_no_replies(self.pg0, tx,
982 "MPLS TTL=0 packets forwarded")
985 # a stream with a non-zero MPLS TTL
986 # PG0 is in the default table
988 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
989 rx = self.send_and_expect(self.pg0, tx, self.pg0)
990 self.verify_capture_ip4(self.pg0, rx, tx)
993 # a stream with a non-zero MPLS TTL
995 # we are ensuring the post-pop lookup occurs in the VRF table
997 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
998 rx = self.send_and_expect(self.pg1, tx, self.pg1)
999 self.verify_capture_ip4(self.pg1, rx, tx)
1001 def test_v6_exp_null(self):
1002 """ MPLS V6 Explicit NULL test """
1005 # a stream with a non-zero MPLS TTL
1006 # PG0 is in the default table
1008 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1009 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1010 self.verify_capture_ip6(self.pg0, rx, tx)
1013 # a stream with a non-zero MPLS TTL
1015 # we are ensuring the post-pop lookup occurs in the VRF table
1017 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1018 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1019 self.verify_capture_ip6(self.pg0, rx, tx)
1021 def test_deag(self):
1025 # A de-agg route - next-hop lookup in default table
1027 route_34_eos = VppMplsRoute(self, 34, 1,
1028 [VppRoutePath("0.0.0.0",
1031 route_34_eos.add_vpp_config()
1034 # ping an interface in the default table
1035 # PG0 is in the default table
1037 tx = self.create_stream_labelled_ip4(self.pg0,
1041 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1042 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1045 # A de-agg route - next-hop lookup in non-default table
1047 route_35_eos = VppMplsRoute(self, 35, 1,
1048 [VppRoutePath("0.0.0.0",
1051 route_35_eos.add_vpp_config()
1054 # ping an interface in the non-default table
1055 # PG0 is in the default table. packet arrive labelled in the
1056 # default table and egress unlabelled in the non-default
1058 tx = self.create_stream_labelled_ip4(
1059 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1060 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1061 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1066 route_36_neos = VppMplsRoute(self, 36, 0,
1067 [VppRoutePath("0.0.0.0",
1069 route_36_neos.add_vpp_config()
1071 tx = self.create_stream_labelled_ip4(self.pg0,
1074 ping=1, ip_itf=self.pg1)
1075 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1076 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1078 route_36_neos.remove_vpp_config()
1079 route_35_eos.remove_vpp_config()
1080 route_34_eos.remove_vpp_config()
1082 def test_interface_rx(self):
1083 """ MPLS Interface Receive """
1086 # Add a non-recursive route that will forward the traffic
1089 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1091 paths=[VppRoutePath(self.pg1.remote_ip4,
1092 self.pg1.sw_if_index)])
1093 route_10_0_0_1.add_vpp_config()
1096 # An interface receive label that maps traffic to RX on interface
1098 # by injecting the packet in on pg0, which is in table 0
1099 # doing an interface-rx on pg1 and matching a route in table 1
1100 # if the packet egresses, then we must have swapped to pg1
1101 # so as to have matched the route in table 1
1103 route_34_eos = VppMplsRoute(self, 34, 1,
1104 [VppRoutePath("0.0.0.0",
1105 self.pg1.sw_if_index,
1106 is_interface_rx=1)])
1107 route_34_eos.add_vpp_config()
1110 # ping an interface in the default table
1111 # PG0 is in the default table
1113 tx = self.create_stream_labelled_ip4(self.pg0,
1116 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1117 self.verify_capture_ip4(self.pg1, rx, tx)
1119 def test_mcast_mid_point(self):
1120 """ MPLS Multicast Mid Point """
1123 # Add a non-recursive route that will forward the traffic
1126 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1128 paths=[VppRoutePath(self.pg1.remote_ip4,
1129 self.pg1.sw_if_index)])
1130 route_10_0_0_1.add_vpp_config()
1133 # Add a mcast entry that replicate to pg2 and pg3
1134 # and replicate to a interface-rx (like a bud node would)
1136 route_3400_eos = VppMplsRoute(
1138 [VppRoutePath(self.pg2.remote_ip4,
1139 self.pg2.sw_if_index,
1140 labels=[VppMplsLabel(3401)]),
1141 VppRoutePath(self.pg3.remote_ip4,
1142 self.pg3.sw_if_index,
1143 labels=[VppMplsLabel(3402)]),
1144 VppRoutePath("0.0.0.0",
1145 self.pg1.sw_if_index,
1146 is_interface_rx=1)],
1148 route_3400_eos.add_vpp_config()
1151 # ping an interface in the default table
1152 # PG0 is in the default table
1154 self.vapi.cli("clear trace")
1155 tx = self.create_stream_labelled_ip4(self.pg0,
1156 [VppMplsLabel(3400, ttl=64)],
1159 self.pg0.add_stream(tx)
1161 self.pg_enable_capture(self.pg_interfaces)
1164 rx = self.pg1.get_capture(257)
1165 self.verify_capture_ip4(self.pg1, rx, tx)
1167 rx = self.pg2.get_capture(257)
1168 self.verify_capture_labelled(self.pg2, rx, tx,
1169 [VppMplsLabel(3401, ttl=63)])
1170 rx = self.pg3.get_capture(257)
1171 self.verify_capture_labelled(self.pg3, rx, tx,
1172 [VppMplsLabel(3402, ttl=63)])
1174 def test_mcast_head(self):
1175 """ MPLS Multicast Head-end """
1178 # Create a multicast tunnel with two replications
1180 mpls_tun = VppMPLSTunnelInterface(
1182 [VppRoutePath(self.pg2.remote_ip4,
1183 self.pg2.sw_if_index,
1184 labels=[VppMplsLabel(42)]),
1185 VppRoutePath(self.pg3.remote_ip4,
1186 self.pg3.sw_if_index,
1187 labels=[VppMplsLabel(43)])],
1189 mpls_tun.add_vpp_config()
1193 # add an unlabelled route through the new tunnel
1195 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1196 [VppRoutePath("0.0.0.0",
1197 mpls_tun._sw_if_index)])
1198 route_10_0_0_3.add_vpp_config()
1200 self.vapi.cli("clear trace")
1201 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1202 self.pg0.add_stream(tx)
1204 self.pg_enable_capture(self.pg_interfaces)
1207 rx = self.pg2.get_capture(257)
1208 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1209 rx = self.pg3.get_capture(257)
1210 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1213 # An an IP multicast route via the tunnel
1215 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1217 route_232_1_1_1 = VppIpMRoute(
1221 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1222 [VppMRoutePath(self.pg0.sw_if_index,
1223 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1224 VppMRoutePath(mpls_tun._sw_if_index,
1225 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1226 route_232_1_1_1.add_vpp_config()
1228 self.vapi.cli("clear trace")
1229 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1230 self.pg0.add_stream(tx)
1232 self.pg_enable_capture(self.pg_interfaces)
1235 rx = self.pg2.get_capture(257)
1236 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1237 rx = self.pg3.get_capture(257)
1238 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1240 def test_mcast_ip4_tail(self):
1241 """ MPLS IPv4 Multicast Tail """
1244 # Add a multicast route that will forward the traffic
1247 route_232_1_1_1 = VppIpMRoute(
1251 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1253 paths=[VppMRoutePath(self.pg1.sw_if_index,
1254 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1255 route_232_1_1_1.add_vpp_config()
1258 # An interface receive label that maps traffic to RX on interface
1260 # by injecting the packet in on pg0, which is in table 0
1261 # doing an rpf-id and matching a route in table 1
1262 # if the packet egresses, then we must have matched the route in
1265 route_34_eos = VppMplsRoute(self, 34, 1,
1266 [VppRoutePath("0.0.0.0",
1267 self.pg1.sw_if_index,
1272 route_34_eos.add_vpp_config()
1275 # Drop due to interface lookup miss
1277 self.vapi.cli("clear trace")
1278 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1279 dst_ip="232.1.1.1", n=1)
1280 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1283 # set the RPF-ID of the enrtry to match the input packet's
1285 route_232_1_1_1.update_rpf_id(55)
1287 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1289 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1290 self.verify_capture_ip4(self.pg1, rx, tx)
1293 # disposed packets have an invalid IPv4 checkusm
1295 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1296 dst_ip="232.1.1.1", n=65,
1298 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1301 # set the RPF-ID of the entry to not match the input packet's
1303 route_232_1_1_1.update_rpf_id(56)
1304 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1306 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1308 def test_mcast_ip6_tail(self):
1309 """ MPLS IPv6 Multicast Tail """
1312 # Add a multicast route that will forward the traffic
1315 route_ff = VppIpMRoute(
1319 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1321 paths=[VppMRoutePath(self.pg1.sw_if_index,
1322 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
1324 route_ff.add_vpp_config()
1327 # An interface receive label that maps traffic to RX on interface
1329 # by injecting the packet in on pg0, which is in table 0
1330 # doing an rpf-id and matching a route in table 1
1331 # if the packet egresses, then we must have matched the route in
1334 route_34_eos = VppMplsRoute(
1337 self.pg1.sw_if_index,
1340 proto=DpoProto.DPO_PROTO_IP6)],
1343 route_34_eos.add_vpp_config()
1346 # Drop due to interface lookup miss
1348 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1350 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1353 # set the RPF-ID of the enrtry to match the input packet's
1355 route_ff.update_rpf_id(55)
1357 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1359 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1360 self.verify_capture_ip6(self.pg1, rx, tx)
1363 # disposed packets have hop-limit = 1
1365 tx = self.create_stream_labelled_ip6(self.pg0,
1369 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1370 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1373 # set the RPF-ID of the enrtry to not match the input packet's
1375 route_ff.update_rpf_id(56)
1376 tx = self.create_stream_labelled_ip6(self.pg0,
1379 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1382 class TestMPLSDisabled(VppTestCase):
1383 """ MPLS disabled """
1386 super(TestMPLSDisabled, self).setUp()
1388 # create 2 pg interfaces
1389 self.create_pg_interfaces(range(2))
1391 self.tbl = VppMplsTable(self, 0)
1392 self.tbl.add_vpp_config()
1394 # PG0 is MPLS enalbed
1396 self.pg0.config_ip4()
1397 self.pg0.resolve_arp()
1398 self.pg0.enable_mpls()
1400 # PG 1 is not MPLS enabled
1404 for i in self.pg_interfaces:
1408 self.pg0.disable_mpls()
1409 super(TestMPLSDisabled, self).tearDown()
1411 def test_mpls_disabled(self):
1412 """ MPLS Disabled """
1414 tx = (Ether(src=self.pg1.remote_mac,
1415 dst=self.pg1.local_mac) /
1416 MPLS(label=32, ttl=64) /
1417 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1418 UDP(sport=1234, dport=1234) /
1422 # A simple MPLS xconnect - eos label in label out
1424 route_32_eos = VppMplsRoute(self, 32, 1,
1425 [VppRoutePath(self.pg0.remote_ip4,
1426 self.pg0.sw_if_index,
1428 route_32_eos.add_vpp_config()
1431 # PG1 does not forward IP traffic
1433 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1438 self.pg1.enable_mpls()
1441 # Now we get packets through
1443 self.pg1.add_stream(tx)
1444 self.pg_enable_capture(self.pg_interfaces)
1447 rx = self.pg0.get_capture(1)
1452 self.pg1.disable_mpls()
1455 # PG1 does not forward IP traffic
1457 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1458 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1461 class TestMPLSPIC(VppTestCase):
1462 """ MPLS PIC edge convergence """
1465 super(TestMPLSPIC, self).setUp()
1467 # create 2 pg interfaces
1468 self.create_pg_interfaces(range(4))
1470 mpls_tbl = VppMplsTable(self, 0)
1471 mpls_tbl.add_vpp_config()
1472 tbl4 = VppIpTable(self, 1)
1473 tbl4.add_vpp_config()
1474 tbl6 = VppIpTable(self, 1, is_ip6=1)
1475 tbl6.add_vpp_config()
1479 self.pg0.config_ip4()
1480 self.pg0.resolve_arp()
1481 self.pg0.enable_mpls()
1483 self.pg1.config_ip4()
1484 self.pg1.resolve_arp()
1485 self.pg1.enable_mpls()
1487 # VRF (customer facing) link
1489 self.pg2.set_table_ip4(1)
1490 self.pg2.config_ip4()
1491 self.pg2.resolve_arp()
1492 self.pg2.set_table_ip6(1)
1493 self.pg2.config_ip6()
1494 self.pg2.resolve_ndp()
1496 self.pg3.set_table_ip4(1)
1497 self.pg3.config_ip4()
1498 self.pg3.resolve_arp()
1499 self.pg3.set_table_ip6(1)
1500 self.pg3.config_ip6()
1501 self.pg3.resolve_ndp()
1504 self.pg0.disable_mpls()
1505 self.pg1.disable_mpls()
1506 for i in self.pg_interfaces:
1512 super(TestMPLSPIC, self).tearDown()
1514 def test_mpls_ibgp_pic(self):
1515 """ MPLS iBGP PIC edge convergence
1517 1) setup many iBGP VPN routes via a pair of iBGP peers.
1518 2) Check EMCP forwarding to these peers
1519 3) withdraw the IGP route to one of these peers.
1520 4) check forwarding continues to the remaining peer
1524 # IGP+LDP core routes
1526 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1527 [VppRoutePath(self.pg0.remote_ip4,
1528 self.pg0.sw_if_index,
1530 core_10_0_0_45.add_vpp_config()
1532 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1533 [VppRoutePath(self.pg1.remote_ip4,
1534 self.pg1.sw_if_index,
1536 core_10_0_0_46.add_vpp_config()
1539 # Lot's of VPN routes. We need more the 64 so VPP will build
1540 # the fast convergence indirection
1544 for ii in range(64):
1545 dst = "192.168.1.%d" % ii
1546 vpn_routes.append(VppIpRoute(self, dst, 32,
1547 [VppRoutePath("10.0.0.45",
1551 VppRoutePath("10.0.0.46",
1554 is_resolve_host=1)],
1556 vpn_routes[ii].add_vpp_config()
1558 pkts.append(Ether(dst=self.pg2.local_mac,
1559 src=self.pg2.remote_mac) /
1560 IP(src=self.pg2.remote_ip4, dst=dst) /
1561 UDP(sport=1234, dport=1234) /
1565 # Send the packet stream (one pkt to each VPN route)
1566 # - expect a 50-50 split of the traffic
1568 self.pg2.add_stream(pkts)
1569 self.pg_enable_capture(self.pg_interfaces)
1572 rx0 = self.pg0._get_capture(1)
1573 rx1 = self.pg1._get_capture(1)
1575 # not testig the LB hashing algorithm so we're not concerned
1576 # with the split ratio, just as long as neither is 0
1577 self.assertNotEqual(0, len(rx0))
1578 self.assertNotEqual(0, len(rx1))
1581 # use a test CLI command to stop the FIB walk process, this
1582 # will prevent the FIB converging the VPN routes and thus allow
1583 # us to probe the interim (psot-fail, pre-converge) state
1585 self.vapi.ppcli("test fib-walk-process disable")
1588 # Withdraw one of the IGP routes
1590 core_10_0_0_46.remove_vpp_config()
1593 # now all packets should be forwarded through the remaining peer
1595 self.vapi.ppcli("clear trace")
1596 self.pg2.add_stream(pkts)
1597 self.pg_enable_capture(self.pg_interfaces)
1600 rx0 = self.pg0.get_capture(len(pkts))
1603 # enable the FIB walk process to converge the FIB
1605 self.vapi.ppcli("test fib-walk-process enable")
1608 # packets should still be forwarded through the remaining peer
1610 self.pg2.add_stream(pkts)
1611 self.pg_enable_capture(self.pg_interfaces)
1614 rx0 = self.pg0.get_capture(64)
1617 # Add the IGP route back and we return to load-balancing
1619 core_10_0_0_46.add_vpp_config()
1621 self.pg2.add_stream(pkts)
1622 self.pg_enable_capture(self.pg_interfaces)
1625 rx0 = self.pg0._get_capture(1)
1626 rx1 = self.pg1._get_capture(1)
1627 self.assertNotEqual(0, len(rx0))
1628 self.assertNotEqual(0, len(rx1))
1630 def test_mpls_ebgp_pic(self):
1631 """ MPLS eBGP PIC edge convergence
1633 1) setup many eBGP VPN routes via a pair of eBGP peers
1634 2) Check EMCP forwarding to these peers
1635 3) withdraw one eBGP path - expect LB across remaining eBGP
1639 # Lot's of VPN routes. We need more the 64 so VPP will build
1640 # the fast convergence indirection
1645 for ii in range(64):
1646 dst = "192.168.1.%d" % ii
1647 local_label = 1600 + ii
1648 vpn_routes.append(VppIpRoute(self, dst, 32,
1649 [VppRoutePath(self.pg2.remote_ip4,
1652 is_resolve_attached=1),
1653 VppRoutePath(self.pg3.remote_ip4,
1656 is_resolve_attached=1)],
1658 vpn_routes[ii].add_vpp_config()
1660 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1662 vpn_bindings[ii].add_vpp_config()
1664 pkts.append(Ether(dst=self.pg0.local_mac,
1665 src=self.pg0.remote_mac) /
1666 MPLS(label=local_label, ttl=64) /
1667 IP(src=self.pg0.remote_ip4, dst=dst) /
1668 UDP(sport=1234, dport=1234) /
1671 self.pg0.add_stream(pkts)
1672 self.pg_enable_capture(self.pg_interfaces)
1675 rx0 = self.pg2._get_capture(1)
1676 rx1 = self.pg3._get_capture(1)
1677 self.assertNotEqual(0, len(rx0))
1678 self.assertNotEqual(0, len(rx1))
1681 # use a test CLI command to stop the FIB walk process, this
1682 # will prevent the FIB converging the VPN routes and thus allow
1683 # us to probe the interim (psot-fail, pre-converge) state
1685 self.vapi.ppcli("test fib-walk-process disable")
1688 # withdraw the connected prefix on the interface.
1690 self.pg2.unconfig_ip4()
1693 # now all packets should be forwarded through the remaining peer
1695 self.pg0.add_stream(pkts)
1696 self.pg_enable_capture(self.pg_interfaces)
1699 rx0 = self.pg3.get_capture(len(pkts))
1702 # enable the FIB walk process to converge the FIB
1704 self.vapi.ppcli("test fib-walk-process enable")
1705 self.pg0.add_stream(pkts)
1706 self.pg_enable_capture(self.pg_interfaces)
1709 rx0 = self.pg3.get_capture(len(pkts))
1712 # put the connecteds back
1714 self.pg2.config_ip4()
1716 self.pg0.add_stream(pkts)
1717 self.pg_enable_capture(self.pg_interfaces)
1720 rx0 = self.pg2._get_capture(1)
1721 rx1 = self.pg3._get_capture(1)
1722 self.assertNotEqual(0, len(rx0))
1723 self.assertNotEqual(0, len(rx1))
1725 def test_mpls_v6_ebgp_pic(self):
1726 """ MPLSv6 eBGP PIC edge convergence
1728 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1729 2) Check EMCP forwarding to these peers
1730 3) withdraw one eBGP path - expect LB across remaining eBGP
1734 # Lot's of VPN routes. We need more the 64 so VPP will build
1735 # the fast convergence indirection
1740 for ii in range(64):
1741 dst = "3000::%d" % ii
1742 local_label = 1600 + ii
1743 vpn_routes.append(VppIpRoute(
1745 [VppRoutePath(self.pg2.remote_ip6,
1748 is_resolve_attached=1,
1749 proto=DpoProto.DPO_PROTO_IP6),
1750 VppRoutePath(self.pg3.remote_ip6,
1753 proto=DpoProto.DPO_PROTO_IP6,
1754 is_resolve_attached=1)],
1757 vpn_routes[ii].add_vpp_config()
1759 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1762 vpn_bindings[ii].add_vpp_config()
1764 pkts.append(Ether(dst=self.pg0.local_mac,
1765 src=self.pg0.remote_mac) /
1766 MPLS(label=local_label, ttl=64) /
1767 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1768 UDP(sport=1234, dport=1234) /
1771 self.pg0.add_stream(pkts)
1772 self.pg_enable_capture(self.pg_interfaces)
1775 rx0 = self.pg2._get_capture(1)
1776 rx1 = self.pg3._get_capture(1)
1777 self.assertNotEqual(0, len(rx0))
1778 self.assertNotEqual(0, len(rx1))
1781 # use a test CLI command to stop the FIB walk process, this
1782 # will prevent the FIB converging the VPN routes and thus allow
1783 # us to probe the interim (psot-fail, pre-converge) state
1785 self.vapi.ppcli("test fib-walk-process disable")
1788 # withdraw the connected prefix on the interface.
1789 # and shutdown the interface so the ND cache is flushed.
1791 self.pg2.unconfig_ip6()
1792 self.pg2.admin_down()
1795 # now all packets should be forwarded through the remaining peer
1797 self.pg0.add_stream(pkts)
1798 self.pg_enable_capture(self.pg_interfaces)
1801 rx0 = self.pg3.get_capture(len(pkts))
1804 # enable the FIB walk process to converge the FIB
1806 self.vapi.ppcli("test fib-walk-process enable")
1807 self.pg0.add_stream(pkts)
1808 self.pg_enable_capture(self.pg_interfaces)
1811 rx0 = self.pg3.get_capture(len(pkts))
1814 # put the connecteds back
1817 self.pg2.config_ip6()
1819 self.pg0.add_stream(pkts)
1820 self.pg_enable_capture(self.pg_interfaces)
1823 rx0 = self.pg2._get_capture(1)
1824 rx1 = self.pg3._get_capture(1)
1825 self.assertNotEqual(0, len(rx0))
1826 self.assertNotEqual(0, len(rx1))
1829 class TestMPLSL2(VppTestCase):
1833 super(TestMPLSL2, self).setUp()
1835 # create 2 pg interfaces
1836 self.create_pg_interfaces(range(2))
1838 # create the default MPLS table
1840 tbl = VppMplsTable(self, 0)
1841 tbl.add_vpp_config()
1842 self.tables.append(tbl)
1844 # use pg0 as the core facing interface
1846 self.pg0.config_ip4()
1847 self.pg0.resolve_arp()
1848 self.pg0.enable_mpls()
1850 # use the other 2 for customer facing L2 links
1851 for i in self.pg_interfaces[1:]:
1855 for i in self.pg_interfaces[1:]:
1858 self.pg0.disable_mpls()
1859 self.pg0.unconfig_ip4()
1860 self.pg0.admin_down()
1861 super(TestMPLSL2, self).tearDown()
1863 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
1864 capture = verify_filter(capture, sent)
1866 self.assertEqual(len(capture), len(sent))
1868 for i in range(len(capture)):
1872 # the MPLS TTL is 255 since it enters a new tunnel
1873 verify_mpls_stack(self, rx, mpls_labels)
1876 rx_eth = Ether(str(rx[MPLS].payload))
1878 self.assertEqual(rx_eth.src, tx_eth.src)
1879 self.assertEqual(rx_eth.dst, tx_eth.dst)
1881 def test_vpws(self):
1882 """ Virtual Private Wire Service """
1885 # Create an MPLS tunnel that pushes 1 label
1886 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
1887 # information is not in the packet, but we test it works anyway
1889 mpls_tun_1 = VppMPLSTunnelInterface(
1891 [VppRoutePath(self.pg0.remote_ip4,
1892 self.pg0.sw_if_index,
1893 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
1895 mpls_tun_1.add_vpp_config()
1896 mpls_tun_1.admin_up()
1899 # Create a label entry to for 55 that does L2 input to the tunnel
1901 route_55_eos = VppMplsRoute(
1903 [VppRoutePath("0.0.0.0",
1904 mpls_tun_1.sw_if_index,
1906 proto=DpoProto.DPO_PROTO_ETHERNET)])
1907 route_55_eos.add_vpp_config()
1910 # Cross-connect the tunnel with one of the customers L2 interfaces
1912 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
1913 mpls_tun_1.sw_if_index,
1915 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
1916 self.pg1.sw_if_index,
1920 # inject a packet from the core
1922 pcore = (Ether(dst=self.pg0.local_mac,
1923 src=self.pg0.remote_mac) /
1924 MPLS(label=55, ttl=64) /
1925 Ether(dst="00:00:de:ad:ba:be",
1926 src="00:00:de:ad:be:ef") /
1927 IP(src="10.10.10.10", dst="11.11.11.11") /
1928 UDP(sport=1234, dport=1234) /
1932 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
1933 payload = pcore[MPLS].payload
1935 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
1936 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
1939 # Inject a packet from the custoer/L2 side
1941 tx1 = pcore[MPLS].payload * 65
1942 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
1944 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
1946 def test_vpls(self):
1947 """ Virtual Private LAN Service """
1949 # Create an L2 MPLS tunnel
1951 mpls_tun = VppMPLSTunnelInterface(
1953 [VppRoutePath(self.pg0.remote_ip4,
1954 self.pg0.sw_if_index,
1955 labels=[VppMplsLabel(42)])],
1957 mpls_tun.add_vpp_config()
1961 # Create a label entry to for 55 that does L2 input to the tunnel
1963 route_55_eos = VppMplsRoute(
1965 [VppRoutePath("0.0.0.0",
1966 mpls_tun.sw_if_index,
1968 proto=DpoProto.DPO_PROTO_ETHERNET)])
1969 route_55_eos.add_vpp_config()
1972 # add to tunnel to the customers bridge-domain
1974 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
1976 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
1980 # Packet from the customer interface and from the core
1982 p_cust = (Ether(dst="00:00:de:ad:ba:be",
1983 src="00:00:de:ad:be:ef") /
1984 IP(src="10.10.10.10", dst="11.11.11.11") /
1985 UDP(sport=1234, dport=1234) /
1987 p_core = (Ether(src="00:00:de:ad:ba:be",
1988 dst="00:00:de:ad:be:ef") /
1989 IP(dst="10.10.10.10", src="11.11.11.11") /
1990 UDP(sport=1234, dport=1234) /
1994 # The BD is learning, so send in one of each packet to learn
1996 p_core_encap = (Ether(dst=self.pg0.local_mac,
1997 src=self.pg0.remote_mac) /
1998 MPLS(label=55, ttl=64) /
2001 self.pg1.add_stream(p_cust)
2002 self.pg_enable_capture(self.pg_interfaces)
2004 self.pg0.add_stream(p_core_encap)
2005 self.pg_enable_capture(self.pg_interfaces)
2008 # we've learnt this so expect it be be forwarded
2009 rx0 = self.pg1.get_capture(1)
2011 self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst)
2012 self.assertEqual(rx0[0][Ether].src, p_core[Ether].src)
2015 # now a stream in each direction
2017 self.pg1.add_stream(p_cust * 65)
2018 self.pg_enable_capture(self.pg_interfaces)
2021 rx0 = self.pg0.get_capture(65)
2023 self.verify_capture_tunneled_ethernet(rx0, p_cust*65,
2027 # remove interfaces from customers bridge-domain
2029 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
2032 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
2036 if __name__ == '__main__':
2037 unittest.main(testRunner=VppTestRunner)