6 from framework import tag_fixme_vpp_workers
7 from framework import VppTestCase, VppTestRunner
8 from vpp_ip import DpoProto, INVALID_INDEX
9 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
10 VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
11 VppIpTable, VppMplsTable, \
12 VppMplsLabel, MplsLspMode, find_mpls_route, \
13 FibPathProto, FibPathType, FibPathFlags, VppMplsLabel, MplsLspMode
14 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
15 from vpp_papi import VppEnum
18 from scapy.packet import Raw
19 from scapy.layers.l2 import Ether, ARP
20 from scapy.layers.inet import IP, UDP, ICMP
21 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
22 from scapy.contrib.mpls import MPLS
26 # scapy removed these attributes.
27 # we asked that they be restored: https://github.com/secdev/scapy/pull/1878
28 # semantic names have more meaning than numbers. so here they are.
33 def verify_filter(capture, sent):
34 if not len(capture) == len(sent):
35 # filter out any IPv6 RAs from the capture
42 def verify_mpls_stack(tst, rx, mpls_labels):
43 # the rx'd packet has the MPLS label popped
45 tst.assertEqual(eth.type, 0x8847)
49 for ii in range(len(mpls_labels)):
50 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
51 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
52 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
54 if ii == len(mpls_labels) - 1:
55 tst.assertEqual(rx_mpls.s, 1)
58 tst.assertEqual(rx_mpls.s, 0)
59 # pop the label to expose the next
60 rx_mpls = rx_mpls[MPLS].payload
63 @tag_fixme_vpp_workers
64 class TestMPLS(VppTestCase):
65 """ MPLS Test Case """
69 super(TestMPLS, cls).setUpClass()
72 def tearDownClass(cls):
73 super(TestMPLS, cls).tearDownClass()
76 super(TestMPLS, self).setUp()
78 # create 2 pg interfaces
79 self.create_pg_interfaces(range(4))
81 # setup both interfaces
82 # assign them different tables.
86 tbl = VppMplsTable(self, 0)
88 self.tables.append(tbl)
90 for i in self.pg_interfaces:
94 tbl = VppIpTable(self, table_id)
96 self.tables.append(tbl)
97 tbl = VppIpTable(self, table_id, is_ip6=1)
99 self.tables.append(tbl)
101 i.set_table_ip4(table_id)
102 i.set_table_ip6(table_id)
111 for i in self.pg_interfaces:
118 super(TestMPLS, self).tearDown()
120 # the default of 64 matches the IP packet TTL default
121 def create_stream_labelled_ip4(
131 self.reset_packet_infos()
133 for i in range(0, n):
134 info = self.create_packet_info(src_if, src_if)
135 payload = self.info_to_payload(info)
136 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
138 for ii in range(len(mpls_labels)):
139 p = p / MPLS(label=mpls_labels[ii].value,
140 ttl=mpls_labels[ii].ttl,
141 cos=mpls_labels[ii].exp)
144 p = (p / IP(src=src_if.local_ip4,
145 dst=src_if.remote_ip4,
147 UDP(sport=1234, dport=1234) /
150 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
151 UDP(sport=1234, dport=1234) /
154 p = (p / IP(src=ip_itf.remote_ip4,
155 dst=ip_itf.local_ip4,
160 p[IP].chksum = chksum
165 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64,
166 ip_dscp=0, payload_size=None):
167 self.reset_packet_infos()
169 for i in range(0, 257):
170 info = self.create_packet_info(src_if, src_if)
171 payload = self.info_to_payload(info)
172 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
173 IP(src=src_if.remote_ip4, dst=dst_ip,
174 ttl=ip_ttl, tos=ip_dscp) /
175 UDP(sport=1234, dport=1234) /
179 self.extend_packet(p, payload_size)
183 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
184 self.reset_packet_infos()
186 for i in range(0, 257):
187 info = self.create_packet_info(src_if, src_if)
188 payload = self.info_to_payload(info)
189 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
190 IPv6(src=src_if.remote_ip6, dst=dst_ip,
191 hlim=ip_ttl, tc=ip_dscp) /
192 UDP(sport=1234, dport=1234) /
198 def create_stream_labelled_ip6(self, src_if, mpls_labels,
199 hlim=64, dst_ip=None):
201 dst_ip = src_if.remote_ip6
202 self.reset_packet_infos()
204 for i in range(0, 257):
205 info = self.create_packet_info(src_if, src_if)
206 payload = self.info_to_payload(info)
207 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
208 for l in mpls_labels:
209 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
211 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
212 UDP(sport=1234, dport=1234) /
218 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
219 ip_ttl=None, ip_dscp=0):
221 capture = verify_filter(capture, sent)
223 self.assertEqual(len(capture), len(sent))
225 for i in range(len(capture)):
229 # the rx'd packet has the MPLS label popped
231 self.assertEqual(eth.type, 0x800)
237 self.assertEqual(rx_ip.src, tx_ip.src)
238 self.assertEqual(rx_ip.dst, tx_ip.dst)
239 self.assertEqual(rx_ip.tos, ip_dscp)
241 # IP processing post pop has decremented the TTL
242 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
244 self.assertEqual(rx_ip.ttl, ip_ttl)
246 self.assertEqual(rx_ip.src, tx_ip.dst)
247 self.assertEqual(rx_ip.dst, tx_ip.src)
252 def verify_capture_labelled_ip4(self, src_if, capture, sent,
253 mpls_labels, ip_ttl=None):
255 capture = verify_filter(capture, sent)
257 self.assertEqual(len(capture), len(sent))
259 for i in range(len(capture)):
265 verify_mpls_stack(self, rx, mpls_labels)
267 self.assertEqual(rx_ip.src, tx_ip.src)
268 self.assertEqual(rx_ip.dst, tx_ip.dst)
270 # IP processing post pop has decremented the TTL
271 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
273 self.assertEqual(rx_ip.ttl, ip_ttl)
278 def verify_capture_labelled_ip6(self, src_if, capture, sent,
279 mpls_labels, ip_ttl=None):
281 capture = verify_filter(capture, sent)
283 self.assertEqual(len(capture), len(sent))
285 for i in range(len(capture)):
291 verify_mpls_stack(self, rx, mpls_labels)
293 self.assertEqual(rx_ip.src, tx_ip.src)
294 self.assertEqual(rx_ip.dst, tx_ip.dst)
296 # IP processing post pop has decremented the TTL
297 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
299 self.assertEqual(rx_ip.hlim, ip_ttl)
304 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
306 capture = verify_filter(capture, sent)
308 self.assertEqual(len(capture), len(sent))
310 for i in range(len(capture)):
316 verify_mpls_stack(self, rx, mpls_labels)
318 self.assertEqual(rx_ip.src, tx_ip.src)
319 self.assertEqual(rx_ip.dst, tx_ip.dst)
320 # IP processing post pop has decremented the TTL
321 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
326 def verify_capture_labelled(self, src_if, capture, sent,
329 capture = verify_filter(capture, sent)
331 self.assertEqual(len(capture), len(sent))
333 for i in range(len(capture)):
335 verify_mpls_stack(self, rx, mpls_labels)
339 def verify_capture_ip6(self, src_if, capture, sent,
340 ip_hlim=None, ip_dscp=0):
342 self.assertEqual(len(capture), len(sent))
344 for i in range(len(capture)):
348 # the rx'd packet has the MPLS label popped
350 self.assertEqual(eth.type, 0x86DD)
355 self.assertEqual(rx_ip.src, tx_ip.src)
356 self.assertEqual(rx_ip.dst, tx_ip.dst)
357 self.assertEqual(rx_ip.tc, ip_dscp)
358 # IP processing post pop has decremented the TTL
360 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
362 self.assertEqual(rx_ip.hlim, ip_hlim)
367 def verify_capture_ip6_icmp(self, src_if, capture, sent):
369 self.assertEqual(len(capture), len(sent))
371 for i in range(len(capture)):
375 # the rx'd packet has the MPLS label popped
377 self.assertEqual(eth.type, 0x86DD)
382 self.assertEqual(rx_ip.dst, tx_ip.src)
383 # ICMP sourced from the interface's address
384 self.assertEqual(rx_ip.src, src_if.local_ip6)
385 # hop-limit reset to 255 for IMCP packet
386 self.assertEqual(rx_ip.hlim, 255)
388 icmp = rx[ICMPv6TimeExceeded]
393 def verify_capture_fragmented_labelled_ip4(self, src_if, capture, sent,
394 mpls_labels, ip_ttl=None):
396 capture = verify_filter(capture, sent)
398 for i in range(len(capture)):
404 verify_mpls_stack(self, rx, mpls_labels)
406 self.assertEqual(rx_ip.src, tx_ip.src)
407 self.assertEqual(rx_ip.dst, tx_ip.dst)
409 # IP processing post pop has decremented the TTL
410 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
412 self.assertEqual(rx_ip.ttl, ip_ttl)
418 """ MPLS label swap tests """
421 # A simple MPLS xconnect - eos label in label out
423 route_32_eos = VppMplsRoute(self, 32, 1,
424 [VppRoutePath(self.pg0.remote_ip4,
425 self.pg0.sw_if_index,
426 labels=[VppMplsLabel(33)])])
427 route_32_eos.add_vpp_config()
430 find_mpls_route(self, 0, 32, 1,
431 [VppRoutePath(self.pg0.remote_ip4,
432 self.pg0.sw_if_index,
433 labels=[VppMplsLabel(33)])]))
436 # a stream that matches the route for 10.0.0.1
437 # PG0 is in the default table
439 tx = self.create_stream_labelled_ip4(self.pg0,
440 [VppMplsLabel(32, ttl=32, exp=1)])
441 rx = self.send_and_expect(self.pg0, tx, self.pg0)
442 self.verify_capture_labelled(self.pg0, rx, tx,
443 [VppMplsLabel(33, ttl=31, exp=1)])
445 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
448 # A simple MPLS xconnect - non-eos label in label out
450 route_32_neos = VppMplsRoute(self, 32, 0,
451 [VppRoutePath(self.pg0.remote_ip4,
452 self.pg0.sw_if_index,
453 labels=[VppMplsLabel(33)])])
454 route_32_neos.add_vpp_config()
457 # a stream that matches the route for 10.0.0.1
458 # PG0 is in the default table
460 tx = self.create_stream_labelled_ip4(self.pg0,
461 [VppMplsLabel(32, ttl=21, exp=7),
463 rx = self.send_and_expect(self.pg0, tx, self.pg0)
464 self.verify_capture_labelled(self.pg0, rx, tx,
465 [VppMplsLabel(33, ttl=20, exp=7),
467 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
470 # A simple MPLS xconnect - non-eos label in label out, uniform mode
472 route_42_neos = VppMplsRoute(
474 [VppRoutePath(self.pg0.remote_ip4,
475 self.pg0.sw_if_index,
476 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
477 route_42_neos.add_vpp_config()
479 tx = self.create_stream_labelled_ip4(self.pg0,
480 [VppMplsLabel(42, ttl=21, exp=7),
482 rx = self.send_and_expect(self.pg0, tx, self.pg0)
483 self.verify_capture_labelled(self.pg0, rx, tx,
484 [VppMplsLabel(43, ttl=20, exp=7),
488 # An MPLS xconnect - EOS label in IP out
490 route_33_eos = VppMplsRoute(self, 33, 1,
491 [VppRoutePath(self.pg0.remote_ip4,
492 self.pg0.sw_if_index,
494 route_33_eos.add_vpp_config()
496 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
497 rx = self.send_and_expect(self.pg0, tx, self.pg0)
498 self.verify_capture_ip4(self.pg0, rx, tx)
501 # disposed packets have an invalid IPv4 checksum
503 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
504 dst_ip=self.pg0.remote_ip4,
507 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
510 # An MPLS xconnect - EOS label in IP out, uniform mode
512 route_3333_eos = VppMplsRoute(
514 [VppRoutePath(self.pg0.remote_ip4,
515 self.pg0.sw_if_index,
516 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
517 route_3333_eos.add_vpp_config()
519 tx = self.create_stream_labelled_ip4(
521 [VppMplsLabel(3333, ttl=55, exp=3)])
522 rx = self.send_and_expect(self.pg0, tx, self.pg0)
523 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
524 tx = self.create_stream_labelled_ip4(
526 [VppMplsLabel(3333, ttl=66, exp=4)])
527 rx = self.send_and_expect(self.pg0, tx, self.pg0)
528 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
531 # An MPLS xconnect - EOS label in IPv6 out
533 route_333_eos = VppMplsRoute(
535 [VppRoutePath(self.pg0.remote_ip6,
536 self.pg0.sw_if_index,
538 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
539 route_333_eos.add_vpp_config()
541 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
542 rx = self.send_and_expect(self.pg0, tx, self.pg0)
543 self.verify_capture_ip6(self.pg0, rx, tx)
546 # disposed packets have an TTL expired
548 tx = self.create_stream_labelled_ip6(self.pg0,
549 [VppMplsLabel(333, ttl=64)],
550 dst_ip=self.pg1.remote_ip6,
552 rx = self.send_and_expect(self.pg0, tx, self.pg0)
553 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
556 # An MPLS xconnect - EOS label in IPv6 out w imp-null
558 route_334_eos = VppMplsRoute(
560 [VppRoutePath(self.pg0.remote_ip6,
561 self.pg0.sw_if_index,
562 labels=[VppMplsLabel(3)])],
563 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
564 route_334_eos.add_vpp_config()
566 tx = self.create_stream_labelled_ip6(self.pg0,
567 [VppMplsLabel(334, ttl=64)])
568 rx = self.send_and_expect(self.pg0, tx, self.pg0)
569 self.verify_capture_ip6(self.pg0, rx, tx)
572 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
574 route_335_eos = VppMplsRoute(
576 [VppRoutePath(self.pg0.remote_ip6,
577 self.pg0.sw_if_index,
578 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
579 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
580 route_335_eos.add_vpp_config()
582 tx = self.create_stream_labelled_ip6(
584 [VppMplsLabel(335, ttl=27, exp=4)])
585 rx = self.send_and_expect(self.pg0, tx, self.pg0)
586 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
589 # disposed packets have an TTL expired
591 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
592 dst_ip=self.pg1.remote_ip6,
594 rx = self.send_and_expect(self.pg0, tx, self.pg0)
595 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
598 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
599 # so this traffic should be dropped.
601 route_33_neos = VppMplsRoute(self, 33, 0,
602 [VppRoutePath(self.pg0.remote_ip4,
603 self.pg0.sw_if_index,
605 route_33_neos.add_vpp_config()
607 tx = self.create_stream_labelled_ip4(self.pg0,
610 self.send_and_assert_no_replies(
612 "MPLS non-EOS packets popped and forwarded")
615 # A recursive EOS x-connect, which resolves through another x-connect
618 route_34_eos = VppMplsRoute(self, 34, 1,
619 [VppRoutePath("0.0.0.0",
622 labels=[VppMplsLabel(44),
624 route_34_eos.add_vpp_config()
625 self.logger.info(self.vapi.cli("sh mpls fib 34"))
627 tx = self.create_stream_labelled_ip4(self.pg0,
628 [VppMplsLabel(34, ttl=3)])
629 rx = self.send_and_expect(self.pg0, tx, self.pg0)
630 self.verify_capture_labelled(self.pg0, rx, tx,
633 VppMplsLabel(45, ttl=2)])
635 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
636 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
639 # A recursive EOS x-connect, which resolves through another x-connect
642 route_35_eos = VppMplsRoute(
644 [VppRoutePath("0.0.0.0",
647 labels=[VppMplsLabel(44)])])
648 route_35_eos.add_vpp_config()
650 tx = self.create_stream_labelled_ip4(self.pg0,
651 [VppMplsLabel(35, ttl=3)])
652 rx = self.send_and_expect(self.pg0, tx, self.pg0)
653 self.verify_capture_labelled(self.pg0, rx, tx,
654 [VppMplsLabel(43, ttl=2),
655 VppMplsLabel(44, ttl=2)])
658 # A recursive non-EOS x-connect, which resolves through another
661 route_34_neos = VppMplsRoute(self, 34, 0,
662 [VppRoutePath("0.0.0.0",
665 labels=[VppMplsLabel(44),
667 route_34_neos.add_vpp_config()
669 tx = self.create_stream_labelled_ip4(self.pg0,
670 [VppMplsLabel(34, ttl=45),
672 rx = self.send_and_expect(self.pg0, tx, self.pg0)
673 # it's the 2nd (counting from 0) label in the stack that is swapped
674 self.verify_capture_labelled(self.pg0, rx, tx,
677 VppMplsLabel(46, ttl=44),
681 # an recursive IP route that resolves through the recursive non-eos
684 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
685 [VppRoutePath("0.0.0.0",
688 labels=[VppMplsLabel(55)])])
689 ip_10_0_0_1.add_vpp_config()
691 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
692 rx = self.send_and_expect(self.pg0, tx, self.pg0)
693 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
698 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
700 ip_10_0_0_1.remove_vpp_config()
701 route_34_neos.remove_vpp_config()
702 route_34_eos.remove_vpp_config()
703 route_33_neos.remove_vpp_config()
704 route_33_eos.remove_vpp_config()
705 route_32_neos.remove_vpp_config()
706 route_32_eos.remove_vpp_config()
709 """ MPLS Local Label Binding test """
712 # Add a non-recursive route with a single out label
714 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
715 [VppRoutePath(self.pg0.remote_ip4,
716 self.pg0.sw_if_index,
717 labels=[VppMplsLabel(45)])])
718 route_10_0_0_1.add_vpp_config()
720 # bind a local label to the route
721 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
722 binding.add_vpp_config()
725 tx = self.create_stream_labelled_ip4(self.pg0,
728 rx = self.send_and_expect(self.pg0, tx, self.pg0)
729 self.verify_capture_labelled(self.pg0, rx, tx,
730 [VppMplsLabel(45, ttl=63),
734 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
735 rx = self.send_and_expect(self.pg0, tx, self.pg0)
736 self.verify_capture_labelled(self.pg0, rx, tx,
737 [VppMplsLabel(45, ttl=63)])
740 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
741 rx = self.send_and_expect(self.pg0, tx, self.pg0)
742 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
747 binding.remove_vpp_config()
748 route_10_0_0_1.remove_vpp_config()
750 def test_imposition(self):
751 """ MPLS label imposition test """
754 # Add a non-recursive route with a single out label
756 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
757 [VppRoutePath(self.pg0.remote_ip4,
758 self.pg0.sw_if_index,
759 labels=[VppMplsLabel(32)])])
760 route_10_0_0_1.add_vpp_config()
763 # a stream that matches the route for 10.0.0.1
764 # PG0 is in the default table
766 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
767 rx = self.send_and_expect(self.pg0, tx, self.pg0)
768 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
771 # Add a non-recursive route with a 3 out labels
773 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
774 [VppRoutePath(self.pg0.remote_ip4,
775 self.pg0.sw_if_index,
776 labels=[VppMplsLabel(32),
779 route_10_0_0_2.add_vpp_config()
781 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
782 ip_ttl=44, ip_dscp=0xff)
783 rx = self.send_and_expect(self.pg0, tx, self.pg0)
784 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
791 # Add a non-recursive route with a single out label in uniform mode
793 route_10_0_0_3 = VppIpRoute(
794 self, "10.0.0.3", 32,
795 [VppRoutePath(self.pg0.remote_ip4,
796 self.pg0.sw_if_index,
797 labels=[VppMplsLabel(32,
798 mode=MplsLspMode.UNIFORM)])])
799 route_10_0_0_3.add_vpp_config()
801 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
802 ip_ttl=54, ip_dscp=0xbe)
803 rx = self.send_and_expect(self.pg0, tx, self.pg0)
804 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
805 [VppMplsLabel(32, ttl=53, exp=5)])
808 # Add a IPv6 non-recursive route with a single out label in
811 route_2001_3 = VppIpRoute(
812 self, "2001::3", 128,
813 [VppRoutePath(self.pg0.remote_ip6,
814 self.pg0.sw_if_index,
815 labels=[VppMplsLabel(32,
816 mode=MplsLspMode.UNIFORM)])])
817 route_2001_3.add_vpp_config()
819 tx = self.create_stream_ip6(self.pg0, "2001::3",
820 ip_ttl=54, ip_dscp=0xbe)
821 rx = self.send_and_expect(self.pg0, tx, self.pg0)
822 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
823 [VppMplsLabel(32, ttl=53, exp=5)])
826 # add a recursive path, with output label, via the 1 label route
828 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
829 [VppRoutePath("10.0.0.1",
831 labels=[VppMplsLabel(44)])])
832 route_11_0_0_1.add_vpp_config()
835 # a stream that matches the route for 11.0.0.1, should pick up
836 # the label stack for 11.0.0.1 and 10.0.0.1
838 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
839 rx = self.send_and_expect(self.pg0, tx, self.pg0)
840 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
844 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
847 # add a recursive path, with 2 labels, via the 3 label route
849 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
850 [VppRoutePath("10.0.0.2",
852 labels=[VppMplsLabel(44),
854 route_11_0_0_2.add_vpp_config()
857 # a stream that matches the route for 11.0.0.1, should pick up
858 # the label stack for 11.0.0.1 and 10.0.0.1
860 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
861 rx = self.send_and_expect(self.pg0, tx, self.pg0)
862 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
869 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
871 rx = self.send_and_expect(self.pg0, tx, self.pg0)
872 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
879 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
884 route_11_0_0_2.remove_vpp_config()
885 route_11_0_0_1.remove_vpp_config()
886 route_10_0_0_2.remove_vpp_config()
887 route_10_0_0_1.remove_vpp_config()
889 def test_imposition_fragmentation(self):
890 """ MPLS label imposition fragmentation test """
893 # Add a ipv4 non-recursive route with a single out label
895 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
896 [VppRoutePath(self.pg0.remote_ip4,
897 self.pg0.sw_if_index,
898 labels=[VppMplsLabel(32)])])
899 route_10_0_0_1.add_vpp_config()
902 # a stream that matches the route for 10.0.0.1
903 # PG0 is in the default table
905 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
906 for i in range(0, 257):
907 self.extend_packet(tx[i], 10000)
910 # 5 fragments per packet (257*5=1285)
912 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
913 self.verify_capture_fragmented_labelled_ip4(self.pg0, rx, tx,
919 route_10_0_0_1.remove_vpp_config()
921 def test_tunnel_pipe(self):
922 """ MPLS Tunnel Tests - Pipe """
925 # Create a tunnel with two out labels
927 mpls_tun = VppMPLSTunnelInterface(
929 [VppRoutePath(self.pg0.remote_ip4,
930 self.pg0.sw_if_index,
931 labels=[VppMplsLabel(44),
933 mpls_tun.add_vpp_config()
937 # add an unlabelled route through the new tunnel
939 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
940 [VppRoutePath("0.0.0.0",
941 mpls_tun._sw_if_index)])
942 route_10_0_0_3.add_vpp_config()
944 self.vapi.cli("clear trace")
945 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
946 self.pg0.add_stream(tx)
948 self.pg_enable_capture(self.pg_interfaces)
951 rx = self.pg0.get_capture()
952 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
957 # add a labelled route through the new tunnel
959 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
960 [VppRoutePath("0.0.0.0",
961 mpls_tun._sw_if_index,
963 route_10_0_0_4.add_vpp_config()
965 self.vapi.cli("clear trace")
966 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
967 self.pg0.add_stream(tx)
969 self.pg_enable_capture(self.pg_interfaces)
972 rx = self.pg0.get_capture()
973 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
976 VppMplsLabel(33, ttl=255)])
979 # change tunnel's MTU to a low value
981 mpls_tun.set_l3_mtu(1200)
983 # send IP into the tunnel to be fragmented
984 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
986 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
992 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
996 # send MPLS into the tunnel to be fragmented
997 tx = self.create_stream_ip4(self.pg0, "10.0.0.4",
999 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1005 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1008 VppMplsLabel(33, ttl=255)])
1010 def test_tunnel_uniform(self):
1011 """ MPLS Tunnel Tests - Uniform """
1014 # Create a tunnel with a single out label
1015 # The label stack is specified here from outer to inner
1017 mpls_tun = VppMPLSTunnelInterface(
1019 [VppRoutePath(self.pg0.remote_ip4,
1020 self.pg0.sw_if_index,
1021 labels=[VppMplsLabel(44, ttl=32),
1022 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1023 mpls_tun.add_vpp_config()
1027 # add an unlabelled route through the new tunnel
1029 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1030 [VppRoutePath("0.0.0.0",
1031 mpls_tun._sw_if_index)])
1032 route_10_0_0_3.add_vpp_config()
1034 self.vapi.cli("clear trace")
1035 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1036 self.pg0.add_stream(tx)
1038 self.pg_enable_capture(self.pg_interfaces)
1041 rx = self.pg0.get_capture()
1042 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1043 [VppMplsLabel(44, ttl=32),
1044 VppMplsLabel(46, ttl=23)])
1047 # add a labelled route through the new tunnel
1049 route_10_0_0_4 = VppIpRoute(
1050 self, "10.0.0.4", 32,
1051 [VppRoutePath("0.0.0.0",
1052 mpls_tun._sw_if_index,
1053 labels=[VppMplsLabel(33, ttl=47)])])
1054 route_10_0_0_4.add_vpp_config()
1056 self.vapi.cli("clear trace")
1057 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1058 self.pg0.add_stream(tx)
1060 self.pg_enable_capture(self.pg_interfaces)
1063 rx = self.pg0.get_capture()
1064 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1065 [VppMplsLabel(44, ttl=32),
1066 VppMplsLabel(46, ttl=47),
1067 VppMplsLabel(33, ttl=47)])
1069 def test_mpls_tunnel_many(self):
1070 """ MPLS Multiple Tunnels """
1072 for ii in range(100):
1073 mpls_tun = VppMPLSTunnelInterface(
1075 [VppRoutePath(self.pg0.remote_ip4,
1076 self.pg0.sw_if_index,
1077 labels=[VppMplsLabel(44, ttl=32),
1078 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1079 mpls_tun.add_vpp_config()
1081 for ii in range(100):
1082 mpls_tun = VppMPLSTunnelInterface(
1084 [VppRoutePath(self.pg0.remote_ip4,
1085 self.pg0.sw_if_index,
1086 labels=[VppMplsLabel(44, ttl=32),
1087 VppMplsLabel(46, MplsLspMode.UNIFORM)])],
1089 mpls_tun.add_vpp_config()
1092 def test_v4_exp_null(self):
1093 """ MPLS V4 Explicit NULL test """
1096 # The first test case has an MPLS TTL of 0
1097 # all packet should be dropped
1099 tx = self.create_stream_labelled_ip4(self.pg0,
1100 [VppMplsLabel(0, ttl=0)])
1101 self.send_and_assert_no_replies(self.pg0, tx,
1102 "MPLS TTL=0 packets forwarded")
1105 # a stream with a non-zero MPLS TTL
1106 # PG0 is in the default table
1108 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1109 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1110 self.verify_capture_ip4(self.pg0, rx, tx)
1113 # a stream with a non-zero MPLS TTL
1115 # we are ensuring the post-pop lookup occurs in the VRF table
1117 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1118 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1119 self.verify_capture_ip4(self.pg1, rx, tx)
1121 def test_v6_exp_null(self):
1122 """ MPLS V6 Explicit NULL test """
1125 # a stream with a non-zero MPLS TTL
1126 # PG0 is in the default table
1128 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1129 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1130 self.verify_capture_ip6(self.pg0, rx, tx)
1133 # a stream with a non-zero MPLS TTL
1135 # we are ensuring the post-pop lookup occurs in the VRF table
1137 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1138 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1139 self.verify_capture_ip6(self.pg0, rx, tx)
1141 def test_deag(self):
1145 # A de-agg route - next-hop lookup in default table
1147 route_34_eos = VppMplsRoute(self, 34, 1,
1148 [VppRoutePath("0.0.0.0",
1151 route_34_eos.add_vpp_config()
1154 # ping an interface in the default table
1155 # PG0 is in the default table
1157 tx = self.create_stream_labelled_ip4(self.pg0,
1161 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1162 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1165 # A de-agg route - next-hop lookup in non-default table
1167 route_35_eos = VppMplsRoute(self, 35, 1,
1168 [VppRoutePath("0.0.0.0",
1171 route_35_eos.add_vpp_config()
1174 # ping an interface in the non-default table
1175 # PG0 is in the default table. packet arrive labelled in the
1176 # default table and egress unlabelled in the non-default
1178 tx = self.create_stream_labelled_ip4(
1179 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1180 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1181 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1186 route_36_neos = VppMplsRoute(self, 36, 0,
1187 [VppRoutePath("0.0.0.0",
1189 route_36_neos.add_vpp_config()
1191 tx = self.create_stream_labelled_ip4(self.pg0,
1194 ping=1, ip_itf=self.pg1)
1195 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1196 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1198 route_36_neos.remove_vpp_config()
1199 route_35_eos.remove_vpp_config()
1200 route_34_eos.remove_vpp_config()
1202 def test_interface_rx(self):
1203 """ MPLS Interface Receive """
1206 # Add a non-recursive route that will forward the traffic
1209 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1211 paths=[VppRoutePath(self.pg1.remote_ip4,
1212 self.pg1.sw_if_index)])
1213 route_10_0_0_1.add_vpp_config()
1216 # An interface receive label that maps traffic to RX on interface
1218 # by injecting the packet in on pg0, which is in table 0
1219 # doing an interface-rx on pg1 and matching a route in table 1
1220 # if the packet egresses, then we must have swapped to pg1
1221 # so as to have matched the route in table 1
1223 route_34_eos = VppMplsRoute(
1225 [VppRoutePath("0.0.0.0",
1226 self.pg1.sw_if_index,
1227 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1228 route_34_eos.add_vpp_config()
1231 # ping an interface in the default table
1232 # PG0 is in the default table
1234 tx = self.create_stream_labelled_ip4(self.pg0,
1237 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1238 self.verify_capture_ip4(self.pg1, rx, tx)
1240 def test_mcast_mid_point(self):
1241 """ MPLS Multicast Mid Point """
1244 # Add a non-recursive route that will forward the traffic
1247 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1249 paths=[VppRoutePath(self.pg1.remote_ip4,
1250 self.pg1.sw_if_index)])
1251 route_10_0_0_1.add_vpp_config()
1254 # Add a mcast entry that replicate to pg2 and pg3
1255 # and replicate to a interface-rx (like a bud node would)
1257 route_3400_eos = VppMplsRoute(
1259 [VppRoutePath(self.pg2.remote_ip4,
1260 self.pg2.sw_if_index,
1261 labels=[VppMplsLabel(3401)]),
1262 VppRoutePath(self.pg3.remote_ip4,
1263 self.pg3.sw_if_index,
1264 labels=[VppMplsLabel(3402)]),
1265 VppRoutePath("0.0.0.0",
1266 self.pg1.sw_if_index,
1267 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1269 route_3400_eos.add_vpp_config()
1272 # ping an interface in the default table
1273 # PG0 is in the default table
1275 self.vapi.cli("clear trace")
1276 tx = self.create_stream_labelled_ip4(self.pg0,
1277 [VppMplsLabel(3400, ttl=64)],
1280 self.pg0.add_stream(tx)
1282 self.pg_enable_capture(self.pg_interfaces)
1285 rx = self.pg1.get_capture(257)
1286 self.verify_capture_ip4(self.pg1, rx, tx)
1288 rx = self.pg2.get_capture(257)
1289 self.verify_capture_labelled(self.pg2, rx, tx,
1290 [VppMplsLabel(3401, ttl=63)])
1291 rx = self.pg3.get_capture(257)
1292 self.verify_capture_labelled(self.pg3, rx, tx,
1293 [VppMplsLabel(3402, ttl=63)])
1295 def test_mcast_head(self):
1296 """ MPLS Multicast Head-end """
1298 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1299 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1302 # Create a multicast tunnel with two replications
1304 mpls_tun = VppMPLSTunnelInterface(
1306 [VppRoutePath(self.pg2.remote_ip4,
1307 self.pg2.sw_if_index,
1308 labels=[VppMplsLabel(42)]),
1309 VppRoutePath(self.pg3.remote_ip4,
1310 self.pg3.sw_if_index,
1311 labels=[VppMplsLabel(43)])],
1313 mpls_tun.add_vpp_config()
1317 # add an unlabelled route through the new tunnel
1319 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1320 [VppRoutePath("0.0.0.0",
1321 mpls_tun._sw_if_index)])
1322 route_10_0_0_3.add_vpp_config()
1324 self.vapi.cli("clear trace")
1325 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1326 self.pg0.add_stream(tx)
1328 self.pg_enable_capture(self.pg_interfaces)
1331 rx = self.pg2.get_capture(257)
1332 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1333 rx = self.pg3.get_capture(257)
1334 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1337 # An an IP multicast route via the tunnel
1339 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1341 route_232_1_1_1 = VppIpMRoute(
1345 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1346 [VppMRoutePath(self.pg0.sw_if_index,
1347 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT),
1348 VppMRoutePath(mpls_tun._sw_if_index,
1349 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1350 route_232_1_1_1.add_vpp_config()
1351 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1353 self.vapi.cli("clear trace")
1354 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1355 self.pg0.add_stream(tx)
1357 self.pg_enable_capture(self.pg_interfaces)
1360 rx = self.pg2.get_capture(257)
1361 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1362 rx = self.pg3.get_capture(257)
1363 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1365 def test_mcast_ip4_tail(self):
1366 """ MPLS IPv4 Multicast Tail """
1368 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1369 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1372 # Add a multicast route that will forward the traffic
1375 route_232_1_1_1 = VppIpMRoute(
1379 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1381 paths=[VppMRoutePath(self.pg1.sw_if_index,
1382 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1383 route_232_1_1_1.add_vpp_config()
1386 # An interface receive label that maps traffic to RX on interface
1388 # by injecting the packet in on pg0, which is in table 0
1389 # doing an rpf-id and matching a route in table 1
1390 # if the packet egresses, then we must have matched the route in
1393 route_34_eos = VppMplsRoute(
1395 [VppRoutePath("0.0.0.0",
1400 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1402 route_34_eos.add_vpp_config()
1405 # Drop due to interface lookup miss
1407 self.vapi.cli("clear trace")
1408 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1409 dst_ip="232.1.1.1", n=1)
1410 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1413 # set the RPF-ID of the entry to match the input packet's
1415 route_232_1_1_1.update_rpf_id(55)
1416 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1418 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1420 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1421 self.verify_capture_ip4(self.pg1, rx, tx)
1424 # disposed packets have an invalid IPv4 checksum
1426 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1427 dst_ip="232.1.1.1", n=65,
1429 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1432 # set the RPF-ID of the entry to not match the input packet's
1434 route_232_1_1_1.update_rpf_id(56)
1435 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1437 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1439 def test_mcast_ip6_tail(self):
1440 """ MPLS IPv6 Multicast Tail """
1442 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1443 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1446 # Add a multicast route that will forward the traffic
1449 route_ff = VppIpMRoute(
1453 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1455 paths=[VppMRoutePath(self.pg1.sw_if_index,
1456 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1457 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1458 route_ff.add_vpp_config()
1461 # An interface receive label that maps traffic to RX on interface
1463 # by injecting the packet in on pg0, which is in table 0
1464 # doing an rpf-id and matching a route in table 1
1465 # if the packet egresses, then we must have matched the route in
1468 route_34_eos = VppMplsRoute(
1475 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1477 route_34_eos.add_vpp_config()
1480 # Drop due to interface lookup miss
1482 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1484 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1487 # set the RPF-ID of the entry to match the input packet's
1489 route_ff.update_rpf_id(55)
1491 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1493 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1494 self.verify_capture_ip6(self.pg1, rx, tx)
1497 # disposed packets have hop-limit = 1
1499 tx = self.create_stream_labelled_ip6(self.pg0,
1503 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1504 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1507 # set the RPF-ID of the entry to not match the input packet's
1509 route_ff.update_rpf_id(56)
1510 tx = self.create_stream_labelled_ip6(self.pg0,
1513 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1519 # Add a non-recursive route with a single out label
1521 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1522 [VppRoutePath(self.pg0.remote_ip4,
1523 self.pg0.sw_if_index,
1524 labels=[VppMplsLabel(45)])])
1525 route_10_0_0_1.add_vpp_config()
1527 # bind a local label to the route
1528 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1529 binding.add_vpp_config()
1532 # a labelled v6 route that resolves through the v4
1534 route_2001_3 = VppIpRoute(
1535 self, "2001::3", 128,
1536 [VppRoutePath("10.0.0.1",
1538 labels=[VppMplsLabel(32)])])
1539 route_2001_3.add_vpp_config()
1541 tx = self.create_stream_ip6(self.pg0, "2001::3")
1542 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1544 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1549 # and a v4 recursive via the v6
1551 route_20_3 = VppIpRoute(
1552 self, "20.0.0.3", 32,
1553 [VppRoutePath("2001::3",
1555 labels=[VppMplsLabel(99)])])
1556 route_20_3.add_vpp_config()
1558 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1559 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1561 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1566 def test_attached(self):
1567 """ Attach Routes with Local Label """
1570 # test that if a local label is associated with an attached/connected
1571 # prefix, that we can reach hosts in the prefix.
1573 binding = VppMplsIpBind(self, 44,
1574 self.pg0._local_ip4_subnet,
1575 self.pg0.local_ip4_prefix_len)
1576 binding.add_vpp_config()
1578 tx = (Ether(src=self.pg1.remote_mac,
1579 dst=self.pg1.local_mac) /
1580 MPLS(label=44, ttl=64) /
1581 IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) /
1582 UDP(sport=1234, dport=1234) /
1584 rxs = self.send_and_expect(self.pg0, [tx], self.pg0)
1586 # if there's an ARP then the label is linked to the glean
1588 self.assertFalse(rx.haslayer(ARP))
1589 # it should be unicasted to the host
1590 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1591 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1594 class TestMPLSDisabled(VppTestCase):
1595 """ MPLS disabled """
1598 def setUpClass(cls):
1599 super(TestMPLSDisabled, cls).setUpClass()
1602 def tearDownClass(cls):
1603 super(TestMPLSDisabled, cls).tearDownClass()
1606 super(TestMPLSDisabled, self).setUp()
1608 # create 2 pg interfaces
1609 self.create_pg_interfaces(range(2))
1611 self.tbl = VppMplsTable(self, 0)
1612 self.tbl.add_vpp_config()
1614 # PG0 is MPLS enabled
1616 self.pg0.config_ip4()
1617 self.pg0.resolve_arp()
1618 self.pg0.enable_mpls()
1620 # PG 1 is not MPLS enabled
1624 for i in self.pg_interfaces:
1628 self.pg0.disable_mpls()
1629 super(TestMPLSDisabled, self).tearDown()
1631 def test_mpls_disabled(self):
1632 """ MPLS Disabled """
1634 self.logger.info(self.vapi.cli("show mpls interface"))
1635 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1636 self.logger.info(self.vapi.cli("show mpls interface pg0"))
1638 tx = (Ether(src=self.pg1.remote_mac,
1639 dst=self.pg1.local_mac) /
1640 MPLS(label=32, ttl=64) /
1641 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1642 UDP(sport=1234, dport=1234) /
1646 # A simple MPLS xconnect - eos label in label out
1648 route_32_eos = VppMplsRoute(self, 32, 1,
1649 [VppRoutePath(self.pg0.remote_ip4,
1650 self.pg0.sw_if_index,
1652 route_32_eos.add_vpp_config()
1655 # PG1 does not forward IP traffic
1657 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1662 self.pg1.enable_mpls()
1664 self.logger.info(self.vapi.cli("show mpls interface"))
1665 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1668 # Now we get packets through
1670 self.pg1.add_stream(tx)
1671 self.pg_enable_capture(self.pg_interfaces)
1674 rx = self.pg0.get_capture(1)
1679 self.pg1.disable_mpls()
1682 # PG1 does not forward IP traffic
1684 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1685 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1688 class TestMPLSPIC(VppTestCase):
1689 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1692 def setUpClass(cls):
1693 super(TestMPLSPIC, cls).setUpClass()
1696 def tearDownClass(cls):
1697 super(TestMPLSPIC, cls).tearDownClass()
1700 super(TestMPLSPIC, self).setUp()
1702 # create 2 pg interfaces
1703 self.create_pg_interfaces(range(4))
1705 mpls_tbl = VppMplsTable(self, 0)
1706 mpls_tbl.add_vpp_config()
1707 tbl4 = VppIpTable(self, 1)
1708 tbl4.add_vpp_config()
1709 tbl6 = VppIpTable(self, 1, is_ip6=1)
1710 tbl6.add_vpp_config()
1714 self.pg0.config_ip4()
1715 self.pg0.resolve_arp()
1716 self.pg0.enable_mpls()
1719 self.pg1.config_ip4()
1720 self.pg1.resolve_arp()
1721 self.pg1.enable_mpls()
1723 # VRF (customer facing) link
1725 self.pg2.set_table_ip4(1)
1726 self.pg2.config_ip4()
1727 self.pg2.resolve_arp()
1728 self.pg2.set_table_ip6(1)
1729 self.pg2.config_ip6()
1730 self.pg2.resolve_ndp()
1733 self.pg3.set_table_ip4(1)
1734 self.pg3.config_ip4()
1735 self.pg3.resolve_arp()
1736 self.pg3.set_table_ip6(1)
1737 self.pg3.config_ip6()
1738 self.pg3.resolve_ndp()
1741 self.pg0.disable_mpls()
1742 self.pg1.disable_mpls()
1743 for i in self.pg_interfaces:
1749 super(TestMPLSPIC, self).tearDown()
1751 def test_mpls_ibgp_pic(self):
1752 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1754 1) setup many iBGP VPN routes via a pair of iBGP peers.
1755 2) Check EMCP forwarding to these peers
1756 3) withdraw the IGP route to one of these peers.
1757 4) check forwarding continues to the remaining peer
1761 # IGP+LDP core routes
1763 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1764 [VppRoutePath(self.pg0.remote_ip4,
1765 self.pg0.sw_if_index,
1767 core_10_0_0_45.add_vpp_config()
1769 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1770 [VppRoutePath(self.pg1.remote_ip4,
1771 self.pg1.sw_if_index,
1773 core_10_0_0_46.add_vpp_config()
1776 # Lot's of VPN routes. We need more the 64 so VPP will build
1777 # the fast convergence indirection
1781 for ii in range(NUM_PKTS):
1782 dst = "192.168.1.%d" % ii
1783 vpn_routes.append(VppIpRoute(
1789 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1794 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1796 vpn_routes[ii].add_vpp_config()
1798 pkts.append(Ether(dst=self.pg2.local_mac,
1799 src=self.pg2.remote_mac) /
1800 IP(src=self.pg2.remote_ip4, dst=dst) /
1801 UDP(sport=1234, dport=1234) /
1805 # Send the packet stream (one pkt to each VPN route)
1806 # - expect a 50-50 split of the traffic
1808 self.pg2.add_stream(pkts)
1809 self.pg_enable_capture(self.pg_interfaces)
1812 rx0 = self.pg0._get_capture(NUM_PKTS)
1813 rx1 = self.pg1._get_capture(NUM_PKTS)
1815 # not testing the LB hashing algorithm so we're not concerned
1816 # with the split ratio, just as long as neither is 0
1817 self.assertNotEqual(0, len(rx0))
1818 self.assertNotEqual(0, len(rx1))
1819 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1820 "Expected all (%s) packets across both ECMP paths. "
1821 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1824 # use a test CLI command to stop the FIB walk process, this
1825 # will prevent the FIB converging the VPN routes and thus allow
1826 # us to probe the interim (post-fail, pre-converge) state
1828 self.vapi.ppcli("test fib-walk-process disable")
1831 # Withdraw one of the IGP routes
1833 core_10_0_0_46.remove_vpp_config()
1836 # now all packets should be forwarded through the remaining peer
1838 self.vapi.ppcli("clear trace")
1839 self.pg2.add_stream(pkts)
1840 self.pg_enable_capture(self.pg_interfaces)
1843 rx0 = self.pg0.get_capture(NUM_PKTS)
1844 self.assertEqual(len(pkts), len(rx0),
1845 "Expected all (%s) packets across single path. "
1846 "rx0: %s." % (len(pkts), len(rx0)))
1849 # enable the FIB walk process to converge the FIB
1851 self.vapi.ppcli("test fib-walk-process enable")
1854 # packets should still be forwarded through the remaining peer
1856 self.pg2.add_stream(pkts)
1857 self.pg_enable_capture(self.pg_interfaces)
1860 rx0 = self.pg0.get_capture(NUM_PKTS)
1861 self.assertEqual(len(pkts), len(rx0),
1862 "Expected all (%s) packets across single path. "
1863 "rx0: %s." % (len(pkts), len(rx0)))
1866 # Add the IGP route back and we return to load-balancing
1868 core_10_0_0_46.add_vpp_config()
1870 self.pg2.add_stream(pkts)
1871 self.pg_enable_capture(self.pg_interfaces)
1874 rx0 = self.pg0._get_capture(NUM_PKTS)
1875 rx1 = self.pg1._get_capture(NUM_PKTS)
1876 self.assertNotEqual(0, len(rx0))
1877 self.assertNotEqual(0, len(rx1))
1878 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1879 "Expected all (%s) packets across both ECMP paths. "
1880 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1882 def test_mpls_ebgp_pic(self):
1883 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1885 1) setup many eBGP VPN routes via a pair of eBGP peers.
1886 2) Check EMCP forwarding to these peers
1887 3) withdraw one eBGP path - expect LB across remaining eBGP
1891 # Lot's of VPN routes. We need more the 64 so VPP will build
1892 # the fast convergence indirection
1897 for ii in range(NUM_PKTS):
1898 dst = "192.168.1.%d" % ii
1899 local_label = 1600 + ii
1900 vpn_routes.append(VppIpRoute(
1903 self.pg2.remote_ip4,
1906 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1908 self.pg3.remote_ip4,
1911 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1913 vpn_routes[ii].add_vpp_config()
1915 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1917 vpn_bindings[ii].add_vpp_config()
1919 pkts.append(Ether(dst=self.pg0.local_mac,
1920 src=self.pg0.remote_mac) /
1921 MPLS(label=local_label, ttl=64) /
1922 IP(src=self.pg0.remote_ip4, dst=dst) /
1923 UDP(sport=1234, dport=1234) /
1927 # Send the packet stream (one pkt to each VPN route)
1928 # - expect a 50-50 split of the traffic
1930 self.pg0.add_stream(pkts)
1931 self.pg_enable_capture(self.pg_interfaces)
1934 rx0 = self.pg2._get_capture(NUM_PKTS)
1935 rx1 = self.pg3._get_capture(NUM_PKTS)
1937 # not testing the LB hashing algorithm so we're not concerned
1938 # with the split ratio, just as long as neither is 0
1939 self.assertNotEqual(0, len(rx0))
1940 self.assertNotEqual(0, len(rx1))
1941 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1942 "Expected all (%s) packets across both ECMP paths. "
1943 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1946 # use a test CLI command to stop the FIB walk process, this
1947 # will prevent the FIB converging the VPN routes and thus allow
1948 # us to probe the interim (post-fail, pre-converge) state
1950 self.vapi.ppcli("test fib-walk-process disable")
1953 # withdraw the connected prefix on the interface.
1955 self.pg2.unconfig_ip4()
1958 # now all packets should be forwarded through the remaining peer
1960 self.pg0.add_stream(pkts)
1961 self.pg_enable_capture(self.pg_interfaces)
1964 rx0 = self.pg3.get_capture(NUM_PKTS)
1965 self.assertEqual(len(pkts), len(rx0),
1966 "Expected all (%s) packets across single path. "
1967 "rx0: %s." % (len(pkts), len(rx0)))
1970 # enable the FIB walk process to converge the FIB
1972 self.vapi.ppcli("test fib-walk-process enable")
1975 # packets should still be forwarded through the remaining peer
1977 self.pg0.add_stream(pkts)
1978 self.pg_enable_capture(self.pg_interfaces)
1981 rx0 = self.pg3.get_capture(NUM_PKTS)
1982 self.assertEqual(len(pkts), len(rx0),
1983 "Expected all (%s) packets across single path. "
1984 "rx0: %s." % (len(pkts), len(rx0)))
1987 # put the connected routes back
1989 self.pg2.config_ip4()
1990 self.pg2.resolve_arp()
1992 self.pg0.add_stream(pkts)
1993 self.pg_enable_capture(self.pg_interfaces)
1996 rx0 = self.pg2._get_capture(NUM_PKTS)
1997 rx1 = self.pg3._get_capture(NUM_PKTS)
1998 self.assertNotEqual(0, len(rx0))
1999 self.assertNotEqual(0, len(rx1))
2000 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2001 "Expected all (%s) packets across both ECMP paths. "
2002 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2004 def test_mpls_v6_ebgp_pic(self):
2005 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
2007 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
2008 2) Check EMCP forwarding to these peers
2009 3) withdraw one eBGP path - expect LB across remaining eBGP
2013 # Lot's of VPN routes. We need more the 64 so VPP will build
2014 # the fast convergence indirection
2019 for ii in range(NUM_PKTS):
2020 dst = "3000::%d" % ii
2021 local_label = 1600 + ii
2022 vpn_routes.append(VppIpRoute(
2025 self.pg2.remote_ip6,
2028 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
2030 self.pg3.remote_ip6,
2033 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
2035 vpn_routes[ii].add_vpp_config()
2037 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
2039 vpn_bindings[ii].add_vpp_config()
2041 pkts.append(Ether(dst=self.pg0.local_mac,
2042 src=self.pg0.remote_mac) /
2043 MPLS(label=local_label, ttl=64) /
2044 IPv6(src=self.pg0.remote_ip6, dst=dst) /
2045 UDP(sport=1234, dport=1234) /
2047 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2049 self.pg0.add_stream(pkts)
2050 self.pg_enable_capture(self.pg_interfaces)
2053 rx0 = self.pg2._get_capture(NUM_PKTS)
2054 rx1 = self.pg3._get_capture(NUM_PKTS)
2055 self.assertNotEqual(0, len(rx0))
2056 self.assertNotEqual(0, len(rx1))
2057 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2058 "Expected all (%s) packets across both ECMP paths. "
2059 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2062 # use a test CLI command to stop the FIB walk process, this
2063 # will prevent the FIB converging the VPN routes and thus allow
2064 # us to probe the interim (post-fail, pre-converge) state
2066 self.vapi.ppcli("test fib-walk-process disable")
2069 # withdraw the connected prefix on the interface.
2070 # and shutdown the interface so the ND cache is flushed.
2072 self.pg2.unconfig_ip6()
2073 self.pg2.admin_down()
2076 # now all packets should be forwarded through the remaining peer
2078 self.pg0.add_stream(pkts)
2079 self.pg_enable_capture(self.pg_interfaces)
2082 rx0 = self.pg3.get_capture(NUM_PKTS)
2083 self.assertEqual(len(pkts), len(rx0),
2084 "Expected all (%s) packets across single path. "
2085 "rx0: %s." % (len(pkts), len(rx0)))
2088 # enable the FIB walk process to converge the FIB
2090 self.vapi.ppcli("test fib-walk-process enable")
2091 self.pg0.add_stream(pkts)
2092 self.pg_enable_capture(self.pg_interfaces)
2095 rx0 = self.pg3.get_capture(NUM_PKTS)
2096 self.assertEqual(len(pkts), len(rx0),
2097 "Expected all (%s) packets across single path. "
2098 "rx0: %s." % (len(pkts), len(rx0)))
2101 # put the connected routes back
2103 self.logger.info(self.vapi.cli("sh log"))
2105 self.pg2.config_ip6()
2106 self.pg2.resolve_ndp()
2108 self.pg0.add_stream(pkts)
2109 self.pg_enable_capture(self.pg_interfaces)
2112 rx0 = self.pg2._get_capture(NUM_PKTS)
2113 rx1 = self.pg3._get_capture(NUM_PKTS)
2114 self.assertNotEqual(0, len(rx0))
2115 self.assertNotEqual(0, len(rx1))
2116 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2117 "Expected all (%s) packets across both ECMP paths. "
2118 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2121 class TestMPLSL2(VppTestCase):
2125 def setUpClass(cls):
2126 super(TestMPLSL2, cls).setUpClass()
2129 def tearDownClass(cls):
2130 super(TestMPLSL2, cls).tearDownClass()
2133 super(TestMPLSL2, self).setUp()
2135 # create 2 pg interfaces
2136 self.create_pg_interfaces(range(2))
2138 # create the default MPLS table
2140 tbl = VppMplsTable(self, 0)
2141 tbl.add_vpp_config()
2142 self.tables.append(tbl)
2144 # use pg0 as the core facing interface, don't resolve ARP
2146 self.pg0.config_ip4()
2147 self.pg0.enable_mpls()
2149 # use the other 2 for customer facing L2 links
2150 for i in self.pg_interfaces[1:]:
2154 for i in self.pg_interfaces[1:]:
2157 self.pg0.disable_mpls()
2158 self.pg0.unconfig_ip4()
2159 self.pg0.admin_down()
2160 super(TestMPLSL2, self).tearDown()
2162 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2163 capture = verify_filter(capture, sent)
2165 self.assertEqual(len(capture), len(sent))
2167 for i in range(len(capture)):
2171 # the MPLS TTL is 255 since it enters a new tunnel
2172 verify_mpls_stack(self, rx, mpls_labels)
2175 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2177 self.assertEqual(rx_eth.src, tx_eth.src)
2178 self.assertEqual(rx_eth.dst, tx_eth.dst)
2180 def verify_arp_req(self, rx, smac, sip, dip):
2182 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2183 self.assertEqual(ether.src, smac)
2186 self.assertEqual(arp.hwtype, 1)
2187 self.assertEqual(arp.ptype, 0x800)
2188 self.assertEqual(arp.hwlen, 6)
2189 self.assertEqual(arp.plen, 4)
2190 self.assertEqual(arp.op, ARP.who_has)
2191 self.assertEqual(arp.hwsrc, smac)
2192 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2193 self.assertEqual(arp.psrc, sip)
2194 self.assertEqual(arp.pdst, dip)
2196 def test_vpws(self):
2197 """ Virtual Private Wire Service """
2200 # Create an MPLS tunnel that pushes 1 label
2201 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2202 # information is not in the packet, but we test it works anyway
2204 mpls_tun_1 = VppMPLSTunnelInterface(
2206 [VppRoutePath(self.pg0.remote_ip4,
2207 self.pg0.sw_if_index,
2208 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2210 mpls_tun_1.add_vpp_config()
2211 mpls_tun_1.admin_up()
2214 # Create a label entry to for 55 that does L2 input to the tunnel
2216 route_55_eos = VppMplsRoute(
2218 [VppRoutePath("0.0.0.0",
2219 mpls_tun_1.sw_if_index,
2220 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2221 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2222 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2223 route_55_eos.add_vpp_config()
2226 # Cross-connect the tunnel with one of the customers L2 interfaces
2228 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2229 mpls_tun_1.sw_if_index,
2231 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2232 self.pg1.sw_if_index,
2236 # inject a packet from the core
2238 pcore = (Ether(dst=self.pg0.local_mac,
2239 src=self.pg0.remote_mac) /
2240 MPLS(label=55, ttl=64) /
2241 Ether(dst="00:00:de:ad:ba:be",
2242 src="00:00:de:ad:be:ef") /
2243 IP(src="10.10.10.10", dst="11.11.11.11") /
2244 UDP(sport=1234, dport=1234) /
2247 tx0 = pcore * NUM_PKTS
2248 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2249 payload = pcore[MPLS].payload
2251 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2252 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2255 # Inject a packet from the customer/L2 side
2256 # there's no resolved ARP entry so the first packet we see should be
2259 tx1 = pcore[MPLS].payload
2260 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2262 self.verify_arp_req(rx1[0],
2265 self.pg0.remote_ip4)
2268 # resolve the ARP entries and send again
2270 self.pg0.resolve_arp()
2271 tx1 = pcore[MPLS].payload * NUM_PKTS
2272 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2274 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2276 def test_vpls(self):
2277 """ Virtual Private LAN Service """
2279 # we skipped this in the setup
2280 self.pg0.resolve_arp()
2283 # Create a L2 MPLS tunnels
2285 mpls_tun1 = VppMPLSTunnelInterface(
2287 [VppRoutePath(self.pg0.remote_ip4,
2288 self.pg0.sw_if_index,
2289 labels=[VppMplsLabel(42)])],
2291 mpls_tun1.add_vpp_config()
2292 mpls_tun1.admin_up()
2294 mpls_tun2 = VppMPLSTunnelInterface(
2296 [VppRoutePath(self.pg0.remote_ip4,
2297 self.pg0.sw_if_index,
2298 labels=[VppMplsLabel(43)])],
2300 mpls_tun2.add_vpp_config()
2301 mpls_tun2.admin_up()
2304 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2305 # the latter includes a Psuedo Wire Control Word
2307 route_55_eos = VppMplsRoute(
2309 [VppRoutePath("0.0.0.0",
2310 mpls_tun1.sw_if_index,
2311 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2312 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2313 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2315 route_56_eos = VppMplsRoute(
2317 [VppRoutePath("0.0.0.0",
2318 mpls_tun2.sw_if_index,
2319 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2320 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2321 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2322 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2325 route_56_eos.add_vpp_config()
2326 route_55_eos.add_vpp_config()
2328 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2331 # add to tunnel to the customers bridge-domain
2333 self.vapi.sw_interface_set_l2_bridge(
2334 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2335 self.vapi.sw_interface_set_l2_bridge(
2336 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2337 self.vapi.sw_interface_set_l2_bridge(
2338 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2341 # Packet from host on the customer interface to each host
2342 # reachable over the core, and vice-versa
2344 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2345 src="00:00:de:ad:be:ef") /
2346 IP(src="10.10.10.10", dst="11.11.11.11") /
2347 UDP(sport=1234, dport=1234) /
2349 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2350 src="00:00:de:ad:be:ef") /
2351 IP(src="10.10.10.10", dst="11.11.11.12") /
2352 UDP(sport=1234, dport=1234) /
2354 p_core1 = (Ether(dst=self.pg0.local_mac,
2355 src=self.pg0.remote_mac) /
2356 MPLS(label=55, ttl=64) /
2357 Ether(src="00:00:de:ad:ba:b1",
2358 dst="00:00:de:ad:be:ef") /
2359 IP(dst="10.10.10.10", src="11.11.11.11") /
2360 UDP(sport=1234, dport=1234) /
2362 p_core2 = (Ether(dst=self.pg0.local_mac,
2363 src=self.pg0.remote_mac) /
2364 MPLS(label=56, ttl=64) /
2365 Raw(b'\x01' * 4) / # PW CW
2366 Ether(src="00:00:de:ad:ba:b2",
2367 dst="00:00:de:ad:be:ef") /
2368 IP(dst="10.10.10.10", src="11.11.11.12") /
2369 UDP(sport=1234, dport=1234) /
2373 # The BD is learning, so send in one of each packet to learn
2376 # 2 packets due to BD flooding
2377 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2378 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2380 # we've learnt this so expect it be be forwarded not flooded
2381 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2382 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2383 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2385 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2386 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2387 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2390 # now a stream in each direction from each host
2392 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2393 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2396 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2397 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2400 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2401 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2404 # remove interfaces from customers bridge-domain
2406 self.vapi.sw_interface_set_l2_bridge(
2407 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2408 self.vapi.sw_interface_set_l2_bridge(
2409 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2410 self.vapi.sw_interface_set_l2_bridge(
2411 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2414 if __name__ == '__main__':
2415 unittest.main(testRunner=VppTestRunner)