net/devlink: Support setting hardware address of port function
PCI PF and VF devlink port can manage the function represented by a devlink port. Allow users to set port function's hardware address. Example of a PCI VF port which supports a port function: $ devlink port show pci/0000:06:00.0/2 pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 function: hw_addr 00:00:00:00:00:00 $ devlink port function set pci/0000:06:00.0/2 hw_addr 00:11:22:33:44:55 $ devlink port show pci/0000:06:00.0/2 pci/0000:06:00.0/2: type eth netdev enp6s0pf0vf1 flavour pcivf pfnum 0 vfnum 1 function: hw_addr 00:11:22:33:44:55 Signed-off-by: Parav Pandit <parav@mellanox.com> Reviewed-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
2a916ecc40
Коммит
a1e8ae907c
|
@ -1119,6 +1119,16 @@ struct devlink_ops {
|
|||
int (*port_function_hw_addr_get)(struct devlink *devlink, struct devlink_port *port,
|
||||
u8 *hw_addr, int *hw_addr_len,
|
||||
struct netlink_ext_ack *extack);
|
||||
/**
|
||||
* @port_function_hw_addr_set: Port function's hardware address set function.
|
||||
*
|
||||
* Should be used by device drivers to set the hardware address of a function managed
|
||||
* by the devlink port. Driver should return -EOPNOTSUPP if it doesn't support port
|
||||
* function handling for a particular port.
|
||||
*/
|
||||
int (*port_function_hw_addr_set)(struct devlink *devlink, struct devlink_port *port,
|
||||
const u8 *hw_addr, int hw_addr_len,
|
||||
struct netlink_ext_ack *extack);
|
||||
};
|
||||
|
||||
static inline void *devlink_priv(struct devlink *devlink)
|
||||
|
|
|
@ -85,6 +85,10 @@ EXPORT_SYMBOL(devlink_dpipe_header_ipv6);
|
|||
EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
|
||||
|
||||
static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {
|
||||
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY },
|
||||
};
|
||||
|
||||
static LIST_HEAD(devlink_list);
|
||||
|
||||
/* devlink_mutex
|
||||
|
@ -827,6 +831,67 @@ static int devlink_port_type_set(struct devlink *devlink,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int
|
||||
devlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *port,
|
||||
const struct nlattr *attr, struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct devlink_ops *ops;
|
||||
const u8 *hw_addr;
|
||||
int hw_addr_len;
|
||||
int err;
|
||||
|
||||
hw_addr = nla_data(attr);
|
||||
hw_addr_len = nla_len(attr);
|
||||
if (hw_addr_len > MAX_ADDR_LEN) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Port function hardware address too long");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (port->type == DEVLINK_PORT_TYPE_ETH) {
|
||||
if (hw_addr_len != ETH_ALEN) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Address must be 6 bytes for Ethernet device");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!is_unicast_ether_addr(hw_addr)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Non-unicast hardware address unsupported");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
ops = devlink->ops;
|
||||
if (!ops->port_function_hw_addr_set) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Port doesn't support function attributes");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
devlink_port_function_set(struct devlink *devlink, struct devlink_port *port,
|
||||
const struct nlattr *attr, struct netlink_ext_ack *extack)
|
||||
{
|
||||
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) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Fail to parse port function attributes");
|
||||
return err;
|
||||
}
|
||||
|
||||
attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
|
||||
if (attr)
|
||||
err = devlink_port_function_hw_addr_set(devlink, port, attr, extack);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
|
@ -842,6 +907,16 @@ static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
|
|||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) {
|
||||
struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];
|
||||
struct netlink_ext_ack *extack = info->extack;
|
||||
|
||||
err = devlink_port_function_set(devlink, devlink_port, attr, extack);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -6758,6 +6833,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
|
|||
[DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
|
||||
[DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
|
||||
[DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
|
||||
[DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
static const struct genl_ops devlink_nl_ops[] = {
|
||||
|
|
Загрузка…
Ссылка в новой задаче