xref: /linux/tools/testing/selftests/net/tuntap_helpers.h (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1*a942fcd7SXu Du /* SPDX-License-Identifier: GPL-2.0-only */
2*a942fcd7SXu Du 
3*a942fcd7SXu Du #ifndef _TUNTAP_HELPERS_H
4*a942fcd7SXu Du #define _TUNTAP_HELPERS_H
5*a942fcd7SXu Du 
6*a942fcd7SXu Du #include <errno.h>
7*a942fcd7SXu Du #include <linux/if_packet.h>
8*a942fcd7SXu Du #include <linux/ipv6.h>
9*a942fcd7SXu Du #include <linux/virtio_net.h>
10*a942fcd7SXu Du #include <netinet/in.h>
11*a942fcd7SXu Du #include <netinet/if_ether.h>
12*a942fcd7SXu Du #include <netinet/udp.h>
13*a942fcd7SXu Du #include <stdio.h>
14*a942fcd7SXu Du #include <stdlib.h>
15*a942fcd7SXu Du #include <string.h>
16*a942fcd7SXu Du #include <unistd.h>
17*a942fcd7SXu Du #include <ynl.h>
18*a942fcd7SXu Du 
19*a942fcd7SXu Du #include "rt-route-user.h"
20*a942fcd7SXu Du #include "rt-addr-user.h"
21*a942fcd7SXu Du #include "rt-neigh-user.h"
22*a942fcd7SXu Du #include "rt-link-user.h"
23*a942fcd7SXu Du 
24*a942fcd7SXu Du #define GENEVE_HLEN 8
25*a942fcd7SXu Du #define PKT_DATA 0xCB
26*a942fcd7SXu Du #define TUNTAP_DEFAULT_TTL 8
27*a942fcd7SXu Du #define TUNTAP_DEFAULT_IPID 1337
28*a942fcd7SXu Du 
29*a942fcd7SXu Du unsigned int if_nametoindex(const char *ifname);
30*a942fcd7SXu Du 
31*a942fcd7SXu Du static inline int ip_addr_len(int family)
32*a942fcd7SXu Du {
33*a942fcd7SXu Du 	return (family == AF_INET) ? sizeof(struct in_addr) :
34*a942fcd7SXu Du 				     sizeof(struct in6_addr);
35*a942fcd7SXu Du }
36*a942fcd7SXu Du 
37*a942fcd7SXu Du static inline void fill_ifaddr_msg(struct ifaddrmsg *ifam, int family,
38*a942fcd7SXu Du 				   int prefix, int flags, const char *dev)
39*a942fcd7SXu Du {
40*a942fcd7SXu Du 	ifam->ifa_family = family;
41*a942fcd7SXu Du 	ifam->ifa_prefixlen = prefix;
42*a942fcd7SXu Du 	ifam->ifa_index = if_nametoindex(dev);
43*a942fcd7SXu Du 	ifam->ifa_flags = flags;
44*a942fcd7SXu Du 	ifam->ifa_scope = RT_SCOPE_UNIVERSE;
45*a942fcd7SXu Du }
46*a942fcd7SXu Du 
47*a942fcd7SXu Du static inline int ip_addr_add(const char *dev, int family, void *addr,
48*a942fcd7SXu Du 			      uint8_t prefix)
49*a942fcd7SXu Du {
50*a942fcd7SXu Du 	int nl_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
51*a942fcd7SXu Du 	int ifa_flags = IFA_F_PERMANENT | IFA_F_NODAD;
52*a942fcd7SXu Du 	int ret = -1, ipalen = ip_addr_len(family);
53*a942fcd7SXu Du 	struct rt_addr_newaddr_req *req;
54*a942fcd7SXu Du 	struct ynl_sock *ys;
55*a942fcd7SXu Du 
56*a942fcd7SXu Du 	ys = ynl_sock_create(&ynl_rt_addr_family, NULL);
57*a942fcd7SXu Du 	if (!ys)
58*a942fcd7SXu Du 		return -1;
59*a942fcd7SXu Du 
60*a942fcd7SXu Du 	req = rt_addr_newaddr_req_alloc();
61*a942fcd7SXu Du 	if (!req)
62*a942fcd7SXu Du 		goto err_req_alloc;
63*a942fcd7SXu Du 
64*a942fcd7SXu Du 	fill_ifaddr_msg(&req->_hdr, family, prefix, ifa_flags, dev);
65*a942fcd7SXu Du 	rt_addr_newaddr_req_set_nlflags(req, nl_flags);
66*a942fcd7SXu Du 	rt_addr_newaddr_req_set_local(req, addr, ipalen);
67*a942fcd7SXu Du 
68*a942fcd7SXu Du 	ret = rt_addr_newaddr(ys, req);
69*a942fcd7SXu Du 	rt_addr_newaddr_req_free(req);
70*a942fcd7SXu Du err_req_alloc:
71*a942fcd7SXu Du 	ynl_sock_destroy(ys);
72*a942fcd7SXu Du 	return ret;
73*a942fcd7SXu Du }
74*a942fcd7SXu Du 
75*a942fcd7SXu Du static inline void fill_neigh_req_header(struct ndmsg *ndm, int family,
76*a942fcd7SXu Du 					 int state, const char *dev)
77*a942fcd7SXu Du {
78*a942fcd7SXu Du 	ndm->ndm_family = family;
79*a942fcd7SXu Du 	ndm->ndm_ifindex = if_nametoindex(dev);
80*a942fcd7SXu Du 	ndm->ndm_state = state;
81*a942fcd7SXu Du 	ndm->ndm_flags = 0;
82*a942fcd7SXu Du 	ndm->ndm_type = RTN_UNICAST;
83*a942fcd7SXu Du }
84*a942fcd7SXu Du 
85*a942fcd7SXu Du static inline int ip_neigh_add(const char *dev, int family, void *addr,
86*a942fcd7SXu Du 			       unsigned char *lladdr)
87*a942fcd7SXu Du {
88*a942fcd7SXu Du 	int nl_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
89*a942fcd7SXu Du 	int ret = -1, ipalen = ip_addr_len(family);
90*a942fcd7SXu Du 	struct rt_neigh_newneigh_req *req;
91*a942fcd7SXu Du 	struct ynl_sock *ys;
92*a942fcd7SXu Du 
93*a942fcd7SXu Du 	ys = ynl_sock_create(&ynl_rt_neigh_family, NULL);
94*a942fcd7SXu Du 	if (!ys)
95*a942fcd7SXu Du 		return -1;
96*a942fcd7SXu Du 
97*a942fcd7SXu Du 	req = rt_neigh_newneigh_req_alloc();
98*a942fcd7SXu Du 	if (!req)
99*a942fcd7SXu Du 		goto err_req_alloc;
100*a942fcd7SXu Du 
101*a942fcd7SXu Du 	fill_neigh_req_header(&req->_hdr, family, NUD_PERMANENT, dev);
102*a942fcd7SXu Du 	rt_neigh_newneigh_req_set_nlflags(req, nl_flags);
103*a942fcd7SXu Du 	rt_neigh_newneigh_req_set_dst(req, addr, ipalen);
104*a942fcd7SXu Du 	rt_neigh_newneigh_req_set_lladdr(req, lladdr, ETH_ALEN);
105*a942fcd7SXu Du 	rt_neigh_newneigh_req_set_ifindex(req, if_nametoindex(dev));
106*a942fcd7SXu Du 
107*a942fcd7SXu Du 	ret = rt_neigh_newneigh(ys, req);
108*a942fcd7SXu Du 	rt_neigh_newneigh_req_free(req);
109*a942fcd7SXu Du err_req_alloc:
110*a942fcd7SXu Du 	ynl_sock_destroy(ys);
111*a942fcd7SXu Du 	return ret;
112*a942fcd7SXu Du }
113*a942fcd7SXu Du 
114*a942fcd7SXu Du static inline void fill_route_req_header(struct rtmsg *rtm, int family,
115*a942fcd7SXu Du 					 int table)
116*a942fcd7SXu Du {
117*a942fcd7SXu Du 	rtm->rtm_family = family;
118*a942fcd7SXu Du 	rtm->rtm_table = table;
119*a942fcd7SXu Du }
120*a942fcd7SXu Du 
121*a942fcd7SXu Du static inline int
122*a942fcd7SXu Du ip_route_get(const char *dev, int family, int table, void *dst,
123*a942fcd7SXu Du 	     void (*parse_rsp)(struct rt_route_getroute_rsp *rsp, void *out),
124*a942fcd7SXu Du 	     void *out)
125*a942fcd7SXu Du {
126*a942fcd7SXu Du 	int ret = -1, ipalen = ip_addr_len(family);
127*a942fcd7SXu Du 	struct rt_route_getroute_req *req;
128*a942fcd7SXu Du 	struct rt_route_getroute_rsp *rsp;
129*a942fcd7SXu Du 	struct ynl_sock *ys;
130*a942fcd7SXu Du 
131*a942fcd7SXu Du 	ys = ynl_sock_create(&ynl_rt_route_family, NULL);
132*a942fcd7SXu Du 	if (!ys)
133*a942fcd7SXu Du 		return -1;
134*a942fcd7SXu Du 
135*a942fcd7SXu Du 	req = rt_route_getroute_req_alloc();
136*a942fcd7SXu Du 	if (!req)
137*a942fcd7SXu Du 		goto err_req_alloc;
138*a942fcd7SXu Du 
139*a942fcd7SXu Du 	fill_route_req_header(&req->_hdr, family, table);
140*a942fcd7SXu Du 	rt_route_getroute_req_set_nlflags(req, NLM_F_REQUEST);
141*a942fcd7SXu Du 	rt_route_getroute_req_set_dst(req, dst, ipalen);
142*a942fcd7SXu Du 	rt_route_getroute_req_set_oif(req, if_nametoindex(dev));
143*a942fcd7SXu Du 
144*a942fcd7SXu Du 	rsp = rt_route_getroute(ys, req);
145*a942fcd7SXu Du 	if (!rsp)
146*a942fcd7SXu Du 		goto err_rsp_get;
147*a942fcd7SXu Du 
148*a942fcd7SXu Du 	ret = 0;
149*a942fcd7SXu Du 	if (parse_rsp)
150*a942fcd7SXu Du 		parse_rsp(rsp, out);
151*a942fcd7SXu Du 
152*a942fcd7SXu Du 	rt_route_getroute_rsp_free(rsp);
153*a942fcd7SXu Du err_rsp_get:
154*a942fcd7SXu Du 	rt_route_getroute_req_free(req);
155*a942fcd7SXu Du err_req_alloc:
156*a942fcd7SXu Du 	ynl_sock_destroy(ys);
157*a942fcd7SXu Du 	return ret;
158*a942fcd7SXu Du }
159*a942fcd7SXu Du 
160*a942fcd7SXu Du static inline int
161*a942fcd7SXu Du ip_link_add(const char *dev, char *link_type,
162*a942fcd7SXu Du 	    int (*fill_link_attr)(struct rt_link_newlink_req *req, void *data),
163*a942fcd7SXu Du 	    void *data)
164*a942fcd7SXu Du {
165*a942fcd7SXu Du 	int nl_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
166*a942fcd7SXu Du 	struct rt_link_newlink_req *req;
167*a942fcd7SXu Du 	struct ynl_sock *ys;
168*a942fcd7SXu Du 	int ret = -1;
169*a942fcd7SXu Du 
170*a942fcd7SXu Du 	ys = ynl_sock_create(&ynl_rt_link_family, NULL);
171*a942fcd7SXu Du 	if (!ys)
172*a942fcd7SXu Du 		return -1;
173*a942fcd7SXu Du 
174*a942fcd7SXu Du 	req = rt_link_newlink_req_alloc();
175*a942fcd7SXu Du 	if (!req)
176*a942fcd7SXu Du 		goto err_req_alloc;
177*a942fcd7SXu Du 
178*a942fcd7SXu Du 	req->_hdr.ifi_flags = IFF_UP;
179*a942fcd7SXu Du 	rt_link_newlink_req_set_nlflags(req, nl_flags);
180*a942fcd7SXu Du 	rt_link_newlink_req_set_ifname(req, dev);
181*a942fcd7SXu Du 	rt_link_newlink_req_set_linkinfo_kind(req, link_type);
182*a942fcd7SXu Du 
183*a942fcd7SXu Du 	if (fill_link_attr && fill_link_attr(req, data) < 0)
184*a942fcd7SXu Du 		goto err_attr_fill;
185*a942fcd7SXu Du 
186*a942fcd7SXu Du 	ret = rt_link_newlink(ys, req);
187*a942fcd7SXu Du err_attr_fill:
188*a942fcd7SXu Du 	rt_link_newlink_req_free(req);
189*a942fcd7SXu Du err_req_alloc:
190*a942fcd7SXu Du 	ynl_sock_destroy(ys);
191*a942fcd7SXu Du 	return ret;
192*a942fcd7SXu Du }
193*a942fcd7SXu Du 
194*a942fcd7SXu Du static inline int ip_link_del(const char *dev)
195*a942fcd7SXu Du {
196*a942fcd7SXu Du 	struct rt_link_dellink_req *req;
197*a942fcd7SXu Du 	struct ynl_sock *ys;
198*a942fcd7SXu Du 	int ret = -1;
199*a942fcd7SXu Du 
200*a942fcd7SXu Du 	ys = ynl_sock_create(&ynl_rt_link_family, NULL);
201*a942fcd7SXu Du 	if (!ys)
202*a942fcd7SXu Du 		return -1;
203*a942fcd7SXu Du 
204*a942fcd7SXu Du 	req = rt_link_dellink_req_alloc();
205*a942fcd7SXu Du 	if (!req)
206*a942fcd7SXu Du 		goto err_req_alloc;
207*a942fcd7SXu Du 
208*a942fcd7SXu Du 	rt_link_dellink_req_set_nlflags(req, NLM_F_REQUEST);
209*a942fcd7SXu Du 	rt_link_dellink_req_set_ifname(req, dev);
210*a942fcd7SXu Du 
211*a942fcd7SXu Du 	ret = rt_link_dellink(ys, req);
212*a942fcd7SXu Du 	rt_link_dellink_req_free(req);
213*a942fcd7SXu Du err_req_alloc:
214*a942fcd7SXu Du 	ynl_sock_destroy(ys);
215*a942fcd7SXu Du 	return ret;
216*a942fcd7SXu Du }
217*a942fcd7SXu Du 
218*a942fcd7SXu Du static inline size_t build_eth(uint8_t *buf, uint16_t proto, unsigned char *src,
219*a942fcd7SXu Du 			       unsigned char *dest)
220*a942fcd7SXu Du {
221*a942fcd7SXu Du 	struct ethhdr *eth = (struct ethhdr *)buf;
222*a942fcd7SXu Du 
223*a942fcd7SXu Du 	eth->h_proto = htons(proto);
224*a942fcd7SXu Du 	memcpy(eth->h_source, src, ETH_ALEN);
225*a942fcd7SXu Du 	memcpy(eth->h_dest, dest, ETH_ALEN);
226*a942fcd7SXu Du 
227*a942fcd7SXu Du 	return ETH_HLEN;
228*a942fcd7SXu Du }
229*a942fcd7SXu Du 
230*a942fcd7SXu Du static inline uint32_t add_csum(const uint8_t *buf, int len)
231*a942fcd7SXu Du {
232*a942fcd7SXu Du 	uint16_t *sbuf = (uint16_t *)buf;
233*a942fcd7SXu Du 	uint32_t sum = 0;
234*a942fcd7SXu Du 
235*a942fcd7SXu Du 	while (len > 1) {
236*a942fcd7SXu Du 		sum += *sbuf++;
237*a942fcd7SXu Du 		len -= 2;
238*a942fcd7SXu Du 	}
239*a942fcd7SXu Du 
240*a942fcd7SXu Du 	if (len)
241*a942fcd7SXu Du 		sum += *(uint8_t *)sbuf;
242*a942fcd7SXu Du 
243*a942fcd7SXu Du 	return sum;
244*a942fcd7SXu Du }
245*a942fcd7SXu Du 
246*a942fcd7SXu Du static inline uint16_t finish_ip_csum(uint32_t sum)
247*a942fcd7SXu Du {
248*a942fcd7SXu Du 	while (sum >> 16)
249*a942fcd7SXu Du 		sum = (sum & 0xffff) + (sum >> 16);
250*a942fcd7SXu Du 	return ~((uint16_t)sum);
251*a942fcd7SXu Du }
252*a942fcd7SXu Du 
253*a942fcd7SXu Du static inline uint16_t build_ip_csum(const uint8_t *buf, int len, uint32_t sum)
254*a942fcd7SXu Du {
255*a942fcd7SXu Du 	sum += add_csum(buf, len);
256*a942fcd7SXu Du 	return finish_ip_csum(sum);
257*a942fcd7SXu Du }
258*a942fcd7SXu Du 
259*a942fcd7SXu Du static inline int build_ipv4_header(uint8_t *buf, uint8_t proto,
260*a942fcd7SXu Du 				    int payload_len, struct in_addr *src,
261*a942fcd7SXu Du 				    struct in_addr *dst)
262*a942fcd7SXu Du {
263*a942fcd7SXu Du 	struct iphdr *iph = (struct iphdr *)buf;
264*a942fcd7SXu Du 
265*a942fcd7SXu Du 	iph->ihl = 5;
266*a942fcd7SXu Du 	iph->version = 4;
267*a942fcd7SXu Du 	iph->ttl = TUNTAP_DEFAULT_TTL;
268*a942fcd7SXu Du 	iph->tot_len = htons(sizeof(*iph) + payload_len);
269*a942fcd7SXu Du 	iph->id = htons(TUNTAP_DEFAULT_IPID);
270*a942fcd7SXu Du 	iph->protocol = proto;
271*a942fcd7SXu Du 	iph->saddr = src->s_addr;
272*a942fcd7SXu Du 	iph->daddr = dst->s_addr;
273*a942fcd7SXu Du 	iph->check = build_ip_csum(buf, iph->ihl << 2, 0);
274*a942fcd7SXu Du 
275*a942fcd7SXu Du 	return iph->ihl << 2;
276*a942fcd7SXu Du }
277*a942fcd7SXu Du 
278*a942fcd7SXu Du static inline void ipv6_set_dsfield(struct ipv6hdr *ip6h, uint8_t dsfield)
279*a942fcd7SXu Du {
280*a942fcd7SXu Du 	uint16_t val, *ptr = (uint16_t *)ip6h;
281*a942fcd7SXu Du 
282*a942fcd7SXu Du 	val = ntohs(*ptr);
283*a942fcd7SXu Du 	val &= 0xF00F;
284*a942fcd7SXu Du 	val |= ((uint16_t)dsfield) << 4;
285*a942fcd7SXu Du 	*ptr = htons(val);
286*a942fcd7SXu Du }
287*a942fcd7SXu Du 
288*a942fcd7SXu Du static inline int build_ipv6_header(uint8_t *buf, uint8_t proto,
289*a942fcd7SXu Du 				    uint8_t dsfield, int payload_len,
290*a942fcd7SXu Du 				    struct in6_addr *src, struct in6_addr *dst)
291*a942fcd7SXu Du {
292*a942fcd7SXu Du 	struct ipv6hdr *ip6h = (struct ipv6hdr *)buf;
293*a942fcd7SXu Du 
294*a942fcd7SXu Du 	ip6h->version = 6;
295*a942fcd7SXu Du 	ip6h->payload_len = htons(payload_len);
296*a942fcd7SXu Du 	ip6h->nexthdr = proto;
297*a942fcd7SXu Du 	ip6h->hop_limit = TUNTAP_DEFAULT_TTL;
298*a942fcd7SXu Du 	ipv6_set_dsfield(ip6h, dsfield);
299*a942fcd7SXu Du 	memcpy(&ip6h->saddr, src, sizeof(ip6h->saddr));
300*a942fcd7SXu Du 	memcpy(&ip6h->daddr, dst, sizeof(ip6h->daddr));
301*a942fcd7SXu Du 
302*a942fcd7SXu Du 	return sizeof(struct ipv6hdr);
303*a942fcd7SXu Du }
304*a942fcd7SXu Du 
305*a942fcd7SXu Du static inline int build_geneve_header(uint8_t *buf, uint32_t vni)
306*a942fcd7SXu Du {
307*a942fcd7SXu Du 	uint16_t protocol = htons(ETH_P_TEB);
308*a942fcd7SXu Du 	uint32_t geneve_vni = htonl((vni << 8) & 0xffffff00);
309*a942fcd7SXu Du 
310*a942fcd7SXu Du 	memcpy(buf + 2, &protocol, 2);
311*a942fcd7SXu Du 	memcpy(buf + 4, &geneve_vni, 4);
312*a942fcd7SXu Du 	return GENEVE_HLEN;
313*a942fcd7SXu Du }
314*a942fcd7SXu Du 
315*a942fcd7SXu Du static inline int build_udp_header(uint8_t *buf, uint16_t sport, uint16_t dport,
316*a942fcd7SXu Du 				   int payload_len)
317*a942fcd7SXu Du {
318*a942fcd7SXu Du 	struct udphdr *udph = (struct udphdr *)buf;
319*a942fcd7SXu Du 
320*a942fcd7SXu Du 	udph->source = htons(sport);
321*a942fcd7SXu Du 	udph->dest = htons(dport);
322*a942fcd7SXu Du 	udph->len = htons(sizeof(*udph) + payload_len);
323*a942fcd7SXu Du 	return sizeof(*udph);
324*a942fcd7SXu Du }
325*a942fcd7SXu Du 
326*a942fcd7SXu Du static inline void build_udp_packet_csum(uint8_t *buf, int family,
327*a942fcd7SXu Du 					 bool csum_off)
328*a942fcd7SXu Du {
329*a942fcd7SXu Du 	struct udphdr *udph = (struct udphdr *)buf;
330*a942fcd7SXu Du 	size_t ipalen = ip_addr_len(family);
331*a942fcd7SXu Du 	uint32_t sum;
332*a942fcd7SXu Du 
333*a942fcd7SXu Du 	/* No extension IPv4 and IPv6 headers addresses are the last fields */
334*a942fcd7SXu Du 	sum = add_csum(buf - 2 * ipalen, 2 * ipalen);
335*a942fcd7SXu Du 	sum += htons(IPPROTO_UDP) + udph->len;
336*a942fcd7SXu Du 
337*a942fcd7SXu Du 	if (!csum_off)
338*a942fcd7SXu Du 		sum += add_csum(buf, udph->len);
339*a942fcd7SXu Du 
340*a942fcd7SXu Du 	udph->check = finish_ip_csum(sum);
341*a942fcd7SXu Du }
342*a942fcd7SXu Du 
343*a942fcd7SXu Du static inline int build_udp_packet(uint8_t *buf, uint16_t sport, uint16_t dport,
344*a942fcd7SXu Du 				   int payload_len, int family, bool csum_off)
345*a942fcd7SXu Du {
346*a942fcd7SXu Du 	struct udphdr *udph = (struct udphdr *)buf;
347*a942fcd7SXu Du 
348*a942fcd7SXu Du 	build_udp_header(buf, sport, dport, payload_len);
349*a942fcd7SXu Du 	memset(buf + sizeof(*udph), PKT_DATA, payload_len);
350*a942fcd7SXu Du 	build_udp_packet_csum(buf, family, csum_off);
351*a942fcd7SXu Du 
352*a942fcd7SXu Du 	return sizeof(*udph) + payload_len;
353*a942fcd7SXu Du }
354*a942fcd7SXu Du 
355*a942fcd7SXu Du static inline int build_virtio_net_hdr_v1_hash_tunnel(uint8_t *buf, bool is_tap,
356*a942fcd7SXu Du 						      int hdr_len, int gso_size,
357*a942fcd7SXu Du 						      int outer_family,
358*a942fcd7SXu Du 						      int inner_family)
359*a942fcd7SXu Du {
360*a942fcd7SXu Du 	struct virtio_net_hdr_v1_hash_tunnel *vh_tunnel = (void *)buf;
361*a942fcd7SXu Du 	struct virtio_net_hdr_v1 *vh = &vh_tunnel->hash_hdr.hdr;
362*a942fcd7SXu Du 	int outer_iphlen, inner_iphlen, eth_hlen, gso_type;
363*a942fcd7SXu Du 
364*a942fcd7SXu Du 	eth_hlen = is_tap ? ETH_HLEN : 0;
365*a942fcd7SXu Du 	outer_iphlen = (outer_family == AF_INET) ? sizeof(struct iphdr) :
366*a942fcd7SXu Du 						   sizeof(struct ipv6hdr);
367*a942fcd7SXu Du 	inner_iphlen = (inner_family == AF_INET) ? sizeof(struct iphdr) :
368*a942fcd7SXu Du 						   sizeof(struct ipv6hdr);
369*a942fcd7SXu Du 
370*a942fcd7SXu Du 	vh_tunnel->outer_th_offset = eth_hlen + outer_iphlen;
371*a942fcd7SXu Du 	vh_tunnel->inner_nh_offset = vh_tunnel->outer_th_offset + ETH_HLEN +
372*a942fcd7SXu Du 				     GENEVE_HLEN + sizeof(struct udphdr);
373*a942fcd7SXu Du 
374*a942fcd7SXu Du 	vh->csum_start = vh_tunnel->inner_nh_offset + inner_iphlen;
375*a942fcd7SXu Du 	vh->csum_offset = __builtin_offsetof(struct udphdr, check);
376*a942fcd7SXu Du 	vh->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
377*a942fcd7SXu Du 	vh->hdr_len = hdr_len;
378*a942fcd7SXu Du 	vh->gso_size = gso_size;
379*a942fcd7SXu Du 
380*a942fcd7SXu Du 	if (gso_size) {
381*a942fcd7SXu Du 		gso_type = outer_family == AF_INET ?
382*a942fcd7SXu Du 				   VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4 :
383*a942fcd7SXu Du 				   VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6;
384*a942fcd7SXu Du 		vh->gso_type = VIRTIO_NET_HDR_GSO_UDP_L4 | gso_type;
385*a942fcd7SXu Du 	}
386*a942fcd7SXu Du 
387*a942fcd7SXu Du 	return sizeof(struct virtio_net_hdr_v1_hash_tunnel);
388*a942fcd7SXu Du }
389*a942fcd7SXu Du 
390*a942fcd7SXu Du #endif /* _TUNTAP_HELPERS_H */
391