2c8250e9d9dbc20fcb50cd2f153ab51685c3e7e2
[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, 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.layers.ipsec import ESP
19
20 from vpp_papi import VppEnum
21 from framework import VppTestCase
22 from asfframework import VppTestRunner
23 from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
24 from vpp_ipip_tun_interface import VppIpIpTunInterface
25 from vpp_vxlan_tunnel import VppVxlanTunnel
26
27 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect
28 from template_ipsec import (
29     IPsecIPv4Params,
30     IPsecIPv6Params,
31     config_tun_params,
32 )
33
34 """ Test_gso is a subclass of VPPTestCase classes.
35     GSO tests.
36 """
37
38
39 class TestGSO(VppTestCase):
40     """GSO Test Case"""
41
42     def __init__(self, *args):
43         VppTestCase.__init__(self, *args)
44
45     @classmethod
46     def setUpClass(self):
47         super(TestGSO, self).setUpClass()
48         res = self.create_pg_interfaces(range(2))
49         res_gso = self.create_pg_interfaces(range(2, 4), 1, 1460)
50         self.create_pg_interfaces(range(4, 5), 1, 8940)
51         self.pg_interfaces.append(res[0])
52         self.pg_interfaces.append(res[1])
53         self.pg_interfaces.append(res_gso[0])
54         self.pg_interfaces.append(res_gso[1])
55
56     @classmethod
57     def tearDownClass(self):
58         super(TestGSO, self).tearDownClass()
59
60     def setUp(self):
61         super(TestGSO, self).setUp()
62         for i in self.pg_interfaces:
63             i.admin_up()
64             i.config_ip4()
65             i.config_ip6()
66             i.disable_ipv6_ra()
67             i.resolve_arp()
68             i.resolve_ndp()
69
70         self.single_tunnel_bd = 10
71         self.vxlan = VppVxlanTunnel(
72             self,
73             src=self.pg0.local_ip4,
74             dst=self.pg0.remote_ip4,
75             vni=self.single_tunnel_bd,
76         )
77
78         self.vxlan2 = VppVxlanTunnel(
79             self,
80             src=self.pg0.local_ip6,
81             dst=self.pg0.remote_ip6,
82             vni=self.single_tunnel_bd,
83         )
84
85         self.ipip4 = VppIpIpTunInterface(
86             self, self.pg0, self.pg0.local_ip4, self.pg0.remote_ip4
87         )
88         self.ipip6 = VppIpIpTunInterface(
89             self, self.pg0, self.pg0.local_ip6, self.pg0.remote_ip6
90         )
91
92     def tearDown(self):
93         super(TestGSO, self).tearDown()
94         if not self.vpp_dead:
95             for i in self.pg_interfaces:
96                 i.unconfig_ip4()
97                 i.unconfig_ip6()
98                 i.admin_down()
99
100     def test_gso(self):
101         """GSO test"""
102         #
103         # Send jumbo frame with gso disabled and DF bit is set
104         #
105         p4 = (
106             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
107             / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, flags="DF")
108             / TCP(sport=1234, dport=1234)
109             / Raw(b"\xa5" * 65200)
110         )
111
112         rxs = self.send_and_expect(self.pg0, [p4], self.pg0)
113
114         for rx in rxs:
115             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
116             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
117             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
118             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
119             self.assertEqual(rx[ICMP].type, 3)  # "dest-unreach"
120             self.assertEqual(rx[ICMP].code, 4)  # "fragmentation-needed"
121
122         #
123         # Send checksum offload frames
124         #
125         p40 = (
126             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
127             / IP(src=self.pg2.remote_ip4, dst=self.pg0.remote_ip4, flags="DF")
128             / TCP(sport=1234, dport=1234)
129             / Raw(b"\xa5" * 1460)
130         )
131
132         rxs = self.send_and_expect(self.pg2, 100 * [p40], self.pg0)
133
134         for rx in rxs:
135             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
136             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
137             self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
138             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
139             payload_len = rx[IP].len - 20 - 20
140             self.assert_ip_checksum_valid(rx)
141             self.assert_tcp_checksum_valid(rx)
142             self.assertEqual(payload_len, len(rx[Raw]))
143
144         p60 = (
145             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
146             / IPv6(src=self.pg2.remote_ip6, dst=self.pg0.remote_ip6)
147             / TCP(sport=1234, dport=1234)
148             / Raw(b"\xa5" * 1440)
149         )
150
151         rxs = self.send_and_expect(self.pg2, 100 * [p60], self.pg0)
152
153         for rx in rxs:
154             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
155             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
156             self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6)
157             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
158             payload_len = rx[IPv6].plen - 20
159             self.assert_tcp_checksum_valid(rx)
160             self.assertEqual(payload_len, len(rx[Raw]))
161
162         #
163         # Send jumbo frame with gso enabled and DF bit is set
164         # input and output interfaces support GSO
165         #
166         self.vapi.feature_gso_enable_disable(
167             sw_if_index=self.pg3.sw_if_index, enable_disable=1
168         )
169         p41 = (
170             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
171             / IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4, flags="DF")
172             / TCP(sport=1234, dport=1234)
173             / Raw(b"\xa5" * 65200)
174         )
175
176         rxs = self.send_and_expect(self.pg2, 100 * [p41], self.pg3, 100)
177
178         for rx in rxs:
179             self.assertEqual(rx[Ether].src, self.pg3.local_mac)
180             self.assertEqual(rx[Ether].dst, self.pg3.remote_mac)
181             self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
182             self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
183             self.assertEqual(rx[IP].len, 65240)  # 65200 + 20 (IP) + 20 (TCP)
184             self.assertEqual(rx[TCP].sport, 1234)
185             self.assertEqual(rx[TCP].dport, 1234)
186
187         #
188         # ipv6
189         #
190         p61 = (
191             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
192             / IPv6(src=self.pg2.remote_ip6, dst=self.pg3.remote_ip6)
193             / TCP(sport=1234, dport=1234)
194             / Raw(b"\xa5" * 65200)
195         )
196
197         rxs = self.send_and_expect(self.pg2, 100 * [p61], self.pg3, 100)
198
199         for rx in rxs:
200             self.assertEqual(rx[Ether].src, self.pg3.local_mac)
201             self.assertEqual(rx[Ether].dst, self.pg3.remote_mac)
202             self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6)
203             self.assertEqual(rx[IPv6].dst, self.pg3.remote_ip6)
204             self.assertEqual(rx[IPv6].plen, 65220)  # 65200 + 20 (TCP)
205             self.assertEqual(rx[TCP].sport, 1234)
206             self.assertEqual(rx[TCP].dport, 1234)
207
208         #
209         # Send jumbo frame with gso enabled only on input interface
210         # and DF bit is set. GSO packet will be chunked into gso_size
211         # data payload
212         #
213         self.vapi.feature_gso_enable_disable(
214             sw_if_index=self.pg0.sw_if_index, enable_disable=1
215         )
216         p42 = (
217             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
218             / IP(src=self.pg2.remote_ip4, dst=self.pg0.remote_ip4, flags="DF")
219             / TCP(sport=1234, dport=1234)
220             / Raw(b"\xa5" * 65200)
221         )
222
223         rxs = self.send_and_expect(self.pg2, 5 * [p42], self.pg0, 225)
224         size = 0
225         for rx in rxs:
226             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
227             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
228             self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
229             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
230             payload_len = rx[IP].len - 20 - 20  # len - 20 (IP4) - 20 (TCP)
231             self.assert_ip_checksum_valid(rx)
232             self.assert_tcp_checksum_valid(rx)
233             self.assertEqual(rx[TCP].sport, 1234)
234             self.assertEqual(rx[TCP].dport, 1234)
235             self.assertEqual(payload_len, len(rx[Raw]))
236             size += payload_len
237         self.assertEqual(size, 65200 * 5)
238
239         #
240         # ipv6
241         #
242         p62 = (
243             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
244             / IPv6(src=self.pg2.remote_ip6, dst=self.pg0.remote_ip6)
245             / TCP(sport=1234, dport=1234)
246             / Raw(b"\xa5" * 65200)
247         )
248
249         rxs = self.send_and_expect(self.pg2, 5 * [p62], self.pg0, 225)
250         size = 0
251         for rx in rxs:
252             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
253             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
254             self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6)
255             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
256             payload_len = rx[IPv6].plen - 20
257             self.assert_tcp_checksum_valid(rx)
258             self.assertEqual(rx[TCP].sport, 1234)
259             self.assertEqual(rx[TCP].dport, 1234)
260             self.assertEqual(payload_len, len(rx[Raw]))
261             size += payload_len
262         self.assertEqual(size, 65200 * 5)
263
264         #
265         # Send jumbo frame with gso enabled only on input interface
266         # and DF bit is unset. GSO packet will be fragmented.
267         #
268         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [576, 0, 0, 0])
269         self.vapi.feature_gso_enable_disable(
270             sw_if_index=self.pg1.sw_if_index, enable_disable=1
271         )
272
273         p43 = (
274             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
275             / IP(src=self.pg2.remote_ip4, dst=self.pg1.remote_ip4)
276             / TCP(sport=1234, dport=1234)
277             / Raw(b"\xa5" * 65200)
278         )
279
280         rxs = self.send_and_expect(self.pg2, 5 * [p43], self.pg1, 5 * 119)
281         size = 0
282         for rx in rxs:
283             self.assertEqual(rx[Ether].src, self.pg1.local_mac)
284             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
285             self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
286             self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
287             self.assert_ip_checksum_valid(rx)
288             size += rx[IP].len - 20
289         size -= 20 * 5  # TCP header
290         self.assertEqual(size, 65200 * 5)
291
292         #
293         # IPv6
294         # Send jumbo frame with gso enabled only on input interface.
295         # ICMPv6 Packet Too Big will be sent back to sender.
296         #
297         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
298         p63 = (
299             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
300             / IPv6(src=self.pg2.remote_ip6, dst=self.pg1.remote_ip6)
301             / TCP(sport=1234, dport=1234)
302             / Raw(b"\xa5" * 65200)
303         )
304
305         rxs = self.send_and_expect_some(self.pg2, 5 * [p63], self.pg2, 5)
306         for rx in rxs:
307             self.assertEqual(rx[Ether].src, self.pg2.local_mac)
308             self.assertEqual(rx[Ether].dst, self.pg2.remote_mac)
309             self.assertEqual(rx[IPv6].src, self.pg2.local_ip6)
310             self.assertEqual(rx[IPv6].dst, self.pg2.remote_ip6)
311             self.assertEqual(rx[IPv6].plen, 1240)  # MTU - IPv6 header
312             self.assertEqual(ipv6nh[rx[IPv6].nh], "ICMPv6")
313             self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 1280)
314             self.assertEqual(rx[IPerror6].src, self.pg2.remote_ip6)
315             self.assertEqual(rx[IPerror6].dst, self.pg1.remote_ip6)
316             self.assertEqual(rx[IPerror6].plen - 20, 65200)
317
318         #
319         # Send jumbo frame with gso enabled only on input interface with 9K MTU
320         # and DF bit is unset. GSO packet will be fragmented. MSS is 8960. GSO
321         # size will be min(MSS, 2048 - 14 - 20) vlib_buffer_t size
322         #
323         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
324         self.vapi.sw_interface_set_mtu(self.pg4.sw_if_index, [9000, 0, 0, 0])
325         p44 = (
326             Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac)
327             / IP(src=self.pg4.remote_ip4, dst=self.pg1.remote_ip4)
328             / TCP(sport=1234, dport=1234)
329             / Raw(b"\xa5" * 65200)
330         )
331
332         rxs = self.send_and_expect(self.pg4, 5 * [p44], self.pg1, 165)
333         size = 0
334         for rx in rxs:
335             self.assertEqual(rx[Ether].src, self.pg1.local_mac)
336             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
337             self.assertEqual(rx[IP].src, self.pg4.remote_ip4)
338             self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
339             payload_len = rx[IP].len - 20 - 20  # len - 20 (IP4) - 20 (TCP)
340             self.assert_ip_checksum_valid(rx)
341             self.assert_tcp_checksum_valid(rx)
342             self.assertEqual(payload_len, len(rx[Raw]))
343             size += payload_len
344         self.assertEqual(size, 65200 * 5)
345
346         #
347         # IPv6
348         #
349         p64 = (
350             Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac)
351             / IPv6(src=self.pg4.remote_ip6, dst=self.pg1.remote_ip6)
352             / TCP(sport=1234, dport=1234)
353             / Raw(b"\xa5" * 65200)
354         )
355
356         rxs = self.send_and_expect(self.pg4, 5 * [p64], self.pg1, 170)
357         size = 0
358         for rx in rxs:
359             self.assertEqual(rx[Ether].src, self.pg1.local_mac)
360             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
361             self.assertEqual(rx[IPv6].src, self.pg4.remote_ip6)
362             self.assertEqual(rx[IPv6].dst, self.pg1.remote_ip6)
363             payload_len = rx[IPv6].plen - 20
364             self.assert_tcp_checksum_valid(rx)
365             self.assertEqual(payload_len, len(rx[Raw]))
366             size += payload_len
367         self.assertEqual(size, 65200 * 5)
368
369         self.vapi.feature_gso_enable_disable(
370             sw_if_index=self.pg0.sw_if_index, enable_disable=0
371         )
372         self.vapi.feature_gso_enable_disable(
373             sw_if_index=self.pg1.sw_if_index, enable_disable=0
374         )
375
376     def test_gso_vxlan(self):
377         """GSO VXLAN test"""
378         self.logger.info(self.vapi.cli("sh int addr"))
379         #
380         # Send jumbo frame with gso enabled only on input interface and
381         # create VXLAN VTEP on VPP pg0, and put vxlan_tunnel0 and pg2
382         # into BD.
383         #
384
385         #
386         # enable ipv4/vxlan
387         #
388         self.vxlan.add_vpp_config()
389         self.vapi.sw_interface_set_l2_bridge(
390             rx_sw_if_index=self.vxlan.sw_if_index, bd_id=self.single_tunnel_bd
391         )
392         self.vapi.sw_interface_set_l2_bridge(
393             rx_sw_if_index=self.pg2.sw_if_index, bd_id=self.single_tunnel_bd
394         )
395         self.vapi.feature_gso_enable_disable(
396             sw_if_index=self.pg0.sw_if_index, enable_disable=1
397         )
398
399         #
400         # IPv4/IPv4 - VXLAN
401         #
402         p45 = (
403             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
404             / IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags="DF")
405             / TCP(sport=1234, dport=1234)
406             / Raw(b"\xa5" * 65200)
407         )
408
409         rxs = self.send_and_expect(self.pg2, 5 * [p45], self.pg0, 225)
410         size = 0
411         for rx in rxs:
412             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
413             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
414             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
415             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
416             self.assert_ip_checksum_valid(rx)
417             self.assert_udp_checksum_valid(rx, ignore_zero_checksum=False)
418             self.assertEqual(rx[VXLAN].vni, 10)
419             inner = rx[VXLAN].payload
420             self.assertEqual(rx[IP].len - 20 - 8 - 8, len(inner))
421             self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
422             self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
423             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
424             self.assertEqual(inner[IP].dst, "172.16.3.3")
425             self.assert_ip_checksum_valid(inner)
426             self.assert_tcp_checksum_valid(inner)
427             payload_len = inner[IP].len - 20 - 20
428             self.assertEqual(payload_len, len(inner[Raw]))
429             size += payload_len
430         self.assertEqual(size, 65200 * 5)
431
432         #
433         # IPv4/IPv6 - VXLAN
434         #
435         p65 = (
436             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
437             / IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3")
438             / TCP(sport=1234, dport=1234)
439             / Raw(b"\xa5" * 65200)
440         )
441
442         rxs = self.send_and_expect(self.pg2, 5 * [p65], self.pg0, 225)
443         size = 0
444         for rx in rxs:
445             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
446             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
447             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
448             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
449             self.assert_ip_checksum_valid(rx)
450             self.assert_udp_checksum_valid(rx, ignore_zero_checksum=False)
451             self.assertEqual(rx[VXLAN].vni, 10)
452             inner = rx[VXLAN].payload
453             self.assertEqual(rx[IP].len - 20 - 8 - 8, len(inner))
454             self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
455             self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
456             self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
457             self.assertEqual(inner[IPv6].dst, "fd01:3::3")
458             self.assert_tcp_checksum_valid(inner)
459             payload_len = inner[IPv6].plen - 20
460             self.assertEqual(payload_len, len(inner[Raw]))
461             size += payload_len
462         self.assertEqual(size, 65200 * 5)
463
464         #
465         # disable ipv4/vxlan
466         #
467         self.vxlan.remove_vpp_config()
468
469         #
470         # enable ipv6/vxlan
471         #
472         self.vxlan2.add_vpp_config()
473         self.vapi.sw_interface_set_l2_bridge(
474             rx_sw_if_index=self.vxlan2.sw_if_index, bd_id=self.single_tunnel_bd
475         )
476
477         #
478         # IPv6/IPv4 - VXLAN
479         #
480         p46 = (
481             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
482             / IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags="DF")
483             / TCP(sport=1234, dport=1234)
484             / Raw(b"\xa5" * 65200)
485         )
486
487         rxs = self.send_and_expect(self.pg2, 5 * [p46], self.pg0, 225)
488         size = 0
489         for rx in rxs:
490             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
491             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
492             self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
493             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
494             self.assert_udp_checksum_valid(rx, ignore_zero_checksum=False)
495             self.assertEqual(rx[VXLAN].vni, 10)
496             inner = rx[VXLAN].payload
497             self.assertEqual(rx[IPv6].plen - 8 - 8, len(inner))
498             self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
499             self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
500             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
501             self.assertEqual(inner[IP].dst, "172.16.3.3")
502             self.assert_ip_checksum_valid(inner)
503             self.assert_tcp_checksum_valid(inner)
504             payload_len = inner[IP].len - 20 - 20
505             self.assertEqual(payload_len, len(inner[Raw]))
506             size += payload_len
507         self.assertEqual(size, 65200 * 5)
508
509         #
510         # IPv6/IPv6 - VXLAN
511         #
512         p66 = (
513             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
514             / IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3")
515             / TCP(sport=1234, dport=1234)
516             / Raw(b"\xa5" * 65200)
517         )
518
519         rxs = self.send_and_expect(self.pg2, 5 * [p66], self.pg0, 225)
520         size = 0
521         for rx in rxs:
522             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
523             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
524             self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
525             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
526             self.assert_udp_checksum_valid(rx, ignore_zero_checksum=False)
527             self.assertEqual(rx[VXLAN].vni, 10)
528             inner = rx[VXLAN].payload
529             self.assertEqual(rx[IPv6].plen - 8 - 8, len(inner))
530             self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
531             self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
532             self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
533             self.assertEqual(inner[IPv6].dst, "fd01:3::3")
534             self.assert_tcp_checksum_valid(inner)
535             payload_len = inner[IPv6].plen - 20
536             self.assertEqual(payload_len, len(inner[Raw]))
537             size += payload_len
538         self.assertEqual(size, 65200 * 5)
539
540         #
541         # disable ipv4/vxlan
542         #
543         self.vxlan2.remove_vpp_config()
544
545         self.vapi.feature_gso_enable_disable(
546             sw_if_index=self.pg0.sw_if_index, enable_disable=0
547         )
548
549     def test_gso_ipip(self):
550         """GSO IPIP test"""
551         self.logger.info(self.vapi.cli("sh int addr"))
552         #
553         # Send jumbo frame with gso enabled only on input interface and
554         # create IPIP tunnel on VPP pg0.
555         #
556         self.vapi.feature_gso_enable_disable(
557             sw_if_index=self.pg0.sw_if_index, enable_disable=1
558         )
559
560         #
561         # enable ipip4
562         #
563         self.ipip4.add_vpp_config()
564
565         # Set interface up and enable IP on it
566         self.ipip4.admin_up()
567         self.ipip4.set_unnumbered(self.pg0.sw_if_index)
568
569         # Add IPv4 routes via tunnel interface
570         self.ip4_via_ip4_tunnel = VppIpRoute(
571             self,
572             "172.16.10.0",
573             24,
574             [
575                 VppRoutePath(
576                     "0.0.0.0",
577                     self.ipip4.sw_if_index,
578                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
579                 )
580             ],
581         )
582         self.ip4_via_ip4_tunnel.add_vpp_config()
583
584         #
585         # IPv4/IPv4 - IPIP
586         #
587         p47 = (
588             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
589             / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags="DF")
590             / TCP(sport=1234, dport=1234)
591             / Raw(b"\xa5" * 65200)
592         )
593
594         rxs = self.send_and_expect(self.pg2, 5 * [p47], self.pg0, 225)
595         size = 0
596         for rx in rxs:
597             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
598             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
599             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
600             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
601             self.assert_ip_checksum_valid(rx)
602             self.assertEqual(rx[IP].proto, 4)  # ipencap
603             inner = rx[IP].payload
604             self.assertEqual(rx[IP].len - 20, len(inner))
605             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
606             self.assertEqual(inner[IP].dst, "172.16.10.3")
607             self.assert_ip_checksum_valid(inner)
608             self.assert_tcp_checksum_valid(inner)
609             payload_len = inner[IP].len - 20 - 20
610             self.assertEqual(payload_len, len(inner[Raw]))
611             size += payload_len
612         self.assertEqual(size, 65200 * 5)
613
614         self.ip6_via_ip4_tunnel = VppIpRoute(
615             self,
616             "fd01:10::",
617             64,
618             [
619                 VppRoutePath(
620                     "::",
621                     self.ipip4.sw_if_index,
622                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
623                 )
624             ],
625         )
626         self.ip6_via_ip4_tunnel.add_vpp_config()
627         #
628         # IPv4/IPv6 - IPIP
629         #
630         p67 = (
631             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
632             / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3")
633             / TCP(sport=1234, dport=1234)
634             / Raw(b"\xa5" * 65200)
635         )
636
637         rxs = self.send_and_expect(self.pg2, 5 * [p67], self.pg0, 225)
638         size = 0
639         for rx in rxs:
640             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
641             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
642             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
643             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
644             self.assert_ip_checksum_valid(rx)
645             self.assertEqual(rx[IP].proto, 41)  # ipv6
646             inner = rx[IP].payload
647             self.assertEqual(rx[IP].len - 20, len(inner))
648             self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
649             self.assertEqual(inner[IPv6].dst, "fd01:10::3")
650             self.assert_tcp_checksum_valid(inner)
651             payload_len = inner[IPv6].plen - 20
652             self.assertEqual(payload_len, len(inner[Raw]))
653             size += payload_len
654         self.assertEqual(size, 65200 * 5)
655
656         #
657         # Send jumbo frame with gso enabled only on input interface and
658         # create IPIP tunnel on VPP pg0. Enable gso feature node on ipip
659         # tunnel - IPSec use case
660         #
661         self.vapi.feature_gso_enable_disable(
662             sw_if_index=self.pg0.sw_if_index, enable_disable=0
663         )
664         self.vapi.feature_gso_enable_disable(
665             sw_if_index=self.ipip4.sw_if_index, enable_disable=1
666         )
667
668         rxs = self.send_and_expect(self.pg2, 5 * [p47], self.pg0, 225)
669         size = 0
670         for rx in rxs:
671             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
672             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
673             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
674             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
675             self.assert_ip_checksum_valid(rx)
676             self.assertEqual(rx[IP].proto, 4)  # ipencap
677             inner = rx[IP].payload
678             self.assertEqual(rx[IP].len - 20, len(inner))
679             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
680             self.assertEqual(inner[IP].dst, "172.16.10.3")
681             self.assert_ip_checksum_valid(inner)
682             self.assert_tcp_checksum_valid(inner)
683             payload_len = inner[IP].len - 20 - 20
684             self.assertEqual(payload_len, len(inner[Raw]))
685             size += payload_len
686         self.assertEqual(size, 65200 * 5)
687
688         #
689         # disable ipip4
690         #
691         self.vapi.feature_gso_enable_disable(
692             sw_if_index=self.ipip4.sw_if_index, enable_disable=0
693         )
694         self.ip4_via_ip4_tunnel.remove_vpp_config()
695         self.ip6_via_ip4_tunnel.remove_vpp_config()
696         self.ipip4.remove_vpp_config()
697
698         #
699         # enable ipip6
700         #
701         self.vapi.feature_gso_enable_disable(
702             sw_if_index=self.pg0.sw_if_index, enable_disable=1
703         )
704         self.ipip6.add_vpp_config()
705
706         # Set interface up and enable IP on it
707         self.ipip6.admin_up()
708         self.ipip6.set_unnumbered(self.pg0.sw_if_index)
709
710         # Add IPv4 routes via tunnel interface
711         self.ip4_via_ip6_tunnel = VppIpRoute(
712             self,
713             "172.16.10.0",
714             24,
715             [
716                 VppRoutePath(
717                     "0.0.0.0",
718                     self.ipip6.sw_if_index,
719                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
720                 )
721             ],
722         )
723         self.ip4_via_ip6_tunnel.add_vpp_config()
724
725         #
726         # IPv6/IPv4 - IPIP
727         #
728         p48 = (
729             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
730             / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags="DF")
731             / TCP(sport=1234, dport=1234)
732             / Raw(b"\xa5" * 65200)
733         )
734
735         rxs = self.send_and_expect(self.pg2, 5 * [p48], self.pg0, 225)
736         size = 0
737         for rx in rxs:
738             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
739             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
740             self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
741             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
742             self.assertEqual(ipv6nh[rx[IPv6].nh], "IP")
743             inner = rx[IPv6].payload
744             self.assertEqual(rx[IPv6].plen, len(inner))
745             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
746             self.assertEqual(inner[IP].dst, "172.16.10.3")
747             self.assert_ip_checksum_valid(inner)
748             self.assert_tcp_checksum_valid(inner)
749             payload_len = inner[IP].len - 20 - 20
750             self.assertEqual(payload_len, len(inner[Raw]))
751             size += payload_len
752         self.assertEqual(size, 65200 * 5)
753
754         self.ip6_via_ip6_tunnel = VppIpRoute(
755             self,
756             "fd01:10::",
757             64,
758             [
759                 VppRoutePath(
760                     "::",
761                     self.ipip6.sw_if_index,
762                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
763                 )
764             ],
765         )
766         self.ip6_via_ip6_tunnel.add_vpp_config()
767
768         #
769         # IPv6/IPv6 - IPIP
770         #
771         p68 = (
772             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
773             / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3")
774             / TCP(sport=1234, dport=1234)
775             / Raw(b"\xa5" * 65200)
776         )
777
778         rxs = self.send_and_expect(self.pg2, 5 * [p68], self.pg0, 225)
779         size = 0
780         for rx in rxs:
781             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
782             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
783             self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
784             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
785             self.assertEqual(ipv6nh[rx[IPv6].nh], "IPv6")
786             inner = rx[IPv6].payload
787             self.assertEqual(rx[IPv6].plen, len(inner))
788             self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
789             self.assertEqual(inner[IPv6].dst, "fd01:10::3")
790             self.assert_tcp_checksum_valid(inner)
791             payload_len = inner[IPv6].plen - 20
792             self.assertEqual(payload_len, len(inner[Raw]))
793             size += payload_len
794         self.assertEqual(size, 65200 * 5)
795
796         #
797         # disable ipip6
798         #
799         self.ip4_via_ip6_tunnel.remove_vpp_config()
800         self.ip6_via_ip6_tunnel.remove_vpp_config()
801         self.ipip6.remove_vpp_config()
802
803         self.vapi.feature_gso_enable_disable(
804             sw_if_index=self.pg0.sw_if_index, enable_disable=0
805         )
806
807     def test_gso_ipsec(self):
808         """GSO IPSEC test"""
809         #
810         # Send jumbo frame with gso enabled only on input interface and
811         # create IPIP tunnel on VPP pg0.
812         #
813
814         #
815         # enable ipip4
816         #
817         self.ipip4.add_vpp_config()
818         self.vapi.feature_gso_enable_disable(
819             sw_if_index=self.ipip4.sw_if_index, enable_disable=1
820         )
821
822         # Add IPv4 routes via tunnel interface
823         self.ip4_via_ip4_tunnel = VppIpRoute(
824             self,
825             "172.16.10.0",
826             24,
827             [
828                 VppRoutePath(
829                     "0.0.0.0",
830                     self.ipip4.sw_if_index,
831                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
832                 )
833             ],
834         )
835         self.ip4_via_ip4_tunnel.add_vpp_config()
836
837         # IPSec config
838         self.ipv4_params = IPsecIPv4Params()
839         self.encryption_type = ESP
840         config_tun_params(self.ipv4_params, self.encryption_type, self.ipip4)
841
842         self.tun_sa_in_v4 = VppIpsecSA(
843             self,
844             self.ipv4_params.scapy_tun_sa_id,
845             self.ipv4_params.scapy_tun_spi,
846             self.ipv4_params.auth_algo_vpp_id,
847             self.ipv4_params.auth_key,
848             self.ipv4_params.crypt_algo_vpp_id,
849             self.ipv4_params.crypt_key,
850             VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP,
851         )
852         self.tun_sa_in_v4.add_vpp_config()
853
854         self.tun_sa_out_v4 = VppIpsecSA(
855             self,
856             self.ipv4_params.vpp_tun_sa_id,
857             self.ipv4_params.vpp_tun_spi,
858             self.ipv4_params.auth_algo_vpp_id,
859             self.ipv4_params.auth_key,
860             self.ipv4_params.crypt_algo_vpp_id,
861             self.ipv4_params.crypt_key,
862             VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP,
863         )
864         self.tun_sa_out_v4.add_vpp_config()
865
866         self.tun_protect_v4 = VppIpsecTunProtect(
867             self, self.ipip4, self.tun_sa_out_v4, [self.tun_sa_in_v4]
868         )
869
870         self.tun_protect_v4.add_vpp_config()
871
872         # Set interface up and enable IP on it
873         self.ipip4.admin_up()
874         self.ipip4.set_unnumbered(self.pg0.sw_if_index)
875
876         #
877         # IPv4/IPv4 - IPSEC
878         #
879         ipsec44 = (
880             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
881             / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags="DF")
882             / TCP(sport=1234, dport=1234)
883             / Raw(b"\xa5" * 65200)
884         )
885
886         rxs = self.send_and_expect(self.pg2, [ipsec44], self.pg0, 45)
887         size = 0
888         for rx in rxs:
889             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
890             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
891             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
892             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
893             self.assertEqual(rx[IP].proto, 50)  # ESP
894             self.assertEqual(rx[ESP].spi, self.ipv4_params.vpp_tun_spi)
895             inner = self.ipv4_params.vpp_tun_sa.decrypt(rx[IP])
896             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
897             self.assertEqual(inner[IP].dst, "172.16.10.3")
898             size += inner[IP].len - 20 - 20
899         self.assertEqual(size, 65200)
900
901         self.ip6_via_ip4_tunnel = VppIpRoute(
902             self,
903             "fd01:10::",
904             64,
905             [
906                 VppRoutePath(
907                     "::",
908                     self.ipip4.sw_if_index,
909                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
910                 )
911             ],
912         )
913         self.ip6_via_ip4_tunnel.add_vpp_config()
914         #
915         # IPv4/IPv6 - IPSEC
916         #
917         ipsec46 = (
918             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
919             / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3")
920             / TCP(sport=1234, dport=1234)
921             / Raw(b"\xa5" * 65200)
922         )
923
924         rxs = self.send_and_expect(self.pg2, [ipsec46], self.pg0, 45)
925         size = 0
926         for rx in rxs:
927             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
928             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
929             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
930             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
931             self.assertEqual(rx[IP].proto, 50)  # ESP
932             self.assertEqual(rx[ESP].spi, self.ipv4_params.vpp_tun_spi)
933             inner = self.ipv4_params.vpp_tun_sa.decrypt(rx[IP])
934             self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
935             self.assertEqual(inner[IPv6].dst, "fd01:10::3")
936             size += inner[IPv6].plen - 20
937         self.assertEqual(size, 65200)
938
939         # disable IPSec
940         self.tun_protect_v4.remove_vpp_config()
941         self.tun_sa_in_v4.remove_vpp_config()
942         self.tun_sa_out_v4.remove_vpp_config()
943
944         #
945         # disable ipip4
946         #
947         self.vapi.feature_gso_enable_disable(self.ipip4.sw_if_index, enable_disable=0)
948         self.ip4_via_ip4_tunnel.remove_vpp_config()
949         self.ip6_via_ip4_tunnel.remove_vpp_config()
950         self.ipip4.remove_vpp_config()
951
952         #
953         # enable ipip6
954         #
955         self.ipip6.add_vpp_config()
956         self.vapi.feature_gso_enable_disable(self.ipip6.sw_if_index, enable_disable=1)
957
958         # Set interface up and enable IP on it
959         self.ipip6.admin_up()
960         self.ipip6.set_unnumbered(self.pg0.sw_if_index)
961
962         # Add IPv4 routes via tunnel interface
963         self.ip4_via_ip6_tunnel = VppIpRoute(
964             self,
965             "172.16.10.0",
966             24,
967             [
968                 VppRoutePath(
969                     "0.0.0.0",
970                     self.ipip6.sw_if_index,
971                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
972                 )
973             ],
974         )
975         self.ip4_via_ip6_tunnel.add_vpp_config()
976
977         # IPSec config
978         self.ipv6_params = IPsecIPv6Params()
979         self.encryption_type = ESP
980         config_tun_params(self.ipv6_params, self.encryption_type, self.ipip6)
981         self.tun_sa_in_v6 = VppIpsecSA(
982             self,
983             self.ipv6_params.scapy_tun_sa_id,
984             self.ipv6_params.scapy_tun_spi,
985             self.ipv6_params.auth_algo_vpp_id,
986             self.ipv6_params.auth_key,
987             self.ipv6_params.crypt_algo_vpp_id,
988             self.ipv6_params.crypt_key,
989             VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP,
990         )
991         self.tun_sa_in_v6.add_vpp_config()
992
993         self.tun_sa_out_v6 = VppIpsecSA(
994             self,
995             self.ipv6_params.vpp_tun_sa_id,
996             self.ipv6_params.vpp_tun_spi,
997             self.ipv6_params.auth_algo_vpp_id,
998             self.ipv6_params.auth_key,
999             self.ipv6_params.crypt_algo_vpp_id,
1000             self.ipv6_params.crypt_key,
1001             VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP,
1002         )
1003         self.tun_sa_out_v6.add_vpp_config()
1004
1005         self.tun_protect_v6 = VppIpsecTunProtect(
1006             self, self.ipip6, self.tun_sa_out_v6, [self.tun_sa_in_v6]
1007         )
1008
1009         self.tun_protect_v6.add_vpp_config()
1010
1011         #
1012         # IPv6/IPv4 - IPSEC
1013         #
1014         ipsec64 = (
1015             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
1016             / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags="DF")
1017             / TCP(sport=1234, dport=1234)
1018             / Raw(b"\xa5" * 65200)
1019         )
1020
1021         rxs = self.send_and_expect(self.pg2, [ipsec64], self.pg0, 45)
1022         size = 0
1023         for rx in rxs:
1024             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1025             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1026             self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
1027             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1028             self.assertEqual(ipv6nh[rx[IPv6].nh], "ESP Header")
1029             self.assertEqual(rx[ESP].spi, self.ipv6_params.vpp_tun_spi)
1030             inner = self.ipv6_params.vpp_tun_sa.decrypt(rx[IPv6])
1031             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
1032             self.assertEqual(inner[IP].dst, "172.16.10.3")
1033             size += inner[IP].len - 20 - 20
1034         self.assertEqual(size, 65200)
1035
1036         self.ip6_via_ip6_tunnel = VppIpRoute(
1037             self,
1038             "fd01:10::",
1039             64,
1040             [
1041                 VppRoutePath(
1042                     "::",
1043                     self.ipip6.sw_if_index,
1044                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
1045                 )
1046             ],
1047         )
1048         self.ip6_via_ip6_tunnel.add_vpp_config()
1049
1050         #
1051         # IPv6/IPv6 - IPSEC
1052         #
1053         ipsec66 = (
1054             Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79")
1055             / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3")
1056             / TCP(sport=1234, dport=1234)
1057             / Raw(b"\xa5" * 65200)
1058         )
1059
1060         rxs = self.send_and_expect(self.pg2, [ipsec66], self.pg0, 45)
1061         size = 0
1062         for rx in rxs:
1063             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1064             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1065             self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
1066             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
1067             self.assertEqual(ipv6nh[rx[IPv6].nh], "ESP Header")
1068             self.assertEqual(rx[ESP].spi, self.ipv6_params.vpp_tun_spi)
1069             inner = self.ipv6_params.vpp_tun_sa.decrypt(rx[IPv6])
1070             self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
1071             self.assertEqual(inner[IPv6].dst, "fd01:10::3")
1072             size += inner[IPv6].plen - 20
1073         self.assertEqual(size, 65200)
1074
1075         # disable IPSec
1076         self.tun_protect_v6.remove_vpp_config()
1077         self.tun_sa_in_v6.remove_vpp_config()
1078         self.tun_sa_out_v6.remove_vpp_config()
1079
1080         #
1081         # disable ipip6
1082         #
1083         self.ip4_via_ip6_tunnel.remove_vpp_config()
1084         self.ip6_via_ip6_tunnel.remove_vpp_config()
1085         self.ipip6.remove_vpp_config()
1086
1087         self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index, enable_disable=0)
1088
1089
1090 if __name__ == "__main__":
1091     unittest.main(testRunner=VppTestRunner)