Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/devlink/rate.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4
* Copyright (c) 2016 Jiri Pirko <[email protected]>
5
*/
6
7
#include "devl_internal.h"
8
9
static inline bool
10
devlink_rate_is_leaf(struct devlink_rate *devlink_rate)
11
{
12
return devlink_rate->type == DEVLINK_RATE_TYPE_LEAF;
13
}
14
15
static inline bool
16
devlink_rate_is_node(struct devlink_rate *devlink_rate)
17
{
18
return devlink_rate->type == DEVLINK_RATE_TYPE_NODE;
19
}
20
21
static struct devlink_rate *
22
devlink_rate_leaf_get_from_info(struct devlink *devlink, struct genl_info *info)
23
{
24
struct devlink_rate *devlink_rate;
25
struct devlink_port *devlink_port;
26
27
devlink_port = devlink_port_get_from_attrs(devlink, info->attrs);
28
if (IS_ERR(devlink_port))
29
return ERR_CAST(devlink_port);
30
devlink_rate = devlink_port->devlink_rate;
31
return devlink_rate ?: ERR_PTR(-ENODEV);
32
}
33
34
static struct devlink_rate *
35
devlink_rate_node_get_by_name(struct devlink *devlink, const char *node_name)
36
{
37
static struct devlink_rate *devlink_rate;
38
39
list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
40
if (devlink_rate_is_node(devlink_rate) &&
41
!strcmp(node_name, devlink_rate->name))
42
return devlink_rate;
43
}
44
return ERR_PTR(-ENODEV);
45
}
46
47
static struct devlink_rate *
48
devlink_rate_node_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
49
{
50
const char *rate_node_name;
51
size_t len;
52
53
if (!attrs[DEVLINK_ATTR_RATE_NODE_NAME])
54
return ERR_PTR(-EINVAL);
55
rate_node_name = nla_data(attrs[DEVLINK_ATTR_RATE_NODE_NAME]);
56
len = strlen(rate_node_name);
57
/* Name cannot be empty or decimal number */
58
if (!len || strspn(rate_node_name, "0123456789") == len)
59
return ERR_PTR(-EINVAL);
60
61
return devlink_rate_node_get_by_name(devlink, rate_node_name);
62
}
63
64
static struct devlink_rate *
65
devlink_rate_node_get_from_info(struct devlink *devlink, struct genl_info *info)
66
{
67
return devlink_rate_node_get_from_attrs(devlink, info->attrs);
68
}
69
70
static struct devlink_rate *
71
devlink_rate_get_from_info(struct devlink *devlink, struct genl_info *info)
72
{
73
struct nlattr **attrs = info->attrs;
74
75
if (attrs[DEVLINK_ATTR_PORT_INDEX])
76
return devlink_rate_leaf_get_from_info(devlink, info);
77
else if (attrs[DEVLINK_ATTR_RATE_NODE_NAME])
78
return devlink_rate_node_get_from_info(devlink, info);
79
else
80
return ERR_PTR(-EINVAL);
81
}
82
83
static int devlink_rate_put_tc_bws(struct sk_buff *msg, u32 *tc_bw)
84
{
85
struct nlattr *nla_tc_bw;
86
int i;
87
88
for (i = 0; i < DEVLINK_RATE_TCS_MAX; i++) {
89
nla_tc_bw = nla_nest_start(msg, DEVLINK_ATTR_RATE_TC_BWS);
90
if (!nla_tc_bw)
91
return -EMSGSIZE;
92
93
if (nla_put_u8(msg, DEVLINK_RATE_TC_ATTR_INDEX, i) ||
94
nla_put_u32(msg, DEVLINK_RATE_TC_ATTR_BW, tc_bw[i]))
95
goto nla_put_failure;
96
97
nla_nest_end(msg, nla_tc_bw);
98
}
99
return 0;
100
101
nla_put_failure:
102
nla_nest_cancel(msg, nla_tc_bw);
103
return -EMSGSIZE;
104
}
105
106
static int devlink_nl_rate_fill(struct sk_buff *msg,
107
struct devlink_rate *devlink_rate,
108
enum devlink_command cmd, u32 portid, u32 seq,
109
int flags, struct netlink_ext_ack *extack)
110
{
111
struct devlink *devlink = devlink_rate->devlink;
112
void *hdr;
113
114
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
115
if (!hdr)
116
return -EMSGSIZE;
117
118
if (devlink_nl_put_handle(msg, devlink))
119
goto nla_put_failure;
120
121
if (nla_put_u16(msg, DEVLINK_ATTR_RATE_TYPE, devlink_rate->type))
122
goto nla_put_failure;
123
124
if (devlink_rate_is_leaf(devlink_rate)) {
125
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
126
devlink_rate->devlink_port->index))
127
goto nla_put_failure;
128
} else if (devlink_rate_is_node(devlink_rate)) {
129
if (nla_put_string(msg, DEVLINK_ATTR_RATE_NODE_NAME,
130
devlink_rate->name))
131
goto nla_put_failure;
132
}
133
134
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_RATE_TX_SHARE,
135
devlink_rate->tx_share))
136
goto nla_put_failure;
137
138
if (devlink_nl_put_u64(msg, DEVLINK_ATTR_RATE_TX_MAX,
139
devlink_rate->tx_max))
140
goto nla_put_failure;
141
142
if (nla_put_u32(msg, DEVLINK_ATTR_RATE_TX_PRIORITY,
143
devlink_rate->tx_priority))
144
goto nla_put_failure;
145
146
if (nla_put_u32(msg, DEVLINK_ATTR_RATE_TX_WEIGHT,
147
devlink_rate->tx_weight))
148
goto nla_put_failure;
149
150
if (devlink_rate->parent)
151
if (nla_put_string(msg, DEVLINK_ATTR_RATE_PARENT_NODE_NAME,
152
devlink_rate->parent->name))
153
goto nla_put_failure;
154
155
if (devlink_rate_put_tc_bws(msg, devlink_rate->tc_bw))
156
goto nla_put_failure;
157
158
genlmsg_end(msg, hdr);
159
return 0;
160
161
nla_put_failure:
162
genlmsg_cancel(msg, hdr);
163
return -EMSGSIZE;
164
}
165
166
static void devlink_rate_notify(struct devlink_rate *devlink_rate,
167
enum devlink_command cmd)
168
{
169
struct devlink *devlink = devlink_rate->devlink;
170
struct sk_buff *msg;
171
int err;
172
173
WARN_ON(cmd != DEVLINK_CMD_RATE_NEW && cmd != DEVLINK_CMD_RATE_DEL);
174
175
if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
176
return;
177
178
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
179
if (!msg)
180
return;
181
182
err = devlink_nl_rate_fill(msg, devlink_rate, cmd, 0, 0, 0, NULL);
183
if (err) {
184
nlmsg_free(msg);
185
return;
186
}
187
188
devlink_nl_notify_send(devlink, msg);
189
}
190
191
void devlink_rates_notify_register(struct devlink *devlink)
192
{
193
struct devlink_rate *rate_node;
194
195
list_for_each_entry(rate_node, &devlink->rate_list, list)
196
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
197
}
198
199
void devlink_rates_notify_unregister(struct devlink *devlink)
200
{
201
struct devlink_rate *rate_node;
202
203
list_for_each_entry_reverse(rate_node, &devlink->rate_list, list)
204
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL);
205
}
206
207
static int
208
devlink_nl_rate_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
209
struct netlink_callback *cb, int flags)
210
{
211
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
212
struct devlink_rate *devlink_rate;
213
int idx = 0;
214
int err = 0;
215
216
list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
217
enum devlink_command cmd = DEVLINK_CMD_RATE_NEW;
218
u32 id = NETLINK_CB(cb->skb).portid;
219
220
if (idx < state->idx) {
221
idx++;
222
continue;
223
}
224
err = devlink_nl_rate_fill(msg, devlink_rate, cmd, id,
225
cb->nlh->nlmsg_seq, flags, NULL);
226
if (err) {
227
state->idx = idx;
228
break;
229
}
230
idx++;
231
}
232
233
return err;
234
}
235
236
int devlink_nl_rate_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
237
{
238
return devlink_nl_dumpit(skb, cb, devlink_nl_rate_get_dump_one);
239
}
240
241
int devlink_nl_rate_get_doit(struct sk_buff *skb, struct genl_info *info)
242
{
243
struct devlink *devlink = info->user_ptr[0];
244
struct devlink_rate *devlink_rate;
245
struct sk_buff *msg;
246
int err;
247
248
devlink_rate = devlink_rate_get_from_info(devlink, info);
249
if (IS_ERR(devlink_rate))
250
return PTR_ERR(devlink_rate);
251
252
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
253
if (!msg)
254
return -ENOMEM;
255
256
err = devlink_nl_rate_fill(msg, devlink_rate, DEVLINK_CMD_RATE_NEW,
257
info->snd_portid, info->snd_seq, 0,
258
info->extack);
259
if (err) {
260
nlmsg_free(msg);
261
return err;
262
}
263
264
return genlmsg_reply(msg, info);
265
}
266
267
static bool
268
devlink_rate_is_parent_node(struct devlink_rate *devlink_rate,
269
struct devlink_rate *parent)
270
{
271
while (parent) {
272
if (parent == devlink_rate)
273
return true;
274
parent = parent->parent;
275
}
276
return false;
277
}
278
279
static int
280
devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate,
281
struct genl_info *info,
282
struct nlattr *nla_parent)
283
{
284
struct devlink *devlink = devlink_rate->devlink;
285
const char *parent_name = nla_data(nla_parent);
286
const struct devlink_ops *ops = devlink->ops;
287
size_t len = strlen(parent_name);
288
struct devlink_rate *parent;
289
int err = -EOPNOTSUPP;
290
291
parent = devlink_rate->parent;
292
293
if (parent && !len) {
294
if (devlink_rate_is_leaf(devlink_rate))
295
err = ops->rate_leaf_parent_set(devlink_rate, NULL,
296
devlink_rate->priv, NULL,
297
info->extack);
298
else if (devlink_rate_is_node(devlink_rate))
299
err = ops->rate_node_parent_set(devlink_rate, NULL,
300
devlink_rate->priv, NULL,
301
info->extack);
302
if (err)
303
return err;
304
305
refcount_dec(&parent->refcnt);
306
devlink_rate->parent = NULL;
307
} else if (len) {
308
parent = devlink_rate_node_get_by_name(devlink, parent_name);
309
if (IS_ERR(parent))
310
return -ENODEV;
311
312
if (parent == devlink_rate) {
313
NL_SET_ERR_MSG(info->extack, "Parent to self is not allowed");
314
return -EINVAL;
315
}
316
317
if (devlink_rate_is_node(devlink_rate) &&
318
devlink_rate_is_parent_node(devlink_rate, parent->parent)) {
319
NL_SET_ERR_MSG(info->extack, "Node is already a parent of parent node.");
320
return -EEXIST;
321
}
322
323
if (devlink_rate_is_leaf(devlink_rate))
324
err = ops->rate_leaf_parent_set(devlink_rate, parent,
325
devlink_rate->priv, parent->priv,
326
info->extack);
327
else if (devlink_rate_is_node(devlink_rate))
328
err = ops->rate_node_parent_set(devlink_rate, parent,
329
devlink_rate->priv, parent->priv,
330
info->extack);
331
if (err)
332
return err;
333
334
if (devlink_rate->parent)
335
/* we're reassigning to other parent in this case */
336
refcount_dec(&devlink_rate->parent->refcnt);
337
338
refcount_inc(&parent->refcnt);
339
devlink_rate->parent = parent;
340
}
341
342
return 0;
343
}
344
345
static int devlink_nl_rate_tc_bw_parse(struct nlattr *parent_nest, u32 *tc_bw,
346
unsigned long *bitmap,
347
struct netlink_ext_ack *extack)
348
{
349
struct nlattr *tb[DEVLINK_RATE_TC_ATTR_MAX + 1];
350
u8 tc_index;
351
int err;
352
353
err = nla_parse_nested(tb, DEVLINK_RATE_TC_ATTR_MAX, parent_nest,
354
devlink_dl_rate_tc_bws_nl_policy, extack);
355
if (err)
356
return err;
357
358
if (!tb[DEVLINK_RATE_TC_ATTR_INDEX]) {
359
NL_SET_ERR_ATTR_MISS(extack, parent_nest,
360
DEVLINK_RATE_TC_ATTR_INDEX);
361
return -EINVAL;
362
}
363
364
tc_index = nla_get_u8(tb[DEVLINK_RATE_TC_ATTR_INDEX]);
365
366
if (!tb[DEVLINK_RATE_TC_ATTR_BW]) {
367
NL_SET_ERR_ATTR_MISS(extack, parent_nest,
368
DEVLINK_RATE_TC_ATTR_BW);
369
return -EINVAL;
370
}
371
372
if (test_and_set_bit(tc_index, bitmap)) {
373
NL_SET_ERR_MSG_FMT(extack,
374
"Duplicate traffic class index specified (%u)",
375
tc_index);
376
return -EINVAL;
377
}
378
379
tc_bw[tc_index] = nla_get_u32(tb[DEVLINK_RATE_TC_ATTR_BW]);
380
381
return 0;
382
}
383
384
static int devlink_nl_rate_tc_bw_set(struct devlink_rate *devlink_rate,
385
struct genl_info *info)
386
{
387
DECLARE_BITMAP(bitmap, DEVLINK_RATE_TCS_MAX) = {};
388
struct devlink *devlink = devlink_rate->devlink;
389
const struct devlink_ops *ops = devlink->ops;
390
u32 tc_bw[DEVLINK_RATE_TCS_MAX] = {};
391
int rem, err = -EOPNOTSUPP, i;
392
struct nlattr *attr;
393
394
nlmsg_for_each_attr_type(attr, DEVLINK_ATTR_RATE_TC_BWS, info->nlhdr,
395
GENL_HDRLEN, rem) {
396
err = devlink_nl_rate_tc_bw_parse(attr, tc_bw, bitmap,
397
info->extack);
398
if (err)
399
return err;
400
}
401
402
for (i = 0; i < DEVLINK_RATE_TCS_MAX; i++) {
403
if (!test_bit(i, bitmap)) {
404
NL_SET_ERR_MSG_FMT(info->extack,
405
"Bandwidth values must be specified for all %u traffic classes",
406
DEVLINK_RATE_TCS_MAX);
407
return -EINVAL;
408
}
409
}
410
411
if (devlink_rate_is_leaf(devlink_rate))
412
err = ops->rate_leaf_tc_bw_set(devlink_rate, devlink_rate->priv,
413
tc_bw, info->extack);
414
else if (devlink_rate_is_node(devlink_rate))
415
err = ops->rate_node_tc_bw_set(devlink_rate, devlink_rate->priv,
416
tc_bw, info->extack);
417
418
if (err)
419
return err;
420
421
memcpy(devlink_rate->tc_bw, tc_bw, sizeof(tc_bw));
422
423
return 0;
424
}
425
426
static int devlink_nl_rate_set(struct devlink_rate *devlink_rate,
427
const struct devlink_ops *ops,
428
struct genl_info *info)
429
{
430
struct nlattr *nla_parent, **attrs = info->attrs;
431
int err = -EOPNOTSUPP;
432
u32 priority;
433
u32 weight;
434
u64 rate;
435
436
if (attrs[DEVLINK_ATTR_RATE_TX_SHARE]) {
437
rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_SHARE]);
438
if (devlink_rate_is_leaf(devlink_rate))
439
err = ops->rate_leaf_tx_share_set(devlink_rate, devlink_rate->priv,
440
rate, info->extack);
441
else if (devlink_rate_is_node(devlink_rate))
442
err = ops->rate_node_tx_share_set(devlink_rate, devlink_rate->priv,
443
rate, info->extack);
444
if (err)
445
return err;
446
devlink_rate->tx_share = rate;
447
}
448
449
if (attrs[DEVLINK_ATTR_RATE_TX_MAX]) {
450
rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_MAX]);
451
if (devlink_rate_is_leaf(devlink_rate))
452
err = ops->rate_leaf_tx_max_set(devlink_rate, devlink_rate->priv,
453
rate, info->extack);
454
else if (devlink_rate_is_node(devlink_rate))
455
err = ops->rate_node_tx_max_set(devlink_rate, devlink_rate->priv,
456
rate, info->extack);
457
if (err)
458
return err;
459
devlink_rate->tx_max = rate;
460
}
461
462
if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY]) {
463
priority = nla_get_u32(attrs[DEVLINK_ATTR_RATE_TX_PRIORITY]);
464
if (devlink_rate_is_leaf(devlink_rate))
465
err = ops->rate_leaf_tx_priority_set(devlink_rate, devlink_rate->priv,
466
priority, info->extack);
467
else if (devlink_rate_is_node(devlink_rate))
468
err = ops->rate_node_tx_priority_set(devlink_rate, devlink_rate->priv,
469
priority, info->extack);
470
471
if (err)
472
return err;
473
devlink_rate->tx_priority = priority;
474
}
475
476
if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT]) {
477
weight = nla_get_u32(attrs[DEVLINK_ATTR_RATE_TX_WEIGHT]);
478
if (devlink_rate_is_leaf(devlink_rate))
479
err = ops->rate_leaf_tx_weight_set(devlink_rate, devlink_rate->priv,
480
weight, info->extack);
481
else if (devlink_rate_is_node(devlink_rate))
482
err = ops->rate_node_tx_weight_set(devlink_rate, devlink_rate->priv,
483
weight, info->extack);
484
485
if (err)
486
return err;
487
devlink_rate->tx_weight = weight;
488
}
489
490
nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME];
491
if (nla_parent) {
492
err = devlink_nl_rate_parent_node_set(devlink_rate, info,
493
nla_parent);
494
if (err)
495
return err;
496
}
497
498
if (attrs[DEVLINK_ATTR_RATE_TC_BWS]) {
499
err = devlink_nl_rate_tc_bw_set(devlink_rate, info);
500
if (err)
501
return err;
502
}
503
504
return 0;
505
}
506
507
static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops,
508
struct genl_info *info,
509
enum devlink_rate_type type)
510
{
511
struct nlattr **attrs = info->attrs;
512
513
if (type == DEVLINK_RATE_TYPE_LEAF) {
514
if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_leaf_tx_share_set) {
515
NL_SET_ERR_MSG(info->extack, "TX share set isn't supported for the leafs");
516
return false;
517
}
518
if (attrs[DEVLINK_ATTR_RATE_TX_MAX] && !ops->rate_leaf_tx_max_set) {
519
NL_SET_ERR_MSG(info->extack, "TX max set isn't supported for the leafs");
520
return false;
521
}
522
if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] &&
523
!ops->rate_leaf_parent_set) {
524
NL_SET_ERR_MSG(info->extack, "Parent set isn't supported for the leafs");
525
return false;
526
}
527
if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY] && !ops->rate_leaf_tx_priority_set) {
528
NL_SET_ERR_MSG_ATTR(info->extack,
529
attrs[DEVLINK_ATTR_RATE_TX_PRIORITY],
530
"TX priority set isn't supported for the leafs");
531
return false;
532
}
533
if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT] && !ops->rate_leaf_tx_weight_set) {
534
NL_SET_ERR_MSG_ATTR(info->extack,
535
attrs[DEVLINK_ATTR_RATE_TX_WEIGHT],
536
"TX weight set isn't supported for the leafs");
537
return false;
538
}
539
if (attrs[DEVLINK_ATTR_RATE_TC_BWS] &&
540
!ops->rate_leaf_tc_bw_set) {
541
NL_SET_ERR_MSG_ATTR(info->extack,
542
attrs[DEVLINK_ATTR_RATE_TC_BWS],
543
"TC bandwidth set isn't supported for the leafs");
544
return false;
545
}
546
} else if (type == DEVLINK_RATE_TYPE_NODE) {
547
if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_node_tx_share_set) {
548
NL_SET_ERR_MSG(info->extack, "TX share set isn't supported for the nodes");
549
return false;
550
}
551
if (attrs[DEVLINK_ATTR_RATE_TX_MAX] && !ops->rate_node_tx_max_set) {
552
NL_SET_ERR_MSG(info->extack, "TX max set isn't supported for the nodes");
553
return false;
554
}
555
if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] &&
556
!ops->rate_node_parent_set) {
557
NL_SET_ERR_MSG(info->extack, "Parent set isn't supported for the nodes");
558
return false;
559
}
560
if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY] && !ops->rate_node_tx_priority_set) {
561
NL_SET_ERR_MSG_ATTR(info->extack,
562
attrs[DEVLINK_ATTR_RATE_TX_PRIORITY],
563
"TX priority set isn't supported for the nodes");
564
return false;
565
}
566
if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT] && !ops->rate_node_tx_weight_set) {
567
NL_SET_ERR_MSG_ATTR(info->extack,
568
attrs[DEVLINK_ATTR_RATE_TX_WEIGHT],
569
"TX weight set isn't supported for the nodes");
570
return false;
571
}
572
if (attrs[DEVLINK_ATTR_RATE_TC_BWS] &&
573
!ops->rate_node_tc_bw_set) {
574
NL_SET_ERR_MSG_ATTR(info->extack,
575
attrs[DEVLINK_ATTR_RATE_TC_BWS],
576
"TC bandwidth set isn't supported for the nodes");
577
return false;
578
}
579
} else {
580
WARN(1, "Unknown type of rate object");
581
return false;
582
}
583
584
return true;
585
}
586
587
int devlink_nl_rate_set_doit(struct sk_buff *skb, struct genl_info *info)
588
{
589
struct devlink *devlink = info->user_ptr[0];
590
struct devlink_rate *devlink_rate;
591
const struct devlink_ops *ops;
592
int err;
593
594
devlink_rate = devlink_rate_get_from_info(devlink, info);
595
if (IS_ERR(devlink_rate))
596
return PTR_ERR(devlink_rate);
597
598
ops = devlink->ops;
599
if (!ops || !devlink_rate_set_ops_supported(ops, info, devlink_rate->type))
600
return -EOPNOTSUPP;
601
602
err = devlink_nl_rate_set(devlink_rate, ops, info);
603
604
if (!err)
605
devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
606
return err;
607
}
608
609
int devlink_nl_rate_new_doit(struct sk_buff *skb, struct genl_info *info)
610
{
611
struct devlink *devlink = info->user_ptr[0];
612
struct devlink_rate *rate_node;
613
const struct devlink_ops *ops;
614
int err;
615
616
ops = devlink->ops;
617
if (!ops || !ops->rate_node_new || !ops->rate_node_del) {
618
NL_SET_ERR_MSG(info->extack, "Rate nodes aren't supported");
619
return -EOPNOTSUPP;
620
}
621
622
if (!devlink_rate_set_ops_supported(ops, info, DEVLINK_RATE_TYPE_NODE))
623
return -EOPNOTSUPP;
624
625
rate_node = devlink_rate_node_get_from_attrs(devlink, info->attrs);
626
if (!IS_ERR(rate_node))
627
return -EEXIST;
628
else if (rate_node == ERR_PTR(-EINVAL))
629
return -EINVAL;
630
631
rate_node = kzalloc(sizeof(*rate_node), GFP_KERNEL);
632
if (!rate_node)
633
return -ENOMEM;
634
635
rate_node->devlink = devlink;
636
rate_node->type = DEVLINK_RATE_TYPE_NODE;
637
rate_node->name = nla_strdup(info->attrs[DEVLINK_ATTR_RATE_NODE_NAME], GFP_KERNEL);
638
if (!rate_node->name) {
639
err = -ENOMEM;
640
goto err_strdup;
641
}
642
643
err = ops->rate_node_new(rate_node, &rate_node->priv, info->extack);
644
if (err)
645
goto err_node_new;
646
647
err = devlink_nl_rate_set(rate_node, ops, info);
648
if (err)
649
goto err_rate_set;
650
651
refcount_set(&rate_node->refcnt, 1);
652
list_add(&rate_node->list, &devlink->rate_list);
653
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
654
return 0;
655
656
err_rate_set:
657
ops->rate_node_del(rate_node, rate_node->priv, info->extack);
658
err_node_new:
659
kfree(rate_node->name);
660
err_strdup:
661
kfree(rate_node);
662
return err;
663
}
664
665
int devlink_nl_rate_del_doit(struct sk_buff *skb, struct genl_info *info)
666
{
667
struct devlink *devlink = info->user_ptr[0];
668
struct devlink_rate *rate_node;
669
int err;
670
671
rate_node = devlink_rate_node_get_from_info(devlink, info);
672
if (IS_ERR(rate_node))
673
return PTR_ERR(rate_node);
674
675
if (refcount_read(&rate_node->refcnt) > 1) {
676
NL_SET_ERR_MSG(info->extack, "Node has children. Cannot delete node.");
677
return -EBUSY;
678
}
679
680
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL);
681
err = devlink->ops->rate_node_del(rate_node, rate_node->priv,
682
info->extack);
683
if (rate_node->parent)
684
refcount_dec(&rate_node->parent->refcnt);
685
list_del(&rate_node->list);
686
kfree(rate_node->name);
687
kfree(rate_node);
688
return err;
689
}
690
691
int devlink_rate_nodes_check(struct devlink *devlink, u16 mode,
692
struct netlink_ext_ack *extack)
693
{
694
struct devlink_rate *devlink_rate;
695
696
list_for_each_entry(devlink_rate, &devlink->rate_list, list)
697
if (devlink_rate_is_node(devlink_rate)) {
698
NL_SET_ERR_MSG(extack, "Rate node(s) exists.");
699
return -EBUSY;
700
}
701
return 0;
702
}
703
704
/**
705
* devl_rate_node_create - create devlink rate node
706
* @devlink: devlink instance
707
* @priv: driver private data
708
* @node_name: name of the resulting node
709
* @parent: parent devlink_rate struct
710
*
711
* Create devlink rate object of type node
712
*/
713
struct devlink_rate *
714
devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,
715
struct devlink_rate *parent)
716
{
717
struct devlink_rate *rate_node;
718
719
rate_node = devlink_rate_node_get_by_name(devlink, node_name);
720
if (!IS_ERR(rate_node))
721
return ERR_PTR(-EEXIST);
722
723
rate_node = kzalloc(sizeof(*rate_node), GFP_KERNEL);
724
if (!rate_node)
725
return ERR_PTR(-ENOMEM);
726
727
if (parent) {
728
rate_node->parent = parent;
729
refcount_inc(&rate_node->parent->refcnt);
730
}
731
732
rate_node->type = DEVLINK_RATE_TYPE_NODE;
733
rate_node->devlink = devlink;
734
rate_node->priv = priv;
735
736
rate_node->name = kstrdup(node_name, GFP_KERNEL);
737
if (!rate_node->name) {
738
kfree(rate_node);
739
return ERR_PTR(-ENOMEM);
740
}
741
742
refcount_set(&rate_node->refcnt, 1);
743
list_add(&rate_node->list, &devlink->rate_list);
744
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
745
return rate_node;
746
}
747
EXPORT_SYMBOL_GPL(devl_rate_node_create);
748
749
/**
750
* devl_rate_leaf_create - create devlink rate leaf
751
* @devlink_port: devlink port object to create rate object on
752
* @priv: driver private data
753
* @parent: parent devlink_rate struct
754
*
755
* Create devlink rate object of type leaf on provided @devlink_port.
756
*/
757
int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv,
758
struct devlink_rate *parent)
759
{
760
struct devlink *devlink = devlink_port->devlink;
761
struct devlink_rate *devlink_rate;
762
763
devl_assert_locked(devlink_port->devlink);
764
765
if (WARN_ON(devlink_port->devlink_rate))
766
return -EBUSY;
767
768
devlink_rate = kzalloc(sizeof(*devlink_rate), GFP_KERNEL);
769
if (!devlink_rate)
770
return -ENOMEM;
771
772
if (parent) {
773
devlink_rate->parent = parent;
774
refcount_inc(&devlink_rate->parent->refcnt);
775
}
776
777
devlink_rate->type = DEVLINK_RATE_TYPE_LEAF;
778
devlink_rate->devlink = devlink;
779
devlink_rate->devlink_port = devlink_port;
780
devlink_rate->priv = priv;
781
list_add_tail(&devlink_rate->list, &devlink->rate_list);
782
devlink_port->devlink_rate = devlink_rate;
783
devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
784
785
return 0;
786
}
787
EXPORT_SYMBOL_GPL(devl_rate_leaf_create);
788
789
/**
790
* devl_rate_leaf_destroy - destroy devlink rate leaf
791
*
792
* @devlink_port: devlink port linked to the rate object
793
*
794
* Destroy the devlink rate object of type leaf on provided @devlink_port.
795
*/
796
void devl_rate_leaf_destroy(struct devlink_port *devlink_port)
797
{
798
struct devlink_rate *devlink_rate = devlink_port->devlink_rate;
799
800
devl_assert_locked(devlink_port->devlink);
801
if (!devlink_rate)
802
return;
803
804
devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_DEL);
805
if (devlink_rate->parent)
806
refcount_dec(&devlink_rate->parent->refcnt);
807
list_del(&devlink_rate->list);
808
devlink_port->devlink_rate = NULL;
809
kfree(devlink_rate);
810
}
811
EXPORT_SYMBOL_GPL(devl_rate_leaf_destroy);
812
813
/**
814
* devl_rate_nodes_destroy - destroy all devlink rate nodes on device
815
* @devlink: devlink instance
816
*
817
* Unset parent for all rate objects and destroy all rate nodes
818
* on specified device.
819
*/
820
void devl_rate_nodes_destroy(struct devlink *devlink)
821
{
822
static struct devlink_rate *devlink_rate, *tmp;
823
const struct devlink_ops *ops = devlink->ops;
824
825
devl_assert_locked(devlink);
826
827
list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
828
if (!devlink_rate->parent)
829
continue;
830
831
refcount_dec(&devlink_rate->parent->refcnt);
832
if (devlink_rate_is_leaf(devlink_rate))
833
ops->rate_leaf_parent_set(devlink_rate, NULL, devlink_rate->priv,
834
NULL, NULL);
835
else if (devlink_rate_is_node(devlink_rate))
836
ops->rate_node_parent_set(devlink_rate, NULL, devlink_rate->priv,
837
NULL, NULL);
838
}
839
list_for_each_entry_safe(devlink_rate, tmp, &devlink->rate_list, list) {
840
if (devlink_rate_is_node(devlink_rate)) {
841
ops->rate_node_del(devlink_rate, devlink_rate->priv, NULL);
842
list_del(&devlink_rate->list);
843
kfree(devlink_rate->name);
844
kfree(devlink_rate);
845
}
846
}
847
}
848
EXPORT_SYMBOL_GPL(devl_rate_nodes_destroy);
849
850