diff mbox

[11/16] ibacm: Add thread to monitor IP address changes

Message ID 1395985810-23822-12-git-send-email-sean.hefty@intel.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Hefty, Sean March 28, 2014, 5:50 a.m. UTC
From: Ira Weiny <ira.weiny@intel.com>

Currently only reports events to the log

Signed-off-by: Ira Weiny <ira.weiny@intel.com>
---
 src/acm.c |   86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 86 insertions(+), 0 deletions(-)

Comments

Bart Van Assche March 28, 2014, 6:43 a.m. UTC | #1
On 03/28/14 06:50, sean.hefty@intel.com wrote:
> +	while ((len = recv(sock, buffer, NL_MSG_BUF_SIZE, 0)) > 0) {
> +		nlh = (struct nlmsghdr *)buffer;
> +		while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) {
> +			struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
> +			struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nlh);
> +			struct rtattr *rth = IFA_RTA(ifa);
> +			int rtl = IFA_PAYLOAD(nlh);
> +
> +			switch (nlh->nlmsg_type) {
> +			[ ... ]
> +			nlh = NLMSG_NEXT(nlh, len);
> +		}
> +	}

Is there any reason why this code doesn't handle netlink buffer
overflows (ENOBUFS) ? From the netlink(7) man page:

Netlink is not a reliable protocol. [ ... ] The kernel can't send a
netlink message if the socket buffer is full: the message will be
dropped and the kernel and the user-space process will no longer have
the same view of kernel state. It is up to the application to detect
when this happens (via the ENOBUFS error returned by recvmsg(2)) and
resynchronize.

Bart.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ira Weiny March 28, 2014, 3:51 p.m. UTC | #2
> On 03/28/14 06:50, sean.hefty@intel.com wrote:
> > +	while ((len = recv(sock, buffer, NL_MSG_BUF_SIZE, 0)) > 0) {
> > +		nlh = (struct nlmsghdr *)buffer;
> > +		while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type !=
> NLMSG_DONE)) {
> > +			struct ifaddrmsg *ifa = (struct ifaddrmsg *)
> NLMSG_DATA(nlh);
> > +			struct ifinfomsg *ifi = (struct ifinfomsg *)
> NLMSG_DATA(nlh);
> > +			struct rtattr *rth = IFA_RTA(ifa);
> > +			int rtl = IFA_PAYLOAD(nlh);
> > +
> > +			switch (nlh->nlmsg_type) {
> > +			[ ... ]
> > +			nlh = NLMSG_NEXT(nlh, len);
> > +		}
> > +	}
> 
> Is there any reason why this code doesn't handle netlink buffer overflows
> (ENOBUFS) ? From the netlink(7) man page:

No reason other than my inexperience with netlink.

> 
> Netlink is not a reliable protocol. [ ... ] The kernel can't send a netlink
> message if the socket buffer is full: the message will be dropped and the
> kernel and the user-space process will no longer have the same view of
> kernel state. It is up to the application to detect when this happens (via the
> ENOBUFS error returned by recvmsg(2)) and resynchronize.

Thanks, I'll rework the patch to account for this.

Maybe by that time I will have Intel's email figured out...

Thanks,
Ira

> 
> Bart.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bart Van Assche March 28, 2014, 4:23 p.m. UTC | #3
On 03/28/14 16:51, Weiny, Ira wrote:
>> On 03/28/14 06:50, sean.hefty@intel.com wrote:
>>> +	while ((len = recv(sock, buffer, NL_MSG_BUF_SIZE, 0)) > 0) {
>>> +		nlh = (struct nlmsghdr *)buffer;
>>> +		while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type !=
>> NLMSG_DONE)) {
>>> +			struct ifaddrmsg *ifa = (struct ifaddrmsg *)
>> NLMSG_DATA(nlh);
>>> +			struct ifinfomsg *ifi = (struct ifinfomsg *)
>> NLMSG_DATA(nlh);
>>> +			struct rtattr *rth = IFA_RTA(ifa);
>>> +			int rtl = IFA_PAYLOAD(nlh);
>>> +
>>> +			switch (nlh->nlmsg_type) {
>>> +			[ ... ]
>>> +			nlh = NLMSG_NEXT(nlh, len);
>>> +		}
>>> +	}
>>
>> Is there any reason why this code doesn't handle netlink buffer overflows
>> (ENOBUFS) ? From the netlink(7) man page:
> 
> No reason other than my inexperience with netlink.

In that case it's probably helpful to have a look at the libnl
documentation. I'm not saying that library should be used here but it's
accompanied by excellent documentation about the netlink protocol. See
also http://www.carisma.slowglass.com/~tgr/libnl/ and
http://www.carisma.slowglass.com/~tgr/libnl/doc/core.html.

Bart.

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/src/acm.c b/src/acm.c
index ebb48f4..a23e953 100644
--- a/src/acm.c
+++ b/src/acm.c
@@ -49,6 +49,9 @@ 
 #include <net/if.h>
 #include <sys/ioctl.h>
 #include <net/if_arp.h>
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
 #include "acm_mad.h"
 #include "acm_util.h"
 
@@ -3368,6 +3371,86 @@  static void acm_port_down(struct acm_port *port)
 	acm_log(1, "%s %d is down\n", port->dev->verbs->device->name, port->port_num);
 }
 
+
+#define NL_MSG_BUF_SIZE 4096
+static void CDECL_FUNC acm_ipnl_handler(void *context)
+{
+	struct sockaddr_nl addr;
+	int sock, len;
+	char buffer[NL_MSG_BUF_SIZE];
+	struct nlmsghdr *nlh;
+	char name[IFNAMSIZ];
+	char ip_str[INET6_ADDRSTRLEN];
+
+	if ((sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
+		acm_log(0, "Failed to open NETLINK_ROUTE socket");
+		return;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.nl_family = AF_NETLINK;
+	addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
+
+	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+		acm_log(0, "Failed to bind NETLINK_ROUTE socket");
+		return;
+	}
+
+	while ((len = recv(sock, buffer, NL_MSG_BUF_SIZE, 0)) > 0) {
+		nlh = (struct nlmsghdr *)buffer;
+		while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) {
+			struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
+			struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nlh);
+			struct rtattr *rth = IFA_RTA(ifa);
+			int rtl = IFA_PAYLOAD(nlh);
+
+			switch (nlh->nlmsg_type) {
+			case RTM_NEWADDR:
+			{
+				if_indextoname(ifa->ifa_index, name);
+				while (rtl && RTA_OK(rth, rtl)) {
+					if (rth->rta_type == IFA_LOCAL) {
+						acm_log(0, "Address added %s : %s\n",
+						        name, inet_ntop(ifa->ifa_family, RTA_DATA(rth),
+							ip_str, sizeof(ip_str)));
+					}
+					rth = RTA_NEXT(rth, rtl);
+				}
+				break;
+			}
+			case RTM_DELADDR:
+			{
+				if_indextoname(ifa->ifa_index, name);
+				while (rtl && RTA_OK(rth, rtl)) {
+					if (rth->rta_type == IFA_LOCAL) {
+						acm_log(0, "Address deleted %s : %s\n",
+						        name, inet_ntop(ifa->ifa_family, RTA_DATA(rth),
+							ip_str, sizeof(ip_str)));
+					}
+					rth = RTA_NEXT(rth, rtl);
+				}
+				break;
+			}
+			case RTM_NEWLINK:
+			{
+				acm_log(2, "Link added : %s\n", if_indextoname(ifi->ifi_index, name));
+				break;
+			}
+			case RTM_DELLINK:
+			{
+				acm_log(2, "Link removed : %s\n", if_indextoname(ifi->ifi_index, name));
+				break;
+			}
+			default:
+				acm_log(2, "unknown netlink message\n");
+				break;
+			}
+			nlh = NLMSG_NEXT(nlh, len);
+		}
+	}
+	return;
+}
+
 /*
  * There is one event handler thread per device.  This is the only thread that
  * modifies the port state or a port endpoint list.  Other threads which access
@@ -3750,6 +3833,9 @@  int CDECL_FUNC main(int argc, char **argv)
 		return -1;
 	}
 
+	acm_log(1, "starting IP Netlink thread\n");
+	beginthread(acm_ipnl_handler, NULL);
+
 	acm_activate_devices();
 	acm_log(1, "starting timeout/retry thread\n");
 	beginthread(acm_retry_handler, NULL);