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        unsigned int flow_limit_count = 0;
 150
 151#ifdef CONFIG_NET_FLOW_LIMIT
 152        struct sd_flow_limit *fl;
 153
 154        rcu_read_lock();
 155        fl = rcu_dereference(sd->flow_limit);
 156        if (fl)
 157                flow_limit_count = fl->count;
 158        rcu_read_unlock();
 159#endif
 160
 161        seq_printf(seq,
 162                   "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
 163                   sd->processed, sd->dropped, sd->time_squeeze, 0,
 164                   0, 0, 0, 0, /* was fastroute */
 165                   0,   /* was cpu_collision */
 166                   sd->received_rps, flow_limit_count);
 167        return 0;
 168}
 169
 170static const struct seq_operations dev_seq_ops = {
 171        .start = dev_seq_start,
 172        .next  = dev_seq_next,
 173        .stop  = dev_seq_stop,
 174        .show  = dev_seq_show,
 175};
 176
 177static int dev_seq_open(struct inode *inode, struct file *file)
 178{
 179        return seq_open_net(inode, file, &dev_seq_ops,
 180                            sizeof(struct seq_net_private));
 181}
 182
 183static const struct file_operations dev_seq_fops = {
 184        .owner   = THIS_MODULE,
 185        .open    = dev_seq_open,
 186        .read    = seq_read,
 187        .llseek  = seq_lseek,
 188        .release = seq_release_net,
 189};
 190
 191static const struct seq_operations softnet_seq_ops = {
 192        .start = softnet_seq_start,
 193        .next  = softnet_seq_next,
 194        .stop  = softnet_seq_stop,
 195        .show  = softnet_seq_show,
 196};
 197
 198static int softnet_seq_open(struct inode *inode, struct file *file)
 199{
 200        return seq_open(file, &softnet_seq_ops);
 201}
 202
 203static const struct file_operations softnet_seq_fops = {
 204        .owner   = THIS_MODULE,
 205        .open    = softnet_seq_open,
 206        .read    = seq_read,
 207        .llseek  = seq_lseek,
 208        .release = seq_release,
 209};
 210
 211static void *ptype_get_idx(loff_t pos)
 212{
 213        struct packet_type *pt = NULL;
 214        loff_t i = 0;
 215        int t;
 216
 217        list_for_each_entry_rcu(pt, &ptype_all, list) {
 218                if (i == pos)
 219                        return pt;
 220                ++i;
 221        }
 222
 223        for (t = 0; t < PTYPE_HASH_SIZE; t++) {
 224                list_for_each_entry_rcu(pt, &ptype_base[t], list) {
 225                        if (i == pos)
 226                                return pt;
 227                        ++i;
 228                }
 229        }
 230        return NULL;
 231}
 232
 233static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
 234        __acquires(RCU)
 235{
 236        rcu_read_lock();
 237        return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;
 238}
 239
 240static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 241{
 242        struct packet_type *pt;
 243        struct list_head *nxt;
 244        int hash;
 245
 246        ++*pos;
 247        if (v == SEQ_START_TOKEN)
 248                return ptype_get_idx(0);
 249
 250        pt = v;
 251        nxt = pt->list.next;
 252        if (pt->type == htons(ETH_P_ALL)) {
 253                if (nxt != &ptype_all)
 254                        goto found;
 255                hash = 0;
 256                nxt = ptype_base[0].next;
 257        } else
 258                hash = ntohs(pt->type) & PTYPE_HASH_MASK;
 259
 260        while (nxt == &ptype_base[hash]) {
 261                if (++hash >= PTYPE_HASH_SIZE)
 262                        return NULL;
 263                nxt = ptype_base[hash].next;
 264        }
 265found:
 266        return list_entry(nxt, struct packet_type, list);
 267}
 268
 269static void ptype_seq_stop(struct seq_file *seq, void *v)
 270        __releases(RCU)
 271{
 272        rcu_read_unlock();
 273}
 274
 275static int ptype_seq_show(struct seq_file *seq, void *v)
 276{
 277        struct packet_type *pt = v;
 278
 279        if (v == SEQ_START_TOKEN)
 280                seq_puts(seq, "Type Device      Function\n");
 281        else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) {
 282                if (pt->type == htons(ETH_P_ALL))
 283                        seq_puts(seq, "ALL ");
 284                else
 285                        seq_printf(seq, "%04x", ntohs(pt->type));
 286
 287                seq_printf(seq, " %-8s %pf\n",
 288                           pt->dev ? pt->dev->name : "", pt->func);
 289        }
 290
 291        return 0;
 292}
 293
 294static const struct seq_operations ptype_seq_ops = {
 295        .start = ptype_seq_start,
 296        .next  = ptype_seq_next,
 297        .stop  = ptype_seq_stop,
 298        .show  = ptype_seq_show,
 299};
 300
 301static int ptype_seq_open(struct inode *inode, struct file *file)
 302{
 303        return seq_open_net(inode, file, &ptype_seq_ops,
 304                        sizeof(struct seq_net_private));
 305}
 306
 307static const struct file_operations ptype_seq_fops = {
 308        .owner   = THIS_MODULE,
 309        .open    = ptype_seq_open,
 310        .read    = seq_read,
 311        .llseek  = seq_lseek,
 312        .release = seq_release_net,
 313};
 314
 315
 316static int __net_init dev_proc_net_init(struct net *net)
 317{
 318        int rc = -ENOMEM;
 319
 320        if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops))
 321                goto out;
 322        if (!proc_create("softnet_stat", S_IRUGO, net->proc_net,
 323                         &softnet_seq_fops))
 324                goto out_dev;
 325        if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
 326                goto out_softnet;
 327
 328        if (wext_proc_init(net))
 329                goto out_ptype;
 330        rc = 0;
 331out:
 332        return rc;
 333out_ptype:
 334        remove_proc_entry("ptype", net->proc_net);
 335out_softnet:
 336        remove_proc_entry("softnet_stat", net->proc_net);
 337out_dev:
 338        remove_proc_entry("dev", net->proc_net);
 339        goto out;
 340}
 341
 342static void __net_exit dev_proc_net_exit(struct net *net)
 343{
 344        wext_proc_exit(net);
 345
 346        remove_proc_entry("ptype", net->proc_net);
 347        remove_proc_entry("softnet_stat", net->proc_net);
 348        remove_proc_entry("dev", net->proc_net);
 349}
 350
 351static struct pernet_operations __net_initdata dev_proc_ops = {
 352        .init = dev_proc_net_init,
 353        .exit = dev_proc_net_exit,
 354};
 355
 356static int dev_mc_seq_show(struct seq_file *seq, void *v)
 357{
 358        struct netdev_hw_addr *ha;
 359        struct net_device *dev = v;
 360
 361        if (v == SEQ_START_TOKEN)
 362                return 0;
 363
 364        netif_addr_lock_bh(dev);
 365        netdev_for_each_mc_addr(ha, dev) {
 366                int i;
 367
 368                seq_printf(seq, "%-4d %-15s %-5d %-5d ", dev->ifindex,
 369                           dev->name, ha->refcount, ha->global_use);
 370
 371                for (i = 0; i < dev->addr_len; i++)
 372                        seq_printf(seq, "%02x", ha->addr[i]);
 373
 374                seq_putc(seq, '\n');
 375        }
 376        netif_addr_unlock_bh(dev);
 377        return 0;
 378}
 379
 380static const struct seq_operations dev_mc_seq_ops = {
 381        .start = dev_seq_start,
 382        .next  = dev_seq_next,
 383        .stop  = dev_seq_stop,
 384        .show  = dev_mc_seq_show,
 385};
 386
 387static int dev_mc_seq_open(struct inode *inode, struct file *file)
 388{
 389        return seq_open_net(inode, file, &dev_mc_seq_ops,
 390                            sizeof(struct seq_net_private));
 391}
 392
 393static const struct file_operations dev_mc_seq_fops = {
 394        .owner   = THIS_MODULE,
 395        .open    = dev_mc_seq_open,
 396        .read    = seq_read,
 397        .llseek  = seq_lseek,
 398        .release = seq_release_net,
 399};
 400
 401static int __net_init dev_mc_net_init(struct net *net)
 402{
 403        if (!proc_create("dev_mcast", 0, net->proc_net, &dev_mc_seq_fops))
 404                return -ENOMEM;
 405        return 0;
 406}
 407
 408static void __net_exit dev_mc_net_exit(struct net *net)
 409{
 410        remove_proc_entry("dev_mcast", net->proc_net);
 411}
 412
 413static struct pernet_operations __net_initdata dev_mc_net_ops = {
 414        .init = dev_mc_net_init,
 415        .exit = dev_mc_net_exit,
 416};
 417
 418int __init dev_proc_init(void)
 419{
 420        int ret = register_pernet_subsys(&dev_proc_ops);
 421        if (!ret)
 422                return register_pernet_subsys(&dev_mc_net_ops);
 423        return ret;
 424}
 425