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#
11import unittest
12
13from scapy.packet import Raw
14from scapy.layers.inet6 import IPv6, Ether, IP, UDP, ICMPv6PacketTooBig
15from scapy.layers.inet6 import ipv6nh, IPerror6
16from scapy.layers.inet import TCP, ICMP
17from scapy.layers.vxlan import VXLAN
18from scapy.data import ETH_P_IP, ETH_P_IPV6, ETH_P_ARP
19
20from framework import VppTestCase, VppTestRunner
21from vpp_object import VppObject
22from vpp_interface import VppInterface
23from vpp_ip import DpoProto
24from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
25from vpp_ipip_tun_interface import VppIpIpTunInterface
26from vpp_vxlan_tunnel import VppVxlanTunnel
27from socket import AF_INET, AF_INET6, inet_pton
28from util import reassemble4
29
30
31""" Test_gso is a subclass of VPPTestCase classes.
32    GSO tests.
33"""
34
35
36class TestGSO(VppTestCase):
37    """ GSO Test Case """
38
39    def __init__(self, *args):
40        VppTestCase.__init__(self, *args)
41
42    @classmethod
43    def setUpClass(self):
44        super(TestGSO, self).setUpClass()
45        res = self.create_pg_interfaces(range(2))
46        res_gso = self.create_pg_interfaces(range(2, 4), 1, 1460)
47        self.create_pg_interfaces(range(4, 5), 1, 8940)
48        self.pg_interfaces.append(res[0])
49        self.pg_interfaces.append(res[1])
50        self.pg_interfaces.append(res_gso[0])
51        self.pg_interfaces.append(res_gso[1])
52
53    @classmethod
54    def tearDownClass(self):
55        super(TestGSO, self).tearDownClass()
56
57    def setUp(self):
58        super(TestGSO, self).setUp()
59        for i in self.pg_interfaces:
60            i.admin_up()
61            i.config_ip4()
62            i.config_ip6()
63            i.disable_ipv6_ra()
64            i.resolve_arp()
65            i.resolve_ndp()
66
67        self.single_tunnel_bd = 10
68        self.vxlan = VppVxlanTunnel(self, src=self.pg0.local_ip4,
69                                    dst=self.pg0.remote_ip4,
70                                    vni=self.single_tunnel_bd)
71
72        self.vxlan2 = VppVxlanTunnel(self, src=self.pg0.local_ip6,
73                                     dst=self.pg0.remote_ip6,
74                                     vni=self.single_tunnel_bd)
75
76        self.ipip4 = VppIpIpTunInterface(self, self.pg0, self.pg0.local_ip4,
77                                         self.pg0.remote_ip4)
78        self.ipip6 = VppIpIpTunInterface(self, self.pg0, self.pg0.local_ip6,
79                                         self.pg0.remote_ip6)
80
81    def tearDown(self):
82        super(TestGSO, self).tearDown()
83        if not self.vpp_dead:
84            for i in self.pg_interfaces:
85                i.unconfig_ip4()
86                i.unconfig_ip6()
87                i.admin_down()
88
89    def test_gso(self):
90        """ GSO test """
91        #
92        # Send jumbo frame with gso disabled and DF bit is set
93        #
94        p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
95              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4,
96                 flags='DF') /
97              TCP(sport=1234, dport=1234) /
98              Raw(b'\xa5' * 65200))
99
100        rxs = self.send_and_expect(self.pg0, [p4], self.pg0)
101
102        for rx in rxs:
103            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
104            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
105            self.assertEqual(rx[IP].src, self.pg0.local_ip4)
106            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
107            self.assertEqual(rx[ICMP].type, 3)  # "dest-unreach"
108            self.assertEqual(rx[ICMP].code, 4)  # "fragmentation-needed"
109
110        #
111        # Send checksum offload frames
112        #
113        p40 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
114               IP(src=self.pg2.remote_ip4, dst=self.pg0.remote_ip4,
115                  flags='DF') /
116               TCP(sport=1234, dport=1234) /
117               Raw(b'\xa5' * 1460))
118
119        rxs = self.send_and_expect(self.pg2, 100*[p40], self.pg0)
120
121        for rx in rxs:
122            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
123            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
124            self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
125            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
126            payload_len = rx[IP].len - 20 - 20
127            self.assert_ip_checksum_valid(rx)
128            self.assert_tcp_checksum_valid(rx)
129            self.assertEqual(payload_len, len(rx[Raw]))
130
131        p60 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
132               IPv6(src=self.pg2.remote_ip6, dst=self.pg0.remote_ip6) /
133               TCP(sport=1234, dport=1234) /
134               Raw(b'\xa5' * 1440))
135
136        rxs = self.send_and_expect(self.pg2, 100*[p60], self.pg0)
137
138        for rx in rxs:
139            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
140            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
141            self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6)
142            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
143            payload_len = rx[IPv6].plen - 20
144            self.assert_tcp_checksum_valid(rx)
145            self.assertEqual(payload_len, len(rx[Raw]))
146
147        #
148        # Send jumbo frame with gso enabled and DF bit is set
149        # input and output interfaces support GSO
150        #
151        self.vapi.feature_gso_enable_disable(self.pg3.sw_if_index)
152        p41 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
153               IP(src=self.pg2.remote_ip4, dst=self.pg3.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, 100*[p41], self.pg3, 100)
159
160        for rx in rxs:
161            self.assertEqual(rx[Ether].src, self.pg3.local_mac)
162            self.assertEqual(rx[Ether].dst, self.pg3.remote_mac)
163            self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
164            self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
165            self.assertEqual(rx[IP].len, 65240)  # 65200 + 20 (IP) + 20 (TCP)
166            self.assertEqual(rx[TCP].sport, 1234)
167            self.assertEqual(rx[TCP].dport, 1234)
168
169        #
170        # ipv6
171        #
172        p61 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
173               IPv6(src=self.pg2.remote_ip6, dst=self.pg3.remote_ip6) /
174               TCP(sport=1234, dport=1234) /
175               Raw(b'\xa5' * 65200))
176
177        rxs = self.send_and_expect(self.pg2, 100*[p61], self.pg3, 100)
178
179        for rx in rxs:
180            self.assertEqual(rx[Ether].src, self.pg3.local_mac)
181            self.assertEqual(rx[Ether].dst, self.pg3.remote_mac)
182            self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6)
183            self.assertEqual(rx[IPv6].dst, self.pg3.remote_ip6)
184            self.assertEqual(rx[IPv6].plen, 65220)  # 65200 + 20 (TCP)
185            self.assertEqual(rx[TCP].sport, 1234)
186            self.assertEqual(rx[TCP].dport, 1234)
187
188        #
189        # Send jumbo frame with gso enabled only on input interface
190        # and DF bit is set. GSO packet will be chunked into gso_size
191        # data payload
192        #
193        self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
194        p42 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
195               IP(src=self.pg2.remote_ip4, dst=self.pg0.remote_ip4,
196                  flags='DF') /
197               TCP(sport=1234, dport=1234) /
198               Raw(b'\xa5' * 65200))
199
200        rxs = self.send_and_expect(self.pg2, 5*[p42], self.pg0, 225)
201        size = 0
202        for rx in rxs:
203            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
204            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
205            self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
206            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
207            payload_len = rx[IP].len - 20 - 20  # len - 20 (IP4) - 20 (TCP)
208            self.assert_ip_checksum_valid(rx)
209            self.assert_tcp_checksum_valid(rx)
210            self.assertEqual(rx[TCP].sport, 1234)
211            self.assertEqual(rx[TCP].dport, 1234)
212            self.assertEqual(payload_len, len(rx[Raw]))
213            size += payload_len
214        self.assertEqual(size, 65200*5)
215
216        #
217        # ipv6
218        #
219        p62 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
220               IPv6(src=self.pg2.remote_ip6, dst=self.pg0.remote_ip6) /
221               TCP(sport=1234, dport=1234) /
222               Raw(b'\xa5' * 65200))
223
224        rxs = self.send_and_expect(self.pg2, 5*[p62], self.pg0, 225)
225        size = 0
226        for rx in rxs:
227            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
228            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
229            self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6)
230            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
231            payload_len = rx[IPv6].plen - 20
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        # Send jumbo frame with gso enabled only on input interface
241        # and DF bit is unset. GSO packet will be fragmented.
242        #
243        self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [576, 0, 0, 0])
244        self.vapi.feature_gso_enable_disable(self.pg1.sw_if_index)
245
246        p43 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
247               IP(src=self.pg2.remote_ip4, dst=self.pg1.remote_ip4) /
248               TCP(sport=1234, dport=1234) /
249               Raw(b'\xa5' * 65200))
250
251        rxs = self.send_and_expect(self.pg2, 5*[p43], self.pg1, 5*119)
252        size = 0
253        for rx in rxs:
254            self.assertEqual(rx[Ether].src, self.pg1.local_mac)
255            self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
256            self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
257            self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
258            self.assert_ip_checksum_valid(rx)
259            size += rx[IP].len - 20
260        size -= 20*5  # TCP header
261        self.assertEqual(size, 65200*5)
262
263        #
264        # IPv6
265        # Send jumbo frame with gso enabled only on input interface.
266        # ICMPv6 Packet Too Big will be sent back to sender.
267        #
268        self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
269        p63 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
270               IPv6(src=self.pg2.remote_ip6, dst=self.pg1.remote_ip6) /
271               TCP(sport=1234, dport=1234) /
272               Raw(b'\xa5' * 65200))
273
274        rxs = self.send_and_expect(self.pg2, 5*[p63], self.pg2, 5)
275        for rx in rxs:
276            self.assertEqual(rx[Ether].src, self.pg2.local_mac)
277            self.assertEqual(rx[Ether].dst, self.pg2.remote_mac)
278            self.assertEqual(rx[IPv6].src, self.pg2.local_ip6)
279            self.assertEqual(rx[IPv6].dst, self.pg2.remote_ip6)
280            self.assertEqual(rx[IPv6].plen, 1240)  # MTU - IPv6 header
281            self.assertEqual(ipv6nh[rx[IPv6].nh], "ICMPv6")
282            self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 1280)
283            self.assertEqual(rx[IPerror6].src, self.pg2.remote_ip6)
284            self.assertEqual(rx[IPerror6].dst, self.pg1.remote_ip6)
285            self.assertEqual(rx[IPerror6].plen - 20, 65200)
286
287        #
288        # Send jumbo frame with gso enabled only on input interface with 9K MTU
289        # and DF bit is unset. GSO packet will be fragmented. MSS is 8960. GSO
290        # size will be min(MSS, 2048 - 14 - 20) vlib_buffer_t size
291        #
292        self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
293        self.vapi.sw_interface_set_mtu(self.pg4.sw_if_index, [9000, 0, 0, 0])
294        p44 = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
295               IP(src=self.pg4.remote_ip4, dst=self.pg1.remote_ip4) /
296               TCP(sport=1234, dport=1234) /
297               Raw(b'\xa5' * 65200))
298
299        rxs = self.send_and_expect(self.pg4, 5*[p44], self.pg1, 165)
300        size = 0
301        for rx in rxs:
302            self.assertEqual(rx[Ether].src, self.pg1.local_mac)
303            self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
304            self.assertEqual(rx[IP].src, self.pg4.remote_ip4)
305            self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
306            payload_len = rx[IP].len - 20 - 20  # len - 20 (IP4) - 20 (TCP)
307            self.assert_ip_checksum_valid(rx)
308            self.assert_tcp_checksum_valid(rx)
309            self.assertEqual(payload_len, len(rx[Raw]))
310            size += payload_len
311        self.assertEqual(size, 65200*5)
312
313        #
314        # IPv6
315        #
316        p64 = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
317               IPv6(src=self.pg4.remote_ip6, dst=self.pg1.remote_ip6) /
318               TCP(sport=1234, dport=1234) /
319               Raw(b'\xa5' * 65200))
320
321        rxs = self.send_and_expect(self.pg4, 5*[p64], self.pg1, 170)
322        size = 0
323        for rx in rxs:
324            self.assertEqual(rx[Ether].src, self.pg1.local_mac)
325            self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
326            self.assertEqual(rx[IPv6].src, self.pg4.remote_ip6)
327            self.assertEqual(rx[IPv6].dst, self.pg1.remote_ip6)
328            payload_len = rx[IPv6].plen - 20
329            self.assert_tcp_checksum_valid(rx)
330            self.assertEqual(payload_len, len(rx[Raw]))
331            size += payload_len
332        self.assertEqual(size, 65200*5)
333
334        self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index,
335                                             enable_disable=0)
336        self.vapi.feature_gso_enable_disable(self.pg1.sw_if_index,
337                                             enable_disable=0)
338
339    def test_gso_vxlan(self):
340        """ GSO VXLAN test """
341        self.logger.info(self.vapi.cli("sh int addr"))
342        #
343        # Send jumbo frame with gso enabled only on input interface and
344        # create VXLAN VTEP on VPP pg0, and put vxlan_tunnel0 and pg2
345        # into BD.
346        #
347
348        #
349        # enable ipv4/vxlan
350        #
351        self.vxlan.add_vpp_config()
352        self.vapi.sw_interface_set_l2_bridge(
353            rx_sw_if_index=self.vxlan.sw_if_index, bd_id=self.single_tunnel_bd)
354        self.vapi.sw_interface_set_l2_bridge(
355            rx_sw_if_index=self.pg2.sw_if_index, bd_id=self.single_tunnel_bd)
356        self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
357
358        #
359        # IPv4/IPv4 - VXLAN
360        #
361        p45 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
362               IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags='DF') /
363               TCP(sport=1234, dport=1234) /
364               Raw(b'\xa5' * 65200))
365
366        rxs = self.send_and_expect(self.pg2, 5*[p45], self.pg0, 225)
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[IP].src, self.pg0.local_ip4)
372            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
373            self.assert_ip_checksum_valid(rx)
374            self.assert_udp_checksum_valid(rx)
375            self.assertEqual(rx[VXLAN].vni, 10)
376            inner = rx[VXLAN].payload
377            self.assertEqual(rx[IP].len - 20 - 8 - 8, len(inner))
378            self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
379            self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
380            self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
381            self.assertEqual(inner[IP].dst, "172.16.3.3")
382            self.assert_ip_checksum_valid(inner)
383            self.assert_tcp_checksum_valid(inner)
384            payload_len = inner[IP].len - 20 - 20
385            self.assertEqual(payload_len, len(inner[Raw]))
386            size += payload_len
387        self.assertEqual(size, 65200*5)
388
389        #
390        # IPv4/IPv6 - VXLAN
391        #
392        p65 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
393               IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3") /
394               TCP(sport=1234, dport=1234) /
395               Raw(b'\xa5' * 65200))
396
397        rxs = self.send_and_expect(self.pg2, 5*[p65], self.pg0, 225)
398        size = 0
399        for rx in rxs:
400            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
401            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
402            self.assertEqual(rx[IP].src, self.pg0.local_ip4)
403            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
404            self.assert_ip_checksum_valid(rx)
405            self.assert_udp_checksum_valid(rx)
406            self.assertEqual(rx[VXLAN].vni, 10)
407            inner = rx[VXLAN].payload
408            self.assertEqual(rx[IP].len - 20 - 8 - 8, len(inner))
409            self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
410            self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
411            self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
412            self.assertEqual(inner[IPv6].dst, "fd01:3::3")
413            self.assert_tcp_checksum_valid(inner)
414            payload_len = inner[IPv6].plen - 20
415            self.assertEqual(payload_len, len(inner[Raw]))
416            size += payload_len
417        self.assertEqual(size, 65200*5)
418
419        #
420        # disable ipv4/vxlan
421        #
422        self.vxlan.remove_vpp_config()
423
424        #
425        # enable ipv6/vxlan
426        #
427        self.vxlan2.add_vpp_config()
428        self.vapi.sw_interface_set_l2_bridge(
429            rx_sw_if_index=self.vxlan2.sw_if_index,
430            bd_id=self.single_tunnel_bd)
431
432        #
433        # IPv6/IPv4 - VXLAN
434        #
435        p46 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
436               IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags='DF') /
437               TCP(sport=1234, dport=1234) /
438               Raw(b'\xa5' * 65200))
439
440        rxs = self.send_and_expect(self.pg2, 5*[p46], self.pg0, 225)
441        size = 0
442        for rx in rxs:
443            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
444            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
445            self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
446            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
447            self.assert_udp_checksum_valid(rx)
448            self.assertEqual(rx[VXLAN].vni, 10)
449            inner = rx[VXLAN].payload
450            self.assertEqual(rx[IPv6].plen - 8 - 8, len(inner))
451            self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
452            self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
453            self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
454            self.assertEqual(inner[IP].dst, "172.16.3.3")
455            self.assert_ip_checksum_valid(inner)
456            self.assert_tcp_checksum_valid(inner)
457            payload_len = inner[IP].len - 20 - 20
458            self.assertEqual(payload_len, len(inner[Raw]))
459            size += payload_len
460        self.assertEqual(size, 65200*5)
461
462        #
463        # IPv6/IPv6 - VXLAN
464        #
465        p66 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
466               IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3") /
467               TCP(sport=1234, dport=1234) /
468               Raw(b'\xa5' * 65200))
469
470        rxs = self.send_and_expect(self.pg2, 5*[p66], self.pg0, 225)
471        size = 0
472        for rx in rxs:
473            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
474            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
475            self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
476            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
477            self.assert_udp_checksum_valid(rx)
478            self.assertEqual(rx[VXLAN].vni, 10)
479            inner = rx[VXLAN].payload
480            self.assertEqual(rx[IPv6].plen - 8 - 8, len(inner))
481            self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
482            self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
483            self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
484            self.assertEqual(inner[IPv6].dst, "fd01:3::3")
485            self.assert_tcp_checksum_valid(inner)
486            payload_len = inner[IPv6].plen - 20
487            self.assertEqual(payload_len, len(inner[Raw]))
488            size += payload_len
489        self.assertEqual(size, 65200*5)
490
491        #
492        # disable ipv4/vxlan
493        #
494        self.vxlan2.remove_vpp_config()
495
496        self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index,
497                                             enable_disable=0)
498
499    def test_gso_ipip(self):
500        """ GSO IPIP test """
501        self.logger.info(self.vapi.cli("sh int addr"))
502        #
503        # Send jumbo frame with gso enabled only on input interface and
504        # create IPIP tunnel on VPP pg0.
505        #
506        self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
507
508        #
509        # enable ipip4
510        #
511        self.ipip4.add_vpp_config()
512
513        # Set interface up and enable IP on it
514        self.ipip4.admin_up()
515        self.ipip4.set_unnumbered(self.pg0.sw_if_index)
516
517        # Add IPv4 routes via tunnel interface
518        self.ip4_via_ip4_tunnel = VppIpRoute(
519                self, "172.16.10.0", 24,
520                [VppRoutePath("0.0.0.0",
521                              self.ipip4.sw_if_index,
522                              proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
523        self.ip4_via_ip4_tunnel.add_vpp_config()
524
525        #
526        # IPv4/IPv4 - IPIP
527        #
528        p47 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
529               IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags='DF') /
530               TCP(sport=1234, dport=1234) /
531               Raw(b'\xa5' * 65200))
532
533        rxs = self.send_and_expect(self.pg2, 5*[p47], self.pg0, 225)
534        size = 0
535        for rx in rxs:
536            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
537            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
538            self.assertEqual(rx[IP].src, self.pg0.local_ip4)
539            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
540            self.assert_ip_checksum_valid(rx)
541            self.assertEqual(rx[IP].proto, 4)  # ipencap
542            inner = rx[IP].payload
543            self.assertEqual(rx[IP].len - 20, len(inner))
544            self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
545            self.assertEqual(inner[IP].dst, "172.16.10.3")
546            self.assert_ip_checksum_valid(inner)
547            self.assert_tcp_checksum_valid(inner)
548            payload_len = inner[IP].len - 20 - 20
549            self.assertEqual(payload_len, len(inner[Raw]))
550            size += payload_len
551        self.assertEqual(size, 65200*5)
552
553        self.ip6_via_ip4_tunnel = VppIpRoute(
554                self, "fd01:10::", 64,
555                [VppRoutePath("::",
556                              self.ipip4.sw_if_index,
557                              proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
558        self.ip6_via_ip4_tunnel.add_vpp_config()
559        #
560        # IPv4/IPv6 - IPIP
561        #
562        p67 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
563               IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") /
564               TCP(sport=1234, dport=1234) /
565               Raw(b'\xa5' * 65200))
566
567        rxs = self.send_and_expect(self.pg2, 5*[p67], self.pg0, 225)
568        size = 0
569        for rx in rxs:
570            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
571            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
572            self.assertEqual(rx[IP].src, self.pg0.local_ip4)
573            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
574            self.assert_ip_checksum_valid(rx)
575            self.assertEqual(rx[IP].proto, 41)  # ipv6
576            inner = rx[IP].payload
577            self.assertEqual(rx[IP].len - 20, len(inner))
578            self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
579            self.assertEqual(inner[IPv6].dst, "fd01:10::3")
580            self.assert_tcp_checksum_valid(inner)
581            payload_len = inner[IPv6].plen - 20
582            self.assertEqual(payload_len, len(inner[Raw]))
583            size += payload_len
584        self.assertEqual(size, 65200*5)
585
586        #
587        # Send jumbo frame with gso enabled only on input interface and
588        # create IPIP tunnel on VPP pg0. Enable gso feature node on ipip
589        # tunnel - IPSec use case
590        #
591        self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index,
592                                             enable_disable=0)
593        self.vapi.feature_gso_enable_disable(self.ipip4.sw_if_index)
594
595        rxs = self.send_and_expect(self.pg2, 5*[p47], self.pg0, 225)
596        size = 0
597        for rx in rxs:
598            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
599            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
600            self.assertEqual(rx[IP].src, self.pg0.local_ip4)
601            self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
602            self.assert_ip_checksum_valid(rx)
603            self.assertEqual(rx[IP].proto, 4)  # ipencap
604            inner = rx[IP].payload
605            self.assertEqual(rx[IP].len - 20, len(inner))
606            self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
607            self.assertEqual(inner[IP].dst, "172.16.10.3")
608            self.assert_ip_checksum_valid(inner)
609            self.assert_tcp_checksum_valid(inner)
610            payload_len = inner[IP].len - 20 - 20
611            self.assertEqual(payload_len, len(inner[Raw]))
612            size += payload_len
613        self.assertEqual(size, 65200*5)
614
615        #
616        # disable ipip4
617        #
618        self.vapi.feature_gso_enable_disable(self.ipip4.sw_if_index,
619                                             enable_disable=0)
620        self.ip4_via_ip4_tunnel.remove_vpp_config()
621        self.ip6_via_ip4_tunnel.remove_vpp_config()
622        self.ipip4.remove_vpp_config()
623
624        #
625        # enable ipip6
626        #
627        self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
628        self.ipip6.add_vpp_config()
629
630        # Set interface up and enable IP on it
631        self.ipip6.admin_up()
632        self.ipip6.set_unnumbered(self.pg0.sw_if_index)
633
634        # Add IPv4 routes via tunnel interface
635        self.ip4_via_ip6_tunnel = VppIpRoute(
636                self, "172.16.10.0", 24,
637                [VppRoutePath("0.0.0.0",
638                              self.ipip6.sw_if_index,
639                              proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
640        self.ip4_via_ip6_tunnel.add_vpp_config()
641
642        #
643        # IPv6/IPv4 - IPIP
644        #
645        p48 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
646               IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags='DF') /
647               TCP(sport=1234, dport=1234) /
648               Raw(b'\xa5' * 65200))
649
650        rxs = self.send_and_expect(self.pg2, 5*[p48], self.pg0, 225)
651        size = 0
652        for rx in rxs:
653            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
654            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
655            self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
656            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
657            self.assertEqual(ipv6nh[rx[IPv6].nh], "IP")
658            inner = rx[IPv6].payload
659            self.assertEqual(rx[IPv6].plen, len(inner))
660            self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
661            self.assertEqual(inner[IP].dst, "172.16.10.3")
662            self.assert_ip_checksum_valid(inner)
663            self.assert_tcp_checksum_valid(inner)
664            payload_len = inner[IP].len - 20 - 20
665            self.assertEqual(payload_len, len(inner[Raw]))
666            size += payload_len
667        self.assertEqual(size, 65200*5)
668
669        self.ip6_via_ip6_tunnel = VppIpRoute(
670                self, "fd01:10::", 64,
671                [VppRoutePath("::",
672                              self.ipip6.sw_if_index,
673                              proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
674        self.ip6_via_ip6_tunnel.add_vpp_config()
675
676        #
677        # IPv6/IPv6 - IPIP
678        #
679        p68 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
680               IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") /
681               TCP(sport=1234, dport=1234) /
682               Raw(b'\xa5' * 65200))
683
684        rxs = self.send_and_expect(self.pg2, 5*[p68], self.pg0, 225)
685        size = 0
686        for rx in rxs:
687            self.assertEqual(rx[Ether].src, self.pg0.local_mac)
688            self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
689            self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
690            self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
691            self.assertEqual(ipv6nh[rx[IPv6].nh], "IPv6")
692            inner = rx[IPv6].payload
693            self.assertEqual(rx[IPv6].plen, len(inner))
694            self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
695            self.assertEqual(inner[IPv6].dst, "fd01:10::3")
696            self.assert_tcp_checksum_valid(inner)
697            payload_len = inner[IPv6].plen - 20
698            self.assertEqual(payload_len, len(inner[Raw]))
699            size += payload_len
700        self.assertEqual(size, 65200*5)
701
702        #
703        # disable ipip6
704        #
705        self.ip4_via_ip6_tunnel.remove_vpp_config()
706        self.ip6_via_ip6_tunnel.remove_vpp_config()
707        self.ipip6.remove_vpp_config()
708
709        self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index,
710                                             enable_disable=0)
711
712if __name__ == '__main__':
713    unittest.main(testRunner=VppTestRunner)
714