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 #define LNET_NIDSTR_COUNT 1024 /* # of nidstrings */
68 #define LNET_NIDSTR_SIZE 32 /* size of each one (see below for usage) */
70 static char libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
71 static int libcfs_nidstring_idx = 0;
74 static spinlock_t libcfs_nidstring_lock;
76 void libcfs_init_nidstrings (void)
78 spin_lock_init(&libcfs_nidstring_lock);
81 # define NIDSTR_LOCK(f) spin_lock_irqsave(&libcfs_nidstring_lock, f)
82 # define NIDSTR_UNLOCK(f) spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
84 # define NIDSTR_LOCK(f) (f=0) /* avoid unused var warnings */
85 # define NIDSTR_UNLOCK(f) (f=0)
89 libcfs_next_nidstring (void)
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;
101 NIDSTR_UNLOCK(flags);
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);
116 void (*nf_addr2str)(__u32 addr, char *str);
117 int (*nf_str2addr)(const char *str, int nob, __u32 *addr);
120 static struct netstrfns libcfs_netstrfns[] = {
121 {/* .nf_type */ LOLND,
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,
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,
168 /* .nf_modname */ "kgmlnd",
169 /* .nf_addr2str */ libcfs_hexnum_addr2str,
170 /* .nf_str2addr */ libcfs_num_str2addr},
171 {/* .nf_type */ MXLND,
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 */
185 const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
188 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
195 libcfs_ip_addr2str(__u32 addr, char *str)
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);
203 snprintf(str, LNET_NIDSTR_SIZE, "%s", he->h_name);
208 snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
209 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
210 (addr >> 8) & 0xff, addr & 0xff);
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
221 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
227 int n = nob; /* XscanfX */
230 if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
232 (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
233 (c & ~0xff) == 0 && (d & ~0xff) == 0) {
234 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
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')) {
244 LIBCFS_ALLOC(tmp, nob + 1);
248 memcpy(tmp, str, nob);
251 he = gethostbyname(tmp);
253 LIBCFS_FREE(tmp, nob);
256 __u32 ip = *(__u32 *)he->h_addr;
268 libcfs_decnum_addr2str(__u32 addr, char *str)
270 snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
274 libcfs_hexnum_addr2str(__u32 addr, char *str)
276 snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
280 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
285 if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
289 if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
293 if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
300 libcfs_lnd2netstrfns(int lnd)
305 for (i = 0; i < libcfs_nnetstrfns; i++)
306 if (lnd == libcfs_netstrfns[i].nf_type)
307 return &libcfs_netstrfns[i];
313 libcfs_name2netstrfns(const char *name)
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];
326 libcfs_isknown_lnd(int type)
328 return libcfs_lnd2netstrfns(type) != NULL;
332 libcfs_lnd2modname(int lnd)
334 struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
336 return (nf == NULL) ? NULL : nf->nf_modname;
340 libcfs_lnd2str(int lnd)
343 struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
348 str = libcfs_next_nidstring();
349 snprintf(str, LNET_NIDSTR_SIZE, "?%u?", lnd);
354 libcfs_str2lnd(const char *str)
356 struct netstrfns *nf = libcfs_name2netstrfns(str);
365 libcfs_net2str(__u32 net)
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();
373 snprintf(str, LNET_NIDSTR_SIZE, "<%u:%u>", lnd, num);
375 snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
377 snprintf(str, LNET_NIDSTR_SIZE, "%s%u", nf->nf_name, num);
383 libcfs_nid2str(lnet_nid_t nid)
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;
393 if (nid == LNET_NID_ANY)
394 return "LNET_NID_ANY";
396 nf = libcfs_lnd2netstrfns(lnd);
397 str = libcfs_next_nidstring();
400 snprintf(str, LNET_NIDSTR_SIZE, "%x@<%u:%u>", addr, lnd, nnum);
402 nf->nf_addr2str(addr, str);
405 snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
408 snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%u",
415 static struct netstrfns *
416 libcfs_str2net_internal(const char *str, __u32 *net)
418 struct netstrfns *nf = NULL;
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)))
430 if (i == libcfs_nnetstrfns)
433 nob = strlen(nf->nf_name);
435 if (strlen(str) == (unsigned int)nob) {
438 if (nf->nf_type == LOLND) /* net number not allowed */
443 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
444 i != (int)strlen(str))
448 *net = LNET_MKNET(nf->nf_type, netnum);
453 libcfs_str2net(const char *str)
457 if (libcfs_str2net_internal(str, &net) != NULL)
460 return LNET_NIDNET(LNET_NID_ANY);
464 libcfs_str2nid(const char *str)
466 const char *sep = strchr(str, '@');
467 struct netstrfns *nf;
472 nf = libcfs_str2net_internal(sep + 1, &net);
476 sep = str + strlen(str);
477 net = LNET_MKNET(SOCKLND, 0);
478 nf = libcfs_lnd2netstrfns(SOCKLND);
479 LASSERT (nf != NULL);
482 if (!nf->nf_str2addr(str, sep - str, &addr))
485 return LNET_MKNID(net, addr);
489 libcfs_id2str(lnet_process_id_t id)
491 char *str = libcfs_next_nidstring();
493 if (id.pid == LNET_PID_ANY) {
494 snprintf(str, LNET_NIDSTR_SIZE,
495 "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
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));
506 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
508 if (!strcmp(str, "*")) {
509 *nidp = LNET_NID_ANY;
513 *nidp = libcfs_str2nid(str);
514 return *nidp != LNET_NID_ANY;
519 libcfs_setnet0alias(int lnd)
521 struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
522 struct netstrfns *nf0 = &libcfs_netstrfns[libcfs_nnetstrfns - 1];
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 */
528 LASSERT (nf != NULL);
529 LASSERT (nf0->nf_type < 0);
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;
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__ */
552 libcfs_setnet0alias(int lnd)
554 LCONSOLE_ERROR_MSG(0x125, "Liblustre cannot interoperate with old "
555 "Portals.\nportals_compatibility must be set to "