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 tx = (Ether(src=self.pg1.remote_mac,
1598 dst=self.pg1.local_mac) /
1599 MPLS(label=32, ttl=64) /
1600 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1601 UDP(sport=1234, dport=1234) /
1605 # A simple MPLS xconnect - eos label in label out
1607 route_32_eos = VppMplsRoute(self, 32, 1,
1608 [VppRoutePath(self.pg0.remote_ip4,
1609 self.pg0.sw_if_index,
1611 route_32_eos.add_vpp_config()
1614 # PG1 does not forward IP traffic
1616 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1621 self.pg1.enable_mpls()
1624 # Now we get packets through
1626 self.pg1.add_stream(tx)
1627 self.pg_enable_capture(self.pg_interfaces)
1630 rx = self.pg0.get_capture(1)
1635 self.pg1.disable_mpls()
1638 # PG1 does not forward IP traffic
1640 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1641 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1644 class TestMPLSPIC(VppTestCase):
1645 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1648 def setUpClass(cls):
1649 super(TestMPLSPIC, cls).setUpClass()
1652 def tearDownClass(cls):
1653 super(TestMPLSPIC, cls).tearDownClass()
1656 super(TestMPLSPIC, self).setUp()
1658 # create 2 pg interfaces
1659 self.create_pg_interfaces(range(4))
1661 mpls_tbl = VppMplsTable(self, 0)
1662 mpls_tbl.add_vpp_config()
1663 tbl4 = VppIpTable(self, 1)
1664 tbl4.add_vpp_config()
1665 tbl6 = VppIpTable(self, 1, is_ip6=1)
1666 tbl6.add_vpp_config()
1670 self.pg0.config_ip4()
1671 self.pg0.resolve_arp()
1672 self.pg0.enable_mpls()
1675 self.pg1.config_ip4()
1676 self.pg1.resolve_arp()
1677 self.pg1.enable_mpls()
1679 # VRF (customer facing) link
1681 self.pg2.set_table_ip4(1)
1682 self.pg2.config_ip4()
1683 self.pg2.resolve_arp()
1684 self.pg2.set_table_ip6(1)
1685 self.pg2.config_ip6()
1686 self.pg2.resolve_ndp()
1689 self.pg3.set_table_ip4(1)
1690 self.pg3.config_ip4()
1691 self.pg3.resolve_arp()
1692 self.pg3.set_table_ip6(1)
1693 self.pg3.config_ip6()
1694 self.pg3.resolve_ndp()
1697 self.pg0.disable_mpls()
1698 self.pg1.disable_mpls()
1699 for i in self.pg_interfaces:
1705 super(TestMPLSPIC, self).tearDown()
1707 def test_mpls_ibgp_pic(self):
1708 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1710 1) setup many iBGP VPN routes via a pair of iBGP peers.
1711 2) Check EMCP forwarding to these peers
1712 3) withdraw the IGP route to one of these peers.
1713 4) check forwarding continues to the remaining peer
1717 # IGP+LDP core routes
1719 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1720 [VppRoutePath(self.pg0.remote_ip4,
1721 self.pg0.sw_if_index,
1723 core_10_0_0_45.add_vpp_config()
1725 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1726 [VppRoutePath(self.pg1.remote_ip4,
1727 self.pg1.sw_if_index,
1729 core_10_0_0_46.add_vpp_config()
1732 # Lot's of VPN routes. We need more the 64 so VPP will build
1733 # the fast convergence indirection
1737 for ii in range(NUM_PKTS):
1738 dst = "192.168.1.%d" % ii
1739 vpn_routes.append(VppIpRoute(
1745 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1750 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1752 vpn_routes[ii].add_vpp_config()
1754 pkts.append(Ether(dst=self.pg2.local_mac,
1755 src=self.pg2.remote_mac) /
1756 IP(src=self.pg2.remote_ip4, dst=dst) /
1757 UDP(sport=1234, dport=1234) /
1761 # Send the packet stream (one pkt to each VPN route)
1762 # - expect a 50-50 split of the traffic
1764 self.pg2.add_stream(pkts)
1765 self.pg_enable_capture(self.pg_interfaces)
1768 rx0 = self.pg0._get_capture(NUM_PKTS)
1769 rx1 = self.pg1._get_capture(NUM_PKTS)
1771 # not testing the LB hashing algorithm so we're not concerned
1772 # with the split ratio, just as long as neither is 0
1773 self.assertNotEqual(0, len(rx0))
1774 self.assertNotEqual(0, len(rx1))
1775 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1776 "Expected all (%s) packets across both ECMP paths. "
1777 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1780 # use a test CLI command to stop the FIB walk process, this
1781 # will prevent the FIB converging the VPN routes and thus allow
1782 # us to probe the interim (post-fail, pre-converge) state
1784 self.vapi.ppcli("test fib-walk-process disable")
1787 # Withdraw one of the IGP routes
1789 core_10_0_0_46.remove_vpp_config()
1792 # now all packets should be forwarded through the remaining peer
1794 self.vapi.ppcli("clear trace")
1795 self.pg2.add_stream(pkts)
1796 self.pg_enable_capture(self.pg_interfaces)
1799 rx0 = self.pg0.get_capture(NUM_PKTS)
1800 self.assertEqual(len(pkts), len(rx0),
1801 "Expected all (%s) packets across single path. "
1802 "rx0: %s." % (len(pkts), len(rx0)))
1805 # enable the FIB walk process to converge the FIB
1807 self.vapi.ppcli("test fib-walk-process enable")
1810 # packets should still be forwarded through the remaining peer
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 # Add the IGP route back and we return to load-balancing
1824 core_10_0_0_46.add_vpp_config()
1826 self.pg2.add_stream(pkts)
1827 self.pg_enable_capture(self.pg_interfaces)
1830 rx0 = self.pg0._get_capture(NUM_PKTS)
1831 rx1 = self.pg1._get_capture(NUM_PKTS)
1832 self.assertNotEqual(0, len(rx0))
1833 self.assertNotEqual(0, len(rx1))
1834 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1835 "Expected all (%s) packets across both ECMP paths. "
1836 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1838 def test_mpls_ebgp_pic(self):
1839 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1841 1) setup many eBGP VPN routes via a pair of eBGP peers.
1842 2) Check EMCP forwarding to these peers
1843 3) withdraw one eBGP path - expect LB across remaining eBGP
1847 # Lot's of VPN routes. We need more the 64 so VPP will build
1848 # the fast convergence indirection
1853 for ii in range(NUM_PKTS):
1854 dst = "192.168.1.%d" % ii
1855 local_label = 1600 + ii
1856 vpn_routes.append(VppIpRoute(
1859 self.pg2.remote_ip4,
1862 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1864 self.pg3.remote_ip4,
1867 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1869 vpn_routes[ii].add_vpp_config()
1871 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1873 vpn_bindings[ii].add_vpp_config()
1875 pkts.append(Ether(dst=self.pg0.local_mac,
1876 src=self.pg0.remote_mac) /
1877 MPLS(label=local_label, ttl=64) /
1878 IP(src=self.pg0.remote_ip4, dst=dst) /
1879 UDP(sport=1234, dport=1234) /
1883 # Send the packet stream (one pkt to each VPN route)
1884 # - expect a 50-50 split of the traffic
1886 self.pg0.add_stream(pkts)
1887 self.pg_enable_capture(self.pg_interfaces)
1890 rx0 = self.pg2._get_capture(NUM_PKTS)
1891 rx1 = self.pg3._get_capture(NUM_PKTS)
1893 # not testing the LB hashing algorithm so we're not concerned
1894 # with the split ratio, just as long as neither is 0
1895 self.assertNotEqual(0, len(rx0))
1896 self.assertNotEqual(0, len(rx1))
1897 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1898 "Expected all (%s) packets across both ECMP paths. "
1899 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1902 # use a test CLI command to stop the FIB walk process, this
1903 # will prevent the FIB converging the VPN routes and thus allow
1904 # us to probe the interim (post-fail, pre-converge) state
1906 self.vapi.ppcli("test fib-walk-process disable")
1909 # withdraw the connected prefix on the interface.
1911 self.pg2.unconfig_ip4()
1914 # now all packets should be forwarded through the remaining peer
1916 self.pg0.add_stream(pkts)
1917 self.pg_enable_capture(self.pg_interfaces)
1920 rx0 = self.pg3.get_capture(NUM_PKTS)
1921 self.assertEqual(len(pkts), len(rx0),
1922 "Expected all (%s) packets across single path. "
1923 "rx0: %s." % (len(pkts), len(rx0)))
1926 # enable the FIB walk process to converge the FIB
1928 self.vapi.ppcli("test fib-walk-process enable")
1931 # packets should still 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 # put the connected routes back
1945 self.pg2.config_ip4()
1946 self.pg2.resolve_arp()
1948 self.pg0.add_stream(pkts)
1949 self.pg_enable_capture(self.pg_interfaces)
1952 rx0 = self.pg2._get_capture(NUM_PKTS)
1953 rx1 = self.pg3._get_capture(NUM_PKTS)
1954 self.assertNotEqual(0, len(rx0))
1955 self.assertNotEqual(0, len(rx1))
1956 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1957 "Expected all (%s) packets across both ECMP paths. "
1958 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1960 def test_mpls_v6_ebgp_pic(self):
1961 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1963 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1964 2) Check EMCP forwarding to these peers
1965 3) withdraw one eBGP path - expect LB across remaining eBGP
1969 # Lot's of VPN routes. We need more the 64 so VPP will build
1970 # the fast convergence indirection
1975 for ii in range(NUM_PKTS):
1976 dst = "3000::%d" % ii
1977 local_label = 1600 + ii
1978 vpn_routes.append(VppIpRoute(
1981 self.pg2.remote_ip6,
1984 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1986 self.pg3.remote_ip6,
1989 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1991 vpn_routes[ii].add_vpp_config()
1993 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1995 vpn_bindings[ii].add_vpp_config()
1997 pkts.append(Ether(dst=self.pg0.local_mac,
1998 src=self.pg0.remote_mac) /
1999 MPLS(label=local_label, ttl=64) /
2000 IPv6(src=self.pg0.remote_ip6, dst=dst) /
2001 UDP(sport=1234, dport=1234) /
2003 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2005 self.pg0.add_stream(pkts)
2006 self.pg_enable_capture(self.pg_interfaces)
2009 rx0 = self.pg2._get_capture(NUM_PKTS)
2010 rx1 = self.pg3._get_capture(NUM_PKTS)
2011 self.assertNotEqual(0, len(rx0))
2012 self.assertNotEqual(0, len(rx1))
2013 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2014 "Expected all (%s) packets across both ECMP paths. "
2015 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2018 # use a test CLI command to stop the FIB walk process, this
2019 # will prevent the FIB converging the VPN routes and thus allow
2020 # us to probe the interim (post-fail, pre-converge) state
2022 self.vapi.ppcli("test fib-walk-process disable")
2025 # withdraw the connected prefix on the interface.
2026 # and shutdown the interface so the ND cache is flushed.
2028 self.pg2.unconfig_ip6()
2029 self.pg2.admin_down()
2032 # now all packets should be forwarded through the remaining peer
2034 self.pg0.add_stream(pkts)
2035 self.pg_enable_capture(self.pg_interfaces)
2038 rx0 = self.pg3.get_capture(NUM_PKTS)
2039 self.assertEqual(len(pkts), len(rx0),
2040 "Expected all (%s) packets across single path. "
2041 "rx0: %s." % (len(pkts), len(rx0)))
2044 # enable the FIB walk process to converge the FIB
2046 self.vapi.ppcli("test fib-walk-process enable")
2047 self.pg0.add_stream(pkts)
2048 self.pg_enable_capture(self.pg_interfaces)
2051 rx0 = self.pg3.get_capture(NUM_PKTS)
2052 self.assertEqual(len(pkts), len(rx0),
2053 "Expected all (%s) packets across single path. "
2054 "rx0: %s." % (len(pkts), len(rx0)))
2057 # put the connected routes back
2059 self.logger.info(self.vapi.cli("sh log"))
2061 self.pg2.config_ip6()
2062 self.pg2.resolve_ndp()
2064 self.pg0.add_stream(pkts)
2065 self.pg_enable_capture(self.pg_interfaces)
2068 rx0 = self.pg2._get_capture(NUM_PKTS)
2069 rx1 = self.pg3._get_capture(NUM_PKTS)
2070 self.assertNotEqual(0, len(rx0))
2071 self.assertNotEqual(0, len(rx1))
2072 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2073 "Expected all (%s) packets across both ECMP paths. "
2074 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2077 class TestMPLSL2(VppTestCase):
2081 def setUpClass(cls):
2082 super(TestMPLSL2, cls).setUpClass()
2085 def tearDownClass(cls):
2086 super(TestMPLSL2, cls).tearDownClass()
2089 super(TestMPLSL2, self).setUp()
2091 # create 2 pg interfaces
2092 self.create_pg_interfaces(range(2))
2094 # create the default MPLS table
2096 tbl = VppMplsTable(self, 0)
2097 tbl.add_vpp_config()
2098 self.tables.append(tbl)
2100 # use pg0 as the core facing interface, don't resolve ARP
2102 self.pg0.config_ip4()
2103 self.pg0.enable_mpls()
2105 # use the other 2 for customer facing L2 links
2106 for i in self.pg_interfaces[1:]:
2110 for i in self.pg_interfaces[1:]:
2113 self.pg0.disable_mpls()
2114 self.pg0.unconfig_ip4()
2115 self.pg0.admin_down()
2116 super(TestMPLSL2, self).tearDown()
2118 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2119 capture = verify_filter(capture, sent)
2121 self.assertEqual(len(capture), len(sent))
2123 for i in range(len(capture)):
2127 # the MPLS TTL is 255 since it enters a new tunnel
2128 verify_mpls_stack(self, rx, mpls_labels)
2131 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2133 self.assertEqual(rx_eth.src, tx_eth.src)
2134 self.assertEqual(rx_eth.dst, tx_eth.dst)
2136 def verify_arp_req(self, rx, smac, sip, dip):
2138 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2139 self.assertEqual(ether.src, smac)
2142 self.assertEqual(arp.hwtype, 1)
2143 self.assertEqual(arp.ptype, 0x800)
2144 self.assertEqual(arp.hwlen, 6)
2145 self.assertEqual(arp.plen, 4)
2146 self.assertEqual(arp.op, ARP.who_has)
2147 self.assertEqual(arp.hwsrc, smac)
2148 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2149 self.assertEqual(arp.psrc, sip)
2150 self.assertEqual(arp.pdst, dip)
2152 def test_vpws(self):
2153 """ Virtual Private Wire Service """
2156 # Create an MPLS tunnel that pushes 1 label
2157 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2158 # information is not in the packet, but we test it works anyway
2160 mpls_tun_1 = VppMPLSTunnelInterface(
2162 [VppRoutePath(self.pg0.remote_ip4,
2163 self.pg0.sw_if_index,
2164 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2166 mpls_tun_1.add_vpp_config()
2167 mpls_tun_1.admin_up()
2170 # Create a label entry to for 55 that does L2 input to the tunnel
2172 route_55_eos = VppMplsRoute(
2174 [VppRoutePath("0.0.0.0",
2175 mpls_tun_1.sw_if_index,
2176 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2177 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2178 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2179 route_55_eos.add_vpp_config()
2182 # Cross-connect the tunnel with one of the customers L2 interfaces
2184 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2185 mpls_tun_1.sw_if_index,
2187 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2188 self.pg1.sw_if_index,
2192 # inject a packet from the core
2194 pcore = (Ether(dst=self.pg0.local_mac,
2195 src=self.pg0.remote_mac) /
2196 MPLS(label=55, ttl=64) /
2197 Ether(dst="00:00:de:ad:ba:be",
2198 src="00:00:de:ad:be:ef") /
2199 IP(src="10.10.10.10", dst="11.11.11.11") /
2200 UDP(sport=1234, dport=1234) /
2203 tx0 = pcore * NUM_PKTS
2204 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2205 payload = pcore[MPLS].payload
2207 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2208 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2211 # Inject a packet from the customer/L2 side
2212 # there's no resolved ARP entry so the first packet we see should be
2215 tx1 = pcore[MPLS].payload
2216 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2218 self.verify_arp_req(rx1[0],
2221 self.pg0.remote_ip4)
2224 # resolve the ARP entries and send again
2226 self.pg0.resolve_arp()
2227 tx1 = pcore[MPLS].payload * NUM_PKTS
2228 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2230 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2232 def test_vpls(self):
2233 """ Virtual Private LAN Service """
2235 # we skipped this in the setup
2236 self.pg0.resolve_arp()
2239 # Create a L2 MPLS tunnels
2241 mpls_tun1 = VppMPLSTunnelInterface(
2243 [VppRoutePath(self.pg0.remote_ip4,
2244 self.pg0.sw_if_index,
2245 labels=[VppMplsLabel(42)])],
2247 mpls_tun1.add_vpp_config()
2248 mpls_tun1.admin_up()
2250 mpls_tun2 = VppMPLSTunnelInterface(
2252 [VppRoutePath(self.pg0.remote_ip4,
2253 self.pg0.sw_if_index,
2254 labels=[VppMplsLabel(43)])],
2256 mpls_tun2.add_vpp_config()
2257 mpls_tun2.admin_up()
2260 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2261 # the latter includes a Psuedo Wire Control Word
2263 route_55_eos = VppMplsRoute(
2265 [VppRoutePath("0.0.0.0",
2266 mpls_tun1.sw_if_index,
2267 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2268 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2269 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2271 route_56_eos = VppMplsRoute(
2273 [VppRoutePath("0.0.0.0",
2274 mpls_tun2.sw_if_index,
2275 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2276 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2277 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2278 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2281 route_56_eos.add_vpp_config()
2282 route_55_eos.add_vpp_config()
2284 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2287 # add to tunnel to the customers bridge-domain
2289 self.vapi.sw_interface_set_l2_bridge(
2290 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2291 self.vapi.sw_interface_set_l2_bridge(
2292 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2293 self.vapi.sw_interface_set_l2_bridge(
2294 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2297 # Packet from host on the customer interface to each host
2298 # reachable over the core, and vice-versa
2300 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2301 src="00:00:de:ad:be:ef") /
2302 IP(src="10.10.10.10", dst="11.11.11.11") /
2303 UDP(sport=1234, dport=1234) /
2305 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2306 src="00:00:de:ad:be:ef") /
2307 IP(src="10.10.10.10", dst="11.11.11.12") /
2308 UDP(sport=1234, dport=1234) /
2310 p_core1 = (Ether(dst=self.pg0.local_mac,
2311 src=self.pg0.remote_mac) /
2312 MPLS(label=55, ttl=64) /
2313 Ether(src="00:00:de:ad:ba:b1",
2314 dst="00:00:de:ad:be:ef") /
2315 IP(dst="10.10.10.10", src="11.11.11.11") /
2316 UDP(sport=1234, dport=1234) /
2318 p_core2 = (Ether(dst=self.pg0.local_mac,
2319 src=self.pg0.remote_mac) /
2320 MPLS(label=56, ttl=64) /
2321 Raw(b'\x01' * 4) / # PW CW
2322 Ether(src="00:00:de:ad:ba:b2",
2323 dst="00:00:de:ad:be:ef") /
2324 IP(dst="10.10.10.10", src="11.11.11.12") /
2325 UDP(sport=1234, dport=1234) /
2329 # The BD is learning, so send in one of each packet to learn
2332 # 2 packets due to BD flooding
2333 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2334 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2336 # we've learnt this so expect it be be forwarded not flooded
2337 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2338 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2339 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2341 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2342 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2343 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2346 # now a stream in each direction from each host
2348 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2349 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2352 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2353 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2356 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2357 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2360 # remove interfaces from customers bridge-domain
2362 self.vapi.sw_interface_set_l2_bridge(
2363 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2364 self.vapi.sw_interface_set_l2_bridge(
2365 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2366 self.vapi.sw_interface_set_l2_bridge(
2367 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2370 if __name__ == '__main__':
2371 unittest.main(testRunner=VppTestRunner)