ip: Replace Sematics for Interface IP addresses
[vpp.git] / test / test_gso.py
1 #!/usr/bin/env python3
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.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
19
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
28
29
30 """ Test_gso is a subclass of VPPTestCase classes.
31     GSO tests.
32 """
33
34
35 class TestGSO(VppTestCase):
36     """ GSO Test Case """
37
38     def __init__(self, *args):
39         VppTestCase.__init__(self, *args)
40
41     @classmethod
42     def setUpClass(self):
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])
51
52     @classmethod
53     def tearDownClass(self):
54         super(TestGSO, self).tearDownClass()
55
56     def setUp(self):
57         super(TestGSO, self).setUp()
58         for i in self.pg_interfaces:
59             i.admin_up()
60             i.config_ip4()
61             i.config_ip6()
62             i.disable_ipv6_ra()
63             i.resolve_arp()
64             i.resolve_ndp()
65
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()
71
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()
76
77     def tearDown(self):
78         super(TestGSO, self).tearDown()
79         if not self.vpp_dead:
80             for i in self.pg_interfaces:
81                 i.unconfig_ip4()
82                 i.unconfig_ip6()
83                 i.admin_down()
84
85     def test_gso(self):
86         """ GSO test """
87         #
88         # Send jumbo frame with gso disabled and DF bit is set
89         #
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,
92                  flags='DF') /
93               TCP(sport=1234, dport=1234) /
94               Raw(b'\xa5' * 65200))
95
96         rxs = self.send_and_expect(self.pg0, [p4], self.pg0)
97
98         for rx in rxs:
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"
105
106         #
107         # Send jumbo frame with gso enabled and DF bit is set
108         # input and output interfaces support GSO
109         #
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,
112                   flags='DF') /
113                TCP(sport=1234, dport=1234) /
114                Raw(b'\xa5' * 65200))
115
116         rxs = self.send_and_expect(self.pg2, [p41], self.pg3)
117
118         for rx in rxs:
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)
126
127         #
128         # ipv6
129         #
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))
134
135         rxs = self.send_and_expect(self.pg2, [p61], self.pg3)
136
137         for rx in rxs:
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)
145
146         #
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
149         # data payload
150         #
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,
154                   flags='DF') /
155                TCP(sport=1234, dport=1234) /
156                Raw(b'\xa5' * 65200))
157
158         rxs = self.send_and_expect(self.pg2, [p42], self.pg0, 45)
159         size = 0
160         for rx in rxs:
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)
167
168         size = rxs[44][TCP].seq + rxs[44][IP].len - 20 - 20
169         self.assertEqual(size, 65200)
170
171         #
172         # ipv6
173         #
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))
178
179         rxs = self.send_and_expect(self.pg2, [p62], self.pg0, 45)
180         size = 0
181         for rx in rxs:
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)
188
189         size = rxs[44][TCP].seq + rxs[44][IPv6].plen - 20
190         self.assertEqual(size, 65200)
191
192         #
193         # Send jumbo frame with gso enabled only on input interface
194         # and DF bit is unset. GSO packet will be fragmented.
195         #
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)
198
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))
203
204         rxs = self.send_and_expect(self.pg2, [p43], self.pg1, 119)
205         size = 0
206         for rx in rxs:
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)
214
215         #
216         # IPv6
217         # Send jumbo frame with gso enabled only on input interface.
218         # ICMPv6 Packet Too Big will be sent back to sender.
219         #
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))
225
226         rxs = self.send_and_expect(self.pg2, [p63], self.pg2, 1)
227         for rx in rxs:
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)
238
239         #
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
243         #
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))
250
251         self.pg1.enable_capture()
252         rxs = self.send_and_expect(self.pg4, [p44], self.pg1, 33)
253         size = 0
254         for rx in rxs:
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)
261
262         #
263         # IPv6
264         #
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))
269
270         self.pg1.enable_capture()
271         rxs = self.send_and_expect(self.pg4, [p64], self.pg1, 34)
272         size = 0
273         for rx in rxs:
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)
280
281     def test_gso_vxlan(self):
282         """ GSO VXLAN test """
283         self.logger.info(self.vapi.cli("sh int addr"))
284         #
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
287         # into BD.
288         #
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)
294
295         #
296         # IPv4/IPv4 - VXLAN
297         #
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))
302
303         self.pg0.enable_capture()
304         rxs = self.send_and_expect(self.pg2, [p45], self.pg0, 45)
305         size = 0
306         for rx in rxs:
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)
319
320         #
321         # IPv4/IPv6 - VXLAN
322         #
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))
327
328         self.pg0.enable_capture()
329         rxs = self.send_and_expect(self.pg2, [p65], self.pg0, 45)
330         size = 0
331         for rx in rxs:
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)
344
345         #
346         # disable ipv4/vxlan
347         #
348         self.vxlan.remove_vpp_config()
349
350         #
351         # enable ipv6/vxlan
352         #
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)
356
357         #
358         # IPv6/IPv4 - VXLAN
359         #
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))
364
365         self.pg0.enable_capture()
366         rxs = self.send_and_expect(self.pg2, [p46], self.pg0, 45)
367         size = 0
368         for rx in rxs:
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)
381
382         #
383         # IPv6/IPv6 - VXLAN
384         #
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))
389
390         self.pg0.enable_capture()
391         rxs = self.send_and_expect(self.pg2, [p66], self.pg0, 45)
392         size = 0
393         for rx in rxs:
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)
406
407 if __name__ == '__main__':
408     unittest.main(testRunner=VppTestRunner)