/* 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 #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. */ void ifstat_update_proc (void) { 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; } /* 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; } /* 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, 0, &p.prefix, p.prefixlen, NULL, ifname); } fclose (fp); return 0; } #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */