Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
   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}
1