aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/devlink.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2019-08-17 15:40:09 -0400
committerDavid S. Miller <davem@davemloft.net>2019-08-17 15:40:09 -0400
commit83beee5a3aff0fb159b2fb4d0cac8f18a193417e (patch)
treece77ccefee1384488408d9b9e49e2148359f30d9 /net/core/devlink.c
parentf77508308fa76d0efc60ebf3c906f467feb062cb (diff)
parent95766451bfb82f972bf3fea93fc6e91a904cf624 (diff)
Merge branch 'drop_monitor-for-offloaded-paths'
Ido Schimmel says: ==================== Add drop monitor for offloaded data paths Users have several ways to debug the kernel and understand why a packet was dropped. For example, using drop monitor and perf. Both utilities trace kfree_skb(), which is the function called when a packet is freed as part of a failure. The information provided by these tools is invaluable when trying to understand the cause of a packet loss. In recent years, large portions of the kernel data path were offloaded to capable devices. Today, it is possible to perform L2 and L3 forwarding in hardware, as well as tunneling (IP-in-IP and VXLAN). Different TC classifiers and actions are also offloaded to capable devices, at both ingress and egress. However, when the data path is offloaded it is not possible to achieve the same level of introspection since packets are dropped by the underlying device and never reach the kernel. This patchset aims to solve this by allowing users to monitor packets that the underlying device decided to drop along with relevant metadata such as the drop reason and ingress port. The above is achieved by exposing a fundamental capability of devices capable of data path offloading - packet trapping. In much the same way as drop monitor registers its probe function with the kfree_skb() tracepoint, the device is instructed to pass to the CPU (trap) packets that it decided to drop in various places in the pipeline. The configuration of the device to pass such packets to the CPU is performed using devlink, as it is not specific to a port, but rather to a device. In the future, we plan to control the policing of such packets using devlink, in order not to overwhelm the CPU. While devlink is used as the control path, the dropped packets are passed along with metadata to drop monitor, which reports them to userspace as netlink events. This allows users to use the same interface for the monitoring of both software and hardware drops. Logically, the solution looks as follows: Netlink event: Packet w/ metadata Or a summary of recent drops ^ | Userspace | +---------------------------------------------------+ Kernel | | +-------+--------+ | | | drop_monitor | | | +-------^--------+ | | | +----+----+ | | Kernel's Rx path | devlink | (non-drop traps) | | +----^----+ ^ | | +-----------+ | +-------+-------+ | | | Device driver | | | +-------^-------+ Kernel | +---------------------------------------------------+ Hardware | | Trapped packet | +--+---+ | | | ASIC | | | +------+ In order to reduce the patch count, this patchset only includes integration with netdevsim. A follow-up patchset will add devlink-trap support in mlxsw. Patches #1-#7 extend drop monitor to also monitor hardware originated drops. Patches #8-#10 add the devlink-trap infrastructure. Patches #11-#12 add devlink-trap support in netdevsim. Patches #13-#16 add tests for the generic infrastructure over netdevsim. Example ======= Instantiate netdevsim --------------------- List supported traps -------------------- netdevsim/netdevsim10: name source_mac_is_multicast type drop generic true action drop group l2_drops name vlan_tag_mismatch type drop generic true action drop group l2_drops name ingress_vlan_filter type drop generic true action drop group l2_drops name ingress_spanning_tree_filter type drop generic true action drop group l2_drops name port_list_is_empty type drop generic true action drop group l2_drops name port_loopback_filter type drop generic true action drop group l2_drops name fid_miss type exception generic false action trap group l2_drops name blackhole_route type drop generic true action drop group l3_drops name ttl_value_is_too_small type exception generic true action trap group l3_drops name tail_drop type drop generic true action drop group buffer_drops Enable a trap ------------- Query statistics ---------------- netdevsim/netdevsim10: name blackhole_route type drop generic true action trap group l3_drops stats: rx: bytes 7384 packets 52 Monitor dropped packets ----------------------- dropwatch> set alertmode packet Setting alert mode Alert mode successfully set dropwatch> set sw true setting software drops monitoring to 1 dropwatch> set hw true setting hardware drops monitoring to 1 dropwatch> start Enabling monitoring... Kernel monitoring activated. Issue Ctrl-C to stop monitoring drop at: ttl_value_is_too_small (l3_drops) origin: hardware input port ifindex: 55 input port name: eth0 timestamp: Mon Aug 12 10:52:20 2019 445911505 nsec protocol: 0x800 length: 142 original length: 142 drop at: ip6_mc_input+0x8b8/0xef8 (0xffffffff9e2bb0e8) origin: software input port ifindex: 4 timestamp: Mon Aug 12 10:53:37 2019 024444587 nsec protocol: 0x86dd length: 110 original length: 110 Future plans ============ * Provide more drop reasons as well as more metadata * Add dropmon support to libpcap, so that tcpdump/tshark could specifically listen on dropmon traffic, instead of capturing all netlink packets via nlmon interface Changes in v3: * Place test with the rest of the netdevsim tests * Fix test to load netdevsim module * Move devlink helpers from the test to devlink_lib.sh. Will be used by mlxsw tests * Re-order netdevsim includes in alphabetical order * Fix reverse xmas tree in netdevsim * Remove double include in netdevsim Changes in v2: * Use drop monitor to report dropped packets instead of devlink * Add drop monitor patches * Add test cases ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
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{