[IPV4]: Consolidate common SNMP code
[deliverable/linux.git] / net / ipv6 / proc.c
CommitLineData
1da177e4
LT
1/*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * This file implements the various access functions for the
7 * PROC file system. This is very similar to the IPv4 version,
8 * except it reports the sockets in the INET6 address family.
9 *
10 * Version: $Id: proc.c,v 1.17 2002/02/01 22:01:04 davem Exp $
11 *
12 * Authors: David S. Miller (davem@caip.rutgers.edu)
13 * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version.
19 */
1da177e4
LT
20#include <linux/socket.h>
21#include <linux/net.h>
22#include <linux/ipv6.h>
23#include <linux/proc_fs.h>
24#include <linux/seq_file.h>
25#include <linux/stddef.h>
97fc8d0b 26#include <asm/unaligned.h>
1da177e4
LT
27#include <net/sock.h>
28#include <net/tcp.h>
29#include <net/transp_v6.h>
30#include <net/ipv6.h>
31
32#ifdef CONFIG_PROC_FS
33static struct proc_dir_entry *proc_net_devsnmp6;
34
35static int fold_prot_inuse(struct proto *proto)
36{
37 int res = 0;
38 int cpu;
39
6f912042 40 for_each_possible_cpu(cpu)
1da177e4
LT
41 res += proto->stats[cpu].inuse;
42
43 return res;
44}
45
46static int sockstat6_seq_show(struct seq_file *seq, void *v)
47{
48 seq_printf(seq, "TCP6: inuse %d\n",
49 fold_prot_inuse(&tcpv6_prot));
50 seq_printf(seq, "UDP6: inuse %d\n",
51 fold_prot_inuse(&udpv6_prot));
ba4e58ec 52 seq_printf(seq, "UDPLITE6: inuse %d\n",
1ab1457c 53 fold_prot_inuse(&udplitev6_prot));
1da177e4
LT
54 seq_printf(seq, "RAW6: inuse %d\n",
55 fold_prot_inuse(&rawv6_prot));
56 seq_printf(seq, "FRAG6: inuse %d memory %d\n",
57 ip6_frag_nqueues, atomic_read(&ip6_frag_mem));
58 return 0;
59}
60
61static struct snmp_mib snmp6_ipstats_list[] = {
62/* ipv6 mib according to RFC 2465 */
63 SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INRECEIVES),
64 SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS),
65 SNMP_MIB_ITEM("Ip6InTooBigErrors", IPSTATS_MIB_INTOOBIGERRORS),
66 SNMP_MIB_ITEM("Ip6InNoRoutes", IPSTATS_MIB_INNOROUTES),
67 SNMP_MIB_ITEM("Ip6InAddrErrors", IPSTATS_MIB_INADDRERRORS),
68 SNMP_MIB_ITEM("Ip6InUnknownProtos", IPSTATS_MIB_INUNKNOWNPROTOS),
69 SNMP_MIB_ITEM("Ip6InTruncatedPkts", IPSTATS_MIB_INTRUNCATEDPKTS),
70 SNMP_MIB_ITEM("Ip6InDiscards", IPSTATS_MIB_INDISCARDS),
71 SNMP_MIB_ITEM("Ip6InDelivers", IPSTATS_MIB_INDELIVERS),
72 SNMP_MIB_ITEM("Ip6OutForwDatagrams", IPSTATS_MIB_OUTFORWDATAGRAMS),
73 SNMP_MIB_ITEM("Ip6OutRequests", IPSTATS_MIB_OUTREQUESTS),
74 SNMP_MIB_ITEM("Ip6OutDiscards", IPSTATS_MIB_OUTDISCARDS),
75 SNMP_MIB_ITEM("Ip6OutNoRoutes", IPSTATS_MIB_OUTNOROUTES),
76 SNMP_MIB_ITEM("Ip6ReasmTimeout", IPSTATS_MIB_REASMTIMEOUT),
77 SNMP_MIB_ITEM("Ip6ReasmReqds", IPSTATS_MIB_REASMREQDS),
78 SNMP_MIB_ITEM("Ip6ReasmOKs", IPSTATS_MIB_REASMOKS),
79 SNMP_MIB_ITEM("Ip6ReasmFails", IPSTATS_MIB_REASMFAILS),
80 SNMP_MIB_ITEM("Ip6FragOKs", IPSTATS_MIB_FRAGOKS),
81 SNMP_MIB_ITEM("Ip6FragFails", IPSTATS_MIB_FRAGFAILS),
82 SNMP_MIB_ITEM("Ip6FragCreates", IPSTATS_MIB_FRAGCREATES),
83 SNMP_MIB_ITEM("Ip6InMcastPkts", IPSTATS_MIB_INMCASTPKTS),
84 SNMP_MIB_ITEM("Ip6OutMcastPkts", IPSTATS_MIB_OUTMCASTPKTS),
85 SNMP_MIB_SENTINEL
86};
87
88static struct snmp_mib snmp6_icmp6_list[] = {
89/* icmpv6 mib according to RFC 2466
90
91 Exceptions: {In|Out}AdminProhibs are removed, because I see
1ab1457c 92 no good reasons to account them separately
1da177e4
LT
93 of another dest.unreachs.
94 OutErrs is zero identically.
95 OutEchos too.
96 OutRouterAdvertisements too.
97 OutGroupMembQueries too.
98 */
99 SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS),
100 SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS),
101 SNMP_MIB_ITEM("Icmp6InDestUnreachs", ICMP6_MIB_INDESTUNREACHS),
102 SNMP_MIB_ITEM("Icmp6InPktTooBigs", ICMP6_MIB_INPKTTOOBIGS),
103 SNMP_MIB_ITEM("Icmp6InTimeExcds", ICMP6_MIB_INTIMEEXCDS),
104 SNMP_MIB_ITEM("Icmp6InParmProblems", ICMP6_MIB_INPARMPROBLEMS),
105 SNMP_MIB_ITEM("Icmp6InEchos", ICMP6_MIB_INECHOS),
106 SNMP_MIB_ITEM("Icmp6InEchoReplies", ICMP6_MIB_INECHOREPLIES),
107 SNMP_MIB_ITEM("Icmp6InGroupMembQueries", ICMP6_MIB_INGROUPMEMBQUERIES),
108 SNMP_MIB_ITEM("Icmp6InGroupMembResponses", ICMP6_MIB_INGROUPMEMBRESPONSES),
109 SNMP_MIB_ITEM("Icmp6InGroupMembReductions", ICMP6_MIB_INGROUPMEMBREDUCTIONS),
110 SNMP_MIB_ITEM("Icmp6InRouterSolicits", ICMP6_MIB_INROUTERSOLICITS),
111 SNMP_MIB_ITEM("Icmp6InRouterAdvertisements", ICMP6_MIB_INROUTERADVERTISEMENTS),
112 SNMP_MIB_ITEM("Icmp6InNeighborSolicits", ICMP6_MIB_INNEIGHBORSOLICITS),
113 SNMP_MIB_ITEM("Icmp6InNeighborAdvertisements", ICMP6_MIB_INNEIGHBORADVERTISEMENTS),
114 SNMP_MIB_ITEM("Icmp6InRedirects", ICMP6_MIB_INREDIRECTS),
115 SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS),
116 SNMP_MIB_ITEM("Icmp6OutDestUnreachs", ICMP6_MIB_OUTDESTUNREACHS),
117 SNMP_MIB_ITEM("Icmp6OutPktTooBigs", ICMP6_MIB_OUTPKTTOOBIGS),
118 SNMP_MIB_ITEM("Icmp6OutTimeExcds", ICMP6_MIB_OUTTIMEEXCDS),
119 SNMP_MIB_ITEM("Icmp6OutParmProblems", ICMP6_MIB_OUTPARMPROBLEMS),
120 SNMP_MIB_ITEM("Icmp6OutEchoReplies", ICMP6_MIB_OUTECHOREPLIES),
121 SNMP_MIB_ITEM("Icmp6OutRouterSolicits", ICMP6_MIB_OUTROUTERSOLICITS),
122 SNMP_MIB_ITEM("Icmp6OutNeighborSolicits", ICMP6_MIB_OUTNEIGHBORSOLICITS),
123 SNMP_MIB_ITEM("Icmp6OutNeighborAdvertisements", ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS),
124 SNMP_MIB_ITEM("Icmp6OutRedirects", ICMP6_MIB_OUTREDIRECTS),
125 SNMP_MIB_ITEM("Icmp6OutGroupMembResponses", ICMP6_MIB_OUTGROUPMEMBRESPONSES),
126 SNMP_MIB_ITEM("Icmp6OutGroupMembReductions", ICMP6_MIB_OUTGROUPMEMBREDUCTIONS),
127 SNMP_MIB_SENTINEL
128};
129
130static struct snmp_mib snmp6_udp6_list[] = {
131 SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS),
132 SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS),
133 SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS),
134 SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS),
135 SNMP_MIB_SENTINEL
136};
137
ba4e58ec
GR
138static struct snmp_mib snmp6_udplite6_list[] = {
139 SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS),
140 SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS),
141 SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS),
142 SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS),
143 SNMP_MIB_SENTINEL
144};
1370b5a5 145#endif /* CONFIG_PROC_FS */
ba4e58ec 146
1da177e4
LT
147static unsigned long
148fold_field(void *mib[], int offt)
149{
1ab1457c
YH
150 unsigned long res = 0;
151 int i;
152
153 for_each_possible_cpu(i) {
154 res += *(((unsigned long *)per_cpu_ptr(mib[0], i)) + offt);
155 res += *(((unsigned long *)per_cpu_ptr(mib[1], i)) + offt);
156 }
157 return res;
1da177e4
LT
158}
159
1370b5a5 160#ifdef CONFIG_PROC_FS
1da177e4
LT
161static inline void
162snmp6_seq_show_item(struct seq_file *seq, void **mib, struct snmp_mib *itemlist)
163{
164 int i;
165 for (i=0; itemlist[i].name; i++)
1ab1457c 166 seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name,
1da177e4
LT
167 fold_field(mib, itemlist[i].entry));
168}
169
170static int snmp6_seq_show(struct seq_file *seq, void *v)
171{
172 struct inet6_dev *idev = (struct inet6_dev *)seq->private;
173
174 if (idev) {
175 seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex);
a11d206d 176 snmp6_seq_show_item(seq, (void **)idev->stats.ipv6, snmp6_ipstats_list);
1da177e4
LT
177 snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list);
178 } else {
179 snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipstats_list);
180 snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list);
181 snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list);
ba4e58ec 182 snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list);
1da177e4
LT
183 }
184 return 0;
185}
186
187static int sockstat6_seq_open(struct inode *inode, struct file *file)
188{
189 return single_open(file, sockstat6_seq_show, NULL);
190}
191
9a32144e 192static const struct file_operations sockstat6_seq_fops = {
1da177e4
LT
193 .owner = THIS_MODULE,
194 .open = sockstat6_seq_open,
195 .read = seq_read,
196 .llseek = seq_lseek,
197 .release = single_release,
198};
199
200static int snmp6_seq_open(struct inode *inode, struct file *file)
201{
202 return single_open(file, snmp6_seq_show, PDE(inode)->data);
203}
204
9a32144e 205static const struct file_operations snmp6_seq_fops = {
1da177e4
LT
206 .owner = THIS_MODULE,
207 .open = snmp6_seq_open,
208 .read = seq_read,
209 .llseek = seq_lseek,
210 .release = single_release,
211};
1370b5a5 212#endif /* CONFIG_PROC_FS */
1da177e4 213
bf99f1bd 214static inline void
97fc8d0b 215__snmp6_fill_stats(u64 *stats, void **mib, int items, int bytes)
bf99f1bd
YH
216{
217 int i;
218 int pad = bytes - sizeof(u64) * items;
219 BUG_ON(pad < 0);
97fc8d0b
YH
220
221 /* Use put_unaligned() because stats may not be aligned for u64. */
222 put_unaligned(items, &stats[0]);
223 for (i = 1; i < items; i++)
224 put_unaligned(fold_field(mib, i), &stats[i]);
225
226 memset(&stats[items], 0, pad);
bf99f1bd
YH
227}
228
229void
97fc8d0b 230snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, int bytes)
bf99f1bd
YH
231{
232 switch(attrtype) {
233 case IFLA_INET6_STATS:
234 __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
235 break;
236 case IFLA_INET6_ICMP6STATS:
237 __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
238 break;
239 }
240}
241
1370b5a5 242#ifdef CONFIG_PROC_FS
1da177e4
LT
243int snmp6_register_dev(struct inet6_dev *idev)
244{
245 struct proc_dir_entry *p;
246
247 if (!idev || !idev->dev)
248 return -EINVAL;
249
250 if (!proc_net_devsnmp6)
251 return -ENOENT;
252
253 p = create_proc_entry(idev->dev->name, S_IRUGO, proc_net_devsnmp6);
254 if (!p)
255 return -ENOMEM;
256
257 p->data = idev;
258 p->proc_fops = &snmp6_seq_fops;
259
260 idev->stats.proc_dir_entry = p;
261 return 0;
262}
263
264int snmp6_unregister_dev(struct inet6_dev *idev)
265{
266 if (!proc_net_devsnmp6)
267 return -ENOENT;
268 if (!idev || !idev->stats.proc_dir_entry)
269 return -EINVAL;
270 remove_proc_entry(idev->stats.proc_dir_entry->name,
271 proc_net_devsnmp6);
272 return 0;
273}
274
275int __init ipv6_misc_proc_init(void)
276{
277 int rc = 0;
278
279 if (!proc_net_fops_create("snmp6", S_IRUGO, &snmp6_seq_fops))
280 goto proc_snmp6_fail;
281
282 proc_net_devsnmp6 = proc_mkdir("dev_snmp6", proc_net);
283 if (!proc_net_devsnmp6)
284 goto proc_dev_snmp6_fail;
285
286 if (!proc_net_fops_create("sockstat6", S_IRUGO, &sockstat6_seq_fops))
287 goto proc_sockstat6_fail;
288out:
289 return rc;
290
291proc_sockstat6_fail:
292 proc_net_remove("dev_snmp6");
293proc_dev_snmp6_fail:
294 proc_net_remove("snmp6");
295proc_snmp6_fail:
296 rc = -ENOMEM;
297 goto out;
298}
299
300void ipv6_misc_proc_exit(void)
301{
302 proc_net_remove("sockstat6");
303 proc_net_remove("dev_snmp6");
304 proc_net_remove("snmp6");
305}
306
307#else /* CONFIG_PROC_FS */
308
309
310int snmp6_register_dev(struct inet6_dev *idev)
311{
312 return 0;
313}
314
315int snmp6_unregister_dev(struct inet6_dev *idev)
316{
317 return 0;
318}
bf99f1bd 319
1da177e4
LT
320#endif /* CONFIG_PROC_FS */
321
322int snmp6_alloc_dev(struct inet6_dev *idev)
323{
324 int err = -ENOMEM;
325
326 if (!idev || !idev->dev)
327 return -EINVAL;
328
a11d206d
YH
329 if (snmp6_mib_init((void **)idev->stats.ipv6, sizeof(struct ipstats_mib),
330 __alignof__(struct ipstats_mib)) < 0)
331 goto err_ip;
1da177e4
LT
332 if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib),
333 __alignof__(struct icmpv6_mib)) < 0)
334 goto err_icmp;
335
336 return 0;
337
338err_icmp:
a11d206d
YH
339 snmp6_mib_free((void **)idev->stats.ipv6);
340err_ip:
1da177e4
LT
341 return err;
342}
343
344int snmp6_free_dev(struct inet6_dev *idev)
345{
346 snmp6_mib_free((void **)idev->stats.icmpv6);
a11d206d 347 snmp6_mib_free((void **)idev->stats.ipv6);
1da177e4
LT
348 return 0;
349}
350
49ed67a9
YH
351int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign)
352{
353 if (ptr == NULL)
354 return -EINVAL;
355
356 ptr[0] = __alloc_percpu(mibsize);
357 if (!ptr[0])
358 goto err0;
359
360 ptr[1] = __alloc_percpu(mibsize);
361 if (!ptr[1])
362 goto err1;
363
364 return 0;
365
366err1:
367 free_percpu(ptr[0]);
368 ptr[0] = NULL;
369err0:
370 return -ENOMEM;
371}
372
373void snmp6_mib_free(void *ptr[2])
374{
375 if (ptr == NULL)
376 return;
377 free_percpu(ptr[0]);
378 free_percpu(ptr[1]);
379 ptr[0] = ptr[1] = NULL;
380}
1da177e4 381
This page took 0.353231 seconds and 5 git commands to generate.