2 """GSO functional tests"""
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
13 from scapy.packet import Raw
14 from scapy.layers.inet6 import IPv6, Ether, IP, UDP, ICMPv6PacketTooBig
15 from scapy.layers.inet6 import ipv6nh, IPerror6
16 from scapy.layers.inet import TCP, ICMP
17 from scapy.layers.vxlan import VXLAN
18 from scapy.data import ETH_P_IP, ETH_P_IPV6, ETH_P_ARP
20 from framework import VppTestCase, VppTestRunner
21 from vpp_object import VppObject
22 from vpp_interface import VppInterface
23 from vpp_ip import DpoProto
24 from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
25 from vpp_vxlan_tunnel import VppVxlanTunnel
26 from socket import AF_INET, AF_INET6, inet_pton
27 from util import reassemble4
30 """ Test_gso is a subclass of VPPTestCase classes.
35 class TestGSO(VppTestCase):
38 def __init__(self, *args):
39 VppTestCase.__init__(self, *args)
43 super(TestGSO, self).setUpClass()
44 res = self.create_pg_interfaces(range(2))
45 res_gso = self.create_pg_interfaces(range(2, 4), 1, 1460)
46 self.create_pg_interfaces(range(4, 5), 1, 8940)
47 self.pg_interfaces.append(res[0])
48 self.pg_interfaces.append(res[1])
49 self.pg_interfaces.append(res_gso[0])
50 self.pg_interfaces.append(res_gso[1])
53 def tearDownClass(self):
54 super(TestGSO, self).tearDownClass()
57 super(TestGSO, self).setUp()
58 for i in self.pg_interfaces:
66 self.single_tunnel_bd = 10
67 self.vxlan = VppVxlanTunnel(self, src=self.pg0.local_ip4,
68 dst=self.pg0.remote_ip4,
69 vni=self.single_tunnel_bd)
70 self.vxlan.add_vpp_config()
72 self.vxlan2 = VppVxlanTunnel(self, src=self.pg0.local_ip6,
73 dst=self.pg0.remote_ip6,
74 vni=self.single_tunnel_bd)
75 self.vxlan2.add_vpp_config()
78 super(TestGSO, self).tearDown()
80 for i in self.pg_interfaces:
88 # Send jumbo frame with gso disabled and DF bit is set
90 p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
91 IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4,
93 TCP(sport=1234, dport=1234) /
96 rxs = self.send_and_expect(self.pg0, [p4], self.pg0)
99 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
100 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
101 self.assertEqual(rx[IP].src, self.pg0.local_ip4)
102 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
103 self.assertEqual(rx[ICMP].type, 3) # "dest-unreach"
104 self.assertEqual(rx[ICMP].code, 4) # "fragmentation-needed"
107 # Send jumbo frame with gso enabled and DF bit is set
108 # input and output interfaces support GSO
110 p41 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
111 IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4,
113 TCP(sport=1234, dport=1234) /
114 Raw(b'\xa5' * 65200))
116 rxs = self.send_and_expect(self.pg2, [p41], self.pg3)
119 self.assertEqual(rx[Ether].src, self.pg3.local_mac)
120 self.assertEqual(rx[Ether].dst, self.pg3.remote_mac)
121 self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
122 self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
123 self.assertEqual(rx[IP].len, 65240) # 65200 + 20 (IP) + 20 (TCP)
124 self.assertEqual(rx[TCP].sport, 1234)
125 self.assertEqual(rx[TCP].dport, 1234)
130 p61 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
131 IPv6(src=self.pg2.remote_ip6, dst=self.pg3.remote_ip6) /
132 TCP(sport=1234, dport=1234) /
133 Raw(b'\xa5' * 65200))
135 rxs = self.send_and_expect(self.pg2, [p61], self.pg3)
138 self.assertEqual(rx[Ether].src, self.pg3.local_mac)
139 self.assertEqual(rx[Ether].dst, self.pg3.remote_mac)
140 self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6)
141 self.assertEqual(rx[IPv6].dst, self.pg3.remote_ip6)
142 self.assertEqual(rx[IPv6].plen, 65220) # 65200 + 20 (TCP)
143 self.assertEqual(rx[TCP].sport, 1234)
144 self.assertEqual(rx[TCP].dport, 1234)
147 # Send jumbo frame with gso enabled only on input interface
148 # and DF bit is set. GSO packet will be chunked into gso_size
151 self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
152 p42 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
153 IP(src=self.pg2.remote_ip4, dst=self.pg0.remote_ip4,
155 TCP(sport=1234, dport=1234) /
156 Raw(b'\xa5' * 65200))
158 rxs = self.send_and_expect(self.pg2, [p42], self.pg0, 45)
161 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
162 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
163 self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
164 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
165 self.assertEqual(rx[TCP].sport, 1234)
166 self.assertEqual(rx[TCP].dport, 1234)
168 size = rxs[44][TCP].seq + rxs[44][IP].len - 20 - 20
169 self.assertEqual(size, 65200)
174 p62 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
175 IPv6(src=self.pg2.remote_ip6, dst=self.pg0.remote_ip6) /
176 TCP(sport=1234, dport=1234) /
177 Raw(b'\xa5' * 65200))
179 rxs = self.send_and_expect(self.pg2, [p62], self.pg0, 45)
182 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
183 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
184 self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6)
185 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
186 self.assertEqual(rx[TCP].sport, 1234)
187 self.assertEqual(rx[TCP].dport, 1234)
189 size = rxs[44][TCP].seq + rxs[44][IPv6].plen - 20
190 self.assertEqual(size, 65200)
193 # Send jumbo frame with gso enabled only on input interface
194 # and DF bit is unset. GSO packet will be fragmented.
196 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [576, 0, 0, 0])
197 self.vapi.feature_gso_enable_disable(self.pg1.sw_if_index)
199 p43 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
200 IP(src=self.pg2.remote_ip4, dst=self.pg1.remote_ip4) /
201 TCP(sport=1234, dport=1234) /
202 Raw(b'\xa5' * 65200))
204 rxs = self.send_and_expect(self.pg2, [p43], self.pg1, 119)
207 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
208 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
209 self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
210 self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
211 size += rx[IP].len - 20
212 size -= 20 # TCP header
213 self.assertEqual(size, 65200)
217 # Send jumbo frame with gso enabled only on input interface.
218 # ICMPv6 Packet Too Big will be sent back to sender.
220 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
221 p63 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
222 IPv6(src=self.pg2.remote_ip6, dst=self.pg1.remote_ip6) /
223 TCP(sport=1234, dport=1234) /
224 Raw(b'\xa5' * 65200))
226 rxs = self.send_and_expect(self.pg2, [p63], self.pg2, 1)
228 self.assertEqual(rx[Ether].src, self.pg2.local_mac)
229 self.assertEqual(rx[Ether].dst, self.pg2.remote_mac)
230 self.assertEqual(rx[IPv6].src, self.pg2.local_ip6)
231 self.assertEqual(rx[IPv6].dst, self.pg2.remote_ip6)
232 self.assertEqual(rx[IPv6].plen, 1240) # MTU - IPv6 header
233 self.assertEqual(ipv6nh[rx[IPv6].nh], "ICMPv6")
234 self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 1280)
235 self.assertEqual(rx[IPerror6].src, self.pg2.remote_ip6)
236 self.assertEqual(rx[IPerror6].dst, self.pg1.remote_ip6)
237 self.assertEqual(rx[IPerror6].plen - 20, 65200)
240 # Send jumbo frame with gso enabled only on input interface with 9K MTU
241 # and DF bit is unset. GSO packet will be fragmented. MSS is 8960. GSO
242 # size will be min(MSS, 2048 - 14 - 20) vlib_buffer_t size
244 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
245 self.vapi.sw_interface_set_mtu(self.pg4.sw_if_index, [9000, 0, 0, 0])
246 p44 = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
247 IP(src=self.pg4.remote_ip4, dst=self.pg1.remote_ip4) /
248 TCP(sport=1234, dport=1234) /
249 Raw(b'\xa5' * 65200))
251 self.pg1.enable_capture()
252 rxs = self.send_and_expect(self.pg4, [p44], self.pg1, 33)
255 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
256 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
257 self.assertEqual(rx[IP].src, self.pg4.remote_ip4)
258 self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
259 size = rxs[32][TCP].seq + rxs[32][IP].len - 20 - 20
260 self.assertEqual(size, 65200)
265 p64 = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
266 IPv6(src=self.pg4.remote_ip6, dst=self.pg1.remote_ip6) /
267 TCP(sport=1234, dport=1234) /
268 Raw(b'\xa5' * 65200))
270 self.pg1.enable_capture()
271 rxs = self.send_and_expect(self.pg4, [p64], self.pg1, 34)
274 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
275 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
276 self.assertEqual(rx[IPv6].src, self.pg4.remote_ip6)
277 self.assertEqual(rx[IPv6].dst, self.pg1.remote_ip6)
278 size = rxs[33][TCP].seq + rxs[33][IPv6].plen - 20
279 self.assertEqual(size, 65200)
281 def test_gso_vxlan(self):
282 """ GSO VXLAN test """
283 self.logger.info(self.vapi.cli("sh int addr"))
285 # Send jumbo frame with gso enabled only on input interface and
286 # create VXLAN VTEP on VPP pg0, and put vxlan_tunnel0 and pg2
289 self.vapi.sw_interface_set_l2_bridge(
290 rx_sw_if_index=self.vxlan.sw_if_index, bd_id=self.single_tunnel_bd)
291 self.vapi.sw_interface_set_l2_bridge(
292 rx_sw_if_index=self.pg2.sw_if_index, bd_id=self.single_tunnel_bd)
293 self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
298 p45 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
299 IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags='DF') /
300 TCP(sport=1234, dport=1234) /
301 Raw(b'\xa5' * 65200))
303 self.pg0.enable_capture()
304 rxs = self.send_and_expect(self.pg2, [p45], self.pg0, 45)
307 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
308 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
309 self.assertEqual(rx[IP].src, self.pg0.local_ip4)
310 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
311 self.assertEqual(rx[VXLAN].vni, 10)
312 inner = rx[VXLAN].payload
313 self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
314 self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
315 self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
316 self.assertEqual(inner[IP].dst, "172.16.3.3")
317 size += inner[IP].len - 20 - 20
318 self.assertEqual(size, 65200)
323 p65 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
324 IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3") /
325 TCP(sport=1234, dport=1234) /
326 Raw(b'\xa5' * 65200))
328 self.pg0.enable_capture()
329 rxs = self.send_and_expect(self.pg2, [p65], self.pg0, 45)
332 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
333 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
334 self.assertEqual(rx[IP].src, self.pg0.local_ip4)
335 self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
336 self.assertEqual(rx[VXLAN].vni, 10)
337 inner = rx[VXLAN].payload
338 self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
339 self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
340 self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
341 self.assertEqual(inner[IPv6].dst, "fd01:3::3")
342 size += inner[IPv6].plen - 20
343 self.assertEqual(size, 65200)
348 self.vxlan.remove_vpp_config()
353 self.vapi.sw_interface_set_l2_bridge(
354 rx_sw_if_index=self.vxlan2.sw_if_index,
355 bd_id=self.single_tunnel_bd)
360 p46 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
361 IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags='DF') /
362 TCP(sport=1234, dport=1234) /
363 Raw(b'\xa5' * 65200))
365 self.pg0.enable_capture()
366 rxs = self.send_and_expect(self.pg2, [p46], self.pg0, 45)
369 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
370 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
371 self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
372 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
373 self.assertEqual(rx[VXLAN].vni, 10)
374 inner = rx[VXLAN].payload
375 self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
376 self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
377 self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
378 self.assertEqual(inner[IP].dst, "172.16.3.3")
379 size += inner[IP].len - 20 - 20
380 self.assertEqual(size, 65200)
385 p66 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
386 IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3") /
387 TCP(sport=1234, dport=1234) /
388 Raw(b'\xa5' * 65200))
390 self.pg0.enable_capture()
391 rxs = self.send_and_expect(self.pg2, [p66], self.pg0, 45)
394 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
395 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
396 self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
397 self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
398 self.assertEqual(rx[VXLAN].vni, 10)
399 inner = rx[VXLAN].payload
400 self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
401 self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
402 self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
403 self.assertEqual(inner[IPv6].dst, "fd01:3::3")
404 size += inner[IPv6].plen - 20
405 self.assertEqual(size, 65200)
407 if __name__ == '__main__':
408 unittest.main(testRunner=VppTestRunner)