blob: 6002595ad3020493c23687a174622409b605ee90 [file] [log] [blame]
/* Interface name and statistics get function using proc file system
* Copyright (C) 1999 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <zebra.h>
#include "if.h"
#include "prefix.h"
#include "log.h"
#include "zebra/ioctl.h"
#include "zebra/connected.h"
#include "zebra/interface.h"
/* Proc filesystem one line buffer. */
#define PROCBUFSIZ 1024
/* Path to device proc file system. */
#ifndef _PATH_PROC_NET_DEV
#define _PATH_PROC_NET_DEV "/proc/net/dev"
#endif /* _PATH_PROC_NET_DEV */
/* Return statistics data pointer. */
static char *
interface_name_cut (char *buf, char **name)
{
char *stat;
/* Skip white space. Line will include header spaces. */
while (*buf == ' ')
buf++;
*name = buf;
/* Cut interface name. */
stat = strrchr (buf, ':');
*stat++ = '\0';
return stat;
}
/* Fetch each statistics field. */
static int
ifstat_dev_fields (int version, char *buf, struct interface *ifp)
{
switch (version)
{
case 3:
sscanf(buf,
"%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
&ifp->stats.rx_bytes,
&ifp->stats.rx_packets,
&ifp->stats.rx_errors,
&ifp->stats.rx_dropped,
&ifp->stats.rx_fifo_errors,
&ifp->stats.rx_frame_errors,
&ifp->stats.rx_compressed,
&ifp->stats.rx_multicast,
&ifp->stats.tx_bytes,
&ifp->stats.tx_packets,
&ifp->stats.tx_errors,
&ifp->stats.tx_dropped,
&ifp->stats.tx_fifo_errors,
&ifp->stats.collisions,
&ifp->stats.tx_carrier_errors,
&ifp->stats.tx_compressed);
break;
case 2:
sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
&ifp->stats.rx_bytes,
&ifp->stats.rx_packets,
&ifp->stats.rx_errors,
&ifp->stats.rx_dropped,
&ifp->stats.rx_fifo_errors,
&ifp->stats.rx_frame_errors,
&ifp->stats.tx_bytes,
&ifp->stats.tx_packets,
&ifp->stats.tx_errors,
&ifp->stats.tx_dropped,
&ifp->stats.tx_fifo_errors,
&ifp->stats.collisions,
&ifp->stats.tx_carrier_errors);
ifp->stats.rx_multicast = 0;
break;
case 1:
sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
&ifp->stats.rx_packets,
&ifp->stats.rx_errors,
&ifp->stats.rx_dropped,
&ifp->stats.rx_fifo_errors,
&ifp->stats.rx_frame_errors,
&ifp->stats.tx_packets,
&ifp->stats.tx_errors,
&ifp->stats.tx_dropped,
&ifp->stats.tx_fifo_errors,
&ifp->stats.collisions,
&ifp->stats.tx_carrier_errors);
ifp->stats.rx_bytes = 0;
ifp->stats.tx_bytes = 0;
ifp->stats.rx_multicast = 0;
break;
}
return 0;
}
/* Update interface's statistics. */
int
ifstat_update_proc ()
{
FILE *fp;
char buf[PROCBUFSIZ];
int version;
struct interface *ifp;
char *stat;
char *name;
/* Open /proc/net/dev. */
fp = fopen (_PATH_PROC_NET_DEV, "r");
if (fp == NULL)
{
zlog_warn ("Can't open proc file %s: %s",
_PATH_PROC_NET_DEV, safe_strerror (errno));
return -1;
}
/* Drop header lines. */
fgets (buf, PROCBUFSIZ, fp);
fgets (buf, PROCBUFSIZ, fp);
/* To detect proc format veresion, parse second line. */
if (strstr (buf, "compressed"))
version = 3;
else if (strstr (buf, "bytes"))
version = 2;
else
version = 1;
/* Update each interface's statistics. */
while (fgets (buf, PROCBUFSIZ, fp) != NULL)
{
stat = interface_name_cut (buf, &name);
ifp = if_get_by_name (name);
ifstat_dev_fields (version, stat, ifp);
}
fclose(fp);
return 0;
}
/* Interface structure allocation by proc filesystem. */
int
interface_list_proc ()
{
FILE *fp;
char buf[PROCBUFSIZ];
struct interface *ifp;
char *name;
/* Open /proc/net/dev. */
fp = fopen (_PATH_PROC_NET_DEV, "r");
if (fp == NULL)
{
zlog_warn ("Can't open proc file %s: %s",
_PATH_PROC_NET_DEV, safe_strerror (errno));
return -1;
}
/* Drop header lines. */
fgets (buf, PROCBUFSIZ, fp);
fgets (buf, PROCBUFSIZ, fp);
/* Only allocate interface structure. Other jobs will be done in
if_ioctl.c. */
while (fgets (buf, PROCBUFSIZ, fp) != NULL)
{
interface_name_cut (buf, &name);
ifp = if_get_by_name (name);
if_add_update (ifp);
}
fclose(fp);
return 0;
}
#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
#ifndef _PATH_PROC_NET_IF_INET6
#define _PATH_PROC_NET_IF_INET6 "/proc/net/if_inet6"
#endif /* _PATH_PROC_NET_IF_INET6 */
int
ifaddr_proc_ipv6 ()
{
FILE *fp;
char buf[PROCBUFSIZ];
int n;
char addr[33];
char ifname[21];
int ifindex, plen, scope, status;
struct interface *ifp;
struct prefix_ipv6 p;
/* Open proc file system. */
fp = fopen (_PATH_PROC_NET_IF_INET6, "r");
if (fp == NULL)
{
zlog_warn ("Can't open proc file %s: %s",
_PATH_PROC_NET_IF_INET6, safe_strerror (errno));
return -1;
}
/* Get interface's IPv6 address. */
while (fgets (buf, PROCBUFSIZ, fp) != NULL)
{
n = sscanf (buf, "%32s %02x %02x %02x %02x %20s",
addr, &ifindex, &plen, &scope, &status, ifname);
if (n != 6)
continue;
ifp = if_get_by_name (ifname);
/* Fetch interface's IPv6 address. */
str2in6_addr (addr, &p.prefix);
p.prefixlen = plen;
connected_add_ipv6 (ifp, &p.prefix, p.prefixlen, NULL, ifname);
}
fclose (fp);
return 0;
}
#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */