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]
318 """ MPLS label swap tests """
321 # A simple MPLS xconnect - eos label in label out
323 route_32_eos = VppMplsRoute(self, 32, 1,
324 [VppRoutePath(self.pg0.remote_ip4,
325 self.pg0.sw_if_index,
327 route_32_eos.add_vpp_config()
330 # a stream that matches the route for 10.0.0.1
331 # PG0 is in the default table
333 self.vapi.cli("clear trace")
334 tx = self.create_stream_labelled_ip4(self.pg0, [32])
335 self.pg0.add_stream(tx)
337 self.pg_enable_capture(self.pg_interfaces)
340 rx = self.pg0.get_capture()
341 self.verify_capture_labelled(self.pg0, rx, tx, [33])
344 # A simple MPLS xconnect - non-eos label in label out
346 route_32_neos = VppMplsRoute(self, 32, 0,
347 [VppRoutePath(self.pg0.remote_ip4,
348 self.pg0.sw_if_index,
350 route_32_neos.add_vpp_config()
353 # a stream that matches the route for 10.0.0.1
354 # PG0 is in the default table
356 self.vapi.cli("clear trace")
357 tx = self.create_stream_labelled_ip4(self.pg0, [32, 99])
358 self.pg0.add_stream(tx)
360 self.pg_enable_capture(self.pg_interfaces)
363 rx = self.pg0.get_capture()
364 self.verify_capture_labelled(self.pg0, rx, tx, [33, 99])
367 # An MPLS xconnect - EOS label in IP out
369 route_33_eos = VppMplsRoute(self, 33, 1,
370 [VppRoutePath(self.pg0.remote_ip4,
371 self.pg0.sw_if_index,
373 route_33_eos.add_vpp_config()
375 self.vapi.cli("clear trace")
376 tx = self.create_stream_labelled_ip4(self.pg0, [33])
377 self.pg0.add_stream(tx)
379 self.pg_enable_capture(self.pg_interfaces)
382 rx = self.pg0.get_capture()
383 self.verify_capture_ip4(self.pg0, rx, tx)
386 # disposed packets have an invalid IPv4 checkusm
388 tx = self.create_stream_labelled_ip4(self.pg0, [33],
389 dst_ip=self.pg0.remote_ip4,
392 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
395 # An MPLS xconnect - EOS label in IPv6 out
397 route_333_eos = VppMplsRoute(
399 [VppRoutePath(self.pg0.remote_ip6,
400 self.pg0.sw_if_index,
402 proto=DpoProto.DPO_PROTO_IP6)])
403 route_333_eos.add_vpp_config()
405 self.vapi.cli("clear trace")
406 tx = self.create_stream_labelled_ip6(self.pg0, [333], 64)
407 self.pg0.add_stream(tx)
409 self.pg_enable_capture(self.pg_interfaces)
412 rx = self.pg0.get_capture()
413 self.verify_capture_ip6(self.pg0, rx, tx)
416 # disposed packets have an TTL expired
418 tx = self.create_stream_labelled_ip6(self.pg0, [333], 64,
419 dst_ip=self.pg1.remote_ip6,
422 self.vapi.cli("clear trace")
423 tx = self.create_stream_labelled_ip6(self.pg0, [333], 64,
424 dst_ip=self.pg1.remote_ip6,
426 self.pg0.add_stream(tx)
428 self.pg_enable_capture(self.pg_interfaces)
431 rx = self.pg0.get_capture()
432 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
435 # An MPLS xconnect - EOS label in IPv6 out w imp-null
437 route_334_eos = VppMplsRoute(
439 [VppRoutePath(self.pg0.remote_ip6,
440 self.pg0.sw_if_index,
442 proto=DpoProto.DPO_PROTO_IP6)])
443 route_334_eos.add_vpp_config()
445 self.vapi.cli("clear trace")
446 tx = self.create_stream_labelled_ip6(self.pg0, [334], 64)
447 self.pg0.add_stream(tx)
449 self.pg_enable_capture(self.pg_interfaces)
452 rx = self.pg0.get_capture()
453 self.verify_capture_ip6(self.pg0, rx, tx)
456 # disposed packets have an TTL expired
458 self.vapi.cli("clear trace")
459 tx = self.create_stream_labelled_ip6(self.pg0, [334], 64,
460 dst_ip=self.pg1.remote_ip6,
462 self.pg0.add_stream(tx)
464 self.pg_enable_capture(self.pg_interfaces)
467 rx = self.pg0.get_capture()
468 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
471 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
472 # so this traffic should be dropped.
474 route_33_neos = VppMplsRoute(self, 33, 0,
475 [VppRoutePath(self.pg0.remote_ip4,
476 self.pg0.sw_if_index,
478 route_33_neos.add_vpp_config()
480 self.vapi.cli("clear trace")
481 tx = self.create_stream_labelled_ip4(self.pg0, [33, 99])
482 self.pg0.add_stream(tx)
484 self.pg_enable_capture(self.pg_interfaces)
486 self.pg0.assert_nothing_captured(
487 remark="MPLS non-EOS packets popped and forwarded")
490 # A recursive EOS x-connect, which resolves through another x-connect
492 route_34_eos = VppMplsRoute(self, 34, 1,
493 [VppRoutePath("0.0.0.0",
497 route_34_eos.add_vpp_config()
499 tx = self.create_stream_labelled_ip4(self.pg0, [34])
500 self.pg0.add_stream(tx)
502 self.pg_enable_capture(self.pg_interfaces)
505 rx = self.pg0.get_capture()
506 self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 45], num=2)
509 # A recursive non-EOS x-connect, which resolves through another
512 route_34_neos = VppMplsRoute(self, 34, 0,
513 [VppRoutePath("0.0.0.0",
517 route_34_neos.add_vpp_config()
519 self.vapi.cli("clear trace")
520 tx = self.create_stream_labelled_ip4(self.pg0, [34, 99])
521 self.pg0.add_stream(tx)
523 self.pg_enable_capture(self.pg_interfaces)
526 rx = self.pg0.get_capture()
527 # it's the 2nd (counting from 0) label in the stack that is swapped
528 self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 46, 99], num=2)
531 # an recursive IP route that resolves through the recursive non-eos
534 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
535 [VppRoutePath("0.0.0.0",
539 ip_10_0_0_1.add_vpp_config()
541 self.vapi.cli("clear trace")
542 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
543 self.pg0.add_stream(tx)
545 self.pg_enable_capture(self.pg_interfaces)
548 rx = self.pg0.get_capture()
549 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 46, 55])
551 ip_10_0_0_1.remove_vpp_config()
552 route_34_neos.remove_vpp_config()
553 route_34_eos.remove_vpp_config()
554 route_33_neos.remove_vpp_config()
555 route_33_eos.remove_vpp_config()
556 route_32_neos.remove_vpp_config()
557 route_32_eos.remove_vpp_config()
560 """ MPLS Local Label Binding test """
563 # Add a non-recursive route with a single out label
565 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
566 [VppRoutePath(self.pg0.remote_ip4,
567 self.pg0.sw_if_index,
569 route_10_0_0_1.add_vpp_config()
571 # bind a local label to the route
572 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
573 binding.add_vpp_config()
576 self.vapi.cli("clear trace")
577 tx = self.create_stream_labelled_ip4(self.pg0, [44, 99])
578 self.pg0.add_stream(tx)
580 self.pg_enable_capture(self.pg_interfaces)
583 rx = self.pg0.get_capture()
584 self.verify_capture_labelled(self.pg0, rx, tx, [45, 99])
587 self.vapi.cli("clear trace")
588 tx = self.create_stream_labelled_ip4(self.pg0, [44])
589 self.pg0.add_stream(tx)
591 self.pg_enable_capture(self.pg_interfaces)
594 rx = self.pg0.get_capture()
595 self.verify_capture_labelled(self.pg0, rx, tx, [45])
598 self.vapi.cli("clear trace")
599 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
600 self.pg0.add_stream(tx)
602 self.pg_enable_capture(self.pg_interfaces)
605 rx = self.pg0.get_capture()
606 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [45])
611 binding.remove_vpp_config()
612 route_10_0_0_1.remove_vpp_config()
614 def test_imposition(self):
615 """ MPLS label imposition test """
618 # Add a non-recursive route with a single out label
620 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
621 [VppRoutePath(self.pg0.remote_ip4,
622 self.pg0.sw_if_index,
624 route_10_0_0_1.add_vpp_config()
627 # a stream that matches the route for 10.0.0.1
628 # PG0 is in the default table
630 self.vapi.cli("clear trace")
631 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
632 self.pg0.add_stream(tx)
634 self.pg_enable_capture(self.pg_interfaces)
637 rx = self.pg0.get_capture()
638 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32])
641 # Add a non-recursive route with a 3 out labels
643 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
644 [VppRoutePath(self.pg0.remote_ip4,
645 self.pg0.sw_if_index,
646 labels=[32, 33, 34])])
647 route_10_0_0_2.add_vpp_config()
650 # a stream that matches the route for 10.0.0.1
651 # PG0 is in the default table
653 self.vapi.cli("clear trace")
654 tx = self.create_stream_ip4(self.pg0, "10.0.0.2")
655 self.pg0.add_stream(tx)
657 self.pg_enable_capture(self.pg_interfaces)
660 rx = self.pg0.get_capture()
661 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 33, 34])
664 # add a recursive path, with output label, via the 1 label route
666 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
667 [VppRoutePath("10.0.0.1",
670 route_11_0_0_1.add_vpp_config()
673 # a stream that matches the route for 11.0.0.1, should pick up
674 # the label stack for 11.0.0.1 and 10.0.0.1
676 self.vapi.cli("clear trace")
677 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
678 self.pg0.add_stream(tx)
680 self.pg_enable_capture(self.pg_interfaces)
683 rx = self.pg0.get_capture()
684 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [32, 44])
687 # add a recursive path, with 2 labels, via the 3 label route
689 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
690 [VppRoutePath("10.0.0.2",
693 route_11_0_0_2.add_vpp_config()
696 # a stream that matches the route for 11.0.0.1, should pick up
697 # the label stack for 11.0.0.1 and 10.0.0.1
699 self.vapi.cli("clear trace")
700 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
701 self.pg0.add_stream(tx)
703 self.pg_enable_capture(self.pg_interfaces)
706 rx = self.pg0.get_capture()
707 self.verify_capture_labelled_ip4(
708 self.pg0, rx, tx, [32, 33, 34, 44, 45])
713 route_11_0_0_2.remove_vpp_config()
714 route_11_0_0_1.remove_vpp_config()
715 route_10_0_0_2.remove_vpp_config()
716 route_10_0_0_1.remove_vpp_config()
718 def test_tunnel(self):
719 """ MPLS Tunnel Tests """
722 # Create a tunnel with a single out label
724 mpls_tun = VppMPLSTunnelInterface(self,
725 [VppRoutePath(self.pg0.remote_ip4,
726 self.pg0.sw_if_index,
728 mpls_tun.add_vpp_config()
732 # add an unlabelled route through the new tunnel
734 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
735 [VppRoutePath("0.0.0.0",
736 mpls_tun._sw_if_index)])
737 route_10_0_0_3.add_vpp_config()
739 self.vapi.cli("clear trace")
740 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
741 self.pg0.add_stream(tx)
743 self.pg_enable_capture(self.pg_interfaces)
746 rx = self.pg0.get_capture()
747 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46])
750 # add a labelled route through the new tunnel
752 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
753 [VppRoutePath("0.0.0.0",
754 mpls_tun._sw_if_index,
756 route_10_0_0_4.add_vpp_config()
758 self.vapi.cli("clear trace")
759 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
760 self.pg0.add_stream(tx)
762 self.pg_enable_capture(self.pg_interfaces)
765 rx = self.pg0.get_capture()
766 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [44, 46, 33],
769 def test_v4_exp_null(self):
770 """ MPLS V4 Explicit NULL test """
773 # The first test case has an MPLS TTL of 0
774 # all packet should be dropped
776 tx = self.create_stream_labelled_ip4(self.pg0, [0], 0)
777 self.pg0.add_stream(tx)
779 self.pg_enable_capture(self.pg_interfaces)
782 self.pg0.assert_nothing_captured(remark="MPLS TTL=0 packets forwarded")
785 # a stream with a non-zero MPLS TTL
786 # PG0 is in the default table
788 tx = self.create_stream_labelled_ip4(self.pg0, [0])
789 self.pg0.add_stream(tx)
791 self.pg_enable_capture(self.pg_interfaces)
794 rx = self.pg0.get_capture()
795 self.verify_capture_ip4(self.pg0, rx, tx)
798 # a stream with a non-zero MPLS TTL
800 # we are ensuring the post-pop lookup occurs in the VRF table
802 self.vapi.cli("clear trace")
803 tx = self.create_stream_labelled_ip4(self.pg1, [0])
804 self.pg1.add_stream(tx)
806 self.pg_enable_capture(self.pg_interfaces)
809 rx = self.pg1.get_capture()
810 self.verify_capture_ip4(self.pg0, rx, tx)
812 def test_v6_exp_null(self):
813 """ MPLS V6 Explicit NULL test """
816 # a stream with a non-zero MPLS TTL
817 # PG0 is in the default table
819 self.vapi.cli("clear trace")
820 tx = self.create_stream_labelled_ip6(self.pg0, 2, 2)
821 self.pg0.add_stream(tx)
823 self.pg_enable_capture(self.pg_interfaces)
826 rx = self.pg0.get_capture()
827 self.verify_capture_ip6(self.pg0, rx, tx)
830 # a stream with a non-zero MPLS TTL
832 # we are ensuring the post-pop lookup occurs in the VRF table
834 self.vapi.cli("clear trace")
835 tx = self.create_stream_labelled_ip6(self.pg1, 2, 2)
836 self.pg1.add_stream(tx)
838 self.pg_enable_capture(self.pg_interfaces)
841 rx = self.pg1.get_capture()
842 self.verify_capture_ip6(self.pg0, rx, tx)
848 # A de-agg route - next-hop lookup in default table
850 route_34_eos = VppMplsRoute(self, 34, 1,
851 [VppRoutePath("0.0.0.0",
854 route_34_eos.add_vpp_config()
857 # ping an interface in the default table
858 # PG0 is in the default table
860 self.vapi.cli("clear trace")
861 tx = self.create_stream_labelled_ip4(self.pg0, [34], ping=1,
863 self.pg0.add_stream(tx)
865 self.pg_enable_capture(self.pg_interfaces)
868 rx = self.pg0.get_capture()
869 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
872 # A de-agg route - next-hop lookup in non-default table
874 route_35_eos = VppMplsRoute(self, 35, 1,
875 [VppRoutePath("0.0.0.0",
878 route_35_eos.add_vpp_config()
881 # ping an interface in the non-default table
882 # PG0 is in the default table. packet arrive labelled in the
883 # default table and egress unlabelled in the non-default
885 self.vapi.cli("clear trace")
886 tx = self.create_stream_labelled_ip4(
887 self.pg0, [35], ping=1, ip_itf=self.pg1)
888 self.pg0.add_stream(tx)
890 self.pg_enable_capture(self.pg_interfaces)
893 packet_count = self.get_packet_count_for_if_idx(self.pg0.sw_if_index)
894 rx = self.pg1.get_capture(packet_count)
895 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
900 route_36_neos = VppMplsRoute(self, 36, 0,
901 [VppRoutePath("0.0.0.0",
903 route_36_neos.add_vpp_config()
905 self.vapi.cli("clear trace")
906 tx = self.create_stream_labelled_ip4(self.pg0, [36, 35],
907 ping=1, ip_itf=self.pg1)
908 self.pg0.add_stream(tx)
910 self.pg_enable_capture(self.pg_interfaces)
913 rx = self.pg1.get_capture(len(tx))
914 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
916 route_36_neos.remove_vpp_config()
917 route_35_eos.remove_vpp_config()
918 route_34_eos.remove_vpp_config()
920 def test_interface_rx(self):
921 """ MPLS Interface Receive """
924 # Add a non-recursive route that will forward the traffic
927 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
929 paths=[VppRoutePath(self.pg1.remote_ip4,
930 self.pg1.sw_if_index)])
931 route_10_0_0_1.add_vpp_config()
934 # An interface receive label that maps traffic to RX on interface
936 # by injecting the packet in on pg0, which is in table 0
937 # doing an interface-rx on pg1 and matching a route in table 1
938 # if the packet egresses, then we must have swapped to pg1
939 # so as to have matched the route in table 1
941 route_34_eos = VppMplsRoute(self, 34, 1,
942 [VppRoutePath("0.0.0.0",
943 self.pg1.sw_if_index,
945 route_34_eos.add_vpp_config()
948 # ping an interface in the default table
949 # PG0 is in the default table
951 self.vapi.cli("clear trace")
952 tx = self.create_stream_labelled_ip4(self.pg0, [34], n=257,
954 self.pg0.add_stream(tx)
956 self.pg_enable_capture(self.pg_interfaces)
959 rx = self.pg1.get_capture(257)
960 self.verify_capture_ip4(self.pg1, rx, tx)
962 def test_mcast_mid_point(self):
963 """ MPLS Multicast Mid Point """
966 # Add a non-recursive route that will forward the traffic
969 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
971 paths=[VppRoutePath(self.pg1.remote_ip4,
972 self.pg1.sw_if_index)])
973 route_10_0_0_1.add_vpp_config()
976 # Add a mcast entry that replicate to pg2 and pg3
977 # and replicate to a interface-rx (like a bud node would)
979 route_3400_eos = VppMplsRoute(self, 3400, 1,
980 [VppRoutePath(self.pg2.remote_ip4,
981 self.pg2.sw_if_index,
983 VppRoutePath(self.pg3.remote_ip4,
984 self.pg3.sw_if_index,
986 VppRoutePath("0.0.0.0",
987 self.pg1.sw_if_index,
990 route_3400_eos.add_vpp_config()
993 # ping an interface in the default table
994 # PG0 is in the default table
996 self.vapi.cli("clear trace")
997 tx = self.create_stream_labelled_ip4(self.pg0, [3400], n=257,
999 self.pg0.add_stream(tx)
1001 self.pg_enable_capture(self.pg_interfaces)
1004 rx = self.pg1.get_capture(257)
1005 self.verify_capture_ip4(self.pg1, rx, tx)
1007 rx = self.pg2.get_capture(257)
1008 self.verify_capture_labelled(self.pg2, rx, tx, [3401])
1009 rx = self.pg3.get_capture(257)
1010 self.verify_capture_labelled(self.pg3, rx, tx, [3402])
1012 def test_mcast_head(self):
1013 """ MPLS Multicast Head-end """
1016 # Create a multicast tunnel with two replications
1018 mpls_tun = VppMPLSTunnelInterface(self,
1019 [VppRoutePath(self.pg2.remote_ip4,
1020 self.pg2.sw_if_index,
1022 VppRoutePath(self.pg3.remote_ip4,
1023 self.pg3.sw_if_index,
1026 mpls_tun.add_vpp_config()
1030 # add an unlabelled route through the new tunnel
1032 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1033 [VppRoutePath("0.0.0.0",
1034 mpls_tun._sw_if_index)])
1035 route_10_0_0_3.add_vpp_config()
1037 self.vapi.cli("clear trace")
1038 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1039 self.pg0.add_stream(tx)
1041 self.pg_enable_capture(self.pg_interfaces)
1044 rx = self.pg2.get_capture(257)
1045 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42])
1046 rx = self.pg3.get_capture(257)
1047 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43])
1050 # An an IP multicast route via the tunnel
1052 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1054 route_232_1_1_1 = VppIpMRoute(
1058 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1059 [VppMRoutePath(self.pg0.sw_if_index,
1060 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1061 VppMRoutePath(mpls_tun._sw_if_index,
1062 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1063 route_232_1_1_1.add_vpp_config()
1065 self.vapi.cli("clear trace")
1066 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1067 self.pg0.add_stream(tx)
1069 self.pg_enable_capture(self.pg_interfaces)
1072 rx = self.pg2.get_capture(257)
1073 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42])
1074 rx = self.pg3.get_capture(257)
1075 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43])
1077 def test_mcast_ip4_tail(self):
1078 """ MPLS IPv4 Multicast Tail """
1081 # Add a multicast route that will forward the traffic
1084 route_232_1_1_1 = VppIpMRoute(
1088 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1090 paths=[VppMRoutePath(self.pg1.sw_if_index,
1091 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1092 route_232_1_1_1.add_vpp_config()
1095 # An interface receive label that maps traffic to RX on interface
1097 # by injecting the packet in on pg0, which is in table 0
1098 # doing an rpf-id and matching a route in table 1
1099 # if the packet egresses, then we must have matched the route in
1102 route_34_eos = VppMplsRoute(self, 34, 1,
1103 [VppRoutePath("0.0.0.0",
1104 self.pg1.sw_if_index,
1109 route_34_eos.add_vpp_config()
1112 # Drop due to interface lookup miss
1114 self.vapi.cli("clear trace")
1115 tx = self.create_stream_labelled_ip4(self.pg0, [34],
1116 dst_ip="232.1.1.1", n=1)
1117 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1120 # set the RPF-ID of the enrtry to match the input packet's
1122 route_232_1_1_1.update_rpf_id(55)
1124 self.vapi.cli("clear trace")
1125 tx = self.create_stream_labelled_ip4(self.pg0, [34],
1126 dst_ip="232.1.1.1", n=257)
1127 self.pg0.add_stream(tx)
1129 self.pg_enable_capture(self.pg_interfaces)
1132 rx = self.pg1.get_capture(257)
1133 self.verify_capture_ip4(self.pg1, rx, tx)
1136 # disposed packets have an invalid IPv4 checkusm
1138 tx = self.create_stream_labelled_ip4(self.pg0, [34],
1139 dst_ip="232.1.1.1", n=65,
1141 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1144 # set the RPF-ID of the enrtry to not match the input packet's
1146 route_232_1_1_1.update_rpf_id(56)
1147 tx = self.create_stream_labelled_ip4(self.pg0, [34],
1149 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1151 def test_mcast_ip6_tail(self):
1152 """ MPLS IPv6 Multicast Tail """
1155 # Add a multicast route that will forward the traffic
1158 route_ff = VppIpMRoute(
1162 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1164 paths=[VppMRoutePath(self.pg1.sw_if_index,
1165 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
1167 route_ff.add_vpp_config()
1170 # An interface receive label that maps traffic to RX on interface
1172 # by injecting the packet in on pg0, which is in table 0
1173 # doing an rpf-id and matching a route in table 1
1174 # if the packet egresses, then we must have matched the route in
1177 route_34_eos = VppMplsRoute(
1180 self.pg1.sw_if_index,
1183 proto=DpoProto.DPO_PROTO_IP6)],
1186 route_34_eos.add_vpp_config()
1189 # Drop due to interface lookup miss
1191 tx = self.create_stream_labelled_ip6(self.pg0, [34], 255,
1195 # set the RPF-ID of the enrtry to match the input packet's
1197 route_ff.update_rpf_id(55)
1199 tx = self.create_stream_labelled_ip6(self.pg0, [34], 255,
1201 self.pg0.add_stream(tx)
1203 self.pg_enable_capture(self.pg_interfaces)
1206 rx = self.pg1.get_capture(257)
1207 self.verify_capture_ip6(self.pg1, rx, tx)
1210 # disposed packets have hop-limit = 1
1212 tx = self.create_stream_labelled_ip6(self.pg0, [34], 255,
1213 dst_ip="ff01::1", hlim=1)
1214 self.pg0.add_stream(tx)
1216 self.pg_enable_capture(self.pg_interfaces)
1219 rx = self.pg0.get_capture(257)
1220 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1223 # set the RPF-ID of the enrtry to not match the input packet's
1225 route_ff.update_rpf_id(56)
1226 tx = self.create_stream_labelled_ip6(self.pg0, [34], 225,
1228 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1231 class TestMPLSDisabled(VppTestCase):
1232 """ MPLS disabled """
1235 super(TestMPLSDisabled, self).setUp()
1237 # create 2 pg interfaces
1238 self.create_pg_interfaces(range(2))
1240 self.tbl = VppMplsTable(self, 0)
1241 self.tbl.add_vpp_config()
1243 # PG0 is MPLS enalbed
1245 self.pg0.config_ip4()
1246 self.pg0.resolve_arp()
1247 self.pg0.enable_mpls()
1249 # PG 1 is not MPLS enabled
1253 for i in self.pg_interfaces:
1257 self.pg0.disable_mpls()
1258 super(TestMPLSDisabled, self).tearDown()
1260 def test_mpls_disabled(self):
1261 """ MPLS Disabled """
1263 tx = (Ether(src=self.pg1.remote_mac,
1264 dst=self.pg1.local_mac) /
1265 MPLS(label=32, ttl=64) /
1266 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1267 UDP(sport=1234, dport=1234) /
1271 # A simple MPLS xconnect - eos label in label out
1273 route_32_eos = VppMplsRoute(self, 32, 1,
1274 [VppRoutePath(self.pg0.remote_ip4,
1275 self.pg0.sw_if_index,
1277 route_32_eos.add_vpp_config()
1280 # PG1 does not forward IP traffic
1282 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1287 self.pg1.enable_mpls()
1290 # Now we get packets through
1292 self.pg1.add_stream(tx)
1293 self.pg_enable_capture(self.pg_interfaces)
1296 rx = self.pg0.get_capture(1)
1301 self.pg1.disable_mpls()
1304 # PG1 does not forward IP traffic
1306 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1307 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1310 class TestMPLSPIC(VppTestCase):
1311 """ MPLS PIC edge convergence """
1314 super(TestMPLSPIC, self).setUp()
1316 # create 2 pg interfaces
1317 self.create_pg_interfaces(range(4))
1319 mpls_tbl = VppMplsTable(self, 0)
1320 mpls_tbl.add_vpp_config()
1321 tbl4 = VppIpTable(self, 1)
1322 tbl4.add_vpp_config()
1323 tbl6 = VppIpTable(self, 1, is_ip6=1)
1324 tbl6.add_vpp_config()
1328 self.pg0.config_ip4()
1329 self.pg0.resolve_arp()
1330 self.pg0.enable_mpls()
1332 self.pg1.config_ip4()
1333 self.pg1.resolve_arp()
1334 self.pg1.enable_mpls()
1336 # VRF (customer facing) link
1338 self.pg2.set_table_ip4(1)
1339 self.pg2.config_ip4()
1340 self.pg2.resolve_arp()
1341 self.pg2.set_table_ip6(1)
1342 self.pg2.config_ip6()
1343 self.pg2.resolve_ndp()
1345 self.pg3.set_table_ip4(1)
1346 self.pg3.config_ip4()
1347 self.pg3.resolve_arp()
1348 self.pg3.set_table_ip6(1)
1349 self.pg3.config_ip6()
1350 self.pg3.resolve_ndp()
1353 self.pg0.disable_mpls()
1354 self.pg1.disable_mpls()
1355 for i in self.pg_interfaces:
1361 super(TestMPLSPIC, self).tearDown()
1363 def test_mpls_ibgp_pic(self):
1364 """ MPLS iBGP PIC edge convergence
1366 1) setup many iBGP VPN routes via a pair of iBGP peers.
1367 2) Check EMCP forwarding to these peers
1368 3) withdraw the IGP route to one of these peers.
1369 4) check forwarding continues to the remaining peer
1373 # IGP+LDP core routes
1375 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1376 [VppRoutePath(self.pg0.remote_ip4,
1377 self.pg0.sw_if_index,
1379 core_10_0_0_45.add_vpp_config()
1381 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1382 [VppRoutePath(self.pg1.remote_ip4,
1383 self.pg1.sw_if_index,
1385 core_10_0_0_46.add_vpp_config()
1388 # Lot's of VPN routes. We need more the 64 so VPP will build
1389 # the fast convergence indirection
1393 for ii in range(64):
1394 dst = "192.168.1.%d" % ii
1395 vpn_routes.append(VppIpRoute(self, dst, 32,
1396 [VppRoutePath("10.0.0.45",
1400 VppRoutePath("10.0.0.46",
1403 is_resolve_host=1)],
1405 vpn_routes[ii].add_vpp_config()
1407 pkts.append(Ether(dst=self.pg2.local_mac,
1408 src=self.pg2.remote_mac) /
1409 IP(src=self.pg2.remote_ip4, dst=dst) /
1410 UDP(sport=1234, dport=1234) /
1414 # Send the packet stream (one pkt to each VPN route)
1415 # - expect a 50-50 split of the traffic
1417 self.pg2.add_stream(pkts)
1418 self.pg_enable_capture(self.pg_interfaces)
1421 rx0 = self.pg0._get_capture(1)
1422 rx1 = self.pg1._get_capture(1)
1424 # not testig the LB hashing algorithm so we're not concerned
1425 # with the split ratio, just as long as neither is 0
1426 self.assertNotEqual(0, len(rx0))
1427 self.assertNotEqual(0, len(rx1))
1430 # use a test CLI command to stop the FIB walk process, this
1431 # will prevent the FIB converging the VPN routes and thus allow
1432 # us to probe the interim (psot-fail, pre-converge) state
1434 self.vapi.ppcli("test fib-walk-process disable")
1437 # Withdraw one of the IGP routes
1439 core_10_0_0_46.remove_vpp_config()
1442 # now all packets should be forwarded through the remaining peer
1444 self.vapi.ppcli("clear trace")
1445 self.pg2.add_stream(pkts)
1446 self.pg_enable_capture(self.pg_interfaces)
1449 rx0 = self.pg0.get_capture(len(pkts))
1452 # enable the FIB walk process to converge the FIB
1454 self.vapi.ppcli("test fib-walk-process enable")
1457 # packets should still be forwarded through the remaining peer
1459 self.pg2.add_stream(pkts)
1460 self.pg_enable_capture(self.pg_interfaces)
1463 rx0 = self.pg0.get_capture(64)
1466 # Add the IGP route back and we return to load-balancing
1468 core_10_0_0_46.add_vpp_config()
1470 self.pg2.add_stream(pkts)
1471 self.pg_enable_capture(self.pg_interfaces)
1474 rx0 = self.pg0._get_capture(1)
1475 rx1 = self.pg1._get_capture(1)
1476 self.assertNotEqual(0, len(rx0))
1477 self.assertNotEqual(0, len(rx1))
1479 def test_mpls_ebgp_pic(self):
1480 """ MPLS eBGP PIC edge convergence
1482 1) setup many eBGP VPN routes via a pair of eBGP peers
1483 2) Check EMCP forwarding to these peers
1484 3) withdraw one eBGP path - expect LB across remaining eBGP
1488 # Lot's of VPN routes. We need more the 64 so VPP will build
1489 # the fast convergence indirection
1494 for ii in range(64):
1495 dst = "192.168.1.%d" % ii
1496 local_label = 1600 + ii
1497 vpn_routes.append(VppIpRoute(self, dst, 32,
1498 [VppRoutePath(self.pg2.remote_ip4,
1501 is_resolve_attached=1),
1502 VppRoutePath(self.pg3.remote_ip4,
1505 is_resolve_attached=1)],
1507 vpn_routes[ii].add_vpp_config()
1509 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1511 vpn_bindings[ii].add_vpp_config()
1513 pkts.append(Ether(dst=self.pg0.local_mac,
1514 src=self.pg0.remote_mac) /
1515 MPLS(label=local_label, ttl=64) /
1516 IP(src=self.pg0.remote_ip4, dst=dst) /
1517 UDP(sport=1234, dport=1234) /
1520 self.pg0.add_stream(pkts)
1521 self.pg_enable_capture(self.pg_interfaces)
1524 rx0 = self.pg2._get_capture(1)
1525 rx1 = self.pg3._get_capture(1)
1526 self.assertNotEqual(0, len(rx0))
1527 self.assertNotEqual(0, len(rx1))
1530 # use a test CLI command to stop the FIB walk process, this
1531 # will prevent the FIB converging the VPN routes and thus allow
1532 # us to probe the interim (psot-fail, pre-converge) state
1534 self.vapi.ppcli("test fib-walk-process disable")
1537 # withdraw the connected prefix on the interface.
1539 self.pg2.unconfig_ip4()
1542 # now all packets should be forwarded through the remaining peer
1544 self.pg0.add_stream(pkts)
1545 self.pg_enable_capture(self.pg_interfaces)
1548 rx0 = self.pg3.get_capture(len(pkts))
1551 # enable the FIB walk process to converge the FIB
1553 self.vapi.ppcli("test fib-walk-process enable")
1554 self.pg0.add_stream(pkts)
1555 self.pg_enable_capture(self.pg_interfaces)
1558 rx0 = self.pg3.get_capture(len(pkts))
1561 # put the connecteds back
1563 self.pg2.config_ip4()
1565 self.pg0.add_stream(pkts)
1566 self.pg_enable_capture(self.pg_interfaces)
1569 rx0 = self.pg2._get_capture(1)
1570 rx1 = self.pg3._get_capture(1)
1571 self.assertNotEqual(0, len(rx0))
1572 self.assertNotEqual(0, len(rx1))
1574 def test_mpls_v6_ebgp_pic(self):
1575 """ MPLSv6 eBGP PIC edge convergence
1577 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1578 2) Check EMCP forwarding to these peers
1579 3) withdraw one eBGP path - expect LB across remaining eBGP
1583 # Lot's of VPN routes. We need more the 64 so VPP will build
1584 # the fast convergence indirection
1589 for ii in range(64):
1590 dst = "3000::%d" % ii
1591 local_label = 1600 + ii
1592 vpn_routes.append(VppIpRoute(
1594 [VppRoutePath(self.pg2.remote_ip6,
1597 is_resolve_attached=1,
1598 proto=DpoProto.DPO_PROTO_IP6),
1599 VppRoutePath(self.pg3.remote_ip6,
1602 proto=DpoProto.DPO_PROTO_IP6,
1603 is_resolve_attached=1)],
1606 vpn_routes[ii].add_vpp_config()
1608 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1611 vpn_bindings[ii].add_vpp_config()
1613 pkts.append(Ether(dst=self.pg0.local_mac,
1614 src=self.pg0.remote_mac) /
1615 MPLS(label=local_label, ttl=64) /
1616 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1617 UDP(sport=1234, dport=1234) /
1620 self.pg0.add_stream(pkts)
1621 self.pg_enable_capture(self.pg_interfaces)
1624 rx0 = self.pg2._get_capture(1)
1625 rx1 = self.pg3._get_capture(1)
1626 self.assertNotEqual(0, len(rx0))
1627 self.assertNotEqual(0, len(rx1))
1630 # use a test CLI command to stop the FIB walk process, this
1631 # will prevent the FIB converging the VPN routes and thus allow
1632 # us to probe the interim (psot-fail, pre-converge) state
1634 self.vapi.ppcli("test fib-walk-process disable")
1637 # withdraw the connected prefix on the interface.
1638 # and shutdown the interface so the ND cache is flushed.
1640 self.pg2.unconfig_ip6()
1641 self.pg2.admin_down()
1644 # now all packets should be forwarded through the remaining peer
1646 self.pg0.add_stream(pkts)
1647 self.pg_enable_capture(self.pg_interfaces)
1650 rx0 = self.pg3.get_capture(len(pkts))
1653 # enable the FIB walk process to converge the FIB
1655 self.vapi.ppcli("test fib-walk-process enable")
1656 self.pg0.add_stream(pkts)
1657 self.pg_enable_capture(self.pg_interfaces)
1660 rx0 = self.pg3.get_capture(len(pkts))
1663 # put the connecteds back
1666 self.pg2.config_ip6()
1668 self.pg0.add_stream(pkts)
1669 self.pg_enable_capture(self.pg_interfaces)
1672 rx0 = self.pg2._get_capture(1)
1673 rx1 = self.pg3._get_capture(1)
1674 self.assertNotEqual(0, len(rx0))
1675 self.assertNotEqual(0, len(rx1))
1678 class TestMPLSL2(VppTestCase):
1682 super(TestMPLSL2, self).setUp()
1684 # create 2 pg interfaces
1685 self.create_pg_interfaces(range(2))
1687 # create the default MPLS table
1689 tbl = VppMplsTable(self, 0)
1690 tbl.add_vpp_config()
1691 self.tables.append(tbl)
1693 # use pg0 as the core facing interface
1695 self.pg0.config_ip4()
1696 self.pg0.resolve_arp()
1697 self.pg0.enable_mpls()
1699 # use the other 2 for customer facing L2 links
1700 for i in self.pg_interfaces[1:]:
1704 for i in self.pg_interfaces[1:]:
1707 self.pg0.disable_mpls()
1708 self.pg0.unconfig_ip4()
1709 self.pg0.admin_down()
1710 super(TestMPLSL2, self).tearDown()
1712 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels,
1715 top = len(mpls_labels) - 1
1717 capture = verify_filter(capture, sent)
1719 self.assertEqual(len(capture), len(sent))
1721 for i in range(len(capture)):
1725 # the MPLS TTL is 255 since it enters a new tunnel
1726 verify_mpls_stack(self, rx, mpls_labels, ttl, top)
1729 rx_eth = Ether(str(rx[MPLS].payload))
1731 self.assertEqual(rx_eth.src, tx_eth.src)
1732 self.assertEqual(rx_eth.dst, tx_eth.dst)
1734 def test_vpws(self):
1735 """ Virtual Private Wire Service """
1738 # Create an MPLS tunnel that pushes 1 label
1740 mpls_tun_1 = VppMPLSTunnelInterface(self,
1741 [VppRoutePath(self.pg0.remote_ip4,
1742 self.pg0.sw_if_index,
1745 mpls_tun_1.add_vpp_config()
1746 mpls_tun_1.admin_up()
1749 # Create a label entry to for 55 that does L2 input to the tunnel
1751 route_55_eos = VppMplsRoute(
1753 [VppRoutePath("0.0.0.0",
1754 mpls_tun_1.sw_if_index,
1756 proto=DpoProto.DPO_PROTO_ETHERNET)])
1757 route_55_eos.add_vpp_config()
1760 # Cross-connect the tunnel with one of the customers L2 interfaces
1762 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
1763 mpls_tun_1.sw_if_index,
1765 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
1766 self.pg1.sw_if_index,
1770 # inject a packet from the core
1772 pcore = (Ether(dst=self.pg0.local_mac,
1773 src=self.pg0.remote_mac) /
1774 MPLS(label=55, ttl=64) /
1775 Ether(dst="00:00:de:ad:ba:be",
1776 src="00:00:de:ad:be:ef") /
1777 IP(src="10.10.10.10", dst="11.11.11.11") /
1778 UDP(sport=1234, dport=1234) /
1781 self.pg0.add_stream(pcore * 65)
1782 self.pg_enable_capture(self.pg_interfaces)
1785 rx0 = self.pg1.get_capture(65)
1786 tx = pcore[MPLS].payload
1788 self.assertEqual(rx0[0][Ether].dst, tx[Ether].dst)
1789 self.assertEqual(rx0[0][Ether].src, tx[Ether].src)
1792 # Inject a packet from the custoer/L2 side
1794 self.pg1.add_stream(tx * 65)
1795 self.pg_enable_capture(self.pg_interfaces)
1798 rx0 = self.pg0.get_capture(65)
1800 self.verify_capture_tunneled_ethernet(rx0, tx*65, [42])
1802 def test_vpls(self):
1803 """ Virtual Private LAN Service """
1805 # Create an L2 MPLS tunnel
1807 mpls_tun = VppMPLSTunnelInterface(self,
1808 [VppRoutePath(self.pg0.remote_ip4,
1809 self.pg0.sw_if_index,
1812 mpls_tun.add_vpp_config()
1816 # Create a label entry to for 55 that does L2 input to the tunnel
1818 route_55_eos = VppMplsRoute(
1820 [VppRoutePath("0.0.0.0",
1821 mpls_tun.sw_if_index,
1823 proto=DpoProto.DPO_PROTO_ETHERNET)])
1824 route_55_eos.add_vpp_config()
1827 # add to tunnel to the customers bridge-domain
1829 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
1831 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
1835 # Packet from the customer interface and from the core
1837 p_cust = (Ether(dst="00:00:de:ad:ba:be",
1838 src="00:00:de:ad:be:ef") /
1839 IP(src="10.10.10.10", dst="11.11.11.11") /
1840 UDP(sport=1234, dport=1234) /
1842 p_core = (Ether(src="00:00:de:ad:ba:be",
1843 dst="00:00:de:ad:be:ef") /
1844 IP(dst="10.10.10.10", src="11.11.11.11") /
1845 UDP(sport=1234, dport=1234) /
1849 # The BD is learning, so send in one of each packet to learn
1851 p_core_encap = (Ether(dst=self.pg0.local_mac,
1852 src=self.pg0.remote_mac) /
1853 MPLS(label=55, ttl=64) /
1856 self.pg1.add_stream(p_cust)
1857 self.pg_enable_capture(self.pg_interfaces)
1859 self.pg0.add_stream(p_core_encap)
1860 self.pg_enable_capture(self.pg_interfaces)
1863 # we've learnt this so expect it be be forwarded
1864 rx0 = self.pg1.get_capture(1)
1866 self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst)
1867 self.assertEqual(rx0[0][Ether].src, p_core[Ether].src)
1870 # now a stream in each direction
1872 self.pg1.add_stream(p_cust * 65)
1873 self.pg_enable_capture(self.pg_interfaces)
1876 rx0 = self.pg0.get_capture(65)
1878 self.verify_capture_tunneled_ethernet(rx0, p_cust*65, [42])
1881 # remove interfaces from customers bridge-domain
1883 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
1886 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
1890 if __name__ == '__main__':
1891 unittest.main(testRunner=VppTestRunner)