ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.64
Committed: Tue Apr 6 14:52:58 2004 UTC (20 years, 1 month ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.63: +2 -2 lines
Log Message:
Update name of project at the top of all soure files. These files now exist
in their own right, rather than as part of the "CMS".

File Contents

# User Rev Content
1 tdb 1.22 /*
2 tdb 1.64 * i-scream libstatgrab
3 tdb 1.15 * http://www.i-scream.org
4 tdb 1.22 * Copyright (C) 2000-2004 i-scream
5 pajs 1.1 *
6 tdb 1.22 * This library is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU Lesser General Public
8     * License as published by the Free Software Foundation; either
9     * version 2.1 of the License, or (at your option) any later version.
10 pajs 1.1 *
11 tdb 1.22 * This library is distributed in the hope that it will be useful,
12 pajs 1.1 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 tdb 1.22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     * Lesser General Public License for more details.
15 pajs 1.1 *
16 tdb 1.22 * You should have received a copy of the GNU Lesser General Public
17     * License along with this library; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19     * 02111-1307 USA
20 tdb 1.23 *
21 tdb 1.64 * $Id: network_stats.c,v 1.63 2004/04/05 18:10:11 ats Exp $
22 pajs 1.1 */
23    
24     #ifdef HAVE_CONFIG_H
25     #include "config.h"
26     #endif
27    
28 tdb 1.4 #include <stdlib.h>
29 pajs 1.6 #include <string.h>
30 pajs 1.1 #include "statgrab.h"
31 ats 1.59 #include "vector.h"
32 ats 1.60 #include "tools.h"
33 tdb 1.11 #include <time.h>
34 pajs 1.1 #ifdef SOLARIS
35     #include <kstat.h>
36     #include <sys/sysinfo.h>
37 ats 1.44 #include <sys/types.h>
38     #include <sys/socket.h>
39     #include <sys/ioctl.h>
40     #include <net/if.h>
41     #include <netinet/in.h>
42     #include <sys/sockio.h>
43 tdb 1.61 #include <unistd.h>
44 pajs 1.6 #endif
45     #ifdef LINUX
46     #include <stdio.h>
47     #include <sys/types.h>
48     #include <regex.h>
49 pajs 1.27 #include <sys/ioctl.h>
50     #include <sys/socket.h>
51     #include <net/if.h>
52     #include <ctype.h>
53     /* Stuff which could be defined by defining KERNEL, but
54     * that would be a bad idea, so we'll just declare it here
55     */
56     typedef __uint8_t u8;
57     typedef __uint16_t u16;
58     typedef __uint32_t u32;
59 ats 1.42 typedef __uint64_t u64;
60 pajs 1.27 #include <linux/ethtool.h>
61     #include <linux/sockios.h>
62 ats 1.32 #include <unistd.h>
63 pajs 1.1 #endif
64 ats 1.18 #ifdef ALLBSD
65 pajs 1.14 #include <sys/types.h>
66     #include <sys/socket.h>
67     #include <ifaddrs.h>
68     #include <net/if.h>
69 pajs 1.26 #include <net/if_media.h>
70     #include <sys/ioctl.h>
71 tdb 1.58 #include <unistd.h>
72 pajs 1.14 #endif
73 pajs 1.1
74 ats 1.62 static void network_stat_init(sg_network_io_stats *s) {
75 ats 1.59 s->interface_name = NULL;
76     s->tx = 0;
77     s->rx = 0;
78     s->ipackets = 0;
79     s->opackets = 0;
80     s->ierrors = 0;
81     s->oerrors = 0;
82     s->collisions = 0;
83 pajs 1.3 }
84    
85 ats 1.62 static void network_stat_destroy(sg_network_io_stats *s) {
86 ats 1.59 free(s->interface_name);
87 pajs 1.1 }
88    
89 ats 1.62 VECTOR_DECLARE_STATIC(network_stats, sg_network_io_stats, 5,
90 ats 1.59 network_stat_init, network_stat_destroy);
91 pajs 1.3
92 ats 1.62 sg_network_io_stats *sg_get_network_io_stats(int *entries){
93 ats 1.59 int interfaces;
94 ats 1.62 sg_network_io_stats *network_stat_ptr;
95 pajs 1.6
96     #ifdef SOLARIS
97 pajs 1.1 kstat_ctl_t *kc;
98     kstat_t *ksp;
99     kstat_named_t *knp;
100 pajs 1.6 #endif
101 pajs 1.3
102 pajs 1.6 #ifdef LINUX
103     FILE *f;
104 pajs 1.12 /* Horrible big enough, but it should be easily big enough */
105 pajs 1.6 char line[8096];
106     regex_t regex;
107 ats 1.49 regmatch_t line_match[9];
108 pajs 1.14 #endif
109 ats 1.18 #ifdef ALLBSD
110 pajs 1.14 struct ifaddrs *net, *net_ptr;
111     struct if_data *net_data;
112     #endif
113    
114 ats 1.18 #ifdef ALLBSD
115 pajs 1.14 if(getifaddrs(&net) != 0){
116     return NULL;
117     }
118    
119     interfaces=0;
120    
121     for(net_ptr=net;net_ptr!=NULL;net_ptr=net_ptr->ifa_next){
122     if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
123 ats 1.59
124     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
125 pajs 1.14 return NULL;
126     }
127     network_stat_ptr=network_stats+interfaces;
128    
129 ats 1.62 if (sg_update_string(&network_stat_ptr->interface_name,
130 ats 1.63 net_ptr->ifa_name) < 0) {
131 ats 1.60 return NULL;
132     }
133 pajs 1.14 net_data=(struct if_data *)net_ptr->ifa_data;
134     network_stat_ptr->rx=net_data->ifi_ibytes;
135 tdb 1.46 network_stat_ptr->tx=net_data->ifi_obytes;
136     network_stat_ptr->ipackets=net_data->ifi_ipackets;
137     network_stat_ptr->opackets=net_data->ifi_opackets;
138     network_stat_ptr->ierrors=net_data->ifi_ierrors;
139     network_stat_ptr->oerrors=net_data->ifi_oerrors;
140     network_stat_ptr->collisions=net_data->ifi_collisions;
141 pajs 1.14 network_stat_ptr->systime=time(NULL);
142     interfaces++;
143     }
144     freeifaddrs(net);
145 pajs 1.6 #endif
146 pajs 1.1
147 pajs 1.6 #ifdef SOLARIS
148 pajs 1.1 if ((kc = kstat_open()) == NULL) {
149     return NULL;
150     }
151    
152 pajs 1.6 interfaces=0;
153 pajs 1.3
154 pajs 1.1 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
155     if (!strcmp(ksp->ks_class, "net")) {
156     kstat_read(kc, ksp, NULL);
157    
158 pajs 1.7 #ifdef SOL7
159 tdb 1.53 #define LRX "rbytes"
160     #define LTX "obytes"
161     #define LIPACKETS "ipackets"
162     #define LOPACKETS "opackets"
163 pajs 1.7 #define VALTYPE value.ui32
164     #else
165 tdb 1.53 #define LRX "rbytes64"
166     #define LTX "obytes64"
167     #define LIPACKETS "ipackets64"
168     #define LOPACKETS "opackets64"
169 pajs 1.7 #define VALTYPE value.ui64
170     #endif
171    
172 tdb 1.53 /* Read rx */
173     if((knp=kstat_data_lookup(ksp, LRX))==NULL){
174 ats 1.44 /* This is a network interface, but it doesn't
175     * have the rbytes/obytes values; for instance,
176     * the loopback devices have this behaviour
177     * (although they do track packets in/out). */
178 ats 1.55 /* FIXME: Show packet counts when byte counts
179     * not available. */
180 pajs 1.1 continue;
181     }
182 pajs 1.3
183 tdb 1.53 /* Create new network_stats */
184 ats 1.59 if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
185 pajs 1.1 return NULL;
186     }
187     network_stat_ptr=network_stats+interfaces;
188 tdb 1.53
189     /* Finish reading rx */
190 pajs 1.7 network_stat_ptr->rx=knp->VALTYPE;
191 pajs 1.1
192 tdb 1.53 /* Read tx */
193     if((knp=kstat_data_lookup(ksp, LTX))==NULL){
194 pajs 1.1 continue;
195     }
196 pajs 1.7 network_stat_ptr->tx=knp->VALTYPE;
197 tdb 1.53
198     /* Read ipackets */
199     if((knp=kstat_data_lookup(ksp, LIPACKETS))==NULL){
200     continue;
201     }
202     network_stat_ptr->ipackets=knp->VALTYPE;
203    
204     /* Read opackets */
205     if((knp=kstat_data_lookup(ksp, LOPACKETS))==NULL){
206     continue;
207     }
208     network_stat_ptr->opackets=knp->VALTYPE;
209    
210     /* Read ierrors */
211     if((knp=kstat_data_lookup(ksp, "ierrors"))==NULL){
212     continue;
213     }
214     network_stat_ptr->ierrors=knp->value.ui32;
215    
216     /* Read oerrors */
217     if((knp=kstat_data_lookup(ksp, "oerrors"))==NULL){
218     continue;
219     }
220     network_stat_ptr->oerrors=knp->value.ui32;
221    
222     /* Read collisions */
223     if((knp=kstat_data_lookup(ksp, "collisions"))==NULL){
224     continue;
225     }
226     network_stat_ptr->collisions=knp->value.ui32;
227    
228     /* Read interface name */
229 ats 1.62 if (sg_update_string(&network_stat_ptr->interface_name,
230 ats 1.63 ksp->ks_name) < 0) {
231 ats 1.60 return NULL;
232 pajs 1.1 }
233 pajs 1.3
234 tdb 1.53 /* Store systime */
235 pajs 1.3 network_stat_ptr->systime=time(NULL);
236 tdb 1.53
237 pajs 1.1 interfaces++;
238     }
239     }
240 pajs 1.2
241     kstat_close(kc);
242 pajs 1.6 #endif
243     #ifdef LINUX
244     f=fopen("/proc/net/dev", "r");
245     if(f==NULL){
246     return NULL;
247     }
248     /* read the 2 lines.. Its the title, so we dont care :) */
249     fgets(line, sizeof(line), f);
250     fgets(line, sizeof(line), f);
251    
252    
253 ats 1.50 if((regcomp(&regex, "^ *([^:]+): *([0-9]+) +([0-9]+) +([0-9]+) +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +([0-9]+) +([0-9]+) +([0-9]+) +[0-9]+ +[0-9]+ +([0-9]+)", REG_EXTENDED))!=0){
254 pajs 1.6 return NULL;
255     }
256    
257     interfaces=0;
258 pajs 1.1
259 pajs 1.6 while((fgets(line, sizeof(line), f)) != NULL){
260 ats 1.51 if((regexec(&regex, line, 9, line_match, 0))!=0){
261 pajs 1.6 continue;
262     }
263 ats 1.59
264     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
265     return NULL;
266 pajs 1.6 }
267     network_stat_ptr=network_stats+interfaces;
268    
269     if(network_stat_ptr->interface_name!=NULL){
270     free(network_stat_ptr->interface_name);
271     }
272    
273 ats 1.62 network_stat_ptr->interface_name=sg_get_string_match(line, &line_match[1]);
274     network_stat_ptr->rx=sg_get_ll_match(line, &line_match[2]);
275     network_stat_ptr->tx=sg_get_ll_match(line, &line_match[5]);
276     network_stat_ptr->ipackets=sg_get_ll_match(line, &line_match[3]);
277     network_stat_ptr->opackets=sg_get_ll_match(line, &line_match[6]);
278     network_stat_ptr->ierrors=sg_get_ll_match(line, &line_match[4]);
279     network_stat_ptr->oerrors=sg_get_ll_match(line, &line_match[7]);
280     network_stat_ptr->collisions=sg_get_ll_match(line, &line_match[8]);
281 pajs 1.6 network_stat_ptr->systime=time(NULL);
282    
283     interfaces++;
284     }
285 pajs 1.12 fclose(f);
286 pajs 1.13 regfree(&regex);
287 pajs 1.6
288     #endif
289 ats 1.20
290     #ifdef CYGWIN
291     return NULL;
292     #endif
293    
294 pajs 1.1 *entries=interfaces;
295    
296     return network_stats;
297 pajs 1.3 }
298    
299 ats 1.62 static long long transfer_diff(long long new, long long old){
300 ats 1.56 #if defined(SOL7) || defined(LINUX) || defined(FREEBSD) || defined(DFBSD) || defined(OPENBSD)
301     /* 32-bit quantities, so we must explicitly deal with wraparound. */
302     #define MAXVAL 0x100000000LL
303     if (new >= old) {
304     return new - old;
305     } else {
306     return MAXVAL + new - old;
307     }
308 pajs 1.8 #else
309 ats 1.56 /* 64-bit quantities, so plain subtraction works. */
310     return new - old;
311 pajs 1.8 #endif
312     }
313    
314 ats 1.62 sg_network_io_stats *sg_get_network_io_stats_diff(int *entries) {
315     VECTOR_DECLARE_STATIC(diff, sg_network_io_stats, 1,
316 ats 1.59 network_stat_init, network_stat_destroy);
317 ats 1.62 sg_network_io_stats *src = NULL, *dest;
318 ats 1.59 int i, j, diff_count, new_count;
319 ats 1.24
320     if (network_stats == NULL) {
321     /* No previous stats, so we can't calculate a difference. */
322 ats 1.62 return sg_get_network_io_stats(entries);
323 pajs 1.3 }
324    
325 ats 1.24 /* Resize the results array to match the previous stats. */
326 ats 1.59 diff_count = VECTOR_SIZE(network_stats);
327     if (VECTOR_RESIZE(diff, diff_count) < 0) {
328 pajs 1.3 return NULL;
329     }
330    
331 ats 1.24 /* Copy the previous stats into the result. */
332     for (i = 0; i < diff_count; i++) {
333     src = &network_stats[i];
334     dest = &diff[i];
335 pajs 1.3
336 ats 1.62 if (sg_update_string(&dest->interface_name,
337 ats 1.63 src->interface_name) < 0) {
338 ats 1.60 return NULL;
339 pajs 1.3 }
340 ats 1.24 dest->rx = src->rx;
341     dest->tx = src->tx;
342 tdb 1.47 dest->ipackets = src->ipackets;
343     dest->opackets = src->opackets;
344     dest->ierrors = src->ierrors;
345     dest->oerrors = src->oerrors;
346     dest->collisions = src->collisions;
347 ats 1.24 dest->systime = src->systime;
348     }
349 pajs 1.3
350 ats 1.24 /* Get a new set of stats. */
351 ats 1.62 if (sg_get_network_io_stats(&new_count) == NULL) {
352 ats 1.21 return NULL;
353     }
354 pajs 1.3
355 ats 1.24 /* For each previous stat... */
356     for (i = 0; i < diff_count; i++) {
357     dest = &diff[i];
358    
359     /* ... find the corresponding new stat ... */
360     for (j = 0; j < new_count; j++) {
361     /* Try the new stat in the same position first,
362     since that's most likely to be it. */
363     src = &network_stats[(i + j) % new_count];
364     if (strcmp(src->interface_name, dest->interface_name) == 0) {
365     break;
366     }
367     }
368     if (j == new_count) {
369     /* No match found. */
370     continue;
371 pajs 1.3 }
372    
373 ats 1.24 /* ... and subtract the previous stat from it to get the
374     difference. */
375     dest->rx = transfer_diff(src->rx, dest->rx);
376     dest->tx = transfer_diff(src->tx, dest->tx);
377 tdb 1.47 dest->ipackets = transfer_diff(src->ipackets, dest->ipackets);
378     dest->opackets = transfer_diff(src->opackets, dest->opackets);
379     dest->ierrors = transfer_diff(src->ierrors, dest->ierrors);
380     dest->oerrors = transfer_diff(src->oerrors, dest->oerrors);
381     dest->collisions = transfer_diff(src->collisions, dest->collisions);
382 ats 1.24 dest->systime = src->systime - dest->systime;
383 pajs 1.3 }
384    
385 ats 1.24 *entries = diff_count;
386     return diff;
387     }
388 ats 1.59
389 pajs 1.25 /* NETWORK INTERFACE STATS */
390    
391 ats 1.62 static void network_iface_stat_init(sg_network_iface_stats *s) {
392 ats 1.59 s->interface_name = NULL;
393     s->speed = 0;
394 ats 1.62 s->dup = SG_IFACE_DUPLEX_UNKNOWN;
395 pajs 1.25 }
396    
397 ats 1.62 static void network_iface_stat_destroy(sg_network_iface_stats *s) {
398 ats 1.59 free(s->interface_name);
399 pajs 1.25 }
400    
401 ats 1.62 sg_network_iface_stats *sg_get_network_iface_stats(int *entries){
402     VECTOR_DECLARE_STATIC(network_iface_stats, sg_network_iface_stats, 5,
403 ats 1.59 network_iface_stat_init, network_iface_stat_destroy);
404 ats 1.62 sg_network_iface_stats *network_iface_stat_ptr;
405 ats 1.43 int ifaces = 0;
406 pajs 1.25
407     #ifdef SOLARIS
408     kstat_ctl_t *kc;
409     kstat_t *ksp;
410     kstat_named_t *knp;
411 ats 1.44 int sock;
412 pajs 1.25 #endif
413 pajs 1.26 #ifdef ALLBSD
414     struct ifaddrs *net, *net_ptr;
415     struct ifmediareq ifmed;
416 pajs 1.36 struct ifreq ifr;
417 ats 1.37 int sock;
418 pajs 1.26 int x;
419     #endif
420 pajs 1.27 #ifdef LINUX
421     FILE *f;
422     /* Horrible big enough, but it should be easily big enough */
423     char line[8096];
424     int sock;
425     #endif
426 ats 1.43
427 pajs 1.26 #ifdef ALLBSD
428     if(getifaddrs(&net) != 0){
429     return NULL;
430     }
431    
432 ats 1.37 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == 0) return NULL;
433 pajs 1.26
434     for(net_ptr=net; net_ptr!=NULL; net_ptr=net_ptr->ifa_next){
435     if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
436 ats 1.59
437     if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
438 pajs 1.26 return NULL;
439     }
440     network_iface_stat_ptr = network_iface_stats + ifaces;
441    
442 ats 1.40 memset(&ifr, 0, sizeof(ifr));
443     strncpy(ifr.ifr_name, net_ptr->ifa_name, sizeof(ifr.ifr_name));
444    
445     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0){
446     continue;
447     }
448     if((ifr.ifr_flags & IFF_UP) != 0){
449     network_iface_stat_ptr->up = 1;
450     }else{
451     network_iface_stat_ptr->up = 0;
452     }
453    
454 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
455 ats 1.63 net_ptr->ifa_name) < 0) {
456 ats 1.60 return NULL;
457     }
458 ats 1.40
459     network_iface_stat_ptr->speed = 0;
460 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
461 ats 1.40 ifaces++;
462    
463 pajs 1.26 memset(&ifmed, 0, sizeof(struct ifmediareq));
464 ats 1.62 sg_strlcpy(ifmed.ifm_name, net_ptr->ifa_name, sizeof(ifmed.ifm_name));
465 ats 1.37 if(ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed) == -1){
466 ats 1.40 /* Not all interfaces support the media ioctls. */
467 pajs 1.26 continue;
468     }
469    
470     /* We may need to change this if we start doing wireless devices too */
471     if( (ifmed.ifm_active | IFM_ETHER) != ifmed.ifm_active ){
472     /* Not a ETHER device */
473     continue;
474     }
475    
476     /* Only intrested in the first 4 bits) - Assuming only ETHER devices */
477     x = ifmed.ifm_active & 0x0f;
478     switch(x){
479     /* 10 Mbit connections. Speedy :) */
480     case(IFM_10_T):
481     case(IFM_10_2):
482     case(IFM_10_5):
483     case(IFM_10_STP):
484     case(IFM_10_FL):
485     network_iface_stat_ptr->speed = 10;
486     break;
487     /* 100 Mbit conneections */
488     case(IFM_100_TX):
489     case(IFM_100_FX):
490     case(IFM_100_T4):
491     case(IFM_100_VG):
492     case(IFM_100_T2):
493     network_iface_stat_ptr->speed = 100;
494     break;
495     /* 1000 Mbit connections */
496     case(IFM_1000_SX):
497     case(IFM_1000_LX):
498     case(IFM_1000_CX):
499 tdb 1.54 #if defined(IFM_1000_TX) && !defined(OPENBSD)
500     case(IFM_1000_TX): /* FreeBSD 4 and others (but NOT OpenBSD)? */
501 tdb 1.45 #endif
502     #ifdef IFM_1000_FX
503     case(IFM_1000_FX): /* FreeBSD 4 */
504     #endif
505     #ifdef IFM_1000_T
506     case(IFM_1000_T): /* FreeBSD 5 */
507 tdb 1.28 #endif
508 pajs 1.26 network_iface_stat_ptr->speed = 1000;
509     break;
510     /* We don't know what it is */
511     default:
512     network_iface_stat_ptr->speed = 0;
513     break;
514     }
515    
516     if( (ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active ){
517 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_FULL;
518 pajs 1.26 }else if( (ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active ){
519 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_HALF;
520 pajs 1.26 }else{
521 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
522 pajs 1.26 }
523 pajs 1.36
524 pajs 1.26 }
525     freeifaddrs(net);
526 ats 1.37 close(sock);
527 pajs 1.26 #endif
528 pajs 1.25
529     #ifdef SOLARIS
530 ats 1.44 if ((kc = kstat_open()) == NULL) {
531     return NULL;
532     }
533    
534     if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
535     return NULL;
536     }
537 pajs 1.25
538 ats 1.44 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
539     if (!strcmp(ksp->ks_class, "net")) {
540     struct ifreq ifr;
541    
542     kstat_read(kc, ksp, NULL);
543    
544     strncpy(ifr.ifr_name, ksp->ks_name, sizeof ifr.ifr_name);
545     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
546     /* Not a network interface. */
547 pajs 1.25 continue;
548     }
549 ats 1.44
550 ats 1.59 if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
551 pajs 1.25 return NULL;
552     }
553 pajs 1.26 network_iface_stat_ptr = network_iface_stats + ifaces;
554 ats 1.44 ifaces++;
555    
556 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
557 ats 1.63 ksp->ks_name) < 0) {
558 ats 1.60 return NULL;
559     }
560 pajs 1.25
561 ats 1.44 if ((ifr.ifr_flags & IFF_UP) != 0) {
562     network_iface_stat_ptr->up = 1;
563     } else {
564     network_iface_stat_ptr->up = 1;
565     }
566 pajs 1.35
567 ats 1.44 if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL) {
568     network_iface_stat_ptr->speed = knp->value.ui64 / (1000 * 1000);
569     } else {
570     network_iface_stat_ptr->speed = 0;
571 pajs 1.25 }
572    
573 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
574 ats 1.44 if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) {
575     switch (knp->value.ui32) {
576     case 1:
577 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_HALF;
578 ats 1.44 break;
579     case 2:
580 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_FULL;
581 ats 1.44 break;
582     }
583 pajs 1.33 }
584 pajs 1.25 }
585     }
586 ats 1.44
587     close(sock);
588 pajs 1.25 kstat_close(kc);
589     #endif
590 pajs 1.27 #ifdef LINUX
591     f = fopen("/proc/net/dev", "r");
592     if(f == NULL){
593     return NULL;
594     }
595    
596     /* Setup stuff so we can do the ioctl to get the info */
597     if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
598     return NULL;
599     }
600    
601     /* Ignore first 2 lines.. Just headings */
602 pajs 1.29 if((fgets(line, sizeof(line), f)) == NULL) return NULL;
603     if((fgets(line, sizeof(line), f)) == NULL) return NULL;
604 pajs 1.27
605     while((fgets(line, sizeof(line), f)) != NULL){
606     char *name, *ptr;
607     struct ifreq ifr;
608 ats 1.38 struct ethtool_cmd ethcmd;
609 pajs 1.27 int err;
610    
611     /* Get the interface name */
612     ptr = strchr(line, ':');
613     if (ptr == NULL) continue;
614     *ptr='\0';
615     name = line;
616     while(isspace(*(name))){
617     name++;
618     }
619    
620 ats 1.38 memset(&ifr, 0, sizeof ifr);
621     strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
622 pajs 1.27
623 ats 1.38 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
624     continue;
625     }
626 pajs 1.27
627     /* We have a good interface to add */
628 ats 1.59 if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
629 pajs 1.27 return NULL;
630     }
631     network_iface_stat_ptr = network_iface_stats + ifaces;
632 ats 1.60
633 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
634 ats 1.63 name) < 0) {
635 ats 1.60 return NULL;
636     }
637 ats 1.38 if ((ifr.ifr_flags & IFF_UP) != 0) {
638 pajs 1.35 network_iface_stat_ptr->up = 1;
639 ats 1.38 } else {
640 pajs 1.35 network_iface_stat_ptr->up = 0;
641     }
642    
643 ats 1.38 memset(&ethcmd, 0, sizeof ethcmd);
644     ethcmd.cmd = ETHTOOL_GSET;
645     ifr.ifr_data = (caddr_t) &ethcmd;
646    
647     err = ioctl(sock, SIOCETHTOOL, &ifr);
648     if (err == 0) {
649     network_iface_stat_ptr->speed = ethcmd.speed;
650    
651     switch (ethcmd.duplex) {
652     case 0x00:
653 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_FULL;
654 ats 1.38 break;
655     case 0x01:
656 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_HALF;
657 ats 1.38 break;
658     default:
659 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
660 ats 1.38 }
661     } else {
662     /* Not all interfaces support the ethtool ioctl. */
663 ats 1.39 network_iface_stat_ptr->speed = 0;
664 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
665 pajs 1.27 }
666 ats 1.38
667 pajs 1.27 ifaces++;
668     }
669 pajs 1.30 close(sock);
670 ats 1.38 fclose(f);
671 pajs 1.27 #endif
672 pajs 1.26 *entries = ifaces;
673 pajs 1.25 return network_iface_stats;
674     }
675