ioam6.c (22504B)
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 615static struct genl_family ioam6_genl_family __ro_after_init = { 616 .name = IOAM6_GENL_NAME, 617 .version = IOAM6_GENL_VERSION, 618 .netnsok = true, 619 .parallel_ops = true, 620 .ops = ioam6_genl_ops, 621 .n_ops = ARRAY_SIZE(ioam6_genl_ops), 622 .module = THIS_MODULE, 623}; 624 625struct ioam6_namespace *ioam6_namespace(struct net *net, __be16 id) 626{ 627 struct ioam6_pernet_data *nsdata = ioam6_pernet(net); 628 629 return rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params); 630} 631 632static void __ioam6_fill_trace_data(struct sk_buff *skb, 633 struct ioam6_namespace *ns, 634 struct ioam6_trace_hdr *trace, 635 struct ioam6_schema *sc, 636 u8 sclen, bool is_input) 637{ 638 struct timespec64 ts; 639 ktime_t tstamp; 640 u64 raw64; 641 u32 raw32; 642 u16 raw16; 643 u8 *data; 644 u8 byte; 645 646 data = trace->data + trace->remlen * 4 - trace->nodelen * 4 - sclen * 4; 647 648 /* hop_lim and node_id */ 649 if (trace->type.bit0) { 650 byte = ipv6_hdr(skb)->hop_limit; 651 if (is_input) 652 byte--; 653 654 raw32 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id; 655 656 *(__be32 *)data = cpu_to_be32((byte << 24) | raw32); 657 data += sizeof(__be32); 658 } 659 660 /* ingress_if_id and egress_if_id */ 661 if (trace->type.bit1) { 662 if (!skb->dev) 663 raw16 = IOAM6_U16_UNAVAILABLE; 664 else 665 raw16 = (__force u16)__in6_dev_get(skb->dev)->cnf.ioam6_id; 666 667 *(__be16 *)data = cpu_to_be16(raw16); 668 data += sizeof(__be16); 669 670 if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) 671 raw16 = IOAM6_U16_UNAVAILABLE; 672 else 673 raw16 = (__force u16)__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id; 674 675 *(__be16 *)data = cpu_to_be16(raw16); 676 data += sizeof(__be16); 677 } 678 679 /* timestamp seconds */ 680 if (trace->type.bit2) { 681 if (!skb->dev) { 682 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 683 } else { 684 tstamp = skb_tstamp_cond(skb, true); 685 ts = ktime_to_timespec64(tstamp); 686 687 *(__be32 *)data = cpu_to_be32((u32)ts.tv_sec); 688 } 689 data += sizeof(__be32); 690 } 691 692 /* timestamp subseconds */ 693 if (trace->type.bit3) { 694 if (!skb->dev) { 695 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 696 } else { 697 if (!trace->type.bit2) { 698 tstamp = skb_tstamp_cond(skb, true); 699 ts = ktime_to_timespec64(tstamp); 700 } 701 702 *(__be32 *)data = cpu_to_be32((u32)(ts.tv_nsec / NSEC_PER_USEC)); 703 } 704 data += sizeof(__be32); 705 } 706 707 /* transit delay */ 708 if (trace->type.bit4) { 709 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 710 data += sizeof(__be32); 711 } 712 713 /* namespace data */ 714 if (trace->type.bit5) { 715 *(__be32 *)data = ns->data; 716 data += sizeof(__be32); 717 } 718 719 /* queue depth */ 720 if (trace->type.bit6) { 721 struct netdev_queue *queue; 722 struct Qdisc *qdisc; 723 __u32 qlen, backlog; 724 725 if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) { 726 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 727 } else { 728 queue = skb_get_tx_queue(skb_dst(skb)->dev, skb); 729 qdisc = rcu_dereference(queue->qdisc); 730 qdisc_qstats_qlen_backlog(qdisc, &qlen, &backlog); 731 732 *(__be32 *)data = cpu_to_be32(backlog); 733 } 734 data += sizeof(__be32); 735 } 736 737 /* checksum complement */ 738 if (trace->type.bit7) { 739 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 740 data += sizeof(__be32); 741 } 742 743 /* hop_lim and node_id (wide) */ 744 if (trace->type.bit8) { 745 byte = ipv6_hdr(skb)->hop_limit; 746 if (is_input) 747 byte--; 748 749 raw64 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id_wide; 750 751 *(__be64 *)data = cpu_to_be64(((u64)byte << 56) | raw64); 752 data += sizeof(__be64); 753 } 754 755 /* ingress_if_id and egress_if_id (wide) */ 756 if (trace->type.bit9) { 757 if (!skb->dev) 758 raw32 = IOAM6_U32_UNAVAILABLE; 759 else 760 raw32 = __in6_dev_get(skb->dev)->cnf.ioam6_id_wide; 761 762 *(__be32 *)data = cpu_to_be32(raw32); 763 data += sizeof(__be32); 764 765 if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) 766 raw32 = IOAM6_U32_UNAVAILABLE; 767 else 768 raw32 = __in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide; 769 770 *(__be32 *)data = cpu_to_be32(raw32); 771 data += sizeof(__be32); 772 } 773 774 /* namespace data (wide) */ 775 if (trace->type.bit10) { 776 *(__be64 *)data = ns->data_wide; 777 data += sizeof(__be64); 778 } 779 780 /* buffer occupancy */ 781 if (trace->type.bit11) { 782 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 783 data += sizeof(__be32); 784 } 785 786 /* bit12 undefined: filled with empty value */ 787 if (trace->type.bit12) { 788 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 789 data += sizeof(__be32); 790 } 791 792 /* bit13 undefined: filled with empty value */ 793 if (trace->type.bit13) { 794 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 795 data += sizeof(__be32); 796 } 797 798 /* bit14 undefined: filled with empty value */ 799 if (trace->type.bit14) { 800 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 801 data += sizeof(__be32); 802 } 803 804 /* bit15 undefined: filled with empty value */ 805 if (trace->type.bit15) { 806 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 807 data += sizeof(__be32); 808 } 809 810 /* bit16 undefined: filled with empty value */ 811 if (trace->type.bit16) { 812 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 813 data += sizeof(__be32); 814 } 815 816 /* bit17 undefined: filled with empty value */ 817 if (trace->type.bit17) { 818 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 819 data += sizeof(__be32); 820 } 821 822 /* bit18 undefined: filled with empty value */ 823 if (trace->type.bit18) { 824 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 825 data += sizeof(__be32); 826 } 827 828 /* bit19 undefined: filled with empty value */ 829 if (trace->type.bit19) { 830 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 831 data += sizeof(__be32); 832 } 833 834 /* bit20 undefined: filled with empty value */ 835 if (trace->type.bit20) { 836 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 837 data += sizeof(__be32); 838 } 839 840 /* bit21 undefined: filled with empty value */ 841 if (trace->type.bit21) { 842 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE); 843 data += sizeof(__be32); 844 } 845 846 /* opaque state snapshot */ 847 if (trace->type.bit22) { 848 if (!sc) { 849 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE >> 8); 850 } else { 851 *(__be32 *)data = sc->hdr; 852 data += sizeof(__be32); 853 854 memcpy(data, sc->data, sc->len); 855 } 856 } 857} 858 859/* called with rcu_read_lock() */ 860void ioam6_fill_trace_data(struct sk_buff *skb, 861 struct ioam6_namespace *ns, 862 struct ioam6_trace_hdr *trace, 863 bool is_input) 864{ 865 struct ioam6_schema *sc; 866 u8 sclen = 0; 867 868 /* Skip if Overflow flag is set 869 */ 870 if (trace->overflow) 871 return; 872 873 /* NodeLen does not include Opaque State Snapshot length. We need to 874 * take it into account if the corresponding bit is set (bit 22) and 875 * if the current IOAM namespace has an active schema attached to it 876 */ 877 sc = rcu_dereference(ns->schema); 878 if (trace->type.bit22) { 879 sclen = sizeof_field(struct ioam6_schema, hdr) / 4; 880 881 if (sc) 882 sclen += sc->len / 4; 883 } 884 885 /* If there is no space remaining, we set the Overflow flag and we 886 * skip without filling the trace 887 */ 888 if (!trace->remlen || trace->remlen < trace->nodelen + sclen) { 889 trace->overflow = 1; 890 return; 891 } 892 893 __ioam6_fill_trace_data(skb, ns, trace, sc, sclen, is_input); 894 trace->remlen -= trace->nodelen + sclen; 895} 896 897static int __net_init ioam6_net_init(struct net *net) 898{ 899 struct ioam6_pernet_data *nsdata; 900 int err = -ENOMEM; 901 902 nsdata = kzalloc(sizeof(*nsdata), GFP_KERNEL); 903 if (!nsdata) 904 goto out; 905 906 mutex_init(&nsdata->lock); 907 net->ipv6.ioam6_data = nsdata; 908 909 err = rhashtable_init(&nsdata->namespaces, &rht_ns_params); 910 if (err) 911 goto free_nsdata; 912 913 err = rhashtable_init(&nsdata->schemas, &rht_sc_params); 914 if (err) 915 goto free_rht_ns; 916 917out: 918 return err; 919free_rht_ns: 920 rhashtable_destroy(&nsdata->namespaces); 921free_nsdata: 922 kfree(nsdata); 923 net->ipv6.ioam6_data = NULL; 924 goto out; 925} 926 927static void __net_exit ioam6_net_exit(struct net *net) 928{ 929 struct ioam6_pernet_data *nsdata = ioam6_pernet(net); 930 931 rhashtable_free_and_destroy(&nsdata->namespaces, ioam6_free_ns, NULL); 932 rhashtable_free_and_destroy(&nsdata->schemas, ioam6_free_sc, NULL); 933 934 kfree(nsdata); 935} 936 937static struct pernet_operations ioam6_net_ops = { 938 .init = ioam6_net_init, 939 .exit = ioam6_net_exit, 940}; 941 942int __init ioam6_init(void) 943{ 944 int err = register_pernet_subsys(&ioam6_net_ops); 945 if (err) 946 goto out; 947 948 err = genl_register_family(&ioam6_genl_family); 949 if (err) 950 goto out_unregister_pernet_subsys; 951 952#ifdef CONFIG_IPV6_IOAM6_LWTUNNEL 953 err = ioam6_iptunnel_init(); 954 if (err) 955 goto out_unregister_genl; 956#endif 957 958 pr_info("In-situ OAM (IOAM) with IPv6\n"); 959 960out: 961 return err; 962#ifdef CONFIG_IPV6_IOAM6_LWTUNNEL 963out_unregister_genl: 964 genl_unregister_family(&ioam6_genl_family); 965#endif 966out_unregister_pernet_subsys: 967 unregister_pernet_subsys(&ioam6_net_ops); 968 goto out; 969} 970 971void ioam6_exit(void) 972{ 973#ifdef CONFIG_IPV6_IOAM6_LWTUNNEL 974 ioam6_iptunnel_exit(); 975#endif 976 genl_unregister_family(&ioam6_genl_family); 977 unregister_pernet_subsys(&ioam6_net_ops); 978}