[dpdk-dev,V17,3/4] eal/linux: uevent parse and process

Message ID 1522339205-27698-4-git-send-email-jia.guo@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation fail Compilation issues

Commit Message

Guo, Jia March 29, 2018, 4 p.m. UTC
  In order to handle the uevent which have been detected from the kernel
side, add uevent parse and process function to translate the uevent into
device event, which user has subscribe to monitor.

Signed-off-by: Jeff Guo <jia.guo@intel.com>
---
v17->v16:
add new file into meson.build, modify coding sytle and add print info,
delete unused part.
---
 lib/librte_eal/linuxapp/eal/eal_dev.c   | 191 +++++++++++++++++++++++++++++++-
 lib/librte_eal/linuxapp/eal/meson.build |   1 +
 2 files changed, 189 insertions(+), 3 deletions(-)
  

Comments

Stephen Hemminger March 29, 2018, 4:59 p.m. UTC | #1
On Fri, 30 Mar 2018 00:00:04 +0800
Jeff Guo <jia.guo@intel.com> wrote:

> +	ret = ioctl(netlink_fd, FIONBIO, &nonblock);
> +	if (ret != 0) {
> +		RTE_LOG(ERR, EAL, "ioctl(FIONBIO) failed.\n");
> +		goto err;
> +	}
> +	retu

Since you use NOWAIT option, this is unnecessary.
  
Stephen Hemminger March 29, 2018, 5 p.m. UTC | #2
On Fri, 30 Mar 2018 00:00:04 +0800
Jeff Guo <jia.guo@intel.com> wrote:

> +dev_uev_monitor_create(int netlink_fd)
> +{
> +	struct sockaddr_nl addr;
> +	int ret;
> +	int size = 64 * 1024;
> +	int nonblock = 1;
> +
> +	memset(&addr, 0, sizeof(addr));
> +	addr.nl_family = AF_NETLINK;
> +	addr.nl_pid = 0;
> +	addr.nl_groups = 0xffffffff;
> +
> +	if (bind(netlink_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> +		RTE_LOG(ERR, EAL, "Failed to bind socket for netlink fd.\n");
> +		goto err;
> +	}
> +
> +	setsockopt(netlink_fd, SOL_SOCKET, SO_PASSCRED, &size, sizeof(size));
> +
> +	ret = ioctl(netlink_fd, FIONBIO, &nonblock);
> +	if (ret != 0) {
> +		RTE_LOG(ERR, EAL, "ioctl(FIONBIO) failed.\n");
> +		goto err;
> +	}
> +	return 0;
> +err:

You should set close on exec for this fd (with fcntl).
  
Guo, Jia April 2, 2018, 4:19 a.m. UTC | #3
On 3/30/2018 1:00 AM, Stephen Hemminger wrote:
> On Fri, 30 Mar 2018 00:00:04 +0800
> Jeff Guo <jia.guo@intel.com> wrote:
>
>> +dev_uev_monitor_create(int netlink_fd)
>> +{
>> +	struct sockaddr_nl addr;
>> +	int ret;
>> +	int size = 64 * 1024;
>> +	int nonblock = 1;
>> +
>> +	memset(&addr, 0, sizeof(addr));
>> +	addr.nl_family = AF_NETLINK;
>> +	addr.nl_pid = 0;
>> +	addr.nl_groups = 0xffffffff;
>> +
>> +	if (bind(netlink_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
>> +		RTE_LOG(ERR, EAL, "Failed to bind socket for netlink fd.\n");
>> +		goto err;
>> +	}
>> +
>> +	setsockopt(netlink_fd, SOL_SOCKET, SO_PASSCRED, &size, sizeof(size));
>> +
>> +	ret = ioctl(netlink_fd, FIONBIO, &nonblock);
>> +	if (ret != 0) {
>> +		RTE_LOG(ERR, EAL, "ioctl(FIONBIO) failed.\n");
>> +		goto err;
>> +	}
>> +	return 0;
>> +err:
> You should set close on exec for this fd (with fcntl).
yes, but i have already set it when fd creation time by SOCK_CLOEXEC.
  
Guo, Jia April 2, 2018, 4:20 a.m. UTC | #4
On 3/30/2018 12:59 AM, Stephen Hemminger wrote:
> On Fri, 30 Mar 2018 00:00:04 +0800
> Jeff Guo <jia.guo@intel.com> wrote:
>
>> +	ret = ioctl(netlink_fd, FIONBIO, &nonblock);
>> +	if (ret != 0) {
>> +		RTE_LOG(ERR, EAL, "ioctl(FIONBIO) failed.\n");
>> +		goto err;
>> +	}
>> +	retu
> Since you use NOWAIT option, this is unnecessary.
i think you are right.
  

Patch

diff --git a/lib/librte_eal/linuxapp/eal/eal_dev.c b/lib/librte_eal/linuxapp/eal/eal_dev.c
index 5ab5830..6466329 100644
--- a/lib/librte_eal/linuxapp/eal/eal_dev.c
+++ b/lib/librte_eal/linuxapp/eal/eal_dev.c
@@ -2,19 +2,204 @@ 
  * Copyright(c) 2018 Intel Corporation
  */
 
-#include <rte_log.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
 #include <rte_dev.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_interrupts.h>
+
+#include "eal_private.h"
+
+static struct rte_intr_handle intr_handle = {.fd = -1 };
+static bool monitor_started;
+
+#define EAL_UEV_MSG_LEN 4096
+#define EAL_UEV_MSG_ELEM_LEN 128
+
+/* identify the system layer which event exposure from */
+enum eal_dev_event_subsystem {
+	EAL_DEV_EVENT_SUBSYSTEM_PCI, /* PCI bus device event */
+	EAL_DEV_EVENT_SUBSYSTEM_UIO, /* UIO driver device event */
+	EAL_DEV_EVENT_SUBSYSTEM_MAX
+};
+
+static int
+dev_uev_monitor_create(int netlink_fd)
+{
+	struct sockaddr_nl addr;
+	int ret;
+	int size = 64 * 1024;
+	int nonblock = 1;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.nl_family = AF_NETLINK;
+	addr.nl_pid = 0;
+	addr.nl_groups = 0xffffffff;
+
+	if (bind(netlink_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		RTE_LOG(ERR, EAL, "Failed to bind socket for netlink fd.\n");
+		goto err;
+	}
+
+	setsockopt(netlink_fd, SOL_SOCKET, SO_PASSCRED, &size, sizeof(size));
+
+	ret = ioctl(netlink_fd, FIONBIO, &nonblock);
+	if (ret != 0) {
+		RTE_LOG(ERR, EAL, "ioctl(FIONBIO) failed.\n");
+		goto err;
+	}
+	return 0;
+err:
+	close(netlink_fd);
+	return -1;
+}
+
+static void
+dev_uev_parse(const char *buf, struct rte_dev_event *event, int length)
+{
+	char action[EAL_UEV_MSG_ELEM_LEN];
+	char subsystem[EAL_UEV_MSG_ELEM_LEN];
+	char pci_slot_name[EAL_UEV_MSG_ELEM_LEN];
+	int i = 0;
+
+	memset(action, 0, EAL_UEV_MSG_ELEM_LEN);
+	memset(subsystem, 0, EAL_UEV_MSG_ELEM_LEN);
+	memset(pci_slot_name, 0, EAL_UEV_MSG_ELEM_LEN);
+
+	while (i < length) {
+		for (; i < length; i++) {
+			if (*buf)
+				break;
+			buf++;
+		}
+		if (!strncmp(buf, "ACTION=", 7)) {
+			buf += 7;
+			i += 7;
+			snprintf(action, sizeof(action), "%s", buf);
+		} else if (!strncmp(buf, "SUBSYSTEM=", 10)) {
+			buf += 10;
+			i += 10;
+			snprintf(subsystem, sizeof(subsystem), "%s", buf);
+		} else if (!strncmp(buf, "PCI_SLOT_NAME=", 14)) {
+			buf += 14;
+			i += 14;
+			snprintf(pci_slot_name, sizeof(subsystem), "%s", buf);
+			event->devname = strdup(pci_slot_name);
+		}
+		for (; i < length; i++) {
+			if (*buf == '\0')
+				break;
+			buf++;
+		}
+	}
+
+	if (!strncmp(subsystem, "uio", 3))
+		event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_UIO;
+	else if (!strncmp(subsystem, "pci", 3))
+		event->subsystem = EAL_DEV_EVENT_SUBSYSTEM_PCI;
+	if (!strncmp(action, "add", 3))
+		event->type = RTE_DEV_EVENT_ADD;
+	if (!strncmp(action, "remove", 6))
+		event->type = RTE_DEV_EVENT_REMOVE;
+}
+
+static int
+dev_uev_receive(int fd, struct rte_dev_event *uevent)
+{
+	int ret;
+	char buf[EAL_UEV_MSG_LEN];
+
+	memset(uevent, 0, sizeof(struct rte_dev_event));
+	memset(buf, 0, EAL_UEV_MSG_LEN);
+
+	ret = recv(fd, buf, EAL_UEV_MSG_LEN, MSG_DONTWAIT);
+	if (ret < 0) {
+		RTE_LOG(ERR, EAL,
+			"Socket read error(%d): %s.\n",
+			errno, strerror(errno));
+		return -1;
+	} else if (ret == 0)
+		/* connection closed */
+		return -1;
+
+	dev_uev_parse(buf, uevent, EAL_UEV_MSG_LEN);
+
+	return 0;
+}
+
+static void
+dev_uev_process(__rte_unused void *param)
+{
+	struct rte_dev_event uevent;
+
+	if (dev_uev_receive(intr_handle.fd, &uevent))
+		return;
+
+	if (uevent.devname)
+		dev_callback_process(uevent.devname, uevent.type);
+}
 
 int __rte_experimental
 rte_dev_event_monitor_start(void)
 {
-	/* TODO: start uevent monitor for linux */
+	int ret;
+
+	if (monitor_started)
+		return 0;
+
+	intr_handle.fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC |
+			SOCK_NONBLOCK,
+			NETLINK_KOBJECT_UEVENT);
+	if (intr_handle.fd < 0) {
+		RTE_LOG(ERR, EAL, "create uevent fd failed.\n");
+		return -1;
+	}
+	intr_handle.type = RTE_INTR_HANDLE_DEV_EVENT;
+
+	ret = dev_uev_monitor_create(intr_handle.fd);
+
+	if (ret) {
+		RTE_LOG(ERR, EAL, "error create device event monitor.\n");
+		return -1;
+	}
+
+	ret = rte_intr_callback_register(&intr_handle, dev_uev_process, NULL);
+
+	if (ret) {
+		RTE_LOG(ERR, EAL, "fail to register uevent callback.\n");
+		return -1;
+	}
+
+	monitor_started = true;
+
 	return 0;
 }
 
 int __rte_experimental
 rte_dev_event_monitor_stop(void)
 {
-	/* TODO: stop uevent monitor for linux */
+	int ret;
+
+	if (!monitor_started)
+		return 0;
+
+	ret = rte_intr_callback_unregister(&intr_handle, dev_uev_process,
+					   (void *)-1);
+	if (ret) {
+		RTE_LOG(ERR, EAL, "fail to unregister uevent callback.");
+		return ret;
+	}
+
+	close(intr_handle.fd);
+	intr_handle.fd = -1;
+	monitor_started = false;
 	return 0;
 }
diff --git a/lib/librte_eal/linuxapp/eal/meson.build b/lib/librte_eal/linuxapp/eal/meson.build
index 03974ff..b222571 100644
--- a/lib/librte_eal/linuxapp/eal/meson.build
+++ b/lib/librte_eal/linuxapp/eal/meson.build
@@ -18,6 +18,7 @@  env_sources = files('eal_alarm.c',
 		'eal_vfio_mp_sync.c',
 		'eal.c',
 		'eal_memory.c',
+		'eal_dev.c',
 )
 
 if has_libnuma == 1