/* * standard Net-SNMP includes */ #include #include #include /* * include our parent header */ #include "etherlike-mib/dot3StatsTable/dot3StatsTable.h" #include "etherlike-mib/dot3StatsTable/dot3StatsTable_data_access.h" #include "etherlike-mib/dot3StatsTable/ioctl_imp_common.h" /* * @retval 0 success * @retval -1 getifaddrs failed * @retval -2 memory allocation failed */ struct ifname * dot3stats_interface_name_list_get (struct ifname *list_head, int *retval) { struct ifaddrs *addrs = NULL, *p = NULL; struct ifname *nameptr1=NULL, *nameptr2 = NULL; DEBUGMSGTL(("access:dot3StatsTable:interface_name_list_get", "called\n")); if ((getifaddrs(&addrs)) < 0) { DEBUGMSGTL(("access:dot3StatsTable:interface_name_list_get", "getifaddrs failed\n")); snmp_log (LOG_ERR, "access:dot3StatsTable,interface_name_list_get, getifaddrs failed\n"); *retval = -1; return NULL; } for (p = addrs; p; p = p->ifa_next) { if (!list_head) { if ( (list_head = (struct ifname *) malloc (sizeof(struct ifname))) < 0) { DEBUGMSGTL(("access:dot3StatsTable:interface_name_list_get", "memory allocation failed\n")); snmp_log (LOG_ERR, "access:dot3StatsTable,interface_name_list_get, memory allocation failed\n"); freeifaddrs(addrs); *retval = -2; return NULL; } memset(list_head, 0, sizeof (struct ifname)); strlcpy(list_head->name, p->ifa_name, IF_NAMESIZE); continue; } for (nameptr1 = list_head; nameptr1; nameptr2 = nameptr1, nameptr1 = nameptr1->ifn_next) if (!strncmp(p->ifa_name, nameptr1->name, IF_NAMESIZE)) break; if (nameptr1) continue; if ( (nameptr2->ifn_next = (struct ifname *) malloc (sizeof(struct ifname))) < 0) { DEBUGMSGTL(("access:dot3StatsTable:interface_name_list_get", "memory allocation failed\n")); snmp_log (LOG_ERR, "access:dot3StatsTable,interface_name_list_get, memory allocation failed\n"); dot3stats_interface_name_list_free (list_head); freeifaddrs(addrs); *retval = -2; return NULL; } nameptr2 = nameptr2->ifn_next; memset(nameptr2, 0, sizeof (struct ifname)); strlcpy(nameptr2->name, p->ifa_name, IF_NAMESIZE); continue; } freeifaddrs(addrs); return list_head; } /* * @retval 0 success * @retval -1 invalid pointer */ int dot3stats_interface_name_list_free (struct ifname *list_head) { struct ifname *nameptr1 = NULL, *nameptr2 = NULL; DEBUGMSGTL(("access:dot3StatsTable:interface_name_list_free", "called\n")); if (!list_head) { snmp_log (LOG_ERR, "access:dot3StatsTable:interface_name_list_free: invalid pointer list_head"); DEBUGMSGTL(("access:dot3StatsTable:interface_name_list_free", "invalid pointer list_head\n")); return -1; } for (nameptr1 = list_head; nameptr1; nameptr1 = nameptr2) { nameptr2 = nameptr1->ifn_next; free (nameptr1); } return 0; } /* * @retval 0 : not found * @retval !0 : ifIndex */ int dot3stats_interface_ioctl_ifindex_get (int fd, const char *name) { #ifndef SIOCGIFINDEX return 0; #else struct ifreq ifrq; int rc = 0; DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_ifindex_get", "called\n")); rc = _dot3Stats_ioctl_get(fd, SIOCGIFINDEX, &ifrq, name); if (rc < 0) { DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_ifindex_get", "error on interface '%s'\n", name)); snmp_log (LOG_ERR, "access:dot3StatsTable:interface_ioctl_ifindex_get, error on interface '%s'\n", name); return 0; } return ifrq.ifr_ifindex; #endif /* SIOCGIFINDEX */ } # if HAVE_LINUX_RTNETLINK_H /* { NETLINK */ /* * The following code is based upon code I got from Stephen Hemminger */ #include #include struct rtnl_handle { int fd; struct sockaddr_nl local; struct sockaddr_nl peer; __u32 seq; __u32 dump; }; struct ifstat_ent { struct ifstat_ent *next; const char *name; int ifindex; struct rtnl_link_stats stats; }; typedef int (*rtnl_filter_t)(const struct sockaddr_nl *, struct nlmsghdr *n, void *); struct rtnl_dump_filter_arg { rtnl_filter_t filter; void *arg1; rtnl_filter_t junk; void *arg2; }; static struct ifstat_ent *kern_db; static const int rcvbuf_size = 1024 * 1024; static int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, int protocol) { socklen_t addr_len; int sndbuf = 32768; memset(rth, 0, sizeof(*rth)); rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol); if (rth->fd < 0) { snmp_log(LOG_ERR, "Cannot open netlink socket"); return -1; } if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { snmp_log(LOG_ERR, "SO_SNDBUF"); return -1; } if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf_size,sizeof(rcvbuf_size)) < 0) { snmp_log(LOG_ERR, "SO_RCVBUF"); return -1; } memset(&rth->local, 0, sizeof(rth->local)); rth->local.nl_family = AF_NETLINK; rth->local.nl_groups = subscriptions; if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { snmp_log(LOG_ERR, "Cannot bind netlink socket"); return -1; } addr_len = sizeof(rth->local); if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { snmp_log(LOG_ERR, "Cannot getsockname"); return -1; } if (addr_len != sizeof(rth->local)) { snmp_log(LOG_ERR, "Wrong address length %d\n", addr_len); return -1; } if (rth->local.nl_family != AF_NETLINK) { snmp_log(LOG_ERR, "Wrong address family %d\n", rth->local.nl_family); return -1; } rth->seq = time(NULL); return 0; } static int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) { return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); } static void rtnl_close(struct rtnl_handle *rth) { if (rth->fd != -1) close(rth->fd); rth->fd = -1; return; } static int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) { struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; memset(&req, 0, sizeof(req)); req.nlh.nlmsg_len = sizeof(req); req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = rth->dump = ++rth->seq; req.g.rtgen_family = family; return send(rth->fd, (void*)&req, sizeof(req), 0); } static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) { memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); while (RTA_OK(rta, len)) { if (rta->rta_type <= max) tb[rta->rta_type] = rta; rta = RTA_NEXT(rta,len); } if (len) snmp_log(LOG_ERR, "parse_rtattr: !!!Deficit %d, rta_len=%d\n", len, rta->rta_len); return 0; } static int get_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *m, void *arg) { struct ifinfomsg *ifi = NLMSG_DATA(m); struct rtattr * tb[IFLA_MAX+1]; int len = m->nlmsg_len; struct ifstat_ent *n; if (m->nlmsg_type != RTM_NEWLINK) return 0; len -= NLMSG_LENGTH(sizeof(*ifi)); if (len < 0) return -1; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); if (tb[IFLA_IFNAME] == NULL || tb[IFLA_STATS] == NULL) return 0; n = malloc(sizeof(*n)); memset(n, 0, sizeof(*n)); n->ifindex = ifi->ifi_index; n->name = strdup(RTA_DATA(tb[IFLA_IFNAME])); memcpy(&n->stats, RTA_DATA(tb[IFLA_STATS]), sizeof(n->stats)); n->next = kern_db; kern_db = n; return 0; } static int rtnl_dump_filter_l(struct rtnl_handle *rth, const struct rtnl_dump_filter_arg *arg) { struct sockaddr_nl nladdr; struct iovec iov; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; char buf[16384]; iov.iov_base = buf; while (1) { int status; const struct rtnl_dump_filter_arg *a; iov.iov_len = sizeof(buf); status = recvmsg(rth->fd, &msg, 0); if (status < 0) { if (errno == EINTR || errno == EAGAIN) continue; fprintf(stderr, "netlink receive error %s (%d)\n", strerror(errno), errno); return -1; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } for (a = arg; a->filter; a++) { struct nlmsghdr *h = (struct nlmsghdr*)buf; while (NLMSG_OK(h, status)) { int err; if (nladdr.nl_pid != 0 || h->nlmsg_pid != rth->local.nl_pid || h->nlmsg_seq != rth->dump) { if (a->junk) { err = a->junk(&nladdr, h, a->arg2); if (err < 0) return err; } goto skip_it; } if (h->nlmsg_type == NLMSG_DONE) return 0; if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { fprintf(stderr, "ERROR truncated\n"); } else { errno = -err->error; perror("RTNETLINK answers"); } return -1; } err = a->filter(&nladdr, h, a->arg1); if (err < 0) return err; skip_it: h = NLMSG_NEXT(h, status); } } while (0); if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } } static int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter, void *arg1, rtnl_filter_t junk, void *arg2) { const struct rtnl_dump_filter_arg a[2] = { { .filter = filter, .arg1 = arg1, .junk = junk, .arg2 = arg2 }, { .filter = NULL, .arg1 = NULL, .junk = NULL, .arg2 = NULL } }; return rtnl_dump_filter_l(rth, a); } int _dot3Stats_netlink_get_errorcntrs(dot3StatsTable_rowreq_ctx *rowreq_ctx, const char *name) { struct rtnl_handle rth; struct ifstat_ent *ke; int done; if (rtnl_open(&rth, 0) < 0) { snmp_log(LOG_ERR, "_dot3Stats_netlink_get_errorcntrs: rtnl_open() failed\n"); return 1; } if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETLINK) < 0) { snmp_log(LOG_ERR, "_dot3Stats_netlink_get_errorcntrs: Cannot send dump request"); rtnl_close(&rth); return 1; } if (rtnl_dump_filter(&rth, get_nlmsg, NULL, NULL, NULL) < 0) { snmp_log(LOG_ERR, "_dot3Stats_netlink_get_errorcntrs: Dump terminated\n"); rtnl_close(&rth); return 1; } rtnl_close(&rth); /* * Now scan kern_db for this if's data * While doing so, we'll throw away the kern db. */ done = 0; while ((ke = kern_db) != NULL) { if (strcmp(ke->name, name) == 0) { dot3StatsTable_data *data = &rowreq_ctx->data; snmp_log(LOG_ERR, "IFLA_STATS for %s\n", name); data->dot3StatsFCSErrors = ke->stats.rx_crc_errors; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSFCSERRORS_FLAG; data->dot3StatsDeferredTransmissions = ke->stats.tx_dropped; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSDEFERREDTRANSMISSIONS_FLAG; data->dot3StatsInternalMacTransmitErrors = ke->stats.tx_fifo_errors; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSINTERNALMACTRANSMITERRORS_FLAG; data->dot3StatsCarrierSenseErrors = ke->stats.tx_carrier_errors; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSCARRIERSENSEERRORS_FLAG; data->dot3StatsFrameTooLongs = ke->stats.rx_frame_errors; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSFRAMETOOLONGS_FLAG; data->dot3StatsInternalMacReceiveErrors = ke->stats.rx_fifo_errors; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSINTERNALMACRECEIVEERRORS_FLAG; done = 1; } kern_db = ke->next; free(ke); } return !done; } # else /* }{ */ int _dot3Stats_netlink_get_errorcntrs(dot3StatsTable_rowreq_ctx *rowreq_ctx, const char *name) { return 1; } # endif /* } */ /* * NAME: getulongfromsysclassnetstatistics * PURPOSE: To get a single statistics value from /sys/class/net//statistics/ * ARGUMENTS: ifname: interface name * ctrname: counter name * valuep: where to store value * RETURNS: 0 if value not available * non-0 if value available */ static int getulongfromsysclassnetstatistics(const char *ifname, const char *ctrname, u_long *valuep) { char path[256]; FILE *fp; int rv; if (ifname == NULL || ctrname == NULL || valuep == NULL) return 0; snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/%s", ifname, ctrname); fp = fopen(path, "rt"); if (fp == NULL) return 0; rv = 1; if (fscanf(fp, "%lu", valuep) != 1) rv = 0; fclose(fp); return rv; } /* * NAME: interface_dot3stats_get_errorcounters * PURPOSE: To get ethernet error statistics * ARGUMENTS: rowreq_ctx: where to store the value(s) * name: interface name * RETURNS: nothing. fields not set if data not available */ void interface_dot3stats_get_errorcounters (dot3StatsTable_rowreq_ctx *rowreq_ctx, const char *name) { u_long value; dot3StatsTable_data *data = &rowreq_ctx->data; FILE *dev; const char NETDEV_FILE[] = "/proc/net/dev"; if (_dot3Stats_netlink_get_errorcntrs(rowreq_ctx, name) == 0) { snmp_log(LOG_NOTICE, "interface_dot3stats_get_errorcounters: got data from IFLA_STATS\n"); return; } if ((dev = fopen(NETDEV_FILE, "r")) != NULL) { char line[256], *lp, *next; size_t namelen = strlen(name); unsigned int value; unsigned int column; while (fgets(line, sizeof(line), dev) != NULL) { /* br0:68395635 1038214 0 0 0 0 0 939411 25626606 90708 0 0 0 0 0 0 */ lp = line; while (*lp == ' ' || *lp == '\t') lp++; if (strncmp(lp, name, namelen) != 0 || lp[namelen] != ':') continue; lp += namelen + 1; /* Skip name and colon */ column = 1; while (1) { value = strtoul(lp, &next, 10); if (next == lp) break; /* no more data */ switch (column) { case 3: data->dot3StatsFCSErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSFCSERRORS_FLAG; break; case 12: data->dot3StatsDeferredTransmissions = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSDEFERREDTRANSMISSIONS_FLAG; break; case 13: data->dot3StatsInternalMacTransmitErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSINTERNALMACTRANSMITERRORS_FLAG; break; case 15: data->dot3StatsCarrierSenseErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSCARRIERSENSEERRORS_FLAG; break; case 6: data->dot3StatsFrameTooLongs = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSFRAMETOOLONGS_FLAG; break; case 5: data->dot3StatsInternalMacReceiveErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSINTERNALMACRECEIVEERRORS_FLAG; break; case 14: data->dot3StatsSingleCollisionFrames = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSSINGLECOLLISIONFRAMES_FLAG; break; } column++; lp = next; } break; } fclose(dev); } if (!(rowreq_ctx->column_exists_flags & COLUMN_DOT3STATSFCSERRORS_FLAG) && getulongfromsysclassnetstatistics(name, "rx_errors", &value)) { data->dot3StatsFCSErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSFCSERRORS_FLAG; } if (!(rowreq_ctx->column_exists_flags & COLUMN_DOT3STATSDEFERREDTRANSMISSIONS_FLAG) && getulongfromsysclassnetstatistics(name, "tx_dropped", &value)) { data->dot3StatsDeferredTransmissions = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSDEFERREDTRANSMISSIONS_FLAG; } if (!(rowreq_ctx->column_exists_flags & COLUMN_DOT3STATSINTERNALMACTRANSMITERRORS_FLAG) && getulongfromsysclassnetstatistics(name, "tx_fifo_errors", &value)) { data->dot3StatsInternalMacTransmitErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSINTERNALMACTRANSMITERRORS_FLAG; } if (!(rowreq_ctx->column_exists_flags & COLUMN_DOT3STATSCARRIERSENSEERRORS_FLAG) && getulongfromsysclassnetstatistics(name, "tx_carrier_errors", &value)) { data->dot3StatsCarrierSenseErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSCARRIERSENSEERRORS_FLAG; } if (!(rowreq_ctx->column_exists_flags & COLUMN_DOT3STATSFRAMETOOLONGS_FLAG) && getulongfromsysclassnetstatistics(name, "rx_frame_errors", &value)) { data->dot3StatsFrameTooLongs = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSFRAMETOOLONGS_FLAG; } if (!(rowreq_ctx->column_exists_flags & COLUMN_DOT3STATSINTERNALMACRECEIVEERRORS_FLAG) && getulongfromsysclassnetstatistics(name, "rx_fifo_errors", &value)) { data->dot3StatsInternalMacReceiveErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSINTERNALMACRECEIVEERRORS_FLAG; } return; } /* * @retval 0 success * @retval -1 cannot get ETHTOOL_DRVINFO failed * @retval -2 nstats zero - no statistcs available * @retval -3 memory allocation for holding the statistics failed * @retval -4 cannot get ETHTOOL_GSTRINGS information * @retval -5 cannot get ETHTOOL_GSTATS information * @retval -6 function not supported if HAVE_LINUX_ETHTOOL_H not defined */ int interface_ioctl_dot3stats_get (dot3StatsTable_rowreq_ctx *rowreq_ctx, int fd, const char *name) { #ifdef HAVE_LINUX_ETHTOOL_H dot3StatsTable_data *data = &rowreq_ctx->data; struct ethtool_drvinfo driver_info; struct ethtool_gstrings *eth_strings; struct ethtool_stats *eth_stats; struct ifreq ifr; unsigned int nstats, size_str, i; int err; DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_dot3Stats_get", "called\n")); memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); memset(&driver_info, 0, sizeof (driver_info)); driver_info.cmd = ETHTOOL_GDRVINFO; ifr.ifr_data = (char *)&driver_info; err = _dot3Stats_ioctl_get(fd, SIOCETHTOOL, &ifr, name); if (err < 0) { DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_dot3Stats_get", "ETHTOOL_GETDRVINFO failed for interface |%s| \n", name)); return -1; } nstats = driver_info.n_stats; if (nstats < 1) { DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_dot3Stats_get", "no stats available for interface |%s| \n", name)); return -2; } size_str = nstats * ETH_GSTRING_LEN; eth_strings = malloc(size_str + sizeof (struct ethtool_gstrings)); if (!eth_strings) { DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_dot3Stats_get", "no memory available\n")); snmp_log (LOG_ERR, "access:dot3StatsTable,interface_ioctl_dot3Stats_get, no memory available\n"); return -3; } memset (eth_strings, 0, (size_str + sizeof (struct ethtool_gstrings))); eth_stats = malloc (size_str + sizeof (struct ethtool_stats)); if (!eth_stats) { free (eth_strings); DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_dot3Stats_get", "no memory available\n")); snmp_log (LOG_ERR, "access:dot3StatsTable,interface_ioctl_dot3Stats_get, no memory available\n"); return -3; } memset (eth_stats, 0, (size_str + sizeof (struct ethtool_stats))); eth_strings->cmd = ETHTOOL_GSTRINGS; eth_strings->string_set = ETH_SS_STATS; eth_strings->len = nstats; ifr.ifr_data = (char *) eth_strings; err = _dot3Stats_ioctl_get(fd, SIOCETHTOOL, &ifr, name); if (err < 0) { DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_dot3Stats_get", "cannot get stats strings information for interface |%s| \n", name)); snmp_log (LOG_ERR, "access:dot3StatsTable,interface_ioctl_dot3Stats_get, cannot get stats strings information for interface |%s| \n", name); free(eth_strings); free(eth_stats); return -4; } eth_stats->cmd = ETHTOOL_GSTATS; eth_stats->n_stats = nstats; ifr.ifr_data = (char *) eth_stats; err = _dot3Stats_ioctl_get(fd, SIOCETHTOOL, &ifr, name); if (err < 0) { DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_dot3Stats_get", "cannot get stats strings information for interface |%s| \n", name)); snmp_log (LOG_ERR, "access:dot3StatsTable,interface_ioctl_dot3Stats_get, cannot get stats information for interface |%s| \n", name); free(eth_strings); free(eth_stats); return -5; } for (i = 0; i < nstats; i++) { char s[ETH_GSTRING_LEN]; strlcpy(s, (const char *) ð_strings->data[i * ETH_GSTRING_LEN], sizeof(s)); if (DOT3STATSALIGNMENTERRORS(s)) { data->dot3StatsAlignmentErrors = (u_long)eth_stats->data[i]; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSALIGNMENTERRORS_FLAG; } if (DOT3STATSMULTIPLECOLLISIONFRAMES(s)) { data->dot3StatsMultipleCollisionFrames = (u_long)eth_stats->data[i]; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSMULTIPLECOLLISIONFRAMES_FLAG; } if (DOT3STATSLATECOLLISIONS(s)) { data->dot3StatsLateCollisions = (u_long)eth_stats->data[i]; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSLATECOLLISIONS_FLAG; } if (DOT3STATSSINGLECOLLISIONFRAMES(s)) { data->dot3StatsSingleCollisionFrames = (u_long)eth_stats->data[i]; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSSINGLECOLLISIONFRAMES_FLAG; } if (DOT3STATSEXCESSIVECOLLISIONS(s)) { data->dot3StatsExcessiveCollisions = (u_long)eth_stats->data[i]; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSEXCESSIVECOLLISIONS_FLAG; } } free(eth_strings); free(eth_stats); return 0; #else return -6; #endif } /* * @retval 0 success * @retval -1 ETHTOOL_GSET failed * @retval -2 function not supported if HAVE_LINUX_ETHTOOL_H not defined */ int interface_ioctl_dot3stats_duplex_get(dot3StatsTable_rowreq_ctx *rowreq_ctx, int fd, const char* name) { #ifdef HAVE_LINUX_ETHTOOL_H dot3StatsTable_data *data = &rowreq_ctx->data; struct ethtool_cmd edata; struct ifreq ifr; int err; DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_dot3Stats_duplex_get", "called\n")); memset(&edata, 0, sizeof (edata)); memset(&ifr, 0, sizeof (ifr)); edata.cmd = ETHTOOL_GSET; ifr.ifr_data = (char *)&edata; err = _dot3Stats_ioctl_get (fd, SIOCETHTOOL, &ifr, name); if (err < 0) { DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_dot3Stats_duplex_get", "ETHTOOL_GSET failed\n")); return -1; } if (err == 0) { rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSDUPLEXSTATUS_FLAG; switch (edata.duplex) { case DUPLEX_HALF: data->dot3StatsDuplexStatus = (u_long) DOT3STATSDUPLEXSTATUS_HALFDUPLEX; break; case DUPLEX_FULL: data->dot3StatsDuplexStatus = (u_long) DOT3STATSDUPLEXSTATUS_FULLDUPLEX; break; default: data->dot3StatsDuplexStatus = (u_long) DOT3STATSDUPLEXSTATUS_UNKNOWN; break; }; } DEBUGMSGTL(("access:dot3StatsTable:interface_ioctl_dot3Stats_duplex_get", "ETHTOOL_GSET processed\n")); return err; #else return -2; #endif } /* * NAME: interface_sysclassnet_dot3stats_get * PURPOSE: To get ethernet statistics from /sys/class/net/... * ARGUMENTS: rowreq_ctx: where to store the value(s) * name: interface name * RETURNS: nothing. fields not set if data not available */ void interface_sysclassnet_dot3stats_get (dot3StatsTable_rowreq_ctx *rowreq_ctx, const char *name) { u_long value; dot3StatsTable_data *data = &rowreq_ctx->data; if (getulongfromsysclassnetstatistics(name, "rx_errors", &value)) { data->dot3StatsFCSErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSFCSERRORS_FLAG; } if (getulongfromsysclassnetstatistics(name, "tx_dropped", &value)) { data->dot3StatsDeferredTransmissions = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSDEFERREDTRANSMISSIONS_FLAG; } if (getulongfromsysclassnetstatistics(name, "tx_fifo_errors", &value)) { data->dot3StatsInternalMacTransmitErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSINTERNALMACTRANSMITERRORS_FLAG; } if (getulongfromsysclassnetstatistics(name, "tx_carrier_errors", &value)) { data->dot3StatsCarrierSenseErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSCARRIERSENSEERRORS_FLAG; } if (getulongfromsysclassnetstatistics(name, "rx_frame_errors", &value)) { data->dot3StatsFrameTooLongs = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSFRAMETOOLONGS_FLAG; } if (getulongfromsysclassnetstatistics(name, "rx_fifo_errors", &value)) { data->dot3StatsInternalMacReceiveErrors = value; rowreq_ctx->column_exists_flags |= COLUMN_DOT3STATSINTERNALMACRECEIVEERRORS_FLAG; } return; } /* ioctl wrapper * * @param fd : socket fd to use w/ioctl, or -1 to open/close one * @param which * @param ifrq * param ifentry : ifentry to update * @param name * * @retval 0 : success * @retval -1 : invalid parameters * @retval -2 : couldn't create socket * @retval -3 : ioctl call failed */ int _dot3Stats_ioctl_get(int fd, int which, struct ifreq *ifrq, const char* name) { int ourfd = -1, rc = 0; DEBUGMSGTL(("access:dot3StatsTable:ioctl", "_dot3Stats_ioctl_get\n")); /* * sanity checks */ if(NULL == name) { DEBUGMSGTL(("access:dot3StatsTable:ioctl", "_dot3Stats_ioctl_get invalid ifname '%s'\n", name)); snmp_log (LOG_ERR, "access:dot3StatsTable:ioctl, _dot3Stats_ioctl_get error on interface '%s'\n", name); return -1; } /* * create socket for ioctls */ if(fd < 0) { fd = ourfd = socket(AF_INET, SOCK_DGRAM, 0); if(ourfd < 0) { DEBUGMSGTL(("access:dot3StatsTable:ioctl", "dot3Stats_ioctl_get couldn't create a socket\n")); snmp_log (LOG_ERR, "access:dot3StatsTable:ioctl, _dot3Stats_ioctl_get error on interface '%s'\n", name); return -2; } } strlcpy(ifrq->ifr_name, name, sizeof(ifrq->ifr_name)); rc = ioctl(fd, which, ifrq); if (rc < 0) { DEBUGMSGTL(("access:dot3StatsTable:ioctl", "dot3Stats_ioctl_get ioctl %d returned %d\n", which, rc)); rc = -3; } if(ourfd >= 0) close(ourfd); return rc; }