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> 151da177e4SLinus Torvalds #include <linux/if_arp.h> 165a0e3ad6STejun Heo #include <linux/slab.h> 17608b4b95SEric W. Biederman #include <linux/nsproxy.h> 181da177e4SLinus Torvalds #include <net/sock.h> 19608b4b95SEric W. Biederman #include <net/net_namespace.h> 201da177e4SLinus Torvalds #include <linux/rtnetlink.h> 21fec5e652STom Herbert #include <linux/vmalloc.h> 22bc3b2d7fSPaul Gortmaker #include <linux/export.h> 23114cf580STom Herbert #include <linux/jiffies.h> 249802c8e2SMing Lei #include <linux/pm_runtime.h> 251da177e4SLinus Torvalds 26342709efSPavel Emelyanov #include "net-sysfs.h" 27342709efSPavel Emelyanov 288b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 291da177e4SLinus Torvalds static const char fmt_hex[] = "%#x\n"; 30d1102b59SDavid S. Miller static const char fmt_long_hex[] = "%#lx\n"; 311da177e4SLinus Torvalds static const char fmt_dec[] = "%d\n"; 328ae6dacaSDavid Decotigny static const char fmt_udec[] = "%u\n"; 331da177e4SLinus Torvalds static const char fmt_ulong[] = "%lu\n"; 34be1f3c2cSBen Hutchings static const char fmt_u64[] = "%llu\n"; 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds static inline int dev_isalive(const struct net_device *dev) 371da177e4SLinus Torvalds { 38fe9925b5SStephen Hemminger return dev->reg_state <= NETREG_REGISTERED; 391da177e4SLinus Torvalds } 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /* use same locking rules as GIF* ioctl's */ 4243cb76d9SGreg Kroah-Hartman static ssize_t netdev_show(const struct device *dev, 4343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 441da177e4SLinus Torvalds ssize_t (*format)(const struct net_device *, char *)) 451da177e4SLinus Torvalds { 466b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 471da177e4SLinus Torvalds ssize_t ret = -EINVAL; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds read_lock(&dev_base_lock); 506b53dafeSWANG Cong if (dev_isalive(ndev)) 516b53dafeSWANG Cong ret = (*format)(ndev, buf); 521da177e4SLinus Torvalds read_unlock(&dev_base_lock); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds return ret; 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* generate a show function for simple field */ 581da177e4SLinus Torvalds #define NETDEVICE_SHOW(field, format_string) \ 596b53dafeSWANG Cong static ssize_t format_##field(const struct net_device *dev, char *buf) \ 601da177e4SLinus Torvalds { \ 616b53dafeSWANG Cong return sprintf(buf, format_string, dev->field); \ 621da177e4SLinus Torvalds } \ 636be8aeefSGreg Kroah-Hartman static ssize_t field##_show(struct device *dev, \ 6443cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 651da177e4SLinus Torvalds { \ 6643cb76d9SGreg Kroah-Hartman return netdev_show(dev, attr, buf, format_##field); \ 676be8aeefSGreg Kroah-Hartman } \ 681da177e4SLinus Torvalds 696be8aeefSGreg Kroah-Hartman #define NETDEVICE_SHOW_RO(field, format_string) \ 706be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(field, format_string); \ 716be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(field) 726be8aeefSGreg Kroah-Hartman 736be8aeefSGreg Kroah-Hartman #define NETDEVICE_SHOW_RW(field, format_string) \ 746be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(field, format_string); \ 756be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(field) 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds /* use same locking and permission rules as SIF* ioctl's */ 7843cb76d9SGreg Kroah-Hartman static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, 791da177e4SLinus Torvalds const char *buf, size_t len, 801da177e4SLinus Torvalds int (*set)(struct net_device *, unsigned long)) 811da177e4SLinus Torvalds { 825e1fccc0SEric W. Biederman struct net_device *netdev = to_net_dev(dev); 835e1fccc0SEric W. Biederman struct net *net = dev_net(netdev); 841da177e4SLinus Torvalds unsigned long new; 851da177e4SLinus Torvalds int ret = -EINVAL; 861da177e4SLinus Torvalds 875e1fccc0SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 881da177e4SLinus Torvalds return -EPERM; 891da177e4SLinus Torvalds 90e1e420c7SShuah Khan ret = kstrtoul(buf, 0, &new); 91e1e420c7SShuah Khan if (ret) 921da177e4SLinus Torvalds goto err; 931da177e4SLinus Torvalds 945a5990d3SStephen Hemminger if (!rtnl_trylock()) 95336ca57cSEric W. Biederman return restart_syscall(); 965a5990d3SStephen Hemminger 975e1fccc0SEric W. Biederman if (dev_isalive(netdev)) { 985e1fccc0SEric W. Biederman if ((ret = (*set)(netdev, new)) == 0) 991da177e4SLinus Torvalds ret = len; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds rtnl_unlock(); 1021da177e4SLinus Torvalds err: 1031da177e4SLinus Torvalds return ret; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 1066be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(dev_id, fmt_hex); 1073f85944fSAmir Vadai NETDEVICE_SHOW_RO(dev_port, fmt_dec); 1086be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(addr_assign_type, fmt_dec); 1096be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(addr_len, fmt_dec); 1106be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(iflink, fmt_dec); 1116be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(ifindex, fmt_dec); 1126be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(type, fmt_dec); 1136be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RO(link_mode, fmt_dec); 1141da177e4SLinus Torvalds 1156b53dafeSWANG Cong static ssize_t format_name_assign_type(const struct net_device *dev, char *buf) 116685343fcSTom Gundersen { 1176b53dafeSWANG Cong return sprintf(buf, fmt_dec, dev->name_assign_type); 118685343fcSTom Gundersen } 119685343fcSTom Gundersen 120685343fcSTom Gundersen static ssize_t name_assign_type_show(struct device *dev, 121685343fcSTom Gundersen struct device_attribute *attr, 122685343fcSTom Gundersen char *buf) 123685343fcSTom Gundersen { 1246b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 125685343fcSTom Gundersen ssize_t ret = -EINVAL; 126685343fcSTom Gundersen 1276b53dafeSWANG Cong if (ndev->name_assign_type != NET_NAME_UNKNOWN) 128685343fcSTom Gundersen ret = netdev_show(dev, attr, buf, format_name_assign_type); 129685343fcSTom Gundersen 130685343fcSTom Gundersen return ret; 131685343fcSTom Gundersen } 132685343fcSTom Gundersen static DEVICE_ATTR_RO(name_assign_type); 133685343fcSTom Gundersen 1341da177e4SLinus Torvalds /* use same locking rules as GIFHWADDR ioctl's */ 1356be8aeefSGreg Kroah-Hartman static ssize_t address_show(struct device *dev, struct device_attribute *attr, 13643cb76d9SGreg Kroah-Hartman char *buf) 1371da177e4SLinus Torvalds { 1386b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 1391da177e4SLinus Torvalds ssize_t ret = -EINVAL; 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds read_lock(&dev_base_lock); 1426b53dafeSWANG Cong if (dev_isalive(ndev)) 1436b53dafeSWANG Cong ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len); 1441da177e4SLinus Torvalds read_unlock(&dev_base_lock); 1451da177e4SLinus Torvalds return ret; 1461da177e4SLinus Torvalds } 1476be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(address); 1481da177e4SLinus Torvalds 1496be8aeefSGreg Kroah-Hartman static ssize_t broadcast_show(struct device *dev, 15043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1511da177e4SLinus Torvalds { 1526b53dafeSWANG Cong struct net_device *ndev = to_net_dev(dev); 1536b53dafeSWANG Cong if (dev_isalive(ndev)) 1546b53dafeSWANG Cong return sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len); 1551da177e4SLinus Torvalds return -EINVAL; 1561da177e4SLinus Torvalds } 1576be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(broadcast); 1581da177e4SLinus Torvalds 1596b53dafeSWANG Cong static int change_carrier(struct net_device *dev, unsigned long new_carrier) 160fdae0fdeSJiri Pirko { 1616b53dafeSWANG Cong if (!netif_running(dev)) 162fdae0fdeSJiri Pirko return -EINVAL; 1636b53dafeSWANG Cong return dev_change_carrier(dev, (bool) new_carrier); 164fdae0fdeSJiri Pirko } 165fdae0fdeSJiri Pirko 1666be8aeefSGreg Kroah-Hartman static ssize_t carrier_store(struct device *dev, struct device_attribute *attr, 167fdae0fdeSJiri Pirko const char *buf, size_t len) 168fdae0fdeSJiri Pirko { 169fdae0fdeSJiri Pirko return netdev_store(dev, attr, buf, len, change_carrier); 170fdae0fdeSJiri Pirko } 171fdae0fdeSJiri Pirko 1726be8aeefSGreg Kroah-Hartman static ssize_t carrier_show(struct device *dev, 17343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1741da177e4SLinus Torvalds { 1751da177e4SLinus Torvalds struct net_device *netdev = to_net_dev(dev); 1761da177e4SLinus Torvalds if (netif_running(netdev)) { 1771da177e4SLinus Torvalds return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds return -EINVAL; 1801da177e4SLinus Torvalds } 1816be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(carrier); 1821da177e4SLinus Torvalds 1836be8aeefSGreg Kroah-Hartman static ssize_t speed_show(struct device *dev, 184d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 185d519e17eSAndy Gospodarek { 186d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 187d519e17eSAndy Gospodarek int ret = -EINVAL; 188d519e17eSAndy Gospodarek 189d519e17eSAndy Gospodarek if (!rtnl_trylock()) 190d519e17eSAndy Gospodarek return restart_syscall(); 191d519e17eSAndy Gospodarek 1928ae6dacaSDavid Decotigny if (netif_running(netdev)) { 1938ae6dacaSDavid Decotigny struct ethtool_cmd cmd; 1944bc71cb9SJiri Pirko if (!__ethtool_get_settings(netdev, &cmd)) 1958ae6dacaSDavid Decotigny ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd)); 196d519e17eSAndy Gospodarek } 197d519e17eSAndy Gospodarek rtnl_unlock(); 198d519e17eSAndy Gospodarek return ret; 199d519e17eSAndy Gospodarek } 2006be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(speed); 201d519e17eSAndy Gospodarek 2026be8aeefSGreg Kroah-Hartman static ssize_t duplex_show(struct device *dev, 203d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 204d519e17eSAndy Gospodarek { 205d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 206d519e17eSAndy Gospodarek int ret = -EINVAL; 207d519e17eSAndy Gospodarek 208d519e17eSAndy Gospodarek if (!rtnl_trylock()) 209d519e17eSAndy Gospodarek return restart_syscall(); 210d519e17eSAndy Gospodarek 2118ae6dacaSDavid Decotigny if (netif_running(netdev)) { 2128ae6dacaSDavid Decotigny struct ethtool_cmd cmd; 213c6c13965SNikolay Aleksandrov if (!__ethtool_get_settings(netdev, &cmd)) { 214c6c13965SNikolay Aleksandrov const char *duplex; 215c6c13965SNikolay Aleksandrov switch (cmd.duplex) { 216c6c13965SNikolay Aleksandrov case DUPLEX_HALF: 217c6c13965SNikolay Aleksandrov duplex = "half"; 218c6c13965SNikolay Aleksandrov break; 219c6c13965SNikolay Aleksandrov case DUPLEX_FULL: 220c6c13965SNikolay Aleksandrov duplex = "full"; 221c6c13965SNikolay Aleksandrov break; 222c6c13965SNikolay Aleksandrov default: 223c6c13965SNikolay Aleksandrov duplex = "unknown"; 224c6c13965SNikolay Aleksandrov break; 225c6c13965SNikolay Aleksandrov } 226c6c13965SNikolay Aleksandrov ret = sprintf(buf, "%s\n", duplex); 227c6c13965SNikolay Aleksandrov } 228d519e17eSAndy Gospodarek } 229d519e17eSAndy Gospodarek rtnl_unlock(); 230d519e17eSAndy Gospodarek return ret; 231d519e17eSAndy Gospodarek } 2326be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(duplex); 233d519e17eSAndy Gospodarek 2346be8aeefSGreg Kroah-Hartman static ssize_t dormant_show(struct device *dev, 23543cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 236b00055aaSStefan Rompf { 237b00055aaSStefan Rompf struct net_device *netdev = to_net_dev(dev); 238b00055aaSStefan Rompf 239b00055aaSStefan Rompf if (netif_running(netdev)) 240b00055aaSStefan Rompf return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); 241b00055aaSStefan Rompf 242b00055aaSStefan Rompf return -EINVAL; 243b00055aaSStefan Rompf } 2446be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(dormant); 245b00055aaSStefan Rompf 24636cbd3dcSJan Engelhardt static const char *const operstates[] = { 247b00055aaSStefan Rompf "unknown", 248b00055aaSStefan Rompf "notpresent", /* currently unused */ 249b00055aaSStefan Rompf "down", 250b00055aaSStefan Rompf "lowerlayerdown", 251b00055aaSStefan Rompf "testing", /* currently unused */ 252b00055aaSStefan Rompf "dormant", 253b00055aaSStefan Rompf "up" 254b00055aaSStefan Rompf }; 255b00055aaSStefan Rompf 2566be8aeefSGreg Kroah-Hartman static ssize_t operstate_show(struct device *dev, 25743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 258b00055aaSStefan Rompf { 259b00055aaSStefan Rompf const struct net_device *netdev = to_net_dev(dev); 260b00055aaSStefan Rompf unsigned char operstate; 261b00055aaSStefan Rompf 262b00055aaSStefan Rompf read_lock(&dev_base_lock); 263b00055aaSStefan Rompf operstate = netdev->operstate; 264b00055aaSStefan Rompf if (!netif_running(netdev)) 265b00055aaSStefan Rompf operstate = IF_OPER_DOWN; 266b00055aaSStefan Rompf read_unlock(&dev_base_lock); 267b00055aaSStefan Rompf 268e3a5cd9eSAdrian Bunk if (operstate >= ARRAY_SIZE(operstates)) 269b00055aaSStefan Rompf return -EINVAL; /* should not happen */ 270b00055aaSStefan Rompf 271b00055aaSStefan Rompf return sprintf(buf, "%s\n", operstates[operstate]); 272b00055aaSStefan Rompf } 2736be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(operstate); 274b00055aaSStefan Rompf 2752d3b479dSdavid decotigny static ssize_t carrier_changes_show(struct device *dev, 2762d3b479dSdavid decotigny struct device_attribute *attr, 2772d3b479dSdavid decotigny char *buf) 2782d3b479dSdavid decotigny { 2792d3b479dSdavid decotigny struct net_device *netdev = to_net_dev(dev); 2802d3b479dSdavid decotigny return sprintf(buf, fmt_dec, 2812d3b479dSdavid decotigny atomic_read(&netdev->carrier_changes)); 2822d3b479dSdavid decotigny } 2832d3b479dSdavid decotigny static DEVICE_ATTR_RO(carrier_changes); 2842d3b479dSdavid decotigny 2851da177e4SLinus Torvalds /* read-write attributes */ 2861da177e4SLinus Torvalds 2876b53dafeSWANG Cong static int change_mtu(struct net_device *dev, unsigned long new_mtu) 2881da177e4SLinus Torvalds { 2896b53dafeSWANG Cong return dev_set_mtu(dev, (int) new_mtu); 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds 2926be8aeefSGreg Kroah-Hartman static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, 29343cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2941da177e4SLinus Torvalds { 29543cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_mtu); 2961da177e4SLinus Torvalds } 2976be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(mtu, fmt_dec); 2981da177e4SLinus Torvalds 2996b53dafeSWANG Cong static int change_flags(struct net_device *dev, unsigned long new_flags) 3001da177e4SLinus Torvalds { 3016b53dafeSWANG Cong return dev_change_flags(dev, (unsigned int) new_flags); 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds 3046be8aeefSGreg Kroah-Hartman static ssize_t flags_store(struct device *dev, struct device_attribute *attr, 30543cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3061da177e4SLinus Torvalds { 30743cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_flags); 3081da177e4SLinus Torvalds } 3096be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(flags, fmt_hex); 3101da177e4SLinus Torvalds 3116b53dafeSWANG Cong static int change_tx_queue_len(struct net_device *dev, unsigned long new_len) 3121da177e4SLinus Torvalds { 3136b53dafeSWANG Cong dev->tx_queue_len = new_len; 3141da177e4SLinus Torvalds return 0; 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 3176be8aeefSGreg Kroah-Hartman static ssize_t tx_queue_len_store(struct device *dev, 31843cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 31943cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 3201da177e4SLinus Torvalds { 3215e1fccc0SEric W. Biederman if (!capable(CAP_NET_ADMIN)) 3225e1fccc0SEric W. Biederman return -EPERM; 3235e1fccc0SEric W. Biederman 32443cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_tx_queue_len); 3251da177e4SLinus Torvalds } 3266be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW_RW(tx_queue_len, fmt_ulong); 3271da177e4SLinus Torvalds 3283b47d303SEric Dumazet static int change_gro_flush_timeout(struct net_device *dev, unsigned long val) 3293b47d303SEric Dumazet { 3303b47d303SEric Dumazet dev->gro_flush_timeout = val; 3313b47d303SEric Dumazet return 0; 3323b47d303SEric Dumazet } 3333b47d303SEric Dumazet 3343b47d303SEric Dumazet static ssize_t gro_flush_timeout_store(struct device *dev, 3353b47d303SEric Dumazet struct device_attribute *attr, 3363b47d303SEric Dumazet const char *buf, size_t len) 3373b47d303SEric Dumazet { 3383b47d303SEric Dumazet if (!capable(CAP_NET_ADMIN)) 3393b47d303SEric Dumazet return -EPERM; 3403b47d303SEric Dumazet 3413b47d303SEric Dumazet return netdev_store(dev, attr, buf, len, change_gro_flush_timeout); 3423b47d303SEric Dumazet } 3433b47d303SEric Dumazet NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong); 3443b47d303SEric Dumazet 3456be8aeefSGreg Kroah-Hartman static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr, 3460b815a1aSStephen Hemminger const char *buf, size_t len) 3470b815a1aSStephen Hemminger { 3480b815a1aSStephen Hemminger struct net_device *netdev = to_net_dev(dev); 3495e1fccc0SEric W. Biederman struct net *net = dev_net(netdev); 3500b815a1aSStephen Hemminger size_t count = len; 3510b815a1aSStephen Hemminger ssize_t ret; 3520b815a1aSStephen Hemminger 3535e1fccc0SEric W. Biederman if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 3540b815a1aSStephen Hemminger return -EPERM; 3550b815a1aSStephen Hemminger 3560b815a1aSStephen Hemminger /* ignore trailing newline */ 3570b815a1aSStephen Hemminger if (len > 0 && buf[len - 1] == '\n') 3580b815a1aSStephen Hemminger --count; 3590b815a1aSStephen Hemminger 360336ca57cSEric W. Biederman if (!rtnl_trylock()) 361336ca57cSEric W. Biederman return restart_syscall(); 3620b815a1aSStephen Hemminger ret = dev_set_alias(netdev, buf, count); 3630b815a1aSStephen Hemminger rtnl_unlock(); 3640b815a1aSStephen Hemminger 3650b815a1aSStephen Hemminger return ret < 0 ? ret : len; 3660b815a1aSStephen Hemminger } 3670b815a1aSStephen Hemminger 3686be8aeefSGreg Kroah-Hartman static ssize_t ifalias_show(struct device *dev, 3690b815a1aSStephen Hemminger struct device_attribute *attr, char *buf) 3700b815a1aSStephen Hemminger { 3710b815a1aSStephen Hemminger const struct net_device *netdev = to_net_dev(dev); 3720b815a1aSStephen Hemminger ssize_t ret = 0; 3730b815a1aSStephen Hemminger 374336ca57cSEric W. Biederman if (!rtnl_trylock()) 375336ca57cSEric W. Biederman return restart_syscall(); 3760b815a1aSStephen Hemminger if (netdev->ifalias) 3770b815a1aSStephen Hemminger ret = sprintf(buf, "%s\n", netdev->ifalias); 3780b815a1aSStephen Hemminger rtnl_unlock(); 3790b815a1aSStephen Hemminger return ret; 3800b815a1aSStephen Hemminger } 3816be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RW(ifalias); 382a512b92bSVlad Dogaru 3836b53dafeSWANG Cong static int change_group(struct net_device *dev, unsigned long new_group) 384a512b92bSVlad Dogaru { 3856b53dafeSWANG Cong dev_set_group(dev, (int) new_group); 386a512b92bSVlad Dogaru return 0; 387a512b92bSVlad Dogaru } 388a512b92bSVlad Dogaru 3896be8aeefSGreg Kroah-Hartman static ssize_t group_store(struct device *dev, struct device_attribute *attr, 390a512b92bSVlad Dogaru const char *buf, size_t len) 391a512b92bSVlad Dogaru { 392a512b92bSVlad Dogaru return netdev_store(dev, attr, buf, len, change_group); 393a512b92bSVlad Dogaru } 3946be8aeefSGreg Kroah-Hartman NETDEVICE_SHOW(group, fmt_dec); 3956be8aeefSGreg Kroah-Hartman static DEVICE_ATTR(netdev_group, S_IRUGO | S_IWUSR, group_show, group_store); 396a512b92bSVlad Dogaru 397cc998ff8SLinus Torvalds static ssize_t phys_port_id_show(struct device *dev, 398ff80e519SJiri Pirko struct device_attribute *attr, char *buf) 399ff80e519SJiri Pirko { 400ff80e519SJiri Pirko struct net_device *netdev = to_net_dev(dev); 401ff80e519SJiri Pirko ssize_t ret = -EINVAL; 402ff80e519SJiri Pirko 403ff80e519SJiri Pirko if (!rtnl_trylock()) 404ff80e519SJiri Pirko return restart_syscall(); 405ff80e519SJiri Pirko 406ff80e519SJiri Pirko if (dev_isalive(netdev)) { 407ff80e519SJiri Pirko struct netdev_phys_port_id ppid; 408ff80e519SJiri Pirko 409ff80e519SJiri Pirko ret = dev_get_phys_port_id(netdev, &ppid); 410ff80e519SJiri Pirko if (!ret) 411ff80e519SJiri Pirko ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); 412ff80e519SJiri Pirko } 413ff80e519SJiri Pirko rtnl_unlock(); 414ff80e519SJiri Pirko 415ff80e519SJiri Pirko return ret; 416ff80e519SJiri Pirko } 417cc998ff8SLinus Torvalds static DEVICE_ATTR_RO(phys_port_id); 418ff80e519SJiri Pirko 4196be8aeefSGreg Kroah-Hartman static struct attribute *net_class_attrs[] = { 4206be8aeefSGreg Kroah-Hartman &dev_attr_netdev_group.attr, 4216be8aeefSGreg Kroah-Hartman &dev_attr_type.attr, 4226be8aeefSGreg Kroah-Hartman &dev_attr_dev_id.attr, 4233f85944fSAmir Vadai &dev_attr_dev_port.attr, 4246be8aeefSGreg Kroah-Hartman &dev_attr_iflink.attr, 4256be8aeefSGreg Kroah-Hartman &dev_attr_ifindex.attr, 426685343fcSTom Gundersen &dev_attr_name_assign_type.attr, 4276be8aeefSGreg Kroah-Hartman &dev_attr_addr_assign_type.attr, 4286be8aeefSGreg Kroah-Hartman &dev_attr_addr_len.attr, 4296be8aeefSGreg Kroah-Hartman &dev_attr_link_mode.attr, 4306be8aeefSGreg Kroah-Hartman &dev_attr_address.attr, 4316be8aeefSGreg Kroah-Hartman &dev_attr_broadcast.attr, 4326be8aeefSGreg Kroah-Hartman &dev_attr_speed.attr, 4336be8aeefSGreg Kroah-Hartman &dev_attr_duplex.attr, 4346be8aeefSGreg Kroah-Hartman &dev_attr_dormant.attr, 4356be8aeefSGreg Kroah-Hartman &dev_attr_operstate.attr, 4362d3b479dSdavid decotigny &dev_attr_carrier_changes.attr, 4376be8aeefSGreg Kroah-Hartman &dev_attr_ifalias.attr, 4386be8aeefSGreg Kroah-Hartman &dev_attr_carrier.attr, 4396be8aeefSGreg Kroah-Hartman &dev_attr_mtu.attr, 4406be8aeefSGreg Kroah-Hartman &dev_attr_flags.attr, 4416be8aeefSGreg Kroah-Hartman &dev_attr_tx_queue_len.attr, 4423b47d303SEric Dumazet &dev_attr_gro_flush_timeout.attr, 443cc998ff8SLinus Torvalds &dev_attr_phys_port_id.attr, 4446be8aeefSGreg Kroah-Hartman NULL, 4451da177e4SLinus Torvalds }; 4466be8aeefSGreg Kroah-Hartman ATTRIBUTE_GROUPS(net_class); 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds /* Show a given an attribute in the statistics group */ 44943cb76d9SGreg Kroah-Hartman static ssize_t netstat_show(const struct device *d, 45043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 4511da177e4SLinus Torvalds unsigned long offset) 4521da177e4SLinus Torvalds { 45343cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 4541da177e4SLinus Torvalds ssize_t ret = -EINVAL; 4551da177e4SLinus Torvalds 456be1f3c2cSBen Hutchings WARN_ON(offset > sizeof(struct rtnl_link_stats64) || 457be1f3c2cSBen Hutchings offset % sizeof(u64) != 0); 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds read_lock(&dev_base_lock); 46096e74088SPavel Emelyanov if (dev_isalive(dev)) { 46128172739SEric Dumazet struct rtnl_link_stats64 temp; 46228172739SEric Dumazet const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); 46328172739SEric Dumazet 464be1f3c2cSBen Hutchings ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *) stats) + offset)); 46596e74088SPavel Emelyanov } 4661da177e4SLinus Torvalds read_unlock(&dev_base_lock); 4671da177e4SLinus Torvalds return ret; 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds /* generate a read-only statistics attribute */ 4711da177e4SLinus Torvalds #define NETSTAT_ENTRY(name) \ 4726be8aeefSGreg Kroah-Hartman static ssize_t name##_show(struct device *d, \ 47343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 4741da177e4SLinus Torvalds { \ 47543cb76d9SGreg Kroah-Hartman return netstat_show(d, attr, buf, \ 476be1f3c2cSBen Hutchings offsetof(struct rtnl_link_stats64, name)); \ 4771da177e4SLinus Torvalds } \ 4786be8aeefSGreg Kroah-Hartman static DEVICE_ATTR_RO(name) 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds NETSTAT_ENTRY(rx_packets); 4811da177e4SLinus Torvalds NETSTAT_ENTRY(tx_packets); 4821da177e4SLinus Torvalds NETSTAT_ENTRY(rx_bytes); 4831da177e4SLinus Torvalds NETSTAT_ENTRY(tx_bytes); 4841da177e4SLinus Torvalds NETSTAT_ENTRY(rx_errors); 4851da177e4SLinus Torvalds NETSTAT_ENTRY(tx_errors); 4861da177e4SLinus Torvalds NETSTAT_ENTRY(rx_dropped); 4871da177e4SLinus Torvalds NETSTAT_ENTRY(tx_dropped); 4881da177e4SLinus Torvalds NETSTAT_ENTRY(multicast); 4891da177e4SLinus Torvalds NETSTAT_ENTRY(collisions); 4901da177e4SLinus Torvalds NETSTAT_ENTRY(rx_length_errors); 4911da177e4SLinus Torvalds NETSTAT_ENTRY(rx_over_errors); 4921da177e4SLinus Torvalds NETSTAT_ENTRY(rx_crc_errors); 4931da177e4SLinus Torvalds NETSTAT_ENTRY(rx_frame_errors); 4941da177e4SLinus Torvalds NETSTAT_ENTRY(rx_fifo_errors); 4951da177e4SLinus Torvalds NETSTAT_ENTRY(rx_missed_errors); 4961da177e4SLinus Torvalds NETSTAT_ENTRY(tx_aborted_errors); 4971da177e4SLinus Torvalds NETSTAT_ENTRY(tx_carrier_errors); 4981da177e4SLinus Torvalds NETSTAT_ENTRY(tx_fifo_errors); 4991da177e4SLinus Torvalds NETSTAT_ENTRY(tx_heartbeat_errors); 5001da177e4SLinus Torvalds NETSTAT_ENTRY(tx_window_errors); 5011da177e4SLinus Torvalds NETSTAT_ENTRY(rx_compressed); 5021da177e4SLinus Torvalds NETSTAT_ENTRY(tx_compressed); 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds static struct attribute *netstat_attrs[] = { 50543cb76d9SGreg Kroah-Hartman &dev_attr_rx_packets.attr, 50643cb76d9SGreg Kroah-Hartman &dev_attr_tx_packets.attr, 50743cb76d9SGreg Kroah-Hartman &dev_attr_rx_bytes.attr, 50843cb76d9SGreg Kroah-Hartman &dev_attr_tx_bytes.attr, 50943cb76d9SGreg Kroah-Hartman &dev_attr_rx_errors.attr, 51043cb76d9SGreg Kroah-Hartman &dev_attr_tx_errors.attr, 51143cb76d9SGreg Kroah-Hartman &dev_attr_rx_dropped.attr, 51243cb76d9SGreg Kroah-Hartman &dev_attr_tx_dropped.attr, 51343cb76d9SGreg Kroah-Hartman &dev_attr_multicast.attr, 51443cb76d9SGreg Kroah-Hartman &dev_attr_collisions.attr, 51543cb76d9SGreg Kroah-Hartman &dev_attr_rx_length_errors.attr, 51643cb76d9SGreg Kroah-Hartman &dev_attr_rx_over_errors.attr, 51743cb76d9SGreg Kroah-Hartman &dev_attr_rx_crc_errors.attr, 51843cb76d9SGreg Kroah-Hartman &dev_attr_rx_frame_errors.attr, 51943cb76d9SGreg Kroah-Hartman &dev_attr_rx_fifo_errors.attr, 52043cb76d9SGreg Kroah-Hartman &dev_attr_rx_missed_errors.attr, 52143cb76d9SGreg Kroah-Hartman &dev_attr_tx_aborted_errors.attr, 52243cb76d9SGreg Kroah-Hartman &dev_attr_tx_carrier_errors.attr, 52343cb76d9SGreg Kroah-Hartman &dev_attr_tx_fifo_errors.attr, 52443cb76d9SGreg Kroah-Hartman &dev_attr_tx_heartbeat_errors.attr, 52543cb76d9SGreg Kroah-Hartman &dev_attr_tx_window_errors.attr, 52643cb76d9SGreg Kroah-Hartman &dev_attr_rx_compressed.attr, 52743cb76d9SGreg Kroah-Hartman &dev_attr_tx_compressed.attr, 5281da177e4SLinus Torvalds NULL 5291da177e4SLinus Torvalds }; 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds static struct attribute_group netstat_group = { 5331da177e4SLinus Torvalds .name = "statistics", 5341da177e4SLinus Torvalds .attrs = netstat_attrs, 5351da177e4SLinus Torvalds }; 53638c1a01cSJohannes Berg 53738c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) 53838c1a01cSJohannes Berg static struct attribute *wireless_attrs[] = { 53938c1a01cSJohannes Berg NULL 54038c1a01cSJohannes Berg }; 54138c1a01cSJohannes Berg 54238c1a01cSJohannes Berg static struct attribute_group wireless_group = { 54338c1a01cSJohannes Berg .name = "wireless", 54438c1a01cSJohannes Berg .attrs = wireless_attrs, 54538c1a01cSJohannes Berg }; 54638c1a01cSJohannes Berg #endif 5476be8aeefSGreg Kroah-Hartman 5486be8aeefSGreg Kroah-Hartman #else /* CONFIG_SYSFS */ 5496be8aeefSGreg Kroah-Hartman #define net_class_groups NULL 550d6523ddfSEric W. Biederman #endif /* CONFIG_SYSFS */ 5511da177e4SLinus Torvalds 552a953be53SMichael Dalton #ifdef CONFIG_SYSFS 5530a9627f2STom Herbert #define to_rx_queue_attr(_attr) container_of(_attr, \ 5540a9627f2STom Herbert struct rx_queue_attribute, attr) 5550a9627f2STom Herbert 5560a9627f2STom Herbert #define to_rx_queue(obj) container_of(obj, struct netdev_rx_queue, kobj) 5570a9627f2STom Herbert 5580a9627f2STom Herbert static ssize_t rx_queue_attr_show(struct kobject *kobj, struct attribute *attr, 5590a9627f2STom Herbert char *buf) 5600a9627f2STom Herbert { 5610a9627f2STom Herbert struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 5620a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 5630a9627f2STom Herbert 5640a9627f2STom Herbert if (!attribute->show) 5650a9627f2STom Herbert return -EIO; 5660a9627f2STom Herbert 5670a9627f2STom Herbert return attribute->show(queue, attribute, buf); 5680a9627f2STom Herbert } 5690a9627f2STom Herbert 5700a9627f2STom Herbert static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr, 5710a9627f2STom Herbert const char *buf, size_t count) 5720a9627f2STom Herbert { 5730a9627f2STom Herbert struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 5740a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 5750a9627f2STom Herbert 5760a9627f2STom Herbert if (!attribute->store) 5770a9627f2STom Herbert return -EIO; 5780a9627f2STom Herbert 5790a9627f2STom Herbert return attribute->store(queue, attribute, buf, count); 5800a9627f2STom Herbert } 5810a9627f2STom Herbert 582fa50d645Sstephen hemminger static const struct sysfs_ops rx_queue_sysfs_ops = { 5830a9627f2STom Herbert .show = rx_queue_attr_show, 5840a9627f2STom Herbert .store = rx_queue_attr_store, 5850a9627f2STom Herbert }; 5860a9627f2STom Herbert 587a953be53SMichael Dalton #ifdef CONFIG_RPS 5880a9627f2STom Herbert static ssize_t show_rps_map(struct netdev_rx_queue *queue, 5890a9627f2STom Herbert struct rx_queue_attribute *attribute, char *buf) 5900a9627f2STom Herbert { 5910a9627f2STom Herbert struct rps_map *map; 5920a9627f2STom Herbert cpumask_var_t mask; 5930a9627f2STom Herbert size_t len = 0; 5940a9627f2STom Herbert int i; 5950a9627f2STom Herbert 5960a9627f2STom Herbert if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 5970a9627f2STom Herbert return -ENOMEM; 5980a9627f2STom Herbert 5990a9627f2STom Herbert rcu_read_lock(); 6000a9627f2STom Herbert map = rcu_dereference(queue->rps_map); 6010a9627f2STom Herbert if (map) 6020a9627f2STom Herbert for (i = 0; i < map->len; i++) 6030a9627f2STom Herbert cpumask_set_cpu(map->cpus[i], mask); 6040a9627f2STom Herbert 6050a9627f2STom Herbert len += cpumask_scnprintf(buf + len, PAGE_SIZE, mask); 6060a9627f2STom Herbert if (PAGE_SIZE - len < 3) { 6070a9627f2STom Herbert rcu_read_unlock(); 6080a9627f2STom Herbert free_cpumask_var(mask); 6090a9627f2STom Herbert return -EINVAL; 6100a9627f2STom Herbert } 6110a9627f2STom Herbert rcu_read_unlock(); 6120a9627f2STom Herbert 6130a9627f2STom Herbert free_cpumask_var(mask); 6140a9627f2STom Herbert len += sprintf(buf + len, "\n"); 6150a9627f2STom Herbert return len; 6160a9627f2STom Herbert } 6170a9627f2STom Herbert 618f5acb907SEric Dumazet static ssize_t store_rps_map(struct netdev_rx_queue *queue, 6190a9627f2STom Herbert struct rx_queue_attribute *attribute, 6200a9627f2STom Herbert const char *buf, size_t len) 6210a9627f2STom Herbert { 6220a9627f2STom Herbert struct rps_map *old_map, *map; 6230a9627f2STom Herbert cpumask_var_t mask; 6240a9627f2STom Herbert int err, cpu, i; 6250a9627f2STom Herbert static DEFINE_SPINLOCK(rps_map_lock); 6260a9627f2STom Herbert 6270a9627f2STom Herbert if (!capable(CAP_NET_ADMIN)) 6280a9627f2STom Herbert return -EPERM; 6290a9627f2STom Herbert 6300a9627f2STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 6310a9627f2STom Herbert return -ENOMEM; 6320a9627f2STom Herbert 6330a9627f2STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 6340a9627f2STom Herbert if (err) { 6350a9627f2STom Herbert free_cpumask_var(mask); 6360a9627f2STom Herbert return err; 6370a9627f2STom Herbert } 6380a9627f2STom Herbert 63995c96174SEric Dumazet map = kzalloc(max_t(unsigned int, 6400a9627f2STom Herbert RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), 6410a9627f2STom Herbert GFP_KERNEL); 6420a9627f2STom Herbert if (!map) { 6430a9627f2STom Herbert free_cpumask_var(mask); 6440a9627f2STom Herbert return -ENOMEM; 6450a9627f2STom Herbert } 6460a9627f2STom Herbert 6470a9627f2STom Herbert i = 0; 6480a9627f2STom Herbert for_each_cpu_and(cpu, mask, cpu_online_mask) 6490a9627f2STom Herbert map->cpus[i++] = cpu; 6500a9627f2STom Herbert 6510a9627f2STom Herbert if (i) 6520a9627f2STom Herbert map->len = i; 6530a9627f2STom Herbert else { 6540a9627f2STom Herbert kfree(map); 6550a9627f2STom Herbert map = NULL; 6560a9627f2STom Herbert } 6570a9627f2STom Herbert 6580a9627f2STom Herbert spin_lock(&rps_map_lock); 6596e3f7fafSEric Dumazet old_map = rcu_dereference_protected(queue->rps_map, 6606e3f7fafSEric Dumazet lockdep_is_held(&rps_map_lock)); 6610a9627f2STom Herbert rcu_assign_pointer(queue->rps_map, map); 6620a9627f2STom Herbert spin_unlock(&rps_map_lock); 6630a9627f2STom Herbert 664adc9300eSEric Dumazet if (map) 665c5905afbSIngo Molnar static_key_slow_inc(&rps_needed); 666adc9300eSEric Dumazet if (old_map) { 667f6f80238SLai Jiangshan kfree_rcu(old_map, rcu); 668c5905afbSIngo Molnar static_key_slow_dec(&rps_needed); 669adc9300eSEric Dumazet } 6700a9627f2STom Herbert free_cpumask_var(mask); 6710a9627f2STom Herbert return len; 6720a9627f2STom Herbert } 6730a9627f2STom Herbert 674fec5e652STom Herbert static ssize_t show_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 675fec5e652STom Herbert struct rx_queue_attribute *attr, 676fec5e652STom Herbert char *buf) 677fec5e652STom Herbert { 678fec5e652STom Herbert struct rps_dev_flow_table *flow_table; 67960b778ceSEric Dumazet unsigned long val = 0; 680fec5e652STom Herbert 681fec5e652STom Herbert rcu_read_lock(); 682fec5e652STom Herbert flow_table = rcu_dereference(queue->rps_flow_table); 683fec5e652STom Herbert if (flow_table) 68460b778ceSEric Dumazet val = (unsigned long)flow_table->mask + 1; 685fec5e652STom Herbert rcu_read_unlock(); 686fec5e652STom Herbert 68760b778ceSEric Dumazet return sprintf(buf, "%lu\n", val); 688fec5e652STom Herbert } 689fec5e652STom Herbert 690fec5e652STom Herbert static void rps_dev_flow_table_release(struct rcu_head *rcu) 691fec5e652STom Herbert { 692fec5e652STom Herbert struct rps_dev_flow_table *table = container_of(rcu, 693fec5e652STom Herbert struct rps_dev_flow_table, rcu); 694243198d0SAl Viro vfree(table); 695fec5e652STom Herbert } 696fec5e652STom Herbert 697f5acb907SEric Dumazet static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 698fec5e652STom Herbert struct rx_queue_attribute *attr, 699fec5e652STom Herbert const char *buf, size_t len) 700fec5e652STom Herbert { 70160b778ceSEric Dumazet unsigned long mask, count; 702fec5e652STom Herbert struct rps_dev_flow_table *table, *old_table; 703fec5e652STom Herbert static DEFINE_SPINLOCK(rps_dev_flow_lock); 70460b778ceSEric Dumazet int rc; 705fec5e652STom Herbert 706fec5e652STom Herbert if (!capable(CAP_NET_ADMIN)) 707fec5e652STom Herbert return -EPERM; 708fec5e652STom Herbert 70960b778ceSEric Dumazet rc = kstrtoul(buf, 0, &count); 71060b778ceSEric Dumazet if (rc < 0) 71160b778ceSEric Dumazet return rc; 712fec5e652STom Herbert 713fec5e652STom Herbert if (count) { 71460b778ceSEric Dumazet mask = count - 1; 71560b778ceSEric Dumazet /* mask = roundup_pow_of_two(count) - 1; 71660b778ceSEric Dumazet * without overflows... 71760b778ceSEric Dumazet */ 71860b778ceSEric Dumazet while ((mask | (mask >> 1)) != mask) 71960b778ceSEric Dumazet mask |= (mask >> 1); 72060b778ceSEric Dumazet /* On 64 bit arches, must check mask fits in table->mask (u32), 7218e3bff96Sstephen hemminger * and on 32bit arches, must check 7228e3bff96Sstephen hemminger * RPS_DEV_FLOW_TABLE_SIZE(mask + 1) doesn't overflow. 72360b778ceSEric Dumazet */ 72460b778ceSEric Dumazet #if BITS_PER_LONG > 32 72560b778ceSEric Dumazet if (mask > (unsigned long)(u32)mask) 726a0a129f8SXi Wang return -EINVAL; 72760b778ceSEric Dumazet #else 72860b778ceSEric Dumazet if (mask > (ULONG_MAX - RPS_DEV_FLOW_TABLE_SIZE(1)) 729a0a129f8SXi Wang / sizeof(struct rps_dev_flow)) { 730fec5e652STom Herbert /* Enforce a limit to prevent overflow */ 731fec5e652STom Herbert return -EINVAL; 732fec5e652STom Herbert } 73360b778ceSEric Dumazet #endif 73460b778ceSEric Dumazet table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(mask + 1)); 735fec5e652STom Herbert if (!table) 736fec5e652STom Herbert return -ENOMEM; 737fec5e652STom Herbert 73860b778ceSEric Dumazet table->mask = mask; 73960b778ceSEric Dumazet for (count = 0; count <= mask; count++) 74060b778ceSEric Dumazet table->flows[count].cpu = RPS_NO_CPU; 741fec5e652STom Herbert } else 742fec5e652STom Herbert table = NULL; 743fec5e652STom Herbert 744fec5e652STom Herbert spin_lock(&rps_dev_flow_lock); 7456e3f7fafSEric Dumazet old_table = rcu_dereference_protected(queue->rps_flow_table, 7466e3f7fafSEric Dumazet lockdep_is_held(&rps_dev_flow_lock)); 747fec5e652STom Herbert rcu_assign_pointer(queue->rps_flow_table, table); 748fec5e652STom Herbert spin_unlock(&rps_dev_flow_lock); 749fec5e652STom Herbert 750fec5e652STom Herbert if (old_table) 751fec5e652STom Herbert call_rcu(&old_table->rcu, rps_dev_flow_table_release); 752fec5e652STom Herbert 753fec5e652STom Herbert return len; 754fec5e652STom Herbert } 755fec5e652STom Herbert 7560a9627f2STom Herbert static struct rx_queue_attribute rps_cpus_attribute = 7570a9627f2STom Herbert __ATTR(rps_cpus, S_IRUGO | S_IWUSR, show_rps_map, store_rps_map); 7580a9627f2STom Herbert 759fec5e652STom Herbert 760fec5e652STom Herbert static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute = 761fec5e652STom Herbert __ATTR(rps_flow_cnt, S_IRUGO | S_IWUSR, 762fec5e652STom Herbert show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt); 763a953be53SMichael Dalton #endif /* CONFIG_RPS */ 764fec5e652STom Herbert 7650a9627f2STom Herbert static struct attribute *rx_queue_default_attrs[] = { 766a953be53SMichael Dalton #ifdef CONFIG_RPS 7670a9627f2STom Herbert &rps_cpus_attribute.attr, 768fec5e652STom Herbert &rps_dev_flow_table_cnt_attribute.attr, 769a953be53SMichael Dalton #endif 7700a9627f2STom Herbert NULL 7710a9627f2STom Herbert }; 7720a9627f2STom Herbert 7730a9627f2STom Herbert static void rx_queue_release(struct kobject *kobj) 7740a9627f2STom Herbert { 7750a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 776a953be53SMichael Dalton #ifdef CONFIG_RPS 7776e3f7fafSEric Dumazet struct rps_map *map; 7786e3f7fafSEric Dumazet struct rps_dev_flow_table *flow_table; 7790a9627f2STom Herbert 780fec5e652STom Herbert 78133d480ceSEric Dumazet map = rcu_dereference_protected(queue->rps_map, 1); 7829ea19481SJohn Fastabend if (map) { 7839ea19481SJohn Fastabend RCU_INIT_POINTER(queue->rps_map, NULL); 784f6f80238SLai Jiangshan kfree_rcu(map, rcu); 7859ea19481SJohn Fastabend } 7866e3f7fafSEric Dumazet 78733d480ceSEric Dumazet flow_table = rcu_dereference_protected(queue->rps_flow_table, 1); 7889ea19481SJohn Fastabend if (flow_table) { 7899ea19481SJohn Fastabend RCU_INIT_POINTER(queue->rps_flow_table, NULL); 7906e3f7fafSEric Dumazet call_rcu(&flow_table->rcu, rps_dev_flow_table_release); 7919ea19481SJohn Fastabend } 792a953be53SMichael Dalton #endif 7930a9627f2STom Herbert 7949ea19481SJohn Fastabend memset(kobj, 0, sizeof(*kobj)); 795fe822240STom Herbert dev_put(queue->dev); 7960a9627f2STom Herbert } 7970a9627f2STom Herbert 79882ef3d5dSWeilong Chen static const void *rx_queue_namespace(struct kobject *kobj) 79982ef3d5dSWeilong Chen { 80082ef3d5dSWeilong Chen struct netdev_rx_queue *queue = to_rx_queue(kobj); 80182ef3d5dSWeilong Chen struct device *dev = &queue->dev->dev; 80282ef3d5dSWeilong Chen const void *ns = NULL; 80382ef3d5dSWeilong Chen 80482ef3d5dSWeilong Chen if (dev->class && dev->class->ns_type) 80582ef3d5dSWeilong Chen ns = dev->class->namespace(dev); 80682ef3d5dSWeilong Chen 80782ef3d5dSWeilong Chen return ns; 80882ef3d5dSWeilong Chen } 80982ef3d5dSWeilong Chen 8100a9627f2STom Herbert static struct kobj_type rx_queue_ktype = { 8110a9627f2STom Herbert .sysfs_ops = &rx_queue_sysfs_ops, 8120a9627f2STom Herbert .release = rx_queue_release, 8130a9627f2STom Herbert .default_attrs = rx_queue_default_attrs, 81482ef3d5dSWeilong Chen .namespace = rx_queue_namespace 8150a9627f2STom Herbert }; 8160a9627f2STom Herbert 8176b53dafeSWANG Cong static int rx_queue_add_kobject(struct net_device *dev, int index) 8180a9627f2STom Herbert { 8196b53dafeSWANG Cong struct netdev_rx_queue *queue = dev->_rx + index; 8200a9627f2STom Herbert struct kobject *kobj = &queue->kobj; 8210a9627f2STom Herbert int error = 0; 8220a9627f2STom Herbert 8236b53dafeSWANG Cong kobj->kset = dev->queues_kset; 8240a9627f2STom Herbert error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, 8250a9627f2STom Herbert "rx-%u", index); 826a953be53SMichael Dalton if (error) 827a953be53SMichael Dalton goto exit; 828a953be53SMichael Dalton 8296b53dafeSWANG Cong if (dev->sysfs_rx_queue_group) { 8306b53dafeSWANG Cong error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); 831a953be53SMichael Dalton if (error) 832a953be53SMichael Dalton goto exit; 8330a9627f2STom Herbert } 8340a9627f2STom Herbert 8350a9627f2STom Herbert kobject_uevent(kobj, KOBJ_ADD); 836fe822240STom Herbert dev_hold(queue->dev); 8370a9627f2STom Herbert 8380a9627f2STom Herbert return error; 839a953be53SMichael Dalton exit: 840a953be53SMichael Dalton kobject_put(kobj); 841a953be53SMichael Dalton return error; 8420a9627f2STom Herbert } 84380dd6eacSPaul Bolle #endif /* CONFIG_SYSFS */ 8440a9627f2STom Herbert 84562fe0b40SBen Hutchings int 8466b53dafeSWANG Cong net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) 8470a9627f2STom Herbert { 848a953be53SMichael Dalton #ifdef CONFIG_SYSFS 8490a9627f2STom Herbert int i; 8500a9627f2STom Herbert int error = 0; 8510a9627f2STom Herbert 852a953be53SMichael Dalton #ifndef CONFIG_RPS 8536b53dafeSWANG Cong if (!dev->sysfs_rx_queue_group) 854a953be53SMichael Dalton return 0; 855a953be53SMichael Dalton #endif 85662fe0b40SBen Hutchings for (i = old_num; i < new_num; i++) { 8576b53dafeSWANG Cong error = rx_queue_add_kobject(dev, i); 85862fe0b40SBen Hutchings if (error) { 85962fe0b40SBen Hutchings new_num = old_num; 8600a9627f2STom Herbert break; 8610a9627f2STom Herbert } 86262fe0b40SBen Hutchings } 8630a9627f2STom Herbert 864a953be53SMichael Dalton while (--i >= new_num) { 8656b53dafeSWANG Cong if (dev->sysfs_rx_queue_group) 8666b53dafeSWANG Cong sysfs_remove_group(&dev->_rx[i].kobj, 8676b53dafeSWANG Cong dev->sysfs_rx_queue_group); 8686b53dafeSWANG Cong kobject_put(&dev->_rx[i].kobj); 869a953be53SMichael Dalton } 8700a9627f2STom Herbert 8710a9627f2STom Herbert return error; 872bf264145STom Herbert #else 873bf264145STom Herbert return 0; 874bf264145STom Herbert #endif 8750a9627f2STom Herbert } 8760a9627f2STom Herbert 877ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 8781d24eb48STom Herbert /* 8791d24eb48STom Herbert * netdev_queue sysfs structures and functions. 8801d24eb48STom Herbert */ 8811d24eb48STom Herbert struct netdev_queue_attribute { 8821d24eb48STom Herbert struct attribute attr; 8831d24eb48STom Herbert ssize_t (*show)(struct netdev_queue *queue, 8841d24eb48STom Herbert struct netdev_queue_attribute *attr, char *buf); 8851d24eb48STom Herbert ssize_t (*store)(struct netdev_queue *queue, 8861d24eb48STom Herbert struct netdev_queue_attribute *attr, const char *buf, size_t len); 8871d24eb48STom Herbert }; 8881d24eb48STom Herbert #define to_netdev_queue_attr(_attr) container_of(_attr, \ 8891d24eb48STom Herbert struct netdev_queue_attribute, attr) 8901d24eb48STom Herbert 8911d24eb48STom Herbert #define to_netdev_queue(obj) container_of(obj, struct netdev_queue, kobj) 8921d24eb48STom Herbert 8931d24eb48STom Herbert static ssize_t netdev_queue_attr_show(struct kobject *kobj, 8941d24eb48STom Herbert struct attribute *attr, char *buf) 89562fe0b40SBen Hutchings { 8961d24eb48STom Herbert struct netdev_queue_attribute *attribute = to_netdev_queue_attr(attr); 8971d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 8981d24eb48STom Herbert 8991d24eb48STom Herbert if (!attribute->show) 9001d24eb48STom Herbert return -EIO; 9011d24eb48STom Herbert 9021d24eb48STom Herbert return attribute->show(queue, attribute, buf); 9031d24eb48STom Herbert } 9041d24eb48STom Herbert 9051d24eb48STom Herbert static ssize_t netdev_queue_attr_store(struct kobject *kobj, 9061d24eb48STom Herbert struct attribute *attr, 9071d24eb48STom Herbert const char *buf, size_t count) 9081d24eb48STom Herbert { 9091d24eb48STom Herbert struct netdev_queue_attribute *attribute = to_netdev_queue_attr(attr); 9101d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 9111d24eb48STom Herbert 9121d24eb48STom Herbert if (!attribute->store) 9131d24eb48STom Herbert return -EIO; 9141d24eb48STom Herbert 9151d24eb48STom Herbert return attribute->store(queue, attribute, buf, count); 9161d24eb48STom Herbert } 9171d24eb48STom Herbert 9181d24eb48STom Herbert static const struct sysfs_ops netdev_queue_sysfs_ops = { 9191d24eb48STom Herbert .show = netdev_queue_attr_show, 9201d24eb48STom Herbert .store = netdev_queue_attr_store, 9211d24eb48STom Herbert }; 9221d24eb48STom Herbert 923ccf5ff69Sdavid decotigny static ssize_t show_trans_timeout(struct netdev_queue *queue, 924ccf5ff69Sdavid decotigny struct netdev_queue_attribute *attribute, 925ccf5ff69Sdavid decotigny char *buf) 926ccf5ff69Sdavid decotigny { 927ccf5ff69Sdavid decotigny unsigned long trans_timeout; 928ccf5ff69Sdavid decotigny 929ccf5ff69Sdavid decotigny spin_lock_irq(&queue->_xmit_lock); 930ccf5ff69Sdavid decotigny trans_timeout = queue->trans_timeout; 931ccf5ff69Sdavid decotigny spin_unlock_irq(&queue->_xmit_lock); 932ccf5ff69Sdavid decotigny 933ccf5ff69Sdavid decotigny return sprintf(buf, "%lu", trans_timeout); 934ccf5ff69Sdavid decotigny } 935ccf5ff69Sdavid decotigny 936ccf5ff69Sdavid decotigny static struct netdev_queue_attribute queue_trans_timeout = 937ccf5ff69Sdavid decotigny __ATTR(tx_timeout, S_IRUGO, show_trans_timeout, NULL); 938ccf5ff69Sdavid decotigny 939114cf580STom Herbert #ifdef CONFIG_BQL 940114cf580STom Herbert /* 941114cf580STom Herbert * Byte queue limits sysfs structures and functions. 942114cf580STom Herbert */ 943114cf580STom Herbert static ssize_t bql_show(char *buf, unsigned int value) 944114cf580STom Herbert { 945114cf580STom Herbert return sprintf(buf, "%u\n", value); 946114cf580STom Herbert } 947114cf580STom Herbert 948114cf580STom Herbert static ssize_t bql_set(const char *buf, const size_t count, 949114cf580STom Herbert unsigned int *pvalue) 950114cf580STom Herbert { 951114cf580STom Herbert unsigned int value; 952114cf580STom Herbert int err; 953114cf580STom Herbert 954114cf580STom Herbert if (!strcmp(buf, "max") || !strcmp(buf, "max\n")) 955114cf580STom Herbert value = DQL_MAX_LIMIT; 956114cf580STom Herbert else { 957114cf580STom Herbert err = kstrtouint(buf, 10, &value); 958114cf580STom Herbert if (err < 0) 959114cf580STom Herbert return err; 960114cf580STom Herbert if (value > DQL_MAX_LIMIT) 961114cf580STom Herbert return -EINVAL; 962114cf580STom Herbert } 963114cf580STom Herbert 964114cf580STom Herbert *pvalue = value; 965114cf580STom Herbert 966114cf580STom Herbert return count; 967114cf580STom Herbert } 968114cf580STom Herbert 969114cf580STom Herbert static ssize_t bql_show_hold_time(struct netdev_queue *queue, 970114cf580STom Herbert struct netdev_queue_attribute *attr, 971114cf580STom Herbert char *buf) 972114cf580STom Herbert { 973114cf580STom Herbert struct dql *dql = &queue->dql; 974114cf580STom Herbert 975114cf580STom Herbert return sprintf(buf, "%u\n", jiffies_to_msecs(dql->slack_hold_time)); 976114cf580STom Herbert } 977114cf580STom Herbert 978114cf580STom Herbert static ssize_t bql_set_hold_time(struct netdev_queue *queue, 979114cf580STom Herbert struct netdev_queue_attribute *attribute, 980114cf580STom Herbert const char *buf, size_t len) 981114cf580STom Herbert { 982114cf580STom Herbert struct dql *dql = &queue->dql; 98395c96174SEric Dumazet unsigned int value; 984114cf580STom Herbert int err; 985114cf580STom Herbert 986114cf580STom Herbert err = kstrtouint(buf, 10, &value); 987114cf580STom Herbert if (err < 0) 988114cf580STom Herbert return err; 989114cf580STom Herbert 990114cf580STom Herbert dql->slack_hold_time = msecs_to_jiffies(value); 991114cf580STom Herbert 992114cf580STom Herbert return len; 993114cf580STom Herbert } 994114cf580STom Herbert 995114cf580STom Herbert static struct netdev_queue_attribute bql_hold_time_attribute = 996114cf580STom Herbert __ATTR(hold_time, S_IRUGO | S_IWUSR, bql_show_hold_time, 997114cf580STom Herbert bql_set_hold_time); 998114cf580STom Herbert 999114cf580STom Herbert static ssize_t bql_show_inflight(struct netdev_queue *queue, 1000114cf580STom Herbert struct netdev_queue_attribute *attr, 1001114cf580STom Herbert char *buf) 1002114cf580STom Herbert { 1003114cf580STom Herbert struct dql *dql = &queue->dql; 1004114cf580STom Herbert 1005114cf580STom Herbert return sprintf(buf, "%u\n", dql->num_queued - dql->num_completed); 1006114cf580STom Herbert } 1007114cf580STom Herbert 1008114cf580STom Herbert static struct netdev_queue_attribute bql_inflight_attribute = 1009795d9a25SHiroaki SHIMODA __ATTR(inflight, S_IRUGO, bql_show_inflight, NULL); 1010114cf580STom Herbert 1011114cf580STom Herbert #define BQL_ATTR(NAME, FIELD) \ 1012114cf580STom Herbert static ssize_t bql_show_ ## NAME(struct netdev_queue *queue, \ 1013114cf580STom Herbert struct netdev_queue_attribute *attr, \ 1014114cf580STom Herbert char *buf) \ 1015114cf580STom Herbert { \ 1016114cf580STom Herbert return bql_show(buf, queue->dql.FIELD); \ 1017114cf580STom Herbert } \ 1018114cf580STom Herbert \ 1019114cf580STom Herbert static ssize_t bql_set_ ## NAME(struct netdev_queue *queue, \ 1020114cf580STom Herbert struct netdev_queue_attribute *attr, \ 1021114cf580STom Herbert const char *buf, size_t len) \ 1022114cf580STom Herbert { \ 1023114cf580STom Herbert return bql_set(buf, len, &queue->dql.FIELD); \ 1024114cf580STom Herbert } \ 1025114cf580STom Herbert \ 1026114cf580STom Herbert static struct netdev_queue_attribute bql_ ## NAME ## _attribute = \ 1027114cf580STom Herbert __ATTR(NAME, S_IRUGO | S_IWUSR, bql_show_ ## NAME, \ 1028114cf580STom Herbert bql_set_ ## NAME); 1029114cf580STom Herbert 1030114cf580STom Herbert BQL_ATTR(limit, limit) 1031114cf580STom Herbert BQL_ATTR(limit_max, max_limit) 1032114cf580STom Herbert BQL_ATTR(limit_min, min_limit) 1033114cf580STom Herbert 1034114cf580STom Herbert static struct attribute *dql_attrs[] = { 1035114cf580STom Herbert &bql_limit_attribute.attr, 1036114cf580STom Herbert &bql_limit_max_attribute.attr, 1037114cf580STom Herbert &bql_limit_min_attribute.attr, 1038114cf580STom Herbert &bql_hold_time_attribute.attr, 1039114cf580STom Herbert &bql_inflight_attribute.attr, 1040114cf580STom Herbert NULL 1041114cf580STom Herbert }; 1042114cf580STom Herbert 1043114cf580STom Herbert static struct attribute_group dql_group = { 1044114cf580STom Herbert .name = "byte_queue_limits", 1045114cf580STom Herbert .attrs = dql_attrs, 1046114cf580STom Herbert }; 1047114cf580STom Herbert #endif /* CONFIG_BQL */ 1048114cf580STom Herbert 1049ccf5ff69Sdavid decotigny #ifdef CONFIG_XPS 1050ed1acc8cSEric Dumazet static unsigned int get_netdev_queue_index(struct netdev_queue *queue) 10511d24eb48STom Herbert { 10521d24eb48STom Herbert struct net_device *dev = queue->dev; 1053ed1acc8cSEric Dumazet unsigned int i; 10541d24eb48STom Herbert 1055ed1acc8cSEric Dumazet i = queue - dev->_tx; 10561d24eb48STom Herbert BUG_ON(i >= dev->num_tx_queues); 10571d24eb48STom Herbert 10581d24eb48STom Herbert return i; 10591d24eb48STom Herbert } 10601d24eb48STom Herbert 10611d24eb48STom Herbert 10621d24eb48STom Herbert static ssize_t show_xps_map(struct netdev_queue *queue, 10631d24eb48STom Herbert struct netdev_queue_attribute *attribute, char *buf) 10641d24eb48STom Herbert { 10651d24eb48STom Herbert struct net_device *dev = queue->dev; 10661d24eb48STom Herbert struct xps_dev_maps *dev_maps; 10671d24eb48STom Herbert cpumask_var_t mask; 10681d24eb48STom Herbert unsigned long index; 10691d24eb48STom Herbert size_t len = 0; 10701d24eb48STom Herbert int i; 10711d24eb48STom Herbert 10721d24eb48STom Herbert if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 10731d24eb48STom Herbert return -ENOMEM; 10741d24eb48STom Herbert 10751d24eb48STom Herbert index = get_netdev_queue_index(queue); 10761d24eb48STom Herbert 10771d24eb48STom Herbert rcu_read_lock(); 10781d24eb48STom Herbert dev_maps = rcu_dereference(dev->xps_maps); 10791d24eb48STom Herbert if (dev_maps) { 10801d24eb48STom Herbert for_each_possible_cpu(i) { 10811d24eb48STom Herbert struct xps_map *map = 10821d24eb48STom Herbert rcu_dereference(dev_maps->cpu_map[i]); 10831d24eb48STom Herbert if (map) { 10841d24eb48STom Herbert int j; 10851d24eb48STom Herbert for (j = 0; j < map->len; j++) { 10861d24eb48STom Herbert if (map->queues[j] == index) { 10871d24eb48STom Herbert cpumask_set_cpu(i, mask); 10881d24eb48STom Herbert break; 10891d24eb48STom Herbert } 10901d24eb48STom Herbert } 10911d24eb48STom Herbert } 10921d24eb48STom Herbert } 10931d24eb48STom Herbert } 10941d24eb48STom Herbert rcu_read_unlock(); 10951d24eb48STom Herbert 10961d24eb48STom Herbert len += cpumask_scnprintf(buf + len, PAGE_SIZE, mask); 10971d24eb48STom Herbert if (PAGE_SIZE - len < 3) { 10981d24eb48STom Herbert free_cpumask_var(mask); 10991d24eb48STom Herbert return -EINVAL; 11001d24eb48STom Herbert } 11011d24eb48STom Herbert 11021d24eb48STom Herbert free_cpumask_var(mask); 11031d24eb48STom Herbert len += sprintf(buf + len, "\n"); 11041d24eb48STom Herbert return len; 11051d24eb48STom Herbert } 11061d24eb48STom Herbert 11071d24eb48STom Herbert static ssize_t store_xps_map(struct netdev_queue *queue, 11081d24eb48STom Herbert struct netdev_queue_attribute *attribute, 11091d24eb48STom Herbert const char *buf, size_t len) 11101d24eb48STom Herbert { 11111d24eb48STom Herbert struct net_device *dev = queue->dev; 11121d24eb48STom Herbert unsigned long index; 1113537c00deSAlexander Duyck cpumask_var_t mask; 1114537c00deSAlexander Duyck int err; 11151d24eb48STom Herbert 11161d24eb48STom Herbert if (!capable(CAP_NET_ADMIN)) 11171d24eb48STom Herbert return -EPERM; 11181d24eb48STom Herbert 11191d24eb48STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 11201d24eb48STom Herbert return -ENOMEM; 11211d24eb48STom Herbert 11221d24eb48STom Herbert index = get_netdev_queue_index(queue); 11231d24eb48STom Herbert 11241d24eb48STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 11251d24eb48STom Herbert if (err) { 11261d24eb48STom Herbert free_cpumask_var(mask); 11271d24eb48STom Herbert return err; 11281d24eb48STom Herbert } 11291d24eb48STom Herbert 1130537c00deSAlexander Duyck err = netif_set_xps_queue(dev, mask, index); 11311d24eb48STom Herbert 11321d24eb48STom Herbert free_cpumask_var(mask); 11331d24eb48STom Herbert 1134537c00deSAlexander Duyck return err ? : len; 11351d24eb48STom Herbert } 11361d24eb48STom Herbert 11371d24eb48STom Herbert static struct netdev_queue_attribute xps_cpus_attribute = 11381d24eb48STom Herbert __ATTR(xps_cpus, S_IRUGO | S_IWUSR, show_xps_map, store_xps_map); 1139ccf5ff69Sdavid decotigny #endif /* CONFIG_XPS */ 11401d24eb48STom Herbert 11411d24eb48STom Herbert static struct attribute *netdev_queue_default_attrs[] = { 1142ccf5ff69Sdavid decotigny &queue_trans_timeout.attr, 1143ccf5ff69Sdavid decotigny #ifdef CONFIG_XPS 11441d24eb48STom Herbert &xps_cpus_attribute.attr, 1145ccf5ff69Sdavid decotigny #endif 11461d24eb48STom Herbert NULL 11471d24eb48STom Herbert }; 11481d24eb48STom Herbert 11491d24eb48STom Herbert static void netdev_queue_release(struct kobject *kobj) 11501d24eb48STom Herbert { 11511d24eb48STom Herbert struct netdev_queue *queue = to_netdev_queue(kobj); 11521d24eb48STom Herbert 11531d24eb48STom Herbert memset(kobj, 0, sizeof(*kobj)); 11541d24eb48STom Herbert dev_put(queue->dev); 11551d24eb48STom Herbert } 11561d24eb48STom Herbert 115782ef3d5dSWeilong Chen static const void *netdev_queue_namespace(struct kobject *kobj) 115882ef3d5dSWeilong Chen { 115982ef3d5dSWeilong Chen struct netdev_queue *queue = to_netdev_queue(kobj); 116082ef3d5dSWeilong Chen struct device *dev = &queue->dev->dev; 116182ef3d5dSWeilong Chen const void *ns = NULL; 116282ef3d5dSWeilong Chen 116382ef3d5dSWeilong Chen if (dev->class && dev->class->ns_type) 116482ef3d5dSWeilong Chen ns = dev->class->namespace(dev); 116582ef3d5dSWeilong Chen 116682ef3d5dSWeilong Chen return ns; 116782ef3d5dSWeilong Chen } 116882ef3d5dSWeilong Chen 11691d24eb48STom Herbert static struct kobj_type netdev_queue_ktype = { 11701d24eb48STom Herbert .sysfs_ops = &netdev_queue_sysfs_ops, 11711d24eb48STom Herbert .release = netdev_queue_release, 11721d24eb48STom Herbert .default_attrs = netdev_queue_default_attrs, 117382ef3d5dSWeilong Chen .namespace = netdev_queue_namespace, 11741d24eb48STom Herbert }; 11751d24eb48STom Herbert 11766b53dafeSWANG Cong static int netdev_queue_add_kobject(struct net_device *dev, int index) 11771d24eb48STom Herbert { 11786b53dafeSWANG Cong struct netdev_queue *queue = dev->_tx + index; 11791d24eb48STom Herbert struct kobject *kobj = &queue->kobj; 11801d24eb48STom Herbert int error = 0; 11811d24eb48STom Herbert 11826b53dafeSWANG Cong kobj->kset = dev->queues_kset; 11831d24eb48STom Herbert error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, 11841d24eb48STom Herbert "tx-%u", index); 1185114cf580STom Herbert if (error) 1186114cf580STom Herbert goto exit; 1187114cf580STom Herbert 1188114cf580STom Herbert #ifdef CONFIG_BQL 1189114cf580STom Herbert error = sysfs_create_group(kobj, &dql_group); 1190114cf580STom Herbert if (error) 1191114cf580STom Herbert goto exit; 1192114cf580STom Herbert #endif 11931d24eb48STom Herbert 11941d24eb48STom Herbert kobject_uevent(kobj, KOBJ_ADD); 11951d24eb48STom Herbert dev_hold(queue->dev); 11961d24eb48STom Herbert 1197114cf580STom Herbert return 0; 1198114cf580STom Herbert exit: 1199114cf580STom Herbert kobject_put(kobj); 12001d24eb48STom Herbert return error; 12011d24eb48STom Herbert } 1202ccf5ff69Sdavid decotigny #endif /* CONFIG_SYSFS */ 12031d24eb48STom Herbert 12041d24eb48STom Herbert int 12056b53dafeSWANG Cong netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) 12061d24eb48STom Herbert { 1207ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 12081d24eb48STom Herbert int i; 12091d24eb48STom Herbert int error = 0; 12101d24eb48STom Herbert 12111d24eb48STom Herbert for (i = old_num; i < new_num; i++) { 12126b53dafeSWANG Cong error = netdev_queue_add_kobject(dev, i); 12131d24eb48STom Herbert if (error) { 12141d24eb48STom Herbert new_num = old_num; 12151d24eb48STom Herbert break; 12161d24eb48STom Herbert } 12171d24eb48STom Herbert } 12181d24eb48STom Herbert 1219114cf580STom Herbert while (--i >= new_num) { 12206b53dafeSWANG Cong struct netdev_queue *queue = dev->_tx + i; 1221114cf580STom Herbert 1222114cf580STom Herbert #ifdef CONFIG_BQL 1223114cf580STom Herbert sysfs_remove_group(&queue->kobj, &dql_group); 1224114cf580STom Herbert #endif 1225114cf580STom Herbert kobject_put(&queue->kobj); 1226114cf580STom Herbert } 12271d24eb48STom Herbert 12281d24eb48STom Herbert return error; 1229bf264145STom Herbert #else 1230bf264145STom Herbert return 0; 1231ccf5ff69Sdavid decotigny #endif /* CONFIG_SYSFS */ 12321d24eb48STom Herbert } 12331d24eb48STom Herbert 12346b53dafeSWANG Cong static int register_queue_kobjects(struct net_device *dev) 12351d24eb48STom Herbert { 1236bf264145STom Herbert int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; 12371d24eb48STom Herbert 1238ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 12396b53dafeSWANG Cong dev->queues_kset = kset_create_and_add("queues", 12406b53dafeSWANG Cong NULL, &dev->dev.kobj); 12416b53dafeSWANG Cong if (!dev->queues_kset) 124262fe0b40SBen Hutchings return -ENOMEM; 12436b53dafeSWANG Cong real_rx = dev->real_num_rx_queues; 1244bf264145STom Herbert #endif 12456b53dafeSWANG Cong real_tx = dev->real_num_tx_queues; 1246bf264145STom Herbert 12476b53dafeSWANG Cong error = net_rx_queue_update_kobjects(dev, 0, real_rx); 12481d24eb48STom Herbert if (error) 12491d24eb48STom Herbert goto error; 1250bf264145STom Herbert rxq = real_rx; 12511d24eb48STom Herbert 12526b53dafeSWANG Cong error = netdev_queue_update_kobjects(dev, 0, real_tx); 12531d24eb48STom Herbert if (error) 12541d24eb48STom Herbert goto error; 1255bf264145STom Herbert txq = real_tx; 12561d24eb48STom Herbert 12571d24eb48STom Herbert return 0; 12581d24eb48STom Herbert 12591d24eb48STom Herbert error: 12606b53dafeSWANG Cong netdev_queue_update_kobjects(dev, txq, 0); 12616b53dafeSWANG Cong net_rx_queue_update_kobjects(dev, rxq, 0); 12621d24eb48STom Herbert return error; 126362fe0b40SBen Hutchings } 126462fe0b40SBen Hutchings 12656b53dafeSWANG Cong static void remove_queue_kobjects(struct net_device *dev) 12660a9627f2STom Herbert { 1267bf264145STom Herbert int real_rx = 0, real_tx = 0; 1268bf264145STom Herbert 1269a953be53SMichael Dalton #ifdef CONFIG_SYSFS 12706b53dafeSWANG Cong real_rx = dev->real_num_rx_queues; 1271bf264145STom Herbert #endif 12726b53dafeSWANG Cong real_tx = dev->real_num_tx_queues; 1273bf264145STom Herbert 12746b53dafeSWANG Cong net_rx_queue_update_kobjects(dev, real_rx, 0); 12756b53dafeSWANG Cong netdev_queue_update_kobjects(dev, real_tx, 0); 1276ccf5ff69Sdavid decotigny #ifdef CONFIG_SYSFS 12776b53dafeSWANG Cong kset_unregister(dev->queues_kset); 1278bf264145STom Herbert #endif 12790a9627f2STom Herbert } 1280608b4b95SEric W. Biederman 12817dc5dbc8SEric W. Biederman static bool net_current_may_mount(void) 12827dc5dbc8SEric W. Biederman { 12837dc5dbc8SEric W. Biederman struct net *net = current->nsproxy->net_ns; 12847dc5dbc8SEric W. Biederman 12857dc5dbc8SEric W. Biederman return ns_capable(net->user_ns, CAP_SYS_ADMIN); 12867dc5dbc8SEric W. Biederman } 12877dc5dbc8SEric W. Biederman 1288a685e089SAl Viro static void *net_grab_current_ns(void) 1289608b4b95SEric W. Biederman { 1290a685e089SAl Viro struct net *ns = current->nsproxy->net_ns; 1291a685e089SAl Viro #ifdef CONFIG_NET_NS 1292a685e089SAl Viro if (ns) 1293a685e089SAl Viro atomic_inc(&ns->passive); 1294a685e089SAl Viro #endif 1295a685e089SAl Viro return ns; 1296608b4b95SEric W. Biederman } 1297608b4b95SEric W. Biederman 1298608b4b95SEric W. Biederman static const void *net_initial_ns(void) 1299608b4b95SEric W. Biederman { 1300608b4b95SEric W. Biederman return &init_net; 1301608b4b95SEric W. Biederman } 1302608b4b95SEric W. Biederman 1303608b4b95SEric W. Biederman static const void *net_netlink_ns(struct sock *sk) 1304608b4b95SEric W. Biederman { 1305608b4b95SEric W. Biederman return sock_net(sk); 1306608b4b95SEric W. Biederman } 1307608b4b95SEric W. Biederman 130804600794SJohannes Berg struct kobj_ns_type_operations net_ns_type_operations = { 1309608b4b95SEric W. Biederman .type = KOBJ_NS_TYPE_NET, 13107dc5dbc8SEric W. Biederman .current_may_mount = net_current_may_mount, 1311a685e089SAl Viro .grab_current_ns = net_grab_current_ns, 1312608b4b95SEric W. Biederman .netlink_ns = net_netlink_ns, 1313608b4b95SEric W. Biederman .initial_ns = net_initial_ns, 1314a685e089SAl Viro .drop_ns = net_drop_ns, 1315608b4b95SEric W. Biederman }; 131604600794SJohannes Berg EXPORT_SYMBOL_GPL(net_ns_type_operations); 1317608b4b95SEric W. Biederman 13187eff2e7aSKay Sievers static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) 13191da177e4SLinus Torvalds { 132043cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 13217eff2e7aSKay Sievers int retval; 13221da177e4SLinus Torvalds 1323312c004dSKay Sievers /* pass interface to uevent. */ 13247eff2e7aSKay Sievers retval = add_uevent_var(env, "INTERFACE=%s", dev->name); 1325bf62456eSEric Rannaud if (retval) 1326bf62456eSEric Rannaud goto exit; 13271da177e4SLinus Torvalds 1328ca2f37dbSJean Tourrilhes /* pass ifindex to uevent. 1329ca2f37dbSJean Tourrilhes * ifindex is useful as it won't change (interface name may change) 1330ca2f37dbSJean Tourrilhes * and is what RtNetlink uses natively. */ 13317eff2e7aSKay Sievers retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); 1332ca2f37dbSJean Tourrilhes 1333bf62456eSEric Rannaud exit: 1334bf62456eSEric Rannaud return retval; 13351da177e4SLinus Torvalds } 13361da177e4SLinus Torvalds 13371da177e4SLinus Torvalds /* 13381da177e4SLinus Torvalds * netdev_release -- destroy and free a dead device. 133943cb76d9SGreg Kroah-Hartman * Called when last reference to device kobject is gone. 13401da177e4SLinus Torvalds */ 134143cb76d9SGreg Kroah-Hartman static void netdev_release(struct device *d) 13421da177e4SLinus Torvalds { 134343cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 13441da177e4SLinus Torvalds 13451da177e4SLinus Torvalds BUG_ON(dev->reg_state != NETREG_RELEASED); 13461da177e4SLinus Torvalds 13470b815a1aSStephen Hemminger kfree(dev->ifalias); 134874d332c1SEric Dumazet netdev_freemem(dev); 13491da177e4SLinus Torvalds } 13501da177e4SLinus Torvalds 1351608b4b95SEric W. Biederman static const void *net_namespace(struct device *d) 1352608b4b95SEric W. Biederman { 1353608b4b95SEric W. Biederman struct net_device *dev; 1354608b4b95SEric W. Biederman dev = container_of(d, struct net_device, dev); 1355608b4b95SEric W. Biederman return dev_net(dev); 1356608b4b95SEric W. Biederman } 1357608b4b95SEric W. Biederman 13581da177e4SLinus Torvalds static struct class net_class = { 13591da177e4SLinus Torvalds .name = "net", 136043cb76d9SGreg Kroah-Hartman .dev_release = netdev_release, 13616be8aeefSGreg Kroah-Hartman .dev_groups = net_class_groups, 136243cb76d9SGreg Kroah-Hartman .dev_uevent = netdev_uevent, 1363608b4b95SEric W. Biederman .ns_type = &net_ns_type_operations, 1364608b4b95SEric W. Biederman .namespace = net_namespace, 13651da177e4SLinus Torvalds }; 13661da177e4SLinus Torvalds 13679093bbb2SStephen Hemminger /* Delete sysfs entries but hold kobject reference until after all 13689093bbb2SStephen Hemminger * netdev references are gone. 13699093bbb2SStephen Hemminger */ 13706b53dafeSWANG Cong void netdev_unregister_kobject(struct net_device *ndev) 13711da177e4SLinus Torvalds { 13726b53dafeSWANG Cong struct device *dev = &(ndev->dev); 13739093bbb2SStephen Hemminger 13749093bbb2SStephen Hemminger kobject_get(&dev->kobj); 13753891845eSEric W. Biederman 13766b53dafeSWANG Cong remove_queue_kobjects(ndev); 13770a9627f2STom Herbert 13789802c8e2SMing Lei pm_runtime_set_memalloc_noio(dev, false); 13799802c8e2SMing Lei 13809093bbb2SStephen Hemminger device_del(dev); 13811da177e4SLinus Torvalds } 13821da177e4SLinus Torvalds 13831da177e4SLinus Torvalds /* Create sysfs entries for network device. */ 13846b53dafeSWANG Cong int netdev_register_kobject(struct net_device *ndev) 13851da177e4SLinus Torvalds { 13866b53dafeSWANG Cong struct device *dev = &(ndev->dev); 13876b53dafeSWANG Cong const struct attribute_group **groups = ndev->sysfs_groups; 13880a9627f2STom Herbert int error = 0; 13891da177e4SLinus Torvalds 1390a1b3f594SEric W. Biederman device_initialize(dev); 139143cb76d9SGreg Kroah-Hartman dev->class = &net_class; 13926b53dafeSWANG Cong dev->platform_data = ndev; 139343cb76d9SGreg Kroah-Hartman dev->groups = groups; 13941da177e4SLinus Torvalds 13956b53dafeSWANG Cong dev_set_name(dev, "%s", ndev->name); 13961da177e4SLinus Torvalds 13978b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 13980c509a6cSEric W. Biederman /* Allow for a device specific group */ 13990c509a6cSEric W. Biederman if (*groups) 14000c509a6cSEric W. Biederman groups++; 14011da177e4SLinus Torvalds 14020c509a6cSEric W. Biederman *groups++ = &netstat_group; 140338c1a01cSJohannes Berg 140438c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) 14056b53dafeSWANG Cong if (ndev->ieee80211_ptr) 140638c1a01cSJohannes Berg *groups++ = &wireless_group; 140738c1a01cSJohannes Berg #if IS_ENABLED(CONFIG_WIRELESS_EXT) 14086b53dafeSWANG Cong else if (ndev->wireless_handlers) 140938c1a01cSJohannes Berg *groups++ = &wireless_group; 141038c1a01cSJohannes Berg #endif 141138c1a01cSJohannes Berg #endif 14128b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 14131da177e4SLinus Torvalds 14140a9627f2STom Herbert error = device_add(dev); 14150a9627f2STom Herbert if (error) 14160a9627f2STom Herbert return error; 14170a9627f2STom Herbert 14186b53dafeSWANG Cong error = register_queue_kobjects(ndev); 14190a9627f2STom Herbert if (error) { 14200a9627f2STom Herbert device_del(dev); 14210a9627f2STom Herbert return error; 14220a9627f2STom Herbert } 14230a9627f2STom Herbert 14249802c8e2SMing Lei pm_runtime_set_memalloc_noio(dev, true); 14259802c8e2SMing Lei 14260a9627f2STom Herbert return error; 14271da177e4SLinus Torvalds } 14281da177e4SLinus Torvalds 142958292cbeSTejun Heo int netdev_class_create_file_ns(struct class_attribute *class_attr, 143058292cbeSTejun Heo const void *ns) 1431b8a9787eSJay Vosburgh { 143258292cbeSTejun Heo return class_create_file_ns(&net_class, class_attr, ns); 1433b8a9787eSJay Vosburgh } 143458292cbeSTejun Heo EXPORT_SYMBOL(netdev_class_create_file_ns); 1435b8a9787eSJay Vosburgh 143658292cbeSTejun Heo void netdev_class_remove_file_ns(struct class_attribute *class_attr, 143758292cbeSTejun Heo const void *ns) 1438b8a9787eSJay Vosburgh { 143958292cbeSTejun Heo class_remove_file_ns(&net_class, class_attr, ns); 1440b8a9787eSJay Vosburgh } 144158292cbeSTejun Heo EXPORT_SYMBOL(netdev_class_remove_file_ns); 1442b8a9787eSJay Vosburgh 1443a48d4bb0SDaniel Borkmann int __init netdev_kobject_init(void) 14441da177e4SLinus Torvalds { 1445608b4b95SEric W. Biederman kobj_ns_type_register(&net_ns_type_operations); 14461da177e4SLinus Torvalds return class_register(&net_class); 14471da177e4SLinus Torvalds } 1448