1// SPDX-License-Identifier: GPL-2.0+
2/*
3 *  IPv6 IOAM implementation
4 *
5 *  Author:
6 *  Justin Iurman <justin.iurman@uliege.be>
7 */
8
9#include <linux/errno.h>
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/net.h>
13#include <linux/ioam6.h>
14#include <linux/ioam6_genl.h>
15#include <linux/rhashtable.h>
16#include <linux/netdevice.h>
17
18#include <net/addrconf.h>
19#include <net/genetlink.h>
20#include <net/ioam6.h>
21#include <net/sch_generic.h>
22
23static void ioam6_ns_release(struct ioam6_namespace *ns)
24{
25	kfree_rcu(ns, rcu);
26}
27
28static void ioam6_sc_release(struct ioam6_schema *sc)
29{
30	kfree_rcu(sc, rcu);
31}
32
33static void ioam6_free_ns(void *ptr, void *arg)
34{
35	struct ioam6_namespace *ns = (struct ioam6_namespace *)ptr;
36
37	if (ns)
38		ioam6_ns_release(ns);
39}
40
41static void ioam6_free_sc(void *ptr, void *arg)
42{
43	struct ioam6_schema *sc = (struct ioam6_schema *)ptr;
44
45	if (sc)
46		ioam6_sc_release(sc);
47}
48
49static int ioam6_ns_cmpfn(struct rhashtable_compare_arg *arg, const void *obj)
50{
51	const struct ioam6_namespace *ns = obj;
52
53	return (ns->id != *(__be16 *)arg->key);
54}
55
56static int ioam6_sc_cmpfn(struct rhashtable_compare_arg *arg, const void *obj)
57{
58	const struct ioam6_schema *sc = obj;
59
60	return (sc->id != *(u32 *)arg->key);
61}
62
63static const struct rhashtable_params rht_ns_params = {
64	.key_len		= sizeof(__be16),
65	.key_offset		= offsetof(struct ioam6_namespace, id),
66	.head_offset		= offsetof(struct ioam6_namespace, head),
67	.automatic_shrinking	= true,
68	.obj_cmpfn		= ioam6_ns_cmpfn,
69};
70
71static const struct rhashtable_params rht_sc_params = {
72	.key_len		= sizeof(u32),
73	.key_offset		= offsetof(struct ioam6_schema, id),
74	.head_offset		= offsetof(struct ioam6_schema, head),
75	.automatic_shrinking	= true,
76	.obj_cmpfn		= ioam6_sc_cmpfn,
77};
78
79static struct genl_family ioam6_genl_family;
80
81static const struct nla_policy ioam6_genl_policy_addns[] = {
82	[IOAM6_ATTR_NS_ID]	= { .type = NLA_U16 },
83	[IOAM6_ATTR_NS_DATA]	= { .type = NLA_U32 },
84	[IOAM6_ATTR_NS_DATA_WIDE] = { .type = NLA_U64 },
85};
86
87static const struct nla_policy ioam6_genl_policy_delns[] = {
88	[IOAM6_ATTR_NS_ID]	= { .type = NLA_U16 },
89};
90
91static const struct nla_policy ioam6_genl_policy_addsc[] = {
92	[IOAM6_ATTR_SC_ID]	= { .type = NLA_U32 },
93	[IOAM6_ATTR_SC_DATA]	= { .type = NLA_BINARY,
94				    .len = IOAM6_MAX_SCHEMA_DATA_LEN },
95};
96
97static const struct nla_policy ioam6_genl_policy_delsc[] = {
98	[IOAM6_ATTR_SC_ID]	= { .type = NLA_U32 },
99};
100
101static const struct nla_policy ioam6_genl_policy_ns_sc[] = {
102	[IOAM6_ATTR_NS_ID]	= { .type = NLA_U16 },
103	[IOAM6_ATTR_SC_ID]	= { .type = NLA_U32 },
104	[IOAM6_ATTR_SC_NONE]	= { .type = NLA_FLAG },
105};
106
107static int ioam6_genl_addns(struct sk_buff *skb, struct genl_info *info)
108{
109	struct ioam6_pernet_data *nsdata;
110	struct ioam6_namespace *ns;
111	u64 data64;
112	u32 data32;
113	__be16 id;
114	int err;
115
116	if (!info->attrs[IOAM6_ATTR_NS_ID])
117		return -EINVAL;
118
119	id = cpu_to_be16(nla_get_u16(info->attrs[IOAM6_ATTR_NS_ID]));
120	nsdata = ioam6_pernet(genl_info_net(info));
121
122	mutex_lock(&nsdata->lock);
123
124	ns = rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
125	if (ns) {
126		err = -EEXIST;
127		goto out_unlock;
128	}
129
130	ns = kzalloc(sizeof(*ns), GFP_KERNEL);
131	if (!ns) {
132		err = -ENOMEM;
133		goto out_unlock;
134	}
135
136	ns->id = id;
137
138	if (!info->attrs[IOAM6_ATTR_NS_DATA])
139		data32 = IOAM6_U32_UNAVAILABLE;
140	else
141		data32 = nla_get_u32(info->attrs[IOAM6_ATTR_NS_DATA]);
142
143	if (!info->attrs[IOAM6_ATTR_NS_DATA_WIDE])
144		data64 = IOAM6_U64_UNAVAILABLE;
145	else
146		data64 = nla_get_u64(info->attrs[IOAM6_ATTR_NS_DATA_WIDE]);
147
148	ns->data = cpu_to_be32(data32);
149	ns->data_wide = cpu_to_be64(data64);
150
151	err = rhashtable_lookup_insert_fast(&nsdata->namespaces, &ns->head,
152					    rht_ns_params);
153	if (err)
154		kfree(ns);
155
156out_unlock:
157	mutex_unlock(&nsdata->lock);
158	return err;
159}
160
161static int ioam6_genl_delns(struct sk_buff *skb, struct genl_info *info)
162{
163	struct ioam6_pernet_data *nsdata;
164	struct ioam6_namespace *ns;
165	struct ioam6_schema *sc;
166	__be16 id;
167	int err;
168
169	if (!info->attrs[IOAM6_ATTR_NS_ID])
170		return -EINVAL;
171
172	id = cpu_to_be16(nla_get_u16(info->attrs[IOAM6_ATTR_NS_ID]));
173	nsdata = ioam6_pernet(genl_info_net(info));
174
175	mutex_lock(&nsdata->lock);
176
177	ns = rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
178	if (!ns) {
179		err = -ENOENT;
180		goto out_unlock;
181	}
182
183	sc = rcu_dereference_protected(ns->schema,
184				       lockdep_is_held(&nsdata->lock));
185
186	err = rhashtable_remove_fast(&nsdata->namespaces, &ns->head,
187				     rht_ns_params);
188	if (err)
189		goto out_unlock;
190
191	if (sc)
192		rcu_assign_pointer(sc->ns, NULL);
193
194	ioam6_ns_release(ns);
195
196out_unlock:
197	mutex_unlock(&nsdata->lock);
198	return err;
199}
200
201static int __ioam6_genl_dumpns_element(struct ioam6_namespace *ns,
202				       u32 portid,
203				       u32 seq,
204				       u32 flags,
205				       struct sk_buff *skb,
206				       u8 cmd)
207{
208	struct ioam6_schema *sc;
209	u64 data64;
210	u32 data32;
211	void *hdr;
212
213	hdr = genlmsg_put(skb, portid, seq, &ioam6_genl_family, flags, cmd);
214	if (!hdr)
215		return -ENOMEM;
216
217	data32 = be32_to_cpu(ns->data);
218	data64 = be64_to_cpu(ns->data_wide);
219
220	if (nla_put_u16(skb, IOAM6_ATTR_NS_ID, be16_to_cpu(ns->id)) ||
221	    (data32 != IOAM6_U32_UNAVAILABLE &&
222	     nla_put_u32(skb, IOAM6_ATTR_NS_DATA, data32)) ||
223	    (data64 != IOAM6_U64_UNAVAILABLE &&
224	     nla_put_u64_64bit(skb, IOAM6_ATTR_NS_DATA_WIDE,
225			       data64, IOAM6_ATTR_PAD)))
226		goto nla_put_failure;
227
228	rcu_read_lock();
229
230	sc = rcu_dereference(ns->schema);
231	if (sc && nla_put_u32(skb, IOAM6_ATTR_SC_ID, sc->id)) {
232		rcu_read_unlock();
233		goto nla_put_failure;
234	}
235
236	rcu_read_unlock();
237
238	genlmsg_end(skb, hdr);
239	return 0;
240
241nla_put_failure:
242	genlmsg_cancel(skb, hdr);
243	return -EMSGSIZE;
244}
245
246static int ioam6_genl_dumpns_start(struct netlink_callback *cb)
247{
248	struct ioam6_pernet_data *nsdata = ioam6_pernet(sock_net(cb->skb->sk));
249	struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
250
251	if (!iter) {
252		iter = kmalloc(sizeof(*iter), GFP_KERNEL);
253		if (!iter)
254			return -ENOMEM;
255
256		cb->args[0] = (long)iter;
257	}
258
259	rhashtable_walk_enter(&nsdata->namespaces, iter);
260
261	return 0;
262}
263
264static int ioam6_genl_dumpns_done(struct netlink_callback *cb)
265{
266	struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
267
268	rhashtable_walk_exit(iter);
269	kfree(iter);
270
271	return 0;
272}
273
274static int ioam6_genl_dumpns(struct sk_buff *skb, struct netlink_callback *cb)
275{
276	struct rhashtable_iter *iter;
277	struct ioam6_namespace *ns;
278	int err;
279
280	iter = (struct rhashtable_iter *)cb->args[0];
281	rhashtable_walk_start(iter);
282
283	for (;;) {
284		ns = rhashtable_walk_next(iter);
285
286		if (IS_ERR(ns)) {
287			if (PTR_ERR(ns) == -EAGAIN)
288				continue;
289			err = PTR_ERR(ns);
290			goto done;
291		} else if (!ns) {
292			break;
293		}
294
295		err = __ioam6_genl_dumpns_element(ns,
296						  NETLINK_CB(cb->skb).portid,
297						  cb->nlh->nlmsg_seq,
298						  NLM_F_MULTI,
299						  skb,
300						  IOAM6_CMD_DUMP_NAMESPACES);
301		if (err)
302			goto done;
303	}
304
305	err = skb->len;
306
307done:
308	rhashtable_walk_stop(iter);
309	return err;
310}
311
312static int ioam6_genl_addsc(struct sk_buff *skb, struct genl_info *info)
313{
314	struct ioam6_pernet_data *nsdata;
315	int len, len_aligned, err;
316	struct ioam6_schema *sc;
317	u32 id;
318
319	if (!info->attrs[IOAM6_ATTR_SC_ID] || !info->attrs[IOAM6_ATTR_SC_DATA])
320		return -EINVAL;
321
322	id = nla_get_u32(info->attrs[IOAM6_ATTR_SC_ID]);
323	nsdata = ioam6_pernet(genl_info_net(info));
324
325	mutex_lock(&nsdata->lock);
326
327	sc = rhashtable_lookup_fast(&nsdata->schemas, &id, rht_sc_params);
328	if (sc) {
329		err = -EEXIST;
330		goto out_unlock;
331	}
332
333	len = nla_len(info->attrs[IOAM6_ATTR_SC_DATA]);
334	len_aligned = ALIGN(len, 4);
335
336	sc = kzalloc(sizeof(*sc) + len_aligned, GFP_KERNEL);
337	if (!sc) {
338		err = -ENOMEM;
339		goto out_unlock;
340	}
341
342	sc->id = id;
343	sc->len = len_aligned;
344	sc->hdr = cpu_to_be32(sc->id | ((u8)(sc->len / 4) << 24));
345	nla_memcpy(sc->data, info->attrs[IOAM6_ATTR_SC_DATA], len);
346
347	err = rhashtable_lookup_insert_fast(&nsdata->schemas, &sc->head,
348					    rht_sc_params);
349	if (err)
350		goto free_sc;
351
352out_unlock:
353	mutex_unlock(&nsdata->lock);
354	return err;
355free_sc:
356	kfree(sc);
357	goto out_unlock;
358}
359
360static int ioam6_genl_delsc(struct sk_buff *skb, struct genl_info *info)
361{
362	struct ioam6_pernet_data *nsdata;
363	struct ioam6_namespace *ns;
364	struct ioam6_schema *sc;
365	int err;
366	u32 id;
367
368	if (!info->attrs[IOAM6_ATTR_SC_ID])
369		return -EINVAL;
370
371	id = nla_get_u32(info->attrs[IOAM6_ATTR_SC_ID]);
372	nsdata = ioam6_pernet(genl_info_net(info));
373
374	mutex_lock(&nsdata->lock);
375
376	sc = rhashtable_lookup_fast(&nsdata->schemas, &id, rht_sc_params);
377	if (!sc) {
378		err = -ENOENT;
379		goto out_unlock;
380	}
381
382	ns = rcu_dereference_protected(sc->ns, lockdep_is_held(&nsdata->lock));
383
384	err = rhashtable_remove_fast(&nsdata->schemas, &sc->head,
385				     rht_sc_params);
386	if (err)
387		goto out_unlock;
388
389	if (ns)
390		rcu_assign_pointer(ns->schema, NULL);
391
392	ioam6_sc_release(sc);
393
394out_unlock:
395	mutex_unlock(&nsdata->lock);
396	return err;
397}
398
399static int __ioam6_genl_dumpsc_element(struct ioam6_schema *sc,
400				       u32 portid, u32 seq, u32 flags,
401				       struct sk_buff *skb, u8 cmd)
402{
403	struct ioam6_namespace *ns;
404	void *hdr;
405
406	hdr = genlmsg_put(skb, portid, seq, &ioam6_genl_family, flags, cmd);
407	if (!hdr)
408		return -ENOMEM;
409
410	if (nla_put_u32(skb, IOAM6_ATTR_SC_ID, sc->id) ||
411	    nla_put(skb, IOAM6_ATTR_SC_DATA, sc->len, sc->data))
412		goto nla_put_failure;
413
414	rcu_read_lock();
415
416	ns = rcu_dereference(sc->ns);
417	if (ns && nla_put_u16(skb, IOAM6_ATTR_NS_ID, be16_to_cpu(ns->id))) {
418		rcu_read_unlock();
419		goto nla_put_failure;
420	}
421
422	rcu_read_unlock();
423
424	genlmsg_end(skb, hdr);
425	return 0;
426
427nla_put_failure:
428	genlmsg_cancel(skb, hdr);
429	return -EMSGSIZE;
430}
431
432static int ioam6_genl_dumpsc_start(struct netlink_callback *cb)
433{
434	struct ioam6_pernet_data *nsdata = ioam6_pernet(sock_net(cb->skb->sk));
435	struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
436
437	if (!iter) {
438		iter = kmalloc(sizeof(*iter), GFP_KERNEL);
439		if (!iter)
440			return -ENOMEM;
441
442		cb->args[0] = (long)iter;
443	}
444
445	rhashtable_walk_enter(&nsdata->schemas, iter);
446
447	return 0;
448}
449
450static int ioam6_genl_dumpsc_done(struct netlink_callback *cb)
451{
452	struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
453
454	rhashtable_walk_exit(iter);
455	kfree(iter);
456
457	return 0;
458}
459
460static int ioam6_genl_dumpsc(struct sk_buff *skb, struct netlink_callback *cb)
461{
462	struct rhashtable_iter *iter;
463	struct ioam6_schema *sc;
464	int err;
465
466	iter = (struct rhashtable_iter *)cb->args[0];
467	rhashtable_walk_start(iter);
468
469	for (;;) {
470		sc = rhashtable_walk_next(iter);
471
472		if (IS_ERR(sc)) {
473			if (PTR_ERR(sc) == -EAGAIN)
474				continue;
475			err = PTR_ERR(sc);
476			goto done;
477		} else if (!sc) {
478			break;
479		}
480
481		err = __ioam6_genl_dumpsc_element(sc,
482						  NETLINK_CB(cb->skb).portid,
483						  cb->nlh->nlmsg_seq,
484						  NLM_F_MULTI,
485						  skb,
486						  IOAM6_CMD_DUMP_SCHEMAS);
487		if (err)
488			goto done;
489	}
490
491	err = skb->len;
492
493done:
494	rhashtable_walk_stop(iter);
495	return err;
496}
497
498static int ioam6_genl_ns_set_schema(struct sk_buff *skb, struct genl_info *info)
499{
500	struct ioam6_namespace *ns, *ns_ref;
501	struct ioam6_schema *sc, *sc_ref;
502	struct ioam6_pernet_data *nsdata;
503	__be16 ns_id;
504	u32 sc_id;
505	int err;
506
507	if (!info->attrs[IOAM6_ATTR_NS_ID] ||
508	    (!info->attrs[IOAM6_ATTR_SC_ID] &&
509	     !info->attrs[IOAM6_ATTR_SC_NONE]))
510		return -EINVAL;
511
512	ns_id = cpu_to_be16(nla_get_u16(info->attrs[IOAM6_ATTR_NS_ID]));
513	nsdata = ioam6_pernet(genl_info_net(info));
514
515	mutex_lock(&nsdata->lock);
516
517	ns = rhashtable_lookup_fast(&nsdata->namespaces, &ns_id, rht_ns_params);
518	if (!ns) {
519		err = -ENOENT;
520		goto out_unlock;
521	}
522
523	if (info->attrs[IOAM6_ATTR_SC_NONE]) {
524		sc = NULL;
525	} else {
526		sc_id = nla_get_u32(info->attrs[IOAM6_ATTR_SC_ID]);
527		sc = rhashtable_lookup_fast(&nsdata->schemas, &sc_id,
528					    rht_sc_params);
529		if (!sc) {
530			err = -ENOENT;
531			goto out_unlock;
532		}
533	}
534
535	sc_ref = rcu_dereference_protected(ns->schema,
536					   lockdep_is_held(&nsdata->lock));
537	if (sc_ref)
538		rcu_assign_pointer(sc_ref->ns, NULL);
539	rcu_assign_pointer(ns->schema, sc);
540
541	if (sc) {
542		ns_ref = rcu_dereference_protected(sc->ns,
543						   lockdep_is_held(&nsdata->lock));
544		if (ns_ref)
545			rcu_assign_pointer(ns_ref->schema, NULL);
546		rcu_assign_pointer(sc->ns, ns);
547	}
548
549	err = 0;
550
551out_unlock:
552	mutex_unlock(&nsdata->lock);
553	return err;
554}
555
556static const struct genl_ops ioam6_genl_ops[] = {
557	{
558		.cmd	= IOAM6_CMD_ADD_NAMESPACE,
559		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
560		.doit	= ioam6_genl_addns,
561		.flags	= GENL_ADMIN_PERM,
562		.policy	= ioam6_genl_policy_addns,
563		.maxattr = ARRAY_SIZE(ioam6_genl_policy_addns) - 1,
564	},
565	{
566		.cmd	= IOAM6_CMD_DEL_NAMESPACE,
567		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
568		.doit	= ioam6_genl_delns,
569		.flags	= GENL_ADMIN_PERM,
570		.policy	= ioam6_genl_policy_delns,
571		.maxattr = ARRAY_SIZE(ioam6_genl_policy_delns) - 1,
572	},
573	{
574		.cmd	= IOAM6_CMD_DUMP_NAMESPACES,
575		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
576		.start	= ioam6_genl_dumpns_start,
577		.dumpit	= ioam6_genl_dumpns,
578		.done	= ioam6_genl_dumpns_done,
579		.flags	= GENL_ADMIN_PERM,
580	},
581	{
582		.cmd	= IOAM6_CMD_ADD_SCHEMA,
583		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
584		.doit	= ioam6_genl_addsc,
585		.flags	= GENL_ADMIN_PERM,
586		.policy	= ioam6_genl_policy_addsc,
587		.maxattr = ARRAY_SIZE(ioam6_genl_policy_addsc) - 1,
588	},
589	{
590		.cmd	= IOAM6_CMD_DEL_SCHEMA,
591		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
592		.doit	= ioam6_genl_delsc,
593		.flags	= GENL_ADMIN_PERM,
594		.policy	= ioam6_genl_policy_delsc,
595		.maxattr = ARRAY_SIZE(ioam6_genl_policy_delsc) - 1,
596	},
597	{
598		.cmd	= IOAM6_CMD_DUMP_SCHEMAS,
599		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
600		.start	= ioam6_genl_dumpsc_start,
601		.dumpit	= ioam6_genl_dumpsc,
602		.done	= ioam6_genl_dumpsc_done,
603		.flags	= GENL_ADMIN_PERM,
604	},
605	{
606		.cmd	= IOAM6_CMD_NS_SET_SCHEMA,
607		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
608		.doit	= ioam6_genl_ns_set_schema,
609		.flags	= GENL_ADMIN_PERM,
610		.policy	= ioam6_genl_policy_ns_sc,
611		.maxattr = ARRAY_SIZE(ioam6_genl_policy_ns_sc) - 1,
612	},
613};
614
615#define IOAM6_GENL_EV_GRP_OFFSET 0
616
617static const struct genl_multicast_group ioam6_mcgrps[] = {
618	[IOAM6_GENL_EV_GRP_OFFSET] = { .name = IOAM6_GENL_EV_GRP_NAME,
619				       .flags = GENL_MCAST_CAP_NET_ADMIN },
620};
621
622static int ioam6_event_put_trace(struct sk_buff *skb,
623				 struct ioam6_trace_hdr *trace,
624				 unsigned int len)
625{
626	if (nla_put_u16(skb, IOAM6_EVENT_ATTR_TRACE_NAMESPACE,
627			be16_to_cpu(trace->namespace_id)) ||
628	    nla_put_u8(skb, IOAM6_EVENT_ATTR_TRACE_NODELEN, trace->nodelen) ||
629	    nla_put_u32(skb, IOAM6_EVENT_ATTR_TRACE_TYPE,
630			be32_to_cpu(trace->type_be32)) ||
631	    nla_put(skb, IOAM6_EVENT_ATTR_TRACE_DATA,
632		    len - sizeof(struct ioam6_trace_hdr) - trace->remlen * 4,
633		    trace->data + trace->remlen * 4))
634		return 1;
635
636	return 0;
637}
638
639void ioam6_event(enum ioam6_event_type type, struct net *net, gfp_t gfp,
640		 void *opt, unsigned int opt_len)
641{
642	struct nlmsghdr *nlh;
643	struct sk_buff *skb;
644
645	if (!genl_has_listeners(&ioam6_genl_family, net,
646				IOAM6_GENL_EV_GRP_OFFSET))
647		return;
648
649	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
650	if (!skb)
651		return;
652
653	nlh = genlmsg_put(skb, 0, 0, &ioam6_genl_family, 0, type);
654	if (!nlh)
655		goto nla_put_failure;
656
657	switch (type) {
658	case IOAM6_EVENT_UNSPEC:
659		WARN_ON_ONCE(1);
660		break;
661	case IOAM6_EVENT_TRACE:
662		if (ioam6_event_put_trace(skb, (struct ioam6_trace_hdr *)opt,
663					  opt_len))
664			goto nla_put_failure;
665		break;
666	}
667
668	genlmsg_end(skb, nlh);
669	genlmsg_multicast_netns(&ioam6_genl_family, net, skb, 0,
670				IOAM6_GENL_EV_GRP_OFFSET, gfp);
671	return;
672
673nla_put_failure:
674	nlmsg_free(skb);
675}
676
677static struct genl_family ioam6_genl_family __ro_after_init = {
678	.name		= IOAM6_GENL_NAME,
679	.version	= IOAM6_GENL_VERSION,
680	.netnsok	= true,
681	.parallel_ops	= true,
682	.ops		= ioam6_genl_ops,
683	.n_ops		= ARRAY_SIZE(ioam6_genl_ops),
684	.resv_start_op	= IOAM6_CMD_NS_SET_SCHEMA + 1,
685	.mcgrps		= ioam6_mcgrps,
686	.n_mcgrps	= ARRAY_SIZE(ioam6_mcgrps),
687	.module		= THIS_MODULE,
688};
689
690struct ioam6_namespace *ioam6_namespace(struct net *net, __be16 id)
691{
692	struct ioam6_pernet_data *nsdata = ioam6_pernet(net);
693
694	return rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
695}
696
697static void __ioam6_fill_trace_data(struct sk_buff *skb,
698				    struct ioam6_namespace *ns,
699				    struct ioam6_trace_hdr *trace,
700				    struct ioam6_schema *sc,
701				    u8 sclen, bool is_input)
702{
703	struct timespec64 ts;
704	ktime_t tstamp;
705	u64 raw64;
706	u32 raw32;
707	u16 raw16;
708	u8 *data;
709	u8 byte;
710
711	data = trace->data + trace->remlen * 4 - trace->nodelen * 4 - sclen * 4;
712
713	/* hop_lim and node_id */
714	if (trace->type.bit0) {
715		byte = ipv6_hdr(skb)->hop_limit;
716		if (is_input)
717			byte--;
718
719		raw32 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id;
720
721		*(__be32 *)data = cpu_to_be32((byte << 24) | raw32);
722		data += sizeof(__be32);
723	}
724
725	/* ingress_if_id and egress_if_id */
726	if (trace->type.bit1) {
727		if (!skb->dev)
728			raw16 = IOAM6_U16_UNAVAILABLE;
729		else
730			raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id);
731
732		*(__be16 *)data = cpu_to_be16(raw16);
733		data += sizeof(__be16);
734
735		if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
736			raw16 = IOAM6_U16_UNAVAILABLE;
737		else
738			raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id);
739
740		*(__be16 *)data = cpu_to_be16(raw16);
741		data += sizeof(__be16);
742	}
743
744	/* timestamp seconds */
745	if (trace->type.bit2) {
746		if (!skb->dev) {
747			*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
748		} else {
749			tstamp = skb_tstamp_cond(skb, true);
750			ts = ktime_to_timespec64(tstamp);
751
752			*(__be32 *)data = cpu_to_be32((u32)ts.tv_sec);
753		}
754		data += sizeof(__be32);
755	}
756
757	/* timestamp subseconds */
758	if (trace->type.bit3) {
759		if (!skb->dev) {
760			*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
761		} else {
762			if (!trace->type.bit2) {
763				tstamp = skb_tstamp_cond(skb, true);
764				ts = ktime_to_timespec64(tstamp);
765			}
766
767			*(__be32 *)data = cpu_to_be32((u32)(ts.tv_nsec / NSEC_PER_USEC));
768		}
769		data += sizeof(__be32);
770	}
771
772	/* transit delay */
773	if (trace->type.bit4) {
774		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
775		data += sizeof(__be32);
776	}
777
778	/* namespace data */
779	if (trace->type.bit5) {
780		*(__be32 *)data = ns->data;
781		data += sizeof(__be32);
782	}
783
784	/* queue depth */
785	if (trace->type.bit6) {
786		struct netdev_queue *queue;
787		struct Qdisc *qdisc;
788		__u32 qlen, backlog;
789
790		if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
791			*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
792		} else {
793			queue = skb_get_tx_queue(skb_dst(skb)->dev, skb);
794			qdisc = rcu_dereference(queue->qdisc);
795			qdisc_qstats_qlen_backlog(qdisc, &qlen, &backlog);
796
797			*(__be32 *)data = cpu_to_be32(backlog);
798		}
799		data += sizeof(__be32);
800	}
801
802	/* checksum complement */
803	if (trace->type.bit7) {
804		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
805		data += sizeof(__be32);
806	}
807
808	/* hop_lim and node_id (wide) */
809	if (trace->type.bit8) {
810		byte = ipv6_hdr(skb)->hop_limit;
811		if (is_input)
812			byte--;
813
814		raw64 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id_wide;
815
816		*(__be64 *)data = cpu_to_be64(((u64)byte << 56) | raw64);
817		data += sizeof(__be64);
818	}
819
820	/* ingress_if_id and egress_if_id (wide) */
821	if (trace->type.bit9) {
822		if (!skb->dev)
823			raw32 = IOAM6_U32_UNAVAILABLE;
824		else
825			raw32 = READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id_wide);
826
827		*(__be32 *)data = cpu_to_be32(raw32);
828		data += sizeof(__be32);
829
830		if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
831			raw32 = IOAM6_U32_UNAVAILABLE;
832		else
833			raw32 = READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide);
834
835		*(__be32 *)data = cpu_to_be32(raw32);
836		data += sizeof(__be32);
837	}
838
839	/* namespace data (wide) */
840	if (trace->type.bit10) {
841		*(__be64 *)data = ns->data_wide;
842		data += sizeof(__be64);
843	}
844
845	/* buffer occupancy */
846	if (trace->type.bit11) {
847		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
848		data += sizeof(__be32);
849	}
850
851	/* bit12 undefined: filled with empty value */
852	if (trace->type.bit12) {
853		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
854		data += sizeof(__be32);
855	}
856
857	/* bit13 undefined: filled with empty value */
858	if (trace->type.bit13) {
859		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
860		data += sizeof(__be32);
861	}
862
863	/* bit14 undefined: filled with empty value */
864	if (trace->type.bit14) {
865		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
866		data += sizeof(__be32);
867	}
868
869	/* bit15 undefined: filled with empty value */
870	if (trace->type.bit15) {
871		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
872		data += sizeof(__be32);
873	}
874
875	/* bit16 undefined: filled with empty value */
876	if (trace->type.bit16) {
877		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
878		data += sizeof(__be32);
879	}
880
881	/* bit17 undefined: filled with empty value */
882	if (trace->type.bit17) {
883		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
884		data += sizeof(__be32);
885	}
886
887	/* bit18 undefined: filled with empty value */
888	if (trace->type.bit18) {
889		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
890		data += sizeof(__be32);
891	}
892
893	/* bit19 undefined: filled with empty value */
894	if (trace->type.bit19) {
895		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
896		data += sizeof(__be32);
897	}
898
899	/* bit20 undefined: filled with empty value */
900	if (trace->type.bit20) {
901		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
902		data += sizeof(__be32);
903	}
904
905	/* bit21 undefined: filled with empty value */
906	if (trace->type.bit21) {
907		*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
908		data += sizeof(__be32);
909	}
910
911	/* opaque state snapshot */
912	if (trace->type.bit22) {
913		if (!sc) {
914			*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE >> 8);
915		} else {
916			*(__be32 *)data = sc->hdr;
917			data += sizeof(__be32);
918
919			memcpy(data, sc->data, sc->len);
920		}
921	}
922}
923
924/* called with rcu_read_lock() */
925void ioam6_fill_trace_data(struct sk_buff *skb,
926			   struct ioam6_namespace *ns,
927			   struct ioam6_trace_hdr *trace,
928			   bool is_input)
929{
930	struct ioam6_schema *sc;
931	u8 sclen = 0;
932
933	/* Skip if Overflow flag is set
934	 */
935	if (trace->overflow)
936		return;
937
938	/* NodeLen does not include Opaque State Snapshot length. We need to
939	 * take it into account if the corresponding bit is set (bit 22) and
940	 * if the current IOAM namespace has an active schema attached to it
941	 */
942	sc = rcu_dereference(ns->schema);
943	if (trace->type.bit22) {
944		sclen = sizeof_field(struct ioam6_schema, hdr) / 4;
945
946		if (sc)
947			sclen += sc->len / 4;
948	}
949
950	/* If there is no space remaining, we set the Overflow flag and we
951	 * skip without filling the trace
952	 */
953	if (!trace->remlen || trace->remlen < trace->nodelen + sclen) {
954		trace->overflow = 1;
955		return;
956	}
957
958	__ioam6_fill_trace_data(skb, ns, trace, sc, sclen, is_input);
959	trace->remlen -= trace->nodelen + sclen;
960}
961
962static int __net_init ioam6_net_init(struct net *net)
963{
964	struct ioam6_pernet_data *nsdata;
965	int err = -ENOMEM;
966
967	nsdata = kzalloc(sizeof(*nsdata), GFP_KERNEL);
968	if (!nsdata)
969		goto out;
970
971	mutex_init(&nsdata->lock);
972	net->ipv6.ioam6_data = nsdata;
973
974	err = rhashtable_init(&nsdata->namespaces, &rht_ns_params);
975	if (err)
976		goto free_nsdata;
977
978	err = rhashtable_init(&nsdata->schemas, &rht_sc_params);
979	if (err)
980		goto free_rht_ns;
981
982out:
983	return err;
984free_rht_ns:
985	rhashtable_destroy(&nsdata->namespaces);
986free_nsdata:
987	kfree(nsdata);
988	net->ipv6.ioam6_data = NULL;
989	goto out;
990}
991
992static void __net_exit ioam6_net_exit(struct net *net)
993{
994	struct ioam6_pernet_data *nsdata = ioam6_pernet(net);
995
996	rhashtable_free_and_destroy(&nsdata->namespaces, ioam6_free_ns, NULL);
997	rhashtable_free_and_destroy(&nsdata->schemas, ioam6_free_sc, NULL);
998
999	kfree(nsdata);
1000}
1001
1002static struct pernet_operations ioam6_net_ops = {
1003	.init = ioam6_net_init,
1004	.exit = ioam6_net_exit,
1005};
1006
1007int __init ioam6_init(void)
1008{
1009	int err = register_pernet_subsys(&ioam6_net_ops);
1010	if (err)
1011		goto out;
1012
1013	err = genl_register_family(&ioam6_genl_family);
1014	if (err)
1015		goto out_unregister_pernet_subsys;
1016
1017#ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
1018	err = ioam6_iptunnel_init();
1019	if (err)
1020		goto out_unregister_genl;
1021#endif
1022
1023	pr_info("In-situ OAM (IOAM) with IPv6\n");
1024
1025out:
1026	return err;
1027#ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
1028out_unregister_genl:
1029	genl_unregister_family(&ioam6_genl_family);
1030#endif
1031out_unregister_pernet_subsys:
1032	unregister_pernet_subsys(&ioam6_net_ops);
1033	goto out;
1034}
1035
1036void ioam6_exit(void)
1037{
1038#ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
1039	ioam6_iptunnel_exit();
1040#endif
1041	genl_unregister_family(&ioam6_genl_family);
1042	unregister_pernet_subsys(&ioam6_net_ops);
1043}
1044