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):
370 self.assertTrue(len(capture) <= len(sent))
372 for i in range(len(capture)):
376 # the rx'd packet has the MPLS label popped
378 self.assertEqual(eth.type, 0x86DD)
383 self.assertEqual(rx_ip.dst, tx_ip.src)
384 # ICMP sourced from the interface's address
385 self.assertEqual(rx_ip.src, src_if.local_ip6)
386 # hop-limit reset to 255 for IMCP packet
387 self.assertEqual(rx_ip.hlim, 255)
389 icmp = rx[ICMPv6TimeExceeded]
394 def verify_capture_fragmented_labelled_ip4(self, src_if, capture, sent,
395 mpls_labels, ip_ttl=None):
397 capture = verify_filter(capture, sent)
399 for i in range(len(capture)):
405 verify_mpls_stack(self, rx, mpls_labels)
407 self.assertEqual(rx_ip.src, tx_ip.src)
408 self.assertEqual(rx_ip.dst, tx_ip.dst)
410 # IP processing post pop has decremented the TTL
411 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
413 self.assertEqual(rx_ip.ttl, ip_ttl)
419 """ MPLS label swap tests """
422 # A simple MPLS xconnect - eos label in label out
424 route_32_eos = VppMplsRoute(self, 32, 1,
425 [VppRoutePath(self.pg0.remote_ip4,
426 self.pg0.sw_if_index,
427 labels=[VppMplsLabel(33)])])
428 route_32_eos.add_vpp_config()
431 find_mpls_route(self, 0, 32, 1,
432 [VppRoutePath(self.pg0.remote_ip4,
433 self.pg0.sw_if_index,
434 labels=[VppMplsLabel(33)])]))
437 # a stream that matches the route for 10.0.0.1
438 # PG0 is in the default table
440 tx = self.create_stream_labelled_ip4(self.pg0,
441 [VppMplsLabel(32, ttl=32, exp=1)])
442 rx = self.send_and_expect(self.pg0, tx, self.pg0)
443 self.verify_capture_labelled(self.pg0, rx, tx,
444 [VppMplsLabel(33, ttl=31, exp=1)])
446 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
449 # A simple MPLS xconnect - non-eos label in label out
451 route_32_neos = VppMplsRoute(self, 32, 0,
452 [VppRoutePath(self.pg0.remote_ip4,
453 self.pg0.sw_if_index,
454 labels=[VppMplsLabel(33)])])
455 route_32_neos.add_vpp_config()
458 # a stream that matches the route for 10.0.0.1
459 # PG0 is in the default table
461 tx = self.create_stream_labelled_ip4(self.pg0,
462 [VppMplsLabel(32, ttl=21, exp=7),
464 rx = self.send_and_expect(self.pg0, tx, self.pg0)
465 self.verify_capture_labelled(self.pg0, rx, tx,
466 [VppMplsLabel(33, ttl=20, exp=7),
468 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
471 # A simple MPLS xconnect - non-eos label in label out, uniform mode
473 route_42_neos = VppMplsRoute(
475 [VppRoutePath(self.pg0.remote_ip4,
476 self.pg0.sw_if_index,
477 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
478 route_42_neos.add_vpp_config()
480 tx = self.create_stream_labelled_ip4(self.pg0,
481 [VppMplsLabel(42, ttl=21, exp=7),
483 rx = self.send_and_expect(self.pg0, tx, self.pg0)
484 self.verify_capture_labelled(self.pg0, rx, tx,
485 [VppMplsLabel(43, ttl=20, exp=7),
489 # An MPLS xconnect - EOS label in IP out
491 route_33_eos = VppMplsRoute(self, 33, 1,
492 [VppRoutePath(self.pg0.remote_ip4,
493 self.pg0.sw_if_index,
495 route_33_eos.add_vpp_config()
497 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
498 rx = self.send_and_expect(self.pg0, tx, self.pg0)
499 self.verify_capture_ip4(self.pg0, rx, tx)
502 # disposed packets have an invalid IPv4 checksum
504 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
505 dst_ip=self.pg0.remote_ip4,
508 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
511 # An MPLS xconnect - EOS label in IP out, uniform mode
513 route_3333_eos = VppMplsRoute(
515 [VppRoutePath(self.pg0.remote_ip4,
516 self.pg0.sw_if_index,
517 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
518 route_3333_eos.add_vpp_config()
520 tx = self.create_stream_labelled_ip4(
522 [VppMplsLabel(3333, ttl=55, exp=3)])
523 rx = self.send_and_expect(self.pg0, tx, self.pg0)
524 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
525 tx = self.create_stream_labelled_ip4(
527 [VppMplsLabel(3333, ttl=66, exp=4)])
528 rx = self.send_and_expect(self.pg0, tx, self.pg0)
529 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
532 # An MPLS xconnect - EOS label in IPv6 out
534 route_333_eos = VppMplsRoute(
536 [VppRoutePath(self.pg0.remote_ip6,
537 self.pg0.sw_if_index,
539 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
540 route_333_eos.add_vpp_config()
542 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
543 rx = self.send_and_expect(self.pg0, tx, self.pg0)
544 self.verify_capture_ip6(self.pg0, rx, tx)
547 # disposed packets have an TTL expired
549 tx = self.create_stream_labelled_ip6(self.pg0,
550 [VppMplsLabel(333, ttl=64)],
551 dst_ip=self.pg1.remote_ip6,
553 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
554 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
557 # An MPLS xconnect - EOS label in IPv6 out w imp-null
559 route_334_eos = VppMplsRoute(
561 [VppRoutePath(self.pg0.remote_ip6,
562 self.pg0.sw_if_index,
563 labels=[VppMplsLabel(3)])],
564 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
565 route_334_eos.add_vpp_config()
567 tx = self.create_stream_labelled_ip6(self.pg0,
568 [VppMplsLabel(334, ttl=64)])
569 rx = self.send_and_expect(self.pg0, tx, self.pg0)
570 self.verify_capture_ip6(self.pg0, rx, tx)
573 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
575 route_335_eos = VppMplsRoute(
577 [VppRoutePath(self.pg0.remote_ip6,
578 self.pg0.sw_if_index,
579 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
580 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
581 route_335_eos.add_vpp_config()
583 tx = self.create_stream_labelled_ip6(
585 [VppMplsLabel(335, ttl=27, exp=4)])
586 rx = self.send_and_expect(self.pg0, tx, self.pg0)
587 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
590 # disposed packets have an TTL expired
592 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
593 dst_ip=self.pg1.remote_ip6,
595 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
596 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
599 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
600 # so this traffic should be dropped.
602 route_33_neos = VppMplsRoute(self, 33, 0,
603 [VppRoutePath(self.pg0.remote_ip4,
604 self.pg0.sw_if_index,
606 route_33_neos.add_vpp_config()
608 tx = self.create_stream_labelled_ip4(self.pg0,
611 self.send_and_assert_no_replies(
613 "MPLS non-EOS packets popped and forwarded")
616 # A recursive EOS x-connect, which resolves through another x-connect
619 route_34_eos = VppMplsRoute(self, 34, 1,
620 [VppRoutePath("0.0.0.0",
623 labels=[VppMplsLabel(44),
625 route_34_eos.add_vpp_config()
626 self.logger.info(self.vapi.cli("sh mpls fib 34"))
628 tx = self.create_stream_labelled_ip4(self.pg0,
629 [VppMplsLabel(34, ttl=3)])
630 rx = self.send_and_expect(self.pg0, tx, self.pg0)
631 self.verify_capture_labelled(self.pg0, rx, tx,
634 VppMplsLabel(45, ttl=2)])
636 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
637 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
640 # A recursive EOS x-connect, which resolves through another x-connect
643 route_35_eos = VppMplsRoute(
645 [VppRoutePath("0.0.0.0",
648 labels=[VppMplsLabel(44)])])
649 route_35_eos.add_vpp_config()
651 tx = self.create_stream_labelled_ip4(self.pg0,
652 [VppMplsLabel(35, ttl=3)])
653 rx = self.send_and_expect(self.pg0, tx, self.pg0)
654 self.verify_capture_labelled(self.pg0, rx, tx,
655 [VppMplsLabel(43, ttl=2),
656 VppMplsLabel(44, ttl=2)])
659 # A recursive non-EOS x-connect, which resolves through another
662 route_34_neos = VppMplsRoute(self, 34, 0,
663 [VppRoutePath("0.0.0.0",
666 labels=[VppMplsLabel(44),
668 route_34_neos.add_vpp_config()
670 tx = self.create_stream_labelled_ip4(self.pg0,
671 [VppMplsLabel(34, ttl=45),
673 rx = self.send_and_expect(self.pg0, tx, self.pg0)
674 # it's the 2nd (counting from 0) label in the stack that is swapped
675 self.verify_capture_labelled(self.pg0, rx, tx,
678 VppMplsLabel(46, ttl=44),
682 # an recursive IP route that resolves through the recursive non-eos
685 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
686 [VppRoutePath("0.0.0.0",
689 labels=[VppMplsLabel(55)])])
690 ip_10_0_0_1.add_vpp_config()
692 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
693 rx = self.send_and_expect(self.pg0, tx, self.pg0)
694 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
699 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
701 ip_10_0_0_1.remove_vpp_config()
702 route_34_neos.remove_vpp_config()
703 route_34_eos.remove_vpp_config()
704 route_33_neos.remove_vpp_config()
705 route_33_eos.remove_vpp_config()
706 route_32_neos.remove_vpp_config()
707 route_32_eos.remove_vpp_config()
710 """ MPLS Local Label Binding test """
713 # Add a non-recursive route with a single out label
715 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
716 [VppRoutePath(self.pg0.remote_ip4,
717 self.pg0.sw_if_index,
718 labels=[VppMplsLabel(45)])])
719 route_10_0_0_1.add_vpp_config()
721 # bind a local label to the route
722 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
723 binding.add_vpp_config()
726 tx = self.create_stream_labelled_ip4(self.pg0,
729 rx = self.send_and_expect(self.pg0, tx, self.pg0)
730 self.verify_capture_labelled(self.pg0, rx, tx,
731 [VppMplsLabel(45, ttl=63),
735 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
736 rx = self.send_and_expect(self.pg0, tx, self.pg0)
737 self.verify_capture_labelled(self.pg0, rx, tx,
738 [VppMplsLabel(45, ttl=63)])
741 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
742 rx = self.send_and_expect(self.pg0, tx, self.pg0)
743 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
748 binding.remove_vpp_config()
749 route_10_0_0_1.remove_vpp_config()
751 def test_imposition(self):
752 """ MPLS label imposition test """
755 # Add a non-recursive route with a single out label
757 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
758 [VppRoutePath(self.pg0.remote_ip4,
759 self.pg0.sw_if_index,
760 labels=[VppMplsLabel(32)])])
761 route_10_0_0_1.add_vpp_config()
764 # a stream that matches the route for 10.0.0.1
765 # PG0 is in the default table
767 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
768 rx = self.send_and_expect(self.pg0, tx, self.pg0)
769 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
772 # Add a non-recursive route with a 3 out labels
774 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
775 [VppRoutePath(self.pg0.remote_ip4,
776 self.pg0.sw_if_index,
777 labels=[VppMplsLabel(32),
780 route_10_0_0_2.add_vpp_config()
782 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
783 ip_ttl=44, ip_dscp=0xff)
784 rx = self.send_and_expect(self.pg0, tx, self.pg0)
785 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
792 # Add a non-recursive route with a single out label in uniform mode
794 route_10_0_0_3 = VppIpRoute(
795 self, "10.0.0.3", 32,
796 [VppRoutePath(self.pg0.remote_ip4,
797 self.pg0.sw_if_index,
798 labels=[VppMplsLabel(32,
799 mode=MplsLspMode.UNIFORM)])])
800 route_10_0_0_3.add_vpp_config()
802 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
803 ip_ttl=54, ip_dscp=0xbe)
804 rx = self.send_and_expect(self.pg0, tx, self.pg0)
805 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
806 [VppMplsLabel(32, ttl=53, exp=5)])
809 # Add a IPv6 non-recursive route with a single out label in
812 route_2001_3 = VppIpRoute(
813 self, "2001::3", 128,
814 [VppRoutePath(self.pg0.remote_ip6,
815 self.pg0.sw_if_index,
816 labels=[VppMplsLabel(32,
817 mode=MplsLspMode.UNIFORM)])])
818 route_2001_3.add_vpp_config()
820 tx = self.create_stream_ip6(self.pg0, "2001::3",
821 ip_ttl=54, ip_dscp=0xbe)
822 rx = self.send_and_expect(self.pg0, tx, self.pg0)
823 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
824 [VppMplsLabel(32, ttl=53, exp=5)])
827 # add a recursive path, with output label, via the 1 label route
829 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
830 [VppRoutePath("10.0.0.1",
832 labels=[VppMplsLabel(44)])])
833 route_11_0_0_1.add_vpp_config()
836 # a stream that matches the route for 11.0.0.1, should pick up
837 # the label stack for 11.0.0.1 and 10.0.0.1
839 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
840 rx = self.send_and_expect(self.pg0, tx, self.pg0)
841 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
845 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
848 # add a recursive path, with 2 labels, via the 3 label route
850 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
851 [VppRoutePath("10.0.0.2",
853 labels=[VppMplsLabel(44),
855 route_11_0_0_2.add_vpp_config()
858 # a stream that matches the route for 11.0.0.1, should pick up
859 # the label stack for 11.0.0.1 and 10.0.0.1
861 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
862 rx = self.send_and_expect(self.pg0, tx, self.pg0)
863 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
870 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
872 rx = self.send_and_expect(self.pg0, tx, self.pg0)
873 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
880 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
885 route_11_0_0_2.remove_vpp_config()
886 route_11_0_0_1.remove_vpp_config()
887 route_10_0_0_2.remove_vpp_config()
888 route_10_0_0_1.remove_vpp_config()
890 def test_imposition_fragmentation(self):
891 """ MPLS label imposition fragmentation test """
894 # Add a ipv4 non-recursive route with a single out label
896 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
897 [VppRoutePath(self.pg0.remote_ip4,
898 self.pg0.sw_if_index,
899 labels=[VppMplsLabel(32)])])
900 route_10_0_0_1.add_vpp_config()
903 # a stream that matches the route for 10.0.0.1
904 # PG0 is in the default table
906 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
907 for i in range(0, 257):
908 self.extend_packet(tx[i], 10000)
911 # 5 fragments per packet (257*5=1285)
913 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
914 self.verify_capture_fragmented_labelled_ip4(self.pg0, rx, tx,
920 route_10_0_0_1.remove_vpp_config()
922 def test_tunnel_pipe(self):
923 """ MPLS Tunnel Tests - Pipe """
926 # Create a tunnel with two out labels
928 mpls_tun = VppMPLSTunnelInterface(
930 [VppRoutePath(self.pg0.remote_ip4,
931 self.pg0.sw_if_index,
932 labels=[VppMplsLabel(44),
934 mpls_tun.add_vpp_config()
938 # add an unlabelled route through the new tunnel
940 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
941 [VppRoutePath("0.0.0.0",
942 mpls_tun._sw_if_index)])
943 route_10_0_0_3.add_vpp_config()
945 self.vapi.cli("clear trace")
946 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
947 self.pg0.add_stream(tx)
949 self.pg_enable_capture(self.pg_interfaces)
952 rx = self.pg0.get_capture()
953 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
958 # add a labelled route through the new tunnel
960 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
961 [VppRoutePath("0.0.0.0",
962 mpls_tun._sw_if_index,
964 route_10_0_0_4.add_vpp_config()
966 self.vapi.cli("clear trace")
967 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
968 self.pg0.add_stream(tx)
970 self.pg_enable_capture(self.pg_interfaces)
973 rx = self.pg0.get_capture()
974 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
977 VppMplsLabel(33, ttl=255)])
980 # change tunnel's MTU to a low value
982 mpls_tun.set_l3_mtu(1200)
984 # send IP into the tunnel to be fragmented
985 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
987 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
993 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
997 # send MPLS into the tunnel to be fragmented
998 tx = self.create_stream_ip4(self.pg0, "10.0.0.4",
1000 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1006 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1009 VppMplsLabel(33, ttl=255)])
1011 def test_tunnel_uniform(self):
1012 """ MPLS Tunnel Tests - Uniform """
1015 # Create a tunnel with a single out label
1016 # The label stack is specified here from outer to inner
1018 mpls_tun = VppMPLSTunnelInterface(
1020 [VppRoutePath(self.pg0.remote_ip4,
1021 self.pg0.sw_if_index,
1022 labels=[VppMplsLabel(44, ttl=32),
1023 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1024 mpls_tun.add_vpp_config()
1028 # add an unlabelled route through the new tunnel
1030 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1031 [VppRoutePath("0.0.0.0",
1032 mpls_tun._sw_if_index)])
1033 route_10_0_0_3.add_vpp_config()
1035 self.vapi.cli("clear trace")
1036 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1037 self.pg0.add_stream(tx)
1039 self.pg_enable_capture(self.pg_interfaces)
1042 rx = self.pg0.get_capture()
1043 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1044 [VppMplsLabel(44, ttl=32),
1045 VppMplsLabel(46, ttl=23)])
1048 # add a labelled route through the new tunnel
1050 route_10_0_0_4 = VppIpRoute(
1051 self, "10.0.0.4", 32,
1052 [VppRoutePath("0.0.0.0",
1053 mpls_tun._sw_if_index,
1054 labels=[VppMplsLabel(33, ttl=47)])])
1055 route_10_0_0_4.add_vpp_config()
1057 self.vapi.cli("clear trace")
1058 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1059 self.pg0.add_stream(tx)
1061 self.pg_enable_capture(self.pg_interfaces)
1064 rx = self.pg0.get_capture()
1065 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1066 [VppMplsLabel(44, ttl=32),
1067 VppMplsLabel(46, ttl=47),
1068 VppMplsLabel(33, ttl=47)])
1070 def test_mpls_tunnel_many(self):
1071 """ MPLS Multiple Tunnels """
1073 for ii in range(100):
1074 mpls_tun = VppMPLSTunnelInterface(
1076 [VppRoutePath(self.pg0.remote_ip4,
1077 self.pg0.sw_if_index,
1078 labels=[VppMplsLabel(44, ttl=32),
1079 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1080 mpls_tun.add_vpp_config()
1082 for ii in range(100):
1083 mpls_tun = VppMPLSTunnelInterface(
1085 [VppRoutePath(self.pg0.remote_ip4,
1086 self.pg0.sw_if_index,
1087 labels=[VppMplsLabel(44, ttl=32),
1088 VppMplsLabel(46, MplsLspMode.UNIFORM)])],
1090 mpls_tun.add_vpp_config()
1093 def test_v4_exp_null(self):
1094 """ MPLS V4 Explicit NULL test """
1097 # The first test case has an MPLS TTL of 0
1098 # all packet should be dropped
1100 tx = self.create_stream_labelled_ip4(self.pg0,
1101 [VppMplsLabel(0, ttl=0)])
1102 self.send_and_assert_no_replies(self.pg0, tx,
1103 "MPLS TTL=0 packets forwarded")
1106 # a stream with a non-zero MPLS TTL
1107 # PG0 is in the default table
1109 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1110 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1111 self.verify_capture_ip4(self.pg0, rx, tx)
1114 # a stream with a non-zero MPLS TTL
1116 # we are ensuring the post-pop lookup occurs in the VRF table
1118 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1119 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1120 self.verify_capture_ip4(self.pg1, rx, tx)
1122 def test_v6_exp_null(self):
1123 """ MPLS V6 Explicit NULL test """
1126 # a stream with a non-zero MPLS TTL
1127 # PG0 is in the default table
1129 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1130 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1131 self.verify_capture_ip6(self.pg0, rx, tx)
1134 # a stream with a non-zero MPLS TTL
1136 # we are ensuring the post-pop lookup occurs in the VRF table
1138 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1139 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1140 self.verify_capture_ip6(self.pg0, rx, tx)
1142 def test_deag(self):
1146 # A de-agg route - next-hop lookup in default table
1148 route_34_eos = VppMplsRoute(self, 34, 1,
1149 [VppRoutePath("0.0.0.0",
1152 route_34_eos.add_vpp_config()
1155 # ping an interface in the default table
1156 # PG0 is in the default table
1158 tx = self.create_stream_labelled_ip4(self.pg0,
1162 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1163 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1166 # A de-agg route - next-hop lookup in non-default table
1168 route_35_eos = VppMplsRoute(self, 35, 1,
1169 [VppRoutePath("0.0.0.0",
1172 route_35_eos.add_vpp_config()
1175 # ping an interface in the non-default table
1176 # PG0 is in the default table. packet arrive labelled in the
1177 # default table and egress unlabelled in the non-default
1179 tx = self.create_stream_labelled_ip4(
1180 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1181 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1182 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1187 route_36_neos = VppMplsRoute(self, 36, 0,
1188 [VppRoutePath("0.0.0.0",
1190 route_36_neos.add_vpp_config()
1192 tx = self.create_stream_labelled_ip4(self.pg0,
1195 ping=1, ip_itf=self.pg1)
1196 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1197 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1199 route_36_neos.remove_vpp_config()
1200 route_35_eos.remove_vpp_config()
1201 route_34_eos.remove_vpp_config()
1203 def test_interface_rx(self):
1204 """ MPLS Interface Receive """
1207 # Add a non-recursive route that will forward the traffic
1210 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1212 paths=[VppRoutePath(self.pg1.remote_ip4,
1213 self.pg1.sw_if_index)])
1214 route_10_0_0_1.add_vpp_config()
1217 # An interface receive label that maps traffic to RX on interface
1219 # by injecting the packet in on pg0, which is in table 0
1220 # doing an interface-rx on pg1 and matching a route in table 1
1221 # if the packet egresses, then we must have swapped to pg1
1222 # so as to have matched the route in table 1
1224 route_34_eos = VppMplsRoute(
1226 [VppRoutePath("0.0.0.0",
1227 self.pg1.sw_if_index,
1228 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1229 route_34_eos.add_vpp_config()
1232 # ping an interface in the default table
1233 # PG0 is in the default table
1235 tx = self.create_stream_labelled_ip4(self.pg0,
1238 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1239 self.verify_capture_ip4(self.pg1, rx, tx)
1241 def test_mcast_mid_point(self):
1242 """ MPLS Multicast Mid Point """
1245 # Add a non-recursive route that will forward the traffic
1248 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1250 paths=[VppRoutePath(self.pg1.remote_ip4,
1251 self.pg1.sw_if_index)])
1252 route_10_0_0_1.add_vpp_config()
1255 # Add a mcast entry that replicate to pg2 and pg3
1256 # and replicate to a interface-rx (like a bud node would)
1258 route_3400_eos = VppMplsRoute(
1260 [VppRoutePath(self.pg2.remote_ip4,
1261 self.pg2.sw_if_index,
1262 labels=[VppMplsLabel(3401)]),
1263 VppRoutePath(self.pg3.remote_ip4,
1264 self.pg3.sw_if_index,
1265 labels=[VppMplsLabel(3402)]),
1266 VppRoutePath("0.0.0.0",
1267 self.pg1.sw_if_index,
1268 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1270 route_3400_eos.add_vpp_config()
1273 # ping an interface in the default table
1274 # PG0 is in the default table
1276 self.vapi.cli("clear trace")
1277 tx = self.create_stream_labelled_ip4(self.pg0,
1278 [VppMplsLabel(3400, ttl=64)],
1281 self.pg0.add_stream(tx)
1283 self.pg_enable_capture(self.pg_interfaces)
1286 rx = self.pg1.get_capture(257)
1287 self.verify_capture_ip4(self.pg1, rx, tx)
1289 rx = self.pg2.get_capture(257)
1290 self.verify_capture_labelled(self.pg2, rx, tx,
1291 [VppMplsLabel(3401, ttl=63)])
1292 rx = self.pg3.get_capture(257)
1293 self.verify_capture_labelled(self.pg3, rx, tx,
1294 [VppMplsLabel(3402, ttl=63)])
1296 def test_mcast_head(self):
1297 """ MPLS Multicast Head-end """
1299 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1300 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1303 # Create a multicast tunnel with two replications
1305 mpls_tun = VppMPLSTunnelInterface(
1307 [VppRoutePath(self.pg2.remote_ip4,
1308 self.pg2.sw_if_index,
1309 labels=[VppMplsLabel(42)]),
1310 VppRoutePath(self.pg3.remote_ip4,
1311 self.pg3.sw_if_index,
1312 labels=[VppMplsLabel(43)])],
1314 mpls_tun.add_vpp_config()
1318 # add an unlabelled route through the new tunnel
1320 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1321 [VppRoutePath("0.0.0.0",
1322 mpls_tun._sw_if_index)])
1323 route_10_0_0_3.add_vpp_config()
1325 self.vapi.cli("clear trace")
1326 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1327 self.pg0.add_stream(tx)
1329 self.pg_enable_capture(self.pg_interfaces)
1332 rx = self.pg2.get_capture(257)
1333 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1334 rx = self.pg3.get_capture(257)
1335 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1338 # An an IP multicast route via the tunnel
1340 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1342 route_232_1_1_1 = VppIpMRoute(
1346 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1347 [VppMRoutePath(self.pg0.sw_if_index,
1348 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT),
1349 VppMRoutePath(mpls_tun._sw_if_index,
1350 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1351 route_232_1_1_1.add_vpp_config()
1352 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1354 self.vapi.cli("clear trace")
1355 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1356 self.pg0.add_stream(tx)
1358 self.pg_enable_capture(self.pg_interfaces)
1361 rx = self.pg2.get_capture(257)
1362 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1363 rx = self.pg3.get_capture(257)
1364 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1366 def test_mcast_ip4_tail(self):
1367 """ MPLS IPv4 Multicast Tail """
1369 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1370 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1373 # Add a multicast route that will forward the traffic
1376 route_232_1_1_1 = VppIpMRoute(
1380 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1382 paths=[VppMRoutePath(self.pg1.sw_if_index,
1383 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1384 route_232_1_1_1.add_vpp_config()
1387 # An interface receive label that maps traffic to RX on interface
1389 # by injecting the packet in on pg0, which is in table 0
1390 # doing an rpf-id and matching a route in table 1
1391 # if the packet egresses, then we must have matched the route in
1394 route_34_eos = VppMplsRoute(
1396 [VppRoutePath("0.0.0.0",
1401 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1403 route_34_eos.add_vpp_config()
1406 # Drop due to interface lookup miss
1408 self.vapi.cli("clear trace")
1409 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1410 dst_ip="232.1.1.1", n=1)
1411 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1414 # set the RPF-ID of the entry to match the input packet's
1416 route_232_1_1_1.update_rpf_id(55)
1417 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1419 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1421 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1422 self.verify_capture_ip4(self.pg1, rx, tx)
1425 # disposed packets have an invalid IPv4 checksum
1427 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1428 dst_ip="232.1.1.1", n=65,
1430 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1433 # set the RPF-ID of the entry to not match the input packet's
1435 route_232_1_1_1.update_rpf_id(56)
1436 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1438 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1440 def test_mcast_ip6_tail(self):
1441 """ MPLS IPv6 Multicast Tail """
1443 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1444 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1447 # Add a multicast route that will forward the traffic
1450 route_ff = VppIpMRoute(
1454 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1456 paths=[VppMRoutePath(self.pg1.sw_if_index,
1457 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1458 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1459 route_ff.add_vpp_config()
1462 # An interface receive label that maps traffic to RX on interface
1464 # by injecting the packet in on pg0, which is in table 0
1465 # doing an rpf-id and matching a route in table 1
1466 # if the packet egresses, then we must have matched the route in
1469 route_34_eos = VppMplsRoute(
1476 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1478 route_34_eos.add_vpp_config()
1481 # Drop due to interface lookup miss
1483 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1485 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1488 # set the RPF-ID of the entry to match the input packet's
1490 route_ff.update_rpf_id(55)
1492 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1494 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1495 self.verify_capture_ip6(self.pg1, rx, tx)
1498 # disposed packets have hop-limit = 1
1500 tx = self.create_stream_labelled_ip6(self.pg0,
1504 rx = self.send_and_expect_some(self.pg0, tx, self.pg0)
1505 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1508 # set the RPF-ID of the entry to not match the input packet's
1510 route_ff.update_rpf_id(56)
1511 tx = self.create_stream_labelled_ip6(self.pg0,
1514 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1520 # Add a non-recursive route with a single out label
1522 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1523 [VppRoutePath(self.pg0.remote_ip4,
1524 self.pg0.sw_if_index,
1525 labels=[VppMplsLabel(45)])])
1526 route_10_0_0_1.add_vpp_config()
1528 # bind a local label to the route
1529 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1530 binding.add_vpp_config()
1533 # a labelled v6 route that resolves through the v4
1535 route_2001_3 = VppIpRoute(
1536 self, "2001::3", 128,
1537 [VppRoutePath("10.0.0.1",
1539 labels=[VppMplsLabel(32)])])
1540 route_2001_3.add_vpp_config()
1542 tx = self.create_stream_ip6(self.pg0, "2001::3")
1543 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1545 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1550 # and a v4 recursive via the v6
1552 route_20_3 = VppIpRoute(
1553 self, "20.0.0.3", 32,
1554 [VppRoutePath("2001::3",
1556 labels=[VppMplsLabel(99)])])
1557 route_20_3.add_vpp_config()
1559 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1560 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1562 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1567 def test_attached(self):
1568 """ Attach Routes with Local Label """
1571 # test that if a local label is associated with an attached/connected
1572 # prefix, that we can reach hosts in the prefix.
1574 binding = VppMplsIpBind(self, 44,
1575 self.pg0._local_ip4_subnet,
1576 self.pg0.local_ip4_prefix_len)
1577 binding.add_vpp_config()
1579 tx = (Ether(src=self.pg1.remote_mac,
1580 dst=self.pg1.local_mac) /
1581 MPLS(label=44, ttl=64) /
1582 IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) /
1583 UDP(sport=1234, dport=1234) /
1585 rxs = self.send_and_expect(self.pg0, [tx], self.pg0)
1587 # if there's an ARP then the label is linked to the glean
1589 self.assertFalse(rx.haslayer(ARP))
1590 # it should be unicasted to the host
1591 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1592 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
1595 class TestMPLSDisabled(VppTestCase):
1596 """ MPLS disabled """
1599 def setUpClass(cls):
1600 super(TestMPLSDisabled, cls).setUpClass()
1603 def tearDownClass(cls):
1604 super(TestMPLSDisabled, cls).tearDownClass()
1607 super(TestMPLSDisabled, self).setUp()
1609 # create 2 pg interfaces
1610 self.create_pg_interfaces(range(2))
1612 self.tbl = VppMplsTable(self, 0)
1613 self.tbl.add_vpp_config()
1615 # PG0 is MPLS enabled
1617 self.pg0.config_ip4()
1618 self.pg0.resolve_arp()
1619 self.pg0.enable_mpls()
1621 # PG 1 is not MPLS enabled
1625 for i in self.pg_interfaces:
1629 self.pg0.disable_mpls()
1630 super(TestMPLSDisabled, self).tearDown()
1632 def test_mpls_disabled(self):
1633 """ MPLS Disabled """
1635 self.logger.info(self.vapi.cli("show mpls interface"))
1636 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1637 self.logger.info(self.vapi.cli("show mpls interface pg0"))
1639 tx = (Ether(src=self.pg1.remote_mac,
1640 dst=self.pg1.local_mac) /
1641 MPLS(label=32, ttl=64) /
1642 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1643 UDP(sport=1234, dport=1234) /
1647 # A simple MPLS xconnect - eos label in label out
1649 route_32_eos = VppMplsRoute(self, 32, 1,
1650 [VppRoutePath(self.pg0.remote_ip4,
1651 self.pg0.sw_if_index,
1653 route_32_eos.add_vpp_config()
1656 # PG1 does not forward IP traffic
1658 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1663 self.pg1.enable_mpls()
1665 self.logger.info(self.vapi.cli("show mpls interface"))
1666 self.logger.info(self.vapi.cli("show mpls interface pg1"))
1669 # Now we get packets through
1671 self.pg1.add_stream(tx)
1672 self.pg_enable_capture(self.pg_interfaces)
1675 rx = self.pg0.get_capture(1)
1680 self.pg1.disable_mpls()
1683 # PG1 does not forward IP traffic
1685 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1686 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1689 class TestMPLSPIC(VppTestCase):
1690 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1693 def setUpClass(cls):
1694 super(TestMPLSPIC, cls).setUpClass()
1697 def tearDownClass(cls):
1698 super(TestMPLSPIC, cls).tearDownClass()
1701 super(TestMPLSPIC, self).setUp()
1703 # create 2 pg interfaces
1704 self.create_pg_interfaces(range(4))
1706 mpls_tbl = VppMplsTable(self, 0)
1707 mpls_tbl.add_vpp_config()
1708 tbl4 = VppIpTable(self, 1)
1709 tbl4.add_vpp_config()
1710 tbl6 = VppIpTable(self, 1, is_ip6=1)
1711 tbl6.add_vpp_config()
1715 self.pg0.config_ip4()
1716 self.pg0.resolve_arp()
1717 self.pg0.enable_mpls()
1720 self.pg1.config_ip4()
1721 self.pg1.resolve_arp()
1722 self.pg1.enable_mpls()
1724 # VRF (customer facing) link
1726 self.pg2.set_table_ip4(1)
1727 self.pg2.config_ip4()
1728 self.pg2.resolve_arp()
1729 self.pg2.set_table_ip6(1)
1730 self.pg2.config_ip6()
1731 self.pg2.resolve_ndp()
1734 self.pg3.set_table_ip4(1)
1735 self.pg3.config_ip4()
1736 self.pg3.resolve_arp()
1737 self.pg3.set_table_ip6(1)
1738 self.pg3.config_ip6()
1739 self.pg3.resolve_ndp()
1742 self.pg0.disable_mpls()
1743 self.pg1.disable_mpls()
1744 for i in self.pg_interfaces:
1750 super(TestMPLSPIC, self).tearDown()
1752 def test_mpls_ibgp_pic(self):
1753 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1755 1) setup many iBGP VPN routes via a pair of iBGP peers.
1756 2) Check EMCP forwarding to these peers
1757 3) withdraw the IGP route to one of these peers.
1758 4) check forwarding continues to the remaining peer
1762 # IGP+LDP core routes
1764 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1765 [VppRoutePath(self.pg0.remote_ip4,
1766 self.pg0.sw_if_index,
1768 core_10_0_0_45.add_vpp_config()
1770 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1771 [VppRoutePath(self.pg1.remote_ip4,
1772 self.pg1.sw_if_index,
1774 core_10_0_0_46.add_vpp_config()
1777 # Lot's of VPN routes. We need more the 64 so VPP will build
1778 # the fast convergence indirection
1782 for ii in range(NUM_PKTS):
1783 dst = "192.168.1.%d" % ii
1784 vpn_routes.append(VppIpRoute(
1790 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1795 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1797 vpn_routes[ii].add_vpp_config()
1799 pkts.append(Ether(dst=self.pg2.local_mac,
1800 src=self.pg2.remote_mac) /
1801 IP(src=self.pg2.remote_ip4, dst=dst) /
1802 UDP(sport=1234, dport=1234) /
1806 # Send the packet stream (one pkt to each VPN route)
1807 # - expect a 50-50 split of the traffic
1809 self.pg2.add_stream(pkts)
1810 self.pg_enable_capture(self.pg_interfaces)
1813 rx0 = self.pg0._get_capture(NUM_PKTS)
1814 rx1 = self.pg1._get_capture(NUM_PKTS)
1816 # not testing the LB hashing algorithm so we're not concerned
1817 # with the split ratio, just as long as neither is 0
1818 self.assertNotEqual(0, len(rx0))
1819 self.assertNotEqual(0, len(rx1))
1820 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1821 "Expected all (%s) packets across both ECMP paths. "
1822 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1825 # use a test CLI command to stop the FIB walk process, this
1826 # will prevent the FIB converging the VPN routes and thus allow
1827 # us to probe the interim (post-fail, pre-converge) state
1829 self.vapi.ppcli("test fib-walk-process disable")
1832 # Withdraw one of the IGP routes
1834 core_10_0_0_46.remove_vpp_config()
1837 # now all packets should be forwarded through the remaining peer
1839 self.vapi.ppcli("clear trace")
1840 self.pg2.add_stream(pkts)
1841 self.pg_enable_capture(self.pg_interfaces)
1844 rx0 = self.pg0.get_capture(NUM_PKTS)
1845 self.assertEqual(len(pkts), len(rx0),
1846 "Expected all (%s) packets across single path. "
1847 "rx0: %s." % (len(pkts), len(rx0)))
1850 # enable the FIB walk process to converge the FIB
1852 self.vapi.ppcli("test fib-walk-process enable")
1855 # packets should still be forwarded through the remaining peer
1857 self.pg2.add_stream(pkts)
1858 self.pg_enable_capture(self.pg_interfaces)
1861 rx0 = self.pg0.get_capture(NUM_PKTS)
1862 self.assertEqual(len(pkts), len(rx0),
1863 "Expected all (%s) packets across single path. "
1864 "rx0: %s." % (len(pkts), len(rx0)))
1867 # Add the IGP route back and we return to load-balancing
1869 core_10_0_0_46.add_vpp_config()
1871 self.pg2.add_stream(pkts)
1872 self.pg_enable_capture(self.pg_interfaces)
1875 rx0 = self.pg0._get_capture(NUM_PKTS)
1876 rx1 = self.pg1._get_capture(NUM_PKTS)
1877 self.assertNotEqual(0, len(rx0))
1878 self.assertNotEqual(0, len(rx1))
1879 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1880 "Expected all (%s) packets across both ECMP paths. "
1881 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1883 def test_mpls_ebgp_pic(self):
1884 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1886 1) setup many eBGP VPN routes via a pair of eBGP peers.
1887 2) Check EMCP forwarding to these peers
1888 3) withdraw one eBGP path - expect LB across remaining eBGP
1892 # Lot's of VPN routes. We need more the 64 so VPP will build
1893 # the fast convergence indirection
1898 for ii in range(NUM_PKTS):
1899 dst = "192.168.1.%d" % ii
1900 local_label = 1600 + ii
1901 vpn_routes.append(VppIpRoute(
1904 self.pg2.remote_ip4,
1907 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1909 self.pg3.remote_ip4,
1912 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1914 vpn_routes[ii].add_vpp_config()
1916 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1918 vpn_bindings[ii].add_vpp_config()
1920 pkts.append(Ether(dst=self.pg0.local_mac,
1921 src=self.pg0.remote_mac) /
1922 MPLS(label=local_label, ttl=64) /
1923 IP(src=self.pg0.remote_ip4, dst=dst) /
1924 UDP(sport=1234, dport=1234) /
1928 # Send the packet stream (one pkt to each VPN route)
1929 # - expect a 50-50 split of the traffic
1931 self.pg0.add_stream(pkts)
1932 self.pg_enable_capture(self.pg_interfaces)
1935 rx0 = self.pg2._get_capture(NUM_PKTS)
1936 rx1 = self.pg3._get_capture(NUM_PKTS)
1938 # not testing the LB hashing algorithm so we're not concerned
1939 # with the split ratio, just as long as neither is 0
1940 self.assertNotEqual(0, len(rx0))
1941 self.assertNotEqual(0, len(rx1))
1942 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1943 "Expected all (%s) packets across both ECMP paths. "
1944 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1947 # use a test CLI command to stop the FIB walk process, this
1948 # will prevent the FIB converging the VPN routes and thus allow
1949 # us to probe the interim (post-fail, pre-converge) state
1951 self.vapi.ppcli("test fib-walk-process disable")
1954 # withdraw the connected prefix on the interface.
1956 self.pg2.unconfig_ip4()
1959 # now all packets should be forwarded through the remaining peer
1961 self.pg0.add_stream(pkts)
1962 self.pg_enable_capture(self.pg_interfaces)
1965 rx0 = self.pg3.get_capture(NUM_PKTS)
1966 self.assertEqual(len(pkts), len(rx0),
1967 "Expected all (%s) packets across single path. "
1968 "rx0: %s." % (len(pkts), len(rx0)))
1971 # enable the FIB walk process to converge the FIB
1973 self.vapi.ppcli("test fib-walk-process enable")
1976 # packets should still be forwarded through the remaining peer
1978 self.pg0.add_stream(pkts)
1979 self.pg_enable_capture(self.pg_interfaces)
1982 rx0 = self.pg3.get_capture(NUM_PKTS)
1983 self.assertEqual(len(pkts), len(rx0),
1984 "Expected all (%s) packets across single path. "
1985 "rx0: %s." % (len(pkts), len(rx0)))
1988 # put the connected routes back
1990 self.pg2.config_ip4()
1991 self.pg2.resolve_arp()
1993 self.pg0.add_stream(pkts)
1994 self.pg_enable_capture(self.pg_interfaces)
1997 rx0 = self.pg2._get_capture(NUM_PKTS)
1998 rx1 = self.pg3._get_capture(NUM_PKTS)
1999 self.assertNotEqual(0, len(rx0))
2000 self.assertNotEqual(0, len(rx1))
2001 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2002 "Expected all (%s) packets across both ECMP paths. "
2003 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2005 def test_mpls_v6_ebgp_pic(self):
2006 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
2008 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
2009 2) Check EMCP forwarding to these peers
2010 3) withdraw one eBGP path - expect LB across remaining eBGP
2014 # Lot's of VPN routes. We need more the 64 so VPP will build
2015 # the fast convergence indirection
2020 for ii in range(NUM_PKTS):
2021 dst = "3000::%d" % ii
2022 local_label = 1600 + ii
2023 vpn_routes.append(VppIpRoute(
2026 self.pg2.remote_ip6,
2029 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
2031 self.pg3.remote_ip6,
2034 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
2036 vpn_routes[ii].add_vpp_config()
2038 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
2040 vpn_bindings[ii].add_vpp_config()
2042 pkts.append(Ether(dst=self.pg0.local_mac,
2043 src=self.pg0.remote_mac) /
2044 MPLS(label=local_label, ttl=64) /
2045 IPv6(src=self.pg0.remote_ip6, dst=dst) /
2046 UDP(sport=1234, dport=1234) /
2048 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2050 self.pg0.add_stream(pkts)
2051 self.pg_enable_capture(self.pg_interfaces)
2054 rx0 = self.pg2._get_capture(NUM_PKTS)
2055 rx1 = self.pg3._get_capture(NUM_PKTS)
2056 self.assertNotEqual(0, len(rx0))
2057 self.assertNotEqual(0, len(rx1))
2058 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2059 "Expected all (%s) packets across both ECMP paths. "
2060 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2063 # use a test CLI command to stop the FIB walk process, this
2064 # will prevent the FIB converging the VPN routes and thus allow
2065 # us to probe the interim (post-fail, pre-converge) state
2067 self.vapi.ppcli("test fib-walk-process disable")
2070 # withdraw the connected prefix on the interface.
2071 # and shutdown the interface so the ND cache is flushed.
2073 self.pg2.unconfig_ip6()
2074 self.pg2.admin_down()
2077 # now all packets should be forwarded through the remaining peer
2079 self.pg0.add_stream(pkts)
2080 self.pg_enable_capture(self.pg_interfaces)
2083 rx0 = self.pg3.get_capture(NUM_PKTS)
2084 self.assertEqual(len(pkts), len(rx0),
2085 "Expected all (%s) packets across single path. "
2086 "rx0: %s." % (len(pkts), len(rx0)))
2089 # enable the FIB walk process to converge the FIB
2091 self.vapi.ppcli("test fib-walk-process enable")
2092 self.pg0.add_stream(pkts)
2093 self.pg_enable_capture(self.pg_interfaces)
2096 rx0 = self.pg3.get_capture(NUM_PKTS)
2097 self.assertEqual(len(pkts), len(rx0),
2098 "Expected all (%s) packets across single path. "
2099 "rx0: %s." % (len(pkts), len(rx0)))
2102 # put the connected routes back
2104 self.logger.info(self.vapi.cli("sh log"))
2106 self.pg2.config_ip6()
2107 self.pg2.resolve_ndp()
2109 self.pg0.add_stream(pkts)
2110 self.pg_enable_capture(self.pg_interfaces)
2113 rx0 = self.pg2._get_capture(NUM_PKTS)
2114 rx1 = self.pg3._get_capture(NUM_PKTS)
2115 self.assertNotEqual(0, len(rx0))
2116 self.assertNotEqual(0, len(rx1))
2117 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2118 "Expected all (%s) packets across both ECMP paths. "
2119 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2122 class TestMPLSL2(VppTestCase):
2126 def setUpClass(cls):
2127 super(TestMPLSL2, cls).setUpClass()
2130 def tearDownClass(cls):
2131 super(TestMPLSL2, cls).tearDownClass()
2134 super(TestMPLSL2, self).setUp()
2136 # create 2 pg interfaces
2137 self.create_pg_interfaces(range(2))
2139 # create the default MPLS table
2141 tbl = VppMplsTable(self, 0)
2142 tbl.add_vpp_config()
2143 self.tables.append(tbl)
2145 # use pg0 as the core facing interface, don't resolve ARP
2147 self.pg0.config_ip4()
2148 self.pg0.enable_mpls()
2150 # use the other 2 for customer facing L2 links
2151 for i in self.pg_interfaces[1:]:
2155 for i in self.pg_interfaces[1:]:
2158 self.pg0.disable_mpls()
2159 self.pg0.unconfig_ip4()
2160 self.pg0.admin_down()
2161 super(TestMPLSL2, self).tearDown()
2163 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2164 capture = verify_filter(capture, sent)
2166 self.assertEqual(len(capture), len(sent))
2168 for i in range(len(capture)):
2172 # the MPLS TTL is 255 since it enters a new tunnel
2173 verify_mpls_stack(self, rx, mpls_labels)
2176 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2178 self.assertEqual(rx_eth.src, tx_eth.src)
2179 self.assertEqual(rx_eth.dst, tx_eth.dst)
2181 def verify_arp_req(self, rx, smac, sip, dip):
2183 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2184 self.assertEqual(ether.src, smac)
2187 self.assertEqual(arp.hwtype, 1)
2188 self.assertEqual(arp.ptype, 0x800)
2189 self.assertEqual(arp.hwlen, 6)
2190 self.assertEqual(arp.plen, 4)
2191 self.assertEqual(arp.op, ARP.who_has)
2192 self.assertEqual(arp.hwsrc, smac)
2193 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2194 self.assertEqual(arp.psrc, sip)
2195 self.assertEqual(arp.pdst, dip)
2197 def test_vpws(self):
2198 """ Virtual Private Wire Service """
2201 # Create an MPLS tunnel that pushes 1 label
2202 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2203 # information is not in the packet, but we test it works anyway
2205 mpls_tun_1 = VppMPLSTunnelInterface(
2207 [VppRoutePath(self.pg0.remote_ip4,
2208 self.pg0.sw_if_index,
2209 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2211 mpls_tun_1.add_vpp_config()
2212 mpls_tun_1.admin_up()
2215 # Create a label entry to for 55 that does L2 input to the tunnel
2217 route_55_eos = VppMplsRoute(
2219 [VppRoutePath("0.0.0.0",
2220 mpls_tun_1.sw_if_index,
2221 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2222 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2223 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2224 route_55_eos.add_vpp_config()
2227 # Cross-connect the tunnel with one of the customers L2 interfaces
2229 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2230 mpls_tun_1.sw_if_index,
2232 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2233 self.pg1.sw_if_index,
2237 # inject a packet from the core
2239 pcore = (Ether(dst=self.pg0.local_mac,
2240 src=self.pg0.remote_mac) /
2241 MPLS(label=55, ttl=64) /
2242 Ether(dst="00:00:de:ad:ba:be",
2243 src="00:00:de:ad:be:ef") /
2244 IP(src="10.10.10.10", dst="11.11.11.11") /
2245 UDP(sport=1234, dport=1234) /
2248 tx0 = pcore * NUM_PKTS
2249 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2250 payload = pcore[MPLS].payload
2252 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2253 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2256 # Inject a packet from the customer/L2 side
2257 # there's no resolved ARP entry so the first packet we see should be
2260 tx1 = pcore[MPLS].payload
2261 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2263 self.verify_arp_req(rx1[0],
2266 self.pg0.remote_ip4)
2269 # resolve the ARP entries and send again
2271 self.pg0.resolve_arp()
2272 tx1 = pcore[MPLS].payload * NUM_PKTS
2273 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2275 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2277 def test_vpls(self):
2278 """ Virtual Private LAN Service """
2280 # we skipped this in the setup
2281 self.pg0.resolve_arp()
2284 # Create a L2 MPLS tunnels
2286 mpls_tun1 = VppMPLSTunnelInterface(
2288 [VppRoutePath(self.pg0.remote_ip4,
2289 self.pg0.sw_if_index,
2290 labels=[VppMplsLabel(42)])],
2292 mpls_tun1.add_vpp_config()
2293 mpls_tun1.admin_up()
2295 mpls_tun2 = VppMPLSTunnelInterface(
2297 [VppRoutePath(self.pg0.remote_ip4,
2298 self.pg0.sw_if_index,
2299 labels=[VppMplsLabel(43)])],
2301 mpls_tun2.add_vpp_config()
2302 mpls_tun2.admin_up()
2305 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2306 # the latter includes a Psuedo Wire Control Word
2308 route_55_eos = VppMplsRoute(
2310 [VppRoutePath("0.0.0.0",
2311 mpls_tun1.sw_if_index,
2312 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2313 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2314 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2316 route_56_eos = VppMplsRoute(
2318 [VppRoutePath("0.0.0.0",
2319 mpls_tun2.sw_if_index,
2320 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2321 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2322 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2323 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2326 route_56_eos.add_vpp_config()
2327 route_55_eos.add_vpp_config()
2329 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2332 # add to tunnel to the customers bridge-domain
2334 self.vapi.sw_interface_set_l2_bridge(
2335 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2336 self.vapi.sw_interface_set_l2_bridge(
2337 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2338 self.vapi.sw_interface_set_l2_bridge(
2339 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2342 # Packet from host on the customer interface to each host
2343 # reachable over the core, and vice-versa
2345 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2346 src="00:00:de:ad:be:ef") /
2347 IP(src="10.10.10.10", dst="11.11.11.11") /
2348 UDP(sport=1234, dport=1234) /
2350 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2351 src="00:00:de:ad:be:ef") /
2352 IP(src="10.10.10.10", dst="11.11.11.12") /
2353 UDP(sport=1234, dport=1234) /
2355 p_core1 = (Ether(dst=self.pg0.local_mac,
2356 src=self.pg0.remote_mac) /
2357 MPLS(label=55, ttl=64) /
2358 Ether(src="00:00:de:ad:ba:b1",
2359 dst="00:00:de:ad:be:ef") /
2360 IP(dst="10.10.10.10", src="11.11.11.11") /
2361 UDP(sport=1234, dport=1234) /
2363 p_core2 = (Ether(dst=self.pg0.local_mac,
2364 src=self.pg0.remote_mac) /
2365 MPLS(label=56, ttl=64) /
2366 Raw(b'\x01' * 4) / # PW CW
2367 Ether(src="00:00:de:ad:ba:b2",
2368 dst="00:00:de:ad:be:ef") /
2369 IP(dst="10.10.10.10", src="11.11.11.12") /
2370 UDP(sport=1234, dport=1234) /
2374 # The BD is learning, so send in one of each packet to learn
2377 # 2 packets due to BD flooding
2378 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2379 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2381 # we've learnt this so expect it be be forwarded not flooded
2382 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2383 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2384 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2386 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2387 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2388 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2391 # now a stream in each direction from each host
2393 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2394 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2397 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2398 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2401 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2402 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2405 # remove interfaces from customers bridge-domain
2407 self.vapi.sw_interface_set_l2_bridge(
2408 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2409 self.vapi.sw_interface_set_l2_bridge(
2410 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2411 self.vapi.sw_interface_set_l2_bridge(
2412 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2415 if __name__ == '__main__':
2416 unittest.main(testRunner=VppTestRunner)