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,
1567 class TestMPLSDisabled(VppTestCase):
1568 """ MPLS disabled """
1571 def setUpClass(cls):
1572 super(TestMPLSDisabled, cls).setUpClass()
1575 def tearDownClass(cls):
1576 super(TestMPLSDisabled, cls).tearDownClass()
1579 super(TestMPLSDisabled, self).setUp()
1581 # create 2 pg interfaces
1582 self.create_pg_interfaces(range(2))
1584 self.tbl = VppMplsTable(self, 0)
1585 self.tbl.add_vpp_config()
1587 # PG0 is MPLS enabled
1589 self.pg0.config_ip4()
1590 self.pg0.resolve_arp()
1591 self.pg0.enable_mpls()
1593 # PG 1 is not MPLS enabled
1597 for i in self.pg_interfaces:
1601 self.pg0.disable_mpls()
1602 super(TestMPLSDisabled, self).tearDown()
1604 def test_mpls_disabled(self):
1605 """ MPLS Disabled """
1607 self.logger.info(self.vapi.cli("show mpls interface"))
1608 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1609 self.logger.info(self.vapi.cli("show mpls interface pg0"))
1611 tx = (Ether(src=self.pg1.remote_mac,
1612 dst=self.pg1.local_mac) /
1613 MPLS(label=32, ttl=64) /
1614 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1615 UDP(sport=1234, dport=1234) /
1619 # A simple MPLS xconnect - eos label in label out
1621 route_32_eos = VppMplsRoute(self, 32, 1,
1622 [VppRoutePath(self.pg0.remote_ip4,
1623 self.pg0.sw_if_index,
1625 route_32_eos.add_vpp_config()
1628 # PG1 does not forward IP traffic
1630 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1635 self.pg1.enable_mpls()
1637 self.logger.info(self.vapi.cli("show mpls interface"))
1638 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1641 # Now we get packets through
1643 self.pg1.add_stream(tx)
1644 self.pg_enable_capture(self.pg_interfaces)
1647 rx = self.pg0.get_capture(1)
1652 self.pg1.disable_mpls()
1655 # PG1 does not forward IP traffic
1657 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1658 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1661 class TestMPLSPIC(VppTestCase):
1662 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1665 def setUpClass(cls):
1666 super(TestMPLSPIC, cls).setUpClass()
1669 def tearDownClass(cls):
1670 super(TestMPLSPIC, cls).tearDownClass()
1673 super(TestMPLSPIC, self).setUp()
1675 # create 2 pg interfaces
1676 self.create_pg_interfaces(range(4))
1678 mpls_tbl = VppMplsTable(self, 0)
1679 mpls_tbl.add_vpp_config()
1680 tbl4 = VppIpTable(self, 1)
1681 tbl4.add_vpp_config()
1682 tbl6 = VppIpTable(self, 1, is_ip6=1)
1683 tbl6.add_vpp_config()
1687 self.pg0.config_ip4()
1688 self.pg0.resolve_arp()
1689 self.pg0.enable_mpls()
1692 self.pg1.config_ip4()
1693 self.pg1.resolve_arp()
1694 self.pg1.enable_mpls()
1696 # VRF (customer facing) link
1698 self.pg2.set_table_ip4(1)
1699 self.pg2.config_ip4()
1700 self.pg2.resolve_arp()
1701 self.pg2.set_table_ip6(1)
1702 self.pg2.config_ip6()
1703 self.pg2.resolve_ndp()
1706 self.pg3.set_table_ip4(1)
1707 self.pg3.config_ip4()
1708 self.pg3.resolve_arp()
1709 self.pg3.set_table_ip6(1)
1710 self.pg3.config_ip6()
1711 self.pg3.resolve_ndp()
1714 self.pg0.disable_mpls()
1715 self.pg1.disable_mpls()
1716 for i in self.pg_interfaces:
1722 super(TestMPLSPIC, self).tearDown()
1724 def test_mpls_ibgp_pic(self):
1725 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1727 1) setup many iBGP VPN routes via a pair of iBGP peers.
1728 2) Check EMCP forwarding to these peers
1729 3) withdraw the IGP route to one of these peers.
1730 4) check forwarding continues to the remaining peer
1734 # IGP+LDP core routes
1736 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1737 [VppRoutePath(self.pg0.remote_ip4,
1738 self.pg0.sw_if_index,
1740 core_10_0_0_45.add_vpp_config()
1742 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1743 [VppRoutePath(self.pg1.remote_ip4,
1744 self.pg1.sw_if_index,
1746 core_10_0_0_46.add_vpp_config()
1749 # Lot's of VPN routes. We need more the 64 so VPP will build
1750 # the fast convergence indirection
1754 for ii in range(NUM_PKTS):
1755 dst = "192.168.1.%d" % ii
1756 vpn_routes.append(VppIpRoute(
1762 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1767 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1769 vpn_routes[ii].add_vpp_config()
1771 pkts.append(Ether(dst=self.pg2.local_mac,
1772 src=self.pg2.remote_mac) /
1773 IP(src=self.pg2.remote_ip4, dst=dst) /
1774 UDP(sport=1234, dport=1234) /
1778 # Send the packet stream (one pkt to each VPN route)
1779 # - expect a 50-50 split of the traffic
1781 self.pg2.add_stream(pkts)
1782 self.pg_enable_capture(self.pg_interfaces)
1785 rx0 = self.pg0._get_capture(NUM_PKTS)
1786 rx1 = self.pg1._get_capture(NUM_PKTS)
1788 # not testing the LB hashing algorithm so we're not concerned
1789 # with the split ratio, just as long as neither is 0
1790 self.assertNotEqual(0, len(rx0))
1791 self.assertNotEqual(0, len(rx1))
1792 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1793 "Expected all (%s) packets across both ECMP paths. "
1794 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1797 # use a test CLI command to stop the FIB walk process, this
1798 # will prevent the FIB converging the VPN routes and thus allow
1799 # us to probe the interim (post-fail, pre-converge) state
1801 self.vapi.ppcli("test fib-walk-process disable")
1804 # Withdraw one of the IGP routes
1806 core_10_0_0_46.remove_vpp_config()
1809 # now all packets should be forwarded through the remaining peer
1811 self.vapi.ppcli("clear trace")
1812 self.pg2.add_stream(pkts)
1813 self.pg_enable_capture(self.pg_interfaces)
1816 rx0 = self.pg0.get_capture(NUM_PKTS)
1817 self.assertEqual(len(pkts), len(rx0),
1818 "Expected all (%s) packets across single path. "
1819 "rx0: %s." % (len(pkts), len(rx0)))
1822 # enable the FIB walk process to converge the FIB
1824 self.vapi.ppcli("test fib-walk-process enable")
1827 # packets should still be forwarded through the remaining peer
1829 self.pg2.add_stream(pkts)
1830 self.pg_enable_capture(self.pg_interfaces)
1833 rx0 = self.pg0.get_capture(NUM_PKTS)
1834 self.assertEqual(len(pkts), len(rx0),
1835 "Expected all (%s) packets across single path. "
1836 "rx0: %s." % (len(pkts), len(rx0)))
1839 # Add the IGP route back and we return to load-balancing
1841 core_10_0_0_46.add_vpp_config()
1843 self.pg2.add_stream(pkts)
1844 self.pg_enable_capture(self.pg_interfaces)
1847 rx0 = self.pg0._get_capture(NUM_PKTS)
1848 rx1 = self.pg1._get_capture(NUM_PKTS)
1849 self.assertNotEqual(0, len(rx0))
1850 self.assertNotEqual(0, len(rx1))
1851 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1852 "Expected all (%s) packets across both ECMP paths. "
1853 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1855 def test_mpls_ebgp_pic(self):
1856 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1858 1) setup many eBGP VPN routes via a pair of eBGP peers.
1859 2) Check EMCP forwarding to these peers
1860 3) withdraw one eBGP path - expect LB across remaining eBGP
1864 # Lot's of VPN routes. We need more the 64 so VPP will build
1865 # the fast convergence indirection
1870 for ii in range(NUM_PKTS):
1871 dst = "192.168.1.%d" % ii
1872 local_label = 1600 + ii
1873 vpn_routes.append(VppIpRoute(
1876 self.pg2.remote_ip4,
1879 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1881 self.pg3.remote_ip4,
1884 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1886 vpn_routes[ii].add_vpp_config()
1888 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1890 vpn_bindings[ii].add_vpp_config()
1892 pkts.append(Ether(dst=self.pg0.local_mac,
1893 src=self.pg0.remote_mac) /
1894 MPLS(label=local_label, ttl=64) /
1895 IP(src=self.pg0.remote_ip4, dst=dst) /
1896 UDP(sport=1234, dport=1234) /
1900 # Send the packet stream (one pkt to each VPN route)
1901 # - expect a 50-50 split of the traffic
1903 self.pg0.add_stream(pkts)
1904 self.pg_enable_capture(self.pg_interfaces)
1907 rx0 = self.pg2._get_capture(NUM_PKTS)
1908 rx1 = self.pg3._get_capture(NUM_PKTS)
1910 # not testing the LB hashing algorithm so we're not concerned
1911 # with the split ratio, just as long as neither is 0
1912 self.assertNotEqual(0, len(rx0))
1913 self.assertNotEqual(0, len(rx1))
1914 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1915 "Expected all (%s) packets across both ECMP paths. "
1916 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1919 # use a test CLI command to stop the FIB walk process, this
1920 # will prevent the FIB converging the VPN routes and thus allow
1921 # us to probe the interim (post-fail, pre-converge) state
1923 self.vapi.ppcli("test fib-walk-process disable")
1926 # withdraw the connected prefix on the interface.
1928 self.pg2.unconfig_ip4()
1931 # now all packets should be forwarded through the remaining peer
1933 self.pg0.add_stream(pkts)
1934 self.pg_enable_capture(self.pg_interfaces)
1937 rx0 = self.pg3.get_capture(NUM_PKTS)
1938 self.assertEqual(len(pkts), len(rx0),
1939 "Expected all (%s) packets across single path. "
1940 "rx0: %s." % (len(pkts), len(rx0)))
1943 # enable the FIB walk process to converge the FIB
1945 self.vapi.ppcli("test fib-walk-process enable")
1948 # packets should still be forwarded through the remaining peer
1950 self.pg0.add_stream(pkts)
1951 self.pg_enable_capture(self.pg_interfaces)
1954 rx0 = self.pg3.get_capture(NUM_PKTS)
1955 self.assertEqual(len(pkts), len(rx0),
1956 "Expected all (%s) packets across single path. "
1957 "rx0: %s." % (len(pkts), len(rx0)))
1960 # put the connected routes back
1962 self.pg2.config_ip4()
1963 self.pg2.resolve_arp()
1965 self.pg0.add_stream(pkts)
1966 self.pg_enable_capture(self.pg_interfaces)
1969 rx0 = self.pg2._get_capture(NUM_PKTS)
1970 rx1 = self.pg3._get_capture(NUM_PKTS)
1971 self.assertNotEqual(0, len(rx0))
1972 self.assertNotEqual(0, len(rx1))
1973 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1974 "Expected all (%s) packets across both ECMP paths. "
1975 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1977 def test_mpls_v6_ebgp_pic(self):
1978 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1980 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1981 2) Check EMCP forwarding to these peers
1982 3) withdraw one eBGP path - expect LB across remaining eBGP
1986 # Lot's of VPN routes. We need more the 64 so VPP will build
1987 # the fast convergence indirection
1992 for ii in range(NUM_PKTS):
1993 dst = "3000::%d" % ii
1994 local_label = 1600 + ii
1995 vpn_routes.append(VppIpRoute(
1998 self.pg2.remote_ip6,
2001 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
2003 self.pg3.remote_ip6,
2006 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
2008 vpn_routes[ii].add_vpp_config()
2010 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
2012 vpn_bindings[ii].add_vpp_config()
2014 pkts.append(Ether(dst=self.pg0.local_mac,
2015 src=self.pg0.remote_mac) /
2016 MPLS(label=local_label, ttl=64) /
2017 IPv6(src=self.pg0.remote_ip6, dst=dst) /
2018 UDP(sport=1234, dport=1234) /
2020 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2022 self.pg0.add_stream(pkts)
2023 self.pg_enable_capture(self.pg_interfaces)
2026 rx0 = self.pg2._get_capture(NUM_PKTS)
2027 rx1 = self.pg3._get_capture(NUM_PKTS)
2028 self.assertNotEqual(0, len(rx0))
2029 self.assertNotEqual(0, len(rx1))
2030 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2031 "Expected all (%s) packets across both ECMP paths. "
2032 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2035 # use a test CLI command to stop the FIB walk process, this
2036 # will prevent the FIB converging the VPN routes and thus allow
2037 # us to probe the interim (post-fail, pre-converge) state
2039 self.vapi.ppcli("test fib-walk-process disable")
2042 # withdraw the connected prefix on the interface.
2043 # and shutdown the interface so the ND cache is flushed.
2045 self.pg2.unconfig_ip6()
2046 self.pg2.admin_down()
2049 # now all packets should be forwarded through the remaining peer
2051 self.pg0.add_stream(pkts)
2052 self.pg_enable_capture(self.pg_interfaces)
2055 rx0 = self.pg3.get_capture(NUM_PKTS)
2056 self.assertEqual(len(pkts), len(rx0),
2057 "Expected all (%s) packets across single path. "
2058 "rx0: %s." % (len(pkts), len(rx0)))
2061 # enable the FIB walk process to converge the FIB
2063 self.vapi.ppcli("test fib-walk-process enable")
2064 self.pg0.add_stream(pkts)
2065 self.pg_enable_capture(self.pg_interfaces)
2068 rx0 = self.pg3.get_capture(NUM_PKTS)
2069 self.assertEqual(len(pkts), len(rx0),
2070 "Expected all (%s) packets across single path. "
2071 "rx0: %s." % (len(pkts), len(rx0)))
2074 # put the connected routes back
2076 self.logger.info(self.vapi.cli("sh log"))
2078 self.pg2.config_ip6()
2079 self.pg2.resolve_ndp()
2081 self.pg0.add_stream(pkts)
2082 self.pg_enable_capture(self.pg_interfaces)
2085 rx0 = self.pg2._get_capture(NUM_PKTS)
2086 rx1 = self.pg3._get_capture(NUM_PKTS)
2087 self.assertNotEqual(0, len(rx0))
2088 self.assertNotEqual(0, len(rx1))
2089 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2090 "Expected all (%s) packets across both ECMP paths. "
2091 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2094 class TestMPLSL2(VppTestCase):
2098 def setUpClass(cls):
2099 super(TestMPLSL2, cls).setUpClass()
2102 def tearDownClass(cls):
2103 super(TestMPLSL2, cls).tearDownClass()
2106 super(TestMPLSL2, self).setUp()
2108 # create 2 pg interfaces
2109 self.create_pg_interfaces(range(2))
2111 # create the default MPLS table
2113 tbl = VppMplsTable(self, 0)
2114 tbl.add_vpp_config()
2115 self.tables.append(tbl)
2117 # use pg0 as the core facing interface, don't resolve ARP
2119 self.pg0.config_ip4()
2120 self.pg0.enable_mpls()
2122 # use the other 2 for customer facing L2 links
2123 for i in self.pg_interfaces[1:]:
2127 for i in self.pg_interfaces[1:]:
2130 self.pg0.disable_mpls()
2131 self.pg0.unconfig_ip4()
2132 self.pg0.admin_down()
2133 super(TestMPLSL2, self).tearDown()
2135 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2136 capture = verify_filter(capture, sent)
2138 self.assertEqual(len(capture), len(sent))
2140 for i in range(len(capture)):
2144 # the MPLS TTL is 255 since it enters a new tunnel
2145 verify_mpls_stack(self, rx, mpls_labels)
2148 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2150 self.assertEqual(rx_eth.src, tx_eth.src)
2151 self.assertEqual(rx_eth.dst, tx_eth.dst)
2153 def verify_arp_req(self, rx, smac, sip, dip):
2155 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2156 self.assertEqual(ether.src, smac)
2159 self.assertEqual(arp.hwtype, 1)
2160 self.assertEqual(arp.ptype, 0x800)
2161 self.assertEqual(arp.hwlen, 6)
2162 self.assertEqual(arp.plen, 4)
2163 self.assertEqual(arp.op, ARP.who_has)
2164 self.assertEqual(arp.hwsrc, smac)
2165 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2166 self.assertEqual(arp.psrc, sip)
2167 self.assertEqual(arp.pdst, dip)
2169 def test_vpws(self):
2170 """ Virtual Private Wire Service """
2173 # Create an MPLS tunnel that pushes 1 label
2174 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2175 # information is not in the packet, but we test it works anyway
2177 mpls_tun_1 = VppMPLSTunnelInterface(
2179 [VppRoutePath(self.pg0.remote_ip4,
2180 self.pg0.sw_if_index,
2181 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2183 mpls_tun_1.add_vpp_config()
2184 mpls_tun_1.admin_up()
2187 # Create a label entry to for 55 that does L2 input to the tunnel
2189 route_55_eos = VppMplsRoute(
2191 [VppRoutePath("0.0.0.0",
2192 mpls_tun_1.sw_if_index,
2193 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2194 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2195 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2196 route_55_eos.add_vpp_config()
2199 # Cross-connect the tunnel with one of the customers L2 interfaces
2201 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2202 mpls_tun_1.sw_if_index,
2204 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2205 self.pg1.sw_if_index,
2209 # inject a packet from the core
2211 pcore = (Ether(dst=self.pg0.local_mac,
2212 src=self.pg0.remote_mac) /
2213 MPLS(label=55, ttl=64) /
2214 Ether(dst="00:00:de:ad:ba:be",
2215 src="00:00:de:ad:be:ef") /
2216 IP(src="10.10.10.10", dst="11.11.11.11") /
2217 UDP(sport=1234, dport=1234) /
2220 tx0 = pcore * NUM_PKTS
2221 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2222 payload = pcore[MPLS].payload
2224 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2225 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2228 # Inject a packet from the customer/L2 side
2229 # there's no resolved ARP entry so the first packet we see should be
2232 tx1 = pcore[MPLS].payload
2233 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2235 self.verify_arp_req(rx1[0],
2238 self.pg0.remote_ip4)
2241 # resolve the ARP entries and send again
2243 self.pg0.resolve_arp()
2244 tx1 = pcore[MPLS].payload * NUM_PKTS
2245 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2247 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2249 def test_vpls(self):
2250 """ Virtual Private LAN Service """
2252 # we skipped this in the setup
2253 self.pg0.resolve_arp()
2256 # Create a L2 MPLS tunnels
2258 mpls_tun1 = VppMPLSTunnelInterface(
2260 [VppRoutePath(self.pg0.remote_ip4,
2261 self.pg0.sw_if_index,
2262 labels=[VppMplsLabel(42)])],
2264 mpls_tun1.add_vpp_config()
2265 mpls_tun1.admin_up()
2267 mpls_tun2 = VppMPLSTunnelInterface(
2269 [VppRoutePath(self.pg0.remote_ip4,
2270 self.pg0.sw_if_index,
2271 labels=[VppMplsLabel(43)])],
2273 mpls_tun2.add_vpp_config()
2274 mpls_tun2.admin_up()
2277 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2278 # the latter includes a Psuedo Wire Control Word
2280 route_55_eos = VppMplsRoute(
2282 [VppRoutePath("0.0.0.0",
2283 mpls_tun1.sw_if_index,
2284 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2285 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2286 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2288 route_56_eos = VppMplsRoute(
2290 [VppRoutePath("0.0.0.0",
2291 mpls_tun2.sw_if_index,
2292 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2293 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2294 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2295 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2298 route_56_eos.add_vpp_config()
2299 route_55_eos.add_vpp_config()
2301 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2304 # add to tunnel to the customers bridge-domain
2306 self.vapi.sw_interface_set_l2_bridge(
2307 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2308 self.vapi.sw_interface_set_l2_bridge(
2309 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2310 self.vapi.sw_interface_set_l2_bridge(
2311 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2314 # Packet from host on the customer interface to each host
2315 # reachable over the core, and vice-versa
2317 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2318 src="00:00:de:ad:be:ef") /
2319 IP(src="10.10.10.10", dst="11.11.11.11") /
2320 UDP(sport=1234, dport=1234) /
2322 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2323 src="00:00:de:ad:be:ef") /
2324 IP(src="10.10.10.10", dst="11.11.11.12") /
2325 UDP(sport=1234, dport=1234) /
2327 p_core1 = (Ether(dst=self.pg0.local_mac,
2328 src=self.pg0.remote_mac) /
2329 MPLS(label=55, ttl=64) /
2330 Ether(src="00:00:de:ad:ba:b1",
2331 dst="00:00:de:ad:be:ef") /
2332 IP(dst="10.10.10.10", src="11.11.11.11") /
2333 UDP(sport=1234, dport=1234) /
2335 p_core2 = (Ether(dst=self.pg0.local_mac,
2336 src=self.pg0.remote_mac) /
2337 MPLS(label=56, ttl=64) /
2338 Raw(b'\x01' * 4) / # PW CW
2339 Ether(src="00:00:de:ad:ba:b2",
2340 dst="00:00:de:ad:be:ef") /
2341 IP(dst="10.10.10.10", src="11.11.11.12") /
2342 UDP(sport=1234, dport=1234) /
2346 # The BD is learning, so send in one of each packet to learn
2349 # 2 packets due to BD flooding
2350 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2351 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2353 # we've learnt this so expect it be be forwarded not flooded
2354 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2355 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2356 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2358 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2359 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2360 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2363 # now a stream in each direction from each host
2365 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2366 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2369 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2370 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2373 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2374 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2377 # remove interfaces from customers bridge-domain
2379 self.vapi.sw_interface_set_l2_bridge(
2380 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2381 self.vapi.sw_interface_set_l2_bridge(
2382 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2383 self.vapi.sw_interface_set_l2_bridge(
2384 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2387 if __name__ == '__main__':
2388 unittest.main(testRunner=VppTestRunner)