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> 1407bbecb3SAlex Belits #include <linux/sched/isolation.h> 15608b4b95SEric W. Biederman #include <linux/nsproxy.h> 161da177e4SLinus Torvalds #include <net/sock.h> 17608b4b95SEric W. Biederman #include <net/net_namespace.h> 181da177e4SLinus Torvalds #include <linux/rtnetlink.h> 19fec5e652STom Herbert #include <linux/vmalloc.h> 20bc3b2d7fSPaul Gortmaker #include <linux/export.h> 21114cf580STom Herbert #include <linux/jiffies.h> 229802c8e2SMing Lei #include <linux/pm_runtime.h> 23aa836df9SFlorian Fainelli #include <linux/of.h> 2488832a22SBen Dooks #include <linux/of_net.h> 254d99f660SAndrei Vagin #include <linux/cpu.h> 261da177e4SLinus Torvalds 27342709efSPavel Emelyanov #include "net-sysfs.h" 28342709efSPavel Emelyanov 298b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 301da177e4SLinus Torvalds static const char fmt_hex[] = "%#x\n"; 311da177e4SLinus Torvalds static const char fmt_dec[] = "%d\n"; 321da177e4SLinus Torvalds static const char fmt_ulong[] = "%lu\n"; 33be1f3c2cSBen Hutchings static const char fmt_u64[] = "%llu\n"; 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds static inline int dev_isalive(const struct net_device *dev) 361da177e4SLinus Torvalds { 37fe9925b5SStephen Hemminger return dev->reg_state <= NETREG_REGISTERED; 381da177e4SLinus Torvalds } 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds /* use same locking rules as GIF* ioctl's */ 4143cb76d9SGreg Kroah-Hartman static ssize_t netdev_show(const struct device *dev, 4243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 431da177e4SLinus Torvalds ssize_t (*format)(const struct net_device *, char *)) 441da177e4SLinus Torvalds { 456b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 461da177e4SLinus Torvalds ssize_t ret = -EINVAL; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds read_lock(&dev_base_lock); 496b53dafeSWANG Cong if (dev_isalive(ndev)) 506b53dafeSWANG Cong ret = (*format)(ndev, buf); 511da177e4SLinus Torvalds read_unlock(&dev_base_lock); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds return ret; 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* generate a show function for simple field */ 571da177e4SLinus Torvalds #define NETDEVICE_SHOW(field, format_string) \ 586b53dafeSWANG Cong static ssize_t format_##field(const struct net_device *dev, char *buf) \ 591da177e4SLinus Torvalds { \ 606b53dafeSWANG Cong return sprintf(buf, format_string, dev->field); \ 611da177e4SLinus Torvalds } \ 626be8aeefSGreg Kroah-Hartman static ssize_t field##_show(struct device *dev, \ 6343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 641da177e4SLinus Torvalds { \ 6543cb76d9SGreg Kroah-Hartman return netdev_show(dev, attr, buf, format_##field); \ 666be8aeefSGreg Kroah-Hartman } \ 671da177e4SLinus Torvalds 686be8aeefSGreg Kroah-Hartman #define NETDEVICE_SHOW_RO(field, format_string) \ 696be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(field, format_string); \ 706be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(field) 716be8aeefSGreg Kroah-Hartman 726be8aeefSGreg Kroah-Hartman #define NETDEVICE_SHOW_RW(field, format_string) \ 736be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(field, format_string); \ 746be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(field) 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds /* use same locking and permission rules as SIF* ioctl's */ 7743cb76d9SGreg Kroah-Hartman static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, 781da177e4SLinus Torvalds const char *buf, size_t len, 791da177e4SLinus Torvalds int (*set)(struct net_device *, unsigned long)) 801da177e4SLinus Torvalds { 815e1fccc0SEric W. Biederman struct net_device *netdev = to_net_dev(dev); 825e1fccc0SEric W. Biederman struct net *net = dev_net(netdev); 831da177e4SLinus Torvalds unsigned long new; 845f0224a6SColin Ian King int ret; 851da177e4SLinus Torvalds 865e1fccc0SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 871da177e4SLinus Torvalds return -EPERM; 881da177e4SLinus Torvalds 89e1e420c7SShuah Khan ret = kstrtoul(buf, 0, &new); 90e1e420c7SShuah Khan if (ret) 911da177e4SLinus Torvalds goto err; 921da177e4SLinus Torvalds 935a5990d3SStephen Hemminger if (!rtnl_trylock()) 94336ca57cSEric W. Biederman return restart_syscall(); 955a5990d3SStephen Hemminger 965e1fccc0SEric W. Biederman if (dev_isalive(netdev)) { 976648c65eSstephen hemminger ret = (*set)(netdev, new); 986648c65eSstephen hemminger if (ret == 0) 991da177e4SLinus Torvalds ret = len; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds rtnl_unlock(); 1021da177e4SLinus Torvalds err: 1031da177e4SLinus Torvalds return ret; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 1066be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(dev_id, fmt_hex); 1073f85944fSAmir Vadai NETDEVICE_SHOW_RO(dev_port, fmt_dec); 1086be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(addr_assign_type, fmt_dec); 1096be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(addr_len, fmt_dec); 1106be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(ifindex, fmt_dec); 1116be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(type, fmt_dec); 1126be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(link_mode, fmt_dec); 1131da177e4SLinus Torvalds 114a54acb3aSNicolas Dichtel static ssize_t iflink_show(struct device *dev, struct device_attribute *attr, 115a54acb3aSNicolas Dichtel char *buf) 116a54acb3aSNicolas Dichtel { 117a54acb3aSNicolas Dichtel struct net_device *ndev = to_net_dev(dev); 118a54acb3aSNicolas Dichtel 119a54acb3aSNicolas Dichtel return sprintf(buf, fmt_dec, dev_get_iflink(ndev)); 120a54acb3aSNicolas Dichtel } 121a54acb3aSNicolas Dichtel static DEVICE_ATTR_RO(iflink); 122a54acb3aSNicolas Dichtel 1236b53dafeSWANG Cong static ssize_t format_name_assign_type(const struct net_device *dev, char *buf) 124685343fcSTom Gundersen { 1256b53dafeSWANG Cong return sprintf(buf, fmt_dec, dev->name_assign_type); 126685343fcSTom Gundersen } 127685343fcSTom Gundersen 128685343fcSTom Gundersen static ssize_t name_assign_type_show(struct device *dev, 129685343fcSTom Gundersen struct device_attribute *attr, 130685343fcSTom Gundersen char *buf) 131685343fcSTom Gundersen { 1326b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 133685343fcSTom Gundersen ssize_t ret = -EINVAL; 134685343fcSTom Gundersen 1356b53dafeSWANG Cong if (ndev->name_assign_type != NET_NAME_UNKNOWN) 136685343fcSTom Gundersen ret = netdev_show(dev, attr, buf, format_name_assign_type); 137685343fcSTom Gundersen 138685343fcSTom Gundersen return ret; 139685343fcSTom Gundersen } 140685343fcSTom Gundersen static DEVICE_ATTR_RO(name_assign_type); 141685343fcSTom Gundersen 1421da177e4SLinus Torvalds /* use same locking rules as GIFHWADDR ioctl's */ 1436be8aeefSGreg Kroah-Hartman static ssize_t address_show(struct device *dev, struct device_attribute *attr, 14443cb76d9SGreg Kroah-Hartman char *buf) 1451da177e4SLinus Torvalds { 1466b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 1471da177e4SLinus Torvalds ssize_t ret = -EINVAL; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds read_lock(&dev_base_lock); 1506b53dafeSWANG Cong if (dev_isalive(ndev)) 1516b53dafeSWANG Cong ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len); 1521da177e4SLinus Torvalds read_unlock(&dev_base_lock); 1531da177e4SLinus Torvalds return ret; 1541da177e4SLinus Torvalds } 1556be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(address); 1561da177e4SLinus Torvalds 1576be8aeefSGreg Kroah-Hartman static ssize_t broadcast_show(struct device *dev, 15843cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1591da177e4SLinus Torvalds { 1606b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 1616648c65eSstephen hemminger 1626b53dafeSWANG Cong if (dev_isalive(ndev)) 1636b53dafeSWANG Cong return sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len); 1641da177e4SLinus Torvalds return -EINVAL; 1651da177e4SLinus Torvalds } 1666be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(broadcast); 1671da177e4SLinus Torvalds 1686b53dafeSWANG Cong static int change_carrier(struct net_device *dev, unsigned long new_carrier) 169fdae0fdeSJiri Pirko { 1706b53dafeSWANG Cong if (!netif_running(dev)) 171fdae0fdeSJiri Pirko return -EINVAL; 1726b53dafeSWANG Cong return dev_change_carrier(dev, (bool)new_carrier); 173fdae0fdeSJiri Pirko } 174fdae0fdeSJiri Pirko 1756be8aeefSGreg Kroah-Hartman static ssize_t carrier_store(struct device *dev, struct device_attribute *attr, 176fdae0fdeSJiri Pirko const char *buf, size_t len) 177fdae0fdeSJiri Pirko { 178146e5e73SAntoine Tenart struct net_device *netdev = to_net_dev(dev); 179146e5e73SAntoine Tenart 180146e5e73SAntoine Tenart /* The check is also done in change_carrier; this helps returning early 181146e5e73SAntoine Tenart * without hitting the trylock/restart in netdev_store. 182146e5e73SAntoine Tenart */ 183146e5e73SAntoine Tenart if (!netdev->netdev_ops->ndo_change_carrier) 184146e5e73SAntoine Tenart return -EOPNOTSUPP; 185146e5e73SAntoine Tenart 186fdae0fdeSJiri Pirko return netdev_store(dev, attr, buf, len, change_carrier); 187fdae0fdeSJiri Pirko } 188fdae0fdeSJiri Pirko 1896be8aeefSGreg Kroah-Hartman static ssize_t carrier_show(struct device *dev, 19043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1911da177e4SLinus Torvalds { 1921da177e4SLinus Torvalds struct net_device *netdev = to_net_dev(dev); 1936648c65eSstephen hemminger 1946648c65eSstephen hemminger if (netif_running(netdev)) 1951da177e4SLinus Torvalds return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); 1966648c65eSstephen hemminger 1971da177e4SLinus Torvalds return -EINVAL; 1981da177e4SLinus Torvalds } 1996be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(carrier); 2001da177e4SLinus Torvalds 2016be8aeefSGreg Kroah-Hartman static ssize_t speed_show(struct device *dev, 202d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 203d519e17eSAndy Gospodarek { 204d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 205d519e17eSAndy Gospodarek int ret = -EINVAL; 206d519e17eSAndy Gospodarek 207146e5e73SAntoine Tenart /* The check is also done in __ethtool_get_link_ksettings; this helps 208146e5e73SAntoine Tenart * returning early without hitting the trylock/restart below. 209146e5e73SAntoine Tenart */ 210146e5e73SAntoine Tenart if (!netdev->ethtool_ops->get_link_ksettings) 211146e5e73SAntoine Tenart return ret; 212146e5e73SAntoine Tenart 213d519e17eSAndy Gospodarek if (!rtnl_trylock()) 214d519e17eSAndy Gospodarek return restart_syscall(); 215d519e17eSAndy Gospodarek 2168ae6dacaSDavid Decotigny if (netif_running(netdev)) { 2177cad1bacSDavid Decotigny struct ethtool_link_ksettings cmd; 2187cad1bacSDavid Decotigny 2197cad1bacSDavid Decotigny if (!__ethtool_get_link_ksettings(netdev, &cmd)) 2207cad1bacSDavid Decotigny ret = sprintf(buf, fmt_dec, cmd.base.speed); 221d519e17eSAndy Gospodarek } 222d519e17eSAndy Gospodarek rtnl_unlock(); 223d519e17eSAndy Gospodarek return ret; 224d519e17eSAndy Gospodarek } 2256be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(speed); 226d519e17eSAndy Gospodarek 2276be8aeefSGreg Kroah-Hartman static ssize_t duplex_show(struct device *dev, 228d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 229d519e17eSAndy Gospodarek { 230d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 231d519e17eSAndy Gospodarek int ret = -EINVAL; 232d519e17eSAndy Gospodarek 233146e5e73SAntoine Tenart /* The check is also done in __ethtool_get_link_ksettings; this helps 234146e5e73SAntoine Tenart * returning early without hitting the trylock/restart below. 235146e5e73SAntoine Tenart */ 236146e5e73SAntoine Tenart if (!netdev->ethtool_ops->get_link_ksettings) 237146e5e73SAntoine Tenart return ret; 238146e5e73SAntoine Tenart 239d519e17eSAndy Gospodarek if (!rtnl_trylock()) 240d519e17eSAndy Gospodarek return restart_syscall(); 241d519e17eSAndy Gospodarek 2428ae6dacaSDavid Decotigny if (netif_running(netdev)) { 2437cad1bacSDavid Decotigny struct ethtool_link_ksettings cmd; 2447cad1bacSDavid Decotigny 2457cad1bacSDavid Decotigny if (!__ethtool_get_link_ksettings(netdev, &cmd)) { 246c6c13965SNikolay Aleksandrov const char *duplex; 2477cad1bacSDavid Decotigny 2487cad1bacSDavid Decotigny switch (cmd.base.duplex) { 249c6c13965SNikolay Aleksandrov case DUPLEX_HALF: 250c6c13965SNikolay Aleksandrov duplex = "half"; 251c6c13965SNikolay Aleksandrov break; 252c6c13965SNikolay Aleksandrov case DUPLEX_FULL: 253c6c13965SNikolay Aleksandrov duplex = "full"; 254c6c13965SNikolay Aleksandrov break; 255c6c13965SNikolay Aleksandrov default: 256c6c13965SNikolay Aleksandrov duplex = "unknown"; 257c6c13965SNikolay Aleksandrov break; 258c6c13965SNikolay Aleksandrov } 259c6c13965SNikolay Aleksandrov ret = sprintf(buf, "%s\n", duplex); 260c6c13965SNikolay Aleksandrov } 261d519e17eSAndy Gospodarek } 262d519e17eSAndy Gospodarek rtnl_unlock(); 263d519e17eSAndy Gospodarek return ret; 264d519e17eSAndy Gospodarek } 2656be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(duplex); 266d519e17eSAndy Gospodarek 267db30a577SAndrew Lunn static ssize_t testing_show(struct device *dev, 268db30a577SAndrew Lunn struct device_attribute *attr, char *buf) 269db30a577SAndrew Lunn { 270db30a577SAndrew Lunn struct net_device *netdev = to_net_dev(dev); 271db30a577SAndrew Lunn 272db30a577SAndrew Lunn if (netif_running(netdev)) 273db30a577SAndrew Lunn return sprintf(buf, fmt_dec, !!netif_testing(netdev)); 274db30a577SAndrew Lunn 275db30a577SAndrew Lunn return -EINVAL; 276db30a577SAndrew Lunn } 277db30a577SAndrew Lunn static DEVICE_ATTR_RO(testing); 278db30a577SAndrew Lunn 2796be8aeefSGreg Kroah-Hartman static ssize_t dormant_show(struct device *dev, 28043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 281b00055aaSStefan Rompf { 282b00055aaSStefan Rompf struct net_device *netdev = to_net_dev(dev); 283b00055aaSStefan Rompf 284b00055aaSStefan Rompf if (netif_running(netdev)) 285b00055aaSStefan Rompf return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); 286b00055aaSStefan Rompf 287b00055aaSStefan Rompf return -EINVAL; 288b00055aaSStefan Rompf } 2896be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(dormant); 290b00055aaSStefan Rompf 29136cbd3dcSJan Engelhardt static const char *const operstates[] = { 292b00055aaSStefan Rompf "unknown", 293b00055aaSStefan Rompf "notpresent", /* currently unused */ 294b00055aaSStefan Rompf "down", 295b00055aaSStefan Rompf "lowerlayerdown", 296db30a577SAndrew Lunn "testing", 297b00055aaSStefan Rompf "dormant", 298b00055aaSStefan Rompf "up" 299b00055aaSStefan Rompf }; 300b00055aaSStefan Rompf 3016be8aeefSGreg Kroah-Hartman static ssize_t operstate_show(struct device *dev, 30243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 303b00055aaSStefan Rompf { 304b00055aaSStefan Rompf const struct net_device *netdev = to_net_dev(dev); 305b00055aaSStefan Rompf unsigned char operstate; 306b00055aaSStefan Rompf 307b00055aaSStefan Rompf read_lock(&dev_base_lock); 308b00055aaSStefan Rompf operstate = netdev->operstate; 309b00055aaSStefan Rompf if (!netif_running(netdev)) 310b00055aaSStefan Rompf operstate = IF_OPER_DOWN; 311b00055aaSStefan Rompf read_unlock(&dev_base_lock); 312b00055aaSStefan Rompf 313e3a5cd9eSAdrian Bunk if (operstate >= ARRAY_SIZE(operstates)) 314b00055aaSStefan Rompf return -EINVAL; /* should not happen */ 315b00055aaSStefan Rompf 316b00055aaSStefan Rompf return sprintf(buf, "%s\n", operstates[operstate]); 317b00055aaSStefan Rompf } 3186be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(operstate); 319b00055aaSStefan Rompf 3202d3b479dSdavid decotigny static ssize_t carrier_changes_show(struct device *dev, 3212d3b479dSdavid decotigny struct device_attribute *attr, 3222d3b479dSdavid decotigny char *buf) 3232d3b479dSdavid decotigny { 3242d3b479dSdavid decotigny struct net_device *netdev = to_net_dev(dev); 3256648c65eSstephen hemminger 3262d3b479dSdavid decotigny return sprintf(buf, fmt_dec, 327b2d3bcfaSDavid Decotigny atomic_read(&netdev->carrier_up_count) + 328b2d3bcfaSDavid Decotigny atomic_read(&netdev->carrier_down_count)); 3292d3b479dSdavid decotigny } 3302d3b479dSdavid decotigny static DEVICE_ATTR_RO(carrier_changes); 3312d3b479dSdavid decotigny 332b2d3bcfaSDavid Decotigny static ssize_t carrier_up_count_show(struct device *dev, 333b2d3bcfaSDavid Decotigny struct device_attribute *attr, 334b2d3bcfaSDavid Decotigny char *buf) 335b2d3bcfaSDavid Decotigny { 336b2d3bcfaSDavid Decotigny struct net_device *netdev = to_net_dev(dev); 337b2d3bcfaSDavid Decotigny 338b2d3bcfaSDavid Decotigny return sprintf(buf, fmt_dec, atomic_read(&netdev->carrier_up_count)); 339b2d3bcfaSDavid Decotigny } 340b2d3bcfaSDavid Decotigny static DEVICE_ATTR_RO(carrier_up_count); 341b2d3bcfaSDavid Decotigny 342b2d3bcfaSDavid Decotigny static ssize_t carrier_down_count_show(struct device *dev, 343b2d3bcfaSDavid Decotigny struct device_attribute *attr, 344b2d3bcfaSDavid Decotigny char *buf) 345b2d3bcfaSDavid Decotigny { 346b2d3bcfaSDavid Decotigny struct net_device *netdev = to_net_dev(dev); 347b2d3bcfaSDavid Decotigny 348b2d3bcfaSDavid Decotigny return sprintf(buf, fmt_dec, atomic_read(&netdev->carrier_down_count)); 349b2d3bcfaSDavid Decotigny } 350b2d3bcfaSDavid Decotigny static DEVICE_ATTR_RO(carrier_down_count); 351b2d3bcfaSDavid Decotigny 3521da177e4SLinus Torvalds /* read-write attributes */ 3531da177e4SLinus Torvalds 3546b53dafeSWANG Cong static int change_mtu(struct net_device *dev, unsigned long new_mtu) 3551da177e4SLinus Torvalds { 3566b53dafeSWANG Cong return dev_set_mtu(dev, (int)new_mtu); 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds 3596be8aeefSGreg Kroah-Hartman static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, 36043cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3611da177e4SLinus Torvalds { 36243cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_mtu); 3631da177e4SLinus Torvalds } 3646be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(mtu, fmt_dec); 3651da177e4SLinus Torvalds 3666b53dafeSWANG Cong static int change_flags(struct net_device *dev, unsigned long new_flags) 3671da177e4SLinus Torvalds { 368567c5e13SPetr Machata return dev_change_flags(dev, (unsigned int)new_flags, NULL); 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds 3716be8aeefSGreg Kroah-Hartman static ssize_t flags_store(struct device *dev, struct device_attribute *attr, 37243cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3731da177e4SLinus Torvalds { 37443cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_flags); 3751da177e4SLinus Torvalds } 3766be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(flags, fmt_hex); 3771da177e4SLinus Torvalds 3786be8aeefSGreg Kroah-Hartman static ssize_t tx_queue_len_store(struct device *dev, 37943cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 38043cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3811da177e4SLinus Torvalds { 3825e1fccc0SEric W. Biederman if (!capable(CAP_NET_ADMIN)) 3835e1fccc0SEric W. Biederman return -EPERM; 3845e1fccc0SEric W. Biederman 3856a643ddbSCong Wang return netdev_store(dev, attr, buf, len, dev_change_tx_queue_len); 3861da177e4SLinus Torvalds } 3870cd29503SAlexey Dobriyan NETDEVICE_SHOW_RW(tx_queue_len, fmt_dec); 3881da177e4SLinus Torvalds 3893b47d303SEric Dumazet static int change_gro_flush_timeout(struct net_device *dev, unsigned long val) 3903b47d303SEric Dumazet { 3917e417a66SEric Dumazet WRITE_ONCE(dev->gro_flush_timeout, val); 3923b47d303SEric Dumazet return 0; 3933b47d303SEric Dumazet } 3943b47d303SEric Dumazet 3953b47d303SEric Dumazet static ssize_t gro_flush_timeout_store(struct device *dev, 3963b47d303SEric Dumazet struct device_attribute *attr, 3973b47d303SEric Dumazet const char *buf, size_t len) 3983b47d303SEric Dumazet { 3993b47d303SEric Dumazet if (!capable(CAP_NET_ADMIN)) 4003b47d303SEric Dumazet return -EPERM; 4013b47d303SEric Dumazet 4023b47d303SEric Dumazet return netdev_store(dev, attr, buf, len, change_gro_flush_timeout); 4033b47d303SEric Dumazet } 4043b47d303SEric Dumazet NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong); 4053b47d303SEric Dumazet 4066f8b12d6SEric Dumazet static int change_napi_defer_hard_irqs(struct net_device *dev, unsigned long val) 4076f8b12d6SEric Dumazet { 4087e417a66SEric Dumazet WRITE_ONCE(dev->napi_defer_hard_irqs, val); 4096f8b12d6SEric Dumazet return 0; 4106f8b12d6SEric Dumazet } 4116f8b12d6SEric Dumazet 4126f8b12d6SEric Dumazet static ssize_t napi_defer_hard_irqs_store(struct device *dev, 4136f8b12d6SEric Dumazet struct device_attribute *attr, 4146f8b12d6SEric Dumazet const char *buf, size_t len) 4156f8b12d6SEric Dumazet { 4166f8b12d6SEric Dumazet if (!capable(CAP_NET_ADMIN)) 4176f8b12d6SEric Dumazet return -EPERM; 4186f8b12d6SEric Dumazet 4196f8b12d6SEric Dumazet return netdev_store(dev, attr, buf, len, change_napi_defer_hard_irqs); 4206f8b12d6SEric Dumazet } 4216f8b12d6SEric Dumazet NETDEVICE_SHOW_RW(napi_defer_hard_irqs, fmt_dec); 4226f8b12d6SEric Dumazet 4236be8aeefSGreg Kroah-Hartman static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr, 4240b815a1aSStephen Hemminger const char *buf, size_t len) 4250b815a1aSStephen Hemminger { 4260b815a1aSStephen Hemminger struct net_device *netdev = to_net_dev(dev); 4275e1fccc0SEric W. Biederman struct net *net = dev_net(netdev); 4280b815a1aSStephen Hemminger size_t count = len; 429c92eb77aSRoopa Prabhu ssize_t ret = 0; 4300b815a1aSStephen Hemminger 4315e1fccc0SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 4320b815a1aSStephen Hemminger return -EPERM; 4330b815a1aSStephen Hemminger 4340b815a1aSStephen Hemminger /* ignore trailing newline */ 4350b815a1aSStephen Hemminger if (len > 0 && buf[len - 1] == '\n') 4360b815a1aSStephen Hemminger --count; 4370b815a1aSStephen Hemminger 438c92eb77aSRoopa Prabhu if (!rtnl_trylock()) 439c92eb77aSRoopa Prabhu return restart_syscall(); 4400b815a1aSStephen Hemminger 441c92eb77aSRoopa Prabhu if (dev_isalive(netdev)) { 442c92eb77aSRoopa Prabhu ret = dev_set_alias(netdev, buf, count); 443c92eb77aSRoopa Prabhu if (ret < 0) 444c92eb77aSRoopa Prabhu goto err; 445c92eb77aSRoopa Prabhu ret = len; 446c92eb77aSRoopa Prabhu netdev_state_change(netdev); 447c92eb77aSRoopa Prabhu } 448c92eb77aSRoopa Prabhu err: 449c92eb77aSRoopa Prabhu rtnl_unlock(); 450c92eb77aSRoopa Prabhu 451c92eb77aSRoopa Prabhu return ret; 4520b815a1aSStephen Hemminger } 4530b815a1aSStephen Hemminger 4546be8aeefSGreg Kroah-Hartman static ssize_t ifalias_show(struct device *dev, 4550b815a1aSStephen Hemminger struct device_attribute *attr, char *buf) 4560b815a1aSStephen Hemminger { 4570b815a1aSStephen Hemminger const struct net_device *netdev = to_net_dev(dev); 4586c557001SFlorian Westphal char tmp[IFALIASZ]; 4590b815a1aSStephen Hemminger ssize_t ret = 0; 4600b815a1aSStephen Hemminger 4616c557001SFlorian Westphal ret = dev_get_alias(netdev, tmp, sizeof(tmp)); 4626c557001SFlorian Westphal if (ret > 0) 4636c557001SFlorian Westphal ret = sprintf(buf, "%s\n", tmp); 4640b815a1aSStephen Hemminger return ret; 4650b815a1aSStephen Hemminger } 4666be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(ifalias); 467a512b92bSVlad Dogaru 4686b53dafeSWANG Cong static int change_group(struct net_device *dev, unsigned long new_group) 469a512b92bSVlad Dogaru { 4706b53dafeSWANG Cong dev_set_group(dev, (int)new_group); 471a512b92bSVlad Dogaru return 0; 472a512b92bSVlad Dogaru } 473a512b92bSVlad Dogaru 4746be8aeefSGreg Kroah-Hartman static ssize_t group_store(struct device *dev, struct device_attribute *attr, 475a512b92bSVlad Dogaru const char *buf, size_t len) 476a512b92bSVlad Dogaru { 477a512b92bSVlad Dogaru return netdev_store(dev, attr, buf, len, change_group); 478a512b92bSVlad Dogaru } 4796be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(group, fmt_dec); 480d6444062SJoe Perches static DEVICE_ATTR(netdev_group, 0644, group_show, group_store); 481a512b92bSVlad Dogaru 482d746d707SAnuradha Karuppiah static int change_proto_down(struct net_device *dev, unsigned long proto_down) 483d746d707SAnuradha Karuppiah { 484d746d707SAnuradha Karuppiah return dev_change_proto_down(dev, (bool)proto_down); 485d746d707SAnuradha Karuppiah } 486d746d707SAnuradha Karuppiah 487d746d707SAnuradha Karuppiah static ssize_t proto_down_store(struct device *dev, 488d746d707SAnuradha Karuppiah struct device_attribute *attr, 489d746d707SAnuradha Karuppiah const char *buf, size_t len) 490d746d707SAnuradha Karuppiah { 491d746d707SAnuradha Karuppiah return netdev_store(dev, attr, buf, len, change_proto_down); 492d746d707SAnuradha Karuppiah } 493d746d707SAnuradha Karuppiah NETDEVICE_SHOW_RW(proto_down, fmt_dec); 494d746d707SAnuradha Karuppiah 495cc998ff8SLinus Torvalds static ssize_t phys_port_id_show(struct device *dev, 496ff80e519SJiri Pirko struct device_attribute *attr, char *buf) 497ff80e519SJiri Pirko { 498ff80e519SJiri Pirko struct net_device *netdev = to_net_dev(dev); 499ff80e519SJiri Pirko ssize_t ret = -EINVAL; 500ff80e519SJiri Pirko 501146e5e73SAntoine Tenart /* The check is also done in dev_get_phys_port_id; this helps returning 502146e5e73SAntoine Tenart * early without hitting the trylock/restart below. 503146e5e73SAntoine Tenart */ 504146e5e73SAntoine Tenart if (!netdev->netdev_ops->ndo_get_phys_port_id) 505146e5e73SAntoine Tenart return -EOPNOTSUPP; 506146e5e73SAntoine Tenart 507ff80e519SJiri Pirko if (!rtnl_trylock()) 508ff80e519SJiri Pirko return restart_syscall(); 509ff80e519SJiri Pirko 510ff80e519SJiri Pirko if (dev_isalive(netdev)) { 51102637fceSJiri Pirko struct netdev_phys_item_id ppid; 512ff80e519SJiri Pirko 513ff80e519SJiri Pirko ret = dev_get_phys_port_id(netdev, &ppid); 514ff80e519SJiri Pirko if (!ret) 515ff80e519SJiri Pirko ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); 516ff80e519SJiri Pirko } 517ff80e519SJiri Pirko rtnl_unlock(); 518ff80e519SJiri Pirko 519ff80e519SJiri Pirko return ret; 520ff80e519SJiri Pirko } 521cc998ff8SLinus Torvalds static DEVICE_ATTR_RO(phys_port_id); 522ff80e519SJiri Pirko 523db24a904SDavid Ahern static ssize_t phys_port_name_show(struct device *dev, 524db24a904SDavid Ahern struct device_attribute *attr, char *buf) 525db24a904SDavid Ahern { 526db24a904SDavid Ahern struct net_device *netdev = to_net_dev(dev); 527db24a904SDavid Ahern ssize_t ret = -EINVAL; 528db24a904SDavid Ahern 529146e5e73SAntoine Tenart /* The checks are also done in dev_get_phys_port_name; this helps 530146e5e73SAntoine Tenart * returning early without hitting the trylock/restart below. 531146e5e73SAntoine Tenart */ 532146e5e73SAntoine Tenart if (!netdev->netdev_ops->ndo_get_phys_port_name && 533146e5e73SAntoine Tenart !netdev->netdev_ops->ndo_get_devlink_port) 534146e5e73SAntoine Tenart return -EOPNOTSUPP; 535146e5e73SAntoine Tenart 536db24a904SDavid Ahern if (!rtnl_trylock()) 537db24a904SDavid Ahern return restart_syscall(); 538db24a904SDavid Ahern 539db24a904SDavid Ahern if (dev_isalive(netdev)) { 540db24a904SDavid Ahern char name[IFNAMSIZ]; 541db24a904SDavid Ahern 542db24a904SDavid Ahern ret = dev_get_phys_port_name(netdev, name, sizeof(name)); 543db24a904SDavid Ahern if (!ret) 544db24a904SDavid Ahern ret = sprintf(buf, "%s\n", name); 545db24a904SDavid Ahern } 546db24a904SDavid Ahern rtnl_unlock(); 547db24a904SDavid Ahern 548db24a904SDavid Ahern return ret; 549db24a904SDavid Ahern } 550db24a904SDavid Ahern static DEVICE_ATTR_RO(phys_port_name); 551db24a904SDavid Ahern 552aecbe01eSJiri Pirko static ssize_t phys_switch_id_show(struct device *dev, 553aecbe01eSJiri Pirko struct device_attribute *attr, char *buf) 554aecbe01eSJiri Pirko { 555aecbe01eSJiri Pirko struct net_device *netdev = to_net_dev(dev); 556aecbe01eSJiri Pirko ssize_t ret = -EINVAL; 557aecbe01eSJiri Pirko 558146e5e73SAntoine Tenart /* The checks are also done in dev_get_phys_port_name; this helps 559146e5e73SAntoine Tenart * returning early without hitting the trylock/restart below. This works 560146e5e73SAntoine Tenart * because recurse is false when calling dev_get_port_parent_id. 561146e5e73SAntoine Tenart */ 562146e5e73SAntoine Tenart if (!netdev->netdev_ops->ndo_get_port_parent_id && 563146e5e73SAntoine Tenart !netdev->netdev_ops->ndo_get_devlink_port) 564146e5e73SAntoine Tenart return -EOPNOTSUPP; 565146e5e73SAntoine Tenart 566aecbe01eSJiri Pirko if (!rtnl_trylock()) 567aecbe01eSJiri Pirko return restart_syscall(); 568aecbe01eSJiri Pirko 569aecbe01eSJiri Pirko if (dev_isalive(netdev)) { 570bccb3025SFlorian Fainelli struct netdev_phys_item_id ppid = { }; 571aecbe01eSJiri Pirko 572bccb3025SFlorian Fainelli ret = dev_get_port_parent_id(netdev, &ppid, false); 573aecbe01eSJiri Pirko if (!ret) 574bccb3025SFlorian Fainelli ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); 575aecbe01eSJiri Pirko } 576aecbe01eSJiri Pirko rtnl_unlock(); 577aecbe01eSJiri Pirko 578aecbe01eSJiri Pirko return ret; 579aecbe01eSJiri Pirko } 580aecbe01eSJiri Pirko static DEVICE_ATTR_RO(phys_switch_id); 581aecbe01eSJiri Pirko 5825fdd2f0eSWei Wang static ssize_t threaded_show(struct device *dev, 5835fdd2f0eSWei Wang struct device_attribute *attr, char *buf) 5845fdd2f0eSWei Wang { 5855fdd2f0eSWei Wang struct net_device *netdev = to_net_dev(dev); 5865fdd2f0eSWei Wang ssize_t ret = -EINVAL; 5875fdd2f0eSWei Wang 5885fdd2f0eSWei Wang if (!rtnl_trylock()) 5895fdd2f0eSWei Wang return restart_syscall(); 5905fdd2f0eSWei Wang 5915fdd2f0eSWei Wang if (dev_isalive(netdev)) 5925fdd2f0eSWei Wang ret = sprintf(buf, fmt_dec, netdev->threaded); 5935fdd2f0eSWei Wang 5945fdd2f0eSWei Wang rtnl_unlock(); 5955fdd2f0eSWei Wang return ret; 5965fdd2f0eSWei Wang } 5975fdd2f0eSWei Wang 5985fdd2f0eSWei Wang static int modify_napi_threaded(struct net_device *dev, unsigned long val) 5995fdd2f0eSWei Wang { 6005fdd2f0eSWei Wang int ret; 6015fdd2f0eSWei Wang 6025fdd2f0eSWei Wang if (list_empty(&dev->napi_list)) 6035fdd2f0eSWei Wang return -EOPNOTSUPP; 6045fdd2f0eSWei Wang 6055fdd2f0eSWei Wang if (val != 0 && val != 1) 6065fdd2f0eSWei Wang return -EOPNOTSUPP; 6075fdd2f0eSWei Wang 6085fdd2f0eSWei Wang ret = dev_set_threaded(dev, val); 6095fdd2f0eSWei Wang 6105fdd2f0eSWei Wang return ret; 6115fdd2f0eSWei Wang } 6125fdd2f0eSWei Wang 6135fdd2f0eSWei Wang static ssize_t threaded_store(struct device *dev, 6145fdd2f0eSWei Wang struct device_attribute *attr, 6155fdd2f0eSWei Wang const char *buf, size_t len) 6165fdd2f0eSWei Wang { 6175fdd2f0eSWei Wang return netdev_store(dev, attr, buf, len, modify_napi_threaded); 6185fdd2f0eSWei Wang } 6195fdd2f0eSWei Wang static DEVICE_ATTR_RW(threaded); 6205fdd2f0eSWei Wang 621ec6cc599Sstephen hemminger static struct attribute *net_class_attrs[] __ro_after_init = { 6226be8aeefSGreg Kroah-Hartman &dev_attr_netdev_group.attr, 6236be8aeefSGreg Kroah-Hartman &dev_attr_type.attr, 6246be8aeefSGreg Kroah-Hartman &dev_attr_dev_id.attr, 6253f85944fSAmir Vadai &dev_attr_dev_port.attr, 6266be8aeefSGreg Kroah-Hartman &dev_attr_iflink.attr, 6276be8aeefSGreg Kroah-Hartman &dev_attr_ifindex.attr, 628685343fcSTom Gundersen &dev_attr_name_assign_type.attr, 6296be8aeefSGreg Kroah-Hartman &dev_attr_addr_assign_type.attr, 6306be8aeefSGreg Kroah-Hartman &dev_attr_addr_len.attr, 6316be8aeefSGreg Kroah-Hartman &dev_attr_link_mode.attr, 6326be8aeefSGreg Kroah-Hartman &dev_attr_address.attr, 6336be8aeefSGreg Kroah-Hartman &dev_attr_broadcast.attr, 6346be8aeefSGreg Kroah-Hartman &dev_attr_speed.attr, 6356be8aeefSGreg Kroah-Hartman &dev_attr_duplex.attr, 6366be8aeefSGreg Kroah-Hartman &dev_attr_dormant.attr, 637db30a577SAndrew Lunn &dev_attr_testing.attr, 6386be8aeefSGreg Kroah-Hartman &dev_attr_operstate.attr, 6392d3b479dSdavid decotigny &dev_attr_carrier_changes.attr, 6406be8aeefSGreg Kroah-Hartman &dev_attr_ifalias.attr, 6416be8aeefSGreg Kroah-Hartman &dev_attr_carrier.attr, 6426be8aeefSGreg Kroah-Hartman &dev_attr_mtu.attr, 6436be8aeefSGreg Kroah-Hartman &dev_attr_flags.attr, 6446be8aeefSGreg Kroah-Hartman &dev_attr_tx_queue_len.attr, 6453b47d303SEric Dumazet &dev_attr_gro_flush_timeout.attr, 6466f8b12d6SEric Dumazet &dev_attr_napi_defer_hard_irqs.attr, 647cc998ff8SLinus Torvalds &dev_attr_phys_port_id.attr, 648db24a904SDavid Ahern &dev_attr_phys_port_name.attr, 649aecbe01eSJiri Pirko &dev_attr_phys_switch_id.attr, 650d746d707SAnuradha Karuppiah &dev_attr_proto_down.attr, 651b2d3bcfaSDavid Decotigny &dev_attr_carrier_up_count.attr, 652b2d3bcfaSDavid Decotigny &dev_attr_carrier_down_count.attr, 6535fdd2f0eSWei Wang &dev_attr_threaded.attr, 6546be8aeefSGreg Kroah-Hartman NULL, 6551da177e4SLinus Torvalds }; 6566be8aeefSGreg Kroah-Hartman ATTRIBUTE_GROUPS(net_class); 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds /* Show a given an attribute in the statistics group */ 65943cb76d9SGreg Kroah-Hartman static ssize_t netstat_show(const struct device *d, 66043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 6611da177e4SLinus Torvalds unsigned long offset) 6621da177e4SLinus Torvalds { 66343cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 6641da177e4SLinus Torvalds ssize_t ret = -EINVAL; 6651da177e4SLinus Torvalds 666be1f3c2cSBen Hutchings WARN_ON(offset > sizeof(struct rtnl_link_stats64) || 667be1f3c2cSBen Hutchings offset % sizeof(u64) != 0); 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds read_lock(&dev_base_lock); 67096e74088SPavel Emelyanov if (dev_isalive(dev)) { 67128172739SEric Dumazet struct rtnl_link_stats64 temp; 67228172739SEric Dumazet const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); 67328172739SEric Dumazet 674be1f3c2cSBen Hutchings ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *)stats) + offset)); 67596e74088SPavel Emelyanov } 6761da177e4SLinus Torvalds read_unlock(&dev_base_lock); 6771da177e4SLinus Torvalds return ret; 6781da177e4SLinus Torvalds } 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds /* generate a read-only statistics attribute */ 6811da177e4SLinus Torvalds #define NETSTAT_ENTRY(name) \ 6826be8aeefSGreg Kroah-Hartman static ssize_t name##_show(struct device *d, \ 68343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 6841da177e4SLinus Torvalds { \ 68543cb76d9SGreg Kroah-Hartman return netstat_show(d, attr, buf, \ 686be1f3c2cSBen Hutchings offsetof(struct rtnl_link_stats64, name)); \ 6871da177e4SLinus Torvalds } \ 6886be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(name) 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds NETSTAT_ENTRY(rx_packets); 6911da177e4SLinus Torvalds NETSTAT_ENTRY(tx_packets); 6921da177e4SLinus Torvalds NETSTAT_ENTRY(rx_bytes); 6931da177e4SLinus Torvalds NETSTAT_ENTRY(tx_bytes); 6941da177e4SLinus Torvalds NETSTAT_ENTRY(rx_errors); 6951da177e4SLinus Torvalds NETSTAT_ENTRY(tx_errors); 6961da177e4SLinus Torvalds NETSTAT_ENTRY(rx_dropped); 6971da177e4SLinus Torvalds NETSTAT_ENTRY(tx_dropped); 6981da177e4SLinus Torvalds NETSTAT_ENTRY(multicast); 6991da177e4SLinus Torvalds NETSTAT_ENTRY(collisions); 7001da177e4SLinus Torvalds NETSTAT_ENTRY(rx_length_errors); 7011da177e4SLinus Torvalds NETSTAT_ENTRY(rx_over_errors); 7021da177e4SLinus Torvalds NETSTAT_ENTRY(rx_crc_errors); 7031da177e4SLinus Torvalds NETSTAT_ENTRY(rx_frame_errors); 7041da177e4SLinus Torvalds NETSTAT_ENTRY(rx_fifo_errors); 7051da177e4SLinus Torvalds NETSTAT_ENTRY(rx_missed_errors); 7061da177e4SLinus Torvalds NETSTAT_ENTRY(tx_aborted_errors); 7071da177e4SLinus Torvalds NETSTAT_ENTRY(tx_carrier_errors); 7081da177e4SLinus Torvalds NETSTAT_ENTRY(tx_fifo_errors); 7091da177e4SLinus Torvalds NETSTAT_ENTRY(tx_heartbeat_errors); 7101da177e4SLinus Torvalds NETSTAT_ENTRY(tx_window_errors); 7111da177e4SLinus Torvalds NETSTAT_ENTRY(rx_compressed); 7121da177e4SLinus Torvalds NETSTAT_ENTRY(tx_compressed); 7136e7333d3SJarod Wilson NETSTAT_ENTRY(rx_nohandler); 7141da177e4SLinus Torvalds 715ec6cc599Sstephen hemminger static struct attribute *netstat_attrs[] __ro_after_init = { 71643cb76d9SGreg Kroah-Hartman &dev_attr_rx_packets.attr, 71743cb76d9SGreg Kroah-Hartman &dev_attr_tx_packets.attr, 71843cb76d9SGreg Kroah-Hartman &dev_attr_rx_bytes.attr, 71943cb76d9SGreg Kroah-Hartman &dev_attr_tx_bytes.attr, 72043cb76d9SGreg Kroah-Hartman &dev_attr_rx_errors.attr, 72143cb76d9SGreg Kroah-Hartman &dev_attr_tx_errors.attr, 72243cb76d9SGreg Kroah-Hartman &dev_attr_rx_dropped.attr, 72343cb76d9SGreg Kroah-Hartman &dev_attr_tx_dropped.attr, 72443cb76d9SGreg Kroah-Hartman &dev_attr_multicast.attr, 72543cb76d9SGreg Kroah-Hartman &dev_attr_collisions.attr, 72643cb76d9SGreg Kroah-Hartman &dev_attr_rx_length_errors.attr, 72743cb76d9SGreg Kroah-Hartman &dev_attr_rx_over_errors.attr, 72843cb76d9SGreg Kroah-Hartman &dev_attr_rx_crc_errors.attr, 72943cb76d9SGreg Kroah-Hartman &dev_attr_rx_frame_errors.attr, 73043cb76d9SGreg Kroah-Hartman &dev_attr_rx_fifo_errors.attr, 73143cb76d9SGreg Kroah-Hartman &dev_attr_rx_missed_errors.attr, 73243cb76d9SGreg Kroah-Hartman &dev_attr_tx_aborted_errors.attr, 73343cb76d9SGreg Kroah-Hartman &dev_attr_tx_carrier_errors.attr, 73443cb76d9SGreg Kroah-Hartman &dev_attr_tx_fifo_errors.attr, 73543cb76d9SGreg Kroah-Hartman &dev_attr_tx_heartbeat_errors.attr, 73643cb76d9SGreg Kroah-Hartman &dev_attr_tx_window_errors.attr, 73743cb76d9SGreg Kroah-Hartman &dev_attr_rx_compressed.attr, 73843cb76d9SGreg Kroah-Hartman &dev_attr_tx_compressed.attr, 7396e7333d3SJarod Wilson &dev_attr_rx_nohandler.attr, 7401da177e4SLinus Torvalds NULL 7411da177e4SLinus Torvalds }; 7421da177e4SLinus Torvalds 74338ef00ccSArvind Yadav static const struct attribute_group netstat_group = { 7441da177e4SLinus Torvalds .name = "statistics", 7451da177e4SLinus Torvalds .attrs = netstat_attrs, 7461da177e4SLinus Torvalds }; 74738c1a01cSJohannes Berg 74838c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) 74938c1a01cSJohannes Berg static struct attribute *wireless_attrs[] = { 75038c1a01cSJohannes Berg NULL 75138c1a01cSJohannes Berg }; 75238c1a01cSJohannes Berg 75338ef00ccSArvind Yadav static const struct attribute_group wireless_group = { 75438c1a01cSJohannes Berg .name = "wireless", 75538c1a01cSJohannes Berg .attrs = wireless_attrs, 75638c1a01cSJohannes Berg }; 75738c1a01cSJohannes Berg #endif 7586be8aeefSGreg Kroah-Hartman 7596be8aeefSGreg Kroah-Hartman #else /* CONFIG_SYSFS */ 7606be8aeefSGreg Kroah-Hartman #define net_class_groups NULL 761d6523ddfSEric W. Biederman #endif /* CONFIG_SYSFS */ 7621da177e4SLinus Torvalds 763a953be53SMichael Dalton #ifdef CONFIG_SYSFS 7646648c65eSstephen hemminger #define to_rx_queue_attr(_attr) \ 7656648c65eSstephen hemminger container_of(_attr, struct rx_queue_attribute, attr) 7660a9627f2STom Herbert 7670a9627f2STom Herbert #define to_rx_queue(obj) container_of(obj, struct netdev_rx_queue, kobj) 7680a9627f2STom Herbert 7690a9627f2STom Herbert static ssize_t rx_queue_attr_show(struct kobject *kobj, struct attribute *attr, 7700a9627f2STom Herbert char *buf) 7710a9627f2STom Herbert { 772667e427bSstephen hemminger const struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 7730a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 7740a9627f2STom Herbert 7750a9627f2STom Herbert if (!attribute->show) 7760a9627f2STom Herbert return -EIO; 7770a9627f2STom Herbert 778718ad681Sstephen hemminger return attribute->show(queue, buf); 7790a9627f2STom Herbert } 7800a9627f2STom Herbert 7810a9627f2STom Herbert static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr, 7820a9627f2STom Herbert const char *buf, size_t count) 7830a9627f2STom Herbert { 784667e427bSstephen hemminger const struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 7850a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 7860a9627f2STom Herbert 7870a9627f2STom Herbert if (!attribute->store) 7880a9627f2STom Herbert return -EIO; 7890a9627f2STom Herbert 790718ad681Sstephen hemminger return attribute->store(queue, buf, count); 7910a9627f2STom Herbert } 7920a9627f2STom Herbert 793fa50d645Sstephen hemminger static const struct sysfs_ops rx_queue_sysfs_ops = { 7940a9627f2STom Herbert .show = rx_queue_attr_show, 7950a9627f2STom Herbert .store = rx_queue_attr_store, 7960a9627f2STom Herbert }; 7970a9627f2STom Herbert 798a953be53SMichael Dalton #ifdef CONFIG_RPS 799718ad681Sstephen hemminger static ssize_t show_rps_map(struct netdev_rx_queue *queue, char *buf) 8000a9627f2STom Herbert { 8010a9627f2STom Herbert struct rps_map *map; 8020a9627f2STom Herbert cpumask_var_t mask; 803f0906827STejun Heo int i, len; 8040a9627f2STom Herbert 8050a9627f2STom Herbert if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 8060a9627f2STom Herbert return -ENOMEM; 8070a9627f2STom Herbert 8080a9627f2STom Herbert rcu_read_lock(); 8090a9627f2STom Herbert map = rcu_dereference(queue->rps_map); 8100a9627f2STom Herbert if (map) 8110a9627f2STom Herbert for (i = 0; i < map->len; i++) 8120a9627f2STom Herbert cpumask_set_cpu(map->cpus[i], mask); 8130a9627f2STom Herbert 814f0906827STejun Heo len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask)); 8150a9627f2STom Herbert rcu_read_unlock(); 8160a9627f2STom Herbert free_cpumask_var(mask); 8170a9627f2STom Herbert 818f0906827STejun Heo return len < PAGE_SIZE ? len : -EINVAL; 8190a9627f2STom Herbert } 8200a9627f2STom Herbert 821f5acb907SEric Dumazet static ssize_t store_rps_map(struct netdev_rx_queue *queue, 8220a9627f2STom Herbert const char *buf, size_t len) 8230a9627f2STom Herbert { 8240a9627f2STom Herbert struct rps_map *old_map, *map; 8250a9627f2STom Herbert cpumask_var_t mask; 82607bbecb3SAlex Belits int err, cpu, i, hk_flags; 827da65ad1fSSasha Levin static DEFINE_MUTEX(rps_map_mutex); 8280a9627f2STom Herbert 8290a9627f2STom Herbert if (!capable(CAP_NET_ADMIN)) 8300a9627f2STom Herbert return -EPERM; 8310a9627f2STom Herbert 8320a9627f2STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 8330a9627f2STom Herbert return -ENOMEM; 8340a9627f2STom Herbert 8350a9627f2STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 8360a9627f2STom Herbert if (err) { 8370a9627f2STom Herbert free_cpumask_var(mask); 8380a9627f2STom Herbert return err; 8390a9627f2STom Herbert } 8400a9627f2STom Herbert 8412e0d8fefSEric Dumazet if (!cpumask_empty(mask)) { 84207bbecb3SAlex Belits hk_flags = HK_FLAG_DOMAIN | HK_FLAG_WQ; 84307bbecb3SAlex Belits cpumask_and(mask, mask, housekeeping_cpumask(hk_flags)); 84407bbecb3SAlex Belits if (cpumask_empty(mask)) { 84507bbecb3SAlex Belits free_cpumask_var(mask); 84607bbecb3SAlex Belits return -EINVAL; 84707bbecb3SAlex Belits } 8482e0d8fefSEric Dumazet } 84907bbecb3SAlex Belits 85095c96174SEric Dumazet map = kzalloc(max_t(unsigned int, 8510a9627f2STom Herbert RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), 8520a9627f2STom Herbert GFP_KERNEL); 8530a9627f2STom Herbert if (!map) { 8540a9627f2STom Herbert free_cpumask_var(mask); 8550a9627f2STom Herbert return -ENOMEM; 8560a9627f2STom Herbert } 8570a9627f2STom Herbert 8580a9627f2STom Herbert i = 0; 8590a9627f2STom Herbert for_each_cpu_and(cpu, mask, cpu_online_mask) 8600a9627f2STom Herbert map->cpus[i++] = cpu; 8610a9627f2STom Herbert 8626648c65eSstephen hemminger if (i) { 8630a9627f2STom Herbert map->len = i; 8646648c65eSstephen hemminger } else { 8650a9627f2STom Herbert kfree(map); 8660a9627f2STom Herbert map = NULL; 8670a9627f2STom Herbert } 8680a9627f2STom Herbert 869da65ad1fSSasha Levin mutex_lock(&rps_map_mutex); 8706e3f7fafSEric Dumazet old_map = rcu_dereference_protected(queue->rps_map, 871da65ad1fSSasha Levin mutex_is_locked(&rps_map_mutex)); 8720a9627f2STom Herbert rcu_assign_pointer(queue->rps_map, map); 8730a9627f2STom Herbert 874adc9300eSEric Dumazet if (map) 875dc05360fSEric Dumazet static_branch_inc(&rps_needed); 87610e4ea75STom Herbert if (old_map) 877dc05360fSEric Dumazet static_branch_dec(&rps_needed); 87810e4ea75STom Herbert 879da65ad1fSSasha Levin mutex_unlock(&rps_map_mutex); 88010e4ea75STom Herbert 88110e4ea75STom Herbert if (old_map) 88210e4ea75STom Herbert kfree_rcu(old_map, rcu); 88310e4ea75STom Herbert 8840a9627f2STom Herbert free_cpumask_var(mask); 8850a9627f2STom Herbert return len; 8860a9627f2STom Herbert } 8870a9627f2STom Herbert 888fec5e652STom Herbert static ssize_t show_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 889fec5e652STom Herbert char *buf) 890fec5e652STom Herbert { 891fec5e652STom Herbert struct rps_dev_flow_table *flow_table; 89260b778ceSEric Dumazet unsigned long val = 0; 893fec5e652STom Herbert 894fec5e652STom Herbert rcu_read_lock(); 895fec5e652STom Herbert flow_table = rcu_dereference(queue->rps_flow_table); 896fec5e652STom Herbert if (flow_table) 89760b778ceSEric Dumazet val = (unsigned long)flow_table->mask + 1; 898fec5e652STom Herbert rcu_read_unlock(); 899fec5e652STom Herbert 90060b778ceSEric Dumazet return sprintf(buf, "%lu\n", val); 901fec5e652STom Herbert } 902fec5e652STom Herbert 903fec5e652STom Herbert static void rps_dev_flow_table_release(struct rcu_head *rcu) 904fec5e652STom Herbert { 905fec5e652STom Herbert struct rps_dev_flow_table *table = container_of(rcu, 906fec5e652STom Herbert struct rps_dev_flow_table, rcu); 907243198d0SAl Viro vfree(table); 908fec5e652STom Herbert } 909fec5e652STom Herbert 910f5acb907SEric Dumazet static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 911fec5e652STom Herbert const char *buf, size_t len) 912fec5e652STom Herbert { 91360b778ceSEric Dumazet unsigned long mask, count; 914fec5e652STom Herbert struct rps_dev_flow_table *table, *old_table; 915fec5e652STom Herbert static DEFINE_SPINLOCK(rps_dev_flow_lock); 91660b778ceSEric Dumazet int rc; 917fec5e652STom Herbert 918fec5e652STom Herbert if (!capable(CAP_NET_ADMIN)) 919fec5e652STom Herbert return -EPERM; 920fec5e652STom Herbert 92160b778ceSEric Dumazet rc = kstrtoul(buf, 0, &count); 92260b778ceSEric Dumazet if (rc < 0) 92360b778ceSEric Dumazet return rc; 924fec5e652STom Herbert 925fec5e652STom Herbert if (count) { 92660b778ceSEric Dumazet mask = count - 1; 92760b778ceSEric Dumazet /* mask = roundup_pow_of_two(count) - 1; 92860b778ceSEric Dumazet * without overflows... 92960b778ceSEric Dumazet */ 93060b778ceSEric Dumazet while ((mask | (mask >> 1)) != mask) 93160b778ceSEric Dumazet mask |= (mask >> 1); 93260b778ceSEric Dumazet /* On 64 bit arches, must check mask fits in table->mask (u32), 9338e3bff96Sstephen hemminger * and on 32bit arches, must check 9348e3bff96Sstephen hemminger * RPS_DEV_FLOW_TABLE_SIZE(mask + 1) doesn't overflow. 93560b778ceSEric Dumazet */ 93660b778ceSEric Dumazet #if BITS_PER_LONG > 32 93760b778ceSEric Dumazet if (mask > (unsigned long)(u32)mask) 938a0a129f8SXi Wang return -EINVAL; 93960b778ceSEric Dumazet #else 94060b778ceSEric Dumazet if (mask > (ULONG_MAX - RPS_DEV_FLOW_TABLE_SIZE(1)) 941a0a129f8SXi Wang / sizeof(struct rps_dev_flow)) { 942fec5e652STom Herbert /* Enforce a limit to prevent overflow */ 943fec5e652STom Herbert return -EINVAL; 944fec5e652STom Herbert } 94560b778ceSEric Dumazet #endif 94660b778ceSEric Dumazet table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(mask + 1)); 947fec5e652STom Herbert if (!table) 948fec5e652STom Herbert return -ENOMEM; 949fec5e652STom Herbert 95060b778ceSEric Dumazet table->mask = mask; 95160b778ceSEric Dumazet for (count = 0; count <= mask; count++) 95260b778ceSEric Dumazet table->flows[count].cpu = RPS_NO_CPU; 9536648c65eSstephen hemminger } else { 954fec5e652STom Herbert table = NULL; 9556648c65eSstephen hemminger } 956fec5e652STom Herbert 957fec5e652STom Herbert spin_lock(&rps_dev_flow_lock); 9586e3f7fafSEric Dumazet old_table = rcu_dereference_protected(queue->rps_flow_table, 9596e3f7fafSEric Dumazet lockdep_is_held(&rps_dev_flow_lock)); 960fec5e652STom Herbert rcu_assign_pointer(queue->rps_flow_table, table); 961fec5e652STom Herbert spin_unlock(&rps_dev_flow_lock); 962fec5e652STom Herbert 963fec5e652STom Herbert if (old_table) 964fec5e652STom Herbert call_rcu(&old_table->rcu, rps_dev_flow_table_release); 965fec5e652STom Herbert 966fec5e652STom Herbert return len; 967fec5e652STom Herbert } 968fec5e652STom Herbert 969667e427bSstephen hemminger static struct rx_queue_attribute rps_cpus_attribute __ro_after_init 970d6444062SJoe Perches = __ATTR(rps_cpus, 0644, show_rps_map, store_rps_map); 9710a9627f2STom Herbert 972667e427bSstephen hemminger static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute __ro_after_init 973d6444062SJoe Perches = __ATTR(rps_flow_cnt, 0644, 974fec5e652STom Herbert show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt); 975a953be53SMichael Dalton #endif /* CONFIG_RPS */ 976fec5e652STom Herbert 977667e427bSstephen hemminger static struct attribute *rx_queue_default_attrs[] __ro_after_init = { 978a953be53SMichael Dalton #ifdef CONFIG_RPS 9790a9627f2STom Herbert &rps_cpus_attribute.attr, 980fec5e652STom Herbert &rps_dev_flow_table_cnt_attribute.attr, 981a953be53SMichael Dalton #endif 9820a9627f2STom Herbert NULL 9830a9627f2STom Herbert }; 984be0d6926SKimberly Brown ATTRIBUTE_GROUPS(rx_queue_default); 9850a9627f2STom Herbert 9860a9627f2STom Herbert static void rx_queue_release(struct kobject *kobj) 9870a9627f2STom Herbert { 9880a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 989a953be53SMichael Dalton #ifdef CONFIG_RPS 9906e3f7fafSEric Dumazet struct rps_map *map; 9916e3f7fafSEric Dumazet struct rps_dev_flow_table *flow_table; 9920a9627f2STom Herbert 99333d480ceSEric Dumazet map = rcu_dereference_protected(queue->rps_map, 1); 9949ea19481SJohn Fastabend if (map) { 9959ea19481SJohn Fastabend RCU_INIT_POINTER(queue->rps_map, NULL); 996f6f80238SLai Jiangshan kfree_rcu(map, rcu); 9979ea19481SJohn Fastabend } 9986e3f7fafSEric Dumazet 99933d480ceSEric Dumazet flow_table = rcu_dereference_protected(queue->rps_flow_table, 1); 10009ea19481SJohn Fastabend if (flow_table) { 10019ea19481SJohn Fastabend RCU_INIT_POINTER(queue->rps_flow_table, NULL); 10026e3f7fafSEric Dumazet call_rcu(&flow_table->rcu, rps_dev_flow_table_release); 10039ea19481SJohn Fastabend } 1004a953be53SMichael Dalton #endif 10050a9627f2STom Herbert 10069ea19481SJohn Fastabend memset(kobj, 0, sizeof(*kobj)); 100780e8921bSEric Dumazet dev_put_track(queue->dev, &queue->dev_tracker); 10080a9627f2STom Herbert } 10090a9627f2STom Herbert 101082ef3d5dSWeilong Chen static const void *rx_queue_namespace(struct kobject *kobj) 101182ef3d5dSWeilong Chen { 101282ef3d5dSWeilong Chen struct netdev_rx_queue *queue = to_rx_queue(kobj); 101382ef3d5dSWeilong Chen struct device *dev = &queue->dev->dev; 101482ef3d5dSWeilong Chen const void *ns = NULL; 101582ef3d5dSWeilong Chen 101682ef3d5dSWeilong Chen if (dev->class && dev->class->ns_type) 101782ef3d5dSWeilong Chen ns = dev->class->namespace(dev); 101882ef3d5dSWeilong Chen 101982ef3d5dSWeilong Chen return ns; 102082ef3d5dSWeilong Chen } 102182ef3d5dSWeilong Chen 1022b0e37c0dSDmitry Torokhov static void rx_queue_get_ownership(struct kobject *kobj, 1023b0e37c0dSDmitry Torokhov kuid_t *uid, kgid_t *gid) 1024b0e37c0dSDmitry Torokhov { 1025b0e37c0dSDmitry Torokhov const struct net *net = rx_queue_namespace(kobj); 1026b0e37c0dSDmitry Torokhov 1027b0e37c0dSDmitry Torokhov net_ns_get_ownership(net, uid, gid); 1028b0e37c0dSDmitry Torokhov } 1029b0e37c0dSDmitry Torokhov 1030667e427bSstephen hemminger static struct kobj_type rx_queue_ktype __ro_after_init = { 10310a9627f2STom Herbert .sysfs_ops = &rx_queue_sysfs_ops, 10320a9627f2STom Herbert .release = rx_queue_release, 1033be0d6926SKimberly Brown .default_groups = rx_queue_default_groups, 1034b0e37c0dSDmitry Torokhov .namespace = rx_queue_namespace, 1035b0e37c0dSDmitry Torokhov .get_ownership = rx_queue_get_ownership, 10360a9627f2STom Herbert }; 10370a9627f2STom Herbert 10386b53dafeSWANG Cong static int rx_queue_add_kobject(struct net_device *dev, int index) 10390a9627f2STom Herbert { 10406b53dafeSWANG Cong struct netdev_rx_queue *queue = dev->_rx + index; 10410a9627f2STom Herbert struct kobject *kobj = &queue->kobj; 10420a9627f2STom Herbert int error = 0; 10430a9627f2STom Herbert 1044ddd9b5e3SJouni Hogander /* Kobject_put later will trigger rx_queue_release call which 1045ddd9b5e3SJouni Hogander * decreases dev refcount: Take that reference here 1046ddd9b5e3SJouni Hogander */ 104780e8921bSEric Dumazet dev_hold_track(queue->dev, &queue->dev_tracker, GFP_KERNEL); 1048ddd9b5e3SJouni Hogander 10496b53dafeSWANG Cong kobj->kset = dev->queues_kset; 10500a9627f2STom Herbert error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, 10510a9627f2STom Herbert "rx-%u", index); 1052a953be53SMichael Dalton if (error) 1053b8eb7183SJouni Hogander goto err; 1054a953be53SMichael Dalton 10556b53dafeSWANG Cong if (dev->sysfs_rx_queue_group) { 10566b53dafeSWANG Cong error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); 1057b8eb7183SJouni Hogander if (error) 1058b8eb7183SJouni Hogander goto err; 10590a9627f2STom Herbert } 10600a9627f2STom Herbert 10610a9627f2STom Herbert kobject_uevent(kobj, KOBJ_ADD); 10620a9627f2STom Herbert 10630a9627f2STom Herbert return error; 1064b8eb7183SJouni Hogander 1065b8eb7183SJouni Hogander err: 1066b8eb7183SJouni Hogander kobject_put(kobj); 1067b8eb7183SJouni Hogander return error; 10680a9627f2STom Herbert } 1069d755407dSChristian Brauner 1070d755407dSChristian Brauner static int rx_queue_change_owner(struct net_device *dev, int index, kuid_t kuid, 1071d755407dSChristian Brauner kgid_t kgid) 1072d755407dSChristian Brauner { 1073d755407dSChristian Brauner struct netdev_rx_queue *queue = dev->_rx + index; 1074d755407dSChristian Brauner struct kobject *kobj = &queue->kobj; 1075d755407dSChristian Brauner int error; 1076d755407dSChristian Brauner 1077d755407dSChristian Brauner error = sysfs_change_owner(kobj, kuid, kgid); 1078d755407dSChristian Brauner if (error) 1079d755407dSChristian Brauner return error; 1080d755407dSChristian Brauner 1081d755407dSChristian Brauner if (dev->sysfs_rx_queue_group) 1082d755407dSChristian Brauner error = sysfs_group_change_owner( 1083d755407dSChristian Brauner kobj, dev->sysfs_rx_queue_group, kuid, kgid); 1084d755407dSChristian Brauner 1085d755407dSChristian Brauner return error; 1086d755407dSChristian Brauner } 108780dd6eacSPaul Bolle #endif /* CONFIG_SYSFS */ 10880a9627f2STom Herbert 108962fe0b40SBen Hutchings int 10906b53dafeSWANG Cong net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) 10910a9627f2STom Herbert { 1092a953be53SMichael Dalton #ifdef CONFIG_SYSFS 10930a9627f2STom Herbert int i; 10940a9627f2STom Herbert int error = 0; 10950a9627f2STom Herbert 1096a953be53SMichael Dalton #ifndef CONFIG_RPS 10976b53dafeSWANG Cong if (!dev->sysfs_rx_queue_group) 1098a953be53SMichael Dalton return 0; 1099a953be53SMichael Dalton #endif 110062fe0b40SBen Hutchings for (i = old_num; i < new_num; i++) { 11016b53dafeSWANG Cong error = rx_queue_add_kobject(dev, i); 110262fe0b40SBen Hutchings if (error) { 110362fe0b40SBen Hutchings new_num = old_num; 11040a9627f2STom Herbert break; 11050a9627f2STom Herbert } 110662fe0b40SBen Hutchings } 11070a9627f2STom Herbert 1108a953be53SMichael Dalton while (--i >= new_num) { 1109002d8a1aSAndrey Vagin struct kobject *kobj = &dev->_rx[i].kobj; 1110002d8a1aSAndrey Vagin 11118b8f3e66SChristian Brauner if (!refcount_read(&dev_net(dev)->ns.count)) 1112002d8a1aSAndrey Vagin kobj->uevent_suppress = 1; 11136b53dafeSWANG Cong if (dev->sysfs_rx_queue_group) 1114002d8a1aSAndrey Vagin sysfs_remove_group(kobj, dev->sysfs_rx_queue_group); 1115002d8a1aSAndrey Vagin kobject_put(kobj); 1116a953be53SMichael Dalton } 11170a9627f2STom Herbert 11180a9627f2STom Herbert return error; 1119bf264145STom Herbert #else 1120bf264145STom Herbert return 0; 1121bf264145STom Herbert #endif 11220a9627f2STom Herbert } 11230a9627f2STom Herbert 1124d755407dSChristian Brauner static int net_rx_queue_change_owner(struct net_device *dev, int num, 1125d755407dSChristian Brauner kuid_t kuid, kgid_t kgid) 1126d755407dSChristian Brauner { 1127d755407dSChristian Brauner #ifdef CONFIG_SYSFS 1128d755407dSChristian Brauner int error = 0; 1129d755407dSChristian Brauner int i; 1130d755407dSChristian Brauner 1131d755407dSChristian Brauner #ifndef CONFIG_RPS 1132d755407dSChristian Brauner if (!dev->sysfs_rx_queue_group) 1133d755407dSChristian Brauner return 0; 1134d755407dSChristian Brauner #endif 1135d755407dSChristian Brauner for (i = 0; i < num; i++) { 1136d755407dSChristian Brauner error = rx_queue_change_owner(dev, i, kuid, kgid); 1137d755407dSChristian Brauner if (error) 1138d755407dSChristian Brauner break; 1139d755407dSChristian Brauner } 1140d755407dSChristian Brauner 1141d755407dSChristian Brauner return error; 1142d755407dSChristian Brauner #else 1143d755407dSChristian Brauner return 0; 1144d755407dSChristian Brauner #endif 1145d755407dSChristian Brauner } 1146d755407dSChristian Brauner 1147ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 11481d24eb48STom Herbert /* 11491d24eb48STom Herbert * netdev_queue sysfs structures and functions. 11501d24eb48STom Herbert */ 11511d24eb48STom Herbert struct netdev_queue_attribute { 11521d24eb48STom Herbert struct attribute attr; 1153718ad681Sstephen hemminger ssize_t (*show)(struct netdev_queue *queue, char *buf); 11541d24eb48STom Herbert ssize_t (*store)(struct netdev_queue *queue, 1155718ad681Sstephen hemminger const char *buf, size_t len); 11561d24eb48STom Herbert }; 11576648c65eSstephen hemminger #define to_netdev_queue_attr(_attr) \ 11586648c65eSstephen hemminger container_of(_attr, struct netdev_queue_attribute, attr) 11591d24eb48STom Herbert 11601d24eb48STom Herbert #define to_netdev_queue(obj) container_of(obj, struct netdev_queue, kobj) 11611d24eb48STom Herbert 11621d24eb48STom Herbert static ssize_t netdev_queue_attr_show(struct kobject *kobj, 11631d24eb48STom Herbert struct attribute *attr, char *buf) 116462fe0b40SBen Hutchings { 1165667e427bSstephen hemminger const struct netdev_queue_attribute *attribute 1166667e427bSstephen hemminger = to_netdev_queue_attr(attr); 11671d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 11681d24eb48STom Herbert 11691d24eb48STom Herbert if (!attribute->show) 11701d24eb48STom Herbert return -EIO; 11711d24eb48STom Herbert 1172718ad681Sstephen hemminger return attribute->show(queue, buf); 11731d24eb48STom Herbert } 11741d24eb48STom Herbert 11751d24eb48STom Herbert static ssize_t netdev_queue_attr_store(struct kobject *kobj, 11761d24eb48STom Herbert struct attribute *attr, 11771d24eb48STom Herbert const char *buf, size_t count) 11781d24eb48STom Herbert { 1179667e427bSstephen hemminger const struct netdev_queue_attribute *attribute 1180667e427bSstephen hemminger = to_netdev_queue_attr(attr); 11811d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 11821d24eb48STom Herbert 11831d24eb48STom Herbert if (!attribute->store) 11841d24eb48STom Herbert return -EIO; 11851d24eb48STom Herbert 1186718ad681Sstephen hemminger return attribute->store(queue, buf, count); 11871d24eb48STom Herbert } 11881d24eb48STom Herbert 11891d24eb48STom Herbert static const struct sysfs_ops netdev_queue_sysfs_ops = { 11901d24eb48STom Herbert .show = netdev_queue_attr_show, 11911d24eb48STom Herbert .store = netdev_queue_attr_store, 11921d24eb48STom Herbert }; 11931d24eb48STom Herbert 11942b9c7581Sstephen hemminger static ssize_t tx_timeout_show(struct netdev_queue *queue, char *buf) 1195ccf5ff69Sdavid decotigny { 11968160fb43SEric Dumazet unsigned long trans_timeout = atomic_long_read(&queue->trans_timeout); 1197ccf5ff69Sdavid decotigny 11989bb5fbeaSXiongfeng Wang return sprintf(buf, fmt_ulong, trans_timeout); 1199ccf5ff69Sdavid decotigny } 1200ccf5ff69Sdavid decotigny 1201c4047f53SThadeu Lima de Souza Cascardo static unsigned int get_netdev_queue_index(struct netdev_queue *queue) 1202822b3b2eSJohn Fastabend { 1203822b3b2eSJohn Fastabend struct net_device *dev = queue->dev; 1204c4047f53SThadeu Lima de Souza Cascardo unsigned int i; 1205822b3b2eSJohn Fastabend 1206c4047f53SThadeu Lima de Souza Cascardo i = queue - dev->_tx; 1207822b3b2eSJohn Fastabend BUG_ON(i >= dev->num_tx_queues); 1208822b3b2eSJohn Fastabend 1209822b3b2eSJohn Fastabend return i; 1210822b3b2eSJohn Fastabend } 1211822b3b2eSJohn Fastabend 12122b9c7581Sstephen hemminger static ssize_t traffic_class_show(struct netdev_queue *queue, 12138d059b0fSAlexander Duyck char *buf) 12148d059b0fSAlexander Duyck { 12158d059b0fSAlexander Duyck struct net_device *dev = queue->dev; 1216b2f17564SAlexander Duyck int num_tc, tc; 1217d7be9775SAlexander Duyck int index; 12188d059b0fSAlexander Duyck 1219d7be9775SAlexander Duyck if (!netif_is_multiqueue(dev)) 1220d7be9775SAlexander Duyck return -ENOENT; 1221d7be9775SAlexander Duyck 1222b2f17564SAlexander Duyck if (!rtnl_trylock()) 1223b2f17564SAlexander Duyck return restart_syscall(); 1224b2f17564SAlexander Duyck 1225d7be9775SAlexander Duyck index = get_netdev_queue_index(queue); 1226ffcfe25bSAlexander Duyck 1227ffcfe25bSAlexander Duyck /* If queue belongs to subordinate dev use its TC mapping */ 1228ffcfe25bSAlexander Duyck dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev; 1229ffcfe25bSAlexander Duyck 1230b2f17564SAlexander Duyck num_tc = dev->num_tc; 1231d7be9775SAlexander Duyck tc = netdev_txq_to_tc(dev, index); 1232b2f17564SAlexander Duyck 1233b2f17564SAlexander Duyck rtnl_unlock(); 1234b2f17564SAlexander Duyck 12358d059b0fSAlexander Duyck if (tc < 0) 12368d059b0fSAlexander Duyck return -EINVAL; 12378d059b0fSAlexander Duyck 1238ffcfe25bSAlexander Duyck /* We can report the traffic class one of two ways: 1239ffcfe25bSAlexander Duyck * Subordinate device traffic classes are reported with the traffic 1240ffcfe25bSAlexander Duyck * class first, and then the subordinate class so for example TC0 on 1241ffcfe25bSAlexander Duyck * subordinate device 2 will be reported as "0-2". If the queue 1242ffcfe25bSAlexander Duyck * belongs to the root device it will be reported with just the 1243ffcfe25bSAlexander Duyck * traffic class, so just "0" for TC 0 for example. 1244ffcfe25bSAlexander Duyck */ 1245b2f17564SAlexander Duyck return num_tc < 0 ? sprintf(buf, "%d%d\n", tc, num_tc) : 1246000fe268SYe Bin sprintf(buf, "%d\n", tc); 12478d059b0fSAlexander Duyck } 12488d059b0fSAlexander Duyck 12498d059b0fSAlexander Duyck #ifdef CONFIG_XPS 12502b9c7581Sstephen hemminger static ssize_t tx_maxrate_show(struct netdev_queue *queue, 1251822b3b2eSJohn Fastabend char *buf) 1252822b3b2eSJohn Fastabend { 1253822b3b2eSJohn Fastabend return sprintf(buf, "%lu\n", queue->tx_maxrate); 1254822b3b2eSJohn Fastabend } 1255822b3b2eSJohn Fastabend 12562b9c7581Sstephen hemminger static ssize_t tx_maxrate_store(struct netdev_queue *queue, 1257822b3b2eSJohn Fastabend const char *buf, size_t len) 1258822b3b2eSJohn Fastabend { 1259822b3b2eSJohn Fastabend struct net_device *dev = queue->dev; 1260822b3b2eSJohn Fastabend int err, index = get_netdev_queue_index(queue); 1261822b3b2eSJohn Fastabend u32 rate = 0; 1262822b3b2eSJohn Fastabend 12633033fcedSTyler Hicks if (!capable(CAP_NET_ADMIN)) 12643033fcedSTyler Hicks return -EPERM; 12653033fcedSTyler Hicks 1266146e5e73SAntoine Tenart /* The check is also done later; this helps returning early without 1267146e5e73SAntoine Tenart * hitting the trylock/restart below. 1268146e5e73SAntoine Tenart */ 1269146e5e73SAntoine Tenart if (!dev->netdev_ops->ndo_set_tx_maxrate) 1270146e5e73SAntoine Tenart return -EOPNOTSUPP; 1271146e5e73SAntoine Tenart 1272822b3b2eSJohn Fastabend err = kstrtou32(buf, 10, &rate); 1273822b3b2eSJohn Fastabend if (err < 0) 1274822b3b2eSJohn Fastabend return err; 1275822b3b2eSJohn Fastabend 1276822b3b2eSJohn Fastabend if (!rtnl_trylock()) 1277822b3b2eSJohn Fastabend return restart_syscall(); 1278822b3b2eSJohn Fastabend 1279822b3b2eSJohn Fastabend err = -EOPNOTSUPP; 1280822b3b2eSJohn Fastabend if (dev->netdev_ops->ndo_set_tx_maxrate) 1281822b3b2eSJohn Fastabend err = dev->netdev_ops->ndo_set_tx_maxrate(dev, index, rate); 1282822b3b2eSJohn Fastabend 1283822b3b2eSJohn Fastabend rtnl_unlock(); 1284822b3b2eSJohn Fastabend if (!err) { 1285822b3b2eSJohn Fastabend queue->tx_maxrate = rate; 1286822b3b2eSJohn Fastabend return len; 1287822b3b2eSJohn Fastabend } 1288822b3b2eSJohn Fastabend return err; 1289822b3b2eSJohn Fastabend } 1290822b3b2eSJohn Fastabend 12912b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_tx_maxrate __ro_after_init 12922b9c7581Sstephen hemminger = __ATTR_RW(tx_maxrate); 1293822b3b2eSJohn Fastabend #endif 1294822b3b2eSJohn Fastabend 12952b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_trans_timeout __ro_after_init 12962b9c7581Sstephen hemminger = __ATTR_RO(tx_timeout); 1297ccf5ff69Sdavid decotigny 12982b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_traffic_class __ro_after_init 12992b9c7581Sstephen hemminger = __ATTR_RO(traffic_class); 13008d059b0fSAlexander Duyck 1301114cf580STom Herbert #ifdef CONFIG_BQL 1302114cf580STom Herbert /* 1303114cf580STom Herbert * Byte queue limits sysfs structures and functions. 1304114cf580STom Herbert */ 1305114cf580STom Herbert static ssize_t bql_show(char *buf, unsigned int value) 1306114cf580STom Herbert { 1307114cf580STom Herbert return sprintf(buf, "%u\n", value); 1308114cf580STom Herbert } 1309114cf580STom Herbert 1310114cf580STom Herbert static ssize_t bql_set(const char *buf, const size_t count, 1311114cf580STom Herbert unsigned int *pvalue) 1312114cf580STom Herbert { 1313114cf580STom Herbert unsigned int value; 1314114cf580STom Herbert int err; 1315114cf580STom Herbert 13166648c65eSstephen hemminger if (!strcmp(buf, "max") || !strcmp(buf, "max\n")) { 1317114cf580STom Herbert value = DQL_MAX_LIMIT; 13186648c65eSstephen hemminger } else { 1319114cf580STom Herbert err = kstrtouint(buf, 10, &value); 1320114cf580STom Herbert if (err < 0) 1321114cf580STom Herbert return err; 1322114cf580STom Herbert if (value > DQL_MAX_LIMIT) 1323114cf580STom Herbert return -EINVAL; 1324114cf580STom Herbert } 1325114cf580STom Herbert 1326114cf580STom Herbert *pvalue = value; 1327114cf580STom Herbert 1328114cf580STom Herbert return count; 1329114cf580STom Herbert } 1330114cf580STom Herbert 1331114cf580STom Herbert static ssize_t bql_show_hold_time(struct netdev_queue *queue, 1332114cf580STom Herbert char *buf) 1333114cf580STom Herbert { 1334114cf580STom Herbert struct dql *dql = &queue->dql; 1335114cf580STom Herbert 1336114cf580STom Herbert return sprintf(buf, "%u\n", jiffies_to_msecs(dql->slack_hold_time)); 1337114cf580STom Herbert } 1338114cf580STom Herbert 1339114cf580STom Herbert static ssize_t bql_set_hold_time(struct netdev_queue *queue, 1340114cf580STom Herbert const char *buf, size_t len) 1341114cf580STom Herbert { 1342114cf580STom Herbert struct dql *dql = &queue->dql; 134395c96174SEric Dumazet unsigned int value; 1344114cf580STom Herbert int err; 1345114cf580STom Herbert 1346114cf580STom Herbert err = kstrtouint(buf, 10, &value); 1347114cf580STom Herbert if (err < 0) 1348114cf580STom Herbert return err; 1349114cf580STom Herbert 1350114cf580STom Herbert dql->slack_hold_time = msecs_to_jiffies(value); 1351114cf580STom Herbert 1352114cf580STom Herbert return len; 1353114cf580STom Herbert } 1354114cf580STom Herbert 1355170c658aSstephen hemminger static struct netdev_queue_attribute bql_hold_time_attribute __ro_after_init 1356d6444062SJoe Perches = __ATTR(hold_time, 0644, 1357170c658aSstephen hemminger bql_show_hold_time, bql_set_hold_time); 1358114cf580STom Herbert 1359114cf580STom Herbert static ssize_t bql_show_inflight(struct netdev_queue *queue, 1360114cf580STom Herbert char *buf) 1361114cf580STom Herbert { 1362114cf580STom Herbert struct dql *dql = &queue->dql; 1363114cf580STom Herbert 1364114cf580STom Herbert return sprintf(buf, "%u\n", dql->num_queued - dql->num_completed); 1365114cf580STom Herbert } 1366114cf580STom Herbert 1367170c658aSstephen hemminger static struct netdev_queue_attribute bql_inflight_attribute __ro_after_init = 1368d6444062SJoe Perches __ATTR(inflight, 0444, bql_show_inflight, NULL); 1369114cf580STom Herbert 1370114cf580STom Herbert #define BQL_ATTR(NAME, FIELD) \ 1371114cf580STom Herbert static ssize_t bql_show_ ## NAME(struct netdev_queue *queue, \ 1372114cf580STom Herbert char *buf) \ 1373114cf580STom Herbert { \ 1374114cf580STom Herbert return bql_show(buf, queue->dql.FIELD); \ 1375114cf580STom Herbert } \ 1376114cf580STom Herbert \ 1377114cf580STom Herbert static ssize_t bql_set_ ## NAME(struct netdev_queue *queue, \ 1378114cf580STom Herbert const char *buf, size_t len) \ 1379114cf580STom Herbert { \ 1380114cf580STom Herbert return bql_set(buf, len, &queue->dql.FIELD); \ 1381114cf580STom Herbert } \ 1382114cf580STom Herbert \ 1383170c658aSstephen hemminger static struct netdev_queue_attribute bql_ ## NAME ## _attribute __ro_after_init \ 1384d6444062SJoe Perches = __ATTR(NAME, 0644, \ 1385170c658aSstephen hemminger bql_show_ ## NAME, bql_set_ ## NAME) 1386114cf580STom Herbert 1387170c658aSstephen hemminger BQL_ATTR(limit, limit); 1388170c658aSstephen hemminger BQL_ATTR(limit_max, max_limit); 1389170c658aSstephen hemminger BQL_ATTR(limit_min, min_limit); 1390114cf580STom Herbert 1391170c658aSstephen hemminger static struct attribute *dql_attrs[] __ro_after_init = { 1392114cf580STom Herbert &bql_limit_attribute.attr, 1393114cf580STom Herbert &bql_limit_max_attribute.attr, 1394114cf580STom Herbert &bql_limit_min_attribute.attr, 1395114cf580STom Herbert &bql_hold_time_attribute.attr, 1396114cf580STom Herbert &bql_inflight_attribute.attr, 1397114cf580STom Herbert NULL 1398114cf580STom Herbert }; 1399114cf580STom Herbert 140038ef00ccSArvind Yadav static const struct attribute_group dql_group = { 1401114cf580STom Herbert .name = "byte_queue_limits", 1402114cf580STom Herbert .attrs = dql_attrs, 1403114cf580STom Herbert }; 1404114cf580STom Herbert #endif /* CONFIG_BQL */ 1405114cf580STom Herbert 1406ccf5ff69Sdavid decotigny #ifdef CONFIG_XPS 14072db6cdaeSAntoine Tenart static ssize_t xps_queue_show(struct net_device *dev, unsigned int index, 14082db6cdaeSAntoine Tenart int tc, char *buf, enum xps_map_type type) 14091d24eb48STom Herbert { 14101d24eb48STom Herbert struct xps_dev_maps *dev_maps; 1411d9a063d2SAntoine Tenart unsigned long *mask; 14122db6cdaeSAntoine Tenart unsigned int nr_ids; 14132db6cdaeSAntoine Tenart int j, len; 1414d7be87a6SAntoine Tenart 14151d24eb48STom Herbert rcu_read_lock(); 14162db6cdaeSAntoine Tenart dev_maps = rcu_dereference(dev->xps_maps[type]); 14172db6cdaeSAntoine Tenart 14182db6cdaeSAntoine Tenart /* Default to nr_cpu_ids/dev->num_rx_queues and do not just return 0 14192db6cdaeSAntoine Tenart * when dev_maps hasn't been allocated yet, to be backward compatible. 14202db6cdaeSAntoine Tenart */ 14212db6cdaeSAntoine Tenart nr_ids = dev_maps ? dev_maps->nr_ids : 14222db6cdaeSAntoine Tenart (type == XPS_CPUS ? nr_cpu_ids : dev->num_rx_queues); 14235478fcd0SAntoine Tenart 14247f08ec6eSAntoine Tenart mask = bitmap_zalloc(nr_ids, GFP_NOWAIT); 14255478fcd0SAntoine Tenart if (!mask) { 14262db6cdaeSAntoine Tenart rcu_read_unlock(); 14272db6cdaeSAntoine Tenart return -ENOMEM; 14285478fcd0SAntoine Tenart } 14295478fcd0SAntoine Tenart 1430255c04a8SAntoine Tenart if (!dev_maps || tc >= dev_maps->num_tc) 143173f5e52bSAntoine Tenart goto out_no_maps; 143273f5e52bSAntoine Tenart 14336f36158eSAntoine Tenart for (j = 0; j < nr_ids; j++) { 1434255c04a8SAntoine Tenart int i, tci = j * dev_maps->num_tc + tc; 1435184c449fSAlexander Duyck struct xps_map *map; 1436184c449fSAlexander Duyck 143780d19669SAmritha Nambiar map = rcu_dereference(dev_maps->attr_map[tci]); 1438184c449fSAlexander Duyck if (!map) 1439184c449fSAlexander Duyck continue; 1440184c449fSAlexander Duyck 1441184c449fSAlexander Duyck for (i = map->len; i--;) { 1442184c449fSAlexander Duyck if (map->queues[i] == index) { 144308a7abf4SChristophe JAILLET __set_bit(j, mask); 14441d24eb48STom Herbert break; 14451d24eb48STom Herbert } 14461d24eb48STom Herbert } 14471d24eb48STom Herbert } 144873f5e52bSAntoine Tenart out_no_maps: 14491d24eb48STom Herbert rcu_read_unlock(); 1450fb250385SAntoine Tenart 14515478fcd0SAntoine Tenart len = bitmap_print_to_pagebuf(false, buf, mask, nr_ids); 1452ea4fe7e8SAntoine Tenart bitmap_free(mask); 1453fb250385SAntoine Tenart 14542db6cdaeSAntoine Tenart return len < PAGE_SIZE ? len : -EINVAL; 14552db6cdaeSAntoine Tenart } 14562db6cdaeSAntoine Tenart 14572db6cdaeSAntoine Tenart static ssize_t xps_cpus_show(struct netdev_queue *queue, char *buf) 14582db6cdaeSAntoine Tenart { 14592db6cdaeSAntoine Tenart struct net_device *dev = queue->dev; 14602db6cdaeSAntoine Tenart unsigned int index; 14612db6cdaeSAntoine Tenart int len, tc; 14622db6cdaeSAntoine Tenart 14632db6cdaeSAntoine Tenart if (!netif_is_multiqueue(dev)) 14642db6cdaeSAntoine Tenart return -ENOENT; 14652db6cdaeSAntoine Tenart 14662db6cdaeSAntoine Tenart index = get_netdev_queue_index(queue); 14672db6cdaeSAntoine Tenart 14682db6cdaeSAntoine Tenart if (!rtnl_trylock()) 14692db6cdaeSAntoine Tenart return restart_syscall(); 14702db6cdaeSAntoine Tenart 14712db6cdaeSAntoine Tenart /* If queue belongs to subordinate dev use its map */ 14722db6cdaeSAntoine Tenart dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev; 14732db6cdaeSAntoine Tenart 14742db6cdaeSAntoine Tenart tc = netdev_txq_to_tc(dev, index); 14752db6cdaeSAntoine Tenart if (tc < 0) { 14762db6cdaeSAntoine Tenart rtnl_unlock(); 14772db6cdaeSAntoine Tenart return -EINVAL; 14782db6cdaeSAntoine Tenart } 14792db6cdaeSAntoine Tenart 14802db6cdaeSAntoine Tenart /* Make sure the subordinate device can't be freed */ 14812db6cdaeSAntoine Tenart get_device(&dev->dev); 14822db6cdaeSAntoine Tenart rtnl_unlock(); 14832db6cdaeSAntoine Tenart 14842db6cdaeSAntoine Tenart len = xps_queue_show(dev, index, tc, buf, XPS_CPUS); 14852db6cdaeSAntoine Tenart 1486d7be87a6SAntoine Tenart put_device(&dev->dev); 14872db6cdaeSAntoine Tenart return len; 14881d24eb48STom Herbert } 14891d24eb48STom Herbert 14902b9c7581Sstephen hemminger static ssize_t xps_cpus_store(struct netdev_queue *queue, 14911d24eb48STom Herbert const char *buf, size_t len) 14921d24eb48STom Herbert { 14931d24eb48STom Herbert struct net_device *dev = queue->dev; 1494d9a063d2SAntoine Tenart unsigned int index; 1495537c00deSAlexander Duyck cpumask_var_t mask; 1496537c00deSAlexander Duyck int err; 14971d24eb48STom Herbert 1498d7be9775SAlexander Duyck if (!netif_is_multiqueue(dev)) 1499d7be9775SAlexander Duyck return -ENOENT; 1500d7be9775SAlexander Duyck 15011d24eb48STom Herbert if (!capable(CAP_NET_ADMIN)) 15021d24eb48STom Herbert return -EPERM; 15031d24eb48STom Herbert 15041d24eb48STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 15051d24eb48STom Herbert return -ENOMEM; 15061d24eb48STom Herbert 15071d24eb48STom Herbert index = get_netdev_queue_index(queue); 15081d24eb48STom Herbert 15091d24eb48STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 15101d24eb48STom Herbert if (err) { 15111d24eb48STom Herbert free_cpumask_var(mask); 15121d24eb48STom Herbert return err; 15131d24eb48STom Herbert } 15141d24eb48STom Herbert 15151ad58225SAntoine Tenart if (!rtnl_trylock()) { 15161ad58225SAntoine Tenart free_cpumask_var(mask); 15171ad58225SAntoine Tenart return restart_syscall(); 15181ad58225SAntoine Tenart } 15191ad58225SAntoine Tenart 1520537c00deSAlexander Duyck err = netif_set_xps_queue(dev, mask, index); 15211ad58225SAntoine Tenart rtnl_unlock(); 15221d24eb48STom Herbert 15231d24eb48STom Herbert free_cpumask_var(mask); 15241d24eb48STom Herbert 1525537c00deSAlexander Duyck return err ? : len; 15261d24eb48STom Herbert } 15271d24eb48STom Herbert 15282b9c7581Sstephen hemminger static struct netdev_queue_attribute xps_cpus_attribute __ro_after_init 15292b9c7581Sstephen hemminger = __ATTR_RW(xps_cpus); 15308af2c06fSAmritha Nambiar 15318af2c06fSAmritha Nambiar static ssize_t xps_rxqs_show(struct netdev_queue *queue, char *buf) 15328af2c06fSAmritha Nambiar { 15338af2c06fSAmritha Nambiar struct net_device *dev = queue->dev; 15342db6cdaeSAntoine Tenart unsigned int index; 15352db6cdaeSAntoine Tenart int tc; 15368af2c06fSAmritha Nambiar 15378af2c06fSAmritha Nambiar index = get_netdev_queue_index(queue); 15388af2c06fSAmritha Nambiar 15394ae2bb81SAntoine Tenart if (!rtnl_trylock()) 15404ae2bb81SAntoine Tenart return restart_syscall(); 15414ae2bb81SAntoine Tenart 15428af2c06fSAmritha Nambiar tc = netdev_txq_to_tc(dev, index); 1543d7be87a6SAntoine Tenart rtnl_unlock(); 1544d7be87a6SAntoine Tenart if (tc < 0) 1545d7be87a6SAntoine Tenart return -EINVAL; 1546255c04a8SAntoine Tenart 15472db6cdaeSAntoine Tenart return xps_queue_show(dev, index, tc, buf, XPS_RXQS); 15488af2c06fSAmritha Nambiar } 15498af2c06fSAmritha Nambiar 15508af2c06fSAmritha Nambiar static ssize_t xps_rxqs_store(struct netdev_queue *queue, const char *buf, 15518af2c06fSAmritha Nambiar size_t len) 15528af2c06fSAmritha Nambiar { 15538af2c06fSAmritha Nambiar struct net_device *dev = queue->dev; 15548af2c06fSAmritha Nambiar struct net *net = dev_net(dev); 1555d9a063d2SAntoine Tenart unsigned long *mask; 1556d9a063d2SAntoine Tenart unsigned int index; 15578af2c06fSAmritha Nambiar int err; 15588af2c06fSAmritha Nambiar 15598af2c06fSAmritha Nambiar if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 15608af2c06fSAmritha Nambiar return -EPERM; 15618af2c06fSAmritha Nambiar 156229ca1c5aSAndy Shevchenko mask = bitmap_zalloc(dev->num_rx_queues, GFP_KERNEL); 15638af2c06fSAmritha Nambiar if (!mask) 15648af2c06fSAmritha Nambiar return -ENOMEM; 15658af2c06fSAmritha Nambiar 15668af2c06fSAmritha Nambiar index = get_netdev_queue_index(queue); 15678af2c06fSAmritha Nambiar 15688af2c06fSAmritha Nambiar err = bitmap_parse(buf, len, mask, dev->num_rx_queues); 15698af2c06fSAmritha Nambiar if (err) { 157029ca1c5aSAndy Shevchenko bitmap_free(mask); 15718af2c06fSAmritha Nambiar return err; 15728af2c06fSAmritha Nambiar } 15738af2c06fSAmritha Nambiar 15742d57b4f1SAntoine Tenart if (!rtnl_trylock()) { 15752d57b4f1SAntoine Tenart bitmap_free(mask); 15762d57b4f1SAntoine Tenart return restart_syscall(); 15772d57b4f1SAntoine Tenart } 15782d57b4f1SAntoine Tenart 15794d99f660SAndrei Vagin cpus_read_lock(); 1580044ab86dSAntoine Tenart err = __netif_set_xps_queue(dev, mask, index, XPS_RXQS); 15814d99f660SAndrei Vagin cpus_read_unlock(); 15824d99f660SAndrei Vagin 15832d57b4f1SAntoine Tenart rtnl_unlock(); 15842d57b4f1SAntoine Tenart 158529ca1c5aSAndy Shevchenko bitmap_free(mask); 15868af2c06fSAmritha Nambiar return err ? : len; 15878af2c06fSAmritha Nambiar } 15888af2c06fSAmritha Nambiar 15898af2c06fSAmritha Nambiar static struct netdev_queue_attribute xps_rxqs_attribute __ro_after_init 15908af2c06fSAmritha Nambiar = __ATTR_RW(xps_rxqs); 1591ccf5ff69Sdavid decotigny #endif /* CONFIG_XPS */ 15921d24eb48STom Herbert 15932b9c7581Sstephen hemminger static struct attribute *netdev_queue_default_attrs[] __ro_after_init = { 1594ccf5ff69Sdavid decotigny &queue_trans_timeout.attr, 15958d059b0fSAlexander Duyck &queue_traffic_class.attr, 1596ccf5ff69Sdavid decotigny #ifdef CONFIG_XPS 15971d24eb48STom Herbert &xps_cpus_attribute.attr, 15988af2c06fSAmritha Nambiar &xps_rxqs_attribute.attr, 1599822b3b2eSJohn Fastabend &queue_tx_maxrate.attr, 1600ccf5ff69Sdavid decotigny #endif 16011d24eb48STom Herbert NULL 16021d24eb48STom Herbert }; 1603be0d6926SKimberly Brown ATTRIBUTE_GROUPS(netdev_queue_default); 16041d24eb48STom Herbert 16051d24eb48STom Herbert static void netdev_queue_release(struct kobject *kobj) 16061d24eb48STom Herbert { 16071d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 16081d24eb48STom Herbert 16091d24eb48STom Herbert memset(kobj, 0, sizeof(*kobj)); 16100b688f24SEric Dumazet dev_put_track(queue->dev, &queue->dev_tracker); 16111d24eb48STom Herbert } 16121d24eb48STom Herbert 161382ef3d5dSWeilong Chen static const void *netdev_queue_namespace(struct kobject *kobj) 161482ef3d5dSWeilong Chen { 161582ef3d5dSWeilong Chen struct netdev_queue *queue = to_netdev_queue(kobj); 161682ef3d5dSWeilong Chen struct device *dev = &queue->dev->dev; 161782ef3d5dSWeilong Chen const void *ns = NULL; 161882ef3d5dSWeilong Chen 161982ef3d5dSWeilong Chen if (dev->class && dev->class->ns_type) 162082ef3d5dSWeilong Chen ns = dev->class->namespace(dev); 162182ef3d5dSWeilong Chen 162282ef3d5dSWeilong Chen return ns; 162382ef3d5dSWeilong Chen } 162482ef3d5dSWeilong Chen 1625b0e37c0dSDmitry Torokhov static void netdev_queue_get_ownership(struct kobject *kobj, 1626b0e37c0dSDmitry Torokhov kuid_t *uid, kgid_t *gid) 1627b0e37c0dSDmitry Torokhov { 1628b0e37c0dSDmitry Torokhov const struct net *net = netdev_queue_namespace(kobj); 1629b0e37c0dSDmitry Torokhov 1630b0e37c0dSDmitry Torokhov net_ns_get_ownership(net, uid, gid); 1631b0e37c0dSDmitry Torokhov } 1632b0e37c0dSDmitry Torokhov 16332b9c7581Sstephen hemminger static struct kobj_type netdev_queue_ktype __ro_after_init = { 16341d24eb48STom Herbert .sysfs_ops = &netdev_queue_sysfs_ops, 16351d24eb48STom Herbert .release = netdev_queue_release, 1636be0d6926SKimberly Brown .default_groups = netdev_queue_default_groups, 163782ef3d5dSWeilong Chen .namespace = netdev_queue_namespace, 1638b0e37c0dSDmitry Torokhov .get_ownership = netdev_queue_get_ownership, 16391d24eb48STom Herbert }; 16401d24eb48STom Herbert 16416b53dafeSWANG Cong static int netdev_queue_add_kobject(struct net_device *dev, int index) 16421d24eb48STom Herbert { 16436b53dafeSWANG Cong struct netdev_queue *queue = dev->_tx + index; 16441d24eb48STom Herbert struct kobject *kobj = &queue->kobj; 16451d24eb48STom Herbert int error = 0; 16461d24eb48STom Herbert 1647e0b60903SJouni Hogander /* Kobject_put later will trigger netdev_queue_release call 1648e0b60903SJouni Hogander * which decreases dev refcount: Take that reference here 1649e0b60903SJouni Hogander */ 16500b688f24SEric Dumazet dev_hold_track(queue->dev, &queue->dev_tracker, GFP_KERNEL); 1651e0b60903SJouni Hogander 16526b53dafeSWANG Cong kobj->kset = dev->queues_kset; 16531d24eb48STom Herbert error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, 16541d24eb48STom Herbert "tx-%u", index); 1655114cf580STom Herbert if (error) 1656b8eb7183SJouni Hogander goto err; 1657114cf580STom Herbert 1658114cf580STom Herbert #ifdef CONFIG_BQL 1659114cf580STom Herbert error = sysfs_create_group(kobj, &dql_group); 1660b8eb7183SJouni Hogander if (error) 1661b8eb7183SJouni Hogander goto err; 1662114cf580STom Herbert #endif 16631d24eb48STom Herbert 16641d24eb48STom Herbert kobject_uevent(kobj, KOBJ_ADD); 166548a322b6SEric Dumazet return 0; 16661d24eb48STom Herbert 1667b8eb7183SJouni Hogander err: 1668b8eb7183SJouni Hogander kobject_put(kobj); 1669b8eb7183SJouni Hogander return error; 16701d24eb48STom Herbert } 1671d755407dSChristian Brauner 1672d755407dSChristian Brauner static int tx_queue_change_owner(struct net_device *ndev, int index, 1673d755407dSChristian Brauner kuid_t kuid, kgid_t kgid) 1674d755407dSChristian Brauner { 1675d755407dSChristian Brauner struct netdev_queue *queue = ndev->_tx + index; 1676d755407dSChristian Brauner struct kobject *kobj = &queue->kobj; 1677d755407dSChristian Brauner int error; 1678d755407dSChristian Brauner 1679d755407dSChristian Brauner error = sysfs_change_owner(kobj, kuid, kgid); 1680d755407dSChristian Brauner if (error) 1681d755407dSChristian Brauner return error; 1682d755407dSChristian Brauner 1683d755407dSChristian Brauner #ifdef CONFIG_BQL 1684d755407dSChristian Brauner error = sysfs_group_change_owner(kobj, &dql_group, kuid, kgid); 1685d755407dSChristian Brauner #endif 1686d755407dSChristian Brauner return error; 1687d755407dSChristian Brauner } 1688ccf5ff69Sdavid decotigny #endif /* CONFIG_SYSFS */ 16891d24eb48STom Herbert 16901d24eb48STom Herbert int 16916b53dafeSWANG Cong netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) 16921d24eb48STom Herbert { 1693ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 16941d24eb48STom Herbert int i; 16951d24eb48STom Herbert int error = 0; 16961d24eb48STom Herbert 16971d24eb48STom Herbert for (i = old_num; i < new_num; i++) { 16986b53dafeSWANG Cong error = netdev_queue_add_kobject(dev, i); 16991d24eb48STom Herbert if (error) { 17001d24eb48STom Herbert new_num = old_num; 17011d24eb48STom Herbert break; 17021d24eb48STom Herbert } 17031d24eb48STom Herbert } 17041d24eb48STom Herbert 1705114cf580STom Herbert while (--i >= new_num) { 17066b53dafeSWANG Cong struct netdev_queue *queue = dev->_tx + i; 1707114cf580STom Herbert 17088b8f3e66SChristian Brauner if (!refcount_read(&dev_net(dev)->ns.count)) 1709002d8a1aSAndrey Vagin queue->kobj.uevent_suppress = 1; 1710114cf580STom Herbert #ifdef CONFIG_BQL 1711114cf580STom Herbert sysfs_remove_group(&queue->kobj, &dql_group); 1712114cf580STom Herbert #endif 1713114cf580STom Herbert kobject_put(&queue->kobj); 1714114cf580STom Herbert } 17151d24eb48STom Herbert 17161d24eb48STom Herbert return error; 1717bf264145STom Herbert #else 1718bf264145STom Herbert return 0; 1719ccf5ff69Sdavid decotigny #endif /* CONFIG_SYSFS */ 17201d24eb48STom Herbert } 17211d24eb48STom Herbert 1722d755407dSChristian Brauner static int net_tx_queue_change_owner(struct net_device *dev, int num, 1723d755407dSChristian Brauner kuid_t kuid, kgid_t kgid) 1724d755407dSChristian Brauner { 1725d755407dSChristian Brauner #ifdef CONFIG_SYSFS 1726d755407dSChristian Brauner int error = 0; 1727d755407dSChristian Brauner int i; 1728d755407dSChristian Brauner 1729d755407dSChristian Brauner for (i = 0; i < num; i++) { 1730d755407dSChristian Brauner error = tx_queue_change_owner(dev, i, kuid, kgid); 1731d755407dSChristian Brauner if (error) 1732d755407dSChristian Brauner break; 1733d755407dSChristian Brauner } 1734d755407dSChristian Brauner 1735d755407dSChristian Brauner return error; 1736d755407dSChristian Brauner #else 1737d755407dSChristian Brauner return 0; 1738d755407dSChristian Brauner #endif /* CONFIG_SYSFS */ 1739d755407dSChristian Brauner } 1740d755407dSChristian Brauner 17416b53dafeSWANG Cong static int register_queue_kobjects(struct net_device *dev) 17421d24eb48STom Herbert { 1743bf264145STom Herbert int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; 17441d24eb48STom Herbert 1745ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 17466b53dafeSWANG Cong dev->queues_kset = kset_create_and_add("queues", 17476b53dafeSWANG Cong NULL, &dev->dev.kobj); 17486b53dafeSWANG Cong if (!dev->queues_kset) 174962fe0b40SBen Hutchings return -ENOMEM; 17506b53dafeSWANG Cong real_rx = dev->real_num_rx_queues; 1751bf264145STom Herbert #endif 17526b53dafeSWANG Cong real_tx = dev->real_num_tx_queues; 1753bf264145STom Herbert 17546b53dafeSWANG Cong error = net_rx_queue_update_kobjects(dev, 0, real_rx); 17551d24eb48STom Herbert if (error) 17561d24eb48STom Herbert goto error; 1757bf264145STom Herbert rxq = real_rx; 17581d24eb48STom Herbert 17596b53dafeSWANG Cong error = netdev_queue_update_kobjects(dev, 0, real_tx); 17601d24eb48STom Herbert if (error) 17611d24eb48STom Herbert goto error; 1762bf264145STom Herbert txq = real_tx; 17631d24eb48STom Herbert 17641d24eb48STom Herbert return 0; 17651d24eb48STom Herbert 17661d24eb48STom Herbert error: 17676b53dafeSWANG Cong netdev_queue_update_kobjects(dev, txq, 0); 17686b53dafeSWANG Cong net_rx_queue_update_kobjects(dev, rxq, 0); 1769895a5e96SYueHaibing #ifdef CONFIG_SYSFS 1770895a5e96SYueHaibing kset_unregister(dev->queues_kset); 1771895a5e96SYueHaibing #endif 17721d24eb48STom Herbert return error; 177362fe0b40SBen Hutchings } 177462fe0b40SBen Hutchings 1775d755407dSChristian Brauner static int queue_change_owner(struct net_device *ndev, kuid_t kuid, kgid_t kgid) 1776d755407dSChristian Brauner { 1777d755407dSChristian Brauner int error = 0, real_rx = 0, real_tx = 0; 1778d755407dSChristian Brauner 1779d755407dSChristian Brauner #ifdef CONFIG_SYSFS 1780d755407dSChristian Brauner if (ndev->queues_kset) { 1781d755407dSChristian Brauner error = sysfs_change_owner(&ndev->queues_kset->kobj, kuid, kgid); 1782d755407dSChristian Brauner if (error) 1783d755407dSChristian Brauner return error; 1784d755407dSChristian Brauner } 1785d755407dSChristian Brauner real_rx = ndev->real_num_rx_queues; 1786d755407dSChristian Brauner #endif 1787d755407dSChristian Brauner real_tx = ndev->real_num_tx_queues; 1788d755407dSChristian Brauner 1789d755407dSChristian Brauner error = net_rx_queue_change_owner(ndev, real_rx, kuid, kgid); 1790d755407dSChristian Brauner if (error) 1791d755407dSChristian Brauner return error; 1792d755407dSChristian Brauner 1793d755407dSChristian Brauner error = net_tx_queue_change_owner(ndev, real_tx, kuid, kgid); 1794d755407dSChristian Brauner if (error) 1795d755407dSChristian Brauner return error; 1796d755407dSChristian Brauner 1797d755407dSChristian Brauner return 0; 1798d755407dSChristian Brauner } 1799d755407dSChristian Brauner 18006b53dafeSWANG Cong static void remove_queue_kobjects(struct net_device *dev) 18010a9627f2STom Herbert { 1802bf264145STom Herbert int real_rx = 0, real_tx = 0; 1803bf264145STom Herbert 1804a953be53SMichael Dalton #ifdef CONFIG_SYSFS 18056b53dafeSWANG Cong real_rx = dev->real_num_rx_queues; 1806bf264145STom Herbert #endif 18076b53dafeSWANG Cong real_tx = dev->real_num_tx_queues; 1808bf264145STom Herbert 18096b53dafeSWANG Cong net_rx_queue_update_kobjects(dev, real_rx, 0); 18106b53dafeSWANG Cong netdev_queue_update_kobjects(dev, real_tx, 0); 1811*d7dac083SAntoine Tenart 1812*d7dac083SAntoine Tenart dev->real_num_rx_queues = 0; 1813*d7dac083SAntoine Tenart dev->real_num_tx_queues = 0; 1814ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 18156b53dafeSWANG Cong kset_unregister(dev->queues_kset); 1816bf264145STom Herbert #endif 18170a9627f2STom Herbert } 1818608b4b95SEric W. Biederman 18197dc5dbc8SEric W. Biederman static bool net_current_may_mount(void) 18207dc5dbc8SEric W. Biederman { 18217dc5dbc8SEric W. Biederman struct net *net = current->nsproxy->net_ns; 18227dc5dbc8SEric W. Biederman 18237dc5dbc8SEric W. Biederman return ns_capable(net->user_ns, CAP_SYS_ADMIN); 18247dc5dbc8SEric W. Biederman } 18257dc5dbc8SEric W. Biederman 1826a685e089SAl Viro static void *net_grab_current_ns(void) 1827608b4b95SEric W. Biederman { 1828a685e089SAl Viro struct net *ns = current->nsproxy->net_ns; 1829a685e089SAl Viro #ifdef CONFIG_NET_NS 1830a685e089SAl Viro if (ns) 1831c122e14dSReshetova, Elena refcount_inc(&ns->passive); 1832a685e089SAl Viro #endif 1833a685e089SAl Viro return ns; 1834608b4b95SEric W. Biederman } 1835608b4b95SEric W. Biederman 1836608b4b95SEric W. Biederman static const void *net_initial_ns(void) 1837608b4b95SEric W. Biederman { 1838608b4b95SEric W. Biederman return &init_net; 1839608b4b95SEric W. Biederman } 1840608b4b95SEric W. Biederman 1841608b4b95SEric W. Biederman static const void *net_netlink_ns(struct sock *sk) 1842608b4b95SEric W. Biederman { 1843608b4b95SEric W. Biederman return sock_net(sk); 1844608b4b95SEric W. Biederman } 1845608b4b95SEric W. Biederman 1846737aec57Sstephen hemminger const struct kobj_ns_type_operations net_ns_type_operations = { 1847608b4b95SEric W. Biederman .type = KOBJ_NS_TYPE_NET, 18487dc5dbc8SEric W. Biederman .current_may_mount = net_current_may_mount, 1849a685e089SAl Viro .grab_current_ns = net_grab_current_ns, 1850608b4b95SEric W. Biederman .netlink_ns = net_netlink_ns, 1851608b4b95SEric W. Biederman .initial_ns = net_initial_ns, 1852a685e089SAl Viro .drop_ns = net_drop_ns, 1853608b4b95SEric W. Biederman }; 185404600794SJohannes Berg EXPORT_SYMBOL_GPL(net_ns_type_operations); 1855608b4b95SEric W. Biederman 18567eff2e7aSKay Sievers static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) 18571da177e4SLinus Torvalds { 185843cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 18597eff2e7aSKay Sievers int retval; 18601da177e4SLinus Torvalds 1861312c004dSKay Sievers /* pass interface to uevent. */ 18627eff2e7aSKay Sievers retval = add_uevent_var(env, "INTERFACE=%s", dev->name); 1863bf62456eSEric Rannaud if (retval) 1864bf62456eSEric Rannaud goto exit; 18651da177e4SLinus Torvalds 1866ca2f37dbSJean Tourrilhes /* pass ifindex to uevent. 1867ca2f37dbSJean Tourrilhes * ifindex is useful as it won't change (interface name may change) 18686648c65eSstephen hemminger * and is what RtNetlink uses natively. 18696648c65eSstephen hemminger */ 18707eff2e7aSKay Sievers retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); 1871ca2f37dbSJean Tourrilhes 1872bf62456eSEric Rannaud exit: 1873bf62456eSEric Rannaud return retval; 18741da177e4SLinus Torvalds } 18751da177e4SLinus Torvalds 18761da177e4SLinus Torvalds /* 18771da177e4SLinus Torvalds * netdev_release -- destroy and free a dead device. 187843cb76d9SGreg Kroah-Hartman * Called when last reference to device kobject is gone. 18791da177e4SLinus Torvalds */ 188043cb76d9SGreg Kroah-Hartman static void netdev_release(struct device *d) 18811da177e4SLinus Torvalds { 188243cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 18831da177e4SLinus Torvalds 18841da177e4SLinus Torvalds BUG_ON(dev->reg_state != NETREG_RELEASED); 18851da177e4SLinus Torvalds 18866c557001SFlorian Westphal /* no need to wait for rcu grace period: 18876c557001SFlorian Westphal * device is dead and about to be freed. 18886c557001SFlorian Westphal */ 18896c557001SFlorian Westphal kfree(rcu_access_pointer(dev->ifalias)); 189074d332c1SEric Dumazet netdev_freemem(dev); 18911da177e4SLinus Torvalds } 18921da177e4SLinus Torvalds 1893608b4b95SEric W. Biederman static const void *net_namespace(struct device *d) 1894608b4b95SEric W. Biederman { 18955c29482dSGeliang Tang struct net_device *dev = to_net_dev(d); 18965c29482dSGeliang Tang 1897608b4b95SEric W. Biederman return dev_net(dev); 1898608b4b95SEric W. Biederman } 1899608b4b95SEric W. Biederman 1900b0e37c0dSDmitry Torokhov static void net_get_ownership(struct device *d, kuid_t *uid, kgid_t *gid) 1901b0e37c0dSDmitry Torokhov { 1902b0e37c0dSDmitry Torokhov struct net_device *dev = to_net_dev(d); 1903b0e37c0dSDmitry Torokhov const struct net *net = dev_net(dev); 1904b0e37c0dSDmitry Torokhov 1905b0e37c0dSDmitry Torokhov net_ns_get_ownership(net, uid, gid); 1906b0e37c0dSDmitry Torokhov } 1907b0e37c0dSDmitry Torokhov 1908e6d473e6Sstephen hemminger static struct class net_class __ro_after_init = { 19091da177e4SLinus Torvalds .name = "net", 191043cb76d9SGreg Kroah-Hartman .dev_release = netdev_release, 19116be8aeefSGreg Kroah-Hartman .dev_groups = net_class_groups, 191243cb76d9SGreg Kroah-Hartman .dev_uevent = netdev_uevent, 1913608b4b95SEric W. Biederman .ns_type = &net_ns_type_operations, 1914608b4b95SEric W. Biederman .namespace = net_namespace, 1915b0e37c0dSDmitry Torokhov .get_ownership = net_get_ownership, 19161da177e4SLinus Torvalds }; 19171da177e4SLinus Torvalds 1918e330fb14SJakub Kicinski #ifdef CONFIG_OF 1919aa836df9SFlorian Fainelli static int of_dev_node_match(struct device *dev, const void *data) 1920aa836df9SFlorian Fainelli { 19212e186a2cSTobias Waldekranz for (; dev; dev = dev->parent) { 19222e186a2cSTobias Waldekranz if (dev->of_node == data) 19232e186a2cSTobias Waldekranz return 1; 19242e186a2cSTobias Waldekranz } 1925aa836df9SFlorian Fainelli 19262e186a2cSTobias Waldekranz return 0; 1927aa836df9SFlorian Fainelli } 1928aa836df9SFlorian Fainelli 19299861f720SRussell King /* 19309861f720SRussell King * of_find_net_device_by_node - lookup the net device for the device node 19319861f720SRussell King * @np: OF device node 19329861f720SRussell King * 19339861f720SRussell King * Looks up the net_device structure corresponding with the device node. 19349861f720SRussell King * If successful, returns a pointer to the net_device with the embedded 19359861f720SRussell King * struct device refcount incremented by one, or NULL on failure. The 19369861f720SRussell King * refcount must be dropped when done with the net_device. 19379861f720SRussell King */ 1938aa836df9SFlorian Fainelli struct net_device *of_find_net_device_by_node(struct device_node *np) 1939aa836df9SFlorian Fainelli { 1940aa836df9SFlorian Fainelli struct device *dev; 1941aa836df9SFlorian Fainelli 1942aa836df9SFlorian Fainelli dev = class_find_device(&net_class, NULL, np, of_dev_node_match); 1943aa836df9SFlorian Fainelli if (!dev) 1944aa836df9SFlorian Fainelli return NULL; 1945aa836df9SFlorian Fainelli 1946aa836df9SFlorian Fainelli return to_net_dev(dev); 1947aa836df9SFlorian Fainelli } 1948aa836df9SFlorian Fainelli EXPORT_SYMBOL(of_find_net_device_by_node); 1949aa836df9SFlorian Fainelli #endif 1950aa836df9SFlorian Fainelli 19519093bbb2SStephen Hemminger /* Delete sysfs entries but hold kobject reference until after all 19529093bbb2SStephen Hemminger * netdev references are gone. 19539093bbb2SStephen Hemminger */ 19546b53dafeSWANG Cong void netdev_unregister_kobject(struct net_device *ndev) 19551da177e4SLinus Torvalds { 19566648c65eSstephen hemminger struct device *dev = &ndev->dev; 19579093bbb2SStephen Hemminger 19588b8f3e66SChristian Brauner if (!refcount_read(&dev_net(ndev)->ns.count)) 1959002d8a1aSAndrey Vagin dev_set_uevent_suppress(dev, 1); 1960002d8a1aSAndrey Vagin 19619093bbb2SStephen Hemminger kobject_get(&dev->kobj); 19623891845eSEric W. Biederman 19636b53dafeSWANG Cong remove_queue_kobjects(ndev); 19640a9627f2STom Herbert 19659802c8e2SMing Lei pm_runtime_set_memalloc_noio(dev, false); 19669802c8e2SMing Lei 19679093bbb2SStephen Hemminger device_del(dev); 19681da177e4SLinus Torvalds } 19691da177e4SLinus Torvalds 19701da177e4SLinus Torvalds /* Create sysfs entries for network device. */ 19716b53dafeSWANG Cong int netdev_register_kobject(struct net_device *ndev) 19721da177e4SLinus Torvalds { 19736648c65eSstephen hemminger struct device *dev = &ndev->dev; 19746b53dafeSWANG Cong const struct attribute_group **groups = ndev->sysfs_groups; 19750a9627f2STom Herbert int error = 0; 19761da177e4SLinus Torvalds 1977a1b3f594SEric W. Biederman device_initialize(dev); 197843cb76d9SGreg Kroah-Hartman dev->class = &net_class; 19796b53dafeSWANG Cong dev->platform_data = ndev; 198043cb76d9SGreg Kroah-Hartman dev->groups = groups; 19811da177e4SLinus Torvalds 19826b53dafeSWANG Cong dev_set_name(dev, "%s", ndev->name); 19831da177e4SLinus Torvalds 19848b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 19850c509a6cSEric W. Biederman /* Allow for a device specific group */ 19860c509a6cSEric W. Biederman if (*groups) 19870c509a6cSEric W. Biederman groups++; 19881da177e4SLinus Torvalds 19890c509a6cSEric W. Biederman *groups++ = &netstat_group; 199038c1a01cSJohannes Berg 199138c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) 19926b53dafeSWANG Cong if (ndev->ieee80211_ptr) 199338c1a01cSJohannes Berg *groups++ = &wireless_group; 199438c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) 19956b53dafeSWANG Cong else if (ndev->wireless_handlers) 199638c1a01cSJohannes Berg *groups++ = &wireless_group; 199738c1a01cSJohannes Berg #endif 199838c1a01cSJohannes Berg #endif 19998b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 20001da177e4SLinus Torvalds 20010a9627f2STom Herbert error = device_add(dev); 20020a9627f2STom Herbert if (error) 20038ed633b9SWang Hai return error; 20040a9627f2STom Herbert 20056b53dafeSWANG Cong error = register_queue_kobjects(ndev); 20068ed633b9SWang Hai if (error) { 20078ed633b9SWang Hai device_del(dev); 20088ed633b9SWang Hai return error; 20098ed633b9SWang Hai } 20100a9627f2STom Herbert 20119802c8e2SMing Lei pm_runtime_set_memalloc_noio(dev, true); 20129802c8e2SMing Lei 20130a9627f2STom Herbert return error; 20141da177e4SLinus Torvalds } 20151da177e4SLinus Torvalds 2016e6dee9f3SChristian Brauner /* Change owner for sysfs entries when moving network devices across network 2017e6dee9f3SChristian Brauner * namespaces owned by different user namespaces. 2018e6dee9f3SChristian Brauner */ 2019e6dee9f3SChristian Brauner int netdev_change_owner(struct net_device *ndev, const struct net *net_old, 2020e6dee9f3SChristian Brauner const struct net *net_new) 2021e6dee9f3SChristian Brauner { 2022f7a1e76dSXin Long kuid_t old_uid = GLOBAL_ROOT_UID, new_uid = GLOBAL_ROOT_UID; 2023f7a1e76dSXin Long kgid_t old_gid = GLOBAL_ROOT_GID, new_gid = GLOBAL_ROOT_GID; 2024e6dee9f3SChristian Brauner struct device *dev = &ndev->dev; 2025e6dee9f3SChristian Brauner int error; 2026e6dee9f3SChristian Brauner 2027e6dee9f3SChristian Brauner net_ns_get_ownership(net_old, &old_uid, &old_gid); 2028e6dee9f3SChristian Brauner net_ns_get_ownership(net_new, &new_uid, &new_gid); 2029e6dee9f3SChristian Brauner 2030e6dee9f3SChristian Brauner /* The network namespace was changed but the owning user namespace is 2031e6dee9f3SChristian Brauner * identical so there's no need to change the owner of sysfs entries. 2032e6dee9f3SChristian Brauner */ 2033e6dee9f3SChristian Brauner if (uid_eq(old_uid, new_uid) && gid_eq(old_gid, new_gid)) 2034e6dee9f3SChristian Brauner return 0; 2035e6dee9f3SChristian Brauner 2036e6dee9f3SChristian Brauner error = device_change_owner(dev, new_uid, new_gid); 2037e6dee9f3SChristian Brauner if (error) 2038e6dee9f3SChristian Brauner return error; 2039e6dee9f3SChristian Brauner 2040d755407dSChristian Brauner error = queue_change_owner(ndev, new_uid, new_gid); 2041d755407dSChristian Brauner if (error) 2042d755407dSChristian Brauner return error; 2043d755407dSChristian Brauner 2044e6dee9f3SChristian Brauner return 0; 2045e6dee9f3SChristian Brauner } 2046e6dee9f3SChristian Brauner 2047b793dc5cSstephen hemminger int netdev_class_create_file_ns(const struct class_attribute *class_attr, 204858292cbeSTejun Heo const void *ns) 2049b8a9787eSJay Vosburgh { 205058292cbeSTejun Heo return class_create_file_ns(&net_class, class_attr, ns); 2051b8a9787eSJay Vosburgh } 205258292cbeSTejun Heo EXPORT_SYMBOL(netdev_class_create_file_ns); 2053b8a9787eSJay Vosburgh 2054b793dc5cSstephen hemminger void netdev_class_remove_file_ns(const struct class_attribute *class_attr, 205558292cbeSTejun Heo const void *ns) 2056b8a9787eSJay Vosburgh { 205758292cbeSTejun Heo class_remove_file_ns(&net_class, class_attr, ns); 2058b8a9787eSJay Vosburgh } 205958292cbeSTejun Heo EXPORT_SYMBOL(netdev_class_remove_file_ns); 2060b8a9787eSJay Vosburgh 2061a48d4bb0SDaniel Borkmann int __init netdev_kobject_init(void) 20621da177e4SLinus Torvalds { 2063608b4b95SEric W. Biederman kobj_ns_type_register(&net_ns_type_operations); 20641da177e4SLinus Torvalds return class_register(&net_class); 20651da177e4SLinus Torvalds } 2066