linux/net/core/net-procfs.c
<<
>>
Prefs
   1#include <linux/netdevice.h>
   2#include <linux/proc_fs.h>
   3#include <linux/seq_file.h>
   4#include <net/wext.h>
   5
   6#define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1)
   7
   8#define get_bucket(x) ((x) >> BUCKET_SPACE)
   9#define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
  10#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
  11
  12extern struct list_head ptype_all __read_mostly;
  13extern struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
  14
  15static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos)
  16{
  17        struct net *net = seq_file_net(seq);
  18        struct net_device *dev;
  19        struct hlist_head *h;
  20        unsigned int count = 0, offset = get_offset(*pos);
  21
  22        h = &net->dev_name_head[get_bucket(*pos)];
  23        hlist_for_each_entry_rcu(dev, h, name_hlist) {
  24                if (++count == offset)
  25                        return dev;
  26        }
  27
  28        return NULL;
  29}
  30
  31static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos)
  32{
  33        struct net_device *dev;
  34        unsigned int bucket;
  35
  36        do {
  37                dev = dev_from_same_bucket(seq, pos);
  38                if (dev)
  39                        return dev;
  40
  41                bucket = get_bucket(*pos) + 1;
  42                *pos = set_bucket_offset(bucket, 1);
  43        } while (bucket < NETDEV_HASHENTRIES);
  44
  45        return NULL;
  46}
  47
  48/*
  49 *      This is invoked by the /proc filesystem handler to display a device
  50 *      in detail.
  51 */
  52static void *dev_seq_start(struct seq_file *seq, loff_t *pos)
  53        __acquires(RCU)
  54{
  55        rcu_read_lock();
  56        if (!*pos)
  57                return SEQ_START_TOKEN;
  58
  59        if (get_bucket(*pos) >= NETDEV_HASHENTRIES)
  60                return NULL;
  61
  62        return dev_from_bucket(seq, pos);
  63}
  64
  65static void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  66{
  67        ++*pos;
  68        return dev_from_bucket(seq, pos);
  69}
  70
  71static void dev_seq_stop(struct seq_file *seq, void *v)
  72        __releases(RCU)
  73{
  74        rcu_read_unlock();
  75}
  76
  77static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
  78{
  79        struct rtnl_link_stats64 temp;
  80        const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
  81
  82        seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
  83                   "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
  84                   dev->name, stats->rx_bytes, stats->rx_packets,
  85                   stats->rx_errors,
  86                   stats->rx_dropped + stats->rx_missed_errors,
  87                   stats->rx_fifo_errors,
  88                   stats->rx_length_errors + stats->rx_over_errors +
  89                    stats->rx_crc_errors + stats->rx_frame_errors,
  90                   stats->rx_compressed, stats->multicast,
  91                   stats->tx_bytes, stats->tx_packets,
  92                   stats->tx_errors, stats->tx_dropped,
  93                   stats->tx_fifo_errors, stats->collisions,
  94                   stats->tx_carrier_errors +
  95                    stats->tx_aborted_errors +
  96                    stats->tx_window_errors +
  97                    stats->tx_heartbeat_errors,
  98                   stats->tx_compressed);
  99}
 100
 101/*
 102 *      Called from the PROCfs module. This now uses the new arbitrary sized
 103 *      /proc/net interface to create /proc/net/dev
 104 */
 105static int dev_seq_show(struct seq_file *seq, void *v)
 106{
 107        if (v == SEQ_START_TOKEN)
 108                seq_puts(seq, "Inter-|   Receive                            "
 109                              "                    |  Transmit\n"
 110                              " face |bytes    packets errs drop fifo frame "
 111                              "compressed multicast|bytes    packets errs "
 112                              "drop fifo colls carrier compressed\n");
 113        else
 114                dev_seq_printf_stats(seq, v);
 115        return 0;
 116}
 117
 118static struct softnet_data *softnet_get_online(loff_t *pos)
 119{
 120        struct softnet_data *sd = NULL;
 121
 122        while (*pos < nr_cpu_ids)
 123                if (cpu_online(*pos)) {
 124                        sd = &per_cpu(softnet_data, *pos);
 125                        break;
 126                } else
 127                        ++*pos;
 128        return sd;
 129}
 130
 131static void *softnet_seq_start(struct seq_file *seq, loff_t *pos)
 132{
 133        return softnet_get_online(pos);
 134}
 135
 136static void *softnet_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 137{
 138        ++*pos;
 139        return softnet_get_online(pos);
 140}
 141
 142static void softnet_seq_stop(struct seq_file *seq, void *v)
 143{
 144}
 145
 146static int softnet_seq_show(struct seq_file *seq, void *v)
 147{
 148        struct softnet_data *sd = v;
 149
 150        seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
 151                   sd->processed, sd->dropped, sd->time_squeeze, 0,
 152                   0, 0, 0, 0, /* was fastroute */
 153                   sd->cpu_collision, sd->received_rps);
 154        return 0;
 155}
 156
 157static const struct seq_operations dev_seq_ops = {
 158        .start = dev_seq_start,
 159        .next  = dev_seq_next,
 160        .stop  = dev_seq_stop,
 161        .show  = dev_seq_show,
 162};
 163
 164static int dev_seq_open(struct inode *inode, struct file *file)
 165{
 166        return seq_open_net(inode, file, &dev_seq_ops,
 167                            sizeof(struct seq_net_private));
 168}
 169
 170static const struct file_operations dev_seq_fops = {
 171        .owner   = THIS_MODULE,
 172        .open    = dev_seq_open,
 173        .read    = seq_read,
 174        .llseek  = seq_lseek,
 175        .release = seq_release_net,
 176};
 177
 178static const struct seq_operations softnet_seq_ops = {
 179        .start = softnet_seq_start,
 180        .next  = softnet_seq_next,
 181        .stop  = softnet_seq_stop,
 182        .show  = softnet_seq_show,
 183};
 184
 185static int softnet_seq_open(struct inode *inode, struct file *file)
 186{
 187        return seq_open(file, &softnet_seq_ops);
 188}
 189
 190static const struct file_operations softnet_seq_fops = {
 191        .owner   = THIS_MODULE,
 192        .open    = softnet_seq_open,
 193        .read    = seq_read,
 194        .llseek  = seq_lseek,
 195        .release = seq_release,
 196};
 197
 198static void *ptype_get_idx(loff_t pos)
 199{
 200        struct packet_type *pt = NULL;
 201        loff_t i = 0;
 202        int t;
 203
 204        list_for_each_entry_rcu(pt, &ptype_all, list) {
 205                if (i == pos)
 206                        return pt;
 207                ++i;
 208        }
 209
 210        for (t = 0; t < PTYPE_HASH_SIZE; t++) {
 211                list_for_each_entry_rcu(pt, &ptype_base[t], list) {
 212                        if (i == pos)
 213                                return pt;
 214                        ++i;
 215                }
 216        }
 217        return NULL;
 218}
 219
 220static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
 221        __acquires(RCU)
 222{
 223        rcu_read_lock();
 224        return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;
 225}
 226
 227static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 228{
 229        struct packet_type *pt;
 230        struct list_head *nxt;
 231        int hash;
 232
 233        ++*pos;
 234        if (v == SEQ_START_TOKEN)
 235                return ptype_get_idx(0);
 236
 237        pt = v;
 238        nxt = pt->list.next;
 239        if (pt->type == htons(ETH_P_ALL)) {
 240                if (nxt != &ptype_all)
 241                        goto found;
 242                hash = 0;
 243                nxt = ptype_base[0].next;
 244        } else
 245                hash = ntohs(pt->type) & PTYPE_HASH_MASK;
 246
 247        while (nxt == &ptype_base[hash]) {
 248                if (++hash >= PTYPE_HASH_SIZE)
 249                        return NULL;
 250                nxt = ptype_base[hash].next;
 251        }
 252found:
 253        return list_entry(nxt, struct packet_type, list);
 254}
 255
 256static void ptype_seq_stop(struct seq_file *seq, void *v)
 257        __releases(RCU)
 258{
 259        rcu_read_unlock();
 260}
 261
 262static int ptype_seq_show(struct seq_file *seq, void *v)
 263{
 264        struct packet_type *pt = v;
 265
 266        if (v == SEQ_START_TOKEN)
 267                seq_puts(seq, "Type Device      Function\n");
 268        else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) {
 269                if (pt->type == htons(ETH_P_ALL))
 270                        seq_puts(seq, "ALL ");
 271                else
 272                        seq_printf(seq, "%04x", ntohs(pt->type));
 273
 274                seq_printf(seq, " %-8s %pf\n",
 275                           pt->dev ? pt->dev->name : "", pt->func);
 276        }
 277
 278        return 0;
 279}
 280
 281static const struct seq_operations ptype_seq_ops = {
 282        .start = ptype_seq_start,
 283        .next  = ptype_seq_next,
 284        .stop  = ptype_seq_stop,
 285        .show  = ptype_seq_show,
 286};
 287
 288static int ptype_seq_open(struct inode *inode, struct file *file)
 289{
 290        return seq_open_net(inode, file, &ptype_seq_ops,
 291                        sizeof(struct seq_net_private));
 292}
 293
 294static const struct file_operations ptype_seq_fops = {
 295        .owner   = THIS_MODULE,
 296        .open    = ptype_seq_open,
 297        .read    = seq_read,
 298        .llseek  = seq_lseek,
 299        .release = seq_release_net,
 300};
 301
 302
 303static int __net_init dev_proc_net_init(struct net *net)
 304{
 305        int rc = -ENOMEM;
 306
 307        if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops))
 308                goto out;
 309        if (!proc_create("softnet_stat", S_IRUGO, net->proc_net,
 310                         &softnet_seq_fops))
 311                goto out_dev;
 312        if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
 313                goto out_softnet;
 314
 315        if (wext_proc_init(net))
 316                goto out_ptype;
 317        rc = 0;
 318out:
 319        return rc;
 320out_ptype:
 321        remove_proc_entry("ptype", net->proc_net);
 322out_softnet:
 323        remove_proc_entry("softnet_stat", net->proc_net);
 324out_dev:
 325        remove_proc_entry("dev", net->proc_net);
 326        goto out;
 327}
 328
 329static void __net_exit dev_proc_net_exit(struct net *net)
 330{
 331        wext_proc_exit(net);
 332
 333        remove_proc_entry("ptype", net->proc_net);
 334        remove_proc_entry("softnet_stat", net->proc_net);
 335        remove_proc_entry("dev", net->proc_net);
 336}
 337
 338static struct pernet_operations __net_initdata dev_proc_ops = {
 339        .init = dev_proc_net_init,
 340        .exit = dev_proc_net_exit,
 341};
 342
 343static int dev_mc_seq_show(struct seq_file *seq, void *v)
 344{
 345        struct netdev_hw_addr *ha;
 346        struct net_device *dev = v;
 347
 348        if (v == SEQ_START_TOKEN)
 349                return 0;
 350
 351        netif_addr_lock_bh(dev);
 352        netdev_for_each_mc_addr(ha, dev) {
 353                int i;
 354
 355                seq_printf(seq, "%-4d %-15s %-5d %-5d ", dev->ifindex,
 356                           dev->name, ha->refcount, ha->global_use);
 357
 358                for (i = 0; i < dev->addr_len; i++)
 359                        seq_printf(seq, "%02x", ha->addr[i]);
 360
 361                seq_putc(seq, '\n');
 362        }
 363        netif_addr_unlock_bh(dev);
 364        return 0;
 365}
 366
 367static const struct seq_operations dev_mc_seq_ops = {
 368        .start = dev_seq_start,
 369        .next  = dev_seq_next,
 370        .stop  = dev_seq_stop,
 371        .show  = dev_mc_seq_show,
 372};
 373
 374static int dev_mc_seq_open(struct inode *inode, struct file *file)
 375{
 376        return seq_open_net(inode, file, &dev_mc_seq_ops,
 377                            sizeof(struct seq_net_private));
 378}
 379
 380static const struct file_operations dev_mc_seq_fops = {
 381        .owner   = THIS_MODULE,
 382        .open    = dev_mc_seq_open,
 383        .read    = seq_read,
 384        .llseek  = seq_lseek,
 385        .release = seq_release_net,
 386};
 387
 388static int __net_init dev_mc_net_init(struct net *net)
 389{
 390        if (!proc_create("dev_mcast", 0, net->proc_net, &dev_mc_seq_fops))
 391                return -ENOMEM;
 392        return 0;
 393}
 394
 395static void __net_exit dev_mc_net_exit(struct net *net)
 396{
 397        remove_proc_entry("dev_mcast", net->proc_net);
 398}
 399
 400static struct pernet_operations __net_initdata dev_mc_net_ops = {
 401        .init = dev_mc_net_init,
 402        .exit = dev_mc_net_exit,
 403};
 404
 405int __init dev_proc_init(void)
 406{
 407        int ret = register_pernet_subsys(&dev_proc_ops);
 408        if (!ret)
 409                return register_pernet_subsys(&dev_mc_net_ops);
 410        return ret;
 411}
 412