Whamcloud - gitweb
a733b29d55c1c8f7b28285c4b4cd8b04302a4e71
[fs/lustre-release.git] / libcfs / libcfs / nidstrings.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see [sun.com URL with a
20  * copy of GPLv2].
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * libcfs/libcfs/nidstrings.c
37  *
38  * Author: Phil Schwan <phil@clusterfs.com>
39  */
40
41 #ifndef EXPORT_SYMTAB
42 # define EXPORT_SYMTAB
43 #endif
44
45 #define DEBUG_SUBSYSTEM S_LNET
46
47 #include <libcfs/libcfs.h>
48 #include <lnet/lnet.h>
49 #ifndef __KERNEL__
50 #ifdef HAVE_GETHOSTBYNAME
51 # include <netdb.h>
52 #endif
53 #endif
54
55 /* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
56  * consistent in all conversion functions.  Some code fragments are copied
57  * around for the sake of clarity...
58  */
59
60 /* CAVEAT EMPTOR! Racey temporary buffer allocation!
61  * Choose the number of nidstrings to support the MAXIMUM expected number of
62  * concurrent users.  If there are more, the returned string will be volatile.
63  * NB this number must allow for a process to be descheduled for a timeslice
64  * between getting its string and using it.
65  */
66
67 #define LNET_NIDSTR_COUNT  128     /* # of nidstrings */
68 #define LNET_NIDSTR_SIZE   32      /* size of each one (see below for usage) */
69
70 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
71 static int       libcfs_nidstring_idx = 0;
72
73 #ifdef __KERNEL__
74 static spinlock_t libcfs_nidstring_lock;
75
76 void libcfs_init_nidstrings (void)
77 {
78         spin_lock_init(&libcfs_nidstring_lock);
79 }
80
81 # define NIDSTR_LOCK(f)   spin_lock_irqsave(&libcfs_nidstring_lock, f)
82 # define NIDSTR_UNLOCK(f) spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
83 #else
84 # define NIDSTR_LOCK(f)   (f=0)                 /* avoid unused var warnings */
85 # define NIDSTR_UNLOCK(f) (f=0)
86 #endif
87
88 static char *
89 libcfs_next_nidstring (void)
90 {
91         char          *str;
92         unsigned long  flags;
93
94         NIDSTR_LOCK(flags);
95
96         str = libcfs_nidstrings[libcfs_nidstring_idx++];
97         if (libcfs_nidstring_idx ==
98             sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
99                 libcfs_nidstring_idx = 0;
100
101         NIDSTR_UNLOCK(flags);
102         return str;
103 }
104
105 static int  libcfs_lo_str2addr(const char *str, int nob, __u32 *addr);
106 static void libcfs_ip_addr2str(__u32 addr, char *str);
107 static int  libcfs_ip_str2addr(const char *str, int nob, __u32 *addr);
108 static void libcfs_decnum_addr2str(__u32 addr, char *str);
109 static void libcfs_hexnum_addr2str(__u32 addr, char *str);
110 static int  libcfs_num_str2addr(const char *str, int nob, __u32 *addr);
111
112 struct netstrfns {
113         int          nf_type;
114         char        *nf_name;
115         char        *nf_modname;
116         void       (*nf_addr2str)(__u32 addr, char *str);
117         int        (*nf_str2addr)(const char *str, int nob, __u32 *addr);
118 };
119
120 static struct netstrfns  libcfs_netstrfns[] = {
121         {/* .nf_type      */  LOLND,
122          /* .nf_name      */  "lo",
123          /* .nf_modname   */  "klolnd",
124          /* .nf_addr2str  */  libcfs_decnum_addr2str,
125          /* .nf_str2addr  */  libcfs_lo_str2addr},
126         {/* .nf_type      */  SOCKLND,
127          /* .nf_name      */  "tcp",
128          /* .nf_modname   */  "ksocklnd",
129          /* .nf_addr2str  */  libcfs_ip_addr2str,
130          /* .nf_str2addr  */  libcfs_ip_str2addr},
131         {/* .nf_type      */  O2IBLND,
132          /* .nf_name      */  "o2ib",
133          /* .nf_modname   */  "ko2iblnd",
134          /* .nf_addr2str  */  libcfs_ip_addr2str,
135          /* .nf_str2addr  */  libcfs_ip_str2addr},
136         {/* .nf_type      */  CIBLND,
137          /* .nf_name      */  "cib",
138          /* .nf_modname   */  "kciblnd",
139          /* .nf_addr2str  */  libcfs_ip_addr2str,
140          /* .nf_str2addr  */  libcfs_ip_str2addr},
141         {/* .nf_type      */  OPENIBLND,
142          /* .nf_name      */  "openib",
143          /* .nf_modname   */  "kopeniblnd",
144          /* .nf_addr2str  */  libcfs_ip_addr2str,
145          /* .nf_str2addr  */  libcfs_ip_str2addr},
146         {/* .nf_type      */  IIBLND,
147          /* .nf_name      */  "iib",
148          /* .nf_modname   */  "kiiblnd",
149          /* .nf_addr2str  */  libcfs_ip_addr2str,
150          /* .nf_str2addr  */  libcfs_ip_str2addr},
151         {/* .nf_type      */  VIBLND,
152          /* .nf_name      */  "vib",
153          /* .nf_modname   */  "kviblnd",
154          /* .nf_addr2str  */  libcfs_ip_addr2str,
155          /* .nf_str2addr  */  libcfs_ip_str2addr},
156         {/* .nf_type      */  RALND,
157          /* .nf_name      */  "ra",
158          /* .nf_modname   */  "kralnd",
159          /* .nf_addr2str  */  libcfs_ip_addr2str,
160          /* .nf_str2addr  */  libcfs_ip_str2addr},
161         {/* .nf_type      */  QSWLND,
162          /* .nf_name      */  "elan",
163          /* .nf_modname   */  "kqswlnd",
164          /* .nf_addr2str  */  libcfs_decnum_addr2str,
165          /* .nf_str2addr  */  libcfs_num_str2addr},
166         {/* .nf_type      */  GMLND,
167          /* .nf_name      */  "gm",
168          /* .nf_modname   */  "kgmlnd",
169          /* .nf_addr2str  */  libcfs_hexnum_addr2str,
170          /* .nf_str2addr  */  libcfs_num_str2addr},
171         {/* .nf_type      */  MXLND,
172          /* .nf_name      */  "mx",
173          /* .nf_modname   */  "kmxlnd",
174          /* .nf_addr2str  */  libcfs_ip_addr2str,
175          /* .nf_str2addr  */  libcfs_ip_str2addr},
176         {/* .nf_type      */  PTLLND,
177          /* .nf_name      */  "ptl",
178          /* .nf_modname   */  "kptllnd",
179          /* .nf_addr2str  */  libcfs_decnum_addr2str,
180          /* .nf_str2addr  */  libcfs_num_str2addr},
181         /* placeholder for net0 alias.  It MUST BE THE LAST ENTRY */
182         {/* .nf_type      */  -1},
183 };
184
185 const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
186
187 int
188 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
189 {
190         *addr = 0;
191         return 1;
192 }
193
194 void
195 libcfs_ip_addr2str(__u32 addr, char *str)
196 {
197 #if 0   /* never lookup */
198 #if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
199         __u32           netip = htonl(addr);
200         struct hostent *he = gethostbyaddr(&netip, sizeof(netip), AF_INET);
201
202         if (he != NULL) {
203                 snprintf(str, LNET_NIDSTR_SIZE, "%s", he->h_name);
204                 return;
205         }
206 #endif
207 #endif
208         snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
209                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
210                  (addr >> 8) & 0xff, addr & 0xff);
211 }
212
213 /* CAVEAT EMPTOR XscanfX
214  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
215  * sscanf may return immediately if it sees the terminating '0' in a string, so
216  * I initialise the %n variable to the expected length.  If sscanf sets it;
217  * fine, if it doesn't, then the scan ended at the end of the string, which is
218  * fine too :) */
219
220 int
221 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
222 {
223         int   a;
224         int   b;
225         int   c;
226         int   d;
227         int   n = nob;                          /* XscanfX */
228
229         /* numeric IP? */
230         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
231             n == nob &&
232             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
233             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
234                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
235                 return 1;
236         }
237
238 #if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
239         /* known hostname? */
240         if (('a' <= str[0] && str[0] <= 'z') ||
241             ('A' <= str[0] && str[0] <= 'Z')) {
242                 char *tmp;
243
244                 LIBCFS_ALLOC(tmp, nob + 1);
245                 if (tmp != NULL) {
246                         struct hostent *he;
247
248                         memcpy(tmp, str, nob);
249                         tmp[nob] = 0;
250
251                         he = gethostbyname(tmp);
252
253                         LIBCFS_FREE(tmp, nob);
254
255                         if (he != NULL) {
256                                 __u32 ip = *(__u32 *)he->h_addr;
257
258                                 *addr = ntohl(ip);
259                                 return 1;
260                         }
261                 }
262         }
263 #endif
264         return 0;
265 }
266
267 void
268 libcfs_decnum_addr2str(__u32 addr, char *str)
269 {
270         snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
271 }
272
273 void
274 libcfs_hexnum_addr2str(__u32 addr, char *str)
275 {
276         snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
277 }
278
279 int
280 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
281 {
282         int     n;
283
284         n = nob;
285         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
286                 return 1;
287
288         n = nob;
289         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
290                 return 1;
291
292         n = nob;
293         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
294                 return 1;
295
296         return 0;
297 }
298
299 struct netstrfns *
300 libcfs_lnd2netstrfns(int lnd)
301 {
302         int    i;
303
304         if (lnd >= 0)
305                 for (i = 0; i < libcfs_nnetstrfns; i++)
306                         if (lnd == libcfs_netstrfns[i].nf_type)
307                                 return &libcfs_netstrfns[i];
308
309         return NULL;
310 }
311
312 struct netstrfns *
313 libcfs_name2netstrfns(const char *name)
314 {
315         int    i;
316
317         for (i = 0; i < libcfs_nnetstrfns; i++)
318                 if (libcfs_netstrfns[i].nf_type >= 0 &&
319                     !strcmp(libcfs_netstrfns[i].nf_name, name))
320                         return &libcfs_netstrfns[i];
321
322         return NULL;
323 }
324
325 int
326 libcfs_isknown_lnd(int type)
327 {
328         return libcfs_lnd2netstrfns(type) != NULL;
329 }
330
331 char *
332 libcfs_lnd2modname(int lnd)
333 {
334         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
335
336         return (nf == NULL) ? NULL : nf->nf_modname;
337 }
338
339 char *
340 libcfs_lnd2str(int lnd)
341 {
342         char           *str;
343         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
344
345         if (nf != NULL)
346                 return nf->nf_name;
347
348         str = libcfs_next_nidstring();
349         snprintf(str, LNET_NIDSTR_SIZE, "?%u?", lnd);
350         return str;
351 }
352
353 int
354 libcfs_str2lnd(const char *str)
355 {
356         struct netstrfns *nf = libcfs_name2netstrfns(str);
357
358         if (nf != NULL)
359                 return nf->nf_type;
360
361         return -1;
362 }
363
364 char *
365 libcfs_net2str(__u32 net)
366 {
367         int               lnd = LNET_NETTYP(net);
368         int               num = LNET_NETNUM(net);
369         struct netstrfns *nf  = libcfs_lnd2netstrfns(lnd);
370         char             *str = libcfs_next_nidstring();
371
372         if (nf == NULL)
373                 snprintf(str, LNET_NIDSTR_SIZE, "<%u:%u>", lnd, num);
374         else if (num == 0)
375                 snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
376         else
377                 snprintf(str, LNET_NIDSTR_SIZE, "%s%u", nf->nf_name, num);
378
379         return str;
380 }
381
382 char *
383 libcfs_nid2str(lnet_nid_t nid)
384 {
385         __u32             addr = LNET_NIDADDR(nid);
386         __u32             net = LNET_NIDNET(nid);
387         int               lnd = LNET_NETTYP(net);
388         int               nnum = LNET_NETNUM(net);
389         struct netstrfns *nf;
390         char             *str;
391         int               nob;
392
393         if (nid == LNET_NID_ANY)
394                 return "LNET_NID_ANY";
395
396         nf = libcfs_lnd2netstrfns(lnd);
397         str = libcfs_next_nidstring();
398
399         if (nf == NULL)
400                 snprintf(str, LNET_NIDSTR_SIZE, "%x@<%u:%u>", addr, lnd, nnum);
401         else {
402                 nf->nf_addr2str(addr, str);
403                 nob = strlen(str);
404                 if (nnum == 0)
405                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
406                                  nf->nf_name);
407                 else
408                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%u",
409                                  nf->nf_name, nnum);
410         }
411
412         return str;
413 }
414
415 static struct netstrfns *
416 libcfs_str2net_internal(const char *str, __u32 *net)
417 {
418         struct netstrfns *nf;
419         int               nob;
420         int               netnum;
421         int               i;
422
423         for (i = 0; i < libcfs_nnetstrfns; i++) {
424                 nf = &libcfs_netstrfns[i];
425                 if (nf->nf_type >= 0 &&
426                     !strncmp(str, nf->nf_name, strlen(nf->nf_name)))
427                         break;
428         }
429
430         if (i == libcfs_nnetstrfns)
431                 return NULL;
432
433         nob = strlen(nf->nf_name);
434
435         if (strlen(str) == (unsigned int)nob) {
436                 netnum = 0;
437         } else {
438                 if (nf->nf_type == LOLND) /* net number not allowed */
439                         return NULL;
440
441                 str += nob;
442                 i = strlen(str);
443                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
444                     i != (int)strlen(str))
445                         return NULL;
446         }
447
448         *net = LNET_MKNET(nf->nf_type, netnum);
449         return nf;
450 }
451
452 __u32
453 libcfs_str2net(const char *str)
454 {
455         __u32  net;
456
457         if (libcfs_str2net_internal(str, &net) != NULL)
458                 return net;
459
460         return LNET_NIDNET(LNET_NID_ANY);
461 }
462
463 lnet_nid_t
464 libcfs_str2nid(const char *str)
465 {
466         const char       *sep = strchr(str, '@');
467         struct netstrfns *nf;
468         __u32             net;
469         __u32             addr;
470
471         if (sep != NULL) {
472                 nf = libcfs_str2net_internal(sep + 1, &net);
473                 if (nf == NULL)
474                         return LNET_NID_ANY;
475         } else {
476                 sep = str + strlen(str);
477                 net = LNET_MKNET(SOCKLND, 0);
478                 nf = libcfs_lnd2netstrfns(SOCKLND);
479                 LASSERT (nf != NULL);
480         }
481
482         if (!nf->nf_str2addr(str, sep - str, &addr))
483                 return LNET_NID_ANY;
484
485         return LNET_MKNID(net, addr);
486 }
487
488 char *
489 libcfs_id2str(lnet_process_id_t id)
490 {
491         char *str = libcfs_next_nidstring();
492
493         if (id.pid == LNET_PID_ANY) {
494                 snprintf(str, LNET_NIDSTR_SIZE,
495                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
496                 return str;
497         }
498
499         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
500                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
501                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
502         return str;
503 }
504
505 int
506 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
507 {
508         if (!strcmp(str, "*")) {
509                 *nidp = LNET_NID_ANY;
510                 return 1;
511         }
512
513         *nidp = libcfs_str2nid(str);
514         return *nidp != LNET_NID_ANY;
515 }
516
517 #ifdef __KERNEL__
518 void
519 libcfs_setnet0alias(int lnd)
520 {
521         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
522         struct netstrfns *nf0 = &libcfs_netstrfns[libcfs_nnetstrfns - 1];
523
524         /* Ghastly hack to allow LNET to inter-operate with portals.
525          * NET type 0 becomes an alias for whatever local network we have, and
526          * this assignment here means we can parse and print its NIDs */
527
528         LASSERT (nf != NULL);
529         LASSERT (nf0->nf_type < 0);
530
531         nf0->nf_name = "zero";//nf->nf_name;
532         nf0->nf_modname = nf->nf_modname;
533         nf0->nf_addr2str = nf->nf_addr2str;
534         nf0->nf_str2addr = nf->nf_str2addr;
535         mb();
536         nf0->nf_type = 0;
537 }
538
539 EXPORT_SYMBOL(libcfs_isknown_lnd);
540 EXPORT_SYMBOL(libcfs_lnd2modname);
541 EXPORT_SYMBOL(libcfs_lnd2str);
542 EXPORT_SYMBOL(libcfs_str2lnd);
543 EXPORT_SYMBOL(libcfs_net2str);
544 EXPORT_SYMBOL(libcfs_nid2str);
545 EXPORT_SYMBOL(libcfs_str2net);
546 EXPORT_SYMBOL(libcfs_str2nid);
547 EXPORT_SYMBOL(libcfs_id2str);
548 EXPORT_SYMBOL(libcfs_str2anynid);
549 EXPORT_SYMBOL(libcfs_setnet0alias);
550 #else  /* __KERNEL__ */
551 void
552 libcfs_setnet0alias(int lnd)
553 {
554         LCONSOLE_ERROR_MSG(0x125, "Liblustre cannot interoperate with old "
555                            "Portals.\nportals_compatibility must be set to "
556                            "'none'.\n");
557 }
558 #endif