summaryrefslogtreecommitdiff
path: root/net/devlink
diff options
context:
space:
mode:
authorJiri Pirko <jiri@nvidia.com>2023-08-28 08:16:44 +0200
committerJakub Kicinski <kuba@kernel.org>2023-08-28 08:02:22 -0700
commiteec1e5ea1d715ce2df8dcdf3dac7112df77a6e17 (patch)
treeefdc327fed02d24732f8487d44f21396cf5a3115 /net/devlink
parent56e65312830ec45e3ccbc929de6f5b86bc301546 (diff)
downloadlinux-eec1e5ea1d715ce2df8dcdf3dac7112df77a6e17.tar.gz
linux-eec1e5ea1d715ce2df8dcdf3dac7112df77a6e17.tar.bz2
linux-eec1e5ea1d715ce2df8dcdf3dac7112df77a6e17.zip
devlink: push port related code into separate file
Cut out another chunk from leftover.c and put port related code into a separate file. Signed-off-by: Jiri Pirko <jiri@nvidia.com> Link: https://lore.kernel.org/r/20230828061657.300667-3-jiri@resnulli.us Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/devlink')
-rw-r--r--net/devlink/Makefile2
-rw-r--r--net/devlink/devl_internal.h32
-rw-r--r--net/devlink/leftover.c1528
-rw-r--r--net/devlink/port.c1515
4 files changed, 1547 insertions, 1530 deletions
diff --git a/net/devlink/Makefile b/net/devlink/Makefile
index a087af581847..456bfb336540 100644
--- a/net/devlink/Makefile
+++ b/net/devlink/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-obj-y := leftover.o core.o netlink.o netlink_gen.o dev.o health.o
+obj-y := leftover.o core.o netlink.o netlink_gen.o dev.o port.o health.o
diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h
index eb1d5066c73f..7d01e2060702 100644
--- a/net/devlink/devl_internal.h
+++ b/net/devlink/devl_internal.h
@@ -3,6 +3,7 @@
* Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
*/
+#include <linux/etherdevice.h>
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/notifier.h>
@@ -11,6 +12,8 @@
#include <linux/xarray.h>
#include <net/devlink.h>
#include <net/net_namespace.h>
+#include <net/rtnetlink.h>
+#include <rdma/ib_verbs.h>
#include "netlink_gen.h"
@@ -149,16 +152,37 @@ devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
/* Notify */
void devlink_notify(struct devlink *devlink, enum devlink_command cmd);
+void devlink_ports_notify_register(struct devlink *devlink);
+void devlink_ports_notify_unregister(struct devlink *devlink);
/* Ports */
+#define ASSERT_DEVLINK_PORT_INITIALIZED(devlink_port) \
+ WARN_ON_ONCE(!(devlink_port)->initialized)
+
+struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
+ unsigned int port_index);
int devlink_port_netdevice_event(struct notifier_block *nb,
unsigned long event, void *ptr);
-
struct devlink_port *
devlink_port_get_from_info(struct devlink *devlink, struct genl_info *info);
struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
struct nlattr **attrs);
+/* Linecards */
+struct devlink_linecard {
+ struct list_head list;
+ struct devlink *devlink;
+ unsigned int index;
+ const struct devlink_linecard_ops *ops;
+ void *priv;
+ enum devlink_linecard_state state;
+ struct mutex state_lock; /* Protects state */
+ const char *type;
+ struct devlink_linecard_type *types;
+ unsigned int types_count;
+ struct devlink *nested_devlink;
+};
+
/* Reload */
bool devlink_reload_actions_valid(const struct devlink_ops *ops);
int devlink_reload(struct devlink *devlink, struct net *dest_net,
@@ -190,6 +214,12 @@ int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info)
int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_cmd_flash_update(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_cmd_selftests_run(struct sk_buff *skb, struct genl_info *info);
+int devlink_nl_cmd_port_set_doit(struct sk_buff *skb, struct genl_info *info);
+int devlink_nl_cmd_port_split_doit(struct sk_buff *skb, struct genl_info *info);
+int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
+ struct genl_info *info);
+int devlink_nl_cmd_port_new_doit(struct sk_buff *skb, struct genl_info *info);
+int devlink_nl_cmd_port_del_doit(struct sk_buff *skb, struct genl_info *info);
int devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
struct genl_info *info);
int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c
index 890eafac9f8f..d14b40fb8fdf 100644
--- a/net/devlink/leftover.c
+++ b/net/devlink/leftover.c
@@ -33,20 +33,6 @@
#include "devl_internal.h"
-struct devlink_linecard {
- struct list_head list;
- struct devlink *devlink;
- unsigned int index;
- const struct devlink_linecard_ops *ops;
- void *priv;
- enum devlink_linecard_state state;
- struct mutex state_lock; /* Protects state */
- const char *type;
- struct devlink_linecard_type *types;
- unsigned int types_count;
- struct devlink *nested_devlink;
-};
-
/**
* struct devlink_resource - devlink resource
* @name: name of the resource
@@ -131,52 +117,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_trap_report);
-#define DEVLINK_PORT_FN_CAPS_VALID_MASK \
- (_BITUL(__DEVLINK_PORT_FN_ATTR_CAPS_MAX) - 1)
-
-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_PORT_FN_ATTR_STATE] =
- NLA_POLICY_RANGE(NLA_U8, DEVLINK_PORT_FN_STATE_INACTIVE,
- DEVLINK_PORT_FN_STATE_ACTIVE),
- [DEVLINK_PORT_FN_ATTR_CAPS] =
- NLA_POLICY_BITFIELD32(DEVLINK_PORT_FN_CAPS_VALID_MASK),
-};
-
-#define ASSERT_DEVLINK_PORT_REGISTERED(devlink_port) \
- WARN_ON_ONCE(!(devlink_port)->registered)
-#define ASSERT_DEVLINK_PORT_NOT_REGISTERED(devlink_port) \
- WARN_ON_ONCE((devlink_port)->registered)
-#define ASSERT_DEVLINK_PORT_INITIALIZED(devlink_port) \
- WARN_ON_ONCE(!(devlink_port)->initialized)
-
-static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
- unsigned int port_index)
-{
- return xa_load(&devlink->ports, port_index);
-}
-
-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);
-}
-
-struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
- struct genl_info *info)
-{
- return devlink_port_get_from_attrs(devlink, info->attrs);
-}
-
static inline bool
devlink_rate_is_leaf(struct devlink_rate *devlink_rate)
{
@@ -439,138 +379,6 @@ devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
return 0;
}
-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(struct devlink_port *devlink_port,
- struct nla_bitfield32 *caps,
- struct netlink_ext_ack *extack)
-{
- bool is_enable;
- int err;
-
- if (!devlink_port->ops->port_fn_roce_get)
- return 0;
-
- err = devlink_port->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;
-}
-
-static int devlink_port_fn_migratable_fill(struct devlink_port *devlink_port,
- struct nla_bitfield32 *caps,
- struct netlink_ext_ack *extack)
-{
- bool is_enable;
- int err;
-
- if (!devlink_port->ops->port_fn_migratable_get ||
- devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF)
- return 0;
-
- err = devlink_port->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;
-}
-
-static int devlink_port_fn_ipsec_crypto_fill(struct devlink_port *devlink_port,
- struct nla_bitfield32 *caps,
- struct netlink_ext_ack *extack)
-{
- bool is_enable;
- int err;
-
- if (!devlink_port->ops->port_fn_ipsec_crypto_get ||
- devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF)
- return 0;
-
- err = devlink_port->ops->port_fn_ipsec_crypto_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_IPSEC_CRYPTO, is_enable);
- return 0;
-}
-
-static int devlink_port_fn_ipsec_packet_fill(struct devlink_port *devlink_port,
- struct nla_bitfield32 *caps,
- struct netlink_ext_ack *extack)
-{
- bool is_enable;
- int err;
-
- if (!devlink_port->ops->port_fn_ipsec_packet_get ||
- devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF)
- return 0;
-
- err = devlink_port->ops->port_fn_ipsec_packet_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_IPSEC_PACKET, is_enable);
- return 0;
-}
-
-static int devlink_port_fn_caps_fill(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(devlink_port, &caps, extack);
- if (err)
- return err;
-
- err = devlink_port_fn_migratable_fill(devlink_port, &caps, extack);
- if (err)
- return err;
-
- err = devlink_port_fn_ipsec_crypto_fill(devlink_port, &caps, extack);
- if (err)
- return err;
-
- err = devlink_port_fn_ipsec_packet_fill(devlink_port, &caps, extack);
- if (err)
- return err;
-
- 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;
-}
-
static int
devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
struct genl_info *info,
@@ -661,113 +469,6 @@ nla_put_failure:
return -EMSGSIZE;
}
-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 */
-}
-
-static int devlink_nl_port_attrs_put(struct sk_buff *msg,
- struct devlink_port *devlink_port)
-{
- struct devlink_port_attrs *attrs = &devlink_port->attrs;
-
- if (!devlink_port->attrs_set)
- return 0;
- if (attrs->lanes) {
- if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes))
- return -EMSGSIZE;
- }
- if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable))
- return -EMSGSIZE;
- if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
- return -EMSGSIZE;
- switch (devlink_port->attrs.flavour) {
- case DEVLINK_PORT_FLAVOUR_PCI_PF:
- 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))
- return -EMSGSIZE;
- if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_pf.external))
- return -EMSGSIZE;
- break;
- case DEVLINK_PORT_FLAVOUR_PCI_VF:
- 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))
- return -EMSGSIZE;
- if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_vf.external))
- return -EMSGSIZE;
- break;
- 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;
- 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;
- }
- return 0;
-}
-
-static int devlink_port_fn_hw_addr_fill(struct devlink_port *port,
- struct sk_buff *msg,
- struct netlink_ext_ack *extack,
- bool *msg_updated)
-{
- u8 hw_addr[MAX_ADDR_LEN];
- int hw_addr_len;
- int err;
-
- if (!port->ops->port_fn_hw_addr_get)
- return 0;
-
- err = port->ops->port_fn_hw_addr_get(port, hw_addr, &hw_addr_len,
- extack);
- 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;
-}
-
static int devlink_nl_rate_fill(struct sk_buff *msg,
struct devlink_rate *devlink_rate,
enum devlink_command cmd, u32 portid, u32 seq,
@@ -825,259 +526,6 @@ nla_put_failure:
return -EMSGSIZE;
}
-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;
-}
-
-static int devlink_port_fn_state_fill(struct devlink_port *port,
- struct sk_buff *msg,
- struct netlink_ext_ack *extack,
- bool *msg_updated)
-{
- enum devlink_port_fn_opstate opstate;
- enum devlink_port_fn_state state;
- int err;
-
- if (!port->ops->port_fn_state_get)
- return 0;
-
- err = port->ops->port_fn_state_get(port, &state, &opstate, extack);
- if (err) {
- if (err == -EOPNOTSUPP)
- return 0;
- return err;
- }
- if (!devlink_port_fn_state_valid(state)) {
- WARN_ON_ONCE(1);
- NL_SET_ERR_MSG(extack, "Invalid state read from driver");
- return -EINVAL;
- }
- if (!devlink_port_fn_opstate_valid(opstate)) {
- WARN_ON_ONCE(1);
- NL_SET_ERR_MSG(extack, "Invalid operational state read from driver");
- 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;
-}
-
-static int
-devlink_port_fn_mig_set(struct devlink_port *devlink_port, bool enable,
- struct netlink_ext_ack *extack)
-{
- return devlink_port->ops->port_fn_migratable_set(devlink_port, enable,
- extack);
-}
-
-static int
-devlink_port_fn_roce_set(struct devlink_port *devlink_port, bool enable,
- struct netlink_ext_ack *extack)
-{
- return devlink_port->ops->port_fn_roce_set(devlink_port, enable,
- extack);
-}
-
-static int
-devlink_port_fn_ipsec_crypto_set(struct devlink_port *devlink_port, bool enable,
- struct netlink_ext_ack *extack)
-{
- return devlink_port->ops->port_fn_ipsec_crypto_set(devlink_port, enable, extack);
-}
-
-static int
-devlink_port_fn_ipsec_packet_set(struct devlink_port *devlink_port, bool enable,
- struct netlink_ext_ack *extack)
-{
- return devlink_port->ops->port_fn_ipsec_packet_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;
- }
- 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;
- }
- if (caps.selector & DEVLINK_PORT_FN_CAP_IPSEC_CRYPTO) {
- err = devlink_port_fn_ipsec_crypto_set(devlink_port, caps_value &
- DEVLINK_PORT_FN_CAP_IPSEC_CRYPTO,
- extack);
- if (err)
- return err;
- }
- if (caps.selector & DEVLINK_PORT_FN_CAP_IPSEC_PACKET) {
- err = devlink_port_fn_ipsec_packet_set(devlink_port, caps_value &
- DEVLINK_PORT_FN_CAP_IPSEC_PACKET,
- extack);
- if (err)
- return err;
- }
- return 0;
-}
-
-static int
-devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
- struct netlink_ext_ack *extack)
-{
- struct nlattr *function_attr;
- bool msg_updated = false;
- int err;
-
- function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION);
- if (!function_attr)
- return -EMSGSIZE;
-
- err = devlink_port_fn_hw_addr_fill(port, msg, extack, &msg_updated);
- if (err)
- goto out;
- err = devlink_port_fn_caps_fill(port, msg, extack, &msg_updated);
- if (err)
- goto out;
- err = devlink_port_fn_state_fill(port, msg, extack, &msg_updated);
-out:
- if (err || !msg_updated)
- nla_nest_cancel(msg, function_attr);
- else
- nla_nest_end(msg, function_attr);
- return err;
-}
-
-static int devlink_nl_port_fill(struct sk_buff *msg,
- struct devlink_port *devlink_port,
- enum devlink_command cmd, u32 portid, u32 seq,
- int flags, struct netlink_ext_ack *extack)
-{
- struct devlink *devlink = devlink_port->devlink;
- 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;
-
- spin_lock_bh(&devlink_port->type_lock);
- if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
- goto nla_put_failure_type_locked;
- if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
- nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
- devlink_port->desired_type))
- goto nla_put_failure_type_locked;
- if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
- if (devlink_port->type_eth.netdev &&
- (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
- devlink_port->type_eth.ifindex) ||
- nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
- devlink_port->type_eth.ifname)))
- goto nla_put_failure_type_locked;
- }
- if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
- struct ib_device *ibdev = devlink_port->type_ib.ibdev;
-
- if (ibdev &&
- nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
- ibdev->name))
- goto nla_put_failure_type_locked;
- }
- spin_unlock_bh(&devlink_port->type_lock);
- if (devlink_nl_port_attrs_put(msg, devlink_port))
- goto nla_put_failure;
- if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
- goto nla_put_failure;
- if (devlink_port->linecard &&
- nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX,
- devlink_port->linecard->index))
- goto nla_put_failure;
-
- genlmsg_end(msg, hdr);
- return 0;
-
-nla_put_failure_type_locked:
- spin_unlock_bh(&devlink_port->type_lock);
-nla_put_failure:
- genlmsg_cancel(msg, hdr);
- return -EMSGSIZE;
-}
-
-static void devlink_port_notify(struct devlink_port *devlink_port,
- enum devlink_command cmd)
-{
- struct devlink *devlink = devlink_port->devlink;
- struct sk_buff *msg;
- int err;
-
- WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_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_port_fill(msg, devlink_port, 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 void devlink_ports_notify(struct devlink *devlink,
- enum devlink_command cmd)
-{
- struct devlink_port *devlink_port;
- unsigned long port_index;
-
- xa_for_each(&devlink->ports, port_index, devlink_port)
- devlink_port_notify(devlink_port, cmd);
-}
-
-static void devlink_ports_notify_register(struct devlink *devlink)
-{
- devlink_ports_notify(devlink, DEVLINK_CMD_PORT_NEW);
-}
-
-static void devlink_ports_notify_unregister(struct devlink *devlink)
-{
- devlink_ports_notify(devlink, DEVLINK_CMD_PORT_DEL);
-}
-
static void devlink_rate_notify(struct devlink_rate *devlink_rate,
enum devlink_command cmd)
{
@@ -1192,377 +640,6 @@ devlink_rate_is_parent_node(struct devlink_rate *devlink_rate,
return false;
}
-int devlink_nl_port_get_doit(struct sk_buff *skb, struct genl_info *info)
-{
- struct devlink_port *devlink_port = info->user_ptr[1];
- struct sk_buff *msg;
- int err;
-
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg)
- return -ENOMEM;
-
- err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_PORT_NEW,
- info->snd_portid, info->snd_seq, 0,
- info->extack);
- if (err) {
- nlmsg_free(msg);
- return err;
- }
-
- return genlmsg_reply(msg, info);
-}
-
-static int
-devlink_nl_port_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
- struct netlink_callback *cb, int flags)
-{
- struct devlink_nl_dump_state *state = devlink_dump_state(cb);
- struct devlink_port *devlink_port;
- unsigned long port_index;
- int err = 0;
-
- xa_for_each_start(&devlink->ports, port_index, devlink_port, state->idx) {
- err = devlink_nl_port_fill(msg, devlink_port,
- DEVLINK_CMD_NEW,
- NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq, flags,
- cb->extack);
- if (err) {
- state->idx = port_index;
- break;
- }
- }
-
- return err;
-}
-
-int devlink_nl_port_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
-{
- return devlink_nl_dumpit(skb, cb, devlink_nl_port_get_dump_one);
-}
-
-static int devlink_port_type_set(struct devlink_port *devlink_port,
- enum devlink_port_type port_type)
-
-{
- int err;
-
- if (!devlink_port->ops->port_type_set)
- return -EOPNOTSUPP;
-
- if (port_type == devlink_port->type)
- return 0;
-
- err = devlink_port->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;
-}
-
-static int devlink_port_function_hw_addr_set(struct devlink_port *port,
- const struct nlattr *attr,
- struct netlink_ext_ack *extack)
-{
- 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) {
- NL_SET_ERR_MSG(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(extack, "Address must be 6 bytes for Ethernet device");
- return -EINVAL;
- }
- if (!is_unicast_ether_addr(hw_addr)) {
- NL_SET_ERR_MSG(extack, "Non-unicast hardware address unsupported");
- return -EINVAL;
- }
- }
-
- return port->ops->port_fn_hw_addr_set(port, hw_addr, hw_addr_len,
- extack);
-}
-
-static int devlink_port_fn_state_set(struct devlink_port *port,
- const struct nlattr *attr,
- struct netlink_ext_ack *extack)
-{
- enum devlink_port_fn_state state;
-
- state = nla_get_u8(attr);
- return port->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_port_ops *ops = devlink_port->ops;
- struct nlattr *attr;
-
- if (tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] &&
- !ops->port_fn_hw_addr_set) {
- NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR],
- "Port doesn't support function attributes");
- return -EOPNOTSUPP;
- }
- 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;
- }
- 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;
- }
- 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;
- }
- }
- if (caps.selector & DEVLINK_PORT_FN_CAP_IPSEC_CRYPTO) {
- if (!ops->port_fn_ipsec_crypto_set) {
- NL_SET_ERR_MSG_ATTR(extack, attr,
- "Port doesn't support ipsec_crypto function attribute");
- return -EOPNOTSUPP;
- }
- if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF) {
- NL_SET_ERR_MSG_ATTR(extack, attr,
- "ipsec_crypto function attribute supported for VFs only");
- return -EOPNOTSUPP;
- }
- }
- if (caps.selector & DEVLINK_PORT_FN_CAP_IPSEC_PACKET) {
- if (!ops->port_fn_ipsec_packet_set) {
- NL_SET_ERR_MSG_ATTR(extack, attr,
- "Port doesn't support ipsec_packet function attribute");
- return -EOPNOTSUPP;
- }
- if (devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF) {
- NL_SET_ERR_MSG_ATTR(extack, attr,
- "ipsec_packet function attribute supported for VFs only");
- return -EOPNOTSUPP;
- }
- }
- }
- return 0;
-}
-
-static int devlink_port_function_set(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(extack, "Fail to parse port function attributes");
- return err;
- }
-
- err = devlink_port_function_validate(port, tb, extack);
- if (err)
- return err;
-
- attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
- if (attr) {
- err = devlink_port_function_hw_addr_set(port, attr, extack);
- if (err)
- return err;
- }
-
- attr = tb[DEVLINK_PORT_FN_ATTR_CAPS];
- if (attr) {
- err = devlink_port_fn_caps_set(port, attr, extack);
- if (err)
- return err;
- }
-
- /* 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)
- err = devlink_port_fn_state_set(port, attr, extack);
-
- if (!err)
- devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
- return err;
-}
-
-static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
- struct genl_info *info)
-{
- struct devlink_port *devlink_port = info->user_ptr[1];
- 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]);
- err = devlink_port_type_set(devlink_port, port_type);
- 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_port, attr, extack);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
- struct genl_info *info)
-{
- struct devlink_port *devlink_port = info->user_ptr[1];
- struct devlink *devlink = info->user_ptr[0];
- u32 count;
-
- if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PORT_SPLIT_COUNT))
- return -EINVAL;
- if (!devlink_port->ops->port_split)
- return -EOPNOTSUPP;
-
- count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
-
- if (!devlink_port->attrs.splittable) {
- /* Split ports cannot be split. */
- if (devlink_port->attrs.split)
- NL_SET_ERR_MSG(info->extack, "Port cannot be split further");
- else
- NL_SET_ERR_MSG(info->extack, "Port cannot be split");
- return -EINVAL;
- }
-
- if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) {
- NL_SET_ERR_MSG(info->extack, "Invalid split count");
- return -EINVAL;
- }
-
- return devlink_port->ops->port_split(devlink, devlink_port, count,
- info->extack);
-}
-
-static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
- struct genl_info *info)
-{
- struct devlink_port *devlink_port = info->user_ptr[1];
- struct devlink *devlink = info->user_ptr[0];
-
- if (!devlink_port->ops->port_unsplit)
- return -EOPNOTSUPP;
- return devlink_port->ops->port_unsplit(devlink, devlink_port, info->extack);
-}
-
-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];
- struct devlink_port *devlink_port;
- struct sk_buff *msg;
- int err;
-
- if (!devlink->ops->port_new)
- return -EOPNOTSUPP;
-
- if (!info->attrs[DEVLINK_ATTR_PORT_FLAVOUR] ||
- !info->attrs[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
- NL_SET_ERR_MSG(extack, "Port flavour or PCI PF are not specified");
- 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, &devlink_port);
- if (err)
- return err;
-
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg) {
- err = -ENOMEM;
- goto err_out_port_del;
- }
- err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_NEW,
- info->snd_portid, info->snd_seq, 0, NULL);
- if (WARN_ON_ONCE(err))
- goto err_out_msg_free;
- err = genlmsg_reply(msg, info);
- if (err)
- goto err_out_port_del;
- return 0;
-
-err_out_msg_free:
- nlmsg_free(msg);
-err_out_port_del:
- devlink_port->ops->port_del(devlink, devlink_port, NULL);
- return err;
-}
-
-static int devlink_nl_cmd_port_del_doit(struct sk_buff *skb,
- struct genl_info *info)
-{
- struct devlink_port *devlink_port = info->user_ptr[1];
- struct netlink_ext_ack *extack = info->extack;
- struct devlink *devlink = info->user_ptr[0];
-
- if (!devlink_port->ops->port_del)
- return -EOPNOTSUPP;
-
- return devlink_port->ops->port_del(devlink, devlink_port, extack);
-}
-
static int
devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate,
struct genl_info *info,
@@ -6783,489 +5860,6 @@ void devlink_notify_unregister(struct devlink *devlink)
devlink_notify(devlink, DEVLINK_CMD_DEL);
}
-static void devlink_port_type_warn(struct work_struct *work)
-{
- struct devlink_port *port = container_of(to_delayed_work(work),
- struct devlink_port,
- type_warn_dw);
- dev_warn(port->devlink->dev, "Type was not se