📄 interface_linux.c
字号:
/* * Interface MIB architecture support * * $Id: interface_linux.c 16595 2007-07-06 21:14:03Z rstory $ */#include <net-snmp/net-snmp-config.h>#include <net-snmp/net-snmp-includes.h>#ifdef HAVE_LINUX_ETHTOOL_H#include <linux/types.h>typedef __u64 u64; /* hack, so we may include kernel's ethtool.h */typedef __u32 u32; /* ditto */typedef __u16 u16; /* ditto */typedef __u8 u8; /* ditto */#include <linux/ethtool.h>#endif /* HAVE_LINUX_ETHTOOL_H */#include "mibII/mibII_common.h"#include "if-mib/ifTable/ifTable_constants.h"#include <net-snmp/agent/net-snmp-agent-includes.h>#if HAVE_SYS_IOCTL_H#include <sys/ioctl.h>#else#error "linux should have sys/ioctl header"#endif#include <net-snmp/data_access/interface.h>#include <net-snmp/data_access/ipaddress.h>#include "if-mib/data_access/interface.h"#include "interface_ioctl.h"#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <linux/sockios.h>#ifndef IF_NAMESIZE#define IF_NAMESIZE 16#endifunsigned intnetsnmp_linux_interface_get_if_speed(int fd, const char *name);#ifdef HAVE_LINUX_ETHTOOL_Hunsigned intnetsnmp_linux_interface_get_if_speed_mii(int fd, const char *name);#endif#define PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME_MS "/proc/sys/net/ipv%d/neigh/%s/retrans_time_ms"#define PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME "/proc/sys/net/ipv%d/neigh/%s/retrans_time"static const char *proc_sys_retrans_time;static unsigned short retrans_time_factor = 1;#define PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME_MS "/proc/sys/net/ipv%d/neigh/%s/base_reachable_time_ms"#define PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME "/proc/sys/net/ipv%d/neigh/%s/base_reachable_time"static const char *proc_sys_basereachable_time;static unsigned short basereachable_time_ms = 0;voidnetsnmp_arch_interface_init(void){ /* * Check which retransmit time interface is available */ char proc_path[ 64+IF_NAMESIZE]; char proc_path2[64+IF_NAMESIZE]; struct stat st; snprintf(proc_path, sizeof(proc_path), PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME_MS, 6, "default"); snprintf(proc_path2, sizeof(proc_path2), PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME_MS, 4, "default"); if ((stat(proc_path, &st) == 0) || (stat(proc_path2, &st) == 0)) { proc_sys_retrans_time = PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME_MS; } else { proc_sys_retrans_time = PROC_SYS_NET_IPVx_NEIGH_RETRANS_TIME; retrans_time_factor = 10; } snprintf(proc_path, sizeof(proc_path), PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME_MS, 6, "default"); snprintf(proc_path2, sizeof(proc_path), PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME, 4, "default"); if ((stat(proc_path, &st) == 0) || (stat(proc_path2, &st) == 0)) { proc_sys_basereachable_time = PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME_MS; basereachable_time_ms = 1; } else { proc_sys_basereachable_time = PROC_SYS_NET_IPVx_BASE_REACHABLE_TIME; }}/* * find the ifIndex for an interface name * NOTE: The Linux version is not efficient for large numbers of calls. * consider using netsnmp_access_interface_ioctl_ifindex_get() * for loops which need to look up a lot of indexes. * * @retval 0 : no index found * @retval >0: ifIndex for interface */oidnetsnmp_arch_interface_index_find(const char *name){ return netsnmp_access_interface_ioctl_ifindex_get(-1, name);}/* * check for ipv6 addresses */void_arch_interface_has_ipv6(oid if_index, u_int *flags, netsnmp_container *addr_container){#ifdef NETSNMP_ENABLE_IPV6 netsnmp_ipaddress_entry *addr_entry = NULL; netsnmp_iterator *addr_it = NULL; u_int addr_container_flags = 0; /* must init to 0 */#endif if (NULL == flags) return; *flags &= ~NETSNMP_INTERFACE_FLAGS_HAS_IPV6;#ifdef NETSNMP_ENABLE_IPV6 /* * get ipv6 addresses */ if (NULL == addr_container) { /* * we only care about ipv6, if we need to allocate our own * temporary container. set the flags (which we also use later * to determine if we need to free the container). */ addr_container_flags = NETSNMP_ACCESS_IPADDRESS_LOAD_IPV6_ONLY; addr_container = netsnmp_access_ipaddress_container_load(NULL, addr_container_flags); if (NULL == addr_container) { DEBUGMSGTL(("access:ifcontainer", "couldn't get ip addresses container\n")); return; } } else { /* * addr_container flags must be 0, so we don't release the * user's container. */ netsnmp_assert(0 == addr_container_flags); } /* * get an ipaddress container iterator, and look for ipv6 addrs */ addr_it = CONTAINER_ITERATOR(addr_container); if (NULL == addr_it) { DEBUGMSGTL(("access:ifcontainer", "couldn't get ip addresses iterator\n")); if (0!=addr_container_flags) netsnmp_access_ipaddress_container_free(addr_container, 0); return; } addr_entry = ITERATOR_FIRST(addr_it); for( ; addr_entry ; addr_entry = ITERATOR_NEXT(addr_it) ) { /* * skip non matching indexes and ipv4 addresses */ if ((if_index != addr_entry->if_index) || (4 == addr_entry->ia_address_len)) continue; /* * found one! no need to keep looking, set the flag and bail */ *flags |= NETSNMP_INTERFACE_FLAGS_HAS_IPV6; break; } /* * make mama proud and clean up after ourselves */ ITERATOR_RELEASE(addr_it); if (0!=addr_container_flags) netsnmp_access_ipaddress_container_free(addr_container, 0); #endif}/** * @internal */static void_arch_interface_flags_v4_get(netsnmp_interface_entry *entry){ FILE *fin; char line[256]; /* * get the retransmit time */ snprintf(line,sizeof(line), proc_sys_retrans_time, 4, entry->name); if (!(fin = fopen(line, "r"))) { DEBUGMSGTL(("access:interface", "Failed to open %s\n", line)); } else { if (fgets(line, sizeof(line), fin)) { entry->retransmit_v4 = atoi(line) * retrans_time_factor; entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V4_RETRANSMIT; } fclose(fin); }}#ifdef NETSNMP_ENABLE_IPV6/** * @internal */static void_arch_interface_flags_v6_get(netsnmp_interface_entry *entry){ FILE *fin; char line[256]; /* * get the retransmit time */ snprintf(line,sizeof(line), proc_sys_retrans_time, 6, entry->name); if (!(fin = fopen(line, "r"))) { DEBUGMSGTL(("access:interface", "Failed to open %s\n", line)); } else { if (fgets(line, sizeof(line), fin)) { entry->retransmit_v6 = atoi(line) * retrans_time_factor; entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V6_RETRANSMIT; } fclose(fin); } /* * get the forwarding status */ snprintf(line, sizeof(line), "/proc/sys/net/ipv6/conf/%s/forwarding", entry->name); if (!(fin = fopen(line, "r"))) { DEBUGMSGTL(("access:interface", "Failed to open %s\n", line)); } else { if (fgets(line, sizeof(line), fin)) { entry->forwarding_v6 = atoi(line); entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V6_FORWARDING; } fclose(fin); } /* * get the reachable time */ snprintf(line, sizeof(line), proc_sys_basereachable_time, 6, entry->name); if (!(fin = fopen(line, "r"))) { DEBUGMSGTL(("access:interface", "Failed to open %s\n", line)); } else { if (fgets(line, sizeof(line), fin)) { if (basereachable_time_ms) { entry->reachable_time = atoi(line); /* millisec */ } else { entry->reachable_time = atoi(line)*1000; /* sec to millisec */ } entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_V6_REACHABLE; } fclose(fin); }}#endif /* NETSNMP_ENABLE_IPV6 *//** * @internal */static int_parse_stats(netsnmp_interface_entry *entry, char *stats, int expected){ /* * scanline_2_2: * [ IN ] * byte pkts errs drop fifo frame cmprs mcst | * [ OUT ] * byte pkts errs drop fifo colls carrier compressed */#ifdef SCNuMAX uintmax_t rec_pkt, rec_oct, rec_err, rec_drop, rec_mcast; uintmax_t snd_pkt, snd_oct, snd_err, snd_drop, coll; const char *scan_line_2_2 = "%" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %*" SCNuMAX " %" SCNuMAX; const char *scan_line_2_0 = "%" SCNuMAX " %" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %" SCNuMAX " %" SCNuMAX " %*" SCNuMAX " %*" SCNuMAX " %" SCNuMAX;#else unsigned long rec_pkt, rec_oct, rec_err, rec_drop, rec_mcast; unsigned long snd_pkt, snd_oct, snd_err, snd_drop, coll; const char *scan_line_2_2 = "%lu %lu %lu %lu %*lu %*lu %*lu %lu %lu %lu %lu %lu %*lu %lu"; const char *scan_line_2_0 = "%lu %lu %*lu %*lu %*lu %lu %lu %*lu %*lu %lu";#endif static const char *scan_line_to_use = NULL; int scan_count; if (10 == expected) scan_line_to_use = scan_line_2_2; else { netsnmp_assert(5 == expected); scan_line_to_use = scan_line_2_0; } while (*stats == ' ') stats++; if ((*stats == 'N') && (0 == strncmp(stats, "No statistics available", sizeof("No statistics available")))) return -1; /* * Now parse the rest of the line (i.e. starting from 'stats') * to extract the relevant statistics, and populate * data structure accordingly. * Use the entry flags field to indicate which counters are valid */ rec_pkt = rec_oct = rec_err = rec_drop = rec_mcast = 0; snd_pkt = snd_oct = snd_err = snd_drop = coll = 0; if (scan_line_to_use == scan_line_2_2) { scan_count = sscanf(stats, scan_line_to_use, &rec_oct, &rec_pkt, &rec_err, &rec_drop, &rec_mcast, &snd_oct, &snd_pkt, &snd_err, &snd_drop, &coll); if (scan_count == expected) { entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_BYTES; entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_DROPS; /* * 2.4 kernel includes a single multicast (input) counter? */ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_MCAST_PKTS; entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_HIGH_SPEED;#ifdef SCNuMAX /* XXX - should be flag for 64-bit variables */ entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_HIGH_BYTES; entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_HAS_HIGH_PACKETS;#endif } } else { scan_count = sscanf(stats, scan_line_to_use, &rec_pkt, &rec_err, &snd_pkt, &snd_err, &coll); if (scan_count == expected) { entry->ns_flags &= ~NETSNMP_INTERFACE_FLAGS_HAS_MCAST_PKTS; rec_oct = rec_drop = 0; snd_oct = snd_drop = 0; } } if(scan_count != expected) { snmp_log(LOG_ERR, "error scanning interface data (expected %d, got %d)\n", expected, scan_count); return scan_count; } entry->ns_flags |= NETSNMP_INTERFACE_FLAGS_ACTIVE; /* * linux previous to 1.3.~13 may miss transmitted loopback pkts: */ if (!strcmp(entry->name, "lo") && rec_pkt > 0 && !snd_pkt) snd_pkt = rec_pkt; /* * subtract out multicast packets from rec_pkt before * we store it as unicast counter. */ rec_pkt -= rec_mcast; entry->stats.ibytes.low = rec_oct & 0xffffffff; entry->stats.iucast.low = rec_pkt & 0xffffffff; entry->stats.imcast.low = rec_mcast & 0xffffffff; entry->stats.obytes.low = snd_oct & 0xffffffff; entry->stats.oucast.low = snd_pkt & 0xffffffff;#ifdef SCNuMAX /* XXX - should be flag for 64-bit variables */ entry->stats.ibytes.high = rec_oct >> 32; entry->stats.iucast.high = rec_pkt >> 32; entry->stats.imcast.high = rec_mcast >> 32; entry->stats.obytes.high = snd_oct >> 32; entry->stats.oucast.high = snd_pkt >> 32;#endif entry->stats.ierrors = rec_err; entry->stats.idiscards = rec_drop; entry->stats.oerrors = snd_err; entry->stats.odiscards = snd_drop; entry->stats.collisions = coll; /* * calculated stats. * * we have imcast, but not ibcast. */ entry->stats.inucast = entry->stats.imcast.low + entry->stats.ibcast.low; entry->stats.onucast = entry->stats.omcast.low + entry->stats.obcast.low; return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -