From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <gaetan.rivet@6wind.com>
Received: from mail-wm0-f65.google.com (mail-wm0-f65.google.com [74.125.82.65])
 by dpdk.org (Postfix) with ESMTP id C50661BED7
 for <dev@dpdk.org>; Thu,  5 Jul 2018 13:49:07 +0200 (CEST)
Received: by mail-wm0-f65.google.com with SMTP id v25-v6so10655977wmc.0
 for <dev@dpdk.org>; Thu, 05 Jul 2018 04:49:07 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=6wind-com.20150623.gappssmtp.com; s=20150623;
 h=from:to:cc:subject:date:message-id:in-reply-to:references;
 bh=YM6KHRri73F0XIIpq0JTRiq1BBgfRhxoV9BuSy/BjHA=;
 b=S7f2A1hMNHZPD7JWlpLmigqSPHk7EXrue2jVgLcrdUTPd/CpZ5s/hgB6qo1yHLHVD9
 q0g3cL+l3/Qt8WqQxWEThqanPcoaO7MVizmICUNQ9TZ1Vb4PMMAiPPy/DOJHsADuL8nN
 buYypU2NJFbQjO7h50tAkjSyY6NlkZmwjusp+xQc3qdXcbpiq6PyyvN3mPEOXuJK+uxX
 h0aU7iSZXbT94zuv0dxf7YSwpzd0cx9AEGKzIxiFcNbuoZxgvRHn9CFlrNToFwVnEexD
 jeedCe9b2NriKqgbxYGkJpW9zy47feNtVt6sqnyPBKQxNzd65zYtZQQ8aDj6lsBJf72x
 BRHw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20161025;
 h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to
 :references;
 bh=YM6KHRri73F0XIIpq0JTRiq1BBgfRhxoV9BuSy/BjHA=;
 b=QCURQxcrRWB6g9l8/6jpm77P99nZUCx9oe33R28slkwK+SjufOjlWLQp/qOoM3WNuz
 Io+q5D5w1G0UZvXTQvMNrhjpK73U9esBZCTs1j9Lz3r5pFdbD4mPdv0pVJYv1S9nRUFe
 73f2Yl1tOgP620yFtlx4FBL3OuB5NMKbOOFlXaMbnynwxZxu8n5JGfmDuzc19qFy3Iks
 gowPrK9epZ9vdmrU8ThREVpD+EvqLsc4Cmm3Zwx0iI/WUTPQl4AmXtBNwAL0oeFSExAV
 ydW1MAMaT7ToxB4Fr5hOssivAOGs7e4flw4d59ZRmLlinw38muoGD2mhv7QdM5OC2uN1
 cZCw==
X-Gm-Message-State: APt69E3pEi6THsdLGzjxv8lEijgxYwz7YWcXgxtC14XSEvsjlo6R78q5
 GklmmAQnJeWReUVDSC/BQEDZvFJm
X-Google-Smtp-Source: AAOMgpfDlmfQBdFDy3sjDfFALDE1UBYPOCuVUjE2PJ588lTZYnCBxEYFiWv1+VGWOi+TDe1+JMXfXQ==
X-Received: by 2002:adf:e285:: with SMTP id v5-v6mr4066413wri.54.1530791347135; 
 Thu, 05 Jul 2018 04:49:07 -0700 (PDT)
Received: from bidouze.dev.6wind.com. (host.78.145.23.62.rev.coltfrance.com.
 [62.23.145.78])
 by smtp.gmail.com with ESMTPSA id o42-v6sm15809183wrc.50.2018.07.05.04.49.05
 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
 Thu, 05 Jul 2018 04:49:06 -0700 (PDT)
From: Gaetan Rivet <gaetan.rivet@6wind.com>
To: dev@dpdk.org
Cc: Gaetan Rivet <gaetan.rivet@6wind.com>
Date: Thu,  5 Jul 2018 13:48:15 +0200
Message-Id: <0a2d77e22658987a6e1e650913f020a140c2c1a9.1530791217.git.gaetan.rivet@6wind.com>
X-Mailer: git-send-email 2.18.0
In-Reply-To: <cover.1530791217.git.gaetan.rivet@6wind.com>
References: <cover.1530791217.git.gaetan.rivet@6wind.com>
Subject: [dpdk-dev] [PATCH v10 08/27] devargs: add function to parse device
	layers
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
X-List-Received-Date: Thu, 05 Jul 2018 11:49:08 -0000

This function is private to the EAL.
It is used to parse each layers in a device description string,
and store the result in an rte_devargs structure.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_devargs.c  | 144 ++++++++++++++++++++
 lib/librte_eal/common/eal_private.h         |  27 ++++
 lib/librte_eal/common/include/rte_devargs.h |  13 +-
 3 files changed, 181 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 0a83beb94..5f89e0b6e 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -13,9 +13,13 @@
 #include <string.h>
 #include <stdarg.h>
 
+#include <rte_bus.h>
+#include <rte_class.h>
 #include <rte_compat.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
+#include <rte_kvargs.h>
+#include <rte_errno.h>
 #include <rte_tailq.h>
 #include "eal_private.h"
 
@@ -56,6 +60,146 @@ rte_eal_parse_devargs_str(const char *devargs_str,
 	return 0;
 }
 
+static size_t
+devargs_layer_count(const char *s)
+{
+	size_t i = s ? 1 : 0;
+
+	while (s != NULL && s[0] != '\0') {
+		i += s[0] == '/';
+		s++;
+	}
+	return i;
+}
+
+int
+rte_devargs_layers_parse(struct rte_devargs *da,
+			 const char *devstr)
+{
+	struct {
+		const char *key;
+		const char *str;
+		struct rte_kvargs *kvlist;
+	} layers[] = {
+		{ "bus=",    NULL, NULL, },
+		{ "class=",  NULL, NULL, },
+		{ "driver=", NULL, NULL, },
+	};
+	struct rte_kvargs_pair *kv = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_bus *bus = NULL;
+	const char *s = devstr;
+	size_t nblayer;
+	size_t i = 0;
+	int ret = 0;
+
+	/* Split each sub-lists. */
+	nblayer = devargs_layer_count(devstr);
+	if (nblayer > RTE_DIM(layers)) {
+		RTE_LOG(ERR, EAL, "Invalid format: too many layers (%zu)\n",
+			nblayer);
+		ret = -E2BIG;
+		goto get_out;
+	}
+
+	/* If the devargs points the devstr
+	 * as source data, then it should not allocate
+	 * anything and keep referring only to it.
+	 */
+	if (da->data != devstr) {
+		da->data = strdup(devstr);
+		if (da->data == NULL) {
+			RTE_LOG(ERR, EAL, "OOM\n");
+			ret = -ENOMEM;
+			goto get_out;
+		}
+		s = da->data;
+	}
+
+	while (s != NULL) {
+		if (strncmp(layers[i].key, s,
+			    strlen(layers[i].key)) &&
+		    /* The last layer is free-form.
+		     * The "driver" key is not required (but accepted).
+		     */
+		    i != RTE_DIM(layers) - 1)
+			goto next_layer;
+		layers[i].str = s;
+		layers[i].kvlist = rte_kvargs_parse2(s, NULL, "/");
+		if (layers[i].kvlist == NULL) {
+			RTE_LOG(ERR, EAL, "Could not parse %s\n", s);
+			ret = -EINVAL;
+			goto get_out;
+		}
+		s = strchr(s, '/');
+		if (s != NULL)
+			s++;
+next_layer:
+		if (i >= RTE_DIM(layers)) {
+			RTE_LOG(ERR, EAL, "Unrecognized layer %s\n", s);
+			ret = -EINVAL;
+			goto get_out;
+		}
+		i++;
+	}
+
+	/* Parse each sub-list. */
+	for (i = 0; i < RTE_DIM(layers); i++) {
+		if (layers[i].kvlist == NULL)
+			continue;
+		kv = &layers[i].kvlist->pairs[0];
+		if (strcmp(kv->key, "bus") == 0) {
+			bus = rte_bus_find_by_name(kv->value);
+			if (bus == NULL) {
+				RTE_LOG(ERR, EAL, "Could not find bus \"%s\"\n",
+					kv->value);
+				ret = -EFAULT;
+				goto get_out;
+			}
+		} else if (strcmp(kv->key, "class") == 0) {
+			cls = rte_class_find_by_name(kv->value);
+			if (cls == NULL) {
+				RTE_LOG(ERR, EAL, "Could not find class \"%s\"\n",
+					kv->value);
+				ret = -EFAULT;
+				goto get_out;
+			}
+		} else if (strcmp(kv->key, "driver") == 0) {
+			/* Ignore */
+			continue;
+		}
+	}
+
+	/* Fill devargs fields. */
+	da->busstr = layers[0].str;
+	da->clsstr = layers[1].str;
+	da->drvstr = layers[2].str;
+	da->bus = bus;
+	da->cls = cls;
+
+	/* If we own the data, clean up a bit
+	 * the several layers string, to ease
+	 * their parsing afterward.
+	 */
+	if (da->data != devstr) {
+		char *s = (void *)(intptr_t)(da->data);
+
+		while ((s = strchr(s, '/'))) {
+			*s = '\0';
+			s++;
+		}
+	}
+
+get_out:
+	for (i = 0; i < RTE_DIM(layers); i++) {
+		if (layers[i].kvlist)
+			rte_kvargs_free(layers[i].kvlist);
+	}
+	if (ret != 0)
+		rte_errno = -ret;
+	return ret;
+}
+
 static int
 bus_name_cmp(const struct rte_bus *bus, const void *name)
 {
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index bdadc4d50..c4c9283c8 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -258,4 +258,31 @@ int rte_mp_channel_init(void);
  */
 void dev_callback_process(char *device_name, enum rte_dev_event_type event);
 
+/**
+ * @internal
+ * Parse a device string and store its information in an
+ * rte_devargs structure.
+ *
+ * Note: if the "data" field of da points to devstr,
+ * then no dynamic allocation is performed and the rte_devargs
+ * can be safely discarded.
+ *
+ * Otherwise ``data`` will hold a workable copy of devstr, that will be
+ * used by layers descriptors within rte_devargs. In this case,
+ * any rte_devargs should be cleaned-up before being freed.
+ *
+ * @param da
+ *   rte_devargs structure to fill.
+ *
+ * @param devstr
+ *   Device string.
+ *
+ * @return
+ *   0 on success.
+ *   Negative errno values on error (rte_errno is set).
+ */
+int
+rte_devargs_layers_parse(struct rte_devargs *da,
+			 const char *devstr);
+
 #endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 6c3b6326b..148600258 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -51,12 +51,19 @@ struct rte_devargs {
 	enum rte_devtype type;
 	/** Device policy. */
 	enum rte_dev_policy policy;
-	/** Bus handle for the device. */
-	struct rte_bus *bus;
 	/** Name of the device. */
 	char name[RTE_DEV_NAME_MAX_LEN];
+	RTE_STD_C11
+	union {
 	/** Arguments string as given by user or "" for no argument. */
-	char *args;
+		char *args;
+		const char *drvstr;
+	};
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< bus-related part of device string. */
+	const char *data; /**< Device string storage. */
 };
 
 /**
-- 
2.18.0