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&#174; 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

Reply via email to