Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  *  IPv6 IOAM implementation
0004  *
0005  *  Author:
0006  *  Justin Iurman <justin.iurman@uliege.be>
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     /* hop_lim and node_id */
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     /* ingress_if_id and egress_if_id */
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     /* timestamp seconds */
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     /* timestamp subseconds */
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     /* transit delay */
0708     if (trace->type.bit4) {
0709         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0710         data += sizeof(__be32);
0711     }
0712 
0713     /* namespace data */
0714     if (trace->type.bit5) {
0715         *(__be32 *)data = ns->data;
0716         data += sizeof(__be32);
0717     }
0718 
0719     /* queue depth */
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     /* checksum complement */
0738     if (trace->type.bit7) {
0739         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0740         data += sizeof(__be32);
0741     }
0742 
0743     /* hop_lim and node_id (wide) */
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     /* ingress_if_id and egress_if_id (wide) */
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     /* namespace data (wide) */
0775     if (trace->type.bit10) {
0776         *(__be64 *)data = ns->data_wide;
0777         data += sizeof(__be64);
0778     }
0779 
0780     /* buffer occupancy */
0781     if (trace->type.bit11) {
0782         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0783         data += sizeof(__be32);
0784     }
0785 
0786     /* bit12 undefined: filled with empty value */
0787     if (trace->type.bit12) {
0788         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0789         data += sizeof(__be32);
0790     }
0791 
0792     /* bit13 undefined: filled with empty value */
0793     if (trace->type.bit13) {
0794         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0795         data += sizeof(__be32);
0796     }
0797 
0798     /* bit14 undefined: filled with empty value */
0799     if (trace->type.bit14) {
0800         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0801         data += sizeof(__be32);
0802     }
0803 
0804     /* bit15 undefined: filled with empty value */
0805     if (trace->type.bit15) {
0806         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0807         data += sizeof(__be32);
0808     }
0809 
0810     /* bit16 undefined: filled with empty value */
0811     if (trace->type.bit16) {
0812         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0813         data += sizeof(__be32);
0814     }
0815 
0816     /* bit17 undefined: filled with empty value */
0817     if (trace->type.bit17) {
0818         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0819         data += sizeof(__be32);
0820     }
0821 
0822     /* bit18 undefined: filled with empty value */
0823     if (trace->type.bit18) {
0824         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0825         data += sizeof(__be32);
0826     }
0827 
0828     /* bit19 undefined: filled with empty value */
0829     if (trace->type.bit19) {
0830         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0831         data += sizeof(__be32);
0832     }
0833 
0834     /* bit20 undefined: filled with empty value */
0835     if (trace->type.bit20) {
0836         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0837         data += sizeof(__be32);
0838     }
0839 
0840     /* bit21 undefined: filled with empty value */
0841     if (trace->type.bit21) {
0842         *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
0843         data += sizeof(__be32);
0844     }
0845 
0846     /* opaque state snapshot */
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 /* called with rcu_read_lock() */
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     /* Skip if Overflow flag is set
0869      */
0870     if (trace->overflow)
0871         return;
0872 
0873     /* NodeLen does not include Opaque State Snapshot length. We need to
0874      * take it into account if the corresponding bit is set (bit 22) and
0875      * if the current IOAM namespace has an active schema attached to it
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     /* If there is no space remaining, we set the Overflow flag and we
0886      * skip without filling the trace
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 }