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