1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
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
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lnet/libcfs/nidstrings.c
38 * Author: Phil Schwan <phil@clusterfs.com>
42 # define EXPORT_SYMTAB
45 #define DEBUG_SUBSYSTEM S_LNET
47 #include <lnet/lnet.h>
48 #include <libcfs/kp30.h>
50 #ifdef HAVE_GETHOSTBYNAME
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...
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.
67 static char libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
68 static int libcfs_nidstring_idx = 0;
71 static spinlock_t libcfs_nidstring_lock;
73 void libcfs_init_nidstrings (void)
75 spin_lock_init(&libcfs_nidstring_lock);
78 # define NIDSTR_LOCK(f) spin_lock_irqsave(&libcfs_nidstring_lock, f)
79 # define NIDSTR_UNLOCK(f) spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
81 # define NIDSTR_LOCK(f) (f=0) /* avoid unused var warnings */
82 # define NIDSTR_UNLOCK(f) (f=0)
86 libcfs_next_nidstring (void)
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;
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);
113 void (*nf_addr2str)(__u32 addr, char *str);
114 int (*nf_str2addr)(const char *str, int nob, __u32 *addr);
117 static struct netstrfns libcfs_netstrfns[] = {
118 {/* .nf_type */ LOLND,
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,
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,
165 /* .nf_modname */ "kgmlnd",
166 /* .nf_addr2str */ libcfs_hexnum_addr2str,
167 /* .nf_str2addr */ libcfs_num_str2addr},
168 {/* .nf_type */ MXLND,
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 */
182 const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
185 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
192 libcfs_ip_addr2str(__u32 addr, char *str)
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);
200 snprintf(str, LNET_NIDSTR_SIZE, "%s", he->h_name);
205 snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
206 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
207 (addr >> 8) & 0xff, addr & 0xff);
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
218 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
224 int n = nob; /* XscanfX */
227 if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
229 (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
230 (c & ~0xff) == 0 && (d & ~0xff) == 0) {
231 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
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')) {
241 LIBCFS_ALLOC(tmp, nob + 1);
245 memcpy(tmp, str, nob);
248 he = gethostbyname(tmp);
250 LIBCFS_FREE(tmp, nob);
253 __u32 ip = *(__u32 *)he->h_addr;
265 libcfs_decnum_addr2str(__u32 addr, char *str)
267 snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
271 libcfs_hexnum_addr2str(__u32 addr, char *str)
273 snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
277 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
282 if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
286 if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
290 if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
297 libcfs_lnd2netstrfns(int lnd)
302 for (i = 0; i < libcfs_nnetstrfns; i++)
303 if (lnd == libcfs_netstrfns[i].nf_type)
304 return &libcfs_netstrfns[i];
310 libcfs_name2netstrfns(const char *name)
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];
323 libcfs_isknown_lnd(int type)
325 return libcfs_lnd2netstrfns(type) != NULL;
329 libcfs_lnd2modname(int lnd)
331 struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
333 return (nf == NULL) ? NULL : nf->nf_modname;
337 libcfs_lnd2str(int lnd)
340 struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
345 str = libcfs_next_nidstring();
346 snprintf(str, LNET_NIDSTR_SIZE, "?%u?", lnd);
351 libcfs_str2lnd(const char *str)
353 struct netstrfns *nf = libcfs_name2netstrfns(str);
362 libcfs_net2str(__u32 net)
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();
370 snprintf(str, LNET_NIDSTR_SIZE, "<%u:%u>", lnd, num);
372 snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
374 snprintf(str, LNET_NIDSTR_SIZE, "%s%u", nf->nf_name, num);
380 libcfs_nid2str(lnet_nid_t nid)
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;
390 if (nid == LNET_NID_ANY)
391 return "LNET_NID_ANY";
393 nf = libcfs_lnd2netstrfns(lnd);
394 str = libcfs_next_nidstring();
397 snprintf(str, LNET_NIDSTR_SIZE, "%x@<%u:%u>", addr, lnd, nnum);
399 nf->nf_addr2str(addr, str);
402 snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
405 snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%u",
412 static struct netstrfns *
413 libcfs_str2net_internal(const char *str, __u32 *net)
415 struct netstrfns *nf = NULL;
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)))
427 if (i == libcfs_nnetstrfns)
430 nob = strlen(nf->nf_name);
432 if (strlen(str) == (unsigned int)nob) {
435 if (nf->nf_type == LOLND) /* net number not allowed */
440 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
441 i != (int)strlen(str))
445 *net = LNET_MKNET(nf->nf_type, netnum);
450 libcfs_str2net(const char *str)
454 if (libcfs_str2net_internal(str, &net) != NULL)
457 return LNET_NIDNET(LNET_NID_ANY);
461 libcfs_str2nid(const char *str)
463 const char *sep = strchr(str, '@');
464 struct netstrfns *nf;
469 nf = libcfs_str2net_internal(sep + 1, &net);
473 sep = str + strlen(str);
474 net = LNET_MKNET(SOCKLND, 0);
475 nf = libcfs_lnd2netstrfns(SOCKLND);
476 LASSERT (nf != NULL);
479 if (!nf->nf_str2addr(str, sep - str, &addr))
482 return LNET_MKNID(net, addr);
486 libcfs_id2str(lnet_process_id_t id)
488 char *str = libcfs_next_nidstring();
490 if (id.pid == LNET_PID_ANY) {
491 snprintf(str, LNET_NIDSTR_SIZE,
492 "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
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));
503 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
505 if (!strcmp(str, "*")) {
506 *nidp = LNET_NID_ANY;
510 *nidp = libcfs_str2nid(str);
511 return *nidp != LNET_NID_ANY;
516 libcfs_setnet0alias(int lnd)
518 struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
519 struct netstrfns *nf0 = &libcfs_netstrfns[libcfs_nnetstrfns - 1];
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 */
525 LASSERT (nf != NULL);
526 LASSERT (nf0->nf_type < 0);
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;
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__ */
549 libcfs_setnet0alias(int lnd)
551 LCONSOLE_ERROR_MSG(0x125, "Liblustre cannot interoperate with old "
552 "Portals.\nportals_compatibility must be set to "