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