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