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