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