aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/devlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/devlink.c')
-rw-r--r--net/core/devlink.c1080
1 files changed, 1075 insertions, 5 deletions
diff --git a/net/core/devlink.c b/net/core/devlink.c
index d3dbb904bf3b..650f36379203 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -18,6 +18,8 @@
18#include <linux/spinlock.h> 18#include <linux/spinlock.h>
19#include <linux/refcount.h> 19#include <linux/refcount.h>
20#include <linux/workqueue.h> 20#include <linux/workqueue.h>
21#include <linux/u64_stats_sync.h>
22#include <linux/timekeeping.h>
21#include <rdma/ib_verbs.h> 23#include <rdma/ib_verbs.h>
22#include <net/netlink.h> 24#include <net/netlink.h>
23#include <net/genetlink.h> 25#include <net/genetlink.h>
@@ -25,6 +27,7 @@
25#include <net/net_namespace.h> 27#include <net/net_namespace.h>
26#include <net/sock.h> 28#include <net/sock.h>
27#include <net/devlink.h> 29#include <net/devlink.h>
30#include <net/drop_monitor.h>
28#define CREATE_TRACE_POINTS 31#define CREATE_TRACE_POINTS
29#include <trace/events/devlink.h> 32#include <trace/events/devlink.h>
30 33
@@ -551,7 +554,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
551 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) 554 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
552 goto nla_put_failure; 555 goto nla_put_failure;
553 556
554 spin_lock(&devlink_port->type_lock); 557 spin_lock_bh(&devlink_port->type_lock);
555 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type)) 558 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
556 goto nla_put_failure_type_locked; 559 goto nla_put_failure_type_locked;
557 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET && 560 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
@@ -576,7 +579,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
576 ibdev->name)) 579 ibdev->name))
577 goto nla_put_failure_type_locked; 580 goto nla_put_failure_type_locked;
578 } 581 }
579 spin_unlock(&devlink_port->type_lock); 582 spin_unlock_bh(&devlink_port->type_lock);
580 if (devlink_nl_port_attrs_put(msg, devlink_port)) 583 if (devlink_nl_port_attrs_put(msg, devlink_port))
581 goto nla_put_failure; 584 goto nla_put_failure;
582 585
@@ -584,7 +587,7 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
584 return 0; 587 return 0;
585 588
586nla_put_failure_type_locked: 589nla_put_failure_type_locked:
587 spin_unlock(&devlink_port->type_lock); 590 spin_unlock_bh(&devlink_port->type_lock);
588nla_put_failure: 591nla_put_failure:
589 genlmsg_cancel(msg, hdr); 592 genlmsg_cancel(msg, hdr);
590 return -EMSGSIZE; 593 return -EMSGSIZE;
@@ -5154,6 +5157,571 @@ devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
5154 return 0; 5157 return 0;
5155} 5158}
5156 5159
5160struct devlink_stats {
5161 u64 rx_bytes;
5162 u64 rx_packets;
5163 struct u64_stats_sync syncp;
5164};
5165
5166/**
5167 * struct devlink_trap_group_item - Packet trap group attributes.
5168 * @group: Immutable packet trap group attributes.
5169 * @refcount: Number of trap items using the group.
5170 * @list: trap_group_list member.
5171 * @stats: Trap group statistics.
5172 *
5173 * Describes packet trap group attributes. Created by devlink during trap
5174 * registration.
5175 */
5176struct devlink_trap_group_item {
5177 const struct devlink_trap_group *group;
5178 refcount_t refcount;
5179 struct list_head list;
5180 struct devlink_stats __percpu *stats;
5181};
5182
5183/**
5184 * struct devlink_trap_item - Packet trap attributes.
5185 * @trap: Immutable packet trap attributes.
5186 * @group_item: Associated group item.
5187 * @list: trap_list member.
5188 * @action: Trap action.
5189 * @stats: Trap statistics.
5190 * @priv: Driver private information.
5191 *
5192 * Describes both mutable and immutable packet trap attributes. Created by
5193 * devlink during trap registration and used for all trap related operations.
5194 */
5195struct devlink_trap_item {
5196 const struct devlink_trap *trap;
5197 struct devlink_trap_group_item *group_item;
5198 struct list_head list;
5199 enum devlink_trap_action action;
5200 struct devlink_stats __percpu *stats;
5201 void *priv;
5202};
5203
5204static struct devlink_trap_item *
5205devlink_trap_item_lookup(struct devlink *devlink, const char *name)
5206{
5207 struct devlink_trap_item *trap_item;
5208
5209 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5210 if (!strcmp(trap_item->trap->name, name))
5211 return trap_item;
5212 }
5213
5214 return NULL;
5215}
5216
5217static struct devlink_trap_item *
5218devlink_trap_item_get_from_info(struct devlink *devlink,
5219 struct genl_info *info)
5220{
5221 struct nlattr *attr;
5222
5223 if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
5224 return NULL;
5225 attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
5226
5227 return devlink_trap_item_lookup(devlink, nla_data(attr));
5228}
5229
5230static int
5231devlink_trap_action_get_from_info(struct genl_info *info,
5232 enum devlink_trap_action *p_trap_action)
5233{
5234 u8 val;
5235
5236 val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
5237 switch (val) {
5238 case DEVLINK_TRAP_ACTION_DROP: /* fall-through */
5239 case DEVLINK_TRAP_ACTION_TRAP:
5240 *p_trap_action = val;
5241 break;
5242 default:
5243 return -EINVAL;
5244 }
5245
5246 return 0;
5247}
5248
5249static int devlink_trap_metadata_put(struct sk_buff *msg,
5250 const struct devlink_trap *trap)
5251{
5252 struct nlattr *attr;
5253
5254 attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
5255 if (!attr)
5256 return -EMSGSIZE;
5257
5258 if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
5259 nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
5260 goto nla_put_failure;
5261
5262 nla_nest_end(msg, attr);
5263
5264 return 0;
5265
5266nla_put_failure:
5267 nla_nest_cancel(msg, attr);
5268 return -EMSGSIZE;
5269}
5270
5271static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
5272 struct devlink_stats *stats)
5273{
5274 int i;
5275
5276 memset(stats, 0, sizeof(*stats));
5277 for_each_possible_cpu(i) {
5278 struct devlink_stats *cpu_stats;
5279 u64 rx_packets, rx_bytes;
5280 unsigned int start;
5281
5282 cpu_stats = per_cpu_ptr(trap_stats, i);
5283 do {
5284 start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
5285 rx_packets = cpu_stats->rx_packets;
5286 rx_bytes = cpu_stats->rx_bytes;
5287 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
5288
5289 stats->rx_packets += rx_packets;
5290 stats->rx_bytes += rx_bytes;
5291 }
5292}
5293
5294static int devlink_trap_stats_put(struct sk_buff *msg,
5295 struct devlink_stats __percpu *trap_stats)
5296{
5297 struct devlink_stats stats;
5298 struct nlattr *attr;
5299
5300 devlink_trap_stats_read(trap_stats, &stats);
5301
5302 attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
5303 if (!attr)
5304 return -EMSGSIZE;
5305
5306 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
5307 stats.rx_packets, DEVLINK_ATTR_PAD))
5308 goto nla_put_failure;
5309
5310 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
5311 stats.rx_bytes, DEVLINK_ATTR_PAD))
5312 goto nla_put_failure;
5313
5314 nla_nest_end(msg, attr);
5315
5316 return 0;
5317
5318nla_put_failure:
5319 nla_nest_cancel(msg, attr);
5320 return -EMSGSIZE;
5321}
5322
5323static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
5324 const struct devlink_trap_item *trap_item,
5325 enum devlink_command cmd, u32 portid, u32 seq,
5326 int flags)
5327{
5328 struct devlink_trap_group_item *group_item = trap_item->group_item;
5329 void *hdr;
5330 int err;
5331
5332 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5333 if (!hdr)
5334 return -EMSGSIZE;
5335
5336 if (devlink_nl_put_handle(msg, devlink))
5337 goto nla_put_failure;
5338
5339 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
5340 group_item->group->name))
5341 goto nla_put_failure;
5342
5343 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
5344 goto nla_put_failure;
5345
5346 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
5347 goto nla_put_failure;
5348
5349 if (trap_item->trap->generic &&
5350 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
5351 goto nla_put_failure;
5352
5353 if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
5354 goto nla_put_failure;
5355
5356 err = devlink_trap_metadata_put(msg, trap_item->trap);
5357 if (err)
5358 goto nla_put_failure;
5359
5360 err = devlink_trap_stats_put(msg, trap_item->stats);
5361 if (err)
5362 goto nla_put_failure;
5363
5364 genlmsg_end(msg, hdr);
5365
5366 return 0;
5367
5368nla_put_failure:
5369 genlmsg_cancel(msg, hdr);
5370 return -EMSGSIZE;
5371}
5372
5373static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
5374 struct genl_info *info)
5375{
5376 struct netlink_ext_ack *extack = info->extack;
5377 struct devlink *devlink = info->user_ptr[0];
5378 struct devlink_trap_item *trap_item;
5379 struct sk_buff *msg;
5380 int err;
5381
5382 if (list_empty(&devlink->trap_list))
5383 return -EOPNOTSUPP;
5384
5385 trap_item = devlink_trap_item_get_from_info(devlink, info);
5386 if (!trap_item) {
5387 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
5388 return -ENOENT;
5389 }
5390
5391 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5392 if (!msg)
5393 return -ENOMEM;
5394
5395 err = devlink_nl_trap_fill(msg, devlink, trap_item,
5396 DEVLINK_CMD_TRAP_NEW, info->snd_portid,
5397 info->snd_seq, 0);
5398 if (err)
5399 goto err_trap_fill;
5400
5401 return genlmsg_reply(msg, info);
5402
5403err_trap_fill:
5404 nlmsg_free(msg);
5405 return err;
5406}
5407
5408static int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
5409 struct netlink_callback *cb)
5410{
5411 struct devlink_trap_item *trap_item;
5412 struct devlink *devlink;
5413 int start = cb->args[0];
5414 int idx = 0;
5415 int err;
5416
5417 mutex_lock(&devlink_mutex);
5418 list_for_each_entry(devlink, &devlink_list, list) {
5419 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5420 continue;
5421 mutex_lock(&devlink->lock);
5422 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5423 if (idx < start) {
5424 idx++;
5425 continue;
5426 }
5427 err = devlink_nl_trap_fill(msg, devlink, trap_item,
5428 DEVLINK_CMD_TRAP_NEW,
5429 NETLINK_CB(cb->skb).portid,
5430 cb->nlh->nlmsg_seq,
5431 NLM_F_MULTI);
5432 if (err) {
5433 mutex_unlock(&devlink->lock);
5434 goto out;
5435 }
5436 idx++;
5437 }
5438 mutex_unlock(&devlink->lock);
5439 }
5440out:
5441 mutex_unlock(&devlink_mutex);
5442
5443 cb->args[0] = idx;
5444 return msg->len;
5445}
5446
5447static int __devlink_trap_action_set(struct devlink *devlink,
5448 struct devlink_trap_item *trap_item,
5449 enum devlink_trap_action trap_action,
5450 struct netlink_ext_ack *extack)
5451{
5452 int err;
5453
5454 if (trap_item->action != trap_action &&
5455 trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
5456 NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
5457 return 0;
5458 }
5459
5460 err = devlink->ops->trap_action_set(devlink, trap_item->trap,
5461 trap_action);
5462 if (err)
5463 return err;
5464
5465 trap_item->action = trap_action;
5466
5467 return 0;
5468}
5469
5470static int devlink_trap_action_set(struct devlink *devlink,
5471 struct devlink_trap_item *trap_item,
5472 struct genl_info *info)
5473{
5474 enum devlink_trap_action trap_action;
5475 int err;
5476
5477 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
5478 return 0;
5479
5480 err = devlink_trap_action_get_from_info(info, &trap_action);
5481 if (err) {
5482 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
5483 return -EINVAL;
5484 }
5485
5486 return __devlink_trap_action_set(devlink, trap_item, trap_action,
5487 info->extack);
5488}
5489
5490static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
5491 struct genl_info *info)
5492{
5493 struct netlink_ext_ack *extack = info->extack;
5494 struct devlink *devlink = info->user_ptr[0];
5495 struct devlink_trap_item *trap_item;
5496 int err;
5497
5498 if (list_empty(&devlink->trap_list))
5499 return -EOPNOTSUPP;
5500
5501 trap_item = devlink_trap_item_get_from_info(devlink, info);
5502 if (!trap_item) {
5503 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
5504 return -ENOENT;
5505 }
5506
5507 err = devlink_trap_action_set(devlink, trap_item, info);
5508 if (err)
5509 return err;
5510
5511 return 0;
5512}
5513
5514static struct devlink_trap_group_item *
5515devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
5516{
5517 struct devlink_trap_group_item *group_item;
5518
5519 list_for_each_entry(group_item, &devlink->trap_group_list, list) {
5520 if (!strcmp(group_item->group->name, name))
5521 return group_item;
5522 }
5523
5524 return NULL;
5525}
5526
5527static struct devlink_trap_group_item *
5528devlink_trap_group_item_get_from_info(struct devlink *devlink,
5529 struct genl_info *info)
5530{
5531 char *name;
5532
5533 if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
5534 return NULL;
5535 name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
5536
5537 return devlink_trap_group_item_lookup(devlink, name);
5538}
5539
5540static int
5541devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
5542 const struct devlink_trap_group_item *group_item,
5543 enum devlink_command cmd, u32 portid, u32 seq,
5544 int flags)
5545{
5546 void *hdr;
5547 int err;
5548
5549 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
5550 if (!hdr)
5551 return -EMSGSIZE;
5552
5553 if (devlink_nl_put_handle(msg, devlink))
5554 goto nla_put_failure;
5555
5556 if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
5557 group_item->group->name))
5558 goto nla_put_failure;
5559
5560 if (group_item->group->generic &&
5561 nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
5562 goto nla_put_failure;
5563
5564 err = devlink_trap_stats_put(msg, group_item->stats);
5565 if (err)
5566 goto nla_put_failure;
5567
5568 genlmsg_end(msg, hdr);
5569
5570 return 0;
5571
5572nla_put_failure:
5573 genlmsg_cancel(msg, hdr);
5574 return -EMSGSIZE;
5575}
5576
5577static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
5578 struct genl_info *info)
5579{
5580 struct netlink_ext_ack *extack = info->extack;
5581 struct devlink *devlink = info->user_ptr[0];
5582 struct devlink_trap_group_item *group_item;
5583 struct sk_buff *msg;
5584 int err;
5585
5586 if (list_empty(&devlink->trap_group_list))
5587 return -EOPNOTSUPP;
5588
5589 group_item = devlink_trap_group_item_get_from_info(devlink, info);
5590 if (!group_item) {
5591 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
5592 return -ENOENT;
5593 }
5594
5595 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5596 if (!msg)
5597 return -ENOMEM;
5598
5599 err = devlink_nl_trap_group_fill(msg, devlink, group_item,
5600 DEVLINK_CMD_TRAP_GROUP_NEW,
5601 info->snd_portid, info->snd_seq, 0);
5602 if (err)
5603 goto err_trap_group_fill;
5604
5605 return genlmsg_reply(msg, info);
5606
5607err_trap_group_fill:
5608 nlmsg_free(msg);
5609 return err;
5610}
5611
5612static int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
5613 struct netlink_callback *cb)
5614{
5615 enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
5616 struct devlink_trap_group_item *group_item;
5617 u32 portid = NETLINK_CB(cb->skb).portid;
5618 struct devlink *devlink;
5619 int start = cb->args[0];
5620 int idx = 0;
5621 int err;
5622
5623 mutex_lock(&devlink_mutex);
5624 list_for_each_entry(devlink, &devlink_list, list) {
5625 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
5626 continue;
5627 mutex_lock(&devlink->lock);
5628 list_for_each_entry(group_item, &devlink->trap_group_list,
5629 list) {
5630 if (idx < start) {
5631 idx++;
5632 continue;
5633 }
5634 err = devlink_nl_trap_group_fill(msg, devlink,
5635 group_item, cmd,
5636 portid,
5637 cb->nlh->nlmsg_seq,
5638 NLM_F_MULTI);
5639 if (err) {
5640 mutex_unlock(&devlink->lock);
5641 goto out;
5642 }
5643 idx++;
5644 }
5645 mutex_unlock(&devlink->lock);
5646 }
5647out:
5648 mutex_unlock(&devlink_mutex);
5649
5650 cb->args[0] = idx;
5651 return msg->len;
5652}
5653
5654static int
5655__devlink_trap_group_action_set(struct devlink *devlink,
5656 struct devlink_trap_group_item *group_item,
5657 enum devlink_trap_action trap_action,
5658 struct netlink_ext_ack *extack)
5659{
5660 const char *group_name = group_item->group->name;
5661 struct devlink_trap_item *trap_item;
5662 int err;
5663
5664 list_for_each_entry(trap_item, &devlink->trap_list, list) {
5665 if (strcmp(trap_item->trap->group.name, group_name))
5666 continue;
5667 err = __devlink_trap_action_set(devlink, trap_item,
5668 trap_action, extack);
5669 if (err)
5670 return err;
5671 }
5672
5673 return 0;
5674}
5675
5676static int
5677devlink_trap_group_action_set(struct devlink *devlink,
5678 struct devlink_trap_group_item *group_item,
5679 struct genl_info *info)
5680{
5681 enum devlink_trap_action trap_action;
5682 int err;
5683
5684 if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
5685 return 0;
5686
5687 err = devlink_trap_action_get_from_info(info, &trap_action);
5688 if (err) {
5689 NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
5690 return -EINVAL;
5691 }
5692
5693 err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
5694 info->extack);
5695 if (err)
5696 return err;
5697
5698 return 0;
5699}
5700
5701static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
5702 struct genl_info *info)
5703{
5704 struct netlink_ext_ack *extack = info->extack;
5705 struct devlink *devlink = info->user_ptr[0];
5706 struct devlink_trap_group_item *group_item;
5707 int err;
5708
5709 if (list_empty(&devlink->trap_group_list))
5710 return -EOPNOTSUPP;
5711
5712 group_item = devlink_trap_group_item_get_from_info(devlink, info);
5713 if (!group_item) {
5714 NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
5715 return -ENOENT;
5716 }
5717
5718 err = devlink_trap_group_action_set(devlink, group_item, info);
5719 if (err)
5720 return err;
5721
5722 return 0;
5723}
5724
5157static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { 5725static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
5158 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, 5726 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
5159 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, 5727 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
@@ -5184,6 +5752,9 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
5184 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 }, 5752 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
5185 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING }, 5753 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
5186 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING }, 5754 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
5755 [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
5756 [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
5757 [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
5187}; 5758};
5188 5759
5189static const struct genl_ops devlink_nl_ops[] = { 5760static const struct genl_ops devlink_nl_ops[] = {
@@ -5483,6 +6054,32 @@ static const struct genl_ops devlink_nl_ops[] = {
5483 .flags = GENL_ADMIN_PERM, 6054 .flags = GENL_ADMIN_PERM,
5484 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, 6055 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5485 }, 6056 },
6057 {
6058 .cmd = DEVLINK_CMD_TRAP_GET,
6059 .doit = devlink_nl_cmd_trap_get_doit,
6060 .dumpit = devlink_nl_cmd_trap_get_dumpit,
6061 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6062 /* can be retrieved by unprivileged users */
6063 },
6064 {
6065 .cmd = DEVLINK_CMD_TRAP_SET,
6066 .doit = devlink_nl_cmd_trap_set_doit,
6067 .flags = GENL_ADMIN_PERM,
6068 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6069 },
6070 {
6071 .cmd = DEVLINK_CMD_TRAP_GROUP_GET,
6072 .doit = devlink_nl_cmd_trap_group_get_doit,
6073 .dumpit = devlink_nl_cmd_trap_group_get_dumpit,
6074 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6075 /* can be retrieved by unprivileged users */
6076 },
6077 {
6078 .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
6079 .doit = devlink_nl_cmd_trap_group_set_doit,
6080 .flags = GENL_ADMIN_PERM,
6081 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
6082 },
5486}; 6083};
5487 6084
5488static struct genl_family devlink_nl_family __ro_after_init = { 6085static struct genl_family devlink_nl_family __ro_after_init = {
@@ -5528,6 +6125,8 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
5528 INIT_LIST_HEAD(&devlink->param_list); 6125 INIT_LIST_HEAD(&devlink->param_list);
5529 INIT_LIST_HEAD(&devlink->region_list); 6126 INIT_LIST_HEAD(&devlink->region_list);
5530 INIT_LIST_HEAD(&devlink->reporter_list); 6127 INIT_LIST_HEAD(&devlink->reporter_list);
6128 INIT_LIST_HEAD(&devlink->trap_list);
6129 INIT_LIST_HEAD(&devlink->trap_group_list);
5531 mutex_init(&devlink->lock); 6130 mutex_init(&devlink->lock);
5532 mutex_init(&devlink->reporters_lock); 6131 mutex_init(&devlink->reporters_lock);
5533 return devlink; 6132 return devlink;
@@ -5574,6 +6173,8 @@ void devlink_free(struct devlink *devlink)
5574{ 6173{
5575 mutex_destroy(&devlink->reporters_lock); 6174 mutex_destroy(&devlink->reporters_lock);
5576 mutex_destroy(&devlink->lock); 6175 mutex_destroy(&devlink->lock);
6176 WARN_ON(!list_empty(&devlink->trap_group_list));
6177 WARN_ON(!list_empty(&devlink->trap_list));
5577 WARN_ON(!list_empty(&devlink->reporter_list)); 6178 WARN_ON(!list_empty(&devlink->reporter_list));
5578 WARN_ON(!list_empty(&devlink->region_list)); 6179 WARN_ON(!list_empty(&devlink->region_list));
5579 WARN_ON(!list_empty(&devlink->param_list)); 6180 WARN_ON(!list_empty(&devlink->param_list));
@@ -5678,10 +6279,10 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port,
5678 if (WARN_ON(!devlink_port->registered)) 6279 if (WARN_ON(!devlink_port->registered))
5679 return; 6280 return;
5680 devlink_port_type_warn_cancel(devlink_port); 6281 devlink_port_type_warn_cancel(devlink_port);
5681 spin_lock(&devlink_port->type_lock); 6282 spin_lock_bh(&devlink_port->type_lock);
5682 devlink_port->type = type; 6283 devlink_port->type = type;
5683 devlink_port->type_dev = type_dev; 6284 devlink_port->type_dev = type_dev;
5684 spin_unlock(&devlink_port->type_lock); 6285 spin_unlock_bh(&devlink_port->type_lock);
5685 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); 6286 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5686} 6287}
5687 6288
@@ -6834,6 +7435,475 @@ unlock:
6834} 7435}
6835EXPORT_SYMBOL_GPL(devlink_region_snapshot_create); 7436EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
6836 7437
7438#define DEVLINK_TRAP(_id, _type) \
7439 { \
7440 .type = DEVLINK_TRAP_TYPE_##_type, \
7441 .id = DEVLINK_TRAP_GENERIC_ID_##_id, \
7442 .name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
7443 }
7444
7445static const struct devlink_trap devlink_trap_generic[] = {
7446 DEVLINK_TRAP(SMAC_MC, DROP),
7447 DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
7448 DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
7449 DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
7450 DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
7451 DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
7452 DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
7453 DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
7454 DEVLINK_TRAP(TAIL_DROP, DROP),
7455};
7456
7457#define DEVLINK_TRAP_GROUP(_id) \
7458 { \
7459 .id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
7460 .name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
7461 }
7462
7463static const struct devlink_trap_group devlink_trap_group_generic[] = {
7464 DEVLINK_TRAP_GROUP(L2_DROPS),
7465 DEVLINK_TRAP_GROUP(L3_DROPS),
7466 DEVLINK_TRAP_GROUP(BUFFER_DROPS),
7467};
7468
7469static int devlink_trap_generic_verify(const struct devlink_trap *trap)
7470{
7471 if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
7472 return -EINVAL;
7473
7474 if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
7475 return -EINVAL;
7476
7477 if (trap->type != devlink_trap_generic[trap->id].type)
7478 return -EINVAL;
7479
7480 return 0;
7481}
7482
7483static int devlink_trap_driver_verify(const struct devlink_trap *trap)
7484{
7485 int i;
7486
7487 if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
7488 return -EINVAL;
7489
7490 for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
7491 if (!strcmp(trap->name, devlink_trap_generic[i].name))
7492 return -EEXIST;
7493 }
7494
7495 return 0;
7496}
7497
7498static int devlink_trap_verify(const struct devlink_trap *trap)
7499{
7500 if (!trap || !trap->name || !trap->group.name)
7501 return -EINVAL;
7502
7503 if (trap->generic)
7504 return devlink_trap_generic_verify(trap);
7505 else
7506 return devlink_trap_driver_verify(trap);
7507}
7508
7509static int
7510devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
7511{
7512 if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
7513 return -EINVAL;
7514
7515 if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
7516 return -EINVAL;
7517
7518 return 0;
7519}
7520
7521static int
7522devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
7523{
7524 int i;
7525
7526 if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
7527 return -EINVAL;
7528
7529 for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
7530 if (!strcmp(group->name, devlink_trap_group_generic[i].name))
7531 return -EEXIST;
7532 }
7533
7534 return 0;
7535}
7536
7537static int devlink_trap_group_verify(const struct devlink_trap_group *group)
7538{
7539 if (group->generic)
7540 return devlink_trap_group_generic_verify(group);
7541 else
7542 return devlink_trap_group_driver_verify(group);
7543}
7544
7545static void
7546devlink_trap_group_notify(struct devlink *devlink,
7547 const struct devlink_trap_group_item *group_item,
7548 enum devlink_command cmd)
7549{
7550 struct sk_buff *msg;
7551 int err;
7552
7553 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
7554 cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
7555
7556 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7557 if (!msg)
7558 return;
7559
7560 err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
7561 0);
7562 if (err) {
7563 nlmsg_free(msg);
7564 return;
7565 }
7566
7567 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
7568 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
7569}
7570
7571static struct devlink_trap_group_item *
7572devlink_trap_group_item_create(struct devlink *devlink,
7573 const struct devlink_trap_group *group)
7574{
7575 struct devlink_trap_group_item *group_item;
7576 int err;
7577
7578 err = devlink_trap_group_verify(group);
7579 if (err)
7580 return ERR_PTR(err);
7581
7582 group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
7583 if (!group_item)
7584 return ERR_PTR(-ENOMEM);
7585
7586 group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
7587 if (!group_item->stats) {
7588 err = -ENOMEM;
7589 goto err_stats_alloc;
7590 }
7591
7592 group_item->group = group;
7593 refcount_set(&group_item->refcount, 1);
7594
7595 if (devlink->ops->trap_group_init) {
7596 err = devlink->ops->trap_group_init(devlink, group);
7597 if (err)
7598 goto err_group_init;
7599 }
7600
7601 list_add_tail(&group_item->list, &devlink->trap_group_list);
7602 devlink_trap_group_notify(devlink, group_item,
7603 DEVLINK_CMD_TRAP_GROUP_NEW);
7604
7605 return group_item;
7606
7607err_group_init:
7608 free_percpu(group_item->stats);
7609err_stats_alloc:
7610 kfree(group_item);
7611 return ERR_PTR(err);
7612}
7613
7614static void
7615devlink_trap_group_item_destroy(struct devlink *devlink,
7616 struct devlink_trap_group_item *group_item)
7617{
7618 devlink_trap_group_notify(devlink, group_item,
7619 DEVLINK_CMD_TRAP_GROUP_DEL);
7620 list_del(&group_item->list);
7621 free_percpu(group_item->stats);
7622 kfree(group_item);
7623}
7624
7625static struct devlink_trap_group_item *
7626devlink_trap_group_item_get(struct devlink *devlink,
7627 const struct devlink_trap_group *group)
7628{
7629 struct devlink_trap_group_item *group_item;
7630
7631 group_item = devlink_trap_group_item_lookup(devlink, group->name);
7632 if (group_item) {
7633 refcount_inc(&group_item->refcount);
7634 return group_item;
7635 }
7636
7637 return devlink_trap_group_item_create(devlink, group);
7638}
7639
7640static void
7641devlink_trap_group_item_put(struct devlink *devlink,
7642 struct devlink_trap_group_item *group_item)
7643{
7644 if (!refcount_dec_and_test(&group_item->refcount))
7645 return;
7646
7647 devlink_trap_group_item_destroy(devlink, group_item);
7648}
7649
7650static int
7651devlink_trap_item_group_link(struct devlink *devlink,
7652 struct devlink_trap_item *trap_item)
7653{
7654 struct devlink_trap_group_item *group_item;
7655
7656 group_item = devlink_trap_group_item_get(devlink,
7657 &trap_item->trap->group);
7658 if (IS_ERR(group_item))
7659 return PTR_ERR(group_item);
7660
7661 trap_item->group_item = group_item;
7662
7663 return 0;
7664}
7665
7666static void
7667devlink_trap_item_group_unlink(struct devlink *devlink,
7668 struct devlink_trap_item *trap_item)
7669{
7670 devlink_trap_group_item_put(devlink, trap_item->group_item);
7671}
7672
7673static void devlink_trap_notify(struct devlink *devlink,
7674 const struct devlink_trap_item *trap_item,
7675 enum devlink_command cmd)
7676{
7677 struct sk_buff *msg;
7678 int err;
7679
7680 WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
7681 cmd != DEVLINK_CMD_TRAP_DEL);
7682
7683 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7684 if (!msg)
7685 return;
7686
7687 err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
7688 if (err) {
7689 nlmsg_free(msg);
7690 return;
7691 }
7692
7693 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
7694 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
7695}
7696
7697static int
7698devlink_trap_register(struct devlink *devlink,
7699 const struct devlink_trap *trap, void *priv)
7700{
7701 struct devlink_trap_item *trap_item;
7702 int err;
7703
7704 if (devlink_trap_item_lookup(devlink, trap->name))
7705 return -EEXIST;
7706
7707 trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
7708 if (!trap_item)
7709 return -ENOMEM;
7710
7711 trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
7712 if (!trap_item->stats) {
7713 err = -ENOMEM;
7714 goto err_stats_alloc;
7715 }
7716
7717 trap_item->trap = trap;
7718 trap_item->action = trap->init_action;
7719 trap_item->priv = priv;
7720
7721 err = devlink_trap_item_group_link(devlink, trap_item);
7722 if (err)
7723 goto err_group_link;
7724
7725 err = devlink->ops->trap_init(devlink, trap, trap_item);
7726 if (err)
7727 goto err_trap_init;
7728
7729 list_add_tail(&trap_item->list, &devlink->trap_list);
7730 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
7731
7732 return 0;
7733
7734err_trap_init:
7735 devlink_trap_item_group_unlink(devlink, trap_item);
7736err_group_link:
7737 free_percpu(trap_item->stats);
7738err_stats_alloc:
7739 kfree(trap_item);
7740 return err;
7741}
7742
7743static void devlink_trap_unregister(struct devlink *devlink,
7744 const struct devlink_trap *trap)
7745{
7746 struct devlink_trap_item *trap_item;
7747
7748 trap_item = devlink_trap_item_lookup(devlink, trap->name);
7749 if (WARN_ON_ONCE(!trap_item))
7750 return;
7751
7752 devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
7753 list_del(&trap_item->list);
7754 if (devlink->ops->trap_fini)
7755 devlink->ops->trap_fini(devlink, trap, trap_item);
7756 devlink_trap_item_group_unlink(devlink, trap_item);
7757 free_percpu(trap_item->stats);
7758 kfree(trap_item);
7759}
7760
7761static void devlink_trap_disable(struct devlink *devlink,
7762 const struct devlink_trap *trap)
7763{
7764 struct devlink_trap_item *trap_item;
7765
7766 trap_item = devlink_trap_item_lookup(devlink, trap->name);
7767 if (WARN_ON_ONCE(!trap_item))
7768 return;
7769
7770 devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP);
7771 trap_item->action = DEVLINK_TRAP_ACTION_DROP;
7772}
7773
7774/**
7775 * devlink_traps_register - Register packet traps with devlink.
7776 * @devlink: devlink.
7777 * @traps: Packet traps.
7778 * @traps_count: Count of provided packet traps.
7779 * @priv: Driver private information.
7780 *
7781 * Return: Non-zero value on failure.
7782 */
7783int devlink_traps_register(struct devlink *devlink,
7784 const struct devlink_trap *traps,
7785 size_t traps_count, void *priv)
7786{
7787 int i, err;
7788
7789 if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
7790 return -EINVAL;
7791
7792 mutex_lock(&devlink->lock);
7793 for (i = 0; i < traps_count; i++) {
7794 const struct devlink_trap *trap = &traps[i];
7795
7796 err = devlink_trap_verify(trap);
7797 if (err)
7798 goto err_trap_verify;
7799
7800 err = devlink_trap_register(devlink, trap, priv);
7801 if (err)
7802 goto err_trap_register;
7803 }
7804 mutex_unlock(&devlink->lock);
7805
7806 return 0;
7807
7808err_trap_register:
7809err_trap_verify:
7810 for (i--; i >= 0; i--)
7811 devlink_trap_unregister(devlink, &traps[i]);
7812 mutex_unlock(&devlink->lock);
7813 return err;
7814}
7815EXPORT_SYMBOL_GPL(devlink_traps_register);
7816
7817/**
7818 * devlink_traps_unregister - Unregister packet traps from devlink.
7819 * @devlink: devlink.
7820 * @traps: Packet traps.
7821 * @traps_count: Count of provided packet traps.
7822 */
7823void devlink_traps_unregister(struct devlink *devlink,
7824 const struct devlink_trap *traps,
7825 size_t traps_count)
7826{
7827 int i;
7828
7829 mutex_lock(&devlink->lock);
7830 /* Make sure we do not have any packets in-flight while unregistering
7831 * traps by disabling all of them and waiting for a grace period.
7832 */
7833 for (i = traps_count - 1; i >= 0; i--)
7834 devlink_trap_disable(devlink, &traps[i]);
7835 synchronize_rcu();
7836 for (i = traps_count - 1; i >= 0; i--)
7837 devlink_trap_unregister(devlink, &traps[i]);
7838 mutex_unlock(&devlink->lock);
7839}
7840EXPORT_SYMBOL_GPL(devlink_traps_unregister);
7841
7842static void
7843devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
7844 size_t skb_len)
7845{
7846 struct devlink_stats *stats;
7847
7848 stats = this_cpu_ptr(trap_stats);
7849 u64_stats_update_begin(&stats->syncp);
7850 stats->rx_bytes += skb_len;
7851 stats->rx_packets++;
7852 u64_stats_update_end(&stats->syncp);
7853}
7854
7855static void
7856devlink_trap_report_metadata_fill(struct net_dm_hw_metadata *hw_metadata,
7857 const struct devlink_trap_item *trap_item,
7858 struct devlink_port *in_devlink_port)
7859{
7860 struct devlink_trap_group_item *group_item = trap_item->group_item;
7861
7862 hw_metadata->trap_group_name = group_item->group->name;
7863 hw_metadata->trap_name = trap_item->trap->name;
7864
7865 spin_lock(&in_devlink_port->type_lock);
7866 if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
7867 hw_metadata->input_dev = in_devlink_port->type_dev;
7868 spin_unlock(&in_devlink_port->type_lock);
7869}
7870
7871/**
7872 * devlink_trap_report - Report trapped packet to drop monitor.
7873 * @devlink: devlink.
7874 * @skb: Trapped packet.
7875 * @trap_ctx: Trap context.
7876 * @in_devlink_port: Input devlink port.
7877 */
7878void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
7879 void *trap_ctx, struct devlink_port *in_devlink_port)
7880{
7881 struct devlink_trap_item *trap_item = trap_ctx;
7882 struct net_dm_hw_metadata hw_metadata = {};
7883
7884 devlink_trap_stats_update(trap_item->stats, skb->len);
7885 devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
7886
7887 devlink_trap_report_metadata_fill(&hw_metadata, trap_item,
7888 in_devlink_port);
7889 net_dm_hw_report(skb, &hw_metadata);
7890}
7891EXPORT_SYMBOL_GPL(devlink_trap_report);
7892
7893/**
7894 * devlink_trap_ctx_priv - Trap context to driver private information.
7895 * @trap_ctx: Trap context.
7896 *
7897 * Return: Driver private information passed during registration.
7898 */
7899void *devlink_trap_ctx_priv(void *trap_ctx)
7900{
7901 struct devlink_trap_item *trap_item = trap_ctx;
7902
7903 return trap_item->priv;
7904}
7905EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
7906
6837static void __devlink_compat_running_version(struct devlink *devlink, 7907static void __devlink_compat_running_version(struct devlink *devlink,
6838 char *buf, size_t len) 7908 char *buf, size_t len)
6839{ 7909{