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
12 from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
14 from scapy.packet import Raw
15 from scapy.layers.l2 import Ether
16 from scapy.layers.inet import IP, UDP, ICMP
17 from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded
18 from scapy.contrib.mpls import MPLS
21 def verify_filter(capture, sent):
22 if not len(capture) == len(sent):
23 # filter out any IPv6 RAs from the capture
30 def verify_mpls_stack(tst, rx, mpls_labels):
31 # the rx'd packet has the MPLS label popped
33 tst.assertEqual(eth.type, 0x8847)
37 for ii in range(len(mpls_labels)):
38 tst.assertEqual(rx_mpls.label, mpls_labels[ii].value)
39 tst.assertEqual(rx_mpls.cos, mpls_labels[ii].exp)
40 tst.assertEqual(rx_mpls.ttl, mpls_labels[ii].ttl)
42 if ii == len(mpls_labels) - 1:
43 tst.assertEqual(rx_mpls.s, 1)
46 tst.assertEqual(rx_mpls.s, 0)
47 # pop the label to expose the next
48 rx_mpls = rx_mpls[MPLS].payload
51 class TestMPLS(VppTestCase):
52 """ MPLS Test Case """
55 super(TestMPLS, self).setUp()
57 # create 2 pg interfaces
58 self.create_pg_interfaces(range(4))
60 # setup both interfaces
61 # assign them different tables.
65 tbl = VppMplsTable(self, 0)
67 self.tables.append(tbl)
69 for i in self.pg_interfaces:
73 tbl = VppIpTable(self, table_id)
75 self.tables.append(tbl)
76 tbl = VppIpTable(self, table_id, is_ip6=1)
78 self.tables.append(tbl)
80 i.set_table_ip4(table_id)
81 i.set_table_ip6(table_id)
90 for i in self.pg_interfaces:
98 super(TestMPLS, self).tearDown()
100 # the default of 64 matches the IP packet TTL default
101 def create_stream_labelled_ip4(
111 self.reset_packet_infos()
113 for i in range(0, n):
114 info = self.create_packet_info(src_if, src_if)
115 payload = self.info_to_payload(info)
116 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
118 for ii in range(len(mpls_labels)):
119 p = p / MPLS(label=mpls_labels[ii].value,
120 ttl=mpls_labels[ii].ttl,
121 cos=mpls_labels[ii].exp)
124 p = (p / IP(src=src_if.local_ip4,
125 dst=src_if.remote_ip4,
127 UDP(sport=1234, dport=1234) /
130 p = (p / IP(src=src_if.local_ip4, dst=dst_ip, ttl=ip_ttl) /
131 UDP(sport=1234, dport=1234) /
134 p = (p / IP(src=ip_itf.remote_ip4,
135 dst=ip_itf.local_ip4,
140 p[IP].chksum = chksum
145 def create_stream_ip4(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
146 self.reset_packet_infos()
148 for i in range(0, 257):
149 info = self.create_packet_info(src_if, src_if)
150 payload = self.info_to_payload(info)
151 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
152 IP(src=src_if.remote_ip4, dst=dst_ip,
153 ttl=ip_ttl, tos=ip_dscp) /
154 UDP(sport=1234, dport=1234) /
160 def create_stream_ip6(self, src_if, dst_ip, ip_ttl=64, ip_dscp=0):
161 self.reset_packet_infos()
163 for i in range(0, 257):
164 info = self.create_packet_info(src_if, src_if)
165 payload = self.info_to_payload(info)
166 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
167 IPv6(src=src_if.remote_ip6, dst=dst_ip,
168 hlim=ip_ttl, tc=ip_dscp) /
169 UDP(sport=1234, dport=1234) /
175 def create_stream_labelled_ip6(self, src_if, mpls_labels,
176 hlim=64, dst_ip=None):
178 dst_ip = src_if.remote_ip6
179 self.reset_packet_infos()
181 for i in range(0, 257):
182 info = self.create_packet_info(src_if, src_if)
183 payload = self.info_to_payload(info)
184 p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
185 for l in mpls_labels:
186 p = p / MPLS(label=l.value, ttl=l.ttl, cos=l.exp)
188 p = p / (IPv6(src=src_if.remote_ip6, dst=dst_ip, hlim=hlim) /
189 UDP(sport=1234, dport=1234) /
195 def verify_capture_ip4(self, src_if, capture, sent, ping_resp=0,
196 ip_ttl=None, ip_dscp=0):
198 capture = verify_filter(capture, sent)
200 self.assertEqual(len(capture), len(sent))
202 for i in range(len(capture)):
206 # the rx'd packet has the MPLS label popped
208 self.assertEqual(eth.type, 0x800)
214 self.assertEqual(rx_ip.src, tx_ip.src)
215 self.assertEqual(rx_ip.dst, tx_ip.dst)
216 self.assertEqual(rx_ip.tos, ip_dscp)
218 # IP processing post pop has decremented the TTL
219 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
221 self.assertEqual(rx_ip.ttl, ip_ttl)
223 self.assertEqual(rx_ip.src, tx_ip.dst)
224 self.assertEqual(rx_ip.dst, tx_ip.src)
229 def verify_capture_labelled_ip4(self, src_if, capture, sent,
230 mpls_labels, ip_ttl=None):
232 capture = verify_filter(capture, sent)
234 self.assertEqual(len(capture), len(sent))
236 for i in range(len(capture)):
242 verify_mpls_stack(self, rx, mpls_labels)
244 self.assertEqual(rx_ip.src, tx_ip.src)
245 self.assertEqual(rx_ip.dst, tx_ip.dst)
247 # IP processing post pop has decremented the TTL
248 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
250 self.assertEqual(rx_ip.ttl, ip_ttl)
255 def verify_capture_labelled_ip6(self, src_if, capture, sent,
256 mpls_labels, ip_ttl=None):
258 capture = verify_filter(capture, sent)
260 self.assertEqual(len(capture), len(sent))
262 for i in range(len(capture)):
268 verify_mpls_stack(self, rx, mpls_labels)
270 self.assertEqual(rx_ip.src, tx_ip.src)
271 self.assertEqual(rx_ip.dst, tx_ip.dst)
273 # IP processing post pop has decremented the TTL
274 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
276 self.assertEqual(rx_ip.hlim, ip_ttl)
281 def verify_capture_tunneled_ip4(self, src_if, capture, sent, mpls_labels):
283 capture = verify_filter(capture, sent)
285 self.assertEqual(len(capture), len(sent))
287 for i in range(len(capture)):
293 verify_mpls_stack(self, rx, mpls_labels)
295 self.assertEqual(rx_ip.src, tx_ip.src)
296 self.assertEqual(rx_ip.dst, tx_ip.dst)
297 # IP processing post pop has decremented the TTL
298 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
303 def verify_capture_labelled(self, src_if, capture, sent,
306 capture = verify_filter(capture, sent)
308 self.assertEqual(len(capture), len(sent))
310 for i in range(len(capture)):
312 verify_mpls_stack(self, rx, mpls_labels)
316 def verify_capture_ip6(self, src_if, capture, sent,
317 ip_hlim=None, ip_dscp=0):
319 self.assertEqual(len(capture), len(sent))
321 for i in range(len(capture)):
325 # the rx'd packet has the MPLS label popped
327 self.assertEqual(eth.type, 0x86DD)
332 self.assertEqual(rx_ip.src, tx_ip.src)
333 self.assertEqual(rx_ip.dst, tx_ip.dst)
334 self.assertEqual(rx_ip.tc, ip_dscp)
335 # IP processing post pop has decremented the TTL
337 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
339 self.assertEqual(rx_ip.hlim, ip_hlim)
344 def verify_capture_ip6_icmp(self, src_if, capture, sent):
346 self.assertEqual(len(capture), len(sent))
348 for i in range(len(capture)):
352 # the rx'd packet has the MPLS label popped
354 self.assertEqual(eth.type, 0x86DD)
359 self.assertEqual(rx_ip.dst, tx_ip.src)
360 # ICMP sourced from the interface's address
361 self.assertEqual(rx_ip.src, src_if.local_ip6)
362 # hop-limit reset to 255 for IMCP packet
363 self.assertEqual(rx_ip.hlim, 254)
365 icmp = rx[ICMPv6TimeExceeded]
371 """ MPLS label swap tests """
374 # A simple MPLS xconnect - eos label in label out
376 route_32_eos = VppMplsRoute(self, 32, 1,
377 [VppRoutePath(self.pg0.remote_ip4,
378 self.pg0.sw_if_index,
379 labels=[VppMplsLabel(33)])])
380 route_32_eos.add_vpp_config()
383 # a stream that matches the route for 10.0.0.1
384 # PG0 is in the default table
386 tx = self.create_stream_labelled_ip4(self.pg0,
387 [VppMplsLabel(32, ttl=32, exp=1)])
388 rx = self.send_and_expect(self.pg0, tx, self.pg0)
389 self.verify_capture_labelled(self.pg0, rx, tx,
390 [VppMplsLabel(33, ttl=31, exp=1)])
392 self.assertEqual(route_32_eos.get_stats_to()['packets'], 257)
395 # A simple MPLS xconnect - non-eos label in label out
397 route_32_neos = VppMplsRoute(self, 32, 0,
398 [VppRoutePath(self.pg0.remote_ip4,
399 self.pg0.sw_if_index,
400 labels=[VppMplsLabel(33)])])
401 route_32_neos.add_vpp_config()
404 # a stream that matches the route for 10.0.0.1
405 # PG0 is in the default table
407 tx = self.create_stream_labelled_ip4(self.pg0,
408 [VppMplsLabel(32, ttl=21, exp=7),
410 rx = self.send_and_expect(self.pg0, tx, self.pg0)
411 self.verify_capture_labelled(self.pg0, rx, tx,
412 [VppMplsLabel(33, ttl=20, exp=7),
414 self.assertEqual(route_32_neos.get_stats_to()['packets'], 257)
417 # A simple MPLS xconnect - non-eos label in label out, uniform mode
419 route_42_neos = VppMplsRoute(
421 [VppRoutePath(self.pg0.remote_ip4,
422 self.pg0.sw_if_index,
423 labels=[VppMplsLabel(43, MplsLspMode.UNIFORM)])])
424 route_42_neos.add_vpp_config()
426 tx = self.create_stream_labelled_ip4(self.pg0,
427 [VppMplsLabel(42, ttl=21, exp=7),
429 rx = self.send_and_expect(self.pg0, tx, self.pg0)
430 self.verify_capture_labelled(self.pg0, rx, tx,
431 [VppMplsLabel(43, ttl=20, exp=7),
435 # An MPLS xconnect - EOS label in IP out
437 route_33_eos = VppMplsRoute(self, 33, 1,
438 [VppRoutePath(self.pg0.remote_ip4,
439 self.pg0.sw_if_index,
441 route_33_eos.add_vpp_config()
443 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)])
444 rx = self.send_and_expect(self.pg0, tx, self.pg0)
445 self.verify_capture_ip4(self.pg0, rx, tx)
448 # disposed packets have an invalid IPv4 checkusm
450 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(33)],
451 dst_ip=self.pg0.remote_ip4,
454 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
457 # An MPLS xconnect - EOS label in IP out, uniform mode
459 route_3333_eos = VppMplsRoute(
461 [VppRoutePath(self.pg0.remote_ip4,
462 self.pg0.sw_if_index,
463 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)])])
464 route_3333_eos.add_vpp_config()
466 tx = self.create_stream_labelled_ip4(
468 [VppMplsLabel(3333, ttl=55, exp=3)])
469 rx = self.send_and_expect(self.pg0, tx, self.pg0)
470 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=54, ip_dscp=0x60)
471 tx = self.create_stream_labelled_ip4(
473 [VppMplsLabel(3333, ttl=66, exp=4)])
474 rx = self.send_and_expect(self.pg0, tx, self.pg0)
475 self.verify_capture_ip4(self.pg0, rx, tx, ip_ttl=65, ip_dscp=0x80)
478 # An MPLS xconnect - EOS label in IPv6 out
480 route_333_eos = VppMplsRoute(
482 [VppRoutePath(self.pg0.remote_ip6,
483 self.pg0.sw_if_index,
485 proto=DpoProto.DPO_PROTO_IP6)])
486 route_333_eos.add_vpp_config()
488 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(333)])
489 rx = self.send_and_expect(self.pg0, tx, self.pg0)
490 self.verify_capture_ip6(self.pg0, rx, tx)
493 # disposed packets have an TTL expired
495 tx = self.create_stream_labelled_ip6(self.pg0,
496 [VppMplsLabel(333, ttl=64)],
497 dst_ip=self.pg1.remote_ip6,
499 rx = self.send_and_expect(self.pg0, tx, self.pg0)
500 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
503 # An MPLS xconnect - EOS label in IPv6 out w imp-null
505 route_334_eos = VppMplsRoute(
507 [VppRoutePath(self.pg0.remote_ip6,
508 self.pg0.sw_if_index,
509 labels=[VppMplsLabel(3)],
510 proto=DpoProto.DPO_PROTO_IP6)])
511 route_334_eos.add_vpp_config()
513 tx = self.create_stream_labelled_ip6(self.pg0,
514 [VppMplsLabel(334, ttl=64)])
515 rx = self.send_and_expect(self.pg0, tx, self.pg0)
516 self.verify_capture_ip6(self.pg0, rx, tx)
519 # An MPLS xconnect - EOS label in IPv6 out w imp-null in uniform mode
521 route_335_eos = VppMplsRoute(
523 [VppRoutePath(self.pg0.remote_ip6,
524 self.pg0.sw_if_index,
525 labels=[VppMplsLabel(3, MplsLspMode.UNIFORM)],
526 proto=DpoProto.DPO_PROTO_IP6)])
527 route_335_eos.add_vpp_config()
529 tx = self.create_stream_labelled_ip6(
531 [VppMplsLabel(335, ttl=27, exp=4)])
532 rx = self.send_and_expect(self.pg0, tx, self.pg0)
533 self.verify_capture_ip6(self.pg0, rx, tx, ip_hlim=26, ip_dscp=0x80)
536 # disposed packets have an TTL expired
538 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(334)],
539 dst_ip=self.pg1.remote_ip6,
541 rx = self.send_and_expect(self.pg0, tx, self.pg0)
542 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
545 # An MPLS xconnect - non-EOS label in IP out - an invalid configuration
546 # so this traffic should be dropped.
548 route_33_neos = VppMplsRoute(self, 33, 0,
549 [VppRoutePath(self.pg0.remote_ip4,
550 self.pg0.sw_if_index,
552 route_33_neos.add_vpp_config()
554 tx = self.create_stream_labelled_ip4(self.pg0,
557 self.send_and_assert_no_replies(
559 "MPLS non-EOS packets popped and forwarded")
562 # A recursive EOS x-connect, which resolves through another x-connect
565 route_34_eos = VppMplsRoute(self, 34, 1,
566 [VppRoutePath("0.0.0.0",
569 labels=[VppMplsLabel(44),
571 route_34_eos.add_vpp_config()
573 tx = self.create_stream_labelled_ip4(self.pg0,
574 [VppMplsLabel(34, ttl=3)])
575 rx = self.send_and_expect(self.pg0, tx, self.pg0)
576 self.verify_capture_labelled(self.pg0, rx, tx,
579 VppMplsLabel(45, ttl=2)])
581 self.assertEqual(route_34_eos.get_stats_to()['packets'], 257)
582 self.assertEqual(route_32_neos.get_stats_via()['packets'], 257)
585 # A recursive EOS x-connect, which resolves through another x-connect
588 route_35_eos = VppMplsRoute(
590 [VppRoutePath("0.0.0.0",
593 labels=[VppMplsLabel(44)])])
594 route_35_eos.add_vpp_config()
596 tx = self.create_stream_labelled_ip4(self.pg0,
597 [VppMplsLabel(35, ttl=3)])
598 rx = self.send_and_expect(self.pg0, tx, self.pg0)
599 self.verify_capture_labelled(self.pg0, rx, tx,
600 [VppMplsLabel(43, ttl=2),
601 VppMplsLabel(44, ttl=2)])
604 # A recursive non-EOS x-connect, which resolves through another
607 route_34_neos = VppMplsRoute(self, 34, 0,
608 [VppRoutePath("0.0.0.0",
611 labels=[VppMplsLabel(44),
613 route_34_neos.add_vpp_config()
615 tx = self.create_stream_labelled_ip4(self.pg0,
616 [VppMplsLabel(34, ttl=45),
618 rx = self.send_and_expect(self.pg0, tx, self.pg0)
619 # it's the 2nd (counting from 0) label in the stack that is swapped
620 self.verify_capture_labelled(self.pg0, rx, tx,
623 VppMplsLabel(46, ttl=44),
627 # an recursive IP route that resolves through the recursive non-eos
630 ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
631 [VppRoutePath("0.0.0.0",
634 labels=[VppMplsLabel(55)])])
635 ip_10_0_0_1.add_vpp_config()
637 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
638 rx = self.send_and_expect(self.pg0, tx, self.pg0)
639 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
644 self.assertEqual(ip_10_0_0_1.get_stats_to()['packets'], 257)
646 ip_10_0_0_1.remove_vpp_config()
647 route_34_neos.remove_vpp_config()
648 route_34_eos.remove_vpp_config()
649 route_33_neos.remove_vpp_config()
650 route_33_eos.remove_vpp_config()
651 route_32_neos.remove_vpp_config()
652 route_32_eos.remove_vpp_config()
655 """ MPLS Local Label Binding test """
658 # Add a non-recursive route with a single out label
660 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
661 [VppRoutePath(self.pg0.remote_ip4,
662 self.pg0.sw_if_index,
663 labels=[VppMplsLabel(45)])])
664 route_10_0_0_1.add_vpp_config()
666 # bind a local label to the route
667 binding = VppMplsIpBind(self, 44, "10.0.0.1", 32)
668 binding.add_vpp_config()
671 tx = self.create_stream_labelled_ip4(self.pg0,
674 rx = self.send_and_expect(self.pg0, tx, self.pg0)
675 self.verify_capture_labelled(self.pg0, rx, tx,
676 [VppMplsLabel(45, ttl=63),
680 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(44)])
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)])
686 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
687 rx = self.send_and_expect(self.pg0, tx, self.pg0)
688 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(45)])
693 binding.remove_vpp_config()
694 route_10_0_0_1.remove_vpp_config()
696 def test_imposition(self):
697 """ MPLS label imposition test """
700 # Add a non-recursive route with a single out label
702 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
703 [VppRoutePath(self.pg0.remote_ip4,
704 self.pg0.sw_if_index,
705 labels=[VppMplsLabel(32)])])
706 route_10_0_0_1.add_vpp_config()
709 # a stream that matches the route for 10.0.0.1
710 # PG0 is in the default table
712 tx = self.create_stream_ip4(self.pg0, "10.0.0.1")
713 rx = self.send_and_expect(self.pg0, tx, self.pg0)
714 self.verify_capture_labelled_ip4(self.pg0, rx, tx, [VppMplsLabel(32)])
717 # Add a non-recursive route with a 3 out labels
719 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
720 [VppRoutePath(self.pg0.remote_ip4,
721 self.pg0.sw_if_index,
722 labels=[VppMplsLabel(32),
725 route_10_0_0_2.add_vpp_config()
727 tx = self.create_stream_ip4(self.pg0, "10.0.0.2",
728 ip_ttl=44, ip_dscp=0xff)
729 rx = self.send_and_expect(self.pg0, tx, self.pg0)
730 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
737 # Add a non-recursive route with a single out label in uniform mode
739 route_10_0_0_3 = VppIpRoute(
740 self, "10.0.0.3", 32,
741 [VppRoutePath(self.pg0.remote_ip4,
742 self.pg0.sw_if_index,
743 labels=[VppMplsLabel(32,
744 mode=MplsLspMode.UNIFORM)])])
745 route_10_0_0_3.add_vpp_config()
747 tx = self.create_stream_ip4(self.pg0, "10.0.0.3",
748 ip_ttl=54, ip_dscp=0xbe)
749 rx = self.send_and_expect(self.pg0, tx, self.pg0)
750 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
751 [VppMplsLabel(32, ttl=53, exp=5)])
754 # Add a IPv6 non-recursive route with a single out label in
757 route_2001_3 = VppIpRoute(
758 self, "2001::3", 128,
759 [VppRoutePath(self.pg0.remote_ip6,
760 self.pg0.sw_if_index,
761 proto=DpoProto.DPO_PROTO_IP6,
762 labels=[VppMplsLabel(32,
763 mode=MplsLspMode.UNIFORM)])],
765 route_2001_3.add_vpp_config()
767 tx = self.create_stream_ip6(self.pg0, "2001::3",
768 ip_ttl=54, ip_dscp=0xbe)
769 rx = self.send_and_expect(self.pg0, tx, self.pg0)
770 self.verify_capture_labelled_ip6(self.pg0, rx, tx,
771 [VppMplsLabel(32, ttl=53, exp=5)])
774 # add a recursive path, with output label, via the 1 label route
776 route_11_0_0_1 = VppIpRoute(self, "11.0.0.1", 32,
777 [VppRoutePath("10.0.0.1",
779 labels=[VppMplsLabel(44)])])
780 route_11_0_0_1.add_vpp_config()
783 # a stream that matches the route for 11.0.0.1, should pick up
784 # the label stack for 11.0.0.1 and 10.0.0.1
786 tx = self.create_stream_ip4(self.pg0, "11.0.0.1")
787 rx = self.send_and_expect(self.pg0, tx, self.pg0)
788 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
792 self.assertEqual(route_11_0_0_1.get_stats_to()['packets'], 257)
795 # add a recursive path, with 2 labels, via the 3 label route
797 route_11_0_0_2 = VppIpRoute(self, "11.0.0.2", 32,
798 [VppRoutePath("10.0.0.2",
800 labels=[VppMplsLabel(44),
802 route_11_0_0_2.add_vpp_config()
805 # a stream that matches the route for 11.0.0.1, should pick up
806 # the label stack for 11.0.0.1 and 10.0.0.1
808 tx = self.create_stream_ip4(self.pg0, "11.0.0.2")
809 rx = self.send_and_expect(self.pg0, tx, self.pg0)
810 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
817 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 257)
819 rx = self.send_and_expect(self.pg0, tx, self.pg0)
820 self.verify_capture_labelled_ip4(self.pg0, rx, tx,
827 self.assertEqual(route_11_0_0_2.get_stats_to()['packets'], 514)
832 route_11_0_0_2.remove_vpp_config()
833 route_11_0_0_1.remove_vpp_config()
834 route_10_0_0_2.remove_vpp_config()
835 route_10_0_0_1.remove_vpp_config()
837 def test_tunnel_pipe(self):
838 """ MPLS Tunnel Tests - Pipe """
841 # Create a tunnel with a single out label
843 mpls_tun = VppMPLSTunnelInterface(
845 [VppRoutePath(self.pg0.remote_ip4,
846 self.pg0.sw_if_index,
847 labels=[VppMplsLabel(44),
849 mpls_tun.add_vpp_config()
853 # add an unlabelled route through the new tunnel
855 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
856 [VppRoutePath("0.0.0.0",
857 mpls_tun._sw_if_index)])
858 route_10_0_0_3.add_vpp_config()
860 self.vapi.cli("clear trace")
861 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
862 self.pg0.add_stream(tx)
864 self.pg_enable_capture(self.pg_interfaces)
867 rx = self.pg0.get_capture()
868 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
873 # add a labelled route through the new tunnel
875 route_10_0_0_4 = VppIpRoute(self, "10.0.0.4", 32,
876 [VppRoutePath("0.0.0.0",
877 mpls_tun._sw_if_index,
879 route_10_0_0_4.add_vpp_config()
881 self.vapi.cli("clear trace")
882 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
883 self.pg0.add_stream(tx)
885 self.pg_enable_capture(self.pg_interfaces)
888 rx = self.pg0.get_capture()
889 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
892 VppMplsLabel(33, ttl=255)])
894 def test_tunnel_uniform(self):
895 """ MPLS Tunnel Tests - Uniform """
898 # Create a tunnel with a single out label
899 # The label stack is specified here from outer to inner
901 mpls_tun = VppMPLSTunnelInterface(
903 [VppRoutePath(self.pg0.remote_ip4,
904 self.pg0.sw_if_index,
905 labels=[VppMplsLabel(44, ttl=32),
906 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
907 mpls_tun.add_vpp_config()
911 # add an unlabelled route through the new tunnel
913 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
914 [VppRoutePath("0.0.0.0",
915 mpls_tun._sw_if_index)])
916 route_10_0_0_3.add_vpp_config()
918 self.vapi.cli("clear trace")
919 tx = self.create_stream_ip4(self.pg0, "10.0.0.3", ip_ttl=24)
920 self.pg0.add_stream(tx)
922 self.pg_enable_capture(self.pg_interfaces)
925 rx = self.pg0.get_capture()
926 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
927 [VppMplsLabel(44, ttl=32),
928 VppMplsLabel(46, ttl=23)])
931 # add a labelled route through the new tunnel
933 route_10_0_0_4 = VppIpRoute(
934 self, "10.0.0.4", 32,
935 [VppRoutePath("0.0.0.0",
936 mpls_tun._sw_if_index,
937 labels=[VppMplsLabel(33, ttl=47)])])
938 route_10_0_0_4.add_vpp_config()
940 self.vapi.cli("clear trace")
941 tx = self.create_stream_ip4(self.pg0, "10.0.0.4")
942 self.pg0.add_stream(tx)
944 self.pg_enable_capture(self.pg_interfaces)
947 rx = self.pg0.get_capture()
948 self.verify_capture_tunneled_ip4(self.pg0, rx, tx,
949 [VppMplsLabel(44, ttl=32),
950 VppMplsLabel(46, ttl=47),
951 VppMplsLabel(33, ttl=47)])
953 def test_v4_exp_null(self):
954 """ MPLS V4 Explicit NULL test """
957 # The first test case has an MPLS TTL of 0
958 # all packet should be dropped
960 tx = self.create_stream_labelled_ip4(self.pg0,
961 [VppMplsLabel(0, ttl=0)])
962 self.send_and_assert_no_replies(self.pg0, tx,
963 "MPLS TTL=0 packets forwarded")
966 # a stream with a non-zero MPLS TTL
967 # PG0 is in the default table
969 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
970 rx = self.send_and_expect(self.pg0, tx, self.pg0)
971 self.verify_capture_ip4(self.pg0, rx, tx)
974 # a stream with a non-zero MPLS TTL
976 # we are ensuring the post-pop lookup occurs in the VRF table
978 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
979 rx = self.send_and_expect(self.pg1, tx, self.pg1)
980 self.verify_capture_ip4(self.pg1, rx, tx)
982 def test_v6_exp_null(self):
983 """ MPLS V6 Explicit NULL test """
986 # a stream with a non-zero MPLS TTL
987 # PG0 is in the default table
989 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
990 rx = self.send_and_expect(self.pg0, tx, self.pg0)
991 self.verify_capture_ip6(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_ip6(self.pg1, [VppMplsLabel(2)])
999 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1000 self.verify_capture_ip6(self.pg0, rx, tx)
1002 def test_deag(self):
1006 # A de-agg route - next-hop lookup in default table
1008 route_34_eos = VppMplsRoute(self, 34, 1,
1009 [VppRoutePath("0.0.0.0",
1012 route_34_eos.add_vpp_config()
1015 # ping an interface in the default table
1016 # PG0 is in the default table
1018 tx = self.create_stream_labelled_ip4(self.pg0,
1022 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1023 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1026 # A de-agg route - next-hop lookup in non-default table
1028 route_35_eos = VppMplsRoute(self, 35, 1,
1029 [VppRoutePath("0.0.0.0",
1032 route_35_eos.add_vpp_config()
1035 # ping an interface in the non-default table
1036 # PG0 is in the default table. packet arrive labelled in the
1037 # default table and egress unlabelled in the non-default
1039 tx = self.create_stream_labelled_ip4(
1040 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1041 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1042 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1047 route_36_neos = VppMplsRoute(self, 36, 0,
1048 [VppRoutePath("0.0.0.0",
1050 route_36_neos.add_vpp_config()
1052 tx = self.create_stream_labelled_ip4(self.pg0,
1055 ping=1, ip_itf=self.pg1)
1056 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1057 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1059 route_36_neos.remove_vpp_config()
1060 route_35_eos.remove_vpp_config()
1061 route_34_eos.remove_vpp_config()
1063 def test_interface_rx(self):
1064 """ MPLS Interface Receive """
1067 # Add a non-recursive route that will forward the traffic
1070 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1072 paths=[VppRoutePath(self.pg1.remote_ip4,
1073 self.pg1.sw_if_index)])
1074 route_10_0_0_1.add_vpp_config()
1077 # An interface receive label that maps traffic to RX on interface
1079 # by injecting the packet in on pg0, which is in table 0
1080 # doing an interface-rx on pg1 and matching a route in table 1
1081 # if the packet egresses, then we must have swapped to pg1
1082 # so as to have matched the route in table 1
1084 route_34_eos = VppMplsRoute(self, 34, 1,
1085 [VppRoutePath("0.0.0.0",
1086 self.pg1.sw_if_index,
1087 is_interface_rx=1)])
1088 route_34_eos.add_vpp_config()
1091 # ping an interface in the default table
1092 # PG0 is in the default table
1094 tx = self.create_stream_labelled_ip4(self.pg0,
1097 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1098 self.verify_capture_ip4(self.pg1, rx, tx)
1100 def test_mcast_mid_point(self):
1101 """ MPLS Multicast Mid Point """
1104 # Add a non-recursive route that will forward the traffic
1107 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1109 paths=[VppRoutePath(self.pg1.remote_ip4,
1110 self.pg1.sw_if_index)])
1111 route_10_0_0_1.add_vpp_config()
1114 # Add a mcast entry that replicate to pg2 and pg3
1115 # and replicate to a interface-rx (like a bud node would)
1117 route_3400_eos = VppMplsRoute(
1119 [VppRoutePath(self.pg2.remote_ip4,
1120 self.pg2.sw_if_index,
1121 labels=[VppMplsLabel(3401)]),
1122 VppRoutePath(self.pg3.remote_ip4,
1123 self.pg3.sw_if_index,
1124 labels=[VppMplsLabel(3402)]),
1125 VppRoutePath("0.0.0.0",
1126 self.pg1.sw_if_index,
1127 is_interface_rx=1)],
1129 route_3400_eos.add_vpp_config()
1132 # ping an interface in the default table
1133 # PG0 is in the default table
1135 self.vapi.cli("clear trace")
1136 tx = self.create_stream_labelled_ip4(self.pg0,
1137 [VppMplsLabel(3400, ttl=64)],
1140 self.pg0.add_stream(tx)
1142 self.pg_enable_capture(self.pg_interfaces)
1145 rx = self.pg1.get_capture(257)
1146 self.verify_capture_ip4(self.pg1, rx, tx)
1148 rx = self.pg2.get_capture(257)
1149 self.verify_capture_labelled(self.pg2, rx, tx,
1150 [VppMplsLabel(3401, ttl=63)])
1151 rx = self.pg3.get_capture(257)
1152 self.verify_capture_labelled(self.pg3, rx, tx,
1153 [VppMplsLabel(3402, ttl=63)])
1155 def test_mcast_head(self):
1156 """ MPLS Multicast Head-end """
1159 # Create a multicast tunnel with two replications
1161 mpls_tun = VppMPLSTunnelInterface(
1163 [VppRoutePath(self.pg2.remote_ip4,
1164 self.pg2.sw_if_index,
1165 labels=[VppMplsLabel(42)]),
1166 VppRoutePath(self.pg3.remote_ip4,
1167 self.pg3.sw_if_index,
1168 labels=[VppMplsLabel(43)])],
1170 mpls_tun.add_vpp_config()
1174 # add an unlabelled route through the new tunnel
1176 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1177 [VppRoutePath("0.0.0.0",
1178 mpls_tun._sw_if_index)])
1179 route_10_0_0_3.add_vpp_config()
1181 self.vapi.cli("clear trace")
1182 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1183 self.pg0.add_stream(tx)
1185 self.pg_enable_capture(self.pg_interfaces)
1188 rx = self.pg2.get_capture(257)
1189 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1190 rx = self.pg3.get_capture(257)
1191 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1194 # An an IP multicast route via the tunnel
1196 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1198 route_232_1_1_1 = VppIpMRoute(
1202 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1203 [VppMRoutePath(self.pg0.sw_if_index,
1204 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1205 VppMRoutePath(mpls_tun._sw_if_index,
1206 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1207 route_232_1_1_1.add_vpp_config()
1209 self.vapi.cli("clear trace")
1210 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1211 self.pg0.add_stream(tx)
1213 self.pg_enable_capture(self.pg_interfaces)
1216 rx = self.pg2.get_capture(257)
1217 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1218 rx = self.pg3.get_capture(257)
1219 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1221 def test_mcast_ip4_tail(self):
1222 """ MPLS IPv4 Multicast Tail """
1225 # Add a multicast route that will forward the traffic
1228 route_232_1_1_1 = VppIpMRoute(
1232 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1234 paths=[VppMRoutePath(self.pg1.sw_if_index,
1235 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1236 route_232_1_1_1.add_vpp_config()
1239 # An interface receive label that maps traffic to RX on interface
1241 # by injecting the packet in on pg0, which is in table 0
1242 # doing an rpf-id and matching a route in table 1
1243 # if the packet egresses, then we must have matched the route in
1246 route_34_eos = VppMplsRoute(self, 34, 1,
1247 [VppRoutePath("0.0.0.0",
1248 self.pg1.sw_if_index,
1253 route_34_eos.add_vpp_config()
1256 # Drop due to interface lookup miss
1258 self.vapi.cli("clear trace")
1259 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1260 dst_ip="232.1.1.1", n=1)
1261 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1264 # set the RPF-ID of the enrtry to match the input packet's
1266 route_232_1_1_1.update_rpf_id(55)
1268 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1270 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1271 self.verify_capture_ip4(self.pg1, rx, tx)
1274 # disposed packets have an invalid IPv4 checkusm
1276 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1277 dst_ip="232.1.1.1", n=65,
1279 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1282 # set the RPF-ID of the entry to not match the input packet's
1284 route_232_1_1_1.update_rpf_id(56)
1285 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1287 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1289 def test_mcast_ip6_tail(self):
1290 """ MPLS IPv6 Multicast Tail """
1293 # Add a multicast route that will forward the traffic
1296 route_ff = VppIpMRoute(
1300 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1302 paths=[VppMRoutePath(self.pg1.sw_if_index,
1303 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
1305 route_ff.add_vpp_config()
1308 # An interface receive label that maps traffic to RX on interface
1310 # by injecting the packet in on pg0, which is in table 0
1311 # doing an rpf-id and matching a route in table 1
1312 # if the packet egresses, then we must have matched the route in
1315 route_34_eos = VppMplsRoute(
1318 self.pg1.sw_if_index,
1321 proto=DpoProto.DPO_PROTO_IP6)],
1324 route_34_eos.add_vpp_config()
1327 # Drop due to interface lookup miss
1329 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1331 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1334 # set the RPF-ID of the enrtry to match the input packet's
1336 route_ff.update_rpf_id(55)
1338 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1340 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1341 self.verify_capture_ip6(self.pg1, rx, tx)
1344 # disposed packets have hop-limit = 1
1346 tx = self.create_stream_labelled_ip6(self.pg0,
1350 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1351 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1354 # set the RPF-ID of the enrtry to not match the input packet's
1356 route_ff.update_rpf_id(56)
1357 tx = self.create_stream_labelled_ip6(self.pg0,
1360 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1363 class TestMPLSDisabled(VppTestCase):
1364 """ MPLS disabled """
1367 super(TestMPLSDisabled, self).setUp()
1369 # create 2 pg interfaces
1370 self.create_pg_interfaces(range(2))
1372 self.tbl = VppMplsTable(self, 0)
1373 self.tbl.add_vpp_config()
1375 # PG0 is MPLS enalbed
1377 self.pg0.config_ip4()
1378 self.pg0.resolve_arp()
1379 self.pg0.enable_mpls()
1381 # PG 1 is not MPLS enabled
1385 for i in self.pg_interfaces:
1389 self.pg0.disable_mpls()
1390 super(TestMPLSDisabled, self).tearDown()
1392 def test_mpls_disabled(self):
1393 """ MPLS Disabled """
1395 tx = (Ether(src=self.pg1.remote_mac,
1396 dst=self.pg1.local_mac) /
1397 MPLS(label=32, ttl=64) /
1398 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1399 UDP(sport=1234, dport=1234) /
1403 # A simple MPLS xconnect - eos label in label out
1405 route_32_eos = VppMplsRoute(self, 32, 1,
1406 [VppRoutePath(self.pg0.remote_ip4,
1407 self.pg0.sw_if_index,
1409 route_32_eos.add_vpp_config()
1412 # PG1 does not forward IP traffic
1414 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1419 self.pg1.enable_mpls()
1422 # Now we get packets through
1424 self.pg1.add_stream(tx)
1425 self.pg_enable_capture(self.pg_interfaces)
1428 rx = self.pg0.get_capture(1)
1433 self.pg1.disable_mpls()
1436 # PG1 does not forward IP traffic
1438 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1439 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1442 class TestMPLSPIC(VppTestCase):
1443 """ MPLS PIC edge convergence """
1446 super(TestMPLSPIC, self).setUp()
1448 # create 2 pg interfaces
1449 self.create_pg_interfaces(range(4))
1451 mpls_tbl = VppMplsTable(self, 0)
1452 mpls_tbl.add_vpp_config()
1453 tbl4 = VppIpTable(self, 1)
1454 tbl4.add_vpp_config()
1455 tbl6 = VppIpTable(self, 1, is_ip6=1)
1456 tbl6.add_vpp_config()
1460 self.pg0.config_ip4()
1461 self.pg0.resolve_arp()
1462 self.pg0.enable_mpls()
1464 self.pg1.config_ip4()
1465 self.pg1.resolve_arp()
1466 self.pg1.enable_mpls()
1468 # VRF (customer facing) link
1470 self.pg2.set_table_ip4(1)
1471 self.pg2.config_ip4()
1472 self.pg2.resolve_arp()
1473 self.pg2.set_table_ip6(1)
1474 self.pg2.config_ip6()
1475 self.pg2.resolve_ndp()
1477 self.pg3.set_table_ip4(1)
1478 self.pg3.config_ip4()
1479 self.pg3.resolve_arp()
1480 self.pg3.set_table_ip6(1)
1481 self.pg3.config_ip6()
1482 self.pg3.resolve_ndp()
1485 self.pg0.disable_mpls()
1486 self.pg1.disable_mpls()
1487 for i in self.pg_interfaces:
1493 super(TestMPLSPIC, self).tearDown()
1495 def test_mpls_ibgp_pic(self):
1496 """ MPLS iBGP PIC edge convergence
1498 1) setup many iBGP VPN routes via a pair of iBGP peers.
1499 2) Check EMCP forwarding to these peers
1500 3) withdraw the IGP route to one of these peers.
1501 4) check forwarding continues to the remaining peer
1505 # IGP+LDP core routes
1507 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1508 [VppRoutePath(self.pg0.remote_ip4,
1509 self.pg0.sw_if_index,
1511 core_10_0_0_45.add_vpp_config()
1513 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1514 [VppRoutePath(self.pg1.remote_ip4,
1515 self.pg1.sw_if_index,
1517 core_10_0_0_46.add_vpp_config()
1520 # Lot's of VPN routes. We need more the 64 so VPP will build
1521 # the fast convergence indirection
1525 for ii in range(64):
1526 dst = "192.168.1.%d" % ii
1527 vpn_routes.append(VppIpRoute(self, dst, 32,
1528 [VppRoutePath("10.0.0.45",
1532 VppRoutePath("10.0.0.46",
1535 is_resolve_host=1)],
1537 vpn_routes[ii].add_vpp_config()
1539 pkts.append(Ether(dst=self.pg2.local_mac,
1540 src=self.pg2.remote_mac) /
1541 IP(src=self.pg2.remote_ip4, dst=dst) /
1542 UDP(sport=1234, dport=1234) /
1546 # Send the packet stream (one pkt to each VPN route)
1547 # - expect a 50-50 split of the traffic
1549 self.pg2.add_stream(pkts)
1550 self.pg_enable_capture(self.pg_interfaces)
1553 rx0 = self.pg0._get_capture(1)
1554 rx1 = self.pg1._get_capture(1)
1556 # not testig the LB hashing algorithm so we're not concerned
1557 # with the split ratio, just as long as neither is 0
1558 self.assertNotEqual(0, len(rx0))
1559 self.assertNotEqual(0, len(rx1))
1562 # use a test CLI command to stop the FIB walk process, this
1563 # will prevent the FIB converging the VPN routes and thus allow
1564 # us to probe the interim (psot-fail, pre-converge) state
1566 self.vapi.ppcli("test fib-walk-process disable")
1569 # Withdraw one of the IGP routes
1571 core_10_0_0_46.remove_vpp_config()
1574 # now all packets should be forwarded through the remaining peer
1576 self.vapi.ppcli("clear trace")
1577 self.pg2.add_stream(pkts)
1578 self.pg_enable_capture(self.pg_interfaces)
1581 rx0 = self.pg0.get_capture(len(pkts))
1584 # enable the FIB walk process to converge the FIB
1586 self.vapi.ppcli("test fib-walk-process enable")
1589 # packets should still be forwarded through the remaining peer
1591 self.pg2.add_stream(pkts)
1592 self.pg_enable_capture(self.pg_interfaces)
1595 rx0 = self.pg0.get_capture(64)
1598 # Add the IGP route back and we return to load-balancing
1600 core_10_0_0_46.add_vpp_config()
1602 self.pg2.add_stream(pkts)
1603 self.pg_enable_capture(self.pg_interfaces)
1606 rx0 = self.pg0._get_capture(1)
1607 rx1 = self.pg1._get_capture(1)
1608 self.assertNotEqual(0, len(rx0))
1609 self.assertNotEqual(0, len(rx1))
1611 def test_mpls_ebgp_pic(self):
1612 """ MPLS eBGP PIC edge convergence
1614 1) setup many eBGP VPN routes via a pair of eBGP peers
1615 2) Check EMCP forwarding to these peers
1616 3) withdraw one eBGP path - expect LB across remaining eBGP
1620 # Lot's of VPN routes. We need more the 64 so VPP will build
1621 # the fast convergence indirection
1626 for ii in range(64):
1627 dst = "192.168.1.%d" % ii
1628 local_label = 1600 + ii
1629 vpn_routes.append(VppIpRoute(self, dst, 32,
1630 [VppRoutePath(self.pg2.remote_ip4,
1633 is_resolve_attached=1),
1634 VppRoutePath(self.pg3.remote_ip4,
1637 is_resolve_attached=1)],
1639 vpn_routes[ii].add_vpp_config()
1641 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1643 vpn_bindings[ii].add_vpp_config()
1645 pkts.append(Ether(dst=self.pg0.local_mac,
1646 src=self.pg0.remote_mac) /
1647 MPLS(label=local_label, ttl=64) /
1648 IP(src=self.pg0.remote_ip4, dst=dst) /
1649 UDP(sport=1234, dport=1234) /
1652 self.pg0.add_stream(pkts)
1653 self.pg_enable_capture(self.pg_interfaces)
1656 rx0 = self.pg2._get_capture(1)
1657 rx1 = self.pg3._get_capture(1)
1658 self.assertNotEqual(0, len(rx0))
1659 self.assertNotEqual(0, len(rx1))
1662 # use a test CLI command to stop the FIB walk process, this
1663 # will prevent the FIB converging the VPN routes and thus allow
1664 # us to probe the interim (psot-fail, pre-converge) state
1666 self.vapi.ppcli("test fib-walk-process disable")
1669 # withdraw the connected prefix on the interface.
1671 self.pg2.unconfig_ip4()
1674 # now all packets should be forwarded through the remaining peer
1676 self.pg0.add_stream(pkts)
1677 self.pg_enable_capture(self.pg_interfaces)
1680 rx0 = self.pg3.get_capture(len(pkts))
1683 # enable the FIB walk process to converge the FIB
1685 self.vapi.ppcli("test fib-walk-process enable")
1686 self.pg0.add_stream(pkts)
1687 self.pg_enable_capture(self.pg_interfaces)
1690 rx0 = self.pg3.get_capture(len(pkts))
1693 # put the connecteds back
1695 self.pg2.config_ip4()
1697 self.pg0.add_stream(pkts)
1698 self.pg_enable_capture(self.pg_interfaces)
1701 rx0 = self.pg2._get_capture(1)
1702 rx1 = self.pg3._get_capture(1)
1703 self.assertNotEqual(0, len(rx0))
1704 self.assertNotEqual(0, len(rx1))
1706 def test_mpls_v6_ebgp_pic(self):
1707 """ MPLSv6 eBGP PIC edge convergence
1709 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1710 2) Check EMCP forwarding to these peers
1711 3) withdraw one eBGP path - expect LB across remaining eBGP
1715 # Lot's of VPN routes. We need more the 64 so VPP will build
1716 # the fast convergence indirection
1721 for ii in range(64):
1722 dst = "3000::%d" % ii
1723 local_label = 1600 + ii
1724 vpn_routes.append(VppIpRoute(
1726 [VppRoutePath(self.pg2.remote_ip6,
1729 is_resolve_attached=1,
1730 proto=DpoProto.DPO_PROTO_IP6),
1731 VppRoutePath(self.pg3.remote_ip6,
1734 proto=DpoProto.DPO_PROTO_IP6,
1735 is_resolve_attached=1)],
1738 vpn_routes[ii].add_vpp_config()
1740 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1743 vpn_bindings[ii].add_vpp_config()
1745 pkts.append(Ether(dst=self.pg0.local_mac,
1746 src=self.pg0.remote_mac) /
1747 MPLS(label=local_label, ttl=64) /
1748 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1749 UDP(sport=1234, dport=1234) /
1752 self.pg0.add_stream(pkts)
1753 self.pg_enable_capture(self.pg_interfaces)
1756 rx0 = self.pg2._get_capture(1)
1757 rx1 = self.pg3._get_capture(1)
1758 self.assertNotEqual(0, len(rx0))
1759 self.assertNotEqual(0, len(rx1))
1762 # use a test CLI command to stop the FIB walk process, this
1763 # will prevent the FIB converging the VPN routes and thus allow
1764 # us to probe the interim (psot-fail, pre-converge) state
1766 self.vapi.ppcli("test fib-walk-process disable")
1769 # withdraw the connected prefix on the interface.
1770 # and shutdown the interface so the ND cache is flushed.
1772 self.pg2.unconfig_ip6()
1773 self.pg2.admin_down()
1776 # now all packets should be forwarded through the remaining peer
1778 self.pg0.add_stream(pkts)
1779 self.pg_enable_capture(self.pg_interfaces)
1782 rx0 = self.pg3.get_capture(len(pkts))
1785 # enable the FIB walk process to converge the FIB
1787 self.vapi.ppcli("test fib-walk-process enable")
1788 self.pg0.add_stream(pkts)
1789 self.pg_enable_capture(self.pg_interfaces)
1792 rx0 = self.pg3.get_capture(len(pkts))
1795 # put the connecteds back
1798 self.pg2.config_ip6()
1800 self.pg0.add_stream(pkts)
1801 self.pg_enable_capture(self.pg_interfaces)
1804 rx0 = self.pg2._get_capture(1)
1805 rx1 = self.pg3._get_capture(1)
1806 self.assertNotEqual(0, len(rx0))
1807 self.assertNotEqual(0, len(rx1))
1810 class TestMPLSL2(VppTestCase):
1814 super(TestMPLSL2, self).setUp()
1816 # create 2 pg interfaces
1817 self.create_pg_interfaces(range(2))
1819 # create the default MPLS table
1821 tbl = VppMplsTable(self, 0)
1822 tbl.add_vpp_config()
1823 self.tables.append(tbl)
1825 # use pg0 as the core facing interface
1827 self.pg0.config_ip4()
1828 self.pg0.resolve_arp()
1829 self.pg0.enable_mpls()
1831 # use the other 2 for customer facing L2 links
1832 for i in self.pg_interfaces[1:]:
1836 for i in self.pg_interfaces[1:]:
1839 self.pg0.disable_mpls()
1840 self.pg0.unconfig_ip4()
1841 self.pg0.admin_down()
1842 super(TestMPLSL2, self).tearDown()
1844 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
1845 capture = verify_filter(capture, sent)
1847 self.assertEqual(len(capture), len(sent))
1849 for i in range(len(capture)):
1853 # the MPLS TTL is 255 since it enters a new tunnel
1854 verify_mpls_stack(self, rx, mpls_labels)
1857 rx_eth = Ether(str(rx[MPLS].payload))
1859 self.assertEqual(rx_eth.src, tx_eth.src)
1860 self.assertEqual(rx_eth.dst, tx_eth.dst)
1862 def test_vpws(self):
1863 """ Virtual Private Wire Service """
1866 # Create an MPLS tunnel that pushes 1 label
1867 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
1868 # information is not in the packet, but we test it works anyway
1870 mpls_tun_1 = VppMPLSTunnelInterface(
1872 [VppRoutePath(self.pg0.remote_ip4,
1873 self.pg0.sw_if_index,
1874 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
1876 mpls_tun_1.add_vpp_config()
1877 mpls_tun_1.admin_up()
1880 # Create a label entry to for 55 that does L2 input to the tunnel
1882 route_55_eos = VppMplsRoute(
1884 [VppRoutePath("0.0.0.0",
1885 mpls_tun_1.sw_if_index,
1887 proto=DpoProto.DPO_PROTO_ETHERNET)])
1888 route_55_eos.add_vpp_config()
1891 # Cross-connect the tunnel with one of the customers L2 interfaces
1893 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
1894 mpls_tun_1.sw_if_index,
1896 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
1897 self.pg1.sw_if_index,
1901 # inject a packet from the core
1903 pcore = (Ether(dst=self.pg0.local_mac,
1904 src=self.pg0.remote_mac) /
1905 MPLS(label=55, ttl=64) /
1906 Ether(dst="00:00:de:ad:ba:be",
1907 src="00:00:de:ad:be:ef") /
1908 IP(src="10.10.10.10", dst="11.11.11.11") /
1909 UDP(sport=1234, dport=1234) /
1913 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
1914 payload = pcore[MPLS].payload
1916 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
1917 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
1920 # Inject a packet from the custoer/L2 side
1922 tx1 = pcore[MPLS].payload * 65
1923 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
1925 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
1927 def test_vpls(self):
1928 """ Virtual Private LAN Service """
1930 # Create an L2 MPLS tunnel
1932 mpls_tun = VppMPLSTunnelInterface(
1934 [VppRoutePath(self.pg0.remote_ip4,
1935 self.pg0.sw_if_index,
1936 labels=[VppMplsLabel(42)])],
1938 mpls_tun.add_vpp_config()
1942 # Create a label entry to for 55 that does L2 input to the tunnel
1944 route_55_eos = VppMplsRoute(
1946 [VppRoutePath("0.0.0.0",
1947 mpls_tun.sw_if_index,
1949 proto=DpoProto.DPO_PROTO_ETHERNET)])
1950 route_55_eos.add_vpp_config()
1953 # add to tunnel to the customers bridge-domain
1955 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
1957 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
1961 # Packet from the customer interface and from the core
1963 p_cust = (Ether(dst="00:00:de:ad:ba:be",
1964 src="00:00:de:ad:be:ef") /
1965 IP(src="10.10.10.10", dst="11.11.11.11") /
1966 UDP(sport=1234, dport=1234) /
1968 p_core = (Ether(src="00:00:de:ad:ba:be",
1969 dst="00:00:de:ad:be:ef") /
1970 IP(dst="10.10.10.10", src="11.11.11.11") /
1971 UDP(sport=1234, dport=1234) /
1975 # The BD is learning, so send in one of each packet to learn
1977 p_core_encap = (Ether(dst=self.pg0.local_mac,
1978 src=self.pg0.remote_mac) /
1979 MPLS(label=55, ttl=64) /
1982 self.pg1.add_stream(p_cust)
1983 self.pg_enable_capture(self.pg_interfaces)
1985 self.pg0.add_stream(p_core_encap)
1986 self.pg_enable_capture(self.pg_interfaces)
1989 # we've learnt this so expect it be be forwarded
1990 rx0 = self.pg1.get_capture(1)
1992 self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst)
1993 self.assertEqual(rx0[0][Ether].src, p_core[Ether].src)
1996 # now a stream in each direction
1998 self.pg1.add_stream(p_cust * 65)
1999 self.pg_enable_capture(self.pg_interfaces)
2002 rx0 = self.pg0.get_capture(65)
2004 self.verify_capture_tunneled_ethernet(rx0, p_cust*65,
2008 # remove interfaces from customers bridge-domain
2010 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
2013 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
2017 if __name__ == '__main__':
2018 unittest.main(testRunner=VppTestRunner)