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
15 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether
17 from scapy.layers.inet import IP, UDP, ICMP
18 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
19 from scapy.contrib.mpls import MPLS
24 def verify_filter(capture, sent):
25 if not len(capture) == len(sent):
26 # filter out any IPv6 RAs from the capture
33 def verify_mpls_stack(tst, rx, mpls_labels):
34 # the rx'd packet has the MPLS label popped
36 tst.assertEqual(eth.type, 0x8847)
40 for ii in range(len(mpls_labels)):
41 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
42 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
43 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
45 if ii == len(mpls_labels) - 1:
46 tst.assertEqual(rx_mpls.s, 1)
49 tst.assertEqual(rx_mpls.s, 0)
50 # pop the label to expose the next
51 rx_mpls = rx_mpls[MPLS].payload
54 class TestMPLS(VppTestCase):
55 """ MPLS Test Case """
59 super(TestMPLS, cls).setUpClass()
62 def tearDownClass(cls):
63 super(TestMPLS, cls).tearDownClass()
66 super(TestMPLS, self).setUp()
68 # create 2 pg interfaces
69 self.create_pg_interfaces(range(4))
71 # setup both interfaces
72 # assign them different tables.
76 tbl = VppMplsTable(self, 0)
78 self.tables.append(tbl)
80 for i in self.pg_interfaces:
84 tbl = VppIpTable(self, table_id)
86 self.tables.append(tbl)
87 tbl = VppIpTable(self, table_id, is_ip6=1)
89 self.tables.append(tbl)
91 i.set_table_ip4(table_id)
92 i.set_table_ip6(table_id)
101 for i in self.pg_interfaces:
109 super(TestMPLS, self).tearDown()
111 # the default of 64 matches the IP packet TTL default
112 def create_stream_labelled_ip4(
122 self.reset_packet_infos()
124 for i in range(0, n):
125 info = self.create_packet_info(src_if, src_if)
126 payload = self.info_to_payload(info)
127 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
129 for ii in range(len(mpls_labels)):
130 p = p / MPLS(label=mpls_labels[ii].value,
131 ttl=mpls_labels[ii].ttl,
132 cos=mpls_labels[ii].exp)
135 p = (p / IP(src=src_if.local_ip4,
136 dst=src_if.remote_ip4,
138 UDP(sport=1234, dport=1234) /
141 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
142 UDP(sport=1234, dport=1234) /
145 p = (p / IP(src=ip_itf.remote_ip4,
146 dst=ip_itf.local_ip4,
151 p[IP].chksum = chksum
156 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
157 self.reset_packet_infos()
159 for i in range(0, 257):
160 info = self.create_packet_info(src_if, src_if)
161 payload = self.info_to_payload(info)
162 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
163 IP(src=src_if.remote_ip4, dst=dst_ip,
164 ttl=ip_ttl, tos=ip_dscp) /
165 UDP(sport=1234, dport=1234) /
171 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
172 self.reset_packet_infos()
174 for i in range(0, 257):
175 info = self.create_packet_info(src_if, src_if)
176 payload = self.info_to_payload(info)
177 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
178 IPv6(src=src_if.remote_ip6, dst=dst_ip,
179 hlim=ip_ttl, tc=ip_dscp) /
180 UDP(sport=1234, dport=1234) /
186 def create_stream_labelled_ip6(self, src_if, mpls_labels,
187 hlim=64, dst_ip=None):
189 dst_ip = src_if.remote_ip6
190 self.reset_packet_infos()
192 for i in range(0, 257):
193 info = self.create_packet_info(src_if, src_if)
194 payload = self.info_to_payload(info)
195 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
196 for l in mpls_labels:
197 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
199 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
200 UDP(sport=1234, dport=1234) /
206 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
207 ip_ttl=None, ip_dscp=0):
209 capture = verify_filter(capture, sent)
211 self.assertEqual(len(capture), len(sent))
213 for i in range(len(capture)):
217 # the rx'd packet has the MPLS label popped
219 self.assertEqual(eth.type, 0x800)
225 self.assertEqual(rx_ip.src, tx_ip.src)
226 self.assertEqual(rx_ip.dst, tx_ip.dst)
227 self.assertEqual(rx_ip.tos, ip_dscp)
229 # IP processing post pop has decremented the TTL
230 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
232 self.assertEqual(rx_ip.ttl, ip_ttl)
234 self.assertEqual(rx_ip.src, tx_ip.dst)
235 self.assertEqual(rx_ip.dst, tx_ip.src)
240 def verify_capture_labelled_ip4(self, src_if, capture, sent,
241 mpls_labels, ip_ttl=None):
243 capture = verify_filter(capture, sent)
245 self.assertEqual(len(capture), len(sent))
247 for i in range(len(capture)):
253 verify_mpls_stack(self, rx, mpls_labels)
255 self.assertEqual(rx_ip.src, tx_ip.src)
256 self.assertEqual(rx_ip.dst, tx_ip.dst)
258 # IP processing post pop has decremented the TTL
259 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
261 self.assertEqual(rx_ip.ttl, ip_ttl)
266 def verify_capture_labelled_ip6(self, src_if, capture, sent,
267 mpls_labels, ip_ttl=None):
269 capture = verify_filter(capture, sent)
271 self.assertEqual(len(capture), len(sent))
273 for i in range(len(capture)):
279 verify_mpls_stack(self, rx, mpls_labels)
281 self.assertEqual(rx_ip.src, tx_ip.src)
282 self.assertEqual(rx_ip.dst, tx_ip.dst)
284 # IP processing post pop has decremented the TTL
285 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
287 self.assertEqual(rx_ip.hlim, ip_ttl)
292 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
294 capture = verify_filter(capture, sent)
296 self.assertEqual(len(capture), len(sent))
298 for i in range(len(capture)):
304 verify_mpls_stack(self, rx, mpls_labels)
306 self.assertEqual(rx_ip.src, tx_ip.src)
307 self.assertEqual(rx_ip.dst, tx_ip.dst)
308 # IP processing post pop has decremented the TTL
309 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
314 def verify_capture_labelled(self, src_if, capture, sent,
317 capture = verify_filter(capture, sent)
319 self.assertEqual(len(capture), len(sent))
321 for i in range(len(capture)):
323 verify_mpls_stack(self, rx, mpls_labels)
327 def verify_capture_ip6(self, src_if, capture, sent,
328 ip_hlim=None, ip_dscp=0):
330 self.assertEqual(len(capture), len(sent))
332 for i in range(len(capture)):
336 # the rx'd packet has the MPLS label popped
338 self.assertEqual(eth.type, 0x86DD)
343 self.assertEqual(rx_ip.src, tx_ip.src)
344 self.assertEqual(rx_ip.dst, tx_ip.dst)
345 self.assertEqual(rx_ip.tc, ip_dscp)
346 # IP processing post pop has decremented the TTL
348 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
350 self.assertEqual(rx_ip.hlim, ip_hlim)
355 def verify_capture_ip6_icmp(self, src_if, capture, sent):
357 self.assertEqual(len(capture), len(sent))
359 for i in range(len(capture)):
363 # the rx'd packet has the MPLS label popped
365 self.assertEqual(eth.type, 0x86DD)
370 self.assertEqual(rx_ip.dst, tx_ip.src)
371 # ICMP sourced from the interface's address
372 self.assertEqual(rx_ip.src, src_if.local_ip6)
373 # hop-limit reset to 255 for IMCP packet
374 self.assertEqual(rx_ip.hlim, 255)
376 icmp = rx[ICMPv6TimeExceeded]
382 """ MPLS label swap tests """
385 # A simple MPLS xconnect - eos label in label out
387 route_32_eos = VppMplsRoute(self, 32, 1,
388 [VppRoutePath(self.pg0.remote_ip4,
389 self.pg0.sw_if_index,
390 labels=[VppMplsLabel(33)])])
391 route_32_eos.add_vpp_config()
394 find_mpls_route(self, 0, 32, 1,
395 [VppRoutePath(self.pg0.remote_ip4,
396 self.pg0.sw_if_index,
397 labels=[VppMplsLabel(33)])]))
400 # a stream that matches the route for 10.0.0.1
401 # PG0 is in the default table
403 tx = self.create_stream_labelled_ip4(self.pg0,
404 [VppMplsLabel(32, ttl=32, exp=1)])
405 rx = self.send_and_expect(self.pg0, tx, self.pg0)
406 self.verify_capture_labelled(self.pg0, rx, tx,
407 [VppMplsLabel(33, ttl=31, exp=1)])
409 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
412 # A simple MPLS xconnect - non-eos label in label out
414 route_32_neos = VppMplsRoute(self, 32, 0,
415 [VppRoutePath(self.pg0.remote_ip4,
416 self.pg0.sw_if_index,
417 labels=[VppMplsLabel(33)])])
418 route_32_neos.add_vpp_config()
421 # a stream that matches the route for 10.0.0.1
422 # PG0 is in the default table
424 tx = self.create_stream_labelled_ip4(self.pg0,
425 [VppMplsLabel(32, ttl=21, exp=7),
427 rx = self.send_and_expect(self.pg0, tx, self.pg0)
428 self.verify_capture_labelled(self.pg0, rx, tx,
429 [VppMplsLabel(33, ttl=20, exp=7),
431 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
434 # A simple MPLS xconnect - non-eos label in label out, uniform mode
436 route_42_neos = VppMplsRoute(
438 [VppRoutePath(self.pg0.remote_ip4,
439 self.pg0.sw_if_index,
440 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
441 route_42_neos.add_vpp_config()
443 tx = self.create_stream_labelled_ip4(self.pg0,
444 [VppMplsLabel(42, ttl=21, exp=7),
446 rx = self.send_and_expect(self.pg0, tx, self.pg0)
447 self.verify_capture_labelled(self.pg0, rx, tx,
448 [VppMplsLabel(43, ttl=20, exp=7),
452 # An MPLS xconnect - EOS label in IP out
454 route_33_eos = VppMplsRoute(self, 33, 1,
455 [VppRoutePath(self.pg0.remote_ip4,
456 self.pg0.sw_if_index,
458 route_33_eos.add_vpp_config()
460 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
461 rx = self.send_and_expect(self.pg0, tx, self.pg0)
462 self.verify_capture_ip4(self.pg0, rx, tx)
465 # disposed packets have an invalid IPv4 checksum
467 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
468 dst_ip=self.pg0.remote_ip4,
471 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
474 # An MPLS xconnect - EOS label in IP out, uniform mode
476 route_3333_eos = VppMplsRoute(
478 [VppRoutePath(self.pg0.remote_ip4,
479 self.pg0.sw_if_index,
480 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
481 route_3333_eos.add_vpp_config()
483 tx = self.create_stream_labelled_ip4(
485 [VppMplsLabel(3333, ttl=55, exp=3)])
486 rx = self.send_and_expect(self.pg0, tx, self.pg0)
487 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
488 tx = self.create_stream_labelled_ip4(
490 [VppMplsLabel(3333, ttl=66, exp=4)])
491 rx = self.send_and_expect(self.pg0, tx, self.pg0)
492 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
495 # An MPLS xconnect - EOS label in IPv6 out
497 route_333_eos = VppMplsRoute(
499 [VppRoutePath(self.pg0.remote_ip6,
500 self.pg0.sw_if_index,
502 proto=DpoProto.DPO_PROTO_IP6)])
503 route_333_eos.add_vpp_config()
505 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
506 rx = self.send_and_expect(self.pg0, tx, self.pg0)
507 self.verify_capture_ip6(self.pg0, rx, tx)
510 # disposed packets have an TTL expired
512 tx = self.create_stream_labelled_ip6(self.pg0,
513 [VppMplsLabel(333, ttl=64)],
514 dst_ip=self.pg1.remote_ip6,
516 rx = self.send_and_expect(self.pg0, tx, self.pg0)
517 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
520 # An MPLS xconnect - EOS label in IPv6 out w imp-null
522 route_334_eos = VppMplsRoute(
524 [VppRoutePath(self.pg0.remote_ip6,
525 self.pg0.sw_if_index,
526 labels=[VppMplsLabel(3)],
527 proto=DpoProto.DPO_PROTO_IP6)])
528 route_334_eos.add_vpp_config()
530 tx = self.create_stream_labelled_ip6(self.pg0,
531 [VppMplsLabel(334, ttl=64)])
532 rx = self.send_and_expect(self.pg0, tx, self.pg0)
533 self.verify_capture_ip6(self.pg0, rx, tx)
536 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
538 route_335_eos = VppMplsRoute(
540 [VppRoutePath(self.pg0.remote_ip6,
541 self.pg0.sw_if_index,
542 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
543 proto=DpoProto.DPO_PROTO_IP6)])
544 route_335_eos.add_vpp_config()
546 tx = self.create_stream_labelled_ip6(
548 [VppMplsLabel(335, ttl=27, exp=4)])
549 rx = self.send_and_expect(self.pg0, tx, self.pg0)
550 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
553 # disposed packets have an TTL expired
555 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
556 dst_ip=self.pg1.remote_ip6,
558 rx = self.send_and_expect(self.pg0, tx, self.pg0)
559 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
562 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
563 # so this traffic should be dropped.
565 route_33_neos = VppMplsRoute(self, 33, 0,
566 [VppRoutePath(self.pg0.remote_ip4,
567 self.pg0.sw_if_index,
569 route_33_neos.add_vpp_config()
571 tx = self.create_stream_labelled_ip4(self.pg0,
574 self.send_and_assert_no_replies(
576 "MPLS non-EOS packets popped and forwarded")
579 # A recursive EOS x-connect, which resolves through another x-connect
582 route_34_eos = VppMplsRoute(self, 34, 1,
583 [VppRoutePath("0.0.0.0",
586 labels=[VppMplsLabel(44),
588 route_34_eos.add_vpp_config()
590 tx = self.create_stream_labelled_ip4(self.pg0,
591 [VppMplsLabel(34, ttl=3)])
592 rx = self.send_and_expect(self.pg0, tx, self.pg0)
593 self.verify_capture_labelled(self.pg0, rx, tx,
596 VppMplsLabel(45, ttl=2)])
598 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
599 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
602 # A recursive EOS x-connect, which resolves through another x-connect
605 route_35_eos = VppMplsRoute(
607 [VppRoutePath("0.0.0.0",
610 labels=[VppMplsLabel(44)])])
611 route_35_eos.add_vpp_config()
613 tx = self.create_stream_labelled_ip4(self.pg0,
614 [VppMplsLabel(35, ttl=3)])
615 rx = self.send_and_expect(self.pg0, tx, self.pg0)
616 self.verify_capture_labelled(self.pg0, rx, tx,
617 [VppMplsLabel(43, ttl=2),
618 VppMplsLabel(44, ttl=2)])
621 # A recursive non-EOS x-connect, which resolves through another
624 route_34_neos = VppMplsRoute(self, 34, 0,
625 [VppRoutePath("0.0.0.0",
628 labels=[VppMplsLabel(44),
630 route_34_neos.add_vpp_config()
632 tx = self.create_stream_labelled_ip4(self.pg0,
633 [VppMplsLabel(34, ttl=45),
635 rx = self.send_and_expect(self.pg0, tx, self.pg0)
636 # it's the 2nd (counting from 0) label in the stack that is swapped
637 self.verify_capture_labelled(self.pg0, rx, tx,
640 VppMplsLabel(46, ttl=44),
644 # an recursive IP route that resolves through the recursive non-eos
647 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
648 [VppRoutePath("0.0.0.0",
651 labels=[VppMplsLabel(55)])])
652 ip_10_0_0_1.add_vpp_config()
654 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
655 rx = self.send_and_expect(self.pg0, tx, self.pg0)
656 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
661 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
663 ip_10_0_0_1.remove_vpp_config()
664 route_34_neos.remove_vpp_config()
665 route_34_eos.remove_vpp_config()
666 route_33_neos.remove_vpp_config()
667 route_33_eos.remove_vpp_config()
668 route_32_neos.remove_vpp_config()
669 route_32_eos.remove_vpp_config()
672 """ MPLS Local Label Binding test """
675 # Add a non-recursive route with a single out label
677 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
678 [VppRoutePath(self.pg0.remote_ip4,
679 self.pg0.sw_if_index,
680 labels=[VppMplsLabel(45)])])
681 route_10_0_0_1.add_vpp_config()
683 # bind a local label to the route
684 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
685 binding.add_vpp_config()
688 tx = self.create_stream_labelled_ip4(self.pg0,
691 rx = self.send_and_expect(self.pg0, tx, self.pg0)
692 self.verify_capture_labelled(self.pg0, rx, tx,
693 [VppMplsLabel(45, ttl=63),
697 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
698 rx = self.send_and_expect(self.pg0, tx, self.pg0)
699 self.verify_capture_labelled(self.pg0, rx, tx,
700 [VppMplsLabel(45, ttl=63)])
703 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
704 rx = self.send_and_expect(self.pg0, tx, self.pg0)
705 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
710 binding.remove_vpp_config()
711 route_10_0_0_1.remove_vpp_config()
713 def test_imposition(self):
714 """ MPLS label imposition test """
717 # Add a non-recursive route with a single out label
719 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
720 [VppRoutePath(self.pg0.remote_ip4,
721 self.pg0.sw_if_index,
722 labels=[VppMplsLabel(32)])])
723 route_10_0_0_1.add_vpp_config()
726 # a stream that matches the route for 10.0.0.1
727 # PG0 is in the default table
729 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
730 rx = self.send_and_expect(self.pg0, tx, self.pg0)
731 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
734 # Add a non-recursive route with a 3 out labels
736 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
737 [VppRoutePath(self.pg0.remote_ip4,
738 self.pg0.sw_if_index,
739 labels=[VppMplsLabel(32),
742 route_10_0_0_2.add_vpp_config()
744 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
745 ip_ttl=44, ip_dscp=0xff)
746 rx = self.send_and_expect(self.pg0, tx, self.pg0)
747 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
754 # Add a non-recursive route with a single out label in uniform mode
756 route_10_0_0_3 = VppIpRoute(
757 self, "10.0.0.3", 32,
758 [VppRoutePath(self.pg0.remote_ip4,
759 self.pg0.sw_if_index,
760 labels=[VppMplsLabel(32,
761 mode=MplsLspMode.UNIFORM)])])
762 route_10_0_0_3.add_vpp_config()
764 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
765 ip_ttl=54, ip_dscp=0xbe)
766 rx = self.send_and_expect(self.pg0, tx, self.pg0)
767 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
768 [VppMplsLabel(32, ttl=53, exp=5)])
771 # Add a IPv6 non-recursive route with a single out label in
774 route_2001_3 = VppIpRoute(
775 self, "2001::3", 128,
776 [VppRoutePath(self.pg0.remote_ip6,
777 self.pg0.sw_if_index,
778 proto=DpoProto.DPO_PROTO_IP6,
779 labels=[VppMplsLabel(32,
780 mode=MplsLspMode.UNIFORM)])],
782 route_2001_3.add_vpp_config()
784 tx = self.create_stream_ip6(self.pg0, "2001::3",
785 ip_ttl=54, ip_dscp=0xbe)
786 rx = self.send_and_expect(self.pg0, tx, self.pg0)
787 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
788 [VppMplsLabel(32, ttl=53, exp=5)])
791 # add a recursive path, with output label, via the 1 label route
793 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
794 [VppRoutePath("10.0.0.1",
796 labels=[VppMplsLabel(44)])])
797 route_11_0_0_1.add_vpp_config()
800 # a stream that matches the route for 11.0.0.1, should pick up
801 # the label stack for 11.0.0.1 and 10.0.0.1
803 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
804 rx = self.send_and_expect(self.pg0, tx, self.pg0)
805 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
809 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
812 # add a recursive path, with 2 labels, via the 3 label route
814 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
815 [VppRoutePath("10.0.0.2",
817 labels=[VppMplsLabel(44),
819 route_11_0_0_2.add_vpp_config()
822 # a stream that matches the route for 11.0.0.1, should pick up
823 # the label stack for 11.0.0.1 and 10.0.0.1
825 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
826 rx = self.send_and_expect(self.pg0, tx, self.pg0)
827 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
834 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
836 rx = self.send_and_expect(self.pg0, tx, self.pg0)
837 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
844 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
849 route_11_0_0_2.remove_vpp_config()
850 route_11_0_0_1.remove_vpp_config()
851 route_10_0_0_2.remove_vpp_config()
852 route_10_0_0_1.remove_vpp_config()
854 def test_tunnel_pipe(self):
855 """ MPLS Tunnel Tests - Pipe """
858 # Create a tunnel with a single out label
860 mpls_tun = VppMPLSTunnelInterface(
862 [VppRoutePath(self.pg0.remote_ip4,
863 self.pg0.sw_if_index,
864 labels=[VppMplsLabel(44),
866 mpls_tun.add_vpp_config()
870 # add an unlabelled route through the new tunnel
872 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
873 [VppRoutePath("0.0.0.0",
874 mpls_tun._sw_if_index)])
875 route_10_0_0_3.add_vpp_config()
877 self.vapi.cli("clear trace")
878 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
879 self.pg0.add_stream(tx)
881 self.pg_enable_capture(self.pg_interfaces)
884 rx = self.pg0.get_capture()
885 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
890 # add a labelled route through the new tunnel
892 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
893 [VppRoutePath("0.0.0.0",
894 mpls_tun._sw_if_index,
896 route_10_0_0_4.add_vpp_config()
898 self.vapi.cli("clear trace")
899 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
900 self.pg0.add_stream(tx)
902 self.pg_enable_capture(self.pg_interfaces)
905 rx = self.pg0.get_capture()
906 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
909 VppMplsLabel(33, ttl=255)])
911 def test_tunnel_uniform(self):
912 """ MPLS Tunnel Tests - Uniform """
915 # Create a tunnel with a single out label
916 # The label stack is specified here from outer to inner
918 mpls_tun = VppMPLSTunnelInterface(
920 [VppRoutePath(self.pg0.remote_ip4,
921 self.pg0.sw_if_index,
922 labels=[VppMplsLabel(44, ttl=32),
923 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
924 mpls_tun.add_vpp_config()
928 # add an unlabelled route through the new tunnel
930 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
931 [VppRoutePath("0.0.0.0",
932 mpls_tun._sw_if_index)])
933 route_10_0_0_3.add_vpp_config()
935 self.vapi.cli("clear trace")
936 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
937 self.pg0.add_stream(tx)
939 self.pg_enable_capture(self.pg_interfaces)
942 rx = self.pg0.get_capture()
943 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
944 [VppMplsLabel(44, ttl=32),
945 VppMplsLabel(46, ttl=23)])
948 # add a labelled route through the new tunnel
950 route_10_0_0_4 = VppIpRoute(
951 self, "10.0.0.4", 32,
952 [VppRoutePath("0.0.0.0",
953 mpls_tun._sw_if_index,
954 labels=[VppMplsLabel(33, ttl=47)])])
955 route_10_0_0_4.add_vpp_config()
957 self.vapi.cli("clear trace")
958 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
959 self.pg0.add_stream(tx)
961 self.pg_enable_capture(self.pg_interfaces)
964 rx = self.pg0.get_capture()
965 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
966 [VppMplsLabel(44, ttl=32),
967 VppMplsLabel(46, ttl=47),
968 VppMplsLabel(33, ttl=47)])
970 def test_mpls_tunnel_many(self):
971 """ Multiple Tunnels """
974 mpls_tun = VppMPLSTunnelInterface(
976 [VppRoutePath(self.pg0.remote_ip4,
977 self.pg0.sw_if_index,
978 labels=[VppMplsLabel(44, ttl=32),
979 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
980 mpls_tun.add_vpp_config()
983 def test_v4_exp_null(self):
984 """ MPLS V4 Explicit NULL test """
987 # The first test case has an MPLS TTL of 0
988 # all packet should be dropped
990 tx = self.create_stream_labelled_ip4(self.pg0,
991 [VppMplsLabel(0, ttl=0)])
992 self.send_and_assert_no_replies(self.pg0, tx,
993 "MPLS TTL=0 packets forwarded")
996 # a stream with a non-zero MPLS TTL
997 # PG0 is in the default table
999 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1000 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1001 self.verify_capture_ip4(self.pg0, rx, tx)
1004 # a stream with a non-zero MPLS TTL
1006 # we are ensuring the post-pop lookup occurs in the VRF table
1008 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1009 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1010 self.verify_capture_ip4(self.pg1, rx, tx)
1012 def test_v6_exp_null(self):
1013 """ MPLS V6 Explicit NULL test """
1016 # a stream with a non-zero MPLS TTL
1017 # PG0 is in the default table
1019 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1020 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1021 self.verify_capture_ip6(self.pg0, rx, tx)
1024 # a stream with a non-zero MPLS TTL
1026 # we are ensuring the post-pop lookup occurs in the VRF table
1028 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1029 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1030 self.verify_capture_ip6(self.pg0, rx, tx)
1032 def test_deag(self):
1036 # A de-agg route - next-hop lookup in default table
1038 route_34_eos = VppMplsRoute(self, 34, 1,
1039 [VppRoutePath("0.0.0.0",
1042 route_34_eos.add_vpp_config()
1045 # ping an interface in the default table
1046 # PG0 is in the default table
1048 tx = self.create_stream_labelled_ip4(self.pg0,
1052 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1053 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1056 # A de-agg route - next-hop lookup in non-default table
1058 route_35_eos = VppMplsRoute(self, 35, 1,
1059 [VppRoutePath("0.0.0.0",
1062 route_35_eos.add_vpp_config()
1065 # ping an interface in the non-default table
1066 # PG0 is in the default table. packet arrive labelled in the
1067 # default table and egress unlabelled in the non-default
1069 tx = self.create_stream_labelled_ip4(
1070 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1071 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1072 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1077 route_36_neos = VppMplsRoute(self, 36, 0,
1078 [VppRoutePath("0.0.0.0",
1080 route_36_neos.add_vpp_config()
1082 tx = self.create_stream_labelled_ip4(self.pg0,
1085 ping=1, ip_itf=self.pg1)
1086 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1087 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1089 route_36_neos.remove_vpp_config()
1090 route_35_eos.remove_vpp_config()
1091 route_34_eos.remove_vpp_config()
1093 def test_interface_rx(self):
1094 """ MPLS Interface Receive """
1097 # Add a non-recursive route that will forward the traffic
1100 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1102 paths=[VppRoutePath(self.pg1.remote_ip4,
1103 self.pg1.sw_if_index)])
1104 route_10_0_0_1.add_vpp_config()
1107 # An interface receive label that maps traffic to RX on interface
1109 # by injecting the packet in on pg0, which is in table 0
1110 # doing an interface-rx on pg1 and matching a route in table 1
1111 # if the packet egresses, then we must have swapped to pg1
1112 # so as to have matched the route in table 1
1114 route_34_eos = VppMplsRoute(self, 34, 1,
1115 [VppRoutePath("0.0.0.0",
1116 self.pg1.sw_if_index,
1117 is_interface_rx=1)])
1118 route_34_eos.add_vpp_config()
1121 # ping an interface in the default table
1122 # PG0 is in the default table
1124 tx = self.create_stream_labelled_ip4(self.pg0,
1127 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1128 self.verify_capture_ip4(self.pg1, rx, tx)
1130 def test_mcast_mid_point(self):
1131 """ MPLS Multicast Mid Point """
1134 # Add a non-recursive route that will forward the traffic
1137 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1139 paths=[VppRoutePath(self.pg1.remote_ip4,
1140 self.pg1.sw_if_index)])
1141 route_10_0_0_1.add_vpp_config()
1144 # Add a mcast entry that replicate to pg2 and pg3
1145 # and replicate to a interface-rx (like a bud node would)
1147 route_3400_eos = VppMplsRoute(
1149 [VppRoutePath(self.pg2.remote_ip4,
1150 self.pg2.sw_if_index,
1151 labels=[VppMplsLabel(3401)]),
1152 VppRoutePath(self.pg3.remote_ip4,
1153 self.pg3.sw_if_index,
1154 labels=[VppMplsLabel(3402)]),
1155 VppRoutePath("0.0.0.0",
1156 self.pg1.sw_if_index,
1157 is_interface_rx=1)],
1159 route_3400_eos.add_vpp_config()
1162 # ping an interface in the default table
1163 # PG0 is in the default table
1165 self.vapi.cli("clear trace")
1166 tx = self.create_stream_labelled_ip4(self.pg0,
1167 [VppMplsLabel(3400, ttl=64)],
1170 self.pg0.add_stream(tx)
1172 self.pg_enable_capture(self.pg_interfaces)
1175 rx = self.pg1.get_capture(257)
1176 self.verify_capture_ip4(self.pg1, rx, tx)
1178 rx = self.pg2.get_capture(257)
1179 self.verify_capture_labelled(self.pg2, rx, tx,
1180 [VppMplsLabel(3401, ttl=63)])
1181 rx = self.pg3.get_capture(257)
1182 self.verify_capture_labelled(self.pg3, rx, tx,
1183 [VppMplsLabel(3402, ttl=63)])
1185 def test_mcast_head(self):
1186 """ MPLS Multicast Head-end """
1189 # Create a multicast tunnel with two replications
1191 mpls_tun = VppMPLSTunnelInterface(
1193 [VppRoutePath(self.pg2.remote_ip4,
1194 self.pg2.sw_if_index,
1195 labels=[VppMplsLabel(42)]),
1196 VppRoutePath(self.pg3.remote_ip4,
1197 self.pg3.sw_if_index,
1198 labels=[VppMplsLabel(43)])],
1200 mpls_tun.add_vpp_config()
1204 # add an unlabelled route through the new tunnel
1206 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1207 [VppRoutePath("0.0.0.0",
1208 mpls_tun._sw_if_index)])
1209 route_10_0_0_3.add_vpp_config()
1211 self.vapi.cli("clear trace")
1212 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1213 self.pg0.add_stream(tx)
1215 self.pg_enable_capture(self.pg_interfaces)
1218 rx = self.pg2.get_capture(257)
1219 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1220 rx = self.pg3.get_capture(257)
1221 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1224 # An an IP multicast route via the tunnel
1226 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1228 route_232_1_1_1 = VppIpMRoute(
1232 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1233 [VppMRoutePath(self.pg0.sw_if_index,
1234 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1235 VppMRoutePath(mpls_tun._sw_if_index,
1236 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1237 route_232_1_1_1.add_vpp_config()
1239 self.vapi.cli("clear trace")
1240 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1241 self.pg0.add_stream(tx)
1243 self.pg_enable_capture(self.pg_interfaces)
1246 rx = self.pg2.get_capture(257)
1247 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1248 rx = self.pg3.get_capture(257)
1249 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1251 def test_mcast_ip4_tail(self):
1252 """ MPLS IPv4 Multicast Tail """
1255 # Add a multicast route that will forward the traffic
1258 route_232_1_1_1 = VppIpMRoute(
1262 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1264 paths=[VppMRoutePath(self.pg1.sw_if_index,
1265 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1266 route_232_1_1_1.add_vpp_config()
1269 # An interface receive label that maps traffic to RX on interface
1271 # by injecting the packet in on pg0, which is in table 0
1272 # doing an rpf-id and matching a route in table 1
1273 # if the packet egresses, then we must have matched the route in
1276 route_34_eos = VppMplsRoute(self, 34, 1,
1277 [VppRoutePath("0.0.0.0",
1278 self.pg1.sw_if_index,
1283 route_34_eos.add_vpp_config()
1286 # Drop due to interface lookup miss
1288 self.vapi.cli("clear trace")
1289 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1290 dst_ip="232.1.1.1", n=1)
1291 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1294 # set the RPF-ID of the entry to match the input packet's
1296 route_232_1_1_1.update_rpf_id(55)
1298 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1300 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1301 self.verify_capture_ip4(self.pg1, rx, tx)
1304 # disposed packets have an invalid IPv4 checksum
1306 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1307 dst_ip="232.1.1.1", n=65,
1309 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1312 # set the RPF-ID of the entry to not match the input packet's
1314 route_232_1_1_1.update_rpf_id(56)
1315 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1317 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1319 def test_mcast_ip6_tail(self):
1320 """ MPLS IPv6 Multicast Tail """
1323 # Add a multicast route that will forward the traffic
1326 route_ff = VppIpMRoute(
1330 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1332 paths=[VppMRoutePath(self.pg1.sw_if_index,
1333 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
1335 route_ff.add_vpp_config()
1338 # An interface receive label that maps traffic to RX on interface
1340 # by injecting the packet in on pg0, which is in table 0
1341 # doing an rpf-id and matching a route in table 1
1342 # if the packet egresses, then we must have matched the route in
1345 route_34_eos = VppMplsRoute(
1348 self.pg1.sw_if_index,
1351 proto=DpoProto.DPO_PROTO_IP6)],
1354 route_34_eos.add_vpp_config()
1357 # Drop due to interface lookup miss
1359 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1361 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1364 # set the RPF-ID of the entry to match the input packet's
1366 route_ff.update_rpf_id(55)
1368 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1370 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1371 self.verify_capture_ip6(self.pg1, rx, tx)
1374 # disposed packets have hop-limit = 1
1376 tx = self.create_stream_labelled_ip6(self.pg0,
1380 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1381 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1384 # set the RPF-ID of the entry to not match the input packet's
1386 route_ff.update_rpf_id(56)
1387 tx = self.create_stream_labelled_ip6(self.pg0,
1390 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1393 class TestMPLSDisabled(VppTestCase):
1394 """ MPLS disabled """
1397 def setUpClass(cls):
1398 super(TestMPLSDisabled, cls).setUpClass()
1401 def tearDownClass(cls):
1402 super(TestMPLSDisabled, cls).tearDownClass()
1405 super(TestMPLSDisabled, self).setUp()
1407 # create 2 pg interfaces
1408 self.create_pg_interfaces(range(2))
1410 self.tbl = VppMplsTable(self, 0)
1411 self.tbl.add_vpp_config()
1413 # PG0 is MPLS enabled
1415 self.pg0.config_ip4()
1416 self.pg0.resolve_arp()
1417 self.pg0.enable_mpls()
1419 # PG 1 is not MPLS enabled
1423 for i in self.pg_interfaces:
1427 self.pg0.disable_mpls()
1428 super(TestMPLSDisabled, self).tearDown()
1430 def test_mpls_disabled(self):
1431 """ MPLS Disabled """
1433 tx = (Ether(src=self.pg1.remote_mac,
1434 dst=self.pg1.local_mac) /
1435 MPLS(label=32, ttl=64) /
1436 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1437 UDP(sport=1234, dport=1234) /
1441 # A simple MPLS xconnect - eos label in label out
1443 route_32_eos = VppMplsRoute(self, 32, 1,
1444 [VppRoutePath(self.pg0.remote_ip4,
1445 self.pg0.sw_if_index,
1447 route_32_eos.add_vpp_config()
1450 # PG1 does not forward IP traffic
1452 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1457 self.pg1.enable_mpls()
1460 # Now we get packets through
1462 self.pg1.add_stream(tx)
1463 self.pg_enable_capture(self.pg_interfaces)
1466 rx = self.pg0.get_capture(1)
1471 self.pg1.disable_mpls()
1474 # PG1 does not forward IP traffic
1476 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1477 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1480 class TestMPLSPIC(VppTestCase):
1481 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1484 def setUpClass(cls):
1485 super(TestMPLSPIC, cls).setUpClass()
1488 def tearDownClass(cls):
1489 super(TestMPLSPIC, cls).tearDownClass()
1492 super(TestMPLSPIC, self).setUp()
1494 # create 2 pg interfaces
1495 self.create_pg_interfaces(range(4))
1497 mpls_tbl = VppMplsTable(self, 0)
1498 mpls_tbl.add_vpp_config()
1499 tbl4 = VppIpTable(self, 1)
1500 tbl4.add_vpp_config()
1501 tbl6 = VppIpTable(self, 1, is_ip6=1)
1502 tbl6.add_vpp_config()
1506 self.pg0.config_ip4()
1507 self.pg0.resolve_arp()
1508 self.pg0.enable_mpls()
1511 self.pg1.config_ip4()
1512 self.pg1.resolve_arp()
1513 self.pg1.enable_mpls()
1515 # VRF (customer facing) link
1517 self.pg2.set_table_ip4(1)
1518 self.pg2.config_ip4()
1519 self.pg2.resolve_arp()
1520 self.pg2.set_table_ip6(1)
1521 self.pg2.config_ip6()
1522 self.pg2.resolve_ndp()
1525 self.pg3.set_table_ip4(1)
1526 self.pg3.config_ip4()
1527 self.pg3.resolve_arp()
1528 self.pg3.set_table_ip6(1)
1529 self.pg3.config_ip6()
1530 self.pg3.resolve_ndp()
1533 self.pg0.disable_mpls()
1534 self.pg1.disable_mpls()
1535 for i in self.pg_interfaces:
1541 super(TestMPLSPIC, self).tearDown()
1543 def test_mpls_ibgp_pic(self):
1544 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1546 1) setup many iBGP VPN routes via a pair of iBGP peers.
1547 2) Check EMCP forwarding to these peers
1548 3) withdraw the IGP route to one of these peers.
1549 4) check forwarding continues to the remaining peer
1553 # IGP+LDP core routes
1555 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1556 [VppRoutePath(self.pg0.remote_ip4,
1557 self.pg0.sw_if_index,
1559 core_10_0_0_45.add_vpp_config()
1561 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1562 [VppRoutePath(self.pg1.remote_ip4,
1563 self.pg1.sw_if_index,
1565 core_10_0_0_46.add_vpp_config()
1568 # Lot's of VPN routes. We need more the 64 so VPP will build
1569 # the fast convergence indirection
1573 for ii in range(NUM_PKTS):
1574 dst = "192.168.1.%d" % ii
1575 vpn_routes.append(VppIpRoute(self, dst, 32,
1576 [VppRoutePath("10.0.0.45",
1580 VppRoutePath("10.0.0.46",
1583 is_resolve_host=1)],
1585 vpn_routes[ii].add_vpp_config()
1587 pkts.append(Ether(dst=self.pg2.local_mac,
1588 src=self.pg2.remote_mac) /
1589 IP(src=self.pg2.remote_ip4, dst=dst) /
1590 UDP(sport=1234, dport=1234) /
1594 # Send the packet stream (one pkt to each VPN route)
1595 # - expect a 50-50 split of the traffic
1597 self.pg2.add_stream(pkts)
1598 self.pg_enable_capture(self.pg_interfaces)
1601 rx0 = self.pg0._get_capture(NUM_PKTS)
1602 rx1 = self.pg1._get_capture(NUM_PKTS)
1604 # not testing the LB hashing algorithm so we're not concerned
1605 # with the split ratio, just as long as neither is 0
1606 self.assertNotEqual(0, len(rx0))
1607 self.assertNotEqual(0, len(rx1))
1608 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1609 "Expected all (%s) packets across both ECMP paths. "
1610 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1613 # use a test CLI command to stop the FIB walk process, this
1614 # will prevent the FIB converging the VPN routes and thus allow
1615 # us to probe the interim (post-fail, pre-converge) state
1617 self.vapi.ppcli("test fib-walk-process disable")
1620 # Withdraw one of the IGP routes
1622 core_10_0_0_46.remove_vpp_config()
1625 # now all packets should be forwarded through the remaining peer
1627 self.vapi.ppcli("clear trace")
1628 self.pg2.add_stream(pkts)
1629 self.pg_enable_capture(self.pg_interfaces)
1632 rx0 = self.pg0.get_capture(NUM_PKTS)
1633 self.assertEqual(len(pkts), len(rx0),
1634 "Expected all (%s) packets across single path. "
1635 "rx0: %s." % (len(pkts), len(rx0)))
1638 # enable the FIB walk process to converge the FIB
1640 self.vapi.ppcli("test fib-walk-process enable")
1643 # packets should still be forwarded through the remaining peer
1645 self.pg2.add_stream(pkts)
1646 self.pg_enable_capture(self.pg_interfaces)
1649 rx0 = self.pg0.get_capture(NUM_PKTS)
1650 self.assertEqual(len(pkts), len(rx0),
1651 "Expected all (%s) packets across single path. "
1652 "rx0: %s." % (len(pkts), len(rx0)))
1655 # Add the IGP route back and we return to load-balancing
1657 core_10_0_0_46.add_vpp_config()
1659 self.pg2.add_stream(pkts)
1660 self.pg_enable_capture(self.pg_interfaces)
1663 rx0 = self.pg0._get_capture(NUM_PKTS)
1664 rx1 = self.pg1._get_capture(NUM_PKTS)
1665 self.assertNotEqual(0, len(rx0))
1666 self.assertNotEqual(0, len(rx1))
1667 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1668 "Expected all (%s) packets across both ECMP paths. "
1669 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1671 def test_mpls_ebgp_pic(self):
1672 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1674 1) setup many eBGP VPN routes via a pair of eBGP peers.
1675 2) Check EMCP forwarding to these peers
1676 3) withdraw one eBGP path - expect LB across remaining eBGP
1680 # Lot's of VPN routes. We need more the 64 so VPP will build
1681 # the fast convergence indirection
1686 for ii in range(NUM_PKTS):
1687 dst = "192.168.1.%d" % ii
1688 local_label = 1600 + ii
1689 vpn_routes.append(VppIpRoute(self, dst, 32,
1690 [VppRoutePath(self.pg2.remote_ip4,
1693 is_resolve_attached=1),
1694 VppRoutePath(self.pg3.remote_ip4,
1697 is_resolve_attached=1)],
1699 vpn_routes[ii].add_vpp_config()
1701 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1703 vpn_bindings[ii].add_vpp_config()
1705 pkts.append(Ether(dst=self.pg0.local_mac,
1706 src=self.pg0.remote_mac) /
1707 MPLS(label=local_label, ttl=64) /
1708 IP(src=self.pg0.remote_ip4, dst=dst) /
1709 UDP(sport=1234, dport=1234) /
1713 # Send the packet stream (one pkt to each VPN route)
1714 # - expect a 50-50 split of the traffic
1716 self.pg0.add_stream(pkts)
1717 self.pg_enable_capture(self.pg_interfaces)
1720 rx0 = self.pg2._get_capture(NUM_PKTS)
1721 rx1 = self.pg3._get_capture(NUM_PKTS)
1723 # not testing the LB hashing algorithm so we're not concerned
1724 # with the split ratio, just as long as neither is 0
1725 self.assertNotEqual(0, len(rx0))
1726 self.assertNotEqual(0, len(rx1))
1727 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1728 "Expected all (%s) packets across both ECMP paths. "
1729 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1732 # use a test CLI command to stop the FIB walk process, this
1733 # will prevent the FIB converging the VPN routes and thus allow
1734 # us to probe the interim (post-fail, pre-converge) state
1736 self.vapi.ppcli("test fib-walk-process disable")
1739 # withdraw the connected prefix on the interface.
1741 self.pg2.unconfig_ip4()
1744 # now all packets should be forwarded through the remaining peer
1746 self.pg0.add_stream(pkts)
1747 self.pg_enable_capture(self.pg_interfaces)
1750 rx0 = self.pg3.get_capture(NUM_PKTS)
1751 self.assertEqual(len(pkts), len(rx0),
1752 "Expected all (%s) packets across single path. "
1753 "rx0: %s." % (len(pkts), len(rx0)))
1756 # enable the FIB walk process to converge the FIB
1758 self.vapi.ppcli("test fib-walk-process enable")
1761 # packets should still be forwarded through the remaining peer
1763 self.pg0.add_stream(pkts)
1764 self.pg_enable_capture(self.pg_interfaces)
1767 rx0 = self.pg3.get_capture(NUM_PKTS)
1768 self.assertEqual(len(pkts), len(rx0),
1769 "Expected all (%s) packets across single path. "
1770 "rx0: %s." % (len(pkts), len(rx0)))
1773 # put the connected routes back
1775 self.pg2.config_ip4()
1776 self.pg2.resolve_arp()
1778 self.pg0.add_stream(pkts)
1779 self.pg_enable_capture(self.pg_interfaces)
1782 rx0 = self.pg2._get_capture(NUM_PKTS)
1783 rx1 = self.pg3._get_capture(NUM_PKTS)
1784 self.assertNotEqual(0, len(rx0))
1785 self.assertNotEqual(0, len(rx1))
1786 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1787 "Expected all (%s) packets across both ECMP paths. "
1788 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1790 def test_mpls_v6_ebgp_pic(self):
1791 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1793 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1794 2) Check EMCP forwarding to these peers
1795 3) withdraw one eBGP path - expect LB across remaining eBGP
1799 # Lot's of VPN routes. We need more the 64 so VPP will build
1800 # the fast convergence indirection
1805 for ii in range(NUM_PKTS):
1806 dst = "3000::%d" % ii
1807 local_label = 1600 + ii
1808 vpn_routes.append(VppIpRoute(
1810 [VppRoutePath(self.pg2.remote_ip6,
1813 is_resolve_attached=1,
1814 proto=DpoProto.DPO_PROTO_IP6),
1815 VppRoutePath(self.pg3.remote_ip6,
1818 proto=DpoProto.DPO_PROTO_IP6,
1819 is_resolve_attached=1)],
1822 vpn_routes[ii].add_vpp_config()
1824 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1827 vpn_bindings[ii].add_vpp_config()
1829 pkts.append(Ether(dst=self.pg0.local_mac,
1830 src=self.pg0.remote_mac) /
1831 MPLS(label=local_label, ttl=64) /
1832 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1833 UDP(sport=1234, dport=1234) /
1836 self.pg0.add_stream(pkts)
1837 self.pg_enable_capture(self.pg_interfaces)
1840 rx0 = self.pg2._get_capture(NUM_PKTS)
1841 rx1 = self.pg3._get_capture(NUM_PKTS)
1842 self.assertNotEqual(0, len(rx0))
1843 self.assertNotEqual(0, len(rx1))
1844 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1845 "Expected all (%s) packets across both ECMP paths. "
1846 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1849 # use a test CLI command to stop the FIB walk process, this
1850 # will prevent the FIB converging the VPN routes and thus allow
1851 # us to probe the interim (post-fail, pre-converge) state
1853 self.vapi.ppcli("test fib-walk-process disable")
1856 # withdraw the connected prefix on the interface.
1857 # and shutdown the interface so the ND cache is flushed.
1859 self.pg2.unconfig_ip6()
1860 self.pg2.admin_down()
1863 # now all packets should be forwarded through the remaining peer
1865 self.pg0.add_stream(pkts)
1866 self.pg_enable_capture(self.pg_interfaces)
1869 rx0 = self.pg3.get_capture(NUM_PKTS)
1870 self.assertEqual(len(pkts), len(rx0),
1871 "Expected all (%s) packets across single path. "
1872 "rx0: %s." % (len(pkts), len(rx0)))
1875 # enable the FIB walk process to converge the FIB
1877 self.vapi.ppcli("test fib-walk-process enable")
1878 self.pg0.add_stream(pkts)
1879 self.pg_enable_capture(self.pg_interfaces)
1882 rx0 = self.pg3.get_capture(NUM_PKTS)
1883 self.assertEqual(len(pkts), len(rx0),
1884 "Expected all (%s) packets across single path. "
1885 "rx0: %s." % (len(pkts), len(rx0)))
1888 # put the connected routes back
1891 self.pg2.config_ip6()
1892 self.pg2.resolve_ndp()
1894 self.pg0.add_stream(pkts)
1895 self.pg_enable_capture(self.pg_interfaces)
1898 rx0 = self.pg2._get_capture(NUM_PKTS)
1899 rx1 = self.pg3._get_capture(NUM_PKTS)
1900 self.assertNotEqual(0, len(rx0))
1901 self.assertNotEqual(0, len(rx1))
1902 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1903 "Expected all (%s) packets across both ECMP paths. "
1904 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1907 class TestMPLSL2(VppTestCase):
1911 def setUpClass(cls):
1912 super(TestMPLSL2, cls).setUpClass()
1915 def tearDownClass(cls):
1916 super(TestMPLSL2, cls).tearDownClass()
1919 super(TestMPLSL2, self).setUp()
1921 # create 2 pg interfaces
1922 self.create_pg_interfaces(range(2))
1924 # create the default MPLS table
1926 tbl = VppMplsTable(self, 0)
1927 tbl.add_vpp_config()
1928 self.tables.append(tbl)
1930 # use pg0 as the core facing interface
1932 self.pg0.config_ip4()
1933 self.pg0.resolve_arp()
1934 self.pg0.enable_mpls()
1936 # use the other 2 for customer facing L2 links
1937 for i in self.pg_interfaces[1:]:
1941 for i in self.pg_interfaces[1:]:
1944 self.pg0.disable_mpls()
1945 self.pg0.unconfig_ip4()
1946 self.pg0.admin_down()
1947 super(TestMPLSL2, self).tearDown()
1949 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
1950 capture = verify_filter(capture, sent)
1952 self.assertEqual(len(capture), len(sent))
1954 for i in range(len(capture)):
1958 # the MPLS TTL is 255 since it enters a new tunnel
1959 verify_mpls_stack(self, rx, mpls_labels)
1962 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
1964 self.assertEqual(rx_eth.src, tx_eth.src)
1965 self.assertEqual(rx_eth.dst, tx_eth.dst)
1967 def test_vpws(self):
1968 """ Virtual Private Wire Service """
1971 # Create an MPLS tunnel that pushes 1 label
1972 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
1973 # information is not in the packet, but we test it works anyway
1975 mpls_tun_1 = VppMPLSTunnelInterface(
1977 [VppRoutePath(self.pg0.remote_ip4,
1978 self.pg0.sw_if_index,
1979 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
1981 mpls_tun_1.add_vpp_config()
1982 mpls_tun_1.admin_up()
1985 # Create a label entry to for 55 that does L2 input to the tunnel
1987 route_55_eos = VppMplsRoute(
1989 [VppRoutePath("0.0.0.0",
1990 mpls_tun_1.sw_if_index,
1992 proto=DpoProto.DPO_PROTO_ETHERNET)])
1993 route_55_eos.add_vpp_config()
1996 # Cross-connect the tunnel with one of the customers L2 interfaces
1998 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
1999 mpls_tun_1.sw_if_index,
2001 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2002 self.pg1.sw_if_index,
2006 # inject a packet from the core
2008 pcore = (Ether(dst=self.pg0.local_mac,
2009 src=self.pg0.remote_mac) /
2010 MPLS(label=55, ttl=64) /
2011 Ether(dst="00:00:de:ad:ba:be",
2012 src="00:00:de:ad:be:ef") /
2013 IP(src="10.10.10.10", dst="11.11.11.11") /
2014 UDP(sport=1234, dport=1234) /
2017 tx0 = pcore * NUM_PKTS
2018 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2019 payload = pcore[MPLS].payload
2021 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2022 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2025 # Inject a packet from the customer/L2 side
2027 tx1 = pcore[MPLS].payload * NUM_PKTS
2028 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2030 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2032 def test_vpls(self):
2033 """ Virtual Private LAN Service """
2035 # Create an L2 MPLS tunnel
2037 mpls_tun = VppMPLSTunnelInterface(
2039 [VppRoutePath(self.pg0.remote_ip4,
2040 self.pg0.sw_if_index,
2041 labels=[VppMplsLabel(42)])],
2043 mpls_tun.add_vpp_config()
2047 # Create a label entry to for 55 that does L2 input to the tunnel
2049 route_55_eos = VppMplsRoute(
2051 [VppRoutePath("0.0.0.0",
2052 mpls_tun.sw_if_index,
2054 proto=DpoProto.DPO_PROTO_ETHERNET)])
2055 route_55_eos.add_vpp_config()
2058 # add to tunnel to the customers bridge-domain
2060 self.vapi.sw_interface_set_l2_bridge(
2061 rx_sw_if_index=mpls_tun.sw_if_index, bd_id=1)
2062 self.vapi.sw_interface_set_l2_bridge(
2063 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2066 # Packet from the customer interface and from the core
2068 p_cust = (Ether(dst="00:00:de:ad:ba:be",
2069 src="00:00:de:ad:be:ef") /
2070 IP(src="10.10.10.10", dst="11.11.11.11") /
2071 UDP(sport=1234, dport=1234) /
2073 p_core = (Ether(src="00:00:de:ad:ba:be",
2074 dst="00:00:de:ad:be:ef") /
2075 IP(dst="10.10.10.10", src="11.11.11.11") /
2076 UDP(sport=1234, dport=1234) /
2080 # The BD is learning, so send in one of each packet to learn
2082 p_core_encap = (Ether(dst=self.pg0.local_mac,
2083 src=self.pg0.remote_mac) /
2084 MPLS(label=55, ttl=64) /
2087 self.pg1.add_stream(p_cust)
2088 self.pg_enable_capture(self.pg_interfaces)
2090 self.pg0.add_stream(p_core_encap)
2091 self.pg_enable_capture(self.pg_interfaces)
2094 # we've learnt this so expect it be be forwarded
2095 rx0 = self.pg1.get_capture(1)
2097 self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst)
2098 self.assertEqual(rx0[0][Ether].src, p_core[Ether].src)
2101 # now a stream in each direction
2103 self.pg1.add_stream(p_cust * NUM_PKTS)
2104 self.pg_enable_capture(self.pg_interfaces)
2107 rx0 = self.pg0.get_capture(NUM_PKTS)
2109 self.verify_capture_tunneled_ethernet(rx0, p_cust*NUM_PKTS,
2113 # remove interfaces from customers bridge-domain
2115 self.vapi.sw_interface_set_l2_bridge(
2116 rx_sw_if_index=mpls_tun.sw_if_index, bd_id=1, enable=0)
2117 self.vapi.sw_interface_set_l2_bridge(
2118 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2121 if __name__ == '__main__':
2122 unittest.main(testRunner=VppTestRunner)