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
22 def verify_filter(capture, sent):
23 if not len(capture) == len(sent):
24 # filter out any IPv6 RAs from the capture
31 def verify_mpls_stack(tst, rx, mpls_labels):
32 # the rx'd packet has the MPLS label popped
34 tst.assertEqual(eth.type, 0x8847)
38 for ii in range(len(mpls_labels)):
39 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
40 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
41 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
43 if ii == len(mpls_labels) - 1:
44 tst.assertEqual(rx_mpls.s, 1)
47 tst.assertEqual(rx_mpls.s, 0)
48 # pop the label to expose the next
49 rx_mpls = rx_mpls[MPLS].payload
52 class TestMPLS(VppTestCase):
53 """ MPLS Test Case """
57 super(TestMPLS, cls).setUpClass()
60 def tearDownClass(cls):
61 super(TestMPLS, cls).tearDownClass()
64 super(TestMPLS, self).setUp()
66 # create 2 pg interfaces
67 self.create_pg_interfaces(range(4))
69 # setup both interfaces
70 # assign them different tables.
74 tbl = VppMplsTable(self, 0)
76 self.tables.append(tbl)
78 for i in self.pg_interfaces:
82 tbl = VppIpTable(self, table_id)
84 self.tables.append(tbl)
85 tbl = VppIpTable(self, table_id, is_ip6=1)
87 self.tables.append(tbl)
89 i.set_table_ip4(table_id)
90 i.set_table_ip6(table_id)
99 for i in self.pg_interfaces:
107 super(TestMPLS, self).tearDown()
109 # the default of 64 matches the IP packet TTL default
110 def create_stream_labelled_ip4(
120 self.reset_packet_infos()
122 for i in range(0, n):
123 info = self.create_packet_info(src_if, src_if)
124 payload = self.info_to_payload(info)
125 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
127 for ii in range(len(mpls_labels)):
128 p = p / MPLS(label=mpls_labels[ii].value,
129 ttl=mpls_labels[ii].ttl,
130 cos=mpls_labels[ii].exp)
133 p = (p / IP(src=src_if.local_ip4,
134 dst=src_if.remote_ip4,
136 UDP(sport=1234, dport=1234) /
139 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
140 UDP(sport=1234, dport=1234) /
143 p = (p / IP(src=ip_itf.remote_ip4,
144 dst=ip_itf.local_ip4,
149 p[IP].chksum = chksum
154 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
155 self.reset_packet_infos()
157 for i in range(0, 257):
158 info = self.create_packet_info(src_if, src_if)
159 payload = self.info_to_payload(info)
160 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
161 IP(src=src_if.remote_ip4, dst=dst_ip,
162 ttl=ip_ttl, tos=ip_dscp) /
163 UDP(sport=1234, dport=1234) /
169 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
170 self.reset_packet_infos()
172 for i in range(0, 257):
173 info = self.create_packet_info(src_if, src_if)
174 payload = self.info_to_payload(info)
175 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
176 IPv6(src=src_if.remote_ip6, dst=dst_ip,
177 hlim=ip_ttl, tc=ip_dscp) /
178 UDP(sport=1234, dport=1234) /
184 def create_stream_labelled_ip6(self, src_if, mpls_labels,
185 hlim=64, dst_ip=None):
187 dst_ip = src_if.remote_ip6
188 self.reset_packet_infos()
190 for i in range(0, 257):
191 info = self.create_packet_info(src_if, src_if)
192 payload = self.info_to_payload(info)
193 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
194 for l in mpls_labels:
195 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
197 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
198 UDP(sport=1234, dport=1234) /
204 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
205 ip_ttl=None, ip_dscp=0):
207 capture = verify_filter(capture, sent)
209 self.assertEqual(len(capture), len(sent))
211 for i in range(len(capture)):
215 # the rx'd packet has the MPLS label popped
217 self.assertEqual(eth.type, 0x800)
223 self.assertEqual(rx_ip.src, tx_ip.src)
224 self.assertEqual(rx_ip.dst, tx_ip.dst)
225 self.assertEqual(rx_ip.tos, ip_dscp)
227 # IP processing post pop has decremented the TTL
228 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
230 self.assertEqual(rx_ip.ttl, ip_ttl)
232 self.assertEqual(rx_ip.src, tx_ip.dst)
233 self.assertEqual(rx_ip.dst, tx_ip.src)
238 def verify_capture_labelled_ip4(self, src_if, capture, sent,
239 mpls_labels, ip_ttl=None):
241 capture = verify_filter(capture, sent)
243 self.assertEqual(len(capture), len(sent))
245 for i in range(len(capture)):
251 verify_mpls_stack(self, rx, mpls_labels)
253 self.assertEqual(rx_ip.src, tx_ip.src)
254 self.assertEqual(rx_ip.dst, tx_ip.dst)
256 # IP processing post pop has decremented the TTL
257 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
259 self.assertEqual(rx_ip.ttl, ip_ttl)
264 def verify_capture_labelled_ip6(self, src_if, capture, sent,
265 mpls_labels, ip_ttl=None):
267 capture = verify_filter(capture, sent)
269 self.assertEqual(len(capture), len(sent))
271 for i in range(len(capture)):
277 verify_mpls_stack(self, rx, mpls_labels)
279 self.assertEqual(rx_ip.src, tx_ip.src)
280 self.assertEqual(rx_ip.dst, tx_ip.dst)
282 # IP processing post pop has decremented the TTL
283 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
285 self.assertEqual(rx_ip.hlim, ip_ttl)
290 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
292 capture = verify_filter(capture, sent)
294 self.assertEqual(len(capture), len(sent))
296 for i in range(len(capture)):
302 verify_mpls_stack(self, rx, mpls_labels)
304 self.assertEqual(rx_ip.src, tx_ip.src)
305 self.assertEqual(rx_ip.dst, tx_ip.dst)
306 # IP processing post pop has decremented the TTL
307 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
312 def verify_capture_labelled(self, src_if, capture, sent,
315 capture = verify_filter(capture, sent)
317 self.assertEqual(len(capture), len(sent))
319 for i in range(len(capture)):
321 verify_mpls_stack(self, rx, mpls_labels)
325 def verify_capture_ip6(self, src_if, capture, sent,
326 ip_hlim=None, ip_dscp=0):
328 self.assertEqual(len(capture), len(sent))
330 for i in range(len(capture)):
334 # the rx'd packet has the MPLS label popped
336 self.assertEqual(eth.type, 0x86DD)
341 self.assertEqual(rx_ip.src, tx_ip.src)
342 self.assertEqual(rx_ip.dst, tx_ip.dst)
343 self.assertEqual(rx_ip.tc, ip_dscp)
344 # IP processing post pop has decremented the TTL
346 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
348 self.assertEqual(rx_ip.hlim, ip_hlim)
353 def verify_capture_ip6_icmp(self, src_if, capture, sent):
355 self.assertEqual(len(capture), len(sent))
357 for i in range(len(capture)):
361 # the rx'd packet has the MPLS label popped
363 self.assertEqual(eth.type, 0x86DD)
368 self.assertEqual(rx_ip.dst, tx_ip.src)
369 # ICMP sourced from the interface's address
370 self.assertEqual(rx_ip.src, src_if.local_ip6)
371 # hop-limit reset to 255 for IMCP packet
372 self.assertEqual(rx_ip.hlim, 255)
374 icmp = rx[ICMPv6TimeExceeded]
380 """ MPLS label swap tests """
383 # A simple MPLS xconnect - eos label in label out
385 route_32_eos = VppMplsRoute(self, 32, 1,
386 [VppRoutePath(self.pg0.remote_ip4,
387 self.pg0.sw_if_index,
388 labels=[VppMplsLabel(33)])])
389 route_32_eos.add_vpp_config()
392 find_mpls_route(self, 0, 32, 1,
393 [VppRoutePath(self.pg0.remote_ip4,
394 self.pg0.sw_if_index,
395 labels=[VppMplsLabel(33)])]))
398 # a stream that matches the route for 10.0.0.1
399 # PG0 is in the default table
401 tx = self.create_stream_labelled_ip4(self.pg0,
402 [VppMplsLabel(32, ttl=32, exp=1)])
403 rx = self.send_and_expect(self.pg0, tx, self.pg0)
404 self.verify_capture_labelled(self.pg0, rx, tx,
405 [VppMplsLabel(33, ttl=31, exp=1)])
407 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
410 # A simple MPLS xconnect - non-eos label in label out
412 route_32_neos = VppMplsRoute(self, 32, 0,
413 [VppRoutePath(self.pg0.remote_ip4,
414 self.pg0.sw_if_index,
415 labels=[VppMplsLabel(33)])])
416 route_32_neos.add_vpp_config()
419 # a stream that matches the route for 10.0.0.1
420 # PG0 is in the default table
422 tx = self.create_stream_labelled_ip4(self.pg0,
423 [VppMplsLabel(32, ttl=21, exp=7),
425 rx = self.send_and_expect(self.pg0, tx, self.pg0)
426 self.verify_capture_labelled(self.pg0, rx, tx,
427 [VppMplsLabel(33, ttl=20, exp=7),
429 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
432 # A simple MPLS xconnect - non-eos label in label out, uniform mode
434 route_42_neos = VppMplsRoute(
436 [VppRoutePath(self.pg0.remote_ip4,
437 self.pg0.sw_if_index,
438 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
439 route_42_neos.add_vpp_config()
441 tx = self.create_stream_labelled_ip4(self.pg0,
442 [VppMplsLabel(42, ttl=21, exp=7),
444 rx = self.send_and_expect(self.pg0, tx, self.pg0)
445 self.verify_capture_labelled(self.pg0, rx, tx,
446 [VppMplsLabel(43, ttl=20, exp=7),
450 # An MPLS xconnect - EOS label in IP out
452 route_33_eos = VppMplsRoute(self, 33, 1,
453 [VppRoutePath(self.pg0.remote_ip4,
454 self.pg0.sw_if_index,
456 route_33_eos.add_vpp_config()
458 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
459 rx = self.send_and_expect(self.pg0, tx, self.pg0)
460 self.verify_capture_ip4(self.pg0, rx, tx)
463 # disposed packets have an invalid IPv4 checksum
465 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
466 dst_ip=self.pg0.remote_ip4,
469 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
472 # An MPLS xconnect - EOS label in IP out, uniform mode
474 route_3333_eos = VppMplsRoute(
476 [VppRoutePath(self.pg0.remote_ip4,
477 self.pg0.sw_if_index,
478 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
479 route_3333_eos.add_vpp_config()
481 tx = self.create_stream_labelled_ip4(
483 [VppMplsLabel(3333, ttl=55, exp=3)])
484 rx = self.send_and_expect(self.pg0, tx, self.pg0)
485 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
486 tx = self.create_stream_labelled_ip4(
488 [VppMplsLabel(3333, ttl=66, exp=4)])
489 rx = self.send_and_expect(self.pg0, tx, self.pg0)
490 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
493 # An MPLS xconnect - EOS label in IPv6 out
495 route_333_eos = VppMplsRoute(
497 [VppRoutePath(self.pg0.remote_ip6,
498 self.pg0.sw_if_index,
500 proto=DpoProto.DPO_PROTO_IP6)])
501 route_333_eos.add_vpp_config()
503 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
504 rx = self.send_and_expect(self.pg0, tx, self.pg0)
505 self.verify_capture_ip6(self.pg0, rx, tx)
508 # disposed packets have an TTL expired
510 tx = self.create_stream_labelled_ip6(self.pg0,
511 [VppMplsLabel(333, ttl=64)],
512 dst_ip=self.pg1.remote_ip6,
514 rx = self.send_and_expect(self.pg0, tx, self.pg0)
515 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
518 # An MPLS xconnect - EOS label in IPv6 out w imp-null
520 route_334_eos = VppMplsRoute(
522 [VppRoutePath(self.pg0.remote_ip6,
523 self.pg0.sw_if_index,
524 labels=[VppMplsLabel(3)],
525 proto=DpoProto.DPO_PROTO_IP6)])
526 route_334_eos.add_vpp_config()
528 tx = self.create_stream_labelled_ip6(self.pg0,
529 [VppMplsLabel(334, ttl=64)])
530 rx = self.send_and_expect(self.pg0, tx, self.pg0)
531 self.verify_capture_ip6(self.pg0, rx, tx)
534 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
536 route_335_eos = VppMplsRoute(
538 [VppRoutePath(self.pg0.remote_ip6,
539 self.pg0.sw_if_index,
540 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
541 proto=DpoProto.DPO_PROTO_IP6)])
542 route_335_eos.add_vpp_config()
544 tx = self.create_stream_labelled_ip6(
546 [VppMplsLabel(335, ttl=27, exp=4)])
547 rx = self.send_and_expect(self.pg0, tx, self.pg0)
548 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
551 # disposed packets have an TTL expired
553 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
554 dst_ip=self.pg1.remote_ip6,
556 rx = self.send_and_expect(self.pg0, tx, self.pg0)
557 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
560 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
561 # so this traffic should be dropped.
563 route_33_neos = VppMplsRoute(self, 33, 0,
564 [VppRoutePath(self.pg0.remote_ip4,
565 self.pg0.sw_if_index,
567 route_33_neos.add_vpp_config()
569 tx = self.create_stream_labelled_ip4(self.pg0,
572 self.send_and_assert_no_replies(
574 "MPLS non-EOS packets popped and forwarded")
577 # A recursive EOS x-connect, which resolves through another x-connect
580 route_34_eos = VppMplsRoute(self, 34, 1,
581 [VppRoutePath("0.0.0.0",
584 labels=[VppMplsLabel(44),
586 route_34_eos.add_vpp_config()
588 tx = self.create_stream_labelled_ip4(self.pg0,
589 [VppMplsLabel(34, ttl=3)])
590 rx = self.send_and_expect(self.pg0, tx, self.pg0)
591 self.verify_capture_labelled(self.pg0, rx, tx,
594 VppMplsLabel(45, ttl=2)])
596 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
597 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
600 # A recursive EOS x-connect, which resolves through another x-connect
603 route_35_eos = VppMplsRoute(
605 [VppRoutePath("0.0.0.0",
608 labels=[VppMplsLabel(44)])])
609 route_35_eos.add_vpp_config()
611 tx = self.create_stream_labelled_ip4(self.pg0,
612 [VppMplsLabel(35, ttl=3)])
613 rx = self.send_and_expect(self.pg0, tx, self.pg0)
614 self.verify_capture_labelled(self.pg0, rx, tx,
615 [VppMplsLabel(43, ttl=2),
616 VppMplsLabel(44, ttl=2)])
619 # A recursive non-EOS x-connect, which resolves through another
622 route_34_neos = VppMplsRoute(self, 34, 0,
623 [VppRoutePath("0.0.0.0",
626 labels=[VppMplsLabel(44),
628 route_34_neos.add_vpp_config()
630 tx = self.create_stream_labelled_ip4(self.pg0,
631 [VppMplsLabel(34, ttl=45),
633 rx = self.send_and_expect(self.pg0, tx, self.pg0)
634 # it's the 2nd (counting from 0) label in the stack that is swapped
635 self.verify_capture_labelled(self.pg0, rx, tx,
638 VppMplsLabel(46, ttl=44),
642 # an recursive IP route that resolves through the recursive non-eos
645 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
646 [VppRoutePath("0.0.0.0",
649 labels=[VppMplsLabel(55)])])
650 ip_10_0_0_1.add_vpp_config()
652 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
653 rx = self.send_and_expect(self.pg0, tx, self.pg0)
654 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
659 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
661 ip_10_0_0_1.remove_vpp_config()
662 route_34_neos.remove_vpp_config()
663 route_34_eos.remove_vpp_config()
664 route_33_neos.remove_vpp_config()
665 route_33_eos.remove_vpp_config()
666 route_32_neos.remove_vpp_config()
667 route_32_eos.remove_vpp_config()
670 """ MPLS Local Label Binding test """
673 # Add a non-recursive route with a single out label
675 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
676 [VppRoutePath(self.pg0.remote_ip4,
677 self.pg0.sw_if_index,
678 labels=[VppMplsLabel(45)])])
679 route_10_0_0_1.add_vpp_config()
681 # bind a local label to the route
682 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
683 binding.add_vpp_config()
686 tx = self.create_stream_labelled_ip4(self.pg0,
689 rx = self.send_and_expect(self.pg0, tx, self.pg0)
690 self.verify_capture_labelled(self.pg0, rx, tx,
691 [VppMplsLabel(45, ttl=63),
695 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
696 rx = self.send_and_expect(self.pg0, tx, self.pg0)
697 self.verify_capture_labelled(self.pg0, rx, tx,
698 [VppMplsLabel(45, ttl=63)])
701 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
702 rx = self.send_and_expect(self.pg0, tx, self.pg0)
703 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
708 binding.remove_vpp_config()
709 route_10_0_0_1.remove_vpp_config()
711 def test_imposition(self):
712 """ MPLS label imposition test """
715 # Add a non-recursive route with a single out label
717 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
718 [VppRoutePath(self.pg0.remote_ip4,
719 self.pg0.sw_if_index,
720 labels=[VppMplsLabel(32)])])
721 route_10_0_0_1.add_vpp_config()
724 # a stream that matches the route for 10.0.0.1
725 # PG0 is in the default table
727 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
728 rx = self.send_and_expect(self.pg0, tx, self.pg0)
729 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
732 # Add a non-recursive route with a 3 out labels
734 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
735 [VppRoutePath(self.pg0.remote_ip4,
736 self.pg0.sw_if_index,
737 labels=[VppMplsLabel(32),
740 route_10_0_0_2.add_vpp_config()
742 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
743 ip_ttl=44, ip_dscp=0xff)
744 rx = self.send_and_expect(self.pg0, tx, self.pg0)
745 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
752 # Add a non-recursive route with a single out label in uniform mode
754 route_10_0_0_3 = VppIpRoute(
755 self, "10.0.0.3", 32,
756 [VppRoutePath(self.pg0.remote_ip4,
757 self.pg0.sw_if_index,
758 labels=[VppMplsLabel(32,
759 mode=MplsLspMode.UNIFORM)])])
760 route_10_0_0_3.add_vpp_config()
762 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
763 ip_ttl=54, ip_dscp=0xbe)
764 rx = self.send_and_expect(self.pg0, tx, self.pg0)
765 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
766 [VppMplsLabel(32, ttl=53, exp=5)])
769 # Add a IPv6 non-recursive route with a single out label in
772 route_2001_3 = VppIpRoute(
773 self, "2001::3", 128,
774 [VppRoutePath(self.pg0.remote_ip6,
775 self.pg0.sw_if_index,
776 proto=DpoProto.DPO_PROTO_IP6,
777 labels=[VppMplsLabel(32,
778 mode=MplsLspMode.UNIFORM)])],
780 route_2001_3.add_vpp_config()
782 tx = self.create_stream_ip6(self.pg0, "2001::3",
783 ip_ttl=54, ip_dscp=0xbe)
784 rx = self.send_and_expect(self.pg0, tx, self.pg0)
785 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
786 [VppMplsLabel(32, ttl=53, exp=5)])
789 # add a recursive path, with output label, via the 1 label route
791 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
792 [VppRoutePath("10.0.0.1",
794 labels=[VppMplsLabel(44)])])
795 route_11_0_0_1.add_vpp_config()
798 # a stream that matches the route for 11.0.0.1, should pick up
799 # the label stack for 11.0.0.1 and 10.0.0.1
801 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
802 rx = self.send_and_expect(self.pg0, tx, self.pg0)
803 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
807 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
810 # add a recursive path, with 2 labels, via the 3 label route
812 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
813 [VppRoutePath("10.0.0.2",
815 labels=[VppMplsLabel(44),
817 route_11_0_0_2.add_vpp_config()
820 # a stream that matches the route for 11.0.0.1, should pick up
821 # the label stack for 11.0.0.1 and 10.0.0.1
823 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
824 rx = self.send_and_expect(self.pg0, tx, self.pg0)
825 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
832 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
834 rx = self.send_and_expect(self.pg0, tx, self.pg0)
835 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
842 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
847 route_11_0_0_2.remove_vpp_config()
848 route_11_0_0_1.remove_vpp_config()
849 route_10_0_0_2.remove_vpp_config()
850 route_10_0_0_1.remove_vpp_config()
852 def test_tunnel_pipe(self):
853 """ MPLS Tunnel Tests - Pipe """
856 # Create a tunnel with a single out label
858 mpls_tun = VppMPLSTunnelInterface(
860 [VppRoutePath(self.pg0.remote_ip4,
861 self.pg0.sw_if_index,
862 labels=[VppMplsLabel(44),
864 mpls_tun.add_vpp_config()
868 # add an unlabelled route through the new tunnel
870 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
871 [VppRoutePath("0.0.0.0",
872 mpls_tun._sw_if_index)])
873 route_10_0_0_3.add_vpp_config()
875 self.vapi.cli("clear trace")
876 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
877 self.pg0.add_stream(tx)
879 self.pg_enable_capture(self.pg_interfaces)
882 rx = self.pg0.get_capture()
883 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
888 # add a labelled route through the new tunnel
890 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
891 [VppRoutePath("0.0.0.0",
892 mpls_tun._sw_if_index,
894 route_10_0_0_4.add_vpp_config()
896 self.vapi.cli("clear trace")
897 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
898 self.pg0.add_stream(tx)
900 self.pg_enable_capture(self.pg_interfaces)
903 rx = self.pg0.get_capture()
904 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
907 VppMplsLabel(33, ttl=255)])
909 def test_tunnel_uniform(self):
910 """ MPLS Tunnel Tests - Uniform """
913 # Create a tunnel with a single out label
914 # The label stack is specified here from outer to inner
916 mpls_tun = VppMPLSTunnelInterface(
918 [VppRoutePath(self.pg0.remote_ip4,
919 self.pg0.sw_if_index,
920 labels=[VppMplsLabel(44, ttl=32),
921 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
922 mpls_tun.add_vpp_config()
926 # add an unlabelled route through the new tunnel
928 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
929 [VppRoutePath("0.0.0.0",
930 mpls_tun._sw_if_index)])
931 route_10_0_0_3.add_vpp_config()
933 self.vapi.cli("clear trace")
934 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
935 self.pg0.add_stream(tx)
937 self.pg_enable_capture(self.pg_interfaces)
940 rx = self.pg0.get_capture()
941 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
942 [VppMplsLabel(44, ttl=32),
943 VppMplsLabel(46, ttl=23)])
946 # add a labelled route through the new tunnel
948 route_10_0_0_4 = VppIpRoute(
949 self, "10.0.0.4", 32,
950 [VppRoutePath("0.0.0.0",
951 mpls_tun._sw_if_index,
952 labels=[VppMplsLabel(33, ttl=47)])])
953 route_10_0_0_4.add_vpp_config()
955 self.vapi.cli("clear trace")
956 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
957 self.pg0.add_stream(tx)
959 self.pg_enable_capture(self.pg_interfaces)
962 rx = self.pg0.get_capture()
963 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
964 [VppMplsLabel(44, ttl=32),
965 VppMplsLabel(46, ttl=47),
966 VppMplsLabel(33, ttl=47)])
968 def test_mpls_tunnel_many(self):
969 """ Multiple Tunnels """
972 mpls_tun = VppMPLSTunnelInterface(
974 [VppRoutePath(self.pg0.remote_ip4,
975 self.pg0.sw_if_index,
976 labels=[VppMplsLabel(44, ttl=32),
977 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
978 mpls_tun.add_vpp_config()
981 def test_v4_exp_null(self):
982 """ MPLS V4 Explicit NULL test """
985 # The first test case has an MPLS TTL of 0
986 # all packet should be dropped
988 tx = self.create_stream_labelled_ip4(self.pg0,
989 [VppMplsLabel(0, ttl=0)])
990 self.send_and_assert_no_replies(self.pg0, tx,
991 "MPLS TTL=0 packets forwarded")
994 # a stream with a non-zero MPLS TTL
995 # PG0 is in the default table
997 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
998 rx = self.send_and_expect(self.pg0, tx, self.pg0)
999 self.verify_capture_ip4(self.pg0, rx, tx)
1002 # a stream with a non-zero MPLS TTL
1004 # we are ensuring the post-pop lookup occurs in the VRF table
1006 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1007 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1008 self.verify_capture_ip4(self.pg1, rx, tx)
1010 def test_v6_exp_null(self):
1011 """ MPLS V6 Explicit NULL test """
1014 # a stream with a non-zero MPLS TTL
1015 # PG0 is in the default table
1017 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1018 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1019 self.verify_capture_ip6(self.pg0, rx, tx)
1022 # a stream with a non-zero MPLS TTL
1024 # we are ensuring the post-pop lookup occurs in the VRF table
1026 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1027 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1028 self.verify_capture_ip6(self.pg0, rx, tx)
1030 def test_deag(self):
1034 # A de-agg route - next-hop lookup in default table
1036 route_34_eos = VppMplsRoute(self, 34, 1,
1037 [VppRoutePath("0.0.0.0",
1040 route_34_eos.add_vpp_config()
1043 # ping an interface in the default table
1044 # PG0 is in the default table
1046 tx = self.create_stream_labelled_ip4(self.pg0,
1050 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1051 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1054 # A de-agg route - next-hop lookup in non-default table
1056 route_35_eos = VppMplsRoute(self, 35, 1,
1057 [VppRoutePath("0.0.0.0",
1060 route_35_eos.add_vpp_config()
1063 # ping an interface in the non-default table
1064 # PG0 is in the default table. packet arrive labelled in the
1065 # default table and egress unlabelled in the non-default
1067 tx = self.create_stream_labelled_ip4(
1068 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1069 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1070 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1075 route_36_neos = VppMplsRoute(self, 36, 0,
1076 [VppRoutePath("0.0.0.0",
1078 route_36_neos.add_vpp_config()
1080 tx = self.create_stream_labelled_ip4(self.pg0,
1083 ping=1, ip_itf=self.pg1)
1084 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1085 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1087 route_36_neos.remove_vpp_config()
1088 route_35_eos.remove_vpp_config()
1089 route_34_eos.remove_vpp_config()
1091 def test_interface_rx(self):
1092 """ MPLS Interface Receive """
1095 # Add a non-recursive route that will forward the traffic
1098 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1100 paths=[VppRoutePath(self.pg1.remote_ip4,
1101 self.pg1.sw_if_index)])
1102 route_10_0_0_1.add_vpp_config()
1105 # An interface receive label that maps traffic to RX on interface
1107 # by injecting the packet in on pg0, which is in table 0
1108 # doing an interface-rx on pg1 and matching a route in table 1
1109 # if the packet egresses, then we must have swapped to pg1
1110 # so as to have matched the route in table 1
1112 route_34_eos = VppMplsRoute(self, 34, 1,
1113 [VppRoutePath("0.0.0.0",
1114 self.pg1.sw_if_index,
1115 is_interface_rx=1)])
1116 route_34_eos.add_vpp_config()
1119 # ping an interface in the default table
1120 # PG0 is in the default table
1122 tx = self.create_stream_labelled_ip4(self.pg0,
1125 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1126 self.verify_capture_ip4(self.pg1, rx, tx)
1128 def test_mcast_mid_point(self):
1129 """ MPLS Multicast Mid Point """
1132 # Add a non-recursive route that will forward the traffic
1135 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1137 paths=[VppRoutePath(self.pg1.remote_ip4,
1138 self.pg1.sw_if_index)])
1139 route_10_0_0_1.add_vpp_config()
1142 # Add a mcast entry that replicate to pg2 and pg3
1143 # and replicate to a interface-rx (like a bud node would)
1145 route_3400_eos = VppMplsRoute(
1147 [VppRoutePath(self.pg2.remote_ip4,
1148 self.pg2.sw_if_index,
1149 labels=[VppMplsLabel(3401)]),
1150 VppRoutePath(self.pg3.remote_ip4,
1151 self.pg3.sw_if_index,
1152 labels=[VppMplsLabel(3402)]),
1153 VppRoutePath("0.0.0.0",
1154 self.pg1.sw_if_index,
1155 is_interface_rx=1)],
1157 route_3400_eos.add_vpp_config()
1160 # ping an interface in the default table
1161 # PG0 is in the default table
1163 self.vapi.cli("clear trace")
1164 tx = self.create_stream_labelled_ip4(self.pg0,
1165 [VppMplsLabel(3400, ttl=64)],
1168 self.pg0.add_stream(tx)
1170 self.pg_enable_capture(self.pg_interfaces)
1173 rx = self.pg1.get_capture(257)
1174 self.verify_capture_ip4(self.pg1, rx, tx)
1176 rx = self.pg2.get_capture(257)
1177 self.verify_capture_labelled(self.pg2, rx, tx,
1178 [VppMplsLabel(3401, ttl=63)])
1179 rx = self.pg3.get_capture(257)
1180 self.verify_capture_labelled(self.pg3, rx, tx,
1181 [VppMplsLabel(3402, ttl=63)])
1183 def test_mcast_head(self):
1184 """ MPLS Multicast Head-end """
1187 # Create a multicast tunnel with two replications
1189 mpls_tun = VppMPLSTunnelInterface(
1191 [VppRoutePath(self.pg2.remote_ip4,
1192 self.pg2.sw_if_index,
1193 labels=[VppMplsLabel(42)]),
1194 VppRoutePath(self.pg3.remote_ip4,
1195 self.pg3.sw_if_index,
1196 labels=[VppMplsLabel(43)])],
1198 mpls_tun.add_vpp_config()
1202 # add an unlabelled route through the new tunnel
1204 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1205 [VppRoutePath("0.0.0.0",
1206 mpls_tun._sw_if_index)])
1207 route_10_0_0_3.add_vpp_config()
1209 self.vapi.cli("clear trace")
1210 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1211 self.pg0.add_stream(tx)
1213 self.pg_enable_capture(self.pg_interfaces)
1216 rx = self.pg2.get_capture(257)
1217 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1218 rx = self.pg3.get_capture(257)
1219 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1222 # An an IP multicast route via the tunnel
1224 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1226 route_232_1_1_1 = VppIpMRoute(
1230 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1231 [VppMRoutePath(self.pg0.sw_if_index,
1232 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1233 VppMRoutePath(mpls_tun._sw_if_index,
1234 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1235 route_232_1_1_1.add_vpp_config()
1237 self.vapi.cli("clear trace")
1238 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1239 self.pg0.add_stream(tx)
1241 self.pg_enable_capture(self.pg_interfaces)
1244 rx = self.pg2.get_capture(257)
1245 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1246 rx = self.pg3.get_capture(257)
1247 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1249 def test_mcast_ip4_tail(self):
1250 """ MPLS IPv4 Multicast Tail """
1253 # Add a multicast route that will forward the traffic
1256 route_232_1_1_1 = VppIpMRoute(
1260 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1262 paths=[VppMRoutePath(self.pg1.sw_if_index,
1263 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1264 route_232_1_1_1.add_vpp_config()
1267 # An interface receive label that maps traffic to RX on interface
1269 # by injecting the packet in on pg0, which is in table 0
1270 # doing an rpf-id and matching a route in table 1
1271 # if the packet egresses, then we must have matched the route in
1274 route_34_eos = VppMplsRoute(self, 34, 1,
1275 [VppRoutePath("0.0.0.0",
1276 self.pg1.sw_if_index,
1281 route_34_eos.add_vpp_config()
1284 # Drop due to interface lookup miss
1286 self.vapi.cli("clear trace")
1287 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1288 dst_ip="232.1.1.1", n=1)
1289 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1292 # set the RPF-ID of the entry to match the input packet's
1294 route_232_1_1_1.update_rpf_id(55)
1296 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1298 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1299 self.verify_capture_ip4(self.pg1, rx, tx)
1302 # disposed packets have an invalid IPv4 checksum
1304 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1305 dst_ip="232.1.1.1", n=65,
1307 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1310 # set the RPF-ID of the entry to not match the input packet's
1312 route_232_1_1_1.update_rpf_id(56)
1313 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1315 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1317 def test_mcast_ip6_tail(self):
1318 """ MPLS IPv6 Multicast Tail """
1321 # Add a multicast route that will forward the traffic
1324 route_ff = VppIpMRoute(
1328 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1330 paths=[VppMRoutePath(self.pg1.sw_if_index,
1331 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
1333 route_ff.add_vpp_config()
1336 # An interface receive label that maps traffic to RX on interface
1338 # by injecting the packet in on pg0, which is in table 0
1339 # doing an rpf-id and matching a route in table 1
1340 # if the packet egresses, then we must have matched the route in
1343 route_34_eos = VppMplsRoute(
1346 self.pg1.sw_if_index,
1349 proto=DpoProto.DPO_PROTO_IP6)],
1352 route_34_eos.add_vpp_config()
1355 # Drop due to interface lookup miss
1357 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1359 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1362 # set the RPF-ID of the entry to match the input packet's
1364 route_ff.update_rpf_id(55)
1366 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1368 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1369 self.verify_capture_ip6(self.pg1, rx, tx)
1372 # disposed packets have hop-limit = 1
1374 tx = self.create_stream_labelled_ip6(self.pg0,
1378 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1379 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1382 # set the RPF-ID of the entry to not match the input packet's
1384 route_ff.update_rpf_id(56)
1385 tx = self.create_stream_labelled_ip6(self.pg0,
1388 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1391 class TestMPLSDisabled(VppTestCase):
1392 """ MPLS disabled """
1395 def setUpClass(cls):
1396 super(TestMPLSDisabled, cls).setUpClass()
1399 def tearDownClass(cls):
1400 super(TestMPLSDisabled, cls).tearDownClass()
1403 super(TestMPLSDisabled, self).setUp()
1405 # create 2 pg interfaces
1406 self.create_pg_interfaces(range(2))
1408 self.tbl = VppMplsTable(self, 0)
1409 self.tbl.add_vpp_config()
1411 # PG0 is MPLS enabled
1413 self.pg0.config_ip4()
1414 self.pg0.resolve_arp()
1415 self.pg0.enable_mpls()
1417 # PG 1 is not MPLS enabled
1421 for i in self.pg_interfaces:
1425 self.pg0.disable_mpls()
1426 super(TestMPLSDisabled, self).tearDown()
1428 def test_mpls_disabled(self):
1429 """ MPLS Disabled """
1431 tx = (Ether(src=self.pg1.remote_mac,
1432 dst=self.pg1.local_mac) /
1433 MPLS(label=32, ttl=64) /
1434 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1435 UDP(sport=1234, dport=1234) /
1439 # A simple MPLS xconnect - eos label in label out
1441 route_32_eos = VppMplsRoute(self, 32, 1,
1442 [VppRoutePath(self.pg0.remote_ip4,
1443 self.pg0.sw_if_index,
1445 route_32_eos.add_vpp_config()
1448 # PG1 does not forward IP traffic
1450 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1455 self.pg1.enable_mpls()
1458 # Now we get packets through
1460 self.pg1.add_stream(tx)
1461 self.pg_enable_capture(self.pg_interfaces)
1464 rx = self.pg0.get_capture(1)
1469 self.pg1.disable_mpls()
1472 # PG1 does not forward IP traffic
1474 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1475 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1478 class TestMPLSPIC(VppTestCase):
1479 """ MPLS PIC edge convergence """
1482 def setUpClass(cls):
1483 super(TestMPLSPIC, cls).setUpClass()
1486 def tearDownClass(cls):
1487 super(TestMPLSPIC, cls).tearDownClass()
1490 super(TestMPLSPIC, self).setUp()
1492 # create 2 pg interfaces
1493 self.create_pg_interfaces(range(4))
1495 mpls_tbl = VppMplsTable(self, 0)
1496 mpls_tbl.add_vpp_config()
1497 tbl4 = VppIpTable(self, 1)
1498 tbl4.add_vpp_config()
1499 tbl6 = VppIpTable(self, 1, is_ip6=1)
1500 tbl6.add_vpp_config()
1504 self.pg0.config_ip4()
1505 self.pg0.resolve_arp()
1506 self.pg0.enable_mpls()
1508 self.pg1.config_ip4()
1509 self.pg1.resolve_arp()
1510 self.pg1.enable_mpls()
1512 # VRF (customer facing) link
1514 self.pg2.set_table_ip4(1)
1515 self.pg2.config_ip4()
1516 self.pg2.resolve_arp()
1517 self.pg2.set_table_ip6(1)
1518 self.pg2.config_ip6()
1519 self.pg2.resolve_ndp()
1521 self.pg3.set_table_ip4(1)
1522 self.pg3.config_ip4()
1523 self.pg3.resolve_arp()
1524 self.pg3.set_table_ip6(1)
1525 self.pg3.config_ip6()
1526 self.pg3.resolve_ndp()
1529 self.pg0.disable_mpls()
1530 self.pg1.disable_mpls()
1531 for i in self.pg_interfaces:
1537 super(TestMPLSPIC, self).tearDown()
1539 def test_mpls_ibgp_pic(self):
1540 """ MPLS iBGP PIC edge convergence
1542 1) setup many iBGP VPN routes via a pair of iBGP peers.
1543 2) Check EMCP forwarding to these peers
1544 3) withdraw the IGP route to one of these peers.
1545 4) check forwarding continues to the remaining peer
1549 # IGP+LDP core routes
1551 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1552 [VppRoutePath(self.pg0.remote_ip4,
1553 self.pg0.sw_if_index,
1555 core_10_0_0_45.add_vpp_config()
1557 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1558 [VppRoutePath(self.pg1.remote_ip4,
1559 self.pg1.sw_if_index,
1561 core_10_0_0_46.add_vpp_config()
1564 # Lot's of VPN routes. We need more the 64 so VPP will build
1565 # the fast convergence indirection
1569 for ii in range(64):
1570 dst = "192.168.1.%d" % ii
1571 vpn_routes.append(VppIpRoute(self, dst, 32,
1572 [VppRoutePath("10.0.0.45",
1576 VppRoutePath("10.0.0.46",
1579 is_resolve_host=1)],
1581 vpn_routes[ii].add_vpp_config()
1583 pkts.append(Ether(dst=self.pg2.local_mac,
1584 src=self.pg2.remote_mac) /
1585 IP(src=self.pg2.remote_ip4, dst=dst) /
1586 UDP(sport=1234, dport=1234) /
1590 # Send the packet stream (one pkt to each VPN route)
1591 # - expect a 50-50 split of the traffic
1593 self.pg2.add_stream(pkts)
1594 self.pg_enable_capture(self.pg_interfaces)
1597 rx0 = self.pg0._get_capture(1)
1598 rx1 = self.pg1._get_capture(1)
1600 # not testing the LB hashing algorithm so we're not concerned
1601 # with the split ratio, just as long as neither is 0
1602 self.assertNotEqual(0, len(rx0))
1603 self.assertNotEqual(0, len(rx1))
1606 # use a test CLI command to stop the FIB walk process, this
1607 # will prevent the FIB converging the VPN routes and thus allow
1608 # us to probe the interim (post-fail, pre-converge) state
1610 self.vapi.ppcli("test fib-walk-process disable")
1613 # Withdraw one of the IGP routes
1615 core_10_0_0_46.remove_vpp_config()
1618 # now all packets should be forwarded through the remaining peer
1620 self.vapi.ppcli("clear trace")
1621 self.pg2.add_stream(pkts)
1622 self.pg_enable_capture(self.pg_interfaces)
1625 rx0 = self.pg0.get_capture(len(pkts))
1628 # enable the FIB walk process to converge the FIB
1630 self.vapi.ppcli("test fib-walk-process enable")
1633 # packets should still be forwarded through the remaining peer
1635 self.pg2.add_stream(pkts)
1636 self.pg_enable_capture(self.pg_interfaces)
1639 rx0 = self.pg0.get_capture(64)
1642 # Add the IGP route back and we return to load-balancing
1644 core_10_0_0_46.add_vpp_config()
1646 self.pg2.add_stream(pkts)
1647 self.pg_enable_capture(self.pg_interfaces)
1650 rx0 = self.pg0._get_capture(1)
1651 rx1 = self.pg1._get_capture(1)
1652 self.assertNotEqual(0, len(rx0))
1653 self.assertNotEqual(0, len(rx1))
1655 def test_mpls_ebgp_pic(self):
1656 """ MPLS eBGP PIC edge convergence
1658 1) setup many eBGP VPN routes via a pair of eBGP peers
1659 2) Check EMCP forwarding to these peers
1660 3) withdraw one eBGP path - expect LB across remaining eBGP
1664 # Lot's of VPN routes. We need more the 64 so VPP will build
1665 # the fast convergence indirection
1670 for ii in range(64):
1671 dst = "192.168.1.%d" % ii
1672 local_label = 1600 + ii
1673 vpn_routes.append(VppIpRoute(self, dst, 32,
1674 [VppRoutePath(self.pg2.remote_ip4,
1677 is_resolve_attached=1),
1678 VppRoutePath(self.pg3.remote_ip4,
1681 is_resolve_attached=1)],
1683 vpn_routes[ii].add_vpp_config()
1685 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1687 vpn_bindings[ii].add_vpp_config()
1689 pkts.append(Ether(dst=self.pg0.local_mac,
1690 src=self.pg0.remote_mac) /
1691 MPLS(label=local_label, ttl=64) /
1692 IP(src=self.pg0.remote_ip4, dst=dst) /
1693 UDP(sport=1234, dport=1234) /
1696 self.pg0.add_stream(pkts)
1697 self.pg_enable_capture(self.pg_interfaces)
1700 rx0 = self.pg2._get_capture(1)
1701 rx1 = self.pg3._get_capture(1)
1702 self.assertNotEqual(0, len(rx0))
1703 self.assertNotEqual(0, len(rx1))
1706 # use a test CLI command to stop the FIB walk process, this
1707 # will prevent the FIB converging the VPN routes and thus allow
1708 # us to probe the interim (post-fail, pre-converge) state
1710 self.vapi.ppcli("test fib-walk-process disable")
1713 # withdraw the connected prefix on the interface.
1715 self.pg2.unconfig_ip4()
1718 # now all packets should be forwarded through the remaining peer
1720 self.pg0.add_stream(pkts)
1721 self.pg_enable_capture(self.pg_interfaces)
1724 rx0 = self.pg3.get_capture(len(pkts))
1727 # enable the FIB walk process to converge the FIB
1729 self.vapi.ppcli("test fib-walk-process enable")
1730 self.pg0.add_stream(pkts)
1731 self.pg_enable_capture(self.pg_interfaces)
1734 rx0 = self.pg3.get_capture(len(pkts))
1737 # put the connecteds back
1739 self.pg2.config_ip4()
1741 self.pg0.add_stream(pkts)
1742 self.pg_enable_capture(self.pg_interfaces)
1745 rx0 = self.pg2._get_capture(1)
1746 rx1 = self.pg3._get_capture(1)
1747 self.assertNotEqual(0, len(rx0))
1748 self.assertNotEqual(0, len(rx1))
1750 def test_mpls_v6_ebgp_pic(self):
1751 """ MPLSv6 eBGP PIC edge convergence
1753 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1754 2) Check EMCP forwarding to these peers
1755 3) withdraw one eBGP path - expect LB across remaining eBGP
1759 # Lot's of VPN routes. We need more the 64 so VPP will build
1760 # the fast convergence indirection
1765 for ii in range(64):
1766 dst = "3000::%d" % ii
1767 local_label = 1600 + ii
1768 vpn_routes.append(VppIpRoute(
1770 [VppRoutePath(self.pg2.remote_ip6,
1773 is_resolve_attached=1,
1774 proto=DpoProto.DPO_PROTO_IP6),
1775 VppRoutePath(self.pg3.remote_ip6,
1778 proto=DpoProto.DPO_PROTO_IP6,
1779 is_resolve_attached=1)],
1782 vpn_routes[ii].add_vpp_config()
1784 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1787 vpn_bindings[ii].add_vpp_config()
1789 pkts.append(Ether(dst=self.pg0.local_mac,
1790 src=self.pg0.remote_mac) /
1791 MPLS(label=local_label, ttl=64) /
1792 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1793 UDP(sport=1234, dport=1234) /
1796 self.pg0.add_stream(pkts)
1797 self.pg_enable_capture(self.pg_interfaces)
1800 rx0 = self.pg2._get_capture(1)
1801 rx1 = self.pg3._get_capture(1)
1802 self.assertNotEqual(0, len(rx0))
1803 self.assertNotEqual(0, len(rx1))
1806 # use a test CLI command to stop the FIB walk process, this
1807 # will prevent the FIB converging the VPN routes and thus allow
1808 # us to probe the interim (post-fail, pre-converge) state
1810 self.vapi.ppcli("test fib-walk-process disable")
1813 # withdraw the connected prefix on the interface.
1814 # and shutdown the interface so the ND cache is flushed.
1816 self.pg2.unconfig_ip6()
1817 self.pg2.admin_down()
1820 # now all packets should be forwarded through the remaining peer
1822 self.pg0.add_stream(pkts)
1823 self.pg_enable_capture(self.pg_interfaces)
1826 rx0 = self.pg3.get_capture(len(pkts))
1829 # enable the FIB walk process to converge the FIB
1831 self.vapi.ppcli("test fib-walk-process enable")
1832 self.pg0.add_stream(pkts)
1833 self.pg_enable_capture(self.pg_interfaces)
1836 rx0 = self.pg3.get_capture(len(pkts))
1839 # put the connecteds back
1842 self.pg2.config_ip6()
1844 self.pg0.add_stream(pkts)
1845 self.pg_enable_capture(self.pg_interfaces)
1848 rx0 = self.pg2._get_capture(1)
1849 rx1 = self.pg3._get_capture(1)
1850 self.assertNotEqual(0, len(rx0))
1851 self.assertNotEqual(0, len(rx1))
1854 class TestMPLSL2(VppTestCase):
1858 def setUpClass(cls):
1859 super(TestMPLSL2, cls).setUpClass()
1862 def tearDownClass(cls):
1863 super(TestMPLSL2, cls).tearDownClass()
1866 super(TestMPLSL2, self).setUp()
1868 # create 2 pg interfaces
1869 self.create_pg_interfaces(range(2))
1871 # create the default MPLS table
1873 tbl = VppMplsTable(self, 0)
1874 tbl.add_vpp_config()
1875 self.tables.append(tbl)
1877 # use pg0 as the core facing interface
1879 self.pg0.config_ip4()
1880 self.pg0.resolve_arp()
1881 self.pg0.enable_mpls()
1883 # use the other 2 for customer facing L2 links
1884 for i in self.pg_interfaces[1:]:
1888 for i in self.pg_interfaces[1:]:
1891 self.pg0.disable_mpls()
1892 self.pg0.unconfig_ip4()
1893 self.pg0.admin_down()
1894 super(TestMPLSL2, self).tearDown()
1896 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
1897 capture = verify_filter(capture, sent)
1899 self.assertEqual(len(capture), len(sent))
1901 for i in range(len(capture)):
1905 # the MPLS TTL is 255 since it enters a new tunnel
1906 verify_mpls_stack(self, rx, mpls_labels)
1909 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
1911 self.assertEqual(rx_eth.src, tx_eth.src)
1912 self.assertEqual(rx_eth.dst, tx_eth.dst)
1914 def test_vpws(self):
1915 """ Virtual Private Wire Service """
1918 # Create an MPLS tunnel that pushes 1 label
1919 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
1920 # information is not in the packet, but we test it works anyway
1922 mpls_tun_1 = VppMPLSTunnelInterface(
1924 [VppRoutePath(self.pg0.remote_ip4,
1925 self.pg0.sw_if_index,
1926 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
1928 mpls_tun_1.add_vpp_config()
1929 mpls_tun_1.admin_up()
1932 # Create a label entry to for 55 that does L2 input to the tunnel
1934 route_55_eos = VppMplsRoute(
1936 [VppRoutePath("0.0.0.0",
1937 mpls_tun_1.sw_if_index,
1939 proto=DpoProto.DPO_PROTO_ETHERNET)])
1940 route_55_eos.add_vpp_config()
1943 # Cross-connect the tunnel with one of the customers L2 interfaces
1945 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
1946 mpls_tun_1.sw_if_index,
1948 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
1949 self.pg1.sw_if_index,
1953 # inject a packet from the core
1955 pcore = (Ether(dst=self.pg0.local_mac,
1956 src=self.pg0.remote_mac) /
1957 MPLS(label=55, ttl=64) /
1958 Ether(dst="00:00:de:ad:ba:be",
1959 src="00:00:de:ad:be:ef") /
1960 IP(src="10.10.10.10", dst="11.11.11.11") /
1961 UDP(sport=1234, dport=1234) /
1965 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
1966 payload = pcore[MPLS].payload
1968 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
1969 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
1972 # Inject a packet from the customer/L2 side
1974 tx1 = pcore[MPLS].payload * 65
1975 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
1977 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
1979 def test_vpls(self):
1980 """ Virtual Private LAN Service """
1982 # Create an L2 MPLS tunnel
1984 mpls_tun = VppMPLSTunnelInterface(
1986 [VppRoutePath(self.pg0.remote_ip4,
1987 self.pg0.sw_if_index,
1988 labels=[VppMplsLabel(42)])],
1990 mpls_tun.add_vpp_config()
1994 # Create a label entry to for 55 that does L2 input to the tunnel
1996 route_55_eos = VppMplsRoute(
1998 [VppRoutePath("0.0.0.0",
1999 mpls_tun.sw_if_index,
2001 proto=DpoProto.DPO_PROTO_ETHERNET)])
2002 route_55_eos.add_vpp_config()
2005 # add to tunnel to the customers bridge-domain
2007 self.vapi.sw_interface_set_l2_bridge(
2008 rx_sw_if_index=mpls_tun.sw_if_index, bd_id=1)
2009 self.vapi.sw_interface_set_l2_bridge(
2010 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2013 # Packet from the customer interface and from the core
2015 p_cust = (Ether(dst="00:00:de:ad:ba:be",
2016 src="00:00:de:ad:be:ef") /
2017 IP(src="10.10.10.10", dst="11.11.11.11") /
2018 UDP(sport=1234, dport=1234) /
2020 p_core = (Ether(src="00:00:de:ad:ba:be",
2021 dst="00:00:de:ad:be:ef") /
2022 IP(dst="10.10.10.10", src="11.11.11.11") /
2023 UDP(sport=1234, dport=1234) /
2027 # The BD is learning, so send in one of each packet to learn
2029 p_core_encap = (Ether(dst=self.pg0.local_mac,
2030 src=self.pg0.remote_mac) /
2031 MPLS(label=55, ttl=64) /
2034 self.pg1.add_stream(p_cust)
2035 self.pg_enable_capture(self.pg_interfaces)
2037 self.pg0.add_stream(p_core_encap)
2038 self.pg_enable_capture(self.pg_interfaces)
2041 # we've learnt this so expect it be be forwarded
2042 rx0 = self.pg1.get_capture(1)
2044 self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst)
2045 self.assertEqual(rx0[0][Ether].src, p_core[Ether].src)
2048 # now a stream in each direction
2050 self.pg1.add_stream(p_cust * 65)
2051 self.pg_enable_capture(self.pg_interfaces)
2054 rx0 = self.pg0.get_capture(65)
2056 self.verify_capture_tunneled_ethernet(rx0, p_cust*65,
2060 # remove interfaces from customers bridge-domain
2062 self.vapi.sw_interface_set_l2_bridge(
2063 rx_sw_if_index=mpls_tun.sw_if_index, bd_id=1, enable=0)
2064 self.vapi.sw_interface_set_l2_bridge(
2065 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2067 if __name__ == '__main__':
2068 unittest.main(testRunner=VppTestRunner)