0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/errno.h>
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/net.h>
0013 #include <linux/ioam6.h>
0014 #include <linux/ioam6_genl.h>
0015 #include <linux/rhashtable.h>
0016 #include <linux/netdevice.h>
0017
0018 #include <net/addrconf.h>
0019 #include <net/genetlink.h>
0020 #include <net/ioam6.h>
0021 #include <net/sch_generic.h>
0022
0023 static void ioam6_ns_release(struct ioam6_namespace *ns)
0024 {
0025 kfree_rcu(ns, rcu);
0026 }
0027
0028 static void ioam6_sc_release(struct ioam6_schema *sc)
0029 {
0030 kfree_rcu(sc, rcu);
0031 }
0032
0033 static void ioam6_free_ns(void *ptr, void *arg)
0034 {
0035 struct ioam6_namespace *ns = (struct ioam6_namespace *)ptr;
0036
0037 if (ns)
0038 ioam6_ns_release(ns);
0039 }
0040
0041 static void ioam6_free_sc(void *ptr, void *arg)
0042 {
0043 struct ioam6_schema *sc = (struct ioam6_schema *)ptr;
0044
0045 if (sc)
0046 ioam6_sc_release(sc);
0047 }
0048
0049 static int ioam6_ns_cmpfn(struct rhashtable_compare_arg *arg, const void *obj)
0050 {
0051 const struct ioam6_namespace *ns = obj;
0052
0053 return (ns->id != *(__be16 *)arg->key);
0054 }
0055
0056 static int ioam6_sc_cmpfn(struct rhashtable_compare_arg *arg, const void *obj)
0057 {
0058 const struct ioam6_schema *sc = obj;
0059
0060 return (sc->id != *(u32 *)arg->key);
0061 }
0062
0063 static const struct rhashtable_params rht_ns_params = {
0064 .key_len = sizeof(__be16),
0065 .key_offset = offsetof(struct ioam6_namespace, id),
0066 .head_offset = offsetof(struct ioam6_namespace, head),
0067 .automatic_shrinking = true,
0068 .obj_cmpfn = ioam6_ns_cmpfn,
0069 };
0070
0071 static const struct rhashtable_params rht_sc_params = {
0072 .key_len = sizeof(u32),
0073 .key_offset = offsetof(struct ioam6_schema, id),
0074 .head_offset = offsetof(struct ioam6_schema, head),
0075 .automatic_shrinking = true,
0076 .obj_cmpfn = ioam6_sc_cmpfn,
0077 };
0078
0079 static struct genl_family ioam6_genl_family;
0080
0081 static const struct nla_policy ioam6_genl_policy_addns[] = {
0082 [IOAM6_ATTR_NS_ID] = { .type = NLA_U16 },
0083 [IOAM6_ATTR_NS_DATA] = { .type = NLA_U32 },
0084 [IOAM6_ATTR_NS_DATA_WIDE] = { .type = NLA_U64 },
0085 };
0086
0087 static const struct nla_policy ioam6_genl_policy_delns[] = {
0088 [IOAM6_ATTR_NS_ID] = { .type = NLA_U16 },
0089 };
0090
0091 static const struct nla_policy ioam6_genl_policy_addsc[] = {
0092 [IOAM6_ATTR_SC_ID] = { .type = NLA_U32 },
0093 [IOAM6_ATTR_SC_DATA] = { .type = NLA_BINARY,
0094 .len = IOAM6_MAX_SCHEMA_DATA_LEN },
0095 };
0096
0097 static const struct nla_policy ioam6_genl_policy_delsc[] = {
0098 [IOAM6_ATTR_SC_ID] = { .type = NLA_U32 },
0099 };
0100
0101 static const struct nla_policy ioam6_genl_policy_ns_sc[] = {
0102 [IOAM6_ATTR_NS_ID] = { .type = NLA_U16 },
0103 [IOAM6_ATTR_SC_ID] = { .type = NLA_U32 },
0104 [IOAM6_ATTR_SC_NONE] = { .type = NLA_FLAG },
0105 };
0106
0107 static int ioam6_genl_addns(struct sk_buff *skb, struct genl_info *info)
0108 {
0109 struct ioam6_pernet_data *nsdata;
0110 struct ioam6_namespace *ns;
0111 u64 data64;
0112 u32 data32;
0113 __be16 id;
0114 int err;
0115
0116 if (!info->attrs[IOAM6_ATTR_NS_ID])
0117 return -EINVAL;
0118
0119 id = cpu_to_be16(nla_get_u16(info->attrs[IOAM6_ATTR_NS_ID]));
0120 nsdata = ioam6_pernet(genl_info_net(info));
0121
0122 mutex_lock(&nsdata->lock);
0123
0124 ns = rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
0125 if (ns) {
0126 err = -EEXIST;
0127 goto out_unlock;
0128 }
0129
0130 ns = kzalloc(sizeof(*ns), GFP_KERNEL);
0131 if (!ns) {
0132 err = -ENOMEM;
0133 goto out_unlock;
0134 }
0135
0136 ns->id = id;
0137
0138 if (!info->attrs[IOAM6_ATTR_NS_DATA])
0139 data32 = IOAM6_U32_UNAVAILABLE;
0140 else
0141 data32 = nla_get_u32(info->attrs[IOAM6_ATTR_NS_DATA]);
0142
0143 if (!info->attrs[IOAM6_ATTR_NS_DATA_WIDE])
0144 data64 = IOAM6_U64_UNAVAILABLE;
0145 else
0146 data64 = nla_get_u64(info->attrs[IOAM6_ATTR_NS_DATA_WIDE]);
0147
0148 ns->data = cpu_to_be32(data32);
0149 ns->data_wide = cpu_to_be64(data64);
0150
0151 err = rhashtable_lookup_insert_fast(&nsdata->namespaces, &ns->head,
0152 rht_ns_params);
0153 if (err)
0154 kfree(ns);
0155
0156 out_unlock:
0157 mutex_unlock(&nsdata->lock);
0158 return err;
0159 }
0160
0161 static int ioam6_genl_delns(struct sk_buff *skb, struct genl_info *info)
0162 {
0163 struct ioam6_pernet_data *nsdata;
0164 struct ioam6_namespace *ns;
0165 struct ioam6_schema *sc;
0166 __be16 id;
0167 int err;
0168
0169 if (!info->attrs[IOAM6_ATTR_NS_ID])
0170 return -EINVAL;
0171
0172 id = cpu_to_be16(nla_get_u16(info->attrs[IOAM6_ATTR_NS_ID]));
0173 nsdata = ioam6_pernet(genl_info_net(info));
0174
0175 mutex_lock(&nsdata->lock);
0176
0177 ns = rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
0178 if (!ns) {
0179 err = -ENOENT;
0180 goto out_unlock;
0181 }
0182
0183 sc = rcu_dereference_protected(ns->schema,
0184 lockdep_is_held(&nsdata->lock));
0185
0186 err = rhashtable_remove_fast(&nsdata->namespaces, &ns->head,
0187 rht_ns_params);
0188 if (err)
0189 goto out_unlock;
0190
0191 if (sc)
0192 rcu_assign_pointer(sc->ns, NULL);
0193
0194 ioam6_ns_release(ns);
0195
0196 out_unlock:
0197 mutex_unlock(&nsdata->lock);
0198 return err;
0199 }
0200
0201 static int __ioam6_genl_dumpns_element(struct ioam6_namespace *ns,
0202 u32 portid,
0203 u32 seq,
0204 u32 flags,
0205 struct sk_buff *skb,
0206 u8 cmd)
0207 {
0208 struct ioam6_schema *sc;
0209 u64 data64;
0210 u32 data32;
0211 void *hdr;
0212
0213 hdr = genlmsg_put(skb, portid, seq, &ioam6_genl_family, flags, cmd);
0214 if (!hdr)
0215 return -ENOMEM;
0216
0217 data32 = be32_to_cpu(ns->data);
0218 data64 = be64_to_cpu(ns->data_wide);
0219
0220 if (nla_put_u16(skb, IOAM6_ATTR_NS_ID, be16_to_cpu(ns->id)) ||
0221 (data32 != IOAM6_U32_UNAVAILABLE &&
0222 nla_put_u32(skb, IOAM6_ATTR_NS_DATA, data32)) ||
0223 (data64 != IOAM6_U64_UNAVAILABLE &&
0224 nla_put_u64_64bit(skb, IOAM6_ATTR_NS_DATA_WIDE,
0225 data64, IOAM6_ATTR_PAD)))
0226 goto nla_put_failure;
0227
0228 rcu_read_lock();
0229
0230 sc = rcu_dereference(ns->schema);
0231 if (sc && nla_put_u32(skb, IOAM6_ATTR_SC_ID, sc->id)) {
0232 rcu_read_unlock();
0233 goto nla_put_failure;
0234 }
0235
0236 rcu_read_unlock();
0237
0238 genlmsg_end(skb, hdr);
0239 return 0;
0240
0241 nla_put_failure:
0242 genlmsg_cancel(skb, hdr);
0243 return -EMSGSIZE;
0244 }
0245
0246 static int ioam6_genl_dumpns_start(struct netlink_callback *cb)
0247 {
0248 struct ioam6_pernet_data *nsdata = ioam6_pernet(sock_net(cb->skb->sk));
0249 struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
0250
0251 if (!iter) {
0252 iter = kmalloc(sizeof(*iter), GFP_KERNEL);
0253 if (!iter)
0254 return -ENOMEM;
0255
0256 cb->args[0] = (long)iter;
0257 }
0258
0259 rhashtable_walk_enter(&nsdata->namespaces, iter);
0260
0261 return 0;
0262 }
0263
0264 static int ioam6_genl_dumpns_done(struct netlink_callback *cb)
0265 {
0266 struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
0267
0268 rhashtable_walk_exit(iter);
0269 kfree(iter);
0270
0271 return 0;
0272 }
0273
0274 static int ioam6_genl_dumpns(struct sk_buff *skb, struct netlink_callback *cb)
0275 {
0276 struct rhashtable_iter *iter;
0277 struct ioam6_namespace *ns;
0278 int err;
0279
0280 iter = (struct rhashtable_iter *)cb->args[0];
0281 rhashtable_walk_start(iter);
0282
0283 for (;;) {
0284 ns = rhashtable_walk_next(iter);
0285
0286 if (IS_ERR(ns)) {
0287 if (PTR_ERR(ns) == -EAGAIN)
0288 continue;
0289 err = PTR_ERR(ns);
0290 goto done;
0291 } else if (!ns) {
0292 break;
0293 }
0294
0295 err = __ioam6_genl_dumpns_element(ns,
0296 NETLINK_CB(cb->skb).portid,
0297 cb->nlh->nlmsg_seq,
0298 NLM_F_MULTI,
0299 skb,
0300 IOAM6_CMD_DUMP_NAMESPACES);
0301 if (err)
0302 goto done;
0303 }
0304
0305 err = skb->len;
0306
0307 done:
0308 rhashtable_walk_stop(iter);
0309 return err;
0310 }
0311
0312 static int ioam6_genl_addsc(struct sk_buff *skb, struct genl_info *info)
0313 {
0314 struct ioam6_pernet_data *nsdata;
0315 int len, len_aligned, err;
0316 struct ioam6_schema *sc;
0317 u32 id;
0318
0319 if (!info->attrs[IOAM6_ATTR_SC_ID] || !info->attrs[IOAM6_ATTR_SC_DATA])
0320 return -EINVAL;
0321
0322 id = nla_get_u32(info->attrs[IOAM6_ATTR_SC_ID]);
0323 nsdata = ioam6_pernet(genl_info_net(info));
0324
0325 mutex_lock(&nsdata->lock);
0326
0327 sc = rhashtable_lookup_fast(&nsdata->schemas, &id, rht_sc_params);
0328 if (sc) {
0329 err = -EEXIST;
0330 goto out_unlock;
0331 }
0332
0333 len = nla_len(info->attrs[IOAM6_ATTR_SC_DATA]);
0334 len_aligned = ALIGN(len, 4);
0335
0336 sc = kzalloc(sizeof(*sc) + len_aligned, GFP_KERNEL);
0337 if (!sc) {
0338 err = -ENOMEM;
0339 goto out_unlock;
0340 }
0341
0342 sc->id = id;
0343 sc->len = len_aligned;
0344 sc->hdr = cpu_to_be32(sc->id | ((u8)(sc->len / 4) << 24));
0345 nla_memcpy(sc->data, info->attrs[IOAM6_ATTR_SC_DATA], len);
0346
0347 err = rhashtable_lookup_insert_fast(&nsdata->schemas, &sc->head,
0348 rht_sc_params);
0349 if (err)
0350 goto free_sc;
0351
0352 out_unlock:
0353 mutex_unlock(&nsdata->lock);
0354 return err;
0355 free_sc:
0356 kfree(sc);
0357 goto out_unlock;
0358 }
0359
0360 static int ioam6_genl_delsc(struct sk_buff *skb, struct genl_info *info)
0361 {
0362 struct ioam6_pernet_data *nsdata;
0363 struct ioam6_namespace *ns;
0364 struct ioam6_schema *sc;
0365 int err;
0366 u32 id;
0367
0368 if (!info->attrs[IOAM6_ATTR_SC_ID])
0369 return -EINVAL;
0370
0371 id = nla_get_u32(info->attrs[IOAM6_ATTR_SC_ID]);
0372 nsdata = ioam6_pernet(genl_info_net(info));
0373
0374 mutex_lock(&nsdata->lock);
0375
0376 sc = rhashtable_lookup_fast(&nsdata->schemas, &id, rht_sc_params);
0377 if (!sc) {
0378 err = -ENOENT;
0379 goto out_unlock;
0380 }
0381
0382 ns = rcu_dereference_protected(sc->ns, lockdep_is_held(&nsdata->lock));
0383
0384 err = rhashtable_remove_fast(&nsdata->schemas, &sc->head,
0385 rht_sc_params);
0386 if (err)
0387 goto out_unlock;
0388
0389 if (ns)
0390 rcu_assign_pointer(ns->schema, NULL);
0391
0392 ioam6_sc_release(sc);
0393
0394 out_unlock:
0395 mutex_unlock(&nsdata->lock);
0396 return err;
0397 }
0398
0399 static int __ioam6_genl_dumpsc_element(struct ioam6_schema *sc,
0400 u32 portid, u32 seq, u32 flags,
0401 struct sk_buff *skb, u8 cmd)
0402 {
0403 struct ioam6_namespace *ns;
0404 void *hdr;
0405
0406 hdr = genlmsg_put(skb, portid, seq, &ioam6_genl_family, flags, cmd);
0407 if (!hdr)
0408 return -ENOMEM;
0409
0410 if (nla_put_u32(skb, IOAM6_ATTR_SC_ID, sc->id) ||
0411 nla_put(skb, IOAM6_ATTR_SC_DATA, sc->len, sc->data))
0412 goto nla_put_failure;
0413
0414 rcu_read_lock();
0415
0416 ns = rcu_dereference(sc->ns);
0417 if (ns && nla_put_u16(skb, IOAM6_ATTR_NS_ID, be16_to_cpu(ns->id))) {
0418 rcu_read_unlock();
0419 goto nla_put_failure;
0420 }
0421
0422 rcu_read_unlock();
0423
0424 genlmsg_end(skb, hdr);
0425 return 0;
0426
0427 nla_put_failure:
0428 genlmsg_cancel(skb, hdr);
0429 return -EMSGSIZE;
0430 }
0431
0432 static int ioam6_genl_dumpsc_start(struct netlink_callback *cb)
0433 {
0434 struct ioam6_pernet_data *nsdata = ioam6_pernet(sock_net(cb->skb->sk));
0435 struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
0436
0437 if (!iter) {
0438 iter = kmalloc(sizeof(*iter), GFP_KERNEL);
0439 if (!iter)
0440 return -ENOMEM;
0441
0442 cb->args[0] = (long)iter;
0443 }
0444
0445 rhashtable_walk_enter(&nsdata->schemas, iter);
0446
0447 return 0;
0448 }
0449
0450 static int ioam6_genl_dumpsc_done(struct netlink_callback *cb)
0451 {
0452 struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
0453
0454 rhashtable_walk_exit(iter);
0455 kfree(iter);
0456
0457 return 0;
0458 }
0459
0460 static int ioam6_genl_dumpsc(struct sk_buff *skb, struct netlink_callback *cb)
0461 {
0462 struct rhashtable_iter *iter;
0463 struct ioam6_schema *sc;
0464 int err;
0465
0466 iter = (struct rhashtable_iter *)cb->args[0];
0467 rhashtable_walk_start(iter);
0468
0469 for (;;) {
0470 sc = rhashtable_walk_next(iter);
0471
0472 if (IS_ERR(sc)) {
0473 if (PTR_ERR(sc) == -EAGAIN)
0474 continue;
0475 err = PTR_ERR(sc);
0476 goto done;
0477 } else if (!sc) {
0478 break;
0479 }
0480
0481 err = __ioam6_genl_dumpsc_element(sc,
0482 NETLINK_CB(cb->skb).portid,
0483 cb->nlh->nlmsg_seq,
0484 NLM_F_MULTI,
0485 skb,
0486 IOAM6_CMD_DUMP_SCHEMAS);
0487 if (err)
0488 goto done;
0489 }
0490
0491 err = skb->len;
0492
0493 done:
0494 rhashtable_walk_stop(iter);
0495 return err;
0496 }
0497
0498 static int ioam6_genl_ns_set_schema(struct sk_buff *skb, struct genl_info *info)
0499 {
0500 struct ioam6_namespace *ns, *ns_ref;
0501 struct ioam6_schema *sc, *sc_ref;
0502 struct ioam6_pernet_data *nsdata;
0503 __be16 ns_id;
0504 u32 sc_id;
0505 int err;
0506
0507 if (!info->attrs[IOAM6_ATTR_NS_ID] ||
0508 (!info->attrs[IOAM6_ATTR_SC_ID] &&
0509 !info->attrs[IOAM6_ATTR_SC_NONE]))
0510 return -EINVAL;
0511
0512 ns_id = cpu_to_be16(nla_get_u16(info->attrs[IOAM6_ATTR_NS_ID]));
0513 nsdata = ioam6_pernet(genl_info_net(info));
0514
0515 mutex_lock(&nsdata->lock);
0516
0517 ns = rhashtable_lookup_fast(&nsdata->namespaces, &ns_id, rht_ns_params);
0518 if (!ns) {
0519 err = -ENOENT;
0520 goto out_unlock;
0521 }
0522
0523 if (info->attrs[IOAM6_ATTR_SC_NONE]) {
0524 sc = NULL;
0525 } else {
0526 sc_id = nla_get_u32(info->attrs[IOAM6_ATTR_SC_ID]);
0527 sc = rhashtable_lookup_fast(&nsdata->schemas, &sc_id,
0528 rht_sc_params);
0529 if (!sc) {
0530 err = -ENOENT;
0531 goto out_unlock;
0532 }
0533 }
0534
0535 sc_ref = rcu_dereference_protected(ns->schema,
0536 lockdep_is_held(&nsdata->lock));
0537 if (sc_ref)
0538 rcu_assign_pointer(sc_ref->ns, NULL);
0539 rcu_assign_pointer(ns->schema, sc);
0540
0541 if (sc) {
0542 ns_ref = rcu_dereference_protected(sc->ns,
0543 lockdep_is_held(&nsdata->lock));
0544 if (ns_ref)
0545 rcu_assign_pointer(ns_ref->schema, NULL);
0546 rcu_assign_pointer(sc->ns, ns);
0547 }
0548
0549 err = 0;
0550
0551 out_unlock:
0552 mutex_unlock(&nsdata->lock);
0553 return err;
0554 }
0555
0556 static const struct genl_ops ioam6_genl_ops[] = {
0557 {
0558 .cmd = IOAM6_CMD_ADD_NAMESPACE,
0559 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0560 .doit = ioam6_genl_addns,
0561 .flags = GENL_ADMIN_PERM,
0562 .policy = ioam6_genl_policy_addns,
0563 .maxattr = ARRAY_SIZE(ioam6_genl_policy_addns) - 1,
0564 },
0565 {
0566 .cmd = IOAM6_CMD_DEL_NAMESPACE,
0567 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0568 .doit = ioam6_genl_delns,
0569 .flags = GENL_ADMIN_PERM,
0570 .policy = ioam6_genl_policy_delns,
0571 .maxattr = ARRAY_SIZE(ioam6_genl_policy_delns) - 1,
0572 },
0573 {
0574 .cmd = IOAM6_CMD_DUMP_NAMESPACES,
0575 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0576 .start = ioam6_genl_dumpns_start,
0577 .dumpit = ioam6_genl_dumpns,
0578 .done = ioam6_genl_dumpns_done,
0579 .flags = GENL_ADMIN_PERM,
0580 },
0581 {
0582 .cmd = IOAM6_CMD_ADD_SCHEMA,
0583 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0584 .doit = ioam6_genl_addsc,
0585 .flags = GENL_ADMIN_PERM,
0586 .policy = ioam6_genl_policy_addsc,
0587 .maxattr = ARRAY_SIZE(ioam6_genl_policy_addsc) - 1,
0588 },
0589 {
0590 .cmd = IOAM6_CMD_DEL_SCHEMA,
0591 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0592 .doit = ioam6_genl_delsc,
0593 .flags = GENL_ADMIN_PERM,
0594 .policy = ioam6_genl_policy_delsc,
0595 .maxattr = ARRAY_SIZE(ioam6_genl_policy_delsc) - 1,
0596 },
0597 {
0598 .cmd = IOAM6_CMD_DUMP_SCHEMAS,
0599 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0600 .start = ioam6_genl_dumpsc_start,
0601 .dumpit = ioam6_genl_dumpsc,
0602 .done = ioam6_genl_dumpsc_done,
0603 .flags = GENL_ADMIN_PERM,
0604 },
0605 {
0606 .cmd = IOAM6_CMD_NS_SET_SCHEMA,
0607 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0608 .doit = ioam6_genl_ns_set_schema,
0609 .flags = GENL_ADMIN_PERM,
0610 .policy = ioam6_genl_policy_ns_sc,
0611 .maxattr = ARRAY_SIZE(ioam6_genl_policy_ns_sc) - 1,
0612 },
0613 };
0614
0615 static struct genl_family ioam6_genl_family __ro_after_init = {
0616 .name = IOAM6_GENL_NAME,
0617 .version = IOAM6_GENL_VERSION,
0618 .netnsok = true,
0619 .parallel_ops = true,
0620 .ops = ioam6_genl_ops,
0621 .n_ops = ARRAY_SIZE(ioam6_genl_ops),
0622 .module = THIS_MODULE,
0623 };
0624
0625 struct ioam6_namespace *ioam6_namespace(struct net *net, __be16 id)
0626 {
0627 struct ioam6_pernet_data *nsdata = ioam6_pernet(net);
0628
0629 return rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
0630 }
0631
0632 static void __ioam6_fill_trace_data(struct sk_buff *skb,
0633 struct ioam6_namespace *ns,
0634 struct ioam6_trace_hdr *trace,
0635 struct ioam6_schema *sc,
0636 u8 sclen, bool is_input)
0637 {
0638 struct timespec64 ts;
0639 ktime_t tstamp;
0640 u64 raw64;
0641 u32 raw32;
0642 u16 raw16;
0643 u8 *data;
0644 u8 byte;
0645
0646 data = trace->data + trace->remlen * 4 - trace->nodelen * 4 - sclen * 4;
0647
0648
0649 if (trace->type.bit0) {
0650 byte = ipv6_hdr(skb)->hop_limit;
0651 if (is_input)
0652 byte--;
0653
0654 raw32 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id;
0655
0656 *(__be32 *)data = cpu_to_be32((byte << 24) | raw32);
0657 data += sizeof(__be32);
0658 }
0659
0660
0661 if (trace->type.bit1) {
0662 if (!skb->dev)
0663 raw16 = IOAM6_U16_UNAVAILABLE;
0664 else
0665 raw16 = (__force u16)__in6_dev_get(skb->dev)->cnf.ioam6_id;
0666
0667 *(__be16 *)data = cpu_to_be16(raw16);
0668 data += sizeof(__be16);
0669
0670 if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
0671 raw16 = IOAM6_U16_UNAVAILABLE;
0672 else
0673 raw16 = (__force u16)__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id;
0674
0675 *(__be16 *)data = cpu_to_be16(raw16);
0676 data += sizeof(__be16);
0677 }
0678
0679
0680 if (trace->type.bit2) {
0681 if (!skb->dev) {
0682 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0683 } else {
0684 tstamp = skb_tstamp_cond(skb, true);
0685 ts = ktime_to_timespec64(tstamp);
0686
0687 *(__be32 *)data = cpu_to_be32((u32)ts.tv_sec);
0688 }
0689 data += sizeof(__be32);
0690 }
0691
0692
0693 if (trace->type.bit3) {
0694 if (!skb->dev) {
0695 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0696 } else {
0697 if (!trace->type.bit2) {
0698 tstamp = skb_tstamp_cond(skb, true);
0699 ts = ktime_to_timespec64(tstamp);
0700 }
0701
0702 *(__be32 *)data = cpu_to_be32((u32)(ts.tv_nsec / NSEC_PER_USEC));
0703 }
0704 data += sizeof(__be32);
0705 }
0706
0707
0708 if (trace->type.bit4) {
0709 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0710 data += sizeof(__be32);
0711 }
0712
0713
0714 if (trace->type.bit5) {
0715 *(__be32 *)data = ns->data;
0716 data += sizeof(__be32);
0717 }
0718
0719
0720 if (trace->type.bit6) {
0721 struct netdev_queue *queue;
0722 struct Qdisc *qdisc;
0723 __u32 qlen, backlog;
0724
0725 if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
0726 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0727 } else {
0728 queue = skb_get_tx_queue(skb_dst(skb)->dev, skb);
0729 qdisc = rcu_dereference(queue->qdisc);
0730 qdisc_qstats_qlen_backlog(qdisc, &qlen, &backlog);
0731
0732 *(__be32 *)data = cpu_to_be32(backlog);
0733 }
0734 data += sizeof(__be32);
0735 }
0736
0737
0738 if (trace->type.bit7) {
0739 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0740 data += sizeof(__be32);
0741 }
0742
0743
0744 if (trace->type.bit8) {
0745 byte = ipv6_hdr(skb)->hop_limit;
0746 if (is_input)
0747 byte--;
0748
0749 raw64 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id_wide;
0750
0751 *(__be64 *)data = cpu_to_be64(((u64)byte << 56) | raw64);
0752 data += sizeof(__be64);
0753 }
0754
0755
0756 if (trace->type.bit9) {
0757 if (!skb->dev)
0758 raw32 = IOAM6_U32_UNAVAILABLE;
0759 else
0760 raw32 = __in6_dev_get(skb->dev)->cnf.ioam6_id_wide;
0761
0762 *(__be32 *)data = cpu_to_be32(raw32);
0763 data += sizeof(__be32);
0764
0765 if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
0766 raw32 = IOAM6_U32_UNAVAILABLE;
0767 else
0768 raw32 = __in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide;
0769
0770 *(__be32 *)data = cpu_to_be32(raw32);
0771 data += sizeof(__be32);
0772 }
0773
0774
0775 if (trace->type.bit10) {
0776 *(__be64 *)data = ns->data_wide;
0777 data += sizeof(__be64);
0778 }
0779
0780
0781 if (trace->type.bit11) {
0782 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0783 data += sizeof(__be32);
0784 }
0785
0786
0787 if (trace->type.bit12) {
0788 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0789 data += sizeof(__be32);
0790 }
0791
0792
0793 if (trace->type.bit13) {
0794 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0795 data += sizeof(__be32);
0796 }
0797
0798
0799 if (trace->type.bit14) {
0800 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0801 data += sizeof(__be32);
0802 }
0803
0804
0805 if (trace->type.bit15) {
0806 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0807 data += sizeof(__be32);
0808 }
0809
0810
0811 if (trace->type.bit16) {
0812 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0813 data += sizeof(__be32);
0814 }
0815
0816
0817 if (trace->type.bit17) {
0818 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0819 data += sizeof(__be32);
0820 }
0821
0822
0823 if (trace->type.bit18) {
0824 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0825 data += sizeof(__be32);
0826 }
0827
0828
0829 if (trace->type.bit19) {
0830 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0831 data += sizeof(__be32);
0832 }
0833
0834
0835 if (trace->type.bit20) {
0836 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0837 data += sizeof(__be32);
0838 }
0839
0840
0841 if (trace->type.bit21) {
0842 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0843 data += sizeof(__be32);
0844 }
0845
0846
0847 if (trace->type.bit22) {
0848 if (!sc) {
0849 *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE >> 8);
0850 } else {
0851 *(__be32 *)data = sc->hdr;
0852 data += sizeof(__be32);
0853
0854 memcpy(data, sc->data, sc->len);
0855 }
0856 }
0857 }
0858
0859
0860 void ioam6_fill_trace_data(struct sk_buff *skb,
0861 struct ioam6_namespace *ns,
0862 struct ioam6_trace_hdr *trace,
0863 bool is_input)
0864 {
0865 struct ioam6_schema *sc;
0866 u8 sclen = 0;
0867
0868
0869
0870 if (trace->overflow)
0871 return;
0872
0873
0874
0875
0876
0877 sc = rcu_dereference(ns->schema);
0878 if (trace->type.bit22) {
0879 sclen = sizeof_field(struct ioam6_schema, hdr) / 4;
0880
0881 if (sc)
0882 sclen += sc->len / 4;
0883 }
0884
0885
0886
0887
0888 if (!trace->remlen || trace->remlen < trace->nodelen + sclen) {
0889 trace->overflow = 1;
0890 return;
0891 }
0892
0893 __ioam6_fill_trace_data(skb, ns, trace, sc, sclen, is_input);
0894 trace->remlen -= trace->nodelen + sclen;
0895 }
0896
0897 static int __net_init ioam6_net_init(struct net *net)
0898 {
0899 struct ioam6_pernet_data *nsdata;
0900 int err = -ENOMEM;
0901
0902 nsdata = kzalloc(sizeof(*nsdata), GFP_KERNEL);
0903 if (!nsdata)
0904 goto out;
0905
0906 mutex_init(&nsdata->lock);
0907 net->ipv6.ioam6_data = nsdata;
0908
0909 err = rhashtable_init(&nsdata->namespaces, &rht_ns_params);
0910 if (err)
0911 goto free_nsdata;
0912
0913 err = rhashtable_init(&nsdata->schemas, &rht_sc_params);
0914 if (err)
0915 goto free_rht_ns;
0916
0917 out:
0918 return err;
0919 free_rht_ns:
0920 rhashtable_destroy(&nsdata->namespaces);
0921 free_nsdata:
0922 kfree(nsdata);
0923 net->ipv6.ioam6_data = NULL;
0924 goto out;
0925 }
0926
0927 static void __net_exit ioam6_net_exit(struct net *net)
0928 {
0929 struct ioam6_pernet_data *nsdata = ioam6_pernet(net);
0930
0931 rhashtable_free_and_destroy(&nsdata->namespaces, ioam6_free_ns, NULL);
0932 rhashtable_free_and_destroy(&nsdata->schemas, ioam6_free_sc, NULL);
0933
0934 kfree(nsdata);
0935 }
0936
0937 static struct pernet_operations ioam6_net_ops = {
0938 .init = ioam6_net_init,
0939 .exit = ioam6_net_exit,
0940 };
0941
0942 int __init ioam6_init(void)
0943 {
0944 int err = register_pernet_subsys(&ioam6_net_ops);
0945 if (err)
0946 goto out;
0947
0948 err = genl_register_family(&ioam6_genl_family);
0949 if (err)
0950 goto out_unregister_pernet_subsys;
0951
0952 #ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
0953 err = ioam6_iptunnel_init();
0954 if (err)
0955 goto out_unregister_genl;
0956 #endif
0957
0958 pr_info("In-situ OAM (IOAM) with IPv6\n");
0959
0960 out:
0961 return err;
0962 #ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
0963 out_unregister_genl:
0964 genl_unregister_family(&ioam6_genl_family);
0965 #endif
0966 out_unregister_pernet_subsys:
0967 unregister_pernet_subsys(&ioam6_net_ops);
0968 goto out;
0969 }
0970
0971 void ioam6_exit(void)
0972 {
0973 #ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
0974 ioam6_iptunnel_exit();
0975 #endif
0976 genl_unregister_family(&ioam6_genl_family);
0977 unregister_pernet_subsys(&ioam6_net_ops);
0978 }