• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2012, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lnet/lnet/nidstrings.c
33  *
34  * Author: Phil Schwan <phil@clusterfs.com>
35  */
36 
37 #define DEBUG_SUBSYSTEM S_LNET
38 
39 #include <linux/libcfs/libcfs.h>
40 #include <uapi/linux/lnet/nidstr.h>
41 
42 /* max value for numeric network address */
43 #define MAX_NUMERIC_VALUE 0xffffffff
44 
45 #define IPSTRING_LENGTH 16
46 
47 /* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
48  * consistent in all conversion functions.  Some code fragments are copied
49  * around for the sake of clarity...
50  */
51 
52 /* CAVEAT EMPTOR! Racey temporary buffer allocation!
53  * Choose the number of nidstrings to support the MAXIMUM expected number of
54  * concurrent users.  If there are more, the returned string will be volatile.
55  * NB this number must allow for a process to be descheduled for a timeslice
56  * between getting its string and using it.
57  */
58 
59 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
60 static int       libcfs_nidstring_idx;
61 
62 static DEFINE_SPINLOCK(libcfs_nidstring_lock);
63 
64 static struct netstrfns *libcfs_namenum2netstrfns(const char *name);
65 
66 char *
libcfs_next_nidstring(void)67 libcfs_next_nidstring(void)
68 {
69 	char *str;
70 	unsigned long flags;
71 
72 	spin_lock_irqsave(&libcfs_nidstring_lock, flags);
73 
74 	str = libcfs_nidstrings[libcfs_nidstring_idx++];
75 	if (libcfs_nidstring_idx == ARRAY_SIZE(libcfs_nidstrings))
76 		libcfs_nidstring_idx = 0;
77 
78 	spin_unlock_irqrestore(&libcfs_nidstring_lock, flags);
79 	return str;
80 }
81 EXPORT_SYMBOL(libcfs_next_nidstring);
82 
83 /**
84  * Nid range list syntax.
85  * \verbatim
86  *
87  * <nidlist>         :== <nidrange> [ ' ' <nidrange> ]
88  * <nidrange>        :== <addrrange> '@' <net>
89  * <addrrange>       :== '*' |
90  *                       <ipaddr_range> |
91  *			 <cfs_expr_list>
92  * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
93  *			 <cfs_expr_list>
94  * <cfs_expr_list>   :== <number> |
95  *                       <expr_list>
96  * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
97  * <range_expr>      :== <number> |
98  *                       <number> '-' <number> |
99  *                       <number> '-' <number> '/' <number>
100  * <net>             :== <netname> | <netname><number>
101  * <netname>         :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
102  *                       "vib" | "ra" | "elan" | "mx" | "ptl"
103  * \endverbatim
104  */
105 
106 /**
107  * Structure to represent \<nidrange\> token of the syntax.
108  *
109  * One of this is created for each \<net\> parsed.
110  */
111 struct nidrange {
112 	/**
113 	 * Link to list of this structures which is built on nid range
114 	 * list parsing.
115 	 */
116 	struct list_head nr_link;
117 	/**
118 	 * List head for addrrange::ar_link.
119 	 */
120 	struct list_head nr_addrranges;
121 	/**
122 	 * Flag indicating that *@<net> is found.
123 	 */
124 	int nr_all;
125 	/**
126 	 * Pointer to corresponding element of libcfs_netstrfns.
127 	 */
128 	struct netstrfns *nr_netstrfns;
129 	/**
130 	 * Number of network. E.g. 5 if \<net\> is "elan5".
131 	 */
132 	int nr_netnum;
133 };
134 
135 /**
136  * Structure to represent \<addrrange\> token of the syntax.
137  */
138 struct addrrange {
139 	/**
140 	 * Link to nidrange::nr_addrranges.
141 	 */
142 	struct list_head ar_link;
143 	/**
144 	 * List head for cfs_expr_list::el_list.
145 	 */
146 	struct list_head ar_numaddr_ranges;
147 };
148 
149 /**
150  * Parses \<addrrange\> token on the syntax.
151  *
152  * Allocates struct addrrange and links to \a nidrange via
153  * (nidrange::nr_addrranges)
154  *
155  * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
156  * \retval -errno otherwise
157  */
158 static int
parse_addrange(const struct cfs_lstr * src,struct nidrange * nidrange)159 parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
160 {
161 	struct addrrange *addrrange;
162 
163 	if (src->ls_len == 1 && src->ls_str[0] == '*') {
164 		nidrange->nr_all = 1;
165 		return 0;
166 	}
167 
168 	LIBCFS_ALLOC(addrrange, sizeof(struct addrrange));
169 	if (!addrrange)
170 		return -ENOMEM;
171 	list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
172 	INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
173 
174 	return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
175 						src->ls_len,
176 						&addrrange->ar_numaddr_ranges);
177 }
178 
179 /**
180  * Finds or creates struct nidrange.
181  *
182  * Checks if \a src is a valid network name, looks for corresponding
183  * nidrange on the ist of nidranges (\a nidlist), creates new struct
184  * nidrange if it is not found.
185  *
186  * \retval pointer to struct nidrange matching network specified via \a src
187  * \retval NULL if \a src does not match any network
188  */
189 static struct nidrange *
add_nidrange(const struct cfs_lstr * src,struct list_head * nidlist)190 add_nidrange(const struct cfs_lstr *src,
191 	     struct list_head *nidlist)
192 {
193 	struct netstrfns *nf;
194 	struct nidrange *nr;
195 	int endlen;
196 	unsigned int netnum;
197 
198 	if (src->ls_len >= LNET_NIDSTR_SIZE)
199 		return NULL;
200 
201 	nf = libcfs_namenum2netstrfns(src->ls_str);
202 	if (!nf)
203 		return NULL;
204 	endlen = src->ls_len - strlen(nf->nf_name);
205 	if (!endlen)
206 		/* network name only, e.g. "elan" or "tcp" */
207 		netnum = 0;
208 	else {
209 		/*
210 		 * e.g. "elan25" or "tcp23", refuse to parse if
211 		 * network name is not appended with decimal or
212 		 * hexadecimal number
213 		 */
214 		if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
215 				       endlen, &netnum, 0, MAX_NUMERIC_VALUE))
216 			return NULL;
217 	}
218 
219 	list_for_each_entry(nr, nidlist, nr_link) {
220 		if (nr->nr_netstrfns != nf)
221 			continue;
222 		if (nr->nr_netnum != netnum)
223 			continue;
224 		return nr;
225 	}
226 
227 	LIBCFS_ALLOC(nr, sizeof(struct nidrange));
228 	if (!nr)
229 		return NULL;
230 	list_add_tail(&nr->nr_link, nidlist);
231 	INIT_LIST_HEAD(&nr->nr_addrranges);
232 	nr->nr_netstrfns = nf;
233 	nr->nr_all = 0;
234 	nr->nr_netnum = netnum;
235 
236 	return nr;
237 }
238 
239 /**
240  * Parses \<nidrange\> token of the syntax.
241  *
242  * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
243  * \retval 0 otherwise
244  */
245 static int
parse_nidrange(struct cfs_lstr * src,struct list_head * nidlist)246 parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
247 {
248 	struct cfs_lstr addrrange;
249 	struct cfs_lstr net;
250 	struct nidrange *nr;
251 
252 	if (!cfs_gettok(src, '@', &addrrange))
253 		goto failed;
254 
255 	if (!cfs_gettok(src, '@', &net) || src->ls_str)
256 		goto failed;
257 
258 	nr = add_nidrange(&net, nidlist);
259 	if (!nr)
260 		goto failed;
261 
262 	if (parse_addrange(&addrrange, nr))
263 		goto failed;
264 
265 	return 1;
266 failed:
267 	return 0;
268 }
269 
270 /**
271  * Frees addrrange structures of \a list.
272  *
273  * For each struct addrrange structure found on \a list it frees
274  * cfs_expr_list list attached to it and frees the addrrange itself.
275  *
276  * \retval none
277  */
278 static void
free_addrranges(struct list_head * list)279 free_addrranges(struct list_head *list)
280 {
281 	while (!list_empty(list)) {
282 		struct addrrange *ar;
283 
284 		ar = list_entry(list->next, struct addrrange, ar_link);
285 
286 		cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
287 		list_del(&ar->ar_link);
288 		LIBCFS_FREE(ar, sizeof(struct addrrange));
289 	}
290 }
291 
292 /**
293  * Frees nidrange strutures of \a list.
294  *
295  * For each struct nidrange structure found on \a list it frees
296  * addrrange list attached to it and frees the nidrange itself.
297  *
298  * \retval none
299  */
300 void
cfs_free_nidlist(struct list_head * list)301 cfs_free_nidlist(struct list_head *list)
302 {
303 	struct list_head *pos, *next;
304 	struct nidrange *nr;
305 
306 	list_for_each_safe(pos, next, list) {
307 		nr = list_entry(pos, struct nidrange, nr_link);
308 		free_addrranges(&nr->nr_addrranges);
309 		list_del(pos);
310 		LIBCFS_FREE(nr, sizeof(struct nidrange));
311 	}
312 }
313 EXPORT_SYMBOL(cfs_free_nidlist);
314 
315 /**
316  * Parses nid range list.
317  *
318  * Parses with rigorous syntax and overflow checking \a str into
319  * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
320  * structures and links that structure to \a nidlist. The resulting
321  * list can be used to match a NID againts set of NIDS defined by \a
322  * str.
323  * \see cfs_match_nid
324  *
325  * \retval 1 on success
326  * \retval 0 otherwise
327  */
328 int
cfs_parse_nidlist(char * str,int len,struct list_head * nidlist)329 cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
330 {
331 	struct cfs_lstr src;
332 	struct cfs_lstr res;
333 	int rc;
334 
335 	src.ls_str = str;
336 	src.ls_len = len;
337 	INIT_LIST_HEAD(nidlist);
338 	while (src.ls_str) {
339 		rc = cfs_gettok(&src, ' ', &res);
340 		if (!rc) {
341 			cfs_free_nidlist(nidlist);
342 			return 0;
343 		}
344 		rc = parse_nidrange(&res, nidlist);
345 		if (!rc) {
346 			cfs_free_nidlist(nidlist);
347 			return 0;
348 		}
349 	}
350 	return 1;
351 }
352 EXPORT_SYMBOL(cfs_parse_nidlist);
353 
354 /**
355  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
356  *
357  * \see cfs_parse_nidlist()
358  *
359  * \retval 1 on match
360  * \retval 0  otherwises
361  */
cfs_match_nid(lnet_nid_t nid,struct list_head * nidlist)362 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
363 {
364 	struct nidrange *nr;
365 	struct addrrange *ar;
366 
367 	list_for_each_entry(nr, nidlist, nr_link) {
368 		if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
369 			continue;
370 		if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
371 			continue;
372 		if (nr->nr_all)
373 			return 1;
374 		list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
375 			if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
376 							    &ar->ar_numaddr_ranges))
377 				return 1;
378 	}
379 	return 0;
380 }
381 EXPORT_SYMBOL(cfs_match_nid);
382 
383 /**
384  * Print the network part of the nidrange \a nr into the specified \a buffer.
385  *
386  * \retval number of characters written
387  */
388 static int
cfs_print_network(char * buffer,int count,struct nidrange * nr)389 cfs_print_network(char *buffer, int count, struct nidrange *nr)
390 {
391 	struct netstrfns *nf = nr->nr_netstrfns;
392 
393 	if (!nr->nr_netnum)
394 		return scnprintf(buffer, count, "@%s", nf->nf_name);
395 	else
396 		return scnprintf(buffer, count, "@%s%u",
397 				 nf->nf_name, nr->nr_netnum);
398 }
399 
400 /**
401  * Print a list of addrrange (\a addrranges) into the specified \a buffer.
402  * At max \a count characters can be printed into \a buffer.
403  *
404  * \retval number of characters written
405  */
406 static int
cfs_print_addrranges(char * buffer,int count,struct list_head * addrranges,struct nidrange * nr)407 cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
408 		     struct nidrange *nr)
409 {
410 	int i = 0;
411 	struct addrrange *ar;
412 	struct netstrfns *nf = nr->nr_netstrfns;
413 
414 	list_for_each_entry(ar, addrranges, ar_link) {
415 		if (i)
416 			i += scnprintf(buffer + i, count - i, " ");
417 		i += nf->nf_print_addrlist(buffer + i, count - i,
418 					   &ar->ar_numaddr_ranges);
419 		i += cfs_print_network(buffer + i, count - i, nr);
420 	}
421 	return i;
422 }
423 
424 /**
425  * Print a list of nidranges (\a nidlist) into the specified \a buffer.
426  * At max \a count characters can be printed into \a buffer.
427  * Nidranges are separated by a space character.
428  *
429  * \retval number of characters written
430  */
cfs_print_nidlist(char * buffer,int count,struct list_head * nidlist)431 int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
432 {
433 	int i = 0;
434 	struct nidrange *nr;
435 
436 	if (count <= 0)
437 		return 0;
438 
439 	list_for_each_entry(nr, nidlist, nr_link) {
440 		if (i)
441 			i += scnprintf(buffer + i, count - i, " ");
442 
443 		if (nr->nr_all) {
444 			LASSERT(list_empty(&nr->nr_addrranges));
445 			i += scnprintf(buffer + i, count - i, "*");
446 			i += cfs_print_network(buffer + i, count - i, nr);
447 		} else {
448 			i += cfs_print_addrranges(buffer + i, count - i,
449 						  &nr->nr_addrranges, nr);
450 		}
451 	}
452 	return i;
453 }
454 EXPORT_SYMBOL(cfs_print_nidlist);
455 
456 /**
457  * Determines minimum and maximum addresses for a single
458  * numeric address range
459  *
460  * \param	ar
461  * \param	min_nid
462  * \param	max_nid
463  */
cfs_ip_ar_min_max(struct addrrange * ar,__u32 * min_nid,__u32 * max_nid)464 static void cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
465 			      __u32 *max_nid)
466 {
467 	struct cfs_expr_list *el;
468 	struct cfs_range_expr *re;
469 	__u32 tmp_ip_addr = 0;
470 	unsigned int min_ip[4] = {0};
471 	unsigned int max_ip[4] = {0};
472 	int re_count = 0;
473 
474 	list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
475 		list_for_each_entry(re, &el->el_exprs, re_link) {
476 			min_ip[re_count] = re->re_lo;
477 			max_ip[re_count] = re->re_hi;
478 			re_count++;
479 		}
480 	}
481 
482 	tmp_ip_addr = ((min_ip[0] << 24) | (min_ip[1] << 16) |
483 		       (min_ip[2] << 8) | min_ip[3]);
484 
485 	if (min_nid)
486 		*min_nid = tmp_ip_addr;
487 
488 	tmp_ip_addr = ((max_ip[0] << 24) | (max_ip[1] << 16) |
489 		       (max_ip[2] << 8) | max_ip[3]);
490 
491 	if (max_nid)
492 		*max_nid = tmp_ip_addr;
493 }
494 
495 /**
496  * Determines minimum and maximum addresses for a single
497  * numeric address range
498  *
499  * \param	ar
500  * \param	min_nid
501  * \param	max_nid
502  */
cfs_num_ar_min_max(struct addrrange * ar,__u32 * min_nid,__u32 * max_nid)503 static void cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
504 			       __u32 *max_nid)
505 {
506 	struct cfs_expr_list *el;
507 	struct cfs_range_expr *re;
508 	unsigned int min_addr = 0;
509 	unsigned int max_addr = 0;
510 
511 	list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
512 		list_for_each_entry(re, &el->el_exprs, re_link) {
513 			if (re->re_lo < min_addr || !min_addr)
514 				min_addr = re->re_lo;
515 			if (re->re_hi > max_addr)
516 				max_addr = re->re_hi;
517 		}
518 	}
519 
520 	if (min_nid)
521 		*min_nid = min_addr;
522 	if (max_nid)
523 		*max_nid = max_addr;
524 }
525 
526 /**
527  * Determines whether an expression list in an nidrange contains exactly
528  * one contiguous address range. Calls the correct netstrfns for the LND
529  *
530  * \param	*nidlist
531  *
532  * \retval	true if contiguous
533  * \retval	false if not contiguous
534  */
cfs_nidrange_is_contiguous(struct list_head * nidlist)535 bool cfs_nidrange_is_contiguous(struct list_head *nidlist)
536 {
537 	struct nidrange *nr;
538 	struct netstrfns *nf = NULL;
539 	char *lndname = NULL;
540 	int netnum = -1;
541 
542 	list_for_each_entry(nr, nidlist, nr_link) {
543 		nf = nr->nr_netstrfns;
544 		if (!lndname)
545 			lndname = nf->nf_name;
546 		if (netnum == -1)
547 			netnum = nr->nr_netnum;
548 
549 		if (strcmp(lndname, nf->nf_name) ||
550 		    netnum != nr->nr_netnum)
551 			return false;
552 	}
553 
554 	if (!nf)
555 		return false;
556 
557 	if (!nf->nf_is_contiguous(nidlist))
558 		return false;
559 
560 	return true;
561 }
562 EXPORT_SYMBOL(cfs_nidrange_is_contiguous);
563 
564 /**
565  * Determines whether an expression list in an num nidrange contains exactly
566  * one contiguous address range.
567  *
568  * \param	*nidlist
569  *
570  * \retval	true if contiguous
571  * \retval	false if not contiguous
572  */
cfs_num_is_contiguous(struct list_head * nidlist)573 static bool cfs_num_is_contiguous(struct list_head *nidlist)
574 {
575 	struct nidrange *nr;
576 	struct addrrange *ar;
577 	struct cfs_expr_list *el;
578 	struct cfs_range_expr *re;
579 	int last_hi = 0;
580 	__u32 last_end_nid = 0;
581 	__u32 current_start_nid = 0;
582 	__u32 current_end_nid = 0;
583 
584 	list_for_each_entry(nr, nidlist, nr_link) {
585 		list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
586 			cfs_num_ar_min_max(ar, &current_start_nid,
587 					   &current_end_nid);
588 			if (last_end_nid &&
589 			    (current_start_nid - last_end_nid != 1))
590 				return false;
591 			last_end_nid = current_end_nid;
592 			list_for_each_entry(el, &ar->ar_numaddr_ranges,
593 					    el_link) {
594 				list_for_each_entry(re, &el->el_exprs,
595 						    re_link) {
596 					if (re->re_stride > 1)
597 						return false;
598 					else if (last_hi &&
599 						 re->re_hi - last_hi != 1)
600 						return false;
601 					last_hi = re->re_hi;
602 				}
603 			}
604 		}
605 	}
606 
607 	return true;
608 }
609 
610 /**
611  * Determines whether an expression list in an ip nidrange contains exactly
612  * one contiguous address range.
613  *
614  * \param	*nidlist
615  *
616  * \retval	true if contiguous
617  * \retval	false if not contiguous
618  */
cfs_ip_is_contiguous(struct list_head * nidlist)619 static bool cfs_ip_is_contiguous(struct list_head *nidlist)
620 {
621 	struct nidrange *nr;
622 	struct addrrange *ar;
623 	struct cfs_expr_list *el;
624 	struct cfs_range_expr *re;
625 	int expr_count;
626 	int last_hi = 255;
627 	int last_diff = 0;
628 	__u32 last_end_nid = 0;
629 	__u32 current_start_nid = 0;
630 	__u32 current_end_nid = 0;
631 
632 	list_for_each_entry(nr, nidlist, nr_link) {
633 		list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
634 			last_hi = 255;
635 			last_diff = 0;
636 			cfs_ip_ar_min_max(ar, &current_start_nid,
637 					  &current_end_nid);
638 			if (last_end_nid &&
639 			    (current_start_nid - last_end_nid != 1))
640 				return false;
641 			last_end_nid = current_end_nid;
642 			list_for_each_entry(el, &ar->ar_numaddr_ranges,
643 					    el_link) {
644 				expr_count = 0;
645 				list_for_each_entry(re, &el->el_exprs,
646 						    re_link) {
647 					expr_count++;
648 					if (re->re_stride > 1 ||
649 					    (last_diff > 0 && last_hi != 255) ||
650 					    (last_diff > 0 && last_hi == 255 &&
651 					     re->re_lo > 0))
652 						return false;
653 					last_hi = re->re_hi;
654 					last_diff = re->re_hi - re->re_lo;
655 				}
656 			}
657 		}
658 	}
659 
660 	return true;
661 }
662 
663 /**
664  * Takes a linked list of nidrange expressions, determines the minimum
665  * and maximum nid and creates appropriate nid structures
666  *
667  * \param	*nidlist
668  * \param	*min_nid
669  * \param	*max_nid
670  */
cfs_nidrange_find_min_max(struct list_head * nidlist,char * min_nid,char * max_nid,size_t nidstr_length)671 void cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
672 			       char *max_nid, size_t nidstr_length)
673 {
674 	struct nidrange *nr;
675 	struct netstrfns *nf = NULL;
676 	int netnum = -1;
677 	__u32 min_addr;
678 	__u32 max_addr;
679 	char *lndname = NULL;
680 	char min_addr_str[IPSTRING_LENGTH];
681 	char max_addr_str[IPSTRING_LENGTH];
682 
683 	list_for_each_entry(nr, nidlist, nr_link) {
684 		nf = nr->nr_netstrfns;
685 		lndname = nf->nf_name;
686 		if (netnum == -1)
687 			netnum = nr->nr_netnum;
688 
689 		nf->nf_min_max(nidlist, &min_addr, &max_addr);
690 	}
691 	nf->nf_addr2str(min_addr, min_addr_str, sizeof(min_addr_str));
692 	nf->nf_addr2str(max_addr, max_addr_str, sizeof(max_addr_str));
693 
694 	snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
695 		 netnum);
696 	snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
697 		 netnum);
698 }
699 EXPORT_SYMBOL(cfs_nidrange_find_min_max);
700 
701 /**
702  * Determines the min and max NID values for num LNDs
703  *
704  * \param	*nidlist
705  * \param	*min_nid
706  * \param	*max_nid
707  */
cfs_num_min_max(struct list_head * nidlist,__u32 * min_nid,__u32 * max_nid)708 static void cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
709 			    __u32 *max_nid)
710 {
711 	struct nidrange	*nr;
712 	struct addrrange *ar;
713 	unsigned int tmp_min_addr = 0;
714 	unsigned int tmp_max_addr = 0;
715 	unsigned int min_addr = 0;
716 	unsigned int max_addr = 0;
717 
718 	list_for_each_entry(nr, nidlist, nr_link) {
719 		list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
720 			cfs_num_ar_min_max(ar, &tmp_min_addr,
721 					   &tmp_max_addr);
722 			if (tmp_min_addr < min_addr || !min_addr)
723 				min_addr = tmp_min_addr;
724 			if (tmp_max_addr > max_addr)
725 				max_addr = tmp_min_addr;
726 		}
727 	}
728 	*max_nid = max_addr;
729 	*min_nid = min_addr;
730 }
731 
732 /**
733  * Takes an nidlist and determines the minimum and maximum
734  * ip addresses.
735  *
736  * \param	*nidlist
737  * \param	*min_nid
738  * \param	*max_nid
739  */
cfs_ip_min_max(struct list_head * nidlist,__u32 * min_nid,__u32 * max_nid)740 static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
741 			   __u32 *max_nid)
742 {
743 	struct nidrange *nr;
744 	struct addrrange *ar;
745 	__u32 tmp_min_ip_addr = 0;
746 	__u32 tmp_max_ip_addr = 0;
747 	__u32 min_ip_addr = 0;
748 	__u32 max_ip_addr = 0;
749 
750 	list_for_each_entry(nr, nidlist, nr_link) {
751 		list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
752 			cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
753 					  &tmp_max_ip_addr);
754 			if (tmp_min_ip_addr < min_ip_addr || !min_ip_addr)
755 				min_ip_addr = tmp_min_ip_addr;
756 			if (tmp_max_ip_addr > max_ip_addr)
757 				max_ip_addr = tmp_max_ip_addr;
758 		}
759 	}
760 
761 	if (min_nid)
762 		*min_nid = min_ip_addr;
763 	if (max_nid)
764 		*max_nid = max_ip_addr;
765 }
766 
767 static int
libcfs_lo_str2addr(const char * str,int nob,__u32 * addr)768 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
769 {
770 	*addr = 0;
771 	return 1;
772 }
773 
774 static void
libcfs_ip_addr2str(__u32 addr,char * str,size_t size)775 libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
776 {
777 	snprintf(str, size, "%u.%u.%u.%u",
778 		 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
779 		 (addr >> 8) & 0xff, addr & 0xff);
780 }
781 
782 /*
783  * CAVEAT EMPTOR XscanfX
784  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
785  * sscanf may return immediately if it sees the terminating '0' in a string, so
786  * I initialise the %n variable to the expected length.  If sscanf sets it;
787  * fine, if it doesn't, then the scan ended at the end of the string, which is
788  * fine too :)
789  */
790 static int
libcfs_ip_str2addr(const char * str,int nob,__u32 * addr)791 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
792 {
793 	unsigned int	a;
794 	unsigned int	b;
795 	unsigned int	c;
796 	unsigned int	d;
797 	int		n = nob; /* XscanfX */
798 
799 	/* numeric IP? */
800 	if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
801 	    n == nob &&
802 	    !(a & ~0xff) && !(b & ~0xff) &&
803 	    !(c & ~0xff) && !(d & ~0xff)) {
804 		*addr = ((a << 24) | (b << 16) | (c << 8) | d);
805 		return 1;
806 	}
807 
808 	return 0;
809 }
810 
811 /* Used by lnet/config.c so it can't be static */
812 int
cfs_ip_addr_parse(char * str,int len,struct list_head * list)813 cfs_ip_addr_parse(char *str, int len, struct list_head *list)
814 {
815 	struct cfs_expr_list *el;
816 	struct cfs_lstr src;
817 	int rc;
818 	int i;
819 
820 	src.ls_str = str;
821 	src.ls_len = len;
822 	i = 0;
823 
824 	while (src.ls_str) {
825 		struct cfs_lstr res;
826 
827 		if (!cfs_gettok(&src, '.', &res)) {
828 			rc = -EINVAL;
829 			goto out;
830 		}
831 
832 		rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el);
833 		if (rc)
834 			goto out;
835 
836 		list_add_tail(&el->el_link, list);
837 		i++;
838 	}
839 
840 	if (i == 4)
841 		return 0;
842 
843 	rc = -EINVAL;
844 out:
845 	cfs_expr_list_free_list(list);
846 
847 	return rc;
848 }
849 
850 static int
libcfs_ip_addr_range_print(char * buffer,int count,struct list_head * list)851 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
852 {
853 	int i = 0, j = 0;
854 	struct cfs_expr_list *el;
855 
856 	list_for_each_entry(el, list, el_link) {
857 		LASSERT(j++ < 4);
858 		if (i)
859 			i += scnprintf(buffer + i, count - i, ".");
860 		i += cfs_expr_list_print(buffer + i, count - i, el);
861 	}
862 	return i;
863 }
864 
865 /**
866  * Matches address (\a addr) against address set encoded in \a list.
867  *
868  * \retval 1 if \a addr matches
869  * \retval 0 otherwise
870  */
871 int
cfs_ip_addr_match(__u32 addr,struct list_head * list)872 cfs_ip_addr_match(__u32 addr, struct list_head *list)
873 {
874 	struct cfs_expr_list *el;
875 	int i = 0;
876 
877 	list_for_each_entry_reverse(el, list, el_link) {
878 		if (!cfs_expr_list_match(addr & 0xff, el))
879 			return 0;
880 		addr >>= 8;
881 		i++;
882 	}
883 
884 	return i == 4;
885 }
886 
887 static void
libcfs_decnum_addr2str(__u32 addr,char * str,size_t size)888 libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
889 {
890 	snprintf(str, size, "%u", addr);
891 }
892 
893 static int
libcfs_num_str2addr(const char * str,int nob,__u32 * addr)894 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
895 {
896 	int     n;
897 
898 	n = nob;
899 	if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
900 		return 1;
901 
902 	n = nob;
903 	if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
904 		return 1;
905 
906 	n = nob;
907 	if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
908 		return 1;
909 
910 	return 0;
911 }
912 
913 /**
914  * Nf_parse_addrlist method for networks using numeric addresses.
915  *
916  * Examples of such networks are gm and elan.
917  *
918  * \retval 0 if \a str parsed to numeric address
919  * \retval errno otherwise
920  */
921 static int
libcfs_num_parse(char * str,int len,struct list_head * list)922 libcfs_num_parse(char *str, int len, struct list_head *list)
923 {
924 	struct cfs_expr_list *el;
925 	int	rc;
926 
927 	rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
928 	if (!rc)
929 		list_add_tail(&el->el_link, list);
930 
931 	return rc;
932 }
933 
934 static int
libcfs_num_addr_range_print(char * buffer,int count,struct list_head * list)935 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
936 {
937 	int i = 0, j = 0;
938 	struct cfs_expr_list *el;
939 
940 	list_for_each_entry(el, list, el_link) {
941 		LASSERT(j++ < 1);
942 		i += cfs_expr_list_print(buffer + i, count - i, el);
943 	}
944 	return i;
945 }
946 
947 /*
948  * Nf_match_addr method for networks using numeric addresses
949  *
950  * \retval 1 on match
951  * \retval 0 otherwise
952  */
953 static int
libcfs_num_match(__u32 addr,struct list_head * numaddr)954 libcfs_num_match(__u32 addr, struct list_head *numaddr)
955 {
956 	struct cfs_expr_list *el;
957 
958 	LASSERT(!list_empty(numaddr));
959 	el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
960 
961 	return cfs_expr_list_match(addr, el);
962 }
963 
964 static struct netstrfns libcfs_netstrfns[] = {
965 	{ .nf_type		= LOLND,
966 	  .nf_name		= "lo",
967 	  .nf_modname		= "klolnd",
968 	  .nf_addr2str		= libcfs_decnum_addr2str,
969 	  .nf_str2addr		= libcfs_lo_str2addr,
970 	  .nf_parse_addrlist	= libcfs_num_parse,
971 	  .nf_print_addrlist	= libcfs_num_addr_range_print,
972 	  .nf_match_addr	= libcfs_num_match,
973 	  .nf_is_contiguous	= cfs_num_is_contiguous,
974 	  .nf_min_max		= cfs_num_min_max },
975 	{ .nf_type		= SOCKLND,
976 	  .nf_name		= "tcp",
977 	  .nf_modname		= "ksocklnd",
978 	  .nf_addr2str		= libcfs_ip_addr2str,
979 	  .nf_str2addr		= libcfs_ip_str2addr,
980 	  .nf_parse_addrlist	= cfs_ip_addr_parse,
981 	  .nf_print_addrlist	= libcfs_ip_addr_range_print,
982 	  .nf_match_addr	= cfs_ip_addr_match,
983 	  .nf_is_contiguous	= cfs_ip_is_contiguous,
984 	  .nf_min_max		= cfs_ip_min_max },
985 	{ .nf_type		= O2IBLND,
986 	  .nf_name		= "o2ib",
987 	  .nf_modname		= "ko2iblnd",
988 	  .nf_addr2str		= libcfs_ip_addr2str,
989 	  .nf_str2addr		= libcfs_ip_str2addr,
990 	  .nf_parse_addrlist	= cfs_ip_addr_parse,
991 	  .nf_print_addrlist	= libcfs_ip_addr_range_print,
992 	  .nf_match_addr	= cfs_ip_addr_match,
993 	  .nf_is_contiguous	= cfs_ip_is_contiguous,
994 	  .nf_min_max		= cfs_ip_min_max },
995 	{ .nf_type		= GNILND,
996 	  .nf_name		= "gni",
997 	  .nf_modname		= "kgnilnd",
998 	  .nf_addr2str		= libcfs_decnum_addr2str,
999 	  .nf_str2addr		= libcfs_num_str2addr,
1000 	  .nf_parse_addrlist	= libcfs_num_parse,
1001 	  .nf_print_addrlist	= libcfs_num_addr_range_print,
1002 	  .nf_match_addr	= libcfs_num_match,
1003 	  .nf_is_contiguous	= cfs_num_is_contiguous,
1004 	  .nf_min_max		= cfs_num_min_max },
1005 	{ .nf_type		= GNIIPLND,
1006 	  .nf_name		= "gip",
1007 	  .nf_modname		= "kgnilnd",
1008 	  .nf_addr2str		= libcfs_ip_addr2str,
1009 	  .nf_str2addr		= libcfs_ip_str2addr,
1010 	  .nf_parse_addrlist	= cfs_ip_addr_parse,
1011 	  .nf_print_addrlist	= libcfs_ip_addr_range_print,
1012 	  .nf_match_addr	= cfs_ip_addr_match,
1013 	  .nf_is_contiguous	= cfs_ip_is_contiguous,
1014 	  .nf_min_max		= cfs_ip_min_max },
1015 };
1016 
1017 static const size_t libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
1018 
1019 static struct netstrfns *
libcfs_lnd2netstrfns(__u32 lnd)1020 libcfs_lnd2netstrfns(__u32 lnd)
1021 {
1022 	int i;
1023 
1024 	for (i = 0; i < libcfs_nnetstrfns; i++)
1025 		if (lnd == libcfs_netstrfns[i].nf_type)
1026 			return &libcfs_netstrfns[i];
1027 
1028 	return NULL;
1029 }
1030 
1031 static struct netstrfns *
libcfs_namenum2netstrfns(const char * name)1032 libcfs_namenum2netstrfns(const char *name)
1033 {
1034 	struct netstrfns *nf;
1035 	int i;
1036 
1037 	for (i = 0; i < libcfs_nnetstrfns; i++) {
1038 		nf = &libcfs_netstrfns[i];
1039 		if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
1040 			return nf;
1041 	}
1042 	return NULL;
1043 }
1044 
1045 static struct netstrfns *
libcfs_name2netstrfns(const char * name)1046 libcfs_name2netstrfns(const char *name)
1047 {
1048 	int    i;
1049 
1050 	for (i = 0; i < libcfs_nnetstrfns; i++)
1051 		if (!strcmp(libcfs_netstrfns[i].nf_name, name))
1052 			return &libcfs_netstrfns[i];
1053 
1054 	return NULL;
1055 }
1056 
1057 int
libcfs_isknown_lnd(__u32 lnd)1058 libcfs_isknown_lnd(__u32 lnd)
1059 {
1060 	return !!libcfs_lnd2netstrfns(lnd);
1061 }
1062 EXPORT_SYMBOL(libcfs_isknown_lnd);
1063 
1064 char *
libcfs_lnd2modname(__u32 lnd)1065 libcfs_lnd2modname(__u32 lnd)
1066 {
1067 	struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
1068 
1069 	return nf ? nf->nf_modname : NULL;
1070 }
1071 EXPORT_SYMBOL(libcfs_lnd2modname);
1072 
1073 int
libcfs_str2lnd(const char * str)1074 libcfs_str2lnd(const char *str)
1075 {
1076 	struct netstrfns *nf = libcfs_name2netstrfns(str);
1077 
1078 	if (nf)
1079 		return nf->nf_type;
1080 
1081 	return -ENXIO;
1082 }
1083 EXPORT_SYMBOL(libcfs_str2lnd);
1084 
1085 char *
libcfs_lnd2str_r(__u32 lnd,char * buf,size_t buf_size)1086 libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
1087 {
1088 	struct netstrfns *nf;
1089 
1090 	nf = libcfs_lnd2netstrfns(lnd);
1091 	if (!nf)
1092 		snprintf(buf, buf_size, "?%u?", lnd);
1093 	else
1094 		snprintf(buf, buf_size, "%s", nf->nf_name);
1095 
1096 	return buf;
1097 }
1098 EXPORT_SYMBOL(libcfs_lnd2str_r);
1099 
1100 char *
libcfs_net2str_r(__u32 net,char * buf,size_t buf_size)1101 libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
1102 {
1103 	__u32 nnum = LNET_NETNUM(net);
1104 	__u32 lnd = LNET_NETTYP(net);
1105 	struct netstrfns *nf;
1106 
1107 	nf = libcfs_lnd2netstrfns(lnd);
1108 	if (!nf)
1109 		snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
1110 	else if (!nnum)
1111 		snprintf(buf, buf_size, "%s", nf->nf_name);
1112 	else
1113 		snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
1114 
1115 	return buf;
1116 }
1117 EXPORT_SYMBOL(libcfs_net2str_r);
1118 
1119 char *
libcfs_nid2str_r(lnet_nid_t nid,char * buf,size_t buf_size)1120 libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
1121 {
1122 	__u32 addr = LNET_NIDADDR(nid);
1123 	__u32 net = LNET_NIDNET(nid);
1124 	__u32 nnum = LNET_NETNUM(net);
1125 	__u32 lnd = LNET_NETTYP(net);
1126 	struct netstrfns *nf;
1127 
1128 	if (nid == LNET_NID_ANY) {
1129 		strncpy(buf, "<?>", buf_size);
1130 		buf[buf_size - 1] = '\0';
1131 		return buf;
1132 	}
1133 
1134 	nf = libcfs_lnd2netstrfns(lnd);
1135 	if (!nf) {
1136 		snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
1137 	} else {
1138 		size_t addr_len;
1139 
1140 		nf->nf_addr2str(addr, buf, buf_size);
1141 		addr_len = strlen(buf);
1142 		if (!nnum)
1143 			snprintf(buf + addr_len, buf_size - addr_len, "@%s",
1144 				 nf->nf_name);
1145 		else
1146 			snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
1147 				 nf->nf_name, nnum);
1148 	}
1149 
1150 	return buf;
1151 }
1152 EXPORT_SYMBOL(libcfs_nid2str_r);
1153 
1154 static struct netstrfns *
libcfs_str2net_internal(const char * str,__u32 * net)1155 libcfs_str2net_internal(const char *str, __u32 *net)
1156 {
1157 	struct netstrfns *nf = NULL;
1158 	int nob;
1159 	unsigned int netnum;
1160 	int i;
1161 
1162 	for (i = 0; i < libcfs_nnetstrfns; i++) {
1163 		nf = &libcfs_netstrfns[i];
1164 		if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
1165 			break;
1166 	}
1167 
1168 	if (i == libcfs_nnetstrfns)
1169 		return NULL;
1170 
1171 	nob = strlen(nf->nf_name);
1172 
1173 	if (strlen(str) == (unsigned int)nob) {
1174 		netnum = 0;
1175 	} else {
1176 		if (nf->nf_type == LOLND) /* net number not allowed */
1177 			return NULL;
1178 
1179 		str += nob;
1180 		i = strlen(str);
1181 		if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
1182 		    i != (int)strlen(str))
1183 			return NULL;
1184 	}
1185 
1186 	*net = LNET_MKNET(nf->nf_type, netnum);
1187 	return nf;
1188 }
1189 
1190 __u32
libcfs_str2net(const char * str)1191 libcfs_str2net(const char *str)
1192 {
1193 	__u32  net;
1194 
1195 	if (libcfs_str2net_internal(str, &net))
1196 		return net;
1197 
1198 	return LNET_NIDNET(LNET_NID_ANY);
1199 }
1200 EXPORT_SYMBOL(libcfs_str2net);
1201 
1202 lnet_nid_t
libcfs_str2nid(const char * str)1203 libcfs_str2nid(const char *str)
1204 {
1205 	const char *sep = strchr(str, '@');
1206 	struct netstrfns *nf;
1207 	__u32 net;
1208 	__u32 addr;
1209 
1210 	if (sep) {
1211 		nf = libcfs_str2net_internal(sep + 1, &net);
1212 		if (!nf)
1213 			return LNET_NID_ANY;
1214 	} else {
1215 		sep = str + strlen(str);
1216 		net = LNET_MKNET(SOCKLND, 0);
1217 		nf = libcfs_lnd2netstrfns(SOCKLND);
1218 		LASSERT(nf);
1219 	}
1220 
1221 	if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
1222 		return LNET_NID_ANY;
1223 
1224 	return LNET_MKNID(net, addr);
1225 }
1226 EXPORT_SYMBOL(libcfs_str2nid);
1227 
1228 char *
libcfs_id2str(struct lnet_process_id id)1229 libcfs_id2str(struct lnet_process_id id)
1230 {
1231 	char *str = libcfs_next_nidstring();
1232 
1233 	if (id.pid == LNET_PID_ANY) {
1234 		snprintf(str, LNET_NIDSTR_SIZE,
1235 			 "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
1236 		return str;
1237 	}
1238 
1239 	snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
1240 		 id.pid & LNET_PID_USERFLAG ? "U" : "",
1241 		 id.pid & ~LNET_PID_USERFLAG, libcfs_nid2str(id.nid));
1242 	return str;
1243 }
1244 EXPORT_SYMBOL(libcfs_id2str);
1245 
1246 int
libcfs_str2anynid(lnet_nid_t * nidp,const char * str)1247 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
1248 {
1249 	if (!strcmp(str, "*")) {
1250 		*nidp = LNET_NID_ANY;
1251 		return 1;
1252 	}
1253 
1254 	*nidp = libcfs_str2nid(str);
1255 	return *nidp != LNET_NID_ANY;
1256 }
1257 EXPORT_SYMBOL(libcfs_str2anynid);
1258