linux/drivers/staging/lustre/lnet/lnet/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.gnu.org/licenses/gpl-2.0.html
  19 *
  20 * GPL HEADER END
  21 */
  22/*
  23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24 * Use is subject to license terms.
  25 *
  26 * Copyright (c) 2011, 2012, Intel Corporation.
  27 */
  28/*
  29 * This file is part of Lustre, http://www.lustre.org/
  30 * Lustre is a trademark of Sun Microsystems, Inc.
  31 *
  32 * lnet/lnet/nidstrings.c
  33 *
  34 * Author: Phil Schwan <phil@clusterfs.com>
  35 */
  36
  37#define DEBUG_SUBSYSTEM S_LNET
  38
  39#include "../../include/linux/libcfs/libcfs.h"
  40#include "../../include/linux/lnet/lnet.h"
  41
  42/* max value for numeric network address */
  43#define MAX_NUMERIC_VALUE 0xffffffff
  44
  45#define IPSTRING_LENGTH 16
  46
  47/* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
  48 * consistent in all conversion functions.  Some code fragments are copied
  49 * around for the sake of clarity...
  50 */
  51
  52/* CAVEAT EMPTOR! Racey temporary buffer allocation!
  53 * Choose the number of nidstrings to support the MAXIMUM expected number of
  54 * concurrent users.  If there are more, the returned string will be volatile.
  55 * NB this number must allow for a process to be descheduled for a timeslice
  56 * between getting its string and using it.
  57 */
  58
  59static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
  60static int       libcfs_nidstring_idx;
  61
  62static DEFINE_SPINLOCK(libcfs_nidstring_lock);
  63
  64static struct netstrfns *libcfs_namenum2netstrfns(const char *name);
  65
  66char *
  67libcfs_next_nidstring(void)
  68{
  69        char *str;
  70        unsigned long flags;
  71
  72        spin_lock_irqsave(&libcfs_nidstring_lock, flags);
  73
  74        str = libcfs_nidstrings[libcfs_nidstring_idx++];
  75        if (libcfs_nidstring_idx == ARRAY_SIZE(libcfs_nidstrings))
  76                libcfs_nidstring_idx = 0;
  77
  78        spin_unlock_irqrestore(&libcfs_nidstring_lock, flags);
  79        return str;
  80}
  81EXPORT_SYMBOL(libcfs_next_nidstring);
  82
  83/**
  84 * Nid range list syntax.
  85 * \verbatim
  86 *
  87 * <nidlist>         :== <nidrange> [ ' ' <nidrange> ]
  88 * <nidrange>        :== <addrrange> '@' <net>
  89 * <addrrange>       :== '*' |
  90 *                       <ipaddr_range> |
  91 *                       <cfs_expr_list>
  92 * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
  93 *                       <cfs_expr_list>
  94 * <cfs_expr_list>   :== <number> |
  95 *                       <expr_list>
  96 * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
  97 * <range_expr>      :== <number> |
  98 *                       <number> '-' <number> |
  99 *                       <number> '-' <number> '/' <number>
 100 * <net>             :== <netname> | <netname><number>
 101 * <netname>         :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
 102 *                       "vib" | "ra" | "elan" | "mx" | "ptl"
 103 * \endverbatim
 104 */
 105
 106/**
 107 * Structure to represent \<nidrange\> token of the syntax.
 108 *
 109 * One of this is created for each \<net\> parsed.
 110 */
 111struct nidrange {
 112        /**
 113         * Link to list of this structures which is built on nid range
 114         * list parsing.
 115         */
 116        struct list_head nr_link;
 117        /**
 118         * List head for addrrange::ar_link.
 119         */
 120        struct list_head nr_addrranges;
 121        /**
 122         * Flag indicating that *@<net> is found.
 123         */
 124        int nr_all;
 125        /**
 126         * Pointer to corresponding element of libcfs_netstrfns.
 127         */
 128        struct netstrfns *nr_netstrfns;
 129        /**
 130         * Number of network. E.g. 5 if \<net\> is "elan5".
 131         */
 132        int nr_netnum;
 133};
 134
 135/**
 136 * Structure to represent \<addrrange\> token of the syntax.
 137 */
 138struct addrrange {
 139        /**
 140         * Link to nidrange::nr_addrranges.
 141         */
 142        struct list_head ar_link;
 143        /**
 144         * List head for cfs_expr_list::el_list.
 145         */
 146        struct list_head ar_numaddr_ranges;
 147};
 148
 149/**
 150 * Parses \<addrrange\> token on the syntax.
 151 *
 152 * Allocates struct addrrange and links to \a nidrange via
 153 * (nidrange::nr_addrranges)
 154 *
 155 * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
 156 * \retval -errno otherwise
 157 */
 158static int
 159parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
 160{
 161        struct addrrange *addrrange;
 162
 163        if (src->ls_len == 1 && src->ls_str[0] == '*') {
 164                nidrange->nr_all = 1;
 165                return 0;
 166        }
 167
 168        LIBCFS_ALLOC(addrrange, sizeof(struct addrrange));
 169        if (!addrrange)
 170                return -ENOMEM;
 171        list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
 172        INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
 173
 174        return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
 175                                                src->ls_len,
 176                                                &addrrange->ar_numaddr_ranges);
 177}
 178
 179/**
 180 * Finds or creates struct nidrange.
 181 *
 182 * Checks if \a src is a valid network name, looks for corresponding
 183 * nidrange on the ist of nidranges (\a nidlist), creates new struct
 184 * nidrange if it is not found.
 185 *
 186 * \retval pointer to struct nidrange matching network specified via \a src
 187 * \retval NULL if \a src does not match any network
 188 */
 189static struct nidrange *
 190add_nidrange(const struct cfs_lstr *src,
 191             struct list_head *nidlist)
 192{
 193        struct netstrfns *nf;
 194        struct nidrange *nr;
 195        int endlen;
 196        unsigned netnum;
 197
 198        if (src->ls_len >= LNET_NIDSTR_SIZE)
 199                return NULL;
 200
 201        nf = libcfs_namenum2netstrfns(src->ls_str);
 202        if (!nf)
 203                return NULL;
 204        endlen = src->ls_len - strlen(nf->nf_name);
 205        if (!endlen)
 206                /* network name only, e.g. "elan" or "tcp" */
 207                netnum = 0;
 208        else {
 209                /*
 210                 * e.g. "elan25" or "tcp23", refuse to parse if
 211                 * network name is not appended with decimal or
 212                 * hexadecimal number
 213                 */
 214                if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
 215                                       endlen, &netnum, 0, MAX_NUMERIC_VALUE))
 216                        return NULL;
 217        }
 218
 219        list_for_each_entry(nr, nidlist, nr_link) {
 220                if (nr->nr_netstrfns != nf)
 221                        continue;
 222                if (nr->nr_netnum != netnum)
 223                        continue;
 224                return nr;
 225        }
 226
 227        LIBCFS_ALLOC(nr, sizeof(struct nidrange));
 228        if (!nr)
 229                return NULL;
 230        list_add_tail(&nr->nr_link, nidlist);
 231        INIT_LIST_HEAD(&nr->nr_addrranges);
 232        nr->nr_netstrfns = nf;
 233        nr->nr_all = 0;
 234        nr->nr_netnum = netnum;
 235
 236        return nr;
 237}
 238
 239/**
 240 * Parses \<nidrange\> token of the syntax.
 241 *
 242 * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
 243 * \retval 0 otherwise
 244 */
 245static int
 246parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
 247{
 248        struct cfs_lstr addrrange;
 249        struct cfs_lstr net;
 250        struct cfs_lstr tmp;
 251        struct nidrange *nr;
 252
 253        tmp = *src;
 254        if (!cfs_gettok(src, '@', &addrrange))
 255                goto failed;
 256
 257        if (!cfs_gettok(src, '@', &net) || src->ls_str)
 258                goto failed;
 259
 260        nr = add_nidrange(&net, nidlist);
 261        if (!nr)
 262                goto failed;
 263
 264        if (parse_addrange(&addrrange, nr))
 265                goto failed;
 266
 267        return 1;
 268failed:
 269        return 0;
 270}
 271
 272/**
 273 * Frees addrrange structures of \a list.
 274 *
 275 * For each struct addrrange structure found on \a list it frees
 276 * cfs_expr_list list attached to it and frees the addrrange itself.
 277 *
 278 * \retval none
 279 */
 280static void
 281free_addrranges(struct list_head *list)
 282{
 283        while (!list_empty(list)) {
 284                struct addrrange *ar;
 285
 286                ar = list_entry(list->next, struct addrrange, ar_link);
 287
 288                cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
 289                list_del(&ar->ar_link);
 290                LIBCFS_FREE(ar, sizeof(struct addrrange));
 291        }
 292}
 293
 294/**
 295 * Frees nidrange strutures of \a list.
 296 *
 297 * For each struct nidrange structure found on \a list it frees
 298 * addrrange list attached to it and frees the nidrange itself.
 299 *
 300 * \retval none
 301 */
 302void
 303cfs_free_nidlist(struct list_head *list)
 304{
 305        struct list_head *pos, *next;
 306        struct nidrange *nr;
 307
 308        list_for_each_safe(pos, next, list) {
 309                nr = list_entry(pos, struct nidrange, nr_link);
 310                free_addrranges(&nr->nr_addrranges);
 311                list_del(pos);
 312                LIBCFS_FREE(nr, sizeof(struct nidrange));
 313        }
 314}
 315EXPORT_SYMBOL(cfs_free_nidlist);
 316
 317/**
 318 * Parses nid range list.
 319 *
 320 * Parses with rigorous syntax and overflow checking \a str into
 321 * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
 322 * structures and links that structure to \a nidlist. The resulting
 323 * list can be used to match a NID againts set of NIDS defined by \a
 324 * str.
 325 * \see cfs_match_nid
 326 *
 327 * \retval 1 on success
 328 * \retval 0 otherwise
 329 */
 330int
 331cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
 332{
 333        struct cfs_lstr src;
 334        struct cfs_lstr res;
 335        int rc;
 336
 337        src.ls_str = str;
 338        src.ls_len = len;
 339        INIT_LIST_HEAD(nidlist);
 340        while (src.ls_str) {
 341                rc = cfs_gettok(&src, ' ', &res);
 342                if (!rc) {
 343                        cfs_free_nidlist(nidlist);
 344                        return 0;
 345                }
 346                rc = parse_nidrange(&res, nidlist);
 347                if (!rc) {
 348                        cfs_free_nidlist(nidlist);
 349                        return 0;
 350                }
 351        }
 352        return 1;
 353}
 354EXPORT_SYMBOL(cfs_parse_nidlist);
 355
 356/**
 357 * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
 358 *
 359 * \see cfs_parse_nidlist()
 360 *
 361 * \retval 1 on match
 362 * \retval 0  otherwises
 363 */
 364int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
 365{
 366        struct nidrange *nr;
 367        struct addrrange *ar;
 368
 369        list_for_each_entry(nr, nidlist, nr_link) {
 370                if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
 371                        continue;
 372                if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
 373                        continue;
 374                if (nr->nr_all)
 375                        return 1;
 376                list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
 377                        if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
 378                                                            &ar->ar_numaddr_ranges))
 379                                return 1;
 380        }
 381        return 0;
 382}
 383EXPORT_SYMBOL(cfs_match_nid);
 384
 385/**
 386 * Print the network part of the nidrange \a nr into the specified \a buffer.
 387 *
 388 * \retval number of characters written
 389 */
 390static int
 391cfs_print_network(char *buffer, int count, struct nidrange *nr)
 392{
 393        struct netstrfns *nf = nr->nr_netstrfns;
 394
 395        if (!nr->nr_netnum)
 396                return scnprintf(buffer, count, "@%s", nf->nf_name);
 397        else
 398                return scnprintf(buffer, count, "@%s%u",
 399                                 nf->nf_name, nr->nr_netnum);
 400}
 401
 402/**
 403 * Print a list of addrrange (\a addrranges) into the specified \a buffer.
 404 * At max \a count characters can be printed into \a buffer.
 405 *
 406 * \retval number of characters written
 407 */
 408static int
 409cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
 410                     struct nidrange *nr)
 411{
 412        int i = 0;
 413        struct addrrange *ar;
 414        struct netstrfns *nf = nr->nr_netstrfns;
 415
 416        list_for_each_entry(ar, addrranges, ar_link) {
 417                if (i)
 418                        i += scnprintf(buffer + i, count - i, " ");
 419                i += nf->nf_print_addrlist(buffer + i, count - i,
 420                                           &ar->ar_numaddr_ranges);
 421                i += cfs_print_network(buffer + i, count - i, nr);
 422        }
 423        return i;
 424}
 425
 426/**
 427 * Print a list of nidranges (\a nidlist) into the specified \a buffer.
 428 * At max \a count characters can be printed into \a buffer.
 429 * Nidranges are separated by a space character.
 430 *
 431 * \retval number of characters written
 432 */
 433int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
 434{
 435        int i = 0;
 436        struct nidrange *nr;
 437
 438        if (count <= 0)
 439                return 0;
 440
 441        list_for_each_entry(nr, nidlist, nr_link) {
 442                if (i)
 443                        i += scnprintf(buffer + i, count - i, " ");
 444
 445                if (nr->nr_all) {
 446                        LASSERT(list_empty(&nr->nr_addrranges));
 447                        i += scnprintf(buffer + i, count - i, "*");
 448                        i += cfs_print_network(buffer + i, count - i, nr);
 449                } else {
 450                        i += cfs_print_addrranges(buffer + i, count - i,
 451                                                  &nr->nr_addrranges, nr);
 452                }
 453        }
 454        return i;
 455}
 456EXPORT_SYMBOL(cfs_print_nidlist);
 457
 458/**
 459 * Determines minimum and maximum addresses for a single
 460 * numeric address range
 461 *
 462 * \param       ar
 463 * \param       min_nid
 464 * \param       max_nid
 465 */
 466static void cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
 467                              __u32 *max_nid)
 468{
 469        struct cfs_expr_list *el;
 470        struct cfs_range_expr *re;
 471        __u32 tmp_ip_addr = 0;
 472        unsigned int min_ip[4] = {0};
 473        unsigned int max_ip[4] = {0};
 474        int re_count = 0;
 475
 476        list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
 477                list_for_each_entry(re, &el->el_exprs, re_link) {
 478                        min_ip[re_count] = re->re_lo;
 479                        max_ip[re_count] = re->re_hi;
 480                        re_count++;
 481                }
 482        }
 483
 484        tmp_ip_addr = ((min_ip[0] << 24) | (min_ip[1] << 16) |
 485                       (min_ip[2] << 8) | min_ip[3]);
 486
 487        if (min_nid)
 488                *min_nid = tmp_ip_addr;
 489
 490        tmp_ip_addr = ((max_ip[0] << 24) | (max_ip[1] << 16) |
 491                       (max_ip[2] << 8) | max_ip[3]);
 492
 493        if (max_nid)
 494                *max_nid = tmp_ip_addr;
 495}
 496
 497/**
 498 * Determines minimum and maximum addresses for a single
 499 * numeric address range
 500 *
 501 * \param       ar
 502 * \param       min_nid
 503 * \param       max_nid
 504 */
 505static void cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
 506                               __u32 *max_nid)
 507{
 508        struct cfs_expr_list *el;
 509        struct cfs_range_expr *re;
 510        unsigned int min_addr = 0;
 511        unsigned int max_addr = 0;
 512
 513        list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
 514                list_for_each_entry(re, &el->el_exprs, re_link) {
 515                        if (re->re_lo < min_addr || !min_addr)
 516                                min_addr = re->re_lo;
 517                        if (re->re_hi > max_addr)
 518                                max_addr = re->re_hi;
 519                }
 520        }
 521
 522        if (min_nid)
 523                *min_nid = min_addr;
 524        if (max_nid)
 525                *max_nid = max_addr;
 526}
 527
 528/**
 529 * Determines whether an expression list in an nidrange contains exactly
 530 * one contiguous address range. Calls the correct netstrfns for the LND
 531 *
 532 * \param       *nidlist
 533 *
 534 * \retval      true if contiguous
 535 * \retval      false if not contiguous
 536 */
 537bool cfs_nidrange_is_contiguous(struct list_head *nidlist)
 538{
 539        struct nidrange *nr;
 540        struct netstrfns *nf = NULL;
 541        char *lndname = NULL;
 542        int netnum = -1;
 543
 544        list_for_each_entry(nr, nidlist, nr_link) {
 545                nf = nr->nr_netstrfns;
 546                if (!lndname)
 547                        lndname = nf->nf_name;
 548                if (netnum == -1)
 549                        netnum = nr->nr_netnum;
 550
 551                if (strcmp(lndname, nf->nf_name) ||
 552                    netnum != nr->nr_netnum)
 553                        return false;
 554        }
 555
 556        if (!nf)
 557                return false;
 558
 559        if (!nf->nf_is_contiguous(nidlist))
 560                return false;
 561
 562        return true;
 563}
 564EXPORT_SYMBOL(cfs_nidrange_is_contiguous);
 565
 566/**
 567 * Determines whether an expression list in an num nidrange contains exactly
 568 * one contiguous address range.
 569 *
 570 * \param       *nidlist
 571 *
 572 * \retval      true if contiguous
 573 * \retval      false if not contiguous
 574 */
 575static bool cfs_num_is_contiguous(struct list_head *nidlist)
 576{
 577        struct nidrange *nr;
 578        struct addrrange *ar;
 579        struct cfs_expr_list *el;
 580        struct cfs_range_expr *re;
 581        int last_hi = 0;
 582        __u32 last_end_nid = 0;
 583        __u32 current_start_nid = 0;
 584        __u32 current_end_nid = 0;
 585
 586        list_for_each_entry(nr, nidlist, nr_link) {
 587                list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
 588                        cfs_num_ar_min_max(ar, &current_start_nid,
 589                                           &current_end_nid);
 590                        if (last_end_nid &&
 591                            (current_start_nid - last_end_nid != 1))
 592                                return false;
 593                        last_end_nid = current_end_nid;
 594                        list_for_each_entry(el, &ar->ar_numaddr_ranges,
 595                                            el_link) {
 596                                list_for_each_entry(re, &el->el_exprs,
 597                                                    re_link) {
 598                                        if (re->re_stride > 1)
 599                                                return false;
 600                                        else if (last_hi &&
 601                                                 re->re_hi - last_hi != 1)
 602                                                return false;
 603                                        last_hi = re->re_hi;
 604                                }
 605                        }
 606                }
 607        }
 608
 609        return true;
 610}
 611
 612/**
 613 * Determines whether an expression list in an ip nidrange contains exactly
 614 * one contiguous address range.
 615 *
 616 * \param       *nidlist
 617 *
 618 * \retval      true if contiguous
 619 * \retval      false if not contiguous
 620 */
 621static bool cfs_ip_is_contiguous(struct list_head *nidlist)
 622{
 623        struct nidrange *nr;
 624        struct addrrange *ar;
 625        struct cfs_expr_list *el;
 626        struct cfs_range_expr *re;
 627        int expr_count;
 628        int last_hi = 255;
 629        int last_diff = 0;
 630        __u32 last_end_nid = 0;
 631        __u32 current_start_nid = 0;
 632        __u32 current_end_nid = 0;
 633
 634        list_for_each_entry(nr, nidlist, nr_link) {
 635                list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
 636                        last_hi = 255;
 637                        last_diff = 0;
 638                        cfs_ip_ar_min_max(ar, &current_start_nid,
 639                                          &current_end_nid);
 640                        if (last_end_nid &&
 641                            (current_start_nid - last_end_nid != 1))
 642                                return false;
 643                        last_end_nid = current_end_nid;
 644                        list_for_each_entry(el, &ar->ar_numaddr_ranges,
 645                                            el_link) {
 646                                expr_count = 0;
 647                                list_for_each_entry(re, &el->el_exprs,
 648                                                    re_link) {
 649                                        expr_count++;
 650                                        if (re->re_stride > 1 ||
 651                                            (last_diff > 0 && last_hi != 255) ||
 652                                            (last_diff > 0 && last_hi == 255 &&
 653                                             re->re_lo > 0))
 654                                                return false;
 655                                        last_hi = re->re_hi;
 656                                        last_diff = re->re_hi - re->re_lo;
 657                                }
 658                        }
 659                }
 660        }
 661
 662        return true;
 663}
 664
 665/**
 666 * Takes a linked list of nidrange expressions, determines the minimum
 667 * and maximum nid and creates appropriate nid structures
 668 *
 669 * \param       *nidlist
 670 * \param       *min_nid
 671 * \param       *max_nid
 672 */
 673void cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
 674                               char *max_nid, size_t nidstr_length)
 675{
 676        struct nidrange *nr;
 677        struct netstrfns *nf = NULL;
 678        int netnum = -1;
 679        __u32 min_addr;
 680        __u32 max_addr;
 681        char *lndname = NULL;
 682        char min_addr_str[IPSTRING_LENGTH];
 683        char max_addr_str[IPSTRING_LENGTH];
 684
 685        list_for_each_entry(nr, nidlist, nr_link) {
 686                nf = nr->nr_netstrfns;
 687                lndname = nf->nf_name;
 688                if (netnum == -1)
 689                        netnum = nr->nr_netnum;
 690
 691                nf->nf_min_max(nidlist, &min_addr, &max_addr);
 692        }
 693        nf->nf_addr2str(min_addr, min_addr_str, sizeof(min_addr_str));
 694        nf->nf_addr2str(max_addr, max_addr_str, sizeof(max_addr_str));
 695
 696        snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
 697                 netnum);
 698        snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
 699                 netnum);
 700}
 701EXPORT_SYMBOL(cfs_nidrange_find_min_max);
 702
 703/**
 704 * Determines the min and max NID values for num LNDs
 705 *
 706 * \param       *nidlist
 707 * \param       *min_nid
 708 * \param       *max_nid
 709 */
 710static void cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
 711                            __u32 *max_nid)
 712{
 713        struct nidrange *nr;
 714        struct addrrange *ar;
 715        unsigned int tmp_min_addr = 0;
 716        unsigned int tmp_max_addr = 0;
 717        unsigned int min_addr = 0;
 718        unsigned int max_addr = 0;
 719
 720        list_for_each_entry(nr, nidlist, nr_link) {
 721                list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
 722                        cfs_num_ar_min_max(ar, &tmp_min_addr,
 723                                           &tmp_max_addr);
 724                        if (tmp_min_addr < min_addr || !min_addr)
 725                                min_addr = tmp_min_addr;
 726                        if (tmp_max_addr > max_addr)
 727                                max_addr = tmp_min_addr;
 728                }
 729        }
 730        *max_nid = max_addr;
 731        *min_nid = min_addr;
 732}
 733
 734/**
 735 * Takes an nidlist and determines the minimum and maximum
 736 * ip addresses.
 737 *
 738 * \param       *nidlist
 739 * \param       *min_nid
 740 * \param       *max_nid
 741 */
 742static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
 743                           __u32 *max_nid)
 744{
 745        struct nidrange *nr;
 746        struct addrrange *ar;
 747        __u32 tmp_min_ip_addr = 0;
 748        __u32 tmp_max_ip_addr = 0;
 749        __u32 min_ip_addr = 0;
 750        __u32 max_ip_addr = 0;
 751
 752        list_for_each_entry(nr, nidlist, nr_link) {
 753                list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
 754                        cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
 755                                          &tmp_max_ip_addr);
 756                        if (tmp_min_ip_addr < min_ip_addr || !min_ip_addr)
 757                                min_ip_addr = tmp_min_ip_addr;
 758                        if (tmp_max_ip_addr > max_ip_addr)
 759                                max_ip_addr = tmp_max_ip_addr;
 760                }
 761        }
 762
 763        if (min_nid)
 764                *min_nid = min_ip_addr;
 765        if (max_nid)
 766                *max_nid = max_ip_addr;
 767}
 768
 769static int
 770libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
 771{
 772        *addr = 0;
 773        return 1;
 774}
 775
 776static void
 777libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
 778{
 779        snprintf(str, size, "%u.%u.%u.%u",
 780                 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
 781                 (addr >> 8) & 0xff, addr & 0xff);
 782}
 783
 784/*
 785 * CAVEAT EMPTOR XscanfX
 786 * I use "%n" at the end of a sscanf format to detect trailing junk.  However
 787 * sscanf may return immediately if it sees the terminating '0' in a string, so
 788 * I initialise the %n variable to the expected length.  If sscanf sets it;
 789 * fine, if it doesn't, then the scan ended at the end of the string, which is
 790 * fine too :)
 791 */
 792static int
 793libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
 794{
 795        unsigned int    a;
 796        unsigned int    b;
 797        unsigned int    c;
 798        unsigned int    d;
 799        int             n = nob; /* XscanfX */
 800
 801        /* numeric IP? */
 802        if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
 803            n == nob &&
 804            !(a & ~0xff) && !(b & ~0xff) &&
 805            !(c & ~0xff) && !(d & ~0xff)) {
 806                *addr = ((a << 24) | (b << 16) | (c << 8) | d);
 807                return 1;
 808        }
 809
 810        return 0;
 811}
 812
 813/* Used by lnet/config.c so it can't be static */
 814int
 815cfs_ip_addr_parse(char *str, int len, struct list_head *list)
 816{
 817        struct cfs_expr_list *el;
 818        struct cfs_lstr src;
 819        int rc;
 820        int i;
 821
 822        src.ls_str = str;
 823        src.ls_len = len;
 824        i = 0;
 825
 826        while (src.ls_str) {
 827                struct cfs_lstr res;
 828
 829                if (!cfs_gettok(&src, '.', &res)) {
 830                        rc = -EINVAL;
 831                        goto out;
 832                }
 833
 834                rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el);
 835                if (rc)
 836                        goto out;
 837
 838                list_add_tail(&el->el_link, list);
 839                i++;
 840        }
 841
 842        if (i == 4)
 843                return 0;
 844
 845        rc = -EINVAL;
 846out:
 847        cfs_expr_list_free_list(list);
 848
 849        return rc;
 850}
 851
 852static int
 853libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
 854{
 855        int i = 0, j = 0;
 856        struct cfs_expr_list *el;
 857
 858        list_for_each_entry(el, list, el_link) {
 859                LASSERT(j++ < 4);
 860                if (i)
 861                        i += scnprintf(buffer + i, count - i, ".");
 862                i += cfs_expr_list_print(buffer + i, count - i, el);
 863        }
 864        return i;
 865}
 866
 867/**
 868 * Matches address (\a addr) against address set encoded in \a list.
 869 *
 870 * \retval 1 if \a addr matches
 871 * \retval 0 otherwise
 872 */
 873int
 874cfs_ip_addr_match(__u32 addr, struct list_head *list)
 875{
 876        struct cfs_expr_list *el;
 877        int i = 0;
 878
 879        list_for_each_entry_reverse(el, list, el_link) {
 880                if (!cfs_expr_list_match(addr & 0xff, el))
 881                        return 0;
 882                addr >>= 8;
 883                i++;
 884        }
 885
 886        return i == 4;
 887}
 888
 889static void
 890libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
 891{
 892        snprintf(str, size, "%u", addr);
 893}
 894
 895static int
 896libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
 897{
 898        int     n;
 899
 900        n = nob;
 901        if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
 902                return 1;
 903
 904        n = nob;
 905        if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
 906                return 1;
 907
 908        n = nob;
 909        if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
 910                return 1;
 911
 912        return 0;
 913}
 914
 915/**
 916 * Nf_parse_addrlist method for networks using numeric addresses.
 917 *
 918 * Examples of such networks are gm and elan.
 919 *
 920 * \retval 0 if \a str parsed to numeric address
 921 * \retval errno otherwise
 922 */
 923static int
 924libcfs_num_parse(char *str, int len, struct list_head *list)
 925{
 926        struct cfs_expr_list *el;
 927        int     rc;
 928
 929        rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
 930        if (!rc)
 931                list_add_tail(&el->el_link, list);
 932
 933        return rc;
 934}
 935
 936static int
 937libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
 938{
 939        int i = 0, j = 0;
 940        struct cfs_expr_list *el;
 941
 942        list_for_each_entry(el, list, el_link) {
 943                LASSERT(j++ < 1);
 944                i += cfs_expr_list_print(buffer + i, count - i, el);
 945        }
 946        return i;
 947}
 948
 949/*
 950 * Nf_match_addr method for networks using numeric addresses
 951 *
 952 * \retval 1 on match
 953 * \retval 0 otherwise
 954 */
 955static int
 956libcfs_num_match(__u32 addr, struct list_head *numaddr)
 957{
 958        struct cfs_expr_list *el;
 959
 960        LASSERT(!list_empty(numaddr));
 961        el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
 962
 963        return cfs_expr_list_match(addr, el);
 964}
 965
 966static struct netstrfns libcfs_netstrfns[] = {
 967        { .nf_type              = LOLND,
 968          .nf_name              = "lo",
 969          .nf_modname           = "klolnd",
 970          .nf_addr2str          = libcfs_decnum_addr2str,
 971          .nf_str2addr          = libcfs_lo_str2addr,
 972          .nf_parse_addrlist    = libcfs_num_parse,
 973          .nf_print_addrlist    = libcfs_num_addr_range_print,
 974          .nf_match_addr        = libcfs_num_match,
 975          .nf_is_contiguous     = cfs_num_is_contiguous,
 976          .nf_min_max           = cfs_num_min_max },
 977        { .nf_type              = SOCKLND,
 978          .nf_name              = "tcp",
 979          .nf_modname           = "ksocklnd",
 980          .nf_addr2str          = libcfs_ip_addr2str,
 981          .nf_str2addr          = libcfs_ip_str2addr,
 982          .nf_parse_addrlist    = cfs_ip_addr_parse,
 983          .nf_print_addrlist    = libcfs_ip_addr_range_print,
 984          .nf_match_addr        = cfs_ip_addr_match,
 985          .nf_is_contiguous     = cfs_ip_is_contiguous,
 986          .nf_min_max           = cfs_ip_min_max },
 987        { .nf_type              = O2IBLND,
 988          .nf_name              = "o2ib",
 989          .nf_modname           = "ko2iblnd",
 990          .nf_addr2str          = libcfs_ip_addr2str,
 991          .nf_str2addr          = libcfs_ip_str2addr,
 992          .nf_parse_addrlist    = cfs_ip_addr_parse,
 993          .nf_print_addrlist    = libcfs_ip_addr_range_print,
 994          .nf_match_addr        = cfs_ip_addr_match,
 995          .nf_is_contiguous     = cfs_ip_is_contiguous,
 996          .nf_min_max           = cfs_ip_min_max },
 997        { .nf_type              = GNILND,
 998          .nf_name              = "gni",
 999          .nf_modname           = "kgnilnd",
1000          .nf_addr2str          = libcfs_decnum_addr2str,
1001          .nf_str2addr          = libcfs_num_str2addr,
1002          .nf_parse_addrlist    = libcfs_num_parse,
1003          .nf_print_addrlist    = libcfs_num_addr_range_print,
1004          .nf_match_addr        = libcfs_num_match,
1005          .nf_is_contiguous     = cfs_num_is_contiguous,
1006          .nf_min_max           = cfs_num_min_max },
1007        { .nf_type              = GNIIPLND,
1008          .nf_name              = "gip",
1009          .nf_modname           = "kgnilnd",
1010          .nf_addr2str          = libcfs_ip_addr2str,
1011          .nf_str2addr          = libcfs_ip_str2addr,
1012          .nf_parse_addrlist    = cfs_ip_addr_parse,
1013          .nf_print_addrlist    = libcfs_ip_addr_range_print,
1014          .nf_match_addr        = cfs_ip_addr_match,
1015          .nf_is_contiguous     = cfs_ip_is_contiguous,
1016          .nf_min_max           = cfs_ip_min_max },
1017};
1018
1019static const size_t libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
1020
1021static struct netstrfns *
1022libcfs_lnd2netstrfns(__u32 lnd)
1023{
1024        int i;
1025
1026        for (i = 0; i < libcfs_nnetstrfns; i++)
1027                if (lnd == libcfs_netstrfns[i].nf_type)
1028                        return &libcfs_netstrfns[i];
1029
1030        return NULL;
1031}
1032
1033static struct netstrfns *
1034libcfs_namenum2netstrfns(const char *name)
1035{
1036        struct netstrfns *nf;
1037        int i;
1038
1039        for (i = 0; i < libcfs_nnetstrfns; i++) {
1040                nf = &libcfs_netstrfns[i];
1041                if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
1042                        return nf;
1043        }
1044        return NULL;
1045}
1046
1047static struct netstrfns *
1048libcfs_name2netstrfns(const char *name)
1049{
1050        int    i;
1051
1052        for (i = 0; i < libcfs_nnetstrfns; i++)
1053                if (!strcmp(libcfs_netstrfns[i].nf_name, name))
1054                        return &libcfs_netstrfns[i];
1055
1056        return NULL;
1057}
1058
1059int
1060libcfs_isknown_lnd(__u32 lnd)
1061{
1062        return !!libcfs_lnd2netstrfns(lnd);
1063}
1064EXPORT_SYMBOL(libcfs_isknown_lnd);
1065
1066char *
1067libcfs_lnd2modname(__u32 lnd)
1068{
1069        struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
1070
1071        return nf ? nf->nf_modname : NULL;
1072}
1073EXPORT_SYMBOL(libcfs_lnd2modname);
1074
1075int
1076libcfs_str2lnd(const char *str)
1077{
1078        struct netstrfns *nf = libcfs_name2netstrfns(str);
1079
1080        if (nf)
1081                return nf->nf_type;
1082
1083        return -ENXIO;
1084}
1085EXPORT_SYMBOL(libcfs_str2lnd);
1086
1087char *
1088libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
1089{
1090        struct netstrfns *nf;
1091
1092        nf = libcfs_lnd2netstrfns(lnd);
1093        if (!nf)
1094                snprintf(buf, buf_size, "?%u?", lnd);
1095        else
1096                snprintf(buf, buf_size, "%s", nf->nf_name);
1097
1098        return buf;
1099}
1100EXPORT_SYMBOL(libcfs_lnd2str_r);
1101
1102char *
1103libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
1104{
1105        __u32 nnum = LNET_NETNUM(net);
1106        __u32 lnd = LNET_NETTYP(net);
1107        struct netstrfns *nf;
1108
1109        nf = libcfs_lnd2netstrfns(lnd);
1110        if (!nf)
1111                snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
1112        else if (!nnum)
1113                snprintf(buf, buf_size, "%s", nf->nf_name);
1114        else
1115                snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
1116
1117        return buf;
1118}
1119EXPORT_SYMBOL(libcfs_net2str_r);
1120
1121char *
1122libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
1123{
1124        __u32 addr = LNET_NIDADDR(nid);
1125        __u32 net = LNET_NIDNET(nid);
1126        __u32 nnum = LNET_NETNUM(net);
1127        __u32 lnd = LNET_NETTYP(net);
1128        struct netstrfns *nf;
1129
1130        if (nid == LNET_NID_ANY) {
1131                strncpy(buf, "<?>", buf_size);
1132                buf[buf_size - 1] = '\0';
1133                return buf;
1134        }
1135
1136        nf = libcfs_lnd2netstrfns(lnd);
1137        if (!nf) {
1138                snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
1139        } else {
1140                size_t addr_len;
1141
1142                nf->nf_addr2str(addr, buf, buf_size);
1143                addr_len = strlen(buf);
1144                if (!nnum)
1145                        snprintf(buf + addr_len, buf_size - addr_len, "@%s",
1146                                 nf->nf_name);
1147                else
1148                        snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
1149                                 nf->nf_name, nnum);
1150        }
1151
1152        return buf;
1153}
1154EXPORT_SYMBOL(libcfs_nid2str_r);
1155
1156static struct netstrfns *
1157libcfs_str2net_internal(const char *str, __u32 *net)
1158{
1159        struct netstrfns *uninitialized_var(nf);
1160        int nob;
1161        unsigned int netnum;
1162        int i;
1163
1164        for (i = 0; i < libcfs_nnetstrfns; i++) {
1165                nf = &libcfs_netstrfns[i];
1166                if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
1167                        break;
1168        }
1169
1170        if (i == libcfs_nnetstrfns)
1171                return NULL;
1172
1173        nob = strlen(nf->nf_name);
1174
1175        if (strlen(str) == (unsigned int)nob) {
1176                netnum = 0;
1177        } else {
1178                if (nf->nf_type == LOLND) /* net number not allowed */
1179                        return NULL;
1180
1181                str += nob;
1182                i = strlen(str);
1183                if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
1184                    i != (int)strlen(str))
1185                        return NULL;
1186        }
1187
1188        *net = LNET_MKNET(nf->nf_type, netnum);
1189        return nf;
1190}
1191
1192__u32
1193libcfs_str2net(const char *str)
1194{
1195        __u32  net;
1196
1197        if (libcfs_str2net_internal(str, &net))
1198                return net;
1199
1200        return LNET_NIDNET(LNET_NID_ANY);
1201}
1202EXPORT_SYMBOL(libcfs_str2net);
1203
1204lnet_nid_t
1205libcfs_str2nid(const char *str)
1206{
1207        const char *sep = strchr(str, '@');
1208        struct netstrfns *nf;
1209        __u32 net;
1210        __u32 addr;
1211
1212        if (sep) {
1213                nf = libcfs_str2net_internal(sep + 1, &net);
1214                if (!nf)
1215                        return LNET_NID_ANY;
1216        } else {
1217                sep = str + strlen(str);
1218                net = LNET_MKNET(SOCKLND, 0);
1219                nf = libcfs_lnd2netstrfns(SOCKLND);
1220                LASSERT(nf);
1221        }
1222
1223        if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
1224                return LNET_NID_ANY;
1225
1226        return LNET_MKNID(net, addr);
1227}
1228EXPORT_SYMBOL(libcfs_str2nid);
1229
1230char *
1231libcfs_id2str(lnet_process_id_t id)
1232{
1233        char *str = libcfs_next_nidstring();
1234
1235        if (id.pid == LNET_PID_ANY) {
1236                snprintf(str, LNET_NIDSTR_SIZE,
1237                         "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
1238                return str;
1239        }
1240
1241        snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
1242                 id.pid & LNET_PID_USERFLAG ? "U" : "",
1243                 id.pid & ~LNET_PID_USERFLAG, libcfs_nid2str(id.nid));
1244        return str;
1245}
1246EXPORT_SYMBOL(libcfs_id2str);
1247
1248int
1249libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
1250{
1251        if (!strcmp(str, "*")) {
1252                *nidp = LNET_NID_ANY;
1253                return 1;
1254        }
1255
1256        *nidp = libcfs_str2nid(str);
1257        return *nidp != LNET_NID_ANY;
1258}
1259EXPORT_SYMBOL(libcfs_str2anynid);
1260