From 9c0ec8c69f565904e316d71b20872e260a0a79b0 Mon Sep 17 00:00:00 2001 From: Martin Baulig Date: Sun, 22 Nov 1998 19:24:14 +0000 Subject: [PATCH] Added implementation for this function. 1998-11-22 Martin Baulig * netload.c (glibtop_get_netload_s): Added implementation for this function. The code here is smart enough to use /proc/net/ip_acct if IP accounting is enabled in the kernel and activated on the requested device and /proc/net/dev if not. To get separate statistics for received and transmitted packets you need to use two accounting rules: ipfwadm -A in -a -P all -W eth0 ipfwadm -A out -a -P all -W eth0 But before you activate IP accounting, please have a look at /proc/net/dev - if if already contains byte counters, then don't use IP accounting. --- sysdeps/linux/ChangeLog | 19 +++ sysdeps/linux/netload.c | 289 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 306 insertions(+), 2 deletions(-) diff --git a/sysdeps/linux/ChangeLog b/sysdeps/linux/ChangeLog index 97d973a0..db1496e3 100644 --- a/sysdeps/linux/ChangeLog +++ b/sysdeps/linux/ChangeLog @@ -1,3 +1,22 @@ +1998-11-22 Martin Baulig + + * netload.c (glibtop_get_netload_s): Added implementation + for this function. + + The code here is smart enough to use /proc/net/ip_acct if + IP accounting is enabled in the kernel and activated on the + requested device and /proc/net/dev if not. + + To get separate statistics for received and transmitted + packets you need to use two accounting rules: + + ipfwadm -A in -a -P all -W eth0 + ipfwadm -A out -a -P all -W eth0 + + But before you activate IP accounting, please have a look + at /proc/net/dev - if if already contains byte counters, + then don't use IP accounting. + 1998-10-28 Martin Baulig * ppp.c: Added code for ISDN here. diff --git a/sysdeps/linux/netload.c b/sysdeps/linux/netload.c index cbaac4f5..cdedfb32 100644 --- a/sysdeps/linux/netload.c +++ b/sysdeps/linux/netload.c @@ -23,14 +23,63 @@ #include #include -static const unsigned long _glibtop_sysdeps_netload = 0; +#include +#include +#include + +#include + +#include +#include + +#include +#include + +static const unsigned long _glibtop_sysdeps_netload = +(1 << GLIBTOP_NETLOAD_ERRORS_IN) + +(1 << GLIBTOP_NETLOAD_ERRORS_OUT) + +(1 << GLIBTOP_NETLOAD_COLLISIONS); + +static const unsigned long _glibtop_sysdeps_netload_data = +(1 << GLIBTOP_NETLOAD_ADDRESS) + +(1 << GLIBTOP_NETLOAD_SUBNET) + +(1 << GLIBTOP_NETLOAD_MTU); + +static const unsigned long _glibtop_sysdeps_netload_bytes = +(1 << GLIBTOP_NETLOAD_BYTES_IN) + +(1 << GLIBTOP_NETLOAD_BYTES_OUT) + +(1 << GLIBTOP_NETLOAD_BYTES_TOTAL); + +static const unsigned long _glibtop_sysdeps_netload_packets = +(1 << GLIBTOP_NETLOAD_PACKETS_IN) + +(1 << GLIBTOP_NETLOAD_PACKETS_OUT) + +(1 << GLIBTOP_NETLOAD_PACKETS_TOTAL); + +static const unsigned long _glibtop_sysdeps_netload_total = +(1 << GLIBTOP_NETLOAD_PACKETS_TOTAL) + +(1 << GLIBTOP_NETLOAD_BYTES_TOTAL); + +static const unsigned long _glibtop_sysdeps_netload_in = +(1 << GLIBTOP_NETLOAD_PACKETS_TOTAL) + +(1 << GLIBTOP_NETLOAD_BYTES_TOTAL) + +(1 << GLIBTOP_NETLOAD_PACKETS_IN) + +(1 << GLIBTOP_NETLOAD_BYTES_IN); + +static const unsigned long _glibtop_sysdeps_netload_out = +(1 << GLIBTOP_NETLOAD_PACKETS_TOTAL) + +(1 << GLIBTOP_NETLOAD_BYTES_TOTAL) + +(1 << GLIBTOP_NETLOAD_PACKETS_OUT) + +(1 << GLIBTOP_NETLOAD_BYTES_OUT); /* Init function. */ void glibtop_init_netload_s (glibtop *server) { - server->sysdeps.netload = _glibtop_sysdeps_netload; + server->sysdeps.netload = _glibtop_sysdeps_netload | + _glibtop_sysdeps_netload_data | + _glibtop_sysdeps_netload_bytes | + _glibtop_sysdeps_netload_packets; } /* Provides network statistics. */ @@ -39,5 +88,241 @@ void glibtop_get_netload_s (glibtop *server, glibtop_netload *buf, const char *interface) { + char buffer [BUFSIZ], *p; + int have_bytes, fields, skfd; + FILE *f; + memset (buf, 0, sizeof (glibtop_netload)); + + skfd = socket (AF_INET, SOCK_DGRAM, 0); + if (skfd) { + struct ifreq ifr; + struct sockaddr_in addr; + char *address; + unsigned flags; + + strcpy (ifr.ifr_name, interface); + if (!ioctl (skfd, SIOCGIFFLAGS, &ifr)) { + buf->flags |= (1 << GLIBTOP_NETLOAD_IF_FLAGS); + flags = ifr.ifr_flags; + } else + flags = 0; + + if (flags & IFF_UP) + buf->if_flags |= (1 << GLIBTOP_IF_FLAGS_UP); + + if (flags & IFF_BROADCAST) + buf->if_flags |= (1 << GLIBTOP_IF_FLAGS_BROADCAST); + + if (flags & IFF_DEBUG) + buf->if_flags |= (1 << GLIBTOP_IF_FLAGS_DEBUG); + + if (flags & IFF_LOOPBACK) + buf->if_flags |= (1 << GLIBTOP_IF_FLAGS_LOOPBACK); + + if (flags & IFF_POINTOPOINT) + buf->if_flags |= (1 << GLIBTOP_IF_FLAGS_POINTOPOINT); + + if (flags & IFF_RUNNING) + buf->if_flags |= (1 << GLIBTOP_IF_FLAGS_RUNNING); + + if (flags & IFF_NOARP) + buf->if_flags |= (1 << GLIBTOP_IF_FLAGS_NOARP); + + if (flags & IFF_PROMISC) + buf->if_flags |= (1 << GLIBTOP_IF_FLAGS_PROMISC); + + if (flags & IFF_ALLMULTI) + buf->if_flags |= (1 << GLIBTOP_IF_FLAGS_ALLMULTI); + + if (flags & IFF_MULTICAST) + buf->if_flags |= (1 << GLIBTOP_IF_FLAGS_MULTICAST); + + strcpy (ifr.ifr_name, interface); + if (!ioctl (skfd, SIOCGIFADDR, &ifr)) { + struct sockaddr_in addr = + *(struct sockaddr_in *) &ifr.ifr_addr; + buf->address = addr.sin_addr.s_addr; + buf->flags |= (1 << GLIBTOP_NETLOAD_ADDRESS); + } + + strcpy (ifr.ifr_name, interface); + if (!ioctl (skfd, SIOCGIFNETMASK, &ifr)) { + struct sockaddr_in addr = + *(struct sockaddr_in *) &ifr.ifr_addr; + buf->subnet = addr.sin_addr.s_addr; + buf->flags |= (1 << GLIBTOP_NETLOAD_SUBNET); + } + + strcpy (ifr.ifr_name, interface); + if (!ioctl (skfd, SIOCGIFMTU, &ifr)) { + buf->mtu = ifr.ifr_mtu; + buf->flags |= (1 << GLIBTOP_NETLOAD_MTU); + } + + close (skfd); + } + + /* If IP accounting is enabled in the kernel and it is + * enabled for the requested interface, we use it to + * get the data. In this case, we don't use /proc/net/dev + * to get errors and collisions. + */ + + f = fopen ("/proc/net/ip_acct", "r"); + if (f) { + int success = 0; + + /* Skip over the header line. */ + fgets (buffer, BUFSIZ-1, f); + + while (fgets (buffer, BUFSIZ-1, f)) { + unsigned long flags, packets, bytes; + char *p, *dev; + + /* Skip over the network thing. */ + dev = skip_token (buffer) + 1; + p = skip_token (dev); + *p++ = 0; + + if (strcmp (dev, interface)) + continue; + + success = 1; + + p = skip_token (p); + + flags = strtoul (p, &p, 16); + + p = skip_multiple_token (p, 2); + + packets = strtoul (p, &p, 0); + bytes = strtoul (p, &p, 0); + + if (flags & IP_FW_F_ACCTIN) { + /* Incoming packets only. */ + + buf->packets_total += packets; + buf->packets_in += packets; + + buf->bytes_total += bytes; + buf->bytes_in += bytes; + + buf->flags |= _glibtop_sysdeps_netload_in; + + } else if (flags & IP_FW_F_ACCTOUT) { + /* Outgoing packets only. */ + + buf->packets_total += packets; + buf->packets_out += packets; + + buf->bytes_total += bytes; + buf->bytes_out += bytes; + + buf->flags |= _glibtop_sysdeps_netload_out; + + } else { + /* Only have total values. */ + + buf->packets_total += packets; + buf->bytes_total += bytes; + + buf->flags |= _glibtop_sysdeps_netload_total; + } + } + + fclose (f); + + if (success) return; + } + + /* Ok, either IP accounting is not enabled in the kernel or + * it was not enabled for the requested interface. */ + + f = fopen ("/proc/net/dev", "r"); + if (!f) return; + + /* Skip over the header line. */ + fgets (buffer, BUFSIZ-1, f); + fgets (buffer, BUFSIZ-1, f); + + /* Starting with 2.1.xx (don't know exactly which version) + * /proc/net/dev contains both byte and package counters. */ + + p = strchr (buffer, '|'); + if (!p) { + fclose (f); + return; + } + + /* Do we already have byte counters ? */ + have_bytes = strncmp (++p, "bytes", 5) == 0; + + /* Count remaining 'Receive' fields so we know where + * the first 'Transmit' field starts. */ + + fields = 0; + while (*p != '|') { + if (isspace (*p)) + fields++; + p++; + } + + /* Should never happen. */ + if (!fields) return; + fields--; + + while (fgets (buffer, BUFSIZ-1, f)) { + char *p, *dev; + + dev = buffer; + while (isspace (*dev)) dev++; + + p = strchr (dev, ':'); + if (!p) continue; + *p++ = 0; + + /* If it's not a digit, then it's most likely an error + * message like 'No statistics available'. */ + while (isspace (*p)) p++; + if (!isdigit (*p)) continue; + + if (strcmp (dev, interface)) + continue; + + /* Only read byte counts if we really have them. */ + + if (have_bytes) + buf->bytes_in = strtoul (p, &p, 0); + + buf->packets_in = strtoul (p, &p, 0); + buf->errors_in = strtoul (p, &p, 0); + + p = skip_multiple_token (p, fields); + + if (have_bytes) + buf->bytes_out = strtoul (p, &p, 0); + + buf->packets_out = strtoul (p, &p, 0); + buf->errors_out = strtoul (p, &p, 0); + + p = skip_multiple_token (p, 2); + + buf->collisions = strtoul (p, &p, 0); + + /* Compute total valules. */ + + buf->bytes_total = buf->bytes_in + buf->bytes_out; + buf->packets_total = buf->packets_in + buf->packets_out; + + /* And now the flags. */ + + buf->flags |= _glibtop_sysdeps_netload; + buf->flags |= _glibtop_sysdeps_netload_packets; + + if (have_bytes) + buf->flags |= _glibtop_sysdeps_netload_bytes; + } + + fclose (f); }