linux/drivers/staging/lustre/lustre/libcfs/nidstrings.c
<<
>>
Prefs
   1/*
   2 * GPL HEADER START
   3 *
   4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 only,
   8 * as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License version 2 for more details (a copy is included
  14 * in the LICENSE file that accompanied this code).
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * version 2 along with this program; If not, see
  18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
  19 *
  20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  21 * CA 95054 USA or visit www.sun.com if you need additional information or
  22 * have any questions.
  23 *
  24 * GPL HEADER END
  25 */
  26/*
  27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  28 * Use is subject to license terms.
  29 *
  30 * Copyright (c) 2011, 2012, Intel Corporation.
  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#define DEBUG_SUBSYSTEM S_LNET
  42
  43#include "../../include/linux/libcfs/libcfs.h"
  44#include "../../include/linux/lnet/lnet.h"
  45
  46/* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
  47 * consistent in all conversion functions.  Some code fragments are copied
  48 * around for the sake of clarity...
  49 */
  50
  51/* CAVEAT EMPTOR! Racey temporary buffer allocation!
  52 * Choose the number of nidstrings to support the MAXIMUM expected number of
  53 * concurrent users.  If there are more, the returned string will be volatile.
  54 * NB this number must allow for a process to be descheduled for a timeslice
  55 * between getting its string and using it.
  56 */
  57
  58static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
  59static int       libcfs_nidstring_idx;
  60
  61static spinlock_t libcfs_nidstring_lock;
  62
  63void libcfs_init_nidstrings(void)
  64{
  65        spin_lock_init(&libcfs_nidstring_lock);
  66}
  67
  68static char *
  69libcfs_next_nidstring(void)
  70{
  71        char      *str;
  72        unsigned long  flags;
  73
  74        spin_lock_irqsave(&libcfs_nidstring_lock, flags);
  75
  76        str = libcfs_nidstrings[libcfs_nidstring_idx++];
  77        if (libcfs_nidstring_idx == ARRAY_SIZE(libcfs_nidstrings))
  78                libcfs_nidstring_idx = 0;
  79
  80        spin_unlock_irqrestore(&libcfs_nidstring_lock, flags);
  81        return str;
  82}
  83
  84static int libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
  85{
  86        *addr = 0;
  87        return 1;
  88}
  89
  90static void libcfs_ip_addr2str(__u32 addr, char *str)
  91{
  92        snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
  93                 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
  94                 (addr >> 8) & 0xff, addr & 0xff);
  95}
  96
  97static int libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
  98{
  99        unsigned int    a;
 100        unsigned int    b;
 101        unsigned int    c;
 102        unsigned int    d;
 103        int             n = nob; /* XscanfX */
 104
 105        /* numeric IP? */
 106        if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
 107            n == nob &&
 108            (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
 109            (c & ~0xff) == 0 && (d & ~0xff) == 0) {
 110                *addr = ((a<<24)|(b<<16)|(c<<8)|d);
 111                return 1;
 112        }
 113
 114        return 0;
 115}
 116
 117static void libcfs_decnum_addr2str(__u32 addr, char *str)
 118{
 119        snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
 120}
 121
 122static void libcfs_hexnum_addr2str(__u32 addr, char *str)
 123{
 124        snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
 125}
 126
 127static int libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
 128{
 129        int     n;
 130
 131        n = nob;
 132        if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
 133                return 1;
 134
 135        n = nob;
 136        if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
 137                return 1;
 138
 139        n = nob;
 140        if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
 141                return 1;
 142
 143        return 0;
 144}
 145
 146/**
 147 * Nf_parse_addrlist method for networks using numeric addresses.
 148 *
 149 * Examples of such networks are gm and elan.
 150 *
 151 * \retval 0 if \a str parsed to numeric address
 152 * \retval errno otherwise
 153 */
 154static int
 155libcfs_num_parse(char *str, int len, struct list_head *list)
 156{
 157        struct cfs_expr_list *el;
 158        int     rc;
 159
 160        rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
 161        if (rc == 0)
 162                list_add_tail(&el->el_link, list);
 163
 164        return rc;
 165}
 166
 167/*
 168 * Nf_match_addr method for networks using numeric addresses
 169 *
 170 * \retval 1 on match
 171 * \retval 0 otherwise
 172 */
 173static int
 174libcfs_num_match(__u32 addr, struct list_head *numaddr)
 175{
 176        struct cfs_expr_list *el;
 177
 178        LASSERT(!list_empty(numaddr));
 179        el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
 180
 181        return cfs_expr_list_match(addr, el);
 182}
 183
 184struct netstrfns {
 185        int       nf_type;
 186        char    *nf_name;
 187        char    *nf_modname;
 188        void       (*nf_addr2str)(__u32 addr, char *str);
 189        int     (*nf_str2addr)(const char *str, int nob, __u32 *addr);
 190        int     (*nf_parse_addrlist)(char *str, int len,
 191                                        struct list_head *list);
 192        int     (*nf_match_addr)(__u32 addr, struct list_head *list);
 193};
 194
 195static struct netstrfns  libcfs_netstrfns[] = {
 196        {/* .nf_type      */  LOLND,
 197         /* .nf_name      */  "lo",
 198         /* .nf_modname   */  "klolnd",
 199         /* .nf_addr2str  */  libcfs_decnum_addr2str,
 200         /* .nf_str2addr  */  libcfs_lo_str2addr,
 201         /* .nf_parse_addr*/  libcfs_num_parse,
 202         /* .nf_match_addr*/  libcfs_num_match},
 203        {/* .nf_type      */  SOCKLND,
 204         /* .nf_name      */  "tcp",
 205         /* .nf_modname   */  "ksocklnd",
 206         /* .nf_addr2str  */  libcfs_ip_addr2str,
 207         /* .nf_str2addr  */  libcfs_ip_str2addr,
 208         /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
 209         /* .nf_match_addr*/  cfs_ip_addr_match},
 210        {/* .nf_type      */  O2IBLND,
 211         /* .nf_name      */  "o2ib",
 212         /* .nf_modname   */  "ko2iblnd",
 213         /* .nf_addr2str  */  libcfs_ip_addr2str,
 214         /* .nf_str2addr  */  libcfs_ip_str2addr,
 215         /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
 216         /* .nf_match_addr*/  cfs_ip_addr_match},
 217        {/* .nf_type      */  CIBLND,
 218         /* .nf_name      */  "cib",
 219         /* .nf_modname   */  "kciblnd",
 220         /* .nf_addr2str  */  libcfs_ip_addr2str,
 221         /* .nf_str2addr  */  libcfs_ip_str2addr,
 222         /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
 223         /* .nf_match_addr*/  cfs_ip_addr_match},
 224        {/* .nf_type      */  OPENIBLND,
 225         /* .nf_name      */  "openib",
 226         /* .nf_modname   */  "kopeniblnd",
 227         /* .nf_addr2str  */  libcfs_ip_addr2str,
 228         /* .nf_str2addr  */  libcfs_ip_str2addr,
 229         /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
 230         /* .nf_match_addr*/  cfs_ip_addr_match},
 231        {/* .nf_type      */  IIBLND,
 232         /* .nf_name      */  "iib",
 233         /* .nf_modname   */  "kiiblnd",
 234         /* .nf_addr2str  */  libcfs_ip_addr2str,
 235         /* .nf_str2addr  */  libcfs_ip_str2addr,
 236         /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
 237         /* .nf_match_addr*/  cfs_ip_addr_match},
 238        {/* .nf_type      */  VIBLND,
 239         /* .nf_name      */  "vib",
 240         /* .nf_modname   */  "kviblnd",
 241         /* .nf_addr2str  */  libcfs_ip_addr2str,
 242         /* .nf_str2addr  */  libcfs_ip_str2addr,
 243         /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
 244         /* .nf_match_addr*/  cfs_ip_addr_match},
 245        {/* .nf_type      */  RALND,
 246         /* .nf_name      */  "ra",
 247         /* .nf_modname   */  "kralnd",
 248         /* .nf_addr2str  */  libcfs_ip_addr2str,
 249         /* .nf_str2addr  */  libcfs_ip_str2addr,
 250         /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
 251         /* .nf_match_addr*/  cfs_ip_addr_match},
 252        {/* .nf_type      */  QSWLND,
 253         /* .nf_name      */  "elan",
 254         /* .nf_modname   */  "kqswlnd",
 255         /* .nf_addr2str  */  libcfs_decnum_addr2str,
 256         /* .nf_str2addr  */  libcfs_num_str2addr,
 257         /* .nf_parse_addrlist*/  libcfs_num_parse,
 258         /* .nf_match_addr*/  libcfs_num_match},
 259        {/* .nf_type      */  GMLND,
 260         /* .nf_name      */  "gm",
 261         /* .nf_modname   */  "kgmlnd",
 262         /* .nf_addr2str  */  libcfs_hexnum_addr2str,
 263         /* .nf_str2addr  */  libcfs_num_str2addr,
 264         /* .nf_parse_addrlist*/  libcfs_num_parse,
 265         /* .nf_match_addr*/  libcfs_num_match},
 266        {/* .nf_type      */  MXLND,
 267         /* .nf_name      */  "mx",
 268         /* .nf_modname   */  "kmxlnd",
 269         /* .nf_addr2str  */  libcfs_ip_addr2str,
 270         /* .nf_str2addr  */  libcfs_ip_str2addr,
 271         /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
 272         /* .nf_match_addr*/  cfs_ip_addr_match},
 273        {/* .nf_type      */  PTLLND,
 274         /* .nf_name      */  "ptl",
 275         /* .nf_modname   */  "kptllnd",
 276         /* .nf_addr2str  */  libcfs_decnum_addr2str,
 277         /* .nf_str2addr  */  libcfs_num_str2addr,
 278         /* .nf_parse_addrlist*/  libcfs_num_parse,
 279         /* .nf_match_addr*/  libcfs_num_match},
 280        {/* .nf_type      */  GNILND,
 281         /* .nf_name      */  "gni",
 282         /* .nf_modname   */  "kgnilnd",
 283         /* .nf_addr2str  */  libcfs_decnum_addr2str,
 284         /* .nf_str2addr  */  libcfs_num_str2addr,
 285         /* .nf_parse_addrlist*/  libcfs_num_parse,
 286         /* .nf_match_addr*/  libcfs_num_match},
 287        /* placeholder for net0 alias.  It MUST BE THE LAST ENTRY */
 288        {/* .nf_type      */  -1},
 289};
 290
 291static const int libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
 292
 293/* CAVEAT EMPTOR XscanfX
 294 * I use "%n" at the end of a sscanf format to detect trailing junk.  However
 295 * sscanf may return immediately if it sees the terminating '0' in a string, so
 296 * I initialise the %n variable to the expected length.  If sscanf sets it;
 297 * fine, if it doesn't, then the scan ended at the end of the string, which is
 298 * fine too :) */
 299
 300static struct netstrfns *
 301libcfs_lnd2netstrfns(int lnd)
 302{
 303        int    i;
 304
 305        if (lnd >= 0)
 306                for (i = 0; i < libcfs_nnetstrfns; i++)
 307                        if (lnd == libcfs_netstrfns[i].nf_type)
 308                                return &libcfs_netstrfns[i];
 309
 310        return NULL;
 311}
 312
 313static struct netstrfns *
 314libcfs_namenum2netstrfns(const char *name)
 315{
 316        struct netstrfns *nf;
 317        int            i;
 318
 319        for (i = 0; i < libcfs_nnetstrfns; i++) {
 320                nf = &libcfs_netstrfns[i];
 321                if (nf->nf_type >= 0 &&
 322                    !strncmp(name, nf->nf_name, strlen(nf->nf_name)))
 323                        return nf;
 324        }
 325        return NULL;
 326}
 327
 328static struct netstrfns *
 329libcfs_name2netstrfns(const char *name)
 330{
 331        int    i;
 332
 333        for (i = 0; i < libcfs_nnetstrfns; i++)
 334                if (libcfs_netstrfns[i].nf_type >= 0 &&
 335                    !strcmp(libcfs_netstrfns[i].nf_name, name))
 336                        return &libcfs_netstrfns[i];
 337
 338        return NULL;
 339}
 340
 341int
 342libcfs_isknown_lnd(int type)
 343{
 344        return libcfs_lnd2netstrfns(type) != NULL;
 345}
 346EXPORT_SYMBOL(libcfs_isknown_lnd);
 347
 348char *
 349libcfs_lnd2modname(int lnd)
 350{
 351        struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
 352
 353        return (nf == NULL) ? NULL : nf->nf_modname;
 354}
 355EXPORT_SYMBOL(libcfs_lnd2modname);
 356
 357char *
 358libcfs_lnd2str(int lnd)
 359{
 360        char       *str;
 361        struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
 362
 363        if (nf != NULL)
 364                return nf->nf_name;
 365
 366        str = libcfs_next_nidstring();
 367        snprintf(str, LNET_NIDSTR_SIZE, "?%d?", lnd);
 368        return str;
 369}
 370EXPORT_SYMBOL(libcfs_lnd2str);
 371
 372int
 373libcfs_str2lnd(const char *str)
 374{
 375        struct netstrfns *nf = libcfs_name2netstrfns(str);
 376
 377        if (nf != NULL)
 378                return nf->nf_type;
 379
 380        return -1;
 381}
 382EXPORT_SYMBOL(libcfs_str2lnd);
 383
 384char *
 385libcfs_net2str(__u32 net)
 386{
 387        int            lnd = LNET_NETTYP(net);
 388        int            num = LNET_NETNUM(net);
 389        struct netstrfns *nf  = libcfs_lnd2netstrfns(lnd);
 390        char         *str = libcfs_next_nidstring();
 391
 392        if (nf == NULL)
 393                snprintf(str, LNET_NIDSTR_SIZE, "<%d:%d>", lnd, num);
 394        else if (num == 0)
 395                snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
 396        else
 397                snprintf(str, LNET_NIDSTR_SIZE, "%s%d", nf->nf_name, num);
 398
 399        return str;
 400}
 401EXPORT_SYMBOL(libcfs_net2str);
 402
 403char *
 404libcfs_nid2str(lnet_nid_t nid)
 405{
 406        __u32        addr = LNET_NIDADDR(nid);
 407        __u32        net = LNET_NIDNET(nid);
 408        int            lnd = LNET_NETTYP(net);
 409        int            nnum = LNET_NETNUM(net);
 410        struct netstrfns *nf;
 411        char         *str;
 412        int            nob;
 413
 414        if (nid == LNET_NID_ANY)
 415                return "<?>";
 416
 417        nf = libcfs_lnd2netstrfns(lnd);
 418        str = libcfs_next_nidstring();
 419
 420        if (nf == NULL)
 421                snprintf(str, LNET_NIDSTR_SIZE, "%x@<%d:%d>", addr, lnd, nnum);
 422        else {
 423                nf->nf_addr2str(addr, str);
 424                nob = strlen(str);
 425                if (nnum == 0)
 426                        snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
 427                                 nf->nf_name);
 428                else
 429                        snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%d",
 430                                 nf->nf_name, nnum);
 431        }
 432
 433        return str;
 434}
 435EXPORT_SYMBOL(libcfs_nid2str);
 436
 437static struct netstrfns *
 438libcfs_str2net_internal(const char *str, __u32 *net)
 439{
 440        struct netstrfns *uninitialized_var(nf);
 441        int            nob;
 442        unsigned int   netnum;
 443        int            i;
 444
 445        for (i = 0; i < libcfs_nnetstrfns; i++) {
 446                nf = &libcfs_netstrfns[i];
 447                if (nf->nf_type >= 0 &&
 448                    !strncmp(str, nf->nf_name, strlen(nf->nf_name)))
 449                        break;
 450        }
 451
 452        if (i == libcfs_nnetstrfns)
 453                return NULL;
 454
 455        nob = strlen(nf->nf_name);
 456
 457        if (strlen(str) == (unsigned int)nob) {
 458                netnum = 0;
 459        } else {
 460                if (nf->nf_type == LOLND) /* net number not allowed */
 461                        return NULL;
 462
 463                str += nob;
 464                i = strlen(str);
 465                if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
 466                    i != (int)strlen(str))
 467                        return NULL;
 468        }
 469
 470        *net = LNET_MKNET(nf->nf_type, netnum);
 471        return nf;
 472}
 473
 474__u32
 475libcfs_str2net(const char *str)
 476{
 477        __u32  net;
 478
 479        if (libcfs_str2net_internal(str, &net) != NULL)
 480                return net;
 481
 482        return LNET_NIDNET(LNET_NID_ANY);
 483}
 484EXPORT_SYMBOL(libcfs_str2net);
 485
 486lnet_nid_t
 487libcfs_str2nid(const char *str)
 488{
 489        const char       *sep = strchr(str, '@');
 490        struct netstrfns *nf;
 491        __u32        net;
 492        __u32        addr;
 493
 494        if (sep != NULL) {
 495                nf = libcfs_str2net_internal(sep + 1, &net);
 496                if (nf == NULL)
 497                        return LNET_NID_ANY;
 498        } else {
 499                sep = str + strlen(str);
 500                net = LNET_MKNET(SOCKLND, 0);
 501                nf = libcfs_lnd2netstrfns(SOCKLND);
 502                LASSERT(nf != NULL);
 503        }
 504
 505        if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
 506                return LNET_NID_ANY;
 507
 508        return LNET_MKNID(net, addr);
 509}
 510EXPORT_SYMBOL(libcfs_str2nid);
 511
 512char *
 513libcfs_id2str(lnet_process_id_t id)
 514{
 515        char *str = libcfs_next_nidstring();
 516
 517        if (id.pid == LNET_PID_ANY) {
 518                snprintf(str, LNET_NIDSTR_SIZE,
 519                         "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
 520                return str;
 521        }
 522
 523        snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
 524                 ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
 525                 (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
 526        return str;
 527}
 528EXPORT_SYMBOL(libcfs_id2str);
 529
 530int
 531libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
 532{
 533        if (!strcmp(str, "*")) {
 534                *nidp = LNET_NID_ANY;
 535                return 1;
 536        }
 537
 538        *nidp = libcfs_str2nid(str);
 539        return *nidp != LNET_NID_ANY;
 540}
 541EXPORT_SYMBOL(libcfs_str2anynid);
 542
 543/**
 544 * Nid range list syntax.
 545 * \verbatim
 546 *
 547 * <nidlist>     :== <nidrange> [ ' ' <nidrange> ]
 548 * <nidrange>   :== <addrrange> '@' <net>
 549 * <addrrange>       :== '*' |
 550 *                     <ipaddr_range> |
 551 *                       <cfs_expr_list>
 552 * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
 553 *                       <cfs_expr_list>
 554 * <cfs_expr_list>   :== <number> |
 555 *                     <expr_list>
 556 * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
 557 * <range_expr>      :== <number> |
 558 *                     <number> '-' <number> |
 559 *                     <number> '-' <number> '/' <number>
 560 * <net>             :== <netname> | <netname><number>
 561 * <netname>     :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
 562 *                     "vib" | "ra" | "elan" | "mx" | "ptl"
 563 * \endverbatim
 564 */
 565
 566/**
 567 * Structure to represent \<nidrange\> token of the syntax.
 568 *
 569 * One of this is created for each \<net\> parsed.
 570 */
 571struct nidrange {
 572        /**
 573         * Link to list of this structures which is built on nid range
 574         * list parsing.
 575         */
 576        struct list_head nr_link;
 577        /**
 578         * List head for addrrange::ar_link.
 579         */
 580        struct list_head nr_addrranges;
 581        /**
 582         * Flag indicating that *@<net> is found.
 583         */
 584        int nr_all;
 585        /**
 586         * Pointer to corresponding element of libcfs_netstrfns.
 587         */
 588        struct netstrfns *nr_netstrfns;
 589        /**
 590         * Number of network. E.g. 5 if \<net\> is "elan5".
 591         */
 592        int nr_netnum;
 593};
 594
 595/**
 596 * Structure to represent \<addrrange\> token of the syntax.
 597 */
 598struct addrrange {
 599        /**
 600         * Link to nidrange::nr_addrranges.
 601         */
 602        struct list_head ar_link;
 603        /**
 604         * List head for cfs_expr_list::el_list.
 605         */
 606        struct list_head ar_numaddr_ranges;
 607};
 608
 609/**
 610 * Parses \<addrrange\> token on the syntax.
 611 *
 612 * Allocates struct addrrange and links to \a nidrange via
 613 * (nidrange::nr_addrranges)
 614 *
 615 * \retval 1 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
 616 * \retval 0 otherwise
 617 */
 618static int
 619parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
 620{
 621        struct addrrange *addrrange;
 622
 623        if (src->ls_len == 1 && src->ls_str[0] == '*') {
 624                nidrange->nr_all = 1;
 625                return 1;
 626        }
 627
 628        LIBCFS_ALLOC(addrrange, sizeof(struct addrrange));
 629        if (addrrange == NULL)
 630                return 0;
 631        list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
 632        INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
 633
 634        return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
 635                                                src->ls_len,
 636                                                &addrrange->ar_numaddr_ranges);
 637}
 638
 639/**
 640 * Finds or creates struct nidrange.
 641 *
 642 * Checks if \a src is a valid network name, looks for corresponding
 643 * nidrange on the ist of nidranges (\a nidlist), creates new struct
 644 * nidrange if it is not found.
 645 *
 646 * \retval pointer to struct nidrange matching network specified via \a src
 647 * \retval NULL if \a src does not match any network
 648 */
 649static struct nidrange *
 650add_nidrange(const struct cfs_lstr *src,
 651             struct list_head *nidlist)
 652{
 653        struct netstrfns *nf;
 654        struct nidrange *nr;
 655        int endlen;
 656        unsigned netnum;
 657
 658        if (src->ls_len >= LNET_NIDSTR_SIZE)
 659                return NULL;
 660
 661        nf = libcfs_namenum2netstrfns(src->ls_str);
 662        if (nf == NULL)
 663                return NULL;
 664        endlen = src->ls_len - strlen(nf->nf_name);
 665        if (endlen == 0)
 666                /* network name only, e.g. "elan" or "tcp" */
 667                netnum = 0;
 668        else {
 669                /* e.g. "elan25" or "tcp23", refuse to parse if
 670                 * network name is not appended with decimal or
 671                 * hexadecimal number */
 672                if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
 673                                       endlen, &netnum, 0, MAX_NUMERIC_VALUE))
 674                        return NULL;
 675        }
 676
 677        list_for_each_entry(nr, nidlist, nr_link) {
 678                if (nr->nr_netstrfns != nf)
 679                        continue;
 680                if (nr->nr_netnum != netnum)
 681                        continue;
 682                return nr;
 683        }
 684
 685        LIBCFS_ALLOC(nr, sizeof(struct nidrange));
 686        if (nr == NULL)
 687                return NULL;
 688        list_add_tail(&nr->nr_link, nidlist);
 689        INIT_LIST_HEAD(&nr->nr_addrranges);
 690        nr->nr_netstrfns = nf;
 691        nr->nr_all = 0;
 692        nr->nr_netnum = netnum;
 693
 694        return nr;
 695}
 696
 697/**
 698 * Parses \<nidrange\> token of the syntax.
 699 *
 700 * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
 701 * \retval 0 otherwise
 702 */
 703static int
 704parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
 705{
 706        struct cfs_lstr addrrange;
 707        struct cfs_lstr net;
 708        struct cfs_lstr tmp;
 709        struct nidrange *nr;
 710
 711        tmp = *src;
 712        if (cfs_gettok(src, '@', &addrrange) == 0)
 713                goto failed;
 714
 715        if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
 716                goto failed;
 717
 718        nr = add_nidrange(&net, nidlist);
 719        if (nr == NULL)
 720                goto failed;
 721
 722        if (parse_addrange(&addrrange, nr) != 0)
 723                goto failed;
 724
 725        return 1;
 726 failed:
 727        CWARN("can't parse nidrange: \"%.*s\"\n", tmp.ls_len, tmp.ls_str);
 728        return 0;
 729}
 730
 731/**
 732 * Frees addrrange structures of \a list.
 733 *
 734 * For each struct addrrange structure found on \a list it frees
 735 * cfs_expr_list list attached to it and frees the addrrange itself.
 736 *
 737 * \retval none
 738 */
 739static void
 740free_addrranges(struct list_head *list)
 741{
 742        while (!list_empty(list)) {
 743                struct addrrange *ar;
 744
 745                ar = list_entry(list->next, struct addrrange, ar_link);
 746
 747                cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
 748                list_del(&ar->ar_link);
 749                LIBCFS_FREE(ar, sizeof(struct addrrange));
 750        }
 751}
 752
 753/**
 754 * Frees nidrange strutures of \a list.
 755 *
 756 * For each struct nidrange structure found on \a list it frees
 757 * addrrange list attached to it and frees the nidrange itself.
 758 *
 759 * \retval none
 760 */
 761void
 762cfs_free_nidlist(struct list_head *list)
 763{
 764        struct list_head *pos, *next;
 765        struct nidrange *nr;
 766
 767        list_for_each_safe(pos, next, list) {
 768                nr = list_entry(pos, struct nidrange, nr_link);
 769                free_addrranges(&nr->nr_addrranges);
 770                list_del(pos);
 771                LIBCFS_FREE(nr, sizeof(struct nidrange));
 772        }
 773}
 774EXPORT_SYMBOL(cfs_free_nidlist);
 775
 776/**
 777 * Parses nid range list.
 778 *
 779 * Parses with rigorous syntax and overflow checking \a str into
 780 * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
 781 * structures and links that structure to \a nidlist. The resulting
 782 * list can be used to match a NID againts set of NIDS defined by \a
 783 * str.
 784 * \see cfs_match_nid
 785 *
 786 * \retval 1 on success
 787 * \retval 0 otherwise
 788 */
 789int
 790cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
 791{
 792        struct cfs_lstr src;
 793        struct cfs_lstr res;
 794        int rc;
 795
 796        src.ls_str = str;
 797        src.ls_len = len;
 798        INIT_LIST_HEAD(nidlist);
 799        while (src.ls_str) {
 800                rc = cfs_gettok(&src, ' ', &res);
 801                if (rc == 0) {
 802                        cfs_free_nidlist(nidlist);
 803                        return 0;
 804                }
 805                rc = parse_nidrange(&res, nidlist);
 806                if (rc == 0) {
 807                        cfs_free_nidlist(nidlist);
 808                        return 0;
 809                }
 810        }
 811        return 1;
 812}
 813EXPORT_SYMBOL(cfs_parse_nidlist);
 814
 815/**
 816 * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
 817 *
 818 * \see cfs_parse_nidlist()
 819 *
 820 * \retval 1 on match
 821 * \retval 0  otherwises
 822 */
 823int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
 824{
 825        struct nidrange *nr;
 826        struct addrrange *ar;
 827
 828        list_for_each_entry(nr, nidlist, nr_link) {
 829                if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
 830                        continue;
 831                if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
 832                        continue;
 833                if (nr->nr_all)
 834                        return 1;
 835                list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
 836                        if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
 837                                                       &ar->ar_numaddr_ranges))
 838                                return 1;
 839        }
 840        return 0;
 841}
 842EXPORT_SYMBOL(cfs_match_nid);
 843