[lustre-devel] [PATCH 33/34] Completely re-write lnet_parse_networks().

NeilBrown neilb at suse.com
Thu Sep 6 17:49:32 PDT 2018


From: Amir Shehata <amir.shehata at intel.com>

Was:

LU-7734 lnet: Multi-Rail local NI split

This patch allows the configuration of multiple NIs under one Net.
It is now possible to have multiple NIDs on the same network:
   Ex: <ip1>@tcp, <ip2>@tcp.
This can be configured using the following syntax:
   Ex: tcp(eth0, eth1)

The data structures for the example above can be visualized
as follows

               NET(tcp)
                |
        -----------------
        |               |
      NI(eth0)        NI(eth1)

For more details refer to the Mult-Rail Requirements and HLD
documents

Signed-off-by: Amir Shehata <amir.shehata at intel.com>
Change-Id: Id7c73b9b811a3082b61e53b9e9f95743188cbd51
Reviewed-on: http://review.whamcloud.com/18274
Tested-by: Jenkins
Reviewed-by: Doug Oucharek <doug.s.oucharek at intel.com>
Tested-by: Maloo <hpdd-maloo at intel.com>
Reviewed-by: Olaf Weber <olaf at sgi.com>
---
 drivers/staging/lustre/lnet/lnet/config.c |  341 ++++++++++++++++++-----------
 1 file changed, 217 insertions(+), 124 deletions(-)

diff --git a/drivers/staging/lustre/lnet/lnet/config.c b/drivers/staging/lustre/lnet/lnet/config.c
index 11d6dbc80507..0571fa6a7249 100644
--- a/drivers/staging/lustre/lnet/lnet/config.c
+++ b/drivers/staging/lustre/lnet/lnet/config.c
@@ -48,8 +48,11 @@ static int lnet_tbnob;			/* track text buf allocation */
 #define LNET_MAX_TEXTBUF_NOB     (64 << 10)	/* bound allocation */
 #define LNET_SINGLE_TEXTBUF_NOB  (4 << 10)
 
+#define SPACESTR " \t\v\r\n"
+#define DELIMITERS ":()[]"
+
 static void
-lnet_syntax(char *name, char *str, int offset, int width)
+lnet_syntax(const char *name, const char *str, int offset, int width)
 {
 	static char dots[LNET_SINGLE_TEXTBUF_NOB];
 	static char dashes[LNET_SINGLE_TEXTBUF_NOB];
@@ -363,6 +366,42 @@ lnet_net_alloc(__u32 net_id, struct list_head *net_list)
 	return net;
 }
 
+static int
+lnet_ni_add_interface(struct lnet_ni *ni, char *iface)
+{
+	int niface = 0;
+
+	if (ni == NULL)
+		return -ENOMEM;
+
+	/* Allocate a separate piece of memory and copy
+	 * into it the string, so we don't have
+	 * a depencency on the tokens string.  This way we
+	 * can free the tokens at the end of the function.
+	 * The newly allocated ni_interfaces[] can be
+	 * freed when freeing the NI */
+	while (niface < LNET_MAX_INTERFACES &&
+	       ni->ni_interfaces[niface] != NULL)
+		niface++;
+
+	if (niface >= LNET_MAX_INTERFACES) {
+		LCONSOLE_ERROR_MSG(0x115, "Too many interfaces "
+				   "for net %s\n",
+				   libcfs_net2str(LNET_NIDNET(ni->ni_nid)));
+		return -EINVAL;
+	}
+
+	ni->ni_interfaces[niface] = kstrdup(iface, GFP_KERNEL);
+
+	if (ni->ni_interfaces[niface] == NULL) {
+		CERROR("Can't allocate net interface name\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/* allocate and add to the provided network */
 struct lnet_ni *
 lnet_ni_alloc(struct lnet_net *net, struct cfs_expr_list *el, char *iface)
 {
@@ -439,24 +478,33 @@ lnet_ni_alloc(struct lnet_net *net, struct cfs_expr_list *el, char *iface)
 		goto failed;
 	list_add_tail(&ni->ni_netlist, &net->net_ni_added);
 
+	/* if an interface name is provided then make sure to add in that
+	 * interface name in NI */
+	if (iface != NULL)
+		if (lnet_ni_add_interface(ni, iface) != 0)
+			goto failed;
+
 	return ni;
 failed:
 	lnet_ni_free(ni);
 	return NULL;
 }
 
+/*
+ * Parse the networks string and create the matching set of NIs on the
+ * nilist.
+ */
 int
 lnet_parse_networks(struct list_head *netlist, char *networks)
 {
-	struct cfs_expr_list *el = NULL;
+	struct cfs_expr_list *net_el = NULL;
+	struct cfs_expr_list *ni_el = NULL;
 	char *tokens;
 	char *str;
-	char *tmp;
 	struct lnet_net *net;
 	struct lnet_ni *ni = NULL;
 	__u32 net_id;
 	int nnets = 0;
-	struct list_head *temp_node;
 
 	if (!networks) {
 		CERROR("networks string is undefined\n");
@@ -476,84 +524,108 @@ lnet_parse_networks(struct list_head *netlist, char *networks)
 		return -ENOMEM;
 	}
 
-	tmp = tokens;
 	str = tokens;
 
-	while (str && *str) {
-		char *comma = strchr(str, ',');
-		char *bracket = strchr(str, '(');
-		char *square = strchr(str, '[');
-		char *iface;
-		int niface;
+	/*
+	 * Main parser loop.
+	 *
+	 * NB we don't check interface conflicts here; it's the LNDs
+	 * responsibility (if it cares at all)
+	 */
+	do {
+		char *nistr;
+		char *elstr;
+		char *name;
 		int rc;
 
 		/*
-		 * NB we don't check interface conflicts here; it's the LNDs
-		 * responsibility (if it cares at all)
+		 * Parse a network string into its components.
+		 *
+		 * <name>{"("...")"}{"["<el>"]"}
 		 */
-		if (square && (!comma || square < comma)) {
-			/*
-			 * i.e: o2ib0(ib0)[1,2], number between square
-			 * brackets are CPTs this NI needs to be bond
-			 */
-			if (bracket && bracket > square) {
-				tmp = square;
+
+		/* Network name (mandatory)
+		 */
+		while (isspace(*str))
+			*str++ = '\0';
+		if (!*str)
+			break;
+		name = str;
+		str += strcspn(str, SPACESTR ":()[],");
+		while (isspace(*str))
+			*str++ = '\0';
+
+		/* Interface list (optional) */
+		if (*str == '(') {
+			*str++ = '\0';
+			nistr = str;
+			str += strcspn(str, ")");
+			if (*str != ')') {
+				str = nistr;
 				goto failed_syntax;
 			}
+			do {
+				*str++ = '\0';
+			} while (isspace(*str));
+		} else {
+			nistr = NULL;
+		}
 
-			tmp = strchr(square, ']');
-			if (!tmp) {
-				tmp = square;
+		/* CPT expression (optional) */
+		if (*str == '[') {
+			elstr = str;
+			str += strcspn(str, "]");
+			if (*str != ']') {
+				str = elstr;
 				goto failed_syntax;
 			}
-
-			rc = cfs_expr_list_parse(square, tmp - square + 1,
-						 0, LNET_CPT_NUMBER - 1, &el);
+			rc = cfs_expr_list_parse(elstr, str - elstr + 1,
+						0, LNET_CPT_NUMBER - 1,
+						&net_el);
 			if (rc) {
-				tmp = square;
+				str = elstr;
 				goto failed_syntax;
 			}
-
-			while (square <= tmp)
-				*square++ = ' ';
+			*elstr = '\0';
+			do {
+				*str++ = '\0';
+			} while (isspace(*str));
 		}
 
-		if (!bracket || (comma && comma < bracket)) {
-			/* no interface list specified */
+		/* Bad delimiters */
+		if (*str && (strchr(DELIMITERS, *str) != NULL))
+			goto failed_syntax;
 
-			if (comma)
-				*comma++ = 0;
-			net_id = libcfs_str2net(strim(str));
+		/* go to the next net if it exits */
+		str += strcspn(str, ",");
+		if (*str == ',')
+			*str++ = '\0';
 
-			if (net_id == LNET_NIDNET(LNET_NID_ANY)) {
-				LCONSOLE_ERROR_MSG(0x113,
-						   "Unrecognised network type\n");
-				tmp = str;
-				goto failed_syntax;
-			}
-
-			if (LNET_NETTYP(net_id) != LOLND) { /* LO is implicit */
-				net = lnet_net_alloc(net_id, netlist);
-				if (!net ||
-				    !lnet_ni_alloc(net, el, NULL))
-					goto failed;
-			}
+		/*
+		 * At this point the name is properly terminated.
+		 */
+		net_id = libcfs_str2net(name);
+		if (net_id == LNET_NIDNET(LNET_NID_ANY)) {
+			LCONSOLE_ERROR_MSG(0x113,
+					"Unrecognised network type\n");
+			str = name;
+			goto failed_syntax;
+		}
 
-			if (el) {
-				cfs_expr_list_free(el);
-				el = NULL;
+		if (LNET_NETTYP(net_id) == LOLND) {
+			/* Loopback is implicit, and there can be only one. */
+			if (net_el) {
+				cfs_expr_list_free(net_el);
+				net_el = NULL;
 			}
-
-			str = comma;
+			/* Should we error out instead? */
 			continue;
 		}
 
-		*bracket = 0;
-		net_id = libcfs_str2net(strim(str));
-		if (net_id == LNET_NIDNET(LNET_NID_ANY)) {
-			tmp = str;
-			goto failed_syntax;
-		}
+		/*
+		 * All network paramaters are now known.
+		 */
+		nnets++;
 
 		/* always allocate a net, since we will eventually add an
 		 * interface to it, or we will fail, in which case we'll
@@ -562,88 +634,107 @@ lnet_parse_networks(struct list_head *netlist, char *networks)
 		if (IS_ERR_OR_NULL(net))
 			goto failed;
 
-		ni = lnet_ni_alloc(net, el, NULL);
-		if (IS_ERR_OR_NULL(ni))
-			goto failed;
-
-		if (el) {
-			cfs_expr_list_free(el);
-			el = NULL;
-		}
-
-		niface = 0;
-		iface = bracket + 1;
+		if (!nistr) {
+			/*
+			 * No interface list was specified, allocate a
+			 * ni using the defaults.
+			 */
+			ni = lnet_ni_alloc(net, net_el, NULL);
+			if (IS_ERR_OR_NULL(ni))
+				goto failed;
 
-		bracket = strchr(iface, ')');
-		if (!bracket) {
-			tmp = iface;
-			goto failed_syntax;
+			if (net_el) {
+				cfs_expr_list_free(net_el);
+				net_el = NULL;
+			}
+			continue;
 		}
 
-		*bracket = 0;
 		do {
-			comma = strchr(iface, ',');
-			if (comma)
-				*comma++ = 0;
-
-			iface = strim(iface);
-			if (!*iface) {
-				tmp = iface;
-				goto failed_syntax;
+			elstr = NULL;
+
+			/* Interface name (mandatory) */
+			while (isspace(*nistr))
+				*nistr++ = '\0';
+			name = nistr;
+			nistr += strcspn(nistr, SPACESTR "[],");
+			while (isspace(*nistr))
+				*nistr++ = '\0';
+
+			/* CPT expression (optional) */
+			if (*nistr == '[') {
+				elstr = nistr;
+				nistr += strcspn(nistr, "]");
+				if (*nistr != ']') {
+					str = elstr;
+					goto failed_syntax;
+				}
+				rc = cfs_expr_list_parse(elstr,
+							nistr - elstr + 1,
+							0, LNET_CPT_NUMBER - 1,
+							&ni_el);
+				if (rc != 0) {
+					str = elstr;
+					goto failed_syntax;
+				}
+				*elstr = '\0';
+				do {
+					*nistr++ = '\0';
+				} while (isspace(*nistr));
+			} else {
+				ni_el = net_el;
 			}
 
-			if (niface == LNET_MAX_INTERFACES) {
-				LCONSOLE_ERROR_MSG(0x115,
-						   "Too many interfaces for net %s\n",
-						   libcfs_net2str(net_id));
-				goto failed;
+			/*
+			 * End of single interface specificaton,
+			 * advance to the start of the next one, if
+			 * any.
+			 */
+			if (*nistr == ',') {
+				do {
+					*nistr++ = '\0';
+				} while (isspace(*nistr));
+				if (!*nistr) {
+					str = nistr;
+					goto failed_syntax;
+				}
+			} else if (*nistr) {
+				str = nistr;
+				goto failed_syntax;
 			}
 
 			/*
-			 * Allocate a separate piece of memory and copy
-			 * into it the string, so we don't have
-			 * a depencency on the tokens string.  This way we
-			 * can free the tokens at the end of the function.
-			 * The newly allocated ni_interfaces[] can be
-			 * freed when freeing the NI
+			 * At this point the name
+			 is properly terminated.
 			 */
-			ni->ni_interfaces[niface] = kstrdup(iface, GFP_KERNEL);
-			if (!ni->ni_interfaces[niface]) {
-				CERROR("Can't allocate net interface name\n");
-				goto failed;
-			}
-			niface++;
-			iface = comma;
-		} while (iface);
-
-		str = bracket + 1;
-		comma = strchr(bracket + 1, ',');
-		if (comma) {
-			*comma = 0;
-			str = strim(str);
-			if (*str) {
-				tmp = str;
+			if (!*name) {
+				str = name;
 				goto failed_syntax;
 			}
-			str = comma + 1;
-			continue;
-		}
 
-		str = strim(str);
-		if (*str) {
-			tmp = str;
-			goto failed_syntax;
-		}
-	}
+			ni = lnet_ni_alloc(net, ni_el, name);
+			if (IS_ERR_OR_NULL(ni))
+				goto failed;
 
-	list_for_each(temp_node, netlist)
-		nnets++;
+			if (ni_el) {
+				if (ni_el != net_el) {
+					cfs_expr_list_free(ni_el);
+					ni_el = NULL;
+				}
+			}
+		} while (*nistr);
+
+		if (net_el) {
+			cfs_expr_list_free(net_el);
+			net_el = NULL;
+		}
+	} while (*str);
 
 	kfree(tokens);
 	return nnets;
 
  failed_syntax:
-	lnet_syntax("networks", networks, (int)(tmp - tokens), strlen(tmp));
+	lnet_syntax("networks", networks, (int)(str - tokens), strlen(str));
  failed:
 	/* free the net list and all the nis on each net */
 	while (!list_empty(netlist)) {
@@ -653,8 +744,10 @@ lnet_parse_networks(struct list_head *netlist, char *networks)
 		lnet_net_free(net);
 	}
 
-	if (el)
-		cfs_expr_list_free(el);
+	if (ni_el && ni_el != net_el)
+		cfs_expr_list_free(ni_el);
+	if (net_el)
+		cfs_expr_list_free(net_el);
 
 	kfree(tokens);
 




More information about the lustre-devel mailing list