6 from framework import VppTestCase, VppTestRunner
7 from vpp_sub_interface import VppDot1QSubint
8 from vpp_gre_interface import VppGreInterface, VppGre6Interface
9 from vpp_ip_route import VppIpRoute, VppRoutePath, DpoProto, VppIpTable
10 from vpp_papi_provider import L2_VTR_OP
12 from scapy.packet import Raw
13 from scapy.layers.l2 import Ether, Dot1Q, GRE
14 from scapy.layers.inet import IP, UDP
15 from scapy.layers.inet6 import IPv6
16 from scapy.volatile import RandMAC, RandIP
18 from util import ppp, ppc
27 class TestGRE(VppTestCase):
32 super(TestGRE, cls).setUpClass()
35 super(TestGRE, self).setUp()
37 # create 3 pg interfaces - set one in a non-default table.
38 self.create_pg_interfaces(range(3))
40 self.tbl = VppIpTable(self, 1)
41 self.tbl.add_vpp_config()
42 self.pg1.set_table_ip4(1)
44 for i in self.pg_interfaces:
48 self.pg0.resolve_arp()
50 self.pg1.resolve_arp()
52 self.pg2.resolve_ndp()
55 for i in self.pg_interfaces:
59 self.pg1.set_table_ip4(0)
60 super(TestGRE, self).tearDown()
62 def create_stream_ip4(self, src_if, src_ip, dst_ip):
64 for i in range(0, 257):
65 info = self.create_packet_info(src_if, src_if)
66 payload = self.info_to_payload(info)
67 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
68 IP(src=src_ip, dst=dst_ip) /
69 UDP(sport=1234, dport=1234) /
75 def create_stream_ip6(self, src_if, src_ip, dst_ip):
77 for i in range(0, 257):
78 info = self.create_packet_info(src_if, src_if)
79 payload = self.info_to_payload(info)
80 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
81 IPv6(src=src_ip, dst=dst_ip) /
82 UDP(sport=1234, dport=1234) /
88 def create_tunnel_stream_4o4(self, src_if,
89 tunnel_src, tunnel_dst,
92 for i in range(0, 257):
93 info = self.create_packet_info(src_if, src_if)
94 payload = self.info_to_payload(info)
95 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
96 IP(src=tunnel_src, dst=tunnel_dst) /
98 IP(src=src_ip, dst=dst_ip) /
99 UDP(sport=1234, dport=1234) /
105 def create_tunnel_stream_6o4(self, src_if,
106 tunnel_src, tunnel_dst,
109 for i in range(0, 257):
110 info = self.create_packet_info(src_if, src_if)
111 payload = self.info_to_payload(info)
112 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
113 IP(src=tunnel_src, dst=tunnel_dst) /
115 IPv6(src=src_ip, dst=dst_ip) /
116 UDP(sport=1234, dport=1234) /
122 def create_tunnel_stream_6o6(self, src_if,
123 tunnel_src, tunnel_dst,
126 for i in range(0, 257):
127 info = self.create_packet_info(src_if, src_if)
128 payload = self.info_to_payload(info)
129 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
130 IPv6(src=tunnel_src, dst=tunnel_dst) /
132 IPv6(src=src_ip, dst=dst_ip) /
133 UDP(sport=1234, dport=1234) /
139 def create_tunnel_stream_l2o4(self, src_if,
140 tunnel_src, tunnel_dst):
142 for i in range(0, 257):
143 info = self.create_packet_info(src_if, src_if)
144 payload = self.info_to_payload(info)
145 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
146 IP(src=tunnel_src, dst=tunnel_dst) /
148 Ether(dst=RandMAC('*:*:*:*:*:*'),
149 src=RandMAC('*:*:*:*:*:*')) /
150 IP(src=str(RandIP()), dst=str(RandIP())) /
151 UDP(sport=1234, dport=1234) /
157 def create_tunnel_stream_vlano4(self, src_if,
158 tunnel_src, tunnel_dst, vlan):
160 for i in range(0, 257):
161 info = self.create_packet_info(src_if, src_if)
162 payload = self.info_to_payload(info)
163 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
164 IP(src=tunnel_src, dst=tunnel_dst) /
166 Ether(dst=RandMAC('*:*:*:*:*:*'),
167 src=RandMAC('*:*:*:*:*:*')) /
169 IP(src=str(RandIP()), dst=str(RandIP())) /
170 UDP(sport=1234, dport=1234) /
176 def verify_tunneled_4o4(self, src_if, capture, sent,
177 tunnel_src, tunnel_dst):
179 self.assertEqual(len(capture), len(sent))
181 for i in range(len(capture)):
189 self.assertEqual(rx_ip.src, tunnel_src)
190 self.assertEqual(rx_ip.dst, tunnel_dst)
195 self.assertEqual(rx_ip.src, tx_ip.src)
196 self.assertEqual(rx_ip.dst, tx_ip.dst)
197 # IP processing post pop has decremented the TTL
198 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
201 self.logger.error(ppp("Rx:", rx))
202 self.logger.error(ppp("Tx:", tx))
205 def verify_tunneled_6o6(self, src_if, capture, sent,
206 tunnel_src, tunnel_dst):
208 self.assertEqual(len(capture), len(sent))
210 for i in range(len(capture)):
218 self.assertEqual(rx_ip.src, tunnel_src)
219 self.assertEqual(rx_ip.dst, tunnel_dst)
221 rx_gre = GRE(str(rx_ip[IPv6].payload))
224 self.assertEqual(rx_ip.src, tx_ip.src)
225 self.assertEqual(rx_ip.dst, tx_ip.dst)
228 self.logger.error(ppp("Rx:", rx))
229 self.logger.error(ppp("Tx:", tx))
232 def verify_tunneled_l2o4(self, src_if, capture, sent,
233 tunnel_src, tunnel_dst):
234 self.assertEqual(len(capture), len(sent))
236 for i in range(len(capture)):
244 self.assertEqual(rx_ip.src, tunnel_src)
245 self.assertEqual(rx_ip.dst, tunnel_dst)
248 rx_l2 = rx_gre[Ether]
251 tx_l2 = tx_gre[Ether]
254 self.assertEqual(rx_ip.src, tx_ip.src)
255 self.assertEqual(rx_ip.dst, tx_ip.dst)
256 # bridged, not L3 forwarded, so no TTL decrement
257 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
260 self.logger.error(ppp("Rx:", rx))
261 self.logger.error(ppp("Tx:", tx))
264 def verify_tunneled_vlano4(self, src_if, capture, sent,
265 tunnel_src, tunnel_dst, vlan):
267 self.assertEqual(len(capture), len(sent))
269 ppc("Unexpected packets captured:", capture)
272 for i in range(len(capture)):
280 self.assertEqual(rx_ip.src, tunnel_src)
281 self.assertEqual(rx_ip.dst, tunnel_dst)
284 rx_l2 = rx_gre[Ether]
285 rx_vlan = rx_l2[Dot1Q]
288 self.assertEqual(rx_vlan.vlan, vlan)
291 tx_l2 = tx_gre[Ether]
294 self.assertEqual(rx_ip.src, tx_ip.src)
295 self.assertEqual(rx_ip.dst, tx_ip.dst)
296 # bridged, not L3 forwarded, so no TTL decrement
297 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
300 self.logger.error(ppp("Rx:", rx))
301 self.logger.error(ppp("Tx:", tx))
304 def verify_decapped_4o4(self, src_if, capture, sent):
305 self.assertEqual(len(capture), len(sent))
307 for i in range(len(capture)):
317 self.assertEqual(rx_ip.src, tx_ip.src)
318 self.assertEqual(rx_ip.dst, tx_ip.dst)
319 # IP processing post pop has decremented the TTL
320 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
323 self.logger.error(ppp("Rx:", rx))
324 self.logger.error(ppp("Tx:", tx))
327 def verify_decapped_6o4(self, src_if, capture, sent):
328 self.assertEqual(len(capture), len(sent))
330 for i in range(len(capture)):
340 self.assertEqual(rx_ip.src, tx_ip.src)
341 self.assertEqual(rx_ip.dst, tx_ip.dst)
342 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
345 self.logger.error(ppp("Rx:", rx))
346 self.logger.error(ppp("Tx:", tx))
350 """ GRE IPv4 tunnel Tests """
353 # Create an L3 GRE tunnel.
355 # - assign an IP Addres
356 # - Add a route via the tunnel
358 gre_if = VppGreInterface(self,
361 gre_if.add_vpp_config()
364 # The double create (create the same tunnel twice) should fail,
365 # and we should still be able to use the original
368 gre_if.add_vpp_config()
372 self.fail("Double GRE tunnel add does not fail")
377 route_via_tun = VppIpRoute(self, "4.4.4.4", 32,
378 [VppRoutePath("0.0.0.0",
379 gre_if.sw_if_index)])
381 route_via_tun.add_vpp_config()
384 # Send a packet stream that is routed into the tunnel
385 # - they are all dropped since the tunnel's desintation IP
386 # is unresolved - or resolves via the default route - which
389 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
390 self.pg0.add_stream(tx)
392 self.pg_enable_capture(self.pg_interfaces)
395 self.pg0.assert_nothing_captured(
396 remark="GRE packets forwarded without DIP resolved")
399 # Add a route that resolves the tunnel's destination
401 route_tun_dst = VppIpRoute(self, "1.1.1.2", 32,
402 [VppRoutePath(self.pg0.remote_ip4,
403 self.pg0.sw_if_index)])
404 route_tun_dst.add_vpp_config()
407 # Send a packet stream that is routed into the tunnel
408 # - packets are GRE encapped
410 self.vapi.cli("clear trace")
411 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
412 self.pg0.add_stream(tx)
414 self.pg_enable_capture(self.pg_interfaces)
417 rx = self.pg0.get_capture(len(tx))
418 self.verify_tunneled_4o4(self.pg0, rx, tx,
419 self.pg0.local_ip4, "1.1.1.2")
422 # Send tunneled packets that match the created tunnel and
423 # are decapped and forwarded
425 self.vapi.cli("clear trace")
426 tx = self.create_tunnel_stream_4o4(self.pg0,
431 self.pg0.add_stream(tx)
433 self.pg_enable_capture(self.pg_interfaces)
436 rx = self.pg0.get_capture(len(tx))
437 self.verify_decapped_4o4(self.pg0, rx, tx)
440 # Send tunneled packets that do not match the tunnel's src
442 self.vapi.cli("clear trace")
443 tx = self.create_tunnel_stream_4o4(self.pg0,
448 self.pg0.add_stream(tx)
450 self.pg_enable_capture(self.pg_interfaces)
453 self.pg0.assert_nothing_captured(
454 remark="GRE packets forwarded despite no SRC address match")
457 # Configure IPv6 on the PG interface so we can route IPv6
460 self.pg0.config_ip6()
461 self.pg0.resolve_ndp()
464 # Send IPv6 tunnel encapslated packets
465 # - dropped since IPv6 is not enabled on the tunnel
467 self.vapi.cli("clear trace")
468 tx = self.create_tunnel_stream_6o4(self.pg0,
473 self.pg0.add_stream(tx)
475 self.pg_enable_capture(self.pg_interfaces)
478 self.pg0.assert_nothing_captured(remark="IPv6 GRE packets forwarded "
479 "despite IPv6 not enabled on tunnel")
482 # Enable IPv6 on the tunnel
487 # Send IPv6 tunnel encapslated packets
488 # - forwarded since IPv6 is enabled on the tunnel
490 self.vapi.cli("clear trace")
491 tx = self.create_tunnel_stream_6o4(self.pg0,
496 self.pg0.add_stream(tx)
498 self.pg_enable_capture(self.pg_interfaces)
501 rx = self.pg0.get_capture(len(tx))
502 self.verify_decapped_6o4(self.pg0, rx, tx)
507 route_tun_dst.remove_vpp_config()
508 route_via_tun.remove_vpp_config()
509 gre_if.remove_vpp_config()
511 self.pg0.unconfig_ip6()
514 """ GRE IPv6 tunnel Tests """
516 self.pg1.config_ip6()
517 self.pg1.resolve_ndp()
520 # Create an L3 GRE tunnel.
522 # - assign an IP Address
523 # - Add a route via the tunnel
525 gre_if = VppGre6Interface(self,
528 gre_if.add_vpp_config()
532 route_via_tun = VppIpRoute(
533 self, "4004::1", 128,
534 [VppRoutePath("0::0",
536 proto=DpoProto.DPO_PROTO_IP6)],
539 route_via_tun.add_vpp_config()
542 # Send a packet stream that is routed into the tunnel
543 # - they are all dropped since the tunnel's desintation IP
544 # is unresolved - or resolves via the default route - which
547 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
548 self.pg2.add_stream(tx)
550 self.pg_enable_capture(self.pg_interfaces)
553 self.pg2.assert_nothing_captured(
554 remark="GRE packets forwarded without DIP resolved")
557 # Add a route that resolves the tunnel's destination
559 route_tun_dst = VppIpRoute(
560 self, "1002::1", 128,
561 [VppRoutePath(self.pg2.remote_ip6,
562 self.pg2.sw_if_index,
563 proto=DpoProto.DPO_PROTO_IP6)],
565 route_tun_dst.add_vpp_config()
568 # Send a packet stream that is routed into the tunnel
569 # - packets are GRE encapped
571 self.vapi.cli("clear trace")
572 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
573 self.pg2.add_stream(tx)
575 self.pg_enable_capture(self.pg_interfaces)
578 rx = self.pg2.get_capture(len(tx))
579 self.verify_tunneled_6o6(self.pg2, rx, tx,
580 self.pg2.local_ip6, "1002::1")
583 # Test decap. decapped packets go out pg1
585 tx = self.create_tunnel_stream_6o6(self.pg2,
590 self.vapi.cli("clear trace")
591 self.pg2.add_stream(tx)
593 self.pg_enable_capture(self.pg_interfaces)
595 rx = self.pg1.get_capture(len(tx))
598 # RX'd packet is UDP over IPv6, test the GRE header is gone.
600 self.assertFalse(rx[0].haslayer(GRE))
601 self.assertEqual(rx[0][IPv6].dst, self.pg1.remote_ip6)
606 route_tun_dst.remove_vpp_config()
607 route_via_tun.remove_vpp_config()
608 gre_if.remove_vpp_config()
610 self.pg2.unconfig_ip6()
611 self.pg1.unconfig_ip6()
613 def test_gre_vrf(self):
614 """ GRE tunnel VRF Tests """
617 # Create an L3 GRE tunnel whose destination is in the non-default
618 # table. The underlay is thus non-default - the overlay is still
621 # - assign an IP Addres
623 gre_if = VppGreInterface(self, self.pg1.local_ip4,
626 gre_if.add_vpp_config()
631 # Add a route via the tunnel - in the overlay
633 route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
634 [VppRoutePath("0.0.0.0",
635 gre_if.sw_if_index)])
636 route_via_tun.add_vpp_config()
639 # Add a route that resolves the tunnel's destination - in the
642 route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
643 paths=[VppRoutePath(self.pg1.remote_ip4,
644 self.pg1.sw_if_index)])
645 route_tun_dst.add_vpp_config()
648 # Send a packet stream that is routed into the tunnel
649 # packets are sent in on pg0 which is in the default table
650 # - packets are GRE encapped
652 self.vapi.cli("clear trace")
653 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
654 self.pg0.add_stream(tx)
656 self.pg_enable_capture(self.pg_interfaces)
659 rx = self.pg1.get_capture(len(tx))
660 self.verify_tunneled_4o4(self.pg1, rx, tx,
661 self.pg1.local_ip4, "2.2.2.2")
664 # Send tunneled packets that match the created tunnel and
665 # are decapped and forwarded. This tests the decap lookup
666 # does not happen in the encap table
668 self.vapi.cli("clear trace")
669 tx = self.create_tunnel_stream_4o4(self.pg1,
674 self.pg1.add_stream(tx)
676 self.pg_enable_capture(self.pg_interfaces)
679 rx = self.pg0.get_capture(len(tx))
680 self.verify_decapped_4o4(self.pg0, rx, tx)
683 # Send tunneled packets that match the created tunnel and
684 # but arrive on an interface that is not in the tunnel's
685 # encap VRF, these are dropped
687 self.vapi.cli("clear trace")
688 tx = self.create_tunnel_stream_4o4(self.pg2,
693 self.pg1.add_stream(tx)
695 self.pg_enable_capture(self.pg_interfaces)
698 self.pg0.assert_nothing_captured(
699 remark="GRE decap packets in wrong VRF")
704 route_tun_dst.remove_vpp_config()
705 route_via_tun.remove_vpp_config()
706 gre_if.remove_vpp_config()
708 def test_gre_l2(self):
709 """ GRE tunnel L2 Tests """
712 # Add routes to resolve the tunnel destinations
714 route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
715 [VppRoutePath(self.pg0.remote_ip4,
716 self.pg0.sw_if_index)])
717 route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
718 [VppRoutePath(self.pg0.remote_ip4,
719 self.pg0.sw_if_index)])
721 route_tun1_dst.add_vpp_config()
722 route_tun2_dst.add_vpp_config()
725 # Create 2 L2 GRE tunnels and x-connect them
727 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
729 type=GreTunnelTypes.TT_TEB)
730 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
732 type=GreTunnelTypes.TT_TEB)
733 gre_if1.add_vpp_config()
734 gre_if2.add_vpp_config()
739 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
742 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
747 # Send in tunnel encapped L2. expect out tunnel encapped L2
750 self.vapi.cli("clear trace")
751 tx = self.create_tunnel_stream_l2o4(self.pg0,
754 self.pg0.add_stream(tx)
756 self.pg_enable_capture(self.pg_interfaces)
759 rx = self.pg0.get_capture(len(tx))
760 self.verify_tunneled_l2o4(self.pg0, rx, tx,
764 self.vapi.cli("clear trace")
765 tx = self.create_tunnel_stream_l2o4(self.pg0,
768 self.pg0.add_stream(tx)
770 self.pg_enable_capture(self.pg_interfaces)
773 rx = self.pg0.get_capture(len(tx))
774 self.verify_tunneled_l2o4(self.pg0, rx, tx,
778 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
781 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
786 # Create a VLAN sub-interfaces on the GRE TEB interfaces
787 # then x-connect them
789 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
790 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
792 # gre_if_11.add_vpp_config()
793 # gre_if_12.add_vpp_config()
798 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
799 gre_if_12.sw_if_index,
801 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
802 gre_if_11.sw_if_index,
806 # Configure both to pop thier respective VLAN tags,
807 # so that during the x-coonect they will subsequently push
809 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
812 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
817 # Send traffic in both directiond - expect the VLAN tags to
820 self.vapi.cli("clear trace")
821 tx = self.create_tunnel_stream_vlano4(self.pg0,
825 self.pg0.add_stream(tx)
827 self.pg_enable_capture(self.pg_interfaces)
830 rx = self.pg0.get_capture(len(tx))
831 self.verify_tunneled_vlano4(self.pg0, rx, tx,
836 self.vapi.cli("clear trace")
837 tx = self.create_tunnel_stream_vlano4(self.pg0,
841 self.pg0.add_stream(tx)
843 self.pg_enable_capture(self.pg_interfaces)
846 rx = self.pg0.get_capture(len(tx))
847 self.verify_tunneled_vlano4(self.pg0, rx, tx,
853 # Cleanup Test resources
855 gre_if_11.remove_vpp_config()
856 gre_if_12.remove_vpp_config()
857 gre_if1.remove_vpp_config()
858 gre_if2.remove_vpp_config()
859 route_tun1_dst.add_vpp_config()
860 route_tun2_dst.add_vpp_config()
863 if __name__ == '__main__':
864 unittest.main(testRunner=VppTestRunner)