From 22e9cfd760be613f33a4135e9247729b64619cc6 Mon Sep 17 00:00:00 2001 From: Mohsin Kazmi Date: Tue, 23 Jul 2019 11:54:48 +0200 Subject: pg: add GSO support Type: feature Change-Id: I72676495a85fbecc946aa266a75234cce70c3a5e Signed-off-by: Mohsin Kazmi --- test/framework.py | 4 +- test/test_gso.py | 175 +++++++++++++++++++++++++++++++++++++++++++++++ test/vpp_pg_interface.py | 18 ++++- 3 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 test/test_gso.py (limited to 'test') diff --git a/test/framework.py b/test/framework.py index 59c451d475c..e4d0f9d13ab 100644 --- a/test/framework.py +++ b/test/framework.py @@ -762,7 +762,7 @@ class VppTestCase(unittest.TestCase): cls._captures = [] @classmethod - def create_pg_interfaces(cls, interfaces): + def create_pg_interfaces(cls, interfaces, gso=0, gso_size=0): """ Create packet-generator interfaces. @@ -772,7 +772,7 @@ class VppTestCase(unittest.TestCase): """ result = [] for i in interfaces: - intf = VppPGInterface(cls, i) + intf = VppPGInterface(cls, i, gso, gso_size) setattr(cls, intf.name, intf) result.append(intf) cls.pg_interfaces = result diff --git a/test/test_gso.py b/test/test_gso.py new file mode 100644 index 00000000000..43d9e92380d --- /dev/null +++ b/test/test_gso.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +"""GSO functional tests""" + +# +# Add tests for: +# - GSO +# - Verify that sending Jumbo frame without GSO enabled correctly +# - Verify that sending Jumbo frame with GSO enabled correctly +# - Verify that sending Jumbo frame with GSO enabled only on ingress interface +# +import unittest + +from scapy.packet import Raw +from scapy.layers.inet6 import IPv6, Ether, IP, UDP, ICMPv6PacketTooBig +from scapy.layers.inet import TCP, ICMP +from scapy.layers.vxlan import VXLAN +from scapy.data import ETH_P_IP, ETH_P_IPV6, ETH_P_ARP + +from framework import VppTestCase, VppTestRunner +from vpp_object import VppObject +from vpp_interface import VppInterface +from vpp_ip import DpoProto +from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto +from socket import AF_INET, AF_INET6, inet_pton +from util import reassemble4 + + +""" Test_gso is a subclass of VPPTestCase classes. + GSO tests. +""" + + +class TestGSO(VppTestCase): + """ GSO Test Case """ + + def __init__(self, *args): + VppTestCase.__init__(self, *args) + + @classmethod + def setUpClass(self): + super(TestGSO, self).setUpClass() + + @classmethod + def tearDownClass(self): + super(TestGSO, self).tearDownClass() + + def setUp(self): + super(TestGSO, self).setUp() + + def tearDown(self): + super(TestGSO, self).tearDown() + if not self.vpp_dead: + for i in self.pg_interfaces: + i.unconfig_ip4() + i.unconfig_ip6() + i.admin_down() + + def test_gso(self): + """ GSO test """ + # + # Send jumbo frame with gso disabled and DF bit is set + # + self.create_pg_interfaces(range(2)) + for i in self.pg_interfaces: + i.admin_up() + i.config_ip4() + i.config_ip6() + i.disable_ipv6_ra() + i.resolve_arp() + i.resolve_ndp() + + p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, + flags='DF') / + TCP(sport=1234, dport=1234) / + Raw('\xa5' * 65200)) + + rxs = self.send_and_expect(self.pg0, [p4], self.pg0) + + 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.assertEqual(rx[ICMP].type, 3) # "dest-unreach" + self.assertEqual(rx[ICMP].code, 4) # "fragmentation-needed" + + # + # Send jumbo frame with gso enabled and DF bit is set + # input and output interfaces support GSO + # + self.create_pg_interfaces(range(2, 4), 1, 1460) + for i in self.pg_interfaces: + i.admin_up() + i.config_ip4() + i.config_ip6() + i.disable_ipv6_ra() + i.resolve_arp() + i.resolve_ndp() + + p41 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / + IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4, + flags='DF') / + TCP(sport=1234, dport=1234) / + Raw('\xa5' * 65200)) + + rxs = self.send_and_expect(self.pg2, [p41], self.pg3) + + for rx in rxs: + self.assertEqual(rx[Ether].src, self.pg3.local_mac) + self.assertEqual(rx[Ether].dst, self.pg3.remote_mac) + self.assertEqual(rx[IP].src, self.pg2.remote_ip4) + self.assertEqual(rx[IP].dst, self.pg3.remote_ip4) + self.assertEqual(rx[IP].len, 65240) # 65200 + 20 (IP) + 20 (TCP) + self.assertEqual(rx[TCP].sport, 1234) + self.assertEqual(rx[TCP].dport, 1234) + + # + # Send jumbo frame with gso enabled only on input interface + # and DF bit is set. GSO packet will be chunked into gso_size + # data payload + # + self.create_pg_interfaces(range(4, 5)) + for i in self.pg_interfaces: + i.admin_up() + i.config_ip4() + i.config_ip6() + i.disable_ipv6_ra() + i.resolve_arp() + i.resolve_ndp() + + p42 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / + IP(src=self.pg2.remote_ip4, dst=self.pg4.remote_ip4, + flags='DF') / + TCP(sport=1234, dport=1234) / + Raw('\xa5' * 65200)) + + rxs = self.send_and_expect(self.pg2, [p42], self.pg4, 45) + size = 0 + for rx in rxs: + self.assertEqual(rx[Ether].src, self.pg4.local_mac) + self.assertEqual(rx[Ether].dst, self.pg4.remote_mac) + self.assertEqual(rx[IP].src, self.pg2.remote_ip4) + self.assertEqual(rx[IP].dst, self.pg4.remote_ip4) + self.assertEqual(rx[TCP].sport, 1234) + self.assertEqual(rx[TCP].dport, 1234) + + size = rxs[44][TCP].seq + rxs[44][IP].len - 20 - 20 + self.assertEqual(size, 65200) + + # + # Send jumbo frame with gso enabled only on input interface + # and DF bit is unset. GSO packet will be fragmented. + # + self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [576, 0, 0, 0]) + + p43 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / + IP(src=self.pg2.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=1234, dport=1234) / + Raw('\xa5' * 65200)) + + rxs = self.send_and_expect(self.pg2, [p43], self.pg1, 119) + size = 0 + for rx in rxs: + rx.show() + self.assertEqual(rx[Ether].src, self.pg1.local_mac) + self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) + self.assertEqual(rx[IP].src, self.pg2.remote_ip4) + self.assertEqual(rx[IP].dst, self.pg1.remote_ip4) + size += rx[IP].len - 20 + size -= 20 # TCP header + self.assertEqual(size, 65200) + +if __name__ == '__main__': + unittest.main(testRunner=VppTestRunner) diff --git a/test/vpp_pg_interface.py b/test/vpp_pg_interface.py index bd4ddaff58a..e6dae66feec 100755 --- a/test/vpp_pg_interface.py +++ b/test/vpp_pg_interface.py @@ -45,6 +45,18 @@ class VppPGInterface(VppInterface): """packet-generator interface index assigned by VPP""" return self._pg_index + @property + def gso_enabled(self): + """gso enabled on packet-generator interface""" + if self._gso_enabled == 0: + return "gso-disabled" + return "gso-enabled" + + @property + def gso_size(self): + """gso size on packet-generator interface""" + return self._gso_size + @property def out_path(self): """pcap file path - captured packets""" @@ -86,17 +98,19 @@ class VppPGInterface(VppInterface): self._out_history_counter += 1 return v - def __init__(self, test, pg_index): + def __init__(self, test, pg_index, gso, gso_size): """ Create VPP packet-generator interface """ super(VppPGInterface, self).__init__(test) - r = test.vapi.pg_create_interface(pg_index) + r = test.vapi.pg_create_interface(pg_index, gso, gso_size) self.set_sw_if_index(r.sw_if_index) self._in_history_counter = 0 self._out_history_counter = 0 self._out_assert_counter = 0 self._pg_index = pg_index + self._gso_enabled = gso + self._gso_size = gso_size self._out_file = "pg%u_out.pcap" % self.pg_index self._out_path = self.test.tempdir + "/" + self._out_file self._in_file = "pg%u_in.pcap" % self.pg_index -- cgit 1.2.3-korg