1 // SPDX-License-Identifier: GPL-2.0
2
3 #define _GNU_SOURCE
4
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <linux/if_tun.h>
12 #include <netinet/tcp.h>
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
15
16 #include "kselftest_harness.h"
17 #include "tuntap_helpers.h"
18
19 static const char param_dev_geneve_name[] = "geneve1";
20 static unsigned char param_hwaddr_outer_dst[] = { 0x00, 0xfe, 0x98,
21 0x14, 0x22, 0x42 };
22 static unsigned char param_hwaddr_outer_src[] = { 0x00, 0xfe, 0x98,
23 0x94, 0xd2, 0x43 };
24 static unsigned char param_hwaddr_inner_dst[] = { 0x00, 0xfe, 0x98,
25 0x94, 0x22, 0xcc };
26 static unsigned char param_hwaddr_inner_src[] = { 0x00, 0xfe, 0x98,
27 0x94, 0xd2, 0xdd };
28
29 static struct in_addr param_ipaddr4_outer_dst = {
30 __constant_htonl(0xac100001),
31 };
32
33 static struct in_addr param_ipaddr4_outer_src = {
34 __constant_htonl(0xac100002),
35 };
36
37 static struct in_addr param_ipaddr4_inner_dst = {
38 __constant_htonl(0xac100101),
39 };
40
41 static struct in_addr param_ipaddr4_inner_src = {
42 __constant_htonl(0xac100102),
43 };
44
45 static struct in6_addr param_ipaddr6_outer_dst = {
46 { { 0xfd, 0x00, 0x0d, 0xb8, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
47 };
48
49 static struct in6_addr param_ipaddr6_outer_src = {
50 { { 0xfd, 0x00, 0x0d, 0xb8, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 } },
51 };
52
53 static struct in6_addr param_ipaddr6_inner_dst = {
54 { { 0xfd, 0x00, 0x0d, 0xb8, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
55 };
56
57 static struct in6_addr param_ipaddr6_inner_src = {
58 { { 0xfd, 0x00, 0x0d, 0xb8, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 } },
59 };
60
61 #ifndef BIT
62 #define BIT(nr) (1UL << (nr))
63 #endif
64
65 #define VN_ID 1
66 #define VN_PORT 4789
67 #define UDP_SRC_PORT 22
68 #define UDP_DST_PORT 48878
69 #define IPPREFIX_LEN 24
70 #define IP6PREFIX_LEN 64
71 #define TIMEOUT_SEC 10
72 #define TIMEOUT_USEC 100000
73 #define MAX_RETRIES 20
74
75 #define UDP_TUNNEL_GENEVE_4IN4 0x01
76 #define UDP_TUNNEL_GENEVE_6IN4 0x02
77 #define UDP_TUNNEL_GENEVE_4IN6 0x04
78 #define UDP_TUNNEL_GENEVE_6IN6 0x08
79
80 #define UDP_TUNNEL_MAX_SEGMENTS BIT(7)
81
82 #define UDP_TUNNEL_OUTER_IPV4 (UDP_TUNNEL_GENEVE_4IN4 | UDP_TUNNEL_GENEVE_6IN4)
83 #define UDP_TUNNEL_INNER_IPV4 (UDP_TUNNEL_GENEVE_4IN4 | UDP_TUNNEL_GENEVE_4IN6)
84
85 #define UDP_TUNNEL_GENEVE_4IN4_HDRLEN \
86 (ETH_HLEN + 2 * sizeof(struct iphdr) + GENEVE_HLEN + \
87 2 * sizeof(struct udphdr))
88 #define UDP_TUNNEL_GENEVE_6IN6_HDRLEN \
89 (ETH_HLEN + 2 * sizeof(struct ipv6hdr) + GENEVE_HLEN + \
90 2 * sizeof(struct udphdr))
91 #define UDP_TUNNEL_GENEVE_4IN6_HDRLEN \
92 (ETH_HLEN + sizeof(struct iphdr) + sizeof(struct ipv6hdr) + \
93 GENEVE_HLEN + 2 * sizeof(struct udphdr))
94 #define UDP_TUNNEL_GENEVE_6IN4_HDRLEN \
95 (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct iphdr) + \
96 GENEVE_HLEN + 2 * sizeof(struct udphdr))
97
98 #define UDP_TUNNEL_HDRLEN(type) \
99 ((type) == UDP_TUNNEL_GENEVE_4IN4 ? UDP_TUNNEL_GENEVE_4IN4_HDRLEN : \
100 (type) == UDP_TUNNEL_GENEVE_6IN6 ? UDP_TUNNEL_GENEVE_6IN6_HDRLEN : \
101 (type) == UDP_TUNNEL_GENEVE_4IN6 ? UDP_TUNNEL_GENEVE_4IN6_HDRLEN : \
102 (type) == UDP_TUNNEL_GENEVE_6IN4 ? UDP_TUNNEL_GENEVE_6IN4_HDRLEN : \
103 0)
104
105 #define UDP_TUNNEL_MSS(type) (ETH_DATA_LEN - UDP_TUNNEL_HDRLEN(type))
106 #define UDP_TUNNEL_MAX(type, is_tap) \
107 (ETH_MAX_MTU - UDP_TUNNEL_HDRLEN(type) - ((is_tap) ? ETH_HLEN : 0))
108
109 #define TUN_VNET_TNL_SIZE sizeof(struct virtio_net_hdr_v1_hash_tunnel)
110 #define MAX_VNET_TUNNEL_PACKET_SZ \
111 (TUN_VNET_TNL_SIZE + ETH_HLEN + UDP_TUNNEL_GENEVE_6IN6_HDRLEN + \
112 ETH_MAX_MTU)
113
114 struct geneve_setup_config {
115 int family;
116 union {
117 struct in_addr r4;
118 struct in6_addr r6;
119 } remote;
120 __be32 vnid;
121 __be16 vnport;
122 unsigned char hwaddr[6];
123 uint8_t csum;
124 };
125
tun_attach(int fd,char * dev)126 static int tun_attach(int fd, char *dev)
127 {
128 struct ifreq ifr;
129
130 memset(&ifr, 0, sizeof(ifr));
131 strcpy(ifr.ifr_name, dev);
132 ifr.ifr_flags = IFF_ATTACH_QUEUE;
133
134 return ioctl(fd, TUNSETQUEUE, (void *)&ifr);
135 }
136
tun_detach(int fd,char * dev)137 static int tun_detach(int fd, char *dev)
138 {
139 struct ifreq ifr;
140
141 memset(&ifr, 0, sizeof(ifr));
142 strcpy(ifr.ifr_name, dev);
143 ifr.ifr_flags = IFF_DETACH_QUEUE;
144
145 return ioctl(fd, TUNSETQUEUE, (void *)&ifr);
146 }
147
tun_alloc(char * dev)148 static int tun_alloc(char *dev)
149 {
150 struct ifreq ifr;
151 int fd, err;
152
153 fd = open("/dev/net/tun", O_RDWR);
154 if (fd < 0) {
155 fprintf(stderr, "can't open tun: %s\n", strerror(errno));
156 return fd;
157 }
158
159 memset(&ifr, 0, sizeof(ifr));
160 strcpy(ifr.ifr_name, dev);
161 ifr.ifr_flags = IFF_TAP | IFF_NAPI | IFF_MULTI_QUEUE;
162
163 err = ioctl(fd, TUNSETIFF, (void *)&ifr);
164 if (err < 0) {
165 fprintf(stderr, "can't TUNSETIFF: %s\n", strerror(errno));
166 close(fd);
167 return err;
168 }
169 strcpy(dev, ifr.ifr_name);
170 return fd;
171 }
172
tun_delete(char * dev)173 static int tun_delete(char *dev)
174 {
175 return ip_link_del(dev);
176 }
177
tun_open(char * dev,const int flags,const int hdrlen,const int features,const unsigned char * mac_addr)178 static int tun_open(char *dev, const int flags, const int hdrlen,
179 const int features, const unsigned char *mac_addr)
180 {
181 struct ifreq ifr = { 0 };
182 int fd, sk = -1;
183
184 fd = open("/dev/net/tun", O_RDWR);
185 if (fd < 0) {
186 perror("open");
187 return -1;
188 }
189
190 ifr.ifr_flags = flags;
191 if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
192 perror("ioctl(TUNSETIFF)");
193 goto err;
194 }
195 strcpy(dev, ifr.ifr_name);
196
197 if (hdrlen > 0) {
198 if (ioctl(fd, TUNSETVNETHDRSZ, &hdrlen) < 0) {
199 perror("ioctl(TUNSETVNETHDRSZ)");
200 goto err;
201 }
202 }
203
204 if (features) {
205 if (ioctl(fd, TUNSETOFFLOAD, features) < 0) {
206 perror("ioctl(TUNSETOFFLOAD)");
207 goto err;
208 }
209 }
210
211 sk = socket(PF_INET, SOCK_DGRAM, 0);
212 if (sk < 0) {
213 perror("socket");
214 goto err;
215 }
216
217 if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
218 perror("ioctl(SIOCGIFFLAGS)");
219 goto err;
220 }
221
222 ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
223 if (ioctl(sk, SIOCSIFFLAGS, &ifr) < 0) {
224 perror("ioctl(SIOCSIFFLAGS)");
225 goto err;
226 }
227
228 if (mac_addr && flags & IFF_TAP) {
229 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
230 memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETH_ALEN);
231
232 if (ioctl(sk, SIOCSIFHWADDR, &ifr) < 0) {
233 perror("ioctl(SIOCSIFHWADDR)");
234 goto err;
235 }
236 }
237
238 out:
239 if (sk >= 0)
240 close(sk);
241 return fd;
242
243 err:
244 close(fd);
245 fd = -1;
246 goto out;
247 }
248
sockaddr_len(int family)249 static size_t sockaddr_len(int family)
250 {
251 return (family == AF_INET) ? sizeof(struct sockaddr_in) :
252 sizeof(struct sockaddr_in6);
253 }
254
geneve_fill_newlink(struct rt_link_newlink_req * req,void * data)255 static int geneve_fill_newlink(struct rt_link_newlink_req *req, void *data)
256 {
257 struct geneve_setup_config *cfg = data;
258
259 #define SET_GENEVE_REMOTE rt_link_newlink_req_set_linkinfo_data_geneve_remote
260 #define SET_GENEVE_REMOTE6 rt_link_newlink_req_set_linkinfo_data_geneve_remote6
261
262 rt_link_newlink_req_set_address(req, cfg->hwaddr, ETH_ALEN);
263 rt_link_newlink_req_set_linkinfo_data_geneve_id(req, cfg->vnid);
264 rt_link_newlink_req_set_linkinfo_data_geneve_port(req, cfg->vnport);
265 rt_link_newlink_req_set_linkinfo_data_geneve_udp_csum(req, cfg->csum);
266
267 if (cfg->family == AF_INET)
268 SET_GENEVE_REMOTE(req, cfg->remote.r4.s_addr);
269 else
270 SET_GENEVE_REMOTE6(req, &cfg->remote.r6,
271 sizeof(cfg->remote.r6));
272
273 return 0;
274 }
275
geneve_create(const char * dev,int family,void * remote,void * hwaddr)276 static int geneve_create(const char *dev, int family, void *remote,
277 void *hwaddr)
278 {
279 struct geneve_setup_config geneve;
280
281 memset(&geneve, 0, sizeof(geneve));
282 geneve.vnid = VN_ID;
283 geneve.vnport = htons(VN_PORT);
284 geneve.csum = 1;
285 geneve.family = family;
286 if (family == AF_INET)
287 memcpy(&geneve.remote.r4, remote, sizeof(struct in_addr));
288 else
289 memcpy(&geneve.remote.r6, remote, sizeof(struct in6_addr));
290 memcpy(geneve.hwaddr, hwaddr, ETH_ALEN);
291
292 return ip_link_add(dev, "geneve", geneve_fill_newlink, (void *)&geneve);
293 }
294
set_pmtu_discover(int fd,bool is_ipv4)295 static int set_pmtu_discover(int fd, bool is_ipv4)
296 {
297 int level, name, val;
298
299 if (is_ipv4) {
300 level = SOL_IP;
301 name = IP_MTU_DISCOVER;
302 val = IP_PMTUDISC_DO;
303 } else {
304 level = SOL_IPV6;
305 name = IPV6_MTU_DISCOVER;
306 val = IPV6_PMTUDISC_DO;
307 }
308
309 return setsockopt(fd, level, name, &val, sizeof(val));
310 }
311
udp_socket_open(struct sockaddr_storage * ssa,bool do_frag,bool do_connect,struct sockaddr_storage * dsa)312 static int udp_socket_open(struct sockaddr_storage *ssa, bool do_frag,
313 bool do_connect, struct sockaddr_storage *dsa)
314 {
315 struct timeval to = { .tv_sec = TIMEOUT_SEC };
316 int fd, family = ssa->ss_family;
317 int salen = sockaddr_len(family);
318
319 fd = socket(family, SOCK_DGRAM, 0);
320 if (fd < 0)
321 return -1;
322
323 if (bind(fd, (struct sockaddr *)ssa, salen) < 0) {
324 perror("bind");
325 goto err;
326 }
327
328 if (do_connect && connect(fd, (struct sockaddr *)dsa, salen) < 0) {
329 perror("connect");
330 goto err;
331 }
332
333 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to)) < 0) {
334 perror("setsockopt(SO_RCVTIMEO)");
335 goto err;
336 }
337
338 if (!do_frag && set_pmtu_discover(fd, family == AF_INET) < 0) {
339 perror("set_pmtu_discover");
340 goto err;
341 }
342 return fd;
343
344 err:
345 close(fd);
346 return -1;
347 }
348
parse_route_rsp(struct rt_route_getroute_rsp * rsp,void * rtm_type)349 static void parse_route_rsp(struct rt_route_getroute_rsp *rsp, void *rtm_type)
350 {
351 *(uint8_t *)rtm_type = rsp->_hdr.rtm_type;
352 }
353
ip_route_check(const char * intf,int family,void * addr)354 static int ip_route_check(const char *intf, int family, void *addr)
355 {
356 uint8_t rtm_type, table = RT_TABLE_LOCAL;
357 int retries = MAX_RETRIES;
358
359 while (retries-- > 0) {
360 if (ip_route_get(intf, family, table, addr, parse_route_rsp,
361 &rtm_type) == 0 &&
362 rtm_type == RTN_LOCAL)
363 break;
364
365 usleep(TIMEOUT_USEC);
366 }
367
368 if (retries < 0)
369 return -1;
370
371 return 0;
372 }
373
send_gso_udp_msg(int socket,struct sockaddr_storage * addr,uint8_t * send_buf,int send_len,int gso_size)374 static int send_gso_udp_msg(int socket, struct sockaddr_storage *addr,
375 uint8_t *send_buf, int send_len, int gso_size)
376 {
377 char control[CMSG_SPACE(sizeof(uint16_t))] = { 0 };
378 int alen = sockaddr_len(addr->ss_family);
379 struct msghdr msg = { 0 };
380 struct iovec iov = { 0 };
381 int ret;
382
383 iov.iov_base = send_buf;
384 iov.iov_len = send_len;
385
386 msg.msg_iov = &iov;
387 msg.msg_iovlen = 1;
388 msg.msg_name = addr;
389 msg.msg_namelen = alen;
390
391 if (gso_size > 0) {
392 struct cmsghdr *cmsg;
393
394 msg.msg_control = control;
395 msg.msg_controllen = sizeof(control);
396
397 cmsg = CMSG_FIRSTHDR(&msg);
398 cmsg->cmsg_level = SOL_UDP;
399 cmsg->cmsg_type = UDP_SEGMENT;
400 cmsg->cmsg_len = CMSG_LEN(sizeof(uint16_t));
401 *(uint16_t *)CMSG_DATA(cmsg) = gso_size;
402 }
403
404 ret = sendmsg(socket, &msg, 0);
405 if (ret < 0)
406 perror("sendmsg");
407
408 return ret;
409 }
410
validate_hdrlen(uint8_t ** cur,int * len,int x)411 static int validate_hdrlen(uint8_t **cur, int *len, int x)
412 {
413 if (*len < x)
414 return -1;
415 *cur += x;
416 *len -= x;
417 return 0;
418 }
419
parse_udp_tunnel_vnet_packet(uint8_t * buf,int len,int tunnel_type,bool is_tap)420 static int parse_udp_tunnel_vnet_packet(uint8_t *buf, int len, int tunnel_type,
421 bool is_tap)
422 {
423 struct ipv6hdr *iph6;
424 struct udphdr *udph;
425 struct iphdr *iph4;
426 uint8_t *cur = buf;
427
428 if (validate_hdrlen(&cur, &len, TUN_VNET_TNL_SIZE))
429 return -1;
430
431 if (is_tap) {
432 if (validate_hdrlen(&cur, &len, ETH_HLEN))
433 return -1;
434 }
435
436 if (tunnel_type & UDP_TUNNEL_OUTER_IPV4) {
437 iph4 = (struct iphdr *)cur;
438 if (validate_hdrlen(&cur, &len, sizeof(struct iphdr)))
439 return -1;
440 if (iph4->version != 4 || iph4->protocol != IPPROTO_UDP)
441 return -1;
442 } else {
443 iph6 = (struct ipv6hdr *)cur;
444 if (validate_hdrlen(&cur, &len, sizeof(struct ipv6hdr)))
445 return -1;
446 if (iph6->version != 6 || iph6->nexthdr != IPPROTO_UDP)
447 return -1;
448 }
449
450 udph = (struct udphdr *)cur;
451 if (validate_hdrlen(&cur, &len, sizeof(struct udphdr)))
452 return -1;
453 if (ntohs(udph->dest) != VN_PORT)
454 return -1;
455
456 if (validate_hdrlen(&cur, &len, GENEVE_HLEN))
457 return -1;
458 if (validate_hdrlen(&cur, &len, ETH_HLEN))
459 return -1;
460
461 if (tunnel_type & UDP_TUNNEL_INNER_IPV4) {
462 iph4 = (struct iphdr *)cur;
463 if (validate_hdrlen(&cur, &len, sizeof(struct iphdr)))
464 return -1;
465 if (iph4->version != 4 || iph4->protocol != IPPROTO_UDP)
466 return -1;
467 } else {
468 iph6 = (struct ipv6hdr *)cur;
469 if (validate_hdrlen(&cur, &len, sizeof(struct ipv6hdr)))
470 return -1;
471 if (iph6->version != 6 || iph6->nexthdr != IPPROTO_UDP)
472 return -1;
473 }
474
475 udph = (struct udphdr *)cur;
476 if (validate_hdrlen(&cur, &len, sizeof(struct udphdr)))
477 return -1;
478 if (ntohs(udph->dest) != UDP_DST_PORT)
479 return -1;
480
481 return len;
482 }
483
FIXTURE(tun)484 FIXTURE(tun)
485 {
486 char ifname[IFNAMSIZ];
487 int fd, fd2;
488 };
489
FIXTURE_SETUP(tun)490 FIXTURE_SETUP(tun)
491 {
492 memset(self->ifname, 0, sizeof(self->ifname));
493
494 self->fd = tun_alloc(self->ifname);
495 ASSERT_GE(self->fd, 0);
496
497 self->fd2 = tun_alloc(self->ifname);
498 ASSERT_GE(self->fd2, 0);
499 }
500
FIXTURE_TEARDOWN(tun)501 FIXTURE_TEARDOWN(tun)
502 {
503 if (self->fd >= 0)
504 close(self->fd);
505 if (self->fd2 >= 0)
506 close(self->fd2);
507 }
508
TEST_F(tun,delete_detach_close)509 TEST_F(tun, delete_detach_close)
510 {
511 EXPECT_EQ(tun_delete(self->ifname), 0);
512 EXPECT_EQ(tun_detach(self->fd, self->ifname), -1);
513 EXPECT_EQ(errno, 22);
514 }
515
TEST_F(tun,detach_delete_close)516 TEST_F(tun, detach_delete_close)
517 {
518 EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
519 EXPECT_EQ(tun_delete(self->ifname), 0);
520 }
521
TEST_F(tun,detach_close_delete)522 TEST_F(tun, detach_close_delete)
523 {
524 EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
525 close(self->fd);
526 self->fd = -1;
527 EXPECT_EQ(tun_delete(self->ifname), 0);
528 }
529
TEST_F(tun,reattach_delete_close)530 TEST_F(tun, reattach_delete_close)
531 {
532 EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
533 EXPECT_EQ(tun_attach(self->fd, self->ifname), 0);
534 EXPECT_EQ(tun_delete(self->ifname), 0);
535 }
536
TEST_F(tun,reattach_close_delete)537 TEST_F(tun, reattach_close_delete)
538 {
539 EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
540 EXPECT_EQ(tun_attach(self->fd, self->ifname), 0);
541 close(self->fd);
542 self->fd = -1;
543 EXPECT_EQ(tun_delete(self->ifname), 0);
544 }
545
FIXTURE(tun_vnet_gso)546 FIXTURE(tun_vnet_gso)
547 {
548 char ifname[IFNAMSIZ];
549 int fd;
550 };
551
FIXTURE_SETUP(tun_vnet_gso)552 FIXTURE_SETUP(tun_vnet_gso)
553 {
554 int flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
555
556 memset(self->ifname, 0, sizeof(self->ifname));
557 self->fd = tun_open(self->ifname, flags, 0, 0, NULL);
558 ASSERT_GE(self->fd, 0);
559 }
560
FIXTURE_TEARDOWN(tun_vnet_gso)561 FIXTURE_TEARDOWN(tun_vnet_gso)
562 {
563 if (self->fd >= 0)
564 close(self->fd);
565 }
566
build_vlan_tcpv4_gso_packet(uint8_t * buf,int payload_len)567 static int build_vlan_tcpv4_gso_packet(uint8_t *buf, int payload_len)
568 {
569 uint16_t vlan_tag[2] = { htons(100), htons(ETH_P_IP) };
570 uint8_t *cur = buf + sizeof(struct virtio_net_hdr);
571 struct virtio_net_hdr vh = { 0 };
572 struct tcphdr tcph = { 0 };
573 uint32_t sum;
574
575 cur += build_eth(cur, ETH_P_8021Q, param_hwaddr_outer_src,
576 param_hwaddr_outer_dst);
577
578 /* 802.1Q tag: VID=100, inner protocol=ETH_P_IP */
579 memcpy(cur, vlan_tag, sizeof(vlan_tag));
580 cur += sizeof(vlan_tag);
581
582 cur += build_ipv4_header(cur, IPPROTO_TCP,
583 sizeof(tcph) + payload_len,
584 ¶m_ipaddr4_outer_src,
585 ¶m_ipaddr4_outer_dst);
586
587 tcph.source = htons(12345);
588 tcph.dest = htons(80);
589 tcph.seq = htonl(1);
590 tcph.doff = sizeof(tcph) / 4;
591 tcph.ack = 1;
592 tcph.window = htons(65535);
593 memcpy(cur, &tcph, sizeof(tcph));
594 memset(cur + sizeof(tcph), PKT_DATA, payload_len);
595
596 sum = add_csum((const uint8_t *)¶m_ipaddr4_outer_src,
597 sizeof(param_ipaddr4_outer_src));
598 sum += add_csum((const uint8_t *)¶m_ipaddr4_outer_dst,
599 sizeof(param_ipaddr4_outer_dst));
600 sum += htons(IPPROTO_TCP) + htons(sizeof(tcph) + payload_len);
601 sum += add_csum(cur, sizeof(tcph) + payload_len);
602 tcph.check = finish_ip_csum(sum);
603 memcpy(cur, &tcph, sizeof(tcph));
604 cur += sizeof(tcph) + payload_len;
605
606 vh.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
607 vh.gso_size = 1400;
608 vh.hdr_len = (cur - buf) - sizeof(vh) - payload_len;
609 memcpy(buf, &vh, sizeof(vh));
610
611 return cur - buf;
612 }
613
TEST_F(tun_vnet_gso,vlan_tcpv4_gso_no_csum)614 TEST_F(tun_vnet_gso, vlan_tcpv4_gso_no_csum)
615 {
616 struct virtio_net_hdr vh;
617 uint8_t pkt[4096] = { 0 };
618 int len, ret;
619
620 len = build_vlan_tcpv4_gso_packet(pkt, 2800);
621 memcpy(&vh, pkt, sizeof(vh));
622
623 /* Valid VLAN-tagged TCPv4 GSO with flags = 0 (no NEEDS_CSUM) */
624 vh.flags = 0;
625 memcpy(pkt, &vh, sizeof(vh));
626 ret = write(self->fd, pkt, len);
627 ASSERT_EQ(ret, len);
628
629 /* Valid VLAN-tagged TCPv4 GSO with flags = DATA_VALID */
630 vh.flags = VIRTIO_NET_HDR_F_DATA_VALID;
631 memcpy(pkt, &vh, sizeof(vh));
632 ret = write(self->fd, pkt, len);
633 ASSERT_EQ(ret, len);
634
635 /* Mismatched GSO type (TCPV6 on VLAN-tagged IPv4 packet) */
636 vh.flags = 0;
637 vh.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
638 memcpy(pkt, &vh, sizeof(vh));
639 ret = write(self->fd, pkt, len);
640 ASSERT_EQ(ret, -1);
641 ASSERT_EQ(errno, EINVAL);
642
643 /* TCP header truncated after 10 bytes, without NEEDS_CSUM.
644 * Requires the transport header offset found by flow dissection:
645 * pulling only sizeof(struct iphdr) + sizeof(struct tcphdr) bytes
646 * from the mac header would accept this frame.
647 */
648 vh.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
649 vh.hdr_len = ETH_HLEN + 4 + sizeof(struct iphdr) + 10;
650 memcpy(pkt, &vh, sizeof(vh));
651 ret = write(self->fd, pkt, sizeof(vh) + vh.hdr_len);
652 ASSERT_EQ(ret, -1);
653 ASSERT_EQ(errno, EINVAL);
654 }
655
TEST_F(tun_vnet_gso,vlan_tcpv4_gso_no_csum_64k)656 TEST_F(tun_vnet_gso, vlan_tcpv4_gso_no_csum_64k)
657 {
658 /* Ethernet frame of 65540 bytes: skb->len is above U16_MAX when the
659 * frame is flow-dissected, before eth_type_trans() pulls ETH_HLEN.
660 */
661 const int payload_len = 65540 - ETH_HLEN - 4 -
662 sizeof(struct iphdr) - sizeof(struct tcphdr);
663 struct virtio_net_hdr vh;
664 uint8_t *pkt;
665 int len, ret;
666
667 pkt = calloc(1, sizeof(vh) + 65540);
668 ASSERT_NE(pkt, NULL);
669
670 len = build_vlan_tcpv4_gso_packet(pkt, payload_len);
671 ASSERT_EQ(len, sizeof(vh) + 65540);
672 memcpy(&vh, pkt, sizeof(vh));
673
674 vh.flags = 0;
675 memcpy(pkt, &vh, sizeof(vh));
676 ret = write(self->fd, pkt, len);
677 free(pkt);
678 ASSERT_EQ(ret, len);
679 }
680
FIXTURE(tun_vnet_udptnl)681 FIXTURE(tun_vnet_udptnl)
682 {
683 char ifname[IFNAMSIZ];
684 int fd, sock;
685 };
686
FIXTURE_VARIANT(tun_vnet_udptnl)687 FIXTURE_VARIANT(tun_vnet_udptnl)
688 {
689 int tunnel_type;
690 int gso_size;
691 int data_size;
692 int r_num_mss;
693 bool is_tap, no_gso;
694 };
695
696 /* clang-format off */
697 #define TUN_VNET_UDPTNL_VARIANT_ADD(type, desc) \
698 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_nogsosz_1byte) { \
699 /* no GSO: send a single byte */ \
700 .tunnel_type = type, \
701 .data_size = 1, \
702 .r_num_mss = 1, \
703 .is_tap = true, \
704 .no_gso = true, \
705 }; \
706 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_nogsosz_1mss) { \
707 /* no GSO: send a single MSS, fall back to no GSO */ \
708 .tunnel_type = type, \
709 .data_size = UDP_TUNNEL_MSS(type), \
710 .r_num_mss = 1, \
711 .is_tap = true, \
712 .no_gso = true, \
713 }; \
714 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_nogsosz_gtmss) { \
715 /* no GSO: send a single MSS + 1B: fail */ \
716 .tunnel_type = type, \
717 .data_size = UDP_TUNNEL_MSS(type) + 1, \
718 .r_num_mss = 1, \
719 .is_tap = true, \
720 .no_gso = true, \
721 }; \
722 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_1byte) { \
723 /* GSO: send 1 byte, gso 1 byte, fall back to no GSO */ \
724 .tunnel_type = type, \
725 .gso_size = 1, \
726 .data_size = 1, \
727 .r_num_mss = 1, \
728 .is_tap = true, \
729 .no_gso = true, \
730 }; \
731 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_1mss) { \
732 /* send a single MSS: fall back to no GSO */ \
733 .tunnel_type = type, \
734 .gso_size = UDP_TUNNEL_MSS(type), \
735 .data_size = UDP_TUNNEL_MSS(type), \
736 .r_num_mss = 1, \
737 .is_tap = true, \
738 .no_gso = true, \
739 }; \
740 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_ltgso) { \
741 /* data <= MSS < gso: will fall back to no GSO */ \
742 .tunnel_type = type, \
743 .gso_size = UDP_TUNNEL_MSS(type) + 1, \
744 .data_size = UDP_TUNNEL_MSS(type), \
745 .r_num_mss = 1, \
746 .is_tap = true, \
747 .no_gso = true, \
748 }; \
749 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_gtgso) { \
750 /* GSO: a single MSS + 1B */ \
751 .tunnel_type = type, \
752 .gso_size = UDP_TUNNEL_MSS(type), \
753 .data_size = UDP_TUNNEL_MSS(type) + 1, \
754 .r_num_mss = 2, \
755 .is_tap = true, \
756 }; \
757 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_2mss) { \
758 /* no GSO: send exactly 2 MSS */ \
759 .tunnel_type = type, \
760 .gso_size = UDP_TUNNEL_MSS(type), \
761 .data_size = UDP_TUNNEL_MSS(type) * 2, \
762 .r_num_mss = 2, \
763 .is_tap = true, \
764 }; \
765 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_maxbytes) { \
766 /* GSO: send max bytes */ \
767 .tunnel_type = type, \
768 .gso_size = UDP_TUNNEL_MSS(type), \
769 .data_size = UDP_TUNNEL_MAX(type, true), \
770 .r_num_mss = UDP_TUNNEL_MAX(type, true) / \
771 UDP_TUNNEL_MSS(type) + 1, \
772 .is_tap = true, \
773 }; \
774 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_over_maxbytes) { \
775 /* GSO: send oversize max bytes: fail */ \
776 .tunnel_type = type, \
777 .gso_size = UDP_TUNNEL_MSS(type), \
778 .data_size = ETH_MAX_MTU, \
779 .r_num_mss = ETH_MAX_MTU / UDP_TUNNEL_MSS(type) + 1, \
780 .is_tap = true, \
781 }; \
782 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_maxsegs) { \
783 /* GSO: send max number of min sized segments */ \
784 .tunnel_type = type, \
785 .gso_size = 1, \
786 .data_size = UDP_TUNNEL_MAX_SEGMENTS, \
787 .r_num_mss = UDP_TUNNEL_MAX_SEGMENTS, \
788 .is_tap = true, \
789 }; \
790 FIXTURE_VARIANT_ADD(tun_vnet_udptnl, desc##_5byte) { \
791 /* GSO: send 5 bytes, gso 2 bytes */ \
792 .tunnel_type = type, \
793 .gso_size = 2, \
794 .data_size = 5, \
795 .r_num_mss = 3, \
796 .is_tap = true, \
797 } /* clang-format on */
798
799 TUN_VNET_UDPTNL_VARIANT_ADD(UDP_TUNNEL_GENEVE_4IN4, 4in4);
800 TUN_VNET_UDPTNL_VARIANT_ADD(UDP_TUNNEL_GENEVE_6IN4, 6in4);
801 TUN_VNET_UDPTNL_VARIANT_ADD(UDP_TUNNEL_GENEVE_4IN6, 4in6);
802 TUN_VNET_UDPTNL_VARIANT_ADD(UDP_TUNNEL_GENEVE_6IN6, 6in6);
803
assign_ifaddr_vars(int family,int is_outer,void ** srcip,void ** dstip,void ** srcmac,void ** dstmac)804 static void assign_ifaddr_vars(int family, int is_outer, void **srcip,
805 void **dstip, void **srcmac, void **dstmac)
806 {
807 if (is_outer) {
808 if (family == AF_INET) {
809 *srcip = (void *)¶m_ipaddr4_outer_src;
810 *dstip = (void *)¶m_ipaddr4_outer_dst;
811 } else {
812 *srcip = (void *)¶m_ipaddr6_outer_src;
813 *dstip = (void *)¶m_ipaddr6_outer_dst;
814 }
815 *srcmac = param_hwaddr_outer_src;
816 *dstmac = param_hwaddr_outer_dst;
817 } else {
818 if (family == AF_INET) {
819 *srcip = (void *)¶m_ipaddr4_inner_src;
820 *dstip = (void *)¶m_ipaddr4_inner_dst;
821 } else {
822 *srcip = (void *)¶m_ipaddr6_inner_src;
823 *dstip = (void *)¶m_ipaddr6_inner_dst;
824 }
825 *srcmac = param_hwaddr_inner_src;
826 *dstmac = param_hwaddr_inner_dst;
827 }
828 }
829
assign_sockaddr_vars(int family,int is_outer,struct sockaddr_storage * src,struct sockaddr_storage * dst)830 static void assign_sockaddr_vars(int family, int is_outer,
831 struct sockaddr_storage *src,
832 struct sockaddr_storage *dst)
833 {
834 src->ss_family = family;
835 dst->ss_family = family;
836
837 if (family == AF_INET) {
838 struct sockaddr_in *s4 = (struct sockaddr_in *)src;
839 struct sockaddr_in *d4 = (struct sockaddr_in *)dst;
840
841 s4->sin_addr = is_outer ? param_ipaddr4_outer_src :
842 param_ipaddr4_inner_src;
843 d4->sin_addr = is_outer ? param_ipaddr4_outer_dst :
844 param_ipaddr4_inner_dst;
845 if (!is_outer) {
846 s4->sin_port = htons(UDP_SRC_PORT);
847 d4->sin_port = htons(UDP_DST_PORT);
848 }
849 } else {
850 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)src;
851 struct sockaddr_in6 *d6 = (struct sockaddr_in6 *)dst;
852
853 s6->sin6_addr = is_outer ? param_ipaddr6_outer_src :
854 param_ipaddr6_inner_src;
855 d6->sin6_addr = is_outer ? param_ipaddr6_outer_dst :
856 param_ipaddr6_inner_dst;
857 if (!is_outer) {
858 s6->sin6_port = htons(UDP_SRC_PORT);
859 d6->sin6_port = htons(UDP_DST_PORT);
860 }
861 }
862 }
863
FIXTURE_SETUP(tun_vnet_udptnl)864 FIXTURE_SETUP(tun_vnet_udptnl)
865 {
866 int ret, family, prefix, flags, features;
867 int tunnel_type = variant->tunnel_type;
868 struct sockaddr_storage ssa, dsa;
869 void *sip, *dip, *smac, *dmac;
870
871 flags = (variant->is_tap ? IFF_TAP : IFF_TUN) | IFF_VNET_HDR |
872 IFF_MULTI_QUEUE | IFF_NO_PI;
873 features = TUN_F_CSUM | TUN_F_UDP_TUNNEL_GSO |
874 TUN_F_UDP_TUNNEL_GSO_CSUM | TUN_F_USO4 | TUN_F_USO6;
875 self->fd = tun_open(self->ifname, flags, TUN_VNET_TNL_SIZE, features,
876 param_hwaddr_outer_src);
877 ASSERT_GE(self->fd, 0);
878
879 family = (tunnel_type & UDP_TUNNEL_OUTER_IPV4) ? AF_INET : AF_INET6;
880 prefix = (family == AF_INET) ? IPPREFIX_LEN : IP6PREFIX_LEN;
881 assign_ifaddr_vars(family, 1, &sip, &dip, &smac, &dmac);
882
883 ret = ip_addr_add(self->ifname, family, sip, prefix);
884 ASSERT_EQ(ret, 0);
885 ret = ip_neigh_add(self->ifname, family, dip, dmac);
886 ASSERT_EQ(ret, 0);
887 ret = ip_route_check(self->ifname, family, sip);
888 ASSERT_EQ(ret, 0);
889
890 ret = geneve_create(param_dev_geneve_name, family, dip,
891 param_hwaddr_inner_src);
892 ASSERT_EQ(ret, 0);
893
894 family = (tunnel_type & UDP_TUNNEL_INNER_IPV4) ? AF_INET : AF_INET6;
895 prefix = (family == AF_INET) ? IPPREFIX_LEN : IP6PREFIX_LEN;
896 assign_ifaddr_vars(family, 0, &sip, &dip, &smac, &dmac);
897
898 ret = ip_addr_add(param_dev_geneve_name, family, sip, prefix);
899 ASSERT_EQ(ret, 0);
900 ret = ip_neigh_add(param_dev_geneve_name, family, dip, dmac);
901 ASSERT_EQ(ret, 0);
902 ret = ip_route_check(param_dev_geneve_name, family, sip);
903 ASSERT_EQ(ret, 0);
904
905 assign_sockaddr_vars(family, 0, &ssa, &dsa);
906 self->sock = udp_socket_open(&ssa, false, true, &dsa);
907 ASSERT_GE(self->sock, 0);
908 }
909
FIXTURE_TEARDOWN(tun_vnet_udptnl)910 FIXTURE_TEARDOWN(tun_vnet_udptnl)
911 {
912 int ret;
913
914 if (self->sock != -1)
915 close(self->sock);
916
917 ret = ip_link_del(param_dev_geneve_name);
918 EXPECT_EQ(ret, 0);
919
920 ret = tun_delete(self->ifname);
921 EXPECT_EQ(ret, 0);
922 }
923
build_gso_packet_into_tun(const FIXTURE_VARIANT (tun_vnet_udptnl)* variant,uint8_t * buf)924 static int build_gso_packet_into_tun(const FIXTURE_VARIANT(tun_vnet_udptnl) *
925 variant,
926 uint8_t *buf)
927 {
928 int pktlen, hlen, proto, inner_family, outer_family;
929 int tunnel_type = variant->tunnel_type;
930 int payload_len = variant->data_size;
931 int gso_size = variant->gso_size;
932 uint8_t *outer_udph, *cur = buf;
933 void *sip, *dip, *smac, *dmac;
934 bool is_tap = variant->is_tap;
935
936 hlen = (is_tap ? ETH_HLEN : 0) + UDP_TUNNEL_HDRLEN(tunnel_type);
937 inner_family = (tunnel_type & UDP_TUNNEL_INNER_IPV4) ? AF_INET :
938 AF_INET6;
939 outer_family = (tunnel_type & UDP_TUNNEL_OUTER_IPV4) ? AF_INET :
940 AF_INET6;
941
942 cur += build_virtio_net_hdr_v1_hash_tunnel(cur, is_tap, hlen, gso_size,
943 outer_family, inner_family);
944
945 pktlen = hlen + payload_len;
946 assign_ifaddr_vars(outer_family, 1, &sip, &dip, &smac, &dmac);
947
948 if (is_tap) {
949 proto = outer_family == AF_INET ? ETH_P_IP : ETH_P_IPV6;
950 pktlen -= ETH_HLEN;
951 cur += build_eth(cur, proto, dmac, smac);
952 }
953
954 if (outer_family == AF_INET) {
955 pktlen = pktlen - sizeof(struct iphdr);
956 cur += build_ipv4_header(cur, IPPROTO_UDP, pktlen, dip, sip);
957 } else {
958 pktlen = pktlen - sizeof(struct ipv6hdr);
959 cur += build_ipv6_header(cur, IPPROTO_UDP, 0, pktlen, dip, sip);
960 }
961
962 outer_udph = cur;
963 assign_ifaddr_vars(inner_family, 0, &sip, &dip, &smac, &dmac);
964
965 pktlen -= sizeof(struct udphdr);
966 proto = inner_family == AF_INET ? ETH_P_IP : ETH_P_IPV6;
967 cur += build_udp_header(cur, UDP_SRC_PORT, VN_PORT, pktlen);
968 cur += build_geneve_header(cur, VN_ID);
969 cur += build_eth(cur, proto, dmac, smac);
970
971 pktlen = sizeof(struct udphdr) + payload_len;
972 if (inner_family == AF_INET)
973 cur += build_ipv4_header(cur, IPPROTO_UDP, pktlen, dip, sip);
974 else
975 cur += build_ipv6_header(cur, IPPROTO_UDP, 0, pktlen, dip, sip);
976
977 cur += build_udp_packet(cur, UDP_DST_PORT, UDP_SRC_PORT, payload_len,
978 inner_family, false);
979
980 build_udp_packet_csum(outer_udph, outer_family, false);
981
982 return cur - buf;
983 }
984
985 static int
receive_gso_packet_from_tunnel(FIXTURE_DATA (tun_vnet_udptnl)* self,const FIXTURE_VARIANT (tun_vnet_udptnl)* variant,int * r_num_mss)986 receive_gso_packet_from_tunnel(FIXTURE_DATA(tun_vnet_udptnl) * self,
987 const FIXTURE_VARIANT(tun_vnet_udptnl) * variant,
988 int *r_num_mss)
989 {
990 uint8_t packet_buf[MAX_VNET_TUNNEL_PACKET_SZ];
991 int len, total_len = 0, socket = self->sock;
992 int payload_len = variant->data_size;
993
994 while (total_len < payload_len) {
995 len = recv(socket, packet_buf, sizeof(packet_buf), 0);
996 if (len <= 0) {
997 if (len < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
998 perror("recv");
999 break;
1000 }
1001
1002 (*r_num_mss)++;
1003 total_len += len;
1004 }
1005
1006 return total_len;
1007 }
1008
send_gso_packet_into_tunnel(FIXTURE_DATA (tun_vnet_udptnl)* self,const FIXTURE_VARIANT (tun_vnet_udptnl)* variant)1009 static int send_gso_packet_into_tunnel(FIXTURE_DATA(tun_vnet_udptnl) * self,
1010 const FIXTURE_VARIANT(tun_vnet_udptnl) *
1011 variant)
1012 {
1013 int family = (variant->tunnel_type & UDP_TUNNEL_INNER_IPV4) ? AF_INET :
1014 AF_INET6;
1015 uint8_t buf[MAX_VNET_TUNNEL_PACKET_SZ] = { 0 };
1016 int payload_len = variant->data_size;
1017 int gso_size = variant->gso_size;
1018 struct sockaddr_storage ssa, dsa;
1019
1020 assign_sockaddr_vars(family, 0, &ssa, &dsa);
1021 return send_gso_udp_msg(self->sock, &dsa, buf, payload_len, gso_size);
1022 }
1023
1024 static int
receive_gso_packet_from_tun(FIXTURE_DATA (tun_vnet_udptnl)* self,const FIXTURE_VARIANT (tun_vnet_udptnl)* variant,struct virtio_net_hdr_v1_hash_tunnel * vnet_hdr)1025 receive_gso_packet_from_tun(FIXTURE_DATA(tun_vnet_udptnl) * self,
1026 const FIXTURE_VARIANT(tun_vnet_udptnl) * variant,
1027 struct virtio_net_hdr_v1_hash_tunnel *vnet_hdr)
1028 {
1029 struct timeval timeout = { .tv_sec = TIMEOUT_SEC };
1030 uint8_t buf[MAX_VNET_TUNNEL_PACKET_SZ];
1031 int tunnel_type = variant->tunnel_type;
1032 int payload_len = variant->data_size;
1033 bool is_tap = variant->is_tap;
1034 int ret, len, total_len = 0;
1035 int tun_fd = self->fd;
1036 fd_set fdset;
1037
1038 while (total_len < payload_len) {
1039 FD_ZERO(&fdset);
1040 FD_SET(tun_fd, &fdset);
1041
1042 ret = select(tun_fd + 1, &fdset, NULL, NULL, &timeout);
1043 if (ret <= 0) {
1044 perror("select");
1045 break;
1046 }
1047 if (!FD_ISSET(tun_fd, &fdset))
1048 continue;
1049
1050 len = read(tun_fd, buf, sizeof(buf));
1051 if (len <= 0) {
1052 if (len < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1053 perror("read");
1054 break;
1055 }
1056
1057 len = parse_udp_tunnel_vnet_packet(buf, len, tunnel_type,
1058 is_tap);
1059 if (len < 0)
1060 continue;
1061
1062 if (total_len == 0)
1063 memcpy(vnet_hdr, buf, TUN_VNET_TNL_SIZE);
1064
1065 total_len += len;
1066 }
1067
1068 return total_len;
1069 }
1070
TEST_F(tun_vnet_udptnl,send_gso_packet)1071 TEST_F(tun_vnet_udptnl, send_gso_packet)
1072 {
1073 uint8_t pkt[MAX_VNET_TUNNEL_PACKET_SZ];
1074 int r_num_mss = 0;
1075 int ret, off;
1076
1077 memset(pkt, 0, sizeof(pkt));
1078 off = build_gso_packet_into_tun(variant, pkt);
1079 ret = write(self->fd, pkt, off);
1080 ASSERT_EQ(ret, off);
1081
1082 ret = receive_gso_packet_from_tunnel(self, variant, &r_num_mss);
1083 EXPECT_EQ(ret, variant->data_size);
1084 EXPECT_EQ(r_num_mss, variant->r_num_mss);
1085 }
1086
TEST_F(tun_vnet_udptnl,recv_gso_packet)1087 TEST_F(tun_vnet_udptnl, recv_gso_packet)
1088 {
1089 struct virtio_net_hdr_v1_hash_tunnel vnet_hdr = { 0 };
1090 struct virtio_net_hdr_v1 *vh = &vnet_hdr.hash_hdr.hdr;
1091 int ret, gso_type = VIRTIO_NET_HDR_GSO_UDP_L4;
1092
1093 ret = send_gso_packet_into_tunnel(self, variant);
1094 EXPECT_EQ(ret, variant->data_size);
1095
1096 memset(&vnet_hdr, 0, sizeof(vnet_hdr));
1097 ret = receive_gso_packet_from_tun(self, variant, &vnet_hdr);
1098 EXPECT_EQ(ret, variant->data_size);
1099
1100 if (!variant->no_gso) {
1101 EXPECT_EQ(vh->gso_size, variant->gso_size);
1102 gso_type |= (variant->tunnel_type & UDP_TUNNEL_OUTER_IPV4) ?
1103 (VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4) :
1104 (VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6);
1105 EXPECT_EQ(vh->gso_type, gso_type);
1106 }
1107 }
1108
1109 XFAIL_ADD(tun_vnet_udptnl, 4in4_nogsosz_gtmss, recv_gso_packet);
1110 XFAIL_ADD(tun_vnet_udptnl, 6in4_nogsosz_gtmss, recv_gso_packet);
1111 XFAIL_ADD(tun_vnet_udptnl, 4in6_nogsosz_gtmss, recv_gso_packet);
1112 XFAIL_ADD(tun_vnet_udptnl, 6in6_nogsosz_gtmss, recv_gso_packet);
1113
1114 XFAIL_ADD(tun_vnet_udptnl, 4in4_over_maxbytes, send_gso_packet);
1115 XFAIL_ADD(tun_vnet_udptnl, 6in4_over_maxbytes, send_gso_packet);
1116 XFAIL_ADD(tun_vnet_udptnl, 4in6_over_maxbytes, send_gso_packet);
1117 XFAIL_ADD(tun_vnet_udptnl, 6in6_over_maxbytes, send_gso_packet);
1118
1119 XFAIL_ADD(tun_vnet_udptnl, 4in4_over_maxbytes, recv_gso_packet);
1120 XFAIL_ADD(tun_vnet_udptnl, 6in4_over_maxbytes, recv_gso_packet);
1121 XFAIL_ADD(tun_vnet_udptnl, 4in6_over_maxbytes, recv_gso_packet);
1122 XFAIL_ADD(tun_vnet_udptnl, 6in6_over_maxbytes, recv_gso_packet);
1123
1124 TEST_HARNESS_MAIN
1125