123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- #include <linux/netdevice.h>
- #include <linux/proc_fs.h>
- #include <linux/seq_file.h>
- #include <net/wext.h>
- #define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1)
- #define get_bucket(x) ((x) >> BUCKET_SPACE)
- #define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
- #define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
- extern struct list_head ptype_all __read_mostly;
- extern struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
- static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos)
- {
- struct net *net = seq_file_net(seq);
- struct net_device *dev;
- struct hlist_head *h;
- unsigned int count = 0, offset = get_offset(*pos);
- h = &net->dev_name_head[get_bucket(*pos)];
- hlist_for_each_entry_rcu(dev, h, name_hlist) {
- if (++count == offset)
- return dev;
- }
- return NULL;
- }
- static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos)
- {
- struct net_device *dev;
- unsigned int bucket;
- do {
- dev = dev_from_same_bucket(seq, pos);
- if (dev)
- return dev;
- bucket = get_bucket(*pos) + 1;
- *pos = set_bucket_offset(bucket, 1);
- } while (bucket < NETDEV_HASHENTRIES);
- return NULL;
- }
- /*
- * This is invoked by the /proc filesystem handler to display a device
- * in detail.
- */
- static void *dev_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(RCU)
- {
- rcu_read_lock();
- if (!*pos)
- return SEQ_START_TOKEN;
- if (get_bucket(*pos) >= NETDEV_HASHENTRIES)
- return NULL;
- return dev_from_bucket(seq, pos);
- }
- static void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
- {
- ++*pos;
- return dev_from_bucket(seq, pos);
- }
- static void dev_seq_stop(struct seq_file *seq, void *v)
- __releases(RCU)
- {
- rcu_read_unlock();
- }
- static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
- {
- struct rtnl_link_stats64 temp;
- const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
- seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
- "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
- dev->name, stats->rx_bytes, stats->rx_packets,
- stats->rx_errors,
- stats->rx_dropped + stats->rx_missed_errors,
- stats->rx_fifo_errors,
- stats->rx_length_errors + stats->rx_over_errors +
- stats->rx_crc_errors + stats->rx_frame_errors,
- stats->rx_compressed, stats->multicast,
- stats->tx_bytes, stats->tx_packets,
- stats->tx_errors, stats->tx_dropped,
- stats->tx_fifo_errors, stats->collisions,
- stats->tx_carrier_errors +
- stats->tx_aborted_errors +
- stats->tx_window_errors +
- stats->tx_heartbeat_errors,
- stats->tx_compressed);
- }
- /*
- * Called from the PROCfs module. This now uses the new arbitrary sized
- * /proc/net interface to create /proc/net/dev
- */
- static int dev_seq_show(struct seq_file *seq, void *v)
- {
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, "Inter-| Receive "
- " | Transmit\n"
- " face |bytes packets errs drop fifo frame "
- "compressed multicast|bytes packets errs "
- "drop fifo colls carrier compressed\n");
- else
- dev_seq_printf_stats(seq, v);
- return 0;
- }
- static struct softnet_data *softnet_get_online(loff_t *pos)
- {
- struct softnet_data *sd = NULL;
- while (*pos < nr_cpu_ids)
- if (cpu_online(*pos)) {
- sd = &per_cpu(softnet_data, *pos);
- break;
- } else
- ++*pos;
- return sd;
- }
- static void *softnet_seq_start(struct seq_file *seq, loff_t *pos)
- {
- return softnet_get_online(pos);
- }
- static void *softnet_seq_next(struct seq_file *seq, void *v, loff_t *pos)
- {
- ++*pos;
- return softnet_get_online(pos);
- }
- static void softnet_seq_stop(struct seq_file *seq, void *v)
- {
- }
- static int softnet_seq_show(struct seq_file *seq, void *v)
- {
- struct softnet_data *sd = v;
- unsigned int flow_limit_count = 0;
- #ifdef CONFIG_NET_FLOW_LIMIT
- struct sd_flow_limit *fl;
- rcu_read_lock();
- fl = rcu_dereference(sd->flow_limit);
- if (fl)
- flow_limit_count = fl->count;
- rcu_read_unlock();
- #endif
- seq_printf(seq,
- "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
- sd->processed, sd->dropped, sd->time_squeeze, 0,
- 0, 0, 0, 0, /* was fastroute */
- 0, /* was cpu_collision */
- sd->received_rps, flow_limit_count);
- return 0;
- }
- static const struct seq_operations dev_seq_ops = {
- .start = dev_seq_start,
- .next = dev_seq_next,
- .stop = dev_seq_stop,
- .show = dev_seq_show,
- };
- static int dev_seq_open(struct inode *inode, struct file *file)
- {
- return seq_open_net(inode, file, &dev_seq_ops,
- sizeof(struct seq_net_private));
- }
- static const struct file_operations dev_seq_fops = {
- .owner = THIS_MODULE,
- .open = dev_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_net,
- };
- static const struct seq_operations softnet_seq_ops = {
- .start = softnet_seq_start,
- .next = softnet_seq_next,
- .stop = softnet_seq_stop,
- .show = softnet_seq_show,
- };
- static int softnet_seq_open(struct inode *inode, struct file *file)
- {
- return seq_open(file, &softnet_seq_ops);
- }
- static const struct file_operations softnet_seq_fops = {
- .owner = THIS_MODULE,
- .open = softnet_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
- };
- static void *ptype_get_idx(loff_t pos)
- {
- struct packet_type *pt = NULL;
- loff_t i = 0;
- int t;
- list_for_each_entry_rcu(pt, &ptype_all, list) {
- if (i == pos)
- return pt;
- ++i;
- }
- for (t = 0; t < PTYPE_HASH_SIZE; t++) {
- list_for_each_entry_rcu(pt, &ptype_base[t], list) {
- if (i == pos)
- return pt;
- ++i;
- }
- }
- return NULL;
- }
- static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(RCU)
- {
- rcu_read_lock();
- return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;
- }
- static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
- {
- struct packet_type *pt;
- struct list_head *nxt;
- int hash;
- ++*pos;
- if (v == SEQ_START_TOKEN)
- return ptype_get_idx(0);
- pt = v;
- nxt = pt->list.next;
- if (pt->type == htons(ETH_P_ALL)) {
- if (nxt != &ptype_all)
- goto found;
- hash = 0;
- nxt = ptype_base[0].next;
- } else
- hash = ntohs(pt->type) & PTYPE_HASH_MASK;
- while (nxt == &ptype_base[hash]) {
- if (++hash >= PTYPE_HASH_SIZE)
- return NULL;
- nxt = ptype_base[hash].next;
- }
- found:
- return list_entry(nxt, struct packet_type, list);
- }
- static void ptype_seq_stop(struct seq_file *seq, void *v)
- __releases(RCU)
- {
- rcu_read_unlock();
- }
- static int ptype_seq_show(struct seq_file *seq, void *v)
- {
- struct packet_type *pt = v;
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, "Type Device Function\n");
- else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) {
- if (pt->type == htons(ETH_P_ALL))
- seq_puts(seq, "ALL ");
- else
- seq_printf(seq, "%04x", ntohs(pt->type));
- seq_printf(seq, " %-8s %pf\n",
- pt->dev ? pt->dev->name : "", pt->func);
- }
- return 0;
- }
- static const struct seq_operations ptype_seq_ops = {
- .start = ptype_seq_start,
- .next = ptype_seq_next,
- .stop = ptype_seq_stop,
- .show = ptype_seq_show,
- };
- static int ptype_seq_open(struct inode *inode, struct file *file)
- {
- return seq_open_net(inode, file, &ptype_seq_ops,
- sizeof(struct seq_net_private));
- }
- static const struct file_operations ptype_seq_fops = {
- .owner = THIS_MODULE,
- .open = ptype_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_net,
- };
- static int __net_init dev_proc_net_init(struct net *net)
- {
- int rc = -ENOMEM;
- if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops))
- goto out;
- if (!proc_create("softnet_stat", S_IRUGO, net->proc_net,
- &softnet_seq_fops))
- goto out_dev;
- if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
- goto out_softnet;
- if (wext_proc_init(net))
- goto out_ptype;
- rc = 0;
- out:
- return rc;
- out_ptype:
- remove_proc_entry("ptype", net->proc_net);
- out_softnet:
- remove_proc_entry("softnet_stat", net->proc_net);
- out_dev:
- remove_proc_entry("dev", net->proc_net);
- goto out;
- }
- static void __net_exit dev_proc_net_exit(struct net *net)
- {
- wext_proc_exit(net);
- remove_proc_entry("ptype", net->proc_net);
- remove_proc_entry("softnet_stat", net->proc_net);
- remove_proc_entry("dev", net->proc_net);
- }
- static struct pernet_operations __net_initdata dev_proc_ops = {
- .init = dev_proc_net_init,
- .exit = dev_proc_net_exit,
- };
- static int dev_mc_seq_show(struct seq_file *seq, void *v)
- {
- struct netdev_hw_addr *ha;
- struct net_device *dev = v;
- if (v == SEQ_START_TOKEN)
- return 0;
- netif_addr_lock_bh(dev);
- netdev_for_each_mc_addr(ha, dev) {
- int i;
- seq_printf(seq, "%-4d %-15s %-5d %-5d ", dev->ifindex,
- dev->name, ha->refcount, ha->global_use);
- for (i = 0; i < dev->addr_len; i++)
- seq_printf(seq, "%02x", ha->addr[i]);
- seq_putc(seq, '\n');
- }
- netif_addr_unlock_bh(dev);
- return 0;
- }
- static const struct seq_operations dev_mc_seq_ops = {
- .start = dev_seq_start,
- .next = dev_seq_next,
- .stop = dev_seq_stop,
- .show = dev_mc_seq_show,
- };
- static int dev_mc_seq_open(struct inode *inode, struct file *file)
- {
- return seq_open_net(inode, file, &dev_mc_seq_ops,
- sizeof(struct seq_net_private));
- }
- static const struct file_operations dev_mc_seq_fops = {
- .owner = THIS_MODULE,
- .open = dev_mc_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_net,
- };
- static int __net_init dev_mc_net_init(struct net *net)
- {
- if (!proc_create("dev_mcast", 0, net->proc_net, &dev_mc_seq_fops))
- return -ENOMEM;
- return 0;
- }
- static void __net_exit dev_mc_net_exit(struct net *net)
- {
- remove_proc_entry("dev_mcast", net->proc_net);
- }
- static struct pernet_operations __net_initdata dev_mc_net_ops = {
- .init = dev_mc_net_init,
- .exit = dev_mc_net_exit,
- };
- int __init dev_proc_init(void)
- {
- int ret = register_pernet_subsys(&dev_proc_ops);
- if (!ret)
- return register_pernet_subsys(&dev_mc_net_ops);
- return ret;
- }
|