ioam6_iptunnel.c (7b34e449e05e452772d3120e1bb2559d0c8fc5b0) ioam6_iptunnel.c (8cb3bf8bff3c47e171f6b66f9ccfc3f1451a11a2)
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * IPv6 IOAM Lightweight Tunnel implementation
4 *
5 * Author:
6 * Justin Iurman <justin.iurman@uliege.be>
7 */
8
9#include <linux/kernel.h>
10#include <linux/skbuff.h>
11#include <linux/net.h>
12#include <linux/in6.h>
13#include <linux/ioam6.h>
14#include <linux/ioam6_iptunnel.h>
15#include <net/dst.h>
16#include <net/sock.h>
17#include <net/lwtunnel.h>
18#include <net/ioam6.h>
19#include <net/netlink.h>
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * IPv6 IOAM Lightweight Tunnel implementation
4 *
5 * Author:
6 * Justin Iurman <justin.iurman@uliege.be>
7 */
8
9#include <linux/kernel.h>
10#include <linux/skbuff.h>
11#include <linux/net.h>
12#include <linux/in6.h>
13#include <linux/ioam6.h>
14#include <linux/ioam6_iptunnel.h>
15#include <net/dst.h>
16#include <net/sock.h>
17#include <net/lwtunnel.h>
18#include <net/ioam6.h>
19#include <net/netlink.h>
20#include <net/ipv6.h>
21#include <net/dst_cache.h>
22#include <net/ip6_route.h>
23#include <net/addrconf.h>
20
21#define IOAM6_MASK_SHORT_FIELDS 0xff100000
22#define IOAM6_MASK_WIDE_FIELDS 0xe00000
23
24struct ioam6_lwt_encap {
25 struct ipv6_hopopt_hdr eh;
26 u8 pad[2]; /* 2-octet padding for 4n-alignment */
27 struct ioam6_hdr ioamh;
28 struct ioam6_trace_hdr traceh;
29} __packed;
30
31struct ioam6_lwt {
24
25#define IOAM6_MASK_SHORT_FIELDS 0xff100000
26#define IOAM6_MASK_WIDE_FIELDS 0xe00000
27
28struct ioam6_lwt_encap {
29 struct ipv6_hopopt_hdr eh;
30 u8 pad[2]; /* 2-octet padding for 4n-alignment */
31 struct ioam6_hdr ioamh;
32 struct ioam6_trace_hdr traceh;
33} __packed;
34
35struct ioam6_lwt {
36 struct dst_cache cache;
37 u8 mode;
38 struct in6_addr tundst;
32 struct ioam6_lwt_encap tuninfo;
33};
34
35static struct ioam6_lwt *ioam6_lwt_state(struct lwtunnel_state *lwt)
36{
37 return (struct ioam6_lwt *)lwt->data;
38}
39
40static struct ioam6_lwt_encap *ioam6_lwt_info(struct lwtunnel_state *lwt)
41{
42 return &ioam6_lwt_state(lwt)->tuninfo;
43}
44
45static struct ioam6_trace_hdr *ioam6_lwt_trace(struct lwtunnel_state *lwt)
46{
47 return &(ioam6_lwt_state(lwt)->tuninfo.traceh);
48}
49
50static const struct nla_policy ioam6_iptunnel_policy[IOAM6_IPTUNNEL_MAX + 1] = {
39 struct ioam6_lwt_encap tuninfo;
40};
41
42static struct ioam6_lwt *ioam6_lwt_state(struct lwtunnel_state *lwt)
43{
44 return (struct ioam6_lwt *)lwt->data;
45}
46
47static struct ioam6_lwt_encap *ioam6_lwt_info(struct lwtunnel_state *lwt)
48{
49 return &ioam6_lwt_state(lwt)->tuninfo;
50}
51
52static struct ioam6_trace_hdr *ioam6_lwt_trace(struct lwtunnel_state *lwt)
53{
54 return &(ioam6_lwt_state(lwt)->tuninfo.traceh);
55}
56
57static const struct nla_policy ioam6_iptunnel_policy[IOAM6_IPTUNNEL_MAX + 1] = {
58 [IOAM6_IPTUNNEL_MODE] = NLA_POLICY_RANGE(NLA_U8,
59 IOAM6_IPTUNNEL_MODE_MIN,
60 IOAM6_IPTUNNEL_MODE_MAX),
61 [IOAM6_IPTUNNEL_DST] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
51 [IOAM6_IPTUNNEL_TRACE] = NLA_POLICY_EXACT_LEN(sizeof(struct ioam6_trace_hdr)),
52};
53
54static bool ioam6_validate_trace_hdr(struct ioam6_trace_hdr *trace)
55{
56 u32 fields;
57
58 if (!trace->type_be32 || !trace->remlen ||

--- 14 unchanged lines hidden (view full) ---

73static int ioam6_build_state(struct net *net, struct nlattr *nla,
74 unsigned int family, const void *cfg,
75 struct lwtunnel_state **ts,
76 struct netlink_ext_ack *extack)
77{
78 struct nlattr *tb[IOAM6_IPTUNNEL_MAX + 1];
79 struct ioam6_lwt_encap *tuninfo;
80 struct ioam6_trace_hdr *trace;
62 [IOAM6_IPTUNNEL_TRACE] = NLA_POLICY_EXACT_LEN(sizeof(struct ioam6_trace_hdr)),
63};
64
65static bool ioam6_validate_trace_hdr(struct ioam6_trace_hdr *trace)
66{
67 u32 fields;
68
69 if (!trace->type_be32 || !trace->remlen ||

--- 14 unchanged lines hidden (view full) ---

84static int ioam6_build_state(struct net *net, struct nlattr *nla,
85 unsigned int family, const void *cfg,
86 struct lwtunnel_state **ts,
87 struct netlink_ext_ack *extack)
88{
89 struct nlattr *tb[IOAM6_IPTUNNEL_MAX + 1];
90 struct ioam6_lwt_encap *tuninfo;
91 struct ioam6_trace_hdr *trace;
81 struct lwtunnel_state *s;
82 int len_aligned;
83 int len, err;
92 struct lwtunnel_state *lwt;
93 struct ioam6_lwt *ilwt;
94 int len_aligned, err;
95 u8 mode;
84
85 if (family != AF_INET6)
86 return -EINVAL;
87
88 err = nla_parse_nested(tb, IOAM6_IPTUNNEL_MAX, nla,
89 ioam6_iptunnel_policy, extack);
90 if (err < 0)
91 return err;
92
96
97 if (family != AF_INET6)
98 return -EINVAL;
99
100 err = nla_parse_nested(tb, IOAM6_IPTUNNEL_MAX, nla,
101 ioam6_iptunnel_policy, extack);
102 if (err < 0)
103 return err;
104
105 if (!tb[IOAM6_IPTUNNEL_MODE])
106 mode = IOAM6_IPTUNNEL_MODE_INLINE;
107 else
108 mode = nla_get_u8(tb[IOAM6_IPTUNNEL_MODE]);
109
110 if (!tb[IOAM6_IPTUNNEL_DST] && mode != IOAM6_IPTUNNEL_MODE_INLINE) {
111 NL_SET_ERR_MSG(extack, "this mode needs a tunnel destination");
112 return -EINVAL;
113 }
114
93 if (!tb[IOAM6_IPTUNNEL_TRACE]) {
94 NL_SET_ERR_MSG(extack, "missing trace");
95 return -EINVAL;
96 }
97
98 trace = nla_data(tb[IOAM6_IPTUNNEL_TRACE]);
99 if (!ioam6_validate_trace_hdr(trace)) {
100 NL_SET_ERR_MSG_ATTR(extack, tb[IOAM6_IPTUNNEL_TRACE],
101 "invalid trace validation");
102 return -EINVAL;
103 }
104
115 if (!tb[IOAM6_IPTUNNEL_TRACE]) {
116 NL_SET_ERR_MSG(extack, "missing trace");
117 return -EINVAL;
118 }
119
120 trace = nla_data(tb[IOAM6_IPTUNNEL_TRACE]);
121 if (!ioam6_validate_trace_hdr(trace)) {
122 NL_SET_ERR_MSG_ATTR(extack, tb[IOAM6_IPTUNNEL_TRACE],
123 "invalid trace validation");
124 return -EINVAL;
125 }
126
105 len = sizeof(*tuninfo) + trace->remlen * 4;
106 len_aligned = ALIGN(len, 8);
107
108 s = lwtunnel_state_alloc(len_aligned);
109 if (!s)
127 len_aligned = ALIGN(trace->remlen * 4, 8);
128 lwt = lwtunnel_state_alloc(sizeof(*ilwt) + len_aligned);
129 if (!lwt)
110 return -ENOMEM;
111
130 return -ENOMEM;
131
112 tuninfo = ioam6_lwt_info(s);
113 tuninfo->eh.hdrlen = (len_aligned >> 3) - 1;
132 ilwt = ioam6_lwt_state(lwt);
133 err = dst_cache_init(&ilwt->cache, GFP_ATOMIC);
134 if (err) {
135 kfree(lwt);
136 return err;
137 }
138
139 ilwt->mode = mode;
140 if (tb[IOAM6_IPTUNNEL_DST])
141 ilwt->tundst = nla_get_in6_addr(tb[IOAM6_IPTUNNEL_DST]);
142
143 tuninfo = ioam6_lwt_info(lwt);
144 tuninfo->eh.hdrlen = ((sizeof(*tuninfo) + len_aligned) >> 3) - 1;
114 tuninfo->pad[0] = IPV6_TLV_PADN;
115 tuninfo->ioamh.type = IOAM6_TYPE_PREALLOC;
116 tuninfo->ioamh.opt_type = IPV6_TLV_IOAM;
117 tuninfo->ioamh.opt_len = sizeof(tuninfo->ioamh) - 2 + sizeof(*trace)
118 + trace->remlen * 4;
119
120 memcpy(&tuninfo->traceh, trace, sizeof(*trace));
121
145 tuninfo->pad[0] = IPV6_TLV_PADN;
146 tuninfo->ioamh.type = IOAM6_TYPE_PREALLOC;
147 tuninfo->ioamh.opt_type = IPV6_TLV_IOAM;
148 tuninfo->ioamh.opt_len = sizeof(tuninfo->ioamh) - 2 + sizeof(*trace)
149 + trace->remlen * 4;
150
151 memcpy(&tuninfo->traceh, trace, sizeof(*trace));
152
122 len = len_aligned - len;
123 if (len == 1) {
124 tuninfo->traceh.data[trace->remlen * 4] = IPV6_TLV_PAD1;
125 } else if (len > 0) {
153 if (len_aligned - trace->remlen * 4) {
126 tuninfo->traceh.data[trace->remlen * 4] = IPV6_TLV_PADN;
154 tuninfo->traceh.data[trace->remlen * 4] = IPV6_TLV_PADN;
127 tuninfo->traceh.data[trace->remlen * 4 + 1] = len - 2;
155 tuninfo->traceh.data[trace->remlen * 4 + 1] = 2;
128 }
129
156 }
157
130 s->type = LWTUNNEL_ENCAP_IOAM6;
131 s->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT;
158 lwt->type = LWTUNNEL_ENCAP_IOAM6;
159 lwt->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT;
132
160
133 *ts = s;
161 *ts = lwt;
134
135 return 0;
136}
137
162
163 return 0;
164}
165
138static int ioam6_do_inline(struct sk_buff *skb, struct ioam6_lwt_encap *tuninfo)
166static int ioam6_do_fill(struct net *net, struct sk_buff *skb)
139{
140 struct ioam6_trace_hdr *trace;
167{
168 struct ioam6_trace_hdr *trace;
141 struct ipv6hdr *oldhdr, *hdr;
142 struct ioam6_namespace *ns;
169 struct ioam6_namespace *ns;
170
171 trace = (struct ioam6_trace_hdr *)(skb_transport_header(skb)
172 + sizeof(struct ipv6_hopopt_hdr) + 2
173 + sizeof(struct ioam6_hdr));
174
175 ns = ioam6_namespace(net, trace->namespace_id);
176 if (ns)
177 ioam6_fill_trace_data(skb, ns, trace, false);
178
179 return 0;
180}
181
182static int ioam6_do_inline(struct net *net, struct sk_buff *skb,
183 struct ioam6_lwt_encap *tuninfo)
184{
185 struct ipv6hdr *oldhdr, *hdr;
143 int hdrlen, err;
144
145 hdrlen = (tuninfo->eh.hdrlen + 1) << 3;
146
147 err = skb_cow_head(skb, hdrlen + skb->mac_len);
148 if (unlikely(err))
149 return err;
150

--- 12 unchanged lines hidden (view full) ---

163 skb_set_transport_header(skb, sizeof(*hdr));
164 skb_postpush_rcsum(skb, hdr, sizeof(*hdr) + hdrlen);
165
166 memcpy(skb_transport_header(skb), (u8 *)tuninfo, hdrlen);
167
168 hdr->nexthdr = NEXTHDR_HOP;
169 hdr->payload_len = cpu_to_be16(skb->len - sizeof(*hdr));
170
186 int hdrlen, err;
187
188 hdrlen = (tuninfo->eh.hdrlen + 1) << 3;
189
190 err = skb_cow_head(skb, hdrlen + skb->mac_len);
191 if (unlikely(err))
192 return err;
193

--- 12 unchanged lines hidden (view full) ---

206 skb_set_transport_header(skb, sizeof(*hdr));
207 skb_postpush_rcsum(skb, hdr, sizeof(*hdr) + hdrlen);
208
209 memcpy(skb_transport_header(skb), (u8 *)tuninfo, hdrlen);
210
211 hdr->nexthdr = NEXTHDR_HOP;
212 hdr->payload_len = cpu_to_be16(skb->len - sizeof(*hdr));
213
171 trace = (struct ioam6_trace_hdr *)(skb_transport_header(skb)
172 + sizeof(struct ipv6_hopopt_hdr) + 2
173 + sizeof(struct ioam6_hdr));
214 return ioam6_do_fill(net, skb);
215}
174
216
175 ns = ioam6_namespace(dev_net(skb_dst(skb)->dev), trace->namespace_id);
176 if (ns)
177 ioam6_fill_trace_data(skb, ns, trace);
217static int ioam6_do_encap(struct net *net, struct sk_buff *skb,
218 struct ioam6_lwt_encap *tuninfo,
219 struct in6_addr *tundst)
220{
221 struct dst_entry *dst = skb_dst(skb);
222 struct ipv6hdr *hdr, *inner_hdr;
223 int hdrlen, len, err;
178
224
179 return 0;
225 hdrlen = (tuninfo->eh.hdrlen + 1) << 3;
226 len = sizeof(*hdr) + hdrlen;
227
228 err = skb_cow_head(skb, len + skb->mac_len);
229 if (unlikely(err))
230 return err;
231
232 inner_hdr = ipv6_hdr(skb);
233
234 skb_push(skb, len);
235 skb_reset_network_header(skb);
236 skb_mac_header_rebuild(skb);
237 skb_set_transport_header(skb, sizeof(*hdr));
238
239 tuninfo->eh.nexthdr = NEXTHDR_IPV6;
240 memcpy(skb_transport_header(skb), (u8 *)tuninfo, hdrlen);
241
242 hdr = ipv6_hdr(skb);
243 memcpy(hdr, inner_hdr, sizeof(*hdr));
244
245 hdr->nexthdr = NEXTHDR_HOP;
246 hdr->payload_len = cpu_to_be16(skb->len - sizeof(*hdr));
247 hdr->daddr = *tundst;
248 ipv6_dev_get_saddr(net, dst->dev, &hdr->daddr,
249 IPV6_PREFER_SRC_PUBLIC, &hdr->saddr);
250
251 skb_postpush_rcsum(skb, hdr, len);
252
253 return ioam6_do_fill(net, skb);
180}
181
182static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
183{
254}
255
256static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
257{
184 struct lwtunnel_state *lwt = skb_dst(skb)->lwtstate;
258 struct dst_entry *dst = skb_dst(skb);
259 struct in6_addr orig_daddr;
260 struct ioam6_lwt *ilwt;
185 int err = -EINVAL;
186
187 if (skb->protocol != htons(ETH_P_IPV6))
188 goto drop;
189
261 int err = -EINVAL;
262
263 if (skb->protocol != htons(ETH_P_IPV6))
264 goto drop;
265
190 /* Only for packets we send and
191 * that do not contain a Hop-by-Hop yet
192 */
193 if (skb->dev || ipv6_hdr(skb)->nexthdr == NEXTHDR_HOP)
194 goto out;
266 ilwt = ioam6_lwt_state(dst->lwtstate);
267 orig_daddr = ipv6_hdr(skb)->daddr;
195
268
196 err = ioam6_do_inline(skb, ioam6_lwt_info(lwt));
197 if (unlikely(err))
269 switch (ilwt->mode) {
270 case IOAM6_IPTUNNEL_MODE_INLINE:
271do_inline:
272 /* Direct insertion - if there is no Hop-by-Hop yet */
273 if (ipv6_hdr(skb)->nexthdr == NEXTHDR_HOP)
274 goto out;
275
276 err = ioam6_do_inline(net, skb, &ilwt->tuninfo);
277 if (unlikely(err))
278 goto drop;
279
280 break;
281 case IOAM6_IPTUNNEL_MODE_ENCAP:
282do_encap:
283 /* Encapsulation (ip6ip6) */
284 err = ioam6_do_encap(net, skb, &ilwt->tuninfo, &ilwt->tundst);
285 if (unlikely(err))
286 goto drop;
287
288 break;
289 case IOAM6_IPTUNNEL_MODE_AUTO:
290 /* Automatic (RFC8200 compliant):
291 * - local packets -> INLINE mode
292 * - in-transit packets -> ENCAP mode
293 */
294 if (!skb->dev)
295 goto do_inline;
296
297 goto do_encap;
298 default:
198 goto drop;
299 goto drop;
300 }
199
301
200 err = skb_cow_head(skb, LL_RESERVED_SPACE(skb_dst(skb)->dev));
302 err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
201 if (unlikely(err))
202 goto drop;
203
303 if (unlikely(err))
304 goto drop;
305
204out:
205 return lwt->orig_output(net, sk, skb);
306 if (!ipv6_addr_equal(&orig_daddr, &ipv6_hdr(skb)->daddr)) {
307 preempt_disable();
308 dst = dst_cache_get(&ilwt->cache);
309 preempt_enable();
206
310
311 if (unlikely(!dst)) {
312 struct ipv6hdr *hdr = ipv6_hdr(skb);
313 struct flowi6 fl6;
314
315 memset(&fl6, 0, sizeof(fl6));
316 fl6.daddr = hdr->daddr;
317 fl6.saddr = hdr->saddr;
318 fl6.flowlabel = ip6_flowinfo(hdr);
319 fl6.flowi6_mark = skb->mark;
320 fl6.flowi6_proto = hdr->nexthdr;
321
322 dst = ip6_route_output(net, NULL, &fl6);
323 if (dst->error) {
324 err = dst->error;
325 dst_release(dst);
326 goto drop;
327 }
328
329 preempt_disable();
330 dst_cache_set_ip6(&ilwt->cache, dst, &fl6.saddr);
331 preempt_enable();
332 }
333
334 skb_dst_drop(skb);
335 skb_dst_set(skb, dst);
336
337 return dst_output(net, sk, skb);
338 }
339out:
340 return dst->lwtstate->orig_output(net, sk, skb);
207drop:
208 kfree_skb(skb);
209 return err;
210}
211
341drop:
342 kfree_skb(skb);
343 return err;
344}
345
346static void ioam6_destroy_state(struct lwtunnel_state *lwt)
347{
348 dst_cache_destroy(&ioam6_lwt_state(lwt)->cache);
349}
350
212static int ioam6_fill_encap_info(struct sk_buff *skb,
213 struct lwtunnel_state *lwtstate)
214{
351static int ioam6_fill_encap_info(struct sk_buff *skb,
352 struct lwtunnel_state *lwtstate)
353{
215 struct ioam6_trace_hdr *trace;
354 struct ioam6_lwt *ilwt = ioam6_lwt_state(lwtstate);
216 int err;
217
355 int err;
356
218 trace = ioam6_lwt_trace(lwtstate);
219
220 err = nla_put(skb, IOAM6_IPTUNNEL_TRACE, sizeof(*trace), trace);
357 err = nla_put_u8(skb, IOAM6_IPTUNNEL_MODE, ilwt->mode);
221 if (err)
358 if (err)
222 return err;
359 goto ret;
223
360
224 return 0;
361 if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE) {
362 err = nla_put_in6_addr(skb, IOAM6_IPTUNNEL_DST, &ilwt->tundst);
363 if (err)
364 goto ret;
365 }
366
367 err = nla_put(skb, IOAM6_IPTUNNEL_TRACE, sizeof(ilwt->tuninfo.traceh),
368 &ilwt->tuninfo.traceh);
369ret:
370 return err;
225}
226
227static int ioam6_encap_nlsize(struct lwtunnel_state *lwtstate)
228{
371}
372
373static int ioam6_encap_nlsize(struct lwtunnel_state *lwtstate)
374{
229 struct ioam6_trace_hdr *trace = ioam6_lwt_trace(lwtstate);
375 struct ioam6_lwt *ilwt = ioam6_lwt_state(lwtstate);
376 int nlsize;
230
377
231 return nla_total_size(sizeof(*trace));
378 nlsize = nla_total_size(sizeof(ilwt->mode)) +
379 nla_total_size(sizeof(ilwt->tuninfo.traceh));
380
381 if (ilwt->mode != IOAM6_IPTUNNEL_MODE_INLINE)
382 nlsize += nla_total_size(sizeof(ilwt->tundst));
383
384 return nlsize;
232}
233
234static int ioam6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
235{
385}
386
387static int ioam6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
388{
236 struct ioam6_trace_hdr *a_hdr = ioam6_lwt_trace(a);
237 struct ioam6_trace_hdr *b_hdr = ioam6_lwt_trace(b);
389 struct ioam6_trace_hdr *trace_a = ioam6_lwt_trace(a);
390 struct ioam6_trace_hdr *trace_b = ioam6_lwt_trace(b);
391 struct ioam6_lwt *ilwt_a = ioam6_lwt_state(a);
392 struct ioam6_lwt *ilwt_b = ioam6_lwt_state(b);
238
393
239 return (a_hdr->namespace_id != b_hdr->namespace_id);
394 return (ilwt_a->mode != ilwt_b->mode ||
395 (ilwt_a->mode != IOAM6_IPTUNNEL_MODE_INLINE &&
396 !ipv6_addr_equal(&ilwt_a->tundst, &ilwt_b->tundst)) ||
397 trace_a->namespace_id != trace_b->namespace_id);
240}
241
242static const struct lwtunnel_encap_ops ioam6_iptun_ops = {
243 .build_state = ioam6_build_state,
398}
399
400static const struct lwtunnel_encap_ops ioam6_iptun_ops = {
401 .build_state = ioam6_build_state,
402 .destroy_state = ioam6_destroy_state,
244 .output = ioam6_output,
245 .fill_encap = ioam6_fill_encap_info,
246 .get_encap_size = ioam6_encap_nlsize,
247 .cmp_encap = ioam6_encap_cmp,
248 .owner = THIS_MODULE,
249};
250
251int __init ioam6_iptunnel_init(void)
252{
253 return lwtunnel_encap_add_ops(&ioam6_iptun_ops, LWTUNNEL_ENCAP_IOAM6);
254}
255
256void ioam6_iptunnel_exit(void)
257{
258 lwtunnel_encap_del_ops(&ioam6_iptun_ops, LWTUNNEL_ENCAP_IOAM6);
259}
403 .output = ioam6_output,
404 .fill_encap = ioam6_fill_encap_info,
405 .get_encap_size = ioam6_encap_nlsize,
406 .cmp_encap = ioam6_encap_cmp,
407 .owner = THIS_MODULE,
408};
409
410int __init ioam6_iptunnel_init(void)
411{
412 return lwtunnel_encap_add_ops(&ioam6_iptun_ops, LWTUNNEL_ENCAP_IOAM6);
413}
414
415void ioam6_iptunnel_exit(void)
416{
417 lwtunnel_encap_del_ops(&ioam6_iptun_ops, LWTUNNEL_ENCAP_IOAM6);
418}