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 <jiri@mellanox.com> 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_nl_rate_fill(struct sk_buff *msg, 84 struct devlink_rate *devlink_rate, 85 enum devlink_command cmd, u32 portid, u32 seq, 86 int flags, struct netlink_ext_ack *extack) 87 { 88 struct devlink *devlink = devlink_rate->devlink; 89 void *hdr; 90 91 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 92 if (!hdr) 93 return -EMSGSIZE; 94 95 if (devlink_nl_put_handle(msg, devlink)) 96 goto nla_put_failure; 97 98 if (nla_put_u16(msg, DEVLINK_ATTR_RATE_TYPE, devlink_rate->type)) 99 goto nla_put_failure; 100 101 if (devlink_rate_is_leaf(devlink_rate)) { 102 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, 103 devlink_rate->devlink_port->index)) 104 goto nla_put_failure; 105 } else if (devlink_rate_is_node(devlink_rate)) { 106 if (nla_put_string(msg, DEVLINK_ATTR_RATE_NODE_NAME, 107 devlink_rate->name)) 108 goto nla_put_failure; 109 } 110 111 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_SHARE, 112 devlink_rate->tx_share, DEVLINK_ATTR_PAD)) 113 goto nla_put_failure; 114 115 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_MAX, 116 devlink_rate->tx_max, DEVLINK_ATTR_PAD)) 117 goto nla_put_failure; 118 119 if (nla_put_u32(msg, DEVLINK_ATTR_RATE_TX_PRIORITY, 120 devlink_rate->tx_priority)) 121 goto nla_put_failure; 122 123 if (nla_put_u32(msg, DEVLINK_ATTR_RATE_TX_WEIGHT, 124 devlink_rate->tx_weight)) 125 goto nla_put_failure; 126 127 if (devlink_rate->parent) 128 if (nla_put_string(msg, DEVLINK_ATTR_RATE_PARENT_NODE_NAME, 129 devlink_rate->parent->name)) 130 goto nla_put_failure; 131 132 genlmsg_end(msg, hdr); 133 return 0; 134 135 nla_put_failure: 136 genlmsg_cancel(msg, hdr); 137 return -EMSGSIZE; 138 } 139 140 static void devlink_rate_notify(struct devlink_rate *devlink_rate, 141 enum devlink_command cmd) 142 { 143 struct devlink *devlink = devlink_rate->devlink; 144 struct sk_buff *msg; 145 int err; 146 147 WARN_ON(cmd != DEVLINK_CMD_RATE_NEW && cmd != DEVLINK_CMD_RATE_DEL); 148 149 if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink)) 150 return; 151 152 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 153 if (!msg) 154 return; 155 156 err = devlink_nl_rate_fill(msg, devlink_rate, cmd, 0, 0, 0, NULL); 157 if (err) { 158 nlmsg_free(msg); 159 return; 160 } 161 162 devlink_nl_notify_send(devlink, msg); 163 } 164 165 void devlink_rates_notify_register(struct devlink *devlink) 166 { 167 struct devlink_rate *rate_node; 168 169 list_for_each_entry(rate_node, &devlink->rate_list, list) 170 devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW); 171 } 172 173 void devlink_rates_notify_unregister(struct devlink *devlink) 174 { 175 struct devlink_rate *rate_node; 176 177 list_for_each_entry_reverse(rate_node, &devlink->rate_list, list) 178 devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL); 179 } 180 181 static int 182 devlink_nl_rate_get_dump_one(struct sk_buff *msg, struct devlink *devlink, 183 struct netlink_callback *cb, int flags) 184 { 185 struct devlink_nl_dump_state *state = devlink_dump_state(cb); 186 struct devlink_rate *devlink_rate; 187 int idx = 0; 188 int err = 0; 189 190 list_for_each_entry(devlink_rate, &devlink->rate_list, list) { 191 enum devlink_command cmd = DEVLINK_CMD_RATE_NEW; 192 u32 id = NETLINK_CB(cb->skb).portid; 193 194 if (idx < state->idx) { 195 idx++; 196 continue; 197 } 198 err = devlink_nl_rate_fill(msg, devlink_rate, cmd, id, 199 cb->nlh->nlmsg_seq, flags, NULL); 200 if (err) { 201 state->idx = idx; 202 break; 203 } 204 idx++; 205 } 206 207 return err; 208 } 209 210 int devlink_nl_rate_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 211 { 212 return devlink_nl_dumpit(skb, cb, devlink_nl_rate_get_dump_one); 213 } 214 215 int devlink_nl_rate_get_doit(struct sk_buff *skb, struct genl_info *info) 216 { 217 struct devlink *devlink = info->user_ptr[0]; 218 struct devlink_rate *devlink_rate; 219 struct sk_buff *msg; 220 int err; 221 222 devlink_rate = devlink_rate_get_from_info(devlink, info); 223 if (IS_ERR(devlink_rate)) 224 return PTR_ERR(devlink_rate); 225 226 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 227 if (!msg) 228 return -ENOMEM; 229 230 err = devlink_nl_rate_fill(msg, devlink_rate, DEVLINK_CMD_RATE_NEW, 231 info->snd_portid, info->snd_seq, 0, 232 info->extack); 233 if (err) { 234 nlmsg_free(msg); 235 return err; 236 } 237 238 return genlmsg_reply(msg, info); 239 } 240 241 static bool 242 devlink_rate_is_parent_node(struct devlink_rate *devlink_rate, 243 struct devlink_rate *parent) 244 { 245 while (parent) { 246 if (parent == devlink_rate) 247 return true; 248 parent = parent->parent; 249 } 250 return false; 251 } 252 253 static int 254 devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate, 255 struct genl_info *info, 256 struct nlattr *nla_parent) 257 { 258 struct devlink *devlink = devlink_rate->devlink; 259 const char *parent_name = nla_data(nla_parent); 260 const struct devlink_ops *ops = devlink->ops; 261 size_t len = strlen(parent_name); 262 struct devlink_rate *parent; 263 int err = -EOPNOTSUPP; 264 265 parent = devlink_rate->parent; 266 267 if (parent && !len) { 268 if (devlink_rate_is_leaf(devlink_rate)) 269 err = ops->rate_leaf_parent_set(devlink_rate, NULL, 270 devlink_rate->priv, NULL, 271 info->extack); 272 else if (devlink_rate_is_node(devlink_rate)) 273 err = ops->rate_node_parent_set(devlink_rate, NULL, 274 devlink_rate->priv, NULL, 275 info->extack); 276 if (err) 277 return err; 278 279 refcount_dec(&parent->refcnt); 280 devlink_rate->parent = NULL; 281 } else if (len) { 282 parent = devlink_rate_node_get_by_name(devlink, parent_name); 283 if (IS_ERR(parent)) 284 return -ENODEV; 285 286 if (parent == devlink_rate) { 287 NL_SET_ERR_MSG(info->extack, "Parent to self is not allowed"); 288 return -EINVAL; 289 } 290 291 if (devlink_rate_is_node(devlink_rate) && 292 devlink_rate_is_parent_node(devlink_rate, parent->parent)) { 293 NL_SET_ERR_MSG(info->extack, "Node is already a parent of parent node."); 294 return -EEXIST; 295 } 296 297 if (devlink_rate_is_leaf(devlink_rate)) 298 err = ops->rate_leaf_parent_set(devlink_rate, parent, 299 devlink_rate->priv, parent->priv, 300 info->extack); 301 else if (devlink_rate_is_node(devlink_rate)) 302 err = ops->rate_node_parent_set(devlink_rate, parent, 303 devlink_rate->priv, parent->priv, 304 info->extack); 305 if (err) 306 return err; 307 308 if (devlink_rate->parent) 309 /* we're reassigning to other parent in this case */ 310 refcount_dec(&devlink_rate->parent->refcnt); 311 312 refcount_inc(&parent->refcnt); 313 devlink_rate->parent = parent; 314 } 315 316 return 0; 317 } 318 319 static int devlink_nl_rate_set(struct devlink_rate *devlink_rate, 320 const struct devlink_ops *ops, 321 struct genl_info *info) 322 { 323 struct nlattr *nla_parent, **attrs = info->attrs; 324 int err = -EOPNOTSUPP; 325 u32 priority; 326 u32 weight; 327 u64 rate; 328 329 if (attrs[DEVLINK_ATTR_RATE_TX_SHARE]) { 330 rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_SHARE]); 331 if (devlink_rate_is_leaf(devlink_rate)) 332 err = ops->rate_leaf_tx_share_set(devlink_rate, devlink_rate->priv, 333 rate, info->extack); 334 else if (devlink_rate_is_node(devlink_rate)) 335 err = ops->rate_node_tx_share_set(devlink_rate, devlink_rate->priv, 336 rate, info->extack); 337 if (err) 338 return err; 339 devlink_rate->tx_share = rate; 340 } 341 342 if (attrs[DEVLINK_ATTR_RATE_TX_MAX]) { 343 rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_MAX]); 344 if (devlink_rate_is_leaf(devlink_rate)) 345 err = ops->rate_leaf_tx_max_set(devlink_rate, devlink_rate->priv, 346 rate, info->extack); 347 else if (devlink_rate_is_node(devlink_rate)) 348 err = ops->rate_node_tx_max_set(devlink_rate, devlink_rate->priv, 349 rate, info->extack); 350 if (err) 351 return err; 352 devlink_rate->tx_max = rate; 353 } 354 355 if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY]) { 356 priority = nla_get_u32(attrs[DEVLINK_ATTR_RATE_TX_PRIORITY]); 357 if (devlink_rate_is_leaf(devlink_rate)) 358 err = ops->rate_leaf_tx_priority_set(devlink_rate, devlink_rate->priv, 359 priority, info->extack); 360 else if (devlink_rate_is_node(devlink_rate)) 361 err = ops->rate_node_tx_priority_set(devlink_rate, devlink_rate->priv, 362 priority, info->extack); 363 364 if (err) 365 return err; 366 devlink_rate->tx_priority = priority; 367 } 368 369 if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT]) { 370 weight = nla_get_u32(attrs[DEVLINK_ATTR_RATE_TX_WEIGHT]); 371 if (devlink_rate_is_leaf(devlink_rate)) 372 err = ops->rate_leaf_tx_weight_set(devlink_rate, devlink_rate->priv, 373 weight, info->extack); 374 else if (devlink_rate_is_node(devlink_rate)) 375 err = ops->rate_node_tx_weight_set(devlink_rate, devlink_rate->priv, 376 weight, info->extack); 377 378 if (err) 379 return err; 380 devlink_rate->tx_weight = weight; 381 } 382 383 nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]; 384 if (nla_parent) { 385 err = devlink_nl_rate_parent_node_set(devlink_rate, info, 386 nla_parent); 387 if (err) 388 return err; 389 } 390 391 return 0; 392 } 393 394 static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops, 395 struct genl_info *info, 396 enum devlink_rate_type type) 397 { 398 struct nlattr **attrs = info->attrs; 399 400 if (type == DEVLINK_RATE_TYPE_LEAF) { 401 if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_leaf_tx_share_set) { 402 NL_SET_ERR_MSG(info->extack, "TX share set isn't supported for the leafs"); 403 return false; 404 } 405 if (attrs[DEVLINK_ATTR_RATE_TX_MAX] && !ops->rate_leaf_tx_max_set) { 406 NL_SET_ERR_MSG(info->extack, "TX max set isn't supported for the leafs"); 407 return false; 408 } 409 if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] && 410 !ops->rate_leaf_parent_set) { 411 NL_SET_ERR_MSG(info->extack, "Parent set isn't supported for the leafs"); 412 return false; 413 } 414 if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY] && !ops->rate_leaf_tx_priority_set) { 415 NL_SET_ERR_MSG_ATTR(info->extack, 416 attrs[DEVLINK_ATTR_RATE_TX_PRIORITY], 417 "TX priority set isn't supported for the leafs"); 418 return false; 419 } 420 if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT] && !ops->rate_leaf_tx_weight_set) { 421 NL_SET_ERR_MSG_ATTR(info->extack, 422 attrs[DEVLINK_ATTR_RATE_TX_WEIGHT], 423 "TX weight set isn't supported for the leafs"); 424 return false; 425 } 426 } else if (type == DEVLINK_RATE_TYPE_NODE) { 427 if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_node_tx_share_set) { 428 NL_SET_ERR_MSG(info->extack, "TX share set isn't supported for the nodes"); 429 return false; 430 } 431 if (attrs[DEVLINK_ATTR_RATE_TX_MAX] && !ops->rate_node_tx_max_set) { 432 NL_SET_ERR_MSG(info->extack, "TX max set isn't supported for the nodes"); 433 return false; 434 } 435 if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] && 436 !ops->rate_node_parent_set) { 437 NL_SET_ERR_MSG(info->extack, "Parent set isn't supported for the nodes"); 438 return false; 439 } 440 if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY] && !ops->rate_node_tx_priority_set) { 441 NL_SET_ERR_MSG_ATTR(info->extack, 442 attrs[DEVLINK_ATTR_RATE_TX_PRIORITY], 443 "TX priority set isn't supported for the nodes"); 444 return false; 445 } 446 if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT] && !ops->rate_node_tx_weight_set) { 447 NL_SET_ERR_MSG_ATTR(info->extack, 448 attrs[DEVLINK_ATTR_RATE_TX_WEIGHT], 449 "TX weight set isn't supported for the nodes"); 450 return false; 451 } 452 } else { 453 WARN(1, "Unknown type of rate object"); 454 return false; 455 } 456 457 return true; 458 } 459 460 int devlink_nl_rate_set_doit(struct sk_buff *skb, struct genl_info *info) 461 { 462 struct devlink *devlink = info->user_ptr[0]; 463 struct devlink_rate *devlink_rate; 464 const struct devlink_ops *ops; 465 int err; 466 467 devlink_rate = devlink_rate_get_from_info(devlink, info); 468 if (IS_ERR(devlink_rate)) 469 return PTR_ERR(devlink_rate); 470 471 ops = devlink->ops; 472 if (!ops || !devlink_rate_set_ops_supported(ops, info, devlink_rate->type)) 473 return -EOPNOTSUPP; 474 475 err = devlink_nl_rate_set(devlink_rate, ops, info); 476 477 if (!err) 478 devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW); 479 return err; 480 } 481 482 int devlink_nl_rate_new_doit(struct sk_buff *skb, struct genl_info *info) 483 { 484 struct devlink *devlink = info->user_ptr[0]; 485 struct devlink_rate *rate_node; 486 const struct devlink_ops *ops; 487 int err; 488 489 ops = devlink->ops; 490 if (!ops || !ops->rate_node_new || !ops->rate_node_del) { 491 NL_SET_ERR_MSG(info->extack, "Rate nodes aren't supported"); 492 return -EOPNOTSUPP; 493 } 494 495 if (!devlink_rate_set_ops_supported(ops, info, DEVLINK_RATE_TYPE_NODE)) 496 return -EOPNOTSUPP; 497 498 rate_node = devlink_rate_node_get_from_attrs(devlink, info->attrs); 499 if (!IS_ERR(rate_node)) 500 return -EEXIST; 501 else if (rate_node == ERR_PTR(-EINVAL)) 502 return -EINVAL; 503 504 rate_node = kzalloc(sizeof(*rate_node), GFP_KERNEL); 505 if (!rate_node) 506 return -ENOMEM; 507 508 rate_node->devlink = devlink; 509 rate_node->type = DEVLINK_RATE_TYPE_NODE; 510 rate_node->name = nla_strdup(info->attrs[DEVLINK_ATTR_RATE_NODE_NAME], GFP_KERNEL); 511 if (!rate_node->name) { 512 err = -ENOMEM; 513 goto err_strdup; 514 } 515 516 err = ops->rate_node_new(rate_node, &rate_node->priv, info->extack); 517 if (err) 518 goto err_node_new; 519 520 err = devlink_nl_rate_set(rate_node, ops, info); 521 if (err) 522 goto err_rate_set; 523 524 refcount_set(&rate_node->refcnt, 1); 525 list_add(&rate_node->list, &devlink->rate_list); 526 devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW); 527 return 0; 528 529 err_rate_set: 530 ops->rate_node_del(rate_node, rate_node->priv, info->extack); 531 err_node_new: 532 kfree(rate_node->name); 533 err_strdup: 534 kfree(rate_node); 535 return err; 536 } 537 538 int devlink_nl_rate_del_doit(struct sk_buff *skb, struct genl_info *info) 539 { 540 struct devlink *devlink = info->user_ptr[0]; 541 struct devlink_rate *rate_node; 542 int err; 543 544 rate_node = devlink_rate_node_get_from_info(devlink, info); 545 if (IS_ERR(rate_node)) 546 return PTR_ERR(rate_node); 547 548 if (refcount_read(&rate_node->refcnt) > 1) { 549 NL_SET_ERR_MSG(info->extack, "Node has children. Cannot delete node."); 550 return -EBUSY; 551 } 552 553 devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL); 554 err = devlink->ops->rate_node_del(rate_node, rate_node->priv, 555 info->extack); 556 if (rate_node->parent) 557 refcount_dec(&rate_node->parent->refcnt); 558 list_del(&rate_node->list); 559 kfree(rate_node->name); 560 kfree(rate_node); 561 return err; 562 } 563 564 int devlink_rate_nodes_check(struct devlink *devlink, u16 mode, 565 struct netlink_ext_ack *extack) 566 { 567 struct devlink_rate *devlink_rate; 568 569 list_for_each_entry(devlink_rate, &devlink->rate_list, list) 570 if (devlink_rate_is_node(devlink_rate)) { 571 NL_SET_ERR_MSG(extack, "Rate node(s) exists."); 572 return -EBUSY; 573 } 574 return 0; 575 } 576 577 /** 578 * devl_rate_node_create - create devlink rate node 579 * @devlink: devlink instance 580 * @priv: driver private data 581 * @node_name: name of the resulting node 582 * @parent: parent devlink_rate struct 583 * 584 * Create devlink rate object of type node 585 */ 586 struct devlink_rate * 587 devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name, 588 struct devlink_rate *parent) 589 { 590 struct devlink_rate *rate_node; 591 592 rate_node = devlink_rate_node_get_by_name(devlink, node_name); 593 if (!IS_ERR(rate_node)) 594 return ERR_PTR(-EEXIST); 595 596 rate_node = kzalloc(sizeof(*rate_node), GFP_KERNEL); 597 if (!rate_node) 598 return ERR_PTR(-ENOMEM); 599 600 if (parent) { 601 rate_node->parent = parent; 602 refcount_inc(&rate_node->parent->refcnt); 603 } 604 605 rate_node->type = DEVLINK_RATE_TYPE_NODE; 606 rate_node->devlink = devlink; 607 rate_node->priv = priv; 608 609 rate_node->name = kstrdup(node_name, GFP_KERNEL); 610 if (!rate_node->name) { 611 kfree(rate_node); 612 return ERR_PTR(-ENOMEM); 613 } 614 615 refcount_set(&rate_node->refcnt, 1); 616 list_add(&rate_node->list, &devlink->rate_list); 617 devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW); 618 return rate_node; 619 } 620 EXPORT_SYMBOL_GPL(devl_rate_node_create); 621 622 /** 623 * devl_rate_leaf_create - create devlink rate leaf 624 * @devlink_port: devlink port object to create rate object on 625 * @priv: driver private data 626 * @parent: parent devlink_rate struct 627 * 628 * Create devlink rate object of type leaf on provided @devlink_port. 629 */ 630 int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv, 631 struct devlink_rate *parent) 632 { 633 struct devlink *devlink = devlink_port->devlink; 634 struct devlink_rate *devlink_rate; 635 636 devl_assert_locked(devlink_port->devlink); 637 638 if (WARN_ON(devlink_port->devlink_rate)) 639 return -EBUSY; 640 641 devlink_rate = kzalloc(sizeof(*devlink_rate), GFP_KERNEL); 642 if (!devlink_rate) 643 return -ENOMEM; 644 645 if (parent) { 646 devlink_rate->parent = parent; 647 refcount_inc(&devlink_rate->parent->refcnt); 648 } 649 650 devlink_rate->type = DEVLINK_RATE_TYPE_LEAF; 651 devlink_rate->devlink = devlink; 652 devlink_rate->devlink_port = devlink_port; 653 devlink_rate->priv = priv; 654 list_add_tail(&devlink_rate->list, &devlink->rate_list); 655 devlink_port->devlink_rate = devlink_rate; 656 devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW); 657 658 return 0; 659 } 660 EXPORT_SYMBOL_GPL(devl_rate_leaf_create); 661 662 /** 663 * devl_rate_leaf_destroy - destroy devlink rate leaf 664 * 665 * @devlink_port: devlink port linked to the rate object 666 * 667 * Destroy the devlink rate object of type leaf on provided @devlink_port. 668 */ 669 void devl_rate_leaf_destroy(struct devlink_port *devlink_port) 670 { 671 struct devlink_rate *devlink_rate = devlink_port->devlink_rate; 672 673 devl_assert_locked(devlink_port->devlink); 674 if (!devlink_rate) 675 return; 676 677 devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_DEL); 678 if (devlink_rate->parent) 679 refcount_dec(&devlink_rate->parent->refcnt); 680 list_del(&devlink_rate->list); 681 devlink_port->devlink_rate = NULL; 682 kfree(devlink_rate); 683 } 684 EXPORT_SYMBOL_GPL(devl_rate_leaf_destroy); 685 686 /** 687 * devl_rate_nodes_destroy - destroy all devlink rate nodes on device 688 * @devlink: devlink instance 689 * 690 * Unset parent for all rate objects and destroy all rate nodes 691 * on specified device. 692 */ 693 void devl_rate_nodes_destroy(struct devlink *devlink) 694 { 695 static struct devlink_rate *devlink_rate, *tmp; 696 const struct devlink_ops *ops = devlink->ops; 697 698 devl_assert_locked(devlink); 699 700 list_for_each_entry(devlink_rate, &devlink->rate_list, list) { 701 if (!devlink_rate->parent) 702 continue; 703 704 refcount_dec(&devlink_rate->parent->refcnt); 705 if (devlink_rate_is_leaf(devlink_rate)) 706 ops->rate_leaf_parent_set(devlink_rate, NULL, devlink_rate->priv, 707 NULL, NULL); 708 else if (devlink_rate_is_node(devlink_rate)) 709 ops->rate_node_parent_set(devlink_rate, NULL, devlink_rate->priv, 710 NULL, NULL); 711 } 712 list_for_each_entry_safe(devlink_rate, tmp, &devlink->rate_list, list) { 713 if (devlink_rate_is_node(devlink_rate)) { 714 ops->rate_node_del(devlink_rate, devlink_rate->priv, NULL); 715 list_del(&devlink_rate->list); 716 kfree(devlink_rate->name); 717 kfree(devlink_rate); 718 } 719 } 720 } 721 EXPORT_SYMBOL_GPL(devl_rate_nodes_destroy); 722
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.