gso: Add gso feature arc
[vpp.git] / test / test_gso.py
1 #!/usr/bin/env python
2 """GSO functional tests"""
3
4 #
5 # Add tests for:
6 # - GSO
7 # - Verify that sending Jumbo frame without GSO enabled correctly
8 # - Verify that sending Jumbo frame with GSO enabled correctly
9 # - Verify that sending Jumbo frame with GSO enabled only on ingress interface
10 #
11 import unittest
12
13 from scapy.packet import Raw
14 from scapy.layers.inet6 import IPv6, Ether, IP, UDP, ICMPv6PacketTooBig
15 from scapy.layers.inet import TCP, ICMP
16 from scapy.layers.vxlan import VXLAN
17 from scapy.data import ETH_P_IP, ETH_P_IPV6, ETH_P_ARP
18
19 from framework import VppTestCase, VppTestRunner
20 from vpp_object import VppObject
21 from vpp_interface import VppInterface
22 from vpp_ip import DpoProto
23 from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
24 from socket import AF_INET, AF_INET6, inet_pton
25 from util import reassemble4
26
27
28 """ Test_gso is a subclass of VPPTestCase classes.
29     GSO tests.
30 """
31
32
33 class TestGSO(VppTestCase):
34     """ GSO Test Case """
35
36     def __init__(self, *args):
37         VppTestCase.__init__(self, *args)
38
39     @classmethod
40     def setUpClass(self):
41         super(TestGSO, self).setUpClass()
42
43     @classmethod
44     def tearDownClass(self):
45         super(TestGSO, self).tearDownClass()
46
47     def setUp(self):
48         super(TestGSO, self).setUp()
49
50     def tearDown(self):
51         super(TestGSO, self).tearDown()
52         if not self.vpp_dead:
53             for i in self.pg_interfaces:
54                 i.unconfig_ip4()
55                 i.unconfig_ip6()
56                 i.admin_down()
57
58     def test_gso(self):
59         """ GSO test """
60         #
61         # Send jumbo frame with gso disabled and DF bit is set
62         #
63         self.create_pg_interfaces(range(2))
64         for i in self.pg_interfaces:
65             i.admin_up()
66             i.config_ip4()
67             i.config_ip6()
68             i.disable_ipv6_ra()
69             i.resolve_arp()
70             i.resolve_ndp()
71
72         p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
73               IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4,
74                  flags='DF') /
75               TCP(sport=1234, dport=1234) /
76               Raw('\xa5' * 65200))
77
78         rxs = self.send_and_expect(self.pg0, [p4], self.pg0)
79
80         for rx in rxs:
81             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
82             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
83             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
84             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
85             self.assertEqual(rx[ICMP].type, 3)  # "dest-unreach"
86             self.assertEqual(rx[ICMP].code, 4)  # "fragmentation-needed"
87
88         #
89         # Send jumbo frame with gso enabled and DF bit is set
90         # input and output interfaces support GSO
91         #
92         self.create_pg_interfaces(range(2, 4), 1, 1460)
93         for i in self.pg_interfaces:
94             i.admin_up()
95             i.config_ip4()
96             i.config_ip6()
97             i.disable_ipv6_ra()
98             i.resolve_arp()
99             i.resolve_ndp()
100
101         p41 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
102                IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4,
103                   flags='DF') /
104                TCP(sport=1234, dport=1234) /
105                Raw('\xa5' * 65200))
106
107         rxs = self.send_and_expect(self.pg2, [p41], self.pg3)
108
109         for rx in rxs:
110             self.assertEqual(rx[Ether].src, self.pg3.local_mac)
111             self.assertEqual(rx[Ether].dst, self.pg3.remote_mac)
112             self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
113             self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
114             self.assertEqual(rx[IP].len, 65240)  # 65200 + 20 (IP) + 20 (TCP)
115             self.assertEqual(rx[TCP].sport, 1234)
116             self.assertEqual(rx[TCP].dport, 1234)
117
118         #
119         # Send jumbo frame with gso enabled only on input interface
120         # and DF bit is set. GSO packet will be chunked into gso_size
121         # data payload
122         #
123         self.create_pg_interfaces(range(4, 5))
124         for i in self.pg_interfaces:
125             i.admin_up()
126             i.config_ip4()
127             i.config_ip6()
128             i.disable_ipv6_ra()
129             i.resolve_arp()
130             i.resolve_ndp()
131
132         self.vapi.feature_gso_enable_disable(self.pg4.sw_if_index)
133         p42 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
134                IP(src=self.pg2.remote_ip4, dst=self.pg4.remote_ip4,
135                   flags='DF') /
136                TCP(sport=1234, dport=1234) /
137                Raw('\xa5' * 65200))
138
139         rxs = self.send_and_expect(self.pg2, [p42], self.pg4, 45)
140         size = 0
141         for rx in rxs:
142             self.assertEqual(rx[Ether].src, self.pg4.local_mac)
143             self.assertEqual(rx[Ether].dst, self.pg4.remote_mac)
144             self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
145             self.assertEqual(rx[IP].dst, self.pg4.remote_ip4)
146             self.assertEqual(rx[TCP].sport, 1234)
147             self.assertEqual(rx[TCP].dport, 1234)
148
149         size = rxs[44][TCP].seq + rxs[44][IP].len - 20 - 20
150         self.assertEqual(size, 65200)
151
152         #
153         # Send jumbo frame with gso enabled only on input interface
154         # and DF bit is unset. GSO packet will be fragmented.
155         #
156         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [576, 0, 0, 0])
157
158         p43 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
159                IP(src=self.pg2.remote_ip4, dst=self.pg1.remote_ip4) /
160                TCP(sport=1234, dport=1234) /
161                Raw('\xa5' * 65200))
162
163         rxs = self.send_and_expect(self.pg2, [p43], self.pg1, 119)
164         size = 0
165         for rx in rxs:
166             self.assertEqual(rx[Ether].src, self.pg1.local_mac)
167             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
168             self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
169             self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
170             size += rx[IP].len - 20
171         size -= 20  # TCP header
172         self.assertEqual(size, 65200)
173
174         #
175         # Send jumbo frame with gso enabled only on input interface with 9K MTU
176         # and DF bit is unset. GSO packet will be fragmented. GSO size will be
177         # 8960.
178         #
179         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
180         self.create_pg_interfaces(range(5, 6), 1, 8960)
181         for i in self.pg_interfaces:
182             i.admin_up()
183             i.config_ip4()
184             i.config_ip6()
185             i.disable_ipv6_ra()
186             i.resolve_arp()
187             i.resolve_ndp()
188
189         self.vapi.sw_interface_set_mtu(self.pg5.sw_if_index, [9000, 0, 0, 0])
190         self.vapi.feature_gso_enable_disable(self.pg1.sw_if_index)
191         p44 = (Ether(src=self.pg5.remote_mac, dst=self.pg5.local_mac) /
192                IP(src=self.pg5.remote_ip4, dst=self.pg1.remote_ip4) /
193                TCP(sport=1234, dport=1234) /
194                Raw('\xa5' * 65200))
195
196         self.pg1.enable_capture()
197         rxs = self.send_and_expect(self.pg5, [p44], self.pg1, 33)
198         size = 0
199         for rx in rxs:
200             self.assertEqual(rx[Ether].src, self.pg1.local_mac)
201             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
202             self.assertEqual(rx[IP].src, self.pg5.remote_ip4)
203             self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
204         size = rxs[32][TCP].seq + rxs[32][IP].len - 20 - 20
205         self.assertEqual(size, 65200)
206
207 if __name__ == '__main__':
208     unittest.main(testRunner=VppTestRunner)