blob: 504d2f3c05ab222d8a2ae8c0abb8c62798f24110 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* Interface name and statistics get function using proc file system
2 * Copyright (C) 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
24#include "if.h"
25#include "prefix.h"
26#include "log.h"
27
28#include "zebra/ioctl.h"
29#include "zebra/connected.h"
30#include "zebra/interface.h"
31
32/* Proc filesystem one line buffer. */
33#define PROCBUFSIZ 1024
34
35/* Path to device proc file system. */
36#ifndef _PATH_PROC_NET_DEV
37#define _PATH_PROC_NET_DEV "/proc/net/dev"
38#endif /* _PATH_PROC_NET_DEV */
39
40/* Return statistics data pointer. */
41static char *
42interface_name_cut (char *buf, char **name)
43{
44 char *stat;
45
46 /* Skip white space. Line will include header spaces. */
47 while (*buf == ' ')
48 buf++;
49 *name = buf;
50
51 /* Cut interface name. */
52 stat = strrchr (buf, ':');
53 *stat++ = '\0';
54
55 return stat;
56}
57
58/* Fetch each statistics field. */
59static int
60ifstat_dev_fields (int version, char *buf, struct interface *ifp)
61{
62 switch (version)
63 {
64 case 3:
65 sscanf(buf,
66 "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
67 &ifp->stats.rx_bytes,
68 &ifp->stats.rx_packets,
69 &ifp->stats.rx_errors,
70 &ifp->stats.rx_dropped,
71 &ifp->stats.rx_fifo_errors,
72 &ifp->stats.rx_frame_errors,
73 &ifp->stats.rx_compressed,
74 &ifp->stats.rx_multicast,
75
76 &ifp->stats.tx_bytes,
77 &ifp->stats.tx_packets,
78 &ifp->stats.tx_errors,
79 &ifp->stats.tx_dropped,
80 &ifp->stats.tx_fifo_errors,
81 &ifp->stats.collisions,
82 &ifp->stats.tx_carrier_errors,
83 &ifp->stats.tx_compressed);
84 break;
85 case 2:
86 sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
87 &ifp->stats.rx_bytes,
88 &ifp->stats.rx_packets,
89 &ifp->stats.rx_errors,
90 &ifp->stats.rx_dropped,
91 &ifp->stats.rx_fifo_errors,
92 &ifp->stats.rx_frame_errors,
93
94 &ifp->stats.tx_bytes,
95 &ifp->stats.tx_packets,
96 &ifp->stats.tx_errors,
97 &ifp->stats.tx_dropped,
98 &ifp->stats.tx_fifo_errors,
99 &ifp->stats.collisions,
100 &ifp->stats.tx_carrier_errors);
101 ifp->stats.rx_multicast = 0;
102 break;
103 case 1:
104 sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
105 &ifp->stats.rx_packets,
106 &ifp->stats.rx_errors,
107 &ifp->stats.rx_dropped,
108 &ifp->stats.rx_fifo_errors,
109 &ifp->stats.rx_frame_errors,
110
111 &ifp->stats.tx_packets,
112 &ifp->stats.tx_errors,
113 &ifp->stats.tx_dropped,
114 &ifp->stats.tx_fifo_errors,
115 &ifp->stats.collisions,
116 &ifp->stats.tx_carrier_errors);
117 ifp->stats.rx_bytes = 0;
118 ifp->stats.tx_bytes = 0;
119 ifp->stats.rx_multicast = 0;
120 break;
121 }
122 return 0;
123}
124
125/* Update interface's statistics. */
126int
127ifstat_update_proc ()
128{
129 FILE *fp;
130 char buf[PROCBUFSIZ];
131 int version;
132 struct interface *ifp;
133 char *stat;
134 char *name;
135
136 /* Open /proc/net/dev. */
137 fp = fopen (_PATH_PROC_NET_DEV, "r");
138 if (fp == NULL)
139 {
140 zlog_warn ("Can't open proc file %s: %s",
ajs6099b3b2004-11-20 02:06:59 +0000141 _PATH_PROC_NET_DEV, safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000142 return -1;
143 }
144
145 /* Drop header lines. */
146 fgets (buf, PROCBUFSIZ, fp);
147 fgets (buf, PROCBUFSIZ, fp);
148
149 /* To detect proc format veresion, parse second line. */
150 if (strstr (buf, "compressed"))
151 version = 3;
152 else if (strstr (buf, "bytes"))
153 version = 2;
154 else
155 version = 1;
156
157 /* Update each interface's statistics. */
158 while (fgets (buf, PROCBUFSIZ, fp) != NULL)
159 {
160 stat = interface_name_cut (buf, &name);
161 ifp = if_get_by_name (name);
162 ifstat_dev_fields (version, stat, ifp);
163 }
paul7f809942003-07-12 21:49:25 +0000164 fclose(fp);
paul718e3742002-12-13 20:15:29 +0000165 return 0;
166}
167
168/* Interface structure allocation by proc filesystem. */
169int
170interface_list_proc ()
171{
172 FILE *fp;
173 char buf[PROCBUFSIZ];
174 struct interface *ifp;
175 char *name;
176
177 /* Open /proc/net/dev. */
178 fp = fopen (_PATH_PROC_NET_DEV, "r");
179 if (fp == NULL)
180 {
181 zlog_warn ("Can't open proc file %s: %s",
ajs6099b3b2004-11-20 02:06:59 +0000182 _PATH_PROC_NET_DEV, safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000183 return -1;
184 }
185
186 /* Drop header lines. */
187 fgets (buf, PROCBUFSIZ, fp);
188 fgets (buf, PROCBUFSIZ, fp);
189
190 /* Only allocate interface structure. Other jobs will be done in
191 if_ioctl.c. */
192 while (fgets (buf, PROCBUFSIZ, fp) != NULL)
193 {
194 interface_name_cut (buf, &name);
195 ifp = if_get_by_name (name);
196 if_add_update (ifp);
197 }
paul7f809942003-07-12 21:49:25 +0000198 fclose(fp);
paul718e3742002-12-13 20:15:29 +0000199 return 0;
200}
201
202#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
203
204#ifndef _PATH_PROC_NET_IF_INET6
205#define _PATH_PROC_NET_IF_INET6 "/proc/net/if_inet6"
206#endif /* _PATH_PROC_NET_IF_INET6 */
207
208int
209ifaddr_proc_ipv6 ()
210{
211 FILE *fp;
212 char buf[PROCBUFSIZ];
213 int n;
214 char addr[33];
215 char ifname[20];
216 int ifindex, plen, scope, status;
217 struct interface *ifp;
218 struct prefix_ipv6 p;
219
220 /* Open proc file system. */
221 fp = fopen (_PATH_PROC_NET_IF_INET6, "r");
222 if (fp == NULL)
223 {
224 zlog_warn ("Can't open proc file %s: %s",
ajs6099b3b2004-11-20 02:06:59 +0000225 _PATH_PROC_NET_IF_INET6, safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000226 return -1;
227 }
228
229 /* Get interface's IPv6 address. */
230 while (fgets (buf, PROCBUFSIZ, fp) != NULL)
231 {
232 n = sscanf (buf, "%32s %02x %02x %02x %02x %20s",
233 addr, &ifindex, &plen, &scope, &status, ifname);
234 if (n != 6)
235 continue;
236
237 ifp = if_get_by_name (ifname);
238
239 /* Fetch interface's IPv6 address. */
240 str2in6_addr (addr, &p.prefix);
241 p.prefixlen = plen;
242
243 connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL);
244 }
hasso42a66d72005-03-07 08:19:44 +0000245 fclose (fp);
paul718e3742002-12-13 20:15:29 +0000246 return 0;
247}
248#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */