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