6 from framework import VppTestCase, VppTestRunner
7 from vpp_ip import DpoProto
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
9 VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
10 MRouteItfFlags, MRouteEntryFlags, VppIpTable, VppMplsTable, \
11 VppMplsLabel, MplsLspMode, find_mpls_route
12 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
15 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether
17 from scapy.layers.inet import IP, UDP, ICMP
18 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
19 from scapy.contrib.mpls import MPLS
22 def verify_filter(capture, sent):
23 if not len(capture) == len(sent):
24 # filter out any IPv6 RAs from the capture
31 def verify_mpls_stack(tst, rx, mpls_labels):
32 # the rx'd packet has the MPLS label popped
34 tst.assertEqual(eth.type, 0x8847)
38 for ii in range(len(mpls_labels)):
39 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
40 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
41 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
43 if ii == len(mpls_labels) - 1:
44 tst.assertEqual(rx_mpls.s, 1)
47 tst.assertEqual(rx_mpls.s, 0)
48 # pop the label to expose the next
49 rx_mpls = rx_mpls[MPLS].payload
52 class TestMPLS(VppTestCase):
53 """ MPLS Test Case """
56 super(TestMPLS, self).setUp()
58 # create 2 pg interfaces
59 self.create_pg_interfaces(range(4))
61 # setup both interfaces
62 # assign them different tables.
66 tbl = VppMplsTable(self, 0)
68 self.tables.append(tbl)
70 for i in self.pg_interfaces:
74 tbl = VppIpTable(self, table_id)
76 self.tables.append(tbl)
77 tbl = VppIpTable(self, table_id, is_ip6=1)
79 self.tables.append(tbl)
81 i.set_table_ip4(table_id)
82 i.set_table_ip6(table_id)
91 for i in self.pg_interfaces:
99 super(TestMPLS, self).tearDown()
101 # the default of 64 matches the IP packet TTL default
102 def create_stream_labelled_ip4(
112 self.reset_packet_infos()
114 for i in range(0, n):
115 info = self.create_packet_info(src_if, src_if)
116 payload = self.info_to_payload(info)
117 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
119 for ii in range(len(mpls_labels)):
120 p = p / MPLS(label=mpls_labels[ii].value,
121 ttl=mpls_labels[ii].ttl,
122 cos=mpls_labels[ii].exp)
125 p = (p / IP(src=src_if.local_ip4,
126 dst=src_if.remote_ip4,
128 UDP(sport=1234, dport=1234) /
131 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
132 UDP(sport=1234, dport=1234) /
135 p = (p / IP(src=ip_itf.remote_ip4,
136 dst=ip_itf.local_ip4,
141 p[IP].chksum = chksum
146 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
147 self.reset_packet_infos()
149 for i in range(0, 257):
150 info = self.create_packet_info(src_if, src_if)
151 payload = self.info_to_payload(info)
152 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
153 IP(src=src_if.remote_ip4, dst=dst_ip,
154 ttl=ip_ttl, tos=ip_dscp) /
155 UDP(sport=1234, dport=1234) /
161 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
162 self.reset_packet_infos()
164 for i in range(0, 257):
165 info = self.create_packet_info(src_if, src_if)
166 payload = self.info_to_payload(info)
167 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
168 IPv6(src=src_if.remote_ip6, dst=dst_ip,
169 hlim=ip_ttl, tc=ip_dscp) /
170 UDP(sport=1234, dport=1234) /
176 def create_stream_labelled_ip6(self, src_if, mpls_labels,
177 hlim=64, dst_ip=None):
179 dst_ip = src_if.remote_ip6
180 self.reset_packet_infos()
182 for i in range(0, 257):
183 info = self.create_packet_info(src_if, src_if)
184 payload = self.info_to_payload(info)
185 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
186 for l in mpls_labels:
187 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
189 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
190 UDP(sport=1234, dport=1234) /
196 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
197 ip_ttl=None, ip_dscp=0):
199 capture = verify_filter(capture, sent)
201 self.assertEqual(len(capture), len(sent))
203 for i in range(len(capture)):
207 # the rx'd packet has the MPLS label popped
209 self.assertEqual(eth.type, 0x800)
215 self.assertEqual(rx_ip.src, tx_ip.src)
216 self.assertEqual(rx_ip.dst, tx_ip.dst)
217 self.assertEqual(rx_ip.tos, ip_dscp)
219 # IP processing post pop has decremented the TTL
220 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
222 self.assertEqual(rx_ip.ttl, ip_ttl)
224 self.assertEqual(rx_ip.src, tx_ip.dst)
225 self.assertEqual(rx_ip.dst, tx_ip.src)
230 def verify_capture_labelled_ip4(self, src_if, capture, sent,
231 mpls_labels, ip_ttl=None):
233 capture = verify_filter(capture, sent)
235 self.assertEqual(len(capture), len(sent))
237 for i in range(len(capture)):
243 verify_mpls_stack(self, rx, mpls_labels)
245 self.assertEqual(rx_ip.src, tx_ip.src)
246 self.assertEqual(rx_ip.dst, tx_ip.dst)
248 # IP processing post pop has decremented the TTL
249 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
251 self.assertEqual(rx_ip.ttl, ip_ttl)
256 def verify_capture_labelled_ip6(self, src_if, capture, sent,
257 mpls_labels, ip_ttl=None):
259 capture = verify_filter(capture, sent)
261 self.assertEqual(len(capture), len(sent))
263 for i in range(len(capture)):
269 verify_mpls_stack(self, rx, mpls_labels)
271 self.assertEqual(rx_ip.src, tx_ip.src)
272 self.assertEqual(rx_ip.dst, tx_ip.dst)
274 # IP processing post pop has decremented the TTL
275 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
277 self.assertEqual(rx_ip.hlim, ip_ttl)
282 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
284 capture = verify_filter(capture, sent)
286 self.assertEqual(len(capture), len(sent))
288 for i in range(len(capture)):
294 verify_mpls_stack(self, rx, mpls_labels)
296 self.assertEqual(rx_ip.src, tx_ip.src)
297 self.assertEqual(rx_ip.dst, tx_ip.dst)
298 # IP processing post pop has decremented the TTL
299 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
304 def verify_capture_labelled(self, src_if, capture, sent,
307 capture = verify_filter(capture, sent)
309 self.assertEqual(len(capture), len(sent))
311 for i in range(len(capture)):
313 verify_mpls_stack(self, rx, mpls_labels)
317 def verify_capture_ip6(self, src_if, capture, sent,
318 ip_hlim=None, ip_dscp=0):
320 self.assertEqual(len(capture), len(sent))
322 for i in range(len(capture)):
326 # the rx'd packet has the MPLS label popped
328 self.assertEqual(eth.type, 0x86DD)
333 self.assertEqual(rx_ip.src, tx_ip.src)
334 self.assertEqual(rx_ip.dst, tx_ip.dst)
335 self.assertEqual(rx_ip.tc, ip_dscp)
336 # IP processing post pop has decremented the TTL
338 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
340 self.assertEqual(rx_ip.hlim, ip_hlim)
345 def verify_capture_ip6_icmp(self, src_if, capture, sent):
347 self.assertEqual(len(capture), len(sent))
349 for i in range(len(capture)):
353 # the rx'd packet has the MPLS label popped
355 self.assertEqual(eth.type, 0x86DD)
360 self.assertEqual(rx_ip.dst, tx_ip.src)
361 # ICMP sourced from the interface's address
362 self.assertEqual(rx_ip.src, src_if.local_ip6)
363 # hop-limit reset to 255 for IMCP packet
364 self.assertEqual(rx_ip.hlim, 255)
366 icmp = rx[ICMPv6TimeExceeded]
372 """ MPLS label swap tests """
375 # A simple MPLS xconnect - eos label in label out
377 route_32_eos = VppMplsRoute(self, 32, 1,
378 [VppRoutePath(self.pg0.remote_ip4,
379 self.pg0.sw_if_index,
380 labels=[VppMplsLabel(33)])])
381 route_32_eos.add_vpp_config()
384 find_mpls_route(self, 0, 32, 1,
385 [VppRoutePath(self.pg0.remote_ip4,
386 self.pg0.sw_if_index,
387 labels=[VppMplsLabel(33)])]))
390 # a stream that matches the route for 10.0.0.1
391 # PG0 is in the default table
393 tx = self.create_stream_labelled_ip4(self.pg0,
394 [VppMplsLabel(32, ttl=32, exp=1)])
395 rx = self.send_and_expect(self.pg0, tx, self.pg0)
396 self.verify_capture_labelled(self.pg0, rx, tx,
397 [VppMplsLabel(33, ttl=31, exp=1)])
399 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
402 # A simple MPLS xconnect - non-eos label in label out
404 route_32_neos = VppMplsRoute(self, 32, 0,
405 [VppRoutePath(self.pg0.remote_ip4,
406 self.pg0.sw_if_index,
407 labels=[VppMplsLabel(33)])])
408 route_32_neos.add_vpp_config()
411 # a stream that matches the route for 10.0.0.1
412 # PG0 is in the default table
414 tx = self.create_stream_labelled_ip4(self.pg0,
415 [VppMplsLabel(32, ttl=21, exp=7),
417 rx = self.send_and_expect(self.pg0, tx, self.pg0)
418 self.verify_capture_labelled(self.pg0, rx, tx,
419 [VppMplsLabel(33, ttl=20, exp=7),
421 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
424 # A simple MPLS xconnect - non-eos label in label out, uniform mode
426 route_42_neos = VppMplsRoute(
428 [VppRoutePath(self.pg0.remote_ip4,
429 self.pg0.sw_if_index,
430 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
431 route_42_neos.add_vpp_config()
433 tx = self.create_stream_labelled_ip4(self.pg0,
434 [VppMplsLabel(42, ttl=21, exp=7),
436 rx = self.send_and_expect(self.pg0, tx, self.pg0)
437 self.verify_capture_labelled(self.pg0, rx, tx,
438 [VppMplsLabel(43, ttl=20, exp=7),
442 # An MPLS xconnect - EOS label in IP out
444 route_33_eos = VppMplsRoute(self, 33, 1,
445 [VppRoutePath(self.pg0.remote_ip4,
446 self.pg0.sw_if_index,
448 route_33_eos.add_vpp_config()
450 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
451 rx = self.send_and_expect(self.pg0, tx, self.pg0)
452 self.verify_capture_ip4(self.pg0, rx, tx)
455 # disposed packets have an invalid IPv4 checksum
457 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
458 dst_ip=self.pg0.remote_ip4,
461 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
464 # An MPLS xconnect - EOS label in IP out, uniform mode
466 route_3333_eos = VppMplsRoute(
468 [VppRoutePath(self.pg0.remote_ip4,
469 self.pg0.sw_if_index,
470 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
471 route_3333_eos.add_vpp_config()
473 tx = self.create_stream_labelled_ip4(
475 [VppMplsLabel(3333, ttl=55, exp=3)])
476 rx = self.send_and_expect(self.pg0, tx, self.pg0)
477 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
478 tx = self.create_stream_labelled_ip4(
480 [VppMplsLabel(3333, ttl=66, exp=4)])
481 rx = self.send_and_expect(self.pg0, tx, self.pg0)
482 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
485 # An MPLS xconnect - EOS label in IPv6 out
487 route_333_eos = VppMplsRoute(
489 [VppRoutePath(self.pg0.remote_ip6,
490 self.pg0.sw_if_index,
492 proto=DpoProto.DPO_PROTO_IP6)])
493 route_333_eos.add_vpp_config()
495 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
496 rx = self.send_and_expect(self.pg0, tx, self.pg0)
497 self.verify_capture_ip6(self.pg0, rx, tx)
500 # disposed packets have an TTL expired
502 tx = self.create_stream_labelled_ip6(self.pg0,
503 [VppMplsLabel(333, ttl=64)],
504 dst_ip=self.pg1.remote_ip6,
506 rx = self.send_and_expect(self.pg0, tx, self.pg0)
507 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
510 # An MPLS xconnect - EOS label in IPv6 out w imp-null
512 route_334_eos = VppMplsRoute(
514 [VppRoutePath(self.pg0.remote_ip6,
515 self.pg0.sw_if_index,
516 labels=[VppMplsLabel(3)],
517 proto=DpoProto.DPO_PROTO_IP6)])
518 route_334_eos.add_vpp_config()
520 tx = self.create_stream_labelled_ip6(self.pg0,
521 [VppMplsLabel(334, ttl=64)])
522 rx = self.send_and_expect(self.pg0, tx, self.pg0)
523 self.verify_capture_ip6(self.pg0, rx, tx)
526 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
528 route_335_eos = VppMplsRoute(
530 [VppRoutePath(self.pg0.remote_ip6,
531 self.pg0.sw_if_index,
532 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
533 proto=DpoProto.DPO_PROTO_IP6)])
534 route_335_eos.add_vpp_config()
536 tx = self.create_stream_labelled_ip6(
538 [VppMplsLabel(335, ttl=27, exp=4)])
539 rx = self.send_and_expect(self.pg0, tx, self.pg0)
540 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
543 # disposed packets have an TTL expired
545 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
546 dst_ip=self.pg1.remote_ip6,
548 rx = self.send_and_expect(self.pg0, tx, self.pg0)
549 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
552 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
553 # so this traffic should be dropped.
555 route_33_neos = VppMplsRoute(self, 33, 0,
556 [VppRoutePath(self.pg0.remote_ip4,
557 self.pg0.sw_if_index,
559 route_33_neos.add_vpp_config()
561 tx = self.create_stream_labelled_ip4(self.pg0,
564 self.send_and_assert_no_replies(
566 "MPLS non-EOS packets popped and forwarded")
569 # A recursive EOS x-connect, which resolves through another x-connect
572 route_34_eos = VppMplsRoute(self, 34, 1,
573 [VppRoutePath("0.0.0.0",
576 labels=[VppMplsLabel(44),
578 route_34_eos.add_vpp_config()
580 tx = self.create_stream_labelled_ip4(self.pg0,
581 [VppMplsLabel(34, ttl=3)])
582 rx = self.send_and_expect(self.pg0, tx, self.pg0)
583 self.verify_capture_labelled(self.pg0, rx, tx,
586 VppMplsLabel(45, ttl=2)])
588 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
589 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
592 # A recursive EOS x-connect, which resolves through another x-connect
595 route_35_eos = VppMplsRoute(
597 [VppRoutePath("0.0.0.0",
600 labels=[VppMplsLabel(44)])])
601 route_35_eos.add_vpp_config()
603 tx = self.create_stream_labelled_ip4(self.pg0,
604 [VppMplsLabel(35, ttl=3)])
605 rx = self.send_and_expect(self.pg0, tx, self.pg0)
606 self.verify_capture_labelled(self.pg0, rx, tx,
607 [VppMplsLabel(43, ttl=2),
608 VppMplsLabel(44, ttl=2)])
611 # A recursive non-EOS x-connect, which resolves through another
614 route_34_neos = VppMplsRoute(self, 34, 0,
615 [VppRoutePath("0.0.0.0",
618 labels=[VppMplsLabel(44),
620 route_34_neos.add_vpp_config()
622 tx = self.create_stream_labelled_ip4(self.pg0,
623 [VppMplsLabel(34, ttl=45),
625 rx = self.send_and_expect(self.pg0, tx, self.pg0)
626 # it's the 2nd (counting from 0) label in the stack that is swapped
627 self.verify_capture_labelled(self.pg0, rx, tx,
630 VppMplsLabel(46, ttl=44),
634 # an recursive IP route that resolves through the recursive non-eos
637 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
638 [VppRoutePath("0.0.0.0",
641 labels=[VppMplsLabel(55)])])
642 ip_10_0_0_1.add_vpp_config()
644 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
645 rx = self.send_and_expect(self.pg0, tx, self.pg0)
646 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
651 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
653 ip_10_0_0_1.remove_vpp_config()
654 route_34_neos.remove_vpp_config()
655 route_34_eos.remove_vpp_config()
656 route_33_neos.remove_vpp_config()
657 route_33_eos.remove_vpp_config()
658 route_32_neos.remove_vpp_config()
659 route_32_eos.remove_vpp_config()
662 """ MPLS Local Label Binding test """
665 # Add a non-recursive route with a single out label
667 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
668 [VppRoutePath(self.pg0.remote_ip4,
669 self.pg0.sw_if_index,
670 labels=[VppMplsLabel(45)])])
671 route_10_0_0_1.add_vpp_config()
673 # bind a local label to the route
674 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
675 binding.add_vpp_config()
678 tx = self.create_stream_labelled_ip4(self.pg0,
681 rx = self.send_and_expect(self.pg0, tx, self.pg0)
682 self.verify_capture_labelled(self.pg0, rx, tx,
683 [VppMplsLabel(45, ttl=63),
687 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
688 rx = self.send_and_expect(self.pg0, tx, self.pg0)
689 self.verify_capture_labelled(self.pg0, rx, tx,
690 [VppMplsLabel(45, ttl=63)])
693 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
694 rx = self.send_and_expect(self.pg0, tx, self.pg0)
695 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
700 binding.remove_vpp_config()
701 route_10_0_0_1.remove_vpp_config()
703 def test_imposition(self):
704 """ MPLS label imposition test """
707 # Add a non-recursive route with a single out label
709 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
710 [VppRoutePath(self.pg0.remote_ip4,
711 self.pg0.sw_if_index,
712 labels=[VppMplsLabel(32)])])
713 route_10_0_0_1.add_vpp_config()
716 # a stream that matches the route for 10.0.0.1
717 # PG0 is in the default table
719 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
720 rx = self.send_and_expect(self.pg0, tx, self.pg0)
721 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
724 # Add a non-recursive route with a 3 out labels
726 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
727 [VppRoutePath(self.pg0.remote_ip4,
728 self.pg0.sw_if_index,
729 labels=[VppMplsLabel(32),
732 route_10_0_0_2.add_vpp_config()
734 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
735 ip_ttl=44, ip_dscp=0xff)
736 rx = self.send_and_expect(self.pg0, tx, self.pg0)
737 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
744 # Add a non-recursive route with a single out label in uniform mode
746 route_10_0_0_3 = VppIpRoute(
747 self, "10.0.0.3", 32,
748 [VppRoutePath(self.pg0.remote_ip4,
749 self.pg0.sw_if_index,
750 labels=[VppMplsLabel(32,
751 mode=MplsLspMode.UNIFORM)])])
752 route_10_0_0_3.add_vpp_config()
754 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
755 ip_ttl=54, ip_dscp=0xbe)
756 rx = self.send_and_expect(self.pg0, tx, self.pg0)
757 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
758 [VppMplsLabel(32, ttl=53, exp=5)])
761 # Add a IPv6 non-recursive route with a single out label in
764 route_2001_3 = VppIpRoute(
765 self, "2001::3", 128,
766 [VppRoutePath(self.pg0.remote_ip6,
767 self.pg0.sw_if_index,
768 proto=DpoProto.DPO_PROTO_IP6,
769 labels=[VppMplsLabel(32,
770 mode=MplsLspMode.UNIFORM)])],
772 route_2001_3.add_vpp_config()
774 tx = self.create_stream_ip6(self.pg0, "2001::3",
775 ip_ttl=54, ip_dscp=0xbe)
776 rx = self.send_and_expect(self.pg0, tx, self.pg0)
777 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
778 [VppMplsLabel(32, ttl=53, exp=5)])
781 # add a recursive path, with output label, via the 1 label route
783 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
784 [VppRoutePath("10.0.0.1",
786 labels=[VppMplsLabel(44)])])
787 route_11_0_0_1.add_vpp_config()
790 # a stream that matches the route for 11.0.0.1, should pick up
791 # the label stack for 11.0.0.1 and 10.0.0.1
793 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
794 rx = self.send_and_expect(self.pg0, tx, self.pg0)
795 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
799 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
802 # add a recursive path, with 2 labels, via the 3 label route
804 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
805 [VppRoutePath("10.0.0.2",
807 labels=[VppMplsLabel(44),
809 route_11_0_0_2.add_vpp_config()
812 # a stream that matches the route for 11.0.0.1, should pick up
813 # the label stack for 11.0.0.1 and 10.0.0.1
815 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
816 rx = self.send_and_expect(self.pg0, tx, self.pg0)
817 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
824 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
826 rx = self.send_and_expect(self.pg0, tx, self.pg0)
827 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
834 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
839 route_11_0_0_2.remove_vpp_config()
840 route_11_0_0_1.remove_vpp_config()
841 route_10_0_0_2.remove_vpp_config()
842 route_10_0_0_1.remove_vpp_config()
844 def test_tunnel_pipe(self):
845 """ MPLS Tunnel Tests - Pipe """
848 # Create a tunnel with a single out label
850 mpls_tun = VppMPLSTunnelInterface(
852 [VppRoutePath(self.pg0.remote_ip4,
853 self.pg0.sw_if_index,
854 labels=[VppMplsLabel(44),
856 mpls_tun.add_vpp_config()
860 # add an unlabelled route through the new tunnel
862 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
863 [VppRoutePath("0.0.0.0",
864 mpls_tun._sw_if_index)])
865 route_10_0_0_3.add_vpp_config()
867 self.vapi.cli("clear trace")
868 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
869 self.pg0.add_stream(tx)
871 self.pg_enable_capture(self.pg_interfaces)
874 rx = self.pg0.get_capture()
875 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
880 # add a labelled route through the new tunnel
882 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
883 [VppRoutePath("0.0.0.0",
884 mpls_tun._sw_if_index,
886 route_10_0_0_4.add_vpp_config()
888 self.vapi.cli("clear trace")
889 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
890 self.pg0.add_stream(tx)
892 self.pg_enable_capture(self.pg_interfaces)
895 rx = self.pg0.get_capture()
896 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
899 VppMplsLabel(33, ttl=255)])
901 def test_tunnel_uniform(self):
902 """ MPLS Tunnel Tests - Uniform """
905 # Create a tunnel with a single out label
906 # The label stack is specified here from outer to inner
908 mpls_tun = VppMPLSTunnelInterface(
910 [VppRoutePath(self.pg0.remote_ip4,
911 self.pg0.sw_if_index,
912 labels=[VppMplsLabel(44, ttl=32),
913 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
914 mpls_tun.add_vpp_config()
918 # add an unlabelled route through the new tunnel
920 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
921 [VppRoutePath("0.0.0.0",
922 mpls_tun._sw_if_index)])
923 route_10_0_0_3.add_vpp_config()
925 self.vapi.cli("clear trace")
926 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
927 self.pg0.add_stream(tx)
929 self.pg_enable_capture(self.pg_interfaces)
932 rx = self.pg0.get_capture()
933 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
934 [VppMplsLabel(44, ttl=32),
935 VppMplsLabel(46, ttl=23)])
938 # add a labelled route through the new tunnel
940 route_10_0_0_4 = VppIpRoute(
941 self, "10.0.0.4", 32,
942 [VppRoutePath("0.0.0.0",
943 mpls_tun._sw_if_index,
944 labels=[VppMplsLabel(33, ttl=47)])])
945 route_10_0_0_4.add_vpp_config()
947 self.vapi.cli("clear trace")
948 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
949 self.pg0.add_stream(tx)
951 self.pg_enable_capture(self.pg_interfaces)
954 rx = self.pg0.get_capture()
955 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
956 [VppMplsLabel(44, ttl=32),
957 VppMplsLabel(46, ttl=47),
958 VppMplsLabel(33, ttl=47)])
960 def test_mpls_tunnel_many(self):
961 """ Multiple Tunnels """
964 mpls_tun = VppMPLSTunnelInterface(
966 [VppRoutePath(self.pg0.remote_ip4,
967 self.pg0.sw_if_index,
968 labels=[VppMplsLabel(44, ttl=32),
969 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
970 mpls_tun.add_vpp_config()
973 def test_v4_exp_null(self):
974 """ MPLS V4 Explicit NULL test """
977 # The first test case has an MPLS TTL of 0
978 # all packet should be dropped
980 tx = self.create_stream_labelled_ip4(self.pg0,
981 [VppMplsLabel(0, ttl=0)])
982 self.send_and_assert_no_replies(self.pg0, tx,
983 "MPLS TTL=0 packets forwarded")
986 # a stream with a non-zero MPLS TTL
987 # PG0 is in the default table
989 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
990 rx = self.send_and_expect(self.pg0, tx, self.pg0)
991 self.verify_capture_ip4(self.pg0, rx, tx)
994 # a stream with a non-zero MPLS TTL
996 # we are ensuring the post-pop lookup occurs in the VRF table
998 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
999 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1000 self.verify_capture_ip4(self.pg1, rx, tx)
1002 def test_v6_exp_null(self):
1003 """ MPLS V6 Explicit NULL test """
1006 # a stream with a non-zero MPLS TTL
1007 # PG0 is in the default table
1009 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1010 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1011 self.verify_capture_ip6(self.pg0, rx, tx)
1014 # a stream with a non-zero MPLS TTL
1016 # we are ensuring the post-pop lookup occurs in the VRF table
1018 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1019 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1020 self.verify_capture_ip6(self.pg0, rx, tx)
1022 def test_deag(self):
1026 # A de-agg route - next-hop lookup in default table
1028 route_34_eos = VppMplsRoute(self, 34, 1,
1029 [VppRoutePath("0.0.0.0",
1032 route_34_eos.add_vpp_config()
1035 # ping an interface in the default table
1036 # PG0 is in the default table
1038 tx = self.create_stream_labelled_ip4(self.pg0,
1042 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1043 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1046 # A de-agg route - next-hop lookup in non-default table
1048 route_35_eos = VppMplsRoute(self, 35, 1,
1049 [VppRoutePath("0.0.0.0",
1052 route_35_eos.add_vpp_config()
1055 # ping an interface in the non-default table
1056 # PG0 is in the default table. packet arrive labelled in the
1057 # default table and egress unlabelled in the non-default
1059 tx = self.create_stream_labelled_ip4(
1060 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1061 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1062 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1067 route_36_neos = VppMplsRoute(self, 36, 0,
1068 [VppRoutePath("0.0.0.0",
1070 route_36_neos.add_vpp_config()
1072 tx = self.create_stream_labelled_ip4(self.pg0,
1075 ping=1, ip_itf=self.pg1)
1076 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1077 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1079 route_36_neos.remove_vpp_config()
1080 route_35_eos.remove_vpp_config()
1081 route_34_eos.remove_vpp_config()
1083 def test_interface_rx(self):
1084 """ MPLS Interface Receive """
1087 # Add a non-recursive route that will forward the traffic
1090 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1092 paths=[VppRoutePath(self.pg1.remote_ip4,
1093 self.pg1.sw_if_index)])
1094 route_10_0_0_1.add_vpp_config()
1097 # An interface receive label that maps traffic to RX on interface
1099 # by injecting the packet in on pg0, which is in table 0
1100 # doing an interface-rx on pg1 and matching a route in table 1
1101 # if the packet egresses, then we must have swapped to pg1
1102 # so as to have matched the route in table 1
1104 route_34_eos = VppMplsRoute(self, 34, 1,
1105 [VppRoutePath("0.0.0.0",
1106 self.pg1.sw_if_index,
1107 is_interface_rx=1)])
1108 route_34_eos.add_vpp_config()
1111 # ping an interface in the default table
1112 # PG0 is in the default table
1114 tx = self.create_stream_labelled_ip4(self.pg0,
1117 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1118 self.verify_capture_ip4(self.pg1, rx, tx)
1120 def test_mcast_mid_point(self):
1121 """ MPLS Multicast Mid Point """
1124 # Add a non-recursive route that will forward the traffic
1127 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1129 paths=[VppRoutePath(self.pg1.remote_ip4,
1130 self.pg1.sw_if_index)])
1131 route_10_0_0_1.add_vpp_config()
1134 # Add a mcast entry that replicate to pg2 and pg3
1135 # and replicate to a interface-rx (like a bud node would)
1137 route_3400_eos = VppMplsRoute(
1139 [VppRoutePath(self.pg2.remote_ip4,
1140 self.pg2.sw_if_index,
1141 labels=[VppMplsLabel(3401)]),
1142 VppRoutePath(self.pg3.remote_ip4,
1143 self.pg3.sw_if_index,
1144 labels=[VppMplsLabel(3402)]),
1145 VppRoutePath("0.0.0.0",
1146 self.pg1.sw_if_index,
1147 is_interface_rx=1)],
1149 route_3400_eos.add_vpp_config()
1152 # ping an interface in the default table
1153 # PG0 is in the default table
1155 self.vapi.cli("clear trace")
1156 tx = self.create_stream_labelled_ip4(self.pg0,
1157 [VppMplsLabel(3400, ttl=64)],
1160 self.pg0.add_stream(tx)
1162 self.pg_enable_capture(self.pg_interfaces)
1165 rx = self.pg1.get_capture(257)
1166 self.verify_capture_ip4(self.pg1, rx, tx)
1168 rx = self.pg2.get_capture(257)
1169 self.verify_capture_labelled(self.pg2, rx, tx,
1170 [VppMplsLabel(3401, ttl=63)])
1171 rx = self.pg3.get_capture(257)
1172 self.verify_capture_labelled(self.pg3, rx, tx,
1173 [VppMplsLabel(3402, ttl=63)])
1175 def test_mcast_head(self):
1176 """ MPLS Multicast Head-end """
1179 # Create a multicast tunnel with two replications
1181 mpls_tun = VppMPLSTunnelInterface(
1183 [VppRoutePath(self.pg2.remote_ip4,
1184 self.pg2.sw_if_index,
1185 labels=[VppMplsLabel(42)]),
1186 VppRoutePath(self.pg3.remote_ip4,
1187 self.pg3.sw_if_index,
1188 labels=[VppMplsLabel(43)])],
1190 mpls_tun.add_vpp_config()
1194 # add an unlabelled route through the new tunnel
1196 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1197 [VppRoutePath("0.0.0.0",
1198 mpls_tun._sw_if_index)])
1199 route_10_0_0_3.add_vpp_config()
1201 self.vapi.cli("clear trace")
1202 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1203 self.pg0.add_stream(tx)
1205 self.pg_enable_capture(self.pg_interfaces)
1208 rx = self.pg2.get_capture(257)
1209 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1210 rx = self.pg3.get_capture(257)
1211 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1214 # An an IP multicast route via the tunnel
1216 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1218 route_232_1_1_1 = VppIpMRoute(
1222 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1223 [VppMRoutePath(self.pg0.sw_if_index,
1224 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1225 VppMRoutePath(mpls_tun._sw_if_index,
1226 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1227 route_232_1_1_1.add_vpp_config()
1229 self.vapi.cli("clear trace")
1230 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1231 self.pg0.add_stream(tx)
1233 self.pg_enable_capture(self.pg_interfaces)
1236 rx = self.pg2.get_capture(257)
1237 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1238 rx = self.pg3.get_capture(257)
1239 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1241 def test_mcast_ip4_tail(self):
1242 """ MPLS IPv4 Multicast Tail """
1245 # Add a multicast route that will forward the traffic
1248 route_232_1_1_1 = VppIpMRoute(
1252 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1254 paths=[VppMRoutePath(self.pg1.sw_if_index,
1255 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1256 route_232_1_1_1.add_vpp_config()
1259 # An interface receive label that maps traffic to RX on interface
1261 # by injecting the packet in on pg0, which is in table 0
1262 # doing an rpf-id and matching a route in table 1
1263 # if the packet egresses, then we must have matched the route in
1266 route_34_eos = VppMplsRoute(self, 34, 1,
1267 [VppRoutePath("0.0.0.0",
1268 self.pg1.sw_if_index,
1273 route_34_eos.add_vpp_config()
1276 # Drop due to interface lookup miss
1278 self.vapi.cli("clear trace")
1279 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1280 dst_ip="232.1.1.1", n=1)
1281 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1284 # set the RPF-ID of the entry to match the input packet's
1286 route_232_1_1_1.update_rpf_id(55)
1288 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1290 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1291 self.verify_capture_ip4(self.pg1, rx, tx)
1294 # disposed packets have an invalid IPv4 checksum
1296 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1297 dst_ip="232.1.1.1", n=65,
1299 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1302 # set the RPF-ID of the entry to not match the input packet's
1304 route_232_1_1_1.update_rpf_id(56)
1305 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1307 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1309 def test_mcast_ip6_tail(self):
1310 """ MPLS IPv6 Multicast Tail """
1313 # Add a multicast route that will forward the traffic
1316 route_ff = VppIpMRoute(
1320 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1322 paths=[VppMRoutePath(self.pg1.sw_if_index,
1323 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
1325 route_ff.add_vpp_config()
1328 # An interface receive label that maps traffic to RX on interface
1330 # by injecting the packet in on pg0, which is in table 0
1331 # doing an rpf-id and matching a route in table 1
1332 # if the packet egresses, then we must have matched the route in
1335 route_34_eos = VppMplsRoute(
1338 self.pg1.sw_if_index,
1341 proto=DpoProto.DPO_PROTO_IP6)],
1344 route_34_eos.add_vpp_config()
1347 # Drop due to interface lookup miss
1349 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1351 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1354 # set the RPF-ID of the entry to match the input packet's
1356 route_ff.update_rpf_id(55)
1358 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1360 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1361 self.verify_capture_ip6(self.pg1, rx, tx)
1364 # disposed packets have hop-limit = 1
1366 tx = self.create_stream_labelled_ip6(self.pg0,
1370 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1371 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1374 # set the RPF-ID of the entry to not match the input packet's
1376 route_ff.update_rpf_id(56)
1377 tx = self.create_stream_labelled_ip6(self.pg0,
1380 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1383 class TestMPLSDisabled(VppTestCase):
1384 """ MPLS disabled """
1387 super(TestMPLSDisabled, self).setUp()
1389 # create 2 pg interfaces
1390 self.create_pg_interfaces(range(2))
1392 self.tbl = VppMplsTable(self, 0)
1393 self.tbl.add_vpp_config()
1395 # PG0 is MPLS enabled
1397 self.pg0.config_ip4()
1398 self.pg0.resolve_arp()
1399 self.pg0.enable_mpls()
1401 # PG 1 is not MPLS enabled
1405 for i in self.pg_interfaces:
1409 self.pg0.disable_mpls()
1410 super(TestMPLSDisabled, self).tearDown()
1412 def test_mpls_disabled(self):
1413 """ MPLS Disabled """
1415 tx = (Ether(src=self.pg1.remote_mac,
1416 dst=self.pg1.local_mac) /
1417 MPLS(label=32, ttl=64) /
1418 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1419 UDP(sport=1234, dport=1234) /
1423 # A simple MPLS xconnect - eos label in label out
1425 route_32_eos = VppMplsRoute(self, 32, 1,
1426 [VppRoutePath(self.pg0.remote_ip4,
1427 self.pg0.sw_if_index,
1429 route_32_eos.add_vpp_config()
1432 # PG1 does not forward IP traffic
1434 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1439 self.pg1.enable_mpls()
1442 # Now we get packets through
1444 self.pg1.add_stream(tx)
1445 self.pg_enable_capture(self.pg_interfaces)
1448 rx = self.pg0.get_capture(1)
1453 self.pg1.disable_mpls()
1456 # PG1 does not forward IP traffic
1458 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1459 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1462 class TestMPLSPIC(VppTestCase):
1463 """ MPLS PIC edge convergence """
1466 super(TestMPLSPIC, self).setUp()
1468 # create 2 pg interfaces
1469 self.create_pg_interfaces(range(4))
1471 mpls_tbl = VppMplsTable(self, 0)
1472 mpls_tbl.add_vpp_config()
1473 tbl4 = VppIpTable(self, 1)
1474 tbl4.add_vpp_config()
1475 tbl6 = VppIpTable(self, 1, is_ip6=1)
1476 tbl6.add_vpp_config()
1480 self.pg0.config_ip4()
1481 self.pg0.resolve_arp()
1482 self.pg0.enable_mpls()
1484 self.pg1.config_ip4()
1485 self.pg1.resolve_arp()
1486 self.pg1.enable_mpls()
1488 # VRF (customer facing) link
1490 self.pg2.set_table_ip4(1)
1491 self.pg2.config_ip4()
1492 self.pg2.resolve_arp()
1493 self.pg2.set_table_ip6(1)
1494 self.pg2.config_ip6()
1495 self.pg2.resolve_ndp()
1497 self.pg3.set_table_ip4(1)
1498 self.pg3.config_ip4()
1499 self.pg3.resolve_arp()
1500 self.pg3.set_table_ip6(1)
1501 self.pg3.config_ip6()
1502 self.pg3.resolve_ndp()
1505 self.pg0.disable_mpls()
1506 self.pg1.disable_mpls()
1507 for i in self.pg_interfaces:
1513 super(TestMPLSPIC, self).tearDown()
1515 def test_mpls_ibgp_pic(self):
1516 """ MPLS iBGP PIC edge convergence
1518 1) setup many iBGP VPN routes via a pair of iBGP peers.
1519 2) Check EMCP forwarding to these peers
1520 3) withdraw the IGP route to one of these peers.
1521 4) check forwarding continues to the remaining peer
1525 # IGP+LDP core routes
1527 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1528 [VppRoutePath(self.pg0.remote_ip4,
1529 self.pg0.sw_if_index,
1531 core_10_0_0_45.add_vpp_config()
1533 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1534 [VppRoutePath(self.pg1.remote_ip4,
1535 self.pg1.sw_if_index,
1537 core_10_0_0_46.add_vpp_config()
1540 # Lot's of VPN routes. We need more the 64 so VPP will build
1541 # the fast convergence indirection
1545 for ii in range(64):
1546 dst = "192.168.1.%d" % ii
1547 vpn_routes.append(VppIpRoute(self, dst, 32,
1548 [VppRoutePath("10.0.0.45",
1552 VppRoutePath("10.0.0.46",
1555 is_resolve_host=1)],
1557 vpn_routes[ii].add_vpp_config()
1559 pkts.append(Ether(dst=self.pg2.local_mac,
1560 src=self.pg2.remote_mac) /
1561 IP(src=self.pg2.remote_ip4, dst=dst) /
1562 UDP(sport=1234, dport=1234) /
1566 # Send the packet stream (one pkt to each VPN route)
1567 # - expect a 50-50 split of the traffic
1569 self.pg2.add_stream(pkts)
1570 self.pg_enable_capture(self.pg_interfaces)
1573 rx0 = self.pg0._get_capture(1)
1574 rx1 = self.pg1._get_capture(1)
1576 # not testing the LB hashing algorithm so we're not concerned
1577 # with the split ratio, just as long as neither is 0
1578 self.assertNotEqual(0, len(rx0))
1579 self.assertNotEqual(0, len(rx1))
1582 # use a test CLI command to stop the FIB walk process, this
1583 # will prevent the FIB converging the VPN routes and thus allow
1584 # us to probe the interim (post-fail, pre-converge) state
1586 self.vapi.ppcli("test fib-walk-process disable")
1589 # Withdraw one of the IGP routes
1591 core_10_0_0_46.remove_vpp_config()
1594 # now all packets should be forwarded through the remaining peer
1596 self.vapi.ppcli("clear trace")
1597 self.pg2.add_stream(pkts)
1598 self.pg_enable_capture(self.pg_interfaces)
1601 rx0 = self.pg0.get_capture(len(pkts))
1604 # enable the FIB walk process to converge the FIB
1606 self.vapi.ppcli("test fib-walk-process enable")
1609 # packets should still be forwarded through the remaining peer
1611 self.pg2.add_stream(pkts)
1612 self.pg_enable_capture(self.pg_interfaces)
1615 rx0 = self.pg0.get_capture(64)
1618 # Add the IGP route back and we return to load-balancing
1620 core_10_0_0_46.add_vpp_config()
1622 self.pg2.add_stream(pkts)
1623 self.pg_enable_capture(self.pg_interfaces)
1626 rx0 = self.pg0._get_capture(1)
1627 rx1 = self.pg1._get_capture(1)
1628 self.assertNotEqual(0, len(rx0))
1629 self.assertNotEqual(0, len(rx1))
1631 def test_mpls_ebgp_pic(self):
1632 """ MPLS eBGP PIC edge convergence
1634 1) setup many eBGP VPN routes via a pair of eBGP peers
1635 2) Check EMCP forwarding to these peers
1636 3) withdraw one eBGP path - expect LB across remaining eBGP
1640 # Lot's of VPN routes. We need more the 64 so VPP will build
1641 # the fast convergence indirection
1646 for ii in range(64):
1647 dst = "192.168.1.%d" % ii
1648 local_label = 1600 + ii
1649 vpn_routes.append(VppIpRoute(self, dst, 32,
1650 [VppRoutePath(self.pg2.remote_ip4,
1653 is_resolve_attached=1),
1654 VppRoutePath(self.pg3.remote_ip4,
1657 is_resolve_attached=1)],
1659 vpn_routes[ii].add_vpp_config()
1661 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1663 vpn_bindings[ii].add_vpp_config()
1665 pkts.append(Ether(dst=self.pg0.local_mac,
1666 src=self.pg0.remote_mac) /
1667 MPLS(label=local_label, ttl=64) /
1668 IP(src=self.pg0.remote_ip4, dst=dst) /
1669 UDP(sport=1234, dport=1234) /
1672 self.pg0.add_stream(pkts)
1673 self.pg_enable_capture(self.pg_interfaces)
1676 rx0 = self.pg2._get_capture(1)
1677 rx1 = self.pg3._get_capture(1)
1678 self.assertNotEqual(0, len(rx0))
1679 self.assertNotEqual(0, len(rx1))
1682 # use a test CLI command to stop the FIB walk process, this
1683 # will prevent the FIB converging the VPN routes and thus allow
1684 # us to probe the interim (post-fail, pre-converge) state
1686 self.vapi.ppcli("test fib-walk-process disable")
1689 # withdraw the connected prefix on the interface.
1691 self.pg2.unconfig_ip4()
1694 # now all packets should be forwarded through the remaining peer
1696 self.pg0.add_stream(pkts)
1697 self.pg_enable_capture(self.pg_interfaces)
1700 rx0 = self.pg3.get_capture(len(pkts))
1703 # enable the FIB walk process to converge the FIB
1705 self.vapi.ppcli("test fib-walk-process enable")
1706 self.pg0.add_stream(pkts)
1707 self.pg_enable_capture(self.pg_interfaces)
1710 rx0 = self.pg3.get_capture(len(pkts))
1713 # put the connecteds back
1715 self.pg2.config_ip4()
1717 self.pg0.add_stream(pkts)
1718 self.pg_enable_capture(self.pg_interfaces)
1721 rx0 = self.pg2._get_capture(1)
1722 rx1 = self.pg3._get_capture(1)
1723 self.assertNotEqual(0, len(rx0))
1724 self.assertNotEqual(0, len(rx1))
1726 def test_mpls_v6_ebgp_pic(self):
1727 """ MPLSv6 eBGP PIC edge convergence
1729 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1730 2) Check EMCP forwarding to these peers
1731 3) withdraw one eBGP path - expect LB across remaining eBGP
1735 # Lot's of VPN routes. We need more the 64 so VPP will build
1736 # the fast convergence indirection
1741 for ii in range(64):
1742 dst = "3000::%d" % ii
1743 local_label = 1600 + ii
1744 vpn_routes.append(VppIpRoute(
1746 [VppRoutePath(self.pg2.remote_ip6,
1749 is_resolve_attached=1,
1750 proto=DpoProto.DPO_PROTO_IP6),
1751 VppRoutePath(self.pg3.remote_ip6,
1754 proto=DpoProto.DPO_PROTO_IP6,
1755 is_resolve_attached=1)],
1758 vpn_routes[ii].add_vpp_config()
1760 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1763 vpn_bindings[ii].add_vpp_config()
1765 pkts.append(Ether(dst=self.pg0.local_mac,
1766 src=self.pg0.remote_mac) /
1767 MPLS(label=local_label, ttl=64) /
1768 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1769 UDP(sport=1234, dport=1234) /
1772 self.pg0.add_stream(pkts)
1773 self.pg_enable_capture(self.pg_interfaces)
1776 rx0 = self.pg2._get_capture(1)
1777 rx1 = self.pg3._get_capture(1)
1778 self.assertNotEqual(0, len(rx0))
1779 self.assertNotEqual(0, len(rx1))
1782 # use a test CLI command to stop the FIB walk process, this
1783 # will prevent the FIB converging the VPN routes and thus allow
1784 # us to probe the interim (post-fail, pre-converge) state
1786 self.vapi.ppcli("test fib-walk-process disable")
1789 # withdraw the connected prefix on the interface.
1790 # and shutdown the interface so the ND cache is flushed.
1792 self.pg2.unconfig_ip6()
1793 self.pg2.admin_down()
1796 # now all packets should be forwarded through the remaining peer
1798 self.pg0.add_stream(pkts)
1799 self.pg_enable_capture(self.pg_interfaces)
1802 rx0 = self.pg3.get_capture(len(pkts))
1805 # enable the FIB walk process to converge the FIB
1807 self.vapi.ppcli("test fib-walk-process enable")
1808 self.pg0.add_stream(pkts)
1809 self.pg_enable_capture(self.pg_interfaces)
1812 rx0 = self.pg3.get_capture(len(pkts))
1815 # put the connecteds back
1818 self.pg2.config_ip6()
1820 self.pg0.add_stream(pkts)
1821 self.pg_enable_capture(self.pg_interfaces)
1824 rx0 = self.pg2._get_capture(1)
1825 rx1 = self.pg3._get_capture(1)
1826 self.assertNotEqual(0, len(rx0))
1827 self.assertNotEqual(0, len(rx1))
1830 class TestMPLSL2(VppTestCase):
1834 super(TestMPLSL2, self).setUp()
1836 # create 2 pg interfaces
1837 self.create_pg_interfaces(range(2))
1839 # create the default MPLS table
1841 tbl = VppMplsTable(self, 0)
1842 tbl.add_vpp_config()
1843 self.tables.append(tbl)
1845 # use pg0 as the core facing interface
1847 self.pg0.config_ip4()
1848 self.pg0.resolve_arp()
1849 self.pg0.enable_mpls()
1851 # use the other 2 for customer facing L2 links
1852 for i in self.pg_interfaces[1:]:
1856 for i in self.pg_interfaces[1:]:
1859 self.pg0.disable_mpls()
1860 self.pg0.unconfig_ip4()
1861 self.pg0.admin_down()
1862 super(TestMPLSL2, self).tearDown()
1864 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
1865 capture = verify_filter(capture, sent)
1867 self.assertEqual(len(capture), len(sent))
1869 for i in range(len(capture)):
1873 # the MPLS TTL is 255 since it enters a new tunnel
1874 verify_mpls_stack(self, rx, mpls_labels)
1877 rx_eth = Ether(scapy.compat.raw(rx[MPLS].payload))
1879 self.assertEqual(rx_eth.src, tx_eth.src)
1880 self.assertEqual(rx_eth.dst, tx_eth.dst)
1882 def test_vpws(self):
1883 """ Virtual Private Wire Service """
1886 # Create an MPLS tunnel that pushes 1 label
1887 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
1888 # information is not in the packet, but we test it works anyway
1890 mpls_tun_1 = VppMPLSTunnelInterface(
1892 [VppRoutePath(self.pg0.remote_ip4,
1893 self.pg0.sw_if_index,
1894 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
1896 mpls_tun_1.add_vpp_config()
1897 mpls_tun_1.admin_up()
1900 # Create a label entry to for 55 that does L2 input to the tunnel
1902 route_55_eos = VppMplsRoute(
1904 [VppRoutePath("0.0.0.0",
1905 mpls_tun_1.sw_if_index,
1907 proto=DpoProto.DPO_PROTO_ETHERNET)])
1908 route_55_eos.add_vpp_config()
1911 # Cross-connect the tunnel with one of the customers L2 interfaces
1913 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
1914 mpls_tun_1.sw_if_index,
1916 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
1917 self.pg1.sw_if_index,
1921 # inject a packet from the core
1923 pcore = (Ether(dst=self.pg0.local_mac,
1924 src=self.pg0.remote_mac) /
1925 MPLS(label=55, ttl=64) /
1926 Ether(dst="00:00:de:ad:ba:be",
1927 src="00:00:de:ad:be:ef") /
1928 IP(src="10.10.10.10", dst="11.11.11.11") /
1929 UDP(sport=1234, dport=1234) /
1933 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
1934 payload = pcore[MPLS].payload
1936 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
1937 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
1940 # Inject a packet from the customer/L2 side
1942 tx1 = pcore[MPLS].payload * 65
1943 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
1945 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
1947 def test_vpls(self):
1948 """ Virtual Private LAN Service """
1950 # Create an L2 MPLS tunnel
1952 mpls_tun = VppMPLSTunnelInterface(
1954 [VppRoutePath(self.pg0.remote_ip4,
1955 self.pg0.sw_if_index,
1956 labels=[VppMplsLabel(42)])],
1958 mpls_tun.add_vpp_config()
1962 # Create a label entry to for 55 that does L2 input to the tunnel
1964 route_55_eos = VppMplsRoute(
1966 [VppRoutePath("0.0.0.0",
1967 mpls_tun.sw_if_index,
1969 proto=DpoProto.DPO_PROTO_ETHERNET)])
1970 route_55_eos.add_vpp_config()
1973 # add to tunnel to the customers bridge-domain
1975 self.vapi.sw_interface_set_l2_bridge(
1976 rx_sw_if_index=mpls_tun.sw_if_index, bd_id=1)
1977 self.vapi.sw_interface_set_l2_bridge(
1978 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1)
1981 # Packet from the customer interface and from the core
1983 p_cust = (Ether(dst="00:00:de:ad:ba:be",
1984 src="00:00:de:ad:be:ef") /
1985 IP(src="10.10.10.10", dst="11.11.11.11") /
1986 UDP(sport=1234, dport=1234) /
1988 p_core = (Ether(src="00:00:de:ad:ba:be",
1989 dst="00:00:de:ad:be:ef") /
1990 IP(dst="10.10.10.10", src="11.11.11.11") /
1991 UDP(sport=1234, dport=1234) /
1995 # The BD is learning, so send in one of each packet to learn
1997 p_core_encap = (Ether(dst=self.pg0.local_mac,
1998 src=self.pg0.remote_mac) /
1999 MPLS(label=55, ttl=64) /
2002 self.pg1.add_stream(p_cust)
2003 self.pg_enable_capture(self.pg_interfaces)
2005 self.pg0.add_stream(p_core_encap)
2006 self.pg_enable_capture(self.pg_interfaces)
2009 # we've learnt this so expect it be be forwarded
2010 rx0 = self.pg1.get_capture(1)
2012 self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst)
2013 self.assertEqual(rx0[0][Ether].src, p_core[Ether].src)
2016 # now a stream in each direction
2018 self.pg1.add_stream(p_cust * 65)
2019 self.pg_enable_capture(self.pg_interfaces)
2022 rx0 = self.pg0.get_capture(65)
2024 self.verify_capture_tunneled_ethernet(rx0, p_cust*65,
2028 # remove interfaces from customers bridge-domain
2030 self.vapi.sw_interface_set_l2_bridge(
2031 rx_sw_if_index=mpls_tun.sw_if_index, bd_id=1, enable=0)
2032 self.vapi.sw_interface_set_l2_bridge(
2033 rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0)
2035 if __name__ == '__main__':
2036 unittest.main(testRunner=VppTestRunner)