2019-05-27 06:55:01 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2016-02-26 16:32:23 +00:00
|
|
|
/*
|
|
|
|
* net/core/devlink.c - Network physical/parent device Netlink interface
|
|
|
|
*
|
|
|
|
* Heavily inspired by net/wireless/
|
|
|
|
* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
|
|
|
|
* Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
|
|
|
|
*/
|
|
|
|
|
2021-12-29 00:49:13 +00:00
|
|
|
#include <linux/etherdevice.h>
|
2016-02-26 16:32:23 +00:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/gfp.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/netdevice.h>
|
2019-03-24 10:14:37 +00:00
|
|
|
#include <linux/spinlock.h>
|
2019-04-29 09:41:45 +00:00
|
|
|
#include <linux/refcount.h>
|
2019-05-23 08:43:35 +00:00
|
|
|
#include <linux/workqueue.h>
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
#include <linux/u64_stats_sync.h>
|
|
|
|
#include <linux/timekeeping.h>
|
2016-02-26 16:32:23 +00:00
|
|
|
#include <rdma/ib_verbs.h>
|
|
|
|
#include <net/netlink.h>
|
|
|
|
#include <net/genetlink.h>
|
|
|
|
#include <net/rtnetlink.h>
|
|
|
|
#include <net/net_namespace.h>
|
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/devlink.h>
|
2016-07-12 16:05:03 +00:00
|
|
|
#define CREATE_TRACE_POINTS
|
|
|
|
#include <trace/events/devlink.h>
|
|
|
|
|
2023-01-05 04:05:19 +00:00
|
|
|
#include "devl_internal.h"
|
2022-04-18 06:42:26 +00:00
|
|
|
|
2022-04-18 06:42:25 +00:00
|
|
|
struct devlink_linecard {
|
|
|
|
struct list_head list;
|
|
|
|
struct devlink *devlink;
|
|
|
|
unsigned int index;
|
2022-04-18 06:42:26 +00:00
|
|
|
const struct devlink_linecard_ops *ops;
|
|
|
|
void *priv;
|
|
|
|
enum devlink_linecard_state state;
|
2022-05-04 15:40:37 +00:00
|
|
|
struct mutex state_lock; /* Protects state */
|
2022-04-18 06:42:26 +00:00
|
|
|
const char *type;
|
|
|
|
struct devlink_linecard_type *types;
|
|
|
|
unsigned int types_count;
|
2022-07-25 08:29:16 +00:00
|
|
|
struct devlink *nested_devlink;
|
2022-04-18 06:42:25 +00:00
|
|
|
};
|
|
|
|
|
2021-11-30 10:16:20 +00:00
|
|
|
/**
|
|
|
|
* struct devlink_resource - devlink resource
|
|
|
|
* @name: name of the resource
|
|
|
|
* @id: id, per devlink instance
|
|
|
|
* @size: size of the resource
|
|
|
|
* @size_new: updated size of the resource, reload is needed
|
|
|
|
* @size_valid: valid in case the total size of the resource is valid
|
|
|
|
* including its children
|
|
|
|
* @parent: parent resource
|
|
|
|
* @size_params: size parameters
|
|
|
|
* @list: parent list
|
|
|
|
* @resource_list: list of child resources
|
|
|
|
* @occ_get: occupancy getter callback
|
|
|
|
* @occ_get_priv: occupancy getter callback priv
|
|
|
|
*/
|
|
|
|
struct devlink_resource {
|
|
|
|
const char *name;
|
|
|
|
u64 id;
|
|
|
|
u64 size;
|
|
|
|
u64 size_new;
|
|
|
|
bool size_valid;
|
|
|
|
struct devlink_resource *parent;
|
|
|
|
struct devlink_resource_size_params size_params;
|
|
|
|
struct list_head list;
|
|
|
|
struct list_head resource_list;
|
|
|
|
devlink_resource_occ_get_t *occ_get;
|
|
|
|
void *occ_get_priv;
|
|
|
|
};
|
|
|
|
|
2017-08-24 06:39:59 +00:00
|
|
|
static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
|
|
|
|
{
|
2017-08-31 00:07:30 +00:00
|
|
|
.name = "destination mac",
|
2017-08-24 06:39:59 +00:00
|
|
|
.id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
|
|
|
|
.bitwidth = 48,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
|
|
|
|
.name = "ethernet",
|
|
|
|
.id = DEVLINK_DPIPE_HEADER_ETHERNET,
|
|
|
|
.fields = devlink_dpipe_fields_ethernet,
|
|
|
|
.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
|
|
|
|
.global = true,
|
|
|
|
};
|
2021-10-28 21:19:13 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_header_ethernet);
|
2017-08-24 06:39:59 +00:00
|
|
|
|
2017-08-24 06:40:00 +00:00
|
|
|
static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
|
|
|
|
{
|
|
|
|
.name = "destination ip",
|
|
|
|
.id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
|
|
|
|
.bitwidth = 32,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
|
|
|
|
.name = "ipv4",
|
|
|
|
.id = DEVLINK_DPIPE_HEADER_IPV4,
|
|
|
|
.fields = devlink_dpipe_fields_ipv4,
|
|
|
|
.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
|
|
|
|
.global = true,
|
|
|
|
};
|
2021-10-28 21:19:13 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv4);
|
2017-08-24 06:40:00 +00:00
|
|
|
|
2017-08-31 15:59:12 +00:00
|
|
|
static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
|
|
|
|
{
|
|
|
|
.name = "destination ip",
|
|
|
|
.id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
|
|
|
|
.bitwidth = 128,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
|
|
|
|
.name = "ipv6",
|
|
|
|
.id = DEVLINK_DPIPE_HEADER_IPV6,
|
|
|
|
.fields = devlink_dpipe_fields_ipv6,
|
|
|
|
.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
|
|
|
|
.global = true,
|
|
|
|
};
|
2021-10-28 21:19:13 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv6);
|
2017-08-31 15:59:12 +00:00
|
|
|
|
2016-07-12 16:05:03 +00:00
|
|
|
EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
|
2019-02-04 18:47:45 +00:00
|
|
|
EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
|
2020-09-29 08:15:50 +00:00
|
|
|
EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_trap_report);
|
2016-02-26 16:32:23 +00:00
|
|
|
|
2022-12-06 18:51:15 +00:00
|
|
|
#define DEVLINK_PORT_FN_CAPS_VALID_MASK \
|
|
|
|
(_BITUL(__DEVLINK_PORT_FN_ATTR_CAPS_MAX) - 1)
|
|
|
|
|
2020-06-19 03:32:49 +00:00
|
|
|
static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {
|
|
|
|
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY },
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
[DEVLINK_PORT_FN_ATTR_STATE] =
|
|
|
|
NLA_POLICY_RANGE(NLA_U8, DEVLINK_PORT_FN_STATE_INACTIVE,
|
|
|
|
DEVLINK_PORT_FN_STATE_ACTIVE),
|
2022-12-06 18:51:15 +00:00
|
|
|
[DEVLINK_PORT_FN_ATTR_CAPS] =
|
|
|
|
NLA_POLICY_BITFIELD32(DEVLINK_PORT_FN_CAPS_VALID_MASK),
|
2020-06-19 03:32:49 +00:00
|
|
|
};
|
|
|
|
|
2022-09-29 07:28:56 +00:00
|
|
|
#define ASSERT_DEVLINK_PORT_REGISTERED(devlink_port) \
|
2022-09-29 07:28:57 +00:00
|
|
|
WARN_ON_ONCE(!(devlink_port)->registered)
|
2022-09-29 07:28:56 +00:00
|
|
|
#define ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port) \
|
2022-09-29 07:28:57 +00:00
|
|
|
WARN_ON_ONCE((devlink_port)->registered)
|
2022-09-29 07:28:58 +00:00
|
|
|
#define ASSERT_DEVLINK_PORT_INITIALIZED(devlink_port) \
|
|
|
|
WARN_ON_ONCE(!(devlink_port)->initialized)
|
2022-09-29 07:28:56 +00:00
|
|
|
|
2016-02-26 16:32:23 +00:00
|
|
|
static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
|
2019-08-30 10:39:44 +00:00
|
|
|
unsigned int port_index)
|
2016-02-26 16:32:23 +00:00
|
|
|
{
|
2022-11-30 08:52:50 +00:00
|
|
|
return xa_load(&devlink->ports, port_index);
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
|
|
|
|
struct nlattr **attrs)
|
|
|
|
{
|
|
|
|
if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
|
|
|
|
u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
|
|
|
|
struct devlink_port *devlink_port;
|
|
|
|
|
|
|
|
devlink_port = devlink_port_get_by_index(devlink, port_index);
|
|
|
|
if (!devlink_port)
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
return devlink_port;
|
|
|
|
}
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:20 +00:00
|
|
|
struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
|
|
|
|
struct genl_info *info)
|
2016-02-26 16:32:23 +00:00
|
|
|
{
|
|
|
|
return devlink_port_get_from_attrs(devlink, info->attrs);
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:19 +00:00
|
|
|
static inline bool
|
|
|
|
devlink_rate_is_leaf(struct devlink_rate *devlink_rate)
|
|
|
|
{
|
|
|
|
return devlink_rate->type == DEVLINK_RATE_TYPE_LEAF;
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:25 +00:00
|
|
|
static inline bool
|
|
|
|
devlink_rate_is_node(struct devlink_rate *devlink_rate)
|
|
|
|
{
|
|
|
|
return devlink_rate->type == DEVLINK_RATE_TYPE_NODE;
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:19 +00:00
|
|
|
static struct devlink_rate *
|
|
|
|
devlink_rate_leaf_get_from_info(struct devlink *devlink, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink_rate *devlink_rate;
|
|
|
|
struct devlink_port *devlink_port;
|
|
|
|
|
|
|
|
devlink_port = devlink_port_get_from_attrs(devlink, info->attrs);
|
|
|
|
if (IS_ERR(devlink_port))
|
|
|
|
return ERR_CAST(devlink_port);
|
|
|
|
devlink_rate = devlink_port->devlink_rate;
|
|
|
|
return devlink_rate ?: ERR_PTR(-ENODEV);
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:25 +00:00
|
|
|
static struct devlink_rate *
|
|
|
|
devlink_rate_node_get_by_name(struct devlink *devlink, const char *node_name)
|
|
|
|
{
|
|
|
|
static struct devlink_rate *devlink_rate;
|
|
|
|
|
|
|
|
list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
|
|
|
|
if (devlink_rate_is_node(devlink_rate) &&
|
|
|
|
!strcmp(node_name, devlink_rate->name))
|
|
|
|
return devlink_rate;
|
|
|
|
}
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_rate *
|
|
|
|
devlink_rate_node_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
|
|
|
|
{
|
|
|
|
const char *rate_node_name;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (!attrs[DEVLINK_ATTR_RATE_NODE_NAME])
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
rate_node_name = nla_data(attrs[DEVLINK_ATTR_RATE_NODE_NAME]);
|
|
|
|
len = strlen(rate_node_name);
|
|
|
|
/* Name cannot be empty or decimal number */
|
|
|
|
if (!len || strspn(rate_node_name, "0123456789") == len)
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
|
|
|
return devlink_rate_node_get_by_name(devlink, rate_node_name);
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:20 +00:00
|
|
|
struct devlink_rate *
|
2021-06-02 12:17:25 +00:00
|
|
|
devlink_rate_node_get_from_info(struct devlink *devlink, struct genl_info *info)
|
|
|
|
{
|
|
|
|
return devlink_rate_node_get_from_attrs(devlink, info->attrs);
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:20 +00:00
|
|
|
struct devlink_rate *
|
2021-06-02 12:17:25 +00:00
|
|
|
devlink_rate_get_from_info(struct devlink *devlink, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nlattr **attrs = info->attrs;
|
|
|
|
|
|
|
|
if (attrs[DEVLINK_ATTR_PORT_INDEX])
|
|
|
|
return devlink_rate_leaf_get_from_info(devlink, info);
|
|
|
|
else if (attrs[DEVLINK_ATTR_RATE_NODE_NAME])
|
|
|
|
return devlink_rate_node_get_from_info(devlink, info);
|
|
|
|
else
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
}
|
|
|
|
|
2022-04-18 06:42:25 +00:00
|
|
|
static struct devlink_linecard *
|
|
|
|
devlink_linecard_get_by_index(struct devlink *devlink,
|
|
|
|
unsigned int linecard_index)
|
|
|
|
{
|
|
|
|
struct devlink_linecard *devlink_linecard;
|
|
|
|
|
|
|
|
list_for_each_entry(devlink_linecard, &devlink->linecard_list, list) {
|
|
|
|
if (devlink_linecard->index == linecard_index)
|
|
|
|
return devlink_linecard;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool devlink_linecard_index_exists(struct devlink *devlink,
|
|
|
|
unsigned int linecard_index)
|
|
|
|
{
|
|
|
|
return devlink_linecard_get_by_index(devlink, linecard_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_linecard *
|
|
|
|
devlink_linecard_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
|
|
|
|
{
|
|
|
|
if (attrs[DEVLINK_ATTR_LINECARD_INDEX]) {
|
|
|
|
u32 linecard_index = nla_get_u32(attrs[DEVLINK_ATTR_LINECARD_INDEX]);
|
|
|
|
struct devlink_linecard *linecard;
|
|
|
|
|
|
|
|
linecard = devlink_linecard_get_by_index(devlink, linecard_index);
|
|
|
|
if (!linecard)
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
return linecard;
|
|
|
|
}
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:20 +00:00
|
|
|
struct devlink_linecard *
|
2022-04-18 06:42:25 +00:00
|
|
|
devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info)
|
|
|
|
{
|
|
|
|
return devlink_linecard_get_from_attrs(devlink, info->attrs);
|
|
|
|
}
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
struct devlink_sb {
|
|
|
|
struct list_head list;
|
|
|
|
unsigned int index;
|
|
|
|
u32 size;
|
|
|
|
u16 ingress_pools_count;
|
|
|
|
u16 egress_pools_count;
|
|
|
|
u16 ingress_tc_count;
|
|
|
|
u16 egress_tc_count;
|
|
|
|
};
|
|
|
|
|
|
|
|
static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
|
|
|
|
{
|
|
|
|
return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
|
|
|
|
unsigned int sb_index)
|
|
|
|
{
|
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
|
|
|
|
list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
|
|
|
|
if (devlink_sb->index == sb_index)
|
|
|
|
return devlink_sb;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool devlink_sb_index_exists(struct devlink *devlink,
|
|
|
|
unsigned int sb_index)
|
|
|
|
{
|
|
|
|
return devlink_sb_get_by_index(devlink, sb_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
|
|
|
|
struct nlattr **attrs)
|
|
|
|
{
|
|
|
|
if (attrs[DEVLINK_ATTR_SB_INDEX]) {
|
|
|
|
u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
|
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
|
|
|
|
devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
|
|
|
|
if (!devlink_sb)
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
|
|
return devlink_sb;
|
|
|
|
}
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
return devlink_sb_get_from_attrs(devlink, info->attrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
|
|
|
|
struct nlattr **attrs,
|
|
|
|
u16 *p_pool_index)
|
|
|
|
{
|
|
|
|
u16 val;
|
|
|
|
|
|
|
|
if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
|
|
|
|
if (val >= devlink_sb_pool_count(devlink_sb))
|
|
|
|
return -EINVAL;
|
|
|
|
*p_pool_index = val;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
|
|
|
|
struct genl_info *info,
|
|
|
|
u16 *p_pool_index)
|
|
|
|
{
|
|
|
|
return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
|
|
|
|
p_pool_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
|
|
|
|
enum devlink_sb_pool_type *p_pool_type)
|
|
|
|
{
|
|
|
|
u8 val;
|
|
|
|
|
|
|
|
if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
|
|
|
|
if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
|
|
|
|
val != DEVLINK_SB_POOL_TYPE_EGRESS)
|
|
|
|
return -EINVAL;
|
|
|
|
*p_pool_type = val;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_sb_pool_type_get_from_info(struct genl_info *info,
|
|
|
|
enum devlink_sb_pool_type *p_pool_type)
|
|
|
|
{
|
|
|
|
return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
|
|
|
|
enum devlink_sb_threshold_type *p_th_type)
|
|
|
|
{
|
|
|
|
u8 val;
|
|
|
|
|
|
|
|
if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
|
|
|
|
if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
|
|
|
|
val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
|
|
|
|
return -EINVAL;
|
|
|
|
*p_th_type = val;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_sb_th_type_get_from_info(struct genl_info *info,
|
|
|
|
enum devlink_sb_threshold_type *p_th_type)
|
|
|
|
{
|
|
|
|
return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
|
|
|
|
struct nlattr **attrs,
|
|
|
|
enum devlink_sb_pool_type pool_type,
|
|
|
|
u16 *p_tc_index)
|
|
|
|
{
|
|
|
|
u16 val;
|
|
|
|
|
|
|
|
if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
|
|
|
|
if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
|
|
|
|
val >= devlink_sb->ingress_tc_count)
|
|
|
|
return -EINVAL;
|
|
|
|
if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
|
|
|
|
val >= devlink_sb->egress_tc_count)
|
|
|
|
return -EINVAL;
|
|
|
|
*p_tc_index = val;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-12-06 18:51:15 +00:00
|
|
|
static void devlink_port_fn_cap_fill(struct nla_bitfield32 *caps,
|
|
|
|
u32 cap, bool is_enable)
|
|
|
|
{
|
|
|
|
caps->selector |= cap;
|
|
|
|
if (is_enable)
|
|
|
|
caps->value |= cap;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_port_fn_roce_fill(const struct devlink_ops *ops,
|
|
|
|
struct devlink_port *devlink_port,
|
|
|
|
struct nla_bitfield32 *caps,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
bool is_enable;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!ops->port_fn_roce_get)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err = ops->port_fn_roce_get(devlink_port, &is_enable, extack);
|
|
|
|
if (err) {
|
|
|
|
if (err == -EOPNOTSUPP)
|
|
|
|
return 0;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
devlink_port_fn_cap_fill(caps, DEVLINK_PORT_FN_CAP_ROCE, is_enable);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-12-06 18:51:18 +00:00
|
|
|
static int devlink_port_fn_migratable_fill(const struct devlink_ops *ops,
|
|
|
|
struct devlink_port *devlink_port,
|
|
|
|
struct nla_bitfield32 *caps,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
bool is_enable;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!ops->port_fn_migratable_get ||
|
|
|
|
devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err = ops->port_fn_migratable_get(devlink_port, &is_enable, extack);
|
|
|
|
if (err) {
|
|
|
|
if (err == -EOPNOTSUPP)
|
|
|
|
return 0;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
devlink_port_fn_cap_fill(caps, DEVLINK_PORT_FN_CAP_MIGRATABLE, is_enable);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-12-06 18:51:15 +00:00
|
|
|
static int devlink_port_fn_caps_fill(const struct devlink_ops *ops,
|
|
|
|
struct devlink_port *devlink_port,
|
|
|
|
struct sk_buff *msg,
|
|
|
|
struct netlink_ext_ack *extack,
|
|
|
|
bool *msg_updated)
|
|
|
|
{
|
|
|
|
struct nla_bitfield32 caps = {};
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = devlink_port_fn_roce_fill(ops, devlink_port, &caps, extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2022-12-06 18:51:18 +00:00
|
|
|
err = devlink_port_fn_migratable_fill(ops, devlink_port, &caps, extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2022-12-06 18:51:15 +00:00
|
|
|
if (!caps.selector)
|
|
|
|
return 0;
|
|
|
|
err = nla_put_bitfield32(msg, DEVLINK_PORT_FN_ATTR_CAPS, caps.value,
|
|
|
|
caps.selector);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
*msg_updated = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
static int
|
|
|
|
devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
|
|
|
|
struct genl_info *info,
|
|
|
|
enum devlink_sb_pool_type pool_type,
|
|
|
|
u16 *p_tc_index)
|
|
|
|
{
|
|
|
|
return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
|
|
|
|
pool_type, p_tc_index);
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:13:08 +00:00
|
|
|
struct devlink_region {
|
|
|
|
struct devlink *devlink;
|
2020-10-04 16:12:54 +00:00
|
|
|
struct devlink_port *port;
|
2018-07-12 12:13:08 +00:00
|
|
|
struct list_head list;
|
2020-10-04 16:12:54 +00:00
|
|
|
union {
|
|
|
|
const struct devlink_region_ops *ops;
|
|
|
|
const struct devlink_port_region_ops *port_ops;
|
|
|
|
};
|
2022-07-28 15:53:43 +00:00
|
|
|
struct mutex snapshot_lock; /* protects snapshot_list,
|
|
|
|
* max_snapshots and cur_snapshots
|
|
|
|
* consistency.
|
|
|
|
*/
|
2018-07-12 12:13:08 +00:00
|
|
|
struct list_head snapshot_list;
|
|
|
|
u32 max_snapshots;
|
|
|
|
u32 cur_snapshots;
|
|
|
|
u64 size;
|
|
|
|
};
|
|
|
|
|
2018-07-12 12:13:10 +00:00
|
|
|
struct devlink_snapshot {
|
|
|
|
struct list_head list;
|
|
|
|
struct devlink_region *region;
|
|
|
|
u8 *data;
|
|
|
|
u32 id;
|
|
|
|
};
|
|
|
|
|
2018-07-12 12:13:08 +00:00
|
|
|
static struct devlink_region *
|
|
|
|
devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
|
|
|
|
{
|
|
|
|
struct devlink_region *region;
|
|
|
|
|
|
|
|
list_for_each_entry(region, &devlink->region_list, list)
|
2020-03-26 18:37:08 +00:00
|
|
|
if (!strcmp(region->ops->name, region_name))
|
2018-07-12 12:13:08 +00:00
|
|
|
return region;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-10-04 16:12:54 +00:00
|
|
|
static struct devlink_region *
|
|
|
|
devlink_port_region_get_by_name(struct devlink_port *port,
|
|
|
|
const char *region_name)
|
|
|
|
{
|
|
|
|
struct devlink_region *region;
|
|
|
|
|
|
|
|
list_for_each_entry(region, &port->region_list, list)
|
|
|
|
if (!strcmp(region->ops->name, region_name))
|
|
|
|
return region;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:13:10 +00:00
|
|
|
static struct devlink_snapshot *
|
|
|
|
devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
|
|
|
|
{
|
|
|
|
struct devlink_snapshot *snapshot;
|
|
|
|
|
|
|
|
list_for_each_entry(snapshot, ®ion->snapshot_list, list)
|
|
|
|
if (snapshot->id == id)
|
|
|
|
return snapshot;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-07-25 08:29:16 +00:00
|
|
|
static int devlink_nl_put_nested_handle(struct sk_buff *msg, struct devlink *devlink)
|
|
|
|
{
|
|
|
|
struct nlattr *nested_attr;
|
|
|
|
|
|
|
|
nested_attr = nla_nest_start(msg, DEVLINK_ATTR_NESTED_DEVLINK);
|
|
|
|
if (!nested_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(msg, nested_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(msg, nested_attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2022-11-02 16:02:11 +00:00
|
|
|
int devlink_nl_port_handle_fill(struct sk_buff *msg, struct devlink_port *devlink_port)
|
|
|
|
{
|
|
|
|
if (devlink_nl_put_handle(msg, devlink_port->devlink))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t devlink_nl_port_handle_size(struct devlink_port *devlink_port)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = devlink_port->devlink;
|
|
|
|
|
|
|
|
return nla_total_size(strlen(devlink->dev->bus->name) + 1) /* DEVLINK_ATTR_BUS_NAME */
|
|
|
|
+ nla_total_size(strlen(dev_name(devlink->dev)) + 1) /* DEVLINK_ATTR_DEV_NAME */
|
|
|
|
+ nla_total_size(4); /* DEVLINK_ATTR_PORT_INDEX */
|
|
|
|
}
|
|
|
|
|
2018-05-18 07:29:00 +00:00
|
|
|
static int devlink_nl_port_attrs_put(struct sk_buff *msg,
|
|
|
|
struct devlink_port *devlink_port)
|
|
|
|
{
|
|
|
|
struct devlink_port_attrs *attrs = &devlink_port->attrs;
|
|
|
|
|
2020-07-09 13:18:14 +00:00
|
|
|
if (!devlink_port->attrs_set)
|
2018-05-18 07:29:00 +00:00
|
|
|
return 0;
|
2020-07-09 13:18:18 +00:00
|
|
|
if (attrs->lanes) {
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
2020-07-09 13:18:20 +00:00
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable))
|
|
|
|
return -EMSGSIZE;
|
2018-05-18 07:29:01 +00:00
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
|
|
|
|
return -EMSGSIZE;
|
2019-08-30 10:39:45 +00:00
|
|
|
switch (devlink_port->attrs.flavour) {
|
|
|
|
case DEVLINK_PORT_FLAVOUR_PCI_PF:
|
devlink: Introduce controller number
A devlink port may be for a controller consist of PCI device.
A devlink instance holds ports of two types of controllers.
(1) controller discovered on same system where eswitch resides
This is the case where PCI PF/VF of a controller and devlink eswitch
instance both are located on a single system.
(2) controller located on external host system.
This is the case where a controller is located in one system and its
devlink eswitch ports are located in a different system.
When a devlink eswitch instance serves the devlink ports of both
controllers together, PCI PF/VF numbers may overlap.
Due to this a unique phys_port_name cannot be constructed.
For example in below such system controller-0 and controller-1, each has
PCI PF pf0 whose eswitch ports can be present in controller-0.
These results in phys_port_name as "pf0" for both.
Similar problem exists for VFs and upcoming Sub functions.
An example view of two controller systems:
---------------------------------------------------------
| |
| --------- --------- ------- ------- |
----------- | | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| server | | ------- ----/---- ---/----- ------- ---/--- ---/--- |
| pci rc |=== | pf0 |______/________/ | pf1 |___/_______/ |
| connect | | ------- ------- |
----------- | | controller_num=1 (no eswitch) |
------|--------------------------------------------------
(internal wire)
|
---------------------------------------------------------
| devlink eswitch ports and reps |
| ----------------------------------------------------- |
| |ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 |ctrl-0 | |
| |pf0 | pf0vfN | pf0sfN | pf1 | pf1vfN |pf1sfN | |
| ----------------------------------------------------- |
| |ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 |ctrl-1 | |
| |pf1 | pf1vfN | pf1sfN | pf1 | pf1vfN |pf0sfN | |
| ----------------------------------------------------- |
| |
| |
| --------- --------- ------- ------- |
| | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| ------- ----/---- ---/----- ------- ---/--- ---/--- |
| | pf0 |______/________/ | pf1 |___/_______/ |
| ------- ------- |
| |
| local controller_num=0 (eswitch) |
---------------------------------------------------------
An example devlink port for external controller with controller
number = 1 for a VF 1 of PF 0:
$ devlink port show pci/0000:06:00.0/2
pci/0000:06:00.0/2: type eth netdev ens2f0pf0vf1 flavour pcivf controller 1 pfnum 0 vfnum 1 external true splittable false
function:
hw_addr 00:00:00:00:00:00
$ devlink port show pci/0000:06:00.0/2 -jp
{
"port": {
"pci/0000:06:00.0/2": {
"type": "eth",
"netdev": "ens2f0pf0vf1",
"flavour": "pcivf",
"controller": 1,
"pfnum": 0,
"vfnum": 1,
"external": true,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:00:00"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-09 04:50:37 +00:00
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
|
|
|
|
attrs->pci_pf.controller) ||
|
|
|
|
nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_pf.pf))
|
2019-07-09 04:17:37 +00:00
|
|
|
return -EMSGSIZE;
|
2020-09-09 04:50:36 +00:00
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_pf.external))
|
|
|
|
return -EMSGSIZE;
|
2019-08-30 10:39:45 +00:00
|
|
|
break;
|
|
|
|
case DEVLINK_PORT_FLAVOUR_PCI_VF:
|
devlink: Introduce controller number
A devlink port may be for a controller consist of PCI device.
A devlink instance holds ports of two types of controllers.
(1) controller discovered on same system where eswitch resides
This is the case where PCI PF/VF of a controller and devlink eswitch
instance both are located on a single system.
(2) controller located on external host system.
This is the case where a controller is located in one system and its
devlink eswitch ports are located in a different system.
When a devlink eswitch instance serves the devlink ports of both
controllers together, PCI PF/VF numbers may overlap.
Due to this a unique phys_port_name cannot be constructed.
For example in below such system controller-0 and controller-1, each has
PCI PF pf0 whose eswitch ports can be present in controller-0.
These results in phys_port_name as "pf0" for both.
Similar problem exists for VFs and upcoming Sub functions.
An example view of two controller systems:
---------------------------------------------------------
| |
| --------- --------- ------- ------- |
----------- | | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| server | | ------- ----/---- ---/----- ------- ---/--- ---/--- |
| pci rc |=== | pf0 |______/________/ | pf1 |___/_______/ |
| connect | | ------- ------- |
----------- | | controller_num=1 (no eswitch) |
------|--------------------------------------------------
(internal wire)
|
---------------------------------------------------------
| devlink eswitch ports and reps |
| ----------------------------------------------------- |
| |ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 |ctrl-0 | |
| |pf0 | pf0vfN | pf0sfN | pf1 | pf1vfN |pf1sfN | |
| ----------------------------------------------------- |
| |ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 |ctrl-1 | |
| |pf1 | pf1vfN | pf1sfN | pf1 | pf1vfN |pf0sfN | |
| ----------------------------------------------------- |
| |
| |
| --------- --------- ------- ------- |
| | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| ------- ----/---- ---/----- ------- ---/--- ---/--- |
| | pf0 |______/________/ | pf1 |___/_______/ |
| ------- ------- |
| |
| local controller_num=0 (eswitch) |
---------------------------------------------------------
An example devlink port for external controller with controller
number = 1 for a VF 1 of PF 0:
$ devlink port show pci/0000:06:00.0/2
pci/0000:06:00.0/2: type eth netdev ens2f0pf0vf1 flavour pcivf controller 1 pfnum 0 vfnum 1 external true splittable false
function:
hw_addr 00:00:00:00:00:00
$ devlink port show pci/0000:06:00.0/2 -jp
{
"port": {
"pci/0000:06:00.0/2": {
"type": "eth",
"netdev": "ens2f0pf0vf1",
"flavour": "pcivf",
"controller": 1,
"pfnum": 0,
"vfnum": 1,
"external": true,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:00:00"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-09 04:50:37 +00:00
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
|
|
|
|
attrs->pci_vf.controller) ||
|
|
|
|
nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_vf.pf) ||
|
|
|
|
nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER, attrs->pci_vf.vf))
|
2019-07-09 04:17:38 +00:00
|
|
|
return -EMSGSIZE;
|
2020-09-09 04:50:36 +00:00
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_vf.external))
|
|
|
|
return -EMSGSIZE;
|
2019-08-30 10:39:45 +00:00
|
|
|
break;
|
devlink: Introduce PCI SF port flavour and port attribute
A PCI sub-function (SF) represents a portion of the device similar
to PCI VF.
In an eswitch, PCI SF may have port which is normally represented
using a representor netdevice.
To have better visibility of eswitch port, its association with SF,
and its representor netdevice, introduce a PCI SF port flavour.
When devlink port flavour is PCI SF, fill up PCI SF attributes of the
port.
Extend port name creation using PCI PF and SF number scheme on best
effort basis, so that vendor drivers can skip defining their own
scheme.
This is done as cApfNSfM, where A, N and M are controller, PCI PF and
PCI SF number respectively.
This is similar to existing naming for PCI PF and PCI VF ports.
An example view of a PCI SF port:
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state active opstate attached
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:13 +00:00
|
|
|
case DEVLINK_PORT_FLAVOUR_PCI_SF:
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
|
|
|
|
attrs->pci_sf.controller) ||
|
|
|
|
nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER,
|
|
|
|
attrs->pci_sf.pf) ||
|
|
|
|
nla_put_u32(msg, DEVLINK_ATTR_PORT_PCI_SF_NUMBER,
|
|
|
|
attrs->pci_sf.sf))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
break;
|
2019-08-30 10:39:45 +00:00
|
|
|
case DEVLINK_PORT_FLAVOUR_PHYSICAL:
|
|
|
|
case DEVLINK_PORT_FLAVOUR_CPU:
|
|
|
|
case DEVLINK_PORT_FLAVOUR_DSA:
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
|
|
|
|
attrs->phys.port_number))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (!attrs->split)
|
|
|
|
return 0;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
|
|
|
|
attrs->phys.port_number))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
|
|
|
|
attrs->phys.split_subport_number))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2019-07-09 04:17:37 +00:00
|
|
|
}
|
2018-05-18 07:29:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
static int devlink_port_fn_hw_addr_fill(const struct devlink_ops *ops,
|
|
|
|
struct devlink_port *port,
|
|
|
|
struct sk_buff *msg,
|
|
|
|
struct netlink_ext_ack *extack,
|
|
|
|
bool *msg_updated)
|
2020-12-12 06:12:12 +00:00
|
|
|
{
|
|
|
|
u8 hw_addr[MAX_ADDR_LEN];
|
|
|
|
int hw_addr_len;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!ops->port_function_hw_addr_get)
|
|
|
|
return 0;
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
err = ops->port_function_hw_addr_get(port, hw_addr, &hw_addr_len,
|
|
|
|
extack);
|
2020-12-12 06:12:12 +00:00
|
|
|
if (err) {
|
|
|
|
if (err == -EOPNOTSUPP)
|
|
|
|
return 0;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
*msg_updated = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:19 +00:00
|
|
|
static int devlink_nl_rate_fill(struct sk_buff *msg,
|
|
|
|
struct devlink_rate *devlink_rate,
|
2021-08-14 09:57:27 +00:00
|
|
|
enum devlink_command cmd, u32 portid, u32 seq,
|
|
|
|
int flags, struct netlink_ext_ack *extack)
|
2021-06-02 12:17:19 +00:00
|
|
|
{
|
2021-08-14 09:57:27 +00:00
|
|
|
struct devlink *devlink = devlink_rate->devlink;
|
2021-06-02 12:17:19 +00:00
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_RATE_TYPE, devlink_rate->type))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (devlink_rate_is_leaf(devlink_rate)) {
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
|
|
|
|
devlink_rate->devlink_port->index))
|
|
|
|
goto nla_put_failure;
|
2021-06-02 12:17:25 +00:00
|
|
|
} else if (devlink_rate_is_node(devlink_rate)) {
|
|
|
|
if (nla_put_string(msg, DEVLINK_ATTR_RATE_NODE_NAME,
|
|
|
|
devlink_rate->name))
|
|
|
|
goto nla_put_failure;
|
2021-06-02 12:17:19 +00:00
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:22 +00:00
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_SHARE,
|
|
|
|
devlink_rate->tx_share, DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_MAX,
|
|
|
|
devlink_rate->tx_max, DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2022-11-15 10:48:15 +00:00
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_RATE_TX_PRIORITY,
|
|
|
|
devlink_rate->tx_priority))
|
|
|
|
goto nla_put_failure;
|
2022-11-15 10:48:16 +00:00
|
|
|
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_RATE_TX_WEIGHT,
|
|
|
|
devlink_rate->tx_weight))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2021-06-02 12:17:28 +00:00
|
|
|
if (devlink_rate->parent)
|
|
|
|
if (nla_put_string(msg, DEVLINK_ATTR_RATE_PARENT_NODE_NAME,
|
|
|
|
devlink_rate->parent->name))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2021-06-02 12:17:19 +00:00
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
static bool
|
|
|
|
devlink_port_fn_state_valid(enum devlink_port_fn_state state)
|
|
|
|
{
|
|
|
|
return state == DEVLINK_PORT_FN_STATE_INACTIVE ||
|
|
|
|
state == DEVLINK_PORT_FN_STATE_ACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
devlink_port_fn_opstate_valid(enum devlink_port_fn_opstate opstate)
|
|
|
|
{
|
|
|
|
return opstate == DEVLINK_PORT_FN_OPSTATE_DETACHED ||
|
|
|
|
opstate == DEVLINK_PORT_FN_OPSTATE_ATTACHED;
|
|
|
|
}
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
static int devlink_port_fn_state_fill(const struct devlink_ops *ops,
|
|
|
|
struct devlink_port *port,
|
|
|
|
struct sk_buff *msg,
|
|
|
|
struct netlink_ext_ack *extack,
|
|
|
|
bool *msg_updated)
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
{
|
|
|
|
enum devlink_port_fn_opstate opstate;
|
|
|
|
enum devlink_port_fn_state state;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!ops->port_fn_state_get)
|
|
|
|
return 0;
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
err = ops->port_fn_state_get(port, &state, &opstate, extack);
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
if (err) {
|
|
|
|
if (err == -EOPNOTSUPP)
|
|
|
|
return 0;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if (!devlink_port_fn_state_valid(state)) {
|
|
|
|
WARN_ON_ONCE(1);
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Invalid state read from driver");
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (!devlink_port_fn_opstate_valid(opstate)) {
|
|
|
|
WARN_ON_ONCE(1);
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Invalid operational state read from driver");
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (nla_put_u8(msg, DEVLINK_PORT_FN_ATTR_STATE, state) ||
|
|
|
|
nla_put_u8(msg, DEVLINK_PORT_FN_ATTR_OPSTATE, opstate))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
*msg_updated = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-12-06 18:51:18 +00:00
|
|
|
static int
|
|
|
|
devlink_port_fn_mig_set(struct devlink_port *devlink_port, bool enable,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
const struct devlink_ops *ops = devlink_port->devlink->ops;
|
|
|
|
|
|
|
|
return ops->port_fn_migratable_set(devlink_port, enable, extack);
|
|
|
|
}
|
|
|
|
|
2022-12-06 18:51:15 +00:00
|
|
|
static int
|
|
|
|
devlink_port_fn_roce_set(struct devlink_port *devlink_port, bool enable,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
const struct devlink_ops *ops = devlink_port->devlink->ops;
|
|
|
|
|
|
|
|
return ops->port_fn_roce_set(devlink_port, enable, extack);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_port_fn_caps_set(struct devlink_port *devlink_port,
|
|
|
|
const struct nlattr *attr,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
struct nla_bitfield32 caps;
|
|
|
|
u32 caps_value;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
caps = nla_get_bitfield32(attr);
|
|
|
|
caps_value = caps.value & caps.selector;
|
|
|
|
if (caps.selector & DEVLINK_PORT_FN_CAP_ROCE) {
|
|
|
|
err = devlink_port_fn_roce_set(devlink_port,
|
|
|
|
caps_value & DEVLINK_PORT_FN_CAP_ROCE,
|
|
|
|
extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
2022-12-06 18:51:18 +00:00
|
|
|
if (caps.selector & DEVLINK_PORT_FN_CAP_MIGRATABLE) {
|
|
|
|
err = devlink_port_fn_mig_set(devlink_port, caps_value &
|
|
|
|
DEVLINK_PORT_FN_CAP_MIGRATABLE,
|
|
|
|
extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
2022-12-06 18:51:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-19 03:32:48 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
const struct devlink_ops *ops;
|
|
|
|
struct nlattr *function_attr;
|
2020-12-12 06:12:12 +00:00
|
|
|
bool msg_updated = false;
|
|
|
|
int err;
|
2020-06-19 03:32:48 +00:00
|
|
|
|
|
|
|
function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION);
|
|
|
|
if (!function_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
ops = port->devlink->ops;
|
|
|
|
err = devlink_port_fn_hw_addr_fill(ops, port, msg, extack,
|
|
|
|
&msg_updated);
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
if (err)
|
|
|
|
goto out;
|
2022-12-06 18:51:15 +00:00
|
|
|
err = devlink_port_fn_caps_fill(ops, port, msg, extack,
|
|
|
|
&msg_updated);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
2021-08-08 11:41:21 +00:00
|
|
|
err = devlink_port_fn_state_fill(ops, port, msg, extack, &msg_updated);
|
2020-06-19 03:32:48 +00:00
|
|
|
out:
|
2020-12-12 06:12:12 +00:00
|
|
|
if (err || !msg_updated)
|
2020-06-19 03:32:48 +00:00
|
|
|
nla_nest_cancel(msg, function_attr);
|
|
|
|
else
|
|
|
|
nla_nest_end(msg, function_attr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2021-08-14 09:57:27 +00:00
|
|
|
static int devlink_nl_port_fill(struct sk_buff *msg,
|
2016-02-26 16:32:23 +00:00
|
|
|
struct devlink_port *devlink_port,
|
2021-08-14 09:57:27 +00:00
|
|
|
enum devlink_command cmd, u32 portid, u32 seq,
|
2022-11-02 16:02:07 +00:00
|
|
|
int flags, struct netlink_ext_ack *extack)
|
2016-02-26 16:32:23 +00:00
|
|
|
{
|
2021-08-14 09:57:27 +00:00
|
|
|
struct devlink *devlink = devlink_port->devlink;
|
2016-02-26 16:32:23 +00:00
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
|
|
|
|
goto nla_put_failure;
|
2019-03-24 10:14:37 +00:00
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
spin_lock_bh(&devlink_port->type_lock);
|
2016-02-26 16:32:23 +00:00
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
|
2019-03-24 10:14:37 +00:00
|
|
|
goto nla_put_failure_type_locked;
|
2016-02-26 16:32:23 +00:00
|
|
|
if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
|
|
|
|
nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
|
|
|
|
devlink_port->desired_type))
|
2019-03-24 10:14:37 +00:00
|
|
|
goto nla_put_failure_type_locked;
|
2016-02-26 16:32:23 +00:00
|
|
|
if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
|
2022-11-02 16:02:07 +00:00
|
|
|
if (devlink_port->type_eth.netdev &&
|
2016-02-26 16:32:23 +00:00
|
|
|
(nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
|
2022-11-02 16:02:07 +00:00
|
|
|
devlink_port->type_eth.ifindex) ||
|
2016-02-26 16:32:23 +00:00
|
|
|
nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
|
2022-11-02 16:02:07 +00:00
|
|
|
devlink_port->type_eth.ifname)))
|
2019-03-24 10:14:37 +00:00
|
|
|
goto nla_put_failure_type_locked;
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
|
2022-11-02 16:01:59 +00:00
|
|
|
struct ib_device *ibdev = devlink_port->type_ib.ibdev;
|
2016-02-26 16:32:23 +00:00
|
|
|
|
|
|
|
if (ibdev &&
|
|
|
|
nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
|
|
|
|
ibdev->name))
|
2019-03-24 10:14:37 +00:00
|
|
|
goto nla_put_failure_type_locked;
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
spin_unlock_bh(&devlink_port->type_lock);
|
2018-05-18 07:29:00 +00:00
|
|
|
if (devlink_nl_port_attrs_put(msg, devlink_port))
|
2016-02-26 16:32:23 +00:00
|
|
|
goto nla_put_failure;
|
2020-06-19 03:32:48 +00:00
|
|
|
if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
|
|
|
|
goto nla_put_failure;
|
2022-04-18 06:42:28 +00:00
|
|
|
if (devlink_port->linecard &&
|
|
|
|
nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX,
|
|
|
|
devlink_port->linecard->index))
|
|
|
|
goto nla_put_failure;
|
2016-02-26 16:32:23 +00:00
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
|
2019-03-24 10:14:37 +00:00
|
|
|
nla_put_failure_type_locked:
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
spin_unlock_bh(&devlink_port->type_lock);
|
2016-02-26 16:32:23 +00:00
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2022-11-02 16:02:07 +00:00
|
|
|
static void devlink_port_notify(struct devlink_port *devlink_port,
|
|
|
|
enum devlink_command cmd)
|
2016-02-26 16:32:23 +00:00
|
|
|
{
|
2021-09-25 11:22:41 +00:00
|
|
|
struct devlink *devlink = devlink_port->devlink;
|
2016-02-26 16:32:23 +00:00
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
|
|
|
|
|
2021-09-25 11:22:41 +00:00
|
|
|
if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
|
|
|
|
return;
|
|
|
|
|
2016-02-26 16:32:23 +00:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return;
|
|
|
|
|
2022-11-02 16:02:07 +00:00
|
|
|
err = devlink_nl_port_fill(msg, devlink_port, cmd, 0, 0, 0, NULL);
|
2016-02-26 16:32:23 +00:00
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-25 11:22:41 +00:00
|
|
|
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), msg,
|
|
|
|
0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:19 +00:00
|
|
|
static void devlink_rate_notify(struct devlink_rate *devlink_rate,
|
|
|
|
enum devlink_command cmd)
|
|
|
|
{
|
2021-09-25 11:22:41 +00:00
|
|
|
struct devlink *devlink = devlink_rate->devlink;
|
2021-06-02 12:17:19 +00:00
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
2021-08-14 09:57:27 +00:00
|
|
|
WARN_ON(cmd != DEVLINK_CMD_RATE_NEW && cmd != DEVLINK_CMD_RATE_DEL);
|
2021-09-29 14:18:20 +00:00
|
|
|
|
|
|
|
if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
|
|
|
|
return;
|
2021-06-02 12:17:19 +00:00
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return;
|
|
|
|
|
2021-08-14 09:57:27 +00:00
|
|
|
err = devlink_nl_rate_fill(msg, devlink_rate, cmd, 0, 0, 0, NULL);
|
2021-06-02 12:17:19 +00:00
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-25 11:22:41 +00:00
|
|
|
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), msg,
|
|
|
|
0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
2021-06-02 12:17:19 +00:00
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:30 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_rate_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2021-06-02 12:17:19 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-05 04:05:30 +00:00
|
|
|
struct devlink_rate *devlink_rate;
|
|
|
|
int idx = 0;
|
2021-06-02 12:17:19 +00:00
|
|
|
int err = 0;
|
|
|
|
|
2023-01-05 04:05:30 +00:00
|
|
|
list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
|
|
|
|
enum devlink_command cmd = DEVLINK_CMD_RATE_NEW;
|
|
|
|
u32 id = NETLINK_CB(cb->skb).portid;
|
2021-06-02 12:17:19 +00:00
|
|
|
|
2023-01-05 04:05:30 +00:00
|
|
|
if (idx < state->idx) {
|
2021-06-02 12:17:19 +00:00
|
|
|
idx++;
|
2023-01-05 04:05:30 +00:00
|
|
|
continue;
|
2021-06-02 12:17:19 +00:00
|
|
|
}
|
2023-01-05 04:05:30 +00:00
|
|
|
err = devlink_nl_rate_fill(msg, devlink_rate, cmd, id,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI, NULL);
|
|
|
|
if (err) {
|
|
|
|
state->idx = idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
idx++;
|
2021-06-02 12:17:19 +00:00
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:30 +00:00
|
|
|
return err;
|
2021-06-02 12:17:19 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_rate_get = {
|
2023-01-05 04:05:30 +00:00
|
|
|
.dump_one = devlink_nl_cmd_rate_get_dump_one,
|
|
|
|
};
|
|
|
|
|
2021-06-02 12:17:19 +00:00
|
|
|
static int devlink_nl_cmd_rate_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink_rate *devlink_rate = info->user_ptr[1];
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2021-08-14 09:57:27 +00:00
|
|
|
err = devlink_nl_rate_fill(msg, devlink_rate, DEVLINK_CMD_RATE_NEW,
|
2021-06-02 12:17:19 +00:00
|
|
|
info->snd_portid, info->snd_seq, 0,
|
|
|
|
info->extack);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:28 +00:00
|
|
|
static bool
|
|
|
|
devlink_rate_is_parent_node(struct devlink_rate *devlink_rate,
|
|
|
|
struct devlink_rate *parent)
|
|
|
|
{
|
|
|
|
while (parent) {
|
|
|
|
if (parent == devlink_rate)
|
|
|
|
return true;
|
|
|
|
parent = parent->parent;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-02-26 16:32:23 +00:00
|
|
|
static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_port *devlink_port = info->user_ptr[1];
|
2016-02-26 16:32:23 +00:00
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2021-08-14 09:57:27 +00:00
|
|
|
err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_PORT_NEW,
|
2020-06-19 03:32:47 +00:00
|
|
|
info->snd_portid, info->snd_seq, 0,
|
2022-11-02 16:02:07 +00:00
|
|
|
info->extack);
|
2016-02-26 16:32:23 +00:00
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_port_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2016-02-26 16:32:23 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-05 04:05:31 +00:00
|
|
|
struct devlink_port *devlink_port;
|
|
|
|
unsigned long port_index;
|
|
|
|
int err = 0;
|
2023-01-05 04:05:27 +00:00
|
|
|
|
2023-02-10 10:01:28 +00:00
|
|
|
xa_for_each_start(&devlink->ports, port_index, devlink_port, state->idx) {
|
2023-01-05 04:05:31 +00:00
|
|
|
err = devlink_nl_port_fill(msg, devlink_port,
|
|
|
|
DEVLINK_CMD_NEW,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI, cb->extack);
|
|
|
|
if (err) {
|
2023-02-10 10:01:28 +00:00
|
|
|
state->idx = port_index;
|
2023-01-05 04:05:31 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
2023-01-05 04:05:31 +00:00
|
|
|
|
|
|
|
return err;
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_port_get = {
|
2023-01-05 04:05:31 +00:00
|
|
|
.dump_one = devlink_nl_cmd_port_get_dump_one,
|
|
|
|
};
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
static int devlink_port_type_set(struct devlink_port *devlink_port,
|
2016-02-26 16:32:23 +00:00
|
|
|
enum devlink_port_type port_type)
|
|
|
|
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2021-08-09 12:03:19 +00:00
|
|
|
if (!devlink_port->devlink->ops->port_type_set)
|
2021-08-08 11:41:21 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (port_type == devlink_port->type)
|
2016-02-26 16:32:23 +00:00
|
|
|
return 0;
|
2021-08-08 11:41:21 +00:00
|
|
|
|
|
|
|
err = devlink_port->devlink->ops->port_type_set(devlink_port,
|
|
|
|
port_type);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
devlink_port->desired_type = port_type;
|
|
|
|
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
|
|
|
|
return 0;
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
static int devlink_port_function_hw_addr_set(struct devlink_port *port,
|
|
|
|
const struct nlattr *attr,
|
|
|
|
struct netlink_ext_ack *extack)
|
2020-06-19 03:32:49 +00:00
|
|
|
{
|
2021-08-08 11:41:21 +00:00
|
|
|
const struct devlink_ops *ops = port->devlink->ops;
|
2020-06-19 03:32:49 +00:00
|
|
|
const u8 *hw_addr;
|
|
|
|
int hw_addr_len;
|
|
|
|
|
|
|
|
hw_addr = nla_data(attr);
|
|
|
|
hw_addr_len = nla_len(attr);
|
|
|
|
if (hw_addr_len > MAX_ADDR_LEN) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Port function hardware address too long");
|
2020-06-19 03:32:49 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (port->type == DEVLINK_PORT_TYPE_ETH) {
|
|
|
|
if (hw_addr_len != ETH_ALEN) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Address must be 6 bytes for Ethernet device");
|
2020-06-19 03:32:49 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (!is_unicast_ether_addr(hw_addr)) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Non-unicast hardware address unsupported");
|
2020-06-19 03:32:49 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
return ops->port_function_hw_addr_set(port, hw_addr, hw_addr_len,
|
|
|
|
extack);
|
2020-06-19 03:32:49 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
static int devlink_port_fn_state_set(struct devlink_port *port,
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
const struct nlattr *attr,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
enum devlink_port_fn_state state;
|
|
|
|
const struct devlink_ops *ops;
|
|
|
|
|
|
|
|
state = nla_get_u8(attr);
|
2021-08-08 11:41:21 +00:00
|
|
|
ops = port->devlink->ops;
|
2022-12-06 18:51:13 +00:00
|
|
|
return ops->port_fn_state_set(port, state, extack);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_port_function_validate(struct devlink_port *devlink_port,
|
|
|
|
struct nlattr **tb,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
const struct devlink_ops *ops = devlink_port->devlink->ops;
|
2022-12-06 18:51:15 +00:00
|
|
|
struct nlattr *attr;
|
2022-12-06 18:51:13 +00:00
|
|
|
|
|
|
|
if (tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] &&
|
|
|
|
!ops->port_function_hw_addr_set) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR],
|
|
|
|
"Port doesn't support function attributes");
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
2022-12-06 18:51:13 +00:00
|
|
|
if (tb[DEVLINK_PORT_FN_ATTR_STATE] && !ops->port_fn_state_set) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR],
|
|
|
|
"Function does not support state setting");
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
2022-12-06 18:51:15 +00:00
|
|
|
attr = tb[DEVLINK_PORT_FN_ATTR_CAPS];
|
|
|
|
if (attr) {
|
|
|
|
struct nla_bitfield32 caps;
|
|
|
|
|
|
|
|
caps = nla_get_bitfield32(attr);
|
|
|
|
if (caps.selector & DEVLINK_PORT_FN_CAP_ROCE &&
|
|
|
|
!ops->port_fn_roce_set) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(extack, attr,
|
|
|
|
"Port doesn't support RoCE function attribute");
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
2022-12-06 18:51:18 +00:00
|
|
|
if (caps.selector & DEVLINK_PORT_FN_CAP_MIGRATABLE) {
|
|
|
|
if (!ops->port_fn_migratable_set) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(extack, attr,
|
|
|
|
"Port doesn't support migratable function attribute");
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(extack, attr,
|
|
|
|
"migratable function attribute supported for VFs only");
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
}
|
2022-12-06 18:51:15 +00:00
|
|
|
}
|
2022-12-06 18:51:13 +00:00
|
|
|
return 0;
|
2020-06-19 03:32:49 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
static int devlink_port_function_set(struct devlink_port *port,
|
|
|
|
const struct nlattr *attr,
|
|
|
|
struct netlink_ext_ack *extack)
|
2020-06-19 03:32:49 +00:00
|
|
|
{
|
|
|
|
struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = nla_parse_nested(tb, DEVLINK_PORT_FUNCTION_ATTR_MAX, attr,
|
|
|
|
devlink_function_nl_policy, extack);
|
|
|
|
if (err < 0) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Fail to parse port function attributes");
|
2020-06-19 03:32:49 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-12-06 18:51:13 +00:00
|
|
|
err = devlink_port_function_validate(port, tb, extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2020-06-19 03:32:49 +00:00
|
|
|
attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
if (attr) {
|
2021-08-08 11:41:21 +00:00
|
|
|
err = devlink_port_function_hw_addr_set(port, attr, extack);
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
2022-12-06 18:51:15 +00:00
|
|
|
|
|
|
|
attr = tb[DEVLINK_PORT_FN_ATTR_CAPS];
|
|
|
|
if (attr) {
|
|
|
|
err = devlink_port_fn_caps_set(port, attr, extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
devlink: Support get and set state of port function
devlink port function can be in active or inactive state.
Allow users to get and set port function's state.
When the port function it activated, its operational state may change
after a while when the device is created and driver binds to it.
Similarly on deactivation flow.
To clearly describe the state of the port function and its device's
operational state in the host system, define state and opstate
attributes.
Example of a PCI SF port which supports a port function:
$ devlink dev eswitch set pci/0000:06:00.0 mode switchdev
$ devlink port show
pci/0000:06:00.0/65535: type eth netdev ens2f0np0 flavour physical port 0 splittable false
$ devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88
pci/0000:08:00.0/32768: type eth netdev eth6 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:00:00 state inactive opstate detached
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state inactive opstate detached
$ devlink port function set pci/0000:06:00.0/32768 hw_addr 00:00:00:00:88:88 state active
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"external": false,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:15 +00:00
|
|
|
/* Keep this as the last function attribute set, so that when
|
|
|
|
* multiple port function attributes are set along with state,
|
|
|
|
* Those can be applied first before activating the state.
|
|
|
|
*/
|
|
|
|
attr = tb[DEVLINK_PORT_FN_ATTR_STATE];
|
|
|
|
if (attr)
|
2021-08-08 11:41:21 +00:00
|
|
|
err = devlink_port_fn_state_set(port, attr, extack);
|
2020-06-19 03:32:49 +00:00
|
|
|
|
2020-12-12 06:12:12 +00:00
|
|
|
if (!err)
|
|
|
|
devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
|
2020-06-19 03:32:49 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-02-26 16:32:23 +00:00
|
|
|
static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_port *devlink_port = info->user_ptr[1];
|
2016-02-26 16:32:23 +00:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
|
|
|
|
enum devlink_port_type port_type;
|
|
|
|
|
|
|
|
port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
|
2021-08-08 11:41:21 +00:00
|
|
|
err = devlink_port_type_set(devlink_port, port_type);
|
2016-02-26 16:32:23 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
2020-06-19 03:32:49 +00:00
|
|
|
|
|
|
|
if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) {
|
|
|
|
struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
|
2021-08-08 11:41:21 +00:00
|
|
|
err = devlink_port_function_set(devlink_port, attr, extack);
|
2020-06-19 03:32:49 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-02-26 16:32:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2022-03-15 06:00:09 +00:00
|
|
|
struct devlink_port *devlink_port = info->user_ptr[1];
|
2016-02-26 16:32:23 +00:00
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
u32 count;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PORT_SPLIT_COUNT))
|
2016-02-26 16:32:23 +00:00
|
|
|
return -EINVAL;
|
2022-03-15 06:00:09 +00:00
|
|
|
if (!devlink->ops->port_split)
|
|
|
|
return -EOPNOTSUPP;
|
2016-02-26 16:32:23 +00:00
|
|
|
|
|
|
|
count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
|
2020-07-09 13:18:21 +00:00
|
|
|
|
|
|
|
if (!devlink_port->attrs.splittable) {
|
|
|
|
/* Split ports cannot be split. */
|
|
|
|
if (devlink_port->attrs.split)
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Port cannot be split further");
|
2020-07-09 13:18:21 +00:00
|
|
|
else
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Port cannot be split");
|
2020-07-09 13:18:21 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Invalid split count");
|
2020-07-09 13:18:21 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2022-03-15 06:00:09 +00:00
|
|
|
return devlink->ops->port_split(devlink, devlink_port, count,
|
|
|
|
info->extack);
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2022-03-15 06:00:09 +00:00
|
|
|
struct devlink_port *devlink_port = info->user_ptr[1];
|
2016-02-26 16:32:23 +00:00
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
|
2022-03-15 06:00:09 +00:00
|
|
|
if (!devlink->ops->port_unsplit)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
return devlink->ops->port_unsplit(devlink, devlink_port, info->extack);
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
|
2022-07-13 14:18:52 +00:00
|
|
|
static int devlink_port_new_notify(struct devlink *devlink,
|
|
|
|
unsigned int port_index,
|
|
|
|
struct genl_info *info)
|
2020-12-12 06:12:14 +00:00
|
|
|
{
|
|
|
|
struct devlink_port *devlink_port;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2022-07-11 08:14:08 +00:00
|
|
|
lockdep_assert_held(&devlink->lock);
|
2020-12-12 06:12:14 +00:00
|
|
|
devlink_port = devlink_port_get_by_index(devlink, port_index);
|
|
|
|
if (!devlink_port) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2021-08-14 09:57:27 +00:00
|
|
|
err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_NEW,
|
2022-11-02 16:02:07 +00:00
|
|
|
info->snd_portid, info->snd_seq, 0, NULL);
|
2020-12-12 06:12:14 +00:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2022-07-13 14:18:53 +00:00
|
|
|
return genlmsg_reply(msg, info);
|
2020-12-12 06:12:14 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_port_new_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
struct devlink_port_new_attrs new_attrs = {};
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
unsigned int new_port_index;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!devlink->ops->port_new || !devlink->ops->port_del)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (!info->attrs[DEVLINK_ATTR_PORT_FLAVOUR] ||
|
|
|
|
!info->attrs[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Port flavour or PCI PF are not specified");
|
2020-12-12 06:12:14 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
new_attrs.flavour = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_FLAVOUR]);
|
|
|
|
new_attrs.pfnum =
|
|
|
|
nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
|
|
|
|
|
|
|
|
if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
|
|
|
|
/* Port index of the new port being created by driver. */
|
|
|
|
new_attrs.port_index =
|
|
|
|
nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
|
|
|
|
new_attrs.port_index_valid = true;
|
|
|
|
}
|
|
|
|
if (info->attrs[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]) {
|
|
|
|
new_attrs.controller =
|
|
|
|
nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]);
|
|
|
|
new_attrs.controller_valid = true;
|
|
|
|
}
|
|
|
|
if (new_attrs.flavour == DEVLINK_PORT_FLAVOUR_PCI_SF &&
|
|
|
|
info->attrs[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]) {
|
|
|
|
new_attrs.sfnum = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]);
|
|
|
|
new_attrs.sfnum_valid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = devlink->ops->port_new(devlink, &new_attrs, extack,
|
|
|
|
&new_port_index);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2022-07-13 14:18:52 +00:00
|
|
|
err = devlink_port_new_notify(devlink, new_port_index, info);
|
2020-12-12 06:12:14 +00:00
|
|
|
if (err && err != -ENODEV) {
|
|
|
|
/* Fail to send the response; destroy newly created port. */
|
|
|
|
devlink->ops->port_del(devlink, new_port_index, extack);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_port_del_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
unsigned int port_index;
|
|
|
|
|
|
|
|
if (!devlink->ops->port_del)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PORT_INDEX)) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Port index is not specified");
|
2020-12-12 06:12:14 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
|
|
|
|
|
|
|
|
return devlink->ops->port_del(devlink, port_index, extack);
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:28 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate,
|
|
|
|
struct genl_info *info,
|
|
|
|
struct nlattr *nla_parent)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = devlink_rate->devlink;
|
|
|
|
const char *parent_name = nla_data(nla_parent);
|
|
|
|
const struct devlink_ops *ops = devlink->ops;
|
|
|
|
size_t len = strlen(parent_name);
|
|
|
|
struct devlink_rate *parent;
|
|
|
|
int err = -EOPNOTSUPP;
|
|
|
|
|
|
|
|
parent = devlink_rate->parent;
|
2022-11-15 10:48:18 +00:00
|
|
|
|
|
|
|
if (parent && !len) {
|
2021-06-02 12:17:28 +00:00
|
|
|
if (devlink_rate_is_leaf(devlink_rate))
|
|
|
|
err = ops->rate_leaf_parent_set(devlink_rate, NULL,
|
|
|
|
devlink_rate->priv, NULL,
|
|
|
|
info->extack);
|
|
|
|
else if (devlink_rate_is_node(devlink_rate))
|
|
|
|
err = ops->rate_node_parent_set(devlink_rate, NULL,
|
|
|
|
devlink_rate->priv, NULL,
|
|
|
|
info->extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
refcount_dec(&parent->refcnt);
|
|
|
|
devlink_rate->parent = NULL;
|
2022-11-15 10:48:18 +00:00
|
|
|
} else if (len) {
|
2021-06-02 12:17:28 +00:00
|
|
|
parent = devlink_rate_node_get_by_name(devlink, parent_name);
|
|
|
|
if (IS_ERR(parent))
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
if (parent == devlink_rate) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Parent to self is not allowed");
|
2021-06-02 12:17:28 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devlink_rate_is_node(devlink_rate) &&
|
|
|
|
devlink_rate_is_parent_node(devlink_rate, parent->parent)) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Node is already a parent of parent node.");
|
2021-06-02 12:17:28 +00:00
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devlink_rate_is_leaf(devlink_rate))
|
|
|
|
err = ops->rate_leaf_parent_set(devlink_rate, parent,
|
|
|
|
devlink_rate->priv, parent->priv,
|
|
|
|
info->extack);
|
|
|
|
else if (devlink_rate_is_node(devlink_rate))
|
|
|
|
err = ops->rate_node_parent_set(devlink_rate, parent,
|
|
|
|
devlink_rate->priv, parent->priv,
|
|
|
|
info->extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2022-11-15 10:48:18 +00:00
|
|
|
if (devlink_rate->parent)
|
|
|
|
/* we're reassigning to other parent in this case */
|
|
|
|
refcount_dec(&devlink_rate->parent->refcnt);
|
|
|
|
|
2021-06-02 12:17:28 +00:00
|
|
|
refcount_inc(&parent->refcnt);
|
|
|
|
devlink_rate->parent = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:22 +00:00
|
|
|
static int devlink_nl_rate_set(struct devlink_rate *devlink_rate,
|
|
|
|
const struct devlink_ops *ops,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2021-06-02 12:17:28 +00:00
|
|
|
struct nlattr *nla_parent, **attrs = info->attrs;
|
2021-06-02 12:17:25 +00:00
|
|
|
int err = -EOPNOTSUPP;
|
2022-11-15 10:48:15 +00:00
|
|
|
u32 priority;
|
2022-11-15 10:48:16 +00:00
|
|
|
u32 weight;
|
2021-06-02 12:17:22 +00:00
|
|
|
u64 rate;
|
|
|
|
|
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_SHARE]) {
|
|
|
|
rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_SHARE]);
|
2021-06-02 12:17:25 +00:00
|
|
|
if (devlink_rate_is_leaf(devlink_rate))
|
|
|
|
err = ops->rate_leaf_tx_share_set(devlink_rate, devlink_rate->priv,
|
|
|
|
rate, info->extack);
|
|
|
|
else if (devlink_rate_is_node(devlink_rate))
|
|
|
|
err = ops->rate_node_tx_share_set(devlink_rate, devlink_rate->priv,
|
|
|
|
rate, info->extack);
|
2021-06-02 12:17:22 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
devlink_rate->tx_share = rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_MAX]) {
|
|
|
|
rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_MAX]);
|
2021-06-02 12:17:25 +00:00
|
|
|
if (devlink_rate_is_leaf(devlink_rate))
|
|
|
|
err = ops->rate_leaf_tx_max_set(devlink_rate, devlink_rate->priv,
|
|
|
|
rate, info->extack);
|
|
|
|
else if (devlink_rate_is_node(devlink_rate))
|
|
|
|
err = ops->rate_node_tx_max_set(devlink_rate, devlink_rate->priv,
|
|
|
|
rate, info->extack);
|
2021-06-02 12:17:22 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
devlink_rate->tx_max = rate;
|
|
|
|
}
|
|
|
|
|
2022-11-15 10:48:15 +00:00
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY]) {
|
|
|
|
priority = nla_get_u32(attrs[DEVLINK_ATTR_RATE_TX_PRIORITY]);
|
|
|
|
if (devlink_rate_is_leaf(devlink_rate))
|
|
|
|
err = ops->rate_leaf_tx_priority_set(devlink_rate, devlink_rate->priv,
|
|
|
|
priority, info->extack);
|
|
|
|
else if (devlink_rate_is_node(devlink_rate))
|
|
|
|
err = ops->rate_node_tx_priority_set(devlink_rate, devlink_rate->priv,
|
|
|
|
priority, info->extack);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
devlink_rate->tx_priority = priority;
|
|
|
|
}
|
|
|
|
|
2022-11-15 10:48:16 +00:00
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT]) {
|
|
|
|
weight = nla_get_u32(attrs[DEVLINK_ATTR_RATE_TX_WEIGHT]);
|
|
|
|
if (devlink_rate_is_leaf(devlink_rate))
|
|
|
|
err = ops->rate_leaf_tx_weight_set(devlink_rate, devlink_rate->priv,
|
|
|
|
weight, info->extack);
|
|
|
|
else if (devlink_rate_is_node(devlink_rate))
|
|
|
|
err = ops->rate_node_tx_weight_set(devlink_rate, devlink_rate->priv,
|
|
|
|
weight, info->extack);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
devlink_rate->tx_weight = weight;
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:28 +00:00
|
|
|
nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME];
|
|
|
|
if (nla_parent) {
|
|
|
|
err = devlink_nl_rate_parent_node_set(devlink_rate, info,
|
|
|
|
nla_parent);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops,
|
|
|
|
struct genl_info *info,
|
|
|
|
enum devlink_rate_type type)
|
|
|
|
{
|
|
|
|
struct nlattr **attrs = info->attrs;
|
|
|
|
|
|
|
|
if (type == DEVLINK_RATE_TYPE_LEAF) {
|
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_leaf_tx_share_set) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "TX share set isn't supported for the leafs");
|
2021-06-02 12:17:22 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_MAX] && !ops->rate_leaf_tx_max_set) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "TX max set isn't supported for the leafs");
|
2021-06-02 12:17:22 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-06-02 12:17:28 +00:00
|
|
|
if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] &&
|
|
|
|
!ops->rate_leaf_parent_set) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Parent set isn't supported for the leafs");
|
2021-06-02 12:17:28 +00:00
|
|
|
return false;
|
|
|
|
}
|
2022-11-15 10:48:15 +00:00
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY] && !ops->rate_leaf_tx_priority_set) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(info->extack,
|
|
|
|
attrs[DEVLINK_ATTR_RATE_TX_PRIORITY],
|
|
|
|
"TX priority set isn't supported for the leafs");
|
|
|
|
return false;
|
|
|
|
}
|
2022-11-15 10:48:16 +00:00
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT] && !ops->rate_leaf_tx_weight_set) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(info->extack,
|
|
|
|
attrs[DEVLINK_ATTR_RATE_TX_WEIGHT],
|
|
|
|
"TX weight set isn't supported for the leafs");
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-02 12:17:25 +00:00
|
|
|
} else if (type == DEVLINK_RATE_TYPE_NODE) {
|
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_node_tx_share_set) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "TX share set isn't supported for the nodes");
|
2021-06-02 12:17:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_MAX] && !ops->rate_node_tx_max_set) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "TX max set isn't supported for the nodes");
|
2021-06-02 12:17:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-06-02 12:17:28 +00:00
|
|
|
if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] &&
|
|
|
|
!ops->rate_node_parent_set) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Parent set isn't supported for the nodes");
|
2021-06-02 12:17:28 +00:00
|
|
|
return false;
|
|
|
|
}
|
2022-11-15 10:48:15 +00:00
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY] && !ops->rate_node_tx_priority_set) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(info->extack,
|
|
|
|
attrs[DEVLINK_ATTR_RATE_TX_PRIORITY],
|
|
|
|
"TX priority set isn't supported for the nodes");
|
|
|
|
return false;
|
|
|
|
}
|
2022-11-15 10:48:16 +00:00
|
|
|
if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT] && !ops->rate_node_tx_weight_set) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(info->extack,
|
|
|
|
attrs[DEVLINK_ATTR_RATE_TX_WEIGHT],
|
|
|
|
"TX weight set isn't supported for the nodes");
|
|
|
|
return false;
|
|
|
|
}
|
2021-06-02 12:17:22 +00:00
|
|
|
} else {
|
2021-06-09 09:54:31 +00:00
|
|
|
WARN(1, "Unknown type of rate object");
|
2021-06-02 12:17:22 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_rate_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink_rate *devlink_rate = info->user_ptr[1];
|
|
|
|
struct devlink *devlink = devlink_rate->devlink;
|
|
|
|
const struct devlink_ops *ops = devlink->ops;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!ops || !devlink_rate_set_ops_supported(ops, info, devlink_rate->type))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
err = devlink_nl_rate_set(devlink_rate, ops, info);
|
|
|
|
|
|
|
|
if (!err)
|
|
|
|
devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:25 +00:00
|
|
|
static int devlink_nl_cmd_rate_new_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_rate *rate_node;
|
|
|
|
const struct devlink_ops *ops;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
ops = devlink->ops;
|
|
|
|
if (!ops || !ops->rate_node_new || !ops->rate_node_del) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Rate nodes aren't supported");
|
2021-06-02 12:17:25 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!devlink_rate_set_ops_supported(ops, info, DEVLINK_RATE_TYPE_NODE))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
rate_node = devlink_rate_node_get_from_attrs(devlink, info->attrs);
|
|
|
|
if (!IS_ERR(rate_node))
|
|
|
|
return -EEXIST;
|
|
|
|
else if (rate_node == ERR_PTR(-EINVAL))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
rate_node = kzalloc(sizeof(*rate_node), GFP_KERNEL);
|
|
|
|
if (!rate_node)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
rate_node->devlink = devlink;
|
|
|
|
rate_node->type = DEVLINK_RATE_TYPE_NODE;
|
|
|
|
rate_node->name = nla_strdup(info->attrs[DEVLINK_ATTR_RATE_NODE_NAME], GFP_KERNEL);
|
|
|
|
if (!rate_node->name) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto err_strdup;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ops->rate_node_new(rate_node, &rate_node->priv, info->extack);
|
|
|
|
if (err)
|
|
|
|
goto err_node_new;
|
|
|
|
|
|
|
|
err = devlink_nl_rate_set(rate_node, ops, info);
|
|
|
|
if (err)
|
|
|
|
goto err_rate_set;
|
|
|
|
|
2021-06-02 12:17:28 +00:00
|
|
|
refcount_set(&rate_node->refcnt, 1);
|
2021-06-02 12:17:25 +00:00
|
|
|
list_add(&rate_node->list, &devlink->rate_list);
|
|
|
|
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_rate_set:
|
|
|
|
ops->rate_node_del(rate_node, rate_node->priv, info->extack);
|
|
|
|
err_node_new:
|
|
|
|
kfree(rate_node->name);
|
|
|
|
err_strdup:
|
|
|
|
kfree(rate_node);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_rate_del_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink_rate *rate_node = info->user_ptr[1];
|
|
|
|
struct devlink *devlink = rate_node->devlink;
|
|
|
|
const struct devlink_ops *ops = devlink->ops;
|
|
|
|
int err;
|
|
|
|
|
2021-06-02 12:17:28 +00:00
|
|
|
if (refcount_read(&rate_node->refcnt) > 1) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Node has children. Cannot delete node.");
|
2021-06-02 12:17:28 +00:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:25 +00:00
|
|
|
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL);
|
|
|
|
err = ops->rate_node_del(rate_node, rate_node->priv, info->extack);
|
2021-06-02 12:17:28 +00:00
|
|
|
if (rate_node->parent)
|
|
|
|
refcount_dec(&rate_node->parent->refcnt);
|
2021-06-02 12:17:25 +00:00
|
|
|
list_del(&rate_node->list);
|
|
|
|
kfree(rate_node->name);
|
|
|
|
kfree(rate_node);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-04-18 06:42:26 +00:00
|
|
|
struct devlink_linecard_type {
|
|
|
|
const char *type;
|
|
|
|
const void *priv;
|
|
|
|
};
|
|
|
|
|
2022-04-18 06:42:25 +00:00
|
|
|
static int devlink_nl_linecard_fill(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct devlink_linecard *linecard,
|
|
|
|
enum devlink_command cmd, u32 portid,
|
|
|
|
u32 seq, int flags,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
2022-04-18 06:42:26 +00:00
|
|
|
struct devlink_linecard_type *linecard_type;
|
|
|
|
struct nlattr *attr;
|
2022-04-18 06:42:25 +00:00
|
|
|
void *hdr;
|
2022-04-18 06:42:26 +00:00
|
|
|
int i;
|
2022-04-18 06:42:25 +00:00
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
|
|
|
|
goto nla_put_failure;
|
2022-04-18 06:42:26 +00:00
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (linecard->type &&
|
|
|
|
nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (linecard->types_count) {
|
|
|
|
attr = nla_nest_start(msg,
|
|
|
|
DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES);
|
|
|
|
if (!attr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
for (i = 0; i < linecard->types_count; i++) {
|
|
|
|
linecard_type = &linecard->types[i];
|
|
|
|
if (nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE,
|
|
|
|
linecard_type->type)) {
|
|
|
|
nla_nest_cancel(msg, attr);
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nla_nest_end(msg, attr);
|
|
|
|
}
|
2022-04-18 06:42:25 +00:00
|
|
|
|
2022-07-25 08:29:16 +00:00
|
|
|
if (linecard->nested_devlink &&
|
|
|
|
devlink_nl_put_nested_handle(msg, linecard->nested_devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2022-04-18 06:42:25 +00:00
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_linecard_notify(struct devlink_linecard *linecard,
|
|
|
|
enum devlink_command cmd)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = linecard->devlink;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW &&
|
|
|
|
cmd != DEVLINK_CMD_LINECARD_DEL);
|
|
|
|
|
|
|
|
if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
|
|
|
|
return;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
err = devlink_nl_linecard_fill(msg, devlink, linecard, cmd, 0, 0, 0,
|
|
|
|
NULL);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
|
|
|
|
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_linecard_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink_linecard *linecard = info->user_ptr[1];
|
|
|
|
struct devlink *devlink = linecard->devlink;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2022-04-18 06:42:26 +00:00
|
|
|
mutex_lock(&linecard->state_lock);
|
2022-04-18 06:42:25 +00:00
|
|
|
err = devlink_nl_linecard_fill(msg, devlink, linecard,
|
|
|
|
DEVLINK_CMD_LINECARD_NEW,
|
|
|
|
info->snd_portid, info->snd_seq, 0,
|
|
|
|
info->extack);
|
2022-04-18 06:42:26 +00:00
|
|
|
mutex_unlock(&linecard->state_lock);
|
2022-04-18 06:42:25 +00:00
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
}
|
|
|
|
|
2023-01-18 15:21:12 +00:00
|
|
|
static int devlink_nl_cmd_linecard_get_dump_one(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2022-04-18 06:42:25 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2022-04-18 06:42:25 +00:00
|
|
|
struct devlink_linecard *linecard;
|
2023-01-18 15:21:12 +00:00
|
|
|
int idx = 0;
|
|
|
|
int err = 0;
|
2023-01-06 06:33:57 +00:00
|
|
|
|
2023-01-18 15:21:12 +00:00
|
|
|
list_for_each_entry(linecard, &devlink->linecard_list, list) {
|
|
|
|
if (idx < state->idx) {
|
2022-04-18 06:42:25 +00:00
|
|
|
idx++;
|
2023-01-18 15:21:12 +00:00
|
|
|
continue;
|
2022-04-18 06:42:25 +00:00
|
|
|
}
|
2023-01-18 15:21:12 +00:00
|
|
|
mutex_lock(&linecard->state_lock);
|
|
|
|
err = devlink_nl_linecard_fill(msg, devlink, linecard,
|
|
|
|
DEVLINK_CMD_LINECARD_NEW,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI,
|
|
|
|
cb->extack);
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
if (err) {
|
|
|
|
state->idx = idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
idx++;
|
2022-04-18 06:42:25 +00:00
|
|
|
}
|
2023-01-18 15:21:12 +00:00
|
|
|
|
|
|
|
return err;
|
2022-04-18 06:42:25 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_linecard_get = {
|
2023-01-18 15:21:12 +00:00
|
|
|
.dump_one = devlink_nl_cmd_linecard_get_dump_one,
|
|
|
|
};
|
|
|
|
|
2022-04-18 06:42:26 +00:00
|
|
|
static struct devlink_linecard_type *
|
|
|
|
devlink_linecard_type_lookup(struct devlink_linecard *linecard,
|
|
|
|
const char *type)
|
|
|
|
{
|
|
|
|
struct devlink_linecard_type *linecard_type;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < linecard->types_count; i++) {
|
|
|
|
linecard_type = &linecard->types[i];
|
|
|
|
if (!strcmp(type, linecard_type->type))
|
|
|
|
return linecard_type;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_linecard_type_set(struct devlink_linecard *linecard,
|
|
|
|
const char *type,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
const struct devlink_linecard_ops *ops = linecard->ops;
|
|
|
|
struct devlink_linecard_type *linecard_type;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
mutex_lock(&linecard->state_lock);
|
|
|
|
if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
|
2022-04-18 06:42:26 +00:00
|
|
|
err = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
|
2022-04-18 06:42:26 +00:00
|
|
|
err = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
linecard_type = devlink_linecard_type_lookup(linecard, type);
|
|
|
|
if (!linecard_type) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Unsupported line card type provided");
|
2022-04-18 06:42:26 +00:00
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONED &&
|
|
|
|
linecard->state != DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Line card already provisioned");
|
2022-04-18 06:42:26 +00:00
|
|
|
err = -EBUSY;
|
|
|
|
/* Check if the line card is provisioned in the same
|
|
|
|
* way the user asks. In case it is, make the operation
|
|
|
|
* to return success.
|
|
|
|
*/
|
|
|
|
if (ops->same_provision &&
|
|
|
|
ops->same_provision(linecard, linecard->priv,
|
|
|
|
linecard_type->type,
|
|
|
|
linecard_type->priv))
|
|
|
|
err = 0;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING;
|
|
|
|
linecard->type = linecard_type->type;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
err = ops->provision(linecard, linecard->priv, linecard_type->type,
|
|
|
|
linecard_type->priv, extack);
|
|
|
|
if (err) {
|
|
|
|
/* Provisioning failed. Assume the linecard is unprovisioned
|
|
|
|
* for future operations.
|
|
|
|
*/
|
|
|
|
mutex_lock(&linecard->state_lock);
|
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
|
|
|
linecard->type = NULL;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
|
|
|
|
out:
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_linecard_type_unset(struct devlink_linecard *linecard,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
mutex_lock(&linecard->state_lock);
|
|
|
|
if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
|
2022-04-18 06:42:26 +00:00
|
|
|
err = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
|
2022-04-18 06:42:26 +00:00
|
|
|
err = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
|
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
|
|
|
linecard->type = NULL;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
err = 0;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Line card is not provisioned");
|
2022-04-18 06:42:26 +00:00
|
|
|
err = 0;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONING;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
err = linecard->ops->unprovision(linecard, linecard->priv,
|
|
|
|
extack);
|
|
|
|
if (err) {
|
|
|
|
/* Unprovisioning failed. Assume the linecard is unprovisioned
|
|
|
|
* for future operations.
|
|
|
|
*/
|
|
|
|
mutex_lock(&linecard->state_lock);
|
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
|
|
|
linecard->type = NULL;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
|
|
|
|
out:
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink_linecard *linecard = info->user_ptr[1];
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) {
|
|
|
|
const char *type;
|
|
|
|
|
|
|
|
type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]);
|
|
|
|
if (strcmp(type, "")) {
|
|
|
|
err = devlink_linecard_type_set(linecard, type, extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
} else {
|
|
|
|
err = devlink_linecard_type_unset(linecard, extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
struct devlink_sb *devlink_sb,
|
|
|
|
enum devlink_command cmd, u32 portid,
|
|
|
|
u32 seq, int flags)
|
|
|
|
{
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
|
|
|
|
devlink_sb->ingress_pools_count))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
|
|
|
|
devlink_sb->egress_pools_count))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
|
|
|
|
devlink_sb->ingress_tc_count))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
|
|
|
|
devlink_sb->egress_tc_count))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
2016-04-14 16:19:13 +00:00
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
2020-07-22 15:57:11 +00:00
|
|
|
devlink_sb = devlink_sb_get_from_info(devlink, info);
|
|
|
|
if (IS_ERR(devlink_sb))
|
|
|
|
return PTR_ERR(devlink_sb);
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
|
|
|
|
DEVLINK_CMD_SB_NEW,
|
|
|
|
info->snd_portid, info->snd_seq, 0);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_sb_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2016-04-14 16:19:13 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-05 04:05:31 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
int idx = 0;
|
|
|
|
int err = 0;
|
2023-01-05 04:05:27 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
|
|
|
|
if (idx < state->idx) {
|
2016-04-14 16:19:13 +00:00
|
|
|
idx++;
|
2023-01-05 04:05:31 +00:00
|
|
|
continue;
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
2023-01-05 04:05:31 +00:00
|
|
|
err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
|
|
|
|
DEVLINK_CMD_SB_NEW,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI);
|
|
|
|
if (err) {
|
|
|
|
state->idx = idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
idx++;
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
2023-01-05 04:05:31 +00:00
|
|
|
|
|
|
|
return err;
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_sb_get = {
|
2023-01-05 04:05:31 +00:00
|
|
|
.dump_one = devlink_nl_cmd_sb_get_dump_one,
|
|
|
|
};
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
struct devlink_sb *devlink_sb,
|
|
|
|
u16 pool_index, enum devlink_command cmd,
|
|
|
|
u32 portid, u32 seq, int flags)
|
|
|
|
{
|
|
|
|
struct devlink_sb_pool_info pool_info;
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
|
|
|
|
pool_index, &pool_info);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
|
|
|
|
pool_info.threshold_type))
|
|
|
|
goto nla_put_failure;
|
2019-02-02 01:56:28 +00:00
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
|
|
|
|
pool_info.cell_size))
|
|
|
|
goto nla_put_failure;
|
2016-04-14 16:19:13 +00:00
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
2016-04-14 16:19:13 +00:00
|
|
|
struct sk_buff *msg;
|
|
|
|
u16 pool_index;
|
|
|
|
int err;
|
|
|
|
|
2020-07-22 15:57:11 +00:00
|
|
|
devlink_sb = devlink_sb_get_from_info(devlink, info);
|
|
|
|
if (IS_ERR(devlink_sb))
|
|
|
|
return PTR_ERR(devlink_sb);
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
|
|
|
|
&pool_index);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2019-02-26 03:34:07 +00:00
|
|
|
if (!devlink->ops->sb_pool_get)
|
2016-04-14 16:19:13 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
|
|
|
|
DEVLINK_CMD_SB_POOL_NEW,
|
|
|
|
info->snd_portid, info->snd_seq, 0);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct devlink_sb *devlink_sb,
|
|
|
|
u32 portid, u32 seq)
|
|
|
|
{
|
|
|
|
u16 pool_count = devlink_sb_pool_count(devlink_sb);
|
|
|
|
u16 pool_index;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
for (pool_index = 0; pool_index < pool_count; pool_index++) {
|
|
|
|
if (*p_idx < start) {
|
|
|
|
(*p_idx)++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
err = devlink_nl_sb_pool_fill(msg, devlink,
|
|
|
|
devlink_sb,
|
|
|
|
pool_index,
|
|
|
|
DEVLINK_CMD_SB_POOL_NEW,
|
|
|
|
portid, seq, NLM_F_MULTI);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
(*p_idx)++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_sb_pool_get_dump_one(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2016-04-14 16:19:13 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-05 04:05:31 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
2019-10-04 09:50:12 +00:00
|
|
|
int err = 0;
|
2023-01-05 04:05:31 +00:00
|
|
|
int idx = 0;
|
2016-04-14 16:19:13 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
if (!devlink->ops->sb_pool_get)
|
|
|
|
return 0;
|
2021-08-14 09:57:28 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
|
|
|
|
err = __sb_pool_get_dumpit(msg, state->idx, &idx,
|
|
|
|
devlink, devlink_sb,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq);
|
|
|
|
if (err == -EOPNOTSUPP) {
|
|
|
|
err = 0;
|
|
|
|
} else if (err) {
|
|
|
|
state->idx = idx;
|
|
|
|
break;
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-04 09:50:12 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
return err;
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_sb_pool_get = {
|
2023-01-05 04:05:31 +00:00
|
|
|
.dump_one = devlink_nl_cmd_sb_pool_get_dump_one,
|
|
|
|
};
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
|
|
|
|
u16 pool_index, u32 size,
|
2019-04-22 12:08:39 +00:00
|
|
|
enum devlink_sb_threshold_type threshold_type,
|
|
|
|
struct netlink_ext_ack *extack)
|
2016-04-14 16:19:13 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
const struct devlink_ops *ops = devlink->ops;
|
|
|
|
|
2019-02-26 03:34:07 +00:00
|
|
|
if (ops->sb_pool_set)
|
2016-04-14 16:19:13 +00:00
|
|
|
return ops->sb_pool_set(devlink, sb_index, pool_index,
|
2019-04-22 12:08:39 +00:00
|
|
|
size, threshold_type, extack);
|
2016-04-14 16:19:13 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
enum devlink_sb_threshold_type threshold_type;
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
2016-04-14 16:19:13 +00:00
|
|
|
u16 pool_index;
|
|
|
|
u32 size;
|
|
|
|
int err;
|
|
|
|
|
2020-07-22 15:57:11 +00:00
|
|
|
devlink_sb = devlink_sb_get_from_info(devlink, info);
|
|
|
|
if (IS_ERR(devlink_sb))
|
|
|
|
return PTR_ERR(devlink_sb);
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
|
|
|
|
&pool_index);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_sb_th_type_get_from_info(info, &threshold_type);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SB_POOL_SIZE))
|
2016-04-14 16:19:13 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
|
|
|
|
return devlink_sb_pool_set(devlink, devlink_sb->index,
|
2019-04-22 12:08:39 +00:00
|
|
|
pool_index, size, threshold_type,
|
|
|
|
info->extack);
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct devlink_port *devlink_port,
|
|
|
|
struct devlink_sb *devlink_sb,
|
|
|
|
u16 pool_index,
|
|
|
|
enum devlink_command cmd,
|
|
|
|
u32 portid, u32 seq, int flags)
|
|
|
|
{
|
2016-04-14 16:19:14 +00:00
|
|
|
const struct devlink_ops *ops = devlink->ops;
|
2016-04-14 16:19:13 +00:00
|
|
|
u32 threshold;
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
2016-04-14 16:19:14 +00:00
|
|
|
err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
|
|
|
|
pool_index, &threshold);
|
2016-04-14 16:19:13 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2016-04-14 16:19:14 +00:00
|
|
|
if (ops->sb_occ_port_pool_get) {
|
|
|
|
u32 cur;
|
|
|
|
u32 max;
|
|
|
|
|
|
|
|
err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
|
|
|
|
pool_index, &cur, &max);
|
|
|
|
if (err && err != -EOPNOTSUPP)
|
2020-11-13 11:16:22 +00:00
|
|
|
goto sb_occ_get_failure;
|
2016-04-14 16:19:14 +00:00
|
|
|
if (!err) {
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
2020-11-13 11:16:22 +00:00
|
|
|
err = -EMSGSIZE;
|
|
|
|
sb_occ_get_failure:
|
2016-04-14 16:19:13 +00:00
|
|
|
genlmsg_cancel(msg, hdr);
|
2020-11-13 11:16:22 +00:00
|
|
|
return err;
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_port *devlink_port = info->user_ptr[1];
|
2016-04-14 16:19:13 +00:00
|
|
|
struct devlink *devlink = devlink_port->devlink;
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
2016-04-14 16:19:13 +00:00
|
|
|
struct sk_buff *msg;
|
|
|
|
u16 pool_index;
|
|
|
|
int err;
|
|
|
|
|
2020-07-22 15:57:11 +00:00
|
|
|
devlink_sb = devlink_sb_get_from_info(devlink, info);
|
|
|
|
if (IS_ERR(devlink_sb))
|
|
|
|
return PTR_ERR(devlink_sb);
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
|
|
|
|
&pool_index);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2019-02-26 03:34:07 +00:00
|
|
|
if (!devlink->ops->sb_port_pool_get)
|
2016-04-14 16:19:13 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
|
|
|
|
devlink_sb, pool_index,
|
|
|
|
DEVLINK_CMD_SB_PORT_POOL_NEW,
|
|
|
|
info->snd_portid, info->snd_seq, 0);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct devlink_sb *devlink_sb,
|
|
|
|
u32 portid, u32 seq)
|
|
|
|
{
|
|
|
|
struct devlink_port *devlink_port;
|
|
|
|
u16 pool_count = devlink_sb_pool_count(devlink_sb);
|
2022-11-30 08:52:50 +00:00
|
|
|
unsigned long port_index;
|
2016-04-14 16:19:13 +00:00
|
|
|
u16 pool_index;
|
|
|
|
int err;
|
|
|
|
|
2022-11-30 08:52:50 +00:00
|
|
|
xa_for_each(&devlink->ports, port_index, devlink_port) {
|
2016-04-14 16:19:13 +00:00
|
|
|
for (pool_index = 0; pool_index < pool_count; pool_index++) {
|
|
|
|
if (*p_idx < start) {
|
|
|
|
(*p_idx)++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
err = devlink_nl_sb_port_pool_fill(msg, devlink,
|
|
|
|
devlink_port,
|
|
|
|
devlink_sb,
|
|
|
|
pool_index,
|
|
|
|
DEVLINK_CMD_SB_PORT_POOL_NEW,
|
|
|
|
portid, seq,
|
|
|
|
NLM_F_MULTI);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
(*p_idx)++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_sb_port_pool_get_dump_one(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2016-04-14 16:19:13 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-05 04:05:31 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
int idx = 0;
|
2019-10-04 09:50:12 +00:00
|
|
|
int err = 0;
|
2016-04-14 16:19:13 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
if (!devlink->ops->sb_port_pool_get)
|
|
|
|
return 0;
|
2021-08-14 09:57:28 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
|
|
|
|
err = __sb_port_pool_get_dumpit(msg, state->idx, &idx,
|
|
|
|
devlink, devlink_sb,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq);
|
|
|
|
if (err == -EOPNOTSUPP) {
|
|
|
|
err = 0;
|
|
|
|
} else if (err) {
|
|
|
|
state->idx = idx;
|
|
|
|
break;
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-04 09:50:12 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
return err;
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_sb_port_pool_get = {
|
2023-01-05 04:05:31 +00:00
|
|
|
.dump_one = devlink_nl_cmd_sb_port_pool_get_dump_one,
|
|
|
|
};
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
|
|
|
|
unsigned int sb_index, u16 pool_index,
|
2019-04-22 12:08:39 +00:00
|
|
|
u32 threshold,
|
|
|
|
struct netlink_ext_ack *extack)
|
2016-04-14 16:19:13 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
const struct devlink_ops *ops = devlink_port->devlink->ops;
|
|
|
|
|
2019-02-26 03:34:07 +00:00
|
|
|
if (ops->sb_port_pool_set)
|
2016-04-14 16:19:13 +00:00
|
|
|
return ops->sb_port_pool_set(devlink_port, sb_index,
|
2019-04-22 12:08:39 +00:00
|
|
|
pool_index, threshold, extack);
|
2016-04-14 16:19:13 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_port *devlink_port = info->user_ptr[1];
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_sb *devlink_sb;
|
2016-04-14 16:19:13 +00:00
|
|
|
u16 pool_index;
|
|
|
|
u32 threshold;
|
|
|
|
int err;
|
|
|
|
|
2020-07-22 15:57:11 +00:00
|
|
|
devlink_sb = devlink_sb_get_from_info(devlink, info);
|
|
|
|
if (IS_ERR(devlink_sb))
|
|
|
|
return PTR_ERR(devlink_sb);
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
|
|
|
|
&pool_index);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SB_THRESHOLD))
|
2016-04-14 16:19:13 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
|
|
|
|
return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
|
2019-04-22 12:08:39 +00:00
|
|
|
pool_index, threshold, info->extack);
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
struct devlink_port *devlink_port,
|
|
|
|
struct devlink_sb *devlink_sb, u16 tc_index,
|
|
|
|
enum devlink_sb_pool_type pool_type,
|
|
|
|
enum devlink_command cmd,
|
|
|
|
u32 portid, u32 seq, int flags)
|
|
|
|
{
|
2016-04-14 16:19:14 +00:00
|
|
|
const struct devlink_ops *ops = devlink->ops;
|
2016-04-14 16:19:13 +00:00
|
|
|
u16 pool_index;
|
|
|
|
u32 threshold;
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
2016-04-14 16:19:14 +00:00
|
|
|
err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
|
|
|
|
tc_index, pool_type,
|
|
|
|
&pool_index, &threshold);
|
2016-04-14 16:19:13 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2016-04-14 16:19:14 +00:00
|
|
|
if (ops->sb_occ_tc_port_bind_get) {
|
|
|
|
u32 cur;
|
|
|
|
u32 max;
|
|
|
|
|
|
|
|
err = ops->sb_occ_tc_port_bind_get(devlink_port,
|
|
|
|
devlink_sb->index,
|
|
|
|
tc_index, pool_type,
|
|
|
|
&cur, &max);
|
|
|
|
if (err && err != -EOPNOTSUPP)
|
|
|
|
return err;
|
|
|
|
if (!err) {
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_port *devlink_port = info->user_ptr[1];
|
2016-04-14 16:19:13 +00:00
|
|
|
struct devlink *devlink = devlink_port->devlink;
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
2016-04-14 16:19:13 +00:00
|
|
|
struct sk_buff *msg;
|
|
|
|
enum devlink_sb_pool_type pool_type;
|
|
|
|
u16 tc_index;
|
|
|
|
int err;
|
|
|
|
|
2020-07-22 15:57:11 +00:00
|
|
|
devlink_sb = devlink_sb_get_from_info(devlink, info);
|
|
|
|
if (IS_ERR(devlink_sb))
|
|
|
|
return PTR_ERR(devlink_sb);
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
err = devlink_sb_pool_type_get_from_info(info, &pool_type);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
|
|
|
|
pool_type, &tc_index);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2019-02-26 03:34:07 +00:00
|
|
|
if (!devlink->ops->sb_tc_pool_bind_get)
|
2016-04-14 16:19:13 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
|
|
|
|
devlink_sb, tc_index, pool_type,
|
|
|
|
DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
|
|
|
|
info->snd_portid,
|
|
|
|
info->snd_seq, 0);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
|
|
|
|
int start, int *p_idx,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct devlink_sb *devlink_sb,
|
|
|
|
u32 portid, u32 seq)
|
|
|
|
{
|
|
|
|
struct devlink_port *devlink_port;
|
2022-11-30 08:52:50 +00:00
|
|
|
unsigned long port_index;
|
2016-04-14 16:19:13 +00:00
|
|
|
u16 tc_index;
|
|
|
|
int err;
|
|
|
|
|
2022-11-30 08:52:50 +00:00
|
|
|
xa_for_each(&devlink->ports, port_index, devlink_port) {
|
2016-04-14 16:19:13 +00:00
|
|
|
for (tc_index = 0;
|
|
|
|
tc_index < devlink_sb->ingress_tc_count; tc_index++) {
|
|
|
|
if (*p_idx < start) {
|
|
|
|
(*p_idx)++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
|
|
|
|
devlink_port,
|
|
|
|
devlink_sb,
|
|
|
|
tc_index,
|
|
|
|
DEVLINK_SB_POOL_TYPE_INGRESS,
|
|
|
|
DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
|
|
|
|
portid, seq,
|
|
|
|
NLM_F_MULTI);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
(*p_idx)++;
|
|
|
|
}
|
|
|
|
for (tc_index = 0;
|
|
|
|
tc_index < devlink_sb->egress_tc_count; tc_index++) {
|
|
|
|
if (*p_idx < start) {
|
|
|
|
(*p_idx)++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
|
|
|
|
devlink_port,
|
|
|
|
devlink_sb,
|
|
|
|
tc_index,
|
|
|
|
DEVLINK_SB_POOL_TYPE_EGRESS,
|
|
|
|
DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
|
|
|
|
portid, seq,
|
|
|
|
NLM_F_MULTI);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
(*p_idx)++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2023-01-05 04:05:31 +00:00
|
|
|
devlink_nl_cmd_sb_tc_pool_bind_get_dump_one(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2016-04-14 16:19:13 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-05 04:05:31 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
int idx = 0;
|
2019-10-04 09:50:12 +00:00
|
|
|
int err = 0;
|
2016-04-14 16:19:13 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
if (!devlink->ops->sb_tc_pool_bind_get)
|
|
|
|
return 0;
|
2018-01-15 07:59:02 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
|
|
|
|
err = __sb_tc_pool_bind_get_dumpit(msg, state->idx, &idx,
|
|
|
|
devlink, devlink_sb,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq);
|
|
|
|
if (err == -EOPNOTSUPP) {
|
|
|
|
err = 0;
|
|
|
|
} else if (err) {
|
|
|
|
state->idx = idx;
|
|
|
|
break;
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-04 09:50:12 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
return err;
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_sb_tc_pool_bind_get = {
|
2023-01-05 04:05:31 +00:00
|
|
|
.dump_one = devlink_nl_cmd_sb_tc_pool_bind_get_dump_one,
|
|
|
|
};
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
|
|
|
|
unsigned int sb_index, u16 tc_index,
|
|
|
|
enum devlink_sb_pool_type pool_type,
|
2019-04-22 12:08:39 +00:00
|
|
|
u16 pool_index, u32 threshold,
|
|
|
|
struct netlink_ext_ack *extack)
|
2016-04-14 16:19:13 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
const struct devlink_ops *ops = devlink_port->devlink->ops;
|
|
|
|
|
2019-02-26 03:34:07 +00:00
|
|
|
if (ops->sb_tc_pool_bind_set)
|
2016-04-14 16:19:13 +00:00
|
|
|
return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
|
|
|
|
tc_index, pool_type,
|
2019-04-22 12:08:39 +00:00
|
|
|
pool_index, threshold, extack);
|
2016-04-14 16:19:13 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_port *devlink_port = info->user_ptr[1];
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
2016-04-14 16:19:13 +00:00
|
|
|
enum devlink_sb_pool_type pool_type;
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
2016-04-14 16:19:13 +00:00
|
|
|
u16 tc_index;
|
|
|
|
u16 pool_index;
|
|
|
|
u32 threshold;
|
|
|
|
int err;
|
|
|
|
|
2020-07-22 15:57:11 +00:00
|
|
|
devlink_sb = devlink_sb_get_from_info(devlink, info);
|
|
|
|
if (IS_ERR(devlink_sb))
|
|
|
|
return PTR_ERR(devlink_sb);
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
err = devlink_sb_pool_type_get_from_info(info, &pool_type);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
|
|
|
|
pool_type, &tc_index);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
|
|
|
|
&pool_index);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SB_THRESHOLD))
|
2016-04-14 16:19:13 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
|
|
|
|
return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
|
|
|
|
tc_index, pool_type,
|
2019-04-22 12:08:39 +00:00
|
|
|
pool_index, threshold, info->extack);
|
2016-04-14 16:19:13 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 16:19:14 +00:00
|
|
|
static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
const struct devlink_ops *ops = devlink->ops;
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
|
|
|
|
devlink_sb = devlink_sb_get_from_info(devlink, info);
|
|
|
|
if (IS_ERR(devlink_sb))
|
|
|
|
return PTR_ERR(devlink_sb);
|
2016-04-14 16:19:14 +00:00
|
|
|
|
2019-02-26 03:34:07 +00:00
|
|
|
if (ops->sb_occ_snapshot)
|
2016-04-14 16:19:14 +00:00
|
|
|
return ops->sb_occ_snapshot(devlink, devlink_sb->index);
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
const struct devlink_ops *ops = devlink->ops;
|
2020-07-22 15:57:11 +00:00
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
|
|
|
|
devlink_sb = devlink_sb_get_from_info(devlink, info);
|
|
|
|
if (IS_ERR(devlink_sb))
|
|
|
|
return PTR_ERR(devlink_sb);
|
2016-04-14 16:19:14 +00:00
|
|
|
|
2019-02-26 03:34:07 +00:00
|
|
|
if (ops->sb_occ_max_clear)
|
2016-04-14 16:19:14 +00:00
|
|
|
return ops->sb_occ_max_clear(devlink, devlink_sb->index);
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2023-02-02 14:47:02 +00:00
|
|
|
int devlink_rate_nodes_check(struct devlink *devlink, u16 mode,
|
|
|
|
struct netlink_ext_ack *extack)
|
2021-06-02 12:17:25 +00:00
|
|
|
{
|
|
|
|
struct devlink_rate *devlink_rate;
|
|
|
|
|
|
|
|
list_for_each_entry(devlink_rate, &devlink->rate_list, list)
|
|
|
|
if (devlink_rate_is_node(devlink_rate)) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Rate node(s) exists.");
|
2021-06-02 12:17:25 +00:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-28 15:24:10 +00:00
|
|
|
int devlink_dpipe_match_put(struct sk_buff *skb,
|
|
|
|
struct devlink_dpipe_match *match)
|
|
|
|
{
|
|
|
|
struct devlink_dpipe_header *header = match->header;
|
|
|
|
struct devlink_dpipe_field *field = &header->fields[match->field_id];
|
|
|
|
struct nlattr *match_attr;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!match_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
|
|
|
|
nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
|
|
|
|
nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
|
|
|
|
nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
|
|
|
|
nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(skb, match_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(skb, match_attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
|
|
|
|
|
|
|
|
static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct nlattr *matches_attr;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
matches_attr = nla_nest_start_noflag(skb,
|
|
|
|
DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!matches_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (table->table_ops->matches_dump(table->priv, skb))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(skb, matches_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(skb, matches_attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int devlink_dpipe_action_put(struct sk_buff *skb,
|
|
|
|
struct devlink_dpipe_action *action)
|
|
|
|
{
|
|
|
|
struct devlink_dpipe_header *header = action->header;
|
|
|
|
struct devlink_dpipe_field *field = &header->fields[action->field_id];
|
|
|
|
struct nlattr *action_attr;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!action_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
|
|
|
|
nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
|
|
|
|
nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
|
|
|
|
nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
|
|
|
|
nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(skb, action_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(skb, action_attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
|
|
|
|
|
|
|
|
static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct nlattr *actions_attr;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
actions_attr = nla_nest_start_noflag(skb,
|
|
|
|
DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!actions_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (table->table_ops->actions_dump(table->priv, skb))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(skb, actions_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(skb, actions_attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_table_put(struct sk_buff *skb,
|
|
|
|
struct devlink_dpipe_table *table)
|
|
|
|
{
|
|
|
|
struct nlattr *table_attr;
|
2017-08-24 06:40:02 +00:00
|
|
|
u64 table_size;
|
2017-03-28 15:24:10 +00:00
|
|
|
|
2017-08-24 06:40:02 +00:00
|
|
|
table_size = table->table_ops->size_get(table->priv);
|
2019-04-26 09:13:06 +00:00
|
|
|
table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!table_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
|
2017-08-24 06:40:02 +00:00
|
|
|
nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
|
2017-03-28 15:24:10 +00:00
|
|
|
DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
|
|
|
|
table->counters_enabled))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2018-01-15 07:59:05 +00:00
|
|
|
if (table->resource_valid) {
|
2018-02-26 16:25:42 +00:00
|
|
|
if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
|
|
|
|
table->resource_id, DEVLINK_ATTR_PAD) ||
|
|
|
|
nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
|
|
|
|
table->resource_units, DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
2018-01-15 07:59:05 +00:00
|
|
|
}
|
2017-03-28 15:24:10 +00:00
|
|
|
if (devlink_dpipe_matches_put(table, skb))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (devlink_dpipe_actions_put(table, skb))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(skb, table_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(skb, table_attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (*pskb) {
|
|
|
|
err = genlmsg_reply(*pskb, info);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
*pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!*pskb)
|
|
|
|
return -ENOMEM;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_tables_fill(struct genl_info *info,
|
|
|
|
enum devlink_command cmd, int flags,
|
|
|
|
struct list_head *dpipe_tables,
|
|
|
|
const char *table_name)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_dpipe_table *table;
|
|
|
|
struct nlattr *tables_attr;
|
|
|
|
struct sk_buff *skb = NULL;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
bool incomplete;
|
|
|
|
void *hdr;
|
|
|
|
int i;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
table = list_first_entry(dpipe_tables,
|
|
|
|
struct devlink_dpipe_table, list);
|
|
|
|
start_again:
|
|
|
|
err = devlink_dpipe_send_and_alloc_skb(&skb, info);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
|
|
|
|
&devlink_nl_family, NLM_F_MULTI, cmd);
|
2017-06-05 00:57:21 +00:00
|
|
|
if (!hdr) {
|
|
|
|
nlmsg_free(skb);
|
2017-03-28 15:24:10 +00:00
|
|
|
return -EMSGSIZE;
|
2017-06-05 00:57:21 +00:00
|
|
|
}
|
2017-03-28 15:24:10 +00:00
|
|
|
|
|
|
|
if (devlink_nl_put_handle(skb, devlink))
|
|
|
|
goto nla_put_failure;
|
2019-04-26 09:13:06 +00:00
|
|
|
tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!tables_attr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
incomplete = false;
|
|
|
|
list_for_each_entry_from(table, dpipe_tables, list) {
|
|
|
|
if (!table_name) {
|
|
|
|
err = devlink_dpipe_table_put(skb, table);
|
|
|
|
if (err) {
|
|
|
|
if (!i)
|
|
|
|
goto err_table_put;
|
|
|
|
incomplete = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!strcmp(table->name, table_name)) {
|
|
|
|
err = devlink_dpipe_table_put(skb, table);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(skb, tables_attr);
|
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
if (incomplete)
|
|
|
|
goto start_again;
|
|
|
|
|
|
|
|
send_done:
|
|
|
|
nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
|
|
|
|
NLMSG_DONE, 0, flags | NLM_F_MULTI);
|
|
|
|
if (!nlh) {
|
|
|
|
err = devlink_dpipe_send_and_alloc_skb(&skb, info);
|
|
|
|
if (err)
|
2018-03-18 15:37:22 +00:00
|
|
|
return err;
|
2017-03-28 15:24:10 +00:00
|
|
|
goto send_done;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(skb, info);
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
err_table_put:
|
|
|
|
nlmsg_free(skb);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
const char *table_name = NULL;
|
|
|
|
|
|
|
|
if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
|
|
|
|
table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
|
|
|
|
|
|
|
|
return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
|
|
|
|
&devlink->dpipe_table_list,
|
|
|
|
table_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_value_put(struct sk_buff *skb,
|
|
|
|
struct devlink_dpipe_value *value)
|
|
|
|
{
|
|
|
|
if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
|
|
|
|
value->value_size, value->value))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (value->mask)
|
|
|
|
if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
|
|
|
|
value->value_size, value->mask))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (value->mapping_valid)
|
|
|
|
if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
|
|
|
|
value->mapping_value))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_action_value_put(struct sk_buff *skb,
|
|
|
|
struct devlink_dpipe_value *value)
|
|
|
|
{
|
|
|
|
if (!value->action)
|
|
|
|
return -EINVAL;
|
|
|
|
if (devlink_dpipe_action_put(skb, value->action))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (devlink_dpipe_value_put(skb, value))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_action_values_put(struct sk_buff *skb,
|
|
|
|
struct devlink_dpipe_value *values,
|
|
|
|
unsigned int values_count)
|
|
|
|
{
|
|
|
|
struct nlattr *action_attr;
|
|
|
|
int i;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
for (i = 0; i < values_count; i++) {
|
2019-04-26 09:13:06 +00:00
|
|
|
action_attr = nla_nest_start_noflag(skb,
|
|
|
|
DEVLINK_ATTR_DPIPE_ACTION_VALUE);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!action_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
err = devlink_dpipe_action_value_put(skb, &values[i]);
|
|
|
|
if (err)
|
|
|
|
goto err_action_value_put;
|
|
|
|
nla_nest_end(skb, action_attr);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_action_value_put:
|
|
|
|
nla_nest_cancel(skb, action_attr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_match_value_put(struct sk_buff *skb,
|
|
|
|
struct devlink_dpipe_value *value)
|
|
|
|
{
|
|
|
|
if (!value->match)
|
|
|
|
return -EINVAL;
|
|
|
|
if (devlink_dpipe_match_put(skb, value->match))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (devlink_dpipe_value_put(skb, value))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_match_values_put(struct sk_buff *skb,
|
|
|
|
struct devlink_dpipe_value *values,
|
|
|
|
unsigned int values_count)
|
|
|
|
{
|
|
|
|
struct nlattr *match_attr;
|
|
|
|
int i;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
for (i = 0; i < values_count; i++) {
|
2019-04-26 09:13:06 +00:00
|
|
|
match_attr = nla_nest_start_noflag(skb,
|
|
|
|
DEVLINK_ATTR_DPIPE_MATCH_VALUE);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!match_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
err = devlink_dpipe_match_value_put(skb, &values[i]);
|
|
|
|
if (err)
|
|
|
|
goto err_match_value_put;
|
|
|
|
nla_nest_end(skb, match_attr);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_match_value_put:
|
|
|
|
nla_nest_cancel(skb, match_attr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_entry_put(struct sk_buff *skb,
|
|
|
|
struct devlink_dpipe_entry *entry)
|
|
|
|
{
|
|
|
|
struct nlattr *entry_attr, *matches_attr, *actions_attr;
|
|
|
|
int err;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!entry_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
|
|
|
|
DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
|
|
|
if (entry->counter_valid)
|
|
|
|
if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
|
|
|
|
entry->counter, DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
matches_attr = nla_nest_start_noflag(skb,
|
|
|
|
DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!matches_attr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
err = devlink_dpipe_match_values_put(skb, entry->match_values,
|
|
|
|
entry->match_values_count);
|
|
|
|
if (err) {
|
|
|
|
nla_nest_cancel(skb, matches_attr);
|
|
|
|
goto err_match_values_put;
|
|
|
|
}
|
|
|
|
nla_nest_end(skb, matches_attr);
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
actions_attr = nla_nest_start_noflag(skb,
|
|
|
|
DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!actions_attr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
err = devlink_dpipe_action_values_put(skb, entry->action_values,
|
|
|
|
entry->action_values_count);
|
|
|
|
if (err) {
|
|
|
|
nla_nest_cancel(skb, actions_attr);
|
|
|
|
goto err_action_values_put;
|
|
|
|
}
|
|
|
|
nla_nest_end(skb, actions_attr);
|
2016-11-22 21:09:57 +00:00
|
|
|
|
2017-03-28 15:24:10 +00:00
|
|
|
nla_nest_end(skb, entry_attr);
|
2016-11-22 21:09:57 +00:00
|
|
|
return 0;
|
2017-03-28 15:24:10 +00:00
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
err_match_values_put:
|
|
|
|
err_action_values_put:
|
|
|
|
nla_nest_cancel(skb, entry_attr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_dpipe_table *
|
|
|
|
devlink_dpipe_table_find(struct list_head *dpipe_tables,
|
2020-02-25 12:27:45 +00:00
|
|
|
const char *table_name, struct devlink *devlink)
|
2017-03-28 15:24:10 +00:00
|
|
|
{
|
|
|
|
struct devlink_dpipe_table *table;
|
2020-02-25 12:27:45 +00:00
|
|
|
list_for_each_entry_rcu(table, dpipe_tables, list,
|
|
|
|
lockdep_is_held(&devlink->lock)) {
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!strcmp(table->name, table_name))
|
|
|
|
return table;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
|
|
|
|
{
|
|
|
|
struct devlink *devlink;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
|
|
|
|
dump_ctx->info);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
|
|
|
|
dump_ctx->info->snd_portid,
|
|
|
|
dump_ctx->info->snd_seq,
|
|
|
|
&devlink_nl_family, NLM_F_MULTI,
|
|
|
|
dump_ctx->cmd);
|
|
|
|
if (!dump_ctx->hdr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
devlink = dump_ctx->info->user_ptr[0];
|
|
|
|
if (devlink_nl_put_handle(dump_ctx->skb, devlink))
|
|
|
|
goto nla_put_failure;
|
2019-04-26 09:13:06 +00:00
|
|
|
dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
|
|
|
|
DEVLINK_ATTR_DPIPE_ENTRIES);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!dump_ctx->nest)
|
|
|
|
goto nla_put_failure;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nlmsg_free(dump_ctx->skb);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
|
|
|
|
|
|
|
|
int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
|
|
|
|
struct devlink_dpipe_entry *entry)
|
|
|
|
{
|
|
|
|
return devlink_dpipe_entry_put(dump_ctx->skb, entry);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
|
|
|
|
|
|
|
|
int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
|
|
|
|
{
|
|
|
|
nla_nest_end(dump_ctx->skb, dump_ctx->nest);
|
|
|
|
genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
|
|
|
|
|
2017-08-24 06:40:03 +00:00
|
|
|
void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
|
|
|
|
|
|
|
|
{
|
|
|
|
unsigned int value_count, value_index;
|
|
|
|
struct devlink_dpipe_value *value;
|
|
|
|
|
|
|
|
value = entry->action_values;
|
|
|
|
value_count = entry->action_values_count;
|
|
|
|
for (value_index = 0; value_index < value_count; value_index++) {
|
|
|
|
kfree(value[value_index].value);
|
|
|
|
kfree(value[value_index].mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
value = entry->match_values;
|
|
|
|
value_count = entry->match_values_count;
|
|
|
|
for (value_index = 0; value_index < value_count; value_index++) {
|
|
|
|
kfree(value[value_index].value);
|
|
|
|
kfree(value[value_index].mask);
|
|
|
|
}
|
|
|
|
}
|
2021-10-28 21:19:13 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_entry_clear);
|
2017-08-24 06:40:03 +00:00
|
|
|
|
2017-03-28 15:24:10 +00:00
|
|
|
static int devlink_dpipe_entries_fill(struct genl_info *info,
|
|
|
|
enum devlink_command cmd, int flags,
|
|
|
|
struct devlink_dpipe_table *table)
|
|
|
|
{
|
|
|
|
struct devlink_dpipe_dump_ctx dump_ctx;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
dump_ctx.skb = NULL;
|
|
|
|
dump_ctx.cmd = cmd;
|
|
|
|
dump_ctx.info = info;
|
|
|
|
|
|
|
|
err = table->table_ops->entries_dump(table->priv,
|
|
|
|
table->counters_enabled,
|
|
|
|
&dump_ctx);
|
|
|
|
if (err)
|
2018-03-18 15:37:22 +00:00
|
|
|
return err;
|
2017-03-28 15:24:10 +00:00
|
|
|
|
|
|
|
send_done:
|
|
|
|
nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
|
|
|
|
NLMSG_DONE, 0, flags | NLM_F_MULTI);
|
|
|
|
if (!nlh) {
|
|
|
|
err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
|
|
|
|
if (err)
|
2018-03-18 15:37:22 +00:00
|
|
|
return err;
|
2017-03-28 15:24:10 +00:00
|
|
|
goto send_done;
|
|
|
|
}
|
|
|
|
return genlmsg_reply(dump_ctx.skb, info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_dpipe_table *table;
|
|
|
|
const char *table_name;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_DPIPE_TABLE_NAME))
|
2017-03-28 15:24:10 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
|
|
|
|
table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
|
2020-02-25 12:27:45 +00:00
|
|
|
table_name, devlink);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!table)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!table->table_ops->entries_dump)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
|
|
|
|
0, table);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_fields_put(struct sk_buff *skb,
|
|
|
|
const struct devlink_dpipe_header *header)
|
|
|
|
{
|
|
|
|
struct devlink_dpipe_field *field;
|
|
|
|
struct nlattr *field_attr;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < header->fields_count; i++) {
|
|
|
|
field = &header->fields[i];
|
2019-04-26 09:13:06 +00:00
|
|
|
field_attr = nla_nest_start_noflag(skb,
|
|
|
|
DEVLINK_ATTR_DPIPE_FIELD);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!field_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
|
|
|
|
nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
|
|
|
|
nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
|
|
|
|
nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
|
|
|
|
goto nla_put_failure;
|
|
|
|
nla_nest_end(skb, field_attr);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(skb, field_attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_header_put(struct sk_buff *skb,
|
|
|
|
struct devlink_dpipe_header *header)
|
|
|
|
{
|
|
|
|
struct nlattr *fields_attr, *header_attr;
|
|
|
|
int err;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
|
2017-04-11 16:02:02 +00:00
|
|
|
if (!header_attr)
|
2017-03-28 15:24:10 +00:00
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
|
|
|
|
nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
|
|
|
|
nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
fields_attr = nla_nest_start_noflag(skb,
|
|
|
|
DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!fields_attr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
err = devlink_dpipe_fields_put(skb, header);
|
|
|
|
if (err) {
|
|
|
|
nla_nest_cancel(skb, fields_attr);
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
nla_nest_end(skb, fields_attr);
|
|
|
|
nla_nest_end(skb, header_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
nla_nest_cancel(skb, header_attr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_headers_fill(struct genl_info *info,
|
|
|
|
enum devlink_command cmd, int flags,
|
|
|
|
struct devlink_dpipe_headers *
|
|
|
|
dpipe_headers)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct nlattr *headers_attr;
|
|
|
|
struct sk_buff *skb = NULL;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
void *hdr;
|
|
|
|
int i, j;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
start_again:
|
|
|
|
err = devlink_dpipe_send_and_alloc_skb(&skb, info);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
|
|
|
|
&devlink_nl_family, NLM_F_MULTI, cmd);
|
2017-06-05 00:57:21 +00:00
|
|
|
if (!hdr) {
|
|
|
|
nlmsg_free(skb);
|
2017-03-28 15:24:10 +00:00
|
|
|
return -EMSGSIZE;
|
2017-06-05 00:57:21 +00:00
|
|
|
}
|
2017-03-28 15:24:10 +00:00
|
|
|
|
|
|
|
if (devlink_nl_put_handle(skb, devlink))
|
|
|
|
goto nla_put_failure;
|
2019-04-26 09:13:06 +00:00
|
|
|
headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!headers_attr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
j = 0;
|
|
|
|
for (; i < dpipe_headers->headers_count; i++) {
|
|
|
|
err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
|
|
|
|
if (err) {
|
|
|
|
if (!j)
|
|
|
|
goto err_table_put;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
nla_nest_end(skb, headers_attr);
|
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
if (i != dpipe_headers->headers_count)
|
|
|
|
goto start_again;
|
|
|
|
|
|
|
|
send_done:
|
|
|
|
nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
|
|
|
|
NLMSG_DONE, 0, flags | NLM_F_MULTI);
|
|
|
|
if (!nlh) {
|
|
|
|
err = devlink_dpipe_send_and_alloc_skb(&skb, info);
|
|
|
|
if (err)
|
2018-03-18 15:37:22 +00:00
|
|
|
return err;
|
2017-03-28 15:24:10 +00:00
|
|
|
goto send_done;
|
|
|
|
}
|
|
|
|
return genlmsg_reply(skb, info);
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
err_table_put:
|
|
|
|
nlmsg_free(skb);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
|
|
|
|
if (!devlink->dpipe_headers)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
|
|
|
|
0, devlink->dpipe_headers);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_dpipe_table_counters_set(struct devlink *devlink,
|
|
|
|
const char *table_name,
|
|
|
|
bool enable)
|
|
|
|
{
|
|
|
|
struct devlink_dpipe_table *table;
|
|
|
|
|
|
|
|
table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
|
2020-02-25 12:27:45 +00:00
|
|
|
table_name, devlink);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!table)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (table->counter_control_extern)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (!(table->counters_enabled ^ enable))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
table->counters_enabled = enable;
|
|
|
|
if (table->table_ops->counters_set_update)
|
|
|
|
table->table_ops->counters_set_update(table->priv, enable);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
const char *table_name;
|
|
|
|
bool counters_enable;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_DPIPE_TABLE_NAME) ||
|
|
|
|
GENL_REQ_ATTR_CHECK(info,
|
|
|
|
DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED))
|
2017-03-28 15:24:10 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
|
|
|
|
counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
|
|
|
|
|
|
|
|
return devlink_dpipe_table_counters_set(devlink, table_name,
|
|
|
|
counters_enable);
|
2016-07-01 11:51:01 +00:00
|
|
|
}
|
|
|
|
|
2018-01-17 03:27:42 +00:00
|
|
|
static struct devlink_resource *
|
2018-01-15 07:59:03 +00:00
|
|
|
devlink_resource_find(struct devlink *devlink,
|
|
|
|
struct devlink_resource *resource, u64 resource_id)
|
|
|
|
{
|
|
|
|
struct list_head *resource_list;
|
|
|
|
|
|
|
|
if (resource)
|
|
|
|
resource_list = &resource->resource_list;
|
|
|
|
else
|
|
|
|
resource_list = &devlink->resource_list;
|
|
|
|
|
|
|
|
list_for_each_entry(resource, resource_list, list) {
|
|
|
|
struct devlink_resource *child_resource;
|
|
|
|
|
|
|
|
if (resource->id == resource_id)
|
|
|
|
return resource;
|
|
|
|
|
|
|
|
child_resource = devlink_resource_find(devlink, resource,
|
|
|
|
resource_id);
|
|
|
|
if (child_resource)
|
|
|
|
return child_resource;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-01-17 03:27:42 +00:00
|
|
|
static void
|
|
|
|
devlink_resource_validate_children(struct devlink_resource *resource)
|
2018-01-15 07:59:03 +00:00
|
|
|
{
|
|
|
|
struct devlink_resource *child_resource;
|
|
|
|
bool size_valid = true;
|
|
|
|
u64 parts_size = 0;
|
|
|
|
|
|
|
|
if (list_empty(&resource->resource_list))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
list_for_each_entry(child_resource, &resource->resource_list, list)
|
|
|
|
parts_size += child_resource->size_new;
|
|
|
|
|
2018-02-26 09:59:53 +00:00
|
|
|
if (parts_size > resource->size_new)
|
2018-01-15 07:59:03 +00:00
|
|
|
size_valid = false;
|
|
|
|
out:
|
|
|
|
resource->size_valid = size_valid;
|
|
|
|
}
|
|
|
|
|
2018-02-20 07:44:20 +00:00
|
|
|
static int
|
|
|
|
devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
u64 reminder;
|
|
|
|
int err = 0;
|
|
|
|
|
2018-03-06 05:53:44 +00:00
|
|
|
if (size > resource->size_params.size_max) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Size larger than maximum");
|
2018-02-20 07:44:20 +00:00
|
|
|
err = -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-03-06 05:53:44 +00:00
|
|
|
if (size < resource->size_params.size_min) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Size smaller than minimum");
|
2018-02-20 07:44:20 +00:00
|
|
|
err = -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-03-06 05:53:44 +00:00
|
|
|
div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
|
2018-02-20 07:44:20 +00:00
|
|
|
if (reminder) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Wrong granularity");
|
2018-02-20 07:44:20 +00:00
|
|
|
err = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-01-15 07:59:03 +00:00
|
|
|
static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_resource *resource;
|
|
|
|
u64 resource_id;
|
|
|
|
u64 size;
|
|
|
|
int err;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_RESOURCE_ID) ||
|
|
|
|
GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_RESOURCE_SIZE))
|
2018-01-15 07:59:03 +00:00
|
|
|
return -EINVAL;
|
|
|
|
resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
|
|
|
|
|
|
|
|
resource = devlink_resource_find(devlink, NULL, resource_id);
|
|
|
|
if (!resource)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
|
2018-02-20 07:44:20 +00:00
|
|
|
err = devlink_resource_validate_size(resource, size, info->extack);
|
2018-01-15 07:59:03 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
resource->size_new = size;
|
|
|
|
devlink_resource_validate_children(resource);
|
|
|
|
if (resource->parent)
|
|
|
|
devlink_resource_validate_children(resource->parent);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-02-26 16:25:42 +00:00
|
|
|
static int
|
2018-01-15 07:59:03 +00:00
|
|
|
devlink_resource_size_params_put(struct devlink_resource *resource,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct devlink_resource_size_params *size_params;
|
|
|
|
|
2018-02-28 12:12:09 +00:00
|
|
|
size_params = &resource->size_params;
|
2018-02-26 16:25:42 +00:00
|
|
|
if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
|
|
|
|
size_params->size_granularity, DEVLINK_ATTR_PAD) ||
|
|
|
|
nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
|
|
|
|
size_params->size_max, DEVLINK_ATTR_PAD) ||
|
|
|
|
nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
|
|
|
|
size_params->size_min, DEVLINK_ATTR_PAD) ||
|
|
|
|
nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
|
|
|
|
return -EMSGSIZE;
|
|
|
|
return 0;
|
2018-01-15 07:59:03 +00:00
|
|
|
}
|
|
|
|
|
2018-04-05 20:13:21 +00:00
|
|
|
static int devlink_resource_occ_put(struct devlink_resource *resource,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
if (!resource->occ_get)
|
|
|
|
return 0;
|
|
|
|
return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
|
|
|
|
resource->occ_get(resource->occ_get_priv),
|
|
|
|
DEVLINK_ATTR_PAD);
|
|
|
|
}
|
|
|
|
|
2018-01-15 07:59:03 +00:00
|
|
|
static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
|
|
|
|
struct devlink_resource *resource)
|
|
|
|
{
|
|
|
|
struct devlink_resource *child_resource;
|
|
|
|
struct nlattr *child_resource_attr;
|
|
|
|
struct nlattr *resource_attr;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
|
2018-01-15 07:59:03 +00:00
|
|
|
if (!resource_attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
|
|
|
|
nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
|
|
|
|
DEVLINK_ATTR_PAD) ||
|
|
|
|
nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
|
|
|
|
DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
2022-12-08 08:31:39 +00:00
|
|
|
if (resource->size != resource->size_new &&
|
|
|
|
nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
|
|
|
|
resource->size_new, DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
2018-04-05 20:13:21 +00:00
|
|
|
if (devlink_resource_occ_put(resource, skb))
|
|
|
|
goto nla_put_failure;
|
2018-02-26 16:25:42 +00:00
|
|
|
if (devlink_resource_size_params_put(resource, skb))
|
|
|
|
goto nla_put_failure;
|
2018-01-15 07:59:03 +00:00
|
|
|
if (list_empty(&resource->resource_list))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
|
|
|
|
resource->size_valid))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
child_resource_attr = nla_nest_start_noflag(skb,
|
|
|
|
DEVLINK_ATTR_RESOURCE_LIST);
|
2018-01-15 07:59:03 +00:00
|
|
|
if (!child_resource_attr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
list_for_each_entry(child_resource, &resource->resource_list, list) {
|
|
|
|
if (devlink_resource_put(devlink, skb, child_resource))
|
|
|
|
goto resource_put_failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(skb, child_resource_attr);
|
|
|
|
out:
|
|
|
|
nla_nest_end(skb, resource_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
resource_put_failure:
|
|
|
|
nla_nest_cancel(skb, child_resource_attr);
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(skb, resource_attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_resource_fill(struct genl_info *info,
|
|
|
|
enum devlink_command cmd, int flags)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_resource *resource;
|
|
|
|
struct nlattr *resources_attr;
|
|
|
|
struct sk_buff *skb = NULL;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
bool incomplete;
|
|
|
|
void *hdr;
|
|
|
|
int i;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
resource = list_first_entry(&devlink->resource_list,
|
|
|
|
struct devlink_resource, list);
|
|
|
|
start_again:
|
|
|
|
err = devlink_dpipe_send_and_alloc_skb(&skb, info);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
|
|
|
|
&devlink_nl_family, NLM_F_MULTI, cmd);
|
|
|
|
if (!hdr) {
|
|
|
|
nlmsg_free(skb);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(skb, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
resources_attr = nla_nest_start_noflag(skb,
|
|
|
|
DEVLINK_ATTR_RESOURCE_LIST);
|
2018-01-15 07:59:03 +00:00
|
|
|
if (!resources_attr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
incomplete = false;
|
|
|
|
i = 0;
|
|
|
|
list_for_each_entry_from(resource, &devlink->resource_list, list) {
|
|
|
|
err = devlink_resource_put(devlink, skb, resource);
|
|
|
|
if (err) {
|
|
|
|
if (!i)
|
|
|
|
goto err_resource_put;
|
|
|
|
incomplete = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
nla_nest_end(skb, resources_attr);
|
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
if (incomplete)
|
|
|
|
goto start_again;
|
|
|
|
send_done:
|
|
|
|
nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
|
|
|
|
NLMSG_DONE, 0, flags | NLM_F_MULTI);
|
|
|
|
if (!nlh) {
|
|
|
|
err = devlink_dpipe_send_and_alloc_skb(&skb, info);
|
|
|
|
if (err)
|
2018-09-21 08:07:55 +00:00
|
|
|
return err;
|
2018-01-15 07:59:03 +00:00
|
|
|
goto send_done;
|
|
|
|
}
|
|
|
|
return genlmsg_reply(skb, info);
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
err_resource_put:
|
|
|
|
nlmsg_free(skb);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
|
|
|
|
if (list_empty(&devlink->resource_list))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
|
|
|
|
}
|
|
|
|
|
2023-02-02 14:47:01 +00:00
|
|
|
int devlink_resources_validate(struct devlink *devlink,
|
|
|
|
struct devlink_resource *resource,
|
|
|
|
struct genl_info *info)
|
2018-01-15 07:59:04 +00:00
|
|
|
{
|
|
|
|
struct list_head *resource_list;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (resource)
|
|
|
|
resource_list = &resource->resource_list;
|
|
|
|
else
|
|
|
|
resource_list = &devlink->resource_list;
|
|
|
|
|
|
|
|
list_for_each_entry(resource, resource_list, list) {
|
|
|
|
if (!resource->size_valid)
|
|
|
|
return -EINVAL;
|
|
|
|
err = devlink_resources_validate(devlink, resource, info);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-07-04 11:30:33 +00:00
|
|
|
static const struct devlink_param devlink_param_generic[] = {
|
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
|
|
|
|
},
|
2018-07-04 11:30:36 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
|
|
|
|
},
|
2018-07-12 12:13:17 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
|
|
|
|
},
|
2018-10-04 05:43:44 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
|
|
|
|
},
|
2018-10-04 05:43:45 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
|
|
|
|
},
|
2018-10-04 05:43:46 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
|
|
|
|
},
|
2018-12-03 07:58:59 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
|
|
|
|
},
|
2019-09-08 23:54:18 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
|
|
|
|
},
|
2019-11-08 23:45:20 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,
|
|
|
|
},
|
2020-10-07 06:00:53 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_REMOTE_DEV_RESET,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_TYPE,
|
|
|
|
},
|
2021-08-10 13:24:15 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_ENABLE_ETH_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_ENABLE_ETH_TYPE,
|
|
|
|
},
|
2021-08-10 13:24:16 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_ENABLE_RDMA_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_ENABLE_RDMA_TYPE,
|
|
|
|
},
|
2021-08-10 13:24:17 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_ENABLE_VNET_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_ENABLE_VNET_TYPE,
|
|
|
|
},
|
2021-10-18 23:16:01 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_IWARP,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_ENABLE_IWARP_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_ENABLE_IWARP_TYPE,
|
|
|
|
},
|
2021-12-09 10:09:24 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_IO_EQ_SIZE,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_IO_EQ_SIZE_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_IO_EQ_SIZE_TYPE,
|
|
|
|
},
|
2021-12-09 10:09:26 +00:00
|
|
|
{
|
|
|
|
.id = DEVLINK_PARAM_GENERIC_ID_EVENT_EQ_SIZE,
|
|
|
|
.name = DEVLINK_PARAM_GENERIC_EVENT_EQ_SIZE_NAME,
|
|
|
|
.type = DEVLINK_PARAM_GENERIC_EVENT_EQ_SIZE_TYPE,
|
|
|
|
},
|
2018-07-04 11:30:33 +00:00
|
|
|
};
|
2018-07-04 11:30:28 +00:00
|
|
|
|
|
|
|
static int devlink_param_generic_verify(const struct devlink_param *param)
|
|
|
|
{
|
|
|
|
/* verify it match generic parameter by id and name */
|
|
|
|
if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
|
|
|
|
return -EINVAL;
|
|
|
|
if (strcmp(param->name, devlink_param_generic[param->id].name))
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
WARN_ON(param->type != devlink_param_generic[param->id].type);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_param_driver_verify(const struct devlink_param *param)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
|
|
|
|
return -EINVAL;
|
|
|
|
/* verify no such name in generic params */
|
|
|
|
for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
|
|
|
|
if (!strcmp(param->name, devlink_param_generic[i].name))
|
|
|
|
return -EEXIST;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_param_item *
|
2023-02-10 10:01:29 +00:00
|
|
|
devlink_param_find_by_name(struct xarray *params, const char *param_name)
|
2018-07-04 11:30:28 +00:00
|
|
|
{
|
|
|
|
struct devlink_param_item *param_item;
|
2023-02-10 10:01:29 +00:00
|
|
|
unsigned long param_id;
|
2018-07-04 11:30:28 +00:00
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
xa_for_each(params, param_id, param_item) {
|
2018-07-04 11:30:28 +00:00
|
|
|
if (!strcmp(param_item->param->name, param_name))
|
|
|
|
return param_item;
|
2023-02-10 10:01:29 +00:00
|
|
|
}
|
2018-07-04 11:30:28 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-07-04 11:30:31 +00:00
|
|
|
static struct devlink_param_item *
|
2023-02-10 10:01:29 +00:00
|
|
|
devlink_param_find_by_id(struct xarray *params, u32 param_id)
|
2018-07-04 11:30:31 +00:00
|
|
|
{
|
2023-02-10 10:01:29 +00:00
|
|
|
return xa_load(params, param_id);
|
2018-07-04 11:30:31 +00:00
|
|
|
}
|
|
|
|
|
2018-07-04 11:30:29 +00:00
|
|
|
static bool
|
|
|
|
devlink_param_cmode_is_supported(const struct devlink_param *param,
|
|
|
|
enum devlink_param_cmode cmode)
|
|
|
|
{
|
|
|
|
return test_bit(cmode, ¶m->supported_cmodes);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_param_get(struct devlink *devlink,
|
|
|
|
const struct devlink_param *param,
|
|
|
|
struct devlink_param_gset_ctx *ctx)
|
|
|
|
{
|
2022-08-09 11:35:06 +00:00
|
|
|
if (!param->get || devlink->reload_failed)
|
2018-07-04 11:30:29 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
return param->get(devlink, param->id, ctx);
|
|
|
|
}
|
|
|
|
|
2018-07-04 11:30:30 +00:00
|
|
|
static int devlink_param_set(struct devlink *devlink,
|
|
|
|
const struct devlink_param *param,
|
|
|
|
struct devlink_param_gset_ctx *ctx)
|
|
|
|
{
|
2022-08-09 11:35:06 +00:00
|
|
|
if (!param->set || devlink->reload_failed)
|
2018-07-04 11:30:30 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
return param->set(devlink, param->id, ctx);
|
|
|
|
}
|
|
|
|
|
2018-07-04 11:30:29 +00:00
|
|
|
static int
|
|
|
|
devlink_param_type_to_nla_type(enum devlink_param_type param_type)
|
|
|
|
{
|
|
|
|
switch (param_type) {
|
|
|
|
case DEVLINK_PARAM_TYPE_U8:
|
|
|
|
return NLA_U8;
|
|
|
|
case DEVLINK_PARAM_TYPE_U16:
|
|
|
|
return NLA_U16;
|
|
|
|
case DEVLINK_PARAM_TYPE_U32:
|
|
|
|
return NLA_U32;
|
|
|
|
case DEVLINK_PARAM_TYPE_STRING:
|
|
|
|
return NLA_STRING;
|
|
|
|
case DEVLINK_PARAM_TYPE_BOOL:
|
|
|
|
return NLA_FLAG;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_nl_param_value_fill_one(struct sk_buff *msg,
|
|
|
|
enum devlink_param_type type,
|
|
|
|
enum devlink_param_cmode cmode,
|
|
|
|
union devlink_param_value val)
|
|
|
|
{
|
|
|
|
struct nlattr *param_value_attr;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
param_value_attr = nla_nest_start_noflag(msg,
|
|
|
|
DEVLINK_ATTR_PARAM_VALUE);
|
2018-07-04 11:30:29 +00:00
|
|
|
if (!param_value_attr)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
|
|
|
|
goto value_nest_cancel;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case DEVLINK_PARAM_TYPE_U8:
|
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
|
|
|
|
goto value_nest_cancel;
|
|
|
|
break;
|
|
|
|
case DEVLINK_PARAM_TYPE_U16:
|
|
|
|
if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
|
|
|
|
goto value_nest_cancel;
|
|
|
|
break;
|
|
|
|
case DEVLINK_PARAM_TYPE_U32:
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
|
|
|
|
goto value_nest_cancel;
|
|
|
|
break;
|
|
|
|
case DEVLINK_PARAM_TYPE_STRING:
|
|
|
|
if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
|
|
|
|
val.vstr))
|
|
|
|
goto value_nest_cancel;
|
|
|
|
break;
|
|
|
|
case DEVLINK_PARAM_TYPE_BOOL:
|
|
|
|
if (val.vbool &&
|
|
|
|
nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
|
|
|
|
goto value_nest_cancel;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(msg, param_value_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
value_nest_cancel:
|
|
|
|
nla_nest_cancel(msg, param_value_attr);
|
|
|
|
nla_put_failure:
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
|
2019-01-28 12:30:21 +00:00
|
|
|
unsigned int port_index,
|
2018-07-04 11:30:29 +00:00
|
|
|
struct devlink_param_item *param_item,
|
|
|
|
enum devlink_command cmd,
|
|
|
|
u32 portid, u32 seq, int flags)
|
|
|
|
{
|
|
|
|
union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
|
2019-02-07 11:22:45 +00:00
|
|
|
bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
|
2018-07-04 11:30:29 +00:00
|
|
|
const struct devlink_param *param = param_item->param;
|
|
|
|
struct devlink_param_gset_ctx ctx;
|
|
|
|
struct nlattr *param_values_list;
|
|
|
|
struct nlattr *param_attr;
|
|
|
|
int nla_type;
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Get value from driver part to driverinit configuration mode */
|
|
|
|
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
|
|
|
|
if (!devlink_param_cmode_is_supported(param, i))
|
|
|
|
continue;
|
|
|
|
if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
|
2023-02-10 10:01:26 +00:00
|
|
|
if (param_item->driverinit_value_new_valid)
|
|
|
|
param_value[i] = param_item->driverinit_value_new;
|
|
|
|
else if (param_item->driverinit_value_valid)
|
|
|
|
param_value[i] = param_item->driverinit_value;
|
|
|
|
else
|
2018-07-04 11:30:29 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
} else {
|
|
|
|
ctx.cmode = i;
|
|
|
|
err = devlink_param_get(devlink, param, &ctx);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
param_value[i] = ctx.val;
|
|
|
|
}
|
2019-02-07 11:22:45 +00:00
|
|
|
param_value_set[i] = true;
|
2018-07-04 11:30:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto genlmsg_cancel;
|
2019-01-28 12:30:21 +00:00
|
|
|
|
2019-01-28 12:30:25 +00:00
|
|
|
if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
|
|
|
|
cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
|
|
|
|
cmd == DEVLINK_CMD_PORT_PARAM_DEL)
|
2019-01-28 12:30:21 +00:00
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
|
|
|
|
goto genlmsg_cancel;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
|
2018-07-04 11:30:29 +00:00
|
|
|
if (!param_attr)
|
|
|
|
goto genlmsg_cancel;
|
|
|
|
if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
|
|
|
|
goto param_nest_cancel;
|
|
|
|
if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
|
|
|
|
goto param_nest_cancel;
|
|
|
|
|
|
|
|
nla_type = devlink_param_type_to_nla_type(param->type);
|
|
|
|
if (nla_type < 0)
|
|
|
|
goto param_nest_cancel;
|
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
|
|
|
|
goto param_nest_cancel;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
param_values_list = nla_nest_start_noflag(msg,
|
|
|
|
DEVLINK_ATTR_PARAM_VALUES_LIST);
|
2018-07-04 11:30:29 +00:00
|
|
|
if (!param_values_list)
|
|
|
|
goto param_nest_cancel;
|
|
|
|
|
|
|
|
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
|
2019-02-07 11:22:45 +00:00
|
|
|
if (!param_value_set[i])
|
2018-07-04 11:30:29 +00:00
|
|
|
continue;
|
|
|
|
err = devlink_nl_param_value_fill_one(msg, param->type,
|
|
|
|
i, param_value[i]);
|
|
|
|
if (err)
|
|
|
|
goto values_list_nest_cancel;
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(msg, param_values_list);
|
|
|
|
nla_nest_end(msg, param_attr);
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
values_list_nest_cancel:
|
|
|
|
nla_nest_end(msg, param_values_list);
|
|
|
|
param_nest_cancel:
|
|
|
|
nla_nest_cancel(msg, param_attr);
|
|
|
|
genlmsg_cancel:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2018-07-04 11:30:32 +00:00
|
|
|
static void devlink_param_notify(struct devlink *devlink,
|
2019-01-28 12:30:25 +00:00
|
|
|
unsigned int port_index,
|
2018-07-04 11:30:32 +00:00
|
|
|
struct devlink_param_item *param_item,
|
|
|
|
enum devlink_command cmd)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
2019-01-28 12:30:25 +00:00
|
|
|
WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
|
|
|
|
cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
|
|
|
|
cmd != DEVLINK_CMD_PORT_PARAM_DEL);
|
2023-01-06 06:34:00 +00:00
|
|
|
|
|
|
|
/* devlink_notify_register() / devlink_notify_unregister()
|
|
|
|
* will replay the notifications if the params are added/removed
|
|
|
|
* outside of the lifetime of the instance.
|
|
|
|
*/
|
|
|
|
if (!devl_is_registered(devlink))
|
|
|
|
return;
|
2018-07-04 11:30:32 +00:00
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return;
|
2019-01-28 12:30:25 +00:00
|
|
|
err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
|
|
|
|
0, 0, 0);
|
2018-07-04 11:30:32 +00:00
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
|
|
|
|
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_param_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2018-07-04 11:30:29 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-05 04:05:31 +00:00
|
|
|
struct devlink_param_item *param_item;
|
2023-02-10 10:01:29 +00:00
|
|
|
unsigned long param_id;
|
2019-10-04 09:50:12 +00:00
|
|
|
int err = 0;
|
2018-07-04 11:30:29 +00:00
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
xa_for_each_start(&devlink->params, param_id, param_item, state->idx) {
|
2023-01-05 04:05:31 +00:00
|
|
|
err = devlink_nl_param_fill(msg, devlink, 0, param_item,
|
|
|
|
DEVLINK_CMD_PARAM_GET,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI);
|
|
|
|
if (err == -EOPNOTSUPP) {
|
|
|
|
err = 0;
|
|
|
|
} else if (err) {
|
2023-02-10 10:01:29 +00:00
|
|
|
state->idx = param_id;
|
2023-01-05 04:05:31 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-07-04 11:30:29 +00:00
|
|
|
}
|
2019-10-04 09:50:12 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
return err;
|
2018-07-04 11:30:29 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_param_get = {
|
2023-01-05 04:05:31 +00:00
|
|
|
.dump_one = devlink_nl_cmd_param_get_dump_one,
|
|
|
|
};
|
|
|
|
|
2018-07-04 11:30:30 +00:00
|
|
|
static int
|
|
|
|
devlink_param_type_get_from_info(struct genl_info *info,
|
|
|
|
enum devlink_param_type *param_type)
|
|
|
|
{
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_TYPE))
|
2018-07-04 11:30:30 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
|
|
|
|
case NLA_U8:
|
|
|
|
*param_type = DEVLINK_PARAM_TYPE_U8;
|
|
|
|
break;
|
|
|
|
case NLA_U16:
|
|
|
|
*param_type = DEVLINK_PARAM_TYPE_U16;
|
|
|
|
break;
|
|
|
|
case NLA_U32:
|
|
|
|
*param_type = DEVLINK_PARAM_TYPE_U32;
|
|
|
|
break;
|
|
|
|
case NLA_STRING:
|
|
|
|
*param_type = DEVLINK_PARAM_TYPE_STRING;
|
|
|
|
break;
|
|
|
|
case NLA_FLAG:
|
|
|
|
*param_type = DEVLINK_PARAM_TYPE_BOOL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_param_value_get_from_info(const struct devlink_param *param,
|
|
|
|
struct genl_info *info,
|
|
|
|
union devlink_param_value *value)
|
|
|
|
{
|
2020-03-03 05:05:11 +00:00
|
|
|
struct nlattr *param_data;
|
2018-10-10 13:09:25 +00:00
|
|
|
int len;
|
|
|
|
|
2020-03-03 05:05:11 +00:00
|
|
|
param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
|
|
|
|
|
|
|
|
if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
|
2018-07-04 11:30:30 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
switch (param->type) {
|
|
|
|
case DEVLINK_PARAM_TYPE_U8:
|
2020-03-03 05:05:11 +00:00
|
|
|
if (nla_len(param_data) != sizeof(u8))
|
|
|
|
return -EINVAL;
|
|
|
|
value->vu8 = nla_get_u8(param_data);
|
2018-07-04 11:30:30 +00:00
|
|
|
break;
|
|
|
|
case DEVLINK_PARAM_TYPE_U16:
|
2020-03-03 05:05:11 +00:00
|
|
|
if (nla_len(param_data) != sizeof(u16))
|
|
|
|
return -EINVAL;
|
|
|
|
value->vu16 = nla_get_u16(param_data);
|
2018-07-04 11:30:30 +00:00
|
|
|
break;
|
|
|
|
case DEVLINK_PARAM_TYPE_U32:
|
2020-03-03 05:05:11 +00:00
|
|
|
if (nla_len(param_data) != sizeof(u32))
|
|
|
|
return -EINVAL;
|
|
|
|
value->vu32 = nla_get_u32(param_data);
|
2018-07-04 11:30:30 +00:00
|
|
|
break;
|
|
|
|
case DEVLINK_PARAM_TYPE_STRING:
|
2020-03-03 05:05:11 +00:00
|
|
|
len = strnlen(nla_data(param_data), nla_len(param_data));
|
|
|
|
if (len == nla_len(param_data) ||
|
2018-10-10 13:09:27 +00:00
|
|
|
len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
|
2018-07-04 11:30:30 +00:00
|
|
|
return -EINVAL;
|
2020-03-03 05:05:11 +00:00
|
|
|
strcpy(value->vstr, nla_data(param_data));
|
2018-07-04 11:30:30 +00:00
|
|
|
break;
|
|
|
|
case DEVLINK_PARAM_TYPE_BOOL:
|
2020-03-03 05:05:11 +00:00
|
|
|
if (param_data && nla_len(param_data))
|
|
|
|
return -EINVAL;
|
|
|
|
value->vbool = nla_get_flag(param_data);
|
2018-07-04 11:30:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-04 11:30:29 +00:00
|
|
|
static struct devlink_param_item *
|
2023-02-10 10:01:29 +00:00
|
|
|
devlink_param_get_from_info(struct xarray *params, struct genl_info *info)
|
2018-07-04 11:30:29 +00:00
|
|
|
{
|
|
|
|
char *param_name;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_NAME))
|
2018-07-04 11:30:29 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
|
2023-02-10 10:01:29 +00:00
|
|
|
return devlink_param_find_by_name(params, param_name);
|
2018-07-04 11:30:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_param_item *param_item;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
param_item = devlink_param_get_from_info(&devlink->params, info);
|
2018-07-04 11:30:29 +00:00
|
|
|
if (!param_item)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2019-01-28 12:30:21 +00:00
|
|
|
err = devlink_nl_param_fill(msg, devlink, 0, param_item,
|
2018-07-04 11:30:29 +00:00
|
|
|
DEVLINK_CMD_PARAM_GET,
|
|
|
|
info->snd_portid, info->snd_seq, 0);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
}
|
|
|
|
|
2019-01-28 12:30:22 +00:00
|
|
|
static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
|
2019-01-28 12:30:25 +00:00
|
|
|
unsigned int port_index,
|
2023-02-10 10:01:29 +00:00
|
|
|
struct xarray *params,
|
2019-01-28 12:30:22 +00:00
|
|
|
struct genl_info *info,
|
|
|
|
enum devlink_command cmd)
|
2018-07-04 11:30:30 +00:00
|
|
|
{
|
|
|
|
enum devlink_param_type param_type;
|
|
|
|
struct devlink_param_gset_ctx ctx;
|
|
|
|
enum devlink_param_cmode cmode;
|
|
|
|
struct devlink_param_item *param_item;
|
|
|
|
const struct devlink_param *param;
|
|
|
|
union devlink_param_value value;
|
|
|
|
int err = 0;
|
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
param_item = devlink_param_get_from_info(params, info);
|
2018-07-04 11:30:30 +00:00
|
|
|
if (!param_item)
|
|
|
|
return -EINVAL;
|
|
|
|
param = param_item->param;
|
|
|
|
err = devlink_param_type_get_from_info(info, ¶m_type);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
if (param_type != param->type)
|
|
|
|
return -EINVAL;
|
|
|
|
err = devlink_param_value_get_from_info(param, info, &value);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
if (param->validate) {
|
|
|
|
err = param->validate(devlink, param->id, value, info->extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_VALUE_CMODE))
|
2018-07-04 11:30:30 +00:00
|
|
|
return -EINVAL;
|
|
|
|
cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
|
|
|
|
if (!devlink_param_cmode_is_supported(param, cmode))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
|
2023-02-10 10:01:26 +00:00
|
|
|
param_item->driverinit_value_new = value;
|
|
|
|
param_item->driverinit_value_new_valid = true;
|
2018-07-04 11:30:30 +00:00
|
|
|
} else {
|
|
|
|
if (!param->set)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
ctx.val = value;
|
|
|
|
ctx.cmode = cmode;
|
|
|
|
err = devlink_param_set(devlink, param, &ctx);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-01-28 12:30:25 +00:00
|
|
|
devlink_param_notify(devlink, port_index, param_item, cmd);
|
2018-07-04 11:30:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-28 12:30:22 +00:00
|
|
|
static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->params,
|
2019-01-28 12:30:22 +00:00
|
|
|
info, DEVLINK_CMD_PARAM_NEW);
|
|
|
|
}
|
|
|
|
|
2019-01-28 12:30:21 +00:00
|
|
|
static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
|
|
|
|
struct netlink_callback *cb)
|
|
|
|
{
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(cb->extack, "Port params are not supported");
|
2019-01-28 12:30:21 +00:00
|
|
|
return msg->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Port params are not supported");
|
2022-08-26 08:27:30 +00:00
|
|
|
return -EINVAL;
|
2019-01-28 12:30:21 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 12:30:22 +00:00
|
|
|
static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Port params are not supported");
|
2022-08-26 08:27:30 +00:00
|
|
|
return -EINVAL;
|
2019-01-28 12:30:22 +00:00
|
|
|
}
|
|
|
|
|
2018-07-12 12:13:12 +00:00
|
|
|
static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct devlink_snapshot *snapshot)
|
|
|
|
{
|
|
|
|
struct nlattr *snap_attr;
|
|
|
|
int err;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
|
2018-07-12 12:13:12 +00:00
|
|
|
if (!snap_attr)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(msg, snap_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(msg, snap_attr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct devlink_region *region)
|
|
|
|
{
|
|
|
|
struct devlink_snapshot *snapshot;
|
|
|
|
struct nlattr *snapshots_attr;
|
|
|
|
int err;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
snapshots_attr = nla_nest_start_noflag(msg,
|
|
|
|
DEVLINK_ATTR_REGION_SNAPSHOTS);
|
2018-07-12 12:13:12 +00:00
|
|
|
if (!snapshots_attr)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
list_for_each_entry(snapshot, ®ion->snapshot_list, list) {
|
|
|
|
err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(msg, snapshots_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(msg, snapshots_attr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:13:11 +00:00
|
|
|
static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
enum devlink_command cmd, u32 portid,
|
|
|
|
u32 seq, int flags,
|
|
|
|
struct devlink_region *region)
|
|
|
|
{
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
err = devlink_nl_put_handle(msg, devlink);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2020-10-26 08:00:59 +00:00
|
|
|
if (region->port) {
|
|
|
|
err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
|
|
|
|
region->port->index);
|
|
|
|
if (err)
|
2020-10-04 16:12:54 +00:00
|
|
|
goto nla_put_failure;
|
2020-10-26 08:00:59 +00:00
|
|
|
}
|
2020-10-04 16:12:54 +00:00
|
|
|
|
2020-03-26 18:37:08 +00:00
|
|
|
err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
|
2018-07-12 12:13:11 +00:00
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
|
|
|
|
region->size,
|
|
|
|
DEVLINK_ATTR_PAD);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2021-09-30 21:21:04 +00:00
|
|
|
err = nla_put_u32(msg, DEVLINK_ATTR_REGION_MAX_SNAPSHOTS,
|
|
|
|
region->max_snapshots);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2018-07-12 12:13:12 +00:00
|
|
|
err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2018-07-12 12:13:11 +00:00
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-05-01 16:40:40 +00:00
|
|
|
static struct sk_buff *
|
|
|
|
devlink_nl_region_notify_build(struct devlink_region *region,
|
|
|
|
struct devlink_snapshot *snapshot,
|
|
|
|
enum devlink_command cmd, u32 portid, u32 seq)
|
2018-07-12 12:13:13 +00:00
|
|
|
{
|
|
|
|
struct devlink *devlink = region->devlink;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
2020-05-01 16:40:40 +00:00
|
|
|
return ERR_PTR(-ENOMEM);
|
2018-07-12 12:13:13 +00:00
|
|
|
|
2020-05-01 16:40:40 +00:00
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
|
|
|
|
if (!hdr) {
|
|
|
|
err = -EMSGSIZE;
|
2018-07-12 12:13:13 +00:00
|
|
|
goto out_free_msg;
|
2020-05-01 16:40:40 +00:00
|
|
|
}
|
2018-07-12 12:13:13 +00:00
|
|
|
|
|
|
|
err = devlink_nl_put_handle(msg, devlink);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel_msg;
|
|
|
|
|
2020-10-26 08:00:59 +00:00
|
|
|
if (region->port) {
|
|
|
|
err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
|
|
|
|
region->port->index);
|
|
|
|
if (err)
|
2020-10-04 16:12:54 +00:00
|
|
|
goto out_cancel_msg;
|
2020-10-26 08:00:59 +00:00
|
|
|
}
|
2020-10-04 16:12:54 +00:00
|
|
|
|
2018-07-12 12:13:13 +00:00
|
|
|
err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
|
2020-03-26 18:37:08 +00:00
|
|
|
region->ops->name);
|
2018-07-12 12:13:13 +00:00
|
|
|
if (err)
|
|
|
|
goto out_cancel_msg;
|
|
|
|
|
|
|
|
if (snapshot) {
|
|
|
|
err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
|
|
|
|
snapshot->id);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel_msg;
|
|
|
|
} else {
|
|
|
|
err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
|
|
|
|
region->size, DEVLINK_ATTR_PAD);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel_msg;
|
|
|
|
}
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
2020-05-01 16:40:40 +00:00
|
|
|
return msg;
|
2018-07-12 12:13:13 +00:00
|
|
|
|
|
|
|
out_cancel_msg:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
out_free_msg:
|
|
|
|
nlmsg_free(msg);
|
2020-05-01 16:40:40 +00:00
|
|
|
return ERR_PTR(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_nl_region_notify(struct devlink_region *region,
|
|
|
|
struct devlink_snapshot *snapshot,
|
|
|
|
enum devlink_command cmd)
|
|
|
|
{
|
2021-09-25 11:22:41 +00:00
|
|
|
struct devlink *devlink = region->devlink;
|
2020-05-01 16:40:40 +00:00
|
|
|
struct sk_buff *msg;
|
|
|
|
|
|
|
|
WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
|
2021-09-29 14:18:20 +00:00
|
|
|
if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
|
|
|
|
return;
|
2020-05-01 16:40:40 +00:00
|
|
|
|
|
|
|
msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
|
|
|
|
if (IS_ERR(msg))
|
|
|
|
return;
|
|
|
|
|
2021-09-25 11:22:41 +00:00
|
|
|
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), msg,
|
|
|
|
0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
2018-07-12 12:13:13 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 18:37:15 +00:00
|
|
|
/**
|
|
|
|
* __devlink_snapshot_id_increment - Increment number of snapshots using an id
|
|
|
|
* @devlink: devlink instance
|
|
|
|
* @id: the snapshot id
|
|
|
|
*
|
|
|
|
* Track when a new snapshot begins using an id. Load the count for the
|
|
|
|
* given id from the snapshot xarray, increment it, and store it back.
|
|
|
|
*
|
|
|
|
* Called when a new snapshot is created with the given id.
|
|
|
|
*
|
|
|
|
* The id *must* have been previously allocated by
|
|
|
|
* devlink_region_snapshot_id_get().
|
|
|
|
*
|
|
|
|
* Returns 0 on success, or an error on failure.
|
|
|
|
*/
|
|
|
|
static int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
|
|
|
|
{
|
|
|
|
unsigned long count;
|
|
|
|
void *p;
|
2022-07-28 15:53:42 +00:00
|
|
|
int err;
|
2020-03-26 18:37:15 +00:00
|
|
|
|
2022-07-28 15:53:42 +00:00
|
|
|
xa_lock(&devlink->snapshot_ids);
|
2020-03-26 18:37:15 +00:00
|
|
|
p = xa_load(&devlink->snapshot_ids, id);
|
2022-07-28 15:53:42 +00:00
|
|
|
if (WARN_ON(!p)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto unlock;
|
|
|
|
}
|
2020-03-26 18:37:15 +00:00
|
|
|
|
2022-07-28 15:53:42 +00:00
|
|
|
if (WARN_ON(!xa_is_value(p))) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto unlock;
|
|
|
|
}
|
2020-03-26 18:37:15 +00:00
|
|
|
|
|
|
|
count = xa_to_value(p);
|
|
|
|
count++;
|
|
|
|
|
2022-07-28 15:53:42 +00:00
|
|
|
err = xa_err(__xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
|
|
|
|
GFP_ATOMIC));
|
|
|
|
unlock:
|
|
|
|
xa_unlock(&devlink->snapshot_ids);
|
|
|
|
return err;
|
2020-03-26 18:37:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
|
|
|
|
* @devlink: devlink instance
|
|
|
|
* @id: the snapshot id
|
|
|
|
*
|
|
|
|
* Track when a snapshot is deleted and stops using an id. Load the count
|
|
|
|
* for the given id from the snapshot xarray, decrement it, and store it
|
|
|
|
* back.
|
|
|
|
*
|
|
|
|
* If the count reaches zero, erase this id from the xarray, freeing it
|
|
|
|
* up for future re-use by devlink_region_snapshot_id_get().
|
|
|
|
*
|
|
|
|
* Called when a snapshot using the given id is deleted, and when the
|
|
|
|
* initial allocator of the id is finished using it.
|
|
|
|
*/
|
|
|
|
static void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
|
|
|
|
{
|
|
|
|
unsigned long count;
|
|
|
|
void *p;
|
|
|
|
|
2022-07-28 15:53:42 +00:00
|
|
|
xa_lock(&devlink->snapshot_ids);
|
2020-03-26 18:37:15 +00:00
|
|
|
p = xa_load(&devlink->snapshot_ids, id);
|
|
|
|
if (WARN_ON(!p))
|
2022-07-28 15:53:42 +00:00
|
|
|
goto unlock;
|
2020-03-26 18:37:15 +00:00
|
|
|
|
|
|
|
if (WARN_ON(!xa_is_value(p)))
|
2022-07-28 15:53:42 +00:00
|
|
|
goto unlock;
|
2020-03-26 18:37:15 +00:00
|
|
|
|
|
|
|
count = xa_to_value(p);
|
|
|
|
|
|
|
|
if (count > 1) {
|
|
|
|
count--;
|
2022-07-28 15:53:42 +00:00
|
|
|
__xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
|
|
|
|
GFP_ATOMIC);
|
2020-03-26 18:37:15 +00:00
|
|
|
} else {
|
|
|
|
/* If this was the last user, we can erase this id */
|
2022-07-28 15:53:42 +00:00
|
|
|
__xa_erase(&devlink->snapshot_ids, id);
|
2020-03-26 18:37:15 +00:00
|
|
|
}
|
2022-07-28 15:53:42 +00:00
|
|
|
unlock:
|
|
|
|
xa_unlock(&devlink->snapshot_ids);
|
2020-03-26 18:37:15 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 18:37:16 +00:00
|
|
|
/**
|
|
|
|
* __devlink_snapshot_id_insert - Insert a specific snapshot ID
|
|
|
|
* @devlink: devlink instance
|
|
|
|
* @id: the snapshot id
|
|
|
|
*
|
|
|
|
* Mark the given snapshot id as used by inserting a zero value into the
|
|
|
|
* snapshot xarray.
|
|
|
|
*
|
|
|
|
* This must be called while holding the devlink instance lock. Unlike
|
|
|
|
* devlink_snapshot_id_get, the initial reference count is zero, not one.
|
|
|
|
* It is expected that the id will immediately be used before
|
|
|
|
* releasing the devlink instance lock.
|
|
|
|
*
|
|
|
|
* Returns zero on success, or an error code if the snapshot id could not
|
|
|
|
* be inserted.
|
|
|
|
*/
|
|
|
|
static int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
|
|
|
|
{
|
2022-07-28 15:53:42 +00:00
|
|
|
int err;
|
2020-03-26 18:37:16 +00:00
|
|
|
|
2022-07-28 15:53:42 +00:00
|
|
|
xa_lock(&devlink->snapshot_ids);
|
|
|
|
if (xa_load(&devlink->snapshot_ids, id)) {
|
|
|
|
xa_unlock(&devlink->snapshot_ids);
|
2020-03-26 18:37:16 +00:00
|
|
|
return -EEXIST;
|
2022-07-28 15:53:42 +00:00
|
|
|
}
|
|
|
|
err = xa_err(__xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
|
|
|
|
GFP_ATOMIC));
|
|
|
|
xa_unlock(&devlink->snapshot_ids);
|
|
|
|
return err;
|
2020-03-26 18:37:16 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 18:37:13 +00:00
|
|
|
/**
|
|
|
|
* __devlink_region_snapshot_id_get - get snapshot ID
|
|
|
|
* @devlink: devlink instance
|
2020-03-26 18:37:14 +00:00
|
|
|
* @id: storage to return snapshot id
|
2020-03-26 18:37:13 +00:00
|
|
|
*
|
2020-03-26 18:37:14 +00:00
|
|
|
* Allocates a new snapshot id. Returns zero on success, or a negative
|
|
|
|
* error on failure. Must be called while holding the devlink instance
|
|
|
|
* lock.
|
2020-03-26 18:37:15 +00:00
|
|
|
*
|
|
|
|
* Snapshot IDs are tracked using an xarray which stores the number of
|
|
|
|
* users of the snapshot id.
|
|
|
|
*
|
|
|
|
* Note that the caller of this function counts as a 'user', in order to
|
|
|
|
* avoid race conditions. The caller must release its hold on the
|
|
|
|
* snapshot by using devlink_region_snapshot_id_put.
|
2020-03-26 18:37:13 +00:00
|
|
|
*/
|
2020-03-26 18:37:14 +00:00
|
|
|
static int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
|
2020-03-26 18:37:13 +00:00
|
|
|
{
|
2020-03-26 18:37:15 +00:00
|
|
|
return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
|
|
|
|
xa_limit_32b, GFP_KERNEL);
|
2020-03-26 18:37:13 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 18:37:11 +00:00
|
|
|
/**
|
|
|
|
* __devlink_region_snapshot_create - create a new snapshot
|
|
|
|
* This will add a new snapshot of a region. The snapshot
|
|
|
|
* will be stored on the region struct and can be accessed
|
|
|
|
* from devlink. This is useful for future analyses of snapshots.
|
|
|
|
* Multiple snapshots can be created on a region.
|
|
|
|
* The @snapshot_id should be obtained using the getter function.
|
|
|
|
*
|
2022-07-28 15:53:43 +00:00
|
|
|
* Must be called only while holding the region snapshot lock.
|
2020-03-26 18:37:11 +00:00
|
|
|
*
|
|
|
|
* @region: devlink region of the snapshot
|
|
|
|
* @data: snapshot data
|
|
|
|
* @snapshot_id: snapshot id to be created
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
__devlink_region_snapshot_create(struct devlink_region *region,
|
|
|
|
u8 *data, u32 snapshot_id)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = region->devlink;
|
|
|
|
struct devlink_snapshot *snapshot;
|
2020-03-26 18:37:15 +00:00
|
|
|
int err;
|
2020-03-26 18:37:11 +00:00
|
|
|
|
2022-07-28 15:53:43 +00:00
|
|
|
lockdep_assert_held(®ion->snapshot_lock);
|
2020-03-26 18:37:11 +00:00
|
|
|
|
|
|
|
/* check if region can hold one more snapshot */
|
|
|
|
if (region->cur_snapshots == region->max_snapshots)
|
2020-03-26 18:37:12 +00:00
|
|
|
return -ENOSPC;
|
2020-03-26 18:37:11 +00:00
|
|
|
|
|
|
|
if (devlink_region_snapshot_get_by_id(region, snapshot_id))
|
|
|
|
return -EEXIST;
|
|
|
|
|
|
|
|
snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
|
|
|
|
if (!snapshot)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2020-03-26 18:37:15 +00:00
|
|
|
err = __devlink_snapshot_id_increment(devlink, snapshot_id);
|
|
|
|
if (err)
|
|
|
|
goto err_snapshot_id_increment;
|
|
|
|
|
2020-03-26 18:37:11 +00:00
|
|
|
snapshot->id = snapshot_id;
|
|
|
|
snapshot->region = region;
|
|
|
|
snapshot->data = data;
|
|
|
|
|
|
|
|
list_add_tail(&snapshot->list, ®ion->snapshot_list);
|
|
|
|
|
|
|
|
region->cur_snapshots++;
|
|
|
|
|
|
|
|
devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
|
|
|
|
return 0;
|
2020-03-26 18:37:15 +00:00
|
|
|
|
|
|
|
err_snapshot_id_increment:
|
|
|
|
kfree(snapshot);
|
|
|
|
return err;
|
2020-03-26 18:37:11 +00:00
|
|
|
}
|
|
|
|
|
2019-08-12 12:28:31 +00:00
|
|
|
static void devlink_region_snapshot_del(struct devlink_region *region,
|
|
|
|
struct devlink_snapshot *snapshot)
|
|
|
|
{
|
2020-03-26 18:37:15 +00:00
|
|
|
struct devlink *devlink = region->devlink;
|
|
|
|
|
2022-07-28 15:53:43 +00:00
|
|
|
lockdep_assert_held(®ion->snapshot_lock);
|
2020-03-26 18:37:15 +00:00
|
|
|
|
2019-08-12 12:28:31 +00:00
|
|
|
devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
|
|
|
|
region->cur_snapshots--;
|
|
|
|
list_del(&snapshot->list);
|
2020-03-26 18:37:09 +00:00
|
|
|
region->ops->destructor(snapshot->data);
|
2020-03-26 18:37:15 +00:00
|
|
|
__devlink_snapshot_id_decrement(devlink, snapshot->id);
|
2019-08-12 12:28:31 +00:00
|
|
|
kfree(snapshot);
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:13:11 +00:00
|
|
|
static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
2020-10-04 16:12:54 +00:00
|
|
|
struct devlink_port *port = NULL;
|
2018-07-12 12:13:11 +00:00
|
|
|
struct devlink_region *region;
|
|
|
|
const char *region_name;
|
|
|
|
struct sk_buff *msg;
|
2020-10-04 16:12:54 +00:00
|
|
|
unsigned int index;
|
2018-07-12 12:13:11 +00:00
|
|
|
int err;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_NAME))
|
2018-07-12 12:13:11 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2020-10-04 16:12:54 +00:00
|
|
|
if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
|
|
|
|
index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
|
|
|
|
|
|
|
|
port = devlink_port_get_by_index(devlink, index);
|
|
|
|
if (!port)
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:13:11 +00:00
|
|
|
region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
|
2020-10-04 16:12:54 +00:00
|
|
|
if (port)
|
|
|
|
region = devlink_port_region_get_by_name(port, region_name);
|
|
|
|
else
|
|
|
|
region = devlink_region_get_by_name(devlink, region_name);
|
|
|
|
|
2018-07-12 12:13:11 +00:00
|
|
|
if (!region)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
|
|
|
|
info->snd_portid, info->snd_seq, 0,
|
|
|
|
region);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
}
|
|
|
|
|
2020-10-04 16:12:54 +00:00
|
|
|
static int devlink_nl_cmd_region_get_port_dumpit(struct sk_buff *msg,
|
|
|
|
struct netlink_callback *cb,
|
|
|
|
struct devlink_port *port,
|
|
|
|
int *idx,
|
|
|
|
int start)
|
|
|
|
{
|
|
|
|
struct devlink_region *region;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
list_for_each_entry(region, &port->region_list, list) {
|
|
|
|
if (*idx < start) {
|
|
|
|
(*idx)++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
err = devlink_nl_region_fill(msg, port->devlink,
|
|
|
|
DEVLINK_CMD_REGION_GET,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI, region);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
(*idx)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_region_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2020-10-04 16:12:54 +00:00
|
|
|
{
|
2023-01-05 04:05:31 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2020-10-04 16:12:54 +00:00
|
|
|
struct devlink_region *region;
|
|
|
|
struct devlink_port *port;
|
2022-11-30 08:52:50 +00:00
|
|
|
unsigned long port_index;
|
2023-01-05 04:05:31 +00:00
|
|
|
int idx = 0;
|
2023-01-05 04:05:29 +00:00
|
|
|
int err;
|
2020-10-04 16:12:54 +00:00
|
|
|
|
|
|
|
list_for_each_entry(region, &devlink->region_list, list) {
|
2023-01-05 04:05:31 +00:00
|
|
|
if (idx < state->idx) {
|
|
|
|
idx++;
|
2020-10-04 16:12:54 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
err = devlink_nl_region_fill(msg, devlink,
|
|
|
|
DEVLINK_CMD_REGION_GET,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI, region);
|
2023-01-05 04:05:31 +00:00
|
|
|
if (err) {
|
|
|
|
state->idx = idx;
|
2023-01-05 04:05:29 +00:00
|
|
|
return err;
|
2023-01-05 04:05:31 +00:00
|
|
|
}
|
|
|
|
idx++;
|
2020-10-04 16:12:54 +00:00
|
|
|
}
|
|
|
|
|
2022-11-30 08:52:50 +00:00
|
|
|
xa_for_each(&devlink->ports, port_index, port) {
|
2023-01-05 04:05:31 +00:00
|
|
|
err = devlink_nl_cmd_region_get_port_dumpit(msg, cb, port, &idx,
|
|
|
|
state->idx);
|
|
|
|
if (err) {
|
|
|
|
state->idx = idx;
|
2023-01-05 04:05:29 +00:00
|
|
|
return err;
|
2023-01-05 04:05:31 +00:00
|
|
|
}
|
2020-10-04 16:12:54 +00:00
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:29 +00:00
|
|
|
return 0;
|
2020-10-04 16:12:54 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_region_get = {
|
2023-01-05 04:05:31 +00:00
|
|
|
.dump_one = devlink_nl_cmd_region_get_dump_one,
|
|
|
|
};
|
2018-07-12 12:13:11 +00:00
|
|
|
|
2018-07-12 12:13:13 +00:00
|
|
|
static int devlink_nl_cmd_region_del(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_snapshot *snapshot;
|
2020-10-04 16:12:54 +00:00
|
|
|
struct devlink_port *port = NULL;
|
2018-07-12 12:13:13 +00:00
|
|
|
struct devlink_region *region;
|
|
|
|
const char *region_name;
|
2020-10-04 16:12:54 +00:00
|
|
|
unsigned int index;
|
2018-07-12 12:13:13 +00:00
|
|
|
u32 snapshot_id;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_NAME) ||
|
|
|
|
GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_SNAPSHOT_ID))
|
2018-07-12 12:13:13 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
|
|
|
|
snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
|
|
|
|
|
2020-10-04 16:12:54 +00:00
|
|
|
if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
|
|
|
|
index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
|
|
|
|
|
|
|
|
port = devlink_port_get_by_index(devlink, index);
|
|
|
|
if (!port)
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (port)
|
|
|
|
region = devlink_port_region_get_by_name(port, region_name);
|
|
|
|
else
|
|
|
|
region = devlink_region_get_by_name(devlink, region_name);
|
|
|
|
|
2018-07-12 12:13:13 +00:00
|
|
|
if (!region)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2022-07-28 15:53:43 +00:00
|
|
|
mutex_lock(®ion->snapshot_lock);
|
2018-07-12 12:13:13 +00:00
|
|
|
snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
|
2022-07-28 15:53:43 +00:00
|
|
|
if (!snapshot) {
|
|
|
|
mutex_unlock(®ion->snapshot_lock);
|
2018-07-12 12:13:13 +00:00
|
|
|
return -EINVAL;
|
2022-07-28 15:53:43 +00:00
|
|
|
}
|
2018-07-12 12:13:13 +00:00
|
|
|
|
2019-08-12 12:28:31 +00:00
|
|
|
devlink_region_snapshot_del(region, snapshot);
|
2022-07-28 15:53:43 +00:00
|
|
|
mutex_unlock(®ion->snapshot_lock);
|
2018-07-12 12:13:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-26 18:37:16 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
2020-05-01 16:40:41 +00:00
|
|
|
struct devlink_snapshot *snapshot;
|
2020-10-04 16:12:54 +00:00
|
|
|
struct devlink_port *port = NULL;
|
2020-05-01 16:40:41 +00:00
|
|
|
struct nlattr *snapshot_id_attr;
|
2020-03-26 18:37:16 +00:00
|
|
|
struct devlink_region *region;
|
|
|
|
const char *region_name;
|
2020-10-04 16:12:54 +00:00
|
|
|
unsigned int index;
|
2020-03-26 18:37:16 +00:00
|
|
|
u32 snapshot_id;
|
|
|
|
u8 *data;
|
|
|
|
int err;
|
|
|
|
|
2022-08-26 03:09:33 +00:00
|
|
|
if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_NAME)) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "No region name provided");
|
2020-03-26 18:37:16 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
|
2020-10-04 16:12:54 +00:00
|
|
|
|
|
|
|
if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
|
|
|
|
index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
|
|
|
|
|
|
|
|
port = devlink_port_get_by_index(devlink, index);
|
|
|
|
if (!port)
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (port)
|
|
|
|
region = devlink_port_region_get_by_name(port, region_name);
|
|
|
|
else
|
|
|
|
region = devlink_region_get_by_name(devlink, region_name);
|
|
|
|
|
2020-03-26 18:37:16 +00:00
|
|
|
if (!region) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "The requested region does not exist");
|
2020-03-26 18:37:16 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!region->ops->snapshot) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "The requested region does not support taking an immediate snapshot");
|
2020-03-26 18:37:16 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2022-07-28 15:53:43 +00:00
|
|
|
mutex_lock(®ion->snapshot_lock);
|
|
|
|
|
2020-03-26 18:37:16 +00:00
|
|
|
if (region->cur_snapshots == region->max_snapshots) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "The region has reached the maximum number of stored snapshots");
|
2022-07-28 15:53:43 +00:00
|
|
|
err = -ENOSPC;
|
|
|
|
goto unlock;
|
2020-03-26 18:37:16 +00:00
|
|
|
}
|
|
|
|
|
2020-05-01 16:40:41 +00:00
|
|
|
snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
|
|
|
|
if (snapshot_id_attr) {
|
|
|
|
snapshot_id = nla_get_u32(snapshot_id_attr);
|
2020-03-26 18:37:16 +00:00
|
|
|
|
2020-05-01 16:40:41 +00:00
|
|
|
if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "The requested snapshot id is already in use");
|
2022-07-28 15:53:43 +00:00
|
|
|
err = -EEXIST;
|
|
|
|
goto unlock;
|
2020-05-01 16:40:41 +00:00
|
|
|
}
|
2020-03-26 18:37:16 +00:00
|
|
|
|
2020-05-01 16:40:41 +00:00
|
|
|
err = __devlink_snapshot_id_insert(devlink, snapshot_id);
|
|
|
|
if (err)
|
2022-07-28 15:53:43 +00:00
|
|
|
goto unlock;
|
2020-05-01 16:40:41 +00:00
|
|
|
} else {
|
|
|
|
err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
|
|
|
|
if (err) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Failed to allocate a new snapshot id");
|
2022-07-28 15:53:43 +00:00
|
|
|
goto unlock;
|
2020-05-01 16:40:41 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-26 18:37:16 +00:00
|
|
|
|
2020-10-04 16:12:54 +00:00
|
|
|
if (port)
|
|
|
|
err = region->port_ops->snapshot(port, region->port_ops,
|
|
|
|
info->extack, &data);
|
|
|
|
else
|
|
|
|
err = region->ops->snapshot(devlink, region->ops,
|
|
|
|
info->extack, &data);
|
2020-03-26 18:37:16 +00:00
|
|
|
if (err)
|
|
|
|
goto err_snapshot_capture;
|
|
|
|
|
|
|
|
err = __devlink_region_snapshot_create(region, data, snapshot_id);
|
|
|
|
if (err)
|
|
|
|
goto err_snapshot_create;
|
|
|
|
|
2020-05-01 16:40:41 +00:00
|
|
|
if (!snapshot_id_attr) {
|
|
|
|
struct sk_buff *msg;
|
|
|
|
|
|
|
|
snapshot = devlink_region_snapshot_get_by_id(region,
|
|
|
|
snapshot_id);
|
2022-08-01 11:59:56 +00:00
|
|
|
if (WARN_ON(!snapshot)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto unlock;
|
|
|
|
}
|
2020-05-01 16:40:41 +00:00
|
|
|
|
|
|
|
msg = devlink_nl_region_notify_build(region, snapshot,
|
|
|
|
DEVLINK_CMD_REGION_NEW,
|
|
|
|
info->snd_portid,
|
|
|
|
info->snd_seq);
|
|
|
|
err = PTR_ERR_OR_ZERO(msg);
|
|
|
|
if (err)
|
|
|
|
goto err_notify;
|
|
|
|
|
|
|
|
err = genlmsg_reply(msg, info);
|
|
|
|
if (err)
|
|
|
|
goto err_notify;
|
|
|
|
}
|
|
|
|
|
2022-07-28 15:53:43 +00:00
|
|
|
mutex_unlock(®ion->snapshot_lock);
|
2020-03-26 18:37:16 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_snapshot_create:
|
|
|
|
region->ops->destructor(data);
|
|
|
|
err_snapshot_capture:
|
|
|
|
__devlink_snapshot_id_decrement(devlink, snapshot_id);
|
2022-07-28 15:53:43 +00:00
|
|
|
mutex_unlock(®ion->snapshot_lock);
|
2020-03-26 18:37:16 +00:00
|
|
|
return err;
|
2020-05-01 16:40:41 +00:00
|
|
|
|
|
|
|
err_notify:
|
|
|
|
devlink_region_snapshot_del(region, snapshot);
|
2022-07-28 15:53:43 +00:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(®ion->snapshot_lock);
|
2020-05-01 16:40:41 +00:00
|
|
|
return err;
|
2020-03-26 18:37:16 +00:00
|
|
|
}
|
|
|
|
|
2018-07-12 12:13:14 +00:00
|
|
|
static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
|
|
|
|
u8 *chunk, u32 chunk_size,
|
|
|
|
u64 addr)
|
|
|
|
{
|
|
|
|
struct nlattr *chunk_attr;
|
|
|
|
int err;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
|
2018-07-12 12:13:14 +00:00
|
|
|
if (!chunk_attr)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
|
|
|
|
DEVLINK_ATTR_PAD);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(msg, chunk_attr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(msg, chunk_attr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DEVLINK_REGION_READ_CHUNK_SIZE 256
|
|
|
|
|
2022-11-28 20:36:43 +00:00
|
|
|
typedef int devlink_chunk_fill_t(void *cb_priv, u8 *chunk, u32 chunk_size,
|
|
|
|
u64 curr_offset,
|
|
|
|
struct netlink_ext_ack *extack);
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_nl_region_read_fill(struct sk_buff *skb, devlink_chunk_fill_t *cb,
|
|
|
|
void *cb_priv, u64 start_offset, u64 end_offset,
|
|
|
|
u64 *new_offset, struct netlink_ext_ack *extack)
|
2018-07-12 12:13:14 +00:00
|
|
|
{
|
|
|
|
u64 curr_offset = start_offset;
|
|
|
|
int err = 0;
|
2022-11-28 20:36:43 +00:00
|
|
|
u8 *data;
|
|
|
|
|
|
|
|
/* Allocate and re-use a single buffer */
|
|
|
|
data = kmalloc(DEVLINK_REGION_READ_CHUNK_SIZE, GFP_KERNEL);
|
|
|
|
if (!data)
|
|
|
|
return -ENOMEM;
|
2018-07-12 12:13:14 +00:00
|
|
|
|
|
|
|
*new_offset = start_offset;
|
|
|
|
|
|
|
|
while (curr_offset < end_offset) {
|
|
|
|
u32 data_size;
|
|
|
|
|
2022-11-28 20:36:39 +00:00
|
|
|
data_size = min_t(u32, end_offset - curr_offset,
|
|
|
|
DEVLINK_REGION_READ_CHUNK_SIZE);
|
2018-07-12 12:13:14 +00:00
|
|
|
|
2022-11-28 20:36:43 +00:00
|
|
|
err = cb(cb_priv, data, data_size, curr_offset, extack);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
|
2022-11-28 20:36:42 +00:00
|
|
|
err = devlink_nl_cmd_region_read_chunk_fill(skb, data, data_size, curr_offset);
|
2018-07-12 12:13:14 +00:00
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
|
|
|
|
curr_offset += data_size;
|
|
|
|
}
|
|
|
|
*new_offset = curr_offset;
|
|
|
|
|
2022-11-28 20:36:43 +00:00
|
|
|
kfree(data);
|
|
|
|
|
2018-07-12 12:13:14 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-11-28 20:36:43 +00:00
|
|
|
static int
|
|
|
|
devlink_region_snapshot_fill(void *cb_priv, u8 *chunk, u32 chunk_size,
|
|
|
|
u64 curr_offset,
|
|
|
|
struct netlink_ext_ack __always_unused *extack)
|
|
|
|
{
|
|
|
|
struct devlink_snapshot *snapshot = cb_priv;
|
|
|
|
|
|
|
|
memcpy(chunk, &snapshot->data[curr_offset], chunk_size);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-11-28 20:36:44 +00:00
|
|
|
static int
|
|
|
|
devlink_region_port_direct_fill(void *cb_priv, u8 *chunk, u32 chunk_size,
|
|
|
|
u64 curr_offset, struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
struct devlink_region *region = cb_priv;
|
|
|
|
|
|
|
|
return region->port_ops->read(region->port, region->port_ops, extack,
|
|
|
|
curr_offset, chunk_size, chunk);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_region_direct_fill(void *cb_priv, u8 *chunk, u32 chunk_size,
|
|
|
|
u64 curr_offset, struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
struct devlink_region *region = cb_priv;
|
|
|
|
|
|
|
|
return region->ops->read(region->devlink, region->ops, extack,
|
|
|
|
curr_offset, chunk_size, chunk);
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:13:14 +00:00
|
|
|
static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
|
|
|
|
struct netlink_callback *cb)
|
|
|
|
{
|
2019-10-05 18:04:42 +00:00
|
|
|
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2022-11-28 20:36:41 +00:00
|
|
|
struct nlattr *chunks_attr, *region_attr, *snapshot_attr;
|
2020-05-13 17:28:22 +00:00
|
|
|
u64 ret_offset, start_offset, end_offset = U64_MAX;
|
2019-10-05 18:04:42 +00:00
|
|
|
struct nlattr **attrs = info->attrs;
|
2020-10-04 16:12:54 +00:00
|
|
|
struct devlink_port *port = NULL;
|
2022-11-28 20:36:44 +00:00
|
|
|
devlink_chunk_fill_t *region_cb;
|
2018-07-12 12:13:14 +00:00
|
|
|
struct devlink_region *region;
|
|
|
|
const char *region_name;
|
|
|
|
struct devlink *devlink;
|
2020-10-04 16:12:54 +00:00
|
|
|
unsigned int index;
|
2022-11-28 20:36:44 +00:00
|
|
|
void *region_cb_priv;
|
2018-07-12 12:13:14 +00:00
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
2023-01-05 04:05:22 +00:00
|
|
|
start_offset = state->start_offset;
|
2018-07-12 12:13:14 +00:00
|
|
|
|
2023-01-06 06:33:56 +00:00
|
|
|
devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs);
|
2022-07-29 07:10:37 +00:00
|
|
|
if (IS_ERR(devlink))
|
|
|
|
return PTR_ERR(devlink);
|
2018-07-12 12:13:14 +00:00
|
|
|
|
2022-11-28 20:36:40 +00:00
|
|
|
if (!attrs[DEVLINK_ATTR_REGION_NAME]) {
|
|
|
|
NL_SET_ERR_MSG(cb->extack, "No region name provided");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
2020-10-04 16:12:54 +00:00
|
|
|
if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
|
|
|
|
index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
|
|
|
|
|
|
|
|
port = devlink_port_get_by_index(devlink, index);
|
2020-10-26 08:01:27 +00:00
|
|
|
if (!port) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
2020-10-04 16:12:54 +00:00
|
|
|
}
|
|
|
|
|
2022-11-28 20:36:40 +00:00
|
|
|
region_attr = attrs[DEVLINK_ATTR_REGION_NAME];
|
|
|
|
region_name = nla_data(region_attr);
|
2020-10-04 16:12:54 +00:00
|
|
|
|
|
|
|
if (port)
|
|
|
|
region = devlink_port_region_get_by_name(port, region_name);
|
|
|
|
else
|
|
|
|
region = devlink_region_get_by_name(devlink, region_name);
|
|
|
|
|
2019-02-12 20:23:58 +00:00
|
|
|
if (!region) {
|
2022-11-28 20:36:40 +00:00
|
|
|
NL_SET_ERR_MSG_ATTR(cb->extack, region_attr, "Requested region does not exist");
|
2019-02-12 20:23:58 +00:00
|
|
|
err = -EINVAL;
|
2018-07-12 12:13:14 +00:00
|
|
|
goto out_unlock;
|
2019-02-12 20:23:58 +00:00
|
|
|
}
|
2018-07-12 12:13:14 +00:00
|
|
|
|
2022-11-28 20:36:41 +00:00
|
|
|
snapshot_attr = attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
|
2022-11-28 20:36:44 +00:00
|
|
|
if (!snapshot_attr) {
|
|
|
|
if (!nla_get_flag(attrs[DEVLINK_ATTR_REGION_DIRECT])) {
|
|
|
|
NL_SET_ERR_MSG(cb->extack, "No snapshot id provided");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!region->ops->read) {
|
|
|
|
NL_SET_ERR_MSG(cb->extack, "Requested region does not support direct read");
|
|
|
|
err = -EOPNOTSUPP;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (port)
|
|
|
|
region_cb = &devlink_region_port_direct_fill;
|
|
|
|
else
|
|
|
|
region_cb = &devlink_region_direct_fill;
|
|
|
|
region_cb_priv = region;
|
|
|
|
} else {
|
|
|
|
struct devlink_snapshot *snapshot;
|
|
|
|
u32 snapshot_id;
|
|
|
|
|
|
|
|
if (nla_get_flag(attrs[DEVLINK_ATTR_REGION_DIRECT])) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(cb->extack, snapshot_attr, "Direct region read does not use snapshot");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
snapshot_id = nla_get_u32(snapshot_attr);
|
|
|
|
snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
|
|
|
|
if (!snapshot) {
|
|
|
|
NL_SET_ERR_MSG_ATTR(cb->extack, snapshot_attr, "Requested snapshot does not exist");
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
region_cb = &devlink_region_snapshot_fill;
|
|
|
|
region_cb_priv = snapshot;
|
2022-11-28 20:36:41 +00:00
|
|
|
}
|
|
|
|
|
2020-05-13 17:28:22 +00:00
|
|
|
if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
|
|
|
|
attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
|
|
|
|
if (!start_offset)
|
|
|
|
start_offset =
|
|
|
|
nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
|
|
|
|
|
|
|
|
end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
|
|
|
|
end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (end_offset > region->size)
|
|
|
|
end_offset = region->size;
|
|
|
|
|
2020-02-04 23:59:50 +00:00
|
|
|
/* return 0 if there is no further data to read */
|
2020-05-13 17:28:22 +00:00
|
|
|
if (start_offset == end_offset) {
|
2020-02-04 23:59:50 +00:00
|
|
|
err = 0;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:13:14 +00:00
|
|
|
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
|
|
|
&devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
|
|
|
|
DEVLINK_CMD_REGION_READ);
|
2019-02-12 20:23:58 +00:00
|
|
|
if (!hdr) {
|
|
|
|
err = -EMSGSIZE;
|
2018-07-12 12:13:14 +00:00
|
|
|
goto out_unlock;
|
2019-02-12 20:23:58 +00:00
|
|
|
}
|
2018-07-12 12:13:14 +00:00
|
|
|
|
|
|
|
err = devlink_nl_put_handle(skb, devlink);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2020-10-26 08:00:59 +00:00
|
|
|
if (region->port) {
|
|
|
|
err = nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX,
|
|
|
|
region->port->index);
|
|
|
|
if (err)
|
2020-10-04 16:12:54 +00:00
|
|
|
goto nla_put_failure;
|
2020-10-26 08:00:59 +00:00
|
|
|
}
|
2020-10-04 16:12:54 +00:00
|
|
|
|
2018-07-12 12:13:14 +00:00
|
|
|
err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
|
2019-02-12 20:23:58 +00:00
|
|
|
if (!chunks_attr) {
|
|
|
|
err = -EMSGSIZE;
|
2018-07-12 12:13:14 +00:00
|
|
|
goto nla_put_failure;
|
2019-02-12 20:23:58 +00:00
|
|
|
}
|
2018-07-12 12:13:14 +00:00
|
|
|
|
2022-11-28 20:36:44 +00:00
|
|
|
err = devlink_nl_region_read_fill(skb, region_cb, region_cb_priv,
|
|
|
|
start_offset, end_offset, &ret_offset,
|
|
|
|
cb->extack);
|
2018-07-12 12:13:14 +00:00
|
|
|
|
|
|
|
if (err && err != -EMSGSIZE)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
/* Check if there was any progress done to prevent infinite loop */
|
2019-02-12 20:23:58 +00:00
|
|
|
if (ret_offset == start_offset) {
|
|
|
|
err = -EINVAL;
|
2018-07-12 12:13:14 +00:00
|
|
|
goto nla_put_failure;
|
2019-02-12 20:23:58 +00:00
|
|
|
}
|
2018-07-12 12:13:14 +00:00
|
|
|
|
2023-01-05 04:05:22 +00:00
|
|
|
state->start_offset = ret_offset;
|
2018-07-12 12:13:14 +00:00
|
|
|
|
|
|
|
nla_nest_end(skb, chunks_attr);
|
|
|
|
genlmsg_end(skb, hdr);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2021-08-14 09:57:28 +00:00
|
|
|
devlink_put(devlink);
|
2018-07-12 12:13:14 +00:00
|
|
|
return skb->len;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(skb, hdr);
|
|
|
|
out_unlock:
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2021-08-14 09:57:28 +00:00
|
|
|
devlink_put(devlink);
|
2019-02-12 20:23:58 +00:00
|
|
|
return err;
|
2018-07-12 12:13:14 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
struct devlink_fmsg_item {
|
|
|
|
struct list_head list;
|
|
|
|
int attrtype;
|
|
|
|
u8 nla_type;
|
|
|
|
u16 len;
|
2020-02-28 13:43:24 +00:00
|
|
|
int value[];
|
2019-02-07 09:36:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct devlink_fmsg {
|
|
|
|
struct list_head item_list;
|
2020-02-11 22:32:42 +00:00
|
|
|
bool putting_binary; /* This flag forces enclosing of binary data
|
|
|
|
* in an array brackets. It forces using
|
|
|
|
* of designated API:
|
|
|
|
* devlink_fmsg_binary_pair_nest_start()
|
|
|
|
* devlink_fmsg_binary_pair_nest_end()
|
|
|
|
*/
|
2019-02-07 09:36:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct devlink_fmsg *devlink_fmsg_alloc(void)
|
|
|
|
{
|
|
|
|
struct devlink_fmsg *fmsg;
|
|
|
|
|
|
|
|
fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
|
|
|
|
if (!fmsg)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&fmsg->item_list);
|
|
|
|
|
|
|
|
return fmsg;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
|
|
|
|
{
|
|
|
|
struct devlink_fmsg_item *item, *tmp;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
|
|
|
|
list_del(&item->list);
|
|
|
|
kfree(item);
|
|
|
|
}
|
|
|
|
kfree(fmsg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
|
|
|
|
int attrtype)
|
|
|
|
{
|
|
|
|
struct devlink_fmsg_item *item;
|
|
|
|
|
|
|
|
item = kzalloc(sizeof(*item), GFP_KERNEL);
|
|
|
|
if (!item)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
item->attrtype = attrtype;
|
|
|
|
list_add_tail(&item->list, &fmsg->item_list);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
|
|
|
|
{
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
|
|
|
|
|
|
|
|
static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
|
|
|
|
{
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
|
|
|
|
}
|
|
|
|
|
|
|
|
int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
|
|
|
|
{
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
return devlink_fmsg_nest_end(fmsg);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
|
|
|
|
|
|
|
|
#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
|
|
|
|
|
|
|
|
static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
|
|
|
|
{
|
|
|
|
struct devlink_fmsg_item *item;
|
|
|
|
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
|
|
|
|
if (!item)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
item->nla_type = NLA_NUL_STRING;
|
|
|
|
item->len = strlen(name) + 1;
|
|
|
|
item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
|
|
|
|
memcpy(&item->value, name, item->len);
|
|
|
|
list_add_tail(&item->list, &fmsg->item_list);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_put_name(fmsg, name);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
|
|
|
|
|
|
|
|
int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
|
|
|
|
{
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
return devlink_fmsg_nest_end(fmsg);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
|
|
|
|
|
|
|
|
int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
err = devlink_fmsg_pair_nest_start(fmsg, name);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
|
|
|
|
|
|
|
|
int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
err = devlink_fmsg_nest_end(fmsg);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_nest_end(fmsg);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
|
|
|
|
|
2020-02-11 22:32:42 +00:00
|
|
|
int devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
fmsg->putting_binary = true;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
|
|
|
|
|
|
|
|
int devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
|
|
|
|
{
|
|
|
|
if (!fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
fmsg->putting_binary = false;
|
|
|
|
return devlink_fmsg_arr_pair_nest_end(fmsg);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
|
|
|
|
const void *value, u16 value_len,
|
|
|
|
u8 value_nla_type)
|
|
|
|
{
|
|
|
|
struct devlink_fmsg_item *item;
|
|
|
|
|
|
|
|
if (value_len > DEVLINK_FMSG_MAX_SIZE)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
|
|
|
|
if (!item)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
item->nla_type = value_nla_type;
|
|
|
|
item->len = value_len;
|
|
|
|
item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
|
|
|
|
memcpy(&item->value, value, item->len);
|
|
|
|
list_add_tail(&item->list, &fmsg->item_list);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-16 10:38:33 +00:00
|
|
|
static int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
|
2019-02-07 09:36:32 +00:00
|
|
|
{
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
|
|
|
|
}
|
|
|
|
|
2021-09-16 10:38:33 +00:00
|
|
|
static int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
|
2019-02-07 09:36:32 +00:00
|
|
|
{
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
|
|
|
|
}
|
|
|
|
|
|
|
|
int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
|
|
|
|
{
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
|
|
|
|
|
2021-09-16 10:38:33 +00:00
|
|
|
static int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
|
2019-02-07 09:36:32 +00:00
|
|
|
{
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
|
|
|
|
}
|
|
|
|
|
|
|
|
int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
|
|
|
|
{
|
2020-02-11 22:32:42 +00:00
|
|
|
if (fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
|
|
|
|
NLA_NUL_STRING);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
|
|
|
|
|
2020-02-11 22:32:42 +00:00
|
|
|
int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
|
|
|
|
u16 value_len)
|
2019-02-07 09:36:32 +00:00
|
|
|
{
|
2020-02-11 22:32:42 +00:00
|
|
|
if (!fmsg->putting_binary)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-02-07 09:36:32 +00:00
|
|
|
return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
|
|
|
|
}
|
2020-02-11 22:32:42 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
|
2019-02-07 09:36:32 +00:00
|
|
|
|
|
|
|
int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
|
|
|
|
bool value)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_pair_nest_start(fmsg, name);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_bool_put(fmsg, value);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_pair_nest_end(fmsg);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
|
|
|
|
|
|
|
|
int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
|
|
|
|
u8 value)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_pair_nest_start(fmsg, name);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_u8_put(fmsg, value);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_pair_nest_end(fmsg);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
|
|
|
|
|
|
|
|
int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
|
|
|
|
u32 value)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_pair_nest_start(fmsg, name);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_u32_put(fmsg, value);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_pair_nest_end(fmsg);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
|
|
|
|
|
|
|
|
int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
|
|
|
|
u64 value)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_pair_nest_start(fmsg, name);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_u64_put(fmsg, value);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_pair_nest_end(fmsg);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
|
|
|
|
|
|
|
|
int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
|
|
|
|
const char *value)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_pair_nest_start(fmsg, name);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_string_put(fmsg, value);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_pair_nest_end(fmsg);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
|
|
|
|
|
|
|
|
int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
|
2019-11-12 12:07:49 +00:00
|
|
|
const void *value, u32 value_len)
|
2019-02-07 09:36:32 +00:00
|
|
|
{
|
2019-11-12 12:07:49 +00:00
|
|
|
u32 data_size;
|
2020-02-11 22:32:42 +00:00
|
|
|
int end_err;
|
2019-11-12 12:07:49 +00:00
|
|
|
u32 offset;
|
2019-02-07 09:36:32 +00:00
|
|
|
int err;
|
|
|
|
|
2020-02-11 22:32:42 +00:00
|
|
|
err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
|
2019-02-07 09:36:32 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2019-11-12 12:07:49 +00:00
|
|
|
for (offset = 0; offset < value_len; offset += data_size) {
|
|
|
|
data_size = value_len - offset;
|
|
|
|
if (data_size > DEVLINK_FMSG_MAX_SIZE)
|
|
|
|
data_size = DEVLINK_FMSG_MAX_SIZE;
|
|
|
|
err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
|
|
|
|
if (err)
|
2020-02-11 22:32:42 +00:00
|
|
|
break;
|
|
|
|
/* Exit from loop with a break (instead of
|
|
|
|
* return) to make sure putting_binary is turned off in
|
|
|
|
* devlink_fmsg_binary_pair_nest_end
|
|
|
|
*/
|
2019-11-12 12:07:49 +00:00
|
|
|
}
|
2019-02-07 09:36:32 +00:00
|
|
|
|
2020-02-11 22:32:42 +00:00
|
|
|
end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
|
|
|
|
if (end_err)
|
|
|
|
err = end_err;
|
2019-02-07 09:36:32 +00:00
|
|
|
|
2020-02-11 22:32:42 +00:00
|
|
|
return err;
|
2019-02-07 09:36:32 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
switch (msg->nla_type) {
|
|
|
|
case NLA_FLAG:
|
|
|
|
case NLA_U8:
|
|
|
|
case NLA_U32:
|
|
|
|
case NLA_U64:
|
|
|
|
case NLA_NUL_STRING:
|
|
|
|
case NLA_BINARY:
|
|
|
|
return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
|
|
|
|
msg->nla_type);
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
|
|
|
|
u8 tmp;
|
|
|
|
|
|
|
|
switch (msg->nla_type) {
|
|
|
|
case NLA_FLAG:
|
|
|
|
/* Always provide flag data, regardless of its value */
|
|
|
|
tmp = *(bool *) msg->value;
|
|
|
|
|
|
|
|
return nla_put_u8(skb, attrtype, tmp);
|
|
|
|
case NLA_U8:
|
|
|
|
return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
|
|
|
|
case NLA_U32:
|
|
|
|
return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
|
|
|
|
case NLA_U64:
|
|
|
|
return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
|
|
|
|
DEVLINK_ATTR_PAD);
|
|
|
|
case NLA_NUL_STRING:
|
|
|
|
return nla_put_string(skb, attrtype, (char *) &msg->value);
|
|
|
|
case NLA_BINARY:
|
|
|
|
return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
|
|
|
|
int *start)
|
|
|
|
{
|
|
|
|
struct devlink_fmsg_item *item;
|
|
|
|
struct nlattr *fmsg_nlattr;
|
2023-01-24 03:52:31 +00:00
|
|
|
int err = 0;
|
2019-02-07 09:36:32 +00:00
|
|
|
int i = 0;
|
|
|
|
|
2019-04-26 09:13:06 +00:00
|
|
|
fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
|
2019-02-07 09:36:32 +00:00
|
|
|
if (!fmsg_nlattr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
list_for_each_entry(item, &fmsg->item_list, list) {
|
|
|
|
if (i < *start) {
|
|
|
|
i++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (item->attrtype) {
|
|
|
|
case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
|
|
|
|
case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
|
|
|
|
case DEVLINK_ATTR_FMSG_ARR_NEST_START:
|
|
|
|
case DEVLINK_ATTR_FMSG_NEST_END:
|
|
|
|
err = nla_put_flag(skb, item->attrtype);
|
|
|
|
break;
|
|
|
|
case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
|
|
|
|
err = devlink_fmsg_item_fill_type(item, skb);
|
|
|
|
if (err)
|
|
|
|
break;
|
|
|
|
err = devlink_fmsg_item_fill_data(item, skb);
|
|
|
|
break;
|
|
|
|
case DEVLINK_ATTR_FMSG_OBJ_NAME:
|
|
|
|
err = nla_put_string(skb, item->attrtype,
|
|
|
|
(char *) &item->value);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
err = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!err)
|
|
|
|
*start = ++i;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
nla_nest_end(skb, fmsg_nlattr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
|
|
|
|
struct genl_info *info,
|
|
|
|
enum devlink_command cmd, int flags)
|
|
|
|
{
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
bool last = false;
|
|
|
|
int index = 0;
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
while (!last) {
|
|
|
|
int tmp_index = index;
|
|
|
|
|
|
|
|
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!skb)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
|
|
|
|
&devlink_nl_family, flags | NLM_F_MULTI, cmd);
|
|
|
|
if (!hdr) {
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
|
|
|
|
if (!err)
|
|
|
|
last = true;
|
|
|
|
else if (err != -EMSGSIZE || tmp_index == index)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
err = genlmsg_reply(skb, info);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!skb)
|
|
|
|
return -ENOMEM;
|
|
|
|
nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
|
|
|
|
NLMSG_DONE, 0, flags | NLM_F_MULTI);
|
|
|
|
if (!nlh) {
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
|
2019-02-11 11:09:07 +00:00
|
|
|
return genlmsg_reply(skb, info);
|
2019-02-07 09:36:32 +00:00
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nlmsg_free(skb);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-05-16 06:49:20 +00:00
|
|
|
static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
|
|
|
|
struct netlink_callback *cb,
|
|
|
|
enum devlink_command cmd)
|
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
|
|
|
int index = state->idx;
|
2019-05-16 06:49:20 +00:00
|
|
|
int tmp_index = index;
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
|
|
|
&devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
|
|
|
|
if (!hdr) {
|
|
|
|
err = -EMSGSIZE;
|
|
|
|
goto nla_put_failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
|
|
|
|
if ((err && err != -EMSGSIZE) || tmp_index == index)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2023-01-05 04:05:22 +00:00
|
|
|
state->idx = index;
|
2019-05-16 06:49:20 +00:00
|
|
|
genlmsg_end(skb, hdr);
|
|
|
|
return skb->len;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(skb, hdr);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-02-07 09:36:33 +00:00
|
|
|
struct devlink_health_reporter {
|
|
|
|
struct list_head list;
|
|
|
|
void *priv;
|
|
|
|
const struct devlink_health_reporter_ops *ops;
|
|
|
|
struct devlink *devlink;
|
2020-07-10 12:25:10 +00:00
|
|
|
struct devlink_port *devlink_port;
|
2019-02-07 09:36:34 +00:00
|
|
|
struct devlink_fmsg *dump_fmsg;
|
|
|
|
struct mutex dump_lock; /* lock parallel read/write from dump buffers */
|
2019-02-07 09:36:33 +00:00
|
|
|
u64 graceful_period;
|
|
|
|
bool auto_recover;
|
2020-03-29 11:05:55 +00:00
|
|
|
bool auto_dump;
|
2019-02-07 09:36:33 +00:00
|
|
|
u8 health_state;
|
2019-02-07 09:36:34 +00:00
|
|
|
u64 dump_ts;
|
2019-11-10 12:11:56 +00:00
|
|
|
u64 dump_real_ts;
|
2019-02-07 09:36:34 +00:00
|
|
|
u64 error_count;
|
|
|
|
u64 recovery_count;
|
|
|
|
u64 last_recovery_ts;
|
|
|
|
};
|
|
|
|
|
2019-02-07 09:36:33 +00:00
|
|
|
void *
|
|
|
|
devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
|
|
|
|
{
|
|
|
|
return reporter->priv;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
|
|
|
|
|
|
|
|
static struct devlink_health_reporter *
|
2020-07-10 12:25:09 +00:00
|
|
|
__devlink_health_reporter_find_by_name(struct list_head *reporter_list,
|
|
|
|
const char *reporter_name)
|
2019-02-07 09:36:33 +00:00
|
|
|
{
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
|
2020-07-10 12:25:09 +00:00
|
|
|
list_for_each_entry(reporter, reporter_list, list)
|
2019-02-07 09:36:33 +00:00
|
|
|
if (!strcmp(reporter->ops->name, reporter_name))
|
|
|
|
return reporter;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-10 12:25:09 +00:00
|
|
|
static struct devlink_health_reporter *
|
|
|
|
devlink_health_reporter_find_by_name(struct devlink *devlink,
|
|
|
|
const char *reporter_name)
|
|
|
|
{
|
|
|
|
return __devlink_health_reporter_find_by_name(&devlink->reporter_list,
|
|
|
|
reporter_name);
|
|
|
|
}
|
|
|
|
|
2020-07-10 12:25:10 +00:00
|
|
|
static struct devlink_health_reporter *
|
|
|
|
devlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
|
|
|
|
const char *reporter_name)
|
|
|
|
{
|
|
|
|
return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list,
|
|
|
|
reporter_name);
|
|
|
|
}
|
|
|
|
|
2020-07-10 12:25:07 +00:00
|
|
|
static struct devlink_health_reporter *
|
|
|
|
__devlink_health_reporter_create(struct devlink *devlink,
|
|
|
|
const struct devlink_health_reporter_ops *ops,
|
|
|
|
u64 graceful_period, void *priv)
|
|
|
|
{
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
|
|
|
|
if (WARN_ON(graceful_period && !ops->recover))
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
|
|
|
reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
|
|
|
|
if (!reporter)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
reporter->priv = priv;
|
|
|
|
reporter->ops = ops;
|
|
|
|
reporter->devlink = devlink;
|
|
|
|
reporter->graceful_period = graceful_period;
|
|
|
|
reporter->auto_recover = !!ops->recover;
|
|
|
|
reporter->auto_dump = !!ops->dump;
|
|
|
|
mutex_init(&reporter->dump_lock);
|
|
|
|
return reporter;
|
|
|
|
}
|
|
|
|
|
2020-07-10 12:25:11 +00:00
|
|
|
/**
|
2023-01-18 15:21:08 +00:00
|
|
|
* devl_port_health_reporter_create - create devlink health reporter for
|
|
|
|
* specified port instance
|
2020-07-10 12:25:11 +00:00
|
|
|
*
|
|
|
|
* @port: devlink_port which should contain the new reporter
|
|
|
|
* @ops: ops
|
|
|
|
* @graceful_period: to avoid recovery loops, in msecs
|
|
|
|
* @priv: priv
|
|
|
|
*/
|
|
|
|
struct devlink_health_reporter *
|
2023-01-18 15:21:08 +00:00
|
|
|
devl_port_health_reporter_create(struct devlink_port *port,
|
|
|
|
const struct devlink_health_reporter_ops *ops,
|
|
|
|
u64 graceful_period, void *priv)
|
2020-07-10 12:25:11 +00:00
|
|
|
{
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
|
2023-01-18 15:21:08 +00:00
|
|
|
devl_assert_locked(port->devlink);
|
2023-01-18 15:21:09 +00:00
|
|
|
|
2020-07-10 12:25:11 +00:00
|
|
|
if (__devlink_health_reporter_find_by_name(&port->reporter_list,
|
2023-01-18 15:21:09 +00:00
|
|
|
ops->name))
|
|
|
|
return ERR_PTR(-EEXIST);
|
2020-07-10 12:25:11 +00:00
|
|
|
|
|
|
|
reporter = __devlink_health_reporter_create(port->devlink, ops,
|
|
|
|
graceful_period, priv);
|
|
|
|
if (IS_ERR(reporter))
|
2023-01-18 15:21:09 +00:00
|
|
|
return reporter;
|
2020-07-10 12:25:11 +00:00
|
|
|
|
|
|
|
reporter->devlink_port = port;
|
|
|
|
list_add_tail(&reporter->list, &port->reporter_list);
|
|
|
|
return reporter;
|
|
|
|
}
|
2023-01-18 15:21:08 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_port_health_reporter_create);
|
|
|
|
|
|
|
|
struct devlink_health_reporter *
|
|
|
|
devlink_port_health_reporter_create(struct devlink_port *port,
|
|
|
|
const struct devlink_health_reporter_ops *ops,
|
|
|
|
u64 graceful_period, void *priv)
|
|
|
|
{
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
struct devlink *devlink = port->devlink;
|
|
|
|
|
|
|
|
devl_lock(devlink);
|
|
|
|
reporter = devl_port_health_reporter_create(port, ops,
|
|
|
|
graceful_period, priv);
|
|
|
|
devl_unlock(devlink);
|
|
|
|
return reporter;
|
|
|
|
}
|
2020-07-10 12:25:11 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
|
|
|
|
|
2019-02-07 09:36:33 +00:00
|
|
|
/**
|
2023-01-18 15:21:08 +00:00
|
|
|
* devl_health_reporter_create - create devlink health reporter
|
2019-02-07 09:36:33 +00:00
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @ops: ops
|
|
|
|
* @graceful_period: to avoid recovery loops, in msecs
|
|
|
|
* @priv: priv
|
|
|
|
*/
|
|
|
|
struct devlink_health_reporter *
|
2023-01-18 15:21:08 +00:00
|
|
|
devl_health_reporter_create(struct devlink *devlink,
|
|
|
|
const struct devlink_health_reporter_ops *ops,
|
|
|
|
u64 graceful_period, void *priv)
|
2019-02-07 09:36:33 +00:00
|
|
|
{
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
|
2023-01-18 15:21:08 +00:00
|
|
|
devl_assert_locked(devlink);
|
2023-01-18 15:21:09 +00:00
|
|
|
|
|
|
|
if (devlink_health_reporter_find_by_name(devlink, ops->name))
|
|
|
|
return ERR_PTR(-EEXIST);
|
2019-02-07 09:36:33 +00:00
|
|
|
|
2020-07-10 12:25:07 +00:00
|
|
|
reporter = __devlink_health_reporter_create(devlink, ops,
|
|
|
|
graceful_period, priv);
|
|
|
|
if (IS_ERR(reporter))
|
2023-01-18 15:21:09 +00:00
|
|
|
return reporter;
|
2019-02-07 09:36:33 +00:00
|
|
|
|
|
|
|
list_add_tail(&reporter->list, &devlink->reporter_list);
|
|
|
|
return reporter;
|
|
|
|
}
|
2023-01-18 15:21:08 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_health_reporter_create);
|
|
|
|
|
|
|
|
struct devlink_health_reporter *
|
|
|
|
devlink_health_reporter_create(struct devlink *devlink,
|
|
|
|
const struct devlink_health_reporter_ops *ops,
|
|
|
|
u64 graceful_period, void *priv)
|
|
|
|
{
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
|
|
|
|
devl_lock(devlink);
|
|
|
|
reporter = devl_health_reporter_create(devlink, ops,
|
|
|
|
graceful_period, priv);
|
|
|
|
devl_unlock(devlink);
|
|
|
|
return reporter;
|
|
|
|
}
|
2019-02-07 09:36:33 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
|
|
|
|
|
2020-07-10 12:25:08 +00:00
|
|
|
static void
|
|
|
|
devlink_health_reporter_free(struct devlink_health_reporter *reporter)
|
|
|
|
{
|
|
|
|
mutex_destroy(&reporter->dump_lock);
|
|
|
|
if (reporter->dump_fmsg)
|
|
|
|
devlink_fmsg_free(reporter->dump_fmsg);
|
|
|
|
kfree(reporter);
|
|
|
|
}
|
|
|
|
|
2019-02-07 09:36:33 +00:00
|
|
|
/**
|
2023-01-18 15:21:08 +00:00
|
|
|
* devl_health_reporter_destroy - destroy devlink health reporter
|
2019-02-07 09:36:33 +00:00
|
|
|
*
|
|
|
|
* @reporter: devlink health reporter to destroy
|
|
|
|
*/
|
|
|
|
void
|
2023-01-18 15:21:08 +00:00
|
|
|
devl_health_reporter_destroy(struct devlink_health_reporter *reporter)
|
2019-02-07 09:36:33 +00:00
|
|
|
{
|
2023-01-18 15:21:08 +00:00
|
|
|
devl_assert_locked(reporter->devlink);
|
|
|
|
|
2023-01-18 15:21:10 +00:00
|
|
|
list_del(&reporter->list);
|
2023-01-18 15:21:11 +00:00
|
|
|
devlink_health_reporter_free(reporter);
|
2019-02-07 09:36:33 +00:00
|
|
|
}
|
2023-01-18 15:21:08 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_health_reporter_destroy);
|
|
|
|
|
|
|
|
void
|
|
|
|
devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = reporter->devlink;
|
|
|
|
|
|
|
|
devl_lock(devlink);
|
|
|
|
devl_health_reporter_destroy(reporter);
|
|
|
|
devl_unlock(devlink);
|
|
|
|
}
|
2019-02-07 09:36:33 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
|
|
|
|
|
2020-01-23 17:57:13 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_health_reporter_fill(struct sk_buff *msg,
|
|
|
|
struct devlink_health_reporter *reporter,
|
|
|
|
enum devlink_command cmd, u32 portid,
|
|
|
|
u32 seq, int flags)
|
|
|
|
{
|
2021-08-14 09:57:27 +00:00
|
|
|
struct devlink *devlink = reporter->devlink;
|
2020-01-23 17:57:13 +00:00
|
|
|
struct nlattr *reporter_attr;
|
|
|
|
void *hdr;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto genlmsg_cancel;
|
|
|
|
|
2020-07-10 12:25:10 +00:00
|
|
|
if (reporter->devlink_port) {
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
|
|
|
|
goto genlmsg_cancel;
|
|
|
|
}
|
2020-01-23 17:57:13 +00:00
|
|
|
reporter_attr = nla_nest_start_noflag(msg,
|
|
|
|
DEVLINK_ATTR_HEALTH_REPORTER);
|
|
|
|
if (!reporter_attr)
|
|
|
|
goto genlmsg_cancel;
|
|
|
|
if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
|
|
|
|
reporter->ops->name))
|
|
|
|
goto reporter_nest_cancel;
|
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
|
|
|
|
reporter->health_state))
|
|
|
|
goto reporter_nest_cancel;
|
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
|
|
|
|
reporter->error_count, DEVLINK_ATTR_PAD))
|
|
|
|
goto reporter_nest_cancel;
|
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
|
|
|
|
reporter->recovery_count, DEVLINK_ATTR_PAD))
|
|
|
|
goto reporter_nest_cancel;
|
|
|
|
if (reporter->ops->recover &&
|
|
|
|
nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
|
|
|
|
reporter->graceful_period,
|
|
|
|
DEVLINK_ATTR_PAD))
|
|
|
|
goto reporter_nest_cancel;
|
|
|
|
if (reporter->ops->recover &&
|
|
|
|
nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
|
|
|
|
reporter->auto_recover))
|
|
|
|
goto reporter_nest_cancel;
|
|
|
|
if (reporter->dump_fmsg &&
|
|
|
|
nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
|
|
|
|
jiffies_to_msecs(reporter->dump_ts),
|
|
|
|
DEVLINK_ATTR_PAD))
|
|
|
|
goto reporter_nest_cancel;
|
|
|
|
if (reporter->dump_fmsg &&
|
|
|
|
nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
|
|
|
|
reporter->dump_real_ts, DEVLINK_ATTR_PAD))
|
|
|
|
goto reporter_nest_cancel;
|
2020-03-29 11:05:55 +00:00
|
|
|
if (reporter->ops->dump &&
|
|
|
|
nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
|
|
|
|
reporter->auto_dump))
|
|
|
|
goto reporter_nest_cancel;
|
2020-01-23 17:57:13 +00:00
|
|
|
|
|
|
|
nla_nest_end(msg, reporter_attr);
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
reporter_nest_cancel:
|
|
|
|
nla_nest_end(msg, reporter_attr);
|
|
|
|
genlmsg_cancel:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_recover_notify(struct devlink_health_reporter *reporter,
|
|
|
|
enum devlink_command cmd)
|
|
|
|
{
|
2021-09-25 11:22:41 +00:00
|
|
|
struct devlink *devlink = reporter->devlink;
|
2020-01-23 17:57:13 +00:00
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
|
2021-09-25 11:22:41 +00:00
|
|
|
WARN_ON(!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED));
|
2020-01-23 17:57:13 +00:00
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return;
|
|
|
|
|
2021-08-14 09:57:27 +00:00
|
|
|
err = devlink_nl_health_reporter_fill(msg, reporter, cmd, 0, 0, 0);
|
2020-01-23 17:57:13 +00:00
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-25 11:22:41 +00:00
|
|
|
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), msg,
|
|
|
|
0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
2020-01-23 17:57:13 +00:00
|
|
|
}
|
|
|
|
|
2020-01-02 15:48:09 +00:00
|
|
|
void
|
|
|
|
devlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
|
|
|
|
{
|
|
|
|
reporter->recovery_count++;
|
|
|
|
reporter->last_recovery_ts = jiffies;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
|
|
|
|
|
2019-02-07 09:36:34 +00:00
|
|
|
static int
|
|
|
|
devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
|
2019-10-10 13:18:49 +00:00
|
|
|
void *priv_ctx, struct netlink_ext_ack *extack)
|
2019-02-07 09:36:34 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2019-10-10 13:18:48 +00:00
|
|
|
if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
|
|
|
|
return 0;
|
|
|
|
|
2019-02-07 09:36:34 +00:00
|
|
|
if (!reporter->ops->recover)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2019-10-10 13:18:49 +00:00
|
|
|
err = reporter->ops->recover(reporter, priv_ctx, extack);
|
2019-02-07 09:36:34 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2020-01-02 15:48:09 +00:00
|
|
|
devlink_health_reporter_recovery_done(reporter);
|
2019-02-07 09:36:34 +00:00
|
|
|
reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
|
2020-01-23 17:57:13 +00:00
|
|
|
devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
|
2019-02-07 09:36:34 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
devlink_health_dump_clear(struct devlink_health_reporter *reporter)
|
|
|
|
{
|
|
|
|
if (!reporter->dump_fmsg)
|
|
|
|
return;
|
|
|
|
devlink_fmsg_free(reporter->dump_fmsg);
|
|
|
|
reporter->dump_fmsg = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
|
2019-10-10 13:18:49 +00:00
|
|
|
void *priv_ctx,
|
|
|
|
struct netlink_ext_ack *extack)
|
2019-02-07 09:36:34 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!reporter->ops->dump)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (reporter->dump_fmsg)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
reporter->dump_fmsg = devlink_fmsg_alloc();
|
|
|
|
if (!reporter->dump_fmsg) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
|
|
|
|
if (err)
|
|
|
|
goto dump_err;
|
|
|
|
|
|
|
|
err = reporter->ops->dump(reporter, reporter->dump_fmsg,
|
2019-10-10 13:18:49 +00:00
|
|
|
priv_ctx, extack);
|
2019-02-07 09:36:34 +00:00
|
|
|
if (err)
|
|
|
|
goto dump_err;
|
|
|
|
|
|
|
|
err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
|
|
|
|
if (err)
|
|
|
|
goto dump_err;
|
|
|
|
|
|
|
|
reporter->dump_ts = jiffies;
|
2019-11-10 12:11:56 +00:00
|
|
|
reporter->dump_real_ts = ktime_get_real_ns();
|
2019-02-07 09:36:34 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
dump_err:
|
|
|
|
devlink_health_dump_clear(reporter);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int devlink_health_report(struct devlink_health_reporter *reporter,
|
|
|
|
const char *msg, void *priv_ctx)
|
|
|
|
{
|
2019-03-03 08:57:29 +00:00
|
|
|
enum devlink_health_reporter_state prev_health_state;
|
2019-02-07 09:36:34 +00:00
|
|
|
struct devlink *devlink = reporter->devlink;
|
2020-05-04 08:27:46 +00:00
|
|
|
unsigned long recover_ts_threshold;
|
2022-07-28 15:53:50 +00:00
|
|
|
int ret;
|
2019-02-07 09:36:34 +00:00
|
|
|
|
|
|
|
/* write a log message of the current error */
|
|
|
|
WARN_ON(!msg);
|
|
|
|
trace_devlink_health_report(devlink, reporter->ops->name, msg);
|
|
|
|
reporter->error_count++;
|
2019-03-03 08:57:29 +00:00
|
|
|
prev_health_state = reporter->health_state;
|
|
|
|
reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
|
2020-01-23 17:57:13 +00:00
|
|
|
devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
|
2019-02-07 09:36:34 +00:00
|
|
|
|
|
|
|
/* abort if the previous error wasn't recovered */
|
2020-05-04 08:27:46 +00:00
|
|
|
recover_ts_threshold = reporter->last_recovery_ts +
|
|
|
|
msecs_to_jiffies(reporter->graceful_period);
|
2019-02-07 09:36:34 +00:00
|
|
|
if (reporter->auto_recover &&
|
2019-03-03 08:57:29 +00:00
|
|
|
(prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
|
2020-05-04 08:27:46 +00:00
|
|
|
(reporter->last_recovery_ts && reporter->recovery_count &&
|
|
|
|
time_is_after_jiffies(recover_ts_threshold)))) {
|
2019-02-07 09:36:34 +00:00
|
|
|
trace_devlink_health_recover_aborted(devlink,
|
|
|
|
reporter->ops->name,
|
|
|
|
reporter->health_state,
|
|
|
|
jiffies -
|
|
|
|
reporter->last_recovery_ts);
|
|
|
|
return -ECANCELED;
|
|
|
|
}
|
|
|
|
|
2020-03-29 11:05:55 +00:00
|
|
|
if (reporter->auto_dump) {
|
|
|
|
mutex_lock(&reporter->dump_lock);
|
|
|
|
/* store current dump of current error, for later analysis */
|
|
|
|
devlink_health_do_dump(reporter, priv_ctx, NULL);
|
|
|
|
mutex_unlock(&reporter->dump_lock);
|
|
|
|
}
|
2019-02-07 09:36:34 +00:00
|
|
|
|
2022-07-28 15:53:50 +00:00
|
|
|
if (!reporter->auto_recover)
|
|
|
|
return 0;
|
2019-02-07 09:36:34 +00:00
|
|
|
|
2022-07-28 15:53:50 +00:00
|
|
|
devl_lock(devlink);
|
|
|
|
ret = devlink_health_reporter_recover(reporter, priv_ctx, NULL);
|
|
|
|
devl_unlock(devlink);
|
|
|
|
|
|
|
|
return ret;
|
2019-02-07 09:36:34 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_health_report);
|
|
|
|
|
2019-02-07 09:36:35 +00:00
|
|
|
static struct devlink_health_reporter *
|
2019-05-16 06:49:20 +00:00
|
|
|
devlink_health_reporter_get_from_attrs(struct devlink *devlink,
|
|
|
|
struct nlattr **attrs)
|
2019-02-07 09:36:35 +00:00
|
|
|
{
|
2020-07-10 12:25:10 +00:00
|
|
|
struct devlink_port *devlink_port;
|
2019-02-07 09:36:35 +00:00
|
|
|
char *reporter_name;
|
|
|
|
|
2019-05-16 06:49:20 +00:00
|
|
|
if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
|
2019-02-07 09:36:35 +00:00
|
|
|
return NULL;
|
|
|
|
|
2019-05-16 06:49:20 +00:00
|
|
|
reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
|
2020-07-10 12:25:10 +00:00
|
|
|
devlink_port = devlink_port_get_from_attrs(devlink, attrs);
|
2023-01-18 15:21:11 +00:00
|
|
|
if (IS_ERR(devlink_port))
|
|
|
|
return devlink_health_reporter_find_by_name(devlink,
|
|
|
|
reporter_name);
|
|
|
|
else
|
|
|
|
return devlink_port_health_reporter_find_by_name(devlink_port,
|
|
|
|
reporter_name);
|
2019-04-29 09:41:45 +00:00
|
|
|
}
|
|
|
|
|
2019-05-16 06:49:20 +00:00
|
|
|
static struct devlink_health_reporter *
|
|
|
|
devlink_health_reporter_get_from_info(struct devlink *devlink,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_health_reporter *
|
|
|
|
devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
|
|
|
|
{
|
2019-10-05 18:04:42 +00:00
|
|
|
const struct genl_dumpit_info *info = genl_dumpit_info(cb);
|
2019-05-16 06:49:20 +00:00
|
|
|
struct devlink_health_reporter *reporter;
|
2019-10-05 18:04:42 +00:00
|
|
|
struct nlattr **attrs = info->attrs;
|
2019-05-16 06:49:20 +00:00
|
|
|
struct devlink *devlink;
|
|
|
|
|
2023-01-06 06:33:56 +00:00
|
|
|
devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs);
|
2019-05-16 06:49:20 +00:00
|
|
|
if (IS_ERR(devlink))
|
2022-07-29 07:10:37 +00:00
|
|
|
return NULL;
|
2023-01-06 06:33:56 +00:00
|
|
|
devl_unlock(devlink);
|
2019-05-16 06:49:20 +00:00
|
|
|
|
|
|
|
reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
|
2021-08-14 09:57:28 +00:00
|
|
|
devlink_put(devlink);
|
2019-05-16 06:49:20 +00:00
|
|
|
return reporter;
|
|
|
|
}
|
|
|
|
|
2020-01-02 15:48:10 +00:00
|
|
|
void
|
|
|
|
devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
|
|
|
|
enum devlink_health_reporter_state state)
|
|
|
|
{
|
|
|
|
if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
|
|
|
|
state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (reporter->health_state == state)
|
|
|
|
return;
|
|
|
|
|
|
|
|
reporter->health_state = state;
|
|
|
|
trace_devlink_health_reporter_state_update(reporter->devlink,
|
|
|
|
reporter->ops->name, state);
|
|
|
|
devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
|
|
|
|
|
2019-02-07 09:36:35 +00:00
|
|
|
static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
reporter = devlink_health_reporter_get_from_info(devlink, info);
|
|
|
|
if (!reporter)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
2023-01-18 15:21:11 +00:00
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
2019-02-07 09:36:35 +00:00
|
|
|
|
2021-08-14 09:57:27 +00:00
|
|
|
err = devlink_nl_health_reporter_fill(msg, reporter,
|
2019-02-07 09:36:35 +00:00
|
|
|
DEVLINK_CMD_HEALTH_REPORTER_GET,
|
|
|
|
info->snd_portid, info->snd_seq,
|
|
|
|
0);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
2023-01-18 15:21:11 +00:00
|
|
|
return err;
|
2019-02-07 09:36:35 +00:00
|
|
|
}
|
|
|
|
|
2023-01-18 15:21:11 +00:00
|
|
|
return genlmsg_reply(msg, info);
|
2019-02-07 09:36:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2023-01-18 15:21:13 +00:00
|
|
|
devlink_nl_cmd_health_reporter_get_dump_one(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2019-02-07 09:36:35 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-18 15:21:13 +00:00
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
struct devlink_port *port;
|
|
|
|
unsigned long port_index;
|
|
|
|
int idx = 0;
|
2019-02-07 09:36:35 +00:00
|
|
|
int err;
|
|
|
|
|
2023-01-18 15:21:13 +00:00
|
|
|
list_for_each_entry(reporter, &devlink->reporter_list, list) {
|
|
|
|
if (idx < state->idx) {
|
|
|
|
idx++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
err = devlink_nl_health_reporter_fill(msg, reporter,
|
|
|
|
DEVLINK_CMD_HEALTH_REPORTER_GET,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI);
|
|
|
|
if (err) {
|
|
|
|
state->idx = idx;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
xa_for_each(&devlink->ports, port_index, port) {
|
|
|
|
list_for_each_entry(reporter, &port->reporter_list, list) {
|
2023-01-05 04:05:23 +00:00
|
|
|
if (idx < state->idx) {
|
2019-02-07 09:36:35 +00:00
|
|
|
idx++;
|
|
|
|
continue;
|
|
|
|
}
|
2023-01-18 15:21:13 +00:00
|
|
|
err = devlink_nl_health_reporter_fill(msg, reporter,
|
|
|
|
DEVLINK_CMD_HEALTH_REPORTER_GET,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI);
|
2019-02-07 09:36:35 +00:00
|
|
|
if (err) {
|
2023-01-05 04:05:27 +00:00
|
|
|
state->idx = idx;
|
2023-01-18 15:21:13 +00:00
|
|
|
return err;
|
2019-02-07 09:36:35 +00:00
|
|
|
}
|
|
|
|
idx++;
|
|
|
|
}
|
2020-07-10 12:25:10 +00:00
|
|
|
}
|
2023-01-18 15:21:13 +00:00
|
|
|
|
|
|
|
return 0;
|
2019-02-07 09:36:35 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_health_reporter_get = {
|
2023-01-18 15:21:13 +00:00
|
|
|
.dump_one = devlink_nl_cmd_health_reporter_get_dump_one,
|
|
|
|
};
|
|
|
|
|
2019-02-07 09:36:36 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
|
|
|
|
reporter = devlink_health_reporter_get_from_info(devlink, info);
|
|
|
|
if (!reporter)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!reporter->ops->recover &&
|
|
|
|
(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
|
2023-01-18 15:21:11 +00:00
|
|
|
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2020-03-29 11:05:55 +00:00
|
|
|
if (!reporter->ops->dump &&
|
2023-01-18 15:21:11 +00:00
|
|
|
info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
|
|
|
|
return -EOPNOTSUPP;
|
2019-02-07 09:36:36 +00:00
|
|
|
|
|
|
|
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
|
|
|
|
reporter->graceful_period =
|
|
|
|
nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
|
|
|
|
|
|
|
|
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
|
|
|
|
reporter->auto_recover =
|
|
|
|
nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
|
|
|
|
|
2020-03-29 11:05:55 +00:00
|
|
|
if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
|
|
|
|
reporter->auto_dump =
|
|
|
|
nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
|
|
|
|
|
2019-02-07 09:36:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-02-07 09:36:37 +00:00
|
|
|
static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
|
|
|
|
reporter = devlink_health_reporter_get_from_info(devlink, info);
|
|
|
|
if (!reporter)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-01-18 15:21:11 +00:00
|
|
|
return devlink_health_reporter_recover(reporter, NULL, info->extack);
|
2019-02-07 09:36:37 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 09:36:38 +00:00
|
|
|
static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
struct devlink_fmsg *fmsg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
reporter = devlink_health_reporter_get_from_info(devlink, info);
|
|
|
|
if (!reporter)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-01-18 15:21:11 +00:00
|
|
|
if (!reporter->ops->diagnose)
|
2019-02-07 09:36:38 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
fmsg = devlink_fmsg_alloc();
|
2023-01-18 15:21:11 +00:00
|
|
|
if (!fmsg)
|
2019-02-07 09:36:38 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
err = devlink_fmsg_obj_nest_start(fmsg);
|
|
|
|
if (err)
|
2023-02-06 15:56:16 +00:00
|
|
|
goto out;
|
2019-02-07 09:36:38 +00:00
|
|
|
|
2019-10-10 13:18:49 +00:00
|
|
|
err = reporter->ops->diagnose(reporter, fmsg, info->extack);
|
2019-02-07 09:36:38 +00:00
|
|
|
if (err)
|
2023-02-06 15:56:16 +00:00
|
|
|
goto out;
|
2019-02-07 09:36:38 +00:00
|
|
|
|
|
|
|
err = devlink_fmsg_obj_nest_end(fmsg);
|
|
|
|
if (err)
|
2023-02-06 15:56:16 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = devlink_fmsg_snd(fmsg, info,
|
|
|
|
DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
|
2019-02-07 09:36:38 +00:00
|
|
|
|
2023-02-06 15:56:16 +00:00
|
|
|
out:
|
|
|
|
devlink_fmsg_free(fmsg);
|
|
|
|
return err;
|
2019-02-07 09:36:38 +00:00
|
|
|
}
|
|
|
|
|
2019-05-16 06:49:20 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
|
|
|
|
struct netlink_callback *cb)
|
2019-02-07 09:36:39 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2019-02-07 09:36:39 +00:00
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
int err;
|
|
|
|
|
2019-05-16 06:49:20 +00:00
|
|
|
reporter = devlink_health_reporter_get_from_cb(cb);
|
2019-02-07 09:36:39 +00:00
|
|
|
if (!reporter)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-01-18 15:21:11 +00:00
|
|
|
if (!reporter->ops->dump)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2019-02-07 09:36:39 +00:00
|
|
|
mutex_lock(&reporter->dump_lock);
|
2023-01-05 04:05:22 +00:00
|
|
|
if (!state->idx) {
|
2019-10-10 13:18:49 +00:00
|
|
|
err = devlink_health_do_dump(reporter, NULL, cb->extack);
|
2019-05-16 06:49:20 +00:00
|
|
|
if (err)
|
|
|
|
goto unlock;
|
2023-01-05 04:05:22 +00:00
|
|
|
state->dump_ts = reporter->dump_ts;
|
2019-05-16 06:49:20 +00:00
|
|
|
}
|
2023-01-05 04:05:22 +00:00
|
|
|
if (!reporter->dump_fmsg || state->dump_ts != reporter->dump_ts) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(cb->extack, "Dump trampled, please retry");
|
2019-05-16 06:49:20 +00:00
|
|
|
err = -EAGAIN;
|
|
|
|
goto unlock;
|
|
|
|
}
|
2019-02-07 09:36:39 +00:00
|
|
|
|
2019-05-16 06:49:20 +00:00
|
|
|
err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
|
|
|
|
DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
|
|
|
|
unlock:
|
2019-02-07 09:36:39 +00:00
|
|
|
mutex_unlock(&reporter->dump_lock);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
|
|
|
|
reporter = devlink_health_reporter_get_from_info(devlink, info);
|
|
|
|
if (!reporter)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-01-18 15:21:11 +00:00
|
|
|
if (!reporter->ops->dump)
|
2019-02-07 09:36:39 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
mutex_lock(&reporter->dump_lock);
|
|
|
|
devlink_health_dump_clear(reporter);
|
|
|
|
mutex_unlock(&reporter->dump_lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-09-15 08:40:57 +00:00
|
|
|
static int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_health_reporter *reporter;
|
|
|
|
|
|
|
|
reporter = devlink_health_reporter_get_from_info(devlink, info);
|
|
|
|
if (!reporter)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-01-18 15:21:11 +00:00
|
|
|
if (!reporter->ops->test)
|
2020-09-15 08:40:57 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2023-01-18 15:21:11 +00:00
|
|
|
return reporter->ops->test(reporter, info->extack);
|
2020-09-15 08:40:57 +00:00
|
|
|
}
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
struct devlink_stats {
|
2022-06-08 15:46:38 +00:00
|
|
|
u64_stats_t rx_bytes;
|
|
|
|
u64_stats_t rx_packets;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
struct u64_stats_sync syncp;
|
|
|
|
};
|
|
|
|
|
2020-03-30 19:38:18 +00:00
|
|
|
/**
|
|
|
|
* struct devlink_trap_policer_item - Packet trap policer attributes.
|
|
|
|
* @policer: Immutable packet trap policer attributes.
|
|
|
|
* @rate: Rate in packets / sec.
|
|
|
|
* @burst: Burst size in packets.
|
|
|
|
* @list: trap_policer_list member.
|
|
|
|
*
|
|
|
|
* Describes packet trap policer attributes. Created by devlink during trap
|
|
|
|
* policer registration.
|
|
|
|
*/
|
|
|
|
struct devlink_trap_policer_item {
|
|
|
|
const struct devlink_trap_policer *policer;
|
|
|
|
u64 rate;
|
|
|
|
u64 burst;
|
|
|
|
struct list_head list;
|
|
|
|
};
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
/**
|
|
|
|
* struct devlink_trap_group_item - Packet trap group attributes.
|
|
|
|
* @group: Immutable packet trap group attributes.
|
2020-03-30 19:38:21 +00:00
|
|
|
* @policer_item: Associated policer item. Can be NULL.
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
* @list: trap_group_list member.
|
|
|
|
* @stats: Trap group statistics.
|
|
|
|
*
|
|
|
|
* Describes packet trap group attributes. Created by devlink during trap
|
2020-03-22 18:48:29 +00:00
|
|
|
* group registration.
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
*/
|
|
|
|
struct devlink_trap_group_item {
|
|
|
|
const struct devlink_trap_group *group;
|
2020-03-30 19:38:21 +00:00
|
|
|
struct devlink_trap_policer_item *policer_item;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
struct list_head list;
|
|
|
|
struct devlink_stats __percpu *stats;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct devlink_trap_item - Packet trap attributes.
|
|
|
|
* @trap: Immutable packet trap attributes.
|
|
|
|
* @group_item: Associated group item.
|
|
|
|
* @list: trap_list member.
|
|
|
|
* @action: Trap action.
|
|
|
|
* @stats: Trap statistics.
|
|
|
|
* @priv: Driver private information.
|
|
|
|
*
|
|
|
|
* Describes both mutable and immutable packet trap attributes. Created by
|
|
|
|
* devlink during trap registration and used for all trap related operations.
|
|
|
|
*/
|
|
|
|
struct devlink_trap_item {
|
|
|
|
const struct devlink_trap *trap;
|
|
|
|
struct devlink_trap_group_item *group_item;
|
|
|
|
struct list_head list;
|
|
|
|
enum devlink_trap_action action;
|
|
|
|
struct devlink_stats __percpu *stats;
|
|
|
|
void *priv;
|
|
|
|
};
|
|
|
|
|
2020-03-30 19:38:18 +00:00
|
|
|
static struct devlink_trap_policer_item *
|
|
|
|
devlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
|
|
|
|
{
|
|
|
|
struct devlink_trap_policer_item *policer_item;
|
|
|
|
|
|
|
|
list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
|
|
|
|
if (policer_item->policer->id == id)
|
|
|
|
return policer_item;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
static struct devlink_trap_item *
|
|
|
|
devlink_trap_item_lookup(struct devlink *devlink, const char *name)
|
|
|
|
{
|
|
|
|
struct devlink_trap_item *trap_item;
|
|
|
|
|
|
|
|
list_for_each_entry(trap_item, &devlink->trap_list, list) {
|
|
|
|
if (!strcmp(trap_item->trap->name, name))
|
|
|
|
return trap_item;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_trap_item *
|
|
|
|
devlink_trap_item_get_from_info(struct devlink *devlink,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct nlattr *attr;
|
|
|
|
|
|
|
|
if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
|
|
|
|
return NULL;
|
|
|
|
attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
|
|
|
|
|
|
|
|
return devlink_trap_item_lookup(devlink, nla_data(attr));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_trap_action_get_from_info(struct genl_info *info,
|
|
|
|
enum devlink_trap_action *p_trap_action)
|
|
|
|
{
|
|
|
|
u8 val;
|
|
|
|
|
|
|
|
val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
|
|
|
|
switch (val) {
|
2020-08-23 22:36:59 +00:00
|
|
|
case DEVLINK_TRAP_ACTION_DROP:
|
|
|
|
case DEVLINK_TRAP_ACTION_TRAP:
|
2020-05-29 18:36:39 +00:00
|
|
|
case DEVLINK_TRAP_ACTION_MIRROR:
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
*p_trap_action = val;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_trap_metadata_put(struct sk_buff *msg,
|
|
|
|
const struct devlink_trap *trap)
|
|
|
|
{
|
|
|
|
struct nlattr *attr;
|
|
|
|
|
|
|
|
attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
|
|
|
|
if (!attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
|
|
|
|
nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
|
|
|
|
goto nla_put_failure;
|
2020-02-25 10:45:19 +00:00
|
|
|
if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
|
|
|
|
nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
|
|
|
|
goto nla_put_failure;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
|
|
|
|
nla_nest_end(msg, attr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(msg, attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
|
|
|
|
struct devlink_stats *stats)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
memset(stats, 0, sizeof(*stats));
|
|
|
|
for_each_possible_cpu(i) {
|
|
|
|
struct devlink_stats *cpu_stats;
|
|
|
|
u64 rx_packets, rx_bytes;
|
|
|
|
unsigned int start;
|
|
|
|
|
|
|
|
cpu_stats = per_cpu_ptr(trap_stats, i);
|
|
|
|
do {
|
2022-10-26 13:22:15 +00:00
|
|
|
start = u64_stats_fetch_begin(&cpu_stats->syncp);
|
2022-06-08 15:46:38 +00:00
|
|
|
rx_packets = u64_stats_read(&cpu_stats->rx_packets);
|
|
|
|
rx_bytes = u64_stats_read(&cpu_stats->rx_bytes);
|
2022-10-26 13:22:15 +00:00
|
|
|
} while (u64_stats_fetch_retry(&cpu_stats->syncp, start));
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
|
2022-06-08 15:46:38 +00:00
|
|
|
u64_stats_add(&stats->rx_packets, rx_packets);
|
|
|
|
u64_stats_add(&stats->rx_bytes, rx_bytes);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-14 13:01:12 +00:00
|
|
|
static int
|
|
|
|
devlink_trap_group_stats_put(struct sk_buff *msg,
|
|
|
|
struct devlink_stats __percpu *trap_stats)
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
{
|
|
|
|
struct devlink_stats stats;
|
|
|
|
struct nlattr *attr;
|
|
|
|
|
|
|
|
devlink_trap_stats_read(trap_stats, &stats);
|
|
|
|
|
|
|
|
attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
|
|
|
|
if (!attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
|
2022-06-08 15:46:38 +00:00
|
|
|
u64_stats_read(&stats.rx_packets),
|
|
|
|
DEVLINK_ATTR_PAD))
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
|
2022-06-08 15:46:38 +00:00
|
|
|
u64_stats_read(&stats.rx_bytes),
|
|
|
|
DEVLINK_ATTR_PAD))
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(msg, attr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(msg, attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
2021-06-14 13:01:12 +00:00
|
|
|
static int devlink_trap_stats_put(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
const struct devlink_trap_item *trap_item)
|
|
|
|
{
|
|
|
|
struct devlink_stats stats;
|
|
|
|
struct nlattr *attr;
|
|
|
|
u64 drops = 0;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (devlink->ops->trap_drop_counter_get) {
|
|
|
|
err = devlink->ops->trap_drop_counter_get(devlink,
|
|
|
|
trap_item->trap,
|
|
|
|
&drops);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
devlink_trap_stats_read(trap_item->stats, &stats);
|
|
|
|
|
|
|
|
attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
|
|
|
|
if (!attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink->ops->trap_drop_counter_get &&
|
|
|
|
nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
|
|
|
|
DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
|
2022-06-08 15:46:38 +00:00
|
|
|
u64_stats_read(&stats.rx_packets),
|
|
|
|
DEVLINK_ATTR_PAD))
|
2021-06-14 13:01:12 +00:00
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
|
2022-06-08 15:46:38 +00:00
|
|
|
u64_stats_read(&stats.rx_bytes),
|
|
|
|
DEVLINK_ATTR_PAD))
|
2021-06-14 13:01:12 +00:00
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(msg, attr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(msg, attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
const struct devlink_trap_item *trap_item,
|
|
|
|
enum devlink_command cmd, u32 portid, u32 seq,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
struct devlink_trap_group_item *group_item = trap_item->group_item;
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
|
|
|
|
group_item->group->name))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (trap_item->trap->generic &&
|
|
|
|
nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
err = devlink_trap_metadata_put(msg, trap_item->trap);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2021-06-14 13:01:12 +00:00
|
|
|
err = devlink_trap_stats_put(msg, devlink, trap_item);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_trap_item *trap_item;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (list_empty(&devlink->trap_list))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
trap_item = devlink_trap_item_get_from_info(devlink, info);
|
|
|
|
if (!trap_item) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Device did not register this trap");
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
err = devlink_nl_trap_fill(msg, devlink, trap_item,
|
|
|
|
DEVLINK_CMD_TRAP_NEW, info->snd_portid,
|
|
|
|
info->snd_seq, 0);
|
|
|
|
if (err)
|
|
|
|
goto err_trap_fill;
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
|
|
|
|
err_trap_fill:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_trap_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-05 04:05:31 +00:00
|
|
|
struct devlink_trap_item *trap_item;
|
|
|
|
int idx = 0;
|
|
|
|
int err = 0;
|
2023-01-05 04:05:27 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
list_for_each_entry(trap_item, &devlink->trap_list, list) {
|
|
|
|
if (idx < state->idx) {
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
idx++;
|
2023-01-05 04:05:31 +00:00
|
|
|
continue;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
2023-01-05 04:05:31 +00:00
|
|
|
err = devlink_nl_trap_fill(msg, devlink, trap_item,
|
|
|
|
DEVLINK_CMD_TRAP_NEW,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI);
|
|
|
|
if (err) {
|
|
|
|
state->idx = idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
idx++;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
2023-01-05 04:05:31 +00:00
|
|
|
|
|
|
|
return err;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_trap_get = {
|
2023-01-05 04:05:31 +00:00
|
|
|
.dump_one = devlink_nl_cmd_trap_get_dump_one,
|
|
|
|
};
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
static int __devlink_trap_action_set(struct devlink *devlink,
|
|
|
|
struct devlink_trap_item *trap_item,
|
|
|
|
enum devlink_trap_action trap_action,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (trap_item->action != trap_action &&
|
|
|
|
trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Cannot change action of non-drop traps. Skipping");
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = devlink->ops->trap_action_set(devlink, trap_item->trap,
|
2020-08-03 16:11:34 +00:00
|
|
|
trap_action, extack);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
trap_item->action = trap_action;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_trap_action_set(struct devlink *devlink,
|
|
|
|
struct devlink_trap_item *trap_item,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
enum devlink_trap_action trap_action;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err = devlink_trap_action_get_from_info(info, &trap_action);
|
|
|
|
if (err) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Invalid trap action");
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return __devlink_trap_action_set(devlink, trap_item, trap_action,
|
|
|
|
info->extack);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_trap_item *trap_item;
|
|
|
|
|
|
|
|
if (list_empty(&devlink->trap_list))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
trap_item = devlink_trap_item_get_from_info(devlink, info);
|
|
|
|
if (!trap_item) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Device did not register this trap");
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2020-12-08 12:10:46 +00:00
|
|
|
return devlink_trap_action_set(devlink, trap_item, info);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct devlink_trap_group_item *
|
|
|
|
devlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
|
|
|
|
{
|
|
|
|
struct devlink_trap_group_item *group_item;
|
|
|
|
|
|
|
|
list_for_each_entry(group_item, &devlink->trap_group_list, list) {
|
|
|
|
if (!strcmp(group_item->group->name, name))
|
|
|
|
return group_item;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-22 18:48:30 +00:00
|
|
|
static struct devlink_trap_group_item *
|
|
|
|
devlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
|
|
|
|
{
|
|
|
|
struct devlink_trap_group_item *group_item;
|
|
|
|
|
|
|
|
list_for_each_entry(group_item, &devlink->trap_group_list, list) {
|
|
|
|
if (group_item->group->id == id)
|
|
|
|
return group_item;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
static struct devlink_trap_group_item *
|
|
|
|
devlink_trap_group_item_get_from_info(struct devlink *devlink,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
|
|
|
|
return NULL;
|
|
|
|
name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
|
|
|
|
|
|
|
|
return devlink_trap_group_item_lookup(devlink, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
const struct devlink_trap_group_item *group_item,
|
|
|
|
enum devlink_command cmd, u32 portid, u32 seq,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
|
|
|
|
group_item->group->name))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (group_item->group->generic &&
|
|
|
|
nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2020-03-30 19:38:21 +00:00
|
|
|
if (group_item->policer_item &&
|
|
|
|
nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
|
|
|
|
group_item->policer_item->policer->id))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
2021-06-14 13:01:12 +00:00
|
|
|
err = devlink_trap_group_stats_put(msg, group_item->stats);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_trap_group_item *group_item;
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (list_empty(&devlink->trap_group_list))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
group_item = devlink_trap_group_item_get_from_info(devlink, info);
|
|
|
|
if (!group_item) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Device did not register this trap group");
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
err = devlink_nl_trap_group_fill(msg, devlink, group_item,
|
|
|
|
DEVLINK_CMD_TRAP_GROUP_NEW,
|
|
|
|
info->snd_portid, info->snd_seq, 0);
|
|
|
|
if (err)
|
|
|
|
goto err_trap_group_fill;
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
|
|
|
|
err_trap_group_fill:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_trap_group_get_dump_one(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-05 04:05:31 +00:00
|
|
|
struct devlink_trap_group_item *group_item;
|
|
|
|
int idx = 0;
|
|
|
|
int err = 0;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
|
2023-01-05 04:05:27 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
list_for_each_entry(group_item, &devlink->trap_group_list, list) {
|
|
|
|
if (idx < state->idx) {
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
idx++;
|
2023-01-05 04:05:31 +00:00
|
|
|
continue;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
2023-01-05 04:05:31 +00:00
|
|
|
err = devlink_nl_trap_group_fill(msg, devlink, group_item,
|
|
|
|
DEVLINK_CMD_TRAP_GROUP_NEW,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI);
|
|
|
|
if (err) {
|
|
|
|
state->idx = idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
idx++;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
2023-01-05 04:05:31 +00:00
|
|
|
|
|
|
|
return err;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_trap_group_get = {
|
2023-01-05 04:05:31 +00:00
|
|
|
.dump_one = devlink_nl_cmd_trap_group_get_dump_one,
|
|
|
|
};
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
static int
|
|
|
|
__devlink_trap_group_action_set(struct devlink *devlink,
|
|
|
|
struct devlink_trap_group_item *group_item,
|
|
|
|
enum devlink_trap_action trap_action,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
const char *group_name = group_item->group->name;
|
|
|
|
struct devlink_trap_item *trap_item;
|
|
|
|
int err;
|
|
|
|
|
2020-10-01 15:11:46 +00:00
|
|
|
if (devlink->ops->trap_group_action_set) {
|
|
|
|
err = devlink->ops->trap_group_action_set(devlink, group_item->group,
|
|
|
|
trap_action, extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
list_for_each_entry(trap_item, &devlink->trap_list, list) {
|
|
|
|
if (strcmp(trap_item->group_item->group->name, group_name))
|
|
|
|
continue;
|
|
|
|
if (trap_item->action != trap_action &&
|
|
|
|
trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP)
|
|
|
|
continue;
|
|
|
|
trap_item->action = trap_action;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
list_for_each_entry(trap_item, &devlink->trap_list, list) {
|
2020-03-22 18:48:30 +00:00
|
|
|
if (strcmp(trap_item->group_item->group->name, group_name))
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
continue;
|
|
|
|
err = __devlink_trap_action_set(devlink, trap_item,
|
|
|
|
trap_action, extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_trap_group_action_set(struct devlink *devlink,
|
|
|
|
struct devlink_trap_group_item *group_item,
|
2020-03-30 19:38:22 +00:00
|
|
|
struct genl_info *info, bool *p_modified)
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
{
|
|
|
|
enum devlink_trap_action trap_action;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err = devlink_trap_action_get_from_info(info, &trap_action);
|
|
|
|
if (err) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(info->extack, "Invalid trap action");
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
|
|
|
|
info->extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2020-03-30 19:38:22 +00:00
|
|
|
*p_modified = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_trap_group_set(struct devlink *devlink,
|
|
|
|
struct devlink_trap_group_item *group_item,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink_trap_policer_item *policer_item;
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
const struct devlink_trap_policer *policer;
|
|
|
|
struct nlattr **attrs = info->attrs;
|
2023-01-13 07:35:43 +00:00
|
|
|
u32 policer_id;
|
2020-03-30 19:38:22 +00:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!devlink->ops->trap_group_set)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2023-01-13 07:35:43 +00:00
|
|
|
policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
|
|
|
|
policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
|
|
|
|
if (policer_id && !policer_item) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
|
2023-01-13 07:35:43 +00:00
|
|
|
return -ENOENT;
|
2020-03-30 19:38:22 +00:00
|
|
|
}
|
|
|
|
policer = policer_item ? policer_item->policer : NULL;
|
|
|
|
|
2020-08-03 16:11:34 +00:00
|
|
|
err = devlink->ops->trap_group_set(devlink, group_item->group, policer,
|
|
|
|
extack);
|
2020-03-30 19:38:22 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
group_item->policer_item = policer_item;
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct devlink_trap_group_item *group_item;
|
2020-03-30 19:38:22 +00:00
|
|
|
bool modified = false;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (list_empty(&devlink->trap_group_list))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
group_item = devlink_trap_group_item_get_from_info(devlink, info);
|
|
|
|
if (!group_item) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Device did not register this trap group");
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2020-03-30 19:38:22 +00:00
|
|
|
err = devlink_trap_group_action_set(devlink, group_item, info,
|
|
|
|
&modified);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2020-03-30 19:38:22 +00:00
|
|
|
err = devlink_trap_group_set(devlink, group_item, info);
|
|
|
|
if (err)
|
|
|
|
goto err_trap_group_set;
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return 0;
|
2020-03-30 19:38:22 +00:00
|
|
|
|
|
|
|
err_trap_group_set:
|
|
|
|
if (modified)
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Trap group set failed, but some changes were committed already");
|
2020-03-30 19:38:22 +00:00
|
|
|
return err;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
|
|
|
|
2020-03-30 19:38:18 +00:00
|
|
|
static struct devlink_trap_policer_item *
|
|
|
|
devlink_trap_policer_item_get_from_info(struct devlink *devlink,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
u32 id;
|
|
|
|
|
|
|
|
if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
|
|
|
|
return NULL;
|
|
|
|
id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
|
|
|
|
|
|
|
|
return devlink_trap_policer_item_lookup(devlink, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
const struct devlink_trap_policer *policer)
|
|
|
|
{
|
|
|
|
struct nlattr *attr;
|
|
|
|
u64 drops;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!devlink->ops->trap_policer_counter_get)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
|
|
|
|
if (!attr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
|
|
|
|
DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
nla_nest_end(msg, attr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
nla_nest_cancel(msg, attr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
|
|
|
|
const struct devlink_trap_policer_item *policer_item,
|
|
|
|
enum devlink_command cmd, u32 portid, u32 seq,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
void *hdr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
|
|
|
|
if (!hdr)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
if (devlink_nl_put_handle(msg, devlink))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
|
|
|
|
policer_item->policer->id))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
|
|
|
|
policer_item->rate, DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
|
|
|
|
policer_item->burst, DEVLINK_ATTR_PAD))
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
err = devlink_trap_policer_stats_put(msg, devlink,
|
|
|
|
policer_item->policer);
|
|
|
|
if (err)
|
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
|
|
genlmsg_end(msg, hdr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nla_put_failure:
|
|
|
|
genlmsg_cancel(msg, hdr);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink_trap_policer_item *policer_item;
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (list_empty(&devlink->trap_policer_list))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
|
|
|
|
if (!policer_item) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
|
2020-03-30 19:38:18 +00:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
|
|
|
|
DEVLINK_CMD_TRAP_POLICER_NEW,
|
|
|
|
info->snd_portid, info->snd_seq, 0);
|
|
|
|
if (err)
|
|
|
|
goto err_trap_policer_fill;
|
|
|
|
|
|
|
|
return genlmsg_reply(msg, info);
|
|
|
|
|
|
|
|
err_trap_policer_fill:
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
static int
|
|
|
|
devlink_nl_cmd_trap_policer_get_dump_one(struct sk_buff *msg,
|
|
|
|
struct devlink *devlink,
|
|
|
|
struct netlink_callback *cb)
|
2020-03-30 19:38:18 +00:00
|
|
|
{
|
2023-01-05 04:05:22 +00:00
|
|
|
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
|
2023-01-05 04:05:31 +00:00
|
|
|
struct devlink_trap_policer_item *policer_item;
|
|
|
|
int idx = 0;
|
|
|
|
int err = 0;
|
2023-01-05 04:05:27 +00:00
|
|
|
|
2023-01-05 04:05:31 +00:00
|
|
|
list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
|
|
|
|
if (idx < state->idx) {
|
2020-03-30 19:38:18 +00:00
|
|
|
idx++;
|
2023-01-05 04:05:31 +00:00
|
|
|
continue;
|
2020-03-30 19:38:18 +00:00
|
|
|
}
|
2023-01-05 04:05:31 +00:00
|
|
|
err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
|
|
|
|
DEVLINK_CMD_TRAP_POLICER_NEW,
|
|
|
|
NETLINK_CB(cb->skb).portid,
|
|
|
|
cb->nlh->nlmsg_seq,
|
|
|
|
NLM_F_MULTI);
|
|
|
|
if (err) {
|
|
|
|
state->idx = idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
idx++;
|
2020-03-30 19:38:18 +00:00
|
|
|
}
|
2023-01-05 04:05:31 +00:00
|
|
|
|
|
|
|
return err;
|
2020-03-30 19:38:18 +00:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:06:13 +00:00
|
|
|
const struct devlink_cmd devl_cmd_trap_policer_get = {
|
2023-01-05 04:05:31 +00:00
|
|
|
.dump_one = devlink_nl_cmd_trap_policer_get_dump_one,
|
|
|
|
};
|
|
|
|
|
2020-03-30 19:38:18 +00:00
|
|
|
static int
|
|
|
|
devlink_trap_policer_set(struct devlink *devlink,
|
|
|
|
struct devlink_trap_policer_item *policer_item,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
struct nlattr **attrs = info->attrs;
|
|
|
|
u64 rate, burst;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
rate = policer_item->rate;
|
|
|
|
burst = policer_item->burst;
|
|
|
|
|
|
|
|
if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
|
|
|
|
rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
|
|
|
|
|
|
|
|
if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
|
|
|
|
burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
|
|
|
|
|
|
|
|
if (rate < policer_item->policer->min_rate) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Policer rate lower than limit");
|
2020-03-30 19:38:18 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rate > policer_item->policer->max_rate) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Policer rate higher than limit");
|
2020-03-30 19:38:18 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (burst < policer_item->policer->min_burst) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Policer burst size lower than limit");
|
2020-03-30 19:38:18 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (burst > policer_item->policer->max_burst) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Policer burst size higher than limit");
|
2020-03-30 19:38:18 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
|
|
|
|
rate, burst, info->extack);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
policer_item->rate = rate;
|
|
|
|
policer_item->burst = burst;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
|
|
|
|
struct genl_info *info)
|
|
|
|
{
|
|
|
|
struct devlink_trap_policer_item *policer_item;
|
|
|
|
struct netlink_ext_ack *extack = info->extack;
|
|
|
|
struct devlink *devlink = info->user_ptr[0];
|
|
|
|
|
|
|
|
if (list_empty(&devlink->trap_policer_list))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (!devlink->ops->trap_policer_set)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
|
|
|
|
if (!policer_item) {
|
2023-02-09 22:20:45 +00:00
|
|
|
NL_SET_ERR_MSG(extack, "Device did not register this trap policer");
|
2020-03-30 19:38:18 +00:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return devlink_trap_policer_set(devlink, policer_item, info);
|
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:20 +00:00
|
|
|
const struct genl_small_ops devlink_nl_ops[56] = {
|
2016-02-26 16:32:23 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-02-26 16:32:23 +00:00
|
|
|
.doit = devlink_nl_cmd_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2016-02-26 16:32:23 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_PORT_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-02-26 16:32:23 +00:00
|
|
|
.doit = devlink_nl_cmd_port_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2016-02-26 16:32:23 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
|
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_PORT_SET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-02-26 16:32:23 +00:00
|
|
|
.doit = devlink_nl_cmd_port_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
|
|
|
|
},
|
2021-06-02 12:17:19 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_RATE_GET,
|
|
|
|
.doit = devlink_nl_cmd_rate_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2021-06-02 12:17:19 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_RATE,
|
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
2021-06-02 12:17:22 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_RATE_SET,
|
|
|
|
.doit = devlink_nl_cmd_rate_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_RATE,
|
|
|
|
},
|
2021-06-02 12:17:25 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_RATE_NEW,
|
|
|
|
.doit = devlink_nl_cmd_rate_new_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_RATE_DEL,
|
|
|
|
.doit = devlink_nl_cmd_rate_del_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_RATE_NODE,
|
|
|
|
},
|
2016-02-26 16:32:23 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_PORT_SPLIT,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-02-26 16:32:23 +00:00
|
|
|
.doit = devlink_nl_cmd_port_split_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
2022-03-15 06:00:09 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
|
2016-02-26 16:32:23 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_PORT_UNSPLIT,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-02-26 16:32:23 +00:00
|
|
|
.doit = devlink_nl_cmd_port_unsplit_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
2022-03-15 06:00:09 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
|
2016-02-26 16:32:23 +00:00
|
|
|
},
|
2020-12-12 06:12:14 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_PORT_NEW,
|
|
|
|
.doit = devlink_nl_cmd_port_new_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_PORT_DEL,
|
|
|
|
.doit = devlink_nl_cmd_port_del_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2022-04-18 06:42:25 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_LINECARD_GET,
|
|
|
|
.doit = devlink_nl_cmd_linecard_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2022-04-18 06:42:25 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
|
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
2022-04-18 06:42:26 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_LINECARD_SET,
|
|
|
|
.doit = devlink_nl_cmd_linecard_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD,
|
|
|
|
},
|
2016-04-14 16:19:13 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SB_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-04-14 16:19:13 +00:00
|
|
|
.doit = devlink_nl_cmd_sb_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2016-04-14 16:19:13 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SB_POOL_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-04-14 16:19:13 +00:00
|
|
|
.doit = devlink_nl_cmd_sb_pool_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2016-04-14 16:19:13 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SB_POOL_SET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-04-14 16:19:13 +00:00
|
|
|
.doit = devlink_nl_cmd_sb_pool_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-04-14 16:19:13 +00:00
|
|
|
.doit = devlink_nl_cmd_sb_port_pool_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2020-07-22 15:57:11 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
|
2016-04-14 16:19:13 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-04-14 16:19:13 +00:00
|
|
|
.doit = devlink_nl_cmd_sb_port_pool_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
2020-07-22 15:57:11 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
|
2016-04-14 16:19:13 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-04-14 16:19:13 +00:00
|
|
|
.doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2020-07-22 15:57:11 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
|
2016-04-14 16:19:13 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-04-14 16:19:13 +00:00
|
|
|
.doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
2020-07-22 15:57:11 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
|
2016-04-14 16:19:13 +00:00
|
|
|
},
|
2016-04-14 16:19:14 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-04-14 16:19:14 +00:00
|
|
|
.doit = devlink_nl_cmd_sb_occ_snapshot_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2016-04-14 16:19:14 +00:00
|
|
|
.doit = devlink_nl_cmd_sb_occ_max_clear_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2016-07-01 11:51:01 +00:00
|
|
|
{
|
2017-02-09 14:54:33 +00:00
|
|
|
.cmd = DEVLINK_CMD_ESWITCH_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2017-02-09 14:54:33 +00:00
|
|
|
.doit = devlink_nl_cmd_eswitch_get_doit,
|
2016-07-01 11:51:01 +00:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
|
|
|
{
|
2017-02-09 14:54:33 +00:00
|
|
|
.cmd = DEVLINK_CMD_ESWITCH_SET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2017-02-09 14:54:33 +00:00
|
|
|
.doit = devlink_nl_cmd_eswitch_set_doit,
|
2016-07-01 11:51:01 +00:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2017-03-28 15:24:10 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2017-03-28 15:24:10 +00:00
|
|
|
.doit = devlink_nl_cmd_dpipe_table_get,
|
2018-03-08 10:52:25 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
2017-03-28 15:24:10 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2017-03-28 15:24:10 +00:00
|
|
|
.doit = devlink_nl_cmd_dpipe_entries_get,
|
2018-03-08 10:52:25 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
2017-03-28 15:24:10 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2017-03-28 15:24:10 +00:00
|
|
|
.doit = devlink_nl_cmd_dpipe_headers_get,
|
2018-03-08 10:52:25 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
2017-03-28 15:24:10 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2017-03-28 15:24:10 +00:00
|
|
|
.doit = devlink_nl_cmd_dpipe_table_counters_set,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2018-01-15 07:59:03 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_RESOURCE_SET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2018-01-15 07:59:03 +00:00
|
|
|
.doit = devlink_nl_cmd_resource_set,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_RESOURCE_DUMP,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2018-01-15 07:59:03 +00:00
|
|
|
.doit = devlink_nl_cmd_resource_dump,
|
2018-03-08 10:52:25 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
2018-01-15 07:59:03 +00:00
|
|
|
},
|
2018-01-15 07:59:04 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_RELOAD,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2018-01-15 07:59:04 +00:00
|
|
|
.doit = devlink_nl_cmd_reload,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2018-07-04 11:30:29 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_PARAM_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2018-07-04 11:30:29 +00:00
|
|
|
.doit = devlink_nl_cmd_param_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2018-07-04 11:30:29 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
2018-07-04 11:30:30 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_PARAM_SET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2018-07-04 11:30:30 +00:00
|
|
|
.doit = devlink_nl_cmd_param_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2019-01-28 12:30:21 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_PORT_PARAM_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2019-01-28 12:30:21 +00:00
|
|
|
.doit = devlink_nl_cmd_port_param_get_doit,
|
|
|
|
.dumpit = devlink_nl_cmd_port_param_get_dumpit,
|
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
|
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
2019-01-28 12:30:22 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_PORT_PARAM_SET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2019-01-28 12:30:22 +00:00
|
|
|
.doit = devlink_nl_cmd_port_param_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
|
|
|
|
},
|
2018-07-12 12:13:11 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_REGION_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2018-07-12 12:13:11 +00:00
|
|
|
.doit = devlink_nl_cmd_region_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2018-07-12 12:13:11 +00:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2020-03-26 18:37:16 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_REGION_NEW,
|
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
|
|
|
.doit = devlink_nl_cmd_region_new,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2018-07-12 12:13:13 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_REGION_DEL,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2018-07-12 12:13:13 +00:00
|
|
|
.doit = devlink_nl_cmd_region_del,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2018-07-12 12:13:14 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_REGION_READ,
|
2019-10-05 18:04:42 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT |
|
|
|
|
GENL_DONT_VALIDATE_DUMP_STRICT,
|
2018-07-12 12:13:14 +00:00
|
|
|
.dumpit = devlink_nl_cmd_region_read_dumpit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2019-01-31 18:50:40 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_INFO_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2019-01-31 18:50:40 +00:00
|
|
|
.doit = devlink_nl_cmd_info_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2019-01-31 18:50:40 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
2019-02-07 09:36:35 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2019-02-07 09:36:35 +00:00
|
|
|
.doit = devlink_nl_cmd_health_reporter_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2022-07-28 15:53:50 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
|
2019-02-07 09:36:35 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
2019-02-07 09:36:36 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2019-02-07 09:36:36 +00:00
|
|
|
.doit = devlink_nl_cmd_health_reporter_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
2022-07-28 15:53:50 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
|
2019-02-07 09:36:36 +00:00
|
|
|
},
|
2019-02-07 09:36:37 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2019-02-07 09:36:37 +00:00
|
|
|
.doit = devlink_nl_cmd_health_reporter_recover_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
2022-07-28 15:53:50 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
|
2019-02-07 09:36:37 +00:00
|
|
|
},
|
2019-02-07 09:36:38 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2019-02-07 09:36:38 +00:00
|
|
|
.doit = devlink_nl_cmd_health_reporter_diagnose_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
2022-07-28 15:53:50 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
|
2019-02-07 09:36:38 +00:00
|
|
|
},
|
2019-02-07 09:36:39 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
|
2019-10-07 07:28:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT |
|
|
|
|
GENL_DONT_VALIDATE_DUMP_STRICT,
|
2019-05-16 06:49:20 +00:00
|
|
|
.dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
|
2019-02-07 09:36:39 +00:00
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2019-02-07 09:36:39 +00:00
|
|
|
.doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
2022-07-28 15:53:50 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
|
2019-02-07 09:36:39 +00:00
|
|
|
},
|
2020-09-15 08:40:57 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_HEALTH_REPORTER_TEST,
|
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
|
|
|
.doit = devlink_nl_cmd_health_reporter_test_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
2022-07-28 15:53:50 +00:00
|
|
|
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
|
2020-09-15 08:40:57 +00:00
|
|
|
},
|
2019-02-14 21:40:44 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_FLASH_UPDATE,
|
2019-04-26 12:07:31 +00:00
|
|
|
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
2019-02-14 21:40:44 +00:00
|
|
|
.doit = devlink_nl_cmd_flash_update,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_TRAP_GET,
|
|
|
|
.doit = devlink_nl_cmd_trap_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_TRAP_SET,
|
|
|
|
.doit = devlink_nl_cmd_trap_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_TRAP_GROUP_GET,
|
|
|
|
.doit = devlink_nl_cmd_trap_group_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_TRAP_GROUP_SET,
|
|
|
|
.doit = devlink_nl_cmd_trap_group_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2020-03-30 19:38:18 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_TRAP_POLICER_GET,
|
|
|
|
.doit = devlink_nl_cmd_trap_policer_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2020-03-30 19:38:18 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_TRAP_POLICER_SET,
|
|
|
|
.doit = devlink_nl_cmd_trap_policer_set_doit,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2022-07-27 16:57:20 +00:00
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SELFTESTS_GET,
|
|
|
|
.doit = devlink_nl_cmd_selftests_get_doit,
|
2023-01-31 09:06:11 +00:00
|
|
|
.dumpit = devlink_nl_instance_iter_dumpit,
|
2022-07-27 16:57:20 +00:00
|
|
|
/* can be retrieved by unprivileged users */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.cmd = DEVLINK_CMD_SELFTESTS_RUN,
|
|
|
|
.doit = devlink_nl_cmd_selftests_run,
|
|
|
|
.flags = GENL_ADMIN_PERM,
|
|
|
|
},
|
2023-01-05 04:05:20 +00:00
|
|
|
/* -- No new ops here! Use split ops going forward! -- */
|
2016-10-24 12:40:03 +00:00
|
|
|
};
|
|
|
|
|
2021-09-25 11:22:41 +00:00
|
|
|
static void
|
|
|
|
devlink_trap_policer_notify(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_policer_item *policer_item,
|
|
|
|
enum devlink_command cmd);
|
|
|
|
static void
|
|
|
|
devlink_trap_group_notify(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_group_item *group_item,
|
|
|
|
enum devlink_command cmd);
|
|
|
|
static void devlink_trap_notify(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_item *trap_item,
|
|
|
|
enum devlink_command cmd);
|
|
|
|
|
2023-01-05 04:05:19 +00:00
|
|
|
void devlink_notify_register(struct devlink *devlink)
|
2021-09-25 11:22:41 +00:00
|
|
|
{
|
|
|
|
struct devlink_trap_policer_item *policer_item;
|
|
|
|
struct devlink_trap_group_item *group_item;
|
2021-10-21 14:16:13 +00:00
|
|
|
struct devlink_param_item *param_item;
|
2021-09-25 11:22:41 +00:00
|
|
|
struct devlink_trap_item *trap_item;
|
|
|
|
struct devlink_port *devlink_port;
|
2022-04-18 06:42:25 +00:00
|
|
|
struct devlink_linecard *linecard;
|
2021-09-29 14:18:20 +00:00
|
|
|
struct devlink_rate *rate_node;
|
|
|
|
struct devlink_region *region;
|
2022-11-30 08:52:50 +00:00
|
|
|
unsigned long port_index;
|
2023-02-10 10:01:29 +00:00
|
|
|
unsigned long param_id;
|
2021-09-25 11:22:41 +00:00
|
|
|
|
|
|
|
devlink_notify(devlink, DEVLINK_CMD_NEW);
|
2022-04-18 06:42:25 +00:00
|
|
|
list_for_each_entry(linecard, &devlink->linecard_list, list)
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
|
2022-11-30 08:52:50 +00:00
|
|
|
xa_for_each(&devlink->ports, port_index, devlink_port)
|
2021-09-25 11:22:41 +00:00
|
|
|
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
|
|
|
|
|
|
|
|
list_for_each_entry(policer_item, &devlink->trap_policer_list, list)
|
|
|
|
devlink_trap_policer_notify(devlink, policer_item,
|
|
|
|
DEVLINK_CMD_TRAP_POLICER_NEW);
|
|
|
|
|
|
|
|
list_for_each_entry(group_item, &devlink->trap_group_list, list)
|
|
|
|
devlink_trap_group_notify(devlink, group_item,
|
|
|
|
DEVLINK_CMD_TRAP_GROUP_NEW);
|
|
|
|
|
|
|
|
list_for_each_entry(trap_item, &devlink->trap_list, list)
|
|
|
|
devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
|
|
|
|
|
2021-09-29 14:18:20 +00:00
|
|
|
list_for_each_entry(rate_node, &devlink->rate_list, list)
|
|
|
|
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
|
|
|
|
|
|
|
|
list_for_each_entry(region, &devlink->region_list, list)
|
|
|
|
devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
|
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
xa_for_each(&devlink->params, param_id, param_item)
|
2021-10-21 14:16:13 +00:00
|
|
|
devlink_param_notify(devlink, 0, param_item,
|
|
|
|
DEVLINK_CMD_PARAM_NEW);
|
2021-09-25 11:22:41 +00:00
|
|
|
}
|
|
|
|
|
2023-01-05 04:05:19 +00:00
|
|
|
void devlink_notify_unregister(struct devlink *devlink)
|
2021-09-25 11:22:41 +00:00
|
|
|
{
|
|
|
|
struct devlink_trap_policer_item *policer_item;
|
|
|
|
struct devlink_trap_group_item *group_item;
|
2021-10-21 14:16:13 +00:00
|
|
|
struct devlink_param_item *param_item;
|
2021-09-25 11:22:41 +00:00
|
|
|
struct devlink_trap_item *trap_item;
|
|
|
|
struct devlink_port *devlink_port;
|
2021-09-29 14:18:20 +00:00
|
|
|
struct devlink_rate *rate_node;
|
|
|
|
struct devlink_region *region;
|
2022-11-30 08:52:50 +00:00
|
|
|
unsigned long port_index;
|
2023-02-10 10:01:29 +00:00
|
|
|
unsigned long param_id;
|
2021-09-25 11:22:41 +00:00
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
xa_for_each(&devlink->params, param_id, param_item)
|
2021-10-21 14:16:13 +00:00
|
|
|
devlink_param_notify(devlink, 0, param_item,
|
|
|
|
DEVLINK_CMD_PARAM_DEL);
|
2021-09-25 11:22:41 +00:00
|
|
|
|
2021-09-29 14:18:20 +00:00
|
|
|
list_for_each_entry_reverse(region, &devlink->region_list, list)
|
|
|
|
devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
|
|
|
|
|
|
|
|
list_for_each_entry_reverse(rate_node, &devlink->rate_list, list)
|
|
|
|
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL);
|
|
|
|
|
2021-09-25 11:22:41 +00:00
|
|
|
list_for_each_entry_reverse(trap_item, &devlink->trap_list, list)
|
|
|
|
devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
|
|
|
|
|
|
|
|
list_for_each_entry_reverse(group_item, &devlink->trap_group_list, list)
|
|
|
|
devlink_trap_group_notify(devlink, group_item,
|
|
|
|
DEVLINK_CMD_TRAP_GROUP_DEL);
|
|
|
|
list_for_each_entry_reverse(policer_item, &devlink->trap_policer_list,
|
|
|
|
list)
|
|
|
|
devlink_trap_policer_notify(devlink, policer_item,
|
|
|
|
DEVLINK_CMD_TRAP_POLICER_DEL);
|
|
|
|
|
2022-11-30 08:52:50 +00:00
|
|
|
xa_for_each(&devlink->ports, port_index, devlink_port)
|
2021-09-25 11:22:41 +00:00
|
|
|
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
|
|
|
|
devlink_notify(devlink, DEVLINK_CMD_DEL);
|
|
|
|
}
|
|
|
|
|
2019-05-23 08:43:35 +00:00
|
|
|
static void devlink_port_type_warn(struct work_struct *work)
|
|
|
|
{
|
|
|
|
WARN(true, "Type was not set for devlink port.");
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
|
|
|
|
{
|
|
|
|
/* Ignore CPU and DSA flavours. */
|
|
|
|
return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
|
2020-10-04 16:12:51 +00:00
|
|
|
devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA &&
|
|
|
|
devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_UNUSED;
|
2019-05-23 08:43:35 +00:00
|
|
|
}
|
|
|
|
|
2020-01-09 17:57:41 +00:00
|
|
|
#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
|
2019-05-23 08:43:35 +00:00
|
|
|
|
|
|
|
static void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
|
|
|
|
{
|
|
|
|
if (!devlink_port_type_should_warn(devlink_port))
|
|
|
|
return;
|
|
|
|
/* Schedule a work to WARN in case driver does not set port
|
|
|
|
* type within timeout.
|
|
|
|
*/
|
|
|
|
schedule_delayed_work(&devlink_port->type_warn_dw,
|
|
|
|
DEVLINK_PORT_TYPE_WARN_TIMEOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
|
|
|
|
{
|
|
|
|
if (!devlink_port_type_should_warn(devlink_port))
|
|
|
|
return;
|
|
|
|
cancel_delayed_work_sync(&devlink_port->type_warn_dw);
|
|
|
|
}
|
|
|
|
|
2022-09-29 07:28:58 +00:00
|
|
|
/**
|
|
|
|
* devlink_port_init() - Init devlink port
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @devlink_port: devlink port
|
|
|
|
*
|
|
|
|
* Initialize essencial stuff that is needed for functions
|
|
|
|
* that may be called before devlink port registration.
|
|
|
|
* Call to this function is optional and not needed
|
|
|
|
* in case the driver does not use such functions.
|
|
|
|
*/
|
|
|
|
void devlink_port_init(struct devlink *devlink,
|
|
|
|
struct devlink_port *devlink_port)
|
|
|
|
{
|
|
|
|
if (devlink_port->initialized)
|
|
|
|
return;
|
|
|
|
devlink_port->devlink = devlink;
|
|
|
|
INIT_LIST_HEAD(&devlink_port->region_list);
|
|
|
|
devlink_port->initialized = true;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_init);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_port_fini() - Deinitialize devlink port
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
|
|
|
*
|
|
|
|
* Deinitialize essencial stuff that is in use for functions
|
|
|
|
* that may be called after devlink port unregistration.
|
|
|
|
* Call to this function is optional and not needed
|
|
|
|
* in case the driver does not use such functions.
|
|
|
|
*/
|
|
|
|
void devlink_port_fini(struct devlink_port *devlink_port)
|
|
|
|
{
|
|
|
|
WARN_ON(!list_empty(&devlink_port->region_list));
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_fini);
|
|
|
|
|
2022-07-12 10:24:22 +00:00
|
|
|
/**
|
|
|
|
* devl_port_register() - Register devlink port
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @devlink_port: devlink port
|
|
|
|
* @port_index: driver-specific numerical identifier of the port
|
|
|
|
*
|
|
|
|
* Register devlink port with provided port index. User can use
|
|
|
|
* any indexing, even hw-related one. devlink_port structure
|
|
|
|
* is convenient to be embedded inside user driver private structure.
|
|
|
|
* Note that the caller should take care of zeroing the devlink_port
|
|
|
|
* structure.
|
|
|
|
*/
|
2022-03-15 06:00:04 +00:00
|
|
|
int devl_port_register(struct devlink *devlink,
|
|
|
|
struct devlink_port *devlink_port,
|
|
|
|
unsigned int port_index)
|
|
|
|
{
|
2022-11-30 08:52:50 +00:00
|
|
|
int err;
|
2022-03-15 06:00:04 +00:00
|
|
|
|
2022-11-30 08:52:50 +00:00
|
|
|
devl_assert_locked(devlink);
|
2022-03-15 06:00:04 +00:00
|
|
|
|
2022-09-29 07:28:56 +00:00
|
|
|
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
|
|
|
|
2022-09-29 07:28:58 +00:00
|
|
|
devlink_port_init(devlink, devlink_port);
|
2022-09-29 07:28:57 +00:00
|
|
|
devlink_port->registered = true;
|
2022-03-15 06:00:04 +00:00
|
|
|
devlink_port->index = port_index;
|
|
|
|
spin_lock_init(&devlink_port->type_lock);
|
|
|
|
INIT_LIST_HEAD(&devlink_port->reporter_list);
|
2022-11-30 08:52:50 +00:00
|
|
|
err = xa_insert(&devlink->ports, port_index, devlink_port, GFP_KERNEL);
|
2023-01-18 15:21:09 +00:00
|
|
|
if (err)
|
2022-11-30 08:52:50 +00:00
|
|
|
return err;
|
2022-03-15 06:00:04 +00:00
|
|
|
|
|
|
|
INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
|
|
|
|
devlink_port_type_warn_schedule(devlink_port);
|
|
|
|
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_port_register);
|
|
|
|
|
2016-02-26 16:32:23 +00:00
|
|
|
/**
|
|
|
|
* devlink_port_register - Register devlink port
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @devlink_port: devlink port
|
2019-02-27 19:36:36 +00:00
|
|
|
* @port_index: driver-specific numerical identifier of the port
|
2016-02-26 16:32:23 +00:00
|
|
|
*
|
|
|
|
* Register devlink port with provided port index. User can use
|
|
|
|
* any indexing, even hw-related one. devlink_port structure
|
|
|
|
* is convenient to be embedded inside user driver private structure.
|
|
|
|
* Note that the caller should take care of zeroing the devlink_port
|
|
|
|
* structure.
|
2022-07-12 10:24:22 +00:00
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
2016-02-26 16:32:23 +00:00
|
|
|
*/
|
|
|
|
int devlink_port_register(struct devlink *devlink,
|
|
|
|
struct devlink_port *devlink_port,
|
|
|
|
unsigned int port_index)
|
|
|
|
{
|
2022-03-15 06:00:04 +00:00
|
|
|
int err;
|
2021-07-28 07:33:47 +00:00
|
|
|
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_lock(devlink);
|
2022-03-15 06:00:04 +00:00
|
|
|
err = devl_port_register(devlink, devlink_port, port_index);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2022-03-15 06:00:04 +00:00
|
|
|
return err;
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_register);
|
|
|
|
|
2022-07-12 10:24:22 +00:00
|
|
|
/**
|
|
|
|
* devl_port_unregister() - Unregister devlink port
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
|
|
|
*/
|
2022-03-15 06:00:04 +00:00
|
|
|
void devl_port_unregister(struct devlink_port *devlink_port)
|
|
|
|
{
|
|
|
|
lockdep_assert_held(&devlink_port->devlink->lock);
|
2022-11-02 16:02:08 +00:00
|
|
|
WARN_ON(devlink_port->type != DEVLINK_PORT_TYPE_NOTSET);
|
2022-03-15 06:00:04 +00:00
|
|
|
|
|
|
|
devlink_port_type_warn_cancel(devlink_port);
|
|
|
|
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
|
2022-11-30 08:52:50 +00:00
|
|
|
xa_erase(&devlink_port->devlink->ports, devlink_port->index);
|
2022-03-15 06:00:04 +00:00
|
|
|
WARN_ON(!list_empty(&devlink_port->reporter_list));
|
2022-09-29 07:28:57 +00:00
|
|
|
devlink_port->registered = false;
|
2022-03-15 06:00:04 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_port_unregister);
|
|
|
|
|
2016-02-26 16:32:23 +00:00
|
|
|
/**
|
|
|
|
* devlink_port_unregister - Unregister devlink port
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
2022-07-12 10:24:22 +00:00
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
2016-02-26 16:32:23 +00:00
|
|
|
*/
|
|
|
|
void devlink_port_unregister(struct devlink_port *devlink_port)
|
|
|
|
{
|
2018-01-15 07:59:02 +00:00
|
|
|
struct devlink *devlink = devlink_port->devlink;
|
|
|
|
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_lock(devlink);
|
2022-03-15 06:00:04 +00:00
|
|
|
devl_port_unregister(devlink_port);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_unregister);
|
|
|
|
|
2020-09-08 22:21:13 +00:00
|
|
|
static void devlink_port_type_netdev_checks(struct devlink_port *devlink_port,
|
|
|
|
struct net_device *netdev)
|
2016-02-26 16:32:23 +00:00
|
|
|
{
|
2019-04-03 12:24:27 +00:00
|
|
|
const struct net_device_ops *ops = netdev->netdev_ops;
|
|
|
|
|
2019-03-28 12:56:46 +00:00
|
|
|
/* If driver registers devlink port, it should set devlink port
|
|
|
|
* attributes accordingly so the compat functions are called
|
|
|
|
* and the original ops are not used.
|
|
|
|
*/
|
2019-04-03 12:24:27 +00:00
|
|
|
if (ops->ndo_get_phys_port_name) {
|
2019-03-28 12:56:46 +00:00
|
|
|
/* Some drivers use the same set of ndos for netdevs
|
|
|
|
* that have devlink_port registered and also for
|
|
|
|
* those who don't. Make sure that ndo_get_phys_port_name
|
|
|
|
* returns -EOPNOTSUPP here in case it is defined.
|
|
|
|
* Warn if not.
|
|
|
|
*/
|
|
|
|
char name[IFNAMSIZ];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
|
|
|
|
WARN_ON(err != -EOPNOTSUPP);
|
|
|
|
}
|
2019-04-03 12:24:27 +00:00
|
|
|
if (ops->ndo_get_port_parent_id) {
|
|
|
|
/* Some drivers use the same set of ndos for netdevs
|
|
|
|
* that have devlink_port registered and also for
|
|
|
|
* those who don't. Make sure that ndo_get_port_parent_id
|
|
|
|
* returns -EOPNOTSUPP here in case it is defined.
|
|
|
|
* Warn if not.
|
|
|
|
*/
|
|
|
|
struct netdev_phys_item_id ppid;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = ops->ndo_get_port_parent_id(netdev, &ppid);
|
|
|
|
WARN_ON(err != -EOPNOTSUPP);
|
|
|
|
}
|
2020-09-08 22:21:13 +00:00
|
|
|
}
|
|
|
|
|
2022-11-02 16:02:01 +00:00
|
|
|
static void __devlink_port_type_set(struct devlink_port *devlink_port,
|
|
|
|
enum devlink_port_type type,
|
2022-11-02 16:02:07 +00:00
|
|
|
void *type_dev)
|
2022-11-02 16:02:01 +00:00
|
|
|
{
|
|
|
|
struct net_device *netdev = type_dev;
|
|
|
|
|
|
|
|
ASSERT_DEVLINK_PORT_REGISTERED(devlink_port);
|
|
|
|
|
|
|
|
if (type == DEVLINK_PORT_TYPE_NOTSET) {
|
|
|
|
devlink_port_type_warn_schedule(devlink_port);
|
|
|
|
} else {
|
|
|
|
devlink_port_type_warn_cancel(devlink_port);
|
|
|
|
if (type == DEVLINK_PORT_TYPE_ETH && netdev)
|
|
|
|
devlink_port_type_netdev_checks(devlink_port, netdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock_bh(&devlink_port->type_lock);
|
|
|
|
devlink_port->type = type;
|
|
|
|
switch (type) {
|
|
|
|
case DEVLINK_PORT_TYPE_ETH:
|
|
|
|
devlink_port->type_eth.netdev = netdev;
|
2022-11-02 16:02:07 +00:00
|
|
|
if (netdev) {
|
|
|
|
ASSERT_RTNL();
|
|
|
|
devlink_port->type_eth.ifindex = netdev->ifindex;
|
|
|
|
BUILD_BUG_ON(sizeof(devlink_port->type_eth.ifname) !=
|
|
|
|
sizeof(netdev->name));
|
|
|
|
strcpy(devlink_port->type_eth.ifname, netdev->name);
|
|
|
|
}
|
2022-11-02 16:02:01 +00:00
|
|
|
break;
|
|
|
|
case DEVLINK_PORT_TYPE_IB:
|
|
|
|
devlink_port->type_ib.ibdev = type_dev;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
spin_unlock_bh(&devlink_port->type_lock);
|
2022-11-02 16:02:07 +00:00
|
|
|
devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
|
2022-11-02 16:02:01 +00:00
|
|
|
}
|
|
|
|
|
2020-09-08 22:21:13 +00:00
|
|
|
/**
|
|
|
|
* devlink_port_type_eth_set - Set port type to Ethernet
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
2022-11-02 16:02:05 +00:00
|
|
|
*
|
|
|
|
* If driver is calling this, most likely it is doing something wrong.
|
2020-09-08 22:21:13 +00:00
|
|
|
*/
|
2022-11-02 16:02:05 +00:00
|
|
|
void devlink_port_type_eth_set(struct devlink_port *devlink_port)
|
2020-09-08 22:21:13 +00:00
|
|
|
{
|
2022-11-02 16:02:05 +00:00
|
|
|
dev_warn(devlink_port->devlink->dev,
|
|
|
|
"devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n",
|
|
|
|
devlink_port->index);
|
2022-11-02 16:02:07 +00:00
|
|
|
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, NULL);
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_port_type_ib_set - Set port type to InfiniBand
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
|
|
|
* @ibdev: related IB device
|
|
|
|
*/
|
|
|
|
void devlink_port_type_ib_set(struct devlink_port *devlink_port,
|
|
|
|
struct ib_device *ibdev)
|
|
|
|
{
|
2022-11-02 16:02:07 +00:00
|
|
|
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_port_type_clear - Clear port type
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
2022-11-02 16:02:05 +00:00
|
|
|
*
|
|
|
|
* If driver is calling this for clearing Ethernet type, most likely
|
|
|
|
* it is doing something wrong.
|
2016-02-26 16:32:23 +00:00
|
|
|
*/
|
|
|
|
void devlink_port_type_clear(struct devlink_port *devlink_port)
|
|
|
|
{
|
2022-11-02 16:02:05 +00:00
|
|
|
if (devlink_port->type == DEVLINK_PORT_TYPE_ETH)
|
|
|
|
dev_warn(devlink_port->devlink->dev,
|
|
|
|
"devlink port type for port %d cleared without a software interface reference, device type not supported by the kernel?\n",
|
|
|
|
devlink_port->index);
|
2022-11-02 16:02:07 +00:00
|
|
|
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_type_clear);
|
|
|
|
|
2023-01-05 04:05:19 +00:00
|
|
|
int devlink_port_netdevice_event(struct notifier_block *nb,
|
|
|
|
unsigned long event, void *ptr)
|
2022-11-02 16:02:03 +00:00
|
|
|
{
|
|
|
|
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
|
|
|
|
struct devlink_port *devlink_port = netdev->devlink_port;
|
|
|
|
struct devlink *devlink;
|
|
|
|
|
|
|
|
devlink = container_of(nb, struct devlink, netdevice_nb);
|
|
|
|
|
|
|
|
if (!devlink_port || devlink_port->devlink != devlink)
|
|
|
|
return NOTIFY_OK;
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
case NETDEV_POST_INIT:
|
|
|
|
/* Set the type but not netdev pointer. It is going to be set
|
|
|
|
* later on by NETDEV_REGISTER event. Happens once during
|
|
|
|
* netdevice register
|
|
|
|
*/
|
|
|
|
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH,
|
2022-11-02 16:02:07 +00:00
|
|
|
NULL);
|
2022-11-02 16:02:03 +00:00
|
|
|
break;
|
|
|
|
case NETDEV_REGISTER:
|
2022-11-02 16:02:07 +00:00
|
|
|
case NETDEV_CHANGENAME:
|
2023-02-06 09:41:51 +00:00
|
|
|
if (devlink_net(devlink) != dev_net(netdev))
|
|
|
|
return NOTIFY_OK;
|
2022-11-02 16:02:03 +00:00
|
|
|
/* Set the netdev on top of previously set type. Note this
|
|
|
|
* event happens also during net namespace change so here
|
|
|
|
* we take into account netdev pointer appearing in this
|
|
|
|
* namespace.
|
|
|
|
*/
|
2022-11-10 08:51:50 +00:00
|
|
|
__devlink_port_type_set(devlink_port, devlink_port->type,
|
2022-11-02 16:02:07 +00:00
|
|
|
netdev);
|
2022-11-02 16:02:03 +00:00
|
|
|
break;
|
|
|
|
case NETDEV_UNREGISTER:
|
2023-02-06 09:41:51 +00:00
|
|
|
if (devlink_net(devlink) != dev_net(netdev))
|
|
|
|
return NOTIFY_OK;
|
2022-11-02 16:02:03 +00:00
|
|
|
/* Clear netdev pointer, but not the type. This event happens
|
|
|
|
* also during net namespace change so we need to clear
|
|
|
|
* pointer to netdev that is going to another net namespace.
|
|
|
|
*/
|
2022-11-10 08:51:50 +00:00
|
|
|
__devlink_port_type_set(devlink_port, devlink_port->type,
|
2022-11-02 16:02:07 +00:00
|
|
|
NULL);
|
2022-11-02 16:02:03 +00:00
|
|
|
break;
|
|
|
|
case NETDEV_PRE_UNINIT:
|
|
|
|
/* Clear the type and the netdev pointer. Happens one during
|
|
|
|
* netdevice unregister.
|
|
|
|
*/
|
|
|
|
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET,
|
2022-11-02 16:02:07 +00:00
|
|
|
NULL);
|
2022-11-02 16:02:03 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NOTIFY_OK;
|
|
|
|
}
|
|
|
|
|
2019-07-09 04:17:35 +00:00
|
|
|
static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
|
2020-07-09 13:18:16 +00:00
|
|
|
enum devlink_port_flavour flavour)
|
2019-07-09 04:17:35 +00:00
|
|
|
{
|
|
|
|
struct devlink_port_attrs *attrs = &devlink_port->attrs;
|
|
|
|
|
2020-07-09 13:18:14 +00:00
|
|
|
devlink_port->attrs_set = true;
|
2019-07-09 04:17:35 +00:00
|
|
|
attrs->flavour = flavour;
|
2020-07-09 13:18:16 +00:00
|
|
|
if (attrs->switch_id.id_len) {
|
2020-07-09 13:18:15 +00:00
|
|
|
devlink_port->switch_port = true;
|
2020-07-09 13:18:16 +00:00
|
|
|
if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
|
|
|
|
attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
|
2019-07-09 04:17:35 +00:00
|
|
|
} else {
|
2020-07-09 13:18:15 +00:00
|
|
|
devlink_port->switch_port = false;
|
2019-07-09 04:17:35 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-26 16:32:23 +00:00
|
|
|
/**
|
2018-05-18 07:29:00 +00:00
|
|
|
* devlink_port_attrs_set - Set port attributes
|
2016-02-26 16:32:23 +00:00
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
2020-07-09 13:18:16 +00:00
|
|
|
* @attrs: devlink port attrs
|
2016-02-26 16:32:23 +00:00
|
|
|
*/
|
2018-05-18 07:29:00 +00:00
|
|
|
void devlink_port_attrs_set(struct devlink_port *devlink_port,
|
2020-07-09 13:18:16 +00:00
|
|
|
struct devlink_port_attrs *attrs)
|
2016-02-26 16:32:23 +00:00
|
|
|
{
|
2019-07-09 04:17:35 +00:00
|
|
|
int ret;
|
2018-05-18 07:29:00 +00:00
|
|
|
|
2022-09-29 07:28:56 +00:00
|
|
|
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
|
|
|
|
2020-07-09 13:18:16 +00:00
|
|
|
devlink_port->attrs = *attrs;
|
|
|
|
ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
|
2019-07-09 04:17:35 +00:00
|
|
|
if (ret)
|
2019-03-24 10:14:33 +00:00
|
|
|
return;
|
2020-07-09 13:18:20 +00:00
|
|
|
WARN_ON(attrs->splittable && attrs->split);
|
2016-02-26 16:32:23 +00:00
|
|
|
}
|
2018-05-18 07:29:00 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
|
2016-02-26 16:32:23 +00:00
|
|
|
|
2019-07-09 04:17:37 +00:00
|
|
|
/**
|
|
|
|
* devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
devlink: Introduce controller number
A devlink port may be for a controller consist of PCI device.
A devlink instance holds ports of two types of controllers.
(1) controller discovered on same system where eswitch resides
This is the case where PCI PF/VF of a controller and devlink eswitch
instance both are located on a single system.
(2) controller located on external host system.
This is the case where a controller is located in one system and its
devlink eswitch ports are located in a different system.
When a devlink eswitch instance serves the devlink ports of both
controllers together, PCI PF/VF numbers may overlap.
Due to this a unique phys_port_name cannot be constructed.
For example in below such system controller-0 and controller-1, each has
PCI PF pf0 whose eswitch ports can be present in controller-0.
These results in phys_port_name as "pf0" for both.
Similar problem exists for VFs and upcoming Sub functions.
An example view of two controller systems:
---------------------------------------------------------
| |
| --------- --------- ------- ------- |
----------- | | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| server | | ------- ----/---- ---/----- ------- ---/--- ---/--- |
| pci rc |=== | pf0 |______/________/ | pf1 |___/_______/ |
| connect | | ------- ------- |
----------- | | controller_num=1 (no eswitch) |
------|--------------------------------------------------
(internal wire)
|
---------------------------------------------------------
| devlink eswitch ports and reps |
| ----------------------------------------------------- |
| |ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 |ctrl-0 | |
| |pf0 | pf0vfN | pf0sfN | pf1 | pf1vfN |pf1sfN | |
| ----------------------------------------------------- |
| |ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 |ctrl-1 | |
| |pf1 | pf1vfN | pf1sfN | pf1 | pf1vfN |pf0sfN | |
| ----------------------------------------------------- |
| |
| |
| --------- --------- ------- ------- |
| | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| ------- ----/---- ---/----- ------- ---/--- ---/--- |
| | pf0 |______/________/ | pf1 |___/_______/ |
| ------- ------- |
| |
| local controller_num=0 (eswitch) |
---------------------------------------------------------
An example devlink port for external controller with controller
number = 1 for a VF 1 of PF 0:
$ devlink port show pci/0000:06:00.0/2
pci/0000:06:00.0/2: type eth netdev ens2f0pf0vf1 flavour pcivf controller 1 pfnum 0 vfnum 1 external true splittable false
function:
hw_addr 00:00:00:00:00:00
$ devlink port show pci/0000:06:00.0/2 -jp
{
"port": {
"pci/0000:06:00.0/2": {
"type": "eth",
"netdev": "ens2f0pf0vf1",
"flavour": "pcivf",
"controller": 1,
"pfnum": 0,
"vfnum": 1,
"external": true,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:00:00"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-09 04:50:37 +00:00
|
|
|
* @controller: associated controller number for the devlink port instance
|
2019-07-09 04:17:37 +00:00
|
|
|
* @pf: associated PF for the devlink port instance
|
2020-09-09 04:50:36 +00:00
|
|
|
* @external: indicates if the port is for an external controller
|
2019-07-09 04:17:37 +00:00
|
|
|
*/
|
devlink: Introduce controller number
A devlink port may be for a controller consist of PCI device.
A devlink instance holds ports of two types of controllers.
(1) controller discovered on same system where eswitch resides
This is the case where PCI PF/VF of a controller and devlink eswitch
instance both are located on a single system.
(2) controller located on external host system.
This is the case where a controller is located in one system and its
devlink eswitch ports are located in a different system.
When a devlink eswitch instance serves the devlink ports of both
controllers together, PCI PF/VF numbers may overlap.
Due to this a unique phys_port_name cannot be constructed.
For example in below such system controller-0 and controller-1, each has
PCI PF pf0 whose eswitch ports can be present in controller-0.
These results in phys_port_name as "pf0" for both.
Similar problem exists for VFs and upcoming Sub functions.
An example view of two controller systems:
---------------------------------------------------------
| |
| --------- --------- ------- ------- |
----------- | | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| server | | ------- ----/---- ---/----- ------- ---/--- ---/--- |
| pci rc |=== | pf0 |______/________/ | pf1 |___/_______/ |
| connect | | ------- ------- |
----------- | | controller_num=1 (no eswitch) |
------|--------------------------------------------------
(internal wire)
|
---------------------------------------------------------
| devlink eswitch ports and reps |
| ----------------------------------------------------- |
| |ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 |ctrl-0 | |
| |pf0 | pf0vfN | pf0sfN | pf1 | pf1vfN |pf1sfN | |
| ----------------------------------------------------- |
| |ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 |ctrl-1 | |
| |pf1 | pf1vfN | pf1sfN | pf1 | pf1vfN |pf0sfN | |
| ----------------------------------------------------- |
| |
| |
| --------- --------- ------- ------- |
| | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| ------- ----/---- ---/----- ------- ---/--- ---/--- |
| | pf0 |______/________/ | pf1 |___/_______/ |
| ------- ------- |
| |
| local controller_num=0 (eswitch) |
---------------------------------------------------------
An example devlink port for external controller with controller
number = 1 for a VF 1 of PF 0:
$ devlink port show pci/0000:06:00.0/2
pci/0000:06:00.0/2: type eth netdev ens2f0pf0vf1 flavour pcivf controller 1 pfnum 0 vfnum 1 external true splittable false
function:
hw_addr 00:00:00:00:00:00
$ devlink port show pci/0000:06:00.0/2 -jp
{
"port": {
"pci/0000:06:00.0/2": {
"type": "eth",
"netdev": "ens2f0pf0vf1",
"flavour": "pcivf",
"controller": 1,
"pfnum": 0,
"vfnum": 1,
"external": true,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:00:00"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-09 04:50:37 +00:00
|
|
|
void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 controller,
|
|
|
|
u16 pf, bool external)
|
2019-07-09 04:17:37 +00:00
|
|
|
{
|
|
|
|
struct devlink_port_attrs *attrs = &devlink_port->attrs;
|
|
|
|
int ret;
|
|
|
|
|
2022-09-29 07:28:56 +00:00
|
|
|
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
|
|
|
|
2019-07-09 04:17:37 +00:00
|
|
|
ret = __devlink_port_attrs_set(devlink_port,
|
2020-07-09 13:18:16 +00:00
|
|
|
DEVLINK_PORT_FLAVOUR_PCI_PF);
|
2019-07-09 04:17:37 +00:00
|
|
|
if (ret)
|
|
|
|
return;
|
devlink: Introduce controller number
A devlink port may be for a controller consist of PCI device.
A devlink instance holds ports of two types of controllers.
(1) controller discovered on same system where eswitch resides
This is the case where PCI PF/VF of a controller and devlink eswitch
instance both are located on a single system.
(2) controller located on external host system.
This is the case where a controller is located in one system and its
devlink eswitch ports are located in a different system.
When a devlink eswitch instance serves the devlink ports of both
controllers together, PCI PF/VF numbers may overlap.
Due to this a unique phys_port_name cannot be constructed.
For example in below such system controller-0 and controller-1, each has
PCI PF pf0 whose eswitch ports can be present in controller-0.
These results in phys_port_name as "pf0" for both.
Similar problem exists for VFs and upcoming Sub functions.
An example view of two controller systems:
---------------------------------------------------------
| |
| --------- --------- ------- ------- |
----------- | | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| server | | ------- ----/---- ---/----- ------- ---/--- ---/--- |
| pci rc |=== | pf0 |______/________/ | pf1 |___/_______/ |
| connect | | ------- ------- |
----------- | | controller_num=1 (no eswitch) |
------|--------------------------------------------------
(internal wire)
|
---------------------------------------------------------
| devlink eswitch ports and reps |
| ----------------------------------------------------- |
| |ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 |ctrl-0 | |
| |pf0 | pf0vfN | pf0sfN | pf1 | pf1vfN |pf1sfN | |
| ----------------------------------------------------- |
| |ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 |ctrl-1 | |
| |pf1 | pf1vfN | pf1sfN | pf1 | pf1vfN |pf0sfN | |
| ----------------------------------------------------- |
| |
| |
| --------- --------- ------- ------- |
| | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| ------- ----/---- ---/----- ------- ---/--- ---/--- |
| | pf0 |______/________/ | pf1 |___/_______/ |
| ------- ------- |
| |
| local controller_num=0 (eswitch) |
---------------------------------------------------------
An example devlink port for external controller with controller
number = 1 for a VF 1 of PF 0:
$ devlink port show pci/0000:06:00.0/2
pci/0000:06:00.0/2: type eth netdev ens2f0pf0vf1 flavour pcivf controller 1 pfnum 0 vfnum 1 external true splittable false
function:
hw_addr 00:00:00:00:00:00
$ devlink port show pci/0000:06:00.0/2 -jp
{
"port": {
"pci/0000:06:00.0/2": {
"type": "eth",
"netdev": "ens2f0pf0vf1",
"flavour": "pcivf",
"controller": 1,
"pfnum": 0,
"vfnum": 1,
"external": true,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:00:00"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-09 04:50:37 +00:00
|
|
|
attrs->pci_pf.controller = controller;
|
2019-07-09 04:17:37 +00:00
|
|
|
attrs->pci_pf.pf = pf;
|
2020-09-09 04:50:36 +00:00
|
|
|
attrs->pci_pf.external = external;
|
2019-07-09 04:17:37 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
|
|
|
|
|
2019-07-09 04:17:38 +00:00
|
|
|
/**
|
|
|
|
* devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
devlink: Introduce controller number
A devlink port may be for a controller consist of PCI device.
A devlink instance holds ports of two types of controllers.
(1) controller discovered on same system where eswitch resides
This is the case where PCI PF/VF of a controller and devlink eswitch
instance both are located on a single system.
(2) controller located on external host system.
This is the case where a controller is located in one system and its
devlink eswitch ports are located in a different system.
When a devlink eswitch instance serves the devlink ports of both
controllers together, PCI PF/VF numbers may overlap.
Due to this a unique phys_port_name cannot be constructed.
For example in below such system controller-0 and controller-1, each has
PCI PF pf0 whose eswitch ports can be present in controller-0.
These results in phys_port_name as "pf0" for both.
Similar problem exists for VFs and upcoming Sub functions.
An example view of two controller systems:
---------------------------------------------------------
| |
| --------- --------- ------- ------- |
----------- | | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| server | | ------- ----/---- ---/----- ------- ---/--- ---/--- |
| pci rc |=== | pf0 |______/________/ | pf1 |___/_______/ |
| connect | | ------- ------- |
----------- | | controller_num=1 (no eswitch) |
------|--------------------------------------------------
(internal wire)
|
---------------------------------------------------------
| devlink eswitch ports and reps |
| ----------------------------------------------------- |
| |ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 |ctrl-0 | |
| |pf0 | pf0vfN | pf0sfN | pf1 | pf1vfN |pf1sfN | |
| ----------------------------------------------------- |
| |ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 |ctrl-1 | |
| |pf1 | pf1vfN | pf1sfN | pf1 | pf1vfN |pf0sfN | |
| ----------------------------------------------------- |
| |
| |
| --------- --------- ------- ------- |
| | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| ------- ----/---- ---/----- ------- ---/--- ---/--- |
| | pf0 |______/________/ | pf1 |___/_______/ |
| ------- ------- |
| |
| local controller_num=0 (eswitch) |
---------------------------------------------------------
An example devlink port for external controller with controller
number = 1 for a VF 1 of PF 0:
$ devlink port show pci/0000:06:00.0/2
pci/0000:06:00.0/2: type eth netdev ens2f0pf0vf1 flavour pcivf controller 1 pfnum 0 vfnum 1 external true splittable false
function:
hw_addr 00:00:00:00:00:00
$ devlink port show pci/0000:06:00.0/2 -jp
{
"port": {
"pci/0000:06:00.0/2": {
"type": "eth",
"netdev": "ens2f0pf0vf1",
"flavour": "pcivf",
"controller": 1,
"pfnum": 0,
"vfnum": 1,
"external": true,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:00:00"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-09 04:50:37 +00:00
|
|
|
* @controller: associated controller number for the devlink port instance
|
2019-07-09 04:17:38 +00:00
|
|
|
* @pf: associated PF for the devlink port instance
|
|
|
|
* @vf: associated VF of a PF for the devlink port instance
|
2020-09-09 04:50:36 +00:00
|
|
|
* @external: indicates if the port is for an external controller
|
2019-07-09 04:17:38 +00:00
|
|
|
*/
|
devlink: Introduce controller number
A devlink port may be for a controller consist of PCI device.
A devlink instance holds ports of two types of controllers.
(1) controller discovered on same system where eswitch resides
This is the case where PCI PF/VF of a controller and devlink eswitch
instance both are located on a single system.
(2) controller located on external host system.
This is the case where a controller is located in one system and its
devlink eswitch ports are located in a different system.
When a devlink eswitch instance serves the devlink ports of both
controllers together, PCI PF/VF numbers may overlap.
Due to this a unique phys_port_name cannot be constructed.
For example in below such system controller-0 and controller-1, each has
PCI PF pf0 whose eswitch ports can be present in controller-0.
These results in phys_port_name as "pf0" for both.
Similar problem exists for VFs and upcoming Sub functions.
An example view of two controller systems:
---------------------------------------------------------
| |
| --------- --------- ------- ------- |
----------- | | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| server | | ------- ----/---- ---/----- ------- ---/--- ---/--- |
| pci rc |=== | pf0 |______/________/ | pf1 |___/_______/ |
| connect | | ------- ------- |
----------- | | controller_num=1 (no eswitch) |
------|--------------------------------------------------
(internal wire)
|
---------------------------------------------------------
| devlink eswitch ports and reps |
| ----------------------------------------------------- |
| |ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 |ctrl-0 | |
| |pf0 | pf0vfN | pf0sfN | pf1 | pf1vfN |pf1sfN | |
| ----------------------------------------------------- |
| |ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 |ctrl-1 | |
| |pf1 | pf1vfN | pf1sfN | pf1 | pf1vfN |pf0sfN | |
| ----------------------------------------------------- |
| |
| |
| --------- --------- ------- ------- |
| | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| ------- ----/---- ---/----- ------- ---/--- ---/--- |
| | pf0 |______/________/ | pf1 |___/_______/ |
| ------- ------- |
| |
| local controller_num=0 (eswitch) |
---------------------------------------------------------
An example devlink port for external controller with controller
number = 1 for a VF 1 of PF 0:
$ devlink port show pci/0000:06:00.0/2
pci/0000:06:00.0/2: type eth netdev ens2f0pf0vf1 flavour pcivf controller 1 pfnum 0 vfnum 1 external true splittable false
function:
hw_addr 00:00:00:00:00:00
$ devlink port show pci/0000:06:00.0/2 -jp
{
"port": {
"pci/0000:06:00.0/2": {
"type": "eth",
"netdev": "ens2f0pf0vf1",
"flavour": "pcivf",
"controller": 1,
"pfnum": 0,
"vfnum": 1,
"external": true,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:00:00"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-09 04:50:37 +00:00
|
|
|
void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller,
|
2020-09-09 04:50:36 +00:00
|
|
|
u16 pf, u16 vf, bool external)
|
2019-07-09 04:17:38 +00:00
|
|
|
{
|
|
|
|
struct devlink_port_attrs *attrs = &devlink_port->attrs;
|
|
|
|
int ret;
|
|
|
|
|
2022-09-29 07:28:56 +00:00
|
|
|
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
|
|
|
|
2019-07-09 04:17:38 +00:00
|
|
|
ret = __devlink_port_attrs_set(devlink_port,
|
2020-07-09 13:18:16 +00:00
|
|
|
DEVLINK_PORT_FLAVOUR_PCI_VF);
|
2019-07-09 04:17:38 +00:00
|
|
|
if (ret)
|
|
|
|
return;
|
devlink: Introduce controller number
A devlink port may be for a controller consist of PCI device.
A devlink instance holds ports of two types of controllers.
(1) controller discovered on same system where eswitch resides
This is the case where PCI PF/VF of a controller and devlink eswitch
instance both are located on a single system.
(2) controller located on external host system.
This is the case where a controller is located in one system and its
devlink eswitch ports are located in a different system.
When a devlink eswitch instance serves the devlink ports of both
controllers together, PCI PF/VF numbers may overlap.
Due to this a unique phys_port_name cannot be constructed.
For example in below such system controller-0 and controller-1, each has
PCI PF pf0 whose eswitch ports can be present in controller-0.
These results in phys_port_name as "pf0" for both.
Similar problem exists for VFs and upcoming Sub functions.
An example view of two controller systems:
---------------------------------------------------------
| |
| --------- --------- ------- ------- |
----------- | | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| server | | ------- ----/---- ---/----- ------- ---/--- ---/--- |
| pci rc |=== | pf0 |______/________/ | pf1 |___/_______/ |
| connect | | ------- ------- |
----------- | | controller_num=1 (no eswitch) |
------|--------------------------------------------------
(internal wire)
|
---------------------------------------------------------
| devlink eswitch ports and reps |
| ----------------------------------------------------- |
| |ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 | ctrl-0 |ctrl-0 | |
| |pf0 | pf0vfN | pf0sfN | pf1 | pf1vfN |pf1sfN | |
| ----------------------------------------------------- |
| |ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 | ctrl-1 |ctrl-1 | |
| |pf1 | pf1vfN | pf1sfN | pf1 | pf1vfN |pf0sfN | |
| ----------------------------------------------------- |
| |
| |
| --------- --------- ------- ------- |
| | vf(s) | | sf(s) | |vf(s)| |sf(s)| |
| ------- ----/---- ---/----- ------- ---/--- ---/--- |
| | pf0 |______/________/ | pf1 |___/_______/ |
| ------- ------- |
| |
| local controller_num=0 (eswitch) |
---------------------------------------------------------
An example devlink port for external controller with controller
number = 1 for a VF 1 of PF 0:
$ devlink port show pci/0000:06:00.0/2
pci/0000:06:00.0/2: type eth netdev ens2f0pf0vf1 flavour pcivf controller 1 pfnum 0 vfnum 1 external true splittable false
function:
hw_addr 00:00:00:00:00:00
$ devlink port show pci/0000:06:00.0/2 -jp
{
"port": {
"pci/0000:06:00.0/2": {
"type": "eth",
"netdev": "ens2f0pf0vf1",
"flavour": "pcivf",
"controller": 1,
"pfnum": 0,
"vfnum": 1,
"external": true,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:00:00"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-09 04:50:37 +00:00
|
|
|
attrs->pci_vf.controller = controller;
|
2019-07-09 04:17:38 +00:00
|
|
|
attrs->pci_vf.pf = pf;
|
|
|
|
attrs->pci_vf.vf = vf;
|
2020-09-09 04:50:36 +00:00
|
|
|
attrs->pci_vf.external = external;
|
2019-07-09 04:17:38 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
|
|
|
|
|
devlink: Introduce PCI SF port flavour and port attribute
A PCI sub-function (SF) represents a portion of the device similar
to PCI VF.
In an eswitch, PCI SF may have port which is normally represented
using a representor netdevice.
To have better visibility of eswitch port, its association with SF,
and its representor netdevice, introduce a PCI SF port flavour.
When devlink port flavour is PCI SF, fill up PCI SF attributes of the
port.
Extend port name creation using PCI PF and SF number scheme on best
effort basis, so that vendor drivers can skip defining their own
scheme.
This is done as cApfNSfM, where A, N and M are controller, PCI PF and
PCI SF number respectively.
This is similar to existing naming for PCI PF and PCI VF ports.
An example view of a PCI SF port:
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state active opstate attached
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:13 +00:00
|
|
|
/**
|
|
|
|
* devlink_port_attrs_pci_sf_set - Set PCI SF port attributes
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
|
|
|
* @controller: associated controller number for the devlink port instance
|
|
|
|
* @pf: associated PF for the devlink port instance
|
|
|
|
* @sf: associated SF of a PF for the devlink port instance
|
2021-03-10 13:35:03 +00:00
|
|
|
* @external: indicates if the port is for an external controller
|
devlink: Introduce PCI SF port flavour and port attribute
A PCI sub-function (SF) represents a portion of the device similar
to PCI VF.
In an eswitch, PCI SF may have port which is normally represented
using a representor netdevice.
To have better visibility of eswitch port, its association with SF,
and its representor netdevice, introduce a PCI SF port flavour.
When devlink port flavour is PCI SF, fill up PCI SF attributes of the
port.
Extend port name creation using PCI PF and SF number scheme on best
effort basis, so that vendor drivers can skip defining their own
scheme.
This is done as cApfNSfM, where A, N and M are controller, PCI PF and
PCI SF number respectively.
This is similar to existing naming for PCI PF and PCI VF ports.
An example view of a PCI SF port:
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state active opstate attached
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:13 +00:00
|
|
|
*/
|
|
|
|
void devlink_port_attrs_pci_sf_set(struct devlink_port *devlink_port, u32 controller,
|
2021-03-10 13:35:03 +00:00
|
|
|
u16 pf, u32 sf, bool external)
|
devlink: Introduce PCI SF port flavour and port attribute
A PCI sub-function (SF) represents a portion of the device similar
to PCI VF.
In an eswitch, PCI SF may have port which is normally represented
using a representor netdevice.
To have better visibility of eswitch port, its association with SF,
and its representor netdevice, introduce a PCI SF port flavour.
When devlink port flavour is PCI SF, fill up PCI SF attributes of the
port.
Extend port name creation using PCI PF and SF number scheme on best
effort basis, so that vendor drivers can skip defining their own
scheme.
This is done as cApfNSfM, where A, N and M are controller, PCI PF and
PCI SF number respectively.
This is similar to existing naming for PCI PF and PCI VF ports.
An example view of a PCI SF port:
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state active opstate attached
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:13 +00:00
|
|
|
{
|
|
|
|
struct devlink_port_attrs *attrs = &devlink_port->attrs;
|
|
|
|
int ret;
|
|
|
|
|
2022-09-29 07:28:56 +00:00
|
|
|
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
|
|
|
|
devlink: Introduce PCI SF port flavour and port attribute
A PCI sub-function (SF) represents a portion of the device similar
to PCI VF.
In an eswitch, PCI SF may have port which is normally represented
using a representor netdevice.
To have better visibility of eswitch port, its association with SF,
and its representor netdevice, introduce a PCI SF port flavour.
When devlink port flavour is PCI SF, fill up PCI SF attributes of the
port.
Extend port name creation using PCI PF and SF number scheme on best
effort basis, so that vendor drivers can skip defining their own
scheme.
This is done as cApfNSfM, where A, N and M are controller, PCI PF and
PCI SF number respectively.
This is similar to existing naming for PCI PF and PCI VF ports.
An example view of a PCI SF port:
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state active opstate attached
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:13 +00:00
|
|
|
ret = __devlink_port_attrs_set(devlink_port,
|
|
|
|
DEVLINK_PORT_FLAVOUR_PCI_SF);
|
|
|
|
if (ret)
|
|
|
|
return;
|
|
|
|
attrs->pci_sf.controller = controller;
|
|
|
|
attrs->pci_sf.pf = pf;
|
|
|
|
attrs->pci_sf.sf = sf;
|
2021-03-10 13:35:03 +00:00
|
|
|
attrs->pci_sf.external = external;
|
devlink: Introduce PCI SF port flavour and port attribute
A PCI sub-function (SF) represents a portion of the device similar
to PCI VF.
In an eswitch, PCI SF may have port which is normally represented
using a representor netdevice.
To have better visibility of eswitch port, its association with SF,
and its representor netdevice, introduce a PCI SF port flavour.
When devlink port flavour is PCI SF, fill up PCI SF attributes of the
port.
Extend port name creation using PCI PF and SF number scheme on best
effort basis, so that vendor drivers can skip defining their own
scheme.
This is done as cApfNSfM, where A, N and M are controller, PCI PF and
PCI SF number respectively.
This is similar to existing naming for PCI PF and PCI VF ports.
An example view of a PCI SF port:
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state active opstate attached
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:13 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_sf_set);
|
|
|
|
|
2022-11-15 10:48:17 +00:00
|
|
|
/**
|
|
|
|
* devl_rate_node_create - create devlink rate node
|
|
|
|
* @devlink: devlink instance
|
|
|
|
* @priv: driver private data
|
|
|
|
* @node_name: name of the resulting node
|
|
|
|
* @parent: parent devlink_rate struct
|
|
|
|
*
|
|
|
|
* Create devlink rate object of type node
|
|
|
|
*/
|
|
|
|
struct devlink_rate *
|
|
|
|
devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,
|
|
|
|
struct devlink_rate *parent)
|
|
|
|
{
|
|
|
|
struct devlink_rate *rate_node;
|
|
|
|
|
|
|
|
rate_node = devlink_rate_node_get_by_name(devlink, node_name);
|
|
|
|
if (!IS_ERR(rate_node))
|
|
|
|
return ERR_PTR(-EEXIST);
|
|
|
|
|
|
|
|
rate_node = kzalloc(sizeof(*rate_node), GFP_KERNEL);
|
|
|
|
if (!rate_node)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
if (parent) {
|
|
|
|
rate_node->parent = parent;
|
|
|
|
refcount_inc(&rate_node->parent->refcnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
rate_node->type = DEVLINK_RATE_TYPE_NODE;
|
|
|
|
rate_node->devlink = devlink;
|
|
|
|
rate_node->priv = priv;
|
|
|
|
|
|
|
|
rate_node->name = kstrdup(node_name, GFP_KERNEL);
|
|
|
|
if (!rate_node->name) {
|
|
|
|
kfree(rate_node);
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
refcount_set(&rate_node->refcnt, 1);
|
|
|
|
list_add(&rate_node->list, &devlink->rate_list);
|
|
|
|
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
|
|
|
|
return rate_node;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_rate_node_create);
|
|
|
|
|
2021-06-02 12:17:19 +00:00
|
|
|
/**
|
2022-03-18 19:23:41 +00:00
|
|
|
* devl_rate_leaf_create - create devlink rate leaf
|
2021-06-02 12:17:19 +00:00
|
|
|
* @devlink_port: devlink port object to create rate object on
|
|
|
|
* @priv: driver private data
|
2022-11-15 10:48:19 +00:00
|
|
|
* @parent: parent devlink_rate struct
|
2021-06-02 12:17:19 +00:00
|
|
|
*
|
|
|
|
* Create devlink rate object of type leaf on provided @devlink_port.
|
|
|
|
*/
|
2022-11-15 10:48:19 +00:00
|
|
|
int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv,
|
|
|
|
struct devlink_rate *parent)
|
2021-06-02 12:17:19 +00:00
|
|
|
{
|
|
|
|
struct devlink *devlink = devlink_port->devlink;
|
|
|
|
struct devlink_rate *devlink_rate;
|
|
|
|
|
2022-03-18 19:23:41 +00:00
|
|
|
devl_assert_locked(devlink_port->devlink);
|
|
|
|
|
|
|
|
if (WARN_ON(devlink_port->devlink_rate))
|
|
|
|
return -EBUSY;
|
|
|
|
|
2021-06-02 12:17:19 +00:00
|
|
|
devlink_rate = kzalloc(sizeof(*devlink_rate), GFP_KERNEL);
|
|
|
|
if (!devlink_rate)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2022-11-15 10:48:19 +00:00
|
|
|
if (parent) {
|
|
|
|
devlink_rate->parent = parent;
|
|
|
|
refcount_inc(&devlink_rate->parent->refcnt);
|
|
|
|
}
|
|
|
|
|
2021-06-02 12:17:19 +00:00
|
|
|
devlink_rate->type = DEVLINK_RATE_TYPE_LEAF;
|
|
|
|
devlink_rate->devlink = devlink;
|
|
|
|
devlink_rate->devlink_port = devlink_port;
|
|
|
|
devlink_rate->priv = priv;
|
|
|
|
list_add_tail(&devlink_rate->list, &devlink->rate_list);
|
|
|
|
devlink_port->devlink_rate = devlink_rate;
|
|
|
|
devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2022-03-18 19:23:41 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_rate_leaf_create);
|
|
|
|
|
2022-07-11 08:14:05 +00:00
|
|
|
/**
|
|
|
|
* devl_rate_leaf_destroy - destroy devlink rate leaf
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port linked to the rate object
|
|
|
|
*
|
|
|
|
* Destroy the devlink rate object of type leaf on provided @devlink_port.
|
|
|
|
*/
|
2022-03-18 19:23:41 +00:00
|
|
|
void devl_rate_leaf_destroy(struct devlink_port *devlink_port)
|
|
|
|
{
|
|
|
|
struct devlink_rate *devlink_rate = devlink_port->devlink_rate;
|
|
|
|
|
|
|
|
devl_assert_locked(devlink_port->devlink);
|
|
|
|
if (!devlink_rate)
|
|
|
|
return;
|
|
|
|
|
|
|
|
devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_DEL);
|
|
|
|
if (devlink_rate->parent)
|
|
|
|
refcount_dec(&devlink_rate->parent->refcnt);
|
|
|
|
list_del(&devlink_rate->list);
|
|
|
|
devlink_port->devlink_rate = NULL;
|
|
|
|
kfree(devlink_rate);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_rate_leaf_destroy);
|
|
|
|
|
2021-06-02 12:17:25 +00:00
|
|
|
/**
|
2022-03-18 19:23:41 +00:00
|
|
|
* devl_rate_nodes_destroy - destroy all devlink rate nodes on device
|
2021-06-02 12:17:25 +00:00
|
|
|
* @devlink: devlink instance
|
|
|
|
*
|
2021-06-02 12:17:28 +00:00
|
|
|
* Unset parent for all rate objects and destroy all rate nodes
|
|
|
|
* on specified device.
|
2021-06-02 12:17:25 +00:00
|
|
|
*/
|
2022-03-18 19:23:41 +00:00
|
|
|
void devl_rate_nodes_destroy(struct devlink *devlink)
|
2021-06-02 12:17:25 +00:00
|
|
|
{
|
|
|
|
static struct devlink_rate *devlink_rate, *tmp;
|
|
|
|
const struct devlink_ops *ops = devlink->ops;
|
|
|
|
|
2022-03-18 19:23:41 +00:00
|
|
|
devl_assert_locked(devlink);
|
|
|
|
|
2021-06-02 12:17:28 +00:00
|
|
|
list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
|
|
|
|
if (!devlink_rate->parent)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
refcount_dec(&devlink_rate->parent->refcnt);
|
|
|
|
if (devlink_rate_is_leaf(devlink_rate))
|
|
|
|
ops->rate_leaf_parent_set(devlink_rate, NULL, devlink_rate->priv,
|
|
|
|
NULL, NULL);
|
|
|
|
else if (devlink_rate_is_node(devlink_rate))
|
|
|
|
ops->rate_node_parent_set(devlink_rate, NULL, devlink_rate->priv,
|
|
|
|
NULL, NULL);
|
|
|
|
}
|
2021-06-02 12:17:25 +00:00
|
|
|
list_for_each_entry_safe(devlink_rate, tmp, &devlink->rate_list, list) {
|
|
|
|
if (devlink_rate_is_node(devlink_rate)) {
|
|
|
|
ops->rate_node_del(devlink_rate, devlink_rate->priv, NULL);
|
|
|
|
list_del(&devlink_rate->list);
|
|
|
|
kfree(devlink_rate->name);
|
|
|
|
kfree(devlink_rate);
|
|
|
|
}
|
|
|
|
}
|
2022-03-18 19:23:41 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_rate_nodes_destroy);
|
|
|
|
|
2022-04-18 06:42:28 +00:00
|
|
|
/**
|
|
|
|
* devlink_port_linecard_set - Link port with a linecard
|
|
|
|
*
|
|
|
|
* @devlink_port: devlink port
|
|
|
|
* @linecard: devlink linecard
|
|
|
|
*/
|
|
|
|
void devlink_port_linecard_set(struct devlink_port *devlink_port,
|
|
|
|
struct devlink_linecard *linecard)
|
|
|
|
{
|
2022-09-29 07:28:56 +00:00
|
|
|
ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port);
|
|
|
|
|
2022-04-18 06:42:28 +00:00
|
|
|
devlink_port->linecard = linecard;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_linecard_set);
|
|
|
|
|
2019-03-28 12:56:37 +00:00
|
|
|
static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
|
|
|
|
char *name, size_t len)
|
2018-05-18 07:29:02 +00:00
|
|
|
{
|
|
|
|
struct devlink_port_attrs *attrs = &devlink_port->attrs;
|
|
|
|
int n = 0;
|
|
|
|
|
2020-07-09 13:18:14 +00:00
|
|
|
if (!devlink_port->attrs_set)
|
2018-05-18 07:29:02 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
switch (attrs->flavour) {
|
|
|
|
case DEVLINK_PORT_FLAVOUR_PHYSICAL:
|
2022-04-18 06:42:28 +00:00
|
|
|
if (devlink_port->linecard)
|
|
|
|
n = snprintf(name, len, "l%u",
|
|
|
|
devlink_port->linecard->index);
|
|
|
|
if (n < len)
|
|
|
|
n += snprintf(name + n, len - n, "p%u",
|
|
|
|
attrs->phys.port_number);
|
2021-05-27 10:48:19 +00:00
|
|
|
if (n < len && attrs->split)
|
|
|
|
n += snprintf(name + n, len - n, "s%u",
|
|
|
|
attrs->phys.split_subport_number);
|
2018-05-18 07:29:02 +00:00
|
|
|
break;
|
|
|
|
case DEVLINK_PORT_FLAVOUR_CPU:
|
|
|
|
case DEVLINK_PORT_FLAVOUR_DSA:
|
2020-10-04 16:12:51 +00:00
|
|
|
case DEVLINK_PORT_FLAVOUR_UNUSED:
|
2018-05-18 07:29:02 +00:00
|
|
|
/* As CPU and DSA ports do not have a netdevice associated
|
|
|
|
* case should not ever happen.
|
|
|
|
*/
|
|
|
|
WARN_ON(1);
|
|
|
|
return -EINVAL;
|
2019-07-09 04:17:37 +00:00
|
|
|
case DEVLINK_PORT_FLAVOUR_PCI_PF:
|
devlink: Use controller while building phys_port_name
Now that controller number attribute is available, use it when
building phsy_port_name for external controller ports.
An example devlink port and representor netdev name consist of controller
annotation for external controller with controller number = 1,
for a VF 1 of PF 0:
$ devlink port show pci/0000:06:00.0/2
pci/0000:06:00.0/2: type eth netdev ens2f0c1pf0vf1 flavour pcivf controller 1 pfnum 0 vfnum 1 external true splittable false
function:
hw_addr 00:00:00:00:00:00
$ devlink port show pci/0000:06:00.0/2 -jp
{
"port": {
"pci/0000:06:00.0/2": {
"type": "eth",
"netdev": "ens2f0c1pf0vf1",
"flavour": "pcivf",
"controller": 1,
"pfnum": 0,
"vfnum": 1,
"external": true,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:00:00"
}
}
}
}
Controller number annotation is skipped for non external controllers to
maintain backward compatibility.
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-09 04:50:38 +00:00
|
|
|
if (attrs->pci_pf.external) {
|
|
|
|
n = snprintf(name, len, "c%u", attrs->pci_pf.controller);
|
|
|
|
if (n >= len)
|
|
|
|
return -EINVAL;
|
|
|
|
len -= n;
|
|
|
|
name += n;
|
|
|
|
}
|
2019-07-09 04:17:37 +00:00
|
|
|
n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
|
|
|
|
break;
|
2019-07-09 04:17:38 +00:00
|
|
|
case DEVLINK_PORT_FLAVOUR_PCI_VF:
|
devlink: Use controller while building phys_port_name
Now that controller number attribute is available, use it when
building phsy_port_name for external controller ports.
An example devlink port and representor netdev name consist of controller
annotation for external controller with controller number = 1,
for a VF 1 of PF 0:
$ devlink port show pci/0000:06:00.0/2
pci/0000:06:00.0/2: type eth netdev ens2f0c1pf0vf1 flavour pcivf controller 1 pfnum 0 vfnum 1 external true splittable false
function:
hw_addr 00:00:00:00:00:00
$ devlink port show pci/0000:06:00.0/2 -jp
{
"port": {
"pci/0000:06:00.0/2": {
"type": "eth",
"netdev": "ens2f0c1pf0vf1",
"flavour": "pcivf",
"controller": 1,
"pfnum": 0,
"vfnum": 1,
"external": true,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:00:00"
}
}
}
}
Controller number annotation is skipped for non external controllers to
maintain backward compatibility.
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-09-09 04:50:38 +00:00
|
|
|
if (attrs->pci_vf.external) {
|
|
|
|
n = snprintf(name, len, "c%u", attrs->pci_vf.controller);
|
|
|
|
if (n >= len)
|
|
|
|
return -EINVAL;
|
|
|
|
len -= n;
|
|
|
|
name += n;
|
|
|
|
}
|
2019-07-09 04:17:38 +00:00
|
|
|
n = snprintf(name, len, "pf%uvf%u",
|
|
|
|
attrs->pci_vf.pf, attrs->pci_vf.vf);
|
|
|
|
break;
|
devlink: Introduce PCI SF port flavour and port attribute
A PCI sub-function (SF) represents a portion of the device similar
to PCI VF.
In an eswitch, PCI SF may have port which is normally represented
using a representor netdevice.
To have better visibility of eswitch port, its association with SF,
and its representor netdevice, introduce a PCI SF port flavour.
When devlink port flavour is PCI SF, fill up PCI SF attributes of the
port.
Extend port name creation using PCI PF and SF number scheme on best
effort basis, so that vendor drivers can skip defining their own
scheme.
This is done as cApfNSfM, where A, N and M are controller, PCI PF and
PCI SF number respectively.
This is similar to existing naming for PCI PF and PCI VF ports.
An example view of a PCI SF port:
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state active opstate attached
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:13 +00:00
|
|
|
case DEVLINK_PORT_FLAVOUR_PCI_SF:
|
2021-03-10 13:35:03 +00:00
|
|
|
if (attrs->pci_sf.external) {
|
|
|
|
n = snprintf(name, len, "c%u", attrs->pci_sf.controller);
|
|
|
|
if (n >= len)
|
|
|
|
return -EINVAL;
|
|
|
|
len -= n;
|
|
|
|
name += n;
|
|
|
|
}
|
devlink: Introduce PCI SF port flavour and port attribute
A PCI sub-function (SF) represents a portion of the device similar
to PCI VF.
In an eswitch, PCI SF may have port which is normally represented
using a representor netdevice.
To have better visibility of eswitch port, its association with SF,
and its representor netdevice, introduce a PCI SF port flavour.
When devlink port flavour is PCI SF, fill up PCI SF attributes of the
port.
Extend port name creation using PCI PF and SF number scheme on best
effort basis, so that vendor drivers can skip defining their own
scheme.
This is done as cApfNSfM, where A, N and M are controller, PCI PF and
PCI SF number respectively.
This is similar to existing naming for PCI PF and PCI VF ports.
An example view of a PCI SF port:
$ devlink port show pci/0000:06:00.0/32768
pci/0000:06:00.0/32768: type eth netdev ens2f0npf0sf88 flavour pcisf controller 0 pfnum 0 sfnum 88 external false splittable false
function:
hw_addr 00:00:00:00:88:88 state active opstate attached
$ devlink port show pci/0000:06:00.0/32768 -jp
{
"port": {
"pci/0000:06:00.0/32768": {
"type": "eth",
"netdev": "ens2f0npf0sf88",
"flavour": "pcisf",
"controller": 0,
"pfnum": 0,
"sfnum": 88,
"splittable": false,
"function": {
"hw_addr": "00:00:00:00:88:88",
"state": "active",
"opstate": "attached"
}
}
}
}
Signed-off-by: Parav Pandit <parav@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Vu Pham <vuhuong@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
2020-12-12 06:12:13 +00:00
|
|
|
n = snprintf(name, len, "pf%usf%u", attrs->pci_sf.pf,
|
|
|
|
attrs->pci_sf.sf);
|
|
|
|
break;
|
2021-07-23 14:56:00 +00:00
|
|
|
case DEVLINK_PORT_FLAVOUR_VIRTUAL:
|
|
|
|
return -EOPNOTSUPP;
|
2018-05-18 07:29:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (n >= len)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-03-28 12:56:37 +00:00
|
|
|
|
2022-04-18 06:42:26 +00:00
|
|
|
static int devlink_linecard_types_init(struct devlink_linecard *linecard)
|
|
|
|
{
|
|
|
|
struct devlink_linecard_type *linecard_type;
|
|
|
|
unsigned int count;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
count = linecard->ops->types_count(linecard, linecard->priv);
|
|
|
|
linecard->types = kmalloc_array(count, sizeof(*linecard_type),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!linecard->types)
|
|
|
|
return -ENOMEM;
|
|
|
|
linecard->types_count = count;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
linecard_type = &linecard->types[i];
|
|
|
|
linecard->ops->types_get(linecard, linecard->priv, i,
|
|
|
|
&linecard_type->type,
|
|
|
|
&linecard_type->priv);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_linecard_types_fini(struct devlink_linecard *linecard)
|
|
|
|
{
|
|
|
|
kfree(linecard->types);
|
|
|
|
}
|
|
|
|
|
2022-04-18 06:42:25 +00:00
|
|
|
/**
|
2023-01-18 15:21:04 +00:00
|
|
|
* devl_linecard_create - Create devlink linecard
|
2022-04-18 06:42:25 +00:00
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @linecard_index: driver-specific numerical identifier of the linecard
|
2022-04-18 06:42:26 +00:00
|
|
|
* @ops: linecards ops
|
|
|
|
* @priv: user priv pointer
|
2022-04-18 06:42:25 +00:00
|
|
|
*
|
|
|
|
* Create devlink linecard instance with provided linecard index.
|
|
|
|
* Caller can use any indexing, even hw-related one.
|
2022-04-18 06:42:26 +00:00
|
|
|
*
|
|
|
|
* Return: Line card structure or an ERR_PTR() encoded error code.
|
2022-04-18 06:42:25 +00:00
|
|
|
*/
|
2022-04-18 06:42:26 +00:00
|
|
|
struct devlink_linecard *
|
2023-01-18 15:21:04 +00:00
|
|
|
devl_linecard_create(struct devlink *devlink, unsigned int linecard_index,
|
|
|
|
const struct devlink_linecard_ops *ops, void *priv)
|
2022-04-18 06:42:25 +00:00
|
|
|
{
|
|
|
|
struct devlink_linecard *linecard;
|
2022-04-18 06:42:26 +00:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (WARN_ON(!ops || !ops->provision || !ops->unprovision ||
|
|
|
|
!ops->types_count || !ops->types_get))
|
|
|
|
return ERR_PTR(-EINVAL);
|
2022-04-18 06:42:25 +00:00
|
|
|
|
2023-01-18 15:21:04 +00:00
|
|
|
if (devlink_linecard_index_exists(devlink, linecard_index))
|
2022-04-18 06:42:25 +00:00
|
|
|
return ERR_PTR(-EEXIST);
|
|
|
|
|
|
|
|
linecard = kzalloc(sizeof(*linecard), GFP_KERNEL);
|
2023-01-18 15:21:04 +00:00
|
|
|
if (!linecard)
|
2022-04-18 06:42:25 +00:00
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
linecard->devlink = devlink;
|
|
|
|
linecard->index = linecard_index;
|
2022-04-18 06:42:26 +00:00
|
|
|
linecard->ops = ops;
|
|
|
|
linecard->priv = priv;
|
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
|
|
|
mutex_init(&linecard->state_lock);
|
|
|
|
|
|
|
|
err = devlink_linecard_types_init(linecard);
|
|
|
|
if (err) {
|
|
|
|
mutex_destroy(&linecard->state_lock);
|
|
|
|
kfree(linecard);
|
|
|
|
return ERR_PTR(err);
|
|
|
|
}
|
|
|
|
|
2022-04-18 06:42:25 +00:00
|
|
|
list_add_tail(&linecard->list, &devlink->linecard_list);
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
return linecard;
|
|
|
|
}
|
2023-01-18 15:21:04 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_linecard_create);
|
2022-04-18 06:42:25 +00:00
|
|
|
|
|
|
|
/**
|
2023-01-18 15:21:04 +00:00
|
|
|
* devl_linecard_destroy - Destroy devlink linecard
|
2022-04-18 06:42:25 +00:00
|
|
|
*
|
|
|
|
* @linecard: devlink linecard
|
|
|
|
*/
|
2023-01-18 15:21:04 +00:00
|
|
|
void devl_linecard_destroy(struct devlink_linecard *linecard)
|
2022-04-18 06:42:25 +00:00
|
|
|
{
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
|
|
|
|
list_del(&linecard->list);
|
2022-04-18 06:42:26 +00:00
|
|
|
devlink_linecard_types_fini(linecard);
|
2023-01-18 15:21:05 +00:00
|
|
|
mutex_destroy(&linecard->state_lock);
|
|
|
|
kfree(linecard);
|
2022-04-18 06:42:25 +00:00
|
|
|
}
|
2023-01-18 15:21:04 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_linecard_destroy);
|
2022-04-18 06:42:25 +00:00
|
|
|
|
2022-04-18 06:42:26 +00:00
|
|
|
/**
|
|
|
|
* devlink_linecard_provision_set - Set provisioning on linecard
|
|
|
|
*
|
|
|
|
* @linecard: devlink linecard
|
|
|
|
* @type: linecard type
|
|
|
|
*
|
|
|
|
* This is either called directly from the provision() op call or
|
|
|
|
* as a result of the provision() op call asynchronously.
|
|
|
|
*/
|
|
|
|
void devlink_linecard_provision_set(struct devlink_linecard *linecard,
|
|
|
|
const char *type)
|
|
|
|
{
|
|
|
|
mutex_lock(&linecard->state_lock);
|
|
|
|
WARN_ON(linecard->type && strcmp(linecard->type, type));
|
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
|
|
|
|
linecard->type = type;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_linecard_provision_set);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_linecard_provision_clear - Clear provisioning on linecard
|
|
|
|
*
|
|
|
|
* @linecard: devlink linecard
|
|
|
|
*
|
|
|
|
* This is either called directly from the unprovision() op call or
|
|
|
|
* as a result of the unprovision() op call asynchronously.
|
|
|
|
*/
|
|
|
|
void devlink_linecard_provision_clear(struct devlink_linecard *linecard)
|
|
|
|
{
|
|
|
|
mutex_lock(&linecard->state_lock);
|
2022-07-25 08:29:16 +00:00
|
|
|
WARN_ON(linecard->nested_devlink);
|
2022-04-18 06:42:26 +00:00
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
|
|
|
|
linecard->type = NULL;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_linecard_provision_fail - Fail provisioning on linecard
|
|
|
|
*
|
|
|
|
* @linecard: devlink linecard
|
|
|
|
*
|
|
|
|
* This is either called directly from the provision() op call or
|
|
|
|
* as a result of the provision() op call asynchronously.
|
|
|
|
*/
|
|
|
|
void devlink_linecard_provision_fail(struct devlink_linecard *linecard)
|
|
|
|
{
|
|
|
|
mutex_lock(&linecard->state_lock);
|
2022-07-25 08:29:16 +00:00
|
|
|
WARN_ON(linecard->nested_devlink);
|
2022-04-18 06:42:26 +00:00
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail);
|
|
|
|
|
2022-04-18 06:42:27 +00:00
|
|
|
/**
|
|
|
|
* devlink_linecard_activate - Set linecard active
|
|
|
|
*
|
|
|
|
* @linecard: devlink linecard
|
|
|
|
*/
|
|
|
|
void devlink_linecard_activate(struct devlink_linecard *linecard)
|
|
|
|
{
|
|
|
|
mutex_lock(&linecard->state_lock);
|
|
|
|
WARN_ON(linecard->state != DEVLINK_LINECARD_STATE_PROVISIONED);
|
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_ACTIVE;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_linecard_activate);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_linecard_deactivate - Set linecard inactive
|
|
|
|
*
|
|
|
|
* @linecard: devlink linecard
|
|
|
|
*/
|
|
|
|
void devlink_linecard_deactivate(struct devlink_linecard *linecard)
|
|
|
|
{
|
|
|
|
mutex_lock(&linecard->state_lock);
|
|
|
|
switch (linecard->state) {
|
|
|
|
case DEVLINK_LINECARD_STATE_ACTIVE:
|
|
|
|
linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
break;
|
|
|
|
case DEVLINK_LINECARD_STATE_UNPROVISIONING:
|
|
|
|
/* Line card is being deactivated as part
|
|
|
|
* of unprovisioning flow.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
WARN_ON(1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_linecard_deactivate);
|
|
|
|
|
2022-07-25 08:29:16 +00:00
|
|
|
/**
|
|
|
|
* devlink_linecard_nested_dl_set - Attach/detach nested devlink
|
|
|
|
* instance to linecard.
|
|
|
|
*
|
|
|
|
* @linecard: devlink linecard
|
|
|
|
* @nested_devlink: devlink instance to attach or NULL to detach
|
|
|
|
*/
|
|
|
|
void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard,
|
|
|
|
struct devlink *nested_devlink)
|
|
|
|
{
|
|
|
|
mutex_lock(&linecard->state_lock);
|
|
|
|
linecard->nested_devlink = nested_devlink;
|
|
|
|
devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
|
|
|
|
mutex_unlock(&linecard->state_lock);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set);
|
|
|
|
|
2022-07-16 11:02:36 +00:00
|
|
|
int devl_sb_register(struct devlink *devlink, unsigned int sb_index,
|
|
|
|
u32 size, u16 ingress_pools_count,
|
|
|
|
u16 egress_pools_count, u16 ingress_tc_count,
|
|
|
|
u16 egress_tc_count)
|
2016-04-14 16:19:13 +00:00
|
|
|
{
|
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
|
2022-07-16 11:02:36 +00:00
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
|
|
|
if (devlink_sb_index_exists(devlink, sb_index))
|
|
|
|
return -EEXIST;
|
2016-04-14 16:19:13 +00:00
|
|
|
|
|
|
|
devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
|
2022-07-16 11:02:36 +00:00
|
|
|
if (!devlink_sb)
|
|
|
|
return -ENOMEM;
|
2016-04-14 16:19:13 +00:00
|
|
|
devlink_sb->index = sb_index;
|
|
|
|
devlink_sb->size = size;
|
|
|
|
devlink_sb->ingress_pools_count = ingress_pools_count;
|
|
|
|
devlink_sb->egress_pools_count = egress_pools_count;
|
|
|
|
devlink_sb->ingress_tc_count = ingress_tc_count;
|
|
|
|
devlink_sb->egress_tc_count = egress_tc_count;
|
|
|
|
list_add_tail(&devlink_sb->list, &devlink->sb_list);
|
2022-07-16 11:02:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_sb_register);
|
|
|
|
|
|
|
|
int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
|
|
|
|
u32 size, u16 ingress_pools_count,
|
|
|
|
u16 egress_pools_count, u16 ingress_tc_count,
|
|
|
|
u16 egress_tc_count)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
devl_lock(devlink);
|
|
|
|
err = devl_sb_register(devlink, sb_index, size, ingress_pools_count,
|
|
|
|
egress_pools_count, ingress_tc_count,
|
|
|
|
egress_tc_count);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2016-04-14 16:19:13 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_sb_register);
|
|
|
|
|
2022-07-16 11:02:36 +00:00
|
|
|
void devl_sb_unregister(struct devlink *devlink, unsigned int sb_index)
|
2016-04-14 16:19:13 +00:00
|
|
|
{
|
|
|
|
struct devlink_sb *devlink_sb;
|
|
|
|
|
2022-07-16 11:02:36 +00:00
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
2016-04-14 16:19:13 +00:00
|
|
|
devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
|
|
|
|
WARN_ON(!devlink_sb);
|
|
|
|
list_del(&devlink_sb->list);
|
|
|
|
kfree(devlink_sb);
|
|
|
|
}
|
2022-07-16 11:02:36 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_sb_unregister);
|
|
|
|
|
|
|
|
void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
|
|
|
|
{
|
|
|
|
devl_lock(devlink);
|
|
|
|
devl_sb_unregister(devlink, sb_index);
|
|
|
|
devl_unlock(devlink);
|
|
|
|
}
|
2016-04-14 16:19:13 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_sb_unregister);
|
|
|
|
|
2022-07-16 11:02:37 +00:00
|
|
|
/**
|
|
|
|
* devl_dpipe_headers_register - register dpipe headers
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @dpipe_headers: dpipe header array
|
|
|
|
*
|
|
|
|
* Register the headers supported by hardware.
|
|
|
|
*/
|
|
|
|
void devl_dpipe_headers_register(struct devlink *devlink,
|
|
|
|
struct devlink_dpipe_headers *dpipe_headers)
|
|
|
|
{
|
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
|
|
|
devlink->dpipe_headers = dpipe_headers;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_dpipe_headers_register);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devl_dpipe_headers_unregister - unregister dpipe headers
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
*
|
|
|
|
* Unregister the headers supported by hardware.
|
|
|
|
*/
|
|
|
|
void devl_dpipe_headers_unregister(struct devlink *devlink)
|
|
|
|
{
|
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
|
|
|
devlink->dpipe_headers = NULL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_dpipe_headers_unregister);
|
|
|
|
|
2017-03-28 15:24:10 +00:00
|
|
|
/**
|
|
|
|
* devlink_dpipe_table_counter_enabled - check if counter allocation
|
|
|
|
* required
|
|
|
|
* @devlink: devlink
|
|
|
|
* @table_name: tables name
|
|
|
|
*
|
|
|
|
* Used by driver to check if counter allocation is required.
|
|
|
|
* After counter allocation is turned on the table entries
|
|
|
|
* are updated to include counter statistics.
|
|
|
|
*
|
|
|
|
* After that point on the driver must respect the counter
|
|
|
|
* state so that each entry added to the table is added
|
|
|
|
* with a counter.
|
|
|
|
*/
|
|
|
|
bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
|
|
|
|
const char *table_name)
|
|
|
|
{
|
|
|
|
struct devlink_dpipe_table *table;
|
|
|
|
bool enabled;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
|
2020-02-25 12:27:45 +00:00
|
|
|
table_name, devlink);
|
2017-03-28 15:24:10 +00:00
|
|
|
enabled = false;
|
|
|
|
if (table)
|
|
|
|
enabled = table->counters_enabled;
|
|
|
|
rcu_read_unlock();
|
|
|
|
return enabled;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
|
|
|
|
|
|
|
|
/**
|
2022-07-16 11:02:37 +00:00
|
|
|
* devl_dpipe_table_register - register dpipe table
|
2017-03-28 15:24:10 +00:00
|
|
|
*
|
2022-07-16 11:02:37 +00:00
|
|
|
* @devlink: devlink
|
|
|
|
* @table_name: table name
|
|
|
|
* @table_ops: table ops
|
|
|
|
* @priv: priv
|
|
|
|
* @counter_control_extern: external control for counters
|
2017-03-28 15:24:10 +00:00
|
|
|
*/
|
2022-07-16 11:02:37 +00:00
|
|
|
int devl_dpipe_table_register(struct devlink *devlink,
|
|
|
|
const char *table_name,
|
|
|
|
struct devlink_dpipe_table_ops *table_ops,
|
|
|
|
void *priv, bool counter_control_extern)
|
2017-03-28 15:24:10 +00:00
|
|
|
{
|
|
|
|
struct devlink_dpipe_table *table;
|
2022-07-16 11:02:37 +00:00
|
|
|
|
|
|
|
lockdep_assert_held(&devlink->lock);
|
2017-03-28 15:24:10 +00:00
|
|
|
|
2017-08-24 06:40:02 +00:00
|
|
|
if (WARN_ON(!table_ops->size_get))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-02-25 12:27:45 +00:00
|
|
|
if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
|
2022-07-16 11:02:37 +00:00
|
|
|
devlink))
|
|
|
|
return -EEXIST;
|
2020-02-23 11:22:33 +00:00
|
|
|
|
2017-03-28 15:24:10 +00:00
|
|
|
table = kzalloc(sizeof(*table), GFP_KERNEL);
|
2022-07-16 11:02:37 +00:00
|
|
|
if (!table)
|
|
|
|
return -ENOMEM;
|
2017-03-28 15:24:10 +00:00
|
|
|
|
|
|
|
table->name = table_name;
|
|
|
|
table->table_ops = table_ops;
|
|
|
|
table->priv = priv;
|
|
|
|
table->counter_control_extern = counter_control_extern;
|
|
|
|
|
|
|
|
list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
|
2022-07-16 11:02:37 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_dpipe_table_register);
|
|
|
|
|
2017-03-28 15:24:10 +00:00
|
|
|
/**
|
2022-07-16 11:02:37 +00:00
|
|
|
* devl_dpipe_table_unregister - unregister dpipe table
|
2017-03-28 15:24:10 +00:00
|
|
|
*
|
2022-07-16 11:02:37 +00:00
|
|
|
* @devlink: devlink
|
|
|
|
* @table_name: table name
|
2017-03-28 15:24:10 +00:00
|
|
|
*/
|
2022-07-16 11:02:37 +00:00
|
|
|
void devl_dpipe_table_unregister(struct devlink *devlink,
|
|
|
|
const char *table_name)
|
2017-03-28 15:24:10 +00:00
|
|
|
{
|
|
|
|
struct devlink_dpipe_table *table;
|
|
|
|
|
2022-07-16 11:02:37 +00:00
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
2017-03-28 15:24:10 +00:00
|
|
|
table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
|
2020-02-25 12:27:45 +00:00
|
|
|
table_name, devlink);
|
2017-03-28 15:24:10 +00:00
|
|
|
if (!table)
|
2022-07-16 11:02:37 +00:00
|
|
|
return;
|
2017-03-28 15:24:10 +00:00
|
|
|
list_del_rcu(&table->list);
|
|
|
|
kfree_rcu(table, rcu);
|
2022-07-16 11:02:37 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_dpipe_table_unregister);
|
|
|
|
|
2018-01-15 07:59:03 +00:00
|
|
|
/**
|
2022-07-16 11:02:35 +00:00
|
|
|
* devl_resource_register - devlink resource register
|
2018-01-15 07:59:03 +00:00
|
|
|
*
|
2022-07-16 11:02:35 +00:00
|
|
|
* @devlink: devlink
|
|
|
|
* @resource_name: resource's name
|
|
|
|
* @resource_size: resource's size
|
|
|
|
* @resource_id: resource's id
|
|
|
|
* @parent_resource_id: resource's parent id
|
|
|
|
* @size_params: size parameters
|
2021-01-21 13:10:23 +00:00
|
|
|
*
|
2022-07-16 11:02:35 +00:00
|
|
|
* Generic resources should reuse the same names across drivers.
|
|
|
|
* Please see the generic resources list at:
|
|
|
|
* Documentation/networking/devlink/devlink-resource.rst
|
2018-01-15 07:59:03 +00:00
|
|
|
*/
|
2022-07-16 11:02:35 +00:00
|
|
|
int devl_resource_register(struct devlink *devlink,
|
|
|
|
const char *resource_name,
|
|
|
|
u64 resource_size,
|
|
|
|
u64 resource_id,
|
|
|
|
u64 parent_resource_id,
|
|
|
|
const struct devlink_resource_size_params *size_params)
|
2018-01-15 07:59:03 +00:00
|
|
|
{
|
|
|
|
struct devlink_resource *resource;
|
|
|
|
struct list_head *resource_list;
|
2018-03-21 02:31:14 +00:00
|
|
|
bool top_hierarchy;
|
2022-07-16 11:02:35 +00:00
|
|
|
|
|
|
|
lockdep_assert_held(&devlink->lock);
|
2018-01-15 07:59:03 +00:00
|
|
|
|
2018-03-21 02:31:14 +00:00
|
|
|
top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
|
|
|
|
|
2018-01-15 07:59:03 +00:00
|
|
|
resource = devlink_resource_find(devlink, NULL, resource_id);
|
2022-07-16 11:02:35 +00:00
|
|
|
if (resource)
|
|
|
|
return -EINVAL;
|
2018-01-15 07:59:03 +00:00
|
|
|
|
|
|
|
resource = kzalloc(sizeof(*resource), GFP_KERNEL);
|
2022-07-16 11:02:35 +00:00
|
|
|
if (!resource)
|
|
|
|
return -ENOMEM;
|
2018-01-15 07:59:03 +00:00
|
|
|
|
|
|
|
if (top_hierarchy) {
|
|
|
|
resource_list = &devlink->resource_list;
|
|
|
|
} else {
|
|
|
|
struct devlink_resource *parent_resource;
|
|
|
|
|
|
|
|
parent_resource = devlink_resource_find(devlink, NULL,
|
|
|
|
parent_resource_id);
|
|
|
|
if (parent_resource) {
|
|
|
|
resource_list = &parent_resource->resource_list;
|
|
|
|
resource->parent = parent_resource;
|
|
|
|
} else {
|
2018-01-22 10:31:19 +00:00
|
|
|
kfree(resource);
|
2022-07-16 11:02:35 +00:00
|
|
|
return -EINVAL;
|
2018-01-15 07:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resource->name = resource_name;
|
|
|
|
resource->size = resource_size;
|
|
|
|
resource->size_new = resource_size;
|
|
|
|
resource->id = resource_id;
|
|
|
|
resource->size_valid = true;
|
2018-02-28 12:12:09 +00:00
|
|
|
memcpy(&resource->size_params, size_params,
|
|
|
|
sizeof(resource->size_params));
|
2018-01-15 07:59:03 +00:00
|
|
|
INIT_LIST_HEAD(&resource->resource_list);
|
|
|
|
list_add_tail(&resource->list, resource_list);
|
2022-07-16 11:02:35 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_resource_register);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_resource_register - devlink resource register
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @resource_name: resource's name
|
|
|
|
* @resource_size: resource's size
|
|
|
|
* @resource_id: resource's id
|
|
|
|
* @parent_resource_id: resource's parent id
|
|
|
|
* @size_params: size parameters
|
|
|
|
*
|
|
|
|
* Generic resources should reuse the same names across drivers.
|
|
|
|
* Please see the generic resources list at:
|
|
|
|
* Documentation/networking/devlink/devlink-resource.rst
|
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
|
|
|
*/
|
|
|
|
int devlink_resource_register(struct devlink *devlink,
|
|
|
|
const char *resource_name,
|
|
|
|
u64 resource_size,
|
|
|
|
u64 resource_id,
|
|
|
|
u64 parent_resource_id,
|
|
|
|
const struct devlink_resource_size_params *size_params)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
devl_lock(devlink);
|
|
|
|
err = devl_resource_register(devlink, resource_name, resource_size,
|
|
|
|
resource_id, parent_resource_id, size_params);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2018-01-15 07:59:03 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_resource_register);
|
|
|
|
|
2021-11-30 10:16:20 +00:00
|
|
|
static void devlink_resource_unregister(struct devlink *devlink,
|
|
|
|
struct devlink_resource *resource)
|
|
|
|
{
|
|
|
|
struct devlink_resource *tmp, *child_resource;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
|
|
|
|
list) {
|
|
|
|
devlink_resource_unregister(devlink, child_resource);
|
|
|
|
list_del(&child_resource->list);
|
|
|
|
kfree(child_resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-15 07:59:03 +00:00
|
|
|
/**
|
2022-07-16 11:02:35 +00:00
|
|
|
* devl_resources_unregister - free all resources
|
2018-01-15 07:59:03 +00:00
|
|
|
*
|
2022-07-16 11:02:35 +00:00
|
|
|
* @devlink: devlink
|
2018-01-15 07:59:03 +00:00
|
|
|
*/
|
2022-07-16 11:02:35 +00:00
|
|
|
void devl_resources_unregister(struct devlink *devlink)
|
2018-01-15 07:59:03 +00:00
|
|
|
{
|
|
|
|
struct devlink_resource *tmp, *child_resource;
|
|
|
|
|
2022-07-16 11:02:35 +00:00
|
|
|
lockdep_assert_held(&devlink->lock);
|
2018-01-15 07:59:03 +00:00
|
|
|
|
2021-11-30 10:16:20 +00:00
|
|
|
list_for_each_entry_safe(child_resource, tmp, &devlink->resource_list,
|
|
|
|
list) {
|
|
|
|
devlink_resource_unregister(devlink, child_resource);
|
2018-01-15 07:59:03 +00:00
|
|
|
list_del(&child_resource->list);
|
|
|
|
kfree(child_resource);
|
|
|
|
}
|
2022-07-16 11:02:35 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_resources_unregister);
|
2018-01-15 07:59:03 +00:00
|
|
|
|
2022-07-16 11:02:35 +00:00
|
|
|
/**
|
|
|
|
* devlink_resources_unregister - free all resources
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
|
|
|
*/
|
|
|
|
void devlink_resources_unregister(struct devlink *devlink)
|
|
|
|
{
|
|
|
|
devl_lock(devlink);
|
|
|
|
devl_resources_unregister(devlink);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2018-01-15 07:59:03 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_resources_unregister);
|
|
|
|
|
2022-07-16 11:02:35 +00:00
|
|
|
/**
|
|
|
|
* devl_resource_size_get - get and update size
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @resource_id: the requested resource id
|
|
|
|
* @p_resource_size: ptr to update
|
|
|
|
*/
|
|
|
|
int devl_resource_size_get(struct devlink *devlink,
|
|
|
|
u64 resource_id,
|
|
|
|
u64 *p_resource_size)
|
|
|
|
{
|
|
|
|
struct devlink_resource *resource;
|
|
|
|
|
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
|
|
|
resource = devlink_resource_find(devlink, NULL, resource_id);
|
|
|
|
if (!resource)
|
|
|
|
return -EINVAL;
|
|
|
|
*p_resource_size = resource->size_new;
|
|
|
|
resource->size = resource->size_new;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_resource_size_get);
|
|
|
|
|
2022-07-16 11:02:37 +00:00
|
|
|
/**
|
|
|
|
* devl_dpipe_table_resource_set - set the resource id
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @table_name: table name
|
|
|
|
* @resource_id: resource id
|
|
|
|
* @resource_units: number of resource's units consumed per table's entry
|
|
|
|
*/
|
|
|
|
int devl_dpipe_table_resource_set(struct devlink *devlink,
|
|
|
|
const char *table_name, u64 resource_id,
|
|
|
|
u64 resource_units)
|
|
|
|
{
|
|
|
|
struct devlink_dpipe_table *table;
|
|
|
|
|
|
|
|
table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
|
|
|
|
table_name, devlink);
|
|
|
|
if (!table)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
table->resource_id = resource_id;
|
|
|
|
table->resource_units = resource_units;
|
|
|
|
table->resource_valid = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_dpipe_table_resource_set);
|
|
|
|
|
2022-07-16 11:02:35 +00:00
|
|
|
/**
|
|
|
|
* devl_resource_occ_get_register - register occupancy getter
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @resource_id: resource id
|
|
|
|
* @occ_get: occupancy getter callback
|
|
|
|
* @occ_get_priv: occupancy getter callback priv
|
|
|
|
*/
|
|
|
|
void devl_resource_occ_get_register(struct devlink *devlink,
|
|
|
|
u64 resource_id,
|
|
|
|
devlink_resource_occ_get_t *occ_get,
|
|
|
|
void *occ_get_priv)
|
|
|
|
{
|
|
|
|
struct devlink_resource *resource;
|
|
|
|
|
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
|
|
|
resource = devlink_resource_find(devlink, NULL, resource_id);
|
|
|
|
if (WARN_ON(!resource))
|
|
|
|
return;
|
|
|
|
WARN_ON(resource->occ_get);
|
|
|
|
|
|
|
|
resource->occ_get = occ_get;
|
|
|
|
resource->occ_get_priv = occ_get_priv;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_resource_occ_get_register);
|
|
|
|
|
2018-04-05 20:13:21 +00:00
|
|
|
/**
|
|
|
|
* devlink_resource_occ_get_register - register occupancy getter
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @resource_id: resource id
|
|
|
|
* @occ_get: occupancy getter callback
|
|
|
|
* @occ_get_priv: occupancy getter callback priv
|
2022-07-16 11:02:35 +00:00
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
2018-04-05 20:13:21 +00:00
|
|
|
*/
|
|
|
|
void devlink_resource_occ_get_register(struct devlink *devlink,
|
|
|
|
u64 resource_id,
|
|
|
|
devlink_resource_occ_get_t *occ_get,
|
|
|
|
void *occ_get_priv)
|
|
|
|
{
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_lock(devlink);
|
2022-07-16 11:02:35 +00:00
|
|
|
devl_resource_occ_get_register(devlink, resource_id,
|
|
|
|
occ_get, occ_get_priv);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2018-04-05 20:13:21 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
|
|
|
|
|
|
|
|
/**
|
2022-07-16 11:02:35 +00:00
|
|
|
* devl_resource_occ_get_unregister - unregister occupancy getter
|
2018-04-05 20:13:21 +00:00
|
|
|
*
|
2022-07-16 11:02:35 +00:00
|
|
|
* @devlink: devlink
|
|
|
|
* @resource_id: resource id
|
2018-04-05 20:13:21 +00:00
|
|
|
*/
|
2022-07-16 11:02:35 +00:00
|
|
|
void devl_resource_occ_get_unregister(struct devlink *devlink,
|
|
|
|
u64 resource_id)
|
2018-04-05 20:13:21 +00:00
|
|
|
{
|
|
|
|
struct devlink_resource *resource;
|
|
|
|
|
2022-07-16 11:02:35 +00:00
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
2018-04-05 20:13:21 +00:00
|
|
|
resource = devlink_resource_find(devlink, NULL, resource_id);
|
|
|
|
if (WARN_ON(!resource))
|
2022-07-16 11:02:35 +00:00
|
|
|
return;
|
2018-04-05 20:13:21 +00:00
|
|
|
WARN_ON(!resource->occ_get);
|
|
|
|
|
|
|
|
resource->occ_get = NULL;
|
|
|
|
resource->occ_get_priv = NULL;
|
2022-07-16 11:02:35 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_resource_occ_get_unregister);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_resource_occ_get_unregister - unregister occupancy getter
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @resource_id: resource id
|
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
|
|
|
*/
|
|
|
|
void devlink_resource_occ_get_unregister(struct devlink *devlink,
|
|
|
|
u64 resource_id)
|
|
|
|
{
|
|
|
|
devl_lock(devlink);
|
|
|
|
devl_resource_occ_get_unregister(devlink, resource_id);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2018-04-05 20:13:21 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
|
|
|
|
|
2019-01-28 12:30:20 +00:00
|
|
|
static int devlink_param_verify(const struct devlink_param *param)
|
|
|
|
{
|
|
|
|
if (!param || !param->name || !param->supported_cmodes)
|
|
|
|
return -EINVAL;
|
|
|
|
if (param->generic)
|
|
|
|
return devlink_param_generic_verify(param);
|
|
|
|
else
|
|
|
|
return devlink_param_driver_verify(param);
|
|
|
|
}
|
|
|
|
|
2023-01-26 07:58:29 +00:00
|
|
|
static int devlink_param_register(struct devlink *devlink,
|
|
|
|
const struct devlink_param *param)
|
|
|
|
{
|
|
|
|
struct devlink_param_item *param_item;
|
2023-02-10 10:01:29 +00:00
|
|
|
int err;
|
2023-01-26 07:58:29 +00:00
|
|
|
|
|
|
|
WARN_ON(devlink_param_verify(param));
|
2023-02-10 10:01:29 +00:00
|
|
|
WARN_ON(devlink_param_find_by_name(&devlink->params, param->name));
|
2023-01-26 07:58:29 +00:00
|
|
|
|
|
|
|
if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
|
|
|
|
WARN_ON(param->get || param->set);
|
|
|
|
else
|
|
|
|
WARN_ON(!param->get || !param->set);
|
|
|
|
|
|
|
|
param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
|
|
|
|
if (!param_item)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
param_item->param = param;
|
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
err = xa_insert(&devlink->params, param->id, param_item, GFP_KERNEL);
|
|
|
|
if (err)
|
|
|
|
goto err_xa_insert;
|
|
|
|
|
2023-01-26 07:58:29 +00:00
|
|
|
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
|
|
|
|
return 0;
|
2023-02-10 10:01:29 +00:00
|
|
|
|
|
|
|
err_xa_insert:
|
|
|
|
kfree(param_item);
|
|
|
|
return err;
|
2023-01-26 07:58:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_param_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_param *param)
|
|
|
|
{
|
|
|
|
struct devlink_param_item *param_item;
|
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
param_item = devlink_param_find_by_id(&devlink->params, param->id);
|
2023-01-26 07:58:30 +00:00
|
|
|
if (WARN_ON(!param_item))
|
|
|
|
return;
|
2023-01-26 07:58:29 +00:00
|
|
|
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_DEL);
|
2023-02-10 10:01:29 +00:00
|
|
|
xa_erase(&devlink->params, param->id);
|
2023-01-26 07:58:29 +00:00
|
|
|
kfree(param_item);
|
|
|
|
}
|
|
|
|
|
2019-01-28 12:30:20 +00:00
|
|
|
/**
|
2023-01-26 07:58:35 +00:00
|
|
|
* devl_params_register - register configuration parameters
|
2019-01-28 12:30:20 +00:00
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @params: configuration parameters array
|
|
|
|
* @params_count: number of parameters provided
|
|
|
|
*
|
|
|
|
* Register the configuration parameters supported by the driver.
|
|
|
|
*/
|
2023-01-26 07:58:35 +00:00
|
|
|
int devl_params_register(struct devlink *devlink,
|
|
|
|
const struct devlink_param *params,
|
|
|
|
size_t params_count)
|
2019-01-28 12:30:20 +00:00
|
|
|
{
|
2021-10-28 13:23:21 +00:00
|
|
|
const struct devlink_param *param = params;
|
|
|
|
int i, err;
|
|
|
|
|
2023-01-26 07:58:35 +00:00
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
2021-10-28 13:23:21 +00:00
|
|
|
for (i = 0; i < params_count; i++, param++) {
|
|
|
|
err = devlink_param_register(devlink, param);
|
|
|
|
if (err)
|
|
|
|
goto rollback;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rollback:
|
|
|
|
if (!i)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
for (param--; i > 0; i--, param--)
|
|
|
|
devlink_param_unregister(devlink, param);
|
|
|
|
return err;
|
2019-01-28 12:30:20 +00:00
|
|
|
}
|
2023-01-26 07:58:35 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_params_register);
|
|
|
|
|
|
|
|
int devlink_params_register(struct devlink *devlink,
|
|
|
|
const struct devlink_param *params,
|
|
|
|
size_t params_count)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
devl_lock(devlink);
|
|
|
|
err = devl_params_register(devlink, params, params_count);
|
|
|
|
devl_unlock(devlink);
|
|
|
|
return err;
|
|
|
|
}
|
2018-07-04 11:30:28 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_params_register);
|
|
|
|
|
|
|
|
/**
|
2023-01-26 07:58:35 +00:00
|
|
|
* devl_params_unregister - unregister configuration parameters
|
2018-07-04 11:30:28 +00:00
|
|
|
* @devlink: devlink
|
|
|
|
* @params: configuration parameters to unregister
|
|
|
|
* @params_count: number of parameters provided
|
|
|
|
*/
|
2023-01-26 07:58:35 +00:00
|
|
|
void devl_params_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_param *params,
|
|
|
|
size_t params_count)
|
2018-07-04 11:30:28 +00:00
|
|
|
{
|
2021-10-28 13:23:21 +00:00
|
|
|
const struct devlink_param *param = params;
|
|
|
|
int i;
|
|
|
|
|
2023-01-26 07:58:35 +00:00
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
2021-10-28 13:23:21 +00:00
|
|
|
for (i = 0; i < params_count; i++, param++)
|
|
|
|
devlink_param_unregister(devlink, param);
|
2018-07-04 11:30:28 +00:00
|
|
|
}
|
2023-01-26 07:58:35 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_params_unregister);
|
|
|
|
|
|
|
|
void devlink_params_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_param *params,
|
|
|
|
size_t params_count)
|
|
|
|
{
|
|
|
|
devl_lock(devlink);
|
|
|
|
devl_params_unregister(devlink, params, params_count);
|
|
|
|
devl_unlock(devlink);
|
|
|
|
}
|
2018-07-04 11:30:28 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_params_unregister);
|
|
|
|
|
2021-09-23 18:12:51 +00:00
|
|
|
/**
|
2023-01-26 07:58:35 +00:00
|
|
|
* devl_param_driverinit_value_get - get configuration parameter
|
|
|
|
* value for driver initializing
|
2021-09-23 18:12:51 +00:00
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @param_id: parameter ID
|
2023-02-10 10:01:27 +00:00
|
|
|
* @val: pointer to store the value of parameter in driverinit
|
|
|
|
* configuration mode
|
2021-09-23 18:12:51 +00:00
|
|
|
*
|
|
|
|
* This function should be used by the driver to get driverinit
|
|
|
|
* configuration for initialization after reload command.
|
|
|
|
*/
|
2023-01-26 07:58:35 +00:00
|
|
|
int devl_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
|
2023-02-10 10:01:27 +00:00
|
|
|
union devlink_param_value *val)
|
2018-07-04 11:30:31 +00:00
|
|
|
{
|
|
|
|
struct devlink_param_item *param_item;
|
|
|
|
|
2023-01-26 07:58:35 +00:00
|
|
|
lockdep_assert_held(&devlink->lock);
|
|
|
|
|
2023-01-26 07:58:34 +00:00
|
|
|
if (WARN_ON(!devlink_reload_supported(devlink->ops)))
|
2021-09-23 18:12:51 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
param_item = devlink_param_find_by_id(&devlink->params, param_id);
|
2018-07-04 11:30:31 +00:00
|
|
|
if (!param_item)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-01-26 07:58:34 +00:00
|
|
|
if (!param_item->driverinit_value_valid)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (WARN_ON(!devlink_param_cmode_is_supported(param_item->param,
|
|
|
|
DEVLINK_PARAM_CMODE_DRIVERINIT)))
|
2018-07-04 11:30:31 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2023-02-10 10:01:27 +00:00
|
|
|
*val = param_item->driverinit_value;
|
2018-07-04 11:30:31 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2023-01-26 07:58:35 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_param_driverinit_value_get);
|
2019-01-28 12:30:23 +00:00
|
|
|
|
2021-09-23 18:12:51 +00:00
|
|
|
/**
|
2023-01-26 07:58:35 +00:00
|
|
|
* devl_param_driverinit_value_set - set value of configuration
|
|
|
|
* parameter for driverinit
|
|
|
|
* configuration mode
|
2021-09-23 18:12:51 +00:00
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @param_id: parameter ID
|
|
|
|
* @init_val: value of parameter to set for driverinit configuration mode
|
|
|
|
*
|
|
|
|
* This function should be used by the driver to set driverinit
|
|
|
|
* configuration mode default value.
|
|
|
|
*/
|
2023-01-26 07:58:35 +00:00
|
|
|
void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
|
|
|
|
union devlink_param_value init_val)
|
2019-01-28 12:30:24 +00:00
|
|
|
{
|
|
|
|
struct devlink_param_item *param_item;
|
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
param_item = devlink_param_find_by_id(&devlink->params, param_id);
|
2023-01-26 07:58:33 +00:00
|
|
|
if (WARN_ON(!param_item))
|
|
|
|
return;
|
2019-01-28 12:30:24 +00:00
|
|
|
|
2023-01-26 07:58:33 +00:00
|
|
|
if (WARN_ON(!devlink_param_cmode_is_supported(param_item->param,
|
|
|
|
DEVLINK_PARAM_CMODE_DRIVERINIT)))
|
|
|
|
return;
|
2019-01-28 12:30:24 +00:00
|
|
|
|
2023-02-10 10:01:25 +00:00
|
|
|
param_item->driverinit_value = init_val;
|
2019-01-28 12:30:24 +00:00
|
|
|
param_item->driverinit_value_valid = true;
|
2023-01-06 06:34:00 +00:00
|
|
|
|
|
|
|
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
|
2019-01-28 12:30:24 +00:00
|
|
|
}
|
2023-01-26 07:58:35 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_param_driverinit_value_set);
|
2018-07-04 11:30:31 +00:00
|
|
|
|
2023-02-10 10:01:26 +00:00
|
|
|
void devlink_params_driverinit_load_new(struct devlink *devlink)
|
|
|
|
{
|
|
|
|
struct devlink_param_item *param_item;
|
2023-02-10 10:01:29 +00:00
|
|
|
unsigned long param_id;
|
2023-02-10 10:01:26 +00:00
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
xa_for_each(&devlink->params, param_id, param_item) {
|
2023-02-10 10:01:26 +00:00
|
|
|
if (!devlink_param_cmode_is_supported(param_item->param,
|
|
|
|
DEVLINK_PARAM_CMODE_DRIVERINIT) ||
|
|
|
|
!param_item->driverinit_value_new_valid)
|
|
|
|
continue;
|
|
|
|
param_item->driverinit_value = param_item->driverinit_value_new;
|
|
|
|
param_item->driverinit_value_valid = true;
|
|
|
|
param_item->driverinit_value_new_valid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-04 11:30:32 +00:00
|
|
|
/**
|
2023-01-26 07:58:35 +00:00
|
|
|
* devl_param_value_changed - notify devlink on a parameter's value
|
|
|
|
* change. Should be called by the driver
|
|
|
|
* right after the change.
|
2018-07-04 11:30:32 +00:00
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @param_id: parameter ID
|
|
|
|
*
|
|
|
|
* This function should be used by the driver to notify devlink on value
|
|
|
|
* change, excluding driverinit configuration mode.
|
|
|
|
* For driverinit configuration mode driver should use the function
|
|
|
|
*/
|
2023-01-26 07:58:35 +00:00
|
|
|
void devl_param_value_changed(struct devlink *devlink, u32 param_id)
|
2018-07-04 11:30:32 +00:00
|
|
|
{
|
|
|
|
struct devlink_param_item *param_item;
|
|
|
|
|
2023-02-10 10:01:29 +00:00
|
|
|
param_item = devlink_param_find_by_id(&devlink->params, param_id);
|
2018-07-04 11:30:32 +00:00
|
|
|
WARN_ON(!param_item);
|
|
|
|
|
2019-01-28 12:30:25 +00:00
|
|
|
devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
|
2018-07-04 11:30:32 +00:00
|
|
|
}
|
2023-01-26 07:58:35 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_param_value_changed);
|
2018-07-04 11:30:32 +00:00
|
|
|
|
2018-07-12 12:13:08 +00:00
|
|
|
/**
|
2022-07-16 11:02:39 +00:00
|
|
|
* devl_region_create - create a new address region
|
2018-07-12 12:13:08 +00:00
|
|
|
*
|
2022-07-16 11:02:39 +00:00
|
|
|
* @devlink: devlink
|
|
|
|
* @ops: region operations and name
|
|
|
|
* @region_max_snapshots: Maximum supported number of snapshots for region
|
|
|
|
* @region_size: size of region
|
2018-07-12 12:13:08 +00:00
|
|
|
*/
|
2022-07-16 11:02:39 +00:00
|
|
|
struct devlink_region *devl_region_create(struct devlink *devlink,
|
|
|
|
const struct devlink_region_ops *ops,
|
|
|
|
u32 region_max_snapshots,
|
|
|
|
u64 region_size)
|
2018-07-12 12:13:08 +00:00
|
|
|
{
|
|
|
|
struct devlink_region *region;
|
2022-07-16 11:02:39 +00:00
|
|
|
|
|
|
|
devl_assert_locked(devlink);
|
2018-07-12 12:13:08 +00:00
|
|
|
|
2020-03-26 18:37:09 +00:00
|
|
|
if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
2022-07-16 11:02:39 +00:00
|
|
|
if (devlink_region_get_by_name(devlink, ops->name))
|
|
|
|
return ERR_PTR(-EEXIST);
|
2018-07-12 12:13:08 +00:00
|
|
|
|
|
|
|
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
2022-07-16 11:02:39 +00:00
|
|
|
if (!region)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
2018-07-12 12:13:08 +00:00
|
|
|
|
|
|
|
region->devlink = devlink;
|
|
|
|
region->max_snapshots = region_max_snapshots;
|
2020-03-26 18:37:08 +00:00
|
|
|
region->ops = ops;
|
2018-07-12 12:13:08 +00:00
|
|
|
region->size = region_size;
|
|
|
|
INIT_LIST_HEAD(®ion->snapshot_list);
|
2022-07-28 15:53:43 +00:00
|
|
|
mutex_init(®ion->snapshot_lock);
|
2018-07-12 12:13:08 +00:00
|
|
|
list_add_tail(®ion->list, &devlink->region_list);
|
2018-07-12 12:13:13 +00:00
|
|
|
devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
|
2018-07-12 12:13:08 +00:00
|
|
|
|
|
|
|
return region;
|
2022-07-16 11:02:39 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_region_create);
|
2018-07-12 12:13:08 +00:00
|
|
|
|
2022-07-16 11:02:39 +00:00
|
|
|
/**
|
|
|
|
* devlink_region_create - create a new address region
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @ops: region operations and name
|
|
|
|
* @region_max_snapshots: Maximum supported number of snapshots for region
|
|
|
|
* @region_size: size of region
|
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
|
|
|
*/
|
|
|
|
struct devlink_region *
|
|
|
|
devlink_region_create(struct devlink *devlink,
|
|
|
|
const struct devlink_region_ops *ops,
|
|
|
|
u32 region_max_snapshots, u64 region_size)
|
|
|
|
{
|
|
|
|
struct devlink_region *region;
|
|
|
|
|
|
|
|
devl_lock(devlink);
|
|
|
|
region = devl_region_create(devlink, ops, region_max_snapshots,
|
|
|
|
region_size);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2022-07-16 11:02:39 +00:00
|
|
|
return region;
|
2018-07-12 12:13:08 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_region_create);
|
|
|
|
|
2020-10-04 16:12:54 +00:00
|
|
|
/**
|
|
|
|
* devlink_port_region_create - create a new address region for a port
|
|
|
|
*
|
|
|
|
* @port: devlink port
|
|
|
|
* @ops: region operations and name
|
|
|
|
* @region_max_snapshots: Maximum supported number of snapshots for region
|
|
|
|
* @region_size: size of region
|
2022-07-16 11:02:39 +00:00
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
2020-10-04 16:12:54 +00:00
|
|
|
*/
|
|
|
|
struct devlink_region *
|
|
|
|
devlink_port_region_create(struct devlink_port *port,
|
|
|
|
const struct devlink_port_region_ops *ops,
|
|
|
|
u32 region_max_snapshots, u64 region_size)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = port->devlink;
|
|
|
|
struct devlink_region *region;
|
|
|
|
int err = 0;
|
|
|
|
|
2022-09-29 07:28:58 +00:00
|
|
|
ASSERT_DEVLINK_PORT_INITIALIZED(port);
|
|
|
|
|
2020-10-04 16:12:54 +00:00
|
|
|
if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_lock(devlink);
|
2020-10-04 16:12:54 +00:00
|
|
|
|
|
|
|
if (devlink_port_region_get_by_name(port, ops->name)) {
|
|
|
|
err = -EEXIST;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
region = kzalloc(sizeof(*region), GFP_KERNEL);
|
|
|
|
if (!region) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
region->devlink = devlink;
|
|
|
|
region->port = port;
|
|
|
|
region->max_snapshots = region_max_snapshots;
|
|
|
|
region->port_ops = ops;
|
|
|
|
region->size = region_size;
|
|
|
|
INIT_LIST_HEAD(®ion->snapshot_list);
|
2022-07-28 15:53:43 +00:00
|
|
|
mutex_init(®ion->snapshot_lock);
|
2020-10-04 16:12:54 +00:00
|
|
|
list_add_tail(®ion->list, &port->region_list);
|
|
|
|
devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
|
|
|
|
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2020-10-04 16:12:54 +00:00
|
|
|
return region;
|
|
|
|
|
|
|
|
unlock:
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2020-10-04 16:12:54 +00:00
|
|
|
return ERR_PTR(err);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_port_region_create);
|
|
|
|
|
2018-07-12 12:13:08 +00:00
|
|
|
/**
|
2022-07-16 11:02:39 +00:00
|
|
|
* devl_region_destroy - destroy address region
|
2018-07-12 12:13:08 +00:00
|
|
|
*
|
2022-07-16 11:02:39 +00:00
|
|
|
* @region: devlink region to destroy
|
2018-07-12 12:13:08 +00:00
|
|
|
*/
|
2022-07-16 11:02:39 +00:00
|
|
|
void devl_region_destroy(struct devlink_region *region)
|
2018-07-12 12:13:08 +00:00
|
|
|
{
|
|
|
|
struct devlink *devlink = region->devlink;
|
2018-07-12 12:13:10 +00:00
|
|
|
struct devlink_snapshot *snapshot, *ts;
|
2018-07-12 12:13:08 +00:00
|
|
|
|
2022-07-16 11:02:39 +00:00
|
|
|
devl_assert_locked(devlink);
|
2018-07-12 12:13:10 +00:00
|
|
|
|
|
|
|
/* Free all snapshots of region */
|
2022-12-15 02:01:00 +00:00
|
|
|
mutex_lock(®ion->snapshot_lock);
|
2018-07-12 12:13:10 +00:00
|
|
|
list_for_each_entry_safe(snapshot, ts, ®ion->snapshot_list, list)
|
2019-08-12 12:28:31 +00:00
|
|
|
devlink_region_snapshot_del(region, snapshot);
|
2022-12-15 02:01:00 +00:00
|
|
|
mutex_unlock(®ion->snapshot_lock);
|
2018-07-12 12:13:10 +00:00
|
|
|
|
2018-07-12 12:13:08 +00:00
|
|
|
list_del(®ion->list);
|
2022-07-28 15:53:43 +00:00
|
|
|
mutex_destroy(®ion->snapshot_lock);
|
2018-07-12 12:13:13 +00:00
|
|
|
|
|
|
|
devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
|
2018-07-12 12:13:08 +00:00
|
|
|
kfree(region);
|
|
|
|
}
|
2022-07-16 11:02:39 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devl_region_destroy);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_region_destroy - destroy address region
|
|
|
|
*
|
|
|
|
* @region: devlink region to destroy
|
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
|
|
|
*/
|
|
|
|
void devlink_region_destroy(struct devlink_region *region)
|
|
|
|
{
|
|
|
|
struct devlink *devlink = region->devlink;
|
|
|
|
|
|
|
|
devl_lock(devlink);
|
|
|
|
devl_region_destroy(region);
|
|
|
|
devl_unlock(devlink);
|
|
|
|
}
|
2018-07-12 12:13:08 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_region_destroy);
|
|
|
|
|
2018-07-12 12:13:09 +00:00
|
|
|
/**
|
2020-01-09 19:08:20 +00:00
|
|
|
* devlink_region_snapshot_id_get - get snapshot ID
|
2018-07-12 12:13:09 +00:00
|
|
|
*
|
|
|
|
* This callback should be called when adding a new snapshot,
|
|
|
|
* Driver should use the same id for multiple snapshots taken
|
|
|
|
* on multiple regions at the same time/by the same trigger.
|
|
|
|
*
|
2020-03-26 18:37:15 +00:00
|
|
|
* The caller of this function must use devlink_region_snapshot_id_put
|
|
|
|
* when finished creating regions using this id.
|
|
|
|
*
|
2020-03-26 18:37:14 +00:00
|
|
|
* Returns zero on success, or a negative error code on failure.
|
|
|
|
*
|
2018-07-12 12:13:09 +00:00
|
|
|
* @devlink: devlink
|
2020-03-26 18:37:14 +00:00
|
|
|
* @id: storage to return id
|
2018-07-12 12:13:09 +00:00
|
|
|
*/
|
2020-03-26 18:37:14 +00:00
|
|
|
int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
|
2018-07-12 12:13:09 +00:00
|
|
|
{
|
2022-07-28 15:53:42 +00:00
|
|
|
return __devlink_region_snapshot_id_get(devlink, id);
|
2018-07-12 12:13:09 +00:00
|
|
|
}
|
2020-01-09 19:08:20 +00:00
|
|
|
EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
|
2018-07-12 12:13:09 +00:00
|
|
|
|
2020-03-26 18:37:15 +00:00
|
|
|
/**
|
|
|
|
* devlink_region_snapshot_id_put - put snapshot ID reference
|
|
|
|
*
|
|
|
|
* This should be called by a driver after finishing creating snapshots
|
|
|
|
* with an id. Doing so ensures that the ID can later be released in the
|
|
|
|
* event that all snapshots using it have been destroyed.
|
|
|
|
*
|
|
|
|
* @devlink: devlink
|
|
|
|
* @id: id to release reference on
|
|
|
|
*/
|
|
|
|
void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
|
|
|
|
{
|
|
|
|
__devlink_snapshot_id_decrement(devlink, id);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
|
|
|
|
|
2018-07-12 12:13:10 +00:00
|
|
|
/**
|
|
|
|
* devlink_region_snapshot_create - create a new snapshot
|
|
|
|
* This will add a new snapshot of a region. The snapshot
|
|
|
|
* will be stored on the region struct and can be accessed
|
2020-03-26 18:37:10 +00:00
|
|
|
* from devlink. This is useful for future analyses of snapshots.
|
2018-07-12 12:13:10 +00:00
|
|
|
* Multiple snapshots can be created on a region.
|
|
|
|
* The @snapshot_id should be obtained using the getter function.
|
|
|
|
*
|
2019-02-27 19:36:36 +00:00
|
|
|
* @region: devlink region of the snapshot
|
2018-07-12 12:13:10 +00:00
|
|
|
* @data: snapshot data
|
|
|
|
* @snapshot_id: snapshot id to be created
|
|
|
|
*/
|
2019-08-09 13:27:15 +00:00
|
|
|
int devlink_region_snapshot_create(struct devlink_region *region,
|
2020-03-26 18:37:09 +00:00
|
|
|
u8 *data, u32 snapshot_id)
|
2018-07-12 12:13:10 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2022-07-28 15:53:43 +00:00
|
|
|
mutex_lock(®ion->snapshot_lock);
|
2020-03-26 18:37:11 +00:00
|
|
|
err = __devlink_region_snapshot_create(region, data, snapshot_id);
|
2022-07-28 15:53:43 +00:00
|
|
|
mutex_unlock(®ion->snapshot_lock);
|
2018-07-12 12:13:10 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
#define DEVLINK_TRAP(_id, _type) \
|
|
|
|
{ \
|
|
|
|
.type = DEVLINK_TRAP_TYPE_##_type, \
|
|
|
|
.id = DEVLINK_TRAP_GENERIC_ID_##_id, \
|
|
|
|
.name = DEVLINK_TRAP_GENERIC_NAME_##_id, \
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct devlink_trap devlink_trap_generic[] = {
|
2019-08-17 13:28:18 +00:00
|
|
|
DEVLINK_TRAP(SMAC_MC, DROP),
|
|
|
|
DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
|
|
|
|
DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
|
|
|
|
DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
|
|
|
|
DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
|
|
|
|
DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
|
|
|
|
DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
|
|
|
|
DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
|
|
|
|
DEVLINK_TRAP(TAIL_DROP, DROP),
|
2019-11-07 16:42:09 +00:00
|
|
|
DEVLINK_TRAP(NON_IP_PACKET, DROP),
|
|
|
|
DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
|
|
|
|
DEVLINK_TRAP(DIP_LB, DROP),
|
|
|
|
DEVLINK_TRAP(SIP_MC, DROP),
|
|
|
|
DEVLINK_TRAP(SIP_LB, DROP),
|
|
|
|
DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
|
|
|
|
DEVLINK_TRAP(IPV4_SIP_BC, DROP),
|
|
|
|
DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
|
|
|
|
DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
|
2019-11-07 16:42:14 +00:00
|
|
|
DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
|
|
|
|
DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
|
|
|
|
DEVLINK_TRAP(RPF, EXCEPTION),
|
|
|
|
DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
|
|
|
|
DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
|
|
|
|
DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
|
2020-01-19 13:00:48 +00:00
|
|
|
DEVLINK_TRAP(NON_ROUTABLE, DROP),
|
2020-01-19 13:00:54 +00:00
|
|
|
DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
|
2020-01-19 13:00:58 +00:00
|
|
|
DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
|
2020-02-24 07:35:47 +00:00
|
|
|
DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
|
|
|
|
DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
|
2020-05-29 18:36:41 +00:00
|
|
|
DEVLINK_TRAP(STP, CONTROL),
|
|
|
|
DEVLINK_TRAP(LACP, CONTROL),
|
|
|
|
DEVLINK_TRAP(LLDP, CONTROL),
|
|
|
|
DEVLINK_TRAP(IGMP_QUERY, CONTROL),
|
|
|
|
DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
|
|
|
|
DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
|
|
|
|
DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
|
|
|
|
DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
|
|
|
|
DEVLINK_TRAP(MLD_QUERY, CONTROL),
|
|
|
|
DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
|
|
|
|
DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
|
|
|
|
DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
|
2020-05-29 18:36:42 +00:00
|
|
|
DEVLINK_TRAP(IPV4_DHCP, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_DHCP, CONTROL),
|
|
|
|
DEVLINK_TRAP(ARP_REQUEST, CONTROL),
|
|
|
|
DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
|
|
|
|
DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV4_BFD, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_BFD, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV4_OSPF, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_OSPF, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV4_BGP, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_BGP, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV4_VRRP, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_VRRP, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV4_PIM, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_PIM, CONTROL),
|
|
|
|
DEVLINK_TRAP(UC_LB, CONTROL),
|
|
|
|
DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
|
|
|
|
DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
|
|
|
|
DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
|
|
|
|
DEVLINK_TRAP(PTP_EVENT, CONTROL),
|
|
|
|
DEVLINK_TRAP(PTP_GENERAL, CONTROL),
|
2020-05-29 18:36:43 +00:00
|
|
|
DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
|
|
|
|
DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
|
2020-08-03 16:11:33 +00:00
|
|
|
DEVLINK_TRAP(EARLY_DROP, DROP),
|
2020-10-01 15:11:45 +00:00
|
|
|
DEVLINK_TRAP(VXLAN_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(LLC_SNAP_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(VLAN_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(MPLS_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(ARP_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(IP_1_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(IP_N_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(GRE_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(UDP_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(TCP_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(IPSEC_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(SCTP_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(DCCP_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(GTP_PARSING, DROP),
|
|
|
|
DEVLINK_TRAP(ESP_PARSING, DROP),
|
2020-11-23 07:12:28 +00:00
|
|
|
DEVLINK_TRAP(BLACKHOLE_NEXTHOP, DROP),
|
2021-01-26 23:24:06 +00:00
|
|
|
DEVLINK_TRAP(DMAC_FILTER, DROP),
|
2022-11-08 10:47:10 +00:00
|
|
|
DEVLINK_TRAP(EAPOL, CONTROL),
|
|
|
|
DEVLINK_TRAP(LOCKED_PORT, DROP),
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#define DEVLINK_TRAP_GROUP(_id) \
|
|
|
|
{ \
|
|
|
|
.id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id, \
|
|
|
|
.name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id, \
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct devlink_trap_group devlink_trap_group_generic[] = {
|
2019-08-17 13:28:18 +00:00
|
|
|
DEVLINK_TRAP_GROUP(L2_DROPS),
|
|
|
|
DEVLINK_TRAP_GROUP(L3_DROPS),
|
2020-05-29 18:36:36 +00:00
|
|
|
DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
|
2019-08-17 13:28:18 +00:00
|
|
|
DEVLINK_TRAP_GROUP(BUFFER_DROPS),
|
2020-01-19 13:00:54 +00:00
|
|
|
DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
|
2020-02-24 07:35:47 +00:00
|
|
|
DEVLINK_TRAP_GROUP(ACL_DROPS),
|
2020-05-29 18:36:41 +00:00
|
|
|
DEVLINK_TRAP_GROUP(STP),
|
|
|
|
DEVLINK_TRAP_GROUP(LACP),
|
|
|
|
DEVLINK_TRAP_GROUP(LLDP),
|
|
|
|
DEVLINK_TRAP_GROUP(MC_SNOOPING),
|
2020-05-29 18:36:42 +00:00
|
|
|
DEVLINK_TRAP_GROUP(DHCP),
|
|
|
|
DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
|
|
|
|
DEVLINK_TRAP_GROUP(BFD),
|
|
|
|
DEVLINK_TRAP_GROUP(OSPF),
|
|
|
|
DEVLINK_TRAP_GROUP(BGP),
|
|
|
|
DEVLINK_TRAP_GROUP(VRRP),
|
|
|
|
DEVLINK_TRAP_GROUP(PIM),
|
|
|
|
DEVLINK_TRAP_GROUP(UC_LB),
|
|
|
|
DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
|
2020-07-29 09:26:44 +00:00
|
|
|
DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY),
|
2020-05-29 18:36:42 +00:00
|
|
|
DEVLINK_TRAP_GROUP(IPV6),
|
|
|
|
DEVLINK_TRAP_GROUP(PTP_EVENT),
|
|
|
|
DEVLINK_TRAP_GROUP(PTP_GENERAL),
|
2020-05-29 18:36:43 +00:00
|
|
|
DEVLINK_TRAP_GROUP(ACL_SAMPLE),
|
|
|
|
DEVLINK_TRAP_GROUP(ACL_TRAP),
|
2020-10-01 15:11:45 +00:00
|
|
|
DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS),
|
2022-11-08 10:47:10 +00:00
|
|
|
DEVLINK_TRAP_GROUP(EAPOL),
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int devlink_trap_generic_verify(const struct devlink_trap *trap)
|
|
|
|
{
|
|
|
|
if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (trap->type != devlink_trap_generic[trap->id].type)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_trap_driver_verify(const struct devlink_trap *trap)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
|
|
|
|
if (!strcmp(trap->name, devlink_trap_generic[i].name))
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_trap_verify(const struct devlink_trap *trap)
|
|
|
|
{
|
2020-03-22 18:48:30 +00:00
|
|
|
if (!trap || !trap->name)
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (trap->generic)
|
|
|
|
return devlink_trap_generic_verify(trap);
|
|
|
|
else
|
|
|
|
return devlink_trap_driver_verify(trap);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_trap_group_generic_verify(const struct devlink_trap_group *group)
|
|
|
|
{
|
|
|
|
if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_trap_group_driver_verify(const struct devlink_trap_group *group)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
|
|
|
|
if (!strcmp(group->name, devlink_trap_group_generic[i].name))
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int devlink_trap_group_verify(const struct devlink_trap_group *group)
|
|
|
|
{
|
|
|
|
if (group->generic)
|
|
|
|
return devlink_trap_group_generic_verify(group);
|
|
|
|
else
|
|
|
|
return devlink_trap_group_driver_verify(group);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
devlink_trap_group_notify(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_group_item *group_item,
|
|
|
|
enum devlink_command cmd)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
|
|
|
|
cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
|
2021-10-26 19:40:41 +00:00
|
|
|
if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
|
|
|
|
return;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
|
|
|
|
0);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
|
|
|
|
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_trap_item_group_link(struct devlink *devlink,
|
|
|
|
struct devlink_trap_item *trap_item)
|
|
|
|
{
|
2020-03-22 18:48:30 +00:00
|
|
|
u16 group_id = trap_item->trap->init_group_id;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
struct devlink_trap_group_item *group_item;
|
|
|
|
|
2020-03-22 18:48:30 +00:00
|
|
|
group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
|
2020-03-22 18:48:29 +00:00
|
|
|
if (WARN_ON_ONCE(!group_item))
|
|
|
|
return -EINVAL;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
|
|
|
|
trap_item->group_item = group_item;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_trap_notify(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_item *trap_item,
|
|
|
|
enum devlink_command cmd)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
|
|
|
|
cmd != DEVLINK_CMD_TRAP_DEL);
|
2021-09-25 11:22:41 +00:00
|
|
|
if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
|
|
|
|
return;
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
|
|
|
|
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_trap_register(struct devlink *devlink,
|
|
|
|
const struct devlink_trap *trap, void *priv)
|
|
|
|
{
|
|
|
|
struct devlink_trap_item *trap_item;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (devlink_trap_item_lookup(devlink, trap->name))
|
|
|
|
return -EEXIST;
|
|
|
|
|
|
|
|
trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
|
|
|
|
if (!trap_item)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
|
|
|
|
if (!trap_item->stats) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto err_stats_alloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
trap_item->trap = trap;
|
|
|
|
trap_item->action = trap->init_action;
|
|
|
|
trap_item->priv = priv;
|
|
|
|
|
|
|
|
err = devlink_trap_item_group_link(devlink, trap_item);
|
|
|
|
if (err)
|
|
|
|
goto err_group_link;
|
|
|
|
|
|
|
|
err = devlink->ops->trap_init(devlink, trap, trap_item);
|
|
|
|
if (err)
|
|
|
|
goto err_trap_init;
|
|
|
|
|
|
|
|
list_add_tail(&trap_item->list, &devlink->trap_list);
|
|
|
|
devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_trap_init:
|
|
|
|
err_group_link:
|
|
|
|
free_percpu(trap_item->stats);
|
|
|
|
err_stats_alloc:
|
|
|
|
kfree(trap_item);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_trap_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_trap *trap)
|
|
|
|
{
|
|
|
|
struct devlink_trap_item *trap_item;
|
|
|
|
|
|
|
|
trap_item = devlink_trap_item_lookup(devlink, trap->name);
|
|
|
|
if (WARN_ON_ONCE(!trap_item))
|
|
|
|
return;
|
|
|
|
|
|
|
|
devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
|
|
|
|
list_del(&trap_item->list);
|
|
|
|
if (devlink->ops->trap_fini)
|
|
|
|
devlink->ops->trap_fini(devlink, trap, trap_item);
|
|
|
|
free_percpu(trap_item->stats);
|
|
|
|
kfree(trap_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void devlink_trap_disable(struct devlink *devlink,
|
|
|
|
const struct devlink_trap *trap)
|
|
|
|
{
|
|
|
|
struct devlink_trap_item *trap_item;
|
|
|
|
|
|
|
|
trap_item = devlink_trap_item_lookup(devlink, trap->name);
|
|
|
|
if (WARN_ON_ONCE(!trap_item))
|
|
|
|
return;
|
|
|
|
|
2020-08-03 16:11:34 +00:00
|
|
|
devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP,
|
|
|
|
NULL);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
trap_item->action = DEVLINK_TRAP_ACTION_DROP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-07-16 11:02:34 +00:00
|
|
|
* devl_traps_register - Register packet traps with devlink.
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
* @devlink: devlink.
|
|
|
|
* @traps: Packet traps.
|
|
|
|
* @traps_count: Count of provided packet traps.
|
|
|
|
* @priv: Driver private information.
|
|
|
|
*
|
|
|
|
* Return: Non-zero value on failure.
|
|
|
|
*/
|
2022-07-16 11:02:34 +00:00
|
|
|
int devl_traps_register(struct devlink *devlink,
|
|
|
|
const struct devlink_trap *traps,
|
|
|
|
size_t traps_count, void *priv)
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
{
|
|
|
|
int i, err;
|
|
|
|
|
|
|
|
if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2022-07-16 11:02:34 +00:00
|
|
|
devl_assert_locked(devlink);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
for (i = 0; i < traps_count; i++) {
|
|
|
|
const struct devlink_trap *trap = &traps[i];
|
|
|
|
|
|
|
|
err = devlink_trap_verify(trap);
|
|
|
|
if (err)
|
|
|
|
goto err_trap_verify;
|
|
|
|
|
|
|
|
err = devlink_trap_register(devlink, trap, priv);
|
|
|
|
if (err)
|
|
|
|
goto err_trap_register;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_trap_register:
|
|
|
|
err_trap_verify:
|
|
|
|
for (i--; i >= 0; i--)
|
|
|
|
devlink_trap_unregister(devlink, &traps[i]);
|
2022-07-16 11:02:34 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_traps_register);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_traps_register - Register packet traps with devlink.
|
|
|
|
* @devlink: devlink.
|
|
|
|
* @traps: Packet traps.
|
|
|
|
* @traps_count: Count of provided packet traps.
|
|
|
|
* @priv: Driver private information.
|
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
|
|
|
*
|
|
|
|
* Return: Non-zero value on failure.
|
|
|
|
*/
|
|
|
|
int devlink_traps_register(struct devlink *devlink,
|
|
|
|
const struct devlink_trap *traps,
|
|
|
|
size_t traps_count, void *priv)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
devl_lock(devlink);
|
|
|
|
err = devl_traps_register(devlink, traps, traps_count, priv);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_traps_register);
|
|
|
|
|
|
|
|
/**
|
2022-07-16 11:02:34 +00:00
|
|
|
* devl_traps_unregister - Unregister packet traps from devlink.
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
* @devlink: devlink.
|
|
|
|
* @traps: Packet traps.
|
|
|
|
* @traps_count: Count of provided packet traps.
|
|
|
|
*/
|
2022-07-16 11:02:34 +00:00
|
|
|
void devl_traps_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_trap *traps,
|
|
|
|
size_t traps_count)
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2022-07-16 11:02:34 +00:00
|
|
|
devl_assert_locked(devlink);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
/* Make sure we do not have any packets in-flight while unregistering
|
|
|
|
* traps by disabling all of them and waiting for a grace period.
|
|
|
|
*/
|
|
|
|
for (i = traps_count - 1; i >= 0; i--)
|
|
|
|
devlink_trap_disable(devlink, &traps[i]);
|
|
|
|
synchronize_rcu();
|
|
|
|
for (i = traps_count - 1; i >= 0; i--)
|
|
|
|
devlink_trap_unregister(devlink, &traps[i]);
|
2022-07-16 11:02:34 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_traps_unregister);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_traps_unregister - Unregister packet traps from devlink.
|
|
|
|
* @devlink: devlink.
|
|
|
|
* @traps: Packet traps.
|
|
|
|
* @traps_count: Count of provided packet traps.
|
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
|
|
|
*/
|
|
|
|
void devlink_traps_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_trap *traps,
|
|
|
|
size_t traps_count)
|
|
|
|
{
|
|
|
|
devl_lock(devlink);
|
|
|
|
devl_traps_unregister(devlink, traps, traps_count);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_traps_unregister);
|
|
|
|
|
|
|
|
static void
|
|
|
|
devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
|
|
|
|
size_t skb_len)
|
|
|
|
{
|
|
|
|
struct devlink_stats *stats;
|
|
|
|
|
|
|
|
stats = this_cpu_ptr(trap_stats);
|
|
|
|
u64_stats_update_begin(&stats->syncp);
|
2022-06-08 15:46:38 +00:00
|
|
|
u64_stats_add(&stats->rx_bytes, skb_len);
|
|
|
|
u64_stats_inc(&stats->rx_packets);
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
u64_stats_update_end(&stats->syncp);
|
|
|
|
}
|
|
|
|
|
2020-09-29 08:15:50 +00:00
|
|
|
static void
|
|
|
|
devlink_trap_report_metadata_set(struct devlink_trap_metadata *metadata,
|
|
|
|
const struct devlink_trap_item *trap_item,
|
|
|
|
struct devlink_port *in_devlink_port,
|
|
|
|
const struct flow_action_cookie *fa_cookie)
|
|
|
|
{
|
|
|
|
metadata->trap_name = trap_item->trap->name;
|
|
|
|
metadata->trap_group_name = trap_item->group_item->group->name;
|
|
|
|
metadata->fa_cookie = fa_cookie;
|
2020-09-29 08:15:55 +00:00
|
|
|
metadata->trap_type = trap_item->trap->type;
|
2020-09-29 08:15:50 +00:00
|
|
|
|
|
|
|
spin_lock(&in_devlink_port->type_lock);
|
|
|
|
if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
|
2022-11-02 16:01:59 +00:00
|
|
|
metadata->input_dev = in_devlink_port->type_eth.netdev;
|
2020-09-29 08:15:50 +00:00
|
|
|
spin_unlock(&in_devlink_port->type_lock);
|
|
|
|
}
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
/**
|
|
|
|
* devlink_trap_report - Report trapped packet to drop monitor.
|
|
|
|
* @devlink: devlink.
|
|
|
|
* @skb: Trapped packet.
|
|
|
|
* @trap_ctx: Trap context.
|
|
|
|
* @in_devlink_port: Input devlink port.
|
2020-02-25 10:45:21 +00:00
|
|
|
* @fa_cookie: Flow action cookie. Could be NULL.
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
*/
|
|
|
|
void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
|
2020-02-25 10:45:21 +00:00
|
|
|
void *trap_ctx, struct devlink_port *in_devlink_port,
|
|
|
|
const struct flow_action_cookie *fa_cookie)
|
|
|
|
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
{
|
|
|
|
struct devlink_trap_item *trap_item = trap_ctx;
|
|
|
|
|
|
|
|
devlink_trap_stats_update(trap_item->stats, skb->len);
|
|
|
|
devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
|
|
|
|
|
2020-09-29 08:15:50 +00:00
|
|
|
if (trace_devlink_trap_report_enabled()) {
|
|
|
|
struct devlink_trap_metadata metadata = {};
|
|
|
|
|
|
|
|
devlink_trap_report_metadata_set(&metadata, trap_item,
|
|
|
|
in_devlink_port, fa_cookie);
|
|
|
|
trace_devlink_trap_report(devlink, skb, &metadata);
|
|
|
|
}
|
devlink: Add packet trap infrastructure
Add the basic packet trap infrastructure that allows device drivers to
register their supported packet traps and trap groups with devlink.
Each driver is expected to provide basic information about each
supported trap, such as name and ID, but also the supported metadata
types that will accompany each packet trapped via the trap. The
currently supported metadata type is just the input port, but more will
be added in the future. For example, output port and traffic class.
Trap groups allow users to set the action of all member traps. In
addition, users can retrieve per-group statistics in case per-trap
statistics are too narrow. In the future, the trap group object can be
extended with more attributes, such as policer settings which will limit
the amount of traffic generated by member traps towards the CPU.
Beside registering their packet traps with devlink, drivers are also
expected to report trapped packets to devlink along with relevant
metadata. devlink will maintain packets and bytes statistics for each
packet trap and will potentially report the trapped packet with its
metadata to user space via drop monitor netlink channel.
The interface towards the drivers is simple and allows devlink to set
the action of the trap. Currently, only two actions are supported:
'trap' and 'drop'. When set to 'trap', the device is expected to provide
the sole copy of the packet to the driver which will pass it to devlink.
When set to 'drop', the device is expected to drop the packet and not
send a copy to the driver. In the future, more actions can be added,
such as 'mirror'.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-08-17 13:28:17 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_trap_report);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_trap_ctx_priv - Trap context to driver private information.
|
|
|
|
* @trap_ctx: Trap context.
|
|
|
|
*
|
|
|
|
* Return: Driver private information passed during registration.
|
|
|
|
*/
|
|
|
|
void *devlink_trap_ctx_priv(void *trap_ctx)
|
|
|
|
{
|
|
|
|
struct devlink_trap_item *trap_item = trap_ctx;
|
|
|
|
|
|
|
|
return trap_item->priv;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
|
|
|
|
|
2020-03-30 19:38:21 +00:00
|
|
|
static int
|
|
|
|
devlink_trap_group_item_policer_link(struct devlink *devlink,
|
|
|
|
struct devlink_trap_group_item *group_item)
|
|
|
|
{
|
|
|
|
u32 policer_id = group_item->group->init_policer_id;
|
|
|
|
struct devlink_trap_policer_item *policer_item;
|
|
|
|
|
|
|
|
if (policer_id == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
|
|
|
|
if (WARN_ON_ONCE(!policer_item))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
group_item->policer_item = policer_item;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-22 18:48:26 +00:00
|
|
|
static int
|
|
|
|
devlink_trap_group_register(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_group *group)
|
|
|
|
{
|
|
|
|
struct devlink_trap_group_item *group_item;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (devlink_trap_group_item_lookup(devlink, group->name))
|
|
|
|
return -EEXIST;
|
|
|
|
|
|
|
|
group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
|
|
|
|
if (!group_item)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
|
|
|
|
if (!group_item->stats) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto err_stats_alloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
group_item->group = group;
|
|
|
|
|
2020-03-30 19:38:21 +00:00
|
|
|
err = devlink_trap_group_item_policer_link(devlink, group_item);
|
|
|
|
if (err)
|
|
|
|
goto err_policer_link;
|
|
|
|
|
2020-03-22 18:48:26 +00:00
|
|
|
if (devlink->ops->trap_group_init) {
|
|
|
|
err = devlink->ops->trap_group_init(devlink, group);
|
|
|
|
if (err)
|
|
|
|
goto err_group_init;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_add_tail(&group_item->list, &devlink->trap_group_list);
|
2021-10-26 19:40:41 +00:00
|
|
|
devlink_trap_group_notify(devlink, group_item,
|
|
|
|
DEVLINK_CMD_TRAP_GROUP_NEW);
|
|
|
|
|
2020-03-22 18:48:26 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_group_init:
|
2020-03-30 19:38:21 +00:00
|
|
|
err_policer_link:
|
2020-03-22 18:48:26 +00:00
|
|
|
free_percpu(group_item->stats);
|
|
|
|
err_stats_alloc:
|
|
|
|
kfree(group_item);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
devlink_trap_group_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_group *group)
|
|
|
|
{
|
|
|
|
struct devlink_trap_group_item *group_item;
|
|
|
|
|
|
|
|
group_item = devlink_trap_group_item_lookup(devlink, group->name);
|
|
|
|
if (WARN_ON_ONCE(!group_item))
|
|
|
|
return;
|
|
|
|
|
2021-10-26 19:40:41 +00:00
|
|
|
devlink_trap_group_notify(devlink, group_item,
|
|
|
|
DEVLINK_CMD_TRAP_GROUP_DEL);
|
2020-03-22 18:48:26 +00:00
|
|
|
list_del(&group_item->list);
|
|
|
|
free_percpu(group_item->stats);
|
|
|
|
kfree(group_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-07-16 11:02:34 +00:00
|
|
|
* devl_trap_groups_register - Register packet trap groups with devlink.
|
2020-03-22 18:48:26 +00:00
|
|
|
* @devlink: devlink.
|
|
|
|
* @groups: Packet trap groups.
|
|
|
|
* @groups_count: Count of provided packet trap groups.
|
|
|
|
*
|
|
|
|
* Return: Non-zero value on failure.
|
|
|
|
*/
|
2022-07-16 11:02:34 +00:00
|
|
|
int devl_trap_groups_register(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_group *groups,
|
|
|
|
size_t groups_count)
|
2020-03-22 18:48:26 +00:00
|
|
|
{
|
|
|
|
int i, err;
|
|
|
|
|
2022-07-16 11:02:34 +00:00
|
|
|
devl_assert_locked(devlink);
|
2020-03-22 18:48:26 +00:00
|
|
|
for (i = 0; i < groups_count; i++) {
|
|
|
|
const struct devlink_trap_group *group = &groups[i];
|
|
|
|
|
|
|
|
err = devlink_trap_group_verify(group);
|
|
|
|
if (err)
|
|
|
|
goto err_trap_group_verify;
|
|
|
|
|
|
|
|
err = devlink_trap_group_register(devlink, group);
|
|
|
|
if (err)
|
|
|
|
goto err_trap_group_register;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_trap_group_register:
|
|
|
|
err_trap_group_verify:
|
|
|
|
for (i--; i >= 0; i--)
|
|
|
|
devlink_trap_group_unregister(devlink, &groups[i]);
|
2022-07-16 11:02:34 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_trap_groups_register);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devlink_trap_groups_register - Register packet trap groups with devlink.
|
|
|
|
* @devlink: devlink.
|
|
|
|
* @groups: Packet trap groups.
|
|
|
|
* @groups_count: Count of provided packet trap groups.
|
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
|
|
|
*
|
|
|
|
* Return: Non-zero value on failure.
|
|
|
|
*/
|
|
|
|
int devlink_trap_groups_register(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_group *groups,
|
|
|
|
size_t groups_count)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
devl_lock(devlink);
|
|
|
|
err = devl_trap_groups_register(devlink, groups, groups_count);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2020-03-22 18:48:26 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_trap_groups_register);
|
|
|
|
|
2022-07-16 11:02:34 +00:00
|
|
|
/**
|
|
|
|
* devl_trap_groups_unregister - Unregister packet trap groups from devlink.
|
|
|
|
* @devlink: devlink.
|
|
|
|
* @groups: Packet trap groups.
|
|
|
|
* @groups_count: Count of provided packet trap groups.
|
|
|
|
*/
|
|
|
|
void devl_trap_groups_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_group *groups,
|
|
|
|
size_t groups_count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
devl_assert_locked(devlink);
|
|
|
|
for (i = groups_count - 1; i >= 0; i--)
|
|
|
|
devlink_trap_group_unregister(devlink, &groups[i]);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_trap_groups_unregister);
|
|
|
|
|
2020-03-22 18:48:26 +00:00
|
|
|
/**
|
|
|
|
* devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
|
|
|
|
* @devlink: devlink.
|
|
|
|
* @groups: Packet trap groups.
|
|
|
|
* @groups_count: Count of provided packet trap groups.
|
2022-07-16 11:02:34 +00:00
|
|
|
*
|
|
|
|
* Context: Takes and release devlink->lock <mutex>.
|
2020-03-22 18:48:26 +00:00
|
|
|
*/
|
|
|
|
void devlink_trap_groups_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_group *groups,
|
|
|
|
size_t groups_count)
|
|
|
|
{
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_lock(devlink);
|
2022-07-16 11:02:34 +00:00
|
|
|
devl_trap_groups_unregister(devlink, groups, groups_count);
|
2022-07-12 10:24:23 +00:00
|
|
|
devl_unlock(devlink);
|
2020-03-22 18:48:26 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
|
|
|
|
|
2020-03-30 19:38:18 +00:00
|
|
|
static void
|
|
|
|
devlink_trap_policer_notify(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_policer_item *policer_item,
|
|
|
|
enum devlink_command cmd)
|
|
|
|
{
|
|
|
|
struct sk_buff *msg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
|
|
|
|
cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
|
2021-10-26 19:40:42 +00:00
|
|
|
if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
|
|
|
|
return;
|
2020-03-30 19:38:18 +00:00
|
|
|
|
|
|
|
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
if (!msg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
|
|
|
|
0, 0);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_free(msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
|
|
|
|
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
devlink_trap_policer_register(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_policer *policer)
|
|
|
|
{
|
|
|
|
struct devlink_trap_policer_item *policer_item;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (devlink_trap_policer_item_lookup(devlink, policer->id))
|
|
|
|
return -EEXIST;
|
|
|
|
|
|
|
|
policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
|
|
|
|
if (!policer_item)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
policer_item->policer = policer;
|
|
|
|
policer_item->rate = policer->init_rate;
|
|
|
|
policer_item->burst = policer->init_burst;
|
|
|
|
|
|
|
|
if (devlink->ops->trap_policer_init) {
|
|
|
|
err = devlink->ops->trap_policer_init(devlink, policer);
|
|
|
|
if (err)
|
|
|
|
goto err_policer_init;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_add_tail(&policer_item->list, &devlink->trap_policer_list);
|
2021-10-26 19:40:42 +00:00
|
|
|
devlink_trap_policer_notify(devlink, policer_item,
|
|
|
|
DEVLINK_CMD_TRAP_POLICER_NEW);
|
|
|
|
|
2020-03-30 19:38:18 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_policer_init:
|
|
|
|
kfree(policer_item);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
devlink_trap_policer_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_policer *policer)
|
|
|
|
{
|
|
|
|
struct devlink_trap_policer_item *policer_item;
|
|
|
|
|
|
|
|
policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
|
|
|
|
if (WARN_ON_ONCE(!policer_item))
|
|
|
|
return;
|
|
|
|
|
2021-10-26 19:40:42 +00:00
|
|
|
devlink_trap_policer_notify(devlink, policer_item,
|
|
|
|
DEVLINK_CMD_TRAP_POLICER_DEL);
|
2020-03-30 19:38:18 +00:00
|
|
|
list_del(&policer_item->list);
|
|
|
|
if (devlink->ops->trap_policer_fini)
|
|
|
|
devlink->ops->trap_policer_fini(devlink, policer);
|
|
|
|
kfree(policer_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-07-16 11:02:34 +00:00
|
|
|
* devl_trap_policers_register - Register packet trap policers with devlink.
|
2020-03-30 19:38:18 +00:00
|
|
|
* @devlink: devlink.
|
|
|
|
* @policers: Packet trap policers.
|
|
|
|
* @policers_count: Count of provided packet trap policers.
|
|
|
|
*
|
|
|
|
* Return: Non-zero value on failure.
|
|
|
|
*/
|
|
|
|
int
|
2022-07-16 11:02:34 +00:00
|
|
|
devl_trap_policers_register(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_policer *policers,
|
|
|
|
size_t policers_count)
|
2020-03-30 19:38:18 +00:00
|
|
|
{
|
|
|
|
int i, err;
|
|
|
|
|
2022-07-16 11:02:34 +00:00
|
|
|
devl_assert_locked(devlink);
|
2020-03-30 19:38:18 +00:00
|
|
|
for (i = 0; i < policers_count; i++) {
|
|
|
|
const struct devlink_trap_policer *policer = &policers[i];
|
|
|
|
|
|
|
|
if (WARN_ON(policer->id == 0 ||
|
|
|
|
policer->max_rate < policer->min_rate ||
|
|
|
|
policer->max_burst < policer->min_burst)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err_trap_policer_verify;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = devlink_trap_policer_register(devlink, policer);
|
|
|
|
if (err)
|
|
|
|
goto err_trap_policer_register;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_trap_policer_register:
|
|
|
|
err_trap_policer_verify:
|
|
|
|
for (i--; i >= 0; i--)
|
|
|
|
devlink_trap_policer_unregister(devlink, &policers[i]);
|
2022-07-16 11:02:34 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_trap_policers_register);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* devl_trap_policers_unregister - Unregister packet trap policers from devlink.
|
|
|
|
* @devlink: devlink.
|
|
|
|
* @policers: Packet trap policers.
|
|
|
|
* @policers_count: Count of provided packet trap policers.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
devl_trap_policers_unregister(struct devlink *devlink,
|
|
|
|
const struct devlink_trap_policer *policers,
|
|
|
|
size_t policers_count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
devl_assert_locked(devlink);
|
|
|
|
for (i = policers_count - 1; i >= 0; i--)
|
|
|
|
devlink_trap_policer_unregister(devlink, &policers[i]);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(devl_trap_policers_unregister);
|
|
|
|
|
2019-03-28 12:56:37 +00:00
|
|
|
int devlink_compat_phys_port_name_get(struct net_device *dev,
|
|
|
|
char *name, size_t len)
|
|
|
|
{
|
|
|
|
struct devlink_port *devlink_port;
|
|
|
|
|
|
|
|
/* RTNL mutex is held here which ensures that devlink_port
|
|
|
|
* instance cannot disappear in the middle. No need to take
|
|
|
|
* any devlink lock as only permanent values are accessed.
|
|
|
|
*/
|
|
|
|
ASSERT_RTNL();
|
|
|
|
|
2022-11-02 16:02:09 +00:00
|
|
|
devlink_port = dev->devlink_port;
|
2019-03-28 12:56:37 +00:00
|
|
|
if (!devlink_port)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return __devlink_port_phys_port_name_get(devlink_port, name, len);
|
|
|
|
}
|
|
|
|
|
2019-04-03 12:24:17 +00:00
|
|
|
int devlink_compat_switch_id_get(struct net_device *dev,
|
|
|
|
struct netdev_phys_item_id *ppid)
|
|
|
|
{
|
|
|
|
struct devlink_port *devlink_port;
|
|
|
|
|
2019-08-12 17:02:02 +00:00
|
|
|
/* Caller must hold RTNL mutex or reference to dev, which ensures that
|
|
|
|
* devlink_port instance cannot disappear in the middle. No need to take
|
2019-04-03 12:24:17 +00:00
|
|
|
* any devlink lock as only permanent values are accessed.
|
|
|
|
*/
|
2022-11-02 16:02:09 +00:00
|
|
|
devlink_port = dev->devlink_port;
|
2020-07-09 13:18:15 +00:00
|
|
|
if (!devlink_port || !devlink_port->switch_port)
|
2019-04-03 12:24:17 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|