linux/drivers/staging/lustre/lnet/lnet/config.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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  28 * Use is subject to license terms.
  29 *
  30 * Copyright (c) 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
  37#define DEBUG_SUBSYSTEM S_LNET
  38#include "../../include/linux/lnet/lib-lnet.h"
  39
  40typedef struct {                            /* tmp struct for parsing routes */
  41        struct list_head         ltb_list;      /* stash on lists */
  42        int             ltb_size;       /* allocated size */
  43        char           ltb_text[0];     /* text buffer */
  44} lnet_text_buf_t;
  45
  46static int lnet_tbnob;                  /* track text buf allocation */
  47#define LNET_MAX_TEXTBUF_NOB     (64<<10)       /* bound allocation */
  48#define LNET_SINGLE_TEXTBUF_NOB  (4<<10)
  49
  50static void
  51lnet_syntax(char *name, char *str, int offset, int width)
  52{
  53        static char dots[LNET_SINGLE_TEXTBUF_NOB];
  54        static char dashes[LNET_SINGLE_TEXTBUF_NOB];
  55
  56        memset(dots, '.', sizeof(dots));
  57        dots[sizeof(dots)-1] = 0;
  58        memset(dashes, '-', sizeof(dashes));
  59        dashes[sizeof(dashes)-1] = 0;
  60
  61        LCONSOLE_ERROR_MSG(0x10f, "Error parsing '%s=\"%s\"'\n", name, str);
  62        LCONSOLE_ERROR_MSG(0x110, "here...........%.*s..%.*s|%.*s|\n",
  63                           (int)strlen(name), dots, offset, dots,
  64                            (width < 1) ? 0 : width - 1, dashes);
  65}
  66
  67static int
  68lnet_issep(char c)
  69{
  70        switch (c) {
  71        case '\n':
  72        case '\r':
  73        case ';':
  74                return 1;
  75        default:
  76                return 0;
  77        }
  78}
  79
  80static int
  81lnet_net_unique(__u32 net, struct list_head *nilist)
  82{
  83        struct list_head       *tmp;
  84        lnet_ni_t       *ni;
  85
  86        list_for_each(tmp, nilist) {
  87                ni = list_entry(tmp, lnet_ni_t, ni_list);
  88
  89                if (LNET_NIDNET(ni->ni_nid) == net)
  90                        return 0;
  91        }
  92
  93        return 1;
  94}
  95
  96void
  97lnet_ni_free(struct lnet_ni *ni)
  98{
  99        if (ni->ni_refs != NULL)
 100                cfs_percpt_free(ni->ni_refs);
 101
 102        if (ni->ni_tx_queues != NULL)
 103                cfs_percpt_free(ni->ni_tx_queues);
 104
 105        if (ni->ni_cpts != NULL)
 106                cfs_expr_list_values_free(ni->ni_cpts, ni->ni_ncpts);
 107
 108        LIBCFS_FREE(ni, sizeof(*ni));
 109}
 110
 111static lnet_ni_t *
 112lnet_ni_alloc(__u32 net, struct cfs_expr_list *el, struct list_head *nilist)
 113{
 114        struct lnet_tx_queue    *tq;
 115        struct lnet_ni          *ni;
 116        int                     rc;
 117        int                     i;
 118
 119        if (!lnet_net_unique(net, nilist)) {
 120                LCONSOLE_ERROR_MSG(0x111, "Duplicate network specified: %s\n",
 121                                   libcfs_net2str(net));
 122                return NULL;
 123        }
 124
 125        LIBCFS_ALLOC(ni, sizeof(*ni));
 126        if (ni == NULL) {
 127                CERROR("Out of memory creating network %s\n",
 128                       libcfs_net2str(net));
 129                return NULL;
 130        }
 131
 132        spin_lock_init(&ni->ni_lock);
 133        INIT_LIST_HEAD(&ni->ni_cptlist);
 134        ni->ni_refs = cfs_percpt_alloc(lnet_cpt_table(),
 135                                       sizeof(*ni->ni_refs[0]));
 136        if (ni->ni_refs == NULL)
 137                goto failed;
 138
 139        ni->ni_tx_queues = cfs_percpt_alloc(lnet_cpt_table(),
 140                                            sizeof(*ni->ni_tx_queues[0]));
 141        if (ni->ni_tx_queues == NULL)
 142                goto failed;
 143
 144        cfs_percpt_for_each(tq, i, ni->ni_tx_queues)
 145                INIT_LIST_HEAD(&tq->tq_delayed);
 146
 147        if (el == NULL) {
 148                ni->ni_cpts  = NULL;
 149                ni->ni_ncpts = LNET_CPT_NUMBER;
 150        } else {
 151                rc = cfs_expr_list_values(el, LNET_CPT_NUMBER, &ni->ni_cpts);
 152                if (rc <= 0) {
 153                        CERROR("Failed to set CPTs for NI %s: %d\n",
 154                               libcfs_net2str(net), rc);
 155                        goto failed;
 156                }
 157
 158                LASSERT(rc <= LNET_CPT_NUMBER);
 159                if (rc == LNET_CPT_NUMBER) {
 160                        LIBCFS_FREE(ni->ni_cpts, rc * sizeof(ni->ni_cpts[0]));
 161                        ni->ni_cpts = NULL;
 162                }
 163
 164                ni->ni_ncpts = rc;
 165        }
 166
 167        /* LND will fill in the address part of the NID */
 168        ni->ni_nid = LNET_MKNID(net, 0);
 169        ni->ni_last_alive = get_seconds();
 170        list_add_tail(&ni->ni_list, nilist);
 171        return ni;
 172 failed:
 173        lnet_ni_free(ni);
 174        return NULL;
 175}
 176
 177int
 178lnet_parse_networks(struct list_head *nilist, char *networks)
 179{
 180        struct cfs_expr_list *el = NULL;
 181        int             tokensize = strlen(networks) + 1;
 182        char            *tokens;
 183        char            *str;
 184        char            *tmp;
 185        struct lnet_ni  *ni;
 186        __u32           net;
 187        int             nnets = 0;
 188
 189        if (strlen(networks) > LNET_SINGLE_TEXTBUF_NOB) {
 190                /* _WAY_ conservative */
 191                LCONSOLE_ERROR_MSG(0x112,
 192                                   "Can't parse networks: string too long\n");
 193                return -EINVAL;
 194        }
 195
 196        LIBCFS_ALLOC(tokens, tokensize);
 197        if (tokens == NULL) {
 198                CERROR("Can't allocate net tokens\n");
 199                return -ENOMEM;
 200        }
 201
 202        the_lnet.ln_network_tokens = tokens;
 203        the_lnet.ln_network_tokens_nob = tokensize;
 204        memcpy(tokens, networks, tokensize);
 205        str = tmp = tokens;
 206
 207        /* Add in the loopback network */
 208        ni = lnet_ni_alloc(LNET_MKNET(LOLND, 0), NULL, nilist);
 209        if (ni == NULL)
 210                goto failed;
 211
 212        while (str != NULL && *str != 0) {
 213                char    *comma = strchr(str, ',');
 214                char    *bracket = strchr(str, '(');
 215                char    *square = strchr(str, '[');
 216                char    *iface;
 217                int     niface;
 218                int     rc;
 219
 220                /* NB we don't check interface conflicts here; it's the LNDs
 221                 * responsibility (if it cares at all) */
 222
 223                if (square != NULL && (comma == NULL || square < comma)) {
 224                        /* i.e: o2ib0(ib0)[1,2], number between square
 225                         * brackets are CPTs this NI needs to be bond */
 226                        if (bracket != NULL && bracket > square) {
 227                                tmp = square;
 228                                goto failed_syntax;
 229                        }
 230
 231                        tmp = strchr(square, ']');
 232                        if (tmp == NULL) {
 233                                tmp = square;
 234                                goto failed_syntax;
 235                        }
 236
 237                        rc = cfs_expr_list_parse(square, tmp - square + 1,
 238                                                 0, LNET_CPT_NUMBER - 1, &el);
 239                        if (rc != 0) {
 240                                tmp = square;
 241                                goto failed_syntax;
 242                        }
 243
 244                        while (square <= tmp)
 245                                *square++ = ' ';
 246                }
 247
 248                if (bracket == NULL ||
 249                    (comma != NULL && comma < bracket)) {
 250
 251                        /* no interface list specified */
 252
 253                        if (comma != NULL)
 254                                *comma++ = 0;
 255                        net = libcfs_str2net(cfs_trimwhite(str));
 256
 257                        if (net == LNET_NIDNET(LNET_NID_ANY)) {
 258                                LCONSOLE_ERROR_MSG(0x113,
 259                                                   "Unrecognised network type\n");
 260                                tmp = str;
 261                                goto failed_syntax;
 262                        }
 263
 264                        if (LNET_NETTYP(net) != LOLND && /* LO is implicit */
 265                            lnet_ni_alloc(net, el, nilist) == NULL)
 266                                goto failed;
 267
 268                        if (el != NULL) {
 269                                cfs_expr_list_free(el);
 270                                el = NULL;
 271                        }
 272
 273                        str = comma;
 274                        continue;
 275                }
 276
 277                *bracket = 0;
 278                net = libcfs_str2net(cfs_trimwhite(str));
 279                if (net == LNET_NIDNET(LNET_NID_ANY)) {
 280                        tmp = str;
 281                        goto failed_syntax;
 282                }
 283
 284                nnets++;
 285                ni = lnet_ni_alloc(net, el, nilist);
 286                if (ni == NULL)
 287                        goto failed;
 288
 289                if (el != NULL) {
 290                        cfs_expr_list_free(el);
 291                        el = NULL;
 292                }
 293
 294                niface = 0;
 295                iface = bracket + 1;
 296
 297                bracket = strchr(iface, ')');
 298                if (bracket == NULL) {
 299                        tmp = iface;
 300                        goto failed_syntax;
 301                }
 302
 303                *bracket = 0;
 304                do {
 305                        comma = strchr(iface, ',');
 306                        if (comma != NULL)
 307                                *comma++ = 0;
 308
 309                        iface = cfs_trimwhite(iface);
 310                        if (*iface == 0) {
 311                                tmp = iface;
 312                                goto failed_syntax;
 313                        }
 314
 315                        if (niface == LNET_MAX_INTERFACES) {
 316                                LCONSOLE_ERROR_MSG(0x115,
 317                                                   "Too many interfaces for net %s\n",
 318                                                   libcfs_net2str(net));
 319                                goto failed;
 320                        }
 321
 322                        ni->ni_interfaces[niface++] = iface;
 323                        iface = comma;
 324                } while (iface != NULL);
 325
 326                str = bracket + 1;
 327                comma = strchr(bracket + 1, ',');
 328                if (comma != NULL) {
 329                        *comma = 0;
 330                        str = cfs_trimwhite(str);
 331                        if (*str != 0) {
 332                                tmp = str;
 333                                goto failed_syntax;
 334                        }
 335                        str = comma + 1;
 336                        continue;
 337                }
 338
 339                str = cfs_trimwhite(str);
 340                if (*str != 0) {
 341                        tmp = str;
 342                        goto failed_syntax;
 343                }
 344        }
 345
 346        LASSERT(!list_empty(nilist));
 347        return 0;
 348
 349 failed_syntax:
 350        lnet_syntax("networks", networks, (int)(tmp - tokens), strlen(tmp));
 351 failed:
 352        while (!list_empty(nilist)) {
 353                ni = list_entry(nilist->next, lnet_ni_t, ni_list);
 354
 355                list_del(&ni->ni_list);
 356                lnet_ni_free(ni);
 357        }
 358
 359        if (el != NULL)
 360                cfs_expr_list_free(el);
 361
 362        LIBCFS_FREE(tokens, tokensize);
 363        the_lnet.ln_network_tokens = NULL;
 364
 365        return -EINVAL;
 366}
 367
 368static lnet_text_buf_t *
 369lnet_new_text_buf(int str_len)
 370{
 371        lnet_text_buf_t *ltb;
 372        int           nob;
 373
 374        /* NB allocate space for the terminating 0 */
 375        nob = offsetof(lnet_text_buf_t, ltb_text[str_len + 1]);
 376        if (nob > LNET_SINGLE_TEXTBUF_NOB) {
 377                /* _way_ conservative for "route net gateway..." */
 378                CERROR("text buffer too big\n");
 379                return NULL;
 380        }
 381
 382        if (lnet_tbnob + nob > LNET_MAX_TEXTBUF_NOB) {
 383                CERROR("Too many text buffers\n");
 384                return NULL;
 385        }
 386
 387        LIBCFS_ALLOC(ltb, nob);
 388        if (ltb == NULL)
 389                return NULL;
 390
 391        ltb->ltb_size = nob;
 392        ltb->ltb_text[0] = 0;
 393        lnet_tbnob += nob;
 394        return ltb;
 395}
 396
 397static void
 398lnet_free_text_buf(lnet_text_buf_t *ltb)
 399{
 400        lnet_tbnob -= ltb->ltb_size;
 401        LIBCFS_FREE(ltb, ltb->ltb_size);
 402}
 403
 404static void
 405lnet_free_text_bufs(struct list_head *tbs)
 406{
 407        lnet_text_buf_t  *ltb;
 408
 409        while (!list_empty(tbs)) {
 410                ltb = list_entry(tbs->next, lnet_text_buf_t, ltb_list);
 411
 412                list_del(&ltb->ltb_list);
 413                lnet_free_text_buf(ltb);
 414        }
 415}
 416
 417static int
 418lnet_str2tbs_sep(struct list_head *tbs, char *str)
 419{
 420        struct list_head        pending;
 421        char         *sep;
 422        int            nob;
 423        int            i;
 424        lnet_text_buf_t  *ltb;
 425
 426        INIT_LIST_HEAD(&pending);
 427
 428        /* Split 'str' into separate commands */
 429        for (;;) {
 430                /* skip leading whitespace */
 431                while (isspace(*str))
 432                        str++;
 433
 434                /* scan for separator or comment */
 435                for (sep = str; *sep != 0; sep++)
 436                        if (lnet_issep(*sep) || *sep == '#')
 437                                break;
 438
 439                nob = (int)(sep - str);
 440                if (nob > 0) {
 441                        ltb = lnet_new_text_buf(nob);
 442                        if (ltb == NULL) {
 443                                lnet_free_text_bufs(&pending);
 444                                return -1;
 445                        }
 446
 447                        for (i = 0; i < nob; i++)
 448                                if (isspace(str[i]))
 449                                        ltb->ltb_text[i] = ' ';
 450                                else
 451                                        ltb->ltb_text[i] = str[i];
 452
 453                        ltb->ltb_text[nob] = 0;
 454
 455                        list_add_tail(&ltb->ltb_list, &pending);
 456                }
 457
 458                if (*sep == '#') {
 459                        /* scan for separator */
 460                        do {
 461                                sep++;
 462                        } while (*sep != 0 && !lnet_issep(*sep));
 463                }
 464
 465                if (*sep == 0)
 466                        break;
 467
 468                str = sep + 1;
 469        }
 470
 471        list_splice(&pending, tbs->prev);
 472        return 0;
 473}
 474
 475static int
 476lnet_expand1tb(struct list_head *list,
 477               char *str, char *sep1, char *sep2,
 478               char *item, int itemlen)
 479{
 480        int           len1 = (int)(sep1 - str);
 481        int           len2 = strlen(sep2 + 1);
 482        lnet_text_buf_t *ltb;
 483
 484        LASSERT(*sep1 == '[');
 485        LASSERT(*sep2 == ']');
 486
 487        ltb = lnet_new_text_buf(len1 + itemlen + len2);
 488        if (ltb == NULL)
 489                return -ENOMEM;
 490
 491        memcpy(ltb->ltb_text, str, len1);
 492        memcpy(&ltb->ltb_text[len1], item, itemlen);
 493        memcpy(&ltb->ltb_text[len1+itemlen], sep2 + 1, len2);
 494        ltb->ltb_text[len1 + itemlen + len2] = 0;
 495
 496        list_add_tail(&ltb->ltb_list, list);
 497        return 0;
 498}
 499
 500static int
 501lnet_str2tbs_expand(struct list_head *tbs, char *str)
 502{
 503        char          num[16];
 504        struct list_head        pending;
 505        char         *sep;
 506        char         *sep2;
 507        char         *parsed;
 508        char         *enditem;
 509        int            lo;
 510        int            hi;
 511        int            stride;
 512        int            i;
 513        int            nob;
 514        int            scanned;
 515
 516        INIT_LIST_HEAD(&pending);
 517
 518        sep = strchr(str, '[');
 519        if (sep == NULL)                        /* nothing to expand */
 520                return 0;
 521
 522        sep2 = strchr(sep, ']');
 523        if (sep2 == NULL)
 524                goto failed;
 525
 526        for (parsed = sep; parsed < sep2; parsed = enditem) {
 527
 528                enditem = ++parsed;
 529                while (enditem < sep2 && *enditem != ',')
 530                        enditem++;
 531
 532                if (enditem == parsed)          /* no empty items */
 533                        goto failed;
 534
 535                if (sscanf(parsed, "%d-%d/%d%n", &lo, &hi, &stride, &scanned) < 3) {
 536
 537                        if (sscanf(parsed, "%d-%d%n", &lo, &hi, &scanned) < 2) {
 538
 539                                /* simple string enumeration */
 540                                if (lnet_expand1tb(&pending, str, sep, sep2,
 541                                                   parsed, (int)(enditem - parsed)) != 0)
 542                                        goto failed;
 543
 544                                continue;
 545                        }
 546
 547                        stride = 1;
 548                }
 549
 550                /* range expansion */
 551
 552                if (enditem != parsed + scanned) /* no trailing junk */
 553                        goto failed;
 554
 555                if (hi < 0 || lo < 0 || stride < 0 || hi < lo ||
 556                    (hi - lo) % stride != 0)
 557                        goto failed;
 558
 559                for (i = lo; i <= hi; i += stride) {
 560
 561                        snprintf(num, sizeof(num), "%d", i);
 562                        nob = strlen(num);
 563                        if (nob + 1 == sizeof(num))
 564                                goto failed;
 565
 566                        if (lnet_expand1tb(&pending, str, sep, sep2,
 567                                           num, nob) != 0)
 568                                goto failed;
 569                }
 570        }
 571
 572        list_splice(&pending, tbs->prev);
 573        return 1;
 574
 575 failed:
 576        lnet_free_text_bufs(&pending);
 577        return -1;
 578}
 579
 580static int
 581lnet_parse_hops(char *str, unsigned int *hops)
 582{
 583        int     len = strlen(str);
 584        int     nob = len;
 585
 586        return (sscanf(str, "%u%n", hops, &nob) >= 1 &&
 587                nob == len &&
 588                *hops > 0 && *hops < 256);
 589}
 590
 591#define LNET_PRIORITY_SEPARATOR (':')
 592
 593static int
 594lnet_parse_priority(char *str, unsigned int *priority, char **token)
 595{
 596        int   nob;
 597        char *sep;
 598        int   len;
 599
 600        sep = strchr(str, LNET_PRIORITY_SEPARATOR);
 601        if (sep == NULL) {
 602                *priority = 0;
 603                return 0;
 604        }
 605        len = strlen(sep + 1);
 606
 607        if ((sscanf((sep+1), "%u%n", priority, &nob) < 1) || (len != nob)) {
 608                /* Update the caller's token pointer so it treats the found
 609                   priority as the token to report in the error message. */
 610                *token += sep - str + 1;
 611                return -1;
 612        }
 613
 614        CDEBUG(D_NET, "gateway %s, priority %d, nob %d\n", str, *priority, nob);
 615
 616        /*
 617         * Change priority separator to \0 to be able to parse NID
 618         */
 619        *sep = '\0';
 620        return 0;
 621}
 622
 623static int
 624lnet_parse_route(char *str, int *im_a_router)
 625{
 626        /* static scratch buffer OK (single threaded) */
 627        static char       cmd[LNET_SINGLE_TEXTBUF_NOB];
 628
 629        struct list_head        nets;
 630        struct list_head        gateways;
 631        struct list_head       *tmp1;
 632        struct list_head       *tmp2;
 633        __u32        net;
 634        lnet_nid_t      nid;
 635        lnet_text_buf_t  *ltb;
 636        int            rc;
 637        char         *sep;
 638        char         *token = str;
 639        int            ntokens = 0;
 640        int            myrc = -1;
 641        unsigned int      hops;
 642        int            got_hops = 0;
 643        unsigned int      priority = 0;
 644
 645        INIT_LIST_HEAD(&gateways);
 646        INIT_LIST_HEAD(&nets);
 647
 648        /* save a copy of the string for error messages */
 649        strncpy(cmd, str, sizeof(cmd) - 1);
 650        cmd[sizeof(cmd) - 1] = 0;
 651
 652        sep = str;
 653        for (;;) {
 654                /* scan for token start */
 655                while (isspace(*sep))
 656                        sep++;
 657                if (*sep == 0) {
 658                        if (ntokens < (got_hops ? 3 : 2))
 659                                goto token_error;
 660                        break;
 661                }
 662
 663                ntokens++;
 664                token = sep++;
 665
 666                /* scan for token end */
 667                while (*sep != 0 && !isspace(*sep))
 668                        sep++;
 669                if (*sep != 0)
 670                        *sep++ = 0;
 671
 672                if (ntokens == 1) {
 673                        tmp2 = &nets;           /* expanding nets */
 674                } else if (ntokens == 2 &&
 675                           lnet_parse_hops(token, &hops)) {
 676                        got_hops = 1;      /* got a hop count */
 677                        continue;
 678                } else {
 679                        tmp2 = &gateways;       /* expanding gateways */
 680                }
 681
 682                ltb = lnet_new_text_buf(strlen(token));
 683                if (ltb == NULL)
 684                        goto out;
 685
 686                strcpy(ltb->ltb_text, token);
 687                tmp1 = &ltb->ltb_list;
 688                list_add_tail(tmp1, tmp2);
 689
 690                while (tmp1 != tmp2) {
 691                        ltb = list_entry(tmp1, lnet_text_buf_t, ltb_list);
 692
 693                        rc = lnet_str2tbs_expand(tmp1->next, ltb->ltb_text);
 694                        if (rc < 0)
 695                                goto token_error;
 696
 697                        tmp1 = tmp1->next;
 698
 699                        if (rc > 0) {           /* expanded! */
 700                                list_del(&ltb->ltb_list);
 701                                lnet_free_text_buf(ltb);
 702                                continue;
 703                        }
 704
 705                        if (ntokens == 1) {
 706                                net = libcfs_str2net(ltb->ltb_text);
 707                                if (net == LNET_NIDNET(LNET_NID_ANY) ||
 708                                    LNET_NETTYP(net) == LOLND)
 709                                        goto token_error;
 710                        } else {
 711                                rc = lnet_parse_priority(ltb->ltb_text,
 712                                                         &priority, &token);
 713                                if (rc < 0)
 714                                        goto token_error;
 715
 716                                nid = libcfs_str2nid(ltb->ltb_text);
 717                                if (nid == LNET_NID_ANY ||
 718                                    LNET_NETTYP(LNET_NIDNET(nid)) == LOLND)
 719                                        goto token_error;
 720                        }
 721                }
 722        }
 723
 724        if (!got_hops)
 725                hops = 1;
 726
 727        LASSERT(!list_empty(&nets));
 728        LASSERT(!list_empty(&gateways));
 729
 730        list_for_each(tmp1, &nets) {
 731                ltb = list_entry(tmp1, lnet_text_buf_t, ltb_list);
 732                net = libcfs_str2net(ltb->ltb_text);
 733                LASSERT(net != LNET_NIDNET(LNET_NID_ANY));
 734
 735                list_for_each(tmp2, &gateways) {
 736                        ltb = list_entry(tmp2, lnet_text_buf_t, ltb_list);
 737                        nid = libcfs_str2nid(ltb->ltb_text);
 738                        LASSERT(nid != LNET_NID_ANY);
 739
 740                        if (lnet_islocalnid(nid)) {
 741                                *im_a_router = 1;
 742                                continue;
 743                        }
 744
 745                        rc = lnet_add_route(net, hops, nid, priority);
 746                        if (rc != 0) {
 747                                CERROR("Can't create route to %s via %s\n",
 748                                       libcfs_net2str(net),
 749                                       libcfs_nid2str(nid));
 750                                goto out;
 751                        }
 752                }
 753        }
 754
 755        myrc = 0;
 756        goto out;
 757
 758 token_error:
 759        lnet_syntax("routes", cmd, (int)(token - str), strlen(token));
 760 out:
 761        lnet_free_text_bufs(&nets);
 762        lnet_free_text_bufs(&gateways);
 763        return myrc;
 764}
 765
 766static int
 767lnet_parse_route_tbs(struct list_head *tbs, int *im_a_router)
 768{
 769        lnet_text_buf_t   *ltb;
 770
 771        while (!list_empty(tbs)) {
 772                ltb = list_entry(tbs->next, lnet_text_buf_t, ltb_list);
 773
 774                if (lnet_parse_route(ltb->ltb_text, im_a_router) < 0) {
 775                        lnet_free_text_bufs(tbs);
 776                        return -EINVAL;
 777                }
 778
 779                list_del(&ltb->ltb_list);
 780                lnet_free_text_buf(ltb);
 781        }
 782
 783        return 0;
 784}
 785
 786int
 787lnet_parse_routes(char *routes, int *im_a_router)
 788{
 789        struct list_head        tbs;
 790        int            rc = 0;
 791
 792        *im_a_router = 0;
 793
 794        INIT_LIST_HEAD(&tbs);
 795
 796        if (lnet_str2tbs_sep(&tbs, routes) < 0) {
 797                CERROR("Error parsing routes\n");
 798                rc = -EINVAL;
 799        } else {
 800                rc = lnet_parse_route_tbs(&tbs, im_a_router);
 801        }
 802
 803        LASSERT(lnet_tbnob == 0);
 804        return rc;
 805}
 806
 807static int
 808lnet_match_network_token(char *token, int len, __u32 *ipaddrs, int nip)
 809{
 810        LIST_HEAD(list);
 811        int             rc;
 812        int             i;
 813
 814        rc = cfs_ip_addr_parse(token, len, &list);
 815        if (rc != 0)
 816                return rc;
 817
 818        for (rc = i = 0; !rc && i < nip; i++)
 819                rc = cfs_ip_addr_match(ipaddrs[i], &list);
 820
 821        cfs_ip_addr_free(&list);
 822
 823        return rc;
 824}
 825
 826static int
 827lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
 828{
 829        static char tokens[LNET_SINGLE_TEXTBUF_NOB];
 830
 831        int   matched = 0;
 832        int   ntokens = 0;
 833        int   len;
 834        char *net = NULL;
 835        char *sep;
 836        char *token;
 837        int   rc;
 838
 839        LASSERT(strlen(net_entry) < sizeof(tokens));
 840
 841        /* work on a copy of the string */
 842        strcpy(tokens, net_entry);
 843        sep = tokens;
 844        for (;;) {
 845                /* scan for token start */
 846                while (isspace(*sep))
 847                        sep++;
 848                if (*sep == 0)
 849                        break;
 850
 851                token = sep++;
 852
 853                /* scan for token end */
 854                while (*sep != 0 && !isspace(*sep))
 855                        sep++;
 856                if (*sep != 0)
 857                        *sep++ = 0;
 858
 859                if (ntokens++ == 0) {
 860                        net = token;
 861                        continue;
 862                }
 863
 864                len = strlen(token);
 865
 866                rc = lnet_match_network_token(token, len, ipaddrs, nip);
 867                if (rc < 0) {
 868                        lnet_syntax("ip2nets", net_entry,
 869                                    (int)(token - tokens), len);
 870                        return rc;
 871                }
 872
 873                matched |= (rc != 0);
 874        }
 875
 876        if (!matched)
 877                return 0;
 878
 879        strcpy(net_entry, net);          /* replace with matched net */
 880        return 1;
 881}
 882
 883static __u32
 884lnet_netspec2net(char *netspec)
 885{
 886        char   *bracket = strchr(netspec, '(');
 887        __u32   net;
 888
 889        if (bracket != NULL)
 890                *bracket = 0;
 891
 892        net = libcfs_str2net(netspec);
 893
 894        if (bracket != NULL)
 895                *bracket = '(';
 896
 897        return net;
 898}
 899
 900static int
 901lnet_splitnets(char *source, struct list_head *nets)
 902{
 903        int            offset = 0;
 904        int            offset2;
 905        int            len;
 906        lnet_text_buf_t  *tb;
 907        lnet_text_buf_t  *tb2;
 908        struct list_head       *t;
 909        char         *sep;
 910        char         *bracket;
 911        __u32        net;
 912
 913        LASSERT(!list_empty(nets));
 914        LASSERT(nets->next == nets->prev);     /* single entry */
 915
 916        tb = list_entry(nets->next, lnet_text_buf_t, ltb_list);
 917
 918        for (;;) {
 919                sep = strchr(tb->ltb_text, ',');
 920                bracket = strchr(tb->ltb_text, '(');
 921
 922                if (sep != NULL &&
 923                    bracket != NULL &&
 924                    bracket < sep) {
 925                        /* netspec lists interfaces... */
 926
 927                        offset2 = offset + (int)(bracket - tb->ltb_text);
 928                        len = strlen(bracket);
 929
 930                        bracket = strchr(bracket + 1, ')');
 931
 932                        if (bracket == NULL ||
 933                            !(bracket[1] == ',' || bracket[1] == 0)) {
 934                                lnet_syntax("ip2nets", source, offset2, len);
 935                                return -EINVAL;
 936                        }
 937
 938                        sep = (bracket[1] == 0) ? NULL : bracket + 1;
 939                }
 940
 941                if (sep != NULL)
 942                        *sep++ = 0;
 943
 944                net = lnet_netspec2net(tb->ltb_text);
 945                if (net == LNET_NIDNET(LNET_NID_ANY)) {
 946                        lnet_syntax("ip2nets", source, offset,
 947                                    strlen(tb->ltb_text));
 948                        return -EINVAL;
 949                }
 950
 951                list_for_each(t, nets) {
 952                        tb2 = list_entry(t, lnet_text_buf_t, ltb_list);
 953
 954                        if (tb2 == tb)
 955                                continue;
 956
 957                        if (net == lnet_netspec2net(tb2->ltb_text)) {
 958                                /* duplicate network */
 959                                lnet_syntax("ip2nets", source, offset,
 960                                            strlen(tb->ltb_text));
 961                                return -EINVAL;
 962                        }
 963                }
 964
 965                if (sep == NULL)
 966                        return 0;
 967
 968                offset += (int)(sep - tb->ltb_text);
 969                tb2 = lnet_new_text_buf(strlen(sep));
 970                if (tb2 == NULL)
 971                        return -ENOMEM;
 972
 973                strcpy(tb2->ltb_text, sep);
 974                list_add_tail(&tb2->ltb_list, nets);
 975
 976                tb = tb2;
 977        }
 978}
 979
 980static int
 981lnet_match_networks(char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
 982{
 983        static char     networks[LNET_SINGLE_TEXTBUF_NOB];
 984        static char     source[LNET_SINGLE_TEXTBUF_NOB];
 985
 986        struct list_head          raw_entries;
 987        struct list_head          matched_nets;
 988        struct list_head          current_nets;
 989        struct list_head         *t;
 990        struct list_head         *t2;
 991        lnet_text_buf_t    *tb;
 992        lnet_text_buf_t    *tb2;
 993        __u32          net1;
 994        __u32          net2;
 995        int              len;
 996        int              count;
 997        int              dup;
 998        int              rc;
 999
1000        INIT_LIST_HEAD(&raw_entries);
1001        if (lnet_str2tbs_sep(&raw_entries, ip2nets) < 0) {
1002                CERROR("Error parsing ip2nets\n");
1003                LASSERT(lnet_tbnob == 0);
1004                return -EINVAL;
1005        }
1006
1007        INIT_LIST_HEAD(&matched_nets);
1008        INIT_LIST_HEAD(&current_nets);
1009        networks[0] = 0;
1010        count = 0;
1011        len = 0;
1012        rc = 0;
1013
1014        while (!list_empty(&raw_entries)) {
1015                tb = list_entry(raw_entries.next, lnet_text_buf_t,
1016                                    ltb_list);
1017
1018                strncpy(source, tb->ltb_text, sizeof(source)-1);
1019                source[sizeof(source)-1] = 0;
1020
1021                /* replace ltb_text with the network(s) add on match */
1022                rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
1023                if (rc < 0)
1024                        break;
1025
1026                list_del(&tb->ltb_list);
1027
1028                if (rc == 0) {            /* no match */
1029                        lnet_free_text_buf(tb);
1030                        continue;
1031                }
1032
1033                /* split into separate networks */
1034                INIT_LIST_HEAD(&current_nets);
1035                list_add(&tb->ltb_list, &current_nets);
1036                rc = lnet_splitnets(source, &current_nets);
1037                if (rc < 0)
1038                        break;
1039
1040                dup = 0;
1041                list_for_each(t, &current_nets) {
1042                        tb = list_entry(t, lnet_text_buf_t, ltb_list);
1043                        net1 = lnet_netspec2net(tb->ltb_text);
1044                        LASSERT(net1 != LNET_NIDNET(LNET_NID_ANY));
1045
1046                        list_for_each(t2, &matched_nets) {
1047                                tb2 = list_entry(t2, lnet_text_buf_t,
1048                                                     ltb_list);
1049                                net2 = lnet_netspec2net(tb2->ltb_text);
1050                                LASSERT(net2 != LNET_NIDNET(LNET_NID_ANY));
1051
1052                                if (net1 == net2) {
1053                                        dup = 1;
1054                                        break;
1055                                }
1056                        }
1057
1058                        if (dup)
1059                                break;
1060                }
1061
1062                if (dup) {
1063                        lnet_free_text_bufs(&current_nets);
1064                        continue;
1065                }
1066
1067                list_for_each_safe(t, t2, &current_nets) {
1068                        tb = list_entry(t, lnet_text_buf_t, ltb_list);
1069
1070                        list_del(&tb->ltb_list);
1071                        list_add_tail(&tb->ltb_list, &matched_nets);
1072
1073                        len += snprintf(networks + len, sizeof(networks) - len,
1074                                        "%s%s", (len == 0) ? "" : ",",
1075                                        tb->ltb_text);
1076
1077                        if (len >= sizeof(networks)) {
1078                                CERROR("Too many matched networks\n");
1079                                rc = -E2BIG;
1080                                goto out;
1081                        }
1082                }
1083
1084                count++;
1085        }
1086
1087 out:
1088        lnet_free_text_bufs(&raw_entries);
1089        lnet_free_text_bufs(&matched_nets);
1090        lnet_free_text_bufs(&current_nets);
1091        LASSERT(lnet_tbnob == 0);
1092
1093        if (rc < 0)
1094                return rc;
1095
1096        *networksp = networks;
1097        return count;
1098}
1099
1100static void
1101lnet_ipaddr_free_enumeration(__u32 *ipaddrs, int nip)
1102{
1103        LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
1104}
1105
1106static int
1107lnet_ipaddr_enumerate(__u32 **ipaddrsp)
1108{
1109        int     up;
1110        __u32      netmask;
1111        __u32     *ipaddrs;
1112        __u32     *ipaddrs2;
1113        int     nip;
1114        char     **ifnames;
1115        int     nif = libcfs_ipif_enumerate(&ifnames);
1116        int     i;
1117        int     rc;
1118
1119        if (nif <= 0)
1120                return nif;
1121
1122        LIBCFS_ALLOC(ipaddrs, nif * sizeof(*ipaddrs));
1123        if (ipaddrs == NULL) {
1124                CERROR("Can't allocate ipaddrs[%d]\n", nif);
1125                libcfs_ipif_free_enumeration(ifnames, nif);
1126                return -ENOMEM;
1127        }
1128
1129        for (i = nip = 0; i < nif; i++) {
1130                if (!strcmp(ifnames[i], "lo"))
1131                        continue;
1132
1133                rc = libcfs_ipif_query(ifnames[i], &up,
1134                                       &ipaddrs[nip], &netmask);
1135                if (rc != 0) {
1136                        CWARN("Can't query interface %s: %d\n",
1137                              ifnames[i], rc);
1138                        continue;
1139                }
1140
1141                if (!up) {
1142                        CWARN("Ignoring interface %s: it's down\n",
1143                              ifnames[i]);
1144                        continue;
1145                }
1146
1147                nip++;
1148        }
1149
1150        libcfs_ipif_free_enumeration(ifnames, nif);
1151
1152        if (nip == nif) {
1153                *ipaddrsp = ipaddrs;
1154        } else {
1155                if (nip > 0) {
1156                        LIBCFS_ALLOC(ipaddrs2, nip * sizeof(*ipaddrs2));
1157                        if (ipaddrs2 == NULL) {
1158                                CERROR("Can't allocate ipaddrs[%d]\n", nip);
1159                                nip = -ENOMEM;
1160                        } else {
1161                                memcpy(ipaddrs2, ipaddrs,
1162                                       nip * sizeof(*ipaddrs));
1163                                *ipaddrsp = ipaddrs2;
1164                                rc = nip;
1165                        }
1166                }
1167                lnet_ipaddr_free_enumeration(ipaddrs, nif);
1168        }
1169        return nip;
1170}
1171
1172int
1173lnet_parse_ip2nets(char **networksp, char *ip2nets)
1174{
1175        __u32     *ipaddrs = NULL;
1176        int     nip = lnet_ipaddr_enumerate(&ipaddrs);
1177        int     rc;
1178
1179        if (nip < 0) {
1180                LCONSOLE_ERROR_MSG(0x117,
1181                                   "Error %d enumerating local IP interfaces for ip2nets to match\n",
1182                                   nip);
1183                return nip;
1184        }
1185
1186        if (nip == 0) {
1187                LCONSOLE_ERROR_MSG(0x118,
1188                                   "No local IP interfaces for ip2nets to match\n");
1189                return -ENOENT;
1190        }
1191
1192        rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
1193        lnet_ipaddr_free_enumeration(ipaddrs, nip);
1194
1195        if (rc < 0) {
1196                LCONSOLE_ERROR_MSG(0x119, "Error %d parsing ip2nets\n", rc);
1197                return rc;
1198        }
1199
1200        if (rc == 0) {
1201                LCONSOLE_ERROR_MSG(0x11a,
1202                                   "ip2nets does not match any local IP interfaces\n");
1203                return -ENOENT;
1204        }
1205
1206        return 0;
1207}
1208
1209int
1210lnet_set_ip_niaddr(lnet_ni_t *ni)
1211{
1212        __u32  net = LNET_NIDNET(ni->ni_nid);
1213        char **names;
1214        int    n;
1215        __u32  ip;
1216        __u32  netmask;
1217        int    up;
1218        int    i;
1219        int    rc;
1220
1221        /* Convenience for LNDs that use the IP address of a local interface as
1222         * the local address part of their NID */
1223
1224        if (ni->ni_interfaces[0] != NULL) {
1225
1226                CLASSERT(LNET_MAX_INTERFACES > 1);
1227
1228                if (ni->ni_interfaces[1] != NULL) {
1229                        CERROR("Net %s doesn't support multiple interfaces\n",
1230                               libcfs_net2str(net));
1231                        return -EPERM;
1232                }
1233
1234                rc = libcfs_ipif_query(ni->ni_interfaces[0],
1235                                       &up, &ip, &netmask);
1236                if (rc != 0) {
1237                        CERROR("Net %s can't query interface %s: %d\n",
1238                               libcfs_net2str(net), ni->ni_interfaces[0], rc);
1239                        return -EPERM;
1240                }
1241
1242                if (!up) {
1243                        CERROR("Net %s can't use interface %s: it's down\n",
1244                               libcfs_net2str(net), ni->ni_interfaces[0]);
1245                        return -ENETDOWN;
1246                }
1247
1248                ni->ni_nid = LNET_MKNID(net, ip);
1249                return 0;
1250        }
1251
1252        n = libcfs_ipif_enumerate(&names);
1253        if (n <= 0) {
1254                CERROR("Net %s can't enumerate interfaces: %d\n",
1255                       libcfs_net2str(net), n);
1256                return 0;
1257        }
1258
1259        for (i = 0; i < n; i++) {
1260                if (!strcmp(names[i], "lo")) /* skip the loopback IF */
1261                        continue;
1262
1263                rc = libcfs_ipif_query(names[i], &up, &ip, &netmask);
1264
1265                if (rc != 0) {
1266                        CWARN("Net %s can't query interface %s: %d\n",
1267                              libcfs_net2str(net), names[i], rc);
1268                        continue;
1269                }
1270
1271                if (!up) {
1272                        CWARN("Net %s ignoring interface %s (down)\n",
1273                              libcfs_net2str(net), names[i]);
1274                        continue;
1275                }
1276
1277                libcfs_ipif_free_enumeration(names, n);
1278                ni->ni_nid = LNET_MKNID(net, ip);
1279                return 0;
1280        }
1281
1282        CERROR("Net %s can't find any interfaces\n", libcfs_net2str(net));
1283        libcfs_ipif_free_enumeration(names, n);
1284        return -ENOENT;
1285}
1286EXPORT_SYMBOL(lnet_set_ip_niaddr);
1287