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> 211da177e4SLinus Torvalds #include <linux/wireless.h> 22fec5e652STom Herbert #include <linux/vmalloc.h> 238f1546caSJohannes Berg #include <net/wext.h> 241da177e4SLinus Torvalds 25342709efSPavel Emelyanov #include "net-sysfs.h" 26342709efSPavel Emelyanov 278b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 281da177e4SLinus Torvalds static const char fmt_hex[] = "%#x\n"; 29d1102b59SDavid S. Miller static const char fmt_long_hex[] = "%#lx\n"; 301da177e4SLinus Torvalds static const char fmt_dec[] = "%d\n"; 311da177e4SLinus Torvalds static const char fmt_ulong[] = "%lu\n"; 32be1f3c2cSBen Hutchings static const char fmt_u64[] = "%llu\n"; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static inline int dev_isalive(const struct net_device *dev) 351da177e4SLinus Torvalds { 36fe9925b5SStephen Hemminger return dev->reg_state <= NETREG_REGISTERED; 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* use same locking rules as GIF* ioctl's */ 4043cb76d9SGreg Kroah-Hartman static ssize_t netdev_show(const struct device *dev, 4143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 421da177e4SLinus Torvalds ssize_t (*format)(const struct net_device *, char *)) 431da177e4SLinus Torvalds { 4443cb76d9SGreg Kroah-Hartman struct net_device *net = to_net_dev(dev); 451da177e4SLinus Torvalds ssize_t ret = -EINVAL; 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds read_lock(&dev_base_lock); 481da177e4SLinus Torvalds if (dev_isalive(net)) 491da177e4SLinus Torvalds ret = (*format)(net, buf); 501da177e4SLinus Torvalds read_unlock(&dev_base_lock); 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds return ret; 531da177e4SLinus Torvalds } 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds /* generate a show function for simple field */ 561da177e4SLinus Torvalds #define NETDEVICE_SHOW(field, format_string) \ 571da177e4SLinus Torvalds static ssize_t format_##field(const struct net_device *net, char *buf) \ 581da177e4SLinus Torvalds { \ 591da177e4SLinus Torvalds return sprintf(buf, format_string, net->field); \ 601da177e4SLinus Torvalds } \ 6143cb76d9SGreg Kroah-Hartman static ssize_t show_##field(struct device *dev, \ 6243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 631da177e4SLinus Torvalds { \ 6443cb76d9SGreg Kroah-Hartman return netdev_show(dev, attr, buf, format_##field); \ 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds /* use same locking and permission rules as SIF* ioctl's */ 6943cb76d9SGreg Kroah-Hartman static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, 701da177e4SLinus Torvalds const char *buf, size_t len, 711da177e4SLinus Torvalds int (*set)(struct net_device *, unsigned long)) 721da177e4SLinus Torvalds { 731da177e4SLinus Torvalds struct net_device *net = to_net_dev(dev); 741da177e4SLinus Torvalds char *endp; 751da177e4SLinus Torvalds unsigned long new; 761da177e4SLinus Torvalds int ret = -EINVAL; 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) 791da177e4SLinus Torvalds return -EPERM; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds new = simple_strtoul(buf, &endp, 0); 821da177e4SLinus Torvalds if (endp == buf) 831da177e4SLinus Torvalds goto err; 841da177e4SLinus Torvalds 855a5990d3SStephen Hemminger if (!rtnl_trylock()) 86336ca57cSEric W. Biederman return restart_syscall(); 875a5990d3SStephen Hemminger 881da177e4SLinus Torvalds if (dev_isalive(net)) { 891da177e4SLinus Torvalds if ((ret = (*set)(net, new)) == 0) 901da177e4SLinus Torvalds ret = len; 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds rtnl_unlock(); 931da177e4SLinus Torvalds err: 941da177e4SLinus Torvalds return ret; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 979d29672cSDavid Woodhouse NETDEVICE_SHOW(dev_id, fmt_hex); 98c1f79426SStefan Assmann NETDEVICE_SHOW(addr_assign_type, fmt_dec); 99fd586bacSKay Sievers NETDEVICE_SHOW(addr_len, fmt_dec); 100fd586bacSKay Sievers NETDEVICE_SHOW(iflink, fmt_dec); 101fd586bacSKay Sievers NETDEVICE_SHOW(ifindex, fmt_dec); 102fd586bacSKay Sievers NETDEVICE_SHOW(features, fmt_long_hex); 103fd586bacSKay Sievers NETDEVICE_SHOW(type, fmt_dec); 104b00055aaSStefan Rompf NETDEVICE_SHOW(link_mode, fmt_dec); 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds /* use same locking rules as GIFHWADDR ioctl's */ 10743cb76d9SGreg Kroah-Hartman static ssize_t show_address(struct device *dev, struct device_attribute *attr, 10843cb76d9SGreg Kroah-Hartman char *buf) 1091da177e4SLinus Torvalds { 1101da177e4SLinus Torvalds struct net_device *net = to_net_dev(dev); 1111da177e4SLinus Torvalds ssize_t ret = -EINVAL; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds read_lock(&dev_base_lock); 1141da177e4SLinus Torvalds if (dev_isalive(net)) 1157ffc49a6SMichael Chan ret = sysfs_format_mac(buf, net->dev_addr, net->addr_len); 1161da177e4SLinus Torvalds read_unlock(&dev_base_lock); 1171da177e4SLinus Torvalds return ret; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 12043cb76d9SGreg Kroah-Hartman static ssize_t show_broadcast(struct device *dev, 12143cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1221da177e4SLinus Torvalds { 1231da177e4SLinus Torvalds struct net_device *net = to_net_dev(dev); 1241da177e4SLinus Torvalds if (dev_isalive(net)) 1257ffc49a6SMichael Chan return sysfs_format_mac(buf, net->broadcast, net->addr_len); 1261da177e4SLinus Torvalds return -EINVAL; 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds 12943cb76d9SGreg Kroah-Hartman static ssize_t show_carrier(struct device *dev, 13043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 1311da177e4SLinus Torvalds { 1321da177e4SLinus Torvalds struct net_device *netdev = to_net_dev(dev); 1331da177e4SLinus Torvalds if (netif_running(netdev)) { 1341da177e4SLinus Torvalds return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds return -EINVAL; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 139d519e17eSAndy Gospodarek static ssize_t show_speed(struct device *dev, 140d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 141d519e17eSAndy Gospodarek { 142d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 143d519e17eSAndy Gospodarek int ret = -EINVAL; 144d519e17eSAndy Gospodarek 145d519e17eSAndy Gospodarek if (!rtnl_trylock()) 146d519e17eSAndy Gospodarek return restart_syscall(); 147d519e17eSAndy Gospodarek 148ac5e3af9SEric Dumazet if (netif_running(netdev) && 149ac5e3af9SEric Dumazet netdev->ethtool_ops && 150ac5e3af9SEric Dumazet netdev->ethtool_ops->get_settings) { 151d519e17eSAndy Gospodarek struct ethtool_cmd cmd = { ETHTOOL_GSET }; 152d519e17eSAndy Gospodarek 153d519e17eSAndy Gospodarek if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) 154d519e17eSAndy Gospodarek ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd)); 155d519e17eSAndy Gospodarek } 156d519e17eSAndy Gospodarek rtnl_unlock(); 157d519e17eSAndy Gospodarek return ret; 158d519e17eSAndy Gospodarek } 159d519e17eSAndy Gospodarek 160d519e17eSAndy Gospodarek static ssize_t show_duplex(struct device *dev, 161d519e17eSAndy Gospodarek struct device_attribute *attr, char *buf) 162d519e17eSAndy Gospodarek { 163d519e17eSAndy Gospodarek struct net_device *netdev = to_net_dev(dev); 164d519e17eSAndy Gospodarek int ret = -EINVAL; 165d519e17eSAndy Gospodarek 166d519e17eSAndy Gospodarek if (!rtnl_trylock()) 167d519e17eSAndy Gospodarek return restart_syscall(); 168d519e17eSAndy Gospodarek 169ac5e3af9SEric Dumazet if (netif_running(netdev) && 170ac5e3af9SEric Dumazet netdev->ethtool_ops && 171ac5e3af9SEric Dumazet netdev->ethtool_ops->get_settings) { 172d519e17eSAndy Gospodarek struct ethtool_cmd cmd = { ETHTOOL_GSET }; 173d519e17eSAndy Gospodarek 174d519e17eSAndy Gospodarek if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) 175d519e17eSAndy Gospodarek ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half"); 176d519e17eSAndy Gospodarek } 177d519e17eSAndy Gospodarek rtnl_unlock(); 178d519e17eSAndy Gospodarek return ret; 179d519e17eSAndy Gospodarek } 180d519e17eSAndy Gospodarek 18143cb76d9SGreg Kroah-Hartman static ssize_t show_dormant(struct device *dev, 18243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 183b00055aaSStefan Rompf { 184b00055aaSStefan Rompf struct net_device *netdev = to_net_dev(dev); 185b00055aaSStefan Rompf 186b00055aaSStefan Rompf if (netif_running(netdev)) 187b00055aaSStefan Rompf return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); 188b00055aaSStefan Rompf 189b00055aaSStefan Rompf return -EINVAL; 190b00055aaSStefan Rompf } 191b00055aaSStefan Rompf 19236cbd3dcSJan Engelhardt static const char *const operstates[] = { 193b00055aaSStefan Rompf "unknown", 194b00055aaSStefan Rompf "notpresent", /* currently unused */ 195b00055aaSStefan Rompf "down", 196b00055aaSStefan Rompf "lowerlayerdown", 197b00055aaSStefan Rompf "testing", /* currently unused */ 198b00055aaSStefan Rompf "dormant", 199b00055aaSStefan Rompf "up" 200b00055aaSStefan Rompf }; 201b00055aaSStefan Rompf 20243cb76d9SGreg Kroah-Hartman static ssize_t show_operstate(struct device *dev, 20343cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 204b00055aaSStefan Rompf { 205b00055aaSStefan Rompf const struct net_device *netdev = to_net_dev(dev); 206b00055aaSStefan Rompf unsigned char operstate; 207b00055aaSStefan Rompf 208b00055aaSStefan Rompf read_lock(&dev_base_lock); 209b00055aaSStefan Rompf operstate = netdev->operstate; 210b00055aaSStefan Rompf if (!netif_running(netdev)) 211b00055aaSStefan Rompf operstate = IF_OPER_DOWN; 212b00055aaSStefan Rompf read_unlock(&dev_base_lock); 213b00055aaSStefan Rompf 214e3a5cd9eSAdrian Bunk if (operstate >= ARRAY_SIZE(operstates)) 215b00055aaSStefan Rompf return -EINVAL; /* should not happen */ 216b00055aaSStefan Rompf 217b00055aaSStefan Rompf return sprintf(buf, "%s\n", operstates[operstate]); 218b00055aaSStefan Rompf } 219b00055aaSStefan Rompf 2201da177e4SLinus Torvalds /* read-write attributes */ 2211da177e4SLinus Torvalds NETDEVICE_SHOW(mtu, fmt_dec); 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds static int change_mtu(struct net_device *net, unsigned long new_mtu) 2241da177e4SLinus Torvalds { 2251da177e4SLinus Torvalds return dev_set_mtu(net, (int) new_mtu); 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 22843cb76d9SGreg Kroah-Hartman static ssize_t store_mtu(struct device *dev, struct device_attribute *attr, 22943cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2301da177e4SLinus Torvalds { 23143cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_mtu); 2321da177e4SLinus Torvalds } 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds NETDEVICE_SHOW(flags, fmt_hex); 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds static int change_flags(struct net_device *net, unsigned long new_flags) 2371da177e4SLinus Torvalds { 2381da177e4SLinus Torvalds return dev_change_flags(net, (unsigned) new_flags); 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 24143cb76d9SGreg Kroah-Hartman static ssize_t store_flags(struct device *dev, struct device_attribute *attr, 24243cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2431da177e4SLinus Torvalds { 24443cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_flags); 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds NETDEVICE_SHOW(tx_queue_len, fmt_ulong); 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds static int change_tx_queue_len(struct net_device *net, unsigned long new_len) 2501da177e4SLinus Torvalds { 2511da177e4SLinus Torvalds net->tx_queue_len = new_len; 2521da177e4SLinus Torvalds return 0; 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds 25543cb76d9SGreg Kroah-Hartman static ssize_t store_tx_queue_len(struct device *dev, 25643cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 25743cb76d9SGreg Kroah-Hartman const char *buf, size_t len) 2581da177e4SLinus Torvalds { 25943cb76d9SGreg Kroah-Hartman return netdev_store(dev, attr, buf, len, change_tx_queue_len); 2601da177e4SLinus Torvalds } 2611da177e4SLinus Torvalds 2620b815a1aSStephen Hemminger static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr, 2630b815a1aSStephen Hemminger const char *buf, size_t len) 2640b815a1aSStephen Hemminger { 2650b815a1aSStephen Hemminger struct net_device *netdev = to_net_dev(dev); 2660b815a1aSStephen Hemminger size_t count = len; 2670b815a1aSStephen Hemminger ssize_t ret; 2680b815a1aSStephen Hemminger 2690b815a1aSStephen Hemminger if (!capable(CAP_NET_ADMIN)) 2700b815a1aSStephen Hemminger return -EPERM; 2710b815a1aSStephen Hemminger 2720b815a1aSStephen Hemminger /* ignore trailing newline */ 2730b815a1aSStephen Hemminger if (len > 0 && buf[len - 1] == '\n') 2740b815a1aSStephen Hemminger --count; 2750b815a1aSStephen Hemminger 276336ca57cSEric W. Biederman if (!rtnl_trylock()) 277336ca57cSEric W. Biederman return restart_syscall(); 2780b815a1aSStephen Hemminger ret = dev_set_alias(netdev, buf, count); 2790b815a1aSStephen Hemminger rtnl_unlock(); 2800b815a1aSStephen Hemminger 2810b815a1aSStephen Hemminger return ret < 0 ? ret : len; 2820b815a1aSStephen Hemminger } 2830b815a1aSStephen Hemminger 2840b815a1aSStephen Hemminger static ssize_t show_ifalias(struct device *dev, 2850b815a1aSStephen Hemminger struct device_attribute *attr, char *buf) 2860b815a1aSStephen Hemminger { 2870b815a1aSStephen Hemminger const struct net_device *netdev = to_net_dev(dev); 2880b815a1aSStephen Hemminger ssize_t ret = 0; 2890b815a1aSStephen Hemminger 290336ca57cSEric W. Biederman if (!rtnl_trylock()) 291336ca57cSEric W. Biederman return restart_syscall(); 2920b815a1aSStephen Hemminger if (netdev->ifalias) 2930b815a1aSStephen Hemminger ret = sprintf(buf, "%s\n", netdev->ifalias); 2940b815a1aSStephen Hemminger rtnl_unlock(); 2950b815a1aSStephen Hemminger return ret; 2960b815a1aSStephen Hemminger } 2970b815a1aSStephen Hemminger 29843cb76d9SGreg Kroah-Hartman static struct device_attribute net_class_attributes[] = { 299c1f79426SStefan Assmann __ATTR(addr_assign_type, S_IRUGO, show_addr_assign_type, NULL), 300fd586bacSKay Sievers __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), 3019d29672cSDavid Woodhouse __ATTR(dev_id, S_IRUGO, show_dev_id, NULL), 3020b815a1aSStephen Hemminger __ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias), 303fd586bacSKay Sievers __ATTR(iflink, S_IRUGO, show_iflink, NULL), 304fd586bacSKay Sievers __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), 305fd586bacSKay Sievers __ATTR(features, S_IRUGO, show_features, NULL), 306fd586bacSKay Sievers __ATTR(type, S_IRUGO, show_type, NULL), 307b00055aaSStefan Rompf __ATTR(link_mode, S_IRUGO, show_link_mode, NULL), 308fd586bacSKay Sievers __ATTR(address, S_IRUGO, show_address, NULL), 309fd586bacSKay Sievers __ATTR(broadcast, S_IRUGO, show_broadcast, NULL), 310fd586bacSKay Sievers __ATTR(carrier, S_IRUGO, show_carrier, NULL), 311d519e17eSAndy Gospodarek __ATTR(speed, S_IRUGO, show_speed, NULL), 312d519e17eSAndy Gospodarek __ATTR(duplex, S_IRUGO, show_duplex, NULL), 313b00055aaSStefan Rompf __ATTR(dormant, S_IRUGO, show_dormant, NULL), 314b00055aaSStefan Rompf __ATTR(operstate, S_IRUGO, show_operstate, NULL), 315fd586bacSKay Sievers __ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu), 316fd586bacSKay Sievers __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags), 317fd586bacSKay Sievers __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, 318fd586bacSKay Sievers store_tx_queue_len), 319fd586bacSKay Sievers {} 3201da177e4SLinus Torvalds }; 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds /* Show a given an attribute in the statistics group */ 32343cb76d9SGreg Kroah-Hartman static ssize_t netstat_show(const struct device *d, 32443cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf, 3251da177e4SLinus Torvalds unsigned long offset) 3261da177e4SLinus Torvalds { 32743cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 3281da177e4SLinus Torvalds ssize_t ret = -EINVAL; 3291da177e4SLinus Torvalds 330be1f3c2cSBen Hutchings WARN_ON(offset > sizeof(struct rtnl_link_stats64) || 331be1f3c2cSBen Hutchings offset % sizeof(u64) != 0); 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds read_lock(&dev_base_lock); 33496e74088SPavel Emelyanov if (dev_isalive(dev)) { 33528172739SEric Dumazet struct rtnl_link_stats64 temp; 33628172739SEric Dumazet const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); 33728172739SEric Dumazet 338be1f3c2cSBen Hutchings ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *) stats) + offset)); 33996e74088SPavel Emelyanov } 3401da177e4SLinus Torvalds read_unlock(&dev_base_lock); 3411da177e4SLinus Torvalds return ret; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds /* generate a read-only statistics attribute */ 3451da177e4SLinus Torvalds #define NETSTAT_ENTRY(name) \ 34643cb76d9SGreg Kroah-Hartman static ssize_t show_##name(struct device *d, \ 34743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 3481da177e4SLinus Torvalds { \ 34943cb76d9SGreg Kroah-Hartman return netstat_show(d, attr, buf, \ 350be1f3c2cSBen Hutchings offsetof(struct rtnl_link_stats64, name)); \ 3511da177e4SLinus Torvalds } \ 35243cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds NETSTAT_ENTRY(rx_packets); 3551da177e4SLinus Torvalds NETSTAT_ENTRY(tx_packets); 3561da177e4SLinus Torvalds NETSTAT_ENTRY(rx_bytes); 3571da177e4SLinus Torvalds NETSTAT_ENTRY(tx_bytes); 3581da177e4SLinus Torvalds NETSTAT_ENTRY(rx_errors); 3591da177e4SLinus Torvalds NETSTAT_ENTRY(tx_errors); 3601da177e4SLinus Torvalds NETSTAT_ENTRY(rx_dropped); 3611da177e4SLinus Torvalds NETSTAT_ENTRY(tx_dropped); 3621da177e4SLinus Torvalds NETSTAT_ENTRY(multicast); 3631da177e4SLinus Torvalds NETSTAT_ENTRY(collisions); 3641da177e4SLinus Torvalds NETSTAT_ENTRY(rx_length_errors); 3651da177e4SLinus Torvalds NETSTAT_ENTRY(rx_over_errors); 3661da177e4SLinus Torvalds NETSTAT_ENTRY(rx_crc_errors); 3671da177e4SLinus Torvalds NETSTAT_ENTRY(rx_frame_errors); 3681da177e4SLinus Torvalds NETSTAT_ENTRY(rx_fifo_errors); 3691da177e4SLinus Torvalds NETSTAT_ENTRY(rx_missed_errors); 3701da177e4SLinus Torvalds NETSTAT_ENTRY(tx_aborted_errors); 3711da177e4SLinus Torvalds NETSTAT_ENTRY(tx_carrier_errors); 3721da177e4SLinus Torvalds NETSTAT_ENTRY(tx_fifo_errors); 3731da177e4SLinus Torvalds NETSTAT_ENTRY(tx_heartbeat_errors); 3741da177e4SLinus Torvalds NETSTAT_ENTRY(tx_window_errors); 3751da177e4SLinus Torvalds NETSTAT_ENTRY(rx_compressed); 3761da177e4SLinus Torvalds NETSTAT_ENTRY(tx_compressed); 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds static struct attribute *netstat_attrs[] = { 37943cb76d9SGreg Kroah-Hartman &dev_attr_rx_packets.attr, 38043cb76d9SGreg Kroah-Hartman &dev_attr_tx_packets.attr, 38143cb76d9SGreg Kroah-Hartman &dev_attr_rx_bytes.attr, 38243cb76d9SGreg Kroah-Hartman &dev_attr_tx_bytes.attr, 38343cb76d9SGreg Kroah-Hartman &dev_attr_rx_errors.attr, 38443cb76d9SGreg Kroah-Hartman &dev_attr_tx_errors.attr, 38543cb76d9SGreg Kroah-Hartman &dev_attr_rx_dropped.attr, 38643cb76d9SGreg Kroah-Hartman &dev_attr_tx_dropped.attr, 38743cb76d9SGreg Kroah-Hartman &dev_attr_multicast.attr, 38843cb76d9SGreg Kroah-Hartman &dev_attr_collisions.attr, 38943cb76d9SGreg Kroah-Hartman &dev_attr_rx_length_errors.attr, 39043cb76d9SGreg Kroah-Hartman &dev_attr_rx_over_errors.attr, 39143cb76d9SGreg Kroah-Hartman &dev_attr_rx_crc_errors.attr, 39243cb76d9SGreg Kroah-Hartman &dev_attr_rx_frame_errors.attr, 39343cb76d9SGreg Kroah-Hartman &dev_attr_rx_fifo_errors.attr, 39443cb76d9SGreg Kroah-Hartman &dev_attr_rx_missed_errors.attr, 39543cb76d9SGreg Kroah-Hartman &dev_attr_tx_aborted_errors.attr, 39643cb76d9SGreg Kroah-Hartman &dev_attr_tx_carrier_errors.attr, 39743cb76d9SGreg Kroah-Hartman &dev_attr_tx_fifo_errors.attr, 39843cb76d9SGreg Kroah-Hartman &dev_attr_tx_heartbeat_errors.attr, 39943cb76d9SGreg Kroah-Hartman &dev_attr_tx_window_errors.attr, 40043cb76d9SGreg Kroah-Hartman &dev_attr_rx_compressed.attr, 40143cb76d9SGreg Kroah-Hartman &dev_attr_tx_compressed.attr, 4021da177e4SLinus Torvalds NULL 4031da177e4SLinus Torvalds }; 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds static struct attribute_group netstat_group = { 4071da177e4SLinus Torvalds .name = "statistics", 4081da177e4SLinus Torvalds .attrs = netstat_attrs, 4091da177e4SLinus Torvalds }; 4101da177e4SLinus Torvalds 41122bb1be4SJohannes Berg #ifdef CONFIG_WIRELESS_EXT_SYSFS 4121da177e4SLinus Torvalds /* helper function that does all the locking etc for wireless stats */ 41343cb76d9SGreg Kroah-Hartman static ssize_t wireless_show(struct device *d, char *buf, 4141da177e4SLinus Torvalds ssize_t (*format)(const struct iw_statistics *, 4151da177e4SLinus Torvalds char *)) 4161da177e4SLinus Torvalds { 41743cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 4188f1546caSJohannes Berg const struct iw_statistics *iw; 4191da177e4SLinus Torvalds ssize_t ret = -EINVAL; 4201da177e4SLinus Torvalds 421b8afe641SEric W. Biederman if (!rtnl_trylock()) 422b8afe641SEric W. Biederman return restart_syscall(); 4236dd214b5SAndrey Borzenkov if (dev_isalive(dev)) { 4248f1546caSJohannes Berg iw = get_wireless_stats(dev); 4258f1546caSJohannes Berg if (iw) 4261da177e4SLinus Torvalds ret = (*format)(iw, buf); 4276dd214b5SAndrey Borzenkov } 428a160ee69SJohannes Berg rtnl_unlock(); 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds return ret; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds /* show function template for wireless fields */ 4341da177e4SLinus Torvalds #define WIRELESS_SHOW(name, field, format_string) \ 4351da177e4SLinus Torvalds static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \ 4361da177e4SLinus Torvalds { \ 4371da177e4SLinus Torvalds return sprintf(buf, format_string, iw->field); \ 4381da177e4SLinus Torvalds } \ 43943cb76d9SGreg Kroah-Hartman static ssize_t show_iw_##name(struct device *d, \ 44043cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) \ 4411da177e4SLinus Torvalds { \ 44243cb76d9SGreg Kroah-Hartman return wireless_show(d, buf, format_iw_##name); \ 4431da177e4SLinus Torvalds } \ 44443cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds WIRELESS_SHOW(status, status, fmt_hex); 4471da177e4SLinus Torvalds WIRELESS_SHOW(link, qual.qual, fmt_dec); 4481da177e4SLinus Torvalds WIRELESS_SHOW(level, qual.level, fmt_dec); 4491da177e4SLinus Torvalds WIRELESS_SHOW(noise, qual.noise, fmt_dec); 4501da177e4SLinus Torvalds WIRELESS_SHOW(nwid, discard.nwid, fmt_dec); 4511da177e4SLinus Torvalds WIRELESS_SHOW(crypt, discard.code, fmt_dec); 4521da177e4SLinus Torvalds WIRELESS_SHOW(fragment, discard.fragment, fmt_dec); 4531da177e4SLinus Torvalds WIRELESS_SHOW(misc, discard.misc, fmt_dec); 4541da177e4SLinus Torvalds WIRELESS_SHOW(retries, discard.retries, fmt_dec); 4551da177e4SLinus Torvalds WIRELESS_SHOW(beacon, miss.beacon, fmt_dec); 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds static struct attribute *wireless_attrs[] = { 45843cb76d9SGreg Kroah-Hartman &dev_attr_status.attr, 45943cb76d9SGreg Kroah-Hartman &dev_attr_link.attr, 46043cb76d9SGreg Kroah-Hartman &dev_attr_level.attr, 46143cb76d9SGreg Kroah-Hartman &dev_attr_noise.attr, 46243cb76d9SGreg Kroah-Hartman &dev_attr_nwid.attr, 46343cb76d9SGreg Kroah-Hartman &dev_attr_crypt.attr, 46443cb76d9SGreg Kroah-Hartman &dev_attr_fragment.attr, 46543cb76d9SGreg Kroah-Hartman &dev_attr_retries.attr, 46643cb76d9SGreg Kroah-Hartman &dev_attr_misc.attr, 46743cb76d9SGreg Kroah-Hartman &dev_attr_beacon.attr, 4681da177e4SLinus Torvalds NULL 4691da177e4SLinus Torvalds }; 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds static struct attribute_group wireless_group = { 4721da177e4SLinus Torvalds .name = "wireless", 4731da177e4SLinus Torvalds .attrs = wireless_attrs, 4741da177e4SLinus Torvalds }; 4751da177e4SLinus Torvalds #endif 476d6523ddfSEric W. Biederman #endif /* CONFIG_SYSFS */ 4771da177e4SLinus Torvalds 47830bde1f5SStephen Rothwell #ifdef CONFIG_RPS 4790a9627f2STom Herbert /* 4800a9627f2STom Herbert * RX queue sysfs structures and functions. 4810a9627f2STom Herbert */ 4820a9627f2STom Herbert struct rx_queue_attribute { 4830a9627f2STom Herbert struct attribute attr; 4840a9627f2STom Herbert ssize_t (*show)(struct netdev_rx_queue *queue, 4850a9627f2STom Herbert struct rx_queue_attribute *attr, char *buf); 4860a9627f2STom Herbert ssize_t (*store)(struct netdev_rx_queue *queue, 4870a9627f2STom Herbert struct rx_queue_attribute *attr, const char *buf, size_t len); 4880a9627f2STom Herbert }; 4890a9627f2STom Herbert #define to_rx_queue_attr(_attr) container_of(_attr, \ 4900a9627f2STom Herbert struct rx_queue_attribute, attr) 4910a9627f2STom Herbert 4920a9627f2STom Herbert #define to_rx_queue(obj) container_of(obj, struct netdev_rx_queue, kobj) 4930a9627f2STom Herbert 4940a9627f2STom Herbert static ssize_t rx_queue_attr_show(struct kobject *kobj, struct attribute *attr, 4950a9627f2STom Herbert char *buf) 4960a9627f2STom Herbert { 4970a9627f2STom Herbert struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 4980a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 4990a9627f2STom Herbert 5000a9627f2STom Herbert if (!attribute->show) 5010a9627f2STom Herbert return -EIO; 5020a9627f2STom Herbert 5030a9627f2STom Herbert return attribute->show(queue, attribute, buf); 5040a9627f2STom Herbert } 5050a9627f2STom Herbert 5060a9627f2STom Herbert static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr, 5070a9627f2STom Herbert const char *buf, size_t count) 5080a9627f2STom Herbert { 5090a9627f2STom Herbert struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); 5100a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 5110a9627f2STom Herbert 5120a9627f2STom Herbert if (!attribute->store) 5130a9627f2STom Herbert return -EIO; 5140a9627f2STom Herbert 5150a9627f2STom Herbert return attribute->store(queue, attribute, buf, count); 5160a9627f2STom Herbert } 5170a9627f2STom Herbert 518fa50d645Sstephen hemminger static const struct sysfs_ops rx_queue_sysfs_ops = { 5190a9627f2STom Herbert .show = rx_queue_attr_show, 5200a9627f2STom Herbert .store = rx_queue_attr_store, 5210a9627f2STom Herbert }; 5220a9627f2STom Herbert 5230a9627f2STom Herbert static ssize_t show_rps_map(struct netdev_rx_queue *queue, 5240a9627f2STom Herbert struct rx_queue_attribute *attribute, char *buf) 5250a9627f2STom Herbert { 5260a9627f2STom Herbert struct rps_map *map; 5270a9627f2STom Herbert cpumask_var_t mask; 5280a9627f2STom Herbert size_t len = 0; 5290a9627f2STom Herbert int i; 5300a9627f2STom Herbert 5310a9627f2STom Herbert if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) 5320a9627f2STom Herbert return -ENOMEM; 5330a9627f2STom Herbert 5340a9627f2STom Herbert rcu_read_lock(); 5350a9627f2STom Herbert map = rcu_dereference(queue->rps_map); 5360a9627f2STom Herbert if (map) 5370a9627f2STom Herbert for (i = 0; i < map->len; i++) 5380a9627f2STom Herbert cpumask_set_cpu(map->cpus[i], mask); 5390a9627f2STom Herbert 5400a9627f2STom Herbert len += cpumask_scnprintf(buf + len, PAGE_SIZE, mask); 5410a9627f2STom Herbert if (PAGE_SIZE - len < 3) { 5420a9627f2STom Herbert rcu_read_unlock(); 5430a9627f2STom Herbert free_cpumask_var(mask); 5440a9627f2STom Herbert return -EINVAL; 5450a9627f2STom Herbert } 5460a9627f2STom Herbert rcu_read_unlock(); 5470a9627f2STom Herbert 5480a9627f2STom Herbert free_cpumask_var(mask); 5490a9627f2STom Herbert len += sprintf(buf + len, "\n"); 5500a9627f2STom Herbert return len; 5510a9627f2STom Herbert } 5520a9627f2STom Herbert 5530a9627f2STom Herbert static void rps_map_release(struct rcu_head *rcu) 5540a9627f2STom Herbert { 5550a9627f2STom Herbert struct rps_map *map = container_of(rcu, struct rps_map, rcu); 5560a9627f2STom Herbert 5570a9627f2STom Herbert kfree(map); 5580a9627f2STom Herbert } 5590a9627f2STom Herbert 560f5acb907SEric Dumazet static ssize_t store_rps_map(struct netdev_rx_queue *queue, 5610a9627f2STom Herbert struct rx_queue_attribute *attribute, 5620a9627f2STom Herbert const char *buf, size_t len) 5630a9627f2STom Herbert { 5640a9627f2STom Herbert struct rps_map *old_map, *map; 5650a9627f2STom Herbert cpumask_var_t mask; 5660a9627f2STom Herbert int err, cpu, i; 5670a9627f2STom Herbert static DEFINE_SPINLOCK(rps_map_lock); 5680a9627f2STom Herbert 5690a9627f2STom Herbert if (!capable(CAP_NET_ADMIN)) 5700a9627f2STom Herbert return -EPERM; 5710a9627f2STom Herbert 5720a9627f2STom Herbert if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 5730a9627f2STom Herbert return -ENOMEM; 5740a9627f2STom Herbert 5750a9627f2STom Herbert err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); 5760a9627f2STom Herbert if (err) { 5770a9627f2STom Herbert free_cpumask_var(mask); 5780a9627f2STom Herbert return err; 5790a9627f2STom Herbert } 5800a9627f2STom Herbert 5810a9627f2STom Herbert map = kzalloc(max_t(unsigned, 5820a9627f2STom Herbert RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), 5830a9627f2STom Herbert GFP_KERNEL); 5840a9627f2STom Herbert if (!map) { 5850a9627f2STom Herbert free_cpumask_var(mask); 5860a9627f2STom Herbert return -ENOMEM; 5870a9627f2STom Herbert } 5880a9627f2STom Herbert 5890a9627f2STom Herbert i = 0; 5900a9627f2STom Herbert for_each_cpu_and(cpu, mask, cpu_online_mask) 5910a9627f2STom Herbert map->cpus[i++] = cpu; 5920a9627f2STom Herbert 5930a9627f2STom Herbert if (i) 5940a9627f2STom Herbert map->len = i; 5950a9627f2STom Herbert else { 5960a9627f2STom Herbert kfree(map); 5970a9627f2STom Herbert map = NULL; 5980a9627f2STom Herbert } 5990a9627f2STom Herbert 6000a9627f2STom Herbert spin_lock(&rps_map_lock); 6016e3f7fafSEric Dumazet old_map = rcu_dereference_protected(queue->rps_map, 6026e3f7fafSEric Dumazet lockdep_is_held(&rps_map_lock)); 6030a9627f2STom Herbert rcu_assign_pointer(queue->rps_map, map); 6040a9627f2STom Herbert spin_unlock(&rps_map_lock); 6050a9627f2STom Herbert 6060a9627f2STom Herbert if (old_map) 6070a9627f2STom Herbert call_rcu(&old_map->rcu, rps_map_release); 6080a9627f2STom Herbert 6090a9627f2STom Herbert free_cpumask_var(mask); 6100a9627f2STom Herbert return len; 6110a9627f2STom Herbert } 6120a9627f2STom Herbert 613fec5e652STom Herbert static ssize_t show_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 614fec5e652STom Herbert struct rx_queue_attribute *attr, 615fec5e652STom Herbert char *buf) 616fec5e652STom Herbert { 617fec5e652STom Herbert struct rps_dev_flow_table *flow_table; 618fec5e652STom Herbert unsigned int val = 0; 619fec5e652STom Herbert 620fec5e652STom Herbert rcu_read_lock(); 621fec5e652STom Herbert flow_table = rcu_dereference(queue->rps_flow_table); 622fec5e652STom Herbert if (flow_table) 623fec5e652STom Herbert val = flow_table->mask + 1; 624fec5e652STom Herbert rcu_read_unlock(); 625fec5e652STom Herbert 626fec5e652STom Herbert return sprintf(buf, "%u\n", val); 627fec5e652STom Herbert } 628fec5e652STom Herbert 629fec5e652STom Herbert static void rps_dev_flow_table_release_work(struct work_struct *work) 630fec5e652STom Herbert { 631fec5e652STom Herbert struct rps_dev_flow_table *table = container_of(work, 632fec5e652STom Herbert struct rps_dev_flow_table, free_work); 633fec5e652STom Herbert 634fec5e652STom Herbert vfree(table); 635fec5e652STom Herbert } 636fec5e652STom Herbert 637fec5e652STom Herbert static void rps_dev_flow_table_release(struct rcu_head *rcu) 638fec5e652STom Herbert { 639fec5e652STom Herbert struct rps_dev_flow_table *table = container_of(rcu, 640fec5e652STom Herbert struct rps_dev_flow_table, rcu); 641fec5e652STom Herbert 642fec5e652STom Herbert INIT_WORK(&table->free_work, rps_dev_flow_table_release_work); 643fec5e652STom Herbert schedule_work(&table->free_work); 644fec5e652STom Herbert } 645fec5e652STom Herbert 646f5acb907SEric Dumazet static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, 647fec5e652STom Herbert struct rx_queue_attribute *attr, 648fec5e652STom Herbert const char *buf, size_t len) 649fec5e652STom Herbert { 650fec5e652STom Herbert unsigned int count; 651fec5e652STom Herbert char *endp; 652fec5e652STom Herbert struct rps_dev_flow_table *table, *old_table; 653fec5e652STom Herbert static DEFINE_SPINLOCK(rps_dev_flow_lock); 654fec5e652STom Herbert 655fec5e652STom Herbert if (!capable(CAP_NET_ADMIN)) 656fec5e652STom Herbert return -EPERM; 657fec5e652STom Herbert 658fec5e652STom Herbert count = simple_strtoul(buf, &endp, 0); 659fec5e652STom Herbert if (endp == buf) 660fec5e652STom Herbert return -EINVAL; 661fec5e652STom Herbert 662fec5e652STom Herbert if (count) { 663fec5e652STom Herbert int i; 664fec5e652STom Herbert 665fec5e652STom Herbert if (count > 1<<30) { 666fec5e652STom Herbert /* Enforce a limit to prevent overflow */ 667fec5e652STom Herbert return -EINVAL; 668fec5e652STom Herbert } 669fec5e652STom Herbert count = roundup_pow_of_two(count); 670fec5e652STom Herbert table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(count)); 671fec5e652STom Herbert if (!table) 672fec5e652STom Herbert return -ENOMEM; 673fec5e652STom Herbert 674fec5e652STom Herbert table->mask = count - 1; 675fec5e652STom Herbert for (i = 0; i < count; i++) 676fec5e652STom Herbert table->flows[i].cpu = RPS_NO_CPU; 677fec5e652STom Herbert } else 678fec5e652STom Herbert table = NULL; 679fec5e652STom Herbert 680fec5e652STom Herbert spin_lock(&rps_dev_flow_lock); 6816e3f7fafSEric Dumazet old_table = rcu_dereference_protected(queue->rps_flow_table, 6826e3f7fafSEric Dumazet lockdep_is_held(&rps_dev_flow_lock)); 683fec5e652STom Herbert rcu_assign_pointer(queue->rps_flow_table, table); 684fec5e652STom Herbert spin_unlock(&rps_dev_flow_lock); 685fec5e652STom Herbert 686fec5e652STom Herbert if (old_table) 687fec5e652STom Herbert call_rcu(&old_table->rcu, rps_dev_flow_table_release); 688fec5e652STom Herbert 689fec5e652STom Herbert return len; 690fec5e652STom Herbert } 691fec5e652STom Herbert 6920a9627f2STom Herbert static struct rx_queue_attribute rps_cpus_attribute = 6930a9627f2STom Herbert __ATTR(rps_cpus, S_IRUGO | S_IWUSR, show_rps_map, store_rps_map); 6940a9627f2STom Herbert 695fec5e652STom Herbert 696fec5e652STom Herbert static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute = 697fec5e652STom Herbert __ATTR(rps_flow_cnt, S_IRUGO | S_IWUSR, 698fec5e652STom Herbert show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt); 699fec5e652STom Herbert 7000a9627f2STom Herbert static struct attribute *rx_queue_default_attrs[] = { 7010a9627f2STom Herbert &rps_cpus_attribute.attr, 702fec5e652STom Herbert &rps_dev_flow_table_cnt_attribute.attr, 7030a9627f2STom Herbert NULL 7040a9627f2STom Herbert }; 7050a9627f2STom Herbert 7060a9627f2STom Herbert static void rx_queue_release(struct kobject *kobj) 7070a9627f2STom Herbert { 7080a9627f2STom Herbert struct netdev_rx_queue *queue = to_rx_queue(kobj); 7096e3f7fafSEric Dumazet struct rps_map *map; 7106e3f7fafSEric Dumazet struct rps_dev_flow_table *flow_table; 7110a9627f2STom Herbert 712fec5e652STom Herbert 7136e3f7fafSEric Dumazet map = rcu_dereference_raw(queue->rps_map); 7146e3f7fafSEric Dumazet if (map) 7156e3f7fafSEric Dumazet call_rcu(&map->rcu, rps_map_release); 7166e3f7fafSEric Dumazet 7176e3f7fafSEric Dumazet flow_table = rcu_dereference_raw(queue->rps_flow_table); 7186e3f7fafSEric Dumazet if (flow_table) 7196e3f7fafSEric Dumazet call_rcu(&flow_table->rcu, rps_dev_flow_table_release); 7200a9627f2STom Herbert 721*fe822240STom Herbert dev_put(queue->dev); 7220a9627f2STom Herbert } 7230a9627f2STom Herbert 7240a9627f2STom Herbert static struct kobj_type rx_queue_ktype = { 7250a9627f2STom Herbert .sysfs_ops = &rx_queue_sysfs_ops, 7260a9627f2STom Herbert .release = rx_queue_release, 7270a9627f2STom Herbert .default_attrs = rx_queue_default_attrs, 7280a9627f2STom Herbert }; 7290a9627f2STom Herbert 7300a9627f2STom Herbert static int rx_queue_add_kobject(struct net_device *net, int index) 7310a9627f2STom Herbert { 7320a9627f2STom Herbert struct netdev_rx_queue *queue = net->_rx + index; 7330a9627f2STom Herbert struct kobject *kobj = &queue->kobj; 7340a9627f2STom Herbert int error = 0; 7350a9627f2STom Herbert 7360a9627f2STom Herbert kobj->kset = net->queues_kset; 7370a9627f2STom Herbert error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, 7380a9627f2STom Herbert "rx-%u", index); 7390a9627f2STom Herbert if (error) { 7400a9627f2STom Herbert kobject_put(kobj); 7410a9627f2STom Herbert return error; 7420a9627f2STom Herbert } 7430a9627f2STom Herbert 7440a9627f2STom Herbert kobject_uevent(kobj, KOBJ_ADD); 745*fe822240STom Herbert dev_hold(queue->dev); 7460a9627f2STom Herbert 7470a9627f2STom Herbert return error; 7480a9627f2STom Herbert } 7490a9627f2STom Herbert 75062fe0b40SBen Hutchings int 75162fe0b40SBen Hutchings net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) 7520a9627f2STom Herbert { 7530a9627f2STom Herbert int i; 7540a9627f2STom Herbert int error = 0; 7550a9627f2STom Herbert 75662fe0b40SBen Hutchings for (i = old_num; i < new_num; i++) { 7570a9627f2STom Herbert error = rx_queue_add_kobject(net, i); 75862fe0b40SBen Hutchings if (error) { 75962fe0b40SBen Hutchings new_num = old_num; 7600a9627f2STom Herbert break; 7610a9627f2STom Herbert } 76262fe0b40SBen Hutchings } 7630a9627f2STom Herbert 76462fe0b40SBen Hutchings while (--i >= new_num) 7650a9627f2STom Herbert kobject_put(&net->_rx[i].kobj); 7660a9627f2STom Herbert 7670a9627f2STom Herbert return error; 7680a9627f2STom Herbert } 7690a9627f2STom Herbert 77062fe0b40SBen Hutchings static int rx_queue_register_kobjects(struct net_device *net) 77162fe0b40SBen Hutchings { 77262fe0b40SBen Hutchings net->queues_kset = kset_create_and_add("queues", 77362fe0b40SBen Hutchings NULL, &net->dev.kobj); 77462fe0b40SBen Hutchings if (!net->queues_kset) 77562fe0b40SBen Hutchings return -ENOMEM; 77662fe0b40SBen Hutchings return net_rx_queue_update_kobjects(net, 0, net->real_num_rx_queues); 77762fe0b40SBen Hutchings } 77862fe0b40SBen Hutchings 7790a9627f2STom Herbert static void rx_queue_remove_kobjects(struct net_device *net) 7800a9627f2STom Herbert { 78162fe0b40SBen Hutchings net_rx_queue_update_kobjects(net, net->real_num_rx_queues, 0); 7820a9627f2STom Herbert kset_unregister(net->queues_kset); 7830a9627f2STom Herbert } 78430bde1f5SStephen Rothwell #endif /* CONFIG_RPS */ 785608b4b95SEric W. Biederman 786608b4b95SEric W. Biederman static const void *net_current_ns(void) 787608b4b95SEric W. Biederman { 788608b4b95SEric W. Biederman return current->nsproxy->net_ns; 789608b4b95SEric W. Biederman } 790608b4b95SEric W. Biederman 791608b4b95SEric W. Biederman static const void *net_initial_ns(void) 792608b4b95SEric W. Biederman { 793608b4b95SEric W. Biederman return &init_net; 794608b4b95SEric W. Biederman } 795608b4b95SEric W. Biederman 796608b4b95SEric W. Biederman static const void *net_netlink_ns(struct sock *sk) 797608b4b95SEric W. Biederman { 798608b4b95SEric W. Biederman return sock_net(sk); 799608b4b95SEric W. Biederman } 800608b4b95SEric W. Biederman 80104600794SJohannes Berg struct kobj_ns_type_operations net_ns_type_operations = { 802608b4b95SEric W. Biederman .type = KOBJ_NS_TYPE_NET, 803608b4b95SEric W. Biederman .current_ns = net_current_ns, 804608b4b95SEric W. Biederman .netlink_ns = net_netlink_ns, 805608b4b95SEric W. Biederman .initial_ns = net_initial_ns, 806608b4b95SEric W. Biederman }; 80704600794SJohannes Berg EXPORT_SYMBOL_GPL(net_ns_type_operations); 808608b4b95SEric W. Biederman 809608b4b95SEric W. Biederman static void net_kobj_ns_exit(struct net *net) 810608b4b95SEric W. Biederman { 811608b4b95SEric W. Biederman kobj_ns_exit(KOBJ_NS_TYPE_NET, net); 812608b4b95SEric W. Biederman } 813608b4b95SEric W. Biederman 814d6523ddfSEric W. Biederman static struct pernet_operations kobj_net_ops = { 815608b4b95SEric W. Biederman .exit = net_kobj_ns_exit, 816608b4b95SEric W. Biederman }; 817608b4b95SEric W. Biederman 8188b41d188SEric W. Biederman 8191da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG 8207eff2e7aSKay Sievers static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) 8211da177e4SLinus Torvalds { 82243cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 8237eff2e7aSKay Sievers int retval; 8241da177e4SLinus Torvalds 825312c004dSKay Sievers /* pass interface to uevent. */ 8267eff2e7aSKay Sievers retval = add_uevent_var(env, "INTERFACE=%s", dev->name); 827bf62456eSEric Rannaud if (retval) 828bf62456eSEric Rannaud goto exit; 8291da177e4SLinus Torvalds 830ca2f37dbSJean Tourrilhes /* pass ifindex to uevent. 831ca2f37dbSJean Tourrilhes * ifindex is useful as it won't change (interface name may change) 832ca2f37dbSJean Tourrilhes * and is what RtNetlink uses natively. */ 8337eff2e7aSKay Sievers retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); 834ca2f37dbSJean Tourrilhes 835bf62456eSEric Rannaud exit: 836bf62456eSEric Rannaud return retval; 8371da177e4SLinus Torvalds } 8381da177e4SLinus Torvalds #endif 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds /* 8411da177e4SLinus Torvalds * netdev_release -- destroy and free a dead device. 84243cb76d9SGreg Kroah-Hartman * Called when last reference to device kobject is gone. 8431da177e4SLinus Torvalds */ 84443cb76d9SGreg Kroah-Hartman static void netdev_release(struct device *d) 8451da177e4SLinus Torvalds { 84643cb76d9SGreg Kroah-Hartman struct net_device *dev = to_net_dev(d); 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds BUG_ON(dev->reg_state != NETREG_RELEASED); 8491da177e4SLinus Torvalds 8500b815a1aSStephen Hemminger kfree(dev->ifalias); 8511da177e4SLinus Torvalds kfree((char *)dev - dev->padded); 8521da177e4SLinus Torvalds } 8531da177e4SLinus Torvalds 854608b4b95SEric W. Biederman static const void *net_namespace(struct device *d) 855608b4b95SEric W. Biederman { 856608b4b95SEric W. Biederman struct net_device *dev; 857608b4b95SEric W. Biederman dev = container_of(d, struct net_device, dev); 858608b4b95SEric W. Biederman return dev_net(dev); 859608b4b95SEric W. Biederman } 860608b4b95SEric W. Biederman 8611da177e4SLinus Torvalds static struct class net_class = { 8621da177e4SLinus Torvalds .name = "net", 86343cb76d9SGreg Kroah-Hartman .dev_release = netdev_release, 8648b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 86543cb76d9SGreg Kroah-Hartman .dev_attrs = net_class_attributes, 8668b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 8671da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG 86843cb76d9SGreg Kroah-Hartman .dev_uevent = netdev_uevent, 8691da177e4SLinus Torvalds #endif 870608b4b95SEric W. Biederman .ns_type = &net_ns_type_operations, 871608b4b95SEric W. Biederman .namespace = net_namespace, 8721da177e4SLinus Torvalds }; 8731da177e4SLinus Torvalds 8749093bbb2SStephen Hemminger /* Delete sysfs entries but hold kobject reference until after all 8759093bbb2SStephen Hemminger * netdev references are gone. 8769093bbb2SStephen Hemminger */ 8778b41d188SEric W. Biederman void netdev_unregister_kobject(struct net_device * net) 8781da177e4SLinus Torvalds { 8799093bbb2SStephen Hemminger struct device *dev = &(net->dev); 8809093bbb2SStephen Hemminger 8819093bbb2SStephen Hemminger kobject_get(&dev->kobj); 8823891845eSEric W. Biederman 88330bde1f5SStephen Rothwell #ifdef CONFIG_RPS 8840a9627f2STom Herbert rx_queue_remove_kobjects(net); 885e880eb6cSTom Herbert #endif 8860a9627f2STom Herbert 8879093bbb2SStephen Hemminger device_del(dev); 8881da177e4SLinus Torvalds } 8891da177e4SLinus Torvalds 8901da177e4SLinus Torvalds /* Create sysfs entries for network device. */ 8918b41d188SEric W. Biederman int netdev_register_kobject(struct net_device *net) 8921da177e4SLinus Torvalds { 89343cb76d9SGreg Kroah-Hartman struct device *dev = &(net->dev); 894a4dbd674SDavid Brownell const struct attribute_group **groups = net->sysfs_groups; 8950a9627f2STom Herbert int error = 0; 8961da177e4SLinus Torvalds 897a1b3f594SEric W. Biederman device_initialize(dev); 89843cb76d9SGreg Kroah-Hartman dev->class = &net_class; 89943cb76d9SGreg Kroah-Hartman dev->platform_data = net; 90043cb76d9SGreg Kroah-Hartman dev->groups = groups; 9011da177e4SLinus Torvalds 902a2205472SStephen Hemminger dev_set_name(dev, "%s", net->name); 9031da177e4SLinus Torvalds 9048b41d188SEric W. Biederman #ifdef CONFIG_SYSFS 9050c509a6cSEric W. Biederman /* Allow for a device specific group */ 9060c509a6cSEric W. Biederman if (*groups) 9070c509a6cSEric W. Biederman groups++; 9081da177e4SLinus Torvalds 9090c509a6cSEric W. Biederman *groups++ = &netstat_group; 91022bb1be4SJohannes Berg #ifdef CONFIG_WIRELESS_EXT_SYSFS 9113d23e349SJohannes Berg if (net->ieee80211_ptr) 912fe9925b5SStephen Hemminger *groups++ = &wireless_group; 9133d23e349SJohannes Berg #ifdef CONFIG_WIRELESS_EXT 9143d23e349SJohannes Berg else if (net->wireless_handlers) 9153d23e349SJohannes Berg *groups++ = &wireless_group; 9163d23e349SJohannes Berg #endif 9171da177e4SLinus Torvalds #endif 9188b41d188SEric W. Biederman #endif /* CONFIG_SYSFS */ 9191da177e4SLinus Torvalds 9200a9627f2STom Herbert error = device_add(dev); 9210a9627f2STom Herbert if (error) 9220a9627f2STom Herbert return error; 9230a9627f2STom Herbert 92430bde1f5SStephen Rothwell #ifdef CONFIG_RPS 9250a9627f2STom Herbert error = rx_queue_register_kobjects(net); 9260a9627f2STom Herbert if (error) { 9270a9627f2STom Herbert device_del(dev); 9280a9627f2STom Herbert return error; 9290a9627f2STom Herbert } 930e880eb6cSTom Herbert #endif 9310a9627f2STom Herbert 9320a9627f2STom Herbert return error; 9331da177e4SLinus Torvalds } 9341da177e4SLinus Torvalds 935b8a9787eSJay Vosburgh int netdev_class_create_file(struct class_attribute *class_attr) 936b8a9787eSJay Vosburgh { 937b8a9787eSJay Vosburgh return class_create_file(&net_class, class_attr); 938b8a9787eSJay Vosburgh } 9399e34a5b5SEric Dumazet EXPORT_SYMBOL(netdev_class_create_file); 940b8a9787eSJay Vosburgh 941b8a9787eSJay Vosburgh void netdev_class_remove_file(struct class_attribute *class_attr) 942b8a9787eSJay Vosburgh { 943b8a9787eSJay Vosburgh class_remove_file(&net_class, class_attr); 944b8a9787eSJay Vosburgh } 945b8a9787eSJay Vosburgh EXPORT_SYMBOL(netdev_class_remove_file); 946b8a9787eSJay Vosburgh 9478b41d188SEric W. Biederman int netdev_kobject_init(void) 9481da177e4SLinus Torvalds { 949608b4b95SEric W. Biederman kobj_ns_type_register(&net_ns_type_operations); 950d6523ddfSEric W. Biederman register_pernet_subsys(&kobj_net_ops); 9511da177e4SLinus Torvalds return class_register(&net_class); 9521da177e4SLinus Torvalds } 953