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 import DpoProto
10 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
11 from vpp_papi_provider import L2_VTR_OP
13 from scapy.packet import Raw
14 from scapy.layers.l2 import Ether, Dot1Q, GRE
15 from scapy.layers.inet import IP, UDP
16 from scapy.layers.inet6 import IPv6
17 from scapy.volatile import RandMAC, RandIP
19 from util import ppp, ppc
28 class TestGRE(VppTestCase):
33 super(TestGRE, cls).setUpClass()
36 super(TestGRE, self).setUp()
38 # create 3 pg interfaces - set one in a non-default table.
39 self.create_pg_interfaces(range(3))
41 self.tbl = VppIpTable(self, 1)
42 self.tbl.add_vpp_config()
43 self.pg1.set_table_ip4(1)
45 for i in self.pg_interfaces:
49 self.pg0.resolve_arp()
51 self.pg1.resolve_arp()
53 self.pg2.resolve_ndp()
56 for i in self.pg_interfaces:
60 self.pg1.set_table_ip4(0)
61 super(TestGRE, self).tearDown()
63 def create_stream_ip4(self, src_if, src_ip, dst_ip):
65 for i in range(0, 257):
66 info = self.create_packet_info(src_if, src_if)
67 payload = self.info_to_payload(info)
68 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
69 IP(src=src_ip, dst=dst_ip) /
70 UDP(sport=1234, dport=1234) /
76 def create_stream_ip6(self, src_if, src_ip, dst_ip):
78 for i in range(0, 257):
79 info = self.create_packet_info(src_if, src_if)
80 payload = self.info_to_payload(info)
81 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
82 IPv6(src=src_ip, dst=dst_ip) /
83 UDP(sport=1234, dport=1234) /
89 def create_tunnel_stream_4o4(self, src_if,
90 tunnel_src, tunnel_dst,
93 for i in range(0, 257):
94 info = self.create_packet_info(src_if, src_if)
95 payload = self.info_to_payload(info)
96 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
97 IP(src=tunnel_src, dst=tunnel_dst) /
99 IP(src=src_ip, dst=dst_ip) /
100 UDP(sport=1234, dport=1234) /
106 def create_tunnel_stream_6o4(self, src_if,
107 tunnel_src, tunnel_dst,
110 for i in range(0, 257):
111 info = self.create_packet_info(src_if, src_if)
112 payload = self.info_to_payload(info)
113 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
114 IP(src=tunnel_src, dst=tunnel_dst) /
116 IPv6(src=src_ip, dst=dst_ip) /
117 UDP(sport=1234, dport=1234) /
123 def create_tunnel_stream_6o6(self, src_if,
124 tunnel_src, tunnel_dst,
127 for i in range(0, 257):
128 info = self.create_packet_info(src_if, src_if)
129 payload = self.info_to_payload(info)
130 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
131 IPv6(src=tunnel_src, dst=tunnel_dst) /
133 IPv6(src=src_ip, dst=dst_ip) /
134 UDP(sport=1234, dport=1234) /
140 def create_tunnel_stream_l2o4(self, src_if,
141 tunnel_src, tunnel_dst):
143 for i in range(0, 257):
144 info = self.create_packet_info(src_if, src_if)
145 payload = self.info_to_payload(info)
146 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
147 IP(src=tunnel_src, dst=tunnel_dst) /
149 Ether(dst=RandMAC('*:*:*:*:*:*'),
150 src=RandMAC('*:*:*:*:*:*')) /
151 IP(src=str(RandIP()), dst=str(RandIP())) /
152 UDP(sport=1234, dport=1234) /
158 def create_tunnel_stream_vlano4(self, src_if,
159 tunnel_src, tunnel_dst, vlan):
161 for i in range(0, 257):
162 info = self.create_packet_info(src_if, src_if)
163 payload = self.info_to_payload(info)
164 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
165 IP(src=tunnel_src, dst=tunnel_dst) /
167 Ether(dst=RandMAC('*:*:*:*:*:*'),
168 src=RandMAC('*:*:*:*:*:*')) /
170 IP(src=str(RandIP()), dst=str(RandIP())) /
171 UDP(sport=1234, dport=1234) /
177 def verify_tunneled_4o4(self, src_if, capture, sent,
178 tunnel_src, tunnel_dst):
180 self.assertEqual(len(capture), len(sent))
182 for i in range(len(capture)):
190 self.assertEqual(rx_ip.src, tunnel_src)
191 self.assertEqual(rx_ip.dst, tunnel_dst)
196 self.assertEqual(rx_ip.src, tx_ip.src)
197 self.assertEqual(rx_ip.dst, tx_ip.dst)
198 # IP processing post pop has decremented the TTL
199 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
202 self.logger.error(ppp("Rx:", rx))
203 self.logger.error(ppp("Tx:", tx))
206 def verify_tunneled_6o6(self, src_if, capture, sent,
207 tunnel_src, tunnel_dst):
209 self.assertEqual(len(capture), len(sent))
211 for i in range(len(capture)):
219 self.assertEqual(rx_ip.src, tunnel_src)
220 self.assertEqual(rx_ip.dst, tunnel_dst)
222 rx_gre = GRE(str(rx_ip[IPv6].payload))
225 self.assertEqual(rx_ip.src, tx_ip.src)
226 self.assertEqual(rx_ip.dst, tx_ip.dst)
229 self.logger.error(ppp("Rx:", rx))
230 self.logger.error(ppp("Tx:", tx))
233 def verify_tunneled_4o6(self, src_if, capture, sent,
234 tunnel_src, tunnel_dst):
236 self.assertEqual(len(capture), len(sent))
238 for i in range(len(capture)):
245 self.assertEqual(rx_ip.src, tunnel_src)
246 self.assertEqual(rx_ip.dst, tunnel_dst)
248 rx_gre = GRE(str(rx_ip[IPv6].payload))
252 self.assertEqual(rx_ip.src, tx_ip.src)
253 self.assertEqual(rx_ip.dst, tx_ip.dst)
256 self.logger.error(ppp("Rx:", rx))
257 self.logger.error(ppp("Tx:", tx))
260 def verify_tunneled_6o4(self, src_if, capture, sent,
261 tunnel_src, tunnel_dst):
263 self.assertEqual(len(capture), len(sent))
265 for i in range(len(capture)):
272 self.assertEqual(rx_ip.src, tunnel_src)
273 self.assertEqual(rx_ip.dst, tunnel_dst)
275 rx_gre = GRE(str(rx_ip[IP].payload))
279 self.assertEqual(rx_ip.src, tx_ip.src)
280 self.assertEqual(rx_ip.dst, tx_ip.dst)
283 self.logger.error(ppp("Rx:", rx))
284 self.logger.error(ppp("Tx:", tx))
287 def verify_tunneled_l2o4(self, src_if, capture, sent,
288 tunnel_src, tunnel_dst):
289 self.assertEqual(len(capture), len(sent))
291 for i in range(len(capture)):
299 self.assertEqual(rx_ip.src, tunnel_src)
300 self.assertEqual(rx_ip.dst, tunnel_dst)
303 rx_l2 = rx_gre[Ether]
306 tx_l2 = tx_gre[Ether]
309 self.assertEqual(rx_ip.src, tx_ip.src)
310 self.assertEqual(rx_ip.dst, tx_ip.dst)
311 # bridged, not L3 forwarded, so no TTL decrement
312 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
315 self.logger.error(ppp("Rx:", rx))
316 self.logger.error(ppp("Tx:", tx))
319 def verify_tunneled_vlano4(self, src_if, capture, sent,
320 tunnel_src, tunnel_dst, vlan):
322 self.assertEqual(len(capture), len(sent))
324 ppc("Unexpected packets captured:", capture)
327 for i in range(len(capture)):
335 self.assertEqual(rx_ip.src, tunnel_src)
336 self.assertEqual(rx_ip.dst, tunnel_dst)
339 rx_l2 = rx_gre[Ether]
340 rx_vlan = rx_l2[Dot1Q]
343 self.assertEqual(rx_vlan.vlan, vlan)
346 tx_l2 = tx_gre[Ether]
349 self.assertEqual(rx_ip.src, tx_ip.src)
350 self.assertEqual(rx_ip.dst, tx_ip.dst)
351 # bridged, not L3 forwarded, so no TTL decrement
352 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
355 self.logger.error(ppp("Rx:", rx))
356 self.logger.error(ppp("Tx:", tx))
359 def verify_decapped_4o4(self, src_if, capture, sent):
360 self.assertEqual(len(capture), len(sent))
362 for i in range(len(capture)):
372 self.assertEqual(rx_ip.src, tx_ip.src)
373 self.assertEqual(rx_ip.dst, tx_ip.dst)
374 # IP processing post pop has decremented the TTL
375 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
378 self.logger.error(ppp("Rx:", rx))
379 self.logger.error(ppp("Tx:", tx))
382 def verify_decapped_6o4(self, src_if, capture, sent):
383 self.assertEqual(len(capture), len(sent))
385 for i in range(len(capture)):
395 self.assertEqual(rx_ip.src, tx_ip.src)
396 self.assertEqual(rx_ip.dst, tx_ip.dst)
397 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
400 self.logger.error(ppp("Rx:", rx))
401 self.logger.error(ppp("Tx:", tx))
405 """ GRE IPv4 tunnel Tests """
408 # Create an L3 GRE tunnel.
410 # - assign an IP Addres
411 # - Add a route via the tunnel
413 gre_if = VppGreInterface(self,
416 gre_if.add_vpp_config()
419 # The double create (create the same tunnel twice) should fail,
420 # and we should still be able to use the original
423 gre_if.add_vpp_config()
427 self.fail("Double GRE tunnel add does not fail")
432 route_via_tun = VppIpRoute(self, "4.4.4.4", 32,
433 [VppRoutePath("0.0.0.0",
434 gre_if.sw_if_index)])
436 route_via_tun.add_vpp_config()
439 # Send a packet stream that is routed into the tunnel
440 # - they are all dropped since the tunnel's desintation IP
441 # is unresolved - or resolves via the default route - which
444 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
445 self.pg0.add_stream(tx)
447 self.pg_enable_capture(self.pg_interfaces)
450 self.pg0.assert_nothing_captured(
451 remark="GRE packets forwarded without DIP resolved")
454 # Add a route that resolves the tunnel's destination
456 route_tun_dst = VppIpRoute(self, "1.1.1.2", 32,
457 [VppRoutePath(self.pg0.remote_ip4,
458 self.pg0.sw_if_index)])
459 route_tun_dst.add_vpp_config()
462 # Send a packet stream that is routed into the tunnel
463 # - packets are GRE encapped
465 self.vapi.cli("clear trace")
466 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
467 self.pg0.add_stream(tx)
469 self.pg_enable_capture(self.pg_interfaces)
472 rx = self.pg0.get_capture(len(tx))
473 self.verify_tunneled_4o4(self.pg0, rx, tx,
474 self.pg0.local_ip4, "1.1.1.2")
477 # Send tunneled packets that match the created tunnel and
478 # are decapped and forwarded
480 self.vapi.cli("clear trace")
481 tx = self.create_tunnel_stream_4o4(self.pg0,
486 self.pg0.add_stream(tx)
488 self.pg_enable_capture(self.pg_interfaces)
491 rx = self.pg0.get_capture(len(tx))
492 self.verify_decapped_4o4(self.pg0, rx, tx)
495 # Send tunneled packets that do not match the tunnel's src
497 self.vapi.cli("clear trace")
498 tx = self.create_tunnel_stream_4o4(self.pg0,
503 self.pg0.add_stream(tx)
505 self.pg_enable_capture(self.pg_interfaces)
508 self.pg0.assert_nothing_captured(
509 remark="GRE packets forwarded despite no SRC address match")
512 # Configure IPv6 on the PG interface so we can route IPv6
515 self.pg0.config_ip6()
516 self.pg0.resolve_ndp()
519 # Send IPv6 tunnel encapslated packets
520 # - dropped since IPv6 is not enabled on the tunnel
522 self.vapi.cli("clear trace")
523 tx = self.create_tunnel_stream_6o4(self.pg0,
528 self.pg0.add_stream(tx)
530 self.pg_enable_capture(self.pg_interfaces)
533 self.pg0.assert_nothing_captured(remark="IPv6 GRE packets forwarded "
534 "despite IPv6 not enabled on tunnel")
537 # Enable IPv6 on the tunnel
542 # Send IPv6 tunnel encapslated packets
543 # - forwarded since IPv6 is enabled on the tunnel
545 self.vapi.cli("clear trace")
546 tx = self.create_tunnel_stream_6o4(self.pg0,
551 self.pg0.add_stream(tx)
553 self.pg_enable_capture(self.pg_interfaces)
556 rx = self.pg0.get_capture(len(tx))
557 self.verify_decapped_6o4(self.pg0, rx, tx)
560 # Send v6 packets for v4 encap
562 route6_via_tun = VppIpRoute(
563 self, "2001::1", 128,
566 proto=DpoProto.DPO_PROTO_IP6)],
568 route6_via_tun.add_vpp_config()
570 tx = self.create_stream_ip6(self.pg0, "2001::2", "2001::1")
571 rx = self.send_and_expect(self.pg0, tx, self.pg0)
573 self.verify_tunneled_6o4(self.pg0, rx, tx,
574 self.pg0.local_ip4, "1.1.1.2")
579 route_tun_dst.remove_vpp_config()
580 route_via_tun.remove_vpp_config()
581 route6_via_tun.remove_vpp_config()
582 gre_if.remove_vpp_config()
584 self.pg0.unconfig_ip6()
587 """ GRE IPv6 tunnel Tests """
589 self.pg1.config_ip6()
590 self.pg1.resolve_ndp()
593 # Create an L3 GRE tunnel.
595 # - assign an IP Address
596 # - Add a route via the tunnel
598 gre_if = VppGre6Interface(self,
601 gre_if.add_vpp_config()
605 route_via_tun = VppIpRoute(
606 self, "4004::1", 128,
607 [VppRoutePath("0::0",
609 proto=DpoProto.DPO_PROTO_IP6)],
612 route_via_tun.add_vpp_config()
615 # Send a packet stream that is routed into the tunnel
616 # - they are all dropped since the tunnel's desintation IP
617 # is unresolved - or resolves via the default route - which
620 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
621 self.pg2.add_stream(tx)
623 self.pg_enable_capture(self.pg_interfaces)
626 self.pg2.assert_nothing_captured(
627 remark="GRE packets forwarded without DIP resolved")
630 # Add a route that resolves the tunnel's destination
632 route_tun_dst = VppIpRoute(
633 self, "1002::1", 128,
634 [VppRoutePath(self.pg2.remote_ip6,
635 self.pg2.sw_if_index,
636 proto=DpoProto.DPO_PROTO_IP6)],
638 route_tun_dst.add_vpp_config()
641 # Send a packet stream that is routed into the tunnel
642 # - packets are GRE encapped
644 self.vapi.cli("clear trace")
645 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
646 self.pg2.add_stream(tx)
648 self.pg_enable_capture(self.pg_interfaces)
651 rx = self.pg2.get_capture(len(tx))
652 self.verify_tunneled_6o6(self.pg2, rx, tx,
653 self.pg2.local_ip6, "1002::1")
656 # Test decap. decapped packets go out pg1
658 tx = self.create_tunnel_stream_6o6(self.pg2,
663 self.vapi.cli("clear trace")
664 self.pg2.add_stream(tx)
666 self.pg_enable_capture(self.pg_interfaces)
668 rx = self.pg1.get_capture(len(tx))
671 # RX'd packet is UDP over IPv6, test the GRE header is gone.
673 self.assertFalse(rx[0].haslayer(GRE))
674 self.assertEqual(rx[0][IPv6].dst, self.pg1.remote_ip6)
679 route4_via_tun = VppIpRoute(self, "1.1.1.1", 32,
680 [VppRoutePath("0.0.0.0",
681 gre_if.sw_if_index)])
682 route4_via_tun.add_vpp_config()
684 tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "1.1.1.1")
685 rx = self.send_and_expect(self.pg0, tx, self.pg2)
687 self.verify_tunneled_4o6(self.pg0, rx, tx,
688 self.pg2.local_ip6, "1002::1")
693 route_tun_dst.remove_vpp_config()
694 route_via_tun.remove_vpp_config()
695 route4_via_tun.remove_vpp_config()
696 gre_if.remove_vpp_config()
698 self.pg2.unconfig_ip6()
699 self.pg1.unconfig_ip6()
701 def test_gre_vrf(self):
702 """ GRE tunnel VRF Tests """
705 # Create an L3 GRE tunnel whose destination is in the non-default
706 # table. The underlay is thus non-default - the overlay is still
709 # - assign an IP Addres
711 gre_if = VppGreInterface(self, self.pg1.local_ip4,
714 gre_if.add_vpp_config()
719 # Add a route via the tunnel - in the overlay
721 route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
722 [VppRoutePath("0.0.0.0",
723 gre_if.sw_if_index)])
724 route_via_tun.add_vpp_config()
727 # Add a route that resolves the tunnel's destination - in the
730 route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
731 paths=[VppRoutePath(self.pg1.remote_ip4,
732 self.pg1.sw_if_index)])
733 route_tun_dst.add_vpp_config()
736 # Send a packet stream that is routed into the tunnel
737 # packets are sent in on pg0 which is in the default table
738 # - packets are GRE encapped
740 self.vapi.cli("clear trace")
741 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
742 self.pg0.add_stream(tx)
744 self.pg_enable_capture(self.pg_interfaces)
747 rx = self.pg1.get_capture(len(tx))
748 self.verify_tunneled_4o4(self.pg1, rx, tx,
749 self.pg1.local_ip4, "2.2.2.2")
752 # Send tunneled packets that match the created tunnel and
753 # are decapped and forwarded. This tests the decap lookup
754 # does not happen in the encap table
756 self.vapi.cli("clear trace")
757 tx = self.create_tunnel_stream_4o4(self.pg1,
762 self.pg1.add_stream(tx)
764 self.pg_enable_capture(self.pg_interfaces)
767 rx = self.pg0.get_capture(len(tx))
768 self.verify_decapped_4o4(self.pg0, rx, tx)
771 # Send tunneled packets that match the created tunnel
772 # but arrive on an interface that is not in the tunnel's
773 # encap VRF, these are dropped.
774 # IP enable the interface so they aren't dropped due to
775 # IP not being enabled.
777 self.pg2.config_ip4()
778 self.vapi.cli("clear trace")
779 tx = self.create_tunnel_stream_4o4(self.pg2,
784 self.pg2.add_stream(tx)
786 self.pg_enable_capture(self.pg_interfaces)
789 self.pg0.assert_nothing_captured(
790 remark="GRE decap packets in wrong VRF")
792 self.pg2.unconfig_ip4()
797 route_tun_dst.remove_vpp_config()
798 route_via_tun.remove_vpp_config()
799 gre_if.remove_vpp_config()
801 def test_gre_l2(self):
802 """ GRE tunnel L2 Tests """
805 # Add routes to resolve the tunnel destinations
807 route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
808 [VppRoutePath(self.pg0.remote_ip4,
809 self.pg0.sw_if_index)])
810 route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
811 [VppRoutePath(self.pg0.remote_ip4,
812 self.pg0.sw_if_index)])
814 route_tun1_dst.add_vpp_config()
815 route_tun2_dst.add_vpp_config()
818 # Create 2 L2 GRE tunnels and x-connect them
820 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
822 type=GreTunnelTypes.TT_TEB)
823 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
825 type=GreTunnelTypes.TT_TEB)
826 gre_if1.add_vpp_config()
827 gre_if2.add_vpp_config()
832 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
835 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
840 # Send in tunnel encapped L2. expect out tunnel encapped L2
843 self.vapi.cli("clear trace")
844 tx = self.create_tunnel_stream_l2o4(self.pg0,
847 self.pg0.add_stream(tx)
849 self.pg_enable_capture(self.pg_interfaces)
852 rx = self.pg0.get_capture(len(tx))
853 self.verify_tunneled_l2o4(self.pg0, rx, tx,
857 self.vapi.cli("clear trace")
858 tx = self.create_tunnel_stream_l2o4(self.pg0,
861 self.pg0.add_stream(tx)
863 self.pg_enable_capture(self.pg_interfaces)
866 rx = self.pg0.get_capture(len(tx))
867 self.verify_tunneled_l2o4(self.pg0, rx, tx,
871 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
874 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
879 # Create a VLAN sub-interfaces on the GRE TEB interfaces
880 # then x-connect them
882 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
883 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
885 # gre_if_11.add_vpp_config()
886 # gre_if_12.add_vpp_config()
891 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
892 gre_if_12.sw_if_index,
894 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
895 gre_if_11.sw_if_index,
899 # Configure both to pop thier respective VLAN tags,
900 # so that during the x-coonect they will subsequently push
902 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
905 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
910 # Send traffic in both directiond - expect the VLAN tags to
913 self.vapi.cli("clear trace")
914 tx = self.create_tunnel_stream_vlano4(self.pg0,
918 self.pg0.add_stream(tx)
920 self.pg_enable_capture(self.pg_interfaces)
923 rx = self.pg0.get_capture(len(tx))
924 self.verify_tunneled_vlano4(self.pg0, rx, tx,
929 self.vapi.cli("clear trace")
930 tx = self.create_tunnel_stream_vlano4(self.pg0,
934 self.pg0.add_stream(tx)
936 self.pg_enable_capture(self.pg_interfaces)
939 rx = self.pg0.get_capture(len(tx))
940 self.verify_tunneled_vlano4(self.pg0, rx, tx,
946 # Cleanup Test resources
948 gre_if_11.remove_vpp_config()
949 gre_if_12.remove_vpp_config()
950 gre_if1.remove_vpp_config()
951 gre_if2.remove_vpp_config()
952 route_tun1_dst.add_vpp_config()
953 route_tun2_dst.add_vpp_config()
956 if __name__ == '__main__':
957 unittest.main(testRunner=VppTestRunner)