11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * net-sysfs.c - network device class and attributes 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2003 Stephen Hemminger <shemminger@osdl.org> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 124fc268d2SRandy Dunlap #include <linux/capability.h> 131da177e4SLinus Torvalds #include <linux/kernel.h> 141da177e4SLinus Torvalds #include <linux/netdevice.h> 15aecbe01eSJiri Pirko #include <net/switchdev.h> 161da177e4SLinus Torvalds #include <linux/if_arp.h> 175a0e3ad6STejun Heo #include <linux/slab.h> 18174cd4b1SIngo Molnar #include <linux/sched/signal.h> 19608b4b95SEric W. Biederman #include <linux/nsproxy.h> 201da177e4SLinus Torvalds #include <net/sock.h> 21608b4b95SEric W. Biederman #include <net/net_namespace.h> 221da177e4SLinus Torvalds #include <linux/rtnetlink.h> 23fec5e652STom Herbert #include <linux/vmalloc.h> 24bc3b2d7fSPaul Gortmaker #include <linux/export.h> 25114cf580STom Herbert #include <linux/jiffies.h> 269802c8e2SMing Lei #include <linux/pm_runtime.h> 27aa836df9SFlorian Fainelli #include <linux/of.h> 2888832a22SBen Dooks #include <linux/of_net.h> 294d99f660SAndrei Vagin #include <linux/cpu.h> 301da177e4SLinus Torvalds 31342709efSPavel Emelyanov #include "net-sysfs.h" 32342709efSPavel Emelyanov 338b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 341da177e4SLinus Torvalds static const char fmt_hex[] = "%#x\n"; 351da177e4SLinus Torvalds static const char fmt_dec[] = "%d\n"; 361da177e4SLinus Torvalds static const char fmt_ulong[] = "%lu\n"; 37be1f3c2cSBen Hutchings static const char fmt_u64[] = "%llu\n"; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds static inline int dev_isalive(const struct net_device *dev) 401da177e4SLinus Torvalds { 41fe9925b5SStephen Hemminger return dev->reg_state <= NETREG_REGISTERED; 421da177e4SLinus Torvalds } 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* use same locking rules as GIF* ioctl's */ 4543cb76d9SGreg Kroah-Hartman static ssize_t netdev_show(const struct device *dev, 4643cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 471da177e4SLinus Torvalds ssize_t (*format)(const struct net_device *, char *)) 481da177e4SLinus Torvalds { 496b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 501da177e4SLinus Torvalds ssize_t ret = -EINVAL; 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds read_lock(&dev_base_lock); 536b53dafeSWANG Cong if (dev_isalive(ndev)) 546b53dafeSWANG Cong ret = (*format)(ndev, buf); 551da177e4SLinus Torvalds read_unlock(&dev_base_lock); 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds return ret; 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds /* generate a show function for simple field */ 611da177e4SLinus Torvalds #define NETDEVICE_SHOW(field, format_string) \ 626b53dafeSWANG Cong static ssize_t format_##field(const struct net_device *dev, char *buf) \ 631da177e4SLinus Torvalds { \ 646b53dafeSWANG Cong return sprintf(buf, format_string, dev->field); \ 651da177e4SLinus Torvalds } \ 666be8aeefSGreg Kroah-Hartman static ssize_t field##_show(struct device *dev, \ 6743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 681da177e4SLinus Torvalds { \ 6943cb76d9SGreg Kroah-Hartman return netdev_show(dev, attr, buf, format_##field); \ 706be8aeefSGreg Kroah-Hartman } \ 711da177e4SLinus Torvalds 726be8aeefSGreg Kroah-Hartman #define NETDEVICE_SHOW_RO(field, format_string) \ 736be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(field, format_string); \ 746be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(field) 756be8aeefSGreg Kroah-Hartman 766be8aeefSGreg Kroah-Hartman #define NETDEVICE_SHOW_RW(field, format_string) \ 776be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(field, format_string); \ 786be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(field) 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds /* use same locking and permission rules as SIF* ioctl's */ 8143cb76d9SGreg Kroah-Hartman static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, 821da177e4SLinus Torvalds const char *buf, size_t len, 831da177e4SLinus Torvalds int (*set)(struct net_device *, unsigned long)) 841da177e4SLinus Torvalds { 855e1fccc0SEric W. Biederman struct net_device *netdev = to_net_dev(dev); 865e1fccc0SEric W. Biederman struct net *net = dev_net(netdev); 871da177e4SLinus Torvalds unsigned long new; 881da177e4SLinus Torvalds int ret = -EINVAL; 891da177e4SLinus Torvalds 905e1fccc0SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 911da177e4SLinus Torvalds return -EPERM; 921da177e4SLinus Torvalds 93e1e420c7SShuah Khan ret = kstrtoul(buf, 0, &new); 94e1e420c7SShuah Khan if (ret) 951da177e4SLinus Torvalds goto err; 961da177e4SLinus Torvalds 975a5990d3SStephen Hemminger if (!rtnl_trylock()) 98336ca57cSEric W. Biederman return restart_syscall(); 995a5990d3SStephen Hemminger 1005e1fccc0SEric W. Biederman if (dev_isalive(netdev)) { 1016648c65eSstephen hemminger ret = (*set)(netdev, new); 1026648c65eSstephen hemminger if (ret == 0) 1031da177e4SLinus Torvalds ret = len; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds rtnl_unlock(); 1061da177e4SLinus Torvalds err: 1071da177e4SLinus Torvalds return ret; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1106be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(dev_id, fmt_hex); 1113f85944fSAmir Vadai NETDEVICE_SHOW_RO(dev_port, fmt_dec); 1126be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(addr_assign_type, fmt_dec); 1136be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(addr_len, fmt_dec); 1146be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(ifindex, fmt_dec); 1156be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(type, fmt_dec); 1166be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(link_mode, fmt_dec); 1171da177e4SLinus Torvalds 118a54acb3aSNicolas Dichtel static ssize_t iflink_show(struct device *dev, struct device_attribute *attr, 119a54acb3aSNicolas Dichtel char *buf) 120a54acb3aSNicolas Dichtel { 121a54acb3aSNicolas Dichtel struct net_device *ndev = to_net_dev(dev); 122a54acb3aSNicolas Dichtel 123a54acb3aSNicolas Dichtel return sprintf(buf, fmt_dec, dev_get_iflink(ndev)); 124a54acb3aSNicolas Dichtel } 125a54acb3aSNicolas Dichtel static DEVICE_ATTR_RO(iflink); 126a54acb3aSNicolas Dichtel 1276b53dafeSWANG Cong static ssize_t format_name_assign_type(const struct net_device *dev, char *buf) 128685343fcSTom Gundersen { 1296b53dafeSWANG Cong return sprintf(buf, fmt_dec, dev->name_assign_type); 130685343fcSTom Gundersen } 131685343fcSTom Gundersen 132685343fcSTom Gundersen static ssize_t name_assign_type_show(struct device *dev, 133685343fcSTom Gundersen struct device_attribute *attr, 134685343fcSTom Gundersen char *buf) 135685343fcSTom Gundersen { 1366b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 137685343fcSTom Gundersen ssize_t ret = -EINVAL; 138685343fcSTom Gundersen 1396b53dafeSWANG Cong if (ndev->name_assign_type != NET_NAME_UNKNOWN) 140685343fcSTom Gundersen ret = netdev_show(dev, attr, buf, format_name_assign_type); 141685343fcSTom Gundersen 142685343fcSTom Gundersen return ret; 143685343fcSTom Gundersen } 144685343fcSTom Gundersen static DEVICE_ATTR_RO(name_assign_type); 145685343fcSTom Gundersen 1461da177e4SLinus Torvalds /* use same locking rules as GIFHWADDR ioctl's */ 1476be8aeefSGreg Kroah-Hartman static ssize_t address_show(struct device *dev, struct device_attribute *attr, 14843cb76d9SGreg Kroah-Hartman char *buf) 1491da177e4SLinus Torvalds { 1506b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 1511da177e4SLinus Torvalds ssize_t ret = -EINVAL; 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds read_lock(&dev_base_lock); 1546b53dafeSWANG Cong if (dev_isalive(ndev)) 1556b53dafeSWANG Cong ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len); 1561da177e4SLinus Torvalds read_unlock(&dev_base_lock); 1571da177e4SLinus Torvalds return ret; 1581da177e4SLinus Torvalds } 1596be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(address); 1601da177e4SLinus Torvalds 1616be8aeefSGreg Kroah-Hartman static ssize_t broadcast_show(struct device *dev, 16243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1631da177e4SLinus Torvalds { 1646b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 1656648c65eSstephen hemminger 1666b53dafeSWANG Cong if (dev_isalive(ndev)) 1676b53dafeSWANG Cong return sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len); 1681da177e4SLinus Torvalds return -EINVAL; 1691da177e4SLinus Torvalds } 1706be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(broadcast); 1711da177e4SLinus Torvalds 1726b53dafeSWANG Cong static int change_carrier(struct net_device *dev, unsigned long new_carrier) 173fdae0fdeSJiri Pirko { 1746b53dafeSWANG Cong if (!netif_running(dev)) 175fdae0fdeSJiri Pirko return -EINVAL; 1766b53dafeSWANG Cong return dev_change_carrier(dev, (bool)new_carrier); 177fdae0fdeSJiri Pirko } 178fdae0fdeSJiri Pirko 1796be8aeefSGreg Kroah-Hartman static ssize_t carrier_store(struct device *dev, struct device_attribute *attr, 180fdae0fdeSJiri Pirko const char *buf, size_t len) 181fdae0fdeSJiri Pirko { 182fdae0fdeSJiri Pirko return netdev_store(dev, attr, buf, len, change_carrier); 183fdae0fdeSJiri Pirko } 184fdae0fdeSJiri Pirko 1856be8aeefSGreg Kroah-Hartman static ssize_t carrier_show(struct device *dev, 18643cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1871da177e4SLinus Torvalds { 1881da177e4SLinus Torvalds struct net_device *netdev = to_net_dev(dev); 1896648c65eSstephen hemminger 1906648c65eSstephen hemminger if (netif_running(netdev)) 1911da177e4SLinus Torvalds return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); 1926648c65eSstephen hemminger 1931da177e4SLinus Torvalds return -EINVAL; 1941da177e4SLinus Torvalds } 1956be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(carrier); 1961da177e4SLinus Torvalds 1976be8aeefSGreg Kroah-Hartman static ssize_t speed_show(struct device *dev, 198d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 199d519e17eSAndy Gospodarek { 200d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 201d519e17eSAndy Gospodarek int ret = -EINVAL; 202d519e17eSAndy Gospodarek 203d519e17eSAndy Gospodarek if (!rtnl_trylock()) 204d519e17eSAndy Gospodarek return restart_syscall(); 205d519e17eSAndy Gospodarek 2068ae6dacaSDavid Decotigny if (netif_running(netdev)) { 2077cad1bacSDavid Decotigny struct ethtool_link_ksettings cmd; 2087cad1bacSDavid Decotigny 2097cad1bacSDavid Decotigny if (!__ethtool_get_link_ksettings(netdev, &cmd)) 2107cad1bacSDavid Decotigny ret = sprintf(buf, fmt_dec, cmd.base.speed); 211d519e17eSAndy Gospodarek } 212d519e17eSAndy Gospodarek rtnl_unlock(); 213d519e17eSAndy Gospodarek return ret; 214d519e17eSAndy Gospodarek } 2156be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(speed); 216d519e17eSAndy Gospodarek 2176be8aeefSGreg Kroah-Hartman static ssize_t duplex_show(struct device *dev, 218d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 219d519e17eSAndy Gospodarek { 220d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 221d519e17eSAndy Gospodarek int ret = -EINVAL; 222d519e17eSAndy Gospodarek 223d519e17eSAndy Gospodarek if (!rtnl_trylock()) 224d519e17eSAndy Gospodarek return restart_syscall(); 225d519e17eSAndy Gospodarek 2268ae6dacaSDavid Decotigny if (netif_running(netdev)) { 2277cad1bacSDavid Decotigny struct ethtool_link_ksettings cmd; 2287cad1bacSDavid Decotigny 2297cad1bacSDavid Decotigny if (!__ethtool_get_link_ksettings(netdev, &cmd)) { 230c6c13965SNikolay Aleksandrov const char *duplex; 2317cad1bacSDavid Decotigny 2327cad1bacSDavid Decotigny switch (cmd.base.duplex) { 233c6c13965SNikolay Aleksandrov case DUPLEX_HALF: 234c6c13965SNikolay Aleksandrov duplex = "half"; 235c6c13965SNikolay Aleksandrov break; 236c6c13965SNikolay Aleksandrov case DUPLEX_FULL: 237c6c13965SNikolay Aleksandrov duplex = "full"; 238c6c13965SNikolay Aleksandrov break; 239c6c13965SNikolay Aleksandrov default: 240c6c13965SNikolay Aleksandrov duplex = "unknown"; 241c6c13965SNikolay Aleksandrov break; 242c6c13965SNikolay Aleksandrov } 243c6c13965SNikolay Aleksandrov ret = sprintf(buf, "%s\n", duplex); 244c6c13965SNikolay Aleksandrov } 245d519e17eSAndy Gospodarek } 246d519e17eSAndy Gospodarek rtnl_unlock(); 247d519e17eSAndy Gospodarek return ret; 248d519e17eSAndy Gospodarek } 2496be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(duplex); 250d519e17eSAndy Gospodarek 2516be8aeefSGreg Kroah-Hartman static ssize_t dormant_show(struct device *dev, 25243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 253b00055aaSStefan Rompf { 254b00055aaSStefan Rompf struct net_device *netdev = to_net_dev(dev); 255b00055aaSStefan Rompf 256b00055aaSStefan Rompf if (netif_running(netdev)) 257b00055aaSStefan Rompf return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); 258b00055aaSStefan Rompf 259b00055aaSStefan Rompf return -EINVAL; 260b00055aaSStefan Rompf } 2616be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(dormant); 262b00055aaSStefan Rompf 26336cbd3dcSJan Engelhardt static const char *const operstates[] = { 264b00055aaSStefan Rompf "unknown", 265b00055aaSStefan Rompf "notpresent", /* currently unused */ 266b00055aaSStefan Rompf "down", 267b00055aaSStefan Rompf "lowerlayerdown", 268b00055aaSStefan Rompf "testing", /* currently unused */ 269b00055aaSStefan Rompf "dormant", 270b00055aaSStefan Rompf "up" 271b00055aaSStefan Rompf }; 272b00055aaSStefan Rompf 2736be8aeefSGreg Kroah-Hartman static ssize_t operstate_show(struct device *dev, 27443cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 275b00055aaSStefan Rompf { 276b00055aaSStefan Rompf const struct net_device *netdev = to_net_dev(dev); 277b00055aaSStefan Rompf unsigned char operstate; 278b00055aaSStefan Rompf 279b00055aaSStefan Rompf read_lock(&dev_base_lock); 280b00055aaSStefan Rompf operstate = netdev->operstate; 281b00055aaSStefan Rompf if (!netif_running(netdev)) 282b00055aaSStefan Rompf operstate = IF_OPER_DOWN; 283b00055aaSStefan Rompf read_unlock(&dev_base_lock); 284b00055aaSStefan Rompf 285e3a5cd9eSAdrian Bunk if (operstate >= ARRAY_SIZE(operstates)) 286b00055aaSStefan Rompf return -EINVAL; /* should not happen */ 287b00055aaSStefan Rompf 288b00055aaSStefan Rompf return sprintf(buf, "%s\n", operstates[operstate]); 289b00055aaSStefan Rompf } 2906be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(operstate); 291b00055aaSStefan Rompf 2922d3b479dSdavid decotigny static ssize_t carrier_changes_show(struct device *dev, 2932d3b479dSdavid decotigny struct device_attribute *attr, 2942d3b479dSdavid decotigny char *buf) 2952d3b479dSdavid decotigny { 2962d3b479dSdavid decotigny struct net_device *netdev = to_net_dev(dev); 2976648c65eSstephen hemminger 2982d3b479dSdavid decotigny return sprintf(buf, fmt_dec, 299b2d3bcfaSDavid Decotigny atomic_read(&netdev->carrier_up_count) + 300b2d3bcfaSDavid Decotigny atomic_read(&netdev->carrier_down_count)); 3012d3b479dSdavid decotigny } 3022d3b479dSdavid decotigny static DEVICE_ATTR_RO(carrier_changes); 3032d3b479dSdavid decotigny 304b2d3bcfaSDavid Decotigny static ssize_t carrier_up_count_show(struct device *dev, 305b2d3bcfaSDavid Decotigny struct device_attribute *attr, 306b2d3bcfaSDavid Decotigny char *buf) 307b2d3bcfaSDavid Decotigny { 308b2d3bcfaSDavid Decotigny struct net_device *netdev = to_net_dev(dev); 309b2d3bcfaSDavid Decotigny 310b2d3bcfaSDavid Decotigny return sprintf(buf, fmt_dec, atomic_read(&netdev->carrier_up_count)); 311b2d3bcfaSDavid Decotigny } 312b2d3bcfaSDavid Decotigny static DEVICE_ATTR_RO(carrier_up_count); 313b2d3bcfaSDavid Decotigny 314b2d3bcfaSDavid Decotigny static ssize_t carrier_down_count_show(struct device *dev, 315b2d3bcfaSDavid Decotigny struct device_attribute *attr, 316b2d3bcfaSDavid Decotigny char *buf) 317b2d3bcfaSDavid Decotigny { 318b2d3bcfaSDavid Decotigny struct net_device *netdev = to_net_dev(dev); 319b2d3bcfaSDavid Decotigny 320b2d3bcfaSDavid Decotigny return sprintf(buf, fmt_dec, atomic_read(&netdev->carrier_down_count)); 321b2d3bcfaSDavid Decotigny } 322b2d3bcfaSDavid Decotigny static DEVICE_ATTR_RO(carrier_down_count); 323b2d3bcfaSDavid Decotigny 3241da177e4SLinus Torvalds /* read-write attributes */ 3251da177e4SLinus Torvalds 3266b53dafeSWANG Cong static int change_mtu(struct net_device *dev, unsigned long new_mtu) 3271da177e4SLinus Torvalds { 3286b53dafeSWANG Cong return dev_set_mtu(dev, (int)new_mtu); 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds 3316be8aeefSGreg Kroah-Hartman static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, 33243cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3331da177e4SLinus Torvalds { 33443cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_mtu); 3351da177e4SLinus Torvalds } 3366be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(mtu, fmt_dec); 3371da177e4SLinus Torvalds 3386b53dafeSWANG Cong static int change_flags(struct net_device *dev, unsigned long new_flags) 3391da177e4SLinus Torvalds { 340567c5e13SPetr Machata return dev_change_flags(dev, (unsigned int)new_flags, NULL); 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 3436be8aeefSGreg Kroah-Hartman static ssize_t flags_store(struct device *dev, struct device_attribute *attr, 34443cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3451da177e4SLinus Torvalds { 34643cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_flags); 3471da177e4SLinus Torvalds } 3486be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(flags, fmt_hex); 3491da177e4SLinus Torvalds 3506be8aeefSGreg Kroah-Hartman static ssize_t tx_queue_len_store(struct device *dev, 35143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 35243cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3531da177e4SLinus Torvalds { 3545e1fccc0SEric W. Biederman if (!capable(CAP_NET_ADMIN)) 3555e1fccc0SEric W. Biederman return -EPERM; 3565e1fccc0SEric W. Biederman 3576a643ddbSCong Wang return netdev_store(dev, attr, buf, len, dev_change_tx_queue_len); 3581da177e4SLinus Torvalds } 3590cd29503SAlexey Dobriyan NETDEVICE_SHOW_RW(tx_queue_len, fmt_dec); 3601da177e4SLinus Torvalds 3613b47d303SEric Dumazet static int change_gro_flush_timeout(struct net_device *dev, unsigned long val) 3623b47d303SEric Dumazet { 3633b47d303SEric Dumazet dev->gro_flush_timeout = val; 3643b47d303SEric Dumazet return 0; 3653b47d303SEric Dumazet } 3663b47d303SEric Dumazet 3673b47d303SEric Dumazet static ssize_t gro_flush_timeout_store(struct device *dev, 3683b47d303SEric Dumazet struct device_attribute *attr, 3693b47d303SEric Dumazet const char *buf, size_t len) 3703b47d303SEric Dumazet { 3713b47d303SEric Dumazet if (!capable(CAP_NET_ADMIN)) 3723b47d303SEric Dumazet return -EPERM; 3733b47d303SEric Dumazet 3743b47d303SEric Dumazet return netdev_store(dev, attr, buf, len, change_gro_flush_timeout); 3753b47d303SEric Dumazet } 3763b47d303SEric Dumazet NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong); 3773b47d303SEric Dumazet 3786be8aeefSGreg Kroah-Hartman static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr, 3790b815a1aSStephen Hemminger const char *buf, size_t len) 3800b815a1aSStephen Hemminger { 3810b815a1aSStephen Hemminger struct net_device *netdev = to_net_dev(dev); 3825e1fccc0SEric W. Biederman struct net *net = dev_net(netdev); 3830b815a1aSStephen Hemminger size_t count = len; 384c92eb77aSRoopa Prabhu ssize_t ret = 0; 3850b815a1aSStephen Hemminger 3865e1fccc0SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 3870b815a1aSStephen Hemminger return -EPERM; 3880b815a1aSStephen Hemminger 3890b815a1aSStephen Hemminger /* ignore trailing newline */ 3900b815a1aSStephen Hemminger if (len > 0 && buf[len - 1] == '\n') 3910b815a1aSStephen Hemminger --count; 3920b815a1aSStephen Hemminger 393c92eb77aSRoopa Prabhu if (!rtnl_trylock()) 394c92eb77aSRoopa Prabhu return restart_syscall(); 3950b815a1aSStephen Hemminger 396c92eb77aSRoopa Prabhu if (dev_isalive(netdev)) { 397c92eb77aSRoopa Prabhu ret = dev_set_alias(netdev, buf, count); 398c92eb77aSRoopa Prabhu if (ret < 0) 399c92eb77aSRoopa Prabhu goto err; 400c92eb77aSRoopa Prabhu ret = len; 401c92eb77aSRoopa Prabhu netdev_state_change(netdev); 402c92eb77aSRoopa Prabhu } 403c92eb77aSRoopa Prabhu err: 404c92eb77aSRoopa Prabhu rtnl_unlock(); 405c92eb77aSRoopa Prabhu 406c92eb77aSRoopa Prabhu return ret; 4070b815a1aSStephen Hemminger } 4080b815a1aSStephen Hemminger 4096be8aeefSGreg Kroah-Hartman static ssize_t ifalias_show(struct device *dev, 4100b815a1aSStephen Hemminger struct device_attribute *attr, char *buf) 4110b815a1aSStephen Hemminger { 4120b815a1aSStephen Hemminger const struct net_device *netdev = to_net_dev(dev); 4136c557001SFlorian Westphal char tmp[IFALIASZ]; 4140b815a1aSStephen Hemminger ssize_t ret = 0; 4150b815a1aSStephen Hemminger 4166c557001SFlorian Westphal ret = dev_get_alias(netdev, tmp, sizeof(tmp)); 4176c557001SFlorian Westphal if (ret > 0) 4186c557001SFlorian Westphal ret = sprintf(buf, "%s\n", tmp); 4190b815a1aSStephen Hemminger return ret; 4200b815a1aSStephen Hemminger } 4216be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(ifalias); 422a512b92bSVlad Dogaru 4236b53dafeSWANG Cong static int change_group(struct net_device *dev, unsigned long new_group) 424a512b92bSVlad Dogaru { 4256b53dafeSWANG Cong dev_set_group(dev, (int)new_group); 426a512b92bSVlad Dogaru return 0; 427a512b92bSVlad Dogaru } 428a512b92bSVlad Dogaru 4296be8aeefSGreg Kroah-Hartman static ssize_t group_store(struct device *dev, struct device_attribute *attr, 430a512b92bSVlad Dogaru const char *buf, size_t len) 431a512b92bSVlad Dogaru { 432a512b92bSVlad Dogaru return netdev_store(dev, attr, buf, len, change_group); 433a512b92bSVlad Dogaru } 4346be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(group, fmt_dec); 435d6444062SJoe Perches static DEVICE_ATTR(netdev_group, 0644, group_show, group_store); 436a512b92bSVlad Dogaru 437d746d707SAnuradha Karuppiah static int change_proto_down(struct net_device *dev, unsigned long proto_down) 438d746d707SAnuradha Karuppiah { 439d746d707SAnuradha Karuppiah return dev_change_proto_down(dev, (bool)proto_down); 440d746d707SAnuradha Karuppiah } 441d746d707SAnuradha Karuppiah 442d746d707SAnuradha Karuppiah static ssize_t proto_down_store(struct device *dev, 443d746d707SAnuradha Karuppiah struct device_attribute *attr, 444d746d707SAnuradha Karuppiah const char *buf, size_t len) 445d746d707SAnuradha Karuppiah { 446d746d707SAnuradha Karuppiah return netdev_store(dev, attr, buf, len, change_proto_down); 447d746d707SAnuradha Karuppiah } 448d746d707SAnuradha Karuppiah NETDEVICE_SHOW_RW(proto_down, fmt_dec); 449d746d707SAnuradha Karuppiah 450cc998ff8SLinus Torvalds static ssize_t phys_port_id_show(struct device *dev, 451ff80e519SJiri Pirko struct device_attribute *attr, char *buf) 452ff80e519SJiri Pirko { 453ff80e519SJiri Pirko struct net_device *netdev = to_net_dev(dev); 454ff80e519SJiri Pirko ssize_t ret = -EINVAL; 455ff80e519SJiri Pirko 456ff80e519SJiri Pirko if (!rtnl_trylock()) 457ff80e519SJiri Pirko return restart_syscall(); 458ff80e519SJiri Pirko 459ff80e519SJiri Pirko if (dev_isalive(netdev)) { 46002637fceSJiri Pirko struct netdev_phys_item_id ppid; 461ff80e519SJiri Pirko 462ff80e519SJiri Pirko ret = dev_get_phys_port_id(netdev, &ppid); 463ff80e519SJiri Pirko if (!ret) 464ff80e519SJiri Pirko ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); 465ff80e519SJiri Pirko } 466ff80e519SJiri Pirko rtnl_unlock(); 467ff80e519SJiri Pirko 468ff80e519SJiri Pirko return ret; 469ff80e519SJiri Pirko } 470cc998ff8SLinus Torvalds static DEVICE_ATTR_RO(phys_port_id); 471ff80e519SJiri Pirko 472db24a904SDavid Ahern static ssize_t phys_port_name_show(struct device *dev, 473db24a904SDavid Ahern struct device_attribute *attr, char *buf) 474db24a904SDavid Ahern { 475db24a904SDavid Ahern struct net_device *netdev = to_net_dev(dev); 476db24a904SDavid Ahern ssize_t ret = -EINVAL; 477db24a904SDavid Ahern 478db24a904SDavid Ahern if (!rtnl_trylock()) 479db24a904SDavid Ahern return restart_syscall(); 480db24a904SDavid Ahern 481db24a904SDavid Ahern if (dev_isalive(netdev)) { 482db24a904SDavid Ahern char name[IFNAMSIZ]; 483db24a904SDavid Ahern 484db24a904SDavid Ahern ret = dev_get_phys_port_name(netdev, name, sizeof(name)); 485db24a904SDavid Ahern if (!ret) 486db24a904SDavid Ahern ret = sprintf(buf, "%s\n", name); 487db24a904SDavid Ahern } 488db24a904SDavid Ahern rtnl_unlock(); 489db24a904SDavid Ahern 490db24a904SDavid Ahern return ret; 491db24a904SDavid Ahern } 492db24a904SDavid Ahern static DEVICE_ATTR_RO(phys_port_name); 493db24a904SDavid Ahern 494aecbe01eSJiri Pirko static ssize_t phys_switch_id_show(struct device *dev, 495aecbe01eSJiri Pirko struct device_attribute *attr, char *buf) 496aecbe01eSJiri Pirko { 497aecbe01eSJiri Pirko struct net_device *netdev = to_net_dev(dev); 498aecbe01eSJiri Pirko ssize_t ret = -EINVAL; 499aecbe01eSJiri Pirko 500aecbe01eSJiri Pirko if (!rtnl_trylock()) 501aecbe01eSJiri Pirko return restart_syscall(); 502aecbe01eSJiri Pirko 503aecbe01eSJiri Pirko if (dev_isalive(netdev)) { 504f8e20a9fSScott Feldman struct switchdev_attr attr = { 5056ff64f6fSIdo Schimmel .orig_dev = netdev, 5061f868398SJiri Pirko .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, 507f8e20a9fSScott Feldman .flags = SWITCHDEV_F_NO_RECURSE, 508f8e20a9fSScott Feldman }; 509aecbe01eSJiri Pirko 510f8e20a9fSScott Feldman ret = switchdev_port_attr_get(netdev, &attr); 511aecbe01eSJiri Pirko if (!ret) 51242275bd8SScott Feldman ret = sprintf(buf, "%*phN\n", attr.u.ppid.id_len, 51342275bd8SScott Feldman attr.u.ppid.id); 514aecbe01eSJiri Pirko } 515aecbe01eSJiri Pirko rtnl_unlock(); 516aecbe01eSJiri Pirko 517aecbe01eSJiri Pirko return ret; 518aecbe01eSJiri Pirko } 519aecbe01eSJiri Pirko static DEVICE_ATTR_RO(phys_switch_id); 520aecbe01eSJiri Pirko 521ec6cc599Sstephen hemminger static struct attribute *net_class_attrs[] __ro_after_init = { 5226be8aeefSGreg Kroah-Hartman &dev_attr_netdev_group.attr, 5236be8aeefSGreg Kroah-Hartman &dev_attr_type.attr, 5246be8aeefSGreg Kroah-Hartman &dev_attr_dev_id.attr, 5253f85944fSAmir Vadai &dev_attr_dev_port.attr, 5266be8aeefSGreg Kroah-Hartman &dev_attr_iflink.attr, 5276be8aeefSGreg Kroah-Hartman &dev_attr_ifindex.attr, 528685343fcSTom Gundersen &dev_attr_name_assign_type.attr, 5296be8aeefSGreg Kroah-Hartman &dev_attr_addr_assign_type.attr, 5306be8aeefSGreg Kroah-Hartman &dev_attr_addr_len.attr, 5316be8aeefSGreg Kroah-Hartman &dev_attr_link_mode.attr, 5326be8aeefSGreg Kroah-Hartman &dev_attr_address.attr, 5336be8aeefSGreg Kroah-Hartman &dev_attr_broadcast.attr, 5346be8aeefSGreg Kroah-Hartman &dev_attr_speed.attr, 5356be8aeefSGreg Kroah-Hartman &dev_attr_duplex.attr, 5366be8aeefSGreg Kroah-Hartman &dev_attr_dormant.attr, 5376be8aeefSGreg Kroah-Hartman &dev_attr_operstate.attr, 5382d3b479dSdavid decotigny &dev_attr_carrier_changes.attr, 5396be8aeefSGreg Kroah-Hartman &dev_attr_ifalias.attr, 5406be8aeefSGreg Kroah-Hartman &dev_attr_carrier.attr, 5416be8aeefSGreg Kroah-Hartman &dev_attr_mtu.attr, 5426be8aeefSGreg Kroah-Hartman &dev_attr_flags.attr, 5436be8aeefSGreg Kroah-Hartman &dev_attr_tx_queue_len.attr, 5443b47d303SEric Dumazet &dev_attr_gro_flush_timeout.attr, 545cc998ff8SLinus Torvalds &dev_attr_phys_port_id.attr, 546db24a904SDavid Ahern &dev_attr_phys_port_name.attr, 547aecbe01eSJiri Pirko &dev_attr_phys_switch_id.attr, 548d746d707SAnuradha Karuppiah &dev_attr_proto_down.attr, 549b2d3bcfaSDavid Decotigny &dev_attr_carrier_up_count.attr, 550b2d3bcfaSDavid Decotigny &dev_attr_carrier_down_count.attr, 5516be8aeefSGreg Kroah-Hartman NULL, 5521da177e4SLinus Torvalds }; 5536be8aeefSGreg Kroah-Hartman ATTRIBUTE_GROUPS(net_class); 5541da177e4SLinus Torvalds 5551da177e4SLinus Torvalds /* Show a given an attribute in the statistics group */ 55643cb76d9SGreg Kroah-Hartman static ssize_t netstat_show(const struct device *d, 55743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 5581da177e4SLinus Torvalds unsigned long offset) 5591da177e4SLinus Torvalds { 56043cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 5611da177e4SLinus Torvalds ssize_t ret = -EINVAL; 5621da177e4SLinus Torvalds 563be1f3c2cSBen Hutchings WARN_ON(offset > sizeof(struct rtnl_link_stats64) || 564be1f3c2cSBen Hutchings offset % sizeof(u64) != 0); 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds read_lock(&dev_base_lock); 56796e74088SPavel Emelyanov if (dev_isalive(dev)) { 56828172739SEric Dumazet struct rtnl_link_stats64 temp; 56928172739SEric Dumazet const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); 57028172739SEric Dumazet 571be1f3c2cSBen Hutchings ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *)stats) + offset)); 57296e74088SPavel Emelyanov } 5731da177e4SLinus Torvalds read_unlock(&dev_base_lock); 5741da177e4SLinus Torvalds return ret; 5751da177e4SLinus Torvalds } 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds /* generate a read-only statistics attribute */ 5781da177e4SLinus Torvalds #define NETSTAT_ENTRY(name) \ 5796be8aeefSGreg Kroah-Hartman static ssize_t name##_show(struct device *d, \ 58043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 5811da177e4SLinus Torvalds { \ 58243cb76d9SGreg Kroah-Hartman return netstat_show(d, attr, buf, \ 583be1f3c2cSBen Hutchings offsetof(struct rtnl_link_stats64, name)); \ 5841da177e4SLinus Torvalds } \ 5856be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(name) 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds NETSTAT_ENTRY(rx_packets); 5881da177e4SLinus Torvalds NETSTAT_ENTRY(tx_packets); 5891da177e4SLinus Torvalds NETSTAT_ENTRY(rx_bytes); 5901da177e4SLinus Torvalds NETSTAT_ENTRY(tx_bytes); 5911da177e4SLinus Torvalds NETSTAT_ENTRY(rx_errors); 5921da177e4SLinus Torvalds NETSTAT_ENTRY(tx_errors); 5931da177e4SLinus Torvalds NETSTAT_ENTRY(rx_dropped); 5941da177e4SLinus Torvalds NETSTAT_ENTRY(tx_dropped); 5951da177e4SLinus Torvalds NETSTAT_ENTRY(multicast); 5961da177e4SLinus Torvalds NETSTAT_ENTRY(collisions); 5971da177e4SLinus Torvalds NETSTAT_ENTRY(rx_length_errors); 5981da177e4SLinus Torvalds NETSTAT_ENTRY(rx_over_errors); 5991da177e4SLinus Torvalds NETSTAT_ENTRY(rx_crc_errors); 6001da177e4SLinus Torvalds NETSTAT_ENTRY(rx_frame_errors); 6011da177e4SLinus Torvalds NETSTAT_ENTRY(rx_fifo_errors); 6021da177e4SLinus Torvalds NETSTAT_ENTRY(rx_missed_errors); 6031da177e4SLinus Torvalds NETSTAT_ENTRY(tx_aborted_errors); 6041da177e4SLinus Torvalds NETSTAT_ENTRY(tx_carrier_errors); 6051da177e4SLinus Torvalds NETSTAT_ENTRY(tx_fifo_errors); 6061da177e4SLinus Torvalds NETSTAT_ENTRY(tx_heartbeat_errors); 6071da177e4SLinus Torvalds NETSTAT_ENTRY(tx_window_errors); 6081da177e4SLinus Torvalds NETSTAT_ENTRY(rx_compressed); 6091da177e4SLinus Torvalds NETSTAT_ENTRY(tx_compressed); 6106e7333d3SJarod Wilson NETSTAT_ENTRY(rx_nohandler); 6111da177e4SLinus Torvalds 612ec6cc599Sstephen hemminger static struct attribute *netstat_attrs[] __ro_after_init = { 61343cb76d9SGreg Kroah-Hartman &dev_attr_rx_packets.attr, 61443cb76d9SGreg Kroah-Hartman &dev_attr_tx_packets.attr, 61543cb76d9SGreg Kroah-Hartman &dev_attr_rx_bytes.attr, 61643cb76d9SGreg Kroah-Hartman &dev_attr_tx_bytes.attr, 61743cb76d9SGreg Kroah-Hartman &dev_attr_rx_errors.attr, 61843cb76d9SGreg Kroah-Hartman &dev_attr_tx_errors.attr, 61943cb76d9SGreg Kroah-Hartman &dev_attr_rx_dropped.attr, 62043cb76d9SGreg Kroah-Hartman &dev_attr_tx_dropped.attr, 62143cb76d9SGreg Kroah-Hartman &dev_attr_multicast.attr, 62243cb76d9SGreg Kroah-Hartman &dev_attr_collisions.attr, 62343cb76d9SGreg Kroah-Hartman &dev_attr_rx_length_errors.attr, 62443cb76d9SGreg Kroah-Hartman &dev_attr_rx_over_errors.attr, 62543cb76d9SGreg Kroah-Hartman &dev_attr_rx_crc_errors.attr, 62643cb76d9SGreg Kroah-Hartman &dev_attr_rx_frame_errors.attr, 62743cb76d9SGreg Kroah-Hartman &dev_attr_rx_fifo_errors.attr, 62843cb76d9SGreg Kroah-Hartman &dev_attr_rx_missed_errors.attr, 62943cb76d9SGreg Kroah-Hartman &dev_attr_tx_aborted_errors.attr, 63043cb76d9SGreg Kroah-Hartman &dev_attr_tx_carrier_errors.attr, 63143cb76d9SGreg Kroah-Hartman &dev_attr_tx_fifo_errors.attr, 63243cb76d9SGreg Kroah-Hartman &dev_attr_tx_heartbeat_errors.attr, 63343cb76d9SGreg Kroah-Hartman &dev_attr_tx_window_errors.attr, 63443cb76d9SGreg Kroah-Hartman &dev_attr_rx_compressed.attr, 63543cb76d9SGreg Kroah-Hartman &dev_attr_tx_compressed.attr, 6366e7333d3SJarod Wilson &dev_attr_rx_nohandler.attr, 6371da177e4SLinus Torvalds NULL 6381da177e4SLinus Torvalds }; 6391da177e4SLinus Torvalds 64038ef00ccSArvind Yadav static const struct attribute_group netstat_group = { 6411da177e4SLinus Torvalds .name = "statistics", 6421da177e4SLinus Torvalds .attrs = netstat_attrs, 6431da177e4SLinus Torvalds }; 64438c1a01cSJohannes Berg 64538c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) 64638c1a01cSJohannes Berg static struct attribute *wireless_attrs[] = { 64738c1a01cSJohannes Berg NULL 64838c1a01cSJohannes Berg }; 64938c1a01cSJohannes Berg 65038ef00ccSArvind Yadav static const struct attribute_group wireless_group = { 65138c1a01cSJohannes Berg .name = "wireless", 65238c1a01cSJohannes Berg .attrs = wireless_attrs, 65338c1a01cSJohannes Berg }; 65438c1a01cSJohannes Berg #endif 6556be8aeefSGreg Kroah-Hartman 6566be8aeefSGreg Kroah-Hartman #else /* CONFIG_SYSFS */ 6576be8aeefSGreg Kroah-Hartman #define net_class_groups NULL 658d6523ddfSEric W. Biederman #endif /* CONFIG_SYSFS */ 6591da177e4SLinus Torvalds 660a953be53SMichael Dalton #ifdef CONFIG_SYSFS 6616648c65eSstephen hemminger #define to_rx_queue_attr(_attr) \ 6626648c65eSstephen hemminger container_of(_attr, struct rx_queue_attribute, attr) 6630a9627f2STom Herbert 6640a9627f2STom Herbert #define to_rx_queue(obj) container_of(obj, struct netdev_rx_queue, kobj) 6650a9627f2STom Herbert 6660a9627f2STom Herbert static ssize_t rx_queue_attr_show(struct kobject *kobj, struct attribute *attr, 6670a9627f2STom Herbert char *buf) 6680a9627f2STom Herbert { 669667e427bSstephen hemminger const struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 6700a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 6710a9627f2STom Herbert 6720a9627f2STom Herbert if (!attribute->show) 6730a9627f2STom Herbert return -EIO; 6740a9627f2STom Herbert 675718ad681Sstephen hemminger return attribute->show(queue, buf); 6760a9627f2STom Herbert } 6770a9627f2STom Herbert 6780a9627f2STom Herbert static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr, 6790a9627f2STom Herbert const char *buf, size_t count) 6800a9627f2STom Herbert { 681667e427bSstephen hemminger const struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 6820a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 6830a9627f2STom Herbert 6840a9627f2STom Herbert if (!attribute->store) 6850a9627f2STom Herbert return -EIO; 6860a9627f2STom Herbert 687718ad681Sstephen hemminger return attribute->store(queue, buf, count); 6880a9627f2STom Herbert } 6890a9627f2STom Herbert 690fa50d645Sstephen hemminger static const struct sysfs_ops rx_queue_sysfs_ops = { 6910a9627f2STom Herbert .show = rx_queue_attr_show, 6920a9627f2STom Herbert .store = rx_queue_attr_store, 6930a9627f2STom Herbert }; 6940a9627f2STom Herbert 695a953be53SMichael Dalton #ifdef CONFIG_RPS 696718ad681Sstephen hemminger static ssize_t show_rps_map(struct netdev_rx_queue *queue, char *buf) 6970a9627f2STom Herbert { 6980a9627f2STom Herbert struct rps_map *map; 6990a9627f2STom Herbert cpumask_var_t mask; 700f0906827STejun Heo int i, len; 7010a9627f2STom Herbert 7020a9627f2STom Herbert if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 7030a9627f2STom Herbert return -ENOMEM; 7040a9627f2STom Herbert 7050a9627f2STom Herbert rcu_read_lock(); 7060a9627f2STom Herbert map = rcu_dereference(queue->rps_map); 7070a9627f2STom Herbert if (map) 7080a9627f2STom Herbert for (i = 0; i < map->len; i++) 7090a9627f2STom Herbert cpumask_set_cpu(map->cpus[i], mask); 7100a9627f2STom Herbert 711f0906827STejun Heo len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask)); 7120a9627f2STom Herbert rcu_read_unlock(); 7130a9627f2STom Herbert free_cpumask_var(mask); 7140a9627f2STom Herbert 715f0906827STejun Heo return len < PAGE_SIZE ? len : -EINVAL; 7160a9627f2STom Herbert } 7170a9627f2STom Herbert 718f5acb907SEric Dumazet static ssize_t store_rps_map(struct netdev_rx_queue *queue, 7190a9627f2STom Herbert const char *buf, size_t len) 7200a9627f2STom Herbert { 7210a9627f2STom Herbert struct rps_map *old_map, *map; 7220a9627f2STom Herbert cpumask_var_t mask; 7230a9627f2STom Herbert int err, cpu, i; 724da65ad1fSSasha Levin static DEFINE_MUTEX(rps_map_mutex); 7250a9627f2STom Herbert 7260a9627f2STom Herbert if (!capable(CAP_NET_ADMIN)) 7270a9627f2STom Herbert return -EPERM; 7280a9627f2STom Herbert 7290a9627f2STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 7300a9627f2STom Herbert return -ENOMEM; 7310a9627f2STom Herbert 7320a9627f2STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 7330a9627f2STom Herbert if (err) { 7340a9627f2STom Herbert free_cpumask_var(mask); 7350a9627f2STom Herbert return err; 7360a9627f2STom Herbert } 7370a9627f2STom Herbert 73895c96174SEric Dumazet map = kzalloc(max_t(unsigned int, 7390a9627f2STom Herbert RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), 7400a9627f2STom Herbert GFP_KERNEL); 7410a9627f2STom Herbert if (!map) { 7420a9627f2STom Herbert free_cpumask_var(mask); 7430a9627f2STom Herbert return -ENOMEM; 7440a9627f2STom Herbert } 7450a9627f2STom Herbert 7460a9627f2STom Herbert i = 0; 7470a9627f2STom Herbert for_each_cpu_and(cpu, mask, cpu_online_mask) 7480a9627f2STom Herbert map->cpus[i++] = cpu; 7490a9627f2STom Herbert 7506648c65eSstephen hemminger if (i) { 7510a9627f2STom Herbert map->len = i; 7526648c65eSstephen hemminger } else { 7530a9627f2STom Herbert kfree(map); 7540a9627f2STom Herbert map = NULL; 7550a9627f2STom Herbert } 7560a9627f2STom Herbert 757da65ad1fSSasha Levin mutex_lock(&rps_map_mutex); 7586e3f7fafSEric Dumazet old_map = rcu_dereference_protected(queue->rps_map, 759da65ad1fSSasha Levin mutex_is_locked(&rps_map_mutex)); 7600a9627f2STom Herbert rcu_assign_pointer(queue->rps_map, map); 7610a9627f2STom Herbert 762adc9300eSEric Dumazet if (map) 763c5905afbSIngo Molnar static_key_slow_inc(&rps_needed); 76410e4ea75STom Herbert if (old_map) 765c5905afbSIngo Molnar static_key_slow_dec(&rps_needed); 76610e4ea75STom Herbert 767da65ad1fSSasha Levin mutex_unlock(&rps_map_mutex); 76810e4ea75STom Herbert 76910e4ea75STom Herbert if (old_map) 77010e4ea75STom Herbert kfree_rcu(old_map, rcu); 77110e4ea75STom Herbert 7720a9627f2STom Herbert free_cpumask_var(mask); 7730a9627f2STom Herbert return len; 7740a9627f2STom Herbert } 7750a9627f2STom Herbert 776fec5e652STom Herbert static ssize_t show_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 777fec5e652STom Herbert char *buf) 778fec5e652STom Herbert { 779fec5e652STom Herbert struct rps_dev_flow_table *flow_table; 78060b778ceSEric Dumazet unsigned long val = 0; 781fec5e652STom Herbert 782fec5e652STom Herbert rcu_read_lock(); 783fec5e652STom Herbert flow_table = rcu_dereference(queue->rps_flow_table); 784fec5e652STom Herbert if (flow_table) 78560b778ceSEric Dumazet val = (unsigned long)flow_table->mask + 1; 786fec5e652STom Herbert rcu_read_unlock(); 787fec5e652STom Herbert 78860b778ceSEric Dumazet return sprintf(buf, "%lu\n", val); 789fec5e652STom Herbert } 790fec5e652STom Herbert 791fec5e652STom Herbert static void rps_dev_flow_table_release(struct rcu_head *rcu) 792fec5e652STom Herbert { 793fec5e652STom Herbert struct rps_dev_flow_table *table = container_of(rcu, 794fec5e652STom Herbert struct rps_dev_flow_table, rcu); 795243198d0SAl Viro vfree(table); 796fec5e652STom Herbert } 797fec5e652STom Herbert 798f5acb907SEric Dumazet static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 799fec5e652STom Herbert const char *buf, size_t len) 800fec5e652STom Herbert { 80160b778ceSEric Dumazet unsigned long mask, count; 802fec5e652STom Herbert struct rps_dev_flow_table *table, *old_table; 803fec5e652STom Herbert static DEFINE_SPINLOCK(rps_dev_flow_lock); 80460b778ceSEric Dumazet int rc; 805fec5e652STom Herbert 806fec5e652STom Herbert if (!capable(CAP_NET_ADMIN)) 807fec5e652STom Herbert return -EPERM; 808fec5e652STom Herbert 80960b778ceSEric Dumazet rc = kstrtoul(buf, 0, &count); 81060b778ceSEric Dumazet if (rc < 0) 81160b778ceSEric Dumazet return rc; 812fec5e652STom Herbert 813fec5e652STom Herbert if (count) { 81460b778ceSEric Dumazet mask = count - 1; 81560b778ceSEric Dumazet /* mask = roundup_pow_of_two(count) - 1; 81660b778ceSEric Dumazet * without overflows... 81760b778ceSEric Dumazet */ 81860b778ceSEric Dumazet while ((mask | (mask >> 1)) != mask) 81960b778ceSEric Dumazet mask |= (mask >> 1); 82060b778ceSEric Dumazet /* On 64 bit arches, must check mask fits in table->mask (u32), 8218e3bff96Sstephen hemminger * and on 32bit arches, must check 8228e3bff96Sstephen hemminger * RPS_DEV_FLOW_TABLE_SIZE(mask + 1) doesn't overflow. 82360b778ceSEric Dumazet */ 82460b778ceSEric Dumazet #if BITS_PER_LONG > 32 82560b778ceSEric Dumazet if (mask > (unsigned long)(u32)mask) 826a0a129f8SXi Wang return -EINVAL; 82760b778ceSEric Dumazet #else 82860b778ceSEric Dumazet if (mask > (ULONG_MAX - RPS_DEV_FLOW_TABLE_SIZE(1)) 829a0a129f8SXi Wang / sizeof(struct rps_dev_flow)) { 830fec5e652STom Herbert /* Enforce a limit to prevent overflow */ 831fec5e652STom Herbert return -EINVAL; 832fec5e652STom Herbert } 83360b778ceSEric Dumazet #endif 83460b778ceSEric Dumazet table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(mask + 1)); 835fec5e652STom Herbert if (!table) 836fec5e652STom Herbert return -ENOMEM; 837fec5e652STom Herbert 83860b778ceSEric Dumazet table->mask = mask; 83960b778ceSEric Dumazet for (count = 0; count <= mask; count++) 84060b778ceSEric Dumazet table->flows[count].cpu = RPS_NO_CPU; 8416648c65eSstephen hemminger } else { 842fec5e652STom Herbert table = NULL; 8436648c65eSstephen hemminger } 844fec5e652STom Herbert 845fec5e652STom Herbert spin_lock(&rps_dev_flow_lock); 8466e3f7fafSEric Dumazet old_table = rcu_dereference_protected(queue->rps_flow_table, 8476e3f7fafSEric Dumazet lockdep_is_held(&rps_dev_flow_lock)); 848fec5e652STom Herbert rcu_assign_pointer(queue->rps_flow_table, table); 849fec5e652STom Herbert spin_unlock(&rps_dev_flow_lock); 850fec5e652STom Herbert 851fec5e652STom Herbert if (old_table) 852fec5e652STom Herbert call_rcu(&old_table->rcu, rps_dev_flow_table_release); 853fec5e652STom Herbert 854fec5e652STom Herbert return len; 855fec5e652STom Herbert } 856fec5e652STom Herbert 857667e427bSstephen hemminger static struct rx_queue_attribute rps_cpus_attribute __ro_after_init 858d6444062SJoe Perches = __ATTR(rps_cpus, 0644, show_rps_map, store_rps_map); 8590a9627f2STom Herbert 860667e427bSstephen hemminger static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute __ro_after_init 861d6444062SJoe Perches = __ATTR(rps_flow_cnt, 0644, 862fec5e652STom Herbert show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt); 863a953be53SMichael Dalton #endif /* CONFIG_RPS */ 864fec5e652STom Herbert 865667e427bSstephen hemminger static struct attribute *rx_queue_default_attrs[] __ro_after_init = { 866a953be53SMichael Dalton #ifdef CONFIG_RPS 8670a9627f2STom Herbert &rps_cpus_attribute.attr, 868fec5e652STom Herbert &rps_dev_flow_table_cnt_attribute.attr, 869a953be53SMichael Dalton #endif 8700a9627f2STom Herbert NULL 8710a9627f2STom Herbert }; 8720a9627f2STom Herbert 8730a9627f2STom Herbert static void rx_queue_release(struct kobject *kobj) 8740a9627f2STom Herbert { 8750a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 876a953be53SMichael Dalton #ifdef CONFIG_RPS 8776e3f7fafSEric Dumazet struct rps_map *map; 8786e3f7fafSEric Dumazet struct rps_dev_flow_table *flow_table; 8790a9627f2STom Herbert 88033d480ceSEric Dumazet map = rcu_dereference_protected(queue->rps_map, 1); 8819ea19481SJohn Fastabend if (map) { 8829ea19481SJohn Fastabend RCU_INIT_POINTER(queue->rps_map, NULL); 883f6f80238SLai Jiangshan kfree_rcu(map, rcu); 8849ea19481SJohn Fastabend } 8856e3f7fafSEric Dumazet 88633d480ceSEric Dumazet flow_table = rcu_dereference_protected(queue->rps_flow_table, 1); 8879ea19481SJohn Fastabend if (flow_table) { 8889ea19481SJohn Fastabend RCU_INIT_POINTER(queue->rps_flow_table, NULL); 8896e3f7fafSEric Dumazet call_rcu(&flow_table->rcu, rps_dev_flow_table_release); 8909ea19481SJohn Fastabend } 891a953be53SMichael Dalton #endif 8920a9627f2STom Herbert 8939ea19481SJohn Fastabend memset(kobj, 0, sizeof(*kobj)); 894fe822240STom Herbert dev_put(queue->dev); 8950a9627f2STom Herbert } 8960a9627f2STom Herbert 89782ef3d5dSWeilong Chen static const void *rx_queue_namespace(struct kobject *kobj) 89882ef3d5dSWeilong Chen { 89982ef3d5dSWeilong Chen struct netdev_rx_queue *queue = to_rx_queue(kobj); 90082ef3d5dSWeilong Chen struct device *dev = &queue->dev->dev; 90182ef3d5dSWeilong Chen const void *ns = NULL; 90282ef3d5dSWeilong Chen 90382ef3d5dSWeilong Chen if (dev->class && dev->class->ns_type) 90482ef3d5dSWeilong Chen ns = dev->class->namespace(dev); 90582ef3d5dSWeilong Chen 90682ef3d5dSWeilong Chen return ns; 90782ef3d5dSWeilong Chen } 90882ef3d5dSWeilong Chen 909b0e37c0dSDmitry Torokhov static void rx_queue_get_ownership(struct kobject *kobj, 910b0e37c0dSDmitry Torokhov kuid_t *uid, kgid_t *gid) 911b0e37c0dSDmitry Torokhov { 912b0e37c0dSDmitry Torokhov const struct net *net = rx_queue_namespace(kobj); 913b0e37c0dSDmitry Torokhov 914b0e37c0dSDmitry Torokhov net_ns_get_ownership(net, uid, gid); 915b0e37c0dSDmitry Torokhov } 916b0e37c0dSDmitry Torokhov 917667e427bSstephen hemminger static struct kobj_type rx_queue_ktype __ro_after_init = { 9180a9627f2STom Herbert .sysfs_ops = &rx_queue_sysfs_ops, 9190a9627f2STom Herbert .release = rx_queue_release, 9200a9627f2STom Herbert .default_attrs = rx_queue_default_attrs, 921b0e37c0dSDmitry Torokhov .namespace = rx_queue_namespace, 922b0e37c0dSDmitry Torokhov .get_ownership = rx_queue_get_ownership, 9230a9627f2STom Herbert }; 9240a9627f2STom Herbert 9256b53dafeSWANG Cong static int rx_queue_add_kobject(struct net_device *dev, int index) 9260a9627f2STom Herbert { 9276b53dafeSWANG Cong struct netdev_rx_queue *queue = dev->_rx + index; 9280a9627f2STom Herbert struct kobject *kobj = &queue->kobj; 9290a9627f2STom Herbert int error = 0; 9300a9627f2STom Herbert 9316b53dafeSWANG Cong kobj->kset = dev->queues_kset; 9320a9627f2STom Herbert error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, 9330a9627f2STom Herbert "rx-%u", index); 934a953be53SMichael Dalton if (error) 935d0d66837Sstephen hemminger return error; 936a953be53SMichael Dalton 9376b53dafeSWANG Cong if (dev->sysfs_rx_queue_group) { 9386b53dafeSWANG Cong error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); 939d0d66837Sstephen hemminger if (error) { 940d0d66837Sstephen hemminger kobject_put(kobj); 941d0d66837Sstephen hemminger return error; 942d0d66837Sstephen hemminger } 9430a9627f2STom Herbert } 9440a9627f2STom Herbert 9450a9627f2STom Herbert kobject_uevent(kobj, KOBJ_ADD); 946fe822240STom Herbert dev_hold(queue->dev); 9470a9627f2STom Herbert 9480a9627f2STom Herbert return error; 9490a9627f2STom Herbert } 95080dd6eacSPaul Bolle #endif /* CONFIG_SYSFS */ 9510a9627f2STom Herbert 95262fe0b40SBen Hutchings int 9536b53dafeSWANG Cong net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) 9540a9627f2STom Herbert { 955a953be53SMichael Dalton #ifdef CONFIG_SYSFS 9560a9627f2STom Herbert int i; 9570a9627f2STom Herbert int error = 0; 9580a9627f2STom Herbert 959a953be53SMichael Dalton #ifndef CONFIG_RPS 9606b53dafeSWANG Cong if (!dev->sysfs_rx_queue_group) 961a953be53SMichael Dalton return 0; 962a953be53SMichael Dalton #endif 96362fe0b40SBen Hutchings for (i = old_num; i < new_num; i++) { 9646b53dafeSWANG Cong error = rx_queue_add_kobject(dev, i); 96562fe0b40SBen Hutchings if (error) { 96662fe0b40SBen Hutchings new_num = old_num; 9670a9627f2STom Herbert break; 9680a9627f2STom Herbert } 96962fe0b40SBen Hutchings } 9700a9627f2STom Herbert 971a953be53SMichael Dalton while (--i >= new_num) { 972002d8a1aSAndrey Vagin struct kobject *kobj = &dev->_rx[i].kobj; 973002d8a1aSAndrey Vagin 974273c28bcSKirill Tkhai if (!refcount_read(&dev_net(dev)->count)) 975002d8a1aSAndrey Vagin kobj->uevent_suppress = 1; 9766b53dafeSWANG Cong if (dev->sysfs_rx_queue_group) 977002d8a1aSAndrey Vagin sysfs_remove_group(kobj, dev->sysfs_rx_queue_group); 978002d8a1aSAndrey Vagin kobject_put(kobj); 979a953be53SMichael Dalton } 9800a9627f2STom Herbert 9810a9627f2STom Herbert return error; 982bf264145STom Herbert #else 983bf264145STom Herbert return 0; 984bf264145STom Herbert #endif 9850a9627f2STom Herbert } 9860a9627f2STom Herbert 987ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 9881d24eb48STom Herbert /* 9891d24eb48STom Herbert * netdev_queue sysfs structures and functions. 9901d24eb48STom Herbert */ 9911d24eb48STom Herbert struct netdev_queue_attribute { 9921d24eb48STom Herbert struct attribute attr; 993718ad681Sstephen hemminger ssize_t (*show)(struct netdev_queue *queue, char *buf); 9941d24eb48STom Herbert ssize_t (*store)(struct netdev_queue *queue, 995718ad681Sstephen hemminger const char *buf, size_t len); 9961d24eb48STom Herbert }; 9976648c65eSstephen hemminger #define to_netdev_queue_attr(_attr) \ 9986648c65eSstephen hemminger container_of(_attr, struct netdev_queue_attribute, attr) 9991d24eb48STom Herbert 10001d24eb48STom Herbert #define to_netdev_queue(obj) container_of(obj, struct netdev_queue, kobj) 10011d24eb48STom Herbert 10021d24eb48STom Herbert static ssize_t netdev_queue_attr_show(struct kobject *kobj, 10031d24eb48STom Herbert struct attribute *attr, char *buf) 100462fe0b40SBen Hutchings { 1005667e427bSstephen hemminger const struct netdev_queue_attribute *attribute 1006667e427bSstephen hemminger = to_netdev_queue_attr(attr); 10071d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 10081d24eb48STom Herbert 10091d24eb48STom Herbert if (!attribute->show) 10101d24eb48STom Herbert return -EIO; 10111d24eb48STom Herbert 1012718ad681Sstephen hemminger return attribute->show(queue, buf); 10131d24eb48STom Herbert } 10141d24eb48STom Herbert 10151d24eb48STom Herbert static ssize_t netdev_queue_attr_store(struct kobject *kobj, 10161d24eb48STom Herbert struct attribute *attr, 10171d24eb48STom Herbert const char *buf, size_t count) 10181d24eb48STom Herbert { 1019667e427bSstephen hemminger const struct netdev_queue_attribute *attribute 1020667e427bSstephen hemminger = to_netdev_queue_attr(attr); 10211d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 10221d24eb48STom Herbert 10231d24eb48STom Herbert if (!attribute->store) 10241d24eb48STom Herbert return -EIO; 10251d24eb48STom Herbert 1026718ad681Sstephen hemminger return attribute->store(queue, buf, count); 10271d24eb48STom Herbert } 10281d24eb48STom Herbert 10291d24eb48STom Herbert static const struct sysfs_ops netdev_queue_sysfs_ops = { 10301d24eb48STom Herbert .show = netdev_queue_attr_show, 10311d24eb48STom Herbert .store = netdev_queue_attr_store, 10321d24eb48STom Herbert }; 10331d24eb48STom Herbert 10342b9c7581Sstephen hemminger static ssize_t tx_timeout_show(struct netdev_queue *queue, char *buf) 1035ccf5ff69Sdavid decotigny { 1036ccf5ff69Sdavid decotigny unsigned long trans_timeout; 1037ccf5ff69Sdavid decotigny 1038ccf5ff69Sdavid decotigny spin_lock_irq(&queue->_xmit_lock); 1039ccf5ff69Sdavid decotigny trans_timeout = queue->trans_timeout; 1040ccf5ff69Sdavid decotigny spin_unlock_irq(&queue->_xmit_lock); 1041ccf5ff69Sdavid decotigny 1042ccf5ff69Sdavid decotigny return sprintf(buf, "%lu", trans_timeout); 1043ccf5ff69Sdavid decotigny } 1044ccf5ff69Sdavid decotigny 1045c4047f53SThadeu Lima de Souza Cascardo static unsigned int get_netdev_queue_index(struct netdev_queue *queue) 1046822b3b2eSJohn Fastabend { 1047822b3b2eSJohn Fastabend struct net_device *dev = queue->dev; 1048c4047f53SThadeu Lima de Souza Cascardo unsigned int i; 1049822b3b2eSJohn Fastabend 1050c4047f53SThadeu Lima de Souza Cascardo i = queue - dev->_tx; 1051822b3b2eSJohn Fastabend BUG_ON(i >= dev->num_tx_queues); 1052822b3b2eSJohn Fastabend 1053822b3b2eSJohn Fastabend return i; 1054822b3b2eSJohn Fastabend } 1055822b3b2eSJohn Fastabend 10562b9c7581Sstephen hemminger static ssize_t traffic_class_show(struct netdev_queue *queue, 10578d059b0fSAlexander Duyck char *buf) 10588d059b0fSAlexander Duyck { 10598d059b0fSAlexander Duyck struct net_device *dev = queue->dev; 1060d7be9775SAlexander Duyck int index; 1061d7be9775SAlexander Duyck int tc; 10628d059b0fSAlexander Duyck 1063d7be9775SAlexander Duyck if (!netif_is_multiqueue(dev)) 1064d7be9775SAlexander Duyck return -ENOENT; 1065d7be9775SAlexander Duyck 1066d7be9775SAlexander Duyck index = get_netdev_queue_index(queue); 1067ffcfe25bSAlexander Duyck 1068ffcfe25bSAlexander Duyck /* If queue belongs to subordinate dev use its TC mapping */ 1069ffcfe25bSAlexander Duyck dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev; 1070ffcfe25bSAlexander Duyck 1071d7be9775SAlexander Duyck tc = netdev_txq_to_tc(dev, index); 10728d059b0fSAlexander Duyck if (tc < 0) 10738d059b0fSAlexander Duyck return -EINVAL; 10748d059b0fSAlexander Duyck 1075ffcfe25bSAlexander Duyck /* We can report the traffic class one of two ways: 1076ffcfe25bSAlexander Duyck * Subordinate device traffic classes are reported with the traffic 1077ffcfe25bSAlexander Duyck * class first, and then the subordinate class so for example TC0 on 1078ffcfe25bSAlexander Duyck * subordinate device 2 will be reported as "0-2". If the queue 1079ffcfe25bSAlexander Duyck * belongs to the root device it will be reported with just the 1080ffcfe25bSAlexander Duyck * traffic class, so just "0" for TC 0 for example. 1081ffcfe25bSAlexander Duyck */ 1082ffcfe25bSAlexander Duyck return dev->num_tc < 0 ? sprintf(buf, "%u%d\n", tc, dev->num_tc) : 1083ffcfe25bSAlexander Duyck sprintf(buf, "%u\n", tc); 10848d059b0fSAlexander Duyck } 10858d059b0fSAlexander Duyck 10868d059b0fSAlexander Duyck #ifdef CONFIG_XPS 10872b9c7581Sstephen hemminger static ssize_t tx_maxrate_show(struct netdev_queue *queue, 1088822b3b2eSJohn Fastabend char *buf) 1089822b3b2eSJohn Fastabend { 1090822b3b2eSJohn Fastabend return sprintf(buf, "%lu\n", queue->tx_maxrate); 1091822b3b2eSJohn Fastabend } 1092822b3b2eSJohn Fastabend 10932b9c7581Sstephen hemminger static ssize_t tx_maxrate_store(struct netdev_queue *queue, 1094822b3b2eSJohn Fastabend const char *buf, size_t len) 1095822b3b2eSJohn Fastabend { 1096822b3b2eSJohn Fastabend struct net_device *dev = queue->dev; 1097822b3b2eSJohn Fastabend int err, index = get_netdev_queue_index(queue); 1098822b3b2eSJohn Fastabend u32 rate = 0; 1099822b3b2eSJohn Fastabend 11003033fcedSTyler Hicks if (!capable(CAP_NET_ADMIN)) 11013033fcedSTyler Hicks return -EPERM; 11023033fcedSTyler Hicks 1103822b3b2eSJohn Fastabend err = kstrtou32(buf, 10, &rate); 1104822b3b2eSJohn Fastabend if (err < 0) 1105822b3b2eSJohn Fastabend return err; 1106822b3b2eSJohn Fastabend 1107822b3b2eSJohn Fastabend if (!rtnl_trylock()) 1108822b3b2eSJohn Fastabend return restart_syscall(); 1109822b3b2eSJohn Fastabend 1110822b3b2eSJohn Fastabend err = -EOPNOTSUPP; 1111822b3b2eSJohn Fastabend if (dev->netdev_ops->ndo_set_tx_maxrate) 1112822b3b2eSJohn Fastabend err = dev->netdev_ops->ndo_set_tx_maxrate(dev, index, rate); 1113822b3b2eSJohn Fastabend 1114822b3b2eSJohn Fastabend rtnl_unlock(); 1115822b3b2eSJohn Fastabend if (!err) { 1116822b3b2eSJohn Fastabend queue->tx_maxrate = rate; 1117822b3b2eSJohn Fastabend return len; 1118822b3b2eSJohn Fastabend } 1119822b3b2eSJohn Fastabend return err; 1120822b3b2eSJohn Fastabend } 1121822b3b2eSJohn Fastabend 11222b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_tx_maxrate __ro_after_init 11232b9c7581Sstephen hemminger = __ATTR_RW(tx_maxrate); 1124822b3b2eSJohn Fastabend #endif 1125822b3b2eSJohn Fastabend 11262b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_trans_timeout __ro_after_init 11272b9c7581Sstephen hemminger = __ATTR_RO(tx_timeout); 1128ccf5ff69Sdavid decotigny 11292b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_traffic_class __ro_after_init 11302b9c7581Sstephen hemminger = __ATTR_RO(traffic_class); 11318d059b0fSAlexander Duyck 1132114cf580STom Herbert #ifdef CONFIG_BQL 1133114cf580STom Herbert /* 1134114cf580STom Herbert * Byte queue limits sysfs structures and functions. 1135114cf580STom Herbert */ 1136114cf580STom Herbert static ssize_t bql_show(char *buf, unsigned int value) 1137114cf580STom Herbert { 1138114cf580STom Herbert return sprintf(buf, "%u\n", value); 1139114cf580STom Herbert } 1140114cf580STom Herbert 1141114cf580STom Herbert static ssize_t bql_set(const char *buf, const size_t count, 1142114cf580STom Herbert unsigned int *pvalue) 1143114cf580STom Herbert { 1144114cf580STom Herbert unsigned int value; 1145114cf580STom Herbert int err; 1146114cf580STom Herbert 11476648c65eSstephen hemminger if (!strcmp(buf, "max") || !strcmp(buf, "max\n")) { 1148114cf580STom Herbert value = DQL_MAX_LIMIT; 11496648c65eSstephen hemminger } else { 1150114cf580STom Herbert err = kstrtouint(buf, 10, &value); 1151114cf580STom Herbert if (err < 0) 1152114cf580STom Herbert return err; 1153114cf580STom Herbert if (value > DQL_MAX_LIMIT) 1154114cf580STom Herbert return -EINVAL; 1155114cf580STom Herbert } 1156114cf580STom Herbert 1157114cf580STom Herbert *pvalue = value; 1158114cf580STom Herbert 1159114cf580STom Herbert return count; 1160114cf580STom Herbert } 1161114cf580STom Herbert 1162114cf580STom Herbert static ssize_t bql_show_hold_time(struct netdev_queue *queue, 1163114cf580STom Herbert char *buf) 1164114cf580STom Herbert { 1165114cf580STom Herbert struct dql *dql = &queue->dql; 1166114cf580STom Herbert 1167114cf580STom Herbert return sprintf(buf, "%u\n", jiffies_to_msecs(dql->slack_hold_time)); 1168114cf580STom Herbert } 1169114cf580STom Herbert 1170114cf580STom Herbert static ssize_t bql_set_hold_time(struct netdev_queue *queue, 1171114cf580STom Herbert const char *buf, size_t len) 1172114cf580STom Herbert { 1173114cf580STom Herbert struct dql *dql = &queue->dql; 117495c96174SEric Dumazet unsigned int value; 1175114cf580STom Herbert int err; 1176114cf580STom Herbert 1177114cf580STom Herbert err = kstrtouint(buf, 10, &value); 1178114cf580STom Herbert if (err < 0) 1179114cf580STom Herbert return err; 1180114cf580STom Herbert 1181114cf580STom Herbert dql->slack_hold_time = msecs_to_jiffies(value); 1182114cf580STom Herbert 1183114cf580STom Herbert return len; 1184114cf580STom Herbert } 1185114cf580STom Herbert 1186170c658aSstephen hemminger static struct netdev_queue_attribute bql_hold_time_attribute __ro_after_init 1187d6444062SJoe Perches = __ATTR(hold_time, 0644, 1188170c658aSstephen hemminger bql_show_hold_time, bql_set_hold_time); 1189114cf580STom Herbert 1190114cf580STom Herbert static ssize_t bql_show_inflight(struct netdev_queue *queue, 1191114cf580STom Herbert char *buf) 1192114cf580STom Herbert { 1193114cf580STom Herbert struct dql *dql = &queue->dql; 1194114cf580STom Herbert 1195114cf580STom Herbert return sprintf(buf, "%u\n", dql->num_queued - dql->num_completed); 1196114cf580STom Herbert } 1197114cf580STom Herbert 1198170c658aSstephen hemminger static struct netdev_queue_attribute bql_inflight_attribute __ro_after_init = 1199d6444062SJoe Perches __ATTR(inflight, 0444, bql_show_inflight, NULL); 1200114cf580STom Herbert 1201114cf580STom Herbert #define BQL_ATTR(NAME, FIELD) \ 1202114cf580STom Herbert static ssize_t bql_show_ ## NAME(struct netdev_queue *queue, \ 1203114cf580STom Herbert char *buf) \ 1204114cf580STom Herbert { \ 1205114cf580STom Herbert return bql_show(buf, queue->dql.FIELD); \ 1206114cf580STom Herbert } \ 1207114cf580STom Herbert \ 1208114cf580STom Herbert static ssize_t bql_set_ ## NAME(struct netdev_queue *queue, \ 1209114cf580STom Herbert const char *buf, size_t len) \ 1210114cf580STom Herbert { \ 1211114cf580STom Herbert return bql_set(buf, len, &queue->dql.FIELD); \ 1212114cf580STom Herbert } \ 1213114cf580STom Herbert \ 1214170c658aSstephen hemminger static struct netdev_queue_attribute bql_ ## NAME ## _attribute __ro_after_init \ 1215d6444062SJoe Perches = __ATTR(NAME, 0644, \ 1216170c658aSstephen hemminger bql_show_ ## NAME, bql_set_ ## NAME) 1217114cf580STom Herbert 1218170c658aSstephen hemminger BQL_ATTR(limit, limit); 1219170c658aSstephen hemminger BQL_ATTR(limit_max, max_limit); 1220170c658aSstephen hemminger BQL_ATTR(limit_min, min_limit); 1221114cf580STom Herbert 1222170c658aSstephen hemminger static struct attribute *dql_attrs[] __ro_after_init = { 1223114cf580STom Herbert &bql_limit_attribute.attr, 1224114cf580STom Herbert &bql_limit_max_attribute.attr, 1225114cf580STom Herbert &bql_limit_min_attribute.attr, 1226114cf580STom Herbert &bql_hold_time_attribute.attr, 1227114cf580STom Herbert &bql_inflight_attribute.attr, 1228114cf580STom Herbert NULL 1229114cf580STom Herbert }; 1230114cf580STom Herbert 123138ef00ccSArvind Yadav static const struct attribute_group dql_group = { 1232114cf580STom Herbert .name = "byte_queue_limits", 1233114cf580STom Herbert .attrs = dql_attrs, 1234114cf580STom Herbert }; 1235114cf580STom Herbert #endif /* CONFIG_BQL */ 1236114cf580STom Herbert 1237ccf5ff69Sdavid decotigny #ifdef CONFIG_XPS 12382b9c7581Sstephen hemminger static ssize_t xps_cpus_show(struct netdev_queue *queue, 1239718ad681Sstephen hemminger char *buf) 12401d24eb48STom Herbert { 12411d24eb48STom Herbert struct net_device *dev = queue->dev; 1242184c449fSAlexander Duyck int cpu, len, num_tc = 1, tc = 0; 12431d24eb48STom Herbert struct xps_dev_maps *dev_maps; 12441d24eb48STom Herbert cpumask_var_t mask; 12451d24eb48STom Herbert unsigned long index; 12461d24eb48STom Herbert 1247d7be9775SAlexander Duyck if (!netif_is_multiqueue(dev)) 1248d7be9775SAlexander Duyck return -ENOENT; 1249d7be9775SAlexander Duyck 12501d24eb48STom Herbert index = get_netdev_queue_index(queue); 12511d24eb48STom Herbert 1252184c449fSAlexander Duyck if (dev->num_tc) { 1253ffcfe25bSAlexander Duyck /* Do not allow XPS on subordinate device directly */ 1254184c449fSAlexander Duyck num_tc = dev->num_tc; 1255ffcfe25bSAlexander Duyck if (num_tc < 0) 1256ffcfe25bSAlexander Duyck return -EINVAL; 1257ffcfe25bSAlexander Duyck 1258ffcfe25bSAlexander Duyck /* If queue belongs to subordinate dev use its map */ 1259ffcfe25bSAlexander Duyck dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev; 1260ffcfe25bSAlexander Duyck 1261184c449fSAlexander Duyck tc = netdev_txq_to_tc(dev, index); 1262184c449fSAlexander Duyck if (tc < 0) 1263184c449fSAlexander Duyck return -EINVAL; 1264184c449fSAlexander Duyck } 1265184c449fSAlexander Duyck 1266664088f8SAlexander Duyck if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 1267664088f8SAlexander Duyck return -ENOMEM; 1268664088f8SAlexander Duyck 12691d24eb48STom Herbert rcu_read_lock(); 127080d19669SAmritha Nambiar dev_maps = rcu_dereference(dev->xps_cpus_map); 12711d24eb48STom Herbert if (dev_maps) { 1272184c449fSAlexander Duyck for_each_possible_cpu(cpu) { 1273184c449fSAlexander Duyck int i, tci = cpu * num_tc + tc; 1274184c449fSAlexander Duyck struct xps_map *map; 1275184c449fSAlexander Duyck 127680d19669SAmritha Nambiar map = rcu_dereference(dev_maps->attr_map[tci]); 1277184c449fSAlexander Duyck if (!map) 1278184c449fSAlexander Duyck continue; 1279184c449fSAlexander Duyck 1280184c449fSAlexander Duyck for (i = map->len; i--;) { 1281184c449fSAlexander Duyck if (map->queues[i] == index) { 1282184c449fSAlexander Duyck cpumask_set_cpu(cpu, mask); 12831d24eb48STom Herbert break; 12841d24eb48STom Herbert } 12851d24eb48STom Herbert } 12861d24eb48STom Herbert } 12871d24eb48STom Herbert } 12881d24eb48STom Herbert rcu_read_unlock(); 12891d24eb48STom Herbert 1290f0906827STejun Heo len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask)); 12911d24eb48STom Herbert free_cpumask_var(mask); 1292f0906827STejun Heo return len < PAGE_SIZE ? len : -EINVAL; 12931d24eb48STom Herbert } 12941d24eb48STom Herbert 12952b9c7581Sstephen hemminger static ssize_t xps_cpus_store(struct netdev_queue *queue, 12961d24eb48STom Herbert const char *buf, size_t len) 12971d24eb48STom Herbert { 12981d24eb48STom Herbert struct net_device *dev = queue->dev; 12991d24eb48STom Herbert unsigned long index; 1300537c00deSAlexander Duyck cpumask_var_t mask; 1301537c00deSAlexander Duyck int err; 13021d24eb48STom Herbert 1303d7be9775SAlexander Duyck if (!netif_is_multiqueue(dev)) 1304d7be9775SAlexander Duyck return -ENOENT; 1305d7be9775SAlexander Duyck 13061d24eb48STom Herbert if (!capable(CAP_NET_ADMIN)) 13071d24eb48STom Herbert return -EPERM; 13081d24eb48STom Herbert 13091d24eb48STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 13101d24eb48STom Herbert return -ENOMEM; 13111d24eb48STom Herbert 13121d24eb48STom Herbert index = get_netdev_queue_index(queue); 13131d24eb48STom Herbert 13141d24eb48STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 13151d24eb48STom Herbert if (err) { 13161d24eb48STom Herbert free_cpumask_var(mask); 13171d24eb48STom Herbert return err; 13181d24eb48STom Herbert } 13191d24eb48STom Herbert 1320537c00deSAlexander Duyck err = netif_set_xps_queue(dev, mask, index); 13211d24eb48STom Herbert 13221d24eb48STom Herbert free_cpumask_var(mask); 13231d24eb48STom Herbert 1324537c00deSAlexander Duyck return err ? : len; 13251d24eb48STom Herbert } 13261d24eb48STom Herbert 13272b9c7581Sstephen hemminger static struct netdev_queue_attribute xps_cpus_attribute __ro_after_init 13282b9c7581Sstephen hemminger = __ATTR_RW(xps_cpus); 13298af2c06fSAmritha Nambiar 13308af2c06fSAmritha Nambiar static ssize_t xps_rxqs_show(struct netdev_queue *queue, char *buf) 13318af2c06fSAmritha Nambiar { 13328af2c06fSAmritha Nambiar struct net_device *dev = queue->dev; 13338af2c06fSAmritha Nambiar struct xps_dev_maps *dev_maps; 13348af2c06fSAmritha Nambiar unsigned long *mask, index; 13358af2c06fSAmritha Nambiar int j, len, num_tc = 1, tc = 0; 13368af2c06fSAmritha Nambiar 13378af2c06fSAmritha Nambiar index = get_netdev_queue_index(queue); 13388af2c06fSAmritha Nambiar 13398af2c06fSAmritha Nambiar if (dev->num_tc) { 13408af2c06fSAmritha Nambiar num_tc = dev->num_tc; 13418af2c06fSAmritha Nambiar tc = netdev_txq_to_tc(dev, index); 13428af2c06fSAmritha Nambiar if (tc < 0) 13438af2c06fSAmritha Nambiar return -EINVAL; 13448af2c06fSAmritha Nambiar } 13458af2c06fSAmritha Nambiar mask = kcalloc(BITS_TO_LONGS(dev->num_rx_queues), sizeof(long), 13468af2c06fSAmritha Nambiar GFP_KERNEL); 13478af2c06fSAmritha Nambiar if (!mask) 13488af2c06fSAmritha Nambiar return -ENOMEM; 13498af2c06fSAmritha Nambiar 13508af2c06fSAmritha Nambiar rcu_read_lock(); 13518af2c06fSAmritha Nambiar dev_maps = rcu_dereference(dev->xps_rxqs_map); 13528af2c06fSAmritha Nambiar if (!dev_maps) 13538af2c06fSAmritha Nambiar goto out_no_maps; 13548af2c06fSAmritha Nambiar 13558af2c06fSAmritha Nambiar for (j = -1; j = netif_attrmask_next(j, NULL, dev->num_rx_queues), 13568af2c06fSAmritha Nambiar j < dev->num_rx_queues;) { 13578af2c06fSAmritha Nambiar int i, tci = j * num_tc + tc; 13588af2c06fSAmritha Nambiar struct xps_map *map; 13598af2c06fSAmritha Nambiar 13608af2c06fSAmritha Nambiar map = rcu_dereference(dev_maps->attr_map[tci]); 13618af2c06fSAmritha Nambiar if (!map) 13628af2c06fSAmritha Nambiar continue; 13638af2c06fSAmritha Nambiar 13648af2c06fSAmritha Nambiar for (i = map->len; i--;) { 13658af2c06fSAmritha Nambiar if (map->queues[i] == index) { 13668af2c06fSAmritha Nambiar set_bit(j, mask); 13678af2c06fSAmritha Nambiar break; 13688af2c06fSAmritha Nambiar } 13698af2c06fSAmritha Nambiar } 13708af2c06fSAmritha Nambiar } 13718af2c06fSAmritha Nambiar out_no_maps: 13728af2c06fSAmritha Nambiar rcu_read_unlock(); 13738af2c06fSAmritha Nambiar 13748af2c06fSAmritha Nambiar len = bitmap_print_to_pagebuf(false, buf, mask, dev->num_rx_queues); 13758af2c06fSAmritha Nambiar kfree(mask); 13768af2c06fSAmritha Nambiar 13778af2c06fSAmritha Nambiar return len < PAGE_SIZE ? len : -EINVAL; 13788af2c06fSAmritha Nambiar } 13798af2c06fSAmritha Nambiar 13808af2c06fSAmritha Nambiar static ssize_t xps_rxqs_store(struct netdev_queue *queue, const char *buf, 13818af2c06fSAmritha Nambiar size_t len) 13828af2c06fSAmritha Nambiar { 13838af2c06fSAmritha Nambiar struct net_device *dev = queue->dev; 13848af2c06fSAmritha Nambiar struct net *net = dev_net(dev); 13858af2c06fSAmritha Nambiar unsigned long *mask, index; 13868af2c06fSAmritha Nambiar int err; 13878af2c06fSAmritha Nambiar 13888af2c06fSAmritha Nambiar if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 13898af2c06fSAmritha Nambiar return -EPERM; 13908af2c06fSAmritha Nambiar 13918af2c06fSAmritha Nambiar mask = kcalloc(BITS_TO_LONGS(dev->num_rx_queues), sizeof(long), 13928af2c06fSAmritha Nambiar GFP_KERNEL); 13938af2c06fSAmritha Nambiar if (!mask) 13948af2c06fSAmritha Nambiar return -ENOMEM; 13958af2c06fSAmritha Nambiar 13968af2c06fSAmritha Nambiar index = get_netdev_queue_index(queue); 13978af2c06fSAmritha Nambiar 13988af2c06fSAmritha Nambiar err = bitmap_parse(buf, len, mask, dev->num_rx_queues); 13998af2c06fSAmritha Nambiar if (err) { 14008af2c06fSAmritha Nambiar kfree(mask); 14018af2c06fSAmritha Nambiar return err; 14028af2c06fSAmritha Nambiar } 14038af2c06fSAmritha Nambiar 14044d99f660SAndrei Vagin cpus_read_lock(); 14058af2c06fSAmritha Nambiar err = __netif_set_xps_queue(dev, mask, index, true); 14064d99f660SAndrei Vagin cpus_read_unlock(); 14074d99f660SAndrei Vagin 14088af2c06fSAmritha Nambiar kfree(mask); 14098af2c06fSAmritha Nambiar return err ? : len; 14108af2c06fSAmritha Nambiar } 14118af2c06fSAmritha Nambiar 14128af2c06fSAmritha Nambiar static struct netdev_queue_attribute xps_rxqs_attribute __ro_after_init 14138af2c06fSAmritha Nambiar = __ATTR_RW(xps_rxqs); 1414ccf5ff69Sdavid decotigny #endif /* CONFIG_XPS */ 14151d24eb48STom Herbert 14162b9c7581Sstephen hemminger static struct attribute *netdev_queue_default_attrs[] __ro_after_init = { 1417ccf5ff69Sdavid decotigny &queue_trans_timeout.attr, 14188d059b0fSAlexander Duyck &queue_traffic_class.attr, 1419ccf5ff69Sdavid decotigny #ifdef CONFIG_XPS 14201d24eb48STom Herbert &xps_cpus_attribute.attr, 14218af2c06fSAmritha Nambiar &xps_rxqs_attribute.attr, 1422822b3b2eSJohn Fastabend &queue_tx_maxrate.attr, 1423ccf5ff69Sdavid decotigny #endif 14241d24eb48STom Herbert NULL 14251d24eb48STom Herbert }; 14261d24eb48STom Herbert 14271d24eb48STom Herbert static void netdev_queue_release(struct kobject *kobj) 14281d24eb48STom Herbert { 14291d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 14301d24eb48STom Herbert 14311d24eb48STom Herbert memset(kobj, 0, sizeof(*kobj)); 14321d24eb48STom Herbert dev_put(queue->dev); 14331d24eb48STom Herbert } 14341d24eb48STom Herbert 143582ef3d5dSWeilong Chen static const void *netdev_queue_namespace(struct kobject *kobj) 143682ef3d5dSWeilong Chen { 143782ef3d5dSWeilong Chen struct netdev_queue *queue = to_netdev_queue(kobj); 143882ef3d5dSWeilong Chen struct device *dev = &queue->dev->dev; 143982ef3d5dSWeilong Chen const void *ns = NULL; 144082ef3d5dSWeilong Chen 144182ef3d5dSWeilong Chen if (dev->class && dev->class->ns_type) 144282ef3d5dSWeilong Chen ns = dev->class->namespace(dev); 144382ef3d5dSWeilong Chen 144482ef3d5dSWeilong Chen return ns; 144582ef3d5dSWeilong Chen } 144682ef3d5dSWeilong Chen 1447b0e37c0dSDmitry Torokhov static void netdev_queue_get_ownership(struct kobject *kobj, 1448b0e37c0dSDmitry Torokhov kuid_t *uid, kgid_t *gid) 1449b0e37c0dSDmitry Torokhov { 1450b0e37c0dSDmitry Torokhov const struct net *net = netdev_queue_namespace(kobj); 1451b0e37c0dSDmitry Torokhov 1452b0e37c0dSDmitry Torokhov net_ns_get_ownership(net, uid, gid); 1453b0e37c0dSDmitry Torokhov } 1454b0e37c0dSDmitry Torokhov 14552b9c7581Sstephen hemminger static struct kobj_type netdev_queue_ktype __ro_after_init = { 14561d24eb48STom Herbert .sysfs_ops = &netdev_queue_sysfs_ops, 14571d24eb48STom Herbert .release = netdev_queue_release, 14581d24eb48STom Herbert .default_attrs = netdev_queue_default_attrs, 145982ef3d5dSWeilong Chen .namespace = netdev_queue_namespace, 1460b0e37c0dSDmitry Torokhov .get_ownership = netdev_queue_get_ownership, 14611d24eb48STom Herbert }; 14621d24eb48STom Herbert 14636b53dafeSWANG Cong static int netdev_queue_add_kobject(struct net_device *dev, int index) 14641d24eb48STom Herbert { 14656b53dafeSWANG Cong struct netdev_queue *queue = dev->_tx + index; 14661d24eb48STom Herbert struct kobject *kobj = &queue->kobj; 14671d24eb48STom Herbert int error = 0; 14681d24eb48STom Herbert 14696b53dafeSWANG Cong kobj->kset = dev->queues_kset; 14701d24eb48STom Herbert error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, 14711d24eb48STom Herbert "tx-%u", index); 1472114cf580STom Herbert if (error) 1473d0d66837Sstephen hemminger return error; 1474114cf580STom Herbert 1475114cf580STom Herbert #ifdef CONFIG_BQL 1476114cf580STom Herbert error = sysfs_create_group(kobj, &dql_group); 1477d0d66837Sstephen hemminger if (error) { 1478d0d66837Sstephen hemminger kobject_put(kobj); 1479d0d66837Sstephen hemminger return error; 1480d0d66837Sstephen hemminger } 1481114cf580STom Herbert #endif 14821d24eb48STom Herbert 14831d24eb48STom Herbert kobject_uevent(kobj, KOBJ_ADD); 14841d24eb48STom Herbert dev_hold(queue->dev); 14851d24eb48STom Herbert 1486114cf580STom Herbert return 0; 14871d24eb48STom Herbert } 1488ccf5ff69Sdavid decotigny #endif /* CONFIG_SYSFS */ 14891d24eb48STom Herbert 14901d24eb48STom Herbert int 14916b53dafeSWANG Cong netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) 14921d24eb48STom Herbert { 1493ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 14941d24eb48STom Herbert int i; 14951d24eb48STom Herbert int error = 0; 14961d24eb48STom Herbert 14971d24eb48STom Herbert for (i = old_num; i < new_num; i++) { 14986b53dafeSWANG Cong error = netdev_queue_add_kobject(dev, i); 14991d24eb48STom Herbert if (error) { 15001d24eb48STom Herbert new_num = old_num; 15011d24eb48STom Herbert break; 15021d24eb48STom Herbert } 15031d24eb48STom Herbert } 15041d24eb48STom Herbert 1505114cf580STom Herbert while (--i >= new_num) { 15066b53dafeSWANG Cong struct netdev_queue *queue = dev->_tx + i; 1507114cf580STom Herbert 1508273c28bcSKirill Tkhai if (!refcount_read(&dev_net(dev)->count)) 1509002d8a1aSAndrey Vagin queue->kobj.uevent_suppress = 1; 1510114cf580STom Herbert #ifdef CONFIG_BQL 1511114cf580STom Herbert sysfs_remove_group(&queue->kobj, &dql_group); 1512114cf580STom Herbert #endif 1513114cf580STom Herbert kobject_put(&queue->kobj); 1514114cf580STom Herbert } 15151d24eb48STom Herbert 15161d24eb48STom Herbert return error; 1517bf264145STom Herbert #else 1518bf264145STom Herbert return 0; 1519ccf5ff69Sdavid decotigny #endif /* CONFIG_SYSFS */ 15201d24eb48STom Herbert } 15211d24eb48STom Herbert 15226b53dafeSWANG Cong static int register_queue_kobjects(struct net_device *dev) 15231d24eb48STom Herbert { 1524bf264145STom Herbert int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; 15251d24eb48STom Herbert 1526ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 15276b53dafeSWANG Cong dev->queues_kset = kset_create_and_add("queues", 15286b53dafeSWANG Cong NULL, &dev->dev.kobj); 15296b53dafeSWANG Cong if (!dev->queues_kset) 153062fe0b40SBen Hutchings return -ENOMEM; 15316b53dafeSWANG Cong real_rx = dev->real_num_rx_queues; 1532bf264145STom Herbert #endif 15336b53dafeSWANG Cong real_tx = dev->real_num_tx_queues; 1534bf264145STom Herbert 15356b53dafeSWANG Cong error = net_rx_queue_update_kobjects(dev, 0, real_rx); 15361d24eb48STom Herbert if (error) 15371d24eb48STom Herbert goto error; 1538bf264145STom Herbert rxq = real_rx; 15391d24eb48STom Herbert 15406b53dafeSWANG Cong error = netdev_queue_update_kobjects(dev, 0, real_tx); 15411d24eb48STom Herbert if (error) 15421d24eb48STom Herbert goto error; 1543bf264145STom Herbert txq = real_tx; 15441d24eb48STom Herbert 15451d24eb48STom Herbert return 0; 15461d24eb48STom Herbert 15471d24eb48STom Herbert error: 15486b53dafeSWANG Cong netdev_queue_update_kobjects(dev, txq, 0); 15496b53dafeSWANG Cong net_rx_queue_update_kobjects(dev, rxq, 0); 1550895a5e96SYueHaibing #ifdef CONFIG_SYSFS 1551895a5e96SYueHaibing kset_unregister(dev->queues_kset); 1552895a5e96SYueHaibing #endif 15531d24eb48STom Herbert return error; 155462fe0b40SBen Hutchings } 155562fe0b40SBen Hutchings 15566b53dafeSWANG Cong static void remove_queue_kobjects(struct net_device *dev) 15570a9627f2STom Herbert { 1558bf264145STom Herbert int real_rx = 0, real_tx = 0; 1559bf264145STom Herbert 1560a953be53SMichael Dalton #ifdef CONFIG_SYSFS 15616b53dafeSWANG Cong real_rx = dev->real_num_rx_queues; 1562bf264145STom Herbert #endif 15636b53dafeSWANG Cong real_tx = dev->real_num_tx_queues; 1564bf264145STom Herbert 15656b53dafeSWANG Cong net_rx_queue_update_kobjects(dev, real_rx, 0); 15666b53dafeSWANG Cong netdev_queue_update_kobjects(dev, real_tx, 0); 1567ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 15686b53dafeSWANG Cong kset_unregister(dev->queues_kset); 1569bf264145STom Herbert #endif 15700a9627f2STom Herbert } 1571608b4b95SEric W. Biederman 15727dc5dbc8SEric W. Biederman static bool net_current_may_mount(void) 15737dc5dbc8SEric W. Biederman { 15747dc5dbc8SEric W. Biederman struct net *net = current->nsproxy->net_ns; 15757dc5dbc8SEric W. Biederman 15767dc5dbc8SEric W. Biederman return ns_capable(net->user_ns, CAP_SYS_ADMIN); 15777dc5dbc8SEric W. Biederman } 15787dc5dbc8SEric W. Biederman 1579a685e089SAl Viro static void *net_grab_current_ns(void) 1580608b4b95SEric W. Biederman { 1581a685e089SAl Viro struct net *ns = current->nsproxy->net_ns; 1582a685e089SAl Viro #ifdef CONFIG_NET_NS 1583a685e089SAl Viro if (ns) 1584c122e14dSReshetova, Elena refcount_inc(&ns->passive); 1585a685e089SAl Viro #endif 1586a685e089SAl Viro return ns; 1587608b4b95SEric W. Biederman } 1588608b4b95SEric W. Biederman 1589608b4b95SEric W. Biederman static const void *net_initial_ns(void) 1590608b4b95SEric W. Biederman { 1591608b4b95SEric W. Biederman return &init_net; 1592608b4b95SEric W. Biederman } 1593608b4b95SEric W. Biederman 1594608b4b95SEric W. Biederman static const void *net_netlink_ns(struct sock *sk) 1595608b4b95SEric W. Biederman { 1596608b4b95SEric W. Biederman return sock_net(sk); 1597608b4b95SEric W. Biederman } 1598608b4b95SEric W. Biederman 1599737aec57Sstephen hemminger const struct kobj_ns_type_operations net_ns_type_operations = { 1600608b4b95SEric W. Biederman .type = KOBJ_NS_TYPE_NET, 16017dc5dbc8SEric W. Biederman .current_may_mount = net_current_may_mount, 1602a685e089SAl Viro .grab_current_ns = net_grab_current_ns, 1603608b4b95SEric W. Biederman .netlink_ns = net_netlink_ns, 1604608b4b95SEric W. Biederman .initial_ns = net_initial_ns, 1605a685e089SAl Viro .drop_ns = net_drop_ns, 1606608b4b95SEric W. Biederman }; 160704600794SJohannes Berg EXPORT_SYMBOL_GPL(net_ns_type_operations); 1608608b4b95SEric W. Biederman 16097eff2e7aSKay Sievers static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) 16101da177e4SLinus Torvalds { 161143cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 16127eff2e7aSKay Sievers int retval; 16131da177e4SLinus Torvalds 1614312c004dSKay Sievers /* pass interface to uevent. */ 16157eff2e7aSKay Sievers retval = add_uevent_var(env, "INTERFACE=%s", dev->name); 1616bf62456eSEric Rannaud if (retval) 1617bf62456eSEric Rannaud goto exit; 16181da177e4SLinus Torvalds 1619ca2f37dbSJean Tourrilhes /* pass ifindex to uevent. 1620ca2f37dbSJean Tourrilhes * ifindex is useful as it won't change (interface name may change) 16216648c65eSstephen hemminger * and is what RtNetlink uses natively. 16226648c65eSstephen hemminger */ 16237eff2e7aSKay Sievers retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); 1624ca2f37dbSJean Tourrilhes 1625bf62456eSEric Rannaud exit: 1626bf62456eSEric Rannaud return retval; 16271da177e4SLinus Torvalds } 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds /* 16301da177e4SLinus Torvalds * netdev_release -- destroy and free a dead device. 163143cb76d9SGreg Kroah-Hartman * Called when last reference to device kobject is gone. 16321da177e4SLinus Torvalds */ 163343cb76d9SGreg Kroah-Hartman static void netdev_release(struct device *d) 16341da177e4SLinus Torvalds { 163543cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 16361da177e4SLinus Torvalds 16371da177e4SLinus Torvalds BUG_ON(dev->reg_state != NETREG_RELEASED); 16381da177e4SLinus Torvalds 16396c557001SFlorian Westphal /* no need to wait for rcu grace period: 16406c557001SFlorian Westphal * device is dead and about to be freed. 16416c557001SFlorian Westphal */ 16426c557001SFlorian Westphal kfree(rcu_access_pointer(dev->ifalias)); 164374d332c1SEric Dumazet netdev_freemem(dev); 16441da177e4SLinus Torvalds } 16451da177e4SLinus Torvalds 1646608b4b95SEric W. Biederman static const void *net_namespace(struct device *d) 1647608b4b95SEric W. Biederman { 16485c29482dSGeliang Tang struct net_device *dev = to_net_dev(d); 16495c29482dSGeliang Tang 1650608b4b95SEric W. Biederman return dev_net(dev); 1651608b4b95SEric W. Biederman } 1652608b4b95SEric W. Biederman 1653b0e37c0dSDmitry Torokhov static void net_get_ownership(struct device *d, kuid_t *uid, kgid_t *gid) 1654b0e37c0dSDmitry Torokhov { 1655b0e37c0dSDmitry Torokhov struct net_device *dev = to_net_dev(d); 1656b0e37c0dSDmitry Torokhov const struct net *net = dev_net(dev); 1657b0e37c0dSDmitry Torokhov 1658b0e37c0dSDmitry Torokhov net_ns_get_ownership(net, uid, gid); 1659b0e37c0dSDmitry Torokhov } 1660b0e37c0dSDmitry Torokhov 1661e6d473e6Sstephen hemminger static struct class net_class __ro_after_init = { 16621da177e4SLinus Torvalds .name = "net", 166343cb76d9SGreg Kroah-Hartman .dev_release = netdev_release, 16646be8aeefSGreg Kroah-Hartman .dev_groups = net_class_groups, 166543cb76d9SGreg Kroah-Hartman .dev_uevent = netdev_uevent, 1666608b4b95SEric W. Biederman .ns_type = &net_ns_type_operations, 1667608b4b95SEric W. Biederman .namespace = net_namespace, 1668b0e37c0dSDmitry Torokhov .get_ownership = net_get_ownership, 16691da177e4SLinus Torvalds }; 16701da177e4SLinus Torvalds 1671aa836df9SFlorian Fainelli #ifdef CONFIG_OF_NET 1672aa836df9SFlorian Fainelli static int of_dev_node_match(struct device *dev, const void *data) 1673aa836df9SFlorian Fainelli { 1674aa836df9SFlorian Fainelli int ret = 0; 1675aa836df9SFlorian Fainelli 1676aa836df9SFlorian Fainelli if (dev->parent) 1677aa836df9SFlorian Fainelli ret = dev->parent->of_node == data; 1678aa836df9SFlorian Fainelli 1679aa836df9SFlorian Fainelli return ret == 0 ? dev->of_node == data : ret; 1680aa836df9SFlorian Fainelli } 1681aa836df9SFlorian Fainelli 16829861f720SRussell King /* 16839861f720SRussell King * of_find_net_device_by_node - lookup the net device for the device node 16849861f720SRussell King * @np: OF device node 16859861f720SRussell King * 16869861f720SRussell King * Looks up the net_device structure corresponding with the device node. 16879861f720SRussell King * If successful, returns a pointer to the net_device with the embedded 16889861f720SRussell King * struct device refcount incremented by one, or NULL on failure. The 16899861f720SRussell King * refcount must be dropped when done with the net_device. 16909861f720SRussell King */ 1691aa836df9SFlorian Fainelli struct net_device *of_find_net_device_by_node(struct device_node *np) 1692aa836df9SFlorian Fainelli { 1693aa836df9SFlorian Fainelli struct device *dev; 1694aa836df9SFlorian Fainelli 1695aa836df9SFlorian Fainelli dev = class_find_device(&net_class, NULL, np, of_dev_node_match); 1696aa836df9SFlorian Fainelli if (!dev) 1697aa836df9SFlorian Fainelli return NULL; 1698aa836df9SFlorian Fainelli 1699aa836df9SFlorian Fainelli return to_net_dev(dev); 1700aa836df9SFlorian Fainelli } 1701aa836df9SFlorian Fainelli EXPORT_SYMBOL(of_find_net_device_by_node); 1702aa836df9SFlorian Fainelli #endif 1703aa836df9SFlorian Fainelli 17049093bbb2SStephen Hemminger /* Delete sysfs entries but hold kobject reference until after all 17059093bbb2SStephen Hemminger * netdev references are gone. 17069093bbb2SStephen Hemminger */ 17076b53dafeSWANG Cong void netdev_unregister_kobject(struct net_device *ndev) 17081da177e4SLinus Torvalds { 17096648c65eSstephen hemminger struct device *dev = &ndev->dev; 17109093bbb2SStephen Hemminger 1711273c28bcSKirill Tkhai if (!refcount_read(&dev_net(ndev)->count)) 1712002d8a1aSAndrey Vagin dev_set_uevent_suppress(dev, 1); 1713002d8a1aSAndrey Vagin 17149093bbb2SStephen Hemminger kobject_get(&dev->kobj); 17153891845eSEric W. Biederman 17166b53dafeSWANG Cong remove_queue_kobjects(ndev); 17170a9627f2STom Herbert 17189802c8e2SMing Lei pm_runtime_set_memalloc_noio(dev, false); 17199802c8e2SMing Lei 17209093bbb2SStephen Hemminger device_del(dev); 17211da177e4SLinus Torvalds } 17221da177e4SLinus Torvalds 17231da177e4SLinus Torvalds /* Create sysfs entries for network device. */ 17246b53dafeSWANG Cong int netdev_register_kobject(struct net_device *ndev) 17251da177e4SLinus Torvalds { 17266648c65eSstephen hemminger struct device *dev = &ndev->dev; 17276b53dafeSWANG Cong const struct attribute_group **groups = ndev->sysfs_groups; 17280a9627f2STom Herbert int error = 0; 17291da177e4SLinus Torvalds 1730a1b3f594SEric W. Biederman device_initialize(dev); 173143cb76d9SGreg Kroah-Hartman dev->class = &net_class; 17326b53dafeSWANG Cong dev->platform_data = ndev; 173343cb76d9SGreg Kroah-Hartman dev->groups = groups; 17341da177e4SLinus Torvalds 17356b53dafeSWANG Cong dev_set_name(dev, "%s", ndev->name); 17361da177e4SLinus Torvalds 17378b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 17380c509a6cSEric W. Biederman /* Allow for a device specific group */ 17390c509a6cSEric W. Biederman if (*groups) 17400c509a6cSEric W. Biederman groups++; 17411da177e4SLinus Torvalds 17420c509a6cSEric W. Biederman *groups++ = &netstat_group; 174338c1a01cSJohannes Berg 174438c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) 17456b53dafeSWANG Cong if (ndev->ieee80211_ptr) 174638c1a01cSJohannes Berg *groups++ = &wireless_group; 174738c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) 17486b53dafeSWANG Cong else if (ndev->wireless_handlers) 174938c1a01cSJohannes Berg *groups++ = &wireless_group; 175038c1a01cSJohannes Berg #endif 175138c1a01cSJohannes Berg #endif 17528b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 17531da177e4SLinus Torvalds 17540a9627f2STom Herbert error = device_add(dev); 17550a9627f2STom Herbert if (error) 17560a9627f2STom Herbert return error; 17570a9627f2STom Herbert 17586b53dafeSWANG Cong error = register_queue_kobjects(ndev); 17590a9627f2STom Herbert if (error) { 17600a9627f2STom Herbert device_del(dev); 17610a9627f2STom Herbert return error; 17620a9627f2STom Herbert } 17630a9627f2STom Herbert 17649802c8e2SMing Lei pm_runtime_set_memalloc_noio(dev, true); 17659802c8e2SMing Lei 17660a9627f2STom Herbert return error; 17671da177e4SLinus Torvalds } 17681da177e4SLinus Torvalds 1769b793dc5cSstephen hemminger int netdev_class_create_file_ns(const struct class_attribute *class_attr, 177058292cbeSTejun Heo const void *ns) 1771b8a9787eSJay Vosburgh { 177258292cbeSTejun Heo return class_create_file_ns(&net_class, class_attr, ns); 1773b8a9787eSJay Vosburgh } 177458292cbeSTejun Heo EXPORT_SYMBOL(netdev_class_create_file_ns); 1775b8a9787eSJay Vosburgh 1776b793dc5cSstephen hemminger void netdev_class_remove_file_ns(const struct class_attribute *class_attr, 177758292cbeSTejun Heo const void *ns) 1778b8a9787eSJay Vosburgh { 177958292cbeSTejun Heo class_remove_file_ns(&net_class, class_attr, ns); 1780b8a9787eSJay Vosburgh } 178158292cbeSTejun Heo EXPORT_SYMBOL(netdev_class_remove_file_ns); 1782b8a9787eSJay Vosburgh 1783a48d4bb0SDaniel Borkmann int __init netdev_kobject_init(void) 17841da177e4SLinus Torvalds { 1785608b4b95SEric W. Biederman kobj_ns_type_register(&net_ns_type_operations); 17861da177e4SLinus Torvalds return class_register(&net_class); 17871da177e4SLinus Torvalds } 1788