ip: add support for buffer offload metadata in ip midchain
[vpp.git] / test / test_gso.py
index 2c8250e..78c5c73 100644 (file)
@@ -11,6 +11,7 @@
 import unittest
 
 from scapy.packet import Raw
 import unittest
 
 from scapy.packet import Raw
+from scapy.layers.l2 import GRE
 from scapy.layers.inet6 import IPv6, Ether, IP, ICMPv6PacketTooBig
 from scapy.layers.inet6 import ipv6nh, IPerror6
 from scapy.layers.inet import TCP, ICMP
 from scapy.layers.inet6 import IPv6, Ether, IP, ICMPv6PacketTooBig
 from scapy.layers.inet6 import ipv6nh, IPerror6
 from scapy.layers.inet import TCP, ICMP
@@ -23,6 +24,7 @@ from asfframework import VppTestRunner
 from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
 from vpp_ipip_tun_interface import VppIpIpTunInterface
 from vpp_vxlan_tunnel import VppVxlanTunnel
 from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
 from vpp_ipip_tun_interface import VppIpIpTunInterface
 from vpp_vxlan_tunnel import VppVxlanTunnel
+from vpp_gre_interface import VppGreInterface
 
 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect
 from template_ipsec import (
 
 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect
 from template_ipsec import (
@@ -89,6 +91,9 @@ class TestGSO(VppTestCase):
             self, self.pg0, self.pg0.local_ip6, self.pg0.remote_ip6
         )
 
             self, self.pg0, self.pg0.local_ip6, self.pg0.remote_ip6
         )
 
+        self.gre4 = VppGreInterface(self, self.pg0.local_ip4, self.pg0.remote_ip4)
+        self.gre6 = VppGreInterface(self, self.pg0.local_ip6, self.pg0.remote_ip6)
+
     def tearDown(self):
         super(TestGSO, self).tearDown()
         if not self.vpp_dead:
     def tearDown(self):
         super(TestGSO, self).tearDown()
         if not self.vpp_dead:
@@ -804,6 +809,202 @@ class TestGSO(VppTestCase):
             sw_if_index=self.pg0.sw_if_index, enable_disable=0
         )
 
             sw_if_index=self.pg0.sw_if_index, enable_disable=0
         )
 
+    def test_gso_gre(self):
+        """GSO GRE test"""
+        #
+        # Send jumbo frame with gso enabled only on gre tunnel interface.
+        # create GRE tunnel on VPP pg0.
+        #
+
+        #
+        # create gre 4 tunnel
+        #
+        self.gre4.add_vpp_config()
+        self.gre4.admin_up()
+        self.gre4.config_ip4()
+
+        #
+        # Add a route that resolves the tunnel's destination
+        #
+        # Add IPv4 routes via tunnel interface
+        self.ip4_via_gre4_tunnel = VppIpRoute(
+            self,
+            "172.16.10.0",
+            24,
+            [
+                VppRoutePath(
+                    "0.0.0.0",
+                    self.gre4.sw_if_index,
+                    proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
+                )
+            ],
+        )
+        self.ip4_via_gre4_tunnel.add_vpp_config()
+
+        pgre4 = (
+            Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
+            / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags="DF")
+            / TCP(sport=1234, dport=1234)
+            / Raw(b"\xa5" * 65200)
+        )
+
+        # test when GSO segmentation is disabled, Packets are truncated
+        rxs = self.send_and_expect(self.pg2, 5 * [pgre4], self.pg0, 5)
+        for rx in rxs:
+            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
+            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
+            self.assertEqual(rx[IP].src, self.pg0.local_ip4)
+            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
+            self.assert_ip_checksum_valid(rx)
+            self.assertEqual(rx[IP].proto, 0x2F)  # GRE encap
+            self.assertEqual(rx[GRE].proto, 0x0800)  # IPv4
+            inner = rx[GRE].payload
+            self.assertNotEqual(rx[IP].len - 20 - 4, len(inner))
+            self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
+            self.assertEqual(inner[IP].dst, "172.16.10.3")
+            self.assert_ip_checksum_valid(inner)
+            payload_len = inner[IP].len - 20 - 20
+            self.assertEqual(payload_len, 65200)
+            # truncated packet to MTU size
+            self.assertNotEqual(payload_len, len(inner[Raw]))
+
+        # enable the GSO segmentation on GRE tunnel
+        self.vapi.feature_gso_enable_disable(
+            sw_if_index=self.gre4.sw_if_index, enable_disable=1
+        )
+
+        # test again, this time payload will be chuncked to GSO size (i.e. 1448)
+        rxs = self.send_and_expect(self.pg2, 5 * [pgre4], self.pg0, 225)
+        size = 0
+        for rx in rxs:
+            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
+            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
+            self.assertEqual(rx[IP].src, self.pg0.local_ip4)
+            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
+            self.assert_ip_checksum_valid(rx)
+            self.assertEqual(rx[IP].proto, 0x2F)  # GRE encap
+            self.assertEqual(rx[GRE].proto, 0x0800)  # IPv4
+            inner = rx[GRE].payload
+            self.assertEqual(rx[IP].len - 20 - 4, len(inner))
+            self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
+            self.assertEqual(inner[IP].dst, "172.16.10.3")
+            self.assert_ip_checksum_valid(inner)
+            self.assert_tcp_checksum_valid(inner)
+            payload_len = inner[IP].len - 20 - 20
+            self.assertEqual(payload_len, len(inner[Raw]))
+            size += payload_len
+        self.assertEqual(size, 65200 * 5)
+
+        # Disable the GSO segmentation on GRE tunnel
+        self.vapi.feature_gso_enable_disable(
+            sw_if_index=self.gre4.sw_if_index, enable_disable=0
+        )
+
+        # test again when GSO segmentation is disabled, Packets are truncated
+        rxs = self.send_and_expect(self.pg2, 5 * [pgre4], self.pg0, 5)
+        for rx in rxs:
+            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
+            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
+            self.assertEqual(rx[IP].src, self.pg0.local_ip4)
+            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
+            self.assert_ip_checksum_valid(rx)
+            self.assertEqual(rx[IP].proto, 0x2F)  # GRE encap
+            self.assertEqual(rx[GRE].proto, 0x0800)  # IPv4
+            inner = rx[GRE].payload
+            self.assertNotEqual(rx[IP].len - 20 - 4, len(inner))
+            self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
+            self.assertEqual(inner[IP].dst, "172.16.10.3")
+            self.assert_ip_checksum_valid(inner)
+            payload_len = inner[IP].len - 20 - 20
+            self.assertEqual(payload_len, 65200)
+            # truncated packet to MTU size
+            self.assertNotEqual(payload_len, len(inner[Raw]))
+
+        self.ip4_via_gre4_tunnel.remove_vpp_config()
+        self.gre4.remove_vpp_config()
+
+        self.gre6.add_vpp_config()
+        self.gre6.admin_up()
+        self.gre6.config_ip4()
+
+        #
+        # Add a route that resolves the tunnel's destination
+        # Add IPv6 routes via tunnel interface
+        #
+        self.vapi.feature_gso_enable_disable(
+            sw_if_index=self.gre6.sw_if_index, enable_disable=1
+        )
+        self.ip6_via_gre6_tunnel = VppIpRoute(
+            self,
+            "fd01:10::",
+            64,
+            [
+                VppRoutePath(
+                    "::",
+                    self.gre6.sw_if_index,
+                    proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
+                )
+            ],
+        )
+        self.ip6_via_gre6_tunnel.add_vpp_config()
+
+        #
+        # Create IPv6 packet
+        #
+        pgre6 = (
+            Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
+            / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3")
+            / TCP(sport=1234, dport=1234)
+            / Raw(b"\xa5" * 65200)
+        )
+
+        # test when GSO segmentation is enabled, payload will be segmented
+        # into GSO size (i.e. 1448)
+        rxs = self.send_and_expect(self.pg2, 5 * [pgre6], self.pg0, 225)
+        size = 0
+        for rx in rxs:
+            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
+            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
+            self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
+            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
+            self.assertEqual(ipv6nh[rx[IPv6].nh], "GRE")
+            self.assertEqual(rx[GRE].proto, 0x86DD)  # IPv6
+            inner = rx[GRE].payload
+            self.assertEqual(rx[IPv6].plen - 4, len(inner))
+            self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
+            self.assertEqual(inner[IPv6].dst, "fd01:10::3")
+            self.assert_tcp_checksum_valid(inner)
+            payload_len = inner[IPv6].plen - 20
+            self.assertEqual(payload_len, len(inner[Raw]))
+            size += payload_len
+        self.assertEqual(size, 65200 * 5)
+
+        # disable GSO segmentation
+        self.vapi.feature_gso_enable_disable(
+            sw_if_index=self.gre6.sw_if_index, enable_disable=0
+        )
+
+        # test again, this time packets will be truncated
+        rxs = self.send_and_expect(self.pg2, 5 * [pgre6], self.pg0, 5)
+        for rx in rxs:
+            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
+            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
+            self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
+            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
+            self.assertEqual(ipv6nh[rx[IPv6].nh], "GRE")
+            self.assertEqual(rx[GRE].proto, 0x86DD)  # IPv6
+            inner = rx[GRE].payload
+            self.assertNotEqual(rx[IPv6].plen - 4, len(inner))
+            self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
+            self.assertEqual(inner[IPv6].dst, "fd01:10::3")
+            payload_len = inner[IPv6].plen - 20
+            self.assertEqual(payload_len, 65200)
+            # packets are truncated to MTU size
+            self.assertNotEqual(payload_len, len(inner[Raw]))
+
+        self.ip6_via_gre6_tunnel.remove_vpp_config()
+        self.gre6.remove_vpp_config()
+
     def test_gso_ipsec(self):
         """GSO IPSEC test"""
         #
     def test_gso_ipsec(self):
         """GSO IPSEC test"""
         #