1 // SPDX-License-Identifier: GPL-2.0+
3 * IPv6 IOAM implementation
6 * Justin Iurman <justin.iurman@uliege.be>
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>
17 #include <net/addrconf.h>
18 #include <net/genetlink.h>
19 #include <net/ioam6.h>
21 static void ioam6_ns_release(struct ioam6_namespace
*ns
)
26 static void ioam6_sc_release(struct ioam6_schema
*sc
)
31 static void ioam6_free_ns(void *ptr
, void *arg
)
33 struct ioam6_namespace
*ns
= (struct ioam6_namespace
*)ptr
;
39 static void ioam6_free_sc(void *ptr
, void *arg
)
41 struct ioam6_schema
*sc
= (struct ioam6_schema
*)ptr
;
47 static int ioam6_ns_cmpfn(struct rhashtable_compare_arg
*arg
, const void *obj
)
49 const struct ioam6_namespace
*ns
= obj
;
51 return (ns
->id
!= *(__be16
*)arg
->key
);
54 static int ioam6_sc_cmpfn(struct rhashtable_compare_arg
*arg
, const void *obj
)
56 const struct ioam6_schema
*sc
= obj
;
58 return (sc
->id
!= *(u32
*)arg
->key
);
61 static const struct rhashtable_params rht_ns_params
= {
62 .key_len
= sizeof(__be16
),
63 .key_offset
= offsetof(struct ioam6_namespace
, id
),
64 .head_offset
= offsetof(struct ioam6_namespace
, head
),
65 .automatic_shrinking
= true,
66 .obj_cmpfn
= ioam6_ns_cmpfn
,
69 static const struct rhashtable_params rht_sc_params
= {
70 .key_len
= sizeof(u32
),
71 .key_offset
= offsetof(struct ioam6_schema
, id
),
72 .head_offset
= offsetof(struct ioam6_schema
, head
),
73 .automatic_shrinking
= true,
74 .obj_cmpfn
= ioam6_sc_cmpfn
,
77 static struct genl_family ioam6_genl_family
;
79 static const struct nla_policy ioam6_genl_policy_addns
[] = {
80 [IOAM6_ATTR_NS_ID
] = { .type
= NLA_U16
},
81 [IOAM6_ATTR_NS_DATA
] = { .type
= NLA_U32
},
82 [IOAM6_ATTR_NS_DATA_WIDE
] = { .type
= NLA_U64
},
85 static const struct nla_policy ioam6_genl_policy_delns
[] = {
86 [IOAM6_ATTR_NS_ID
] = { .type
= NLA_U16
},
89 static const struct nla_policy ioam6_genl_policy_addsc
[] = {
90 [IOAM6_ATTR_SC_ID
] = { .type
= NLA_U32
},
91 [IOAM6_ATTR_SC_DATA
] = { .type
= NLA_BINARY
,
92 .len
= IOAM6_MAX_SCHEMA_DATA_LEN
},
95 static const struct nla_policy ioam6_genl_policy_delsc
[] = {
96 [IOAM6_ATTR_SC_ID
] = { .type
= NLA_U32
},
99 static const struct nla_policy ioam6_genl_policy_ns_sc
[] = {
100 [IOAM6_ATTR_NS_ID
] = { .type
= NLA_U16
},
101 [IOAM6_ATTR_SC_ID
] = { .type
= NLA_U32
},
102 [IOAM6_ATTR_SC_NONE
] = { .type
= NLA_FLAG
},
105 static int ioam6_genl_addns(struct sk_buff
*skb
, struct genl_info
*info
)
107 struct ioam6_pernet_data
*nsdata
;
108 struct ioam6_namespace
*ns
;
114 if (!info
->attrs
[IOAM6_ATTR_NS_ID
])
117 id
= cpu_to_be16(nla_get_u16(info
->attrs
[IOAM6_ATTR_NS_ID
]));
118 nsdata
= ioam6_pernet(genl_info_net(info
));
120 mutex_lock(&nsdata
->lock
);
122 ns
= rhashtable_lookup_fast(&nsdata
->namespaces
, &id
, rht_ns_params
);
128 ns
= kzalloc(sizeof(*ns
), GFP_KERNEL
);
136 if (!info
->attrs
[IOAM6_ATTR_NS_DATA
])
137 data32
= IOAM6_U32_UNAVAILABLE
;
139 data32
= nla_get_u32(info
->attrs
[IOAM6_ATTR_NS_DATA
]);
141 if (!info
->attrs
[IOAM6_ATTR_NS_DATA_WIDE
])
142 data64
= IOAM6_U64_UNAVAILABLE
;
144 data64
= nla_get_u64(info
->attrs
[IOAM6_ATTR_NS_DATA_WIDE
]);
146 ns
->data
= cpu_to_be32(data32
);
147 ns
->data_wide
= cpu_to_be64(data64
);
149 err
= rhashtable_lookup_insert_fast(&nsdata
->namespaces
, &ns
->head
,
155 mutex_unlock(&nsdata
->lock
);
159 static int ioam6_genl_delns(struct sk_buff
*skb
, struct genl_info
*info
)
161 struct ioam6_pernet_data
*nsdata
;
162 struct ioam6_namespace
*ns
;
163 struct ioam6_schema
*sc
;
167 if (!info
->attrs
[IOAM6_ATTR_NS_ID
])
170 id
= cpu_to_be16(nla_get_u16(info
->attrs
[IOAM6_ATTR_NS_ID
]));
171 nsdata
= ioam6_pernet(genl_info_net(info
));
173 mutex_lock(&nsdata
->lock
);
175 ns
= rhashtable_lookup_fast(&nsdata
->namespaces
, &id
, rht_ns_params
);
181 sc
= rcu_dereference_protected(ns
->schema
,
182 lockdep_is_held(&nsdata
->lock
));
184 err
= rhashtable_remove_fast(&nsdata
->namespaces
, &ns
->head
,
190 rcu_assign_pointer(sc
->ns
, NULL
);
192 ioam6_ns_release(ns
);
195 mutex_unlock(&nsdata
->lock
);
199 static int __ioam6_genl_dumpns_element(struct ioam6_namespace
*ns
,
206 struct ioam6_schema
*sc
;
211 hdr
= genlmsg_put(skb
, portid
, seq
, &ioam6_genl_family
, flags
, cmd
);
215 data32
= be32_to_cpu(ns
->data
);
216 data64
= be64_to_cpu(ns
->data_wide
);
218 if (nla_put_u16(skb
, IOAM6_ATTR_NS_ID
, be16_to_cpu(ns
->id
)) ||
219 (data32
!= IOAM6_U32_UNAVAILABLE
&&
220 nla_put_u32(skb
, IOAM6_ATTR_NS_DATA
, data32
)) ||
221 (data64
!= IOAM6_U64_UNAVAILABLE
&&
222 nla_put_u64_64bit(skb
, IOAM6_ATTR_NS_DATA_WIDE
,
223 data64
, IOAM6_ATTR_PAD
)))
224 goto nla_put_failure
;
228 sc
= rcu_dereference(ns
->schema
);
229 if (sc
&& nla_put_u32(skb
, IOAM6_ATTR_SC_ID
, sc
->id
)) {
231 goto nla_put_failure
;
236 genlmsg_end(skb
, hdr
);
240 genlmsg_cancel(skb
, hdr
);
244 static int ioam6_genl_dumpns_start(struct netlink_callback
*cb
)
246 struct ioam6_pernet_data
*nsdata
= ioam6_pernet(sock_net(cb
->skb
->sk
));
247 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
250 iter
= kmalloc(sizeof(*iter
), GFP_KERNEL
);
254 cb
->args
[0] = (long)iter
;
257 rhashtable_walk_enter(&nsdata
->namespaces
, iter
);
262 static int ioam6_genl_dumpns_done(struct netlink_callback
*cb
)
264 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
266 rhashtable_walk_exit(iter
);
272 static int ioam6_genl_dumpns(struct sk_buff
*skb
, struct netlink_callback
*cb
)
274 struct rhashtable_iter
*iter
;
275 struct ioam6_namespace
*ns
;
278 iter
= (struct rhashtable_iter
*)cb
->args
[0];
279 rhashtable_walk_start(iter
);
282 ns
= rhashtable_walk_next(iter
);
285 if (PTR_ERR(ns
) == -EAGAIN
)
293 err
= __ioam6_genl_dumpns_element(ns
,
294 NETLINK_CB(cb
->skb
).portid
,
298 IOAM6_CMD_DUMP_NAMESPACES
);
306 rhashtable_walk_stop(iter
);
310 static int ioam6_genl_addsc(struct sk_buff
*skb
, struct genl_info
*info
)
312 struct ioam6_pernet_data
*nsdata
;
313 int len
, len_aligned
, err
;
314 struct ioam6_schema
*sc
;
317 if (!info
->attrs
[IOAM6_ATTR_SC_ID
] || !info
->attrs
[IOAM6_ATTR_SC_DATA
])
320 id
= nla_get_u32(info
->attrs
[IOAM6_ATTR_SC_ID
]);
321 nsdata
= ioam6_pernet(genl_info_net(info
));
323 mutex_lock(&nsdata
->lock
);
325 sc
= rhashtable_lookup_fast(&nsdata
->schemas
, &id
, rht_sc_params
);
331 len
= nla_len(info
->attrs
[IOAM6_ATTR_SC_DATA
]);
332 len_aligned
= ALIGN(len
, 4);
334 sc
= kzalloc(sizeof(*sc
) + len_aligned
, GFP_KERNEL
);
341 sc
->len
= len_aligned
;
342 sc
->hdr
= cpu_to_be32(sc
->id
| ((u8
)(sc
->len
/ 4) << 24));
343 nla_memcpy(sc
->data
, info
->attrs
[IOAM6_ATTR_SC_DATA
], len
);
345 err
= rhashtable_lookup_insert_fast(&nsdata
->schemas
, &sc
->head
,
351 mutex_unlock(&nsdata
->lock
);
358 static int ioam6_genl_delsc(struct sk_buff
*skb
, struct genl_info
*info
)
360 struct ioam6_pernet_data
*nsdata
;
361 struct ioam6_namespace
*ns
;
362 struct ioam6_schema
*sc
;
366 if (!info
->attrs
[IOAM6_ATTR_SC_ID
])
369 id
= nla_get_u32(info
->attrs
[IOAM6_ATTR_SC_ID
]);
370 nsdata
= ioam6_pernet(genl_info_net(info
));
372 mutex_lock(&nsdata
->lock
);
374 sc
= rhashtable_lookup_fast(&nsdata
->schemas
, &id
, rht_sc_params
);
380 ns
= rcu_dereference_protected(sc
->ns
, lockdep_is_held(&nsdata
->lock
));
382 err
= rhashtable_remove_fast(&nsdata
->schemas
, &sc
->head
,
388 rcu_assign_pointer(ns
->schema
, NULL
);
390 ioam6_sc_release(sc
);
393 mutex_unlock(&nsdata
->lock
);
397 static int __ioam6_genl_dumpsc_element(struct ioam6_schema
*sc
,
398 u32 portid
, u32 seq
, u32 flags
,
399 struct sk_buff
*skb
, u8 cmd
)
401 struct ioam6_namespace
*ns
;
404 hdr
= genlmsg_put(skb
, portid
, seq
, &ioam6_genl_family
, flags
, cmd
);
408 if (nla_put_u32(skb
, IOAM6_ATTR_SC_ID
, sc
->id
) ||
409 nla_put(skb
, IOAM6_ATTR_SC_DATA
, sc
->len
, sc
->data
))
410 goto nla_put_failure
;
414 ns
= rcu_dereference(sc
->ns
);
415 if (ns
&& nla_put_u16(skb
, IOAM6_ATTR_NS_ID
, be16_to_cpu(ns
->id
))) {
417 goto nla_put_failure
;
422 genlmsg_end(skb
, hdr
);
426 genlmsg_cancel(skb
, hdr
);
430 static int ioam6_genl_dumpsc_start(struct netlink_callback
*cb
)
432 struct ioam6_pernet_data
*nsdata
= ioam6_pernet(sock_net(cb
->skb
->sk
));
433 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
436 iter
= kmalloc(sizeof(*iter
), GFP_KERNEL
);
440 cb
->args
[0] = (long)iter
;
443 rhashtable_walk_enter(&nsdata
->schemas
, iter
);
448 static int ioam6_genl_dumpsc_done(struct netlink_callback
*cb
)
450 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
452 rhashtable_walk_exit(iter
);
458 static int ioam6_genl_dumpsc(struct sk_buff
*skb
, struct netlink_callback
*cb
)
460 struct rhashtable_iter
*iter
;
461 struct ioam6_schema
*sc
;
464 iter
= (struct rhashtable_iter
*)cb
->args
[0];
465 rhashtable_walk_start(iter
);
468 sc
= rhashtable_walk_next(iter
);
471 if (PTR_ERR(sc
) == -EAGAIN
)
479 err
= __ioam6_genl_dumpsc_element(sc
,
480 NETLINK_CB(cb
->skb
).portid
,
484 IOAM6_CMD_DUMP_SCHEMAS
);
492 rhashtable_walk_stop(iter
);
496 static int ioam6_genl_ns_set_schema(struct sk_buff
*skb
, struct genl_info
*info
)
498 struct ioam6_namespace
*ns
, *ns_ref
;
499 struct ioam6_schema
*sc
, *sc_ref
;
500 struct ioam6_pernet_data
*nsdata
;
505 if (!info
->attrs
[IOAM6_ATTR_NS_ID
] ||
506 (!info
->attrs
[IOAM6_ATTR_SC_ID
] &&
507 !info
->attrs
[IOAM6_ATTR_SC_NONE
]))
510 ns_id
= cpu_to_be16(nla_get_u16(info
->attrs
[IOAM6_ATTR_NS_ID
]));
511 nsdata
= ioam6_pernet(genl_info_net(info
));
513 mutex_lock(&nsdata
->lock
);
515 ns
= rhashtable_lookup_fast(&nsdata
->namespaces
, &ns_id
, rht_ns_params
);
521 if (info
->attrs
[IOAM6_ATTR_SC_NONE
]) {
524 sc_id
= nla_get_u32(info
->attrs
[IOAM6_ATTR_SC_ID
]);
525 sc
= rhashtable_lookup_fast(&nsdata
->schemas
, &sc_id
,
533 sc_ref
= rcu_dereference_protected(ns
->schema
,
534 lockdep_is_held(&nsdata
->lock
));
536 rcu_assign_pointer(sc_ref
->ns
, NULL
);
537 rcu_assign_pointer(ns
->schema
, sc
);
540 ns_ref
= rcu_dereference_protected(sc
->ns
,
541 lockdep_is_held(&nsdata
->lock
));
543 rcu_assign_pointer(ns_ref
->schema
, NULL
);
544 rcu_assign_pointer(sc
->ns
, ns
);
550 mutex_unlock(&nsdata
->lock
);
554 static const struct genl_ops ioam6_genl_ops
[] = {
556 .cmd
= IOAM6_CMD_ADD_NAMESPACE
,
557 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
558 .doit
= ioam6_genl_addns
,
559 .flags
= GENL_ADMIN_PERM
,
560 .policy
= ioam6_genl_policy_addns
,
561 .maxattr
= ARRAY_SIZE(ioam6_genl_policy_addns
) - 1,
564 .cmd
= IOAM6_CMD_DEL_NAMESPACE
,
565 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
566 .doit
= ioam6_genl_delns
,
567 .flags
= GENL_ADMIN_PERM
,
568 .policy
= ioam6_genl_policy_delns
,
569 .maxattr
= ARRAY_SIZE(ioam6_genl_policy_delns
) - 1,
572 .cmd
= IOAM6_CMD_DUMP_NAMESPACES
,
573 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
574 .start
= ioam6_genl_dumpns_start
,
575 .dumpit
= ioam6_genl_dumpns
,
576 .done
= ioam6_genl_dumpns_done
,
577 .flags
= GENL_ADMIN_PERM
,
580 .cmd
= IOAM6_CMD_ADD_SCHEMA
,
581 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
582 .doit
= ioam6_genl_addsc
,
583 .flags
= GENL_ADMIN_PERM
,
584 .policy
= ioam6_genl_policy_addsc
,
585 .maxattr
= ARRAY_SIZE(ioam6_genl_policy_addsc
) - 1,
588 .cmd
= IOAM6_CMD_DEL_SCHEMA
,
589 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
590 .doit
= ioam6_genl_delsc
,
591 .flags
= GENL_ADMIN_PERM
,
592 .policy
= ioam6_genl_policy_delsc
,
593 .maxattr
= ARRAY_SIZE(ioam6_genl_policy_delsc
) - 1,
596 .cmd
= IOAM6_CMD_DUMP_SCHEMAS
,
597 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
598 .start
= ioam6_genl_dumpsc_start
,
599 .dumpit
= ioam6_genl_dumpsc
,
600 .done
= ioam6_genl_dumpsc_done
,
601 .flags
= GENL_ADMIN_PERM
,
604 .cmd
= IOAM6_CMD_NS_SET_SCHEMA
,
605 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
606 .doit
= ioam6_genl_ns_set_schema
,
607 .flags
= GENL_ADMIN_PERM
,
608 .policy
= ioam6_genl_policy_ns_sc
,
609 .maxattr
= ARRAY_SIZE(ioam6_genl_policy_ns_sc
) - 1,
613 static struct genl_family ioam6_genl_family __ro_after_init
= {
614 .name
= IOAM6_GENL_NAME
,
615 .version
= IOAM6_GENL_VERSION
,
617 .parallel_ops
= true,
618 .ops
= ioam6_genl_ops
,
619 .n_ops
= ARRAY_SIZE(ioam6_genl_ops
),
620 .module
= THIS_MODULE
,
623 struct ioam6_namespace
*ioam6_namespace(struct net
*net
, __be16 id
)
625 struct ioam6_pernet_data
*nsdata
= ioam6_pernet(net
);
627 return rhashtable_lookup_fast(&nsdata
->namespaces
, &id
, rht_ns_params
);
630 static void __ioam6_fill_trace_data(struct sk_buff
*skb
,
631 struct ioam6_namespace
*ns
,
632 struct ioam6_trace_hdr
*trace
,
633 struct ioam6_schema
*sc
,
636 struct __kernel_sock_timeval ts
;
643 data
= trace
->data
+ trace
->remlen
* 4 - trace
->nodelen
* 4 - sclen
* 4;
645 /* hop_lim and node_id */
646 if (trace
->type
.bit0
) {
647 byte
= ipv6_hdr(skb
)->hop_limit
;
651 raw32
= dev_net(skb_dst(skb
)->dev
)->ipv6
.sysctl
.ioam6_id
;
653 *(__be32
*)data
= cpu_to_be32((byte
<< 24) | raw32
);
654 data
+= sizeof(__be32
);
657 /* ingress_if_id and egress_if_id */
658 if (trace
->type
.bit1
) {
660 raw16
= IOAM6_U16_UNAVAILABLE
;
662 raw16
= (__force u16
)__in6_dev_get(skb
->dev
)->cnf
.ioam6_id
;
664 *(__be16
*)data
= cpu_to_be16(raw16
);
665 data
+= sizeof(__be16
);
667 if (skb_dst(skb
)->dev
->flags
& IFF_LOOPBACK
)
668 raw16
= IOAM6_U16_UNAVAILABLE
;
670 raw16
= (__force u16
)__in6_dev_get(skb_dst(skb
)->dev
)->cnf
.ioam6_id
;
672 *(__be16
*)data
= cpu_to_be16(raw16
);
673 data
+= sizeof(__be16
);
676 /* timestamp seconds */
677 if (trace
->type
.bit2
) {
679 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
682 __net_timestamp(skb
);
684 skb_get_new_timestamp(skb
, &ts
);
685 *(__be32
*)data
= cpu_to_be32((u32
)ts
.tv_sec
);
687 data
+= sizeof(__be32
);
690 /* timestamp subseconds */
691 if (trace
->type
.bit3
) {
693 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
696 __net_timestamp(skb
);
698 if (!trace
->type
.bit2
)
699 skb_get_new_timestamp(skb
, &ts
);
701 *(__be32
*)data
= cpu_to_be32((u32
)ts
.tv_usec
);
703 data
+= sizeof(__be32
);
707 if (trace
->type
.bit4
) {
708 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
709 data
+= sizeof(__be32
);
713 if (trace
->type
.bit5
) {
714 *(__be32
*)data
= ns
->data
;
715 data
+= sizeof(__be32
);
719 if (trace
->type
.bit6
) {
720 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
721 data
+= sizeof(__be32
);
724 /* checksum complement */
725 if (trace
->type
.bit7
) {
726 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
727 data
+= sizeof(__be32
);
730 /* hop_lim and node_id (wide) */
731 if (trace
->type
.bit8
) {
732 byte
= ipv6_hdr(skb
)->hop_limit
;
736 raw64
= dev_net(skb_dst(skb
)->dev
)->ipv6
.sysctl
.ioam6_id_wide
;
738 *(__be64
*)data
= cpu_to_be64(((u64
)byte
<< 56) | raw64
);
739 data
+= sizeof(__be64
);
742 /* ingress_if_id and egress_if_id (wide) */
743 if (trace
->type
.bit9
) {
745 raw32
= IOAM6_U32_UNAVAILABLE
;
747 raw32
= __in6_dev_get(skb
->dev
)->cnf
.ioam6_id_wide
;
749 *(__be32
*)data
= cpu_to_be32(raw32
);
750 data
+= sizeof(__be32
);
752 if (skb_dst(skb
)->dev
->flags
& IFF_LOOPBACK
)
753 raw32
= IOAM6_U32_UNAVAILABLE
;
755 raw32
= __in6_dev_get(skb_dst(skb
)->dev
)->cnf
.ioam6_id_wide
;
757 *(__be32
*)data
= cpu_to_be32(raw32
);
758 data
+= sizeof(__be32
);
761 /* namespace data (wide) */
762 if (trace
->type
.bit10
) {
763 *(__be64
*)data
= ns
->data_wide
;
764 data
+= sizeof(__be64
);
767 /* buffer occupancy */
768 if (trace
->type
.bit11
) {
769 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
770 data
+= sizeof(__be32
);
773 /* bit12 undefined: filled with empty value */
774 if (trace
->type
.bit12
) {
775 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
776 data
+= sizeof(__be32
);
779 /* bit13 undefined: filled with empty value */
780 if (trace
->type
.bit13
) {
781 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
782 data
+= sizeof(__be32
);
785 /* bit14 undefined: filled with empty value */
786 if (trace
->type
.bit14
) {
787 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
788 data
+= sizeof(__be32
);
791 /* bit15 undefined: filled with empty value */
792 if (trace
->type
.bit15
) {
793 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
794 data
+= sizeof(__be32
);
797 /* bit16 undefined: filled with empty value */
798 if (trace
->type
.bit16
) {
799 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
800 data
+= sizeof(__be32
);
803 /* bit17 undefined: filled with empty value */
804 if (trace
->type
.bit17
) {
805 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
806 data
+= sizeof(__be32
);
809 /* bit18 undefined: filled with empty value */
810 if (trace
->type
.bit18
) {
811 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
812 data
+= sizeof(__be32
);
815 /* bit19 undefined: filled with empty value */
816 if (trace
->type
.bit19
) {
817 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
818 data
+= sizeof(__be32
);
821 /* bit20 undefined: filled with empty value */
822 if (trace
->type
.bit20
) {
823 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
824 data
+= sizeof(__be32
);
827 /* bit21 undefined: filled with empty value */
828 if (trace
->type
.bit21
) {
829 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
);
830 data
+= sizeof(__be32
);
833 /* opaque state snapshot */
834 if (trace
->type
.bit22
) {
836 *(__be32
*)data
= cpu_to_be32(IOAM6_U32_UNAVAILABLE
>> 8);
838 *(__be32
*)data
= sc
->hdr
;
839 data
+= sizeof(__be32
);
841 memcpy(data
, sc
->data
, sc
->len
);
846 /* called with rcu_read_lock() */
847 void ioam6_fill_trace_data(struct sk_buff
*skb
,
848 struct ioam6_namespace
*ns
,
849 struct ioam6_trace_hdr
*trace
)
851 struct ioam6_schema
*sc
;
854 /* Skip if Overflow flag is set
859 /* NodeLen does not include Opaque State Snapshot length. We need to
860 * take it into account if the corresponding bit is set (bit 22) and
861 * if the current IOAM namespace has an active schema attached to it
863 sc
= rcu_dereference(ns
->schema
);
864 if (trace
->type
.bit22
) {
865 sclen
= sizeof_field(struct ioam6_schema
, hdr
) / 4;
868 sclen
+= sc
->len
/ 4;
871 /* If there is no space remaining, we set the Overflow flag and we
872 * skip without filling the trace
874 if (!trace
->remlen
|| trace
->remlen
< trace
->nodelen
+ sclen
) {
879 __ioam6_fill_trace_data(skb
, ns
, trace
, sc
, sclen
);
880 trace
->remlen
-= trace
->nodelen
+ sclen
;
883 static int __net_init
ioam6_net_init(struct net
*net
)
885 struct ioam6_pernet_data
*nsdata
;
888 nsdata
= kzalloc(sizeof(*nsdata
), GFP_KERNEL
);
892 mutex_init(&nsdata
->lock
);
893 net
->ipv6
.ioam6_data
= nsdata
;
895 err
= rhashtable_init(&nsdata
->namespaces
, &rht_ns_params
);
899 err
= rhashtable_init(&nsdata
->schemas
, &rht_sc_params
);
906 rhashtable_destroy(&nsdata
->namespaces
);
909 net
->ipv6
.ioam6_data
= NULL
;
913 static void __net_exit
ioam6_net_exit(struct net
*net
)
915 struct ioam6_pernet_data
*nsdata
= ioam6_pernet(net
);
917 rhashtable_free_and_destroy(&nsdata
->namespaces
, ioam6_free_ns
, NULL
);
918 rhashtable_free_and_destroy(&nsdata
->schemas
, ioam6_free_sc
, NULL
);
923 static struct pernet_operations ioam6_net_ops
= {
924 .init
= ioam6_net_init
,
925 .exit
= ioam6_net_exit
,
928 int __init
ioam6_init(void)
930 int err
= register_pernet_subsys(&ioam6_net_ops
);
934 err
= genl_register_family(&ioam6_genl_family
);
936 goto out_unregister_pernet_subsys
;
938 #ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
939 err
= ioam6_iptunnel_init();
941 goto out_unregister_genl
;
944 pr_info("In-situ OAM (IOAM) with IPv6\n");
948 #ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
950 genl_unregister_family(&ioam6_genl_family
);
952 out_unregister_pernet_subsys
:
953 unregister_pernet_subsys(&ioam6_net_ops
);
957 void ioam6_exit(void)
959 #ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
960 ioam6_iptunnel_exit();
962 genl_unregister_family(&ioam6_genl_family
);
963 unregister_pernet_subsys(&ioam6_net_ops
);