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, 255)
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_mpls_tunnel_many(self):
954 """ Multiple Tunnels """
957 mpls_tun = VppMPLSTunnelInterface(
959 [VppRoutePath(self.pg0.remote_ip4,
960 self.pg0.sw_if_index,
961 labels=[VppMplsLabel(44, ttl=32),
962 VppMplsLabel(46, MplsLspMode.UNIFORM)])])
963 mpls_tun.add_vpp_config()
966 def test_v4_exp_null(self):
967 """ MPLS V4 Explicit NULL test """
970 # The first test case has an MPLS TTL of 0
971 # all packet should be dropped
973 tx = self.create_stream_labelled_ip4(self.pg0,
974 [VppMplsLabel(0, ttl=0)])
975 self.send_and_assert_no_replies(self.pg0, tx,
976 "MPLS TTL=0 packets forwarded")
979 # a stream with a non-zero MPLS TTL
980 # PG0 is in the default table
982 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(0)])
983 rx = self.send_and_expect(self.pg0, tx, self.pg0)
984 self.verify_capture_ip4(self.pg0, rx, tx)
987 # a stream with a non-zero MPLS TTL
989 # we are ensuring the post-pop lookup occurs in the VRF table
991 tx = self.create_stream_labelled_ip4(self.pg1, [VppMplsLabel(0)])
992 rx = self.send_and_expect(self.pg1, tx, self.pg1)
993 self.verify_capture_ip4(self.pg1, rx, tx)
995 def test_v6_exp_null(self):
996 """ MPLS V6 Explicit NULL test """
999 # a stream with a non-zero MPLS TTL
1000 # PG0 is in the default table
1002 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(2)])
1003 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1004 self.verify_capture_ip6(self.pg0, rx, tx)
1007 # a stream with a non-zero MPLS TTL
1009 # we are ensuring the post-pop lookup occurs in the VRF table
1011 tx = self.create_stream_labelled_ip6(self.pg1, [VppMplsLabel(2)])
1012 rx = self.send_and_expect(self.pg1, tx, self.pg1)
1013 self.verify_capture_ip6(self.pg0, rx, tx)
1015 def test_deag(self):
1019 # A de-agg route - next-hop lookup in default table
1021 route_34_eos = VppMplsRoute(self, 34, 1,
1022 [VppRoutePath("0.0.0.0",
1025 route_34_eos.add_vpp_config()
1028 # ping an interface in the default table
1029 # PG0 is in the default table
1031 tx = self.create_stream_labelled_ip4(self.pg0,
1035 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1036 self.verify_capture_ip4(self.pg0, rx, tx, ping_resp=1)
1039 # A de-agg route - next-hop lookup in non-default table
1041 route_35_eos = VppMplsRoute(self, 35, 1,
1042 [VppRoutePath("0.0.0.0",
1045 route_35_eos.add_vpp_config()
1048 # ping an interface in the non-default table
1049 # PG0 is in the default table. packet arrive labelled in the
1050 # default table and egress unlabelled in the non-default
1052 tx = self.create_stream_labelled_ip4(
1053 self.pg0, [VppMplsLabel(35)], ping=1, ip_itf=self.pg1)
1054 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1055 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1060 route_36_neos = VppMplsRoute(self, 36, 0,
1061 [VppRoutePath("0.0.0.0",
1063 route_36_neos.add_vpp_config()
1065 tx = self.create_stream_labelled_ip4(self.pg0,
1068 ping=1, ip_itf=self.pg1)
1069 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1070 self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1)
1072 route_36_neos.remove_vpp_config()
1073 route_35_eos.remove_vpp_config()
1074 route_34_eos.remove_vpp_config()
1076 def test_interface_rx(self):
1077 """ MPLS Interface Receive """
1080 # Add a non-recursive route that will forward the traffic
1083 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1085 paths=[VppRoutePath(self.pg1.remote_ip4,
1086 self.pg1.sw_if_index)])
1087 route_10_0_0_1.add_vpp_config()
1090 # An interface receive label that maps traffic to RX on interface
1092 # by injecting the packet in on pg0, which is in table 0
1093 # doing an interface-rx on pg1 and matching a route in table 1
1094 # if the packet egresses, then we must have swapped to pg1
1095 # so as to have matched the route in table 1
1097 route_34_eos = VppMplsRoute(self, 34, 1,
1098 [VppRoutePath("0.0.0.0",
1099 self.pg1.sw_if_index,
1100 is_interface_rx=1)])
1101 route_34_eos.add_vpp_config()
1104 # ping an interface in the default table
1105 # PG0 is in the default table
1107 tx = self.create_stream_labelled_ip4(self.pg0,
1110 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1111 self.verify_capture_ip4(self.pg1, rx, tx)
1113 def test_mcast_mid_point(self):
1114 """ MPLS Multicast Mid Point """
1117 # Add a non-recursive route that will forward the traffic
1120 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1122 paths=[VppRoutePath(self.pg1.remote_ip4,
1123 self.pg1.sw_if_index)])
1124 route_10_0_0_1.add_vpp_config()
1127 # Add a mcast entry that replicate to pg2 and pg3
1128 # and replicate to a interface-rx (like a bud node would)
1130 route_3400_eos = VppMplsRoute(
1132 [VppRoutePath(self.pg2.remote_ip4,
1133 self.pg2.sw_if_index,
1134 labels=[VppMplsLabel(3401)]),
1135 VppRoutePath(self.pg3.remote_ip4,
1136 self.pg3.sw_if_index,
1137 labels=[VppMplsLabel(3402)]),
1138 VppRoutePath("0.0.0.0",
1139 self.pg1.sw_if_index,
1140 is_interface_rx=1)],
1142 route_3400_eos.add_vpp_config()
1145 # ping an interface in the default table
1146 # PG0 is in the default table
1148 self.vapi.cli("clear trace")
1149 tx = self.create_stream_labelled_ip4(self.pg0,
1150 [VppMplsLabel(3400, ttl=64)],
1153 self.pg0.add_stream(tx)
1155 self.pg_enable_capture(self.pg_interfaces)
1158 rx = self.pg1.get_capture(257)
1159 self.verify_capture_ip4(self.pg1, rx, tx)
1161 rx = self.pg2.get_capture(257)
1162 self.verify_capture_labelled(self.pg2, rx, tx,
1163 [VppMplsLabel(3401, ttl=63)])
1164 rx = self.pg3.get_capture(257)
1165 self.verify_capture_labelled(self.pg3, rx, tx,
1166 [VppMplsLabel(3402, ttl=63)])
1168 def test_mcast_head(self):
1169 """ MPLS Multicast Head-end """
1172 # Create a multicast tunnel with two replications
1174 mpls_tun = VppMPLSTunnelInterface(
1176 [VppRoutePath(self.pg2.remote_ip4,
1177 self.pg2.sw_if_index,
1178 labels=[VppMplsLabel(42)]),
1179 VppRoutePath(self.pg3.remote_ip4,
1180 self.pg3.sw_if_index,
1181 labels=[VppMplsLabel(43)])],
1183 mpls_tun.add_vpp_config()
1187 # add an unlabelled route through the new tunnel
1189 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1190 [VppRoutePath("0.0.0.0",
1191 mpls_tun._sw_if_index)])
1192 route_10_0_0_3.add_vpp_config()
1194 self.vapi.cli("clear trace")
1195 tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
1196 self.pg0.add_stream(tx)
1198 self.pg_enable_capture(self.pg_interfaces)
1201 rx = self.pg2.get_capture(257)
1202 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1203 rx = self.pg3.get_capture(257)
1204 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1207 # An an IP multicast route via the tunnel
1209 # one accepting interface, pg0, 1 forwarding interface via the tunnel
1211 route_232_1_1_1 = VppIpMRoute(
1215 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1216 [VppMRoutePath(self.pg0.sw_if_index,
1217 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
1218 VppMRoutePath(mpls_tun._sw_if_index,
1219 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1220 route_232_1_1_1.add_vpp_config()
1222 self.vapi.cli("clear trace")
1223 tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
1224 self.pg0.add_stream(tx)
1226 self.pg_enable_capture(self.pg_interfaces)
1229 rx = self.pg2.get_capture(257)
1230 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(42)])
1231 rx = self.pg3.get_capture(257)
1232 self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [VppMplsLabel(43)])
1234 def test_mcast_ip4_tail(self):
1235 """ MPLS IPv4 Multicast Tail """
1238 # Add a multicast route that will forward the traffic
1241 route_232_1_1_1 = VppIpMRoute(
1245 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1247 paths=[VppMRoutePath(self.pg1.sw_if_index,
1248 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
1249 route_232_1_1_1.add_vpp_config()
1252 # An interface receive label that maps traffic to RX on interface
1254 # by injecting the packet in on pg0, which is in table 0
1255 # doing an rpf-id and matching a route in table 1
1256 # if the packet egresses, then we must have matched the route in
1259 route_34_eos = VppMplsRoute(self, 34, 1,
1260 [VppRoutePath("0.0.0.0",
1261 self.pg1.sw_if_index,
1266 route_34_eos.add_vpp_config()
1269 # Drop due to interface lookup miss
1271 self.vapi.cli("clear trace")
1272 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1273 dst_ip="232.1.1.1", n=1)
1274 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
1277 # set the RPF-ID of the enrtry to match the input packet's
1279 route_232_1_1_1.update_rpf_id(55)
1281 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1283 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1284 self.verify_capture_ip4(self.pg1, rx, tx)
1287 # disposed packets have an invalid IPv4 checkusm
1289 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1290 dst_ip="232.1.1.1", n=65,
1292 self.send_and_assert_no_replies(self.pg0, tx, "Invalid Checksum")
1295 # set the RPF-ID of the entry to not match the input packet's
1297 route_232_1_1_1.update_rpf_id(56)
1298 tx = self.create_stream_labelled_ip4(self.pg0, [VppMplsLabel(34)],
1300 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1302 def test_mcast_ip6_tail(self):
1303 """ MPLS IPv6 Multicast Tail """
1306 # Add a multicast route that will forward the traffic
1309 route_ff = VppIpMRoute(
1313 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
1315 paths=[VppMRoutePath(self.pg1.sw_if_index,
1316 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)],
1318 route_ff.add_vpp_config()
1321 # An interface receive label that maps traffic to RX on interface
1323 # by injecting the packet in on pg0, which is in table 0
1324 # doing an rpf-id and matching a route in table 1
1325 # if the packet egresses, then we must have matched the route in
1328 route_34_eos = VppMplsRoute(
1331 self.pg1.sw_if_index,
1334 proto=DpoProto.DPO_PROTO_IP6)],
1337 route_34_eos.add_vpp_config()
1340 # Drop due to interface lookup miss
1342 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1344 self.send_and_assert_no_replies(self.pg0, tx, "RPF Miss")
1347 # set the RPF-ID of the enrtry to match the input packet's
1349 route_ff.update_rpf_id(55)
1351 tx = self.create_stream_labelled_ip6(self.pg0, [VppMplsLabel(34)],
1353 rx = self.send_and_expect(self.pg0, tx, self.pg1)
1354 self.verify_capture_ip6(self.pg1, rx, tx)
1357 # disposed packets have hop-limit = 1
1359 tx = self.create_stream_labelled_ip6(self.pg0,
1363 rx = self.send_and_expect(self.pg0, tx, self.pg0)
1364 self.verify_capture_ip6_icmp(self.pg0, rx, tx)
1367 # set the RPF-ID of the enrtry to not match the input packet's
1369 route_ff.update_rpf_id(56)
1370 tx = self.create_stream_labelled_ip6(self.pg0,
1373 self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
1376 class TestMPLSDisabled(VppTestCase):
1377 """ MPLS disabled """
1380 super(TestMPLSDisabled, self).setUp()
1382 # create 2 pg interfaces
1383 self.create_pg_interfaces(range(2))
1385 self.tbl = VppMplsTable(self, 0)
1386 self.tbl.add_vpp_config()
1388 # PG0 is MPLS enalbed
1390 self.pg0.config_ip4()
1391 self.pg0.resolve_arp()
1392 self.pg0.enable_mpls()
1394 # PG 1 is not MPLS enabled
1398 for i in self.pg_interfaces:
1402 self.pg0.disable_mpls()
1403 super(TestMPLSDisabled, self).tearDown()
1405 def test_mpls_disabled(self):
1406 """ MPLS Disabled """
1408 tx = (Ether(src=self.pg1.remote_mac,
1409 dst=self.pg1.local_mac) /
1410 MPLS(label=32, ttl=64) /
1411 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
1412 UDP(sport=1234, dport=1234) /
1416 # A simple MPLS xconnect - eos label in label out
1418 route_32_eos = VppMplsRoute(self, 32, 1,
1419 [VppRoutePath(self.pg0.remote_ip4,
1420 self.pg0.sw_if_index,
1422 route_32_eos.add_vpp_config()
1425 # PG1 does not forward IP traffic
1427 self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled")
1432 self.pg1.enable_mpls()
1435 # Now we get packets through
1437 self.pg1.add_stream(tx)
1438 self.pg_enable_capture(self.pg_interfaces)
1441 rx = self.pg0.get_capture(1)
1446 self.pg1.disable_mpls()
1449 # PG1 does not forward IP traffic
1451 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1452 self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled")
1455 class TestMPLSPIC(VppTestCase):
1456 """ MPLS PIC edge convergence """
1459 super(TestMPLSPIC, self).setUp()
1461 # create 2 pg interfaces
1462 self.create_pg_interfaces(range(4))
1464 mpls_tbl = VppMplsTable(self, 0)
1465 mpls_tbl.add_vpp_config()
1466 tbl4 = VppIpTable(self, 1)
1467 tbl4.add_vpp_config()
1468 tbl6 = VppIpTable(self, 1, is_ip6=1)
1469 tbl6.add_vpp_config()
1473 self.pg0.config_ip4()
1474 self.pg0.resolve_arp()
1475 self.pg0.enable_mpls()
1477 self.pg1.config_ip4()
1478 self.pg1.resolve_arp()
1479 self.pg1.enable_mpls()
1481 # VRF (customer facing) link
1483 self.pg2.set_table_ip4(1)
1484 self.pg2.config_ip4()
1485 self.pg2.resolve_arp()
1486 self.pg2.set_table_ip6(1)
1487 self.pg2.config_ip6()
1488 self.pg2.resolve_ndp()
1490 self.pg3.set_table_ip4(1)
1491 self.pg3.config_ip4()
1492 self.pg3.resolve_arp()
1493 self.pg3.set_table_ip6(1)
1494 self.pg3.config_ip6()
1495 self.pg3.resolve_ndp()
1498 self.pg0.disable_mpls()
1499 self.pg1.disable_mpls()
1500 for i in self.pg_interfaces:
1506 super(TestMPLSPIC, self).tearDown()
1508 def test_mpls_ibgp_pic(self):
1509 """ MPLS iBGP PIC edge convergence
1511 1) setup many iBGP VPN routes via a pair of iBGP peers.
1512 2) Check EMCP forwarding to these peers
1513 3) withdraw the IGP route to one of these peers.
1514 4) check forwarding continues to the remaining peer
1518 # IGP+LDP core routes
1520 core_10_0_0_45 = VppIpRoute(self, "10.0.0.45", 32,
1521 [VppRoutePath(self.pg0.remote_ip4,
1522 self.pg0.sw_if_index,
1524 core_10_0_0_45.add_vpp_config()
1526 core_10_0_0_46 = VppIpRoute(self, "10.0.0.46", 32,
1527 [VppRoutePath(self.pg1.remote_ip4,
1528 self.pg1.sw_if_index,
1530 core_10_0_0_46.add_vpp_config()
1533 # Lot's of VPN routes. We need more the 64 so VPP will build
1534 # the fast convergence indirection
1538 for ii in range(64):
1539 dst = "192.168.1.%d" % ii
1540 vpn_routes.append(VppIpRoute(self, dst, 32,
1541 [VppRoutePath("10.0.0.45",
1545 VppRoutePath("10.0.0.46",
1548 is_resolve_host=1)],
1550 vpn_routes[ii].add_vpp_config()
1552 pkts.append(Ether(dst=self.pg2.local_mac,
1553 src=self.pg2.remote_mac) /
1554 IP(src=self.pg2.remote_ip4, dst=dst) /
1555 UDP(sport=1234, dport=1234) /
1559 # Send the packet stream (one pkt to each VPN route)
1560 # - expect a 50-50 split of the traffic
1562 self.pg2.add_stream(pkts)
1563 self.pg_enable_capture(self.pg_interfaces)
1566 rx0 = self.pg0._get_capture(1)
1567 rx1 = self.pg1._get_capture(1)
1569 # not testig the LB hashing algorithm so we're not concerned
1570 # with the split ratio, just as long as neither is 0
1571 self.assertNotEqual(0, len(rx0))
1572 self.assertNotEqual(0, len(rx1))
1575 # use a test CLI command to stop the FIB walk process, this
1576 # will prevent the FIB converging the VPN routes and thus allow
1577 # us to probe the interim (psot-fail, pre-converge) state
1579 self.vapi.ppcli("test fib-walk-process disable")
1582 # Withdraw one of the IGP routes
1584 core_10_0_0_46.remove_vpp_config()
1587 # now all packets should be forwarded through the remaining peer
1589 self.vapi.ppcli("clear trace")
1590 self.pg2.add_stream(pkts)
1591 self.pg_enable_capture(self.pg_interfaces)
1594 rx0 = self.pg0.get_capture(len(pkts))
1597 # enable the FIB walk process to converge the FIB
1599 self.vapi.ppcli("test fib-walk-process enable")
1602 # packets should still be forwarded through the remaining peer
1604 self.pg2.add_stream(pkts)
1605 self.pg_enable_capture(self.pg_interfaces)
1608 rx0 = self.pg0.get_capture(64)
1611 # Add the IGP route back and we return to load-balancing
1613 core_10_0_0_46.add_vpp_config()
1615 self.pg2.add_stream(pkts)
1616 self.pg_enable_capture(self.pg_interfaces)
1619 rx0 = self.pg0._get_capture(1)
1620 rx1 = self.pg1._get_capture(1)
1621 self.assertNotEqual(0, len(rx0))
1622 self.assertNotEqual(0, len(rx1))
1624 def test_mpls_ebgp_pic(self):
1625 """ MPLS eBGP PIC edge convergence
1627 1) setup many eBGP VPN routes via a pair of eBGP peers
1628 2) Check EMCP forwarding to these peers
1629 3) withdraw one eBGP path - expect LB across remaining eBGP
1633 # Lot's of VPN routes. We need more the 64 so VPP will build
1634 # the fast convergence indirection
1639 for ii in range(64):
1640 dst = "192.168.1.%d" % ii
1641 local_label = 1600 + ii
1642 vpn_routes.append(VppIpRoute(self, dst, 32,
1643 [VppRoutePath(self.pg2.remote_ip4,
1646 is_resolve_attached=1),
1647 VppRoutePath(self.pg3.remote_ip4,
1650 is_resolve_attached=1)],
1652 vpn_routes[ii].add_vpp_config()
1654 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 32,
1656 vpn_bindings[ii].add_vpp_config()
1658 pkts.append(Ether(dst=self.pg0.local_mac,
1659 src=self.pg0.remote_mac) /
1660 MPLS(label=local_label, ttl=64) /
1661 IP(src=self.pg0.remote_ip4, dst=dst) /
1662 UDP(sport=1234, dport=1234) /
1665 self.pg0.add_stream(pkts)
1666 self.pg_enable_capture(self.pg_interfaces)
1669 rx0 = self.pg2._get_capture(1)
1670 rx1 = self.pg3._get_capture(1)
1671 self.assertNotEqual(0, len(rx0))
1672 self.assertNotEqual(0, len(rx1))
1675 # use a test CLI command to stop the FIB walk process, this
1676 # will prevent the FIB converging the VPN routes and thus allow
1677 # us to probe the interim (psot-fail, pre-converge) state
1679 self.vapi.ppcli("test fib-walk-process disable")
1682 # withdraw the connected prefix on the interface.
1684 self.pg2.unconfig_ip4()
1687 # now all packets should be forwarded through the remaining peer
1689 self.pg0.add_stream(pkts)
1690 self.pg_enable_capture(self.pg_interfaces)
1693 rx0 = self.pg3.get_capture(len(pkts))
1696 # enable the FIB walk process to converge the FIB
1698 self.vapi.ppcli("test fib-walk-process enable")
1699 self.pg0.add_stream(pkts)
1700 self.pg_enable_capture(self.pg_interfaces)
1703 rx0 = self.pg3.get_capture(len(pkts))
1706 # put the connecteds back
1708 self.pg2.config_ip4()
1710 self.pg0.add_stream(pkts)
1711 self.pg_enable_capture(self.pg_interfaces)
1714 rx0 = self.pg2._get_capture(1)
1715 rx1 = self.pg3._get_capture(1)
1716 self.assertNotEqual(0, len(rx0))
1717 self.assertNotEqual(0, len(rx1))
1719 def test_mpls_v6_ebgp_pic(self):
1720 """ MPLSv6 eBGP PIC edge convergence
1722 1) setup many eBGP VPNv6 routes via a pair of eBGP peers
1723 2) Check EMCP forwarding to these peers
1724 3) withdraw one eBGP path - expect LB across remaining eBGP
1728 # Lot's of VPN routes. We need more the 64 so VPP will build
1729 # the fast convergence indirection
1734 for ii in range(64):
1735 dst = "3000::%d" % ii
1736 local_label = 1600 + ii
1737 vpn_routes.append(VppIpRoute(
1739 [VppRoutePath(self.pg2.remote_ip6,
1742 is_resolve_attached=1,
1743 proto=DpoProto.DPO_PROTO_IP6),
1744 VppRoutePath(self.pg3.remote_ip6,
1747 proto=DpoProto.DPO_PROTO_IP6,
1748 is_resolve_attached=1)],
1751 vpn_routes[ii].add_vpp_config()
1753 vpn_bindings.append(VppMplsIpBind(self, local_label, dst, 128,
1756 vpn_bindings[ii].add_vpp_config()
1758 pkts.append(Ether(dst=self.pg0.local_mac,
1759 src=self.pg0.remote_mac) /
1760 MPLS(label=local_label, ttl=64) /
1761 IPv6(src=self.pg0.remote_ip6, dst=dst) /
1762 UDP(sport=1234, dport=1234) /
1765 self.pg0.add_stream(pkts)
1766 self.pg_enable_capture(self.pg_interfaces)
1769 rx0 = self.pg2._get_capture(1)
1770 rx1 = self.pg3._get_capture(1)
1771 self.assertNotEqual(0, len(rx0))
1772 self.assertNotEqual(0, len(rx1))
1775 # use a test CLI command to stop the FIB walk process, this
1776 # will prevent the FIB converging the VPN routes and thus allow
1777 # us to probe the interim (psot-fail, pre-converge) state
1779 self.vapi.ppcli("test fib-walk-process disable")
1782 # withdraw the connected prefix on the interface.
1783 # and shutdown the interface so the ND cache is flushed.
1785 self.pg2.unconfig_ip6()
1786 self.pg2.admin_down()
1789 # now all packets should be forwarded through the remaining peer
1791 self.pg0.add_stream(pkts)
1792 self.pg_enable_capture(self.pg_interfaces)
1795 rx0 = self.pg3.get_capture(len(pkts))
1798 # enable the FIB walk process to converge the FIB
1800 self.vapi.ppcli("test fib-walk-process enable")
1801 self.pg0.add_stream(pkts)
1802 self.pg_enable_capture(self.pg_interfaces)
1805 rx0 = self.pg3.get_capture(len(pkts))
1808 # put the connecteds back
1811 self.pg2.config_ip6()
1813 self.pg0.add_stream(pkts)
1814 self.pg_enable_capture(self.pg_interfaces)
1817 rx0 = self.pg2._get_capture(1)
1818 rx1 = self.pg3._get_capture(1)
1819 self.assertNotEqual(0, len(rx0))
1820 self.assertNotEqual(0, len(rx1))
1823 class TestMPLSL2(VppTestCase):
1827 super(TestMPLSL2, self).setUp()
1829 # create 2 pg interfaces
1830 self.create_pg_interfaces(range(2))
1832 # create the default MPLS table
1834 tbl = VppMplsTable(self, 0)
1835 tbl.add_vpp_config()
1836 self.tables.append(tbl)
1838 # use pg0 as the core facing interface
1840 self.pg0.config_ip4()
1841 self.pg0.resolve_arp()
1842 self.pg0.enable_mpls()
1844 # use the other 2 for customer facing L2 links
1845 for i in self.pg_interfaces[1:]:
1849 for i in self.pg_interfaces[1:]:
1852 self.pg0.disable_mpls()
1853 self.pg0.unconfig_ip4()
1854 self.pg0.admin_down()
1855 super(TestMPLSL2, self).tearDown()
1857 def verify_capture_tunneled_ethernet(self, capture, sent, mpls_labels):
1858 capture = verify_filter(capture, sent)
1860 self.assertEqual(len(capture), len(sent))
1862 for i in range(len(capture)):
1866 # the MPLS TTL is 255 since it enters a new tunnel
1867 verify_mpls_stack(self, rx, mpls_labels)
1870 rx_eth = Ether(str(rx[MPLS].payload))
1872 self.assertEqual(rx_eth.src, tx_eth.src)
1873 self.assertEqual(rx_eth.dst, tx_eth.dst)
1875 def test_vpws(self):
1876 """ Virtual Private Wire Service """
1879 # Create an MPLS tunnel that pushes 1 label
1880 # For Ethernet over MPLS the uniform mode is irrelevant since ttl/cos
1881 # information is not in the packet, but we test it works anyway
1883 mpls_tun_1 = VppMPLSTunnelInterface(
1885 [VppRoutePath(self.pg0.remote_ip4,
1886 self.pg0.sw_if_index,
1887 labels=[VppMplsLabel(42, MplsLspMode.UNIFORM)])],
1889 mpls_tun_1.add_vpp_config()
1890 mpls_tun_1.admin_up()
1893 # Create a label entry to for 55 that does L2 input to the tunnel
1895 route_55_eos = VppMplsRoute(
1897 [VppRoutePath("0.0.0.0",
1898 mpls_tun_1.sw_if_index,
1900 proto=DpoProto.DPO_PROTO_ETHERNET)])
1901 route_55_eos.add_vpp_config()
1904 # Cross-connect the tunnel with one of the customers L2 interfaces
1906 self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index,
1907 mpls_tun_1.sw_if_index,
1909 self.vapi.sw_interface_set_l2_xconnect(mpls_tun_1.sw_if_index,
1910 self.pg1.sw_if_index,
1914 # inject a packet from the core
1916 pcore = (Ether(dst=self.pg0.local_mac,
1917 src=self.pg0.remote_mac) /
1918 MPLS(label=55, ttl=64) /
1919 Ether(dst="00:00:de:ad:ba:be",
1920 src="00:00:de:ad:be:ef") /
1921 IP(src="10.10.10.10", dst="11.11.11.11") /
1922 UDP(sport=1234, dport=1234) /
1926 rx0 = self.send_and_expect(self.pg0, tx0, self.pg1)
1927 payload = pcore[MPLS].payload
1929 self.assertEqual(rx0[0][Ether].dst, payload[Ether].dst)
1930 self.assertEqual(rx0[0][Ether].src, payload[Ether].src)
1933 # Inject a packet from the custoer/L2 side
1935 tx1 = pcore[MPLS].payload * 65
1936 rx1 = self.send_and_expect(self.pg1, tx1, self.pg0)
1938 self.verify_capture_tunneled_ethernet(rx1, tx1, [VppMplsLabel(42)])
1940 def test_vpls(self):
1941 """ Virtual Private LAN Service """
1943 # Create an L2 MPLS tunnel
1945 mpls_tun = VppMPLSTunnelInterface(
1947 [VppRoutePath(self.pg0.remote_ip4,
1948 self.pg0.sw_if_index,
1949 labels=[VppMplsLabel(42)])],
1951 mpls_tun.add_vpp_config()
1955 # Create a label entry to for 55 that does L2 input to the tunnel
1957 route_55_eos = VppMplsRoute(
1959 [VppRoutePath("0.0.0.0",
1960 mpls_tun.sw_if_index,
1962 proto=DpoProto.DPO_PROTO_ETHERNET)])
1963 route_55_eos.add_vpp_config()
1966 # add to tunnel to the customers bridge-domain
1968 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
1970 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
1974 # Packet from the customer interface and from the core
1976 p_cust = (Ether(dst="00:00:de:ad:ba:be",
1977 src="00:00:de:ad:be:ef") /
1978 IP(src="10.10.10.10", dst="11.11.11.11") /
1979 UDP(sport=1234, dport=1234) /
1981 p_core = (Ether(src="00:00:de:ad:ba:be",
1982 dst="00:00:de:ad:be:ef") /
1983 IP(dst="10.10.10.10", src="11.11.11.11") /
1984 UDP(sport=1234, dport=1234) /
1988 # The BD is learning, so send in one of each packet to learn
1990 p_core_encap = (Ether(dst=self.pg0.local_mac,
1991 src=self.pg0.remote_mac) /
1992 MPLS(label=55, ttl=64) /
1995 self.pg1.add_stream(p_cust)
1996 self.pg_enable_capture(self.pg_interfaces)
1998 self.pg0.add_stream(p_core_encap)
1999 self.pg_enable_capture(self.pg_interfaces)
2002 # we've learnt this so expect it be be forwarded
2003 rx0 = self.pg1.get_capture(1)
2005 self.assertEqual(rx0[0][Ether].dst, p_core[Ether].dst)
2006 self.assertEqual(rx0[0][Ether].src, p_core[Ether].src)
2009 # now a stream in each direction
2011 self.pg1.add_stream(p_cust * 65)
2012 self.pg_enable_capture(self.pg_interfaces)
2015 rx0 = self.pg0.get_capture(65)
2017 self.verify_capture_tunneled_ethernet(rx0, p_cust*65,
2021 # remove interfaces from customers bridge-domain
2023 self.vapi.sw_interface_set_l2_bridge(mpls_tun.sw_if_index,
2026 self.vapi.sw_interface_set_l2_bridge(self.pg1.sw_if_index,
2030 if __name__ == '__main__':
2031 unittest.main(testRunner=VppTestRunner)