| /* 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. */ |
| 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 */ |