6 from framework import VppTestCase, VppTestRunner
7 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
8 VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
9 MRouteItfFlags, MRouteEntryFlags, DpoProto, VppIpTable, VppMplsTable
10 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
12 from scapy.packet import Raw
13 from scapy.layers.l2 import Ether
14 from scapy.layers.inet import IP, UDP, ICMP
15 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
16 from scapy.contrib.mpls import MPLS
19 def verify_filter(capture, sent):
20 if not len(capture) == len(sent):
21 # filter out any IPv6 RAs from the capture
28 def verify_mpls_stack(tst, rx, mpls_labels, ttl=255, num=0):
29 # the rx'd packet has the MPLS label popped
31 tst.assertEqual(eth.type, 0x8847)
35 for ii in range(len(mpls_labels)):
36 tst.assertEqual(rx_mpls.label, mpls_labels[ii])
37 tst.assertEqual(rx_mpls.cos, 0)
39 tst.assertEqual(rx_mpls.ttl, ttl)
41 tst.assertEqual(rx_mpls.ttl, 255)
42 if ii == len(mpls_labels) - 1:
43 tst.assertEqual(rx_mpls.s, 1)
46 tst.assertEqual(rx_mpls.s, 0)
47 # pop the label to expose the next
48 rx_mpls = rx_mpls[MPLS].payload
51 class TestMPLS(VppTestCase):
52 """ MPLS Test Case """
55 super(TestMPLS, self).setUp()
57 # create 2 pg interfaces
58 self.create_pg_interfaces(range(4))
60 # setup both interfaces
61 # assign them different tables.
65 tbl = VppMplsTable(self, 0)
67 self.tables.append(tbl)
69 for i in self.pg_interfaces:
73 tbl = VppIpTable(self, table_id)
75 self.tables.append(tbl)
76 tbl = VppIpTable(self, table_id, is_ip6=1)
78 self.tables.append(tbl)
80 i.set_table_ip4(table_id)
81 i.set_table_ip6(table_id)
90 for i in self.pg_interfaces:
98 super(TestMPLS, self).tearDown()
100 # the default of 64 matches the IP packet TTL default
101 def create_stream_labelled_ip4(
111 self.reset_packet_infos()
113 for i in range(0, n):
114 info = self.create_packet_info(src_if, src_if)
115 payload = self.info_to_payload(info)
116 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
118 for ii in range(len(mpls_labels)):
119 if ii == len(mpls_labels) - 1:
120 p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=1)
122 p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=0)
125 p = (p / IP(src=src_if.local_ip4, dst=src_if.remote_ip4) /
126 UDP(sport=1234, dport=1234) /
129 p = (p / IP(src=src_if.local_ip4, dst=dst_ip) /
130 UDP(sport=1234, dport=1234) /
133 p = (p / IP(src=ip_itf.remote_ip4,
134 dst=ip_itf.local_ip4) /
138 p[IP].chksum = chksum
143 def create_stream_ip4(self, src_if, dst_ip):
144 self.reset_packet_infos()
146 for i in range(0, 257):
147 info = self.create_packet_info(src_if, src_if)
148 payload = self.info_to_payload(info)
149 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
150 IP(src=src_if.remote_ip4, dst=dst_ip) /
151 UDP(sport=1234, dport=1234) /
157 def create_stream_labelled_ip6(self, src_if, mpls_label, mpls_ttl,
158 dst_ip=None, hlim=64):
160 dst_ip = src_if.remote_ip6
161 self.reset_packet_infos()
163 for i in range(0, 257):
164 info = self.create_packet_info(src_if, src_if)
165 payload = self.info_to_payload(info)
166 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
167 MPLS(label=mpls_label, ttl=mpls_ttl) /
168 IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
169 UDP(sport=1234, dport=1234) /
175 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0):
177 capture = verify_filter(capture, sent)
179 self.assertEqual(len(capture), len(sent))
181 for i in range(len(capture)):
185 # the rx'd packet has the MPLS label popped
187 self.assertEqual(eth.type, 0x800)
193 self.assertEqual(rx_ip.src, tx_ip.src)
194 self.assertEqual(rx_ip.dst, tx_ip.dst)
195 # IP processing post pop has decremented the TTL
196 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
198 self.assertEqual(rx_ip.src, tx_ip.dst)
199 self.assertEqual(rx_ip.dst, tx_ip.src)
204 def verify_capture_labelled_ip4(self, src_if, capture, sent,
207 capture = verify_filter(capture, sent)
209 self.assertEqual(len(capture), len(sent))
211 for i in range(len(capture)):
217 # the MPLS TTL is copied from the IP
218 verify_mpls_stack(self, rx, mpls_labels, rx_ip.ttl,
219 len(mpls_labels) - 1)
221 self.assertEqual(rx_ip.src, tx_ip.src)
222 self.assertEqual(rx_ip.dst, tx_ip.dst)
223 # IP processing post pop has decremented the TTL
224 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
229 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels,
232 top = len(mpls_labels) - 1
234 capture = verify_filter(capture, sent)
236 self.assertEqual(len(capture), len(sent))
238 for i in range(len(capture)):
244 # the MPLS TTL is 255 since it enters a new tunnel
245 verify_mpls_stack(self, rx, mpls_labels, ttl, top)
247 self.assertEqual(rx_ip.src, tx_ip.src)
248 self.assertEqual(rx_ip.dst, tx_ip.dst)
249 # IP processing post pop has decremented the TTL
250 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
255 def verify_capture_labelled(self, src_if, capture, sent,
256 mpls_labels, ttl=254, num=0):
258 capture = verify_filter(capture, sent)
260 self.assertEqual(len(capture), len(sent))
262 for i in range(len(capture)):
264 verify_mpls_stack(self, rx, mpls_labels, ttl, num)
268 def verify_capture_ip6(self, src_if, capture, sent):
270 self.assertEqual(len(capture), len(sent))
272 for i in range(len(capture)):
276 # the rx'd packet has the MPLS label popped
278 self.assertEqual(eth.type, 0x86DD)
283 self.assertEqual(rx_ip.src, tx_ip.src)
284 self.assertEqual(rx_ip.dst, tx_ip.dst)
285 # IP processing post pop has decremented the TTL
286 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
291 def verify_capture_ip6_icmp(self, src_if, capture, sent):
293 self.assertEqual(len(capture), len(sent))
295 for i in range(len(capture)):
299 # the rx'd packet has the MPLS label popped
301 self.assertEqual(eth.type, 0x86DD)
306 self.assertEqual(rx_ip.dst, tx_ip.src)
307 # ICMP sourced from the interface's address
308 self.assertEqual(rx_ip.src, src_if.local_ip6)
309 # hop-limit reset to 255 for IMCP packet
310 self.assertEqual(rx_ip.hlim, 254)
312 icmp = rx[ICMPv6TimeExceeded]
317 def send_and_assert_no_replies(self, intf, pkts, remark):
318 intf.add_stream(pkts)
319 self.pg_enable_capture(self.pg_interfaces)
321 for i in self.pg_interfaces:
322 i.assert_nothing_captured(remark=remark)
325 """ MPLS label swap tests """
328 # A simple MPLS xconnect - eos label in label out
330 route_32_eos = VppMplsRoute(self, 32, 1,
331 [VppRoutePath(self.pg0.remote_ip4,
332 self.pg0.sw_if_index,
334 route_32_eos.add_vpp_config()
337 # a stream that matches the route for 10.0.0.1
338 # PG0 is in the default table
340 self.vapi.cli("clear trace")
341 tx = self.create_stream_labelled_ip4(self.pg0, [32])
342 self.pg0.add_stream(tx)
344 self.pg_enable_capture(self.pg_interfaces)
347 rx = self.pg0.get_capture()
348 self.verify_capture_labelled(self.pg0, rx, tx, [33])
351 # A simple MPLS xconnect - non-eos label in label out
353 route_32_neos = VppMplsRoute(self, 32, 0,
354 [VppRoutePath(self.pg0.remote_ip4,
355 self.pg0.sw_if_index,
357 route_32_neos.add_vpp_config()
360 # a stream that matches the route for 10.0.0.1
361 # PG0 is in the default table
363 self.vapi.cli("clear trace")
364 tx = self.create_stream_labelled_ip4(self.pg0, [32, 99])
365 self.pg0.add_stream(tx)
367 self.pg_enable_capture(self.pg_interfaces)
370 rx = self.pg0.get_capture()
371 self.verify_capture_labelled(self.pg0, rx, tx, [33, 99])
374 # An MPLS xconnect - EOS label in IP out
376 route_33_eos = VppMplsRoute(self, 33, 1,
377 [VppRoutePath(self.pg0.remote_ip4,
378 self.pg0.sw_if_index,
380 route_33_eos.add_vpp_config()
382 self.vapi.cli("clear trace")
383 tx = self.create_stream_labelled_ip4(self.pg0, [33])
384 self.pg0.add_stream(tx)
386 self.pg_enable_capture(self.pg_interfaces)
389 rx = self.pg0.get_capture()
390 self.verify_capture_ip4(self.pg0, rx, tx)
393 # disposed packets have an invalid IPv4 checkusm
395 tx = self.create_stream_labelled_ip4(self.pg0, [33],
396 dst_ip=self.pg0.remote_ip4,
399 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
402 # An MPLS xconnect - EOS label in IPv6 out
404 route_333_eos = VppMplsRoute(
406 [VppRoutePath(self.pg0.remote_ip6,
407 self.pg0.sw_if_index,
409 proto=DpoProto.DPO_PROTO_IP6)])
410 route_333_eos.add_vpp_config()
412 self.vapi.cli("clear trace")
413 tx = self.create_stream_labelled_ip6(self.pg0, [333], 64)
414 self.pg0.add_stream(tx)
416 self.pg_enable_capture(self.pg_interfaces)
419 rx = self.pg0.get_capture()
420 self.verify_capture_ip6(self.pg0, rx, tx)
423 # disposed packets have an TTL expired
425 tx = self.create_stream_labelled_ip6(self.pg0, [333], 64,
426 dst_ip=self.pg1.remote_ip6,
429 self.vapi.cli("clear trace")
430 tx = self.create_stream_labelled_ip6(self.pg0, [333], 64,
431 dst_ip=self.pg1.remote_ip6,
433 self.pg0.add_stream(tx)
435 self.pg_enable_capture(self.pg_interfaces)
438 rx = self.pg0.get_capture()
439 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
442 # An MPLS xconnect - EOS label in IPv6 out w imp-null
444 route_334_eos = VppMplsRoute(
446 [VppRoutePath(self.pg0.remote_ip6,
447 self.pg0.sw_if_index,
449 proto=DpoProto.DPO_PROTO_IP6)])
450 route_334_eos.add_vpp_config()
452 self.vapi.cli("clear trace")
453 tx = self.create_stream_labelled_ip6(self.pg0, [334], 64)
454 self.pg0.add_stream(tx)
456 self.pg_enable_capture(self.pg_interfaces)
459 rx = self.pg0.get_capture()
460 self.verify_capture_ip6(self.pg0, rx, tx)
463 # disposed packets have an TTL expired
465 self.vapi.cli("clear trace")
466 tx = self.create_stream_labelled_ip6(self.pg0, [334], 64,
467 dst_ip=self.pg1.remote_ip6,
469 self.pg0.add_stream(tx)
471 self.pg_enable_capture(self.pg_interfaces)
474 rx = self.pg0.get_capture()
475 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
478 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
479 # so this traffic should be dropped.
481 route_33_neos = VppMplsRoute(self, 33, 0,
482 [VppRoutePath(self.pg0.remote_ip4,
483 self.pg0.sw_if_index,
485 route_33_neos.add_vpp_config()
487 self.vapi.cli("clear trace")
488 tx = self.create_stream_labelled_ip4(self.pg0, [33, 99])
489 self.pg0.add_stream(tx)
491 self.pg_enable_capture(self.pg_interfaces)
493 self.pg0.assert_nothing_captured(
494 remark="MPLS non-EOS packets popped and forwarded")
497 # A recursive EOS x-connect, which resolves through another x-connect
499 route_34_eos = VppMplsRoute(self, 34, 1,
500 [VppRoutePath("0.0.0.0",
504 route_34_eos.add_vpp_config()
506 tx = self.create_stream_labelled_ip4(self.pg0, [34])
507 self.pg0.add_stream(tx)
509 self.pg_enable_capture(self.pg_interfaces)
512 rx = self.pg0.get_capture()
513 self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 45], num=2)
516 # A recursive non-EOS x-connect, which resolves through another
519 route_34_neos = VppMplsRoute(self, 34, 0,
520 [VppRoutePath("0.0.0.0",
524 route_34_neos.add_vpp_config()
526 self.vapi.cli("clear trace")
527 tx = self.create_stream_labelled_ip4(self.pg0, [34, 99])
528 self.pg0.add_stream(tx)
530 self.pg_enable_capture(self.pg_interfaces)
533 rx = self.pg0.get_capture()
534 # it's the 2nd (counting from 0) label in the stack that is swapped
535 self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 46, 99], num=2)
538 # an recursive IP route that resolves through the recursive non-eos
541 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
542 [VppRoutePath("0.0.0.0",
546 ip_10_0_0_1.add_vpp_config()
548 self.vapi.cli("clear trace")
549 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
550 self.pg0.add_stream(tx)
552 self.pg_enable_capture(self.pg_interfaces)
555 rx = self.pg0.get_capture()
556 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 46, 55])
558 ip_10_0_0_1.remove_vpp_config()
559 route_34_neos.remove_vpp_config()
560 route_34_eos.remove_vpp_config()
561 route_33_neos.remove_vpp_config()
562 route_33_eos.remove_vpp_config()
563 route_32_neos.remove_vpp_config()
564 route_32_eos.remove_vpp_config()
567 """ MPLS Local Label Binding test """
570 # Add a non-recursive route with a single out label
572 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
573 [VppRoutePath(self.pg0.remote_ip4,
574 self.pg0.sw_if_index,
576 route_10_0_0_1.add_vpp_config()
578 # bind a local label to the route
579 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
580 binding.add_vpp_config()
583 self.vapi.cli("clear trace")
584 tx = self.create_stream_labelled_ip4(self.pg0, [44, 99])
585 self.pg0.add_stream(tx)
587 self.pg_enable_capture(self.pg_interfaces)
590 rx = self.pg0.get_capture()
591 self.verify_capture_labelled(self.pg0, rx, tx, [45, 99])
594 self.vapi.cli("clear trace")
595 tx = self.create_stream_labelled_ip4(self.pg0, [44])
596 self.pg0.add_stream(tx)
598 self.pg_enable_capture(self.pg_interfaces)
601 rx = self.pg0.get_capture()
602 self.verify_capture_labelled(self.pg0, rx, tx, [45])
605 self.vapi.cli("clear trace")
606 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
607 self.pg0.add_stream(tx)
609 self.pg_enable_capture(self.pg_interfaces)
612 rx = self.pg0.get_capture()
613 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [45])
618 binding.remove_vpp_config()
619 route_10_0_0_1.remove_vpp_config()
621 def test_imposition(self):
622 """ MPLS label imposition test """
625 # Add a non-recursive route with a single out label
627 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
628 [VppRoutePath(self.pg0.remote_ip4,
629 self.pg0.sw_if_index,
631 route_10_0_0_1.add_vpp_config()
634 # a stream that matches the route for 10.0.0.1
635 # PG0 is in the default table
637 self.vapi.cli("clear trace")
638 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
639 self.pg0.add_stream(tx)
641 self.pg_enable_capture(self.pg_interfaces)
644 rx = self.pg0.get_capture()
645 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32])
648 # Add a non-recursive route with a 3 out labels
650 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
651 [VppRoutePath(self.pg0.remote_ip4,
652 self.pg0.sw_if_index,
653 labels=[32, 33, 34])])
654 route_10_0_0_2.add_vpp_config()
657 # a stream that matches the route for 10.0.0.1
658 # PG0 is in the default table
660 self.vapi.cli("clear trace")
661 tx = self.create_stream_ip4(self.pg0, "10.0.0.2")
662 self.pg0.add_stream(tx)
664 self.pg_enable_capture(self.pg_interfaces)
667 rx = self.pg0.get_capture()
668 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 33, 34])
671 # add a recursive path, with output label, via the 1 label route
673 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
674 [VppRoutePath("10.0.0.1",
677 route_11_0_0_1.add_vpp_config()
680 # a stream that matches the route for 11.0.0.1, should pick up
681 # the label stack for 11.0.0.1 and 10.0.0.1
683 self.vapi.cli("clear trace")
684 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
685 self.pg0.add_stream(tx)
687 self.pg_enable_capture(self.pg_interfaces)
690 rx = self.pg0.get_capture()
691 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 44])
694 # add a recursive path, with 2 labels, via the 3 label route
696 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
697 [VppRoutePath("10.0.0.2",
700 route_11_0_0_2.add_vpp_config()
703 # a stream that matches the route for 11.0.0.1, should pick up
704 # the label stack for 11.0.0.1 and 10.0.0.1
706 self.vapi.cli("clear trace")
707 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
708 self.pg0.add_stream(tx)
710 self.pg_enable_capture(self.pg_interfaces)
713 rx = self.pg0.get_capture()
714 self.verify_capture_labelled_ip4(
715 self.pg0, rx, tx, [32, 33, 34, 44, 45])
720 route_11_0_0_2.remove_vpp_config()
721 route_11_0_0_1.remove_vpp_config()
722 route_10_0_0_2.remove_vpp_config()
723 route_10_0_0_1.remove_vpp_config()
725 def test_tunnel(self):
726 """ MPLS Tunnel Tests """
729 # Create a tunnel with a single out label
731 mpls_tun = VppMPLSTunnelInterface(self,
732 [VppRoutePath(self.pg0.remote_ip4,
733 self.pg0.sw_if_index,
735 mpls_tun.add_vpp_config()
739 # add an unlabelled route through the new tunnel
741 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
742 [VppRoutePath("0.0.0.0",
743 mpls_tun._sw_if_index)])
744 route_10_0_0_3.add_vpp_config()
746 self.vapi.cli("clear trace")
747 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
748 self.pg0.add_stream(tx)
750 self.pg_enable_capture(self.pg_interfaces)
753 rx = self.pg0.get_capture()
754 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46])
757 # add a labelled route through the new tunnel
759 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
760 [VppRoutePath("0.0.0.0",
761 mpls_tun._sw_if_index,
763 route_10_0_0_4.add_vpp_config()
765 self.vapi.cli("clear trace")
766 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
767 self.pg0.add_stream(tx)
769 self.pg_enable_capture(self.pg_interfaces)
772 rx = self.pg0.get_capture()
773 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46, 33],
776 def test_v4_exp_null(self):
777 """ MPLS V4 Explicit NULL test """
780 # The first test case has an MPLS TTL of 0
781 # all packet should be dropped
783 tx = self.create_stream_labelled_ip4(self.pg0, [0], 0)
784 self.pg0.add_stream(tx)
786 self.pg_enable_capture(self.pg_interfaces)
789 self.pg0.assert_nothing_captured(remark="MPLS TTL=0 packets forwarded")
792 # a stream with a non-zero MPLS TTL
793 # PG0 is in the default table
795 tx = self.create_stream_labelled_ip4(self.pg0, [0])
796 self.pg0.add_stream(tx)
798 self.pg_enable_capture(self.pg_interfaces)
801 rx = self.pg0.get_capture()
802 self.verify_capture_ip4(self.pg0, rx, tx)
805 # a stream with a non-zero MPLS TTL
807 # we are ensuring the post-pop lookup occurs in the VRF table
809 self.vapi.cli("clear trace")
810 tx = self.create_stream_labelled_ip4(self.pg1, [0])
811 self.pg1.add_stream(tx)
813 self.pg_enable_capture(self.pg_interfaces)
816 rx = self.pg1.get_capture()
817 self.verify_capture_ip4(self.pg0, rx, tx)
819 def test_v6_exp_null(self):
820 """ MPLS V6 Explicit NULL test """
823 # a stream with a non-zero MPLS TTL
824 # PG0 is in the default table
826 self.vapi.cli("clear trace")
827 tx = self.create_stream_labelled_ip6(self.pg0, 2, 2)
828 self.pg0.add_stream(tx)
830 self.pg_enable_capture(self.pg_interfaces)
833 rx = self.pg0.get_capture()
834 self.verify_capture_ip6(self.pg0, rx, tx)
837 # a stream with a non-zero MPLS TTL
839 # we are ensuring the post-pop lookup occurs in the VRF table
841 self.vapi.cli("clear trace")
842 tx = self.create_stream_labelled_ip6(self.pg1, 2, 2)
843 self.pg1.add_stream(tx)
845 self.pg_enable_capture(self.pg_interfaces)
848 rx = self.pg1.get_capture()
849 self.verify_capture_ip6(self.pg0, rx, tx)
855 # A de-agg route - next-hop lookup in default table
857 route_34_eos = VppMplsRoute(self, 34, 1,
858 [VppRoutePath("0.0.0.0",
861 route_34_eos.add_vpp_config()
864 # ping an interface in the default table
865 # PG0 is in the default table
867 self.vapi.cli("clear trace")
868 tx = self.create_stream_labelled_ip4(self.pg0, [34], ping=1,
870 self.pg0.add_stream(tx)
872 self.pg_enable_capture(self.pg_interfaces)
875 rx = self.pg0.get_capture()
876 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
879 # A de-agg route - next-hop lookup in non-default table
881 route_35_eos = VppMplsRoute(self, 35, 1,
882 [VppRoutePath("0.0.0.0",
885 route_35_eos.add_vpp_config()
888 # ping an interface in the non-default table
889 # PG0 is in the default table. packet arrive labelled in the
890 # default table and egress unlabelled in the non-default
892 self.vapi.cli("clear trace")
893 tx = self.create_stream_labelled_ip4(
894 self.pg0, [35], ping=1, ip_itf=self.pg1)
895 self.pg0.add_stream(tx)
897 self.pg_enable_capture(self.pg_interfaces)
900 packet_count = self.get_packet_count_for_if_idx(self.pg0.sw_if_index)
901 rx = self.pg1.get_capture(packet_count)
902 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
907 route_36_neos = VppMplsRoute(self, 36, 0,
908 [VppRoutePath("0.0.0.0",
910 route_36_neos.add_vpp_config()
912 self.vapi.cli("clear trace")
913 tx = self.create_stream_labelled_ip4(self.pg0, [36, 35],
914 ping=1, ip_itf=self.pg1)
915 self.pg0.add_stream(tx)
917 self.pg_enable_capture(self.pg_interfaces)
920 rx = self.pg1.get_capture(len(tx))
921 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
923 route_36_neos.remove_vpp_config()
924 route_35_eos.remove_vpp_config()
925 route_34_eos.remove_vpp_config()
927 def test_interface_rx(self):
928 """ MPLS Interface Receive """
931 # Add a non-recursive route that will forward the traffic
934 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
936 paths=[VppRoutePath(self.pg1.remote_ip4,
937 self.pg1.sw_if_index)])
938 route_10_0_0_1.add_vpp_config()
941 # An interface receive label that maps traffic to RX on interface
943 # by injecting the packet in on pg0, which is in table 0
944 # doing an interface-rx on pg1 and matching a route in table 1
945 # if the packet egresses, then we must have swapped to pg1
946 # so as to have matched the route in table 1
948 route_34_eos = VppMplsRoute(self, 34, 1,
949 [VppRoutePath("0.0.0.0",
950 self.pg1.sw_if_index,
952 route_34_eos.add_vpp_config()
955 # ping an interface in the default table
956 # PG0 is in the default table
958 self.vapi.cli("clear trace")
959 tx = self.create_stream_labelled_ip4(self.pg0, [34], n=257,
961 self.pg0.add_stream(tx)
963 self.pg_enable_capture(self.pg_interfaces)
966 rx = self.pg1.get_capture(257)
967 self.verify_capture_ip4(self.pg1, rx, tx)
969 def test_mcast_mid_point(self):
970 """ MPLS Multicast Mid Point """
973 # Add a non-recursive route that will forward the traffic
976 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
978 paths=[VppRoutePath(self.pg1.remote_ip4,
979 self.pg1.sw_if_index)])
980 route_10_0_0_1.add_vpp_config()
983 # Add a mcast entry that replicate to pg2 and pg3
984 # and replicate to a interface-rx (like a bud node would)
986 route_3400_eos = VppMplsRoute(self, 3400, 1,
987 [VppRoutePath(self.pg2.remote_ip4,
988 self.pg2.sw_if_index,
990 VppRoutePath(self.pg3.remote_ip4,
991 self.pg3.sw_if_index,
993 VppRoutePath("0.0.0.0",
994 self.pg1.sw_if_index,
997 route_3400_eos.add_vpp_config()
1000 # ping an interface in the default table
1001 # PG0 is in the default table
1003 self.vapi.cli("clear trace")
1004 tx = self.create_stream_labelled_ip4(self.pg0, [3400], n=257,
1006 self.pg0.add_stream(tx)
1008 self.pg_enable_capture(self.pg_interfaces)
1011 rx = self.pg1.get_capture(257)
1012 self.verify_capture_ip4(self.pg1, rx, tx)
1014 rx = self.pg2.get_capture(257)
1015 self.verify_capture_labelled(self.pg2, rx, tx, [3401])
1016 rx = self.pg3.get_capture(257)
1017 self.verify_capture_labelled(self.pg3, rx, tx, [3402])
1019 def test_mcast_head(self):
1020 """ MPLS Multicast Head-end """
1023 # Create a multicast tunnel with two replications
1025 mpls_tun = VppMPLSTunnelInterface(self,
1026 [VppRoutePath(self.pg2.remote_ip4,
1027 self.pg2.sw_if_index,
1029 VppRoutePath(self.pg3.remote_ip4,
1030 self.pg3.sw_if_index,
1033 mpls_tun.add_vpp_config()
1037 # add an unlabelled route through the new tunnel
1039 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1040 [VppRoutePath("0.0.0.0",
1041 mpls_tun._sw_if_index)])
1042 route_10_0_0_3.add_vpp_config()
1044 self.vapi.cli("clear trace")
1045 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1046 self.pg0.add_stream(tx)
1048 self.pg_enable_capture(self.pg_interfaces)
1051 rx = self.pg2.get_capture(257)
1052 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42])
1053 rx = self.pg3.get_capture(257)
1054 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43])
1057 # An an IP multicast route via the tunnel
1059 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1061 route_232_1_1_1 = VppIpMRoute(
1065 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1066 [VppMRoutePath(self.pg0.sw_if_index,
1067 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1068 VppMRoutePath(mpls_tun._sw_if_index,
1069 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1070 route_232_1_1_1.add_vpp_config()
1072 self.vapi.cli("clear trace")
1073 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1074 self.pg0.add_stream(tx)
1076 self.pg_enable_capture(self.pg_interfaces)
1079 rx = self.pg2.get_capture(257)
1080 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42])
1081 rx = self.pg3.get_capture(257)
1082 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43])
1084 def test_mcast_ip4_tail(self):
1085 """ MPLS IPv4 Multicast Tail """
1088 # Add a multicast route that will forward the traffic
1091 route_232_1_1_1 = VppIpMRoute(
1095 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1097 paths=[VppMRoutePath(self.pg1.sw_if_index,
1098 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1099 route_232_1_1_1.add_vpp_config()
1102 # An interface receive label that maps traffic to RX on interface
1104 # by injecting the packet in on pg0, which is in table 0
1105 # doing an rpf-id and matching a route in table 1
1106 # if the packet egresses, then we must have matched the route in
1109 route_34_eos = VppMplsRoute(self, 34, 1,
1110 [VppRoutePath("0.0.0.0",
1111 self.pg1.sw_if_index,
1116 route_34_eos.add_vpp_config()
1119 # Drop due to interface lookup miss
1121 self.vapi.cli("clear trace")
1122 tx = self.create_stream_labelled_ip4(self.pg0, [34],
1123 dst_ip="232.1.1.1", n=1)
1124 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1127 # set the RPF-ID of the enrtry to match the input packet's
1129 route_232_1_1_1.update_rpf_id(55)
1131 self.vapi.cli("clear trace")
1132 tx = self.create_stream_labelled_ip4(self.pg0, [34],
1133 dst_ip="232.1.1.1", n=257)
1134 self.pg0.add_stream(tx)
1136 self.pg_enable_capture(self.pg_interfaces)
1139 rx = self.pg1.get_capture(257)
1140 self.verify_capture_ip4(self.pg1, rx, tx)
1143 # disposed packets have an invalid IPv4 checkusm
1145 tx = self.create_stream_labelled_ip4(self.pg0, [34],
1146 dst_ip="232.1.1.1", n=65,
1148 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1151 # set the RPF-ID of the enrtry to not match the input packet's
1153 route_232_1_1_1.update_rpf_id(56)
1154 tx = self.create_stream_labelled_ip4(self.pg0, [34],
1156 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1158 def test_mcast_ip6_tail(self):
1159 """ MPLS IPv6 Multicast Tail """
1162 # Add a multicast route that will forward the traffic
1165 route_ff = VppIpMRoute(
1169 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1171 paths=[VppMRoutePath(self.pg1.sw_if_index,
1172 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
1174 route_ff.add_vpp_config()
1177 # An interface receive label that maps traffic to RX on interface
1179 # by injecting the packet in on pg0, which is in table 0
1180 # doing an rpf-id and matching a route in table 1
1181 # if the packet egresses, then we must have matched the route in
1184 route_34_eos = VppMplsRoute(
1187 self.pg1.sw_if_index,
1190 proto=DpoProto.DPO_PROTO_IP6)],
1193 route_34_eos.add_vpp_config()
1196 # Drop due to interface lookup miss
1198 tx = self.create_stream_labelled_ip6(self.pg0, [34], 255,
1202 # set the RPF-ID of the enrtry to match the input packet's
1204 route_ff.update_rpf_id(55)
1206 tx = self.create_stream_labelled_ip6(self.pg0, [34], 255,
1208 self.pg0.add_stream(tx)
1210 self.pg_enable_capture(self.pg_interfaces)
1213 rx = self.pg1.get_capture(257)
1214 self.verify_capture_ip6(self.pg1, rx, tx)
1217 # disposed packets have hop-limit = 1
1219 tx = self.create_stream_labelled_ip6(self.pg0, [34], 255,
1220 dst_ip="ff01::1", hlim=1)
1221 self.send_and_assert_no_replies(self.pg0, tx, "Hop Limt Expired")
1224 # set the RPF-ID of the enrtry to not match the input packet's
1226 route_ff.update_rpf_id(56)
1227 tx = self.create_stream_labelled_ip6(self.pg0, [34], 225,
1229 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1232 class TestMPLSDisabled(VppTestCase):
1233 """ MPLS disabled """
1236 super(TestMPLSDisabled, self).setUp()
1238 # create 2 pg interfaces
1239 self.create_pg_interfaces(range(2))
1241 self.tbl = VppMplsTable(self, 0)
1242 self.tbl.add_vpp_config()
1244 # PG0 is MPLS enalbed
1246 self.pg0.config_ip4()
1247 self.pg0.resolve_arp()
1248 self.pg0.enable_mpls()
1250 # PG 1 is not MPLS enabled
1254 for i in self.pg_interfaces:
1258 self.pg0.disable_mpls()
1259 super(TestMPLSDisabled, self).tearDown()
1261 def send_and_assert_no_replies(self, intf, pkts, remark):
1262 intf.add_stream(pkts)
1263 self.pg_enable_capture(self.pg_interfaces)
1265 for i in self.pg_interfaces:
1267 i.assert_nothing_captured(remark=remark)
1269 def test_mpls_disabled(self):
1270 """ MPLS Disabled """
1272 tx = (Ether(src=self.pg1.remote_mac,
1273 dst=self.pg1.local_mac) /
1274 MPLS(label=32, ttl=64) /
1275 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1276 UDP(sport=1234, dport=1234) /
1280 # A simple MPLS xconnect - eos label in label out
1282 route_32_eos = VppMplsRoute(self, 32, 1,
1283 [VppRoutePath(self.pg0.remote_ip4,
1284 self.pg0.sw_if_index,
1286 route_32_eos.add_vpp_config()
1289 # PG1 does not forward IP traffic
1291 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1296 self.pg1.enable_mpls()
1299 # Now we get packets through
1301 self.pg1.add_stream(tx)
1302 self.pg_enable_capture(self.pg_interfaces)
1305 rx = self.pg0.get_capture(1)
1310 self.pg1.disable_mpls()
1313 # PG1 does not forward IP traffic
1315 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1316 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1319 class TestMPLSPIC(VppTestCase):
1320 """ MPLS PIC edge convergence """
1323 super(TestMPLSPIC, self).setUp()
1325 # create 2 pg interfaces
1326 self.create_pg_interfaces(range(4))
1328 mpls_tbl = VppMplsTable(self, 0)
1329 mpls_tbl.add_vpp_config()
1330 tbl4 = VppIpTable(self, 1)
1331 tbl4.add_vpp_config()
1332 tbl6 = VppIpTable(self, 1, is_ip6=1)
1333 tbl6.add_vpp_config()
1337 self.pg0.config_ip4()
1338 self.pg0.resolve_arp()
1339 self.pg0.enable_mpls()
1341 self.pg1.config_ip4()
1342 self.pg1.resolve_arp()
1343 self.pg1.enable_mpls()
1345 # VRF (customer facing) link
1347 self.pg2.set_table_ip4(1)
1348 self.pg2.config_ip4()
1349 self.pg2.resolve_arp()
1350 self.pg2.set_table_ip6(1)
1351 self.pg2.config_ip6()
1352 self.pg2.resolve_ndp()
1354 self.pg3.set_table_ip4(1)
1355 self.pg3.config_ip4()
1356 self.pg3.resolve_arp()
1357 self.pg3.set_table_ip6(1)
1358 self.pg3.config_ip6()
1359 self.pg3.resolve_ndp()
1362 self.pg0.disable_mpls()
1363 self.pg1.disable_mpls()
1364 for i in self.pg_interfaces:
1370 super(TestMPLSPIC, self).tearDown()
1372 def test_mpls_ibgp_pic(self):
1373 """ MPLS iBGP PIC edge convergence
1375 1) setup many iBGP VPN routes via a pair of iBGP peers.
1376 2) Check EMCP forwarding to these peers
1377 3) withdraw the IGP route to one of these peers.
1378 4) check forwarding continues to the remaining peer
1382 # IGP+LDP core routes
1384 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1385 [VppRoutePath(self.pg0.remote_ip4,
1386 self.pg0.sw_if_index,
1388 core_10_0_0_45.add_vpp_config()
1390 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1391 [VppRoutePath(self.pg1.remote_ip4,
1392 self.pg1.sw_if_index,
1394 core_10_0_0_46.add_vpp_config()
1397 # Lot's of VPN routes. We need more the 64 so VPP will build
1398 # the fast convergence indirection
1402 for ii in range(64):
1403 dst = "192.168.1.%d" % ii
1404 vpn_routes.append(VppIpRoute(self, dst, 32,
1405 [VppRoutePath("10.0.0.45",
1409 VppRoutePath("10.0.0.46",
1412 is_resolve_host=1)],
1414 vpn_routes[ii].add_vpp_config()
1416 pkts.append(Ether(dst=self.pg2.local_mac,
1417 src=self.pg2.remote_mac) /
1418 IP(src=self.pg2.remote_ip4, dst=dst) /
1419 UDP(sport=1234, dport=1234) /
1423 # Send the packet stream (one pkt to each VPN route)
1424 # - expect a 50-50 split of the traffic
1426 self.pg2.add_stream(pkts)
1427 self.pg_enable_capture(self.pg_interfaces)
1430 rx0 = self.pg0._get_capture(1)
1431 rx1 = self.pg1._get_capture(1)
1433 # not testig the LB hashing algorithm so we're not concerned
1434 # with the split ratio, just as long as neither is 0
1435 self.assertNotEqual(0, len(rx0))
1436 self.assertNotEqual(0, len(rx1))
1439 # use a test CLI command to stop the FIB walk process, this
1440 # will prevent the FIB converging the VPN routes and thus allow
1441 # us to probe the interim (psot-fail, pre-converge) state
1443 self.vapi.ppcli("test fib-walk-process disable")
1446 # Withdraw one of the IGP routes
1448 core_10_0_0_46.remove_vpp_config()
1451 # now all packets should be forwarded through the remaining peer
1453 self.vapi.ppcli("clear trace")
1454 self.pg2.add_stream(pkts)
1455 self.pg_enable_capture(self.pg_interfaces)
1458 rx0 = self.pg0.get_capture(len(pkts))
1461 # enable the FIB walk process to converge the FIB
1463 self.vapi.ppcli("test fib-walk-process enable")
1466 # packets should still be forwarded through the remaining peer
1468 self.pg2.add_stream(pkts)
1469 self.pg_enable_capture(self.pg_interfaces)
1472 rx0 = self.pg0.get_capture(64)
1475 # Add the IGP route back and we return to load-balancing
1477 core_10_0_0_46.add_vpp_config()
1479 self.pg2.add_stream(pkts)
1480 self.pg_enable_capture(self.pg_interfaces)
1483 rx0 = self.pg0._get_capture(1)
1484 rx1 = self.pg1._get_capture(1)
1485 self.assertNotEqual(0, len(rx0))
1486 self.assertNotEqual(0, len(rx1))
1488 def test_mpls_ebgp_pic(self):
1489 """ MPLS eBGP PIC edge convergence
1491 1) setup many eBGP VPN routes via a pair of eBGP peers
1492 2) Check EMCP forwarding to these peers
1493 3) withdraw one eBGP path - expect LB across remaining eBGP
1497 # Lot's of VPN routes. We need more the 64 so VPP will build
1498 # the fast convergence indirection
1503 for ii in range(64):
1504 dst = "192.168.1.%d" % ii
1505 local_label = 1600 + ii
1506 vpn_routes.append(VppIpRoute(self, dst, 32,
1507 [VppRoutePath(self.pg2.remote_ip4,
1510 is_resolve_attached=1),
1511 VppRoutePath(self.pg3.remote_ip4,
1514 is_resolve_attached=1)],
1516 vpn_routes[ii].add_vpp_config()
1518 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1520 vpn_bindings[ii].add_vpp_config()
1522 pkts.append(Ether(dst=self.pg0.local_mac,
1523 src=self.pg0.remote_mac) /
1524 MPLS(label=local_label, ttl=64) /
1525 IP(src=self.pg0.remote_ip4, dst=dst) /
1526 UDP(sport=1234, dport=1234) /
1529 self.pg0.add_stream(pkts)
1530 self.pg_enable_capture(self.pg_interfaces)
1533 rx0 = self.pg2._get_capture(1)
1534 rx1 = self.pg3._get_capture(1)
1535 self.assertNotEqual(0, len(rx0))
1536 self.assertNotEqual(0, len(rx1))
1539 # use a test CLI command to stop the FIB walk process, this
1540 # will prevent the FIB converging the VPN routes and thus allow
1541 # us to probe the interim (psot-fail, pre-converge) state
1543 self.vapi.ppcli("test fib-walk-process disable")
1546 # withdraw the connected prefix on the interface.
1548 self.pg2.unconfig_ip4()
1551 # now all packets should be forwarded through the remaining peer
1553 self.pg0.add_stream(pkts)
1554 self.pg_enable_capture(self.pg_interfaces)
1557 rx0 = self.pg3.get_capture(len(pkts))
1560 # enable the FIB walk process to converge the FIB
1562 self.vapi.ppcli("test fib-walk-process enable")
1563 self.pg0.add_stream(pkts)
1564 self.pg_enable_capture(self.pg_interfaces)
1567 rx0 = self.pg3.get_capture(len(pkts))
1570 # put the connecteds back
1572 self.pg2.config_ip4()
1574 self.pg0.add_stream(pkts)
1575 self.pg_enable_capture(self.pg_interfaces)
1578 rx0 = self.pg2._get_capture(1)
1579 rx1 = self.pg3._get_capture(1)
1580 self.assertNotEqual(0, len(rx0))
1581 self.assertNotEqual(0, len(rx1))
1583 def test_mpls_v6_ebgp_pic(self):
1584 """ MPLSv6 eBGP PIC edge convergence
1586 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1587 2) Check EMCP forwarding to these peers
1588 3) withdraw one eBGP path - expect LB across remaining eBGP
1592 # Lot's of VPN routes. We need more the 64 so VPP will build
1593 # the fast convergence indirection
1598 for ii in range(64):
1599 dst = "3000::%d" % ii
1600 local_label = 1600 + ii
1601 vpn_routes.append(VppIpRoute(
1603 [VppRoutePath(self.pg2.remote_ip6,
1606 is_resolve_attached=1,
1607 proto=DpoProto.DPO_PROTO_IP6),
1608 VppRoutePath(self.pg3.remote_ip6,
1611 proto=DpoProto.DPO_PROTO_IP6,
1612 is_resolve_attached=1)],
1615 vpn_routes[ii].add_vpp_config()
1617 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1620 vpn_bindings[ii].add_vpp_config()
1622 pkts.append(Ether(dst=self.pg0.local_mac,
1623 src=self.pg0.remote_mac) /
1624 MPLS(label=local_label, ttl=64) /
1625 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1626 UDP(sport=1234, dport=1234) /
1629 self.pg0.add_stream(pkts)
1630 self.pg_enable_capture(self.pg_interfaces)
1633 rx0 = self.pg2._get_capture(1)
1634 rx1 = self.pg3._get_capture(1)
1635 self.assertNotEqual(0, len(rx0))
1636 self.assertNotEqual(0, len(rx1))
1639 # use a test CLI command to stop the FIB walk process, this
1640 # will prevent the FIB converging the VPN routes and thus allow
1641 # us to probe the interim (psot-fail, pre-converge) state
1643 self.vapi.ppcli("test fib-walk-process disable")
1646 # withdraw the connected prefix on the interface.
1647 # and shutdown the interface so the ND cache is flushed.
1649 self.pg2.unconfig_ip6()
1650 self.pg2.admin_down()
1653 # now all packets should be forwarded through the remaining peer
1655 self.pg0.add_stream(pkts)
1656 self.pg_enable_capture(self.pg_interfaces)
1659 rx0 = self.pg3.get_capture(len(pkts))
1662 # enable the FIB walk process to converge the FIB
1664 self.vapi.ppcli("test fib-walk-process enable")
1665 self.pg0.add_stream(pkts)
1666 self.pg_enable_capture(self.pg_interfaces)
1669 rx0 = self.pg3.get_capture(len(pkts))
1672 # put the connecteds back
1675 self.pg2.config_ip6()
1677 self.pg0.add_stream(pkts)
1678 self.pg_enable_capture(self.pg_interfaces)
1681 rx0 = self.pg2._get_capture(1)
1682 rx1 = self.pg3._get_capture(1)
1683 self.assertNotEqual(0, len(rx0))
1684 self.assertNotEqual(0, len(rx1))
1687 class TestMPLSL2(VppTestCase):
1691 super(TestMPLSL2, self).setUp()
1693 # create 2 pg interfaces
1694 self.create_pg_interfaces(range(2))
1696 # create the default MPLS table
1698 tbl = VppMplsTable(self, 0)
1699 tbl.add_vpp_config()
1700 self.tables.append(tbl)
1702 # use pg0 as the core facing interface
1704 self.pg0.config_ip4()
1705 self.pg0.resolve_arp()
1706 self.pg0.enable_mpls()
1708 # use the other 2 for customer facing L2 links
1709 for i in self.pg_interfaces[1:]:
1713 for i in self.pg_interfaces[1:]:
1716 self.pg0.disable_mpls()
1717 self.pg0.unconfig_ip4()
1718 self.pg0.admin_down()
1719 super(TestMPLSL2, self).tearDown()
1721 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels,
1724 top = len(mpls_labels) - 1
1726 capture = verify_filter(capture, sent)
1728 self.assertEqual(len(capture), len(sent))
1730 for i in range(len(capture)):
1734 # the MPLS TTL is 255 since it enters a new tunnel
1735 verify_mpls_stack(self, rx, mpls_labels, ttl, top)
1738 rx_eth = Ether(str(rx[MPLS].payload))
1740 self.assertEqual(rx_eth.src, tx_eth.src)
1741 self.assertEqual(rx_eth.dst, tx_eth.dst)
1743 def test_vpws(self):
1744 """ Virtual Private Wire Service """
1747 # Create an MPLS tunnel that pushes 1 label
1749 mpls_tun_1 = VppMPLSTunnelInterface(self,
1750 [VppRoutePath(self.pg0.remote_ip4,
1751 self.pg0.sw_if_index,
1754 mpls_tun_1.add_vpp_config()
1755 mpls_tun_1.admin_up()
1758 # Create a label entry to for 55 that does L2 input to the tunnel
1760 route_55_eos = VppMplsRoute(
1762 [VppRoutePath("0.0.0.0",
1763 mpls_tun_1.sw_if_index,
1765 proto=DpoProto.DPO_PROTO_ETHERNET)])
1766 route_55_eos.add_vpp_config()
1769 # Cross-connect the tunnel with one of the customers L2 interfaces
1771 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
1772 mpls_tun_1.sw_if_index,
1774 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
1775 self.pg1.sw_if_index,
1779 # inject a packet from the core
1781 pcore = (Ether(dst=self.pg0.local_mac,
1782 src=self.pg0.remote_mac) /
1783 MPLS(label=55, ttl=64) /
1784 Ether(dst="00:00:de:ad:ba:be",
1785 src="00:00:de:ad:be:ef") /
1786 IP(src="10.10.10.10", dst="11.11.11.11") /
1787 UDP(sport=1234, dport=1234) /
1790 self.pg0.add_stream(pcore * 65)
1791 self.pg_enable_capture(self.pg_interfaces)
1794 rx0 = self.pg1.get_capture(65)
1795 tx = pcore[MPLS].payload
1797 self.assertEqual(rx0[0][Ether].dst, tx[Ether].dst)
1798 self.assertEqual(rx0[0][Ether].src, tx[Ether].src)
1801 # Inject a packet from the custoer/L2 side
1803 self.pg1.add_stream(tx * 65)
1804 self.pg_enable_capture(self.pg_interfaces)
1807 rx0 = self.pg0.get_capture(65)
1809 self.verify_capture_tunneled_ethernet(rx0, tx*65, [42])
1811 def test_vpls(self):
1812 """ Virtual Private LAN Service """
1814 # Create an L2 MPLS tunnel
1816 mpls_tun = VppMPLSTunnelInterface(self,
1817 [VppRoutePath(self.pg0.remote_ip4,
1818 self.pg0.sw_if_index,
1821 mpls_tun.add_vpp_config()
1825 # Create a label entry to for 55 that does L2 input to the tunnel
1827 route_55_eos = VppMplsRoute(
1829 [VppRoutePath("0.0.0.0",
1830 mpls_tun.sw_if_index,
1832 proto=DpoProto.DPO_PROTO_ETHERNET)])
1833 route_55_eos.add_vpp_config()
1836 # add to tunnel to the customers bridge-domain
1838 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
1840 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
1844 # Packet from the customer interface and from the core
1846 p_cust = (Ether(dst="00:00:de:ad:ba:be",
1847 src="00:00:de:ad:be:ef") /
1848 IP(src="10.10.10.10", dst="11.11.11.11") /
1849 UDP(sport=1234, dport=1234) /
1851 p_core = (Ether(src="00:00:de:ad:ba:be",
1852 dst="00:00:de:ad:be:ef") /
1853 IP(dst="10.10.10.10", src="11.11.11.11") /
1854 UDP(sport=1234, dport=1234) /
1858 # The BD is learning, so send in one of each packet to learn
1860 p_core_encap = (Ether(dst=self.pg0.local_mac,
1861 src=self.pg0.remote_mac) /
1862 MPLS(label=55, ttl=64) /
1865 self.pg1.add_stream(p_cust)
1866 self.pg_enable_capture(self.pg_interfaces)
1868 self.pg0.add_stream(p_core_encap)
1869 self.pg_enable_capture(self.pg_interfaces)
1872 # we've learnt this so expect it be be forwarded
1873 rx0 = self.pg1.get_capture(1)
1875 self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst)
1876 self.assertEqual(rx0[0][Ether].src, p_core[Ether].src)
1879 # now a stream in each direction
1881 self.pg1.add_stream(p_cust * 65)
1882 self.pg_enable_capture(self.pg_interfaces)
1885 rx0 = self.pg0.get_capture(65)
1887 self.verify_capture_tunneled_ethernet(rx0, p_cust*65, [42])
1890 # remove interfaces from customers bridge-domain
1892 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
1895 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
1899 if __name__ == '__main__':
1900 unittest.main(testRunner=VppTestRunner)