Robert Story wrote:
> On Tue, 09 Mar 2010 14:01:46 +0100 Josef wrote:
> JM> How do I publish this patch? Do I have to do
> JM> special things to replace the original patch?
>
> no, you should be able to just attach the new file... you might need to reopen
> the patch, as Dave probably closed it when he applied the last patch...
OK, so here goes.
The patch is attached and it completely replaces the original patch I
posted a couple of weeks ago.
Josef
--
These are my personal views and not those of Fujitsu Technology Solutions!
Josef Möllers (Pinguinpfleger bei FTS)
If failure had no penalty success would not be a prize (T. Pratchett)
Company Details: http://de.ts.fujitsu.com/imprint.html
--- net-snmp-5.5/agent/mibgroup/etherlike-mib/data_access/dot3stats_linux.c.josef 2010-03-09 15:58:39.000000000 +0100
+++ net-snmp-5.5/agent/mibgroup/etherlike-mib/data_access/dot3stats_linux.c 2010-03-09 16:30:22.000000000 +0100
@@ -135,6 +135,506 @@
#endif /* SIOCGIFINDEX */
}
+# if HAVE_LINUX_RTNETLINK_H /* { NETLINK */
+/*
+ * The following code is based upon code I got from Stephen Hemminger
+ */
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
+# include <errno.h>
+
+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/<ifname>/statistics/<ctrname>
+ * 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, 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
--- net-snmp-5.5/agent/mibgroup/etherlike-mib/dot3StatsTable/dot3StatsTable_data_access.c.josef 2010-03-09 15:57:34.000000000 +0100
+++ net-snmp-5.5/agent/mibgroup/etherlike-mib/dot3StatsTable/dot3StatsTable_data_access.c 2010-03-09 16:19:54.000000000 +0100
@@ -326,6 +326,8 @@
continue;
}
+ interface_dot3stats_get_errorcounters(rowreq_ctx, p->name);
+
/*
* insert into table container
*/
------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
Net-snmp-coders mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders