13029 lines · 339.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * 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> */ #include <linux/etherdevice.h>#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>#include <linux/spinlock.h>#include <linux/refcount.h>#include <linux/workqueue.h>#include <linux/u64_stats_sync.h>#include <linux/timekeeping.h>#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>#define CREATE_TRACE_POINTS#include <trace/events/devlink.h> #define DEVLINK_RELOAD_STATS_ARRAY_SIZE \	(__DEVLINK_RELOAD_LIMIT_MAX * __DEVLINK_RELOAD_ACTION_MAX) struct devlink_dev_stats {	u32 reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE];	u32 remote_reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE];}; struct devlink {	u32 index;	struct xarray ports;	struct list_head rate_list;	struct list_head sb_list;	struct list_head dpipe_table_list;	struct list_head resource_list;	struct list_head param_list;	struct list_head region_list;	struct list_head reporter_list;	struct mutex reporters_lock; /* protects reporter_list */	struct devlink_dpipe_headers *dpipe_headers;	struct list_head trap_list;	struct list_head trap_group_list;	struct list_head trap_policer_list;	struct list_head linecard_list;	struct mutex linecards_lock; /* protects linecard_list */	const struct devlink_ops *ops;	u64 features;	struct xarray snapshot_ids;	struct devlink_dev_stats stats;	struct device *dev;	possible_net_t _net;	/* Serializes access to devlink instance specific objects such as	 * port, sb, dpipe, resource, params, region, traps and more.	 */	struct mutex lock;	struct lock_class_key lock_key;	u8 reload_failed:1;	refcount_t refcount;	struct completion comp;	struct rcu_head rcu;	struct notifier_block netdevice_nb;	char priv[] __aligned(NETDEV_ALIGN);}; struct devlink_linecard_ops;struct devlink_linecard_type; struct devlink_linecard {	struct list_head list;	struct devlink *devlink;	unsigned int index;	refcount_t refcount;	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 * @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;}; void *devlink_priv(struct devlink *devlink){	return &devlink->priv;}EXPORT_SYMBOL_GPL(devlink_priv); struct devlink *priv_to_devlink(void *priv){	return container_of(priv, struct devlink, priv);}EXPORT_SYMBOL_GPL(priv_to_devlink); struct device *devlink_to_dev(const struct devlink *devlink){	return devlink->dev;}EXPORT_SYMBOL_GPL(devlink_to_dev); static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {	{		.name = "destination mac",		.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,};EXPORT_SYMBOL_GPL(devlink_dpipe_header_ethernet); 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,};EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv4); 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,};EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv6); 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),}; static const struct nla_policy devlink_selftest_nl_policy[DEVLINK_ATTR_SELFTEST_ID_MAX + 1] = {	[DEVLINK_ATTR_SELFTEST_ID_FLASH] = { .type = NLA_FLAG },}; static DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC);#define DEVLINK_REGISTERED XA_MARK_1#define DEVLINK_UNREGISTERING XA_MARK_2 /* devlink instances are open to the access from the user space after * devlink_register() call. Such logical barrier allows us to have certain * expectations related to locking. * * Before *_register() - we are in initialization stage and no parallel * access possible to the devlink instance. All drivers perform that phase * by implicitly holding device_lock. * * After *_register() - users and driver can access devlink instance at * the same time. */#define ASSERT_DEVLINK_REGISTERED(d)                                           \	WARN_ON_ONCE(!xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED))#define ASSERT_DEVLINK_NOT_REGISTERED(d)                                       \	WARN_ON_ONCE(xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED)) struct net *devlink_net(const struct devlink *devlink){	return read_pnet(&devlink->_net);}EXPORT_SYMBOL_GPL(devlink_net); static void __devlink_put_rcu(struct rcu_head *head){	struct devlink *devlink = container_of(head, struct devlink, rcu); 	complete(&devlink->comp);} void devlink_put(struct devlink *devlink){	if (refcount_dec_and_test(&devlink->refcount))		/* Make sure unregister operation that may await the completion		 * is unblocked only after all users are after the end of		 * RCU grace period.		 */		call_rcu(&devlink->rcu, __devlink_put_rcu);} struct devlink *__must_check devlink_try_get(struct devlink *devlink){	if (refcount_inc_not_zero(&devlink->refcount))		return devlink;	return NULL;} void devl_assert_locked(struct devlink *devlink){	lockdep_assert_held(&devlink->lock);}EXPORT_SYMBOL_GPL(devl_assert_locked); #ifdef CONFIG_LOCKDEP/* For use in conjunction with LOCKDEP only e.g. rcu_dereference_protected() */bool devl_lock_is_held(struct devlink *devlink){	return lockdep_is_held(&devlink->lock);}EXPORT_SYMBOL_GPL(devl_lock_is_held);#endif void devl_lock(struct devlink *devlink){	mutex_lock(&devlink->lock);}EXPORT_SYMBOL_GPL(devl_lock); int devl_trylock(struct devlink *devlink){	return mutex_trylock(&devlink->lock);}EXPORT_SYMBOL_GPL(devl_trylock); void devl_unlock(struct devlink *devlink){	mutex_unlock(&devlink->lock);}EXPORT_SYMBOL_GPL(devl_unlock); static struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp, xa_mark_t filter,		     void * (*xa_find_fn)(struct xarray *, unsigned long *,					  unsigned long, xa_mark_t)){	struct devlink *devlink; 	rcu_read_lock();retry:	devlink = xa_find_fn(&devlinks, indexp, ULONG_MAX, DEVLINK_REGISTERED);	if (!devlink)		goto unlock; 	/* In case devlink_unregister() was already called and "unregistering"	 * mark was set, do not allow to get a devlink reference here.	 * This prevents live-lock of devlink_unregister() wait for completion.	 */	if (xa_get_mark(&devlinks, *indexp, DEVLINK_UNREGISTERING))		goto retry; 	/* For a possible retry, the xa_find_after() should be always used */	xa_find_fn = xa_find_after;	if (!devlink_try_get(devlink))		goto retry;	if (!net_eq(devlink_net(devlink), net)) {		devlink_put(devlink);		goto retry;	}unlock:	rcu_read_unlock();	return devlink;} static struct devlink *devlinks_xa_find_get_first(struct net *net,						  unsigned long *indexp,						  xa_mark_t filter){	return devlinks_xa_find_get(net, indexp, filter, xa_find);} static struct devlink *devlinks_xa_find_get_next(struct net *net,						 unsigned long *indexp,						 xa_mark_t filter){	return devlinks_xa_find_get(net, indexp, filter, xa_find_after);} /* Iterate over devlink pointers which were possible to get reference to. * devlink_put() needs to be called for each iterated devlink pointer * in loop body in order to release the reference. */#define devlinks_xa_for_each_get(net, index, devlink, filter)			\	for (index = 0,								\	     devlink = devlinks_xa_find_get_first(net, &index, filter);		\	     devlink; devlink = devlinks_xa_find_get_next(net, &index, filter)) #define devlinks_xa_for_each_registered_get(net, index, devlink)		\	devlinks_xa_for_each_get(net, index, devlink, DEVLINK_REGISTERED) static struct devlink *devlink_get_from_attrs(struct net *net,					      struct nlattr **attrs){	struct devlink *devlink;	unsigned long index;	char *busname;	char *devname; 	if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])		return ERR_PTR(-EINVAL); 	busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);	devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]); 	devlinks_xa_for_each_registered_get(net, index, devlink) {		if (strcmp(devlink->dev->bus->name, busname) == 0 &&		    strcmp(dev_name(devlink->dev), devname) == 0)			return devlink;		devlink_put(devlink);	} 	return ERR_PTR(-ENODEV);} #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);} 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);} static 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 booldevlink_rate_is_leaf(struct devlink_rate *devlink_rate){	return devlink_rate->type == DEVLINK_RATE_TYPE_LEAF;} static inline booldevlink_rate_is_node(struct devlink_rate *devlink_rate){	return devlink_rate->type == DEVLINK_RATE_TYPE_NODE;} 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);} 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);} static struct devlink_rate *devlink_rate_node_get_from_info(struct devlink *devlink, struct genl_info *info){	return devlink_rate_node_get_from_attrs(devlink, info->attrs);} static struct devlink_rate *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);} 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;} 

Lines 1–500 of 13029.