api: ip: add IP_ROUTE_LOOKUP API
[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_ipip_tun_interface import VppIpIpTunInterface
26 from vpp_vxlan_tunnel import VppVxlanTunnel
27 from socket import AF_INET, AF_INET6, inet_pton
28 from util import reassemble4
29
30
31 """ Test_gso is a subclass of VPPTestCase classes.
32     GSO tests.
33 """
34
35
36 class 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 jumbo frame with gso enabled and DF bit is set
112         # input and output interfaces support GSO
113         #
114         p41 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
115                IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4,
116                   flags='DF') /
117                TCP(sport=1234, dport=1234) /
118                Raw(b'\xa5' * 65200))
119
120         rxs = self.send_and_expect(self.pg2, [p41], self.pg3)
121
122         for rx in rxs:
123             self.assertEqual(rx[Ether].src, self.pg3.local_mac)
124             self.assertEqual(rx[Ether].dst, self.pg3.remote_mac)
125             self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
126             self.assertEqual(rx[IP].dst, self.pg3.remote_ip4)
127             self.assertEqual(rx[IP].len, 65240)  # 65200 + 20 (IP) + 20 (TCP)
128             self.assertEqual(rx[TCP].sport, 1234)
129             self.assertEqual(rx[TCP].dport, 1234)
130
131         #
132         # ipv6
133         #
134         p61 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
135                IPv6(src=self.pg2.remote_ip6, dst=self.pg3.remote_ip6) /
136                TCP(sport=1234, dport=1234) /
137                Raw(b'\xa5' * 65200))
138
139         rxs = self.send_and_expect(self.pg2, [p61], self.pg3)
140
141         for rx in rxs:
142             self.assertEqual(rx[Ether].src, self.pg3.local_mac)
143             self.assertEqual(rx[Ether].dst, self.pg3.remote_mac)
144             self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6)
145             self.assertEqual(rx[IPv6].dst, self.pg3.remote_ip6)
146             self.assertEqual(rx[IPv6].plen, 65220)  # 65200 + 20 (TCP)
147             self.assertEqual(rx[TCP].sport, 1234)
148             self.assertEqual(rx[TCP].dport, 1234)
149
150         #
151         # Send jumbo frame with gso enabled only on input interface
152         # and DF bit is set. GSO packet will be chunked into gso_size
153         # data payload
154         #
155         self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
156         p42 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
157                IP(src=self.pg2.remote_ip4, dst=self.pg0.remote_ip4,
158                   flags='DF') /
159                TCP(sport=1234, dport=1234) /
160                Raw(b'\xa5' * 65200))
161
162         rxs = self.send_and_expect(self.pg2, [p42], self.pg0, 45)
163         size = 0
164         for rx in rxs:
165             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
166             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
167             self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
168             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
169             self.assertEqual(rx[TCP].sport, 1234)
170             self.assertEqual(rx[TCP].dport, 1234)
171
172         size = rxs[44][TCP].seq + rxs[44][IP].len - 20 - 20
173         self.assertEqual(size, 65200)
174
175         #
176         # ipv6
177         #
178         p62 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
179                IPv6(src=self.pg2.remote_ip6, dst=self.pg0.remote_ip6) /
180                TCP(sport=1234, dport=1234) /
181                Raw(b'\xa5' * 65200))
182
183         rxs = self.send_and_expect(self.pg2, [p62], self.pg0, 45)
184         size = 0
185         for rx in rxs:
186             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
187             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
188             self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6)
189             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
190             self.assertEqual(rx[TCP].sport, 1234)
191             self.assertEqual(rx[TCP].dport, 1234)
192
193         size = rxs[44][TCP].seq + rxs[44][IPv6].plen - 20
194         self.assertEqual(size, 65200)
195
196         #
197         # Send jumbo frame with gso enabled only on input interface
198         # and DF bit is unset. GSO packet will be fragmented.
199         #
200         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [576, 0, 0, 0])
201         self.vapi.feature_gso_enable_disable(self.pg1.sw_if_index)
202
203         p43 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
204                IP(src=self.pg2.remote_ip4, dst=self.pg1.remote_ip4) /
205                TCP(sport=1234, dport=1234) /
206                Raw(b'\xa5' * 65200))
207
208         rxs = self.send_and_expect(self.pg2, [p43], self.pg1, 119)
209         size = 0
210         for rx in rxs:
211             self.assertEqual(rx[Ether].src, self.pg1.local_mac)
212             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
213             self.assertEqual(rx[IP].src, self.pg2.remote_ip4)
214             self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
215             size += rx[IP].len - 20
216         size -= 20  # TCP header
217         self.assertEqual(size, 65200)
218
219         #
220         # IPv6
221         # Send jumbo frame with gso enabled only on input interface.
222         # ICMPv6 Packet Too Big will be sent back to sender.
223         #
224         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0])
225         p63 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) /
226                IPv6(src=self.pg2.remote_ip6, dst=self.pg1.remote_ip6) /
227                TCP(sport=1234, dport=1234) /
228                Raw(b'\xa5' * 65200))
229
230         rxs = self.send_and_expect(self.pg2, [p63], self.pg2, 1)
231         for rx in rxs:
232             self.assertEqual(rx[Ether].src, self.pg2.local_mac)
233             self.assertEqual(rx[Ether].dst, self.pg2.remote_mac)
234             self.assertEqual(rx[IPv6].src, self.pg2.local_ip6)
235             self.assertEqual(rx[IPv6].dst, self.pg2.remote_ip6)
236             self.assertEqual(rx[IPv6].plen, 1240)  # MTU - IPv6 header
237             self.assertEqual(ipv6nh[rx[IPv6].nh], "ICMPv6")
238             self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 1280)
239             self.assertEqual(rx[IPerror6].src, self.pg2.remote_ip6)
240             self.assertEqual(rx[IPerror6].dst, self.pg1.remote_ip6)
241             self.assertEqual(rx[IPerror6].plen - 20, 65200)
242
243         #
244         # Send jumbo frame with gso enabled only on input interface with 9K MTU
245         # and DF bit is unset. GSO packet will be fragmented. MSS is 8960. GSO
246         # size will be min(MSS, 2048 - 14 - 20) vlib_buffer_t size
247         #
248         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
249         self.vapi.sw_interface_set_mtu(self.pg4.sw_if_index, [9000, 0, 0, 0])
250         p44 = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
251                IP(src=self.pg4.remote_ip4, dst=self.pg1.remote_ip4) /
252                TCP(sport=1234, dport=1234) /
253                Raw(b'\xa5' * 65200))
254
255         self.pg1.enable_capture()
256         rxs = self.send_and_expect(self.pg4, [p44], self.pg1, 33)
257         size = 0
258         for rx in rxs:
259             self.assertEqual(rx[Ether].src, self.pg1.local_mac)
260             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
261             self.assertEqual(rx[IP].src, self.pg4.remote_ip4)
262             self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
263         size = rxs[32][TCP].seq + rxs[32][IP].len - 20 - 20
264         self.assertEqual(size, 65200)
265
266         #
267         # IPv6
268         #
269         p64 = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) /
270                IPv6(src=self.pg4.remote_ip6, dst=self.pg1.remote_ip6) /
271                TCP(sport=1234, dport=1234) /
272                Raw(b'\xa5' * 65200))
273
274         self.pg1.enable_capture()
275         rxs = self.send_and_expect(self.pg4, [p64], self.pg1, 34)
276         size = 0
277         for rx in rxs:
278             self.assertEqual(rx[Ether].src, self.pg1.local_mac)
279             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
280             self.assertEqual(rx[IPv6].src, self.pg4.remote_ip6)
281             self.assertEqual(rx[IPv6].dst, self.pg1.remote_ip6)
282         size = rxs[33][TCP].seq + rxs[33][IPv6].plen - 20
283         self.assertEqual(size, 65200)
284
285     def test_gso_vxlan(self):
286         """ GSO VXLAN test """
287         self.logger.info(self.vapi.cli("sh int addr"))
288         #
289         # Send jumbo frame with gso enabled only on input interface and
290         # create VXLAN VTEP on VPP pg0, and put vxlan_tunnel0 and pg2
291         # into BD.
292         #
293
294         #
295         # enable ipv4/vxlan
296         #
297         self.vxlan.add_vpp_config()
298         self.vapi.sw_interface_set_l2_bridge(
299             rx_sw_if_index=self.vxlan.sw_if_index, bd_id=self.single_tunnel_bd)
300         self.vapi.sw_interface_set_l2_bridge(
301             rx_sw_if_index=self.pg2.sw_if_index, bd_id=self.single_tunnel_bd)
302         self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
303
304         #
305         # IPv4/IPv4 - VXLAN
306         #
307         p45 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
308                IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags='DF') /
309                TCP(sport=1234, dport=1234) /
310                Raw(b'\xa5' * 65200))
311
312         rxs = self.send_and_expect(self.pg2, [p45], self.pg0, 45)
313         size = 0
314         for rx in rxs:
315             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
316             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
317             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
318             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
319             self.assertEqual(rx[VXLAN].vni, 10)
320             inner = rx[VXLAN].payload
321             self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
322             self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
323             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
324             self.assertEqual(inner[IP].dst, "172.16.3.3")
325             size += inner[IP].len - 20 - 20
326         self.assertEqual(size, 65200)
327
328         #
329         # IPv4/IPv6 - VXLAN
330         #
331         p65 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
332                IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3") /
333                TCP(sport=1234, dport=1234) /
334                Raw(b'\xa5' * 65200))
335
336         rxs = self.send_and_expect(self.pg2, [p65], self.pg0, 45)
337         size = 0
338         for rx in rxs:
339             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
340             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
341             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
342             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
343             self.assertEqual(rx[VXLAN].vni, 10)
344             inner = rx[VXLAN].payload
345             self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
346             self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
347             self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
348             self.assertEqual(inner[IPv6].dst, "fd01:3::3")
349             size += inner[IPv6].plen - 20
350         self.assertEqual(size, 65200)
351
352         #
353         # disable ipv4/vxlan
354         #
355         self.vxlan.remove_vpp_config()
356
357         #
358         # enable ipv6/vxlan
359         #
360         self.vxlan2.add_vpp_config()
361         self.vapi.sw_interface_set_l2_bridge(
362             rx_sw_if_index=self.vxlan2.sw_if_index,
363             bd_id=self.single_tunnel_bd)
364
365         #
366         # IPv6/IPv4 - VXLAN
367         #
368         p46 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
369                IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags='DF') /
370                TCP(sport=1234, dport=1234) /
371                Raw(b'\xa5' * 65200))
372
373         rxs = self.send_and_expect(self.pg2, [p46], self.pg0, 45)
374         size = 0
375         for rx in rxs:
376             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
377             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
378             self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
379             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
380             self.assertEqual(rx[VXLAN].vni, 10)
381             inner = rx[VXLAN].payload
382             self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
383             self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
384             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
385             self.assertEqual(inner[IP].dst, "172.16.3.3")
386             size += inner[IP].len - 20 - 20
387         self.assertEqual(size, 65200)
388
389         #
390         # IPv6/IPv6 - VXLAN
391         #
392         p66 = (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, [p66], self.pg0, 45)
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[IPv6].src, self.pg0.local_ip6)
403             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
404             self.assertEqual(rx[VXLAN].vni, 10)
405             inner = rx[VXLAN].payload
406             self.assertEqual(inner[Ether].src, self.pg2.remote_mac)
407             self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79")
408             self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
409             self.assertEqual(inner[IPv6].dst, "fd01:3::3")
410             size += inner[IPv6].plen - 20
411         self.assertEqual(size, 65200)
412
413         #
414         # disable ipv4/vxlan
415         #
416         self.vxlan2.remove_vpp_config()
417
418     def test_gso_ipip(self):
419         """ GSO IPIP test """
420         self.logger.info(self.vapi.cli("sh int addr"))
421         #
422         # Send jumbo frame with gso enabled only on input interface and
423         # create IPIP tunnel on VPP pg0.
424         #
425         self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
426
427         #
428         # enable ipip4
429         #
430         self.ipip4.add_vpp_config()
431
432         # Set interface up and enable IP on it
433         self.ipip4.admin_up()
434         self.ipip4.set_unnumbered(self.pg0.sw_if_index)
435
436         # Add IPv4 routes via tunnel interface
437         self.ip4_via_ip4_tunnel = VppIpRoute(
438                 self, "172.16.10.0", 24,
439                 [VppRoutePath("0.0.0.0",
440                               self.ipip4.sw_if_index,
441                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
442         self.ip4_via_ip4_tunnel.add_vpp_config()
443
444         #
445         # IPv4/IPv4 - IPIP
446         #
447         p47 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
448                IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags='DF') /
449                TCP(sport=1234, dport=1234) /
450                Raw(b'\xa5' * 65200))
451
452         rxs = self.send_and_expect(self.pg2, [p47], self.pg0, 45)
453         size = 0
454         for rx in rxs:
455             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
456             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
457             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
458             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
459             self.assertEqual(rx[IP].proto, 4)  # ipencap
460             inner = rx[IP].payload
461             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
462             self.assertEqual(inner[IP].dst, "172.16.10.3")
463             size += inner[IP].len - 20 - 20
464         self.assertEqual(size, 65200)
465
466         self.ip6_via_ip4_tunnel = VppIpRoute(
467                 self, "fd01:10::", 64,
468                 [VppRoutePath("::",
469                               self.ipip4.sw_if_index,
470                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
471         self.ip6_via_ip4_tunnel.add_vpp_config()
472         #
473         # IPv4/IPv6 - IPIP
474         #
475         p67 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
476                IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") /
477                TCP(sport=1234, dport=1234) /
478                Raw(b'\xa5' * 65200))
479
480         rxs = self.send_and_expect(self.pg2, [p67], self.pg0, 45)
481         size = 0
482         for rx in rxs:
483             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
484             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
485             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
486             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
487             self.assertEqual(rx[IP].proto, 41)  # ipv6
488             inner = rx[IP].payload
489             self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
490             self.assertEqual(inner[IPv6].dst, "fd01:10::3")
491             size += inner[IPv6].plen - 20
492         self.assertEqual(size, 65200)
493
494         #
495         # Send jumbo frame with gso enabled only on input interface and
496         # create IPIP tunnel on VPP pg0. Enable gso feature node on ipip
497         # tunnel - IPSec use case
498         #
499         self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index, 0)
500         self.vapi.feature_gso_enable_disable(self.ipip4.sw_if_index)
501
502         rxs = self.send_and_expect(self.pg2, [p47], self.pg0, 45)
503         size = 0
504         for rx in rxs:
505             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
506             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
507             self.assertEqual(rx[IP].src, self.pg0.local_ip4)
508             self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
509             self.assertEqual(rx[IP].proto, 4)  # ipencap
510             inner = rx[IP].payload
511             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
512             self.assertEqual(inner[IP].dst, "172.16.10.3")
513             size += inner[IP].len - 20 - 20
514         self.assertEqual(size, 65200)
515
516         #
517         # disable ipip4
518         #
519         self.vapi.feature_gso_enable_disable(self.ipip4.sw_if_index, 0)
520         self.ip4_via_ip4_tunnel.remove_vpp_config()
521         self.ip6_via_ip4_tunnel.remove_vpp_config()
522         self.ipip4.remove_vpp_config()
523
524         #
525         # enable ipip6
526         #
527         self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
528         self.ipip6.add_vpp_config()
529
530         # Set interface up and enable IP on it
531         self.ipip6.admin_up()
532         self.ipip6.set_unnumbered(self.pg0.sw_if_index)
533
534         # Add IPv4 routes via tunnel interface
535         self.ip4_via_ip6_tunnel = VppIpRoute(
536                 self, "172.16.10.0", 24,
537                 [VppRoutePath("0.0.0.0",
538                               self.ipip6.sw_if_index,
539                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
540         self.ip4_via_ip6_tunnel.add_vpp_config()
541
542         #
543         # IPv6/IPv4 - IPIP
544         #
545         p48 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
546                IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags='DF') /
547                TCP(sport=1234, dport=1234) /
548                Raw(b'\xa5' * 65200))
549
550         rxs = self.send_and_expect(self.pg2, [p48], self.pg0, 45)
551         size = 0
552         for rx in rxs:
553             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
554             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
555             self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
556             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
557             self.assertEqual(ipv6nh[rx[IPv6].nh], "IP")
558             inner = rx[IPv6].payload
559             self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
560             self.assertEqual(inner[IP].dst, "172.16.10.3")
561             size += inner[IP].len - 20 - 20
562         self.assertEqual(size, 65200)
563
564         self.ip6_via_ip6_tunnel = VppIpRoute(
565                 self, "fd01:10::", 64,
566                 [VppRoutePath("::",
567                               self.ipip6.sw_if_index,
568                               proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
569         self.ip6_via_ip6_tunnel.add_vpp_config()
570
571         #
572         # IPv6/IPv6 - IPIP
573         #
574         p68 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
575                IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") /
576                TCP(sport=1234, dport=1234) /
577                Raw(b'\xa5' * 65200))
578
579         rxs = self.send_and_expect(self.pg2, [p68], self.pg0, 45)
580         size = 0
581         for rx in rxs:
582             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
583             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
584             self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
585             self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
586             self.assertEqual(ipv6nh[rx[IPv6].nh], "IPv6")
587             inner = rx[IPv6].payload
588             self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
589             self.assertEqual(inner[IPv6].dst, "fd01:10::3")
590             size += inner[IPv6].plen - 20
591         self.assertEqual(size, 65200)
592
593         #
594         # disable ipip6
595         #
596         self.ip4_via_ip6_tunnel.remove_vpp_config()
597         self.ip6_via_ip6_tunnel.remove_vpp_config()
598         self.ipip6.remove_vpp_config()
599
600 if __name__ == '__main__':
601     unittest.main(testRunner=VppTestRunner)