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(10):
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()
1082 def test_v4_exp_null(self):
1083 """ MPLS V4 Explicit NULL test """
1086 # The first test case has an MPLS TTL of 0
1087 # all packet should be dropped
1089 tx = self.create_stream_labelled_ip4(self.pg0,
1090 [VppMplsLabel(0, ttl=0)])
1091 self.send_and_assert_no_replies(self.pg0, tx,
1092 "MPLS TTL=0 packets forwarded")
1095 # a stream with a non-zero MPLS TTL
1096 # PG0 is in the default table
1098 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1099 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1100 self.verify_capture_ip4(self.pg0, rx, tx)
1103 # a stream with a non-zero MPLS TTL
1105 # we are ensuring the post-pop lookup occurs in the VRF table
1107 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1108 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1109 self.verify_capture_ip4(self.pg1, rx, tx)
1111 def test_v6_exp_null(self):
1112 """ MPLS V6 Explicit NULL test """
1115 # a stream with a non-zero MPLS TTL
1116 # PG0 is in the default table
1118 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1119 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1120 self.verify_capture_ip6(self.pg0, rx, tx)
1123 # a stream with a non-zero MPLS TTL
1125 # we are ensuring the post-pop lookup occurs in the VRF table
1127 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1128 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1129 self.verify_capture_ip6(self.pg0, rx, tx)
1131 def test_deag(self):
1135 # A de-agg route - next-hop lookup in default table
1137 route_34_eos = VppMplsRoute(self, 34, 1,
1138 [VppRoutePath("0.0.0.0",
1141 route_34_eos.add_vpp_config()
1144 # ping an interface in the default table
1145 # PG0 is in the default table
1147 tx = self.create_stream_labelled_ip4(self.pg0,
1151 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1152 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1155 # A de-agg route - next-hop lookup in non-default table
1157 route_35_eos = VppMplsRoute(self, 35, 1,
1158 [VppRoutePath("0.0.0.0",
1161 route_35_eos.add_vpp_config()
1164 # ping an interface in the non-default table
1165 # PG0 is in the default table. packet arrive labelled in the
1166 # default table and egress unlabelled in the non-default
1168 tx = self.create_stream_labelled_ip4(
1169 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1170 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1171 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1176 route_36_neos = VppMplsRoute(self, 36, 0,
1177 [VppRoutePath("0.0.0.0",
1179 route_36_neos.add_vpp_config()
1181 tx = self.create_stream_labelled_ip4(self.pg0,
1184 ping=1, ip_itf=self.pg1)
1185 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1186 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1188 route_36_neos.remove_vpp_config()
1189 route_35_eos.remove_vpp_config()
1190 route_34_eos.remove_vpp_config()
1192 def test_interface_rx(self):
1193 """ MPLS Interface Receive """
1196 # Add a non-recursive route that will forward the traffic
1199 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1201 paths=[VppRoutePath(self.pg1.remote_ip4,
1202 self.pg1.sw_if_index)])
1203 route_10_0_0_1.add_vpp_config()
1206 # An interface receive label that maps traffic to RX on interface
1208 # by injecting the packet in on pg0, which is in table 0
1209 # doing an interface-rx on pg1 and matching a route in table 1
1210 # if the packet egresses, then we must have swapped to pg1
1211 # so as to have matched the route in table 1
1213 route_34_eos = VppMplsRoute(
1215 [VppRoutePath("0.0.0.0",
1216 self.pg1.sw_if_index,
1217 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1218 route_34_eos.add_vpp_config()
1221 # ping an interface in the default table
1222 # PG0 is in the default table
1224 tx = self.create_stream_labelled_ip4(self.pg0,
1227 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1228 self.verify_capture_ip4(self.pg1, rx, tx)
1230 def test_mcast_mid_point(self):
1231 """ MPLS Multicast Mid Point """
1234 # Add a non-recursive route that will forward the traffic
1237 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1239 paths=[VppRoutePath(self.pg1.remote_ip4,
1240 self.pg1.sw_if_index)])
1241 route_10_0_0_1.add_vpp_config()
1244 # Add a mcast entry that replicate to pg2 and pg3
1245 # and replicate to a interface-rx (like a bud node would)
1247 route_3400_eos = VppMplsRoute(
1249 [VppRoutePath(self.pg2.remote_ip4,
1250 self.pg2.sw_if_index,
1251 labels=[VppMplsLabel(3401)]),
1252 VppRoutePath(self.pg3.remote_ip4,
1253 self.pg3.sw_if_index,
1254 labels=[VppMplsLabel(3402)]),
1255 VppRoutePath("0.0.0.0",
1256 self.pg1.sw_if_index,
1257 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1259 route_3400_eos.add_vpp_config()
1262 # ping an interface in the default table
1263 # PG0 is in the default table
1265 self.vapi.cli("clear trace")
1266 tx = self.create_stream_labelled_ip4(self.pg0,
1267 [VppMplsLabel(3400, ttl=64)],
1270 self.pg0.add_stream(tx)
1272 self.pg_enable_capture(self.pg_interfaces)
1275 rx = self.pg1.get_capture(257)
1276 self.verify_capture_ip4(self.pg1, rx, tx)
1278 rx = self.pg2.get_capture(257)
1279 self.verify_capture_labelled(self.pg2, rx, tx,
1280 [VppMplsLabel(3401, ttl=63)])
1281 rx = self.pg3.get_capture(257)
1282 self.verify_capture_labelled(self.pg3, rx, tx,
1283 [VppMplsLabel(3402, ttl=63)])
1285 def test_mcast_head(self):
1286 """ MPLS Multicast Head-end """
1288 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1289 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1292 # Create a multicast tunnel with two replications
1294 mpls_tun = VppMPLSTunnelInterface(
1296 [VppRoutePath(self.pg2.remote_ip4,
1297 self.pg2.sw_if_index,
1298 labels=[VppMplsLabel(42)]),
1299 VppRoutePath(self.pg3.remote_ip4,
1300 self.pg3.sw_if_index,
1301 labels=[VppMplsLabel(43)])],
1303 mpls_tun.add_vpp_config()
1307 # add an unlabelled route through the new tunnel
1309 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1310 [VppRoutePath("0.0.0.0",
1311 mpls_tun._sw_if_index)])
1312 route_10_0_0_3.add_vpp_config()
1314 self.vapi.cli("clear trace")
1315 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1316 self.pg0.add_stream(tx)
1318 self.pg_enable_capture(self.pg_interfaces)
1321 rx = self.pg2.get_capture(257)
1322 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1323 rx = self.pg3.get_capture(257)
1324 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1327 # An an IP multicast route via the tunnel
1329 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1331 route_232_1_1_1 = VppIpMRoute(
1335 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1336 [VppMRoutePath(self.pg0.sw_if_index,
1337 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT),
1338 VppMRoutePath(mpls_tun._sw_if_index,
1339 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1340 route_232_1_1_1.add_vpp_config()
1341 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1343 self.vapi.cli("clear trace")
1344 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1345 self.pg0.add_stream(tx)
1347 self.pg_enable_capture(self.pg_interfaces)
1350 rx = self.pg2.get_capture(257)
1351 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1352 rx = self.pg3.get_capture(257)
1353 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1355 def test_mcast_ip4_tail(self):
1356 """ MPLS IPv4 Multicast Tail """
1358 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1359 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1362 # Add a multicast route that will forward the traffic
1365 route_232_1_1_1 = VppIpMRoute(
1369 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1371 paths=[VppMRoutePath(self.pg1.sw_if_index,
1372 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1373 route_232_1_1_1.add_vpp_config()
1376 # An interface receive label that maps traffic to RX on interface
1378 # by injecting the packet in on pg0, which is in table 0
1379 # doing an rpf-id and matching a route in table 1
1380 # if the packet egresses, then we must have matched the route in
1383 route_34_eos = VppMplsRoute(
1385 [VppRoutePath("0.0.0.0",
1390 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1392 route_34_eos.add_vpp_config()
1395 # Drop due to interface lookup miss
1397 self.vapi.cli("clear trace")
1398 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1399 dst_ip="232.1.1.1", n=1)
1400 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1403 # set the RPF-ID of the entry to match the input packet's
1405 route_232_1_1_1.update_rpf_id(55)
1406 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1408 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1410 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1411 self.verify_capture_ip4(self.pg1, rx, tx)
1414 # disposed packets have an invalid IPv4 checksum
1416 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1417 dst_ip="232.1.1.1", n=65,
1419 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1422 # set the RPF-ID of the entry to not match the input packet's
1424 route_232_1_1_1.update_rpf_id(56)
1425 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1427 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1429 def test_mcast_ip6_tail(self):
1430 """ MPLS IPv6 Multicast Tail """
1432 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1433 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1436 # Add a multicast route that will forward the traffic
1439 route_ff = VppIpMRoute(
1443 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1445 paths=[VppMRoutePath(self.pg1.sw_if_index,
1446 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1447 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1448 route_ff.add_vpp_config()
1451 # An interface receive label that maps traffic to RX on interface
1453 # by injecting the packet in on pg0, which is in table 0
1454 # doing an rpf-id and matching a route in table 1
1455 # if the packet egresses, then we must have matched the route in
1458 route_34_eos = VppMplsRoute(
1465 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1467 route_34_eos.add_vpp_config()
1470 # Drop due to interface lookup miss
1472 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1474 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1477 # set the RPF-ID of the entry to match the input packet's
1479 route_ff.update_rpf_id(55)
1481 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1483 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1484 self.verify_capture_ip6(self.pg1, rx, tx)
1487 # disposed packets have hop-limit = 1
1489 tx = self.create_stream_labelled_ip6(self.pg0,
1493 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1494 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1497 # set the RPF-ID of the entry to not match the input packet's
1499 route_ff.update_rpf_id(56)
1500 tx = self.create_stream_labelled_ip6(self.pg0,
1503 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1509 # Add a non-recursive route with a single out label
1511 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1512 [VppRoutePath(self.pg0.remote_ip4,
1513 self.pg0.sw_if_index,
1514 labels=[VppMplsLabel(45)])])
1515 route_10_0_0_1.add_vpp_config()
1517 # bind a local label to the route
1518 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1519 binding.add_vpp_config()
1522 # a labelled v6 route that resolves through the v4
1524 route_2001_3 = VppIpRoute(
1525 self, "2001::3", 128,
1526 [VppRoutePath("10.0.0.1",
1528 labels=[VppMplsLabel(32)])])
1529 route_2001_3.add_vpp_config()
1531 tx = self.create_stream_ip6(self.pg0, "2001::3")
1532 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1534 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1539 # and a v4 recursive via the v6
1541 route_20_3 = VppIpRoute(
1542 self, "20.0.0.3", 32,
1543 [VppRoutePath("2001::3",
1545 labels=[VppMplsLabel(99)])])
1546 route_20_3.add_vpp_config()
1548 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1549 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1551 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1557 class TestMPLSDisabled(VppTestCase):
1558 """ MPLS disabled """
1561 def setUpClass(cls):
1562 super(TestMPLSDisabled, cls).setUpClass()
1565 def tearDownClass(cls):
1566 super(TestMPLSDisabled, cls).tearDownClass()
1569 super(TestMPLSDisabled, self).setUp()
1571 # create 2 pg interfaces
1572 self.create_pg_interfaces(range(2))
1574 self.tbl = VppMplsTable(self, 0)
1575 self.tbl.add_vpp_config()
1577 # PG0 is MPLS enabled
1579 self.pg0.config_ip4()
1580 self.pg0.resolve_arp()
1581 self.pg0.enable_mpls()
1583 # PG 1 is not MPLS enabled
1587 for i in self.pg_interfaces:
1591 self.pg0.disable_mpls()
1592 super(TestMPLSDisabled, self).tearDown()
1594 def test_mpls_disabled(self):
1595 """ MPLS Disabled """
1597 self.logger.info(self.vapi.cli("show mpls interface"))
1598 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1599 self.logger.info(self.vapi.cli("show mpls interface pg0"))
1601 tx = (Ether(src=self.pg1.remote_mac,
1602 dst=self.pg1.local_mac) /
1603 MPLS(label=32, ttl=64) /
1604 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1605 UDP(sport=1234, dport=1234) /
1609 # A simple MPLS xconnect - eos label in label out
1611 route_32_eos = VppMplsRoute(self, 32, 1,
1612 [VppRoutePath(self.pg0.remote_ip4,
1613 self.pg0.sw_if_index,
1615 route_32_eos.add_vpp_config()
1618 # PG1 does not forward IP traffic
1620 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1625 self.pg1.enable_mpls()
1627 self.logger.info(self.vapi.cli("show mpls interface"))
1628 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1631 # Now we get packets through
1633 self.pg1.add_stream(tx)
1634 self.pg_enable_capture(self.pg_interfaces)
1637 rx = self.pg0.get_capture(1)
1642 self.pg1.disable_mpls()
1645 # PG1 does not forward IP traffic
1647 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1648 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1651 class TestMPLSPIC(VppTestCase):
1652 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1655 def setUpClass(cls):
1656 super(TestMPLSPIC, cls).setUpClass()
1659 def tearDownClass(cls):
1660 super(TestMPLSPIC, cls).tearDownClass()
1663 super(TestMPLSPIC, self).setUp()
1665 # create 2 pg interfaces
1666 self.create_pg_interfaces(range(4))
1668 mpls_tbl = VppMplsTable(self, 0)
1669 mpls_tbl.add_vpp_config()
1670 tbl4 = VppIpTable(self, 1)
1671 tbl4.add_vpp_config()
1672 tbl6 = VppIpTable(self, 1, is_ip6=1)
1673 tbl6.add_vpp_config()
1677 self.pg0.config_ip4()
1678 self.pg0.resolve_arp()
1679 self.pg0.enable_mpls()
1682 self.pg1.config_ip4()
1683 self.pg1.resolve_arp()
1684 self.pg1.enable_mpls()
1686 # VRF (customer facing) link
1688 self.pg2.set_table_ip4(1)
1689 self.pg2.config_ip4()
1690 self.pg2.resolve_arp()
1691 self.pg2.set_table_ip6(1)
1692 self.pg2.config_ip6()
1693 self.pg2.resolve_ndp()
1696 self.pg3.set_table_ip4(1)
1697 self.pg3.config_ip4()
1698 self.pg3.resolve_arp()
1699 self.pg3.set_table_ip6(1)
1700 self.pg3.config_ip6()
1701 self.pg3.resolve_ndp()
1704 self.pg0.disable_mpls()
1705 self.pg1.disable_mpls()
1706 for i in self.pg_interfaces:
1712 super(TestMPLSPIC, self).tearDown()
1714 def test_mpls_ibgp_pic(self):
1715 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1717 1) setup many iBGP VPN routes via a pair of iBGP peers.
1718 2) Check EMCP forwarding to these peers
1719 3) withdraw the IGP route to one of these peers.
1720 4) check forwarding continues to the remaining peer
1724 # IGP+LDP core routes
1726 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1727 [VppRoutePath(self.pg0.remote_ip4,
1728 self.pg0.sw_if_index,
1730 core_10_0_0_45.add_vpp_config()
1732 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1733 [VppRoutePath(self.pg1.remote_ip4,
1734 self.pg1.sw_if_index,
1736 core_10_0_0_46.add_vpp_config()
1739 # Lot's of VPN routes. We need more the 64 so VPP will build
1740 # the fast convergence indirection
1744 for ii in range(NUM_PKTS):
1745 dst = "192.168.1.%d" % ii
1746 vpn_routes.append(VppIpRoute(
1752 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1757 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1759 vpn_routes[ii].add_vpp_config()
1761 pkts.append(Ether(dst=self.pg2.local_mac,
1762 src=self.pg2.remote_mac) /
1763 IP(src=self.pg2.remote_ip4, dst=dst) /
1764 UDP(sport=1234, dport=1234) /
1768 # Send the packet stream (one pkt to each VPN route)
1769 # - expect a 50-50 split of the traffic
1771 self.pg2.add_stream(pkts)
1772 self.pg_enable_capture(self.pg_interfaces)
1775 rx0 = self.pg0._get_capture(NUM_PKTS)
1776 rx1 = self.pg1._get_capture(NUM_PKTS)
1778 # not testing the LB hashing algorithm so we're not concerned
1779 # with the split ratio, just as long as neither is 0
1780 self.assertNotEqual(0, len(rx0))
1781 self.assertNotEqual(0, len(rx1))
1782 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1783 "Expected all (%s) packets across both ECMP paths. "
1784 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1787 # use a test CLI command to stop the FIB walk process, this
1788 # will prevent the FIB converging the VPN routes and thus allow
1789 # us to probe the interim (post-fail, pre-converge) state
1791 self.vapi.ppcli("test fib-walk-process disable")
1794 # Withdraw one of the IGP routes
1796 core_10_0_0_46.remove_vpp_config()
1799 # now all packets should be forwarded through the remaining peer
1801 self.vapi.ppcli("clear trace")
1802 self.pg2.add_stream(pkts)
1803 self.pg_enable_capture(self.pg_interfaces)
1806 rx0 = self.pg0.get_capture(NUM_PKTS)
1807 self.assertEqual(len(pkts), len(rx0),
1808 "Expected all (%s) packets across single path. "
1809 "rx0: %s." % (len(pkts), len(rx0)))
1812 # enable the FIB walk process to converge the FIB
1814 self.vapi.ppcli("test fib-walk-process enable")
1817 # packets should still be forwarded through the remaining peer
1819 self.pg2.add_stream(pkts)
1820 self.pg_enable_capture(self.pg_interfaces)
1823 rx0 = self.pg0.get_capture(NUM_PKTS)
1824 self.assertEqual(len(pkts), len(rx0),
1825 "Expected all (%s) packets across single path. "
1826 "rx0: %s." % (len(pkts), len(rx0)))
1829 # Add the IGP route back and we return to load-balancing
1831 core_10_0_0_46.add_vpp_config()
1833 self.pg2.add_stream(pkts)
1834 self.pg_enable_capture(self.pg_interfaces)
1837 rx0 = self.pg0._get_capture(NUM_PKTS)
1838 rx1 = self.pg1._get_capture(NUM_PKTS)
1839 self.assertNotEqual(0, len(rx0))
1840 self.assertNotEqual(0, len(rx1))
1841 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1842 "Expected all (%s) packets across both ECMP paths. "
1843 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1845 def test_mpls_ebgp_pic(self):
1846 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1848 1) setup many eBGP VPN routes via a pair of eBGP peers.
1849 2) Check EMCP forwarding to these peers
1850 3) withdraw one eBGP path - expect LB across remaining eBGP
1854 # Lot's of VPN routes. We need more the 64 so VPP will build
1855 # the fast convergence indirection
1860 for ii in range(NUM_PKTS):
1861 dst = "192.168.1.%d" % ii
1862 local_label = 1600 + ii
1863 vpn_routes.append(VppIpRoute(
1866 self.pg2.remote_ip4,
1869 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1871 self.pg3.remote_ip4,
1874 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1876 vpn_routes[ii].add_vpp_config()
1878 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1880 vpn_bindings[ii].add_vpp_config()
1882 pkts.append(Ether(dst=self.pg0.local_mac,
1883 src=self.pg0.remote_mac) /
1884 MPLS(label=local_label, ttl=64) /
1885 IP(src=self.pg0.remote_ip4, dst=dst) /
1886 UDP(sport=1234, dport=1234) /
1890 # Send the packet stream (one pkt to each VPN route)
1891 # - expect a 50-50 split of the traffic
1893 self.pg0.add_stream(pkts)
1894 self.pg_enable_capture(self.pg_interfaces)
1897 rx0 = self.pg2._get_capture(NUM_PKTS)
1898 rx1 = self.pg3._get_capture(NUM_PKTS)
1900 # not testing the LB hashing algorithm so we're not concerned
1901 # with the split ratio, just as long as neither is 0
1902 self.assertNotEqual(0, len(rx0))
1903 self.assertNotEqual(0, len(rx1))
1904 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1905 "Expected all (%s) packets across both ECMP paths. "
1906 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1909 # use a test CLI command to stop the FIB walk process, this
1910 # will prevent the FIB converging the VPN routes and thus allow
1911 # us to probe the interim (post-fail, pre-converge) state
1913 self.vapi.ppcli("test fib-walk-process disable")
1916 # withdraw the connected prefix on the interface.
1918 self.pg2.unconfig_ip4()
1921 # now all packets should be forwarded through the remaining peer
1923 self.pg0.add_stream(pkts)
1924 self.pg_enable_capture(self.pg_interfaces)
1927 rx0 = self.pg3.get_capture(NUM_PKTS)
1928 self.assertEqual(len(pkts), len(rx0),
1929 "Expected all (%s) packets across single path. "
1930 "rx0: %s." % (len(pkts), len(rx0)))
1933 # enable the FIB walk process to converge the FIB
1935 self.vapi.ppcli("test fib-walk-process enable")
1938 # packets should still be forwarded through the remaining peer
1940 self.pg0.add_stream(pkts)
1941 self.pg_enable_capture(self.pg_interfaces)
1944 rx0 = self.pg3.get_capture(NUM_PKTS)
1945 self.assertEqual(len(pkts), len(rx0),
1946 "Expected all (%s) packets across single path. "
1947 "rx0: %s." % (len(pkts), len(rx0)))
1950 # put the connected routes back
1952 self.pg2.config_ip4()
1953 self.pg2.resolve_arp()
1955 self.pg0.add_stream(pkts)
1956 self.pg_enable_capture(self.pg_interfaces)
1959 rx0 = self.pg2._get_capture(NUM_PKTS)
1960 rx1 = self.pg3._get_capture(NUM_PKTS)
1961 self.assertNotEqual(0, len(rx0))
1962 self.assertNotEqual(0, len(rx1))
1963 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1964 "Expected all (%s) packets across both ECMP paths. "
1965 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1967 def test_mpls_v6_ebgp_pic(self):
1968 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1970 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1971 2) Check EMCP forwarding to these peers
1972 3) withdraw one eBGP path - expect LB across remaining eBGP
1976 # Lot's of VPN routes. We need more the 64 so VPP will build
1977 # the fast convergence indirection
1982 for ii in range(NUM_PKTS):
1983 dst = "3000::%d" % ii
1984 local_label = 1600 + ii
1985 vpn_routes.append(VppIpRoute(
1988 self.pg2.remote_ip6,
1991 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1993 self.pg3.remote_ip6,
1996 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1998 vpn_routes[ii].add_vpp_config()
2000 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
2002 vpn_bindings[ii].add_vpp_config()
2004 pkts.append(Ether(dst=self.pg0.local_mac,
2005 src=self.pg0.remote_mac) /
2006 MPLS(label=local_label, ttl=64) /
2007 IPv6(src=self.pg0.remote_ip6, dst=dst) /
2008 UDP(sport=1234, dport=1234) /
2010 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2012 self.pg0.add_stream(pkts)
2013 self.pg_enable_capture(self.pg_interfaces)
2016 rx0 = self.pg2._get_capture(NUM_PKTS)
2017 rx1 = self.pg3._get_capture(NUM_PKTS)
2018 self.assertNotEqual(0, len(rx0))
2019 self.assertNotEqual(0, len(rx1))
2020 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2021 "Expected all (%s) packets across both ECMP paths. "
2022 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2025 # use a test CLI command to stop the FIB walk process, this
2026 # will prevent the FIB converging the VPN routes and thus allow
2027 # us to probe the interim (post-fail, pre-converge) state
2029 self.vapi.ppcli("test fib-walk-process disable")
2032 # withdraw the connected prefix on the interface.
2033 # and shutdown the interface so the ND cache is flushed.
2035 self.pg2.unconfig_ip6()
2036 self.pg2.admin_down()
2039 # now all packets should be forwarded through the remaining peer
2041 self.pg0.add_stream(pkts)
2042 self.pg_enable_capture(self.pg_interfaces)
2045 rx0 = self.pg3.get_capture(NUM_PKTS)
2046 self.assertEqual(len(pkts), len(rx0),
2047 "Expected all (%s) packets across single path. "
2048 "rx0: %s." % (len(pkts), len(rx0)))
2051 # enable the FIB walk process to converge the FIB
2053 self.vapi.ppcli("test fib-walk-process enable")
2054 self.pg0.add_stream(pkts)
2055 self.pg_enable_capture(self.pg_interfaces)
2058 rx0 = self.pg3.get_capture(NUM_PKTS)
2059 self.assertEqual(len(pkts), len(rx0),
2060 "Expected all (%s) packets across single path. "
2061 "rx0: %s." % (len(pkts), len(rx0)))
2064 # put the connected routes back
2066 self.logger.info(self.vapi.cli("sh log"))
2068 self.pg2.config_ip6()
2069 self.pg2.resolve_ndp()
2071 self.pg0.add_stream(pkts)
2072 self.pg_enable_capture(self.pg_interfaces)
2075 rx0 = self.pg2._get_capture(NUM_PKTS)
2076 rx1 = self.pg3._get_capture(NUM_PKTS)
2077 self.assertNotEqual(0, len(rx0))
2078 self.assertNotEqual(0, len(rx1))
2079 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2080 "Expected all (%s) packets across both ECMP paths. "
2081 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2084 class TestMPLSL2(VppTestCase):
2088 def setUpClass(cls):
2089 super(TestMPLSL2, cls).setUpClass()
2092 def tearDownClass(cls):
2093 super(TestMPLSL2, cls).tearDownClass()
2096 super(TestMPLSL2, self).setUp()
2098 # create 2 pg interfaces
2099 self.create_pg_interfaces(range(2))
2101 # create the default MPLS table
2103 tbl = VppMplsTable(self, 0)
2104 tbl.add_vpp_config()
2105 self.tables.append(tbl)
2107 # use pg0 as the core facing interface, don't resolve ARP
2109 self.pg0.config_ip4()
2110 self.pg0.enable_mpls()
2112 # use the other 2 for customer facing L2 links
2113 for i in self.pg_interfaces[1:]:
2117 for i in self.pg_interfaces[1:]:
2120 self.pg0.disable_mpls()
2121 self.pg0.unconfig_ip4()
2122 self.pg0.admin_down()
2123 super(TestMPLSL2, self).tearDown()
2125 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2126 capture = verify_filter(capture, sent)
2128 self.assertEqual(len(capture), len(sent))
2130 for i in range(len(capture)):
2134 # the MPLS TTL is 255 since it enters a new tunnel
2135 verify_mpls_stack(self, rx, mpls_labels)
2138 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2140 self.assertEqual(rx_eth.src, tx_eth.src)
2141 self.assertEqual(rx_eth.dst, tx_eth.dst)
2143 def verify_arp_req(self, rx, smac, sip, dip):
2145 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2146 self.assertEqual(ether.src, smac)
2149 self.assertEqual(arp.hwtype, 1)
2150 self.assertEqual(arp.ptype, 0x800)
2151 self.assertEqual(arp.hwlen, 6)
2152 self.assertEqual(arp.plen, 4)
2153 self.assertEqual(arp.op, ARP.who_has)
2154 self.assertEqual(arp.hwsrc, smac)
2155 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2156 self.assertEqual(arp.psrc, sip)
2157 self.assertEqual(arp.pdst, dip)
2159 def test_vpws(self):
2160 """ Virtual Private Wire Service """
2163 # Create an MPLS tunnel that pushes 1 label
2164 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2165 # information is not in the packet, but we test it works anyway
2167 mpls_tun_1 = VppMPLSTunnelInterface(
2169 [VppRoutePath(self.pg0.remote_ip4,
2170 self.pg0.sw_if_index,
2171 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2173 mpls_tun_1.add_vpp_config()
2174 mpls_tun_1.admin_up()
2177 # Create a label entry to for 55 that does L2 input to the tunnel
2179 route_55_eos = VppMplsRoute(
2181 [VppRoutePath("0.0.0.0",
2182 mpls_tun_1.sw_if_index,
2183 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2184 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2185 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2186 route_55_eos.add_vpp_config()
2189 # Cross-connect the tunnel with one of the customers L2 interfaces
2191 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2192 mpls_tun_1.sw_if_index,
2194 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2195 self.pg1.sw_if_index,
2199 # inject a packet from the core
2201 pcore = (Ether(dst=self.pg0.local_mac,
2202 src=self.pg0.remote_mac) /
2203 MPLS(label=55, ttl=64) /
2204 Ether(dst="00:00:de:ad:ba:be",
2205 src="00:00:de:ad:be:ef") /
2206 IP(src="10.10.10.10", dst="11.11.11.11") /
2207 UDP(sport=1234, dport=1234) /
2210 tx0 = pcore * NUM_PKTS
2211 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2212 payload = pcore[MPLS].payload
2214 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2215 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2218 # Inject a packet from the customer/L2 side
2219 # there's no resolved ARP entry so the first packet we see should be
2222 tx1 = pcore[MPLS].payload
2223 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2225 self.verify_arp_req(rx1[0],
2228 self.pg0.remote_ip4)
2231 # resolve the ARP entries and send again
2233 self.pg0.resolve_arp()
2234 tx1 = pcore[MPLS].payload * NUM_PKTS
2235 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2237 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2239 def test_vpls(self):
2240 """ Virtual Private LAN Service """
2242 # we skipped this in the setup
2243 self.pg0.resolve_arp()
2246 # Create a L2 MPLS tunnels
2248 mpls_tun1 = VppMPLSTunnelInterface(
2250 [VppRoutePath(self.pg0.remote_ip4,
2251 self.pg0.sw_if_index,
2252 labels=[VppMplsLabel(42)])],
2254 mpls_tun1.add_vpp_config()
2255 mpls_tun1.admin_up()
2257 mpls_tun2 = VppMPLSTunnelInterface(
2259 [VppRoutePath(self.pg0.remote_ip4,
2260 self.pg0.sw_if_index,
2261 labels=[VppMplsLabel(43)])],
2263 mpls_tun2.add_vpp_config()
2264 mpls_tun2.admin_up()
2267 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2268 # the latter includes a Psuedo Wire Control Word
2270 route_55_eos = VppMplsRoute(
2272 [VppRoutePath("0.0.0.0",
2273 mpls_tun1.sw_if_index,
2274 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2275 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2276 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2278 route_56_eos = VppMplsRoute(
2280 [VppRoutePath("0.0.0.0",
2281 mpls_tun2.sw_if_index,
2282 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2283 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2284 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2285 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2288 route_56_eos.add_vpp_config()
2289 route_55_eos.add_vpp_config()
2291 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2294 # add to tunnel to the customers bridge-domain
2296 self.vapi.sw_interface_set_l2_bridge(
2297 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2298 self.vapi.sw_interface_set_l2_bridge(
2299 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2300 self.vapi.sw_interface_set_l2_bridge(
2301 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2304 # Packet from host on the customer interface to each host
2305 # reachable over the core, and vice-versa
2307 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2308 src="00:00:de:ad:be:ef") /
2309 IP(src="10.10.10.10", dst="11.11.11.11") /
2310 UDP(sport=1234, dport=1234) /
2312 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2313 src="00:00:de:ad:be:ef") /
2314 IP(src="10.10.10.10", dst="11.11.11.12") /
2315 UDP(sport=1234, dport=1234) /
2317 p_core1 = (Ether(dst=self.pg0.local_mac,
2318 src=self.pg0.remote_mac) /
2319 MPLS(label=55, ttl=64) /
2320 Ether(src="00:00:de:ad:ba:b1",
2321 dst="00:00:de:ad:be:ef") /
2322 IP(dst="10.10.10.10", src="11.11.11.11") /
2323 UDP(sport=1234, dport=1234) /
2325 p_core2 = (Ether(dst=self.pg0.local_mac,
2326 src=self.pg0.remote_mac) /
2327 MPLS(label=56, ttl=64) /
2328 Raw(b'\x01' * 4) / # PW CW
2329 Ether(src="00:00:de:ad:ba:b2",
2330 dst="00:00:de:ad:be:ef") /
2331 IP(dst="10.10.10.10", src="11.11.11.12") /
2332 UDP(sport=1234, dport=1234) /
2336 # The BD is learning, so send in one of each packet to learn
2339 # 2 packets due to BD flooding
2340 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2341 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2343 # we've learnt this so expect it be be forwarded not flooded
2344 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2345 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2346 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2348 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2349 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2350 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2353 # now a stream in each direction from each host
2355 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2356 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2359 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2360 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2363 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2364 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2367 # remove interfaces from customers bridge-domain
2369 self.vapi.sw_interface_set_l2_bridge(
2370 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2371 self.vapi.sw_interface_set_l2_bridge(
2372 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2373 self.vapi.sw_interface_set_l2_bridge(
2374 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2377 if __name__ == '__main__':
2378 unittest.main(testRunner=VppTestRunner)