0001
0002 #include <linux/netdevice.h>
0003 #include <linux/proc_fs.h>
0004 #include <linux/seq_file.h>
0005 #include <net/wext.h>
0006
0007 #include "dev.h"
0008
0009 #define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1)
0010
0011 #define get_bucket(x) ((x) >> BUCKET_SPACE)
0012 #define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
0013 #define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
0014
0015 static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos)
0016 {
0017 struct net *net = seq_file_net(seq);
0018 struct net_device *dev;
0019 struct hlist_head *h;
0020 unsigned int count = 0, offset = get_offset(*pos);
0021
0022 h = &net->dev_index_head[get_bucket(*pos)];
0023 hlist_for_each_entry_rcu(dev, h, index_hlist) {
0024 if (++count == offset)
0025 return dev;
0026 }
0027
0028 return NULL;
0029 }
0030
0031 static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos)
0032 {
0033 struct net_device *dev;
0034 unsigned int bucket;
0035
0036 do {
0037 dev = dev_from_same_bucket(seq, pos);
0038 if (dev)
0039 return dev;
0040
0041 bucket = get_bucket(*pos) + 1;
0042 *pos = set_bucket_offset(bucket, 1);
0043 } while (bucket < NETDEV_HASHENTRIES);
0044
0045 return NULL;
0046 }
0047
0048
0049
0050
0051
0052 static void *dev_seq_start(struct seq_file *seq, loff_t *pos)
0053 __acquires(RCU)
0054 {
0055 rcu_read_lock();
0056 if (!*pos)
0057 return SEQ_START_TOKEN;
0058
0059 if (get_bucket(*pos) >= NETDEV_HASHENTRIES)
0060 return NULL;
0061
0062 return dev_from_bucket(seq, pos);
0063 }
0064
0065 static void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
0066 {
0067 ++*pos;
0068 return dev_from_bucket(seq, pos);
0069 }
0070
0071 static void dev_seq_stop(struct seq_file *seq, void *v)
0072 __releases(RCU)
0073 {
0074 rcu_read_unlock();
0075 }
0076
0077 static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
0078 {
0079 struct rtnl_link_stats64 temp;
0080 const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
0081
0082 seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
0083 "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
0084 dev->name, stats->rx_bytes, stats->rx_packets,
0085 stats->rx_errors,
0086 stats->rx_dropped + stats->rx_missed_errors,
0087 stats->rx_fifo_errors,
0088 stats->rx_length_errors + stats->rx_over_errors +
0089 stats->rx_crc_errors + stats->rx_frame_errors,
0090 stats->rx_compressed, stats->multicast,
0091 stats->tx_bytes, stats->tx_packets,
0092 stats->tx_errors, stats->tx_dropped,
0093 stats->tx_fifo_errors, stats->collisions,
0094 stats->tx_carrier_errors +
0095 stats->tx_aborted_errors +
0096 stats->tx_window_errors +
0097 stats->tx_heartbeat_errors,
0098 stats->tx_compressed);
0099 }
0100
0101
0102
0103
0104
0105 static int dev_seq_show(struct seq_file *seq, void *v)
0106 {
0107 if (v == SEQ_START_TOKEN)
0108 seq_puts(seq, "Inter-| Receive "
0109 " | Transmit\n"
0110 " face |bytes packets errs drop fifo frame "
0111 "compressed multicast|bytes packets errs "
0112 "drop fifo colls carrier compressed\n");
0113 else
0114 dev_seq_printf_stats(seq, v);
0115 return 0;
0116 }
0117
0118 static u32 softnet_backlog_len(struct softnet_data *sd)
0119 {
0120 return skb_queue_len_lockless(&sd->input_pkt_queue) +
0121 skb_queue_len_lockless(&sd->process_queue);
0122 }
0123
0124 static struct softnet_data *softnet_get_online(loff_t *pos)
0125 {
0126 struct softnet_data *sd = NULL;
0127
0128 while (*pos < nr_cpu_ids)
0129 if (cpu_online(*pos)) {
0130 sd = &per_cpu(softnet_data, *pos);
0131 break;
0132 } else
0133 ++*pos;
0134 return sd;
0135 }
0136
0137 static void *softnet_seq_start(struct seq_file *seq, loff_t *pos)
0138 {
0139 return softnet_get_online(pos);
0140 }
0141
0142 static void *softnet_seq_next(struct seq_file *seq, void *v, loff_t *pos)
0143 {
0144 ++*pos;
0145 return softnet_get_online(pos);
0146 }
0147
0148 static void softnet_seq_stop(struct seq_file *seq, void *v)
0149 {
0150 }
0151
0152 static int softnet_seq_show(struct seq_file *seq, void *v)
0153 {
0154 struct softnet_data *sd = v;
0155 unsigned int flow_limit_count = 0;
0156
0157 #ifdef CONFIG_NET_FLOW_LIMIT
0158 struct sd_flow_limit *fl;
0159
0160 rcu_read_lock();
0161 fl = rcu_dereference(sd->flow_limit);
0162 if (fl)
0163 flow_limit_count = fl->count;
0164 rcu_read_unlock();
0165 #endif
0166
0167
0168
0169
0170
0171 seq_printf(seq,
0172 "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
0173 sd->processed, sd->dropped, sd->time_squeeze, 0,
0174 0, 0, 0, 0,
0175 0,
0176 sd->received_rps, flow_limit_count,
0177 softnet_backlog_len(sd), (int)seq->index);
0178 return 0;
0179 }
0180
0181 static const struct seq_operations dev_seq_ops = {
0182 .start = dev_seq_start,
0183 .next = dev_seq_next,
0184 .stop = dev_seq_stop,
0185 .show = dev_seq_show,
0186 };
0187
0188 static const struct seq_operations softnet_seq_ops = {
0189 .start = softnet_seq_start,
0190 .next = softnet_seq_next,
0191 .stop = softnet_seq_stop,
0192 .show = softnet_seq_show,
0193 };
0194
0195 static void *ptype_get_idx(struct seq_file *seq, loff_t pos)
0196 {
0197 struct list_head *ptype_list = NULL;
0198 struct packet_type *pt = NULL;
0199 struct net_device *dev;
0200 loff_t i = 0;
0201 int t;
0202
0203 for_each_netdev_rcu(seq_file_net(seq), dev) {
0204 ptype_list = &dev->ptype_all;
0205 list_for_each_entry_rcu(pt, ptype_list, list) {
0206 if (i == pos)
0207 return pt;
0208 ++i;
0209 }
0210 }
0211
0212 list_for_each_entry_rcu(pt, &ptype_all, list) {
0213 if (i == pos)
0214 return pt;
0215 ++i;
0216 }
0217
0218 for (t = 0; t < PTYPE_HASH_SIZE; t++) {
0219 list_for_each_entry_rcu(pt, &ptype_base[t], list) {
0220 if (i == pos)
0221 return pt;
0222 ++i;
0223 }
0224 }
0225 return NULL;
0226 }
0227
0228 static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
0229 __acquires(RCU)
0230 {
0231 rcu_read_lock();
0232 return *pos ? ptype_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
0233 }
0234
0235 static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
0236 {
0237 struct net_device *dev;
0238 struct packet_type *pt;
0239 struct list_head *nxt;
0240 int hash;
0241
0242 ++*pos;
0243 if (v == SEQ_START_TOKEN)
0244 return ptype_get_idx(seq, 0);
0245
0246 pt = v;
0247 nxt = pt->list.next;
0248 if (pt->dev) {
0249 if (nxt != &pt->dev->ptype_all)
0250 goto found;
0251
0252 dev = pt->dev;
0253 for_each_netdev_continue_rcu(seq_file_net(seq), dev) {
0254 if (!list_empty(&dev->ptype_all)) {
0255 nxt = dev->ptype_all.next;
0256 goto found;
0257 }
0258 }
0259
0260 nxt = ptype_all.next;
0261 goto ptype_all;
0262 }
0263
0264 if (pt->type == htons(ETH_P_ALL)) {
0265 ptype_all:
0266 if (nxt != &ptype_all)
0267 goto found;
0268 hash = 0;
0269 nxt = ptype_base[0].next;
0270 } else
0271 hash = ntohs(pt->type) & PTYPE_HASH_MASK;
0272
0273 while (nxt == &ptype_base[hash]) {
0274 if (++hash >= PTYPE_HASH_SIZE)
0275 return NULL;
0276 nxt = ptype_base[hash].next;
0277 }
0278 found:
0279 return list_entry(nxt, struct packet_type, list);
0280 }
0281
0282 static void ptype_seq_stop(struct seq_file *seq, void *v)
0283 __releases(RCU)
0284 {
0285 rcu_read_unlock();
0286 }
0287
0288 static int ptype_seq_show(struct seq_file *seq, void *v)
0289 {
0290 struct packet_type *pt = v;
0291
0292 if (v == SEQ_START_TOKEN)
0293 seq_puts(seq, "Type Device Function\n");
0294 else if ((!pt->af_packet_net || net_eq(pt->af_packet_net, seq_file_net(seq))) &&
0295 (!pt->dev || net_eq(dev_net(pt->dev), seq_file_net(seq)))) {
0296 if (pt->type == htons(ETH_P_ALL))
0297 seq_puts(seq, "ALL ");
0298 else
0299 seq_printf(seq, "%04x", ntohs(pt->type));
0300
0301 seq_printf(seq, " %-8s %ps\n",
0302 pt->dev ? pt->dev->name : "", pt->func);
0303 }
0304
0305 return 0;
0306 }
0307
0308 static const struct seq_operations ptype_seq_ops = {
0309 .start = ptype_seq_start,
0310 .next = ptype_seq_next,
0311 .stop = ptype_seq_stop,
0312 .show = ptype_seq_show,
0313 };
0314
0315 static int __net_init dev_proc_net_init(struct net *net)
0316 {
0317 int rc = -ENOMEM;
0318
0319 if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops,
0320 sizeof(struct seq_net_private)))
0321 goto out;
0322 if (!proc_create_seq("softnet_stat", 0444, net->proc_net,
0323 &softnet_seq_ops))
0324 goto out_dev;
0325 if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
0326 sizeof(struct seq_net_private)))
0327 goto out_softnet;
0328
0329 if (wext_proc_init(net))
0330 goto out_ptype;
0331 rc = 0;
0332 out:
0333 return rc;
0334 out_ptype:
0335 remove_proc_entry("ptype", net->proc_net);
0336 out_softnet:
0337 remove_proc_entry("softnet_stat", net->proc_net);
0338 out_dev:
0339 remove_proc_entry("dev", net->proc_net);
0340 goto out;
0341 }
0342
0343 static void __net_exit dev_proc_net_exit(struct net *net)
0344 {
0345 wext_proc_exit(net);
0346
0347 remove_proc_entry("ptype", net->proc_net);
0348 remove_proc_entry("softnet_stat", net->proc_net);
0349 remove_proc_entry("dev", net->proc_net);
0350 }
0351
0352 static struct pernet_operations __net_initdata dev_proc_ops = {
0353 .init = dev_proc_net_init,
0354 .exit = dev_proc_net_exit,
0355 };
0356
0357 static int dev_mc_seq_show(struct seq_file *seq, void *v)
0358 {
0359 struct netdev_hw_addr *ha;
0360 struct net_device *dev = v;
0361
0362 if (v == SEQ_START_TOKEN)
0363 return 0;
0364
0365 netif_addr_lock_bh(dev);
0366 netdev_for_each_mc_addr(ha, dev) {
0367 seq_printf(seq, "%-4d %-15s %-5d %-5d %*phN\n",
0368 dev->ifindex, dev->name,
0369 ha->refcount, ha->global_use,
0370 (int)dev->addr_len, ha->addr);
0371 }
0372 netif_addr_unlock_bh(dev);
0373 return 0;
0374 }
0375
0376 static const struct seq_operations dev_mc_seq_ops = {
0377 .start = dev_seq_start,
0378 .next = dev_seq_next,
0379 .stop = dev_seq_stop,
0380 .show = dev_mc_seq_show,
0381 };
0382
0383 static int __net_init dev_mc_net_init(struct net *net)
0384 {
0385 if (!proc_create_net("dev_mcast", 0, net->proc_net, &dev_mc_seq_ops,
0386 sizeof(struct seq_net_private)))
0387 return -ENOMEM;
0388 return 0;
0389 }
0390
0391 static void __net_exit dev_mc_net_exit(struct net *net)
0392 {
0393 remove_proc_entry("dev_mcast", net->proc_net);
0394 }
0395
0396 static struct pernet_operations __net_initdata dev_mc_net_ops = {
0397 .init = dev_mc_net_init,
0398 .exit = dev_mc_net_exit,
0399 };
0400
0401 int __init dev_proc_init(void)
0402 {
0403 int ret = register_pernet_subsys(&dev_proc_ops);
0404 if (!ret)
0405 return register_pernet_subsys(&dev_mc_net_ops);
0406 return ret;
0407 }