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> 291da177e4SLinus Torvalds 30342709efSPavel Emelyanov #include "net-sysfs.h" 31342709efSPavel Emelyanov 328b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 331da177e4SLinus Torvalds static const char fmt_hex[] = "%#x\n"; 341da177e4SLinus Torvalds static const char fmt_dec[] = "%d\n"; 351da177e4SLinus Torvalds static const char fmt_ulong[] = "%lu\n"; 36be1f3c2cSBen Hutchings static const char fmt_u64[] = "%llu\n"; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds static inline int dev_isalive(const struct net_device *dev) 391da177e4SLinus Torvalds { 40fe9925b5SStephen Hemminger return dev->reg_state <= NETREG_REGISTERED; 411da177e4SLinus Torvalds } 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds /* use same locking rules as GIF* ioctl's */ 4443cb76d9SGreg Kroah-Hartman static ssize_t netdev_show(const struct device *dev, 4543cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 461da177e4SLinus Torvalds ssize_t (*format)(const struct net_device *, char *)) 471da177e4SLinus Torvalds { 486b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 491da177e4SLinus Torvalds ssize_t ret = -EINVAL; 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds read_lock(&dev_base_lock); 526b53dafeSWANG Cong if (dev_isalive(ndev)) 536b53dafeSWANG Cong ret = (*format)(ndev, buf); 541da177e4SLinus Torvalds read_unlock(&dev_base_lock); 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds return ret; 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds /* generate a show function for simple field */ 601da177e4SLinus Torvalds #define NETDEVICE_SHOW(field, format_string) \ 616b53dafeSWANG Cong static ssize_t format_##field(const struct net_device *dev, char *buf) \ 621da177e4SLinus Torvalds { \ 636b53dafeSWANG Cong return sprintf(buf, format_string, dev->field); \ 641da177e4SLinus Torvalds } \ 656be8aeefSGreg Kroah-Hartman static ssize_t field##_show(struct device *dev, \ 6643cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 671da177e4SLinus Torvalds { \ 6843cb76d9SGreg Kroah-Hartman return netdev_show(dev, attr, buf, format_##field); \ 696be8aeefSGreg Kroah-Hartman } \ 701da177e4SLinus Torvalds 716be8aeefSGreg Kroah-Hartman #define NETDEVICE_SHOW_RO(field, format_string) \ 726be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(field, format_string); \ 736be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(field) 746be8aeefSGreg Kroah-Hartman 756be8aeefSGreg Kroah-Hartman #define NETDEVICE_SHOW_RW(field, format_string) \ 766be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(field, format_string); \ 776be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(field) 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /* use same locking and permission rules as SIF* ioctl's */ 8043cb76d9SGreg Kroah-Hartman static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, 811da177e4SLinus Torvalds const char *buf, size_t len, 821da177e4SLinus Torvalds int (*set)(struct net_device *, unsigned long)) 831da177e4SLinus Torvalds { 845e1fccc0SEric W. Biederman struct net_device *netdev = to_net_dev(dev); 855e1fccc0SEric W. Biederman struct net *net = dev_net(netdev); 861da177e4SLinus Torvalds unsigned long new; 871da177e4SLinus Torvalds int ret = -EINVAL; 881da177e4SLinus Torvalds 895e1fccc0SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 901da177e4SLinus Torvalds return -EPERM; 911da177e4SLinus Torvalds 92e1e420c7SShuah Khan ret = kstrtoul(buf, 0, &new); 93e1e420c7SShuah Khan if (ret) 941da177e4SLinus Torvalds goto err; 951da177e4SLinus Torvalds 965a5990d3SStephen Hemminger if (!rtnl_trylock()) 97336ca57cSEric W. Biederman return restart_syscall(); 985a5990d3SStephen Hemminger 995e1fccc0SEric W. Biederman if (dev_isalive(netdev)) { 1006648c65eSstephen hemminger ret = (*set)(netdev, new); 1016648c65eSstephen hemminger if (ret == 0) 1021da177e4SLinus Torvalds ret = len; 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds rtnl_unlock(); 1051da177e4SLinus Torvalds err: 1061da177e4SLinus Torvalds return ret; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 1096be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(dev_id, fmt_hex); 1103f85944fSAmir Vadai NETDEVICE_SHOW_RO(dev_port, fmt_dec); 1116be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(addr_assign_type, fmt_dec); 1126be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(addr_len, fmt_dec); 1136be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(ifindex, fmt_dec); 1146be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(type, fmt_dec); 1156be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(link_mode, fmt_dec); 1161da177e4SLinus Torvalds 117a54acb3aSNicolas Dichtel static ssize_t iflink_show(struct device *dev, struct device_attribute *attr, 118a54acb3aSNicolas Dichtel char *buf) 119a54acb3aSNicolas Dichtel { 120a54acb3aSNicolas Dichtel struct net_device *ndev = to_net_dev(dev); 121a54acb3aSNicolas Dichtel 122a54acb3aSNicolas Dichtel return sprintf(buf, fmt_dec, dev_get_iflink(ndev)); 123a54acb3aSNicolas Dichtel } 124a54acb3aSNicolas Dichtel static DEVICE_ATTR_RO(iflink); 125a54acb3aSNicolas Dichtel 1266b53dafeSWANG Cong static ssize_t format_name_assign_type(const struct net_device *dev, char *buf) 127685343fcSTom Gundersen { 1286b53dafeSWANG Cong return sprintf(buf, fmt_dec, dev->name_assign_type); 129685343fcSTom Gundersen } 130685343fcSTom Gundersen 131685343fcSTom Gundersen static ssize_t name_assign_type_show(struct device *dev, 132685343fcSTom Gundersen struct device_attribute *attr, 133685343fcSTom Gundersen char *buf) 134685343fcSTom Gundersen { 1356b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 136685343fcSTom Gundersen ssize_t ret = -EINVAL; 137685343fcSTom Gundersen 1386b53dafeSWANG Cong if (ndev->name_assign_type != NET_NAME_UNKNOWN) 139685343fcSTom Gundersen ret = netdev_show(dev, attr, buf, format_name_assign_type); 140685343fcSTom Gundersen 141685343fcSTom Gundersen return ret; 142685343fcSTom Gundersen } 143685343fcSTom Gundersen static DEVICE_ATTR_RO(name_assign_type); 144685343fcSTom Gundersen 1451da177e4SLinus Torvalds /* use same locking rules as GIFHWADDR ioctl's */ 1466be8aeefSGreg Kroah-Hartman static ssize_t address_show(struct device *dev, struct device_attribute *attr, 14743cb76d9SGreg Kroah-Hartman char *buf) 1481da177e4SLinus Torvalds { 1496b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 1501da177e4SLinus Torvalds ssize_t ret = -EINVAL; 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds read_lock(&dev_base_lock); 1536b53dafeSWANG Cong if (dev_isalive(ndev)) 1546b53dafeSWANG Cong ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len); 1551da177e4SLinus Torvalds read_unlock(&dev_base_lock); 1561da177e4SLinus Torvalds return ret; 1571da177e4SLinus Torvalds } 1586be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(address); 1591da177e4SLinus Torvalds 1606be8aeefSGreg Kroah-Hartman static ssize_t broadcast_show(struct device *dev, 16143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1621da177e4SLinus Torvalds { 1636b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 1646648c65eSstephen hemminger 1656b53dafeSWANG Cong if (dev_isalive(ndev)) 1666b53dafeSWANG Cong return sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len); 1671da177e4SLinus Torvalds return -EINVAL; 1681da177e4SLinus Torvalds } 1696be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(broadcast); 1701da177e4SLinus Torvalds 1716b53dafeSWANG Cong static int change_carrier(struct net_device *dev, unsigned long new_carrier) 172fdae0fdeSJiri Pirko { 1736b53dafeSWANG Cong if (!netif_running(dev)) 174fdae0fdeSJiri Pirko return -EINVAL; 1756b53dafeSWANG Cong return dev_change_carrier(dev, (bool)new_carrier); 176fdae0fdeSJiri Pirko } 177fdae0fdeSJiri Pirko 1786be8aeefSGreg Kroah-Hartman static ssize_t carrier_store(struct device *dev, struct device_attribute *attr, 179fdae0fdeSJiri Pirko const char *buf, size_t len) 180fdae0fdeSJiri Pirko { 181fdae0fdeSJiri Pirko return netdev_store(dev, attr, buf, len, change_carrier); 182fdae0fdeSJiri Pirko } 183fdae0fdeSJiri Pirko 1846be8aeefSGreg Kroah-Hartman static ssize_t carrier_show(struct device *dev, 18543cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1861da177e4SLinus Torvalds { 1871da177e4SLinus Torvalds struct net_device *netdev = to_net_dev(dev); 1886648c65eSstephen hemminger 1896648c65eSstephen hemminger if (netif_running(netdev)) 1901da177e4SLinus Torvalds return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); 1916648c65eSstephen hemminger 1921da177e4SLinus Torvalds return -EINVAL; 1931da177e4SLinus Torvalds } 1946be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(carrier); 1951da177e4SLinus Torvalds 1966be8aeefSGreg Kroah-Hartman static ssize_t speed_show(struct device *dev, 197d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 198d519e17eSAndy Gospodarek { 199d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 200d519e17eSAndy Gospodarek int ret = -EINVAL; 201d519e17eSAndy Gospodarek 202d519e17eSAndy Gospodarek if (!rtnl_trylock()) 203d519e17eSAndy Gospodarek return restart_syscall(); 204d519e17eSAndy Gospodarek 2058ae6dacaSDavid Decotigny if (netif_running(netdev)) { 2067cad1bacSDavid Decotigny struct ethtool_link_ksettings cmd; 2077cad1bacSDavid Decotigny 2087cad1bacSDavid Decotigny if (!__ethtool_get_link_ksettings(netdev, &cmd)) 2097cad1bacSDavid Decotigny ret = sprintf(buf, fmt_dec, cmd.base.speed); 210d519e17eSAndy Gospodarek } 211d519e17eSAndy Gospodarek rtnl_unlock(); 212d519e17eSAndy Gospodarek return ret; 213d519e17eSAndy Gospodarek } 2146be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(speed); 215d519e17eSAndy Gospodarek 2166be8aeefSGreg Kroah-Hartman static ssize_t duplex_show(struct device *dev, 217d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 218d519e17eSAndy Gospodarek { 219d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 220d519e17eSAndy Gospodarek int ret = -EINVAL; 221d519e17eSAndy Gospodarek 222d519e17eSAndy Gospodarek if (!rtnl_trylock()) 223d519e17eSAndy Gospodarek return restart_syscall(); 224d519e17eSAndy Gospodarek 2258ae6dacaSDavid Decotigny if (netif_running(netdev)) { 2267cad1bacSDavid Decotigny struct ethtool_link_ksettings cmd; 2277cad1bacSDavid Decotigny 2287cad1bacSDavid Decotigny if (!__ethtool_get_link_ksettings(netdev, &cmd)) { 229c6c13965SNikolay Aleksandrov const char *duplex; 2307cad1bacSDavid Decotigny 2317cad1bacSDavid Decotigny switch (cmd.base.duplex) { 232c6c13965SNikolay Aleksandrov case DUPLEX_HALF: 233c6c13965SNikolay Aleksandrov duplex = "half"; 234c6c13965SNikolay Aleksandrov break; 235c6c13965SNikolay Aleksandrov case DUPLEX_FULL: 236c6c13965SNikolay Aleksandrov duplex = "full"; 237c6c13965SNikolay Aleksandrov break; 238c6c13965SNikolay Aleksandrov default: 239c6c13965SNikolay Aleksandrov duplex = "unknown"; 240c6c13965SNikolay Aleksandrov break; 241c6c13965SNikolay Aleksandrov } 242c6c13965SNikolay Aleksandrov ret = sprintf(buf, "%s\n", duplex); 243c6c13965SNikolay Aleksandrov } 244d519e17eSAndy Gospodarek } 245d519e17eSAndy Gospodarek rtnl_unlock(); 246d519e17eSAndy Gospodarek return ret; 247d519e17eSAndy Gospodarek } 2486be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(duplex); 249d519e17eSAndy Gospodarek 2506be8aeefSGreg Kroah-Hartman static ssize_t dormant_show(struct device *dev, 25143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 252b00055aaSStefan Rompf { 253b00055aaSStefan Rompf struct net_device *netdev = to_net_dev(dev); 254b00055aaSStefan Rompf 255b00055aaSStefan Rompf if (netif_running(netdev)) 256b00055aaSStefan Rompf return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); 257b00055aaSStefan Rompf 258b00055aaSStefan Rompf return -EINVAL; 259b00055aaSStefan Rompf } 2606be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(dormant); 261b00055aaSStefan Rompf 26236cbd3dcSJan Engelhardt static const char *const operstates[] = { 263b00055aaSStefan Rompf "unknown", 264b00055aaSStefan Rompf "notpresent", /* currently unused */ 265b00055aaSStefan Rompf "down", 266b00055aaSStefan Rompf "lowerlayerdown", 267b00055aaSStefan Rompf "testing", /* currently unused */ 268b00055aaSStefan Rompf "dormant", 269b00055aaSStefan Rompf "up" 270b00055aaSStefan Rompf }; 271b00055aaSStefan Rompf 2726be8aeefSGreg Kroah-Hartman static ssize_t operstate_show(struct device *dev, 27343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 274b00055aaSStefan Rompf { 275b00055aaSStefan Rompf const struct net_device *netdev = to_net_dev(dev); 276b00055aaSStefan Rompf unsigned char operstate; 277b00055aaSStefan Rompf 278b00055aaSStefan Rompf read_lock(&dev_base_lock); 279b00055aaSStefan Rompf operstate = netdev->operstate; 280b00055aaSStefan Rompf if (!netif_running(netdev)) 281b00055aaSStefan Rompf operstate = IF_OPER_DOWN; 282b00055aaSStefan Rompf read_unlock(&dev_base_lock); 283b00055aaSStefan Rompf 284e3a5cd9eSAdrian Bunk if (operstate >= ARRAY_SIZE(operstates)) 285b00055aaSStefan Rompf return -EINVAL; /* should not happen */ 286b00055aaSStefan Rompf 287b00055aaSStefan Rompf return sprintf(buf, "%s\n", operstates[operstate]); 288b00055aaSStefan Rompf } 2896be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(operstate); 290b00055aaSStefan Rompf 2912d3b479dSdavid decotigny static ssize_t carrier_changes_show(struct device *dev, 2922d3b479dSdavid decotigny struct device_attribute *attr, 2932d3b479dSdavid decotigny char *buf) 2942d3b479dSdavid decotigny { 2952d3b479dSdavid decotigny struct net_device *netdev = to_net_dev(dev); 2966648c65eSstephen hemminger 2972d3b479dSdavid decotigny return sprintf(buf, fmt_dec, 2982d3b479dSdavid decotigny atomic_read(&netdev->carrier_changes)); 2992d3b479dSdavid decotigny } 3002d3b479dSdavid decotigny static DEVICE_ATTR_RO(carrier_changes); 3012d3b479dSdavid decotigny 3021da177e4SLinus Torvalds /* read-write attributes */ 3031da177e4SLinus Torvalds 3046b53dafeSWANG Cong static int change_mtu(struct net_device *dev, unsigned long new_mtu) 3051da177e4SLinus Torvalds { 3066b53dafeSWANG Cong return dev_set_mtu(dev, (int)new_mtu); 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds 3096be8aeefSGreg Kroah-Hartman static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, 31043cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3111da177e4SLinus Torvalds { 31243cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_mtu); 3131da177e4SLinus Torvalds } 3146be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(mtu, fmt_dec); 3151da177e4SLinus Torvalds 3166b53dafeSWANG Cong static int change_flags(struct net_device *dev, unsigned long new_flags) 3171da177e4SLinus Torvalds { 3186b53dafeSWANG Cong return dev_change_flags(dev, (unsigned int)new_flags); 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3216be8aeefSGreg Kroah-Hartman static ssize_t flags_store(struct device *dev, struct device_attribute *attr, 32243cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3231da177e4SLinus Torvalds { 32443cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_flags); 3251da177e4SLinus Torvalds } 3266be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(flags, fmt_hex); 3271da177e4SLinus Torvalds 3286b53dafeSWANG Cong static int change_tx_queue_len(struct net_device *dev, unsigned long new_len) 3291da177e4SLinus Torvalds { 3300cd29503SAlexey Dobriyan unsigned int orig_len = dev->tx_queue_len; 3310cd29503SAlexey Dobriyan int res; 3320cd29503SAlexey Dobriyan 3330cd29503SAlexey Dobriyan if (new_len != (unsigned int)new_len) 3340cd29503SAlexey Dobriyan return -ERANGE; 33508294a26SJason Wang 33608294a26SJason Wang if (new_len != orig_len) { 3376b53dafeSWANG Cong dev->tx_queue_len = new_len; 33808294a26SJason Wang res = call_netdevice_notifiers(NETDEV_CHANGE_TX_QUEUE_LEN, dev); 33908294a26SJason Wang res = notifier_to_errno(res); 34008294a26SJason Wang if (res) { 34108294a26SJason Wang netdev_err(dev, 34208294a26SJason Wang "refused to change device tx_queue_len\n"); 34308294a26SJason Wang dev->tx_queue_len = orig_len; 34408294a26SJason Wang return -EFAULT; 34508294a26SJason Wang } 34608294a26SJason Wang } 34708294a26SJason Wang 3481da177e4SLinus Torvalds return 0; 3491da177e4SLinus Torvalds } 3501da177e4SLinus Torvalds 3516be8aeefSGreg Kroah-Hartman static ssize_t tx_queue_len_store(struct device *dev, 35243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 35343cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3541da177e4SLinus Torvalds { 3555e1fccc0SEric W. Biederman if (!capable(CAP_NET_ADMIN)) 3565e1fccc0SEric W. Biederman return -EPERM; 3575e1fccc0SEric W. Biederman 35843cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_tx_queue_len); 3591da177e4SLinus Torvalds } 3600cd29503SAlexey Dobriyan NETDEVICE_SHOW_RW(tx_queue_len, fmt_dec); 3611da177e4SLinus Torvalds 3623b47d303SEric Dumazet static int change_gro_flush_timeout(struct net_device *dev, unsigned long val) 3633b47d303SEric Dumazet { 3643b47d303SEric Dumazet dev->gro_flush_timeout = val; 3653b47d303SEric Dumazet return 0; 3663b47d303SEric Dumazet } 3673b47d303SEric Dumazet 3683b47d303SEric Dumazet static ssize_t gro_flush_timeout_store(struct device *dev, 3693b47d303SEric Dumazet struct device_attribute *attr, 3703b47d303SEric Dumazet const char *buf, size_t len) 3713b47d303SEric Dumazet { 3723b47d303SEric Dumazet if (!capable(CAP_NET_ADMIN)) 3733b47d303SEric Dumazet return -EPERM; 3743b47d303SEric Dumazet 3753b47d303SEric Dumazet return netdev_store(dev, attr, buf, len, change_gro_flush_timeout); 3763b47d303SEric Dumazet } 3773b47d303SEric Dumazet NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong); 3783b47d303SEric Dumazet 3796be8aeefSGreg Kroah-Hartman static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr, 3800b815a1aSStephen Hemminger const char *buf, size_t len) 3810b815a1aSStephen Hemminger { 3820b815a1aSStephen Hemminger struct net_device *netdev = to_net_dev(dev); 3835e1fccc0SEric W. Biederman struct net *net = dev_net(netdev); 3840b815a1aSStephen Hemminger size_t count = len; 3850b815a1aSStephen Hemminger ssize_t ret; 3860b815a1aSStephen Hemminger 3875e1fccc0SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 3880b815a1aSStephen Hemminger return -EPERM; 3890b815a1aSStephen Hemminger 3900b815a1aSStephen Hemminger /* ignore trailing newline */ 3910b815a1aSStephen Hemminger if (len > 0 && buf[len - 1] == '\n') 3920b815a1aSStephen Hemminger --count; 3930b815a1aSStephen Hemminger 3940b815a1aSStephen Hemminger ret = dev_set_alias(netdev, buf, count); 3950b815a1aSStephen Hemminger 3960b815a1aSStephen Hemminger return ret < 0 ? ret : len; 3970b815a1aSStephen Hemminger } 3980b815a1aSStephen Hemminger 3996be8aeefSGreg Kroah-Hartman static ssize_t ifalias_show(struct device *dev, 4000b815a1aSStephen Hemminger struct device_attribute *attr, char *buf) 4010b815a1aSStephen Hemminger { 4020b815a1aSStephen Hemminger const struct net_device *netdev = to_net_dev(dev); 4036c557001SFlorian Westphal char tmp[IFALIASZ]; 4040b815a1aSStephen Hemminger ssize_t ret = 0; 4050b815a1aSStephen Hemminger 4066c557001SFlorian Westphal ret = dev_get_alias(netdev, tmp, sizeof(tmp)); 4076c557001SFlorian Westphal if (ret > 0) 4086c557001SFlorian Westphal ret = sprintf(buf, "%s\n", tmp); 4090b815a1aSStephen Hemminger return ret; 4100b815a1aSStephen Hemminger } 4116be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(ifalias); 412a512b92bSVlad Dogaru 4136b53dafeSWANG Cong static int change_group(struct net_device *dev, unsigned long new_group) 414a512b92bSVlad Dogaru { 4156b53dafeSWANG Cong dev_set_group(dev, (int)new_group); 416a512b92bSVlad Dogaru return 0; 417a512b92bSVlad Dogaru } 418a512b92bSVlad Dogaru 4196be8aeefSGreg Kroah-Hartman static ssize_t group_store(struct device *dev, struct device_attribute *attr, 420a512b92bSVlad Dogaru const char *buf, size_t len) 421a512b92bSVlad Dogaru { 422a512b92bSVlad Dogaru return netdev_store(dev, attr, buf, len, change_group); 423a512b92bSVlad Dogaru } 4246be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(group, fmt_dec); 4256be8aeefSGreg Kroah-Hartman static DEVICE_ATTR(netdev_group, S_IRUGO | S_IWUSR, group_show, group_store); 426a512b92bSVlad Dogaru 427d746d707SAnuradha Karuppiah static int change_proto_down(struct net_device *dev, unsigned long proto_down) 428d746d707SAnuradha Karuppiah { 429d746d707SAnuradha Karuppiah return dev_change_proto_down(dev, (bool)proto_down); 430d746d707SAnuradha Karuppiah } 431d746d707SAnuradha Karuppiah 432d746d707SAnuradha Karuppiah static ssize_t proto_down_store(struct device *dev, 433d746d707SAnuradha Karuppiah struct device_attribute *attr, 434d746d707SAnuradha Karuppiah const char *buf, size_t len) 435d746d707SAnuradha Karuppiah { 436d746d707SAnuradha Karuppiah return netdev_store(dev, attr, buf, len, change_proto_down); 437d746d707SAnuradha Karuppiah } 438d746d707SAnuradha Karuppiah NETDEVICE_SHOW_RW(proto_down, fmt_dec); 439d746d707SAnuradha Karuppiah 440cc998ff8SLinus Torvalds static ssize_t phys_port_id_show(struct device *dev, 441ff80e519SJiri Pirko struct device_attribute *attr, char *buf) 442ff80e519SJiri Pirko { 443ff80e519SJiri Pirko struct net_device *netdev = to_net_dev(dev); 444ff80e519SJiri Pirko ssize_t ret = -EINVAL; 445ff80e519SJiri Pirko 446ff80e519SJiri Pirko if (!rtnl_trylock()) 447ff80e519SJiri Pirko return restart_syscall(); 448ff80e519SJiri Pirko 449ff80e519SJiri Pirko if (dev_isalive(netdev)) { 45002637fceSJiri Pirko struct netdev_phys_item_id ppid; 451ff80e519SJiri Pirko 452ff80e519SJiri Pirko ret = dev_get_phys_port_id(netdev, &ppid); 453ff80e519SJiri Pirko if (!ret) 454ff80e519SJiri Pirko ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); 455ff80e519SJiri Pirko } 456ff80e519SJiri Pirko rtnl_unlock(); 457ff80e519SJiri Pirko 458ff80e519SJiri Pirko return ret; 459ff80e519SJiri Pirko } 460cc998ff8SLinus Torvalds static DEVICE_ATTR_RO(phys_port_id); 461ff80e519SJiri Pirko 462db24a904SDavid Ahern static ssize_t phys_port_name_show(struct device *dev, 463db24a904SDavid Ahern struct device_attribute *attr, char *buf) 464db24a904SDavid Ahern { 465db24a904SDavid Ahern struct net_device *netdev = to_net_dev(dev); 466db24a904SDavid Ahern ssize_t ret = -EINVAL; 467db24a904SDavid Ahern 468db24a904SDavid Ahern if (!rtnl_trylock()) 469db24a904SDavid Ahern return restart_syscall(); 470db24a904SDavid Ahern 471db24a904SDavid Ahern if (dev_isalive(netdev)) { 472db24a904SDavid Ahern char name[IFNAMSIZ]; 473db24a904SDavid Ahern 474db24a904SDavid Ahern ret = dev_get_phys_port_name(netdev, name, sizeof(name)); 475db24a904SDavid Ahern if (!ret) 476db24a904SDavid Ahern ret = sprintf(buf, "%s\n", name); 477db24a904SDavid Ahern } 478db24a904SDavid Ahern rtnl_unlock(); 479db24a904SDavid Ahern 480db24a904SDavid Ahern return ret; 481db24a904SDavid Ahern } 482db24a904SDavid Ahern static DEVICE_ATTR_RO(phys_port_name); 483db24a904SDavid Ahern 484aecbe01eSJiri Pirko static ssize_t phys_switch_id_show(struct device *dev, 485aecbe01eSJiri Pirko struct device_attribute *attr, char *buf) 486aecbe01eSJiri Pirko { 487aecbe01eSJiri Pirko struct net_device *netdev = to_net_dev(dev); 488aecbe01eSJiri Pirko ssize_t ret = -EINVAL; 489aecbe01eSJiri Pirko 490aecbe01eSJiri Pirko if (!rtnl_trylock()) 491aecbe01eSJiri Pirko return restart_syscall(); 492aecbe01eSJiri Pirko 493aecbe01eSJiri Pirko if (dev_isalive(netdev)) { 494f8e20a9fSScott Feldman struct switchdev_attr attr = { 4956ff64f6fSIdo Schimmel .orig_dev = netdev, 4961f868398SJiri Pirko .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, 497f8e20a9fSScott Feldman .flags = SWITCHDEV_F_NO_RECURSE, 498f8e20a9fSScott Feldman }; 499aecbe01eSJiri Pirko 500f8e20a9fSScott Feldman ret = switchdev_port_attr_get(netdev, &attr); 501aecbe01eSJiri Pirko if (!ret) 50242275bd8SScott Feldman ret = sprintf(buf, "%*phN\n", attr.u.ppid.id_len, 50342275bd8SScott Feldman attr.u.ppid.id); 504aecbe01eSJiri Pirko } 505aecbe01eSJiri Pirko rtnl_unlock(); 506aecbe01eSJiri Pirko 507aecbe01eSJiri Pirko return ret; 508aecbe01eSJiri Pirko } 509aecbe01eSJiri Pirko static DEVICE_ATTR_RO(phys_switch_id); 510aecbe01eSJiri Pirko 511ec6cc599Sstephen hemminger static struct attribute *net_class_attrs[] __ro_after_init = { 5126be8aeefSGreg Kroah-Hartman &dev_attr_netdev_group.attr, 5136be8aeefSGreg Kroah-Hartman &dev_attr_type.attr, 5146be8aeefSGreg Kroah-Hartman &dev_attr_dev_id.attr, 5153f85944fSAmir Vadai &dev_attr_dev_port.attr, 5166be8aeefSGreg Kroah-Hartman &dev_attr_iflink.attr, 5176be8aeefSGreg Kroah-Hartman &dev_attr_ifindex.attr, 518685343fcSTom Gundersen &dev_attr_name_assign_type.attr, 5196be8aeefSGreg Kroah-Hartman &dev_attr_addr_assign_type.attr, 5206be8aeefSGreg Kroah-Hartman &dev_attr_addr_len.attr, 5216be8aeefSGreg Kroah-Hartman &dev_attr_link_mode.attr, 5226be8aeefSGreg Kroah-Hartman &dev_attr_address.attr, 5236be8aeefSGreg Kroah-Hartman &dev_attr_broadcast.attr, 5246be8aeefSGreg Kroah-Hartman &dev_attr_speed.attr, 5256be8aeefSGreg Kroah-Hartman &dev_attr_duplex.attr, 5266be8aeefSGreg Kroah-Hartman &dev_attr_dormant.attr, 5276be8aeefSGreg Kroah-Hartman &dev_attr_operstate.attr, 5282d3b479dSdavid decotigny &dev_attr_carrier_changes.attr, 5296be8aeefSGreg Kroah-Hartman &dev_attr_ifalias.attr, 5306be8aeefSGreg Kroah-Hartman &dev_attr_carrier.attr, 5316be8aeefSGreg Kroah-Hartman &dev_attr_mtu.attr, 5326be8aeefSGreg Kroah-Hartman &dev_attr_flags.attr, 5336be8aeefSGreg Kroah-Hartman &dev_attr_tx_queue_len.attr, 5343b47d303SEric Dumazet &dev_attr_gro_flush_timeout.attr, 535cc998ff8SLinus Torvalds &dev_attr_phys_port_id.attr, 536db24a904SDavid Ahern &dev_attr_phys_port_name.attr, 537aecbe01eSJiri Pirko &dev_attr_phys_switch_id.attr, 538d746d707SAnuradha Karuppiah &dev_attr_proto_down.attr, 5396be8aeefSGreg Kroah-Hartman NULL, 5401da177e4SLinus Torvalds }; 5416be8aeefSGreg Kroah-Hartman ATTRIBUTE_GROUPS(net_class); 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds /* Show a given an attribute in the statistics group */ 54443cb76d9SGreg Kroah-Hartman static ssize_t netstat_show(const struct device *d, 54543cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 5461da177e4SLinus Torvalds unsigned long offset) 5471da177e4SLinus Torvalds { 54843cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 5491da177e4SLinus Torvalds ssize_t ret = -EINVAL; 5501da177e4SLinus Torvalds 551be1f3c2cSBen Hutchings WARN_ON(offset > sizeof(struct rtnl_link_stats64) || 552be1f3c2cSBen Hutchings offset % sizeof(u64) != 0); 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds read_lock(&dev_base_lock); 55596e74088SPavel Emelyanov if (dev_isalive(dev)) { 55628172739SEric Dumazet struct rtnl_link_stats64 temp; 55728172739SEric Dumazet const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); 55828172739SEric Dumazet 559be1f3c2cSBen Hutchings ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *)stats) + offset)); 56096e74088SPavel Emelyanov } 5611da177e4SLinus Torvalds read_unlock(&dev_base_lock); 5621da177e4SLinus Torvalds return ret; 5631da177e4SLinus Torvalds } 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds /* generate a read-only statistics attribute */ 5661da177e4SLinus Torvalds #define NETSTAT_ENTRY(name) \ 5676be8aeefSGreg Kroah-Hartman static ssize_t name##_show(struct device *d, \ 56843cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 5691da177e4SLinus Torvalds { \ 57043cb76d9SGreg Kroah-Hartman return netstat_show(d, attr, buf, \ 571be1f3c2cSBen Hutchings offsetof(struct rtnl_link_stats64, name)); \ 5721da177e4SLinus Torvalds } \ 5736be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(name) 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds NETSTAT_ENTRY(rx_packets); 5761da177e4SLinus Torvalds NETSTAT_ENTRY(tx_packets); 5771da177e4SLinus Torvalds NETSTAT_ENTRY(rx_bytes); 5781da177e4SLinus Torvalds NETSTAT_ENTRY(tx_bytes); 5791da177e4SLinus Torvalds NETSTAT_ENTRY(rx_errors); 5801da177e4SLinus Torvalds NETSTAT_ENTRY(tx_errors); 5811da177e4SLinus Torvalds NETSTAT_ENTRY(rx_dropped); 5821da177e4SLinus Torvalds NETSTAT_ENTRY(tx_dropped); 5831da177e4SLinus Torvalds NETSTAT_ENTRY(multicast); 5841da177e4SLinus Torvalds NETSTAT_ENTRY(collisions); 5851da177e4SLinus Torvalds NETSTAT_ENTRY(rx_length_errors); 5861da177e4SLinus Torvalds NETSTAT_ENTRY(rx_over_errors); 5871da177e4SLinus Torvalds NETSTAT_ENTRY(rx_crc_errors); 5881da177e4SLinus Torvalds NETSTAT_ENTRY(rx_frame_errors); 5891da177e4SLinus Torvalds NETSTAT_ENTRY(rx_fifo_errors); 5901da177e4SLinus Torvalds NETSTAT_ENTRY(rx_missed_errors); 5911da177e4SLinus Torvalds NETSTAT_ENTRY(tx_aborted_errors); 5921da177e4SLinus Torvalds NETSTAT_ENTRY(tx_carrier_errors); 5931da177e4SLinus Torvalds NETSTAT_ENTRY(tx_fifo_errors); 5941da177e4SLinus Torvalds NETSTAT_ENTRY(tx_heartbeat_errors); 5951da177e4SLinus Torvalds NETSTAT_ENTRY(tx_window_errors); 5961da177e4SLinus Torvalds NETSTAT_ENTRY(rx_compressed); 5971da177e4SLinus Torvalds NETSTAT_ENTRY(tx_compressed); 5986e7333d3SJarod Wilson NETSTAT_ENTRY(rx_nohandler); 5991da177e4SLinus Torvalds 600ec6cc599Sstephen hemminger static struct attribute *netstat_attrs[] __ro_after_init = { 60143cb76d9SGreg Kroah-Hartman &dev_attr_rx_packets.attr, 60243cb76d9SGreg Kroah-Hartman &dev_attr_tx_packets.attr, 60343cb76d9SGreg Kroah-Hartman &dev_attr_rx_bytes.attr, 60443cb76d9SGreg Kroah-Hartman &dev_attr_tx_bytes.attr, 60543cb76d9SGreg Kroah-Hartman &dev_attr_rx_errors.attr, 60643cb76d9SGreg Kroah-Hartman &dev_attr_tx_errors.attr, 60743cb76d9SGreg Kroah-Hartman &dev_attr_rx_dropped.attr, 60843cb76d9SGreg Kroah-Hartman &dev_attr_tx_dropped.attr, 60943cb76d9SGreg Kroah-Hartman &dev_attr_multicast.attr, 61043cb76d9SGreg Kroah-Hartman &dev_attr_collisions.attr, 61143cb76d9SGreg Kroah-Hartman &dev_attr_rx_length_errors.attr, 61243cb76d9SGreg Kroah-Hartman &dev_attr_rx_over_errors.attr, 61343cb76d9SGreg Kroah-Hartman &dev_attr_rx_crc_errors.attr, 61443cb76d9SGreg Kroah-Hartman &dev_attr_rx_frame_errors.attr, 61543cb76d9SGreg Kroah-Hartman &dev_attr_rx_fifo_errors.attr, 61643cb76d9SGreg Kroah-Hartman &dev_attr_rx_missed_errors.attr, 61743cb76d9SGreg Kroah-Hartman &dev_attr_tx_aborted_errors.attr, 61843cb76d9SGreg Kroah-Hartman &dev_attr_tx_carrier_errors.attr, 61943cb76d9SGreg Kroah-Hartman &dev_attr_tx_fifo_errors.attr, 62043cb76d9SGreg Kroah-Hartman &dev_attr_tx_heartbeat_errors.attr, 62143cb76d9SGreg Kroah-Hartman &dev_attr_tx_window_errors.attr, 62243cb76d9SGreg Kroah-Hartman &dev_attr_rx_compressed.attr, 62343cb76d9SGreg Kroah-Hartman &dev_attr_tx_compressed.attr, 6246e7333d3SJarod Wilson &dev_attr_rx_nohandler.attr, 6251da177e4SLinus Torvalds NULL 6261da177e4SLinus Torvalds }; 6271da177e4SLinus Torvalds 62838ef00ccSArvind Yadav static const struct attribute_group netstat_group = { 6291da177e4SLinus Torvalds .name = "statistics", 6301da177e4SLinus Torvalds .attrs = netstat_attrs, 6311da177e4SLinus Torvalds }; 63238c1a01cSJohannes Berg 63338c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) 63438c1a01cSJohannes Berg static struct attribute *wireless_attrs[] = { 63538c1a01cSJohannes Berg NULL 63638c1a01cSJohannes Berg }; 63738c1a01cSJohannes Berg 63838ef00ccSArvind Yadav static const struct attribute_group wireless_group = { 63938c1a01cSJohannes Berg .name = "wireless", 64038c1a01cSJohannes Berg .attrs = wireless_attrs, 64138c1a01cSJohannes Berg }; 64238c1a01cSJohannes Berg #endif 6436be8aeefSGreg Kroah-Hartman 6446be8aeefSGreg Kroah-Hartman #else /* CONFIG_SYSFS */ 6456be8aeefSGreg Kroah-Hartman #define net_class_groups NULL 646d6523ddfSEric W. Biederman #endif /* CONFIG_SYSFS */ 6471da177e4SLinus Torvalds 648a953be53SMichael Dalton #ifdef CONFIG_SYSFS 6496648c65eSstephen hemminger #define to_rx_queue_attr(_attr) \ 6506648c65eSstephen hemminger container_of(_attr, struct rx_queue_attribute, attr) 6510a9627f2STom Herbert 6520a9627f2STom Herbert #define to_rx_queue(obj) container_of(obj, struct netdev_rx_queue, kobj) 6530a9627f2STom Herbert 6540a9627f2STom Herbert static ssize_t rx_queue_attr_show(struct kobject *kobj, struct attribute *attr, 6550a9627f2STom Herbert char *buf) 6560a9627f2STom Herbert { 657667e427bSstephen hemminger const struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 6580a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 6590a9627f2STom Herbert 6600a9627f2STom Herbert if (!attribute->show) 6610a9627f2STom Herbert return -EIO; 6620a9627f2STom Herbert 663718ad681Sstephen hemminger return attribute->show(queue, buf); 6640a9627f2STom Herbert } 6650a9627f2STom Herbert 6660a9627f2STom Herbert static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr, 6670a9627f2STom Herbert const char *buf, size_t count) 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->store) 6730a9627f2STom Herbert return -EIO; 6740a9627f2STom Herbert 675718ad681Sstephen hemminger return attribute->store(queue, buf, count); 6760a9627f2STom Herbert } 6770a9627f2STom Herbert 678fa50d645Sstephen hemminger static const struct sysfs_ops rx_queue_sysfs_ops = { 6790a9627f2STom Herbert .show = rx_queue_attr_show, 6800a9627f2STom Herbert .store = rx_queue_attr_store, 6810a9627f2STom Herbert }; 6820a9627f2STom Herbert 683a953be53SMichael Dalton #ifdef CONFIG_RPS 684718ad681Sstephen hemminger static ssize_t show_rps_map(struct netdev_rx_queue *queue, char *buf) 6850a9627f2STom Herbert { 6860a9627f2STom Herbert struct rps_map *map; 6870a9627f2STom Herbert cpumask_var_t mask; 688f0906827STejun Heo int i, len; 6890a9627f2STom Herbert 6900a9627f2STom Herbert if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 6910a9627f2STom Herbert return -ENOMEM; 6920a9627f2STom Herbert 6930a9627f2STom Herbert rcu_read_lock(); 6940a9627f2STom Herbert map = rcu_dereference(queue->rps_map); 6950a9627f2STom Herbert if (map) 6960a9627f2STom Herbert for (i = 0; i < map->len; i++) 6970a9627f2STom Herbert cpumask_set_cpu(map->cpus[i], mask); 6980a9627f2STom Herbert 699f0906827STejun Heo len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask)); 7000a9627f2STom Herbert rcu_read_unlock(); 7010a9627f2STom Herbert free_cpumask_var(mask); 7020a9627f2STom Herbert 703f0906827STejun Heo return len < PAGE_SIZE ? len : -EINVAL; 7040a9627f2STom Herbert } 7050a9627f2STom Herbert 706f5acb907SEric Dumazet static ssize_t store_rps_map(struct netdev_rx_queue *queue, 7070a9627f2STom Herbert const char *buf, size_t len) 7080a9627f2STom Herbert { 7090a9627f2STom Herbert struct rps_map *old_map, *map; 7100a9627f2STom Herbert cpumask_var_t mask; 7110a9627f2STom Herbert int err, cpu, i; 712da65ad1fSSasha Levin static DEFINE_MUTEX(rps_map_mutex); 7130a9627f2STom Herbert 7140a9627f2STom Herbert if (!capable(CAP_NET_ADMIN)) 7150a9627f2STom Herbert return -EPERM; 7160a9627f2STom Herbert 7170a9627f2STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 7180a9627f2STom Herbert return -ENOMEM; 7190a9627f2STom Herbert 7200a9627f2STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 7210a9627f2STom Herbert if (err) { 7220a9627f2STom Herbert free_cpumask_var(mask); 7230a9627f2STom Herbert return err; 7240a9627f2STom Herbert } 7250a9627f2STom Herbert 72695c96174SEric Dumazet map = kzalloc(max_t(unsigned int, 7270a9627f2STom Herbert RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), 7280a9627f2STom Herbert GFP_KERNEL); 7290a9627f2STom Herbert if (!map) { 7300a9627f2STom Herbert free_cpumask_var(mask); 7310a9627f2STom Herbert return -ENOMEM; 7320a9627f2STom Herbert } 7330a9627f2STom Herbert 7340a9627f2STom Herbert i = 0; 7350a9627f2STom Herbert for_each_cpu_and(cpu, mask, cpu_online_mask) 7360a9627f2STom Herbert map->cpus[i++] = cpu; 7370a9627f2STom Herbert 7386648c65eSstephen hemminger if (i) { 7390a9627f2STom Herbert map->len = i; 7406648c65eSstephen hemminger } else { 7410a9627f2STom Herbert kfree(map); 7420a9627f2STom Herbert map = NULL; 7430a9627f2STom Herbert } 7440a9627f2STom Herbert 745da65ad1fSSasha Levin mutex_lock(&rps_map_mutex); 7466e3f7fafSEric Dumazet old_map = rcu_dereference_protected(queue->rps_map, 747da65ad1fSSasha Levin mutex_is_locked(&rps_map_mutex)); 7480a9627f2STom Herbert rcu_assign_pointer(queue->rps_map, map); 7490a9627f2STom Herbert 750adc9300eSEric Dumazet if (map) 751c5905afbSIngo Molnar static_key_slow_inc(&rps_needed); 75210e4ea75STom Herbert if (old_map) 753c5905afbSIngo Molnar static_key_slow_dec(&rps_needed); 75410e4ea75STom Herbert 755da65ad1fSSasha Levin mutex_unlock(&rps_map_mutex); 75610e4ea75STom Herbert 75710e4ea75STom Herbert if (old_map) 75810e4ea75STom Herbert kfree_rcu(old_map, rcu); 75910e4ea75STom Herbert 7600a9627f2STom Herbert free_cpumask_var(mask); 7610a9627f2STom Herbert return len; 7620a9627f2STom Herbert } 7630a9627f2STom Herbert 764fec5e652STom Herbert static ssize_t show_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 765fec5e652STom Herbert char *buf) 766fec5e652STom Herbert { 767fec5e652STom Herbert struct rps_dev_flow_table *flow_table; 76860b778ceSEric Dumazet unsigned long val = 0; 769fec5e652STom Herbert 770fec5e652STom Herbert rcu_read_lock(); 771fec5e652STom Herbert flow_table = rcu_dereference(queue->rps_flow_table); 772fec5e652STom Herbert if (flow_table) 77360b778ceSEric Dumazet val = (unsigned long)flow_table->mask + 1; 774fec5e652STom Herbert rcu_read_unlock(); 775fec5e652STom Herbert 77660b778ceSEric Dumazet return sprintf(buf, "%lu\n", val); 777fec5e652STom Herbert } 778fec5e652STom Herbert 779fec5e652STom Herbert static void rps_dev_flow_table_release(struct rcu_head *rcu) 780fec5e652STom Herbert { 781fec5e652STom Herbert struct rps_dev_flow_table *table = container_of(rcu, 782fec5e652STom Herbert struct rps_dev_flow_table, rcu); 783243198d0SAl Viro vfree(table); 784fec5e652STom Herbert } 785fec5e652STom Herbert 786f5acb907SEric Dumazet static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 787fec5e652STom Herbert const char *buf, size_t len) 788fec5e652STom Herbert { 78960b778ceSEric Dumazet unsigned long mask, count; 790fec5e652STom Herbert struct rps_dev_flow_table *table, *old_table; 791fec5e652STom Herbert static DEFINE_SPINLOCK(rps_dev_flow_lock); 79260b778ceSEric Dumazet int rc; 793fec5e652STom Herbert 794fec5e652STom Herbert if (!capable(CAP_NET_ADMIN)) 795fec5e652STom Herbert return -EPERM; 796fec5e652STom Herbert 79760b778ceSEric Dumazet rc = kstrtoul(buf, 0, &count); 79860b778ceSEric Dumazet if (rc < 0) 79960b778ceSEric Dumazet return rc; 800fec5e652STom Herbert 801fec5e652STom Herbert if (count) { 80260b778ceSEric Dumazet mask = count - 1; 80360b778ceSEric Dumazet /* mask = roundup_pow_of_two(count) - 1; 80460b778ceSEric Dumazet * without overflows... 80560b778ceSEric Dumazet */ 80660b778ceSEric Dumazet while ((mask | (mask >> 1)) != mask) 80760b778ceSEric Dumazet mask |= (mask >> 1); 80860b778ceSEric Dumazet /* On 64 bit arches, must check mask fits in table->mask (u32), 8098e3bff96Sstephen hemminger * and on 32bit arches, must check 8108e3bff96Sstephen hemminger * RPS_DEV_FLOW_TABLE_SIZE(mask + 1) doesn't overflow. 81160b778ceSEric Dumazet */ 81260b778ceSEric Dumazet #if BITS_PER_LONG > 32 81360b778ceSEric Dumazet if (mask > (unsigned long)(u32)mask) 814a0a129f8SXi Wang return -EINVAL; 81560b778ceSEric Dumazet #else 81660b778ceSEric Dumazet if (mask > (ULONG_MAX - RPS_DEV_FLOW_TABLE_SIZE(1)) 817a0a129f8SXi Wang / sizeof(struct rps_dev_flow)) { 818fec5e652STom Herbert /* Enforce a limit to prevent overflow */ 819fec5e652STom Herbert return -EINVAL; 820fec5e652STom Herbert } 82160b778ceSEric Dumazet #endif 82260b778ceSEric Dumazet table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(mask + 1)); 823fec5e652STom Herbert if (!table) 824fec5e652STom Herbert return -ENOMEM; 825fec5e652STom Herbert 82660b778ceSEric Dumazet table->mask = mask; 82760b778ceSEric Dumazet for (count = 0; count <= mask; count++) 82860b778ceSEric Dumazet table->flows[count].cpu = RPS_NO_CPU; 8296648c65eSstephen hemminger } else { 830fec5e652STom Herbert table = NULL; 8316648c65eSstephen hemminger } 832fec5e652STom Herbert 833fec5e652STom Herbert spin_lock(&rps_dev_flow_lock); 8346e3f7fafSEric Dumazet old_table = rcu_dereference_protected(queue->rps_flow_table, 8356e3f7fafSEric Dumazet lockdep_is_held(&rps_dev_flow_lock)); 836fec5e652STom Herbert rcu_assign_pointer(queue->rps_flow_table, table); 837fec5e652STom Herbert spin_unlock(&rps_dev_flow_lock); 838fec5e652STom Herbert 839fec5e652STom Herbert if (old_table) 840fec5e652STom Herbert call_rcu(&old_table->rcu, rps_dev_flow_table_release); 841fec5e652STom Herbert 842fec5e652STom Herbert return len; 843fec5e652STom Herbert } 844fec5e652STom Herbert 845667e427bSstephen hemminger static struct rx_queue_attribute rps_cpus_attribute __ro_after_init 846667e427bSstephen hemminger = __ATTR(rps_cpus, S_IRUGO | S_IWUSR, show_rps_map, store_rps_map); 8470a9627f2STom Herbert 848667e427bSstephen hemminger static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute __ro_after_init 849667e427bSstephen hemminger = __ATTR(rps_flow_cnt, S_IRUGO | S_IWUSR, 850fec5e652STom Herbert show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt); 851a953be53SMichael Dalton #endif /* CONFIG_RPS */ 852fec5e652STom Herbert 853667e427bSstephen hemminger static struct attribute *rx_queue_default_attrs[] __ro_after_init = { 854a953be53SMichael Dalton #ifdef CONFIG_RPS 8550a9627f2STom Herbert &rps_cpus_attribute.attr, 856fec5e652STom Herbert &rps_dev_flow_table_cnt_attribute.attr, 857a953be53SMichael Dalton #endif 8580a9627f2STom Herbert NULL 8590a9627f2STom Herbert }; 8600a9627f2STom Herbert 8610a9627f2STom Herbert static void rx_queue_release(struct kobject *kobj) 8620a9627f2STom Herbert { 8630a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 864a953be53SMichael Dalton #ifdef CONFIG_RPS 8656e3f7fafSEric Dumazet struct rps_map *map; 8666e3f7fafSEric Dumazet struct rps_dev_flow_table *flow_table; 8670a9627f2STom Herbert 86833d480ceSEric Dumazet map = rcu_dereference_protected(queue->rps_map, 1); 8699ea19481SJohn Fastabend if (map) { 8709ea19481SJohn Fastabend RCU_INIT_POINTER(queue->rps_map, NULL); 871f6f80238SLai Jiangshan kfree_rcu(map, rcu); 8729ea19481SJohn Fastabend } 8736e3f7fafSEric Dumazet 87433d480ceSEric Dumazet flow_table = rcu_dereference_protected(queue->rps_flow_table, 1); 8759ea19481SJohn Fastabend if (flow_table) { 8769ea19481SJohn Fastabend RCU_INIT_POINTER(queue->rps_flow_table, NULL); 8776e3f7fafSEric Dumazet call_rcu(&flow_table->rcu, rps_dev_flow_table_release); 8789ea19481SJohn Fastabend } 879a953be53SMichael Dalton #endif 8800a9627f2STom Herbert 8819ea19481SJohn Fastabend memset(kobj, 0, sizeof(*kobj)); 882fe822240STom Herbert dev_put(queue->dev); 8830a9627f2STom Herbert } 8840a9627f2STom Herbert 88582ef3d5dSWeilong Chen static const void *rx_queue_namespace(struct kobject *kobj) 88682ef3d5dSWeilong Chen { 88782ef3d5dSWeilong Chen struct netdev_rx_queue *queue = to_rx_queue(kobj); 88882ef3d5dSWeilong Chen struct device *dev = &queue->dev->dev; 88982ef3d5dSWeilong Chen const void *ns = NULL; 89082ef3d5dSWeilong Chen 89182ef3d5dSWeilong Chen if (dev->class && dev->class->ns_type) 89282ef3d5dSWeilong Chen ns = dev->class->namespace(dev); 89382ef3d5dSWeilong Chen 89482ef3d5dSWeilong Chen return ns; 89582ef3d5dSWeilong Chen } 89682ef3d5dSWeilong Chen 897667e427bSstephen hemminger static struct kobj_type rx_queue_ktype __ro_after_init = { 8980a9627f2STom Herbert .sysfs_ops = &rx_queue_sysfs_ops, 8990a9627f2STom Herbert .release = rx_queue_release, 9000a9627f2STom Herbert .default_attrs = rx_queue_default_attrs, 90182ef3d5dSWeilong Chen .namespace = rx_queue_namespace 9020a9627f2STom Herbert }; 9030a9627f2STom Herbert 9046b53dafeSWANG Cong static int rx_queue_add_kobject(struct net_device *dev, int index) 9050a9627f2STom Herbert { 9066b53dafeSWANG Cong struct netdev_rx_queue *queue = dev->_rx + index; 9070a9627f2STom Herbert struct kobject *kobj = &queue->kobj; 9080a9627f2STom Herbert int error = 0; 9090a9627f2STom Herbert 9106b53dafeSWANG Cong kobj->kset = dev->queues_kset; 9110a9627f2STom Herbert error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, 9120a9627f2STom Herbert "rx-%u", index); 913a953be53SMichael Dalton if (error) 914d0d66837Sstephen hemminger return error; 915a953be53SMichael Dalton 9166b53dafeSWANG Cong if (dev->sysfs_rx_queue_group) { 9176b53dafeSWANG Cong error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); 918d0d66837Sstephen hemminger if (error) { 919d0d66837Sstephen hemminger kobject_put(kobj); 920d0d66837Sstephen hemminger return error; 921d0d66837Sstephen hemminger } 9220a9627f2STom Herbert } 9230a9627f2STom Herbert 9240a9627f2STom Herbert kobject_uevent(kobj, KOBJ_ADD); 925fe822240STom Herbert dev_hold(queue->dev); 9260a9627f2STom Herbert 9270a9627f2STom Herbert return error; 9280a9627f2STom Herbert } 92980dd6eacSPaul Bolle #endif /* CONFIG_SYSFS */ 9300a9627f2STom Herbert 93162fe0b40SBen Hutchings int 9326b53dafeSWANG Cong net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) 9330a9627f2STom Herbert { 934a953be53SMichael Dalton #ifdef CONFIG_SYSFS 9350a9627f2STom Herbert int i; 9360a9627f2STom Herbert int error = 0; 9370a9627f2STom Herbert 938a953be53SMichael Dalton #ifndef CONFIG_RPS 9396b53dafeSWANG Cong if (!dev->sysfs_rx_queue_group) 940a953be53SMichael Dalton return 0; 941a953be53SMichael Dalton #endif 94262fe0b40SBen Hutchings for (i = old_num; i < new_num; i++) { 9436b53dafeSWANG Cong error = rx_queue_add_kobject(dev, i); 94462fe0b40SBen Hutchings if (error) { 94562fe0b40SBen Hutchings new_num = old_num; 9460a9627f2STom Herbert break; 9470a9627f2STom Herbert } 94862fe0b40SBen Hutchings } 9490a9627f2STom Herbert 950a953be53SMichael Dalton while (--i >= new_num) { 951002d8a1aSAndrey Vagin struct kobject *kobj = &dev->_rx[i].kobj; 952002d8a1aSAndrey Vagin 95391864f58SAndrey Vagin if (!atomic_read(&dev_net(dev)->count)) 954002d8a1aSAndrey Vagin kobj->uevent_suppress = 1; 9556b53dafeSWANG Cong if (dev->sysfs_rx_queue_group) 956002d8a1aSAndrey Vagin sysfs_remove_group(kobj, dev->sysfs_rx_queue_group); 957002d8a1aSAndrey Vagin kobject_put(kobj); 958a953be53SMichael Dalton } 9590a9627f2STom Herbert 9600a9627f2STom Herbert return error; 961bf264145STom Herbert #else 962bf264145STom Herbert return 0; 963bf264145STom Herbert #endif 9640a9627f2STom Herbert } 9650a9627f2STom Herbert 966ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 9671d24eb48STom Herbert /* 9681d24eb48STom Herbert * netdev_queue sysfs structures and functions. 9691d24eb48STom Herbert */ 9701d24eb48STom Herbert struct netdev_queue_attribute { 9711d24eb48STom Herbert struct attribute attr; 972718ad681Sstephen hemminger ssize_t (*show)(struct netdev_queue *queue, char *buf); 9731d24eb48STom Herbert ssize_t (*store)(struct netdev_queue *queue, 974718ad681Sstephen hemminger const char *buf, size_t len); 9751d24eb48STom Herbert }; 9766648c65eSstephen hemminger #define to_netdev_queue_attr(_attr) \ 9776648c65eSstephen hemminger container_of(_attr, struct netdev_queue_attribute, attr) 9781d24eb48STom Herbert 9791d24eb48STom Herbert #define to_netdev_queue(obj) container_of(obj, struct netdev_queue, kobj) 9801d24eb48STom Herbert 9811d24eb48STom Herbert static ssize_t netdev_queue_attr_show(struct kobject *kobj, 9821d24eb48STom Herbert struct attribute *attr, char *buf) 98362fe0b40SBen Hutchings { 984667e427bSstephen hemminger const struct netdev_queue_attribute *attribute 985667e427bSstephen hemminger = to_netdev_queue_attr(attr); 9861d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 9871d24eb48STom Herbert 9881d24eb48STom Herbert if (!attribute->show) 9891d24eb48STom Herbert return -EIO; 9901d24eb48STom Herbert 991718ad681Sstephen hemminger return attribute->show(queue, buf); 9921d24eb48STom Herbert } 9931d24eb48STom Herbert 9941d24eb48STom Herbert static ssize_t netdev_queue_attr_store(struct kobject *kobj, 9951d24eb48STom Herbert struct attribute *attr, 9961d24eb48STom Herbert const char *buf, size_t count) 9971d24eb48STom Herbert { 998667e427bSstephen hemminger const struct netdev_queue_attribute *attribute 999667e427bSstephen hemminger = to_netdev_queue_attr(attr); 10001d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 10011d24eb48STom Herbert 10021d24eb48STom Herbert if (!attribute->store) 10031d24eb48STom Herbert return -EIO; 10041d24eb48STom Herbert 1005718ad681Sstephen hemminger return attribute->store(queue, buf, count); 10061d24eb48STom Herbert } 10071d24eb48STom Herbert 10081d24eb48STom Herbert static const struct sysfs_ops netdev_queue_sysfs_ops = { 10091d24eb48STom Herbert .show = netdev_queue_attr_show, 10101d24eb48STom Herbert .store = netdev_queue_attr_store, 10111d24eb48STom Herbert }; 10121d24eb48STom Herbert 10132b9c7581Sstephen hemminger static ssize_t tx_timeout_show(struct netdev_queue *queue, char *buf) 1014ccf5ff69Sdavid decotigny { 1015ccf5ff69Sdavid decotigny unsigned long trans_timeout; 1016ccf5ff69Sdavid decotigny 1017ccf5ff69Sdavid decotigny spin_lock_irq(&queue->_xmit_lock); 1018ccf5ff69Sdavid decotigny trans_timeout = queue->trans_timeout; 1019ccf5ff69Sdavid decotigny spin_unlock_irq(&queue->_xmit_lock); 1020ccf5ff69Sdavid decotigny 1021ccf5ff69Sdavid decotigny return sprintf(buf, "%lu", trans_timeout); 1022ccf5ff69Sdavid decotigny } 1023ccf5ff69Sdavid decotigny 1024c4047f53SThadeu Lima de Souza Cascardo static unsigned int get_netdev_queue_index(struct netdev_queue *queue) 1025822b3b2eSJohn Fastabend { 1026822b3b2eSJohn Fastabend struct net_device *dev = queue->dev; 1027c4047f53SThadeu Lima de Souza Cascardo unsigned int i; 1028822b3b2eSJohn Fastabend 1029c4047f53SThadeu Lima de Souza Cascardo i = queue - dev->_tx; 1030822b3b2eSJohn Fastabend BUG_ON(i >= dev->num_tx_queues); 1031822b3b2eSJohn Fastabend 1032822b3b2eSJohn Fastabend return i; 1033822b3b2eSJohn Fastabend } 1034822b3b2eSJohn Fastabend 10352b9c7581Sstephen hemminger static ssize_t traffic_class_show(struct netdev_queue *queue, 10368d059b0fSAlexander Duyck char *buf) 10378d059b0fSAlexander Duyck { 10388d059b0fSAlexander Duyck struct net_device *dev = queue->dev; 10398d059b0fSAlexander Duyck int index = get_netdev_queue_index(queue); 10408d059b0fSAlexander Duyck int tc = netdev_txq_to_tc(dev, index); 10418d059b0fSAlexander Duyck 10428d059b0fSAlexander Duyck if (tc < 0) 10438d059b0fSAlexander Duyck return -EINVAL; 10448d059b0fSAlexander Duyck 10458d059b0fSAlexander Duyck return sprintf(buf, "%u\n", tc); 10468d059b0fSAlexander Duyck } 10478d059b0fSAlexander Duyck 10488d059b0fSAlexander Duyck #ifdef CONFIG_XPS 10492b9c7581Sstephen hemminger static ssize_t tx_maxrate_show(struct netdev_queue *queue, 1050822b3b2eSJohn Fastabend char *buf) 1051822b3b2eSJohn Fastabend { 1052822b3b2eSJohn Fastabend return sprintf(buf, "%lu\n", queue->tx_maxrate); 1053822b3b2eSJohn Fastabend } 1054822b3b2eSJohn Fastabend 10552b9c7581Sstephen hemminger static ssize_t tx_maxrate_store(struct netdev_queue *queue, 1056822b3b2eSJohn Fastabend const char *buf, size_t len) 1057822b3b2eSJohn Fastabend { 1058822b3b2eSJohn Fastabend struct net_device *dev = queue->dev; 1059822b3b2eSJohn Fastabend int err, index = get_netdev_queue_index(queue); 1060822b3b2eSJohn Fastabend u32 rate = 0; 1061822b3b2eSJohn Fastabend 1062822b3b2eSJohn Fastabend err = kstrtou32(buf, 10, &rate); 1063822b3b2eSJohn Fastabend if (err < 0) 1064822b3b2eSJohn Fastabend return err; 1065822b3b2eSJohn Fastabend 1066822b3b2eSJohn Fastabend if (!rtnl_trylock()) 1067822b3b2eSJohn Fastabend return restart_syscall(); 1068822b3b2eSJohn Fastabend 1069822b3b2eSJohn Fastabend err = -EOPNOTSUPP; 1070822b3b2eSJohn Fastabend if (dev->netdev_ops->ndo_set_tx_maxrate) 1071822b3b2eSJohn Fastabend err = dev->netdev_ops->ndo_set_tx_maxrate(dev, index, rate); 1072822b3b2eSJohn Fastabend 1073822b3b2eSJohn Fastabend rtnl_unlock(); 1074822b3b2eSJohn Fastabend if (!err) { 1075822b3b2eSJohn Fastabend queue->tx_maxrate = rate; 1076822b3b2eSJohn Fastabend return len; 1077822b3b2eSJohn Fastabend } 1078822b3b2eSJohn Fastabend return err; 1079822b3b2eSJohn Fastabend } 1080822b3b2eSJohn Fastabend 10812b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_tx_maxrate __ro_after_init 10822b9c7581Sstephen hemminger = __ATTR_RW(tx_maxrate); 1083822b3b2eSJohn Fastabend #endif 1084822b3b2eSJohn Fastabend 10852b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_trans_timeout __ro_after_init 10862b9c7581Sstephen hemminger = __ATTR_RO(tx_timeout); 1087ccf5ff69Sdavid decotigny 10882b9c7581Sstephen hemminger static struct netdev_queue_attribute queue_traffic_class __ro_after_init 10892b9c7581Sstephen hemminger = __ATTR_RO(traffic_class); 10908d059b0fSAlexander Duyck 1091114cf580STom Herbert #ifdef CONFIG_BQL 1092114cf580STom Herbert /* 1093114cf580STom Herbert * Byte queue limits sysfs structures and functions. 1094114cf580STom Herbert */ 1095114cf580STom Herbert static ssize_t bql_show(char *buf, unsigned int value) 1096114cf580STom Herbert { 1097114cf580STom Herbert return sprintf(buf, "%u\n", value); 1098114cf580STom Herbert } 1099114cf580STom Herbert 1100114cf580STom Herbert static ssize_t bql_set(const char *buf, const size_t count, 1101114cf580STom Herbert unsigned int *pvalue) 1102114cf580STom Herbert { 1103114cf580STom Herbert unsigned int value; 1104114cf580STom Herbert int err; 1105114cf580STom Herbert 11066648c65eSstephen hemminger if (!strcmp(buf, "max") || !strcmp(buf, "max\n")) { 1107114cf580STom Herbert value = DQL_MAX_LIMIT; 11086648c65eSstephen hemminger } else { 1109114cf580STom Herbert err = kstrtouint(buf, 10, &value); 1110114cf580STom Herbert if (err < 0) 1111114cf580STom Herbert return err; 1112114cf580STom Herbert if (value > DQL_MAX_LIMIT) 1113114cf580STom Herbert return -EINVAL; 1114114cf580STom Herbert } 1115114cf580STom Herbert 1116114cf580STom Herbert *pvalue = value; 1117114cf580STom Herbert 1118114cf580STom Herbert return count; 1119114cf580STom Herbert } 1120114cf580STom Herbert 1121114cf580STom Herbert static ssize_t bql_show_hold_time(struct netdev_queue *queue, 1122114cf580STom Herbert char *buf) 1123114cf580STom Herbert { 1124114cf580STom Herbert struct dql *dql = &queue->dql; 1125114cf580STom Herbert 1126114cf580STom Herbert return sprintf(buf, "%u\n", jiffies_to_msecs(dql->slack_hold_time)); 1127114cf580STom Herbert } 1128114cf580STom Herbert 1129114cf580STom Herbert static ssize_t bql_set_hold_time(struct netdev_queue *queue, 1130114cf580STom Herbert const char *buf, size_t len) 1131114cf580STom Herbert { 1132114cf580STom Herbert struct dql *dql = &queue->dql; 113395c96174SEric Dumazet unsigned int value; 1134114cf580STom Herbert int err; 1135114cf580STom Herbert 1136114cf580STom Herbert err = kstrtouint(buf, 10, &value); 1137114cf580STom Herbert if (err < 0) 1138114cf580STom Herbert return err; 1139114cf580STom Herbert 1140114cf580STom Herbert dql->slack_hold_time = msecs_to_jiffies(value); 1141114cf580STom Herbert 1142114cf580STom Herbert return len; 1143114cf580STom Herbert } 1144114cf580STom Herbert 1145170c658aSstephen hemminger static struct netdev_queue_attribute bql_hold_time_attribute __ro_after_init 1146170c658aSstephen hemminger = __ATTR(hold_time, S_IRUGO | S_IWUSR, 1147170c658aSstephen hemminger bql_show_hold_time, bql_set_hold_time); 1148114cf580STom Herbert 1149114cf580STom Herbert static ssize_t bql_show_inflight(struct netdev_queue *queue, 1150114cf580STom Herbert char *buf) 1151114cf580STom Herbert { 1152114cf580STom Herbert struct dql *dql = &queue->dql; 1153114cf580STom Herbert 1154114cf580STom Herbert return sprintf(buf, "%u\n", dql->num_queued - dql->num_completed); 1155114cf580STom Herbert } 1156114cf580STom Herbert 1157170c658aSstephen hemminger static struct netdev_queue_attribute bql_inflight_attribute __ro_after_init = 1158795d9a25SHiroaki SHIMODA __ATTR(inflight, S_IRUGO, bql_show_inflight, NULL); 1159114cf580STom Herbert 1160114cf580STom Herbert #define BQL_ATTR(NAME, FIELD) \ 1161114cf580STom Herbert static ssize_t bql_show_ ## NAME(struct netdev_queue *queue, \ 1162114cf580STom Herbert char *buf) \ 1163114cf580STom Herbert { \ 1164114cf580STom Herbert return bql_show(buf, queue->dql.FIELD); \ 1165114cf580STom Herbert } \ 1166114cf580STom Herbert \ 1167114cf580STom Herbert static ssize_t bql_set_ ## NAME(struct netdev_queue *queue, \ 1168114cf580STom Herbert const char *buf, size_t len) \ 1169114cf580STom Herbert { \ 1170114cf580STom Herbert return bql_set(buf, len, &queue->dql.FIELD); \ 1171114cf580STom Herbert } \ 1172114cf580STom Herbert \ 1173170c658aSstephen hemminger static struct netdev_queue_attribute bql_ ## NAME ## _attribute __ro_after_init \ 1174170c658aSstephen hemminger = __ATTR(NAME, S_IRUGO | S_IWUSR, \ 1175170c658aSstephen hemminger bql_show_ ## NAME, bql_set_ ## NAME) 1176114cf580STom Herbert 1177170c658aSstephen hemminger BQL_ATTR(limit, limit); 1178170c658aSstephen hemminger BQL_ATTR(limit_max, max_limit); 1179170c658aSstephen hemminger BQL_ATTR(limit_min, min_limit); 1180114cf580STom Herbert 1181170c658aSstephen hemminger static struct attribute *dql_attrs[] __ro_after_init = { 1182114cf580STom Herbert &bql_limit_attribute.attr, 1183114cf580STom Herbert &bql_limit_max_attribute.attr, 1184114cf580STom Herbert &bql_limit_min_attribute.attr, 1185114cf580STom Herbert &bql_hold_time_attribute.attr, 1186114cf580STom Herbert &bql_inflight_attribute.attr, 1187114cf580STom Herbert NULL 1188114cf580STom Herbert }; 1189114cf580STom Herbert 119038ef00ccSArvind Yadav static const struct attribute_group dql_group = { 1191114cf580STom Herbert .name = "byte_queue_limits", 1192114cf580STom Herbert .attrs = dql_attrs, 1193114cf580STom Herbert }; 1194114cf580STom Herbert #endif /* CONFIG_BQL */ 1195114cf580STom Herbert 1196ccf5ff69Sdavid decotigny #ifdef CONFIG_XPS 11972b9c7581Sstephen hemminger static ssize_t xps_cpus_show(struct netdev_queue *queue, 1198718ad681Sstephen hemminger char *buf) 11991d24eb48STom Herbert { 12001d24eb48STom Herbert struct net_device *dev = queue->dev; 1201184c449fSAlexander Duyck int cpu, len, num_tc = 1, tc = 0; 12021d24eb48STom Herbert struct xps_dev_maps *dev_maps; 12031d24eb48STom Herbert cpumask_var_t mask; 12041d24eb48STom Herbert unsigned long index; 12051d24eb48STom Herbert 12061d24eb48STom Herbert if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 12071d24eb48STom Herbert return -ENOMEM; 12081d24eb48STom Herbert 12091d24eb48STom Herbert index = get_netdev_queue_index(queue); 12101d24eb48STom Herbert 1211184c449fSAlexander Duyck if (dev->num_tc) { 1212184c449fSAlexander Duyck num_tc = dev->num_tc; 1213184c449fSAlexander Duyck tc = netdev_txq_to_tc(dev, index); 1214184c449fSAlexander Duyck if (tc < 0) 1215184c449fSAlexander Duyck return -EINVAL; 1216184c449fSAlexander Duyck } 1217184c449fSAlexander Duyck 12181d24eb48STom Herbert rcu_read_lock(); 12191d24eb48STom Herbert dev_maps = rcu_dereference(dev->xps_maps); 12201d24eb48STom Herbert if (dev_maps) { 1221184c449fSAlexander Duyck for_each_possible_cpu(cpu) { 1222184c449fSAlexander Duyck int i, tci = cpu * num_tc + tc; 1223184c449fSAlexander Duyck struct xps_map *map; 1224184c449fSAlexander Duyck 1225184c449fSAlexander Duyck map = rcu_dereference(dev_maps->cpu_map[tci]); 1226184c449fSAlexander Duyck if (!map) 1227184c449fSAlexander Duyck continue; 1228184c449fSAlexander Duyck 1229184c449fSAlexander Duyck for (i = map->len; i--;) { 1230184c449fSAlexander Duyck if (map->queues[i] == index) { 1231184c449fSAlexander Duyck cpumask_set_cpu(cpu, mask); 12321d24eb48STom Herbert break; 12331d24eb48STom Herbert } 12341d24eb48STom Herbert } 12351d24eb48STom Herbert } 12361d24eb48STom Herbert } 12371d24eb48STom Herbert rcu_read_unlock(); 12381d24eb48STom Herbert 1239f0906827STejun Heo len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask)); 12401d24eb48STom Herbert free_cpumask_var(mask); 1241f0906827STejun Heo return len < PAGE_SIZE ? len : -EINVAL; 12421d24eb48STom Herbert } 12431d24eb48STom Herbert 12442b9c7581Sstephen hemminger static ssize_t xps_cpus_store(struct netdev_queue *queue, 12451d24eb48STom Herbert const char *buf, size_t len) 12461d24eb48STom Herbert { 12471d24eb48STom Herbert struct net_device *dev = queue->dev; 12481d24eb48STom Herbert unsigned long index; 1249537c00deSAlexander Duyck cpumask_var_t mask; 1250537c00deSAlexander Duyck int err; 12511d24eb48STom Herbert 12521d24eb48STom Herbert if (!capable(CAP_NET_ADMIN)) 12531d24eb48STom Herbert return -EPERM; 12541d24eb48STom Herbert 12551d24eb48STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 12561d24eb48STom Herbert return -ENOMEM; 12571d24eb48STom Herbert 12581d24eb48STom Herbert index = get_netdev_queue_index(queue); 12591d24eb48STom Herbert 12601d24eb48STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 12611d24eb48STom Herbert if (err) { 12621d24eb48STom Herbert free_cpumask_var(mask); 12631d24eb48STom Herbert return err; 12641d24eb48STom Herbert } 12651d24eb48STom Herbert 1266537c00deSAlexander Duyck err = netif_set_xps_queue(dev, mask, index); 12671d24eb48STom Herbert 12681d24eb48STom Herbert free_cpumask_var(mask); 12691d24eb48STom Herbert 1270537c00deSAlexander Duyck return err ? : len; 12711d24eb48STom Herbert } 12721d24eb48STom Herbert 12732b9c7581Sstephen hemminger static struct netdev_queue_attribute xps_cpus_attribute __ro_after_init 12742b9c7581Sstephen hemminger = __ATTR_RW(xps_cpus); 1275ccf5ff69Sdavid decotigny #endif /* CONFIG_XPS */ 12761d24eb48STom Herbert 12772b9c7581Sstephen hemminger static struct attribute *netdev_queue_default_attrs[] __ro_after_init = { 1278ccf5ff69Sdavid decotigny &queue_trans_timeout.attr, 12798d059b0fSAlexander Duyck &queue_traffic_class.attr, 1280ccf5ff69Sdavid decotigny #ifdef CONFIG_XPS 12811d24eb48STom Herbert &xps_cpus_attribute.attr, 1282822b3b2eSJohn Fastabend &queue_tx_maxrate.attr, 1283ccf5ff69Sdavid decotigny #endif 12841d24eb48STom Herbert NULL 12851d24eb48STom Herbert }; 12861d24eb48STom Herbert 12871d24eb48STom Herbert static void netdev_queue_release(struct kobject *kobj) 12881d24eb48STom Herbert { 12891d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 12901d24eb48STom Herbert 12911d24eb48STom Herbert memset(kobj, 0, sizeof(*kobj)); 12921d24eb48STom Herbert dev_put(queue->dev); 12931d24eb48STom Herbert } 12941d24eb48STom Herbert 129582ef3d5dSWeilong Chen static const void *netdev_queue_namespace(struct kobject *kobj) 129682ef3d5dSWeilong Chen { 129782ef3d5dSWeilong Chen struct netdev_queue *queue = to_netdev_queue(kobj); 129882ef3d5dSWeilong Chen struct device *dev = &queue->dev->dev; 129982ef3d5dSWeilong Chen const void *ns = NULL; 130082ef3d5dSWeilong Chen 130182ef3d5dSWeilong Chen if (dev->class && dev->class->ns_type) 130282ef3d5dSWeilong Chen ns = dev->class->namespace(dev); 130382ef3d5dSWeilong Chen 130482ef3d5dSWeilong Chen return ns; 130582ef3d5dSWeilong Chen } 130682ef3d5dSWeilong Chen 13072b9c7581Sstephen hemminger static struct kobj_type netdev_queue_ktype __ro_after_init = { 13081d24eb48STom Herbert .sysfs_ops = &netdev_queue_sysfs_ops, 13091d24eb48STom Herbert .release = netdev_queue_release, 13101d24eb48STom Herbert .default_attrs = netdev_queue_default_attrs, 131182ef3d5dSWeilong Chen .namespace = netdev_queue_namespace, 13121d24eb48STom Herbert }; 13131d24eb48STom Herbert 13146b53dafeSWANG Cong static int netdev_queue_add_kobject(struct net_device *dev, int index) 13151d24eb48STom Herbert { 13166b53dafeSWANG Cong struct netdev_queue *queue = dev->_tx + index; 13171d24eb48STom Herbert struct kobject *kobj = &queue->kobj; 13181d24eb48STom Herbert int error = 0; 13191d24eb48STom Herbert 13206b53dafeSWANG Cong kobj->kset = dev->queues_kset; 13211d24eb48STom Herbert error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, 13221d24eb48STom Herbert "tx-%u", index); 1323114cf580STom Herbert if (error) 1324d0d66837Sstephen hemminger return error; 1325114cf580STom Herbert 1326114cf580STom Herbert #ifdef CONFIG_BQL 1327114cf580STom Herbert error = sysfs_create_group(kobj, &dql_group); 1328d0d66837Sstephen hemminger if (error) { 1329d0d66837Sstephen hemminger kobject_put(kobj); 1330d0d66837Sstephen hemminger return error; 1331d0d66837Sstephen hemminger } 1332114cf580STom Herbert #endif 13331d24eb48STom Herbert 13341d24eb48STom Herbert kobject_uevent(kobj, KOBJ_ADD); 13351d24eb48STom Herbert dev_hold(queue->dev); 13361d24eb48STom Herbert 1337114cf580STom Herbert return 0; 13381d24eb48STom Herbert } 1339ccf5ff69Sdavid decotigny #endif /* CONFIG_SYSFS */ 13401d24eb48STom Herbert 13411d24eb48STom Herbert int 13426b53dafeSWANG Cong netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) 13431d24eb48STom Herbert { 1344ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 13451d24eb48STom Herbert int i; 13461d24eb48STom Herbert int error = 0; 13471d24eb48STom Herbert 13481d24eb48STom Herbert for (i = old_num; i < new_num; i++) { 13496b53dafeSWANG Cong error = netdev_queue_add_kobject(dev, i); 13501d24eb48STom Herbert if (error) { 13511d24eb48STom Herbert new_num = old_num; 13521d24eb48STom Herbert break; 13531d24eb48STom Herbert } 13541d24eb48STom Herbert } 13551d24eb48STom Herbert 1356114cf580STom Herbert while (--i >= new_num) { 13576b53dafeSWANG Cong struct netdev_queue *queue = dev->_tx + i; 1358114cf580STom Herbert 135991864f58SAndrey Vagin if (!atomic_read(&dev_net(dev)->count)) 1360002d8a1aSAndrey Vagin queue->kobj.uevent_suppress = 1; 1361114cf580STom Herbert #ifdef CONFIG_BQL 1362114cf580STom Herbert sysfs_remove_group(&queue->kobj, &dql_group); 1363114cf580STom Herbert #endif 1364114cf580STom Herbert kobject_put(&queue->kobj); 1365114cf580STom Herbert } 13661d24eb48STom Herbert 13671d24eb48STom Herbert return error; 1368bf264145STom Herbert #else 1369bf264145STom Herbert return 0; 1370ccf5ff69Sdavid decotigny #endif /* CONFIG_SYSFS */ 13711d24eb48STom Herbert } 13721d24eb48STom Herbert 13736b53dafeSWANG Cong static int register_queue_kobjects(struct net_device *dev) 13741d24eb48STom Herbert { 1375bf264145STom Herbert int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; 13761d24eb48STom Herbert 1377ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 13786b53dafeSWANG Cong dev->queues_kset = kset_create_and_add("queues", 13796b53dafeSWANG Cong NULL, &dev->dev.kobj); 13806b53dafeSWANG Cong if (!dev->queues_kset) 138162fe0b40SBen Hutchings return -ENOMEM; 13826b53dafeSWANG Cong real_rx = dev->real_num_rx_queues; 1383bf264145STom Herbert #endif 13846b53dafeSWANG Cong real_tx = dev->real_num_tx_queues; 1385bf264145STom Herbert 13866b53dafeSWANG Cong error = net_rx_queue_update_kobjects(dev, 0, real_rx); 13871d24eb48STom Herbert if (error) 13881d24eb48STom Herbert goto error; 1389bf264145STom Herbert rxq = real_rx; 13901d24eb48STom Herbert 13916b53dafeSWANG Cong error = netdev_queue_update_kobjects(dev, 0, real_tx); 13921d24eb48STom Herbert if (error) 13931d24eb48STom Herbert goto error; 1394bf264145STom Herbert txq = real_tx; 13951d24eb48STom Herbert 13961d24eb48STom Herbert return 0; 13971d24eb48STom Herbert 13981d24eb48STom Herbert error: 13996b53dafeSWANG Cong netdev_queue_update_kobjects(dev, txq, 0); 14006b53dafeSWANG Cong net_rx_queue_update_kobjects(dev, rxq, 0); 14011d24eb48STom Herbert return error; 140262fe0b40SBen Hutchings } 140362fe0b40SBen Hutchings 14046b53dafeSWANG Cong static void remove_queue_kobjects(struct net_device *dev) 14050a9627f2STom Herbert { 1406bf264145STom Herbert int real_rx = 0, real_tx = 0; 1407bf264145STom Herbert 1408a953be53SMichael Dalton #ifdef CONFIG_SYSFS 14096b53dafeSWANG Cong real_rx = dev->real_num_rx_queues; 1410bf264145STom Herbert #endif 14116b53dafeSWANG Cong real_tx = dev->real_num_tx_queues; 1412bf264145STom Herbert 14136b53dafeSWANG Cong net_rx_queue_update_kobjects(dev, real_rx, 0); 14146b53dafeSWANG Cong netdev_queue_update_kobjects(dev, real_tx, 0); 1415ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 14166b53dafeSWANG Cong kset_unregister(dev->queues_kset); 1417bf264145STom Herbert #endif 14180a9627f2STom Herbert } 1419608b4b95SEric W. Biederman 14207dc5dbc8SEric W. Biederman static bool net_current_may_mount(void) 14217dc5dbc8SEric W. Biederman { 14227dc5dbc8SEric W. Biederman struct net *net = current->nsproxy->net_ns; 14237dc5dbc8SEric W. Biederman 14247dc5dbc8SEric W. Biederman return ns_capable(net->user_ns, CAP_SYS_ADMIN); 14257dc5dbc8SEric W. Biederman } 14267dc5dbc8SEric W. Biederman 1427a685e089SAl Viro static void *net_grab_current_ns(void) 1428608b4b95SEric W. Biederman { 1429a685e089SAl Viro struct net *ns = current->nsproxy->net_ns; 1430a685e089SAl Viro #ifdef CONFIG_NET_NS 1431a685e089SAl Viro if (ns) 1432c122e14dSReshetova, Elena refcount_inc(&ns->passive); 1433a685e089SAl Viro #endif 1434a685e089SAl Viro return ns; 1435608b4b95SEric W. Biederman } 1436608b4b95SEric W. Biederman 1437608b4b95SEric W. Biederman static const void *net_initial_ns(void) 1438608b4b95SEric W. Biederman { 1439608b4b95SEric W. Biederman return &init_net; 1440608b4b95SEric W. Biederman } 1441608b4b95SEric W. Biederman 1442608b4b95SEric W. Biederman static const void *net_netlink_ns(struct sock *sk) 1443608b4b95SEric W. Biederman { 1444608b4b95SEric W. Biederman return sock_net(sk); 1445608b4b95SEric W. Biederman } 1446608b4b95SEric W. Biederman 1447737aec57Sstephen hemminger const struct kobj_ns_type_operations net_ns_type_operations = { 1448608b4b95SEric W. Biederman .type = KOBJ_NS_TYPE_NET, 14497dc5dbc8SEric W. Biederman .current_may_mount = net_current_may_mount, 1450a685e089SAl Viro .grab_current_ns = net_grab_current_ns, 1451608b4b95SEric W. Biederman .netlink_ns = net_netlink_ns, 1452608b4b95SEric W. Biederman .initial_ns = net_initial_ns, 1453a685e089SAl Viro .drop_ns = net_drop_ns, 1454608b4b95SEric W. Biederman }; 145504600794SJohannes Berg EXPORT_SYMBOL_GPL(net_ns_type_operations); 1456608b4b95SEric W. Biederman 14577eff2e7aSKay Sievers static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) 14581da177e4SLinus Torvalds { 145943cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 14607eff2e7aSKay Sievers int retval; 14611da177e4SLinus Torvalds 1462312c004dSKay Sievers /* pass interface to uevent. */ 14637eff2e7aSKay Sievers retval = add_uevent_var(env, "INTERFACE=%s", dev->name); 1464bf62456eSEric Rannaud if (retval) 1465bf62456eSEric Rannaud goto exit; 14661da177e4SLinus Torvalds 1467ca2f37dbSJean Tourrilhes /* pass ifindex to uevent. 1468ca2f37dbSJean Tourrilhes * ifindex is useful as it won't change (interface name may change) 14696648c65eSstephen hemminger * and is what RtNetlink uses natively. 14706648c65eSstephen hemminger */ 14717eff2e7aSKay Sievers retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); 1472ca2f37dbSJean Tourrilhes 1473bf62456eSEric Rannaud exit: 1474bf62456eSEric Rannaud return retval; 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds 14771da177e4SLinus Torvalds /* 14781da177e4SLinus Torvalds * netdev_release -- destroy and free a dead device. 147943cb76d9SGreg Kroah-Hartman * Called when last reference to device kobject is gone. 14801da177e4SLinus Torvalds */ 148143cb76d9SGreg Kroah-Hartman static void netdev_release(struct device *d) 14821da177e4SLinus Torvalds { 148343cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 14841da177e4SLinus Torvalds 14851da177e4SLinus Torvalds BUG_ON(dev->reg_state != NETREG_RELEASED); 14861da177e4SLinus Torvalds 14876c557001SFlorian Westphal /* no need to wait for rcu grace period: 14886c557001SFlorian Westphal * device is dead and about to be freed. 14896c557001SFlorian Westphal */ 14906c557001SFlorian Westphal kfree(rcu_access_pointer(dev->ifalias)); 149174d332c1SEric Dumazet netdev_freemem(dev); 14921da177e4SLinus Torvalds } 14931da177e4SLinus Torvalds 1494608b4b95SEric W. Biederman static const void *net_namespace(struct device *d) 1495608b4b95SEric W. Biederman { 14965c29482dSGeliang Tang struct net_device *dev = to_net_dev(d); 14975c29482dSGeliang Tang 1498608b4b95SEric W. Biederman return dev_net(dev); 1499608b4b95SEric W. Biederman } 1500608b4b95SEric W. Biederman 1501e6d473e6Sstephen hemminger static struct class net_class __ro_after_init = { 15021da177e4SLinus Torvalds .name = "net", 150343cb76d9SGreg Kroah-Hartman .dev_release = netdev_release, 15046be8aeefSGreg Kroah-Hartman .dev_groups = net_class_groups, 150543cb76d9SGreg Kroah-Hartman .dev_uevent = netdev_uevent, 1506608b4b95SEric W. Biederman .ns_type = &net_ns_type_operations, 1507608b4b95SEric W. Biederman .namespace = net_namespace, 15081da177e4SLinus Torvalds }; 15091da177e4SLinus Torvalds 1510aa836df9SFlorian Fainelli #ifdef CONFIG_OF_NET 1511aa836df9SFlorian Fainelli static int of_dev_node_match(struct device *dev, const void *data) 1512aa836df9SFlorian Fainelli { 1513aa836df9SFlorian Fainelli int ret = 0; 1514aa836df9SFlorian Fainelli 1515aa836df9SFlorian Fainelli if (dev->parent) 1516aa836df9SFlorian Fainelli ret = dev->parent->of_node == data; 1517aa836df9SFlorian Fainelli 1518aa836df9SFlorian Fainelli return ret == 0 ? dev->of_node == data : ret; 1519aa836df9SFlorian Fainelli } 1520aa836df9SFlorian Fainelli 15219861f720SRussell King /* 15229861f720SRussell King * of_find_net_device_by_node - lookup the net device for the device node 15239861f720SRussell King * @np: OF device node 15249861f720SRussell King * 15259861f720SRussell King * Looks up the net_device structure corresponding with the device node. 15269861f720SRussell King * If successful, returns a pointer to the net_device with the embedded 15279861f720SRussell King * struct device refcount incremented by one, or NULL on failure. The 15289861f720SRussell King * refcount must be dropped when done with the net_device. 15299861f720SRussell King */ 1530aa836df9SFlorian Fainelli struct net_device *of_find_net_device_by_node(struct device_node *np) 1531aa836df9SFlorian Fainelli { 1532aa836df9SFlorian Fainelli struct device *dev; 1533aa836df9SFlorian Fainelli 1534aa836df9SFlorian Fainelli dev = class_find_device(&net_class, NULL, np, of_dev_node_match); 1535aa836df9SFlorian Fainelli if (!dev) 1536aa836df9SFlorian Fainelli return NULL; 1537aa836df9SFlorian Fainelli 1538aa836df9SFlorian Fainelli return to_net_dev(dev); 1539aa836df9SFlorian Fainelli } 1540aa836df9SFlorian Fainelli EXPORT_SYMBOL(of_find_net_device_by_node); 1541aa836df9SFlorian Fainelli #endif 1542aa836df9SFlorian Fainelli 15439093bbb2SStephen Hemminger /* Delete sysfs entries but hold kobject reference until after all 15449093bbb2SStephen Hemminger * netdev references are gone. 15459093bbb2SStephen Hemminger */ 15466b53dafeSWANG Cong void netdev_unregister_kobject(struct net_device *ndev) 15471da177e4SLinus Torvalds { 15486648c65eSstephen hemminger struct device *dev = &ndev->dev; 15499093bbb2SStephen Hemminger 155091864f58SAndrey Vagin if (!atomic_read(&dev_net(ndev)->count)) 1551002d8a1aSAndrey Vagin dev_set_uevent_suppress(dev, 1); 1552002d8a1aSAndrey Vagin 15539093bbb2SStephen Hemminger kobject_get(&dev->kobj); 15543891845eSEric W. Biederman 15556b53dafeSWANG Cong remove_queue_kobjects(ndev); 15560a9627f2STom Herbert 15579802c8e2SMing Lei pm_runtime_set_memalloc_noio(dev, false); 15589802c8e2SMing Lei 15599093bbb2SStephen Hemminger device_del(dev); 15601da177e4SLinus Torvalds } 15611da177e4SLinus Torvalds 15621da177e4SLinus Torvalds /* Create sysfs entries for network device. */ 15636b53dafeSWANG Cong int netdev_register_kobject(struct net_device *ndev) 15641da177e4SLinus Torvalds { 15656648c65eSstephen hemminger struct device *dev = &ndev->dev; 15666b53dafeSWANG Cong const struct attribute_group **groups = ndev->sysfs_groups; 15670a9627f2STom Herbert int error = 0; 15681da177e4SLinus Torvalds 1569a1b3f594SEric W. Biederman device_initialize(dev); 157043cb76d9SGreg Kroah-Hartman dev->class = &net_class; 15716b53dafeSWANG Cong dev->platform_data = ndev; 157243cb76d9SGreg Kroah-Hartman dev->groups = groups; 15731da177e4SLinus Torvalds 15746b53dafeSWANG Cong dev_set_name(dev, "%s", ndev->name); 15751da177e4SLinus Torvalds 15768b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 15770c509a6cSEric W. Biederman /* Allow for a device specific group */ 15780c509a6cSEric W. Biederman if (*groups) 15790c509a6cSEric W. Biederman groups++; 15801da177e4SLinus Torvalds 15810c509a6cSEric W. Biederman *groups++ = &netstat_group; 158238c1a01cSJohannes Berg 158338c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) 15846b53dafeSWANG Cong if (ndev->ieee80211_ptr) 158538c1a01cSJohannes Berg *groups++ = &wireless_group; 158638c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) 15876b53dafeSWANG Cong else if (ndev->wireless_handlers) 158838c1a01cSJohannes Berg *groups++ = &wireless_group; 158938c1a01cSJohannes Berg #endif 159038c1a01cSJohannes Berg #endif 15918b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 15921da177e4SLinus Torvalds 15930a9627f2STom Herbert error = device_add(dev); 15940a9627f2STom Herbert if (error) 15950a9627f2STom Herbert return error; 15960a9627f2STom Herbert 15976b53dafeSWANG Cong error = register_queue_kobjects(ndev); 15980a9627f2STom Herbert if (error) { 15990a9627f2STom Herbert device_del(dev); 16000a9627f2STom Herbert return error; 16010a9627f2STom Herbert } 16020a9627f2STom Herbert 16039802c8e2SMing Lei pm_runtime_set_memalloc_noio(dev, true); 16049802c8e2SMing Lei 16050a9627f2STom Herbert return error; 16061da177e4SLinus Torvalds } 16071da177e4SLinus Torvalds 1608b793dc5cSstephen hemminger int netdev_class_create_file_ns(const struct class_attribute *class_attr, 160958292cbeSTejun Heo const void *ns) 1610b8a9787eSJay Vosburgh { 161158292cbeSTejun Heo return class_create_file_ns(&net_class, class_attr, ns); 1612b8a9787eSJay Vosburgh } 161358292cbeSTejun Heo EXPORT_SYMBOL(netdev_class_create_file_ns); 1614b8a9787eSJay Vosburgh 1615b793dc5cSstephen hemminger void netdev_class_remove_file_ns(const struct class_attribute *class_attr, 161658292cbeSTejun Heo const void *ns) 1617b8a9787eSJay Vosburgh { 161858292cbeSTejun Heo class_remove_file_ns(&net_class, class_attr, ns); 1619b8a9787eSJay Vosburgh } 162058292cbeSTejun Heo EXPORT_SYMBOL(netdev_class_remove_file_ns); 1621b8a9787eSJay Vosburgh 1622a48d4bb0SDaniel Borkmann int __init netdev_kobject_init(void) 16231da177e4SLinus Torvalds { 1624608b4b95SEric W. Biederman kobj_ns_type_register(&net_ns_type_operations); 16251da177e4SLinus Torvalds return class_register(&net_class); 16261da177e4SLinus Torvalds } 1627