Whamcloud - gitweb
Revert "b=23913 fix "ASSERTION(!cfs_list_empty(&dquot->dq_hash)) failed""
[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  * 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
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
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  * lnet/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 <lnet/lnet.h>
48 #include <libcfs/kp30.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 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
68 static int       libcfs_nidstring_idx = 0;
69
70 #ifdef __KERNEL__
71 static spinlock_t libcfs_nidstring_lock;
72
73 void libcfs_init_nidstrings (void)
74 {
75         spin_lock_init(&libcfs_nidstring_lock);
76 }
77
78 # define NIDSTR_LOCK(f)   spin_lock_irqsave(&libcfs_nidstring_lock, f)
79 # define NIDSTR_UNLOCK(f) spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
80 #else
81 # define NIDSTR_LOCK(f)   (f=0)                 /* avoid unused var warnings */
82 # define NIDSTR_UNLOCK(f) (f=0)
83 #endif
84
85 static char *
86 libcfs_next_nidstring (void)
87 {
88         char          *str;
89         unsigned long  flags;
90
91         NIDSTR_LOCK(flags);
92
93         str = libcfs_nidstrings[libcfs_nidstring_idx++];
94         if (libcfs_nidstring_idx ==
95             sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
96                 libcfs_nidstring_idx = 0;
97
98         NIDSTR_UNLOCK(flags);
99         return str;
100 }
101
102 static int  libcfs_lo_str2addr(const char *str, int nob, __u32 *addr);
103 static void libcfs_ip_addr2str(__u32 addr, char *str);
104 static int  libcfs_ip_str2addr(const char *str, int nob, __u32 *addr);
105 static void libcfs_decnum_addr2str(__u32 addr, char *str);
106 static void libcfs_hexnum_addr2str(__u32 addr, char *str);
107 static int  libcfs_num_str2addr(const char *str, int nob, __u32 *addr);
108
109 struct netstrfns {
110         int          nf_type;
111         char        *nf_name;
112         char        *nf_modname;
113         void       (*nf_addr2str)(__u32 addr, char *str);
114         int        (*nf_str2addr)(const char *str, int nob, __u32 *addr);
115 };
116
117 static struct netstrfns  libcfs_netstrfns[] = {
118         {/* .nf_type      */  LOLND,
119          /* .nf_name      */  "lo",
120          /* .nf_modname   */  "klolnd",
121          /* .nf_addr2str  */  libcfs_decnum_addr2str,
122          /* .nf_str2addr  */  libcfs_lo_str2addr},
123         {/* .nf_type      */  SOCKLND,
124          /* .nf_name      */  "tcp",
125          /* .nf_modname   */  "ksocklnd",
126          /* .nf_addr2str  */  libcfs_ip_addr2str,
127          /* .nf_str2addr  */  libcfs_ip_str2addr},
128         {/* .nf_type      */  O2IBLND,
129          /* .nf_name      */  "o2ib",
130          /* .nf_modname   */  "ko2iblnd",
131          /* .nf_addr2str  */  libcfs_ip_addr2str,
132          /* .nf_str2addr  */  libcfs_ip_str2addr},
133         {/* .nf_type      */  CIBLND,
134          /* .nf_name      */  "cib",
135          /* .nf_modname   */  "kciblnd",
136          /* .nf_addr2str  */  libcfs_ip_addr2str,
137          /* .nf_str2addr  */  libcfs_ip_str2addr},
138         {/* .nf_type      */  OPENIBLND,
139          /* .nf_name      */  "openib",
140          /* .nf_modname   */  "kopeniblnd",
141          /* .nf_addr2str  */  libcfs_ip_addr2str,
142          /* .nf_str2addr  */  libcfs_ip_str2addr},
143         {/* .nf_type      */  IIBLND,
144          /* .nf_name      */  "iib",
145          /* .nf_modname   */  "kiiblnd",
146          /* .nf_addr2str  */  libcfs_ip_addr2str,
147          /* .nf_str2addr  */  libcfs_ip_str2addr},
148         {/* .nf_type      */  VIBLND,
149          /* .nf_name      */  "vib",
150          /* .nf_modname   */  "kviblnd",
151          /* .nf_addr2str  */  libcfs_ip_addr2str,
152          /* .nf_str2addr  */  libcfs_ip_str2addr},
153         {/* .nf_type      */  RALND,
154          /* .nf_name      */  "ra",
155          /* .nf_modname   */  "kralnd",
156          /* .nf_addr2str  */  libcfs_ip_addr2str,
157          /* .nf_str2addr  */  libcfs_ip_str2addr},
158         {/* .nf_type      */  QSWLND,
159          /* .nf_name      */  "elan",
160          /* .nf_modname   */  "kqswlnd",
161          /* .nf_addr2str  */  libcfs_decnum_addr2str,
162          /* .nf_str2addr  */  libcfs_num_str2addr},
163         {/* .nf_type      */  GMLND,
164          /* .nf_name      */  "gm",
165          /* .nf_modname   */  "kgmlnd",
166          /* .nf_addr2str  */  libcfs_hexnum_addr2str,
167          /* .nf_str2addr  */  libcfs_num_str2addr},
168         {/* .nf_type      */  MXLND,
169          /* .nf_name      */  "mx",
170          /* .nf_modname   */  "kmxlnd",
171          /* .nf_addr2str  */  libcfs_ip_addr2str,
172          /* .nf_str2addr  */  libcfs_ip_str2addr},
173         {/* .nf_type      */  PTLLND,
174          /* .nf_name      */  "ptl",
175          /* .nf_modname   */  "kptllnd",
176          /* .nf_addr2str  */  libcfs_decnum_addr2str,
177          /* .nf_str2addr  */  libcfs_num_str2addr},
178         /* placeholder for net0 alias.  It MUST BE THE LAST ENTRY */
179         {/* .nf_type      */  -1},
180 };
181
182 const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
183
184 int
185 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
186 {
187         *addr = 0;
188         return 1;
189 }
190
191 void
192 libcfs_ip_addr2str(__u32 addr, char *str)
193 {
194 #if 0   /* never lookup */
195 #if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
196         __u32           netip = htonl(addr);
197         struct hostent *he = gethostbyaddr(&netip, sizeof(netip), AF_INET);
198
199         if (he != NULL) {
200                 snprintf(str, LNET_NIDSTR_SIZE, "%s", he->h_name);
201                 return;
202         }
203 #endif
204 #endif
205         snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
206                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
207                  (addr >> 8) & 0xff, addr & 0xff);
208 }
209
210 /* CAVEAT EMPTOR XscanfX
211  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
212  * sscanf may return immediately if it sees the terminating '0' in a string, so
213  * I initialise the %n variable to the expected length.  If sscanf sets it;
214  * fine, if it doesn't, then the scan ended at the end of the string, which is
215  * fine too :) */
216
217 int
218 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
219 {
220         int   a;
221         int   b;
222         int   c;
223         int   d;
224         int   n = nob;                          /* XscanfX */
225
226         /* numeric IP? */
227         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
228             n == nob &&
229             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
230             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
231                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
232                 return 1;
233         }
234
235 #if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
236         /* known hostname? */
237         if (('a' <= str[0] && str[0] <= 'z') ||
238             ('A' <= str[0] && str[0] <= 'Z')) {
239                 char *tmp;
240
241                 LIBCFS_ALLOC(tmp, nob + 1);
242                 if (tmp != NULL) {
243                         struct hostent *he;
244
245                         memcpy(tmp, str, nob);
246                         tmp[nob] = 0;
247
248                         he = gethostbyname(tmp);
249
250                         LIBCFS_FREE(tmp, nob);
251
252                         if (he != NULL) {
253                                 __u32 ip = *(__u32 *)he->h_addr;
254
255                                 *addr = ntohl(ip);
256                                 return 1;
257                         }
258                 }
259         }
260 #endif
261         return 0;
262 }
263
264 void
265 libcfs_decnum_addr2str(__u32 addr, char *str)
266 {
267         snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
268 }
269
270 void
271 libcfs_hexnum_addr2str(__u32 addr, char *str)
272 {
273         snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
274 }
275
276 int
277 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
278 {
279         int     n;
280
281         n = nob;
282         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
283                 return 1;
284
285         n = nob;
286         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
287                 return 1;
288
289         n = nob;
290         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
291                 return 1;
292
293         return 0;
294 }
295
296 struct netstrfns *
297 libcfs_lnd2netstrfns(int lnd)
298 {
299         int    i;
300
301         if (lnd >= 0)
302                 for (i = 0; i < libcfs_nnetstrfns; i++)
303                         if (lnd == libcfs_netstrfns[i].nf_type)
304                                 return &libcfs_netstrfns[i];
305
306         return NULL;
307 }
308
309 struct netstrfns *
310 libcfs_name2netstrfns(const char *name)
311 {
312         int    i;
313
314         for (i = 0; i < libcfs_nnetstrfns; i++)
315                 if (libcfs_netstrfns[i].nf_type >= 0 &&
316                     !strcmp(libcfs_netstrfns[i].nf_name, name))
317                         return &libcfs_netstrfns[i];
318
319         return NULL;
320 }
321
322 int
323 libcfs_isknown_lnd(int type)
324 {
325         return libcfs_lnd2netstrfns(type) != NULL;
326 }
327
328 char *
329 libcfs_lnd2modname(int lnd)
330 {
331         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
332
333         return (nf == NULL) ? NULL : nf->nf_modname;
334 }
335
336 char *
337 libcfs_lnd2str(int lnd)
338 {
339         char           *str;
340         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
341
342         if (nf != NULL)
343                 return nf->nf_name;
344
345         str = libcfs_next_nidstring();
346         snprintf(str, LNET_NIDSTR_SIZE, "?%u?", lnd);
347         return str;
348 }
349
350 int
351 libcfs_str2lnd(const char *str)
352 {
353         struct netstrfns *nf = libcfs_name2netstrfns(str);
354
355         if (nf != NULL)
356                 return nf->nf_type;
357
358         return -1;
359 }
360
361 char *
362 libcfs_net2str(__u32 net)
363 {
364         int               lnd = LNET_NETTYP(net);
365         int               num = LNET_NETNUM(net);
366         struct netstrfns *nf  = libcfs_lnd2netstrfns(lnd);
367         char             *str = libcfs_next_nidstring();
368
369         if (nf == NULL)
370                 snprintf(str, LNET_NIDSTR_SIZE, "<%u:%u>", lnd, num);
371         else if (num == 0)
372                 snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
373         else
374                 snprintf(str, LNET_NIDSTR_SIZE, "%s%u", nf->nf_name, num);
375
376         return str;
377 }
378
379 char *
380 libcfs_nid2str(lnet_nid_t nid)
381 {
382         __u32             addr = LNET_NIDADDR(nid);
383         __u32             net = LNET_NIDNET(nid);
384         int               lnd = LNET_NETTYP(net);
385         int               nnum = LNET_NETNUM(net);
386         struct netstrfns *nf;
387         char             *str;
388         int               nob;
389
390         if (nid == LNET_NID_ANY)
391                 return "LNET_NID_ANY";
392
393         nf = libcfs_lnd2netstrfns(lnd);
394         str = libcfs_next_nidstring();
395
396         if (nf == NULL)
397                 snprintf(str, LNET_NIDSTR_SIZE, "%x@<%u:%u>", addr, lnd, nnum);
398         else {
399                 nf->nf_addr2str(addr, str);
400                 nob = strlen(str);
401                 if (nnum == 0)
402                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
403                                  nf->nf_name);
404                 else
405                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%u",
406                                  nf->nf_name, nnum);
407         }
408
409         return str;
410 }
411
412 static struct netstrfns *
413 libcfs_str2net_internal(const char *str, __u32 *net)
414 {
415         struct netstrfns *nf = NULL;
416         int               nob;
417         int               netnum;
418         int               i;
419
420         for (i = 0; i < libcfs_nnetstrfns; i++) {
421                 nf = &libcfs_netstrfns[i];
422                 if (nf->nf_type >= 0 &&
423                     !strncmp(str, nf->nf_name, strlen(nf->nf_name)))
424                         break;
425         }
426
427         if (i == libcfs_nnetstrfns)
428                 return NULL;
429
430         nob = strlen(nf->nf_name);
431
432         if (strlen(str) == (unsigned int)nob) {
433                 netnum = 0;
434         } else {
435                 if (nf->nf_type == LOLND) /* net number not allowed */
436                         return NULL;
437
438                 str += nob;
439                 i = strlen(str);
440                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
441                     i != (int)strlen(str))
442                         return NULL;
443         }
444
445         *net = LNET_MKNET(nf->nf_type, netnum);
446         return nf;
447 }
448
449 __u32
450 libcfs_str2net(const char *str)
451 {
452         __u32  net;
453
454         if (libcfs_str2net_internal(str, &net) != NULL)
455                 return net;
456
457         return LNET_NIDNET(LNET_NID_ANY);
458 }
459
460 lnet_nid_t
461 libcfs_str2nid(const char *str)
462 {
463         const char       *sep = strchr(str, '@');
464         struct netstrfns *nf;
465         __u32             net;
466         __u32             addr;
467
468         if (sep != NULL) {
469                 nf = libcfs_str2net_internal(sep + 1, &net);
470                 if (nf == NULL)
471                         return LNET_NID_ANY;
472         } else {
473                 sep = str + strlen(str);
474                 net = LNET_MKNET(SOCKLND, 0);
475                 nf = libcfs_lnd2netstrfns(SOCKLND);
476                 LASSERT (nf != NULL);
477         }
478
479         if (!nf->nf_str2addr(str, sep - str, &addr))
480                 return LNET_NID_ANY;
481
482         return LNET_MKNID(net, addr);
483 }
484
485 char *
486 libcfs_id2str(lnet_process_id_t id)
487 {
488         char *str = libcfs_next_nidstring();
489
490         if (id.pid == LNET_PID_ANY) {
491                 snprintf(str, LNET_NIDSTR_SIZE,
492                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
493                 return str;
494         }
495
496         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
497                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
498                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
499         return str;
500 }
501
502 int
503 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
504 {
505         if (!strcmp(str, "*")) {
506                 *nidp = LNET_NID_ANY;
507                 return 1;
508         }
509
510         *nidp = libcfs_str2nid(str);
511         return *nidp != LNET_NID_ANY;
512 }
513
514 #ifdef __KERNEL__
515 void
516 libcfs_setnet0alias(int lnd)
517 {
518         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
519         struct netstrfns *nf0 = &libcfs_netstrfns[libcfs_nnetstrfns - 1];
520
521         /* Ghastly hack to allow LNET to inter-operate with portals.
522          * NET type 0 becomes an alias for whatever local network we have, and
523          * this assignment here means we can parse and print its NIDs */
524
525         LASSERT (nf != NULL);
526         LASSERT (nf0->nf_type < 0);
527
528         nf0->nf_name = "zero";//nf->nf_name;
529         nf0->nf_modname = nf->nf_modname;
530         nf0->nf_addr2str = nf->nf_addr2str;
531         nf0->nf_str2addr = nf->nf_str2addr;
532         mb();
533         nf0->nf_type = 0;
534 }
535
536 EXPORT_SYMBOL(libcfs_isknown_lnd);
537 EXPORT_SYMBOL(libcfs_lnd2modname);
538 EXPORT_SYMBOL(libcfs_lnd2str);
539 EXPORT_SYMBOL(libcfs_str2lnd);
540 EXPORT_SYMBOL(libcfs_net2str);
541 EXPORT_SYMBOL(libcfs_nid2str);
542 EXPORT_SYMBOL(libcfs_str2net);
543 EXPORT_SYMBOL(libcfs_str2nid);
544 EXPORT_SYMBOL(libcfs_id2str);
545 EXPORT_SYMBOL(libcfs_str2anynid);
546 EXPORT_SYMBOL(libcfs_setnet0alias);
547 #else  /* __KERNEL__ */
548 void
549 libcfs_setnet0alias(int lnd)
550 {
551         LCONSOLE_ERROR_MSG(0x125, "Liblustre cannot interoperate with old "
552                            "Portals.\nportals_compatibility must be set to "
553                            "'none'.\n");
554 }
555 #endif