12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * net-sysfs.c - network device class and attributes 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (c) 2003 Stephen Hemminger <shemminger@osdl.org> 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 84fc268d2SRandy Dunlap #include <linux/capability.h> 91da177e4SLinus Torvalds #include <linux/kernel.h> 101da177e4SLinus Torvalds #include <linux/netdevice.h> 111da177e4SLinus Torvalds #include <linux/if_arp.h> 125a0e3ad6STejun Heo #include <linux/slab.h> 13174cd4b1SIngo Molnar #include <linux/sched/signal.h> 14608b4b95SEric W. Biederman #include <linux/nsproxy.h> 151da177e4SLinus Torvalds #include <net/sock.h> 16608b4b95SEric W. Biederman #include <net/net_namespace.h> 171da177e4SLinus Torvalds #include <linux/rtnetlink.h> 18fec5e652STom Herbert #include <linux/vmalloc.h> 19bc3b2d7fSPaul Gortmaker #include <linux/export.h> 20114cf580STom Herbert #include <linux/jiffies.h> 219802c8e2SMing Lei #include <linux/pm_runtime.h> 22aa836df9SFlorian Fainelli #include <linux/of.h> 2388832a22SBen Dooks #include <linux/of_net.h> 244d99f660SAndrei Vagin #include <linux/cpu.h> 251da177e4SLinus Torvalds 26342709efSPavel Emelyanov #include "net-sysfs.h" 27342709efSPavel Emelyanov 288b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 291da177e4SLinus Torvalds static const char fmt_hex[] = "%#x\n"; 301da177e4SLinus Torvalds static const char fmt_dec[] = "%d\n"; 311da177e4SLinus Torvalds static const char fmt_ulong[] = "%lu\n"; 32be1f3c2cSBen Hutchings static const char fmt_u64[] = "%llu\n"; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static inline int dev_isalive(const struct net_device *dev) 351da177e4SLinus Torvalds { 36fe9925b5SStephen Hemminger return dev->reg_state <= NETREG_REGISTERED; 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* use same locking rules as GIF* ioctl's */ 4043cb76d9SGreg Kroah-Hartman static ssize_t netdev_show(const struct device *dev, 4143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 421da177e4SLinus Torvalds ssize_t (*format)(const struct net_device *, char *)) 431da177e4SLinus Torvalds { 446b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 451da177e4SLinus Torvalds ssize_t ret = -EINVAL; 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds read_lock(&dev_base_lock); 486b53dafeSWANG Cong if (dev_isalive(ndev)) 496b53dafeSWANG Cong ret = (*format)(ndev, buf); 501da177e4SLinus Torvalds read_unlock(&dev_base_lock); 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds return ret; 531da177e4SLinus Torvalds } 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds /* generate a show function for simple field */ 561da177e4SLinus Torvalds #define NETDEVICE_SHOW(field, format_string) \ 576b53dafeSWANG Cong static ssize_t format_##field(const struct net_device *dev, char *buf) \ 581da177e4SLinus Torvalds { \ 596b53dafeSWANG Cong return sprintf(buf, format_string, dev->field); \ 601da177e4SLinus Torvalds } \ 616be8aeefSGreg Kroah-Hartman static ssize_t field##_show(struct device *dev, \ 6243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 631da177e4SLinus Torvalds { \ 6443cb76d9SGreg Kroah-Hartman return netdev_show(dev, attr, buf, format_##field); \ 656be8aeefSGreg Kroah-Hartman } \ 661da177e4SLinus Torvalds 676be8aeefSGreg Kroah-Hartman #define NETDEVICE_SHOW_RO(field, format_string) \ 686be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(field, format_string); \ 696be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(field) 706be8aeefSGreg Kroah-Hartman 716be8aeefSGreg Kroah-Hartman #define NETDEVICE_SHOW_RW(field, format_string) \ 726be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(field, format_string); \ 736be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(field) 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds /* use same locking and permission rules as SIF* ioctl's */ 7643cb76d9SGreg Kroah-Hartman static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, 771da177e4SLinus Torvalds const char *buf, size_t len, 781da177e4SLinus Torvalds int (*set)(struct net_device *, unsigned long)) 791da177e4SLinus Torvalds { 805e1fccc0SEric W. Biederman struct net_device *netdev = to_net_dev(dev); 815e1fccc0SEric W. Biederman struct net *net = dev_net(netdev); 821da177e4SLinus Torvalds unsigned long new; 835f0224a6SColin Ian King int ret; 841da177e4SLinus Torvalds 855e1fccc0SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 861da177e4SLinus Torvalds return -EPERM; 871da177e4SLinus Torvalds 88e1e420c7SShuah Khan ret = kstrtoul(buf, 0, &new); 89e1e420c7SShuah Khan if (ret) 901da177e4SLinus Torvalds goto err; 911da177e4SLinus Torvalds 925a5990d3SStephen Hemminger if (!rtnl_trylock()) 93336ca57cSEric W. Biederman return restart_syscall(); 945a5990d3SStephen Hemminger 955e1fccc0SEric W. Biederman if (dev_isalive(netdev)) { 966648c65eSstephen hemminger ret = (*set)(netdev, new); 976648c65eSstephen hemminger if (ret == 0) 981da177e4SLinus Torvalds ret = len; 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds rtnl_unlock(); 1011da177e4SLinus Torvalds err: 1021da177e4SLinus Torvalds return ret; 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds 1056be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(dev_id, fmt_hex); 1063f85944fSAmir Vadai NETDEVICE_SHOW_RO(dev_port, fmt_dec); 1076be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(addr_assign_type, fmt_dec); 1086be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(addr_len, fmt_dec); 1096be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(ifindex, fmt_dec); 1106be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(type, fmt_dec); 1116be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(link_mode, fmt_dec); 1121da177e4SLinus Torvalds 113a54acb3aSNicolas Dichtel static ssize_t iflink_show(struct device *dev, struct device_attribute *attr, 114a54acb3aSNicolas Dichtel char *buf) 115a54acb3aSNicolas Dichtel { 116a54acb3aSNicolas Dichtel struct net_device *ndev = to_net_dev(dev); 117a54acb3aSNicolas Dichtel 118a54acb3aSNicolas Dichtel return sprintf(buf, fmt_dec, dev_get_iflink(ndev)); 119a54acb3aSNicolas Dichtel } 120a54acb3aSNicolas Dichtel static DEVICE_ATTR_RO(iflink); 121a54acb3aSNicolas Dichtel 1226b53dafeSWANG Cong static ssize_t format_name_assign_type(const struct net_device *dev, char *buf) 123685343fcSTom Gundersen { 1246b53dafeSWANG Cong return sprintf(buf, fmt_dec, dev->name_assign_type); 125685343fcSTom Gundersen } 126685343fcSTom Gundersen 127685343fcSTom Gundersen static ssize_t name_assign_type_show(struct device *dev, 128685343fcSTom Gundersen struct device_attribute *attr, 129685343fcSTom Gundersen char *buf) 130685343fcSTom Gundersen { 1316b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 132685343fcSTom Gundersen ssize_t ret = -EINVAL; 133685343fcSTom Gundersen 1346b53dafeSWANG Cong if (ndev->name_assign_type != NET_NAME_UNKNOWN) 135685343fcSTom Gundersen ret = netdev_show(dev, attr, buf, format_name_assign_type); 136685343fcSTom Gundersen 137685343fcSTom Gundersen return ret; 138685343fcSTom Gundersen } 139685343fcSTom Gundersen static DEVICE_ATTR_RO(name_assign_type); 140685343fcSTom Gundersen 1411da177e4SLinus Torvalds /* use same locking rules as GIFHWADDR ioctl's */ 1426be8aeefSGreg Kroah-Hartman static ssize_t address_show(struct device *dev, struct device_attribute *attr, 14343cb76d9SGreg Kroah-Hartman char *buf) 1441da177e4SLinus Torvalds { 1456b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 1461da177e4SLinus Torvalds ssize_t ret = -EINVAL; 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds read_lock(&dev_base_lock); 1496b53dafeSWANG Cong if (dev_isalive(ndev)) 1506b53dafeSWANG Cong ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len); 1511da177e4SLinus Torvalds read_unlock(&dev_base_lock); 1521da177e4SLinus Torvalds return ret; 1531da177e4SLinus Torvalds } 1546be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(address); 1551da177e4SLinus Torvalds 1566be8aeefSGreg Kroah-Hartman static ssize_t broadcast_show(struct device *dev, 15743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1581da177e4SLinus Torvalds { 1596b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 1606648c65eSstephen hemminger 1616b53dafeSWANG Cong if (dev_isalive(ndev)) 1626b53dafeSWANG Cong return sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len); 1631da177e4SLinus Torvalds return -EINVAL; 1641da177e4SLinus Torvalds } 1656be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(broadcast); 1661da177e4SLinus Torvalds 1676b53dafeSWANG Cong static int change_carrier(struct net_device *dev, unsigned long new_carrier) 168fdae0fdeSJiri Pirko { 1696b53dafeSWANG Cong if (!netif_running(dev)) 170fdae0fdeSJiri Pirko return -EINVAL; 1716b53dafeSWANG Cong return dev_change_carrier(dev, (bool)new_carrier); 172fdae0fdeSJiri Pirko } 173fdae0fdeSJiri Pirko 1746be8aeefSGreg Kroah-Hartman static ssize_t carrier_store(struct device *dev, struct device_attribute *attr, 175fdae0fdeSJiri Pirko const char *buf, size_t len) 176fdae0fdeSJiri Pirko { 177fdae0fdeSJiri Pirko return netdev_store(dev, attr, buf, len, change_carrier); 178fdae0fdeSJiri Pirko } 179fdae0fdeSJiri Pirko 1806be8aeefSGreg Kroah-Hartman static ssize_t carrier_show(struct device *dev, 18143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1821da177e4SLinus Torvalds { 1831da177e4SLinus Torvalds struct net_device *netdev = to_net_dev(dev); 1846648c65eSstephen hemminger 1856648c65eSstephen hemminger if (netif_running(netdev)) 1861da177e4SLinus Torvalds return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); 1876648c65eSstephen hemminger 1881da177e4SLinus Torvalds return -EINVAL; 1891da177e4SLinus Torvalds } 1906be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(carrier); 1911da177e4SLinus Torvalds 1926be8aeefSGreg Kroah-Hartman static ssize_t speed_show(struct device *dev, 193d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 194d519e17eSAndy Gospodarek { 195d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 196d519e17eSAndy Gospodarek int ret = -EINVAL; 197d519e17eSAndy Gospodarek 198d519e17eSAndy Gospodarek if (!rtnl_trylock()) 199d519e17eSAndy Gospodarek return restart_syscall(); 200d519e17eSAndy Gospodarek 2018ae6dacaSDavid Decotigny if (netif_running(netdev)) { 2027cad1bacSDavid Decotigny struct ethtool_link_ksettings cmd; 2037cad1bacSDavid Decotigny 2047cad1bacSDavid Decotigny if (!__ethtool_get_link_ksettings(netdev, &cmd)) 2057cad1bacSDavid Decotigny ret = sprintf(buf, fmt_dec, cmd.base.speed); 206d519e17eSAndy Gospodarek } 207d519e17eSAndy Gospodarek rtnl_unlock(); 208d519e17eSAndy Gospodarek return ret; 209d519e17eSAndy Gospodarek } 2106be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(speed); 211d519e17eSAndy Gospodarek 2126be8aeefSGreg Kroah-Hartman static ssize_t duplex_show(struct device *dev, 213d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 214d519e17eSAndy Gospodarek { 215d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 216d519e17eSAndy Gospodarek int ret = -EINVAL; 217d519e17eSAndy Gospodarek 218d519e17eSAndy Gospodarek if (!rtnl_trylock()) 219d519e17eSAndy Gospodarek return restart_syscall(); 220d519e17eSAndy Gospodarek 2218ae6dacaSDavid Decotigny if (netif_running(netdev)) { 2227cad1bacSDavid Decotigny struct ethtool_link_ksettings cmd; 2237cad1bacSDavid Decotigny 2247cad1bacSDavid Decotigny if (!__ethtool_get_link_ksettings(netdev, &cmd)) { 225c6c13965SNikolay Aleksandrov const char *duplex; 2267cad1bacSDavid Decotigny 2277cad1bacSDavid Decotigny switch (cmd.base.duplex) { 228c6c13965SNikolay Aleksandrov case DUPLEX_HALF: 229c6c13965SNikolay Aleksandrov duplex = "half"; 230c6c13965SNikolay Aleksandrov break; 231c6c13965SNikolay Aleksandrov case DUPLEX_FULL: 232c6c13965SNikolay Aleksandrov duplex = "full"; 233c6c13965SNikolay Aleksandrov break; 234c6c13965SNikolay Aleksandrov default: 235c6c13965SNikolay Aleksandrov duplex = "unknown"; 236c6c13965SNikolay Aleksandrov break; 237c6c13965SNikolay Aleksandrov } 238c6c13965SNikolay Aleksandrov ret = sprintf(buf, "%s\n", duplex); 239c6c13965SNikolay Aleksandrov } 240d519e17eSAndy Gospodarek } 241d519e17eSAndy Gospodarek rtnl_unlock(); 242d519e17eSAndy Gospodarek return ret; 243d519e17eSAndy Gospodarek } 2446be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(duplex); 245d519e17eSAndy Gospodarek 246db30a577SAndrew Lunn static ssize_t testing_show(struct device *dev, 247db30a577SAndrew Lunn struct device_attribute *attr, char *buf) 248db30a577SAndrew Lunn { 249db30a577SAndrew Lunn struct net_device *netdev = to_net_dev(dev); 250db30a577SAndrew Lunn 251db30a577SAndrew Lunn if (netif_running(netdev)) 252db30a577SAndrew Lunn return sprintf(buf, fmt_dec, !!netif_testing(netdev)); 253db30a577SAndrew Lunn 254db30a577SAndrew Lunn return -EINVAL; 255db30a577SAndrew Lunn } 256db30a577SAndrew Lunn static DEVICE_ATTR_RO(testing); 257db30a577SAndrew Lunn 2586be8aeefSGreg Kroah-Hartman static ssize_t dormant_show(struct device *dev, 25943cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 260b00055aaSStefan Rompf { 261b00055aaSStefan Rompf struct net_device *netdev = to_net_dev(dev); 262b00055aaSStefan Rompf 263b00055aaSStefan Rompf if (netif_running(netdev)) 264b00055aaSStefan Rompf return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); 265b00055aaSStefan Rompf 266b00055aaSStefan Rompf return -EINVAL; 267b00055aaSStefan Rompf } 2686be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(dormant); 269b00055aaSStefan Rompf 27036cbd3dcSJan Engelhardt static const char *const operstates[] = { 271b00055aaSStefan Rompf "unknown", 272b00055aaSStefan Rompf "notpresent", /* currently unused */ 273b00055aaSStefan Rompf "down", 274b00055aaSStefan Rompf "lowerlayerdown", 275db30a577SAndrew Lunn "testing", 276b00055aaSStefan Rompf "dormant", 277b00055aaSStefan Rompf "up" 278b00055aaSStefan Rompf }; 279b00055aaSStefan Rompf 2806be8aeefSGreg Kroah-Hartman static ssize_t operstate_show(struct device *dev, 28143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 282b00055aaSStefan Rompf { 283b00055aaSStefan Rompf const struct net_device *netdev = to_net_dev(dev); 284b00055aaSStefan Rompf unsigned char operstate; 285b00055aaSStefan Rompf 286b00055aaSStefan Rompf read_lock(&dev_base_lock); 287b00055aaSStefan Rompf operstate = netdev->operstate; 288b00055aaSStefan Rompf if (!netif_running(netdev)) 289b00055aaSStefan Rompf operstate = IF_OPER_DOWN; 290b00055aaSStefan Rompf read_unlock(&dev_base_lock); 291b00055aaSStefan Rompf 292e3a5cd9eSAdrian Bunk if (operstate >= ARRAY_SIZE(operstates)) 293b00055aaSStefan Rompf return -EINVAL; /* should not happen */ 294b00055aaSStefan Rompf 295b00055aaSStefan Rompf return sprintf(buf, "%s\n", operstates[operstate]); 296b00055aaSStefan Rompf } 2976be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(operstate); 298b00055aaSStefan Rompf 2992d3b479dSdavid decotigny static ssize_t carrier_changes_show(struct device *dev, 3002d3b479dSdavid decotigny struct device_attribute *attr, 3012d3b479dSdavid decotigny char *buf) 3022d3b479dSdavid decotigny { 3032d3b479dSdavid decotigny struct net_device *netdev = to_net_dev(dev); 3046648c65eSstephen hemminger 3052d3b479dSdavid decotigny return sprintf(buf, fmt_dec, 306b2d3bcfaSDavid Decotigny atomic_read(&netdev->carrier_up_count) + 307b2d3bcfaSDavid Decotigny atomic_read(&netdev->carrier_down_count)); 3082d3b479dSdavid decotigny } 3092d3b479dSdavid decotigny static DEVICE_ATTR_RO(carrier_changes); 3102d3b479dSdavid decotigny 311b2d3bcfaSDavid Decotigny static ssize_t carrier_up_count_show(struct device *dev, 312b2d3bcfaSDavid Decotigny struct device_attribute *attr, 313b2d3bcfaSDavid Decotigny char *buf) 314b2d3bcfaSDavid Decotigny { 315b2d3bcfaSDavid Decotigny struct net_device *netdev = to_net_dev(dev); 316b2d3bcfaSDavid Decotigny 317b2d3bcfaSDavid Decotigny return sprintf(buf, fmt_dec, atomic_read(&netdev->carrier_up_count)); 318b2d3bcfaSDavid Decotigny } 319b2d3bcfaSDavid Decotigny static DEVICE_ATTR_RO(carrier_up_count); 320b2d3bcfaSDavid Decotigny 321b2d3bcfaSDavid Decotigny static ssize_t carrier_down_count_show(struct device *dev, 322b2d3bcfaSDavid Decotigny struct device_attribute *attr, 323b2d3bcfaSDavid Decotigny char *buf) 324b2d3bcfaSDavid Decotigny { 325b2d3bcfaSDavid Decotigny struct net_device *netdev = to_net_dev(dev); 326b2d3bcfaSDavid Decotigny 327b2d3bcfaSDavid Decotigny return sprintf(buf, fmt_dec, atomic_read(&netdev->carrier_down_count)); 328b2d3bcfaSDavid Decotigny } 329b2d3bcfaSDavid Decotigny static DEVICE_ATTR_RO(carrier_down_count); 330b2d3bcfaSDavid Decotigny 3311da177e4SLinus Torvalds /* read-write attributes */ 3321da177e4SLinus Torvalds 3336b53dafeSWANG Cong static int change_mtu(struct net_device *dev, unsigned long new_mtu) 3341da177e4SLinus Torvalds { 3356b53dafeSWANG Cong return dev_set_mtu(dev, (int)new_mtu); 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 3386be8aeefSGreg Kroah-Hartman static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, 33943cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3401da177e4SLinus Torvalds { 34143cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_mtu); 3421da177e4SLinus Torvalds } 3436be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(mtu, fmt_dec); 3441da177e4SLinus Torvalds 3456b53dafeSWANG Cong static int change_flags(struct net_device *dev, unsigned long new_flags) 3461da177e4SLinus Torvalds { 347567c5e13SPetr Machata return dev_change_flags(dev, (unsigned int)new_flags, NULL); 3481da177e4SLinus Torvalds } 3491da177e4SLinus Torvalds 3506be8aeefSGreg Kroah-Hartman static ssize_t flags_store(struct device *dev, struct device_attribute *attr, 35143cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3521da177e4SLinus Torvalds { 35343cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_flags); 3541da177e4SLinus Torvalds } 3556be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(flags, fmt_hex); 3561da177e4SLinus Torvalds 3576be8aeefSGreg Kroah-Hartman static ssize_t tx_queue_len_store(struct device *dev, 35843cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 35943cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3601da177e4SLinus Torvalds { 3615e1fccc0SEric W. Biederman if (!capable(CAP_NET_ADMIN)) 3625e1fccc0SEric W. Biederman return -EPERM; 3635e1fccc0SEric W. Biederman 3646a643ddbSCong Wang return netdev_store(dev, attr, buf, len, dev_change_tx_queue_len); 3651da177e4SLinus Torvalds } 3660cd29503SAlexey Dobriyan NETDEVICE_SHOW_RW(tx_queue_len, fmt_dec); 3671da177e4SLinus Torvalds 3683b47d303SEric Dumazet static int change_gro_flush_timeout(struct net_device *dev, unsigned long val) 3693b47d303SEric Dumazet { 3707e417a66SEric Dumazet WRITE_ONCE(dev->gro_flush_timeout, val); 3713b47d303SEric Dumazet return 0; 3723b47d303SEric Dumazet } 3733b47d303SEric Dumazet 3743b47d303SEric Dumazet static ssize_t gro_flush_timeout_store(struct device *dev, 3753b47d303SEric Dumazet struct device_attribute *attr, 3763b47d303SEric Dumazet const char *buf, size_t len) 3773b47d303SEric Dumazet { 3783b47d303SEric Dumazet if (!capable(CAP_NET_ADMIN)) 3793b47d303SEric Dumazet return -EPERM; 3803b47d303SEric Dumazet 3813b47d303SEric Dumazet return netdev_store(dev, attr, buf, len, change_gro_flush_timeout); 3823b47d303SEric Dumazet } 3833b47d303SEric Dumazet NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong); 3843b47d303SEric Dumazet 3856f8b12d6SEric Dumazet static int change_napi_defer_hard_irqs(struct net_device *dev, unsigned long val) 3866f8b12d6SEric Dumazet { 3877e417a66SEric Dumazet WRITE_ONCE(dev->napi_defer_hard_irqs, val); 3886f8b12d6SEric Dumazet return 0; 3896f8b12d6SEric Dumazet } 3906f8b12d6SEric Dumazet 3916f8b12d6SEric Dumazet static ssize_t napi_defer_hard_irqs_store(struct device *dev, 3926f8b12d6SEric Dumazet struct device_attribute *attr, 3936f8b12d6SEric Dumazet const char *buf, size_t len) 3946f8b12d6SEric Dumazet { 3956f8b12d6SEric Dumazet if (!capable(CAP_NET_ADMIN)) 3966f8b12d6SEric Dumazet return -EPERM; 3976f8b12d6SEric Dumazet 3986f8b12d6SEric Dumazet return netdev_store(dev, attr, buf, len, change_napi_defer_hard_irqs); 3996f8b12d6SEric Dumazet } 4006f8b12d6SEric Dumazet NETDEVICE_SHOW_RW(napi_defer_hard_irqs, fmt_dec); 4016f8b12d6SEric Dumazet 4026be8aeefSGreg Kroah-Hartman static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr, 4030b815a1aSStephen Hemminger const char *buf, size_t len) 4040b815a1aSStephen Hemminger { 4050b815a1aSStephen Hemminger struct net_device *netdev = to_net_dev(dev); 4065e1fccc0SEric W. Biederman struct net *net = dev_net(netdev); 4070b815a1aSStephen Hemminger size_t count = len; 408c92eb77aSRoopa Prabhu ssize_t ret = 0; 4090b815a1aSStephen Hemminger 4105e1fccc0SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 4110b815a1aSStephen Hemminger return -EPERM; 4120b815a1aSStephen Hemminger 4130b815a1aSStephen Hemminger /* ignore trailing newline */ 4140b815a1aSStephen Hemminger if (len > 0 && buf[len - 1] == '\n') 4150b815a1aSStephen Hemminger --count; 4160b815a1aSStephen Hemminger 417c92eb77aSRoopa Prabhu if (!rtnl_trylock()) 418c92eb77aSRoopa Prabhu return restart_syscall(); 4190b815a1aSStephen Hemminger 420c92eb77aSRoopa Prabhu if (dev_isalive(netdev)) { 421c92eb77aSRoopa Prabhu ret = dev_set_alias(netdev, buf, count); 422c92eb77aSRoopa Prabhu if (ret < 0) 423c92eb77aSRoopa Prabhu goto err; 424c92eb77aSRoopa Prabhu ret = len; 425c92eb77aSRoopa Prabhu netdev_state_change(netdev); 426c92eb77aSRoopa Prabhu } 427c92eb77aSRoopa Prabhu err: 428c92eb77aSRoopa Prabhu rtnl_unlock(); 429c92eb77aSRoopa Prabhu 430c92eb77aSRoopa Prabhu return ret; 4310b815a1aSStephen Hemminger } 4320b815a1aSStephen Hemminger 4336be8aeefSGreg Kroah-Hartman static ssize_t ifalias_show(struct device *dev, 4340b815a1aSStephen Hemminger struct device_attribute *attr, char *buf) 4350b815a1aSStephen Hemminger { 4360b815a1aSStephen Hemminger const struct net_device *netdev = to_net_dev(dev); 4376c557001SFlorian Westphal char tmp[IFALIASZ]; 4380b815a1aSStephen Hemminger ssize_t ret = 0; 4390b815a1aSStephen Hemminger 4406c557001SFlorian Westphal ret = dev_get_alias(netdev, tmp, sizeof(tmp)); 4416c557001SFlorian Westphal if (ret > 0) 4426c557001SFlorian Westphal ret = sprintf(buf, "%s\n", tmp); 4430b815a1aSStephen Hemminger return ret; 4440b815a1aSStephen Hemminger } 4456be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(ifalias); 446a512b92bSVlad Dogaru 4476b53dafeSWANG Cong static int change_group(struct net_device *dev, unsigned long new_group) 448a512b92bSVlad Dogaru { 4496b53dafeSWANG Cong dev_set_group(dev, (int)new_group); 450a512b92bSVlad Dogaru return 0; 451a512b92bSVlad Dogaru } 452a512b92bSVlad Dogaru 4536be8aeefSGreg Kroah-Hartman static ssize_t group_store(struct device *dev, struct device_attribute *attr, 454a512b92bSVlad Dogaru const char *buf, size_t len) 455a512b92bSVlad Dogaru { 456a512b92bSVlad Dogaru return netdev_store(dev, attr, buf, len, change_group); 457a512b92bSVlad Dogaru } 4586be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(group, fmt_dec); 459d6444062SJoe Perches static DEVICE_ATTR(netdev_group, 0644, group_show, group_store); 460a512b92bSVlad Dogaru 461d746d707SAnuradha Karuppiah static int change_proto_down(struct net_device *dev, unsigned long proto_down) 462d746d707SAnuradha Karuppiah { 463d746d707SAnuradha Karuppiah return dev_change_proto_down(dev, (bool)proto_down); 464d746d707SAnuradha Karuppiah } 465d746d707SAnuradha Karuppiah 466d746d707SAnuradha Karuppiah static ssize_t proto_down_store(struct device *dev, 467d746d707SAnuradha Karuppiah struct device_attribute *attr, 468d746d707SAnuradha Karuppiah const char *buf, size_t len) 469d746d707SAnuradha Karuppiah { 470d746d707SAnuradha Karuppiah return netdev_store(dev, attr, buf, len, change_proto_down); 471d746d707SAnuradha Karuppiah } 472d746d707SAnuradha Karuppiah NETDEVICE_SHOW_RW(proto_down, fmt_dec); 473d746d707SAnuradha Karuppiah 474cc998ff8SLinus Torvalds static ssize_t phys_port_id_show(struct device *dev, 475ff80e519SJiri Pirko struct device_attribute *attr, char *buf) 476ff80e519SJiri Pirko { 477ff80e519SJiri Pirko struct net_device *netdev = to_net_dev(dev); 478ff80e519SJiri Pirko ssize_t ret = -EINVAL; 479ff80e519SJiri Pirko 480ff80e519SJiri Pirko if (!rtnl_trylock()) 481ff80e519SJiri Pirko return restart_syscall(); 482ff80e519SJiri Pirko 483ff80e519SJiri Pirko if (dev_isalive(netdev)) { 48402637fceSJiri Pirko struct netdev_phys_item_id ppid; 485ff80e519SJiri Pirko 486ff80e519SJiri Pirko ret = dev_get_phys_port_id(netdev, &ppid); 487ff80e519SJiri Pirko if (!ret) 488ff80e519SJiri Pirko ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); 489ff80e519SJiri Pirko } 490ff80e519SJiri Pirko rtnl_unlock(); 491ff80e519SJiri Pirko 492ff80e519SJiri Pirko return ret; 493ff80e519SJiri Pirko } 494cc998ff8SLinus Torvalds static DEVICE_ATTR_RO(phys_port_id); 495ff80e519SJiri Pirko 496db24a904SDavid Ahern static ssize_t phys_port_name_show(struct device *dev, 497db24a904SDavid Ahern struct device_attribute *attr, char *buf) 498db24a904SDavid Ahern { 499db24a904SDavid Ahern struct net_device *netdev = to_net_dev(dev); 500db24a904SDavid Ahern ssize_t ret = -EINVAL; 501db24a904SDavid Ahern 502db24a904SDavid Ahern if (!rtnl_trylock()) 503db24a904SDavid Ahern return restart_syscall(); 504db24a904SDavid Ahern 505db24a904SDavid Ahern if (dev_isalive(netdev)) { 506db24a904SDavid Ahern char name[IFNAMSIZ]; 507db24a904SDavid Ahern 508db24a904SDavid Ahern ret = dev_get_phys_port_name(netdev, name, sizeof(name)); 509db24a904SDavid Ahern if (!ret) 510db24a904SDavid Ahern ret = sprintf(buf, "%s\n", name); 511db24a904SDavid Ahern } 512db24a904SDavid Ahern rtnl_unlock(); 513db24a904SDavid Ahern 514db24a904SDavid Ahern return ret; 515db24a904SDavid Ahern } 516db24a904SDavid Ahern static DEVICE_ATTR_RO(phys_port_name); 517db24a904SDavid Ahern 518aecbe01eSJiri Pirko static ssize_t phys_switch_id_show(struct device *dev, 519aecbe01eSJiri Pirko struct device_attribute *attr, char *buf) 520aecbe01eSJiri Pirko { 521aecbe01eSJiri Pirko struct net_device *netdev = to_net_dev(dev); 522aecbe01eSJiri Pirko ssize_t ret = -EINVAL; 523aecbe01eSJiri Pirko 524aecbe01eSJiri Pirko if (!rtnl_trylock()) 525aecbe01eSJiri Pirko return restart_syscall(); 526aecbe01eSJiri Pirko 527aecbe01eSJiri Pirko if (dev_isalive(netdev)) { 528bccb3025SFlorian Fainelli struct netdev_phys_item_id ppid = { }; 529aecbe01eSJiri Pirko 530bccb3025SFlorian Fainelli ret = dev_get_port_parent_id(netdev, &ppid, false); 531aecbe01eSJiri Pirko if (!ret) 532bccb3025SFlorian Fainelli ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); 533aecbe01eSJiri Pirko } 534aecbe01eSJiri Pirko rtnl_unlock(); 535aecbe01eSJiri Pirko 536aecbe01eSJiri Pirko return ret; 537aecbe01eSJiri Pirko } 538aecbe01eSJiri Pirko static DEVICE_ATTR_RO(phys_switch_id); 539aecbe01eSJiri Pirko 540ec6cc599Sstephen hemminger static struct attribute *net_class_attrs[] __ro_after_init = { 5416be8aeefSGreg Kroah-Hartman &dev_attr_netdev_group.attr, 5426be8aeefSGreg Kroah-Hartman &dev_attr_type.attr, 5436be8aeefSGreg Kroah-Hartman &dev_attr_dev_id.attr, 5443f85944fSAmir Vadai &dev_attr_dev_port.attr, 5456be8aeefSGreg Kroah-Hartman &dev_attr_iflink.attr, 5466be8aeefSGreg Kroah-Hartman &dev_attr_ifindex.attr, 547685343fcSTom Gundersen &dev_attr_name_assign_type.attr, 5486be8aeefSGreg Kroah-Hartman &dev_attr_addr_assign_type.attr, 5496be8aeefSGreg Kroah-Hartman &dev_attr_addr_len.attr, 5506be8aeefSGreg Kroah-Hartman &dev_attr_link_mode.attr, 5516be8aeefSGreg Kroah-Hartman &dev_attr_address.attr, 5526be8aeefSGreg Kroah-Hartman &dev_attr_broadcast.attr, 5536be8aeefSGreg Kroah-Hartman &dev_attr_speed.attr, 5546be8aeefSGreg Kroah-Hartman &dev_attr_duplex.attr, 5556be8aeefSGreg Kroah-Hartman &dev_attr_dormant.attr, 556db30a577SAndrew Lunn &dev_attr_testing.attr, 5576be8aeefSGreg Kroah-Hartman &dev_attr_operstate.attr, 5582d3b479dSdavid decotigny &dev_attr_carrier_changes.attr, 5596be8aeefSGreg Kroah-Hartman &dev_attr_ifalias.attr, 5606be8aeefSGreg Kroah-Hartman &dev_attr_carrier.attr, 5616be8aeefSGreg Kroah-Hartman &dev_attr_mtu.attr, 5626be8aeefSGreg Kroah-Hartman &dev_attr_flags.attr, 5636be8aeefSGreg Kroah-Hartman &dev_attr_tx_queue_len.attr, 5643b47d303SEric Dumazet &dev_attr_gro_flush_timeout.attr, 5656f8b12d6SEric Dumazet &dev_attr_napi_defer_hard_irqs.attr, 566cc998ff8SLinus Torvalds &dev_attr_phys_port_id.attr, 567db24a904SDavid Ahern &dev_attr_phys_port_name.attr, 568aecbe01eSJiri Pirko &dev_attr_phys_switch_id.attr, 569d746d707SAnuradha Karuppiah &dev_attr_proto_down.attr, 570b2d3bcfaSDavid Decotigny &dev_attr_carrier_up_count.attr, 571b2d3bcfaSDavid Decotigny &dev_attr_carrier_down_count.attr, 5726be8aeefSGreg Kroah-Hartman NULL, 5731da177e4SLinus Torvalds }; 5746be8aeefSGreg Kroah-Hartman ATTRIBUTE_GROUPS(net_class); 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds /* Show a given an attribute in the statistics group */ 57743cb76d9SGreg Kroah-Hartman static ssize_t netstat_show(const struct device *d, 57843cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 5791da177e4SLinus Torvalds unsigned long offset) 5801da177e4SLinus Torvalds { 58143cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 5821da177e4SLinus Torvalds ssize_t ret = -EINVAL; 5831da177e4SLinus Torvalds 584be1f3c2cSBen Hutchings WARN_ON(offset > sizeof(struct rtnl_link_stats64) || 585be1f3c2cSBen Hutchings offset % sizeof(u64) != 0); 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds read_lock(&dev_base_lock); 58896e74088SPavel Emelyanov if (dev_isalive(dev)) { 58928172739SEric Dumazet struct rtnl_link_stats64 temp; 59028172739SEric Dumazet const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); 59128172739SEric Dumazet 592be1f3c2cSBen Hutchings ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *)stats) + offset)); 59396e74088SPavel Emelyanov } 5941da177e4SLinus Torvalds read_unlock(&dev_base_lock); 5951da177e4SLinus Torvalds return ret; 5961da177e4SLinus Torvalds } 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds /* generate a read-only statistics attribute */ 5991da177e4SLinus Torvalds #define NETSTAT_ENTRY(name) \ 6006be8aeefSGreg Kroah-Hartman static ssize_t name##_show(struct device *d, \ 60143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 6021da177e4SLinus Torvalds { \ 60343cb76d9SGreg Kroah-Hartman return netstat_show(d, attr, buf, \ 604be1f3c2cSBen Hutchings offsetof(struct rtnl_link_stats64, name)); \ 6051da177e4SLinus Torvalds } \ 6066be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(name) 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds NETSTAT_ENTRY(rx_packets); 6091da177e4SLinus Torvalds NETSTAT_ENTRY(tx_packets); 6101da177e4SLinus Torvalds NETSTAT_ENTRY(rx_bytes); 6111da177e4SLinus Torvalds NETSTAT_ENTRY(tx_bytes); 6121da177e4SLinus Torvalds NETSTAT_ENTRY(rx_errors); 6131da177e4SLinus Torvalds NETSTAT_ENTRY(tx_errors); 6141da177e4SLinus Torvalds NETSTAT_ENTRY(rx_dropped); 6151da177e4SLinus Torvalds NETSTAT_ENTRY(tx_dropped); 6161da177e4SLinus Torvalds NETSTAT_ENTRY(multicast); 6171da177e4SLinus Torvalds NETSTAT_ENTRY(collisions); 6181da177e4SLinus Torvalds NETSTAT_ENTRY(rx_length_errors); 6191da177e4SLinus Torvalds NETSTAT_ENTRY(rx_over_errors); 6201da177e4SLinus Torvalds NETSTAT_ENTRY(rx_crc_errors); 6211da177e4SLinus Torvalds NETSTAT_ENTRY(rx_frame_errors); 6221da177e4SLinus Torvalds NETSTAT_ENTRY(rx_fifo_errors); 6231da177e4SLinus Torvalds NETSTAT_ENTRY(rx_missed_errors); 6241da177e4SLinus Torvalds NETSTAT_ENTRY(tx_aborted_errors); 6251da177e4SLinus Torvalds NETSTAT_ENTRY(tx_carrier_errors); 6261da177e4SLinus Torvalds NETSTAT_ENTRY(tx_fifo_errors); 6271da177e4SLinus Torvalds NETSTAT_ENTRY(tx_heartbeat_errors); 6281da177e4SLinus Torvalds NETSTAT_ENTRY(tx_window_errors); 6291da177e4SLinus Torvalds NETSTAT_ENTRY(rx_compressed); 6301da177e4SLinus Torvalds NETSTAT_ENTRY(tx_compressed); 6316e7333d3SJarod Wilson NETSTAT_ENTRY(rx_nohandler); 6321da177e4SLinus Torvalds 633ec6cc599Sstephen hemminger static struct attribute *netstat_attrs[] __ro_after_init = { 63443cb76d9SGreg Kroah-Hartman &dev_attr_rx_packets.attr, 63543cb76d9SGreg Kroah-Hartman &dev_attr_tx_packets.attr, 63643cb76d9SGreg Kroah-Hartman &dev_attr_rx_bytes.attr, 63743cb76d9SGreg Kroah-Hartman &dev_attr_tx_bytes.attr, 63843cb76d9SGreg Kroah-Hartman &dev_attr_rx_errors.attr, 63943cb76d9SGreg Kroah-Hartman &dev_attr_tx_errors.attr, 64043cb76d9SGreg Kroah-Hartman &dev_attr_rx_dropped.attr, 64143cb76d9SGreg Kroah-Hartman &dev_attr_tx_dropped.attr, 64243cb76d9SGreg Kroah-Hartman &dev_attr_multicast.attr, 64343cb76d9SGreg Kroah-Hartman &dev_attr_collisions.attr, 64443cb76d9SGreg Kroah-Hartman &dev_attr_rx_length_errors.attr, 64543cb76d9SGreg Kroah-Hartman &dev_attr_rx_over_errors.attr, 64643cb76d9SGreg Kroah-Hartman &dev_attr_rx_crc_errors.attr, 64743cb76d9SGreg Kroah-Hartman &dev_attr_rx_frame_errors.attr, 64843cb76d9SGreg Kroah-Hartman &dev_attr_rx_fifo_errors.attr, 64943cb76d9SGreg Kroah-Hartman &dev_attr_rx_missed_errors.attr, 65043cb76d9SGreg Kroah-Hartman &dev_attr_tx_aborted_errors.attr, 65143cb76d9SGreg Kroah-Hartman &dev_attr_tx_carrier_errors.attr, 65243cb76d9SGreg Kroah-Hartman &dev_attr_tx_fifo_errors.attr, 65343cb76d9SGreg Kroah-Hartman &dev_attr_tx_heartbeat_errors.attr, 65443cb76d9SGreg Kroah-Hartman &dev_attr_tx_window_errors.attr, 65543cb76d9SGreg Kroah-Hartman &dev_attr_rx_compressed.attr, 65643cb76d9SGreg Kroah-Hartman &dev_attr_tx_compressed.attr, 6576e7333d3SJarod Wilson &dev_attr_rx_nohandler.attr, 6581da177e4SLinus Torvalds NULL 6591da177e4SLinus Torvalds }; 6601da177e4SLinus Torvalds 66138ef00ccSArvind Yadav static const struct attribute_group netstat_group = { 6621da177e4SLinus Torvalds .name = "statistics", 6631da177e4SLinus Torvalds .attrs = netstat_attrs, 6641da177e4SLinus Torvalds }; 66538c1a01cSJohannes Berg 66638c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) 66738c1a01cSJohannes Berg static struct attribute *wireless_attrs[] = { 66838c1a01cSJohannes Berg NULL 66938c1a01cSJohannes Berg }; 67038c1a01cSJohannes Berg 67138ef00ccSArvind Yadav static const struct attribute_group wireless_group = { 67238c1a01cSJohannes Berg .name = "wireless", 67338c1a01cSJohannes Berg .attrs = wireless_attrs, 67438c1a01cSJohannes Berg }; 67538c1a01cSJohannes Berg #endif 6766be8aeefSGreg Kroah-Hartman 6776be8aeefSGreg Kroah-Hartman #else /* CONFIG_SYSFS */ 6786be8aeefSGreg Kroah-Hartman #define net_class_groups NULL 679d6523ddfSEric W. Biederman #endif /* CONFIG_SYSFS */ 6801da177e4SLinus Torvalds 681a953be53SMichael Dalton #ifdef CONFIG_SYSFS 6826648c65eSstephen hemminger #define to_rx_queue_attr(_attr) \ 6836648c65eSstephen hemminger container_of(_attr, struct rx_queue_attribute, attr) 6840a9627f2STom Herbert 6850a9627f2STom Herbert #define to_rx_queue(obj) container_of(obj, struct netdev_rx_queue, kobj) 6860a9627f2STom Herbert 6870a9627f2STom Herbert static ssize_t rx_queue_attr_show(struct kobject *kobj, struct attribute *attr, 6880a9627f2STom Herbert char *buf) 6890a9627f2STom Herbert { 690667e427bSstephen hemminger const struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 6910a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 6920a9627f2STom Herbert 6930a9627f2STom Herbert if (!attribute->show) 6940a9627f2STom Herbert return -EIO; 6950a9627f2STom Herbert 696718ad681Sstephen hemminger return attribute->show(queue, buf); 6970a9627f2STom Herbert } 6980a9627f2STom Herbert 6990a9627f2STom Herbert static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr, 7000a9627f2STom Herbert const char *buf, size_t count) 7010a9627f2STom Herbert { 702667e427bSstephen hemminger const struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 7030a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 7040a9627f2STom Herbert 7050a9627f2STom Herbert if (!attribute->store) 7060a9627f2STom Herbert return -EIO; 7070a9627f2STom Herbert 708718ad681Sstephen hemminger return attribute->store(queue, buf, count); 7090a9627f2STom Herbert } 7100a9627f2STom Herbert 711fa50d645Sstephen hemminger static const struct sysfs_ops rx_queue_sysfs_ops = { 7120a9627f2STom Herbert .show = rx_queue_attr_show, 7130a9627f2STom Herbert .store = rx_queue_attr_store, 7140a9627f2STom Herbert }; 7150a9627f2STom Herbert 716a953be53SMichael Dalton #ifdef CONFIG_RPS 717718ad681Sstephen hemminger static ssize_t show_rps_map(struct netdev_rx_queue *queue, char *buf) 7180a9627f2STom Herbert { 7190a9627f2STom Herbert struct rps_map *map; 7200a9627f2STom Herbert cpumask_var_t mask; 721f0906827STejun Heo int i, len; 7220a9627f2STom Herbert 7230a9627f2STom Herbert if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 7240a9627f2STom Herbert return -ENOMEM; 7250a9627f2STom Herbert 7260a9627f2STom Herbert rcu_read_lock(); 7270a9627f2STom Herbert map = rcu_dereference(queue->rps_map); 7280a9627f2STom Herbert if (map) 7290a9627f2STom Herbert for (i = 0; i < map->len; i++) 7300a9627f2STom Herbert cpumask_set_cpu(map->cpus[i], mask); 7310a9627f2STom Herbert 732f0906827STejun Heo len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask)); 7330a9627f2STom Herbert rcu_read_unlock(); 7340a9627f2STom Herbert free_cpumask_var(mask); 7350a9627f2STom Herbert 736f0906827STejun Heo return len < PAGE_SIZE ? len : -EINVAL; 7370a9627f2STom Herbert } 7380a9627f2STom Herbert 739f5acb907SEric Dumazet static ssize_t store_rps_map(struct netdev_rx_queue *queue, 7400a9627f2STom Herbert const char *buf, size_t len) 7410a9627f2STom Herbert { 7420a9627f2STom Herbert struct rps_map *old_map, *map; 7430a9627f2STom Herbert cpumask_var_t mask; 7440a9627f2STom Herbert int err, cpu, i; 745da65ad1fSSasha Levin static DEFINE_MUTEX(rps_map_mutex); 7460a9627f2STom Herbert 7470a9627f2STom Herbert if (!capable(CAP_NET_ADMIN)) 7480a9627f2STom Herbert return -EPERM; 7490a9627f2STom Herbert 7500a9627f2STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 7510a9627f2STom Herbert return -ENOMEM; 7520a9627f2STom Herbert 7530a9627f2STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 7540a9627f2STom Herbert if (err) { 7550a9627f2STom Herbert free_cpumask_var(mask); 7560a9627f2STom Herbert return err; 7570a9627f2STom Herbert } 7580a9627f2STom Herbert 75995c96174SEric Dumazet map = kzalloc(max_t(unsigned int, 7600a9627f2STom Herbert RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), 7610a9627f2STom Herbert GFP_KERNEL); 7620a9627f2STom Herbert if (!map) { 7630a9627f2STom Herbert free_cpumask_var(mask); 7640a9627f2STom Herbert return -ENOMEM; 7650a9627f2STom Herbert } 7660a9627f2STom Herbert 7670a9627f2STom Herbert i = 0; 7680a9627f2STom Herbert for_each_cpu_and(cpu, mask, cpu_online_mask) 7690a9627f2STom Herbert map->cpus[i++] = cpu; 7700a9627f2STom Herbert 7716648c65eSstephen hemminger if (i) { 7720a9627f2STom Herbert map->len = i; 7736648c65eSstephen hemminger } else { 7740a9627f2STom Herbert kfree(map); 7750a9627f2STom Herbert map = NULL; 7760a9627f2STom Herbert } 7770a9627f2STom Herbert 778da65ad1fSSasha Levin mutex_lock(&rps_map_mutex); 7796e3f7fafSEric Dumazet old_map = rcu_dereference_protected(queue->rps_map, 780da65ad1fSSasha Levin mutex_is_locked(&rps_map_mutex)); 7810a9627f2STom Herbert rcu_assign_pointer(queue->rps_map, map); 7820a9627f2STom Herbert 783adc9300eSEric Dumazet if (map) 784dc05360fSEric Dumazet static_branch_inc(&rps_needed); 78510e4ea75STom Herbert if (old_map) 786dc05360fSEric Dumazet static_branch_dec(&rps_needed); 78710e4ea75STom Herbert 788da65ad1fSSasha Levin mutex_unlock(&rps_map_mutex); 78910e4ea75STom Herbert 79010e4ea75STom Herbert if (old_map) 79110e4ea75STom Herbert kfree_rcu(old_map, rcu); 79210e4ea75STom Herbert 7930a9627f2STom Herbert free_cpumask_var(mask); 7940a9627f2STom Herbert return len; 7950a9627f2STom Herbert } 7960a9627f2STom Herbert 797fec5e652STom Herbert static ssize_t show_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 798fec5e652STom Herbert char *buf) 799fec5e652STom Herbert { 800fec5e652STom Herbert struct rps_dev_flow_table *flow_table; 80160b778ceSEric Dumazet unsigned long val = 0; 802fec5e652STom Herbert 803fec5e652STom Herbert rcu_read_lock(); 804fec5e652STom Herbert flow_table = rcu_dereference(queue->rps_flow_table); 805fec5e652STom Herbert if (flow_table) 80660b778ceSEric Dumazet val = (unsigned long)flow_table->mask + 1; 807fec5e652STom Herbert rcu_read_unlock(); 808fec5e652STom Herbert 80960b778ceSEric Dumazet return sprintf(buf, "%lu\n", val); 810fec5e652STom Herbert } 811fec5e652STom Herbert 812fec5e652STom Herbert static void rps_dev_flow_table_release(struct rcu_head *rcu) 813fec5e652STom Herbert { 814fec5e652STom Herbert struct rps_dev_flow_table *table = container_of(rcu, 815fec5e652STom Herbert struct rps_dev_flow_table, rcu); 816243198d0SAl Viro vfree(table); 817fec5e652STom Herbert } 818fec5e652STom Herbert 819f5acb907SEric Dumazet static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 820fec5e652STom Herbert const char *buf, size_t len) 821fec5e652STom Herbert { 82260b778ceSEric Dumazet unsigned long mask, count; 823fec5e652STom Herbert struct rps_dev_flow_table *table, *old_table; 824fec5e652STom Herbert static DEFINE_SPINLOCK(rps_dev_flow_lock); 82560b778ceSEric Dumazet int rc; 826fec5e652STom Herbert 827fec5e652STom Herbert if (!capable(CAP_NET_ADMIN)) 828fec5e652STom Herbert return -EPERM; 829fec5e652STom Herbert 83060b778ceSEric Dumazet rc = kstrtoul(buf, 0, &count); 83160b778ceSEric Dumazet if (rc < 0) 83260b778ceSEric Dumazet return rc; 833fec5e652STom Herbert 834fec5e652STom Herbert if (count) { 83560b778ceSEric Dumazet mask = count - 1; 83660b778ceSEric Dumazet /* mask = roundup_pow_of_two(count) - 1; 83760b778ceSEric Dumazet * without overflows... 83860b778ceSEric Dumazet */ 83960b778ceSEric Dumazet while ((mask | (mask >> 1)) != mask) 84060b778ceSEric Dumazet mask |= (mask >> 1); 84160b778ceSEric Dumazet /* On 64 bit arches, must check mask fits in table->mask (u32), 8428e3bff96Sstephen hemminger * and on 32bit arches, must check 8438e3bff96Sstephen hemminger * RPS_DEV_FLOW_TABLE_SIZE(mask + 1) doesn't overflow. 84460b778ceSEric Dumazet */ 84560b778ceSEric Dumazet #if BITS_PER_LONG > 32 84660b778ceSEric Dumazet if (mask > (unsigned long)(u32)mask) 847a0a129f8SXi Wang return -EINVAL; 84860b778ceSEric Dumazet #else 84960b778ceSEric Dumazet if (mask > (ULONG_MAX - RPS_DEV_FLOW_TABLE_SIZE(1)) 850a0a129f8SXi Wang / sizeof(struct rps_dev_flow)) { 851fec5e652STom Herbert /* Enforce a limit to prevent overflow */ 852fec5e652STom Herbert return -EINVAL; 853fec5e652STom Herbert } 85460b778ceSEric Dumazet #endif 85560b778ceSEric Dumazet table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(mask + 1)); 856fec5e652STom Herbert if (!table) 857fec5e652STom Herbert return -ENOMEM; 858fec5e652STom Herbert 85960b778ceSEric Dumazet table->mask = mask; 86060b778ceSEric Dumazet for (count = 0; count <= mask; count++) 86160b778ceSEric Dumazet table->flows[count].cpu = RPS_NO_CPU; 8626648c65eSstephen hemminger } else { 863fec5e652STom Herbert table = NULL; 8646648c65eSstephen hemminger } 865fec5e652STom Herbert 866fec5e652STom Herbert spin_lock(&rps_dev_flow_lock); 8676e3f7fafSEric Dumazet old_table = rcu_dereference_protected(queue->rps_flow_table, 8686e3f7fafSEric Dumazet lockdep_is_held(&rps_dev_flow_lock)); 869fec5e652STom Herbert rcu_assign_pointer(queue->rps_flow_table, table); 870fec5e652STom Herbert spin_unlock(&rps_dev_flow_lock); 871fec5e652STom Herbert 872fec5e652STom Herbert if (old_table) 873fec5e652STom Herbert call_rcu(&old_table->rcu, rps_dev_flow_table_release); 874fec5e652STom Herbert 875fec5e652STom Herbert return len; 876fec5e652STom Herbert } 877fec5e652STom Herbert 878667e427bSstephen hemminger static struct rx_queue_attribute rps_cpus_attribute __ro_after_init 879d6444062SJoe Perches = __ATTR(rps_cpus, 0644, show_rps_map, store_rps_map); 8800a9627f2STom Herbert 881667e427bSstephen hemminger static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute __ro_after_init 882d6444062SJoe Perches = __ATTR(rps_flow_cnt, 0644, 883fec5e652STom Herbert show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt); 884a953be53SMichael Dalton #endif /* CONFIG_RPS */ 885fec5e652STom Herbert 886667e427bSstephen hemminger static struct attribute *rx_queue_default_attrs[] __ro_after_init = { 887a953be53SMichael Dalton #ifdef CONFIG_RPS 8880a9627f2STom Herbert &rps_cpus_attribute.attr, 889fec5e652STom Herbert &rps_dev_flow_table_cnt_attribute.attr, 890a953be53SMichael Dalton #endif 8910a9627f2STom Herbert NULL 8920a9627f2STom Herbert }; 893be0d6926SKimberly Brown ATTRIBUTE_GROUPS(rx_queue_default); 8940a9627f2STom Herbert 8950a9627f2STom Herbert static void rx_queue_release(struct kobject *kobj) 8960a9627f2STom Herbert { 8970a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 898a953be53SMichael Dalton #ifdef CONFIG_RPS 8996e3f7fafSEric Dumazet struct rps_map *map; 9006e3f7fafSEric Dumazet struct rps_dev_flow_table *flow_table; 9010a9627f2STom Herbert 90233d480ceSEric Dumazet map = rcu_dereference_protected(queue->rps_map, 1); 9039ea19481SJohn Fastabend if (map) { 9049ea19481SJohn Fastabend RCU_INIT_POINTER(queue->rps_map, NULL); 905f6f80238SLai Jiangshan kfree_rcu(map, rcu); 9069ea19481SJohn Fastabend } 9076e3f7fafSEric Dumazet 90833d480ceSEric Dumazet flow_table = rcu_dereference_protected(queue->rps_flow_table, 1); 9099ea19481SJohn Fastabend if (flow_table) { 9109ea19481SJohn Fastabend RCU_INIT_POINTER(queue->rps_flow_table, NULL); 9116e3f7fafSEric Dumazet call_rcu(&flow_table->rcu, rps_dev_flow_table_release); 9129ea19481SJohn Fastabend } 913a953be53SMichael Dalton #endif 9140a9627f2STom Herbert 9159ea19481SJohn Fastabend memset(kobj, 0, sizeof(*kobj)); 916fe822240STom Herbert dev_put(queue->dev); 9170a9627f2STom Herbert } 9180a9627f2STom Herbert 91982ef3d5dSWeilong Chen static const void *rx_queue_namespace(struct kobject *kobj) 92082ef3d5dSWeilong Chen { 92182ef3d5dSWeilong Chen struct netdev_rx_queue *queue = to_rx_queue(kobj); 92282ef3d5dSWeilong Chen struct device *dev = &queue->dev->dev; 92382ef3d5dSWeilong Chen const void *ns = NULL; 92482ef3d5dSWeilong Chen 92582ef3d5dSWeilong Chen if (dev->class && dev->class->ns_type) 92682ef3d5dSWeilong Chen ns = dev->class->namespace(dev); 92782ef3d5dSWeilong Chen 92882ef3d5dSWeilong Chen return ns; 92982ef3d5dSWeilong Chen } 93082ef3d5dSWeilong Chen 931b0e37c0dSDmitry Torokhov static void rx_queue_get_ownership(struct kobject *kobj, 932b0e37c0dSDmitry Torokhov kuid_t *uid, kgid_t *gid) 933b0e37c0dSDmitry Torokhov { 934b0e37c0dSDmitry Torokhov const struct net *net = rx_queue_namespace(kobj); 935b0e37c0dSDmitry Torokhov 936b0e37c0dSDmitry Torokhov net_ns_get_ownership(net, uid, gid); 937b0e37c0dSDmitry Torokhov } 938b0e37c0dSDmitry Torokhov 939667e427bSstephen hemminger static struct kobj_type rx_queue_ktype __ro_after_init = { 9400a9627f2STom Herbert .sysfs_ops = &rx_queue_sysfs_ops, 9410a9627f2STom Herbert .release = rx_queue_release, 942be0d6926SKimberly Brown .default_groups = rx_queue_default_groups, 943b0e37c0dSDmitry Torokhov .namespace = rx_queue_namespace, 944b0e37c0dSDmitry Torokhov .get_ownership = rx_queue_get_ownership, 9450a9627f2STom Herbert }; 9460a9627f2STom Herbert 9476b53dafeSWANG Cong static int rx_queue_add_kobject(struct net_device *dev, int index) 9480a9627f2STom Herbert { 9496b53dafeSWANG Cong struct netdev_rx_queue *queue = dev->_rx + index; 9500a9627f2STom Herbert struct kobject *kobj = &queue->kobj; 9510a9627f2STom Herbert int error = 0; 9520a9627f2STom Herbert 953ddd9b5e3SJouni Hogander /* Kobject_put later will trigger rx_queue_release call which 954ddd9b5e3SJouni Hogander * decreases dev refcount: Take that reference here 955ddd9b5e3SJouni Hogander */ 956ddd9b5e3SJouni Hogander dev_hold(queue->dev); 957ddd9b5e3SJouni Hogander 9586b53dafeSWANG Cong kobj->kset = dev->queues_kset; 9590a9627f2STom Herbert error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, 9600a9627f2STom Herbert "rx-%u", index); 961a953be53SMichael Dalton if (error) 962b8eb7183SJouni Hogander goto err; 963a953be53SMichael Dalton 9646b53dafeSWANG Cong if (dev->sysfs_rx_queue_group) { 9656b53dafeSWANG Cong error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); 966b8eb7183SJouni Hogander if (error) 967b8eb7183SJouni Hogander goto err; 9680a9627f2STom Herbert } 9690a9627f2STom Herbert 9700a9627f2STom Herbert kobject_uevent(kobj, KOBJ_ADD); 9710a9627f2STom Herbert 9720a9627f2STom Herbert return error; 973b8eb7183SJouni Hogander 974b8eb7183SJouni Hogander err: 975b8eb7183SJouni Hogander kobject_put(kobj); 976b8eb7183SJouni Hogander return error; 9770a9627f2STom Herbert } 978d755407dSChristian Brauner 979d755407dSChristian Brauner static int rx_queue_change_owner(struct net_device *dev, int index, kuid_t kuid, 980d755407dSChristian Brauner kgid_t kgid) 981d755407dSChristian Brauner { 982d755407dSChristian Brauner struct netdev_rx_queue *queue = dev->_rx + index; 983d755407dSChristian Brauner struct kobject *kobj = &queue->kobj; 984d755407dSChristian Brauner int error; 985d755407dSChristian Brauner 986d755407dSChristian Brauner error = sysfs_change_owner(kobj, kuid, kgid); 987d755407dSChristian Brauner if (error) 988d755407dSChristian Brauner return error; 989d755407dSChristian Brauner 990d755407dSChristian Brauner if (dev->sysfs_rx_queue_group) 991d755407dSChristian Brauner error = sysfs_group_change_owner( 992d755407dSChristian Brauner kobj, dev->sysfs_rx_queue_group, kuid, kgid); 993d755407dSChristian Brauner 994d755407dSChristian Brauner return error; 995d755407dSChristian Brauner } 99680dd6eacSPaul Bolle #endif /* CONFIG_SYSFS */ 9970a9627f2STom Herbert 99862fe0b40SBen Hutchings int 9996b53dafeSWANG Cong net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) 10000a9627f2STom Herbert { 1001a953be53SMichael Dalton #ifdef CONFIG_SYSFS 10020a9627f2STom Herbert int i; 10030a9627f2STom Herbert int error = 0; 10040a9627f2STom Herbert 1005a953be53SMichael Dalton #ifndef CONFIG_RPS 10066b53dafeSWANG Cong if (!dev->sysfs_rx_queue_group) 1007a953be53SMichael Dalton return 0; 1008a953be53SMichael Dalton #endif 100962fe0b40SBen Hutchings for (i = old_num; i < new_num; i++) { 10106b53dafeSWANG Cong error = rx_queue_add_kobject(dev, i); 101162fe0b40SBen Hutchings if (error) { 101262fe0b40SBen Hutchings new_num = old_num; 10130a9627f2STom Herbert break; 10140a9627f2STom Herbert } 101562fe0b40SBen Hutchings } 10160a9627f2STom Herbert 1017a953be53SMichael Dalton while (--i >= new_num) { 1018002d8a1aSAndrey Vagin struct kobject *kobj = &dev->_rx[i].kobj; 1019002d8a1aSAndrey Vagin 1020273c28bcSKirill Tkhai if (!refcount_read(&dev_net(dev)->count)) 1021002d8a1aSAndrey Vagin kobj->uevent_suppress = 1; 10226b53dafeSWANG Cong if (dev->sysfs_rx_queue_group) 1023002d8a1aSAndrey Vagin sysfs_remove_group(kobj, dev->sysfs_rx_queue_group); 1024002d8a1aSAndrey Vagin kobject_put(kobj); 1025a953be53SMichael Dalton } 10260a9627f2STom Herbert 10270a9627f2STom Herbert return error; 1028bf264145STom Herbert #else 1029bf264145STom Herbert return 0; 1030bf264145STom Herbert #endif 10310a9627f2STom Herbert } 10320a9627f2STom Herbert 1033d755407dSChristian Brauner static int net_rx_queue_change_owner(struct net_device *dev, int num, 1034d755407dSChristian Brauner kuid_t kuid, kgid_t kgid) 1035d755407dSChristian Brauner { 1036d755407dSChristian Brauner #ifdef CONFIG_SYSFS 1037d755407dSChristian Brauner int error = 0; 1038d755407dSChristian Brauner int i; 1039d755407dSChristian Brauner 1040d755407dSChristian Brauner #ifndef CONFIG_RPS 1041d755407dSChristian Brauner if (!dev->sysfs_rx_queue_group) 1042d755407dSChristian Brauner return 0; 1043d755407dSChristian Brauner #endif 1044d755407dSChristian Brauner for (i = 0; i < num; i++) { 1045d755407dSChristian Brauner error = rx_queue_change_owner(dev, i, kuid, kgid); 1046d755407dSChristian Brauner if (error) 1047d755407dSChristian Brauner break; 1048d755407dSChristian Brauner } 1049d755407dSChristian Brauner 1050d755407dSChristian Brauner return error; 1051d755407dSChristian Brauner #else 1052d755407dSChristian Brauner return 0; 1053d755407dSChristian Brauner #endif 1054d755407dSChristian Brauner } 1055d755407dSChristian Brauner 1056ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 10571d24eb48STom Herbert /* 10581d24eb48STom Herbert * netdev_queue sysfs structures and functions. 10591d24eb48STom Herbert */ 10601d24eb48STom Herbert struct netdev_queue_attribute { 10611d24eb48STom Herbert struct attribute attr; 1062718ad681Sstephen hemminger ssize_t (*show)(struct netdev_queue *queue, char *buf); 10631d24eb48STom Herbert ssize_t (*store)(struct netdev_queue *queue, 1064718ad681Sstephen hemminger const char *buf, size_t len); 10651d24eb48STom Herbert }; 10666648c65eSstephen hemminger #define to_netdev_queue_attr(_attr) \ 10676648c65eSstephen hemminger container_of(_attr, struct netdev_queue_attribute, attr) 10681d24eb48STom Herbert 10691d24eb48STom Herbert #define to_netdev_queue(obj) container_of(obj, struct netdev_queue, kobj) 10701d24eb48STom Herbert 10711d24eb48STom Herbert static ssize_t netdev_queue_attr_show(struct kobject *kobj, 10721d24eb48STom Herbert struct attribute *attr, char *buf) 107362fe0b40SBen Hutchings { 1074667e427bSstephen hemminger const struct netdev_queue_attribute *attribute 1075667e427bSstephen hemminger = to_netdev_queue_attr(attr); 10761d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 10771d24eb48STom Herbert 10781d24eb48STom Herbert if (!attribute->show) 10791d24eb48STom Herbert return -EIO; 10801d24eb48STom Herbert 1081718ad681Sstephen hemminger return attribute->show(queue, buf); 10821d24eb48STom Herbert } 10831d24eb48STom Herbert 10841d24eb48STom Herbert static ssize_t netdev_queue_attr_store(struct kobject *kobj, 10851d24eb48STom Herbert struct attribute *attr, 10861d24eb48STom Herbert const char *buf, size_t count) 10871d24eb48STom Herbert { 1088667e427bSstephen hemminger const struct netdev_queue_attribute *attribute 1089667e427bSstephen hemminger = to_netdev_queue_attr(attr); 10901d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 10911d24eb48STom Herbert 10921d24eb48STom Herbert if (!attribute->store) 10931d24eb48STom Herbert return -EIO; 10941d24eb48STom Herbert 1095718ad681Sstephen hemminger return attribute->store(queue, buf, count); 10961d24eb48STom Herbert } 10971d24eb48STom Herbert 10981d24eb48STom Herbert static const struct sysfs_ops netdev_queue_sysfs_ops = { 10991d24eb48STom Herbert .show = netdev_queue_attr_show, 11001d24eb48STom Herbert .store = netdev_queue_attr_store, 11011d24eb48STom Herbert }; 11021d24eb48STom Herbert 11032b9c7581Sstephen hemminger static ssize_t tx_timeout_show(struct netdev_queue *queue, char *buf) 1104ccf5ff69Sdavid decotigny { 1105ccf5ff69Sdavid decotigny unsigned long trans_timeout; 1106ccf5ff69Sdavid decotigny 1107ccf5ff69Sdavid decotigny spin_lock_irq(&queue->_xmit_lock); 1108ccf5ff69Sdavid decotigny trans_timeout = queue->trans_timeout; 1109ccf5ff69Sdavid decotigny spin_unlock_irq(&queue->_xmit_lock); 1110ccf5ff69Sdavid decotigny 1111ccf5ff69Sdavid decotigny return sprintf(buf, "%lu", trans_timeout); 1112ccf5ff69Sdavid decotigny } 1113ccf5ff69Sdavid decotigny 1114c4047f53SThadeu Lima de Souza Cascardo static unsigned int get_netdev_queue_index(struct netdev_queue *queue) 1115822b3b2eSJohn Fastabend { 1116822b3b2eSJohn Fastabend struct net_device *dev = queue->dev; 1117c4047f53SThadeu Lima de Souza Cascardo unsigned int i; 1118822b3b2eSJohn Fastabend 1119c4047f53SThadeu Lima de Souza Cascardo i = queue - dev->_tx; 1120822b3b2eSJohn Fastabend BUG_ON(i >= dev->num_tx_queues); 1121822b3b2eSJohn Fastabend 1122822b3b2eSJohn Fastabend return i; 1123822b3b2eSJohn Fastabend } 1124822b3b2eSJohn Fastabend 11252b9c7581Sstephen hemminger static ssize_t traffic_class_show(struct netdev_queue *queue, 11268d059b0fSAlexander Duyck char *buf) 11278d059b0fSAlexander Duyck { 11288d059b0fSAlexander Duyck struct net_device *dev = queue->dev; 1129d7be9775SAlexander Duyck int index; 1130d7be9775SAlexander Duyck int tc; 11318d059b0fSAlexander Duyck 1132d7be9775SAlexander Duyck if (!netif_is_multiqueue(dev)) 1133d7be9775SAlexander Duyck return -ENOENT; 1134d7be9775SAlexander Duyck 1135d7be9775SAlexander Duyck index = get_netdev_queue_index(queue); 1136ffcfe25bSAlexander Duyck 1137ffcfe25bSAlexander Duyck /* If queue belongs to subordinate dev use its TC mapping */ 1138ffcfe25bSAlexander Duyck dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev; 1139ffcfe25bSAlexander Duyck 1140d7be9775SAlexander Duyck tc = netdev_txq_to_tc(dev, index); 11418d059b0fSAlexander Duyck if (tc < 0) 11428d059b0fSAlexander Duyck return -EINVAL; 11438d059b0fSAlexander Duyck 1144ffcfe25bSAlexander Duyck /* We can report the traffic class one of two ways: 1145ffcfe25bSAlexander Duyck * Subordinate device traffic classes are reported with the traffic 1146ffcfe25bSAlexander Duyck * class first, and then the subordinate class so for example TC0 on 1147ffcfe25bSAlexander Duyck * subordinate device 2 will be reported as "0-2". If the queue 1148ffcfe25bSAlexander Duyck * belongs to the root device it will be reported with just the 1149ffcfe25bSAlexander Duyck * traffic class, so just "0" for TC 0 for example. 1150ffcfe25bSAlexander Duyck */ 1151ffcfe25bSAlexander Duyck return dev->num_tc < 0 ? sprintf(buf, "%u%d\n", tc, dev->num_tc) : 1152ffcfe25bSAlexander Duyck sprintf(buf, "%u\n", tc); 11538d059b0fSAlexander Duyck } 11548d059b0fSAlexander Duyck 11558d059b0fSAlexander Duyck #ifdef CONFIG_XPS 11562b9c7581Sstephen hemminger static ssize_t tx_maxrate_show(struct netdev_queue *queue, 1157822b3b2eSJohn Fastabend char *buf) 1158822b3b2eSJohn Fastabend { 1159822b3b2eSJohn Fastabend return sprintf(buf, "%lu\n", queue->tx_maxrate); 1160822b3b2eSJohn Fastabend } 1161822b3b2eSJohn Fastabend 11622b9c7581Sstephen hemminger static ssize_t tx_maxrate_store(struct netdev_queue *queue, 1163822b3b2eSJohn Fastabend const char *buf, size_t len) 1164822b3b2eSJohn Fastabend { 1165822b3b2eSJohn Fastabend struct net_device *dev = queue->dev; 1166822b3b2eSJohn Fastabend int err, index = get_netdev_queue_index(queue); 1167822b3b2eSJohn Fastabend u32 rate = 0; 1168822b3b2eSJohn Fastabend 11693033fcedSTyler Hicks if (!capable(CAP_NET_ADMIN)) 11703033fcedSTyler Hicks return -EPERM; 11713033fcedSTyler Hicks 1172822b3b2eSJohn Fastabend err = kstrtou32(buf, 10, &rate); 1173822b3b2eSJohn Fastabend if (err < 0) 1174822b3b2eSJohn Fastabend return err; 1175822b3b2eSJohn Fastabend 1176822b3b2eSJohn Fastabend if (!rtnl_trylock()) 1177822b3b2eSJohn Fastabend return restart_syscall(); 1178822b3b2eSJohn Fastabend 1179822b3b2eSJohn Fastabend err = -EOPNOTSUPP; 1180822b3b2eSJohn Fastabend if (dev->netdev_ops->ndo_set_tx_maxrate) 1181822b3b2eSJohn Fastabend err = dev->netdev_ops->ndo_set_tx_maxrate(dev, index, rate); 1182822b3b2eSJohn Fastabend 1183822b3b2eSJohn Fastabend rtnl_unlock(); 1184822b3b2eSJohn Fastabend if (!err) { 1185822b3b2eSJohn Fastabend queue->tx_maxrate = rate; 1186822b3b2eSJohn Fastabend return len; 1187822b3b2eSJohn Fastabend } 1188822b3b2eSJohn Fastabend return err; 1189822b3b2eSJohn Fastabend } 1190822b3b2eSJohn Fastabend 11912b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_tx_maxrate __ro_after_init 11922b9c7581Sstephen hemminger = __ATTR_RW(tx_maxrate); 1193822b3b2eSJohn Fastabend #endif 1194822b3b2eSJohn Fastabend 11952b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_trans_timeout __ro_after_init 11962b9c7581Sstephen hemminger = __ATTR_RO(tx_timeout); 1197ccf5ff69Sdavid decotigny 11982b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_traffic_class __ro_after_init 11992b9c7581Sstephen hemminger = __ATTR_RO(traffic_class); 12008d059b0fSAlexander Duyck 1201114cf580STom Herbert #ifdef CONFIG_BQL 1202114cf580STom Herbert /* 1203114cf580STom Herbert * Byte queue limits sysfs structures and functions. 1204114cf580STom Herbert */ 1205114cf580STom Herbert static ssize_t bql_show(char *buf, unsigned int value) 1206114cf580STom Herbert { 1207114cf580STom Herbert return sprintf(buf, "%u\n", value); 1208114cf580STom Herbert } 1209114cf580STom Herbert 1210114cf580STom Herbert static ssize_t bql_set(const char *buf, const size_t count, 1211114cf580STom Herbert unsigned int *pvalue) 1212114cf580STom Herbert { 1213114cf580STom Herbert unsigned int value; 1214114cf580STom Herbert int err; 1215114cf580STom Herbert 12166648c65eSstephen hemminger if (!strcmp(buf, "max") || !strcmp(buf, "max\n")) { 1217114cf580STom Herbert value = DQL_MAX_LIMIT; 12186648c65eSstephen hemminger } else { 1219114cf580STom Herbert err = kstrtouint(buf, 10, &value); 1220114cf580STom Herbert if (err < 0) 1221114cf580STom Herbert return err; 1222114cf580STom Herbert if (value > DQL_MAX_LIMIT) 1223114cf580STom Herbert return -EINVAL; 1224114cf580STom Herbert } 1225114cf580STom Herbert 1226114cf580STom Herbert *pvalue = value; 1227114cf580STom Herbert 1228114cf580STom Herbert return count; 1229114cf580STom Herbert } 1230114cf580STom Herbert 1231114cf580STom Herbert static ssize_t bql_show_hold_time(struct netdev_queue *queue, 1232114cf580STom Herbert char *buf) 1233114cf580STom Herbert { 1234114cf580STom Herbert struct dql *dql = &queue->dql; 1235114cf580STom Herbert 1236114cf580STom Herbert return sprintf(buf, "%u\n", jiffies_to_msecs(dql->slack_hold_time)); 1237114cf580STom Herbert } 1238114cf580STom Herbert 1239114cf580STom Herbert static ssize_t bql_set_hold_time(struct netdev_queue *queue, 1240114cf580STom Herbert const char *buf, size_t len) 1241114cf580STom Herbert { 1242114cf580STom Herbert struct dql *dql = &queue->dql; 124395c96174SEric Dumazet unsigned int value; 1244114cf580STom Herbert int err; 1245114cf580STom Herbert 1246114cf580STom Herbert err = kstrtouint(buf, 10, &value); 1247114cf580STom Herbert if (err < 0) 1248114cf580STom Herbert return err; 1249114cf580STom Herbert 1250114cf580STom Herbert dql->slack_hold_time = msecs_to_jiffies(value); 1251114cf580STom Herbert 1252114cf580STom Herbert return len; 1253114cf580STom Herbert } 1254114cf580STom Herbert 1255170c658aSstephen hemminger static struct netdev_queue_attribute bql_hold_time_attribute __ro_after_init 1256d6444062SJoe Perches = __ATTR(hold_time, 0644, 1257170c658aSstephen hemminger bql_show_hold_time, bql_set_hold_time); 1258114cf580STom Herbert 1259114cf580STom Herbert static ssize_t bql_show_inflight(struct netdev_queue *queue, 1260114cf580STom Herbert char *buf) 1261114cf580STom Herbert { 1262114cf580STom Herbert struct dql *dql = &queue->dql; 1263114cf580STom Herbert 1264114cf580STom Herbert return sprintf(buf, "%u\n", dql->num_queued - dql->num_completed); 1265114cf580STom Herbert } 1266114cf580STom Herbert 1267170c658aSstephen hemminger static struct netdev_queue_attribute bql_inflight_attribute __ro_after_init = 1268d6444062SJoe Perches __ATTR(inflight, 0444, bql_show_inflight, NULL); 1269114cf580STom Herbert 1270114cf580STom Herbert #define BQL_ATTR(NAME, FIELD) \ 1271114cf580STom Herbert static ssize_t bql_show_ ## NAME(struct netdev_queue *queue, \ 1272114cf580STom Herbert char *buf) \ 1273114cf580STom Herbert { \ 1274114cf580STom Herbert return bql_show(buf, queue->dql.FIELD); \ 1275114cf580STom Herbert } \ 1276114cf580STom Herbert \ 1277114cf580STom Herbert static ssize_t bql_set_ ## NAME(struct netdev_queue *queue, \ 1278114cf580STom Herbert const char *buf, size_t len) \ 1279114cf580STom Herbert { \ 1280114cf580STom Herbert return bql_set(buf, len, &queue->dql.FIELD); \ 1281114cf580STom Herbert } \ 1282114cf580STom Herbert \ 1283170c658aSstephen hemminger static struct netdev_queue_attribute bql_ ## NAME ## _attribute __ro_after_init \ 1284d6444062SJoe Perches = __ATTR(NAME, 0644, \ 1285170c658aSstephen hemminger bql_show_ ## NAME, bql_set_ ## NAME) 1286114cf580STom Herbert 1287170c658aSstephen hemminger BQL_ATTR(limit, limit); 1288170c658aSstephen hemminger BQL_ATTR(limit_max, max_limit); 1289170c658aSstephen hemminger BQL_ATTR(limit_min, min_limit); 1290114cf580STom Herbert 1291170c658aSstephen hemminger static struct attribute *dql_attrs[] __ro_after_init = { 1292114cf580STom Herbert &bql_limit_attribute.attr, 1293114cf580STom Herbert &bql_limit_max_attribute.attr, 1294114cf580STom Herbert &bql_limit_min_attribute.attr, 1295114cf580STom Herbert &bql_hold_time_attribute.attr, 1296114cf580STom Herbert &bql_inflight_attribute.attr, 1297114cf580STom Herbert NULL 1298114cf580STom Herbert }; 1299114cf580STom Herbert 130038ef00ccSArvind Yadav static const struct attribute_group dql_group = { 1301114cf580STom Herbert .name = "byte_queue_limits", 1302114cf580STom Herbert .attrs = dql_attrs, 1303114cf580STom Herbert }; 1304114cf580STom Herbert #endif /* CONFIG_BQL */ 1305114cf580STom Herbert 1306ccf5ff69Sdavid decotigny #ifdef CONFIG_XPS 13072b9c7581Sstephen hemminger static ssize_t xps_cpus_show(struct netdev_queue *queue, 1308718ad681Sstephen hemminger char *buf) 13091d24eb48STom Herbert { 13101d24eb48STom Herbert struct net_device *dev = queue->dev; 1311184c449fSAlexander Duyck int cpu, len, num_tc = 1, tc = 0; 13121d24eb48STom Herbert struct xps_dev_maps *dev_maps; 13131d24eb48STom Herbert cpumask_var_t mask; 13141d24eb48STom Herbert unsigned long index; 13151d24eb48STom Herbert 1316d7be9775SAlexander Duyck if (!netif_is_multiqueue(dev)) 1317d7be9775SAlexander Duyck return -ENOENT; 1318d7be9775SAlexander Duyck 13191d24eb48STom Herbert index = get_netdev_queue_index(queue); 13201d24eb48STom Herbert 1321184c449fSAlexander Duyck if (dev->num_tc) { 1322ffcfe25bSAlexander Duyck /* Do not allow XPS on subordinate device directly */ 1323184c449fSAlexander Duyck num_tc = dev->num_tc; 1324ffcfe25bSAlexander Duyck if (num_tc < 0) 1325ffcfe25bSAlexander Duyck return -EINVAL; 1326ffcfe25bSAlexander Duyck 1327ffcfe25bSAlexander Duyck /* If queue belongs to subordinate dev use its map */ 1328ffcfe25bSAlexander Duyck dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev; 1329ffcfe25bSAlexander Duyck 1330184c449fSAlexander Duyck tc = netdev_txq_to_tc(dev, index); 1331184c449fSAlexander Duyck if (tc < 0) 1332184c449fSAlexander Duyck return -EINVAL; 1333184c449fSAlexander Duyck } 1334184c449fSAlexander Duyck 1335664088f8SAlexander Duyck if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 1336664088f8SAlexander Duyck return -ENOMEM; 1337664088f8SAlexander Duyck 13381d24eb48STom Herbert rcu_read_lock(); 133980d19669SAmritha Nambiar dev_maps = rcu_dereference(dev->xps_cpus_map); 13401d24eb48STom Herbert if (dev_maps) { 1341184c449fSAlexander Duyck for_each_possible_cpu(cpu) { 1342184c449fSAlexander Duyck int i, tci = cpu * num_tc + tc; 1343184c449fSAlexander Duyck struct xps_map *map; 1344184c449fSAlexander Duyck 134580d19669SAmritha Nambiar map = rcu_dereference(dev_maps->attr_map[tci]); 1346184c449fSAlexander Duyck if (!map) 1347184c449fSAlexander Duyck continue; 1348184c449fSAlexander Duyck 1349184c449fSAlexander Duyck for (i = map->len; i--;) { 1350184c449fSAlexander Duyck if (map->queues[i] == index) { 1351184c449fSAlexander Duyck cpumask_set_cpu(cpu, mask); 13521d24eb48STom Herbert break; 13531d24eb48STom Herbert } 13541d24eb48STom Herbert } 13551d24eb48STom Herbert } 13561d24eb48STom Herbert } 13571d24eb48STom Herbert rcu_read_unlock(); 13581d24eb48STom Herbert 1359f0906827STejun Heo len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask)); 13601d24eb48STom Herbert free_cpumask_var(mask); 1361f0906827STejun Heo return len < PAGE_SIZE ? len : -EINVAL; 13621d24eb48STom Herbert } 13631d24eb48STom Herbert 13642b9c7581Sstephen hemminger static ssize_t xps_cpus_store(struct netdev_queue *queue, 13651d24eb48STom Herbert const char *buf, size_t len) 13661d24eb48STom Herbert { 13671d24eb48STom Herbert struct net_device *dev = queue->dev; 13681d24eb48STom Herbert unsigned long index; 1369537c00deSAlexander Duyck cpumask_var_t mask; 1370537c00deSAlexander Duyck int err; 13711d24eb48STom Herbert 1372d7be9775SAlexander Duyck if (!netif_is_multiqueue(dev)) 1373d7be9775SAlexander Duyck return -ENOENT; 1374d7be9775SAlexander Duyck 13751d24eb48STom Herbert if (!capable(CAP_NET_ADMIN)) 13761d24eb48STom Herbert return -EPERM; 13771d24eb48STom Herbert 13781d24eb48STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 13791d24eb48STom Herbert return -ENOMEM; 13801d24eb48STom Herbert 13811d24eb48STom Herbert index = get_netdev_queue_index(queue); 13821d24eb48STom Herbert 13831d24eb48STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 13841d24eb48STom Herbert if (err) { 13851d24eb48STom Herbert free_cpumask_var(mask); 13861d24eb48STom Herbert return err; 13871d24eb48STom Herbert } 13881d24eb48STom Herbert 1389537c00deSAlexander Duyck err = netif_set_xps_queue(dev, mask, index); 13901d24eb48STom Herbert 13911d24eb48STom Herbert free_cpumask_var(mask); 13921d24eb48STom Herbert 1393537c00deSAlexander Duyck return err ? : len; 13941d24eb48STom Herbert } 13951d24eb48STom Herbert 13962b9c7581Sstephen hemminger static struct netdev_queue_attribute xps_cpus_attribute __ro_after_init 13972b9c7581Sstephen hemminger = __ATTR_RW(xps_cpus); 13988af2c06fSAmritha Nambiar 13998af2c06fSAmritha Nambiar static ssize_t xps_rxqs_show(struct netdev_queue *queue, char *buf) 14008af2c06fSAmritha Nambiar { 14018af2c06fSAmritha Nambiar struct net_device *dev = queue->dev; 14028af2c06fSAmritha Nambiar struct xps_dev_maps *dev_maps; 14038af2c06fSAmritha Nambiar unsigned long *mask, index; 14048af2c06fSAmritha Nambiar int j, len, num_tc = 1, tc = 0; 14058af2c06fSAmritha Nambiar 14068af2c06fSAmritha Nambiar index = get_netdev_queue_index(queue); 14078af2c06fSAmritha Nambiar 14088af2c06fSAmritha Nambiar if (dev->num_tc) { 14098af2c06fSAmritha Nambiar num_tc = dev->num_tc; 14108af2c06fSAmritha Nambiar tc = netdev_txq_to_tc(dev, index); 14118af2c06fSAmritha Nambiar if (tc < 0) 14128af2c06fSAmritha Nambiar return -EINVAL; 14138af2c06fSAmritha Nambiar } 141429ca1c5aSAndy Shevchenko mask = bitmap_zalloc(dev->num_rx_queues, GFP_KERNEL); 14158af2c06fSAmritha Nambiar if (!mask) 14168af2c06fSAmritha Nambiar return -ENOMEM; 14178af2c06fSAmritha Nambiar 14188af2c06fSAmritha Nambiar rcu_read_lock(); 14198af2c06fSAmritha Nambiar dev_maps = rcu_dereference(dev->xps_rxqs_map); 14208af2c06fSAmritha Nambiar if (!dev_maps) 14218af2c06fSAmritha Nambiar goto out_no_maps; 14228af2c06fSAmritha Nambiar 14238af2c06fSAmritha Nambiar for (j = -1; j = netif_attrmask_next(j, NULL, dev->num_rx_queues), 14248af2c06fSAmritha Nambiar j < dev->num_rx_queues;) { 14258af2c06fSAmritha Nambiar int i, tci = j * num_tc + tc; 14268af2c06fSAmritha Nambiar struct xps_map *map; 14278af2c06fSAmritha Nambiar 14288af2c06fSAmritha Nambiar map = rcu_dereference(dev_maps->attr_map[tci]); 14298af2c06fSAmritha Nambiar if (!map) 14308af2c06fSAmritha Nambiar continue; 14318af2c06fSAmritha Nambiar 14328af2c06fSAmritha Nambiar for (i = map->len; i--;) { 14338af2c06fSAmritha Nambiar if (map->queues[i] == index) { 14348af2c06fSAmritha Nambiar set_bit(j, mask); 14358af2c06fSAmritha Nambiar break; 14368af2c06fSAmritha Nambiar } 14378af2c06fSAmritha Nambiar } 14388af2c06fSAmritha Nambiar } 14398af2c06fSAmritha Nambiar out_no_maps: 14408af2c06fSAmritha Nambiar rcu_read_unlock(); 14418af2c06fSAmritha Nambiar 14428af2c06fSAmritha Nambiar len = bitmap_print_to_pagebuf(false, buf, mask, dev->num_rx_queues); 144329ca1c5aSAndy Shevchenko bitmap_free(mask); 14448af2c06fSAmritha Nambiar 14458af2c06fSAmritha Nambiar return len < PAGE_SIZE ? len : -EINVAL; 14468af2c06fSAmritha Nambiar } 14478af2c06fSAmritha Nambiar 14488af2c06fSAmritha Nambiar static ssize_t xps_rxqs_store(struct netdev_queue *queue, const char *buf, 14498af2c06fSAmritha Nambiar size_t len) 14508af2c06fSAmritha Nambiar { 14518af2c06fSAmritha Nambiar struct net_device *dev = queue->dev; 14528af2c06fSAmritha Nambiar struct net *net = dev_net(dev); 14538af2c06fSAmritha Nambiar unsigned long *mask, index; 14548af2c06fSAmritha Nambiar int err; 14558af2c06fSAmritha Nambiar 14568af2c06fSAmritha Nambiar if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 14578af2c06fSAmritha Nambiar return -EPERM; 14588af2c06fSAmritha Nambiar 145929ca1c5aSAndy Shevchenko mask = bitmap_zalloc(dev->num_rx_queues, GFP_KERNEL); 14608af2c06fSAmritha Nambiar if (!mask) 14618af2c06fSAmritha Nambiar return -ENOMEM; 14628af2c06fSAmritha Nambiar 14638af2c06fSAmritha Nambiar index = get_netdev_queue_index(queue); 14648af2c06fSAmritha Nambiar 14658af2c06fSAmritha Nambiar err = bitmap_parse(buf, len, mask, dev->num_rx_queues); 14668af2c06fSAmritha Nambiar if (err) { 146729ca1c5aSAndy Shevchenko bitmap_free(mask); 14688af2c06fSAmritha Nambiar return err; 14698af2c06fSAmritha Nambiar } 14708af2c06fSAmritha Nambiar 14714d99f660SAndrei Vagin cpus_read_lock(); 14728af2c06fSAmritha Nambiar err = __netif_set_xps_queue(dev, mask, index, true); 14734d99f660SAndrei Vagin cpus_read_unlock(); 14744d99f660SAndrei Vagin 147529ca1c5aSAndy Shevchenko bitmap_free(mask); 14768af2c06fSAmritha Nambiar return err ? : len; 14778af2c06fSAmritha Nambiar } 14788af2c06fSAmritha Nambiar 14798af2c06fSAmritha Nambiar static struct netdev_queue_attribute xps_rxqs_attribute __ro_after_init 14808af2c06fSAmritha Nambiar = __ATTR_RW(xps_rxqs); 1481ccf5ff69Sdavid decotigny #endif /* CONFIG_XPS */ 14821d24eb48STom Herbert 14832b9c7581Sstephen hemminger static struct attribute *netdev_queue_default_attrs[] __ro_after_init = { 1484ccf5ff69Sdavid decotigny &queue_trans_timeout.attr, 14858d059b0fSAlexander Duyck &queue_traffic_class.attr, 1486ccf5ff69Sdavid decotigny #ifdef CONFIG_XPS 14871d24eb48STom Herbert &xps_cpus_attribute.attr, 14888af2c06fSAmritha Nambiar &xps_rxqs_attribute.attr, 1489822b3b2eSJohn Fastabend &queue_tx_maxrate.attr, 1490ccf5ff69Sdavid decotigny #endif 14911d24eb48STom Herbert NULL 14921d24eb48STom Herbert }; 1493be0d6926SKimberly Brown ATTRIBUTE_GROUPS(netdev_queue_default); 14941d24eb48STom Herbert 14951d24eb48STom Herbert static void netdev_queue_release(struct kobject *kobj) 14961d24eb48STom Herbert { 14971d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 14981d24eb48STom Herbert 14991d24eb48STom Herbert memset(kobj, 0, sizeof(*kobj)); 15001d24eb48STom Herbert dev_put(queue->dev); 15011d24eb48STom Herbert } 15021d24eb48STom Herbert 150382ef3d5dSWeilong Chen static const void *netdev_queue_namespace(struct kobject *kobj) 150482ef3d5dSWeilong Chen { 150582ef3d5dSWeilong Chen struct netdev_queue *queue = to_netdev_queue(kobj); 150682ef3d5dSWeilong Chen struct device *dev = &queue->dev->dev; 150782ef3d5dSWeilong Chen const void *ns = NULL; 150882ef3d5dSWeilong Chen 150982ef3d5dSWeilong Chen if (dev->class && dev->class->ns_type) 151082ef3d5dSWeilong Chen ns = dev->class->namespace(dev); 151182ef3d5dSWeilong Chen 151282ef3d5dSWeilong Chen return ns; 151382ef3d5dSWeilong Chen } 151482ef3d5dSWeilong Chen 1515b0e37c0dSDmitry Torokhov static void netdev_queue_get_ownership(struct kobject *kobj, 1516b0e37c0dSDmitry Torokhov kuid_t *uid, kgid_t *gid) 1517b0e37c0dSDmitry Torokhov { 1518b0e37c0dSDmitry Torokhov const struct net *net = netdev_queue_namespace(kobj); 1519b0e37c0dSDmitry Torokhov 1520b0e37c0dSDmitry Torokhov net_ns_get_ownership(net, uid, gid); 1521b0e37c0dSDmitry Torokhov } 1522b0e37c0dSDmitry Torokhov 15232b9c7581Sstephen hemminger static struct kobj_type netdev_queue_ktype __ro_after_init = { 15241d24eb48STom Herbert .sysfs_ops = &netdev_queue_sysfs_ops, 15251d24eb48STom Herbert .release = netdev_queue_release, 1526be0d6926SKimberly Brown .default_groups = netdev_queue_default_groups, 152782ef3d5dSWeilong Chen .namespace = netdev_queue_namespace, 1528b0e37c0dSDmitry Torokhov .get_ownership = netdev_queue_get_ownership, 15291d24eb48STom Herbert }; 15301d24eb48STom Herbert 15316b53dafeSWANG Cong static int netdev_queue_add_kobject(struct net_device *dev, int index) 15321d24eb48STom Herbert { 15336b53dafeSWANG Cong struct netdev_queue *queue = dev->_tx + index; 15341d24eb48STom Herbert struct kobject *kobj = &queue->kobj; 15351d24eb48STom Herbert int error = 0; 15361d24eb48STom Herbert 1537e0b60903SJouni Hogander /* Kobject_put later will trigger netdev_queue_release call 1538e0b60903SJouni Hogander * which decreases dev refcount: Take that reference here 1539e0b60903SJouni Hogander */ 1540e0b60903SJouni Hogander dev_hold(queue->dev); 1541e0b60903SJouni Hogander 15426b53dafeSWANG Cong kobj->kset = dev->queues_kset; 15431d24eb48STom Herbert error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, 15441d24eb48STom Herbert "tx-%u", index); 1545114cf580STom Herbert if (error) 1546b8eb7183SJouni Hogander goto err; 1547114cf580STom Herbert 1548114cf580STom Herbert #ifdef CONFIG_BQL 1549114cf580STom Herbert error = sysfs_create_group(kobj, &dql_group); 1550b8eb7183SJouni Hogander if (error) 1551b8eb7183SJouni Hogander goto err; 1552114cf580STom Herbert #endif 15531d24eb48STom Herbert 15541d24eb48STom Herbert kobject_uevent(kobj, KOBJ_ADD); 155548a322b6SEric Dumazet return 0; 15561d24eb48STom Herbert 1557b8eb7183SJouni Hogander err: 1558b8eb7183SJouni Hogander kobject_put(kobj); 1559b8eb7183SJouni Hogander return error; 15601d24eb48STom Herbert } 1561d755407dSChristian Brauner 1562d755407dSChristian Brauner static int tx_queue_change_owner(struct net_device *ndev, int index, 1563d755407dSChristian Brauner kuid_t kuid, kgid_t kgid) 1564d755407dSChristian Brauner { 1565d755407dSChristian Brauner struct netdev_queue *queue = ndev->_tx + index; 1566d755407dSChristian Brauner struct kobject *kobj = &queue->kobj; 1567d755407dSChristian Brauner int error; 1568d755407dSChristian Brauner 1569d755407dSChristian Brauner error = sysfs_change_owner(kobj, kuid, kgid); 1570d755407dSChristian Brauner if (error) 1571d755407dSChristian Brauner return error; 1572d755407dSChristian Brauner 1573d755407dSChristian Brauner #ifdef CONFIG_BQL 1574d755407dSChristian Brauner error = sysfs_group_change_owner(kobj, &dql_group, kuid, kgid); 1575d755407dSChristian Brauner #endif 1576d755407dSChristian Brauner return error; 1577d755407dSChristian Brauner } 1578ccf5ff69Sdavid decotigny #endif /* CONFIG_SYSFS */ 15791d24eb48STom Herbert 15801d24eb48STom Herbert int 15816b53dafeSWANG Cong netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) 15821d24eb48STom Herbert { 1583ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 15841d24eb48STom Herbert int i; 15851d24eb48STom Herbert int error = 0; 15861d24eb48STom Herbert 15871d24eb48STom Herbert for (i = old_num; i < new_num; i++) { 15886b53dafeSWANG Cong error = netdev_queue_add_kobject(dev, i); 15891d24eb48STom Herbert if (error) { 15901d24eb48STom Herbert new_num = old_num; 15911d24eb48STom Herbert break; 15921d24eb48STom Herbert } 15931d24eb48STom Herbert } 15941d24eb48STom Herbert 1595114cf580STom Herbert while (--i >= new_num) { 15966b53dafeSWANG Cong struct netdev_queue *queue = dev->_tx + i; 1597114cf580STom Herbert 1598273c28bcSKirill Tkhai if (!refcount_read(&dev_net(dev)->count)) 1599002d8a1aSAndrey Vagin queue->kobj.uevent_suppress = 1; 1600114cf580STom Herbert #ifdef CONFIG_BQL 1601114cf580STom Herbert sysfs_remove_group(&queue->kobj, &dql_group); 1602114cf580STom Herbert #endif 1603114cf580STom Herbert kobject_put(&queue->kobj); 1604114cf580STom Herbert } 16051d24eb48STom Herbert 16061d24eb48STom Herbert return error; 1607bf264145STom Herbert #else 1608bf264145STom Herbert return 0; 1609ccf5ff69Sdavid decotigny #endif /* CONFIG_SYSFS */ 16101d24eb48STom Herbert } 16111d24eb48STom Herbert 1612d755407dSChristian Brauner static int net_tx_queue_change_owner(struct net_device *dev, int num, 1613d755407dSChristian Brauner kuid_t kuid, kgid_t kgid) 1614d755407dSChristian Brauner { 1615d755407dSChristian Brauner #ifdef CONFIG_SYSFS 1616d755407dSChristian Brauner int error = 0; 1617d755407dSChristian Brauner int i; 1618d755407dSChristian Brauner 1619d755407dSChristian Brauner for (i = 0; i < num; i++) { 1620d755407dSChristian Brauner error = tx_queue_change_owner(dev, i, kuid, kgid); 1621d755407dSChristian Brauner if (error) 1622d755407dSChristian Brauner break; 1623d755407dSChristian Brauner } 1624d755407dSChristian Brauner 1625d755407dSChristian Brauner return error; 1626d755407dSChristian Brauner #else 1627d755407dSChristian Brauner return 0; 1628d755407dSChristian Brauner #endif /* CONFIG_SYSFS */ 1629d755407dSChristian Brauner } 1630d755407dSChristian Brauner 16316b53dafeSWANG Cong static int register_queue_kobjects(struct net_device *dev) 16321d24eb48STom Herbert { 1633bf264145STom Herbert int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; 16341d24eb48STom Herbert 1635ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 16366b53dafeSWANG Cong dev->queues_kset = kset_create_and_add("queues", 16376b53dafeSWANG Cong NULL, &dev->dev.kobj); 16386b53dafeSWANG Cong if (!dev->queues_kset) 163962fe0b40SBen Hutchings return -ENOMEM; 16406b53dafeSWANG Cong real_rx = dev->real_num_rx_queues; 1641bf264145STom Herbert #endif 16426b53dafeSWANG Cong real_tx = dev->real_num_tx_queues; 1643bf264145STom Herbert 16446b53dafeSWANG Cong error = net_rx_queue_update_kobjects(dev, 0, real_rx); 16451d24eb48STom Herbert if (error) 16461d24eb48STom Herbert goto error; 1647bf264145STom Herbert rxq = real_rx; 16481d24eb48STom Herbert 16496b53dafeSWANG Cong error = netdev_queue_update_kobjects(dev, 0, real_tx); 16501d24eb48STom Herbert if (error) 16511d24eb48STom Herbert goto error; 1652bf264145STom Herbert txq = real_tx; 16531d24eb48STom Herbert 16541d24eb48STom Herbert return 0; 16551d24eb48STom Herbert 16561d24eb48STom Herbert error: 16576b53dafeSWANG Cong netdev_queue_update_kobjects(dev, txq, 0); 16586b53dafeSWANG Cong net_rx_queue_update_kobjects(dev, rxq, 0); 1659895a5e96SYueHaibing #ifdef CONFIG_SYSFS 1660895a5e96SYueHaibing kset_unregister(dev->queues_kset); 1661895a5e96SYueHaibing #endif 16621d24eb48STom Herbert return error; 166362fe0b40SBen Hutchings } 166462fe0b40SBen Hutchings 1665d755407dSChristian Brauner static int queue_change_owner(struct net_device *ndev, kuid_t kuid, kgid_t kgid) 1666d755407dSChristian Brauner { 1667d755407dSChristian Brauner int error = 0, real_rx = 0, real_tx = 0; 1668d755407dSChristian Brauner 1669d755407dSChristian Brauner #ifdef CONFIG_SYSFS 1670d755407dSChristian Brauner if (ndev->queues_kset) { 1671d755407dSChristian Brauner error = sysfs_change_owner(&ndev->queues_kset->kobj, kuid, kgid); 1672d755407dSChristian Brauner if (error) 1673d755407dSChristian Brauner return error; 1674d755407dSChristian Brauner } 1675d755407dSChristian Brauner real_rx = ndev->real_num_rx_queues; 1676d755407dSChristian Brauner #endif 1677d755407dSChristian Brauner real_tx = ndev->real_num_tx_queues; 1678d755407dSChristian Brauner 1679d755407dSChristian Brauner error = net_rx_queue_change_owner(ndev, real_rx, kuid, kgid); 1680d755407dSChristian Brauner if (error) 1681d755407dSChristian Brauner return error; 1682d755407dSChristian Brauner 1683d755407dSChristian Brauner error = net_tx_queue_change_owner(ndev, real_tx, kuid, kgid); 1684d755407dSChristian Brauner if (error) 1685d755407dSChristian Brauner return error; 1686d755407dSChristian Brauner 1687d755407dSChristian Brauner return 0; 1688d755407dSChristian Brauner } 1689d755407dSChristian Brauner 16906b53dafeSWANG Cong static void remove_queue_kobjects(struct net_device *dev) 16910a9627f2STom Herbert { 1692bf264145STom Herbert int real_rx = 0, real_tx = 0; 1693bf264145STom Herbert 1694a953be53SMichael Dalton #ifdef CONFIG_SYSFS 16956b53dafeSWANG Cong real_rx = dev->real_num_rx_queues; 1696bf264145STom Herbert #endif 16976b53dafeSWANG Cong real_tx = dev->real_num_tx_queues; 1698bf264145STom Herbert 16996b53dafeSWANG Cong net_rx_queue_update_kobjects(dev, real_rx, 0); 17006b53dafeSWANG Cong netdev_queue_update_kobjects(dev, real_tx, 0); 1701ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 17026b53dafeSWANG Cong kset_unregister(dev->queues_kset); 1703bf264145STom Herbert #endif 17040a9627f2STom Herbert } 1705608b4b95SEric W. Biederman 17067dc5dbc8SEric W. Biederman static bool net_current_may_mount(void) 17077dc5dbc8SEric W. Biederman { 17087dc5dbc8SEric W. Biederman struct net *net = current->nsproxy->net_ns; 17097dc5dbc8SEric W. Biederman 17107dc5dbc8SEric W. Biederman return ns_capable(net->user_ns, CAP_SYS_ADMIN); 17117dc5dbc8SEric W. Biederman } 17127dc5dbc8SEric W. Biederman 1713a685e089SAl Viro static void *net_grab_current_ns(void) 1714608b4b95SEric W. Biederman { 1715a685e089SAl Viro struct net *ns = current->nsproxy->net_ns; 1716a685e089SAl Viro #ifdef CONFIG_NET_NS 1717a685e089SAl Viro if (ns) 1718c122e14dSReshetova, Elena refcount_inc(&ns->passive); 1719a685e089SAl Viro #endif 1720a685e089SAl Viro return ns; 1721608b4b95SEric W. Biederman } 1722608b4b95SEric W. Biederman 1723608b4b95SEric W. Biederman static const void *net_initial_ns(void) 1724608b4b95SEric W. Biederman { 1725608b4b95SEric W. Biederman return &init_net; 1726608b4b95SEric W. Biederman } 1727608b4b95SEric W. Biederman 1728608b4b95SEric W. Biederman static const void *net_netlink_ns(struct sock *sk) 1729608b4b95SEric W. Biederman { 1730608b4b95SEric W. Biederman return sock_net(sk); 1731608b4b95SEric W. Biederman } 1732608b4b95SEric W. Biederman 1733737aec57Sstephen hemminger const struct kobj_ns_type_operations net_ns_type_operations = { 1734608b4b95SEric W. Biederman .type = KOBJ_NS_TYPE_NET, 17357dc5dbc8SEric W. Biederman .current_may_mount = net_current_may_mount, 1736a685e089SAl Viro .grab_current_ns = net_grab_current_ns, 1737608b4b95SEric W. Biederman .netlink_ns = net_netlink_ns, 1738608b4b95SEric W. Biederman .initial_ns = net_initial_ns, 1739a685e089SAl Viro .drop_ns = net_drop_ns, 1740608b4b95SEric W. Biederman }; 174104600794SJohannes Berg EXPORT_SYMBOL_GPL(net_ns_type_operations); 1742608b4b95SEric W. Biederman 17437eff2e7aSKay Sievers static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) 17441da177e4SLinus Torvalds { 174543cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 17467eff2e7aSKay Sievers int retval; 17471da177e4SLinus Torvalds 1748312c004dSKay Sievers /* pass interface to uevent. */ 17497eff2e7aSKay Sievers retval = add_uevent_var(env, "INTERFACE=%s", dev->name); 1750bf62456eSEric Rannaud if (retval) 1751bf62456eSEric Rannaud goto exit; 17521da177e4SLinus Torvalds 1753ca2f37dbSJean Tourrilhes /* pass ifindex to uevent. 1754ca2f37dbSJean Tourrilhes * ifindex is useful as it won't change (interface name may change) 17556648c65eSstephen hemminger * and is what RtNetlink uses natively. 17566648c65eSstephen hemminger */ 17577eff2e7aSKay Sievers retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); 1758ca2f37dbSJean Tourrilhes 1759bf62456eSEric Rannaud exit: 1760bf62456eSEric Rannaud return retval; 17611da177e4SLinus Torvalds } 17621da177e4SLinus Torvalds 17631da177e4SLinus Torvalds /* 17641da177e4SLinus Torvalds * netdev_release -- destroy and free a dead device. 176543cb76d9SGreg Kroah-Hartman * Called when last reference to device kobject is gone. 17661da177e4SLinus Torvalds */ 176743cb76d9SGreg Kroah-Hartman static void netdev_release(struct device *d) 17681da177e4SLinus Torvalds { 176943cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 17701da177e4SLinus Torvalds 17711da177e4SLinus Torvalds BUG_ON(dev->reg_state != NETREG_RELEASED); 17721da177e4SLinus Torvalds 17736c557001SFlorian Westphal /* no need to wait for rcu grace period: 17746c557001SFlorian Westphal * device is dead and about to be freed. 17756c557001SFlorian Westphal */ 17766c557001SFlorian Westphal kfree(rcu_access_pointer(dev->ifalias)); 177774d332c1SEric Dumazet netdev_freemem(dev); 17781da177e4SLinus Torvalds } 17791da177e4SLinus Torvalds 1780608b4b95SEric W. Biederman static const void *net_namespace(struct device *d) 1781608b4b95SEric W. Biederman { 17825c29482dSGeliang Tang struct net_device *dev = to_net_dev(d); 17835c29482dSGeliang Tang 1784608b4b95SEric W. Biederman return dev_net(dev); 1785608b4b95SEric W. Biederman } 1786608b4b95SEric W. Biederman 1787b0e37c0dSDmitry Torokhov static void net_get_ownership(struct device *d, kuid_t *uid, kgid_t *gid) 1788b0e37c0dSDmitry Torokhov { 1789b0e37c0dSDmitry Torokhov struct net_device *dev = to_net_dev(d); 1790b0e37c0dSDmitry Torokhov const struct net *net = dev_net(dev); 1791b0e37c0dSDmitry Torokhov 1792b0e37c0dSDmitry Torokhov net_ns_get_ownership(net, uid, gid); 1793b0e37c0dSDmitry Torokhov } 1794b0e37c0dSDmitry Torokhov 1795e6d473e6Sstephen hemminger static struct class net_class __ro_after_init = { 17961da177e4SLinus Torvalds .name = "net", 179743cb76d9SGreg Kroah-Hartman .dev_release = netdev_release, 17986be8aeefSGreg Kroah-Hartman .dev_groups = net_class_groups, 179943cb76d9SGreg Kroah-Hartman .dev_uevent = netdev_uevent, 1800608b4b95SEric W. Biederman .ns_type = &net_ns_type_operations, 1801608b4b95SEric W. Biederman .namespace = net_namespace, 1802b0e37c0dSDmitry Torokhov .get_ownership = net_get_ownership, 18031da177e4SLinus Torvalds }; 18041da177e4SLinus Torvalds 1805aa836df9SFlorian Fainelli #ifdef CONFIG_OF_NET 1806aa836df9SFlorian Fainelli static int of_dev_node_match(struct device *dev, const void *data) 1807aa836df9SFlorian Fainelli { 1808aa836df9SFlorian Fainelli int ret = 0; 1809aa836df9SFlorian Fainelli 1810aa836df9SFlorian Fainelli if (dev->parent) 1811aa836df9SFlorian Fainelli ret = dev->parent->of_node == data; 1812aa836df9SFlorian Fainelli 1813aa836df9SFlorian Fainelli return ret == 0 ? dev->of_node == data : ret; 1814aa836df9SFlorian Fainelli } 1815aa836df9SFlorian Fainelli 18169861f720SRussell King /* 18179861f720SRussell King * of_find_net_device_by_node - lookup the net device for the device node 18189861f720SRussell King * @np: OF device node 18199861f720SRussell King * 18209861f720SRussell King * Looks up the net_device structure corresponding with the device node. 18219861f720SRussell King * If successful, returns a pointer to the net_device with the embedded 18229861f720SRussell King * struct device refcount incremented by one, or NULL on failure. The 18239861f720SRussell King * refcount must be dropped when done with the net_device. 18249861f720SRussell King */ 1825aa836df9SFlorian Fainelli struct net_device *of_find_net_device_by_node(struct device_node *np) 1826aa836df9SFlorian Fainelli { 1827aa836df9SFlorian Fainelli struct device *dev; 1828aa836df9SFlorian Fainelli 1829aa836df9SFlorian Fainelli dev = class_find_device(&net_class, NULL, np, of_dev_node_match); 1830aa836df9SFlorian Fainelli if (!dev) 1831aa836df9SFlorian Fainelli return NULL; 1832aa836df9SFlorian Fainelli 1833aa836df9SFlorian Fainelli return to_net_dev(dev); 1834aa836df9SFlorian Fainelli } 1835aa836df9SFlorian Fainelli EXPORT_SYMBOL(of_find_net_device_by_node); 1836aa836df9SFlorian Fainelli #endif 1837aa836df9SFlorian Fainelli 18389093bbb2SStephen Hemminger /* Delete sysfs entries but hold kobject reference until after all 18399093bbb2SStephen Hemminger * netdev references are gone. 18409093bbb2SStephen Hemminger */ 18416b53dafeSWANG Cong void netdev_unregister_kobject(struct net_device *ndev) 18421da177e4SLinus Torvalds { 18436648c65eSstephen hemminger struct device *dev = &ndev->dev; 18449093bbb2SStephen Hemminger 1845273c28bcSKirill Tkhai if (!refcount_read(&dev_net(ndev)->count)) 1846002d8a1aSAndrey Vagin dev_set_uevent_suppress(dev, 1); 1847002d8a1aSAndrey Vagin 18489093bbb2SStephen Hemminger kobject_get(&dev->kobj); 18493891845eSEric W. Biederman 18506b53dafeSWANG Cong remove_queue_kobjects(ndev); 18510a9627f2STom Herbert 18529802c8e2SMing Lei pm_runtime_set_memalloc_noio(dev, false); 18539802c8e2SMing Lei 18549093bbb2SStephen Hemminger device_del(dev); 18551da177e4SLinus Torvalds } 18561da177e4SLinus Torvalds 18571da177e4SLinus Torvalds /* Create sysfs entries for network device. */ 18586b53dafeSWANG Cong int netdev_register_kobject(struct net_device *ndev) 18591da177e4SLinus Torvalds { 18606648c65eSstephen hemminger struct device *dev = &ndev->dev; 18616b53dafeSWANG Cong const struct attribute_group **groups = ndev->sysfs_groups; 18620a9627f2STom Herbert int error = 0; 18631da177e4SLinus Torvalds 1864a1b3f594SEric W. Biederman device_initialize(dev); 186543cb76d9SGreg Kroah-Hartman dev->class = &net_class; 18666b53dafeSWANG Cong dev->platform_data = ndev; 186743cb76d9SGreg Kroah-Hartman dev->groups = groups; 18681da177e4SLinus Torvalds 18696b53dafeSWANG Cong dev_set_name(dev, "%s", ndev->name); 18701da177e4SLinus Torvalds 18718b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 18720c509a6cSEric W. Biederman /* Allow for a device specific group */ 18730c509a6cSEric W. Biederman if (*groups) 18740c509a6cSEric W. Biederman groups++; 18751da177e4SLinus Torvalds 18760c509a6cSEric W. Biederman *groups++ = &netstat_group; 187738c1a01cSJohannes Berg 187838c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) 18796b53dafeSWANG Cong if (ndev->ieee80211_ptr) 188038c1a01cSJohannes Berg *groups++ = &wireless_group; 188138c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) 18826b53dafeSWANG Cong else if (ndev->wireless_handlers) 188338c1a01cSJohannes Berg *groups++ = &wireless_group; 188438c1a01cSJohannes Berg #endif 188538c1a01cSJohannes Berg #endif 18868b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 18871da177e4SLinus Torvalds 18880a9627f2STom Herbert error = device_add(dev); 18890a9627f2STom Herbert if (error) 18908ed633b9SWang Hai return error; 18910a9627f2STom Herbert 18926b53dafeSWANG Cong error = register_queue_kobjects(ndev); 18938ed633b9SWang Hai if (error) { 18948ed633b9SWang Hai device_del(dev); 18958ed633b9SWang Hai return error; 18968ed633b9SWang Hai } 18970a9627f2STom Herbert 18989802c8e2SMing Lei pm_runtime_set_memalloc_noio(dev, true); 18999802c8e2SMing Lei 19000a9627f2STom Herbert return error; 19011da177e4SLinus Torvalds } 19021da177e4SLinus Torvalds 1903e6dee9f3SChristian Brauner /* Change owner for sysfs entries when moving network devices across network 1904e6dee9f3SChristian Brauner * namespaces owned by different user namespaces. 1905e6dee9f3SChristian Brauner */ 1906e6dee9f3SChristian Brauner int netdev_change_owner(struct net_device *ndev, const struct net *net_old, 1907e6dee9f3SChristian Brauner const struct net *net_new) 1908e6dee9f3SChristian Brauner { 1909e6dee9f3SChristian Brauner struct device *dev = &ndev->dev; 1910e6dee9f3SChristian Brauner kuid_t old_uid, new_uid; 1911e6dee9f3SChristian Brauner kgid_t old_gid, new_gid; 1912e6dee9f3SChristian Brauner int error; 1913e6dee9f3SChristian Brauner 1914e6dee9f3SChristian Brauner net_ns_get_ownership(net_old, &old_uid, &old_gid); 1915e6dee9f3SChristian Brauner net_ns_get_ownership(net_new, &new_uid, &new_gid); 1916e6dee9f3SChristian Brauner 1917e6dee9f3SChristian Brauner /* The network namespace was changed but the owning user namespace is 1918e6dee9f3SChristian Brauner * identical so there's no need to change the owner of sysfs entries. 1919e6dee9f3SChristian Brauner */ 1920e6dee9f3SChristian Brauner if (uid_eq(old_uid, new_uid) && gid_eq(old_gid, new_gid)) 1921e6dee9f3SChristian Brauner return 0; 1922e6dee9f3SChristian Brauner 1923e6dee9f3SChristian Brauner error = device_change_owner(dev, new_uid, new_gid); 1924e6dee9f3SChristian Brauner if (error) 1925e6dee9f3SChristian Brauner return error; 1926e6dee9f3SChristian Brauner 1927d755407dSChristian Brauner error = queue_change_owner(ndev, new_uid, new_gid); 1928d755407dSChristian Brauner if (error) 1929d755407dSChristian Brauner return error; 1930d755407dSChristian Brauner 1931e6dee9f3SChristian Brauner return 0; 1932e6dee9f3SChristian Brauner } 1933e6dee9f3SChristian Brauner 1934b793dc5cSstephen hemminger int netdev_class_create_file_ns(const struct class_attribute *class_attr, 193558292cbeSTejun Heo const void *ns) 1936b8a9787eSJay Vosburgh { 193758292cbeSTejun Heo return class_create_file_ns(&net_class, class_attr, ns); 1938b8a9787eSJay Vosburgh } 193958292cbeSTejun Heo EXPORT_SYMBOL(netdev_class_create_file_ns); 1940b8a9787eSJay Vosburgh 1941b793dc5cSstephen hemminger void netdev_class_remove_file_ns(const struct class_attribute *class_attr, 194258292cbeSTejun Heo const void *ns) 1943b8a9787eSJay Vosburgh { 194458292cbeSTejun Heo class_remove_file_ns(&net_class, class_attr, ns); 1945b8a9787eSJay Vosburgh } 194658292cbeSTejun Heo EXPORT_SYMBOL(netdev_class_remove_file_ns); 1947b8a9787eSJay Vosburgh 1948a48d4bb0SDaniel Borkmann int __init netdev_kobject_init(void) 19491da177e4SLinus Torvalds { 1950608b4b95SEric W. Biederman kobj_ns_type_register(&net_ns_type_operations); 19511da177e4SLinus Torvalds return class_register(&net_class); 19521da177e4SLinus Torvalds } 1953