6 from framework import VppTestCase, VppTestRunner
7 from vpp_ip import DpoProto, INVALID_INDEX
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
9 VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
10 VppIpTable, VppMplsTable, \
11 VppMplsLabel, MplsLspMode, find_mpls_route, \
12 FibPathProto, FibPathType, FibPathFlags, VppMplsLabel, MplsLspMode
13 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
14 from vpp_papi import VppEnum
17 from scapy.packet import Raw
18 from scapy.layers.l2 import Ether, ARP
19 from scapy.layers.inet import IP, UDP, ICMP
20 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
21 from scapy.contrib.mpls import MPLS
25 # scapy removed these attributes.
26 # we asked that they be restored: https://github.com/secdev/scapy/pull/1878
27 # semantic names have more meaning than numbers. so here they are.
32 def verify_filter(capture, sent):
33 if not len(capture) == len(sent):
34 # filter out any IPv6 RAs from the capture
41 def verify_mpls_stack(tst, rx, mpls_labels):
42 # the rx'd packet has the MPLS label popped
44 tst.assertEqual(eth.type, 0x8847)
48 for ii in range(len(mpls_labels)):
49 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
50 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
51 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
53 if ii == len(mpls_labels) - 1:
54 tst.assertEqual(rx_mpls.s, 1)
57 tst.assertEqual(rx_mpls.s, 0)
58 # pop the label to expose the next
59 rx_mpls = rx_mpls[MPLS].payload
62 class TestMPLS(VppTestCase):
63 """ MPLS Test Case """
67 super(TestMPLS, cls).setUpClass()
70 def tearDownClass(cls):
71 super(TestMPLS, cls).tearDownClass()
74 super(TestMPLS, self).setUp()
76 # create 2 pg interfaces
77 self.create_pg_interfaces(range(4))
79 # setup both interfaces
80 # assign them different tables.
84 tbl = VppMplsTable(self, 0)
86 self.tables.append(tbl)
88 for i in self.pg_interfaces:
92 tbl = VppIpTable(self, table_id)
94 self.tables.append(tbl)
95 tbl = VppIpTable(self, table_id, is_ip6=1)
97 self.tables.append(tbl)
99 i.set_table_ip4(table_id)
100 i.set_table_ip6(table_id)
109 for i in self.pg_interfaces:
116 super(TestMPLS, self).tearDown()
118 # the default of 64 matches the IP packet TTL default
119 def create_stream_labelled_ip4(
129 self.reset_packet_infos()
131 for i in range(0, n):
132 info = self.create_packet_info(src_if, src_if)
133 payload = self.info_to_payload(info)
134 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
136 for ii in range(len(mpls_labels)):
137 p = p / MPLS(label=mpls_labels[ii].value,
138 ttl=mpls_labels[ii].ttl,
139 cos=mpls_labels[ii].exp)
142 p = (p / IP(src=src_if.local_ip4,
143 dst=src_if.remote_ip4,
145 UDP(sport=1234, dport=1234) /
148 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
149 UDP(sport=1234, dport=1234) /
152 p = (p / IP(src=ip_itf.remote_ip4,
153 dst=ip_itf.local_ip4,
158 p[IP].chksum = chksum
163 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64,
164 ip_dscp=0, payload_size=None):
165 self.reset_packet_infos()
167 for i in range(0, 257):
168 info = self.create_packet_info(src_if, src_if)
169 payload = self.info_to_payload(info)
170 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
171 IP(src=src_if.remote_ip4, dst=dst_ip,
172 ttl=ip_ttl, tos=ip_dscp) /
173 UDP(sport=1234, dport=1234) /
177 self.extend_packet(p, payload_size)
181 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
182 self.reset_packet_infos()
184 for i in range(0, 257):
185 info = self.create_packet_info(src_if, src_if)
186 payload = self.info_to_payload(info)
187 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
188 IPv6(src=src_if.remote_ip6, dst=dst_ip,
189 hlim=ip_ttl, tc=ip_dscp) /
190 UDP(sport=1234, dport=1234) /
196 def create_stream_labelled_ip6(self, src_if, mpls_labels,
197 hlim=64, dst_ip=None):
199 dst_ip = src_if.remote_ip6
200 self.reset_packet_infos()
202 for i in range(0, 257):
203 info = self.create_packet_info(src_if, src_if)
204 payload = self.info_to_payload(info)
205 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
206 for l in mpls_labels:
207 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
209 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
210 UDP(sport=1234, dport=1234) /
216 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
217 ip_ttl=None, ip_dscp=0):
219 capture = verify_filter(capture, sent)
221 self.assertEqual(len(capture), len(sent))
223 for i in range(len(capture)):
227 # the rx'd packet has the MPLS label popped
229 self.assertEqual(eth.type, 0x800)
235 self.assertEqual(rx_ip.src, tx_ip.src)
236 self.assertEqual(rx_ip.dst, tx_ip.dst)
237 self.assertEqual(rx_ip.tos, ip_dscp)
239 # IP processing post pop has decremented the TTL
240 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
242 self.assertEqual(rx_ip.ttl, ip_ttl)
244 self.assertEqual(rx_ip.src, tx_ip.dst)
245 self.assertEqual(rx_ip.dst, tx_ip.src)
250 def verify_capture_labelled_ip4(self, src_if, capture, sent,
251 mpls_labels, ip_ttl=None):
253 capture = verify_filter(capture, sent)
255 self.assertEqual(len(capture), len(sent))
257 for i in range(len(capture)):
263 verify_mpls_stack(self, rx, mpls_labels)
265 self.assertEqual(rx_ip.src, tx_ip.src)
266 self.assertEqual(rx_ip.dst, tx_ip.dst)
268 # IP processing post pop has decremented the TTL
269 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
271 self.assertEqual(rx_ip.ttl, ip_ttl)
276 def verify_capture_labelled_ip6(self, src_if, capture, sent,
277 mpls_labels, ip_ttl=None):
279 capture = verify_filter(capture, sent)
281 self.assertEqual(len(capture), len(sent))
283 for i in range(len(capture)):
289 verify_mpls_stack(self, rx, mpls_labels)
291 self.assertEqual(rx_ip.src, tx_ip.src)
292 self.assertEqual(rx_ip.dst, tx_ip.dst)
294 # IP processing post pop has decremented the TTL
295 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
297 self.assertEqual(rx_ip.hlim, ip_ttl)
302 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
304 capture = verify_filter(capture, sent)
306 self.assertEqual(len(capture), len(sent))
308 for i in range(len(capture)):
314 verify_mpls_stack(self, rx, mpls_labels)
316 self.assertEqual(rx_ip.src, tx_ip.src)
317 self.assertEqual(rx_ip.dst, tx_ip.dst)
318 # IP processing post pop has decremented the TTL
319 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
324 def verify_capture_labelled(self, src_if, capture, sent,
327 capture = verify_filter(capture, sent)
329 self.assertEqual(len(capture), len(sent))
331 for i in range(len(capture)):
333 verify_mpls_stack(self, rx, mpls_labels)
337 def verify_capture_ip6(self, src_if, capture, sent,
338 ip_hlim=None, ip_dscp=0):
340 self.assertEqual(len(capture), len(sent))
342 for i in range(len(capture)):
346 # the rx'd packet has the MPLS label popped
348 self.assertEqual(eth.type, 0x86DD)
353 self.assertEqual(rx_ip.src, tx_ip.src)
354 self.assertEqual(rx_ip.dst, tx_ip.dst)
355 self.assertEqual(rx_ip.tc, ip_dscp)
356 # IP processing post pop has decremented the TTL
358 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
360 self.assertEqual(rx_ip.hlim, ip_hlim)
365 def verify_capture_ip6_icmp(self, src_if, capture, sent):
367 self.assertEqual(len(capture), len(sent))
369 for i in range(len(capture)):
373 # the rx'd packet has the MPLS label popped
375 self.assertEqual(eth.type, 0x86DD)
380 self.assertEqual(rx_ip.dst, tx_ip.src)
381 # ICMP sourced from the interface's address
382 self.assertEqual(rx_ip.src, src_if.local_ip6)
383 # hop-limit reset to 255 for IMCP packet
384 self.assertEqual(rx_ip.hlim, 255)
386 icmp = rx[ICMPv6TimeExceeded]
391 def verify_capture_fragmented_labelled_ip4(self, src_if, capture, sent,
392 mpls_labels, ip_ttl=None):
394 capture = verify_filter(capture, sent)
396 for i in range(len(capture)):
402 verify_mpls_stack(self, rx, mpls_labels)
404 self.assertEqual(rx_ip.src, tx_ip.src)
405 self.assertEqual(rx_ip.dst, tx_ip.dst)
407 # IP processing post pop has decremented the TTL
408 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
410 self.assertEqual(rx_ip.ttl, ip_ttl)
416 """ MPLS label swap tests """
419 # A simple MPLS xconnect - eos label in label out
421 route_32_eos = VppMplsRoute(self, 32, 1,
422 [VppRoutePath(self.pg0.remote_ip4,
423 self.pg0.sw_if_index,
424 labels=[VppMplsLabel(33)])])
425 route_32_eos.add_vpp_config()
428 find_mpls_route(self, 0, 32, 1,
429 [VppRoutePath(self.pg0.remote_ip4,
430 self.pg0.sw_if_index,
431 labels=[VppMplsLabel(33)])]))
434 # a stream that matches the route for 10.0.0.1
435 # PG0 is in the default table
437 tx = self.create_stream_labelled_ip4(self.pg0,
438 [VppMplsLabel(32, ttl=32, exp=1)])
439 rx = self.send_and_expect(self.pg0, tx, self.pg0)
440 self.verify_capture_labelled(self.pg0, rx, tx,
441 [VppMplsLabel(33, ttl=31, exp=1)])
443 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
446 # A simple MPLS xconnect - non-eos label in label out
448 route_32_neos = VppMplsRoute(self, 32, 0,
449 [VppRoutePath(self.pg0.remote_ip4,
450 self.pg0.sw_if_index,
451 labels=[VppMplsLabel(33)])])
452 route_32_neos.add_vpp_config()
455 # a stream that matches the route for 10.0.0.1
456 # PG0 is in the default table
458 tx = self.create_stream_labelled_ip4(self.pg0,
459 [VppMplsLabel(32, ttl=21, exp=7),
461 rx = self.send_and_expect(self.pg0, tx, self.pg0)
462 self.verify_capture_labelled(self.pg0, rx, tx,
463 [VppMplsLabel(33, ttl=20, exp=7),
465 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
468 # A simple MPLS xconnect - non-eos label in label out, uniform mode
470 route_42_neos = VppMplsRoute(
472 [VppRoutePath(self.pg0.remote_ip4,
473 self.pg0.sw_if_index,
474 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
475 route_42_neos.add_vpp_config()
477 tx = self.create_stream_labelled_ip4(self.pg0,
478 [VppMplsLabel(42, ttl=21, exp=7),
480 rx = self.send_and_expect(self.pg0, tx, self.pg0)
481 self.verify_capture_labelled(self.pg0, rx, tx,
482 [VppMplsLabel(43, ttl=20, exp=7),
486 # An MPLS xconnect - EOS label in IP out
488 route_33_eos = VppMplsRoute(self, 33, 1,
489 [VppRoutePath(self.pg0.remote_ip4,
490 self.pg0.sw_if_index,
492 route_33_eos.add_vpp_config()
494 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
495 rx = self.send_and_expect(self.pg0, tx, self.pg0)
496 self.verify_capture_ip4(self.pg0, rx, tx)
499 # disposed packets have an invalid IPv4 checksum
501 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
502 dst_ip=self.pg0.remote_ip4,
505 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
508 # An MPLS xconnect - EOS label in IP out, uniform mode
510 route_3333_eos = VppMplsRoute(
512 [VppRoutePath(self.pg0.remote_ip4,
513 self.pg0.sw_if_index,
514 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
515 route_3333_eos.add_vpp_config()
517 tx = self.create_stream_labelled_ip4(
519 [VppMplsLabel(3333, ttl=55, exp=3)])
520 rx = self.send_and_expect(self.pg0, tx, self.pg0)
521 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
522 tx = self.create_stream_labelled_ip4(
524 [VppMplsLabel(3333, ttl=66, exp=4)])
525 rx = self.send_and_expect(self.pg0, tx, self.pg0)
526 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
529 # An MPLS xconnect - EOS label in IPv6 out
531 route_333_eos = VppMplsRoute(
533 [VppRoutePath(self.pg0.remote_ip6,
534 self.pg0.sw_if_index,
536 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
537 route_333_eos.add_vpp_config()
539 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
540 rx = self.send_and_expect(self.pg0, tx, self.pg0)
541 self.verify_capture_ip6(self.pg0, rx, tx)
544 # disposed packets have an TTL expired
546 tx = self.create_stream_labelled_ip6(self.pg0,
547 [VppMplsLabel(333, ttl=64)],
548 dst_ip=self.pg1.remote_ip6,
550 rx = self.send_and_expect(self.pg0, tx, self.pg0)
551 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
554 # An MPLS xconnect - EOS label in IPv6 out w imp-null
556 route_334_eos = VppMplsRoute(
558 [VppRoutePath(self.pg0.remote_ip6,
559 self.pg0.sw_if_index,
560 labels=[VppMplsLabel(3)])],
561 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
562 route_334_eos.add_vpp_config()
564 tx = self.create_stream_labelled_ip6(self.pg0,
565 [VppMplsLabel(334, ttl=64)])
566 rx = self.send_and_expect(self.pg0, tx, self.pg0)
567 self.verify_capture_ip6(self.pg0, rx, tx)
570 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
572 route_335_eos = VppMplsRoute(
574 [VppRoutePath(self.pg0.remote_ip6,
575 self.pg0.sw_if_index,
576 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])],
577 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
578 route_335_eos.add_vpp_config()
580 tx = self.create_stream_labelled_ip6(
582 [VppMplsLabel(335, ttl=27, exp=4)])
583 rx = self.send_and_expect(self.pg0, tx, self.pg0)
584 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
587 # disposed packets have an TTL expired
589 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
590 dst_ip=self.pg1.remote_ip6,
592 rx = self.send_and_expect(self.pg0, tx, self.pg0)
593 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
596 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
597 # so this traffic should be dropped.
599 route_33_neos = VppMplsRoute(self, 33, 0,
600 [VppRoutePath(self.pg0.remote_ip4,
601 self.pg0.sw_if_index,
603 route_33_neos.add_vpp_config()
605 tx = self.create_stream_labelled_ip4(self.pg0,
608 self.send_and_assert_no_replies(
610 "MPLS non-EOS packets popped and forwarded")
613 # A recursive EOS x-connect, which resolves through another x-connect
616 route_34_eos = VppMplsRoute(self, 34, 1,
617 [VppRoutePath("0.0.0.0",
620 labels=[VppMplsLabel(44),
622 route_34_eos.add_vpp_config()
623 self.logger.info(self.vapi.cli("sh mpls fib 34"))
625 tx = self.create_stream_labelled_ip4(self.pg0,
626 [VppMplsLabel(34, ttl=3)])
627 rx = self.send_and_expect(self.pg0, tx, self.pg0)
628 self.verify_capture_labelled(self.pg0, rx, tx,
631 VppMplsLabel(45, ttl=2)])
633 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
634 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
637 # A recursive EOS x-connect, which resolves through another x-connect
640 route_35_eos = VppMplsRoute(
642 [VppRoutePath("0.0.0.0",
645 labels=[VppMplsLabel(44)])])
646 route_35_eos.add_vpp_config()
648 tx = self.create_stream_labelled_ip4(self.pg0,
649 [VppMplsLabel(35, ttl=3)])
650 rx = self.send_and_expect(self.pg0, tx, self.pg0)
651 self.verify_capture_labelled(self.pg0, rx, tx,
652 [VppMplsLabel(43, ttl=2),
653 VppMplsLabel(44, ttl=2)])
656 # A recursive non-EOS x-connect, which resolves through another
659 route_34_neos = VppMplsRoute(self, 34, 0,
660 [VppRoutePath("0.0.0.0",
663 labels=[VppMplsLabel(44),
665 route_34_neos.add_vpp_config()
667 tx = self.create_stream_labelled_ip4(self.pg0,
668 [VppMplsLabel(34, ttl=45),
670 rx = self.send_and_expect(self.pg0, tx, self.pg0)
671 # it's the 2nd (counting from 0) label in the stack that is swapped
672 self.verify_capture_labelled(self.pg0, rx, tx,
675 VppMplsLabel(46, ttl=44),
679 # an recursive IP route that resolves through the recursive non-eos
682 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
683 [VppRoutePath("0.0.0.0",
686 labels=[VppMplsLabel(55)])])
687 ip_10_0_0_1.add_vpp_config()
689 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
690 rx = self.send_and_expect(self.pg0, tx, self.pg0)
691 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
696 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
698 ip_10_0_0_1.remove_vpp_config()
699 route_34_neos.remove_vpp_config()
700 route_34_eos.remove_vpp_config()
701 route_33_neos.remove_vpp_config()
702 route_33_eos.remove_vpp_config()
703 route_32_neos.remove_vpp_config()
704 route_32_eos.remove_vpp_config()
707 """ MPLS Local Label Binding test """
710 # Add a non-recursive route with a single out label
712 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
713 [VppRoutePath(self.pg0.remote_ip4,
714 self.pg0.sw_if_index,
715 labels=[VppMplsLabel(45)])])
716 route_10_0_0_1.add_vpp_config()
718 # bind a local label to the route
719 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
720 binding.add_vpp_config()
723 tx = self.create_stream_labelled_ip4(self.pg0,
726 rx = self.send_and_expect(self.pg0, tx, self.pg0)
727 self.verify_capture_labelled(self.pg0, rx, tx,
728 [VppMplsLabel(45, ttl=63),
732 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
733 rx = self.send_and_expect(self.pg0, tx, self.pg0)
734 self.verify_capture_labelled(self.pg0, rx, tx,
735 [VppMplsLabel(45, ttl=63)])
738 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
739 rx = self.send_and_expect(self.pg0, tx, self.pg0)
740 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
745 binding.remove_vpp_config()
746 route_10_0_0_1.remove_vpp_config()
748 def test_imposition(self):
749 """ MPLS label imposition test """
752 # Add a non-recursive route with a single out label
754 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
755 [VppRoutePath(self.pg0.remote_ip4,
756 self.pg0.sw_if_index,
757 labels=[VppMplsLabel(32)])])
758 route_10_0_0_1.add_vpp_config()
761 # a stream that matches the route for 10.0.0.1
762 # PG0 is in the default table
764 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
765 rx = self.send_and_expect(self.pg0, tx, self.pg0)
766 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
769 # Add a non-recursive route with a 3 out labels
771 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
772 [VppRoutePath(self.pg0.remote_ip4,
773 self.pg0.sw_if_index,
774 labels=[VppMplsLabel(32),
777 route_10_0_0_2.add_vpp_config()
779 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
780 ip_ttl=44, ip_dscp=0xff)
781 rx = self.send_and_expect(self.pg0, tx, self.pg0)
782 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
789 # Add a non-recursive route with a single out label in uniform mode
791 route_10_0_0_3 = VppIpRoute(
792 self, "10.0.0.3", 32,
793 [VppRoutePath(self.pg0.remote_ip4,
794 self.pg0.sw_if_index,
795 labels=[VppMplsLabel(32,
796 mode=MplsLspMode.UNIFORM)])])
797 route_10_0_0_3.add_vpp_config()
799 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
800 ip_ttl=54, ip_dscp=0xbe)
801 rx = self.send_and_expect(self.pg0, tx, self.pg0)
802 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
803 [VppMplsLabel(32, ttl=53, exp=5)])
806 # Add a IPv6 non-recursive route with a single out label in
809 route_2001_3 = VppIpRoute(
810 self, "2001::3", 128,
811 [VppRoutePath(self.pg0.remote_ip6,
812 self.pg0.sw_if_index,
813 labels=[VppMplsLabel(32,
814 mode=MplsLspMode.UNIFORM)])])
815 route_2001_3.add_vpp_config()
817 tx = self.create_stream_ip6(self.pg0, "2001::3",
818 ip_ttl=54, ip_dscp=0xbe)
819 rx = self.send_and_expect(self.pg0, tx, self.pg0)
820 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
821 [VppMplsLabel(32, ttl=53, exp=5)])
824 # add a recursive path, with output label, via the 1 label route
826 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
827 [VppRoutePath("10.0.0.1",
829 labels=[VppMplsLabel(44)])])
830 route_11_0_0_1.add_vpp_config()
833 # a stream that matches the route for 11.0.0.1, should pick up
834 # the label stack for 11.0.0.1 and 10.0.0.1
836 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
837 rx = self.send_and_expect(self.pg0, tx, self.pg0)
838 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
842 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
845 # add a recursive path, with 2 labels, via the 3 label route
847 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
848 [VppRoutePath("10.0.0.2",
850 labels=[VppMplsLabel(44),
852 route_11_0_0_2.add_vpp_config()
855 # a stream that matches the route for 11.0.0.1, should pick up
856 # the label stack for 11.0.0.1 and 10.0.0.1
858 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
859 rx = self.send_and_expect(self.pg0, tx, self.pg0)
860 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
867 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
869 rx = self.send_and_expect(self.pg0, tx, self.pg0)
870 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
877 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
882 route_11_0_0_2.remove_vpp_config()
883 route_11_0_0_1.remove_vpp_config()
884 route_10_0_0_2.remove_vpp_config()
885 route_10_0_0_1.remove_vpp_config()
887 def test_imposition_fragmentation(self):
888 """ MPLS label imposition fragmentation test """
891 # Add a ipv4 non-recursive route with a single out label
893 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
894 [VppRoutePath(self.pg0.remote_ip4,
895 self.pg0.sw_if_index,
896 labels=[VppMplsLabel(32)])])
897 route_10_0_0_1.add_vpp_config()
900 # a stream that matches the route for 10.0.0.1
901 # PG0 is in the default table
903 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
904 for i in range(0, 257):
905 self.extend_packet(tx[i], 10000)
908 # 5 fragments per packet (257*5=1285)
910 rx = self.send_and_expect(self.pg0, tx, self.pg0, 1285)
911 self.verify_capture_fragmented_labelled_ip4(self.pg0, rx, tx,
917 route_10_0_0_1.remove_vpp_config()
919 def test_tunnel_pipe(self):
920 """ MPLS Tunnel Tests - Pipe """
923 # Create a tunnel with two out labels
925 mpls_tun = VppMPLSTunnelInterface(
927 [VppRoutePath(self.pg0.remote_ip4,
928 self.pg0.sw_if_index,
929 labels=[VppMplsLabel(44),
931 mpls_tun.add_vpp_config()
935 # add an unlabelled route through the new tunnel
937 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
938 [VppRoutePath("0.0.0.0",
939 mpls_tun._sw_if_index)])
940 route_10_0_0_3.add_vpp_config()
942 self.vapi.cli("clear trace")
943 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
944 self.pg0.add_stream(tx)
946 self.pg_enable_capture(self.pg_interfaces)
949 rx = self.pg0.get_capture()
950 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
955 # add a labelled route through the new tunnel
957 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
958 [VppRoutePath("0.0.0.0",
959 mpls_tun._sw_if_index,
961 route_10_0_0_4.add_vpp_config()
963 self.vapi.cli("clear trace")
964 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
965 self.pg0.add_stream(tx)
967 self.pg_enable_capture(self.pg_interfaces)
970 rx = self.pg0.get_capture()
971 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
974 VppMplsLabel(33, ttl=255)])
977 # change tunnel's MTU to a low value
979 mpls_tun.set_l3_mtu(1200)
981 # send IP into the tunnel to be fragmented
982 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
984 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
990 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
994 # send MPLS into the tunnel to be fragmented
995 tx = self.create_stream_ip4(self.pg0, "10.0.0.4",
997 rx = self.send_and_expect(self.pg0, tx, self.pg0, len(tx)*2)
1003 self.verify_capture_tunneled_ip4(self.pg0, rx, fake_tx,
1006 VppMplsLabel(33, ttl=255)])
1008 def test_tunnel_uniform(self):
1009 """ MPLS Tunnel Tests - Uniform """
1012 # Create a tunnel with a single out label
1013 # The label stack is specified here from outer to inner
1015 mpls_tun = VppMPLSTunnelInterface(
1017 [VppRoutePath(self.pg0.remote_ip4,
1018 self.pg0.sw_if_index,
1019 labels=[VppMplsLabel(44, ttl=32),
1020 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1021 mpls_tun.add_vpp_config()
1025 # add an unlabelled route through the new tunnel
1027 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1028 [VppRoutePath("0.0.0.0",
1029 mpls_tun._sw_if_index)])
1030 route_10_0_0_3.add_vpp_config()
1032 self.vapi.cli("clear trace")
1033 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
1034 self.pg0.add_stream(tx)
1036 self.pg_enable_capture(self.pg_interfaces)
1039 rx = self.pg0.get_capture()
1040 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1041 [VppMplsLabel(44, ttl=32),
1042 VppMplsLabel(46, ttl=23)])
1045 # add a labelled route through the new tunnel
1047 route_10_0_0_4 = VppIpRoute(
1048 self, "10.0.0.4", 32,
1049 [VppRoutePath("0.0.0.0",
1050 mpls_tun._sw_if_index,
1051 labels=[VppMplsLabel(33, ttl=47)])])
1052 route_10_0_0_4.add_vpp_config()
1054 self.vapi.cli("clear trace")
1055 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
1056 self.pg0.add_stream(tx)
1058 self.pg_enable_capture(self.pg_interfaces)
1061 rx = self.pg0.get_capture()
1062 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
1063 [VppMplsLabel(44, ttl=32),
1064 VppMplsLabel(46, ttl=47),
1065 VppMplsLabel(33, ttl=47)])
1067 def test_mpls_tunnel_many(self):
1068 """ MPLS Multiple Tunnels """
1070 for ii in range(10):
1071 mpls_tun = VppMPLSTunnelInterface(
1073 [VppRoutePath(self.pg0.remote_ip4,
1074 self.pg0.sw_if_index,
1075 labels=[VppMplsLabel(44, ttl=32),
1076 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
1077 mpls_tun.add_vpp_config()
1080 def test_v4_exp_null(self):
1081 """ MPLS V4 Explicit NULL test """
1084 # The first test case has an MPLS TTL of 0
1085 # all packet should be dropped
1087 tx = self.create_stream_labelled_ip4(self.pg0,
1088 [VppMplsLabel(0, ttl=0)])
1089 self.send_and_assert_no_replies(self.pg0, tx,
1090 "MPLS TTL=0 packets forwarded")
1093 # a stream with a non-zero MPLS TTL
1094 # PG0 is in the default table
1096 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
1097 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1098 self.verify_capture_ip4(self.pg0, rx, tx)
1101 # a stream with a non-zero MPLS TTL
1103 # we are ensuring the post-pop lookup occurs in the VRF table
1105 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
1106 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1107 self.verify_capture_ip4(self.pg1, rx, tx)
1109 def test_v6_exp_null(self):
1110 """ MPLS V6 Explicit NULL test """
1113 # a stream with a non-zero MPLS TTL
1114 # PG0 is in the default table
1116 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1117 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1118 self.verify_capture_ip6(self.pg0, rx, tx)
1121 # a stream with a non-zero MPLS TTL
1123 # we are ensuring the post-pop lookup occurs in the VRF table
1125 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1126 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1127 self.verify_capture_ip6(self.pg0, rx, tx)
1129 def test_deag(self):
1133 # A de-agg route - next-hop lookup in default table
1135 route_34_eos = VppMplsRoute(self, 34, 1,
1136 [VppRoutePath("0.0.0.0",
1139 route_34_eos.add_vpp_config()
1142 # ping an interface in the default table
1143 # PG0 is in the default table
1145 tx = self.create_stream_labelled_ip4(self.pg0,
1149 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1150 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1153 # A de-agg route - next-hop lookup in non-default table
1155 route_35_eos = VppMplsRoute(self, 35, 1,
1156 [VppRoutePath("0.0.0.0",
1159 route_35_eos.add_vpp_config()
1162 # ping an interface in the non-default table
1163 # PG0 is in the default table. packet arrive labelled in the
1164 # default table and egress unlabelled in the non-default
1166 tx = self.create_stream_labelled_ip4(
1167 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1168 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1169 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1174 route_36_neos = VppMplsRoute(self, 36, 0,
1175 [VppRoutePath("0.0.0.0",
1177 route_36_neos.add_vpp_config()
1179 tx = self.create_stream_labelled_ip4(self.pg0,
1182 ping=1, ip_itf=self.pg1)
1183 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1184 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1186 route_36_neos.remove_vpp_config()
1187 route_35_eos.remove_vpp_config()
1188 route_34_eos.remove_vpp_config()
1190 def test_interface_rx(self):
1191 """ MPLS Interface Receive """
1194 # Add a non-recursive route that will forward the traffic
1197 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1199 paths=[VppRoutePath(self.pg1.remote_ip4,
1200 self.pg1.sw_if_index)])
1201 route_10_0_0_1.add_vpp_config()
1204 # An interface receive label that maps traffic to RX on interface
1206 # by injecting the packet in on pg0, which is in table 0
1207 # doing an interface-rx on pg1 and matching a route in table 1
1208 # if the packet egresses, then we must have swapped to pg1
1209 # so as to have matched the route in table 1
1211 route_34_eos = VppMplsRoute(
1213 [VppRoutePath("0.0.0.0",
1214 self.pg1.sw_if_index,
1215 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)])
1216 route_34_eos.add_vpp_config()
1219 # ping an interface in the default table
1220 # PG0 is in the default table
1222 tx = self.create_stream_labelled_ip4(self.pg0,
1225 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1226 self.verify_capture_ip4(self.pg1, rx, tx)
1228 def test_mcast_mid_point(self):
1229 """ MPLS Multicast Mid Point """
1232 # Add a non-recursive route that will forward the traffic
1235 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1237 paths=[VppRoutePath(self.pg1.remote_ip4,
1238 self.pg1.sw_if_index)])
1239 route_10_0_0_1.add_vpp_config()
1242 # Add a mcast entry that replicate to pg2 and pg3
1243 # and replicate to a interface-rx (like a bud node would)
1245 route_3400_eos = VppMplsRoute(
1247 [VppRoutePath(self.pg2.remote_ip4,
1248 self.pg2.sw_if_index,
1249 labels=[VppMplsLabel(3401)]),
1250 VppRoutePath(self.pg3.remote_ip4,
1251 self.pg3.sw_if_index,
1252 labels=[VppMplsLabel(3402)]),
1253 VppRoutePath("0.0.0.0",
1254 self.pg1.sw_if_index,
1255 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX)],
1257 route_3400_eos.add_vpp_config()
1260 # ping an interface in the default table
1261 # PG0 is in the default table
1263 self.vapi.cli("clear trace")
1264 tx = self.create_stream_labelled_ip4(self.pg0,
1265 [VppMplsLabel(3400, ttl=64)],
1268 self.pg0.add_stream(tx)
1270 self.pg_enable_capture(self.pg_interfaces)
1273 rx = self.pg1.get_capture(257)
1274 self.verify_capture_ip4(self.pg1, rx, tx)
1276 rx = self.pg2.get_capture(257)
1277 self.verify_capture_labelled(self.pg2, rx, tx,
1278 [VppMplsLabel(3401, ttl=63)])
1279 rx = self.pg3.get_capture(257)
1280 self.verify_capture_labelled(self.pg3, rx, tx,
1281 [VppMplsLabel(3402, ttl=63)])
1283 def test_mcast_head(self):
1284 """ MPLS Multicast Head-end """
1286 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1287 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1290 # Create a multicast tunnel with two replications
1292 mpls_tun = VppMPLSTunnelInterface(
1294 [VppRoutePath(self.pg2.remote_ip4,
1295 self.pg2.sw_if_index,
1296 labels=[VppMplsLabel(42)]),
1297 VppRoutePath(self.pg3.remote_ip4,
1298 self.pg3.sw_if_index,
1299 labels=[VppMplsLabel(43)])],
1301 mpls_tun.add_vpp_config()
1305 # add an unlabelled route through the new tunnel
1307 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1308 [VppRoutePath("0.0.0.0",
1309 mpls_tun._sw_if_index)])
1310 route_10_0_0_3.add_vpp_config()
1312 self.vapi.cli("clear trace")
1313 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1314 self.pg0.add_stream(tx)
1316 self.pg_enable_capture(self.pg_interfaces)
1319 rx = self.pg2.get_capture(257)
1320 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1321 rx = self.pg3.get_capture(257)
1322 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1325 # An an IP multicast route via the tunnel
1327 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1329 route_232_1_1_1 = VppIpMRoute(
1333 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1334 [VppMRoutePath(self.pg0.sw_if_index,
1335 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT),
1336 VppMRoutePath(mpls_tun._sw_if_index,
1337 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1338 route_232_1_1_1.add_vpp_config()
1339 self.logger.info(self.vapi.cli("sh ip mfib index 0"))
1341 self.vapi.cli("clear trace")
1342 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1343 self.pg0.add_stream(tx)
1345 self.pg_enable_capture(self.pg_interfaces)
1348 rx = self.pg2.get_capture(257)
1349 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1350 rx = self.pg3.get_capture(257)
1351 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1353 def test_mcast_ip4_tail(self):
1354 """ MPLS IPv4 Multicast Tail """
1356 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1357 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1360 # Add a multicast route that will forward the traffic
1363 route_232_1_1_1 = VppIpMRoute(
1367 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1369 paths=[VppMRoutePath(self.pg1.sw_if_index,
1370 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
1371 route_232_1_1_1.add_vpp_config()
1374 # An interface receive label that maps traffic to RX on interface
1376 # by injecting the packet in on pg0, which is in table 0
1377 # doing an rpf-id and matching a route in table 1
1378 # if the packet egresses, then we must have matched the route in
1381 route_34_eos = VppMplsRoute(
1383 [VppRoutePath("0.0.0.0",
1388 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)
1390 route_34_eos.add_vpp_config()
1393 # Drop due to interface lookup miss
1395 self.vapi.cli("clear trace")
1396 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1397 dst_ip="232.1.1.1", n=1)
1398 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1401 # set the RPF-ID of the entry to match the input packet's
1403 route_232_1_1_1.update_rpf_id(55)
1404 self.logger.info(self.vapi.cli("sh ip mfib index 1 232.1.1.1"))
1406 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1408 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1409 self.verify_capture_ip4(self.pg1, rx, tx)
1412 # disposed packets have an invalid IPv4 checksum
1414 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1415 dst_ip="232.1.1.1", n=65,
1417 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1420 # set the RPF-ID of the entry to not match the input packet's
1422 route_232_1_1_1.update_rpf_id(56)
1423 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1425 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1427 def test_mcast_ip6_tail(self):
1428 """ MPLS IPv6 Multicast Tail """
1430 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1431 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
1434 # Add a multicast route that will forward the traffic
1437 route_ff = VppIpMRoute(
1441 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
1443 paths=[VppMRoutePath(self.pg1.sw_if_index,
1444 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
1445 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
1446 route_ff.add_vpp_config()
1449 # An interface receive label that maps traffic to RX on interface
1451 # by injecting the packet in on pg0, which is in table 0
1452 # doing an rpf-id and matching a route in table 1
1453 # if the packet egresses, then we must have matched the route in
1456 route_34_eos = VppMplsRoute(
1463 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)
1465 route_34_eos.add_vpp_config()
1468 # Drop due to interface lookup miss
1470 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1472 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1475 # set the RPF-ID of the entry to match the input packet's
1477 route_ff.update_rpf_id(55)
1479 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1481 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1482 self.verify_capture_ip6(self.pg1, rx, tx)
1485 # disposed packets have hop-limit = 1
1487 tx = self.create_stream_labelled_ip6(self.pg0,
1491 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1492 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1495 # set the RPF-ID of the entry to not match the input packet's
1497 route_ff.update_rpf_id(56)
1498 tx = self.create_stream_labelled_ip6(self.pg0,
1501 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1507 # Add a non-recursive route with a single out label
1509 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1510 [VppRoutePath(self.pg0.remote_ip4,
1511 self.pg0.sw_if_index,
1512 labels=[VppMplsLabel(45)])])
1513 route_10_0_0_1.add_vpp_config()
1515 # bind a local label to the route
1516 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
1517 binding.add_vpp_config()
1520 # a labelled v6 route that resolves through the v4
1522 route_2001_3 = VppIpRoute(
1523 self, "2001::3", 128,
1524 [VppRoutePath("10.0.0.1",
1526 labels=[VppMplsLabel(32)])])
1527 route_2001_3.add_vpp_config()
1529 tx = self.create_stream_ip6(self.pg0, "2001::3")
1530 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1532 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
1537 # and a v4 recursive via the v6
1539 route_20_3 = VppIpRoute(
1540 self, "20.0.0.3", 32,
1541 [VppRoutePath("2001::3",
1543 labels=[VppMplsLabel(99)])])
1544 route_20_3.add_vpp_config()
1546 tx = self.create_stream_ip4(self.pg0, "20.0.0.3")
1547 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1549 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
1555 class TestMPLSDisabled(VppTestCase):
1556 """ MPLS disabled """
1559 def setUpClass(cls):
1560 super(TestMPLSDisabled, cls).setUpClass()
1563 def tearDownClass(cls):
1564 super(TestMPLSDisabled, cls).tearDownClass()
1567 super(TestMPLSDisabled, self).setUp()
1569 # create 2 pg interfaces
1570 self.create_pg_interfaces(range(2))
1572 self.tbl = VppMplsTable(self, 0)
1573 self.tbl.add_vpp_config()
1575 # PG0 is MPLS enabled
1577 self.pg0.config_ip4()
1578 self.pg0.resolve_arp()
1579 self.pg0.enable_mpls()
1581 # PG 1 is not MPLS enabled
1585 for i in self.pg_interfaces:
1589 self.pg0.disable_mpls()
1590 super(TestMPLSDisabled, self).tearDown()
1592 def test_mpls_disabled(self):
1593 """ MPLS Disabled """
1595 tx = (Ether(src=self.pg1.remote_mac,
1596 dst=self.pg1.local_mac) /
1597 MPLS(label=32, ttl=64) /
1598 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1599 UDP(sport=1234, dport=1234) /
1603 # A simple MPLS xconnect - eos label in label out
1605 route_32_eos = VppMplsRoute(self, 32, 1,
1606 [VppRoutePath(self.pg0.remote_ip4,
1607 self.pg0.sw_if_index,
1609 route_32_eos.add_vpp_config()
1612 # PG1 does not forward IP traffic
1614 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1619 self.pg1.enable_mpls()
1622 # Now we get packets through
1624 self.pg1.add_stream(tx)
1625 self.pg_enable_capture(self.pg_interfaces)
1628 rx = self.pg0.get_capture(1)
1633 self.pg1.disable_mpls()
1636 # PG1 does not forward IP traffic
1638 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1639 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1642 class TestMPLSPIC(VppTestCase):
1643 """ MPLS Prefix-Independent Convergence (PIC) edge convergence """
1646 def setUpClass(cls):
1647 super(TestMPLSPIC, cls).setUpClass()
1650 def tearDownClass(cls):
1651 super(TestMPLSPIC, cls).tearDownClass()
1654 super(TestMPLSPIC, self).setUp()
1656 # create 2 pg interfaces
1657 self.create_pg_interfaces(range(4))
1659 mpls_tbl = VppMplsTable(self, 0)
1660 mpls_tbl.add_vpp_config()
1661 tbl4 = VppIpTable(self, 1)
1662 tbl4.add_vpp_config()
1663 tbl6 = VppIpTable(self, 1, is_ip6=1)
1664 tbl6.add_vpp_config()
1668 self.pg0.config_ip4()
1669 self.pg0.resolve_arp()
1670 self.pg0.enable_mpls()
1673 self.pg1.config_ip4()
1674 self.pg1.resolve_arp()
1675 self.pg1.enable_mpls()
1677 # VRF (customer facing) link
1679 self.pg2.set_table_ip4(1)
1680 self.pg2.config_ip4()
1681 self.pg2.resolve_arp()
1682 self.pg2.set_table_ip6(1)
1683 self.pg2.config_ip6()
1684 self.pg2.resolve_ndp()
1687 self.pg3.set_table_ip4(1)
1688 self.pg3.config_ip4()
1689 self.pg3.resolve_arp()
1690 self.pg3.set_table_ip6(1)
1691 self.pg3.config_ip6()
1692 self.pg3.resolve_ndp()
1695 self.pg0.disable_mpls()
1696 self.pg1.disable_mpls()
1697 for i in self.pg_interfaces:
1703 super(TestMPLSPIC, self).tearDown()
1705 def test_mpls_ibgp_pic(self):
1706 """ MPLS iBGP Prefix-Independent Convergence (PIC) edge convergence
1708 1) setup many iBGP VPN routes via a pair of iBGP peers.
1709 2) Check EMCP forwarding to these peers
1710 3) withdraw the IGP route to one of these peers.
1711 4) check forwarding continues to the remaining peer
1715 # IGP+LDP core routes
1717 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1718 [VppRoutePath(self.pg0.remote_ip4,
1719 self.pg0.sw_if_index,
1721 core_10_0_0_45.add_vpp_config()
1723 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1724 [VppRoutePath(self.pg1.remote_ip4,
1725 self.pg1.sw_if_index,
1727 core_10_0_0_46.add_vpp_config()
1730 # Lot's of VPN routes. We need more the 64 so VPP will build
1731 # the fast convergence indirection
1735 for ii in range(NUM_PKTS):
1736 dst = "192.168.1.%d" % ii
1737 vpn_routes.append(VppIpRoute(
1743 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST),
1748 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_HOST)],
1750 vpn_routes[ii].add_vpp_config()
1752 pkts.append(Ether(dst=self.pg2.local_mac,
1753 src=self.pg2.remote_mac) /
1754 IP(src=self.pg2.remote_ip4, dst=dst) /
1755 UDP(sport=1234, dport=1234) /
1759 # Send the packet stream (one pkt to each VPN route)
1760 # - expect a 50-50 split of the traffic
1762 self.pg2.add_stream(pkts)
1763 self.pg_enable_capture(self.pg_interfaces)
1766 rx0 = self.pg0._get_capture(NUM_PKTS)
1767 rx1 = self.pg1._get_capture(NUM_PKTS)
1769 # not testing the LB hashing algorithm so we're not concerned
1770 # with the split ratio, just as long as neither is 0
1771 self.assertNotEqual(0, len(rx0))
1772 self.assertNotEqual(0, len(rx1))
1773 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1774 "Expected all (%s) packets across both ECMP paths. "
1775 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1778 # use a test CLI command to stop the FIB walk process, this
1779 # will prevent the FIB converging the VPN routes and thus allow
1780 # us to probe the interim (post-fail, pre-converge) state
1782 self.vapi.ppcli("test fib-walk-process disable")
1785 # Withdraw one of the IGP routes
1787 core_10_0_0_46.remove_vpp_config()
1790 # now all packets should be forwarded through the remaining peer
1792 self.vapi.ppcli("clear trace")
1793 self.pg2.add_stream(pkts)
1794 self.pg_enable_capture(self.pg_interfaces)
1797 rx0 = self.pg0.get_capture(NUM_PKTS)
1798 self.assertEqual(len(pkts), len(rx0),
1799 "Expected all (%s) packets across single path. "
1800 "rx0: %s." % (len(pkts), len(rx0)))
1803 # enable the FIB walk process to converge the FIB
1805 self.vapi.ppcli("test fib-walk-process enable")
1808 # packets should still be forwarded through the remaining peer
1810 self.pg2.add_stream(pkts)
1811 self.pg_enable_capture(self.pg_interfaces)
1814 rx0 = self.pg0.get_capture(NUM_PKTS)
1815 self.assertEqual(len(pkts), len(rx0),
1816 "Expected all (%s) packets across single path. "
1817 "rx0: %s." % (len(pkts), len(rx0)))
1820 # Add the IGP route back and we return to load-balancing
1822 core_10_0_0_46.add_vpp_config()
1824 self.pg2.add_stream(pkts)
1825 self.pg_enable_capture(self.pg_interfaces)
1828 rx0 = self.pg0._get_capture(NUM_PKTS)
1829 rx1 = self.pg1._get_capture(NUM_PKTS)
1830 self.assertNotEqual(0, len(rx0))
1831 self.assertNotEqual(0, len(rx1))
1832 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1833 "Expected all (%s) packets across both ECMP paths. "
1834 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1836 def test_mpls_ebgp_pic(self):
1837 """ MPLS eBGP Prefix-Independent Convergence (PIC) edge convergence
1839 1) setup many eBGP VPN routes via a pair of eBGP peers.
1840 2) Check EMCP forwarding to these peers
1841 3) withdraw one eBGP path - expect LB across remaining eBGP
1845 # Lot's of VPN routes. We need more the 64 so VPP will build
1846 # the fast convergence indirection
1851 for ii in range(NUM_PKTS):
1852 dst = "192.168.1.%d" % ii
1853 local_label = 1600 + ii
1854 vpn_routes.append(VppIpRoute(
1857 self.pg2.remote_ip4,
1860 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1862 self.pg3.remote_ip4,
1865 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1867 vpn_routes[ii].add_vpp_config()
1869 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1871 vpn_bindings[ii].add_vpp_config()
1873 pkts.append(Ether(dst=self.pg0.local_mac,
1874 src=self.pg0.remote_mac) /
1875 MPLS(label=local_label, ttl=64) /
1876 IP(src=self.pg0.remote_ip4, dst=dst) /
1877 UDP(sport=1234, dport=1234) /
1881 # Send the packet stream (one pkt to each VPN route)
1882 # - expect a 50-50 split of the traffic
1884 self.pg0.add_stream(pkts)
1885 self.pg_enable_capture(self.pg_interfaces)
1888 rx0 = self.pg2._get_capture(NUM_PKTS)
1889 rx1 = self.pg3._get_capture(NUM_PKTS)
1891 # not testing the LB hashing algorithm so we're not concerned
1892 # with the split ratio, just as long as neither is 0
1893 self.assertNotEqual(0, len(rx0))
1894 self.assertNotEqual(0, len(rx1))
1895 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1896 "Expected all (%s) packets across both ECMP paths. "
1897 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1900 # use a test CLI command to stop the FIB walk process, this
1901 # will prevent the FIB converging the VPN routes and thus allow
1902 # us to probe the interim (post-fail, pre-converge) state
1904 self.vapi.ppcli("test fib-walk-process disable")
1907 # withdraw the connected prefix on the interface.
1909 self.pg2.unconfig_ip4()
1912 # now all packets should be forwarded through the remaining peer
1914 self.pg0.add_stream(pkts)
1915 self.pg_enable_capture(self.pg_interfaces)
1918 rx0 = self.pg3.get_capture(NUM_PKTS)
1919 self.assertEqual(len(pkts), len(rx0),
1920 "Expected all (%s) packets across single path. "
1921 "rx0: %s." % (len(pkts), len(rx0)))
1924 # enable the FIB walk process to converge the FIB
1926 self.vapi.ppcli("test fib-walk-process enable")
1929 # packets should still be forwarded through the remaining peer
1931 self.pg0.add_stream(pkts)
1932 self.pg_enable_capture(self.pg_interfaces)
1935 rx0 = self.pg3.get_capture(NUM_PKTS)
1936 self.assertEqual(len(pkts), len(rx0),
1937 "Expected all (%s) packets across single path. "
1938 "rx0: %s." % (len(pkts), len(rx0)))
1941 # put the connected routes back
1943 self.pg2.config_ip4()
1944 self.pg2.resolve_arp()
1946 self.pg0.add_stream(pkts)
1947 self.pg_enable_capture(self.pg_interfaces)
1950 rx0 = self.pg2._get_capture(NUM_PKTS)
1951 rx1 = self.pg3._get_capture(NUM_PKTS)
1952 self.assertNotEqual(0, len(rx0))
1953 self.assertNotEqual(0, len(rx1))
1954 self.assertEqual(len(pkts), len(rx0) + len(rx1),
1955 "Expected all (%s) packets across both ECMP paths. "
1956 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
1958 def test_mpls_v6_ebgp_pic(self):
1959 """ MPLSv6 eBGP Prefix-Independent Convergence (PIC) edge convergence
1961 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1962 2) Check EMCP forwarding to these peers
1963 3) withdraw one eBGP path - expect LB across remaining eBGP
1967 # Lot's of VPN routes. We need more the 64 so VPP will build
1968 # the fast convergence indirection
1973 for ii in range(NUM_PKTS):
1974 dst = "3000::%d" % ii
1975 local_label = 1600 + ii
1976 vpn_routes.append(VppIpRoute(
1979 self.pg2.remote_ip6,
1982 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED),
1984 self.pg3.remote_ip6,
1987 flags=FibPathFlags.FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED)],
1989 vpn_routes[ii].add_vpp_config()
1991 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1993 vpn_bindings[ii].add_vpp_config()
1995 pkts.append(Ether(dst=self.pg0.local_mac,
1996 src=self.pg0.remote_mac) /
1997 MPLS(label=local_label, ttl=64) /
1998 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1999 UDP(sport=1234, dport=1234) /
2001 self.logger.info(self.vapi.cli("sh ip6 fib %s" % dst))
2003 self.pg0.add_stream(pkts)
2004 self.pg_enable_capture(self.pg_interfaces)
2007 rx0 = self.pg2._get_capture(NUM_PKTS)
2008 rx1 = self.pg3._get_capture(NUM_PKTS)
2009 self.assertNotEqual(0, len(rx0))
2010 self.assertNotEqual(0, len(rx1))
2011 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2012 "Expected all (%s) packets across both ECMP paths. "
2013 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2016 # use a test CLI command to stop the FIB walk process, this
2017 # will prevent the FIB converging the VPN routes and thus allow
2018 # us to probe the interim (post-fail, pre-converge) state
2020 self.vapi.ppcli("test fib-walk-process disable")
2023 # withdraw the connected prefix on the interface.
2024 # and shutdown the interface so the ND cache is flushed.
2026 self.pg2.unconfig_ip6()
2027 self.pg2.admin_down()
2030 # now all packets should be forwarded through the remaining peer
2032 self.pg0.add_stream(pkts)
2033 self.pg_enable_capture(self.pg_interfaces)
2036 rx0 = self.pg3.get_capture(NUM_PKTS)
2037 self.assertEqual(len(pkts), len(rx0),
2038 "Expected all (%s) packets across single path. "
2039 "rx0: %s." % (len(pkts), len(rx0)))
2042 # enable the FIB walk process to converge the FIB
2044 self.vapi.ppcli("test fib-walk-process enable")
2045 self.pg0.add_stream(pkts)
2046 self.pg_enable_capture(self.pg_interfaces)
2049 rx0 = self.pg3.get_capture(NUM_PKTS)
2050 self.assertEqual(len(pkts), len(rx0),
2051 "Expected all (%s) packets across single path. "
2052 "rx0: %s." % (len(pkts), len(rx0)))
2055 # put the connected routes back
2057 self.logger.info(self.vapi.cli("sh log"))
2059 self.pg2.config_ip6()
2060 self.pg2.resolve_ndp()
2062 self.pg0.add_stream(pkts)
2063 self.pg_enable_capture(self.pg_interfaces)
2066 rx0 = self.pg2._get_capture(NUM_PKTS)
2067 rx1 = self.pg3._get_capture(NUM_PKTS)
2068 self.assertNotEqual(0, len(rx0))
2069 self.assertNotEqual(0, len(rx1))
2070 self.assertEqual(len(pkts), len(rx0) + len(rx1),
2071 "Expected all (%s) packets across both ECMP paths. "
2072 "rx0: %s rx1: %s." % (len(pkts), len(rx0), len(rx1)))
2075 class TestMPLSL2(VppTestCase):
2079 def setUpClass(cls):
2080 super(TestMPLSL2, cls).setUpClass()
2083 def tearDownClass(cls):
2084 super(TestMPLSL2, cls).tearDownClass()
2087 super(TestMPLSL2, self).setUp()
2089 # create 2 pg interfaces
2090 self.create_pg_interfaces(range(2))
2092 # create the default MPLS table
2094 tbl = VppMplsTable(self, 0)
2095 tbl.add_vpp_config()
2096 self.tables.append(tbl)
2098 # use pg0 as the core facing interface, don't resolve ARP
2100 self.pg0.config_ip4()
2101 self.pg0.enable_mpls()
2103 # use the other 2 for customer facing L2 links
2104 for i in self.pg_interfaces[1:]:
2108 for i in self.pg_interfaces[1:]:
2111 self.pg0.disable_mpls()
2112 self.pg0.unconfig_ip4()
2113 self.pg0.admin_down()
2114 super(TestMPLSL2, self).tearDown()
2116 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
2117 capture = verify_filter(capture, sent)
2119 self.assertEqual(len(capture), len(sent))
2121 for i in range(len(capture)):
2125 # the MPLS TTL is 255 since it enters a new tunnel
2126 verify_mpls_stack(self, rx, mpls_labels)
2129 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
2131 self.assertEqual(rx_eth.src, tx_eth.src)
2132 self.assertEqual(rx_eth.dst, tx_eth.dst)
2134 def verify_arp_req(self, rx, smac, sip, dip):
2136 self.assertEqual(ether.dst, "ff:ff:ff:ff:ff:ff")
2137 self.assertEqual(ether.src, smac)
2140 self.assertEqual(arp.hwtype, 1)
2141 self.assertEqual(arp.ptype, 0x800)
2142 self.assertEqual(arp.hwlen, 6)
2143 self.assertEqual(arp.plen, 4)
2144 self.assertEqual(arp.op, ARP.who_has)
2145 self.assertEqual(arp.hwsrc, smac)
2146 self.assertEqual(arp.hwdst, "00:00:00:00:00:00")
2147 self.assertEqual(arp.psrc, sip)
2148 self.assertEqual(arp.pdst, dip)
2150 def test_vpws(self):
2151 """ Virtual Private Wire Service """
2154 # Create an MPLS tunnel that pushes 1 label
2155 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
2156 # information is not in the packet, but we test it works anyway
2158 mpls_tun_1 = VppMPLSTunnelInterface(
2160 [VppRoutePath(self.pg0.remote_ip4,
2161 self.pg0.sw_if_index,
2162 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
2164 mpls_tun_1.add_vpp_config()
2165 mpls_tun_1.admin_up()
2168 # Create a label entry to for 55 that does L2 input to the tunnel
2170 route_55_eos = VppMplsRoute(
2172 [VppRoutePath("0.0.0.0",
2173 mpls_tun_1.sw_if_index,
2174 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2175 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2176 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2177 route_55_eos.add_vpp_config()
2180 # Cross-connect the tunnel with one of the customers L2 interfaces
2182 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
2183 mpls_tun_1.sw_if_index,
2185 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
2186 self.pg1.sw_if_index,
2190 # inject a packet from the core
2192 pcore = (Ether(dst=self.pg0.local_mac,
2193 src=self.pg0.remote_mac) /
2194 MPLS(label=55, ttl=64) /
2195 Ether(dst="00:00:de:ad:ba:be",
2196 src="00:00:de:ad:be:ef") /
2197 IP(src="10.10.10.10", dst="11.11.11.11") /
2198 UDP(sport=1234, dport=1234) /
2201 tx0 = pcore * NUM_PKTS
2202 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
2203 payload = pcore[MPLS].payload
2205 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
2206 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
2209 # Inject a packet from the customer/L2 side
2210 # there's no resolved ARP entry so the first packet we see should be
2213 tx1 = pcore[MPLS].payload
2214 rx1 = self.send_and_expect(self.pg1, [tx1], self.pg0)
2216 self.verify_arp_req(rx1[0],
2219 self.pg0.remote_ip4)
2222 # resolve the ARP entries and send again
2224 self.pg0.resolve_arp()
2225 tx1 = pcore[MPLS].payload * NUM_PKTS
2226 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
2228 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
2230 def test_vpls(self):
2231 """ Virtual Private LAN Service """
2233 # we skipped this in the setup
2234 self.pg0.resolve_arp()
2237 # Create a L2 MPLS tunnels
2239 mpls_tun1 = VppMPLSTunnelInterface(
2241 [VppRoutePath(self.pg0.remote_ip4,
2242 self.pg0.sw_if_index,
2243 labels=[VppMplsLabel(42)])],
2245 mpls_tun1.add_vpp_config()
2246 mpls_tun1.admin_up()
2248 mpls_tun2 = VppMPLSTunnelInterface(
2250 [VppRoutePath(self.pg0.remote_ip4,
2251 self.pg0.sw_if_index,
2252 labels=[VppMplsLabel(43)])],
2254 mpls_tun2.add_vpp_config()
2255 mpls_tun2.admin_up()
2258 # Create a label entries, 55 and 56, that do L2 input to the tunnel
2259 # the latter includes a Psuedo Wire Control Word
2261 route_55_eos = VppMplsRoute(
2263 [VppRoutePath("0.0.0.0",
2264 mpls_tun1.sw_if_index,
2265 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2266 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2267 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2269 route_56_eos = VppMplsRoute(
2271 [VppRoutePath("0.0.0.0",
2272 mpls_tun2.sw_if_index,
2273 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
2274 flags=FibPathFlags.FIB_PATH_FLAG_POP_PW_CW,
2275 proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)],
2276 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_ETHERNET)
2279 route_56_eos.add_vpp_config()
2280 route_55_eos.add_vpp_config()
2282 self.logger.info(self.vapi.cli("sh mpls fib 56"))
2285 # add to tunnel to the customers bridge-domain
2287 self.vapi.sw_interface_set_l2_bridge(
2288 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1)
2289 self.vapi.sw_interface_set_l2_bridge(
2290 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1)
2291 self.vapi.sw_interface_set_l2_bridge(
2292 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
2295 # Packet from host on the customer interface to each host
2296 # reachable over the core, and vice-versa
2298 p_cust1 = (Ether(dst="00:00:de:ad:ba:b1",
2299 src="00:00:de:ad:be:ef") /
2300 IP(src="10.10.10.10", dst="11.11.11.11") /
2301 UDP(sport=1234, dport=1234) /
2303 p_cust2 = (Ether(dst="00:00:de:ad:ba:b2",
2304 src="00:00:de:ad:be:ef") /
2305 IP(src="10.10.10.10", dst="11.11.11.12") /
2306 UDP(sport=1234, dport=1234) /
2308 p_core1 = (Ether(dst=self.pg0.local_mac,
2309 src=self.pg0.remote_mac) /
2310 MPLS(label=55, ttl=64) /
2311 Ether(src="00:00:de:ad:ba:b1",
2312 dst="00:00:de:ad:be:ef") /
2313 IP(dst="10.10.10.10", src="11.11.11.11") /
2314 UDP(sport=1234, dport=1234) /
2316 p_core2 = (Ether(dst=self.pg0.local_mac,
2317 src=self.pg0.remote_mac) /
2318 MPLS(label=56, ttl=64) /
2319 Raw(b'\x01' * 4) / # PW CW
2320 Ether(src="00:00:de:ad:ba:b2",
2321 dst="00:00:de:ad:be:ef") /
2322 IP(dst="10.10.10.10", src="11.11.11.12") /
2323 UDP(sport=1234, dport=1234) /
2327 # The BD is learning, so send in one of each packet to learn
2330 # 2 packets due to BD flooding
2331 rx = self.send_and_expect(self.pg1, p_cust1, self.pg0, n_rx=2)
2332 rx = self.send_and_expect(self.pg1, p_cust2, self.pg0, n_rx=2)
2334 # we've learnt this so expect it be be forwarded not flooded
2335 rx = self.send_and_expect(self.pg0, [p_core1], self.pg1)
2336 self.assertEqual(rx[0][Ether].dst, p_cust1[Ether].src)
2337 self.assertEqual(rx[0][Ether].src, p_cust1[Ether].dst)
2339 rx = self.send_and_expect(self.pg0, [p_core2], self.pg1)
2340 self.assertEqual(rx[0][Ether].dst, p_cust2[Ether].src)
2341 self.assertEqual(rx[0][Ether].src, p_cust2[Ether].dst)
2344 # now a stream in each direction from each host
2346 rx = self.send_and_expect(self.pg1, p_cust1 * NUM_PKTS, self.pg0)
2347 self.verify_capture_tunneled_ethernet(rx, p_cust1 * NUM_PKTS,
2350 rx = self.send_and_expect(self.pg1, p_cust2 * NUM_PKTS, self.pg0)
2351 self.verify_capture_tunneled_ethernet(rx, p_cust2 * NUM_PKTS,
2354 rx = self.send_and_expect(self.pg0, p_core1 * NUM_PKTS, self.pg1)
2355 rx = self.send_and_expect(self.pg0, p_core2 * NUM_PKTS, self.pg1)
2358 # remove interfaces from customers bridge-domain
2360 self.vapi.sw_interface_set_l2_bridge(
2361 rx_sw_if_index=mpls_tun1.sw_if_index, bd_id=1, enable=0)
2362 self.vapi.sw_interface_set_l2_bridge(
2363 rx_sw_if_index=mpls_tun2.sw_if_index, bd_id=1, enable=0)
2364 self.vapi.sw_interface_set_l2_bridge(
2365 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2368 if __name__ == '__main__':
2369 unittest.main(testRunner=VppTestRunner)