2415 lines · 58.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * net-sysfs.c - network device class and attributes * * Copyright (c) 2003 Stephen Hemminger <shemminger@osdl.org> */ #include <linux/capability.h>#include <linux/kernel.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/slab.h>#include <linux/sched/signal.h>#include <linux/sched/isolation.h>#include <linux/nsproxy.h>#include <net/sock.h>#include <net/net_namespace.h>#include <linux/rtnetlink.h>#include <linux/vmalloc.h>#include <linux/export.h>#include <linux/jiffies.h>#include <linux/pm_runtime.h>#include <linux/of.h>#include <linux/of_net.h>#include <linux/cpu.h>#include <net/netdev_lock.h>#include <net/netdev_rx_queue.h>#include <net/rps.h> #include "dev.h"#include "net-sysfs.h" #ifdef CONFIG_SYSFSstatic const char fmt_hex[] = "%#x\n";static const char fmt_dec[] = "%d\n";static const char fmt_uint[] = "%u\n";static const char fmt_ulong[] = "%lu\n";static const char fmt_u64[] = "%llu\n"; /* There is a possible ABBA deadlock between rtnl_lock and kernfs_node->active, * when unregistering a net device and accessing associated sysfs files. The * potential deadlock is as follow: * *         CPU 0                                         CPU 1 * *    rtnl_lock                                   vfs_read *    unregister_netdevice_many                   kernfs_seq_start *    device_del / kobject_put                      kernfs_get_active (kn->active++) *    kernfs_drain                                sysfs_kf_seq_show *    wait_event(                                 rtnl_lock *       kn->active == KN_DEACTIVATED_BIAS)       -> waits on CPU 0 to release *    -> waits on CPU 1 to decrease kn->active       the rtnl lock. * * The historical fix was to use rtnl_trylock with restart_syscall to bail out * of sysfs operations when the lock couldn't be taken. This fixed the above * issue as it allowed CPU 1 to bail out of the ABBA situation. * * But it came with performances issues, as syscalls are being restarted in * loops when there was contention on the rtnl lock, with huge slow downs in * specific scenarios (e.g. lots of virtual interfaces created and userspace * daemons querying their attributes). * * The idea below is to bail out of the active kernfs_node protection * (kn->active) while trying to take the rtnl lock. * * This replaces rtnl_lock() and still has to be used with rtnl_unlock(). The * net device is guaranteed to be alive if this returns successfully. */static int sysfs_rtnl_lock(struct kobject *kobj, struct attribute *attr,			   struct net_device *ndev){	struct kernfs_node *kn;	int ret = 0; 	/* First, we hold a reference to the net device as the unregistration	 * path might run in parallel. This will ensure the net device and the	 * associated sysfs objects won't be freed while we try to take the rtnl	 * lock.	 */	dev_hold(ndev);	/* sysfs_break_active_protection was introduced to allow self-removal of	 * devices and their associated sysfs files by bailing out of the	 * sysfs/kernfs protection. We do this here to allow the unregistration	 * path to complete in parallel. The following takes a reference on the	 * kobject and the kernfs_node being accessed.	 *	 * This works because we hold a reference onto the net device and the	 * unregistration path will wait for us eventually in netdev_run_todo	 * (outside an rtnl lock section).	 */	kn = sysfs_break_active_protection(kobj, attr);	/* We can now try to take the rtnl lock. This can't deadlock us as the	 * unregistration path is able to drain sysfs files (kernfs_node) thanks	 * to the above dance.	 */	if (rtnl_lock_interruptible()) {		ret = -ERESTARTSYS;		goto unbreak;	}	/* Check dismantle on the device hasn't started, otherwise deny the	 * operation.	 */	if (!dev_isalive(ndev)) {		rtnl_unlock();		ret = -ENODEV;		goto unbreak;	}	/* We are now sure the device dismantle hasn't started nor that it can	 * start before we exit the locking section as we hold the rtnl lock.	 * There's no need to keep unbreaking the sysfs protection nor to hold	 * a net device reference from that point; that was only needed to take	 * the rtnl lock.	 */unbreak:	sysfs_unbreak_active_protection(kn);	dev_put(ndev); 	return ret;} /* use same locking rules as GIF* ioctl's */static ssize_t netdev_show(const struct device *dev,			   struct device_attribute *attr, char *buf,			   ssize_t (*format)(const struct net_device *, char *)){	struct net_device *ndev = to_net_dev(dev);	ssize_t ret = -EINVAL; 	rcu_read_lock();	if (dev_isalive(ndev))		ret = (*format)(ndev, buf);	rcu_read_unlock(); 	return ret;} /* generate a show function for simple field */#define NETDEVICE_SHOW(field, format_string)				\static ssize_t format_##field(const struct net_device *dev, char *buf)	\{									\	return sysfs_emit(buf, format_string, READ_ONCE(dev->field));		\}									\static ssize_t field##_show(struct device *dev,				\			    struct device_attribute *attr, char *buf)	\{									\	return netdev_show(dev, attr, buf, format_##field);		\}									\ #define NETDEVICE_SHOW_RO(field, format_string)				\NETDEVICE_SHOW(field, format_string);					\static DEVICE_ATTR_RO(field) #define NETDEVICE_SHOW_RW(field, format_string)				\NETDEVICE_SHOW(field, format_string);					\static DEVICE_ATTR_RW(field) /* use same locking and permission rules as SIF* ioctl's */static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,			    const char *buf, size_t len,			    int (*set)(struct net_device *, unsigned long)){	struct net_device *netdev = to_net_dev(dev);	struct net *net = dev_net(netdev);	unsigned long new;	int ret; 	if (!ns_capable(net->user_ns, CAP_NET_ADMIN))		return -EPERM; 	ret = kstrtoul(buf, 0, &new);	if (ret)		goto err; 	ret = sysfs_rtnl_lock(&dev->kobj, &attr->attr, netdev);	if (ret)		goto err; 	ret = (*set)(netdev, new);	if (ret == 0)		ret = len; 	rtnl_unlock(); err:	return ret;} /* Same as netdev_store() but takes netdev_lock() instead of rtnl_lock() */static ssize_tnetdev_lock_store(struct device *dev, struct device_attribute *attr,		  const char *buf, size_t len,		  int (*set)(struct net_device *, unsigned long)){	struct net_device *netdev = to_net_dev(dev);	struct net *net = dev_net(netdev);	unsigned long new;	int ret; 	if (!ns_capable(net->user_ns, CAP_NET_ADMIN))		return -EPERM; 	ret = kstrtoul(buf, 0, &new);	if (ret)		return ret; 	netdev_lock(netdev); 	if (dev_isalive(netdev)) {		ret = (*set)(netdev, new);		if (ret == 0)			ret = len;	}	netdev_unlock(netdev); 	return ret;} NETDEVICE_SHOW_RO(dev_id, fmt_hex);NETDEVICE_SHOW_RO(dev_port, fmt_dec);NETDEVICE_SHOW_RO(addr_assign_type, fmt_dec);NETDEVICE_SHOW_RO(addr_len, fmt_dec);NETDEVICE_SHOW_RO(ifindex, fmt_dec);NETDEVICE_SHOW_RO(type, fmt_dec);NETDEVICE_SHOW_RO(link_mode, fmt_dec); static ssize_t iflink_show(struct device *dev, struct device_attribute *attr,			   char *buf){	struct net_device *ndev = to_net_dev(dev); 	return sysfs_emit(buf, fmt_dec, dev_get_iflink(ndev));}static DEVICE_ATTR_RO(iflink); static ssize_t format_name_assign_type(const struct net_device *dev, char *buf){	return sysfs_emit(buf, fmt_dec, READ_ONCE(dev->name_assign_type));} static ssize_t name_assign_type_show(struct device *dev,				     struct device_attribute *attr,				     char *buf){	struct net_device *ndev = to_net_dev(dev);	ssize_t ret = -EINVAL; 	if (READ_ONCE(ndev->name_assign_type) != NET_NAME_UNKNOWN)		ret = netdev_show(dev, attr, buf, format_name_assign_type); 	return ret;}static DEVICE_ATTR_RO(name_assign_type); /* use same locking rules as GIFHWADDR ioctl's (netif_get_mac_address()) */static ssize_t address_show(struct device *dev, struct device_attribute *attr,			    char *buf){	struct net_device *ndev = to_net_dev(dev);	ssize_t ret = -EINVAL; 	down_read(&dev_addr_sem); 	rcu_read_lock();	if (dev_isalive(ndev))		ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len);	rcu_read_unlock(); 	up_read(&dev_addr_sem);	return ret;}static DEVICE_ATTR_RO(address); static ssize_t broadcast_show(struct device *dev,			      struct device_attribute *attr, char *buf){	struct net_device *ndev = to_net_dev(dev);	int ret = -EINVAL; 	rcu_read_lock();	if (dev_isalive(ndev))		ret = sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len);	rcu_read_unlock();	return ret;}static DEVICE_ATTR_RO(broadcast); static int change_carrier(struct net_device *dev, unsigned long new_carrier){	if (!netif_running(dev))		return -EINVAL;	return dev_change_carrier(dev, (bool)new_carrier);} static ssize_t carrier_store(struct device *dev, struct device_attribute *attr,			     const char *buf, size_t len){	struct net_device *netdev = to_net_dev(dev); 	/* The check is also done in change_carrier; this helps returning early	 * without hitting the locking section in netdev_store.	 */	if (!netdev->netdev_ops->ndo_change_carrier)		return -EOPNOTSUPP; 	return netdev_store(dev, attr, buf, len, change_carrier);} static ssize_t carrier_show(struct device *dev,			    struct device_attribute *attr, char *buf){	struct net_device *netdev = to_net_dev(dev);	int ret; 	ret = sysfs_rtnl_lock(&dev->kobj, &attr->attr, netdev);	if (ret)		return ret; 	ret = -EINVAL;	if (netif_running(netdev)) {		/* Synchronize carrier state with link watch,		 * see also rtnl_getlink().		 */		linkwatch_sync_dev(netdev); 		ret = sysfs_emit(buf, fmt_dec, !!netif_carrier_ok(netdev));	} 	rtnl_unlock();	return ret;}static DEVICE_ATTR_RW(carrier); static ssize_t speed_show(struct device *dev,			  struct device_attribute *attr, char *buf){	struct net_device *netdev = to_net_dev(dev);	int ret = -EINVAL; 	/* The check is also done in __ethtool_get_link_ksettings; this helps	 * returning early without hitting the locking section below.	 */	if (!netdev->ethtool_ops->get_link_ksettings)		return ret; 	ret = sysfs_rtnl_lock(&dev->kobj, &attr->attr, netdev);	if (ret)		return ret; 	ret = -EINVAL;	if (netif_running(netdev)) {		struct ethtool_link_ksettings cmd; 		if (!__ethtool_get_link_ksettings(netdev, &cmd))			ret = sysfs_emit(buf, fmt_dec, cmd.base.speed);	}	rtnl_unlock();	return ret;}static DEVICE_ATTR_RO(speed); static ssize_t duplex_show(struct device *dev,			   struct device_attribute *attr, char *buf){	struct net_device *netdev = to_net_dev(dev);	int ret = -EINVAL; 	/* The check is also done in __ethtool_get_link_ksettings; this helps	 * returning early without hitting the locking section below.	 */	if (!netdev->ethtool_ops->get_link_ksettings)		return ret; 	ret = sysfs_rtnl_lock(&dev->kobj, &attr->attr, netdev);	if (ret)		return ret; 	ret = -EINVAL;	if (netif_running(netdev)) {		struct ethtool_link_ksettings cmd; 		if (!__ethtool_get_link_ksettings(netdev, &cmd)) {			const char *duplex; 			switch (cmd.base.duplex) {			case DUPLEX_HALF:				duplex = "half";				break;			case DUPLEX_FULL:				duplex = "full";				break;			default:				duplex = "unknown";				break;			}			ret = sysfs_emit(buf, "%s\n", duplex);		}	}	rtnl_unlock();	return ret;}static DEVICE_ATTR_RO(duplex); static ssize_t testing_show(struct device *dev,			    struct device_attribute *attr, char *buf){	struct net_device *netdev = to_net_dev(dev); 	if (netif_running(netdev))		return sysfs_emit(buf, fmt_dec, !!netif_testing(netdev)); 	return -EINVAL;}static DEVICE_ATTR_RO(testing); static ssize_t dormant_show(struct device *dev,			    struct device_attribute *attr, char *buf){	struct net_device *netdev = to_net_dev(dev); 	if (netif_running(netdev))		return sysfs_emit(buf, fmt_dec, !!netif_dormant(netdev)); 	return -EINVAL;}static DEVICE_ATTR_RO(dormant); static const char *const operstates[] = {	"unknown",	"notpresent", /* currently unused */	"down",	"lowerlayerdown",	"testing",	"dormant",	"up"}; static ssize_t operstate_show(struct device *dev,			      struct device_attribute *attr, char *buf){	const struct net_device *netdev = to_net_dev(dev);	unsigned char operstate; 	operstate = READ_ONCE(netdev->operstate);	if (!netif_running(netdev))		operstate = IF_OPER_DOWN; 	if (operstate >= ARRAY_SIZE(operstates))		return -EINVAL; /* should not happen */ 	return sysfs_emit(buf, "%s\n", operstates[operstate]);}static DEVICE_ATTR_RO(operstate); static ssize_t carrier_changes_show(struct device *dev,				    struct device_attribute *attr,				    char *buf){	struct net_device *netdev = to_net_dev(dev); 	return sysfs_emit(buf, fmt_dec,			  atomic_read(&netdev->carrier_up_count) +			  atomic_read(&netdev->carrier_down_count));}static DEVICE_ATTR_RO(carrier_changes); static ssize_t carrier_up_count_show(struct device *dev,				     struct device_attribute *attr,				     char *buf){	struct net_device *netdev = to_net_dev(dev); 	return sysfs_emit(buf, fmt_dec, atomic_read(&netdev->carrier_up_count));}static DEVICE_ATTR_RO(carrier_up_count); static ssize_t carrier_down_count_show(struct device *dev,				       struct device_attribute *attr,				       char *buf){	struct net_device *netdev = to_net_dev(dev); 	return sysfs_emit(buf, fmt_dec, atomic_read(&netdev->carrier_down_count));}static DEVICE_ATTR_RO(carrier_down_count); /* read-write attributes */ static int change_mtu(struct net_device *dev, unsigned long new_mtu){	return dev_set_mtu(dev, (int)new_mtu);} static ssize_t mtu_store(struct device *dev, struct device_attribute *attr,			 const char *buf, size_t len){	return netdev_store(dev, attr, buf, len, change_mtu);}NETDEVICE_SHOW_RW(mtu, fmt_dec); static int change_flags(struct net_device *dev, unsigned long new_flags){

Lines 1–500 of 2415.