linux/net/tipc/bearer.c
<<
>>
Prefs
   1/*
   2 * net/tipc/bearer.c: TIPC bearer code
   3 *
   4 * Copyright (c) 1996-2006, Ericsson AB
   5 * Copyright (c) 2004-2006, 2010-2011, Wind River Systems
   6 * All rights reserved.
   7 *
   8 * Redistribution and use in source and binary forms, with or without
   9 * modification, are permitted provided that the following conditions are met:
  10 *
  11 * 1. Redistributions of source code must retain the above copyright
  12 *    notice, this list of conditions and the following disclaimer.
  13 * 2. Redistributions in binary form must reproduce the above copyright
  14 *    notice, this list of conditions and the following disclaimer in the
  15 *    documentation and/or other materials provided with the distribution.
  16 * 3. Neither the names of the copyright holders nor the names of its
  17 *    contributors may be used to endorse or promote products derived from
  18 *    this software without specific prior written permission.
  19 *
  20 * Alternatively, this software may be distributed under the terms of the
  21 * GNU General Public License ("GPL") version 2 as published by the Free
  22 * Software Foundation.
  23 *
  24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34 * POSSIBILITY OF SUCH DAMAGE.
  35 */
  36
  37#include "core.h"
  38#include "config.h"
  39#include "bearer.h"
  40#include "discover.h"
  41
  42#define MAX_ADDR_STR 32
  43
  44static struct tipc_media *media_list[MAX_MEDIA];
  45static u32 media_count;
  46
  47struct tipc_bearer tipc_bearers[MAX_BEARERS];
  48
  49static void bearer_disable(struct tipc_bearer *b_ptr);
  50
  51/**
  52 * media_name_valid - validate media name
  53 *
  54 * Returns 1 if media name is valid, otherwise 0.
  55 */
  56static int media_name_valid(const char *name)
  57{
  58        u32 len;
  59
  60        len = strlen(name);
  61        if ((len + 1) > TIPC_MAX_MEDIA_NAME)
  62                return 0;
  63        return strspn(name, tipc_alphabet) == len;
  64}
  65
  66/**
  67 * tipc_media_find - locates specified media object by name
  68 */
  69struct tipc_media *tipc_media_find(const char *name)
  70{
  71        u32 i;
  72
  73        for (i = 0; i < media_count; i++) {
  74                if (!strcmp(media_list[i]->name, name))
  75                        return media_list[i];
  76        }
  77        return NULL;
  78}
  79
  80/**
  81 * media_find_id - locates specified media object by type identifier
  82 */
  83static struct tipc_media *media_find_id(u8 type)
  84{
  85        u32 i;
  86
  87        for (i = 0; i < media_count; i++) {
  88                if (media_list[i]->type_id == type)
  89                        return media_list[i];
  90        }
  91        return NULL;
  92}
  93
  94/**
  95 * tipc_register_media - register a media type
  96 *
  97 * Bearers for this media type must be activated separately at a later stage.
  98 */
  99int tipc_register_media(struct tipc_media *m_ptr)
 100{
 101        int res = -EINVAL;
 102
 103        write_lock_bh(&tipc_net_lock);
 104
 105        if (!media_name_valid(m_ptr->name))
 106                goto exit;
 107        if ((m_ptr->bcast_addr.media_id != m_ptr->type_id) ||
 108            !m_ptr->bcast_addr.broadcast)
 109                goto exit;
 110        if (m_ptr->priority > TIPC_MAX_LINK_PRI)
 111                goto exit;
 112        if ((m_ptr->tolerance < TIPC_MIN_LINK_TOL) ||
 113            (m_ptr->tolerance > TIPC_MAX_LINK_TOL))
 114                goto exit;
 115        if (media_count >= MAX_MEDIA)
 116                goto exit;
 117        if (tipc_media_find(m_ptr->name) || media_find_id(m_ptr->type_id))
 118                goto exit;
 119
 120        media_list[media_count] = m_ptr;
 121        media_count++;
 122        res = 0;
 123exit:
 124        write_unlock_bh(&tipc_net_lock);
 125        if (res)
 126                pr_warn("Media <%s> registration error\n", m_ptr->name);
 127        return res;
 128}
 129
 130/**
 131 * tipc_media_addr_printf - record media address in print buffer
 132 */
 133void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a)
 134{
 135        char addr_str[MAX_ADDR_STR];
 136        struct tipc_media *m_ptr;
 137        int ret;
 138
 139        m_ptr = media_find_id(a->media_id);
 140
 141        if (m_ptr && !m_ptr->addr2str(a, addr_str, sizeof(addr_str)))
 142                ret = tipc_snprintf(buf, len, "%s(%s)", m_ptr->name, addr_str);
 143        else {
 144                u32 i;
 145
 146                ret = tipc_snprintf(buf, len, "UNKNOWN(%u)", a->media_id);
 147                for (i = 0; i < sizeof(a->value); i++)
 148                        ret += tipc_snprintf(buf - ret, len + ret,
 149                                            "-%02x", a->value[i]);
 150        }
 151}
 152
 153/**
 154 * tipc_media_get_names - record names of registered media in buffer
 155 */
 156struct sk_buff *tipc_media_get_names(void)
 157{
 158        struct sk_buff *buf;
 159        int i;
 160
 161        buf = tipc_cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
 162        if (!buf)
 163                return NULL;
 164
 165        read_lock_bh(&tipc_net_lock);
 166        for (i = 0; i < media_count; i++) {
 167                tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME,
 168                                    media_list[i]->name,
 169                                    strlen(media_list[i]->name) + 1);
 170        }
 171        read_unlock_bh(&tipc_net_lock);
 172        return buf;
 173}
 174
 175/**
 176 * bearer_name_validate - validate & (optionally) deconstruct bearer name
 177 * @name: ptr to bearer name string
 178 * @name_parts: ptr to area for bearer name components (or NULL if not needed)
 179 *
 180 * Returns 1 if bearer name is valid, otherwise 0.
 181 */
 182static int bearer_name_validate(const char *name,
 183                                struct tipc_bearer_names *name_parts)
 184{
 185        char name_copy[TIPC_MAX_BEARER_NAME];
 186        char *media_name;
 187        char *if_name;
 188        u32 media_len;
 189        u32 if_len;
 190
 191        /* copy bearer name & ensure length is OK */
 192        name_copy[TIPC_MAX_BEARER_NAME - 1] = 0;
 193        /* need above in case non-Posix strncpy() doesn't pad with nulls */
 194        strncpy(name_copy, name, TIPC_MAX_BEARER_NAME);
 195        if (name_copy[TIPC_MAX_BEARER_NAME - 1] != 0)
 196                return 0;
 197
 198        /* ensure all component parts of bearer name are present */
 199        media_name = name_copy;
 200        if_name = strchr(media_name, ':');
 201        if (if_name == NULL)
 202                return 0;
 203        *(if_name++) = 0;
 204        media_len = if_name - media_name;
 205        if_len = strlen(if_name) + 1;
 206
 207        /* validate component parts of bearer name */
 208        if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) ||
 209            (if_len <= 1) || (if_len > TIPC_MAX_IF_NAME) ||
 210            (strspn(media_name, tipc_alphabet) != (media_len - 1)) ||
 211            (strspn(if_name, tipc_alphabet) != (if_len - 1)))
 212                return 0;
 213
 214        /* return bearer name components, if necessary */
 215        if (name_parts) {
 216                strcpy(name_parts->media_name, media_name);
 217                strcpy(name_parts->if_name, if_name);
 218        }
 219        return 1;
 220}
 221
 222/**
 223 * tipc_bearer_find - locates bearer object with matching bearer name
 224 */
 225struct tipc_bearer *tipc_bearer_find(const char *name)
 226{
 227        struct tipc_bearer *b_ptr;
 228        u32 i;
 229
 230        for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
 231                if (b_ptr->active && (!strcmp(b_ptr->name, name)))
 232                        return b_ptr;
 233        }
 234        return NULL;
 235}
 236
 237/**
 238 * tipc_bearer_find_interface - locates bearer object with matching interface name
 239 */
 240struct tipc_bearer *tipc_bearer_find_interface(const char *if_name)
 241{
 242        struct tipc_bearer *b_ptr;
 243        char *b_if_name;
 244        u32 i;
 245
 246        for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
 247                if (!b_ptr->active)
 248                        continue;
 249                b_if_name = strchr(b_ptr->name, ':') + 1;
 250                if (!strcmp(b_if_name, if_name))
 251                        return b_ptr;
 252        }
 253        return NULL;
 254}
 255
 256/**
 257 * tipc_bearer_get_names - record names of bearers in buffer
 258 */
 259struct sk_buff *tipc_bearer_get_names(void)
 260{
 261        struct sk_buff *buf;
 262        struct tipc_bearer *b_ptr;
 263        int i, j;
 264
 265        buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
 266        if (!buf)
 267                return NULL;
 268
 269        read_lock_bh(&tipc_net_lock);
 270        for (i = 0; i < media_count; i++) {
 271                for (j = 0; j < MAX_BEARERS; j++) {
 272                        b_ptr = &tipc_bearers[j];
 273                        if (b_ptr->active && (b_ptr->media == media_list[i])) {
 274                                tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
 275                                                    b_ptr->name,
 276                                                    strlen(b_ptr->name) + 1);
 277                        }
 278                }
 279        }
 280        read_unlock_bh(&tipc_net_lock);
 281        return buf;
 282}
 283
 284void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest)
 285{
 286        tipc_nmap_add(&b_ptr->nodes, dest);
 287        tipc_bcbearer_sort();
 288        tipc_disc_add_dest(b_ptr->link_req);
 289}
 290
 291void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest)
 292{
 293        tipc_nmap_remove(&b_ptr->nodes, dest);
 294        tipc_bcbearer_sort();
 295        tipc_disc_remove_dest(b_ptr->link_req);
 296}
 297
 298/*
 299 * bearer_push(): Resolve bearer congestion. Force the waiting
 300 * links to push out their unsent packets, one packet per link
 301 * per iteration, until all packets are gone or congestion reoccurs.
 302 * 'tipc_net_lock' is read_locked when this function is called
 303 * bearer.lock must be taken before calling
 304 * Returns binary true(1) ore false(0)
 305 */
 306static int bearer_push(struct tipc_bearer *b_ptr)
 307{
 308        u32 res = 0;
 309        struct tipc_link *ln, *tln;
 310
 311        if (b_ptr->blocked)
 312                return 0;
 313
 314        while (!list_empty(&b_ptr->cong_links) && (res != PUSH_FAILED)) {
 315                list_for_each_entry_safe(ln, tln, &b_ptr->cong_links, link_list) {
 316                        res = tipc_link_push_packet(ln);
 317                        if (res == PUSH_FAILED)
 318                                break;
 319                        if (res == PUSH_FINISHED)
 320                                list_move_tail(&ln->link_list, &b_ptr->links);
 321                }
 322        }
 323        return list_empty(&b_ptr->cong_links);
 324}
 325
 326void tipc_bearer_lock_push(struct tipc_bearer *b_ptr)
 327{
 328        spin_lock_bh(&b_ptr->lock);
 329        bearer_push(b_ptr);
 330        spin_unlock_bh(&b_ptr->lock);
 331}
 332
 333
 334/*
 335 * Interrupt enabling new requests after bearer congestion or blocking:
 336 * See bearer_send().
 337 */
 338void tipc_continue(struct tipc_bearer *b_ptr)
 339{
 340        spin_lock_bh(&b_ptr->lock);
 341        if (!list_empty(&b_ptr->cong_links))
 342                tipc_k_signal((Handler)tipc_bearer_lock_push, (unsigned long)b_ptr);
 343        b_ptr->blocked = 0;
 344        spin_unlock_bh(&b_ptr->lock);
 345}
 346
 347/*
 348 * Schedule link for sending of messages after the bearer
 349 * has been deblocked by 'continue()'. This method is called
 350 * when somebody tries to send a message via this link while
 351 * the bearer is congested. 'tipc_net_lock' is in read_lock here
 352 * bearer.lock is busy
 353 */
 354static void tipc_bearer_schedule_unlocked(struct tipc_bearer *b_ptr,
 355                                                struct tipc_link *l_ptr)
 356{
 357        list_move_tail(&l_ptr->link_list, &b_ptr->cong_links);
 358}
 359
 360/*
 361 * Schedule link for sending of messages after the bearer
 362 * has been deblocked by 'continue()'. This method is called
 363 * when somebody tries to send a message via this link while
 364 * the bearer is congested. 'tipc_net_lock' is in read_lock here,
 365 * bearer.lock is free
 366 */
 367void tipc_bearer_schedule(struct tipc_bearer *b_ptr, struct tipc_link *l_ptr)
 368{
 369        spin_lock_bh(&b_ptr->lock);
 370        tipc_bearer_schedule_unlocked(b_ptr, l_ptr);
 371        spin_unlock_bh(&b_ptr->lock);
 372}
 373
 374
 375/*
 376 * tipc_bearer_resolve_congestion(): Check if there is bearer congestion,
 377 * and if there is, try to resolve it before returning.
 378 * 'tipc_net_lock' is read_locked when this function is called
 379 */
 380int tipc_bearer_resolve_congestion(struct tipc_bearer *b_ptr,
 381                                        struct tipc_link *l_ptr)
 382{
 383        int res = 1;
 384
 385        if (list_empty(&b_ptr->cong_links))
 386                return 1;
 387        spin_lock_bh(&b_ptr->lock);
 388        if (!bearer_push(b_ptr)) {
 389                tipc_bearer_schedule_unlocked(b_ptr, l_ptr);
 390                res = 0;
 391        }
 392        spin_unlock_bh(&b_ptr->lock);
 393        return res;
 394}
 395
 396/**
 397 * tipc_bearer_congested - determines if bearer is currently congested
 398 */
 399int tipc_bearer_congested(struct tipc_bearer *b_ptr, struct tipc_link *l_ptr)
 400{
 401        if (unlikely(b_ptr->blocked))
 402                return 1;
 403        if (likely(list_empty(&b_ptr->cong_links)))
 404                return 0;
 405        return !tipc_bearer_resolve_congestion(b_ptr, l_ptr);
 406}
 407
 408/**
 409 * tipc_enable_bearer - enable bearer with the given name
 410 */
 411int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
 412{
 413        struct tipc_bearer *b_ptr;
 414        struct tipc_media *m_ptr;
 415        struct tipc_bearer_names b_names;
 416        char addr_string[16];
 417        u32 bearer_id;
 418        u32 with_this_prio;
 419        u32 i;
 420        int res = -EINVAL;
 421
 422        if (!tipc_own_addr) {
 423                pr_warn("Bearer <%s> rejected, not supported in standalone mode\n",
 424                        name);
 425                return -ENOPROTOOPT;
 426        }
 427        if (!bearer_name_validate(name, &b_names)) {
 428                pr_warn("Bearer <%s> rejected, illegal name\n", name);
 429                return -EINVAL;
 430        }
 431        if (tipc_addr_domain_valid(disc_domain) &&
 432            (disc_domain != tipc_own_addr)) {
 433                if (tipc_in_scope(disc_domain, tipc_own_addr)) {
 434                        disc_domain = tipc_own_addr & TIPC_CLUSTER_MASK;
 435                        res = 0;   /* accept any node in own cluster */
 436                } else if (in_own_cluster_exact(disc_domain))
 437                        res = 0;   /* accept specified node in own cluster */
 438        }
 439        if (res) {
 440                pr_warn("Bearer <%s> rejected, illegal discovery domain\n",
 441                        name);
 442                return -EINVAL;
 443        }
 444        if ((priority > TIPC_MAX_LINK_PRI) &&
 445            (priority != TIPC_MEDIA_LINK_PRI)) {
 446                pr_warn("Bearer <%s> rejected, illegal priority\n", name);
 447                return -EINVAL;
 448        }
 449
 450        write_lock_bh(&tipc_net_lock);
 451
 452        m_ptr = tipc_media_find(b_names.media_name);
 453        if (!m_ptr) {
 454                pr_warn("Bearer <%s> rejected, media <%s> not registered\n",
 455                        name, b_names.media_name);
 456                goto exit;
 457        }
 458
 459        if (priority == TIPC_MEDIA_LINK_PRI)
 460                priority = m_ptr->priority;
 461
 462restart:
 463        bearer_id = MAX_BEARERS;
 464        with_this_prio = 1;
 465        for (i = MAX_BEARERS; i-- != 0; ) {
 466                if (!tipc_bearers[i].active) {
 467                        bearer_id = i;
 468                        continue;
 469                }
 470                if (!strcmp(name, tipc_bearers[i].name)) {
 471                        pr_warn("Bearer <%s> rejected, already enabled\n",
 472                                name);
 473                        goto exit;
 474                }
 475                if ((tipc_bearers[i].priority == priority) &&
 476                    (++with_this_prio > 2)) {
 477                        if (priority-- == 0) {
 478                                pr_warn("Bearer <%s> rejected, duplicate priority\n",
 479                                        name);
 480                                goto exit;
 481                        }
 482                        pr_warn("Bearer <%s> priority adjustment required %u->%u\n",
 483                                name, priority + 1, priority);
 484                        goto restart;
 485                }
 486        }
 487        if (bearer_id >= MAX_BEARERS) {
 488                pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
 489                        name, MAX_BEARERS);
 490                goto exit;
 491        }
 492
 493        b_ptr = &tipc_bearers[bearer_id];
 494        strcpy(b_ptr->name, name);
 495        res = m_ptr->enable_bearer(b_ptr);
 496        if (res) {
 497                pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
 498                        name, -res);
 499                goto exit;
 500        }
 501
 502        b_ptr->identity = bearer_id;
 503        b_ptr->media = m_ptr;
 504        b_ptr->tolerance = m_ptr->tolerance;
 505        b_ptr->window = m_ptr->window;
 506        b_ptr->net_plane = bearer_id + 'A';
 507        b_ptr->active = 1;
 508        b_ptr->priority = priority;
 509        INIT_LIST_HEAD(&b_ptr->cong_links);
 510        INIT_LIST_HEAD(&b_ptr->links);
 511        spin_lock_init(&b_ptr->lock);
 512
 513        res = tipc_disc_create(b_ptr, &m_ptr->bcast_addr, disc_domain);
 514        if (res) {
 515                bearer_disable(b_ptr);
 516                pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
 517                        name);
 518                goto exit;
 519        }
 520        pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
 521                name,
 522                tipc_addr_string_fill(addr_string, disc_domain), priority);
 523exit:
 524        write_unlock_bh(&tipc_net_lock);
 525        return res;
 526}
 527
 528/**
 529 * tipc_block_bearer - Block the bearer with the given name, and reset all its links
 530 */
 531int tipc_block_bearer(const char *name)
 532{
 533        struct tipc_bearer *b_ptr = NULL;
 534        struct tipc_link *l_ptr;
 535        struct tipc_link *temp_l_ptr;
 536
 537        read_lock_bh(&tipc_net_lock);
 538        b_ptr = tipc_bearer_find(name);
 539        if (!b_ptr) {
 540                pr_warn("Attempt to block unknown bearer <%s>\n", name);
 541                read_unlock_bh(&tipc_net_lock);
 542                return -EINVAL;
 543        }
 544
 545        pr_info("Blocking bearer <%s>\n", name);
 546        spin_lock_bh(&b_ptr->lock);
 547        b_ptr->blocked = 1;
 548        list_splice_init(&b_ptr->cong_links, &b_ptr->links);
 549        list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
 550                struct tipc_node *n_ptr = l_ptr->owner;
 551
 552                spin_lock_bh(&n_ptr->lock);
 553                tipc_link_reset(l_ptr);
 554                spin_unlock_bh(&n_ptr->lock);
 555        }
 556        spin_unlock_bh(&b_ptr->lock);
 557        read_unlock_bh(&tipc_net_lock);
 558        return 0;
 559}
 560
 561/**
 562 * bearer_disable
 563 *
 564 * Note: This routine assumes caller holds tipc_net_lock.
 565 */
 566static void bearer_disable(struct tipc_bearer *b_ptr)
 567{
 568        struct tipc_link *l_ptr;
 569        struct tipc_link *temp_l_ptr;
 570
 571        pr_info("Disabling bearer <%s>\n", b_ptr->name);
 572        spin_lock_bh(&b_ptr->lock);
 573        b_ptr->blocked = 1;
 574        b_ptr->media->disable_bearer(b_ptr);
 575        list_splice_init(&b_ptr->cong_links, &b_ptr->links);
 576        list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
 577                tipc_link_delete(l_ptr);
 578        }
 579        if (b_ptr->link_req)
 580                tipc_disc_delete(b_ptr->link_req);
 581        spin_unlock_bh(&b_ptr->lock);
 582        memset(b_ptr, 0, sizeof(struct tipc_bearer));
 583}
 584
 585int tipc_disable_bearer(const char *name)
 586{
 587        struct tipc_bearer *b_ptr;
 588        int res;
 589
 590        write_lock_bh(&tipc_net_lock);
 591        b_ptr = tipc_bearer_find(name);
 592        if (b_ptr == NULL) {
 593                pr_warn("Attempt to disable unknown bearer <%s>\n", name);
 594                res = -EINVAL;
 595        } else {
 596                bearer_disable(b_ptr);
 597                res = 0;
 598        }
 599        write_unlock_bh(&tipc_net_lock);
 600        return res;
 601}
 602
 603
 604
 605void tipc_bearer_stop(void)
 606{
 607        u32 i;
 608
 609        for (i = 0; i < MAX_BEARERS; i++) {
 610                if (tipc_bearers[i].active)
 611                        bearer_disable(&tipc_bearers[i]);
 612        }
 613        media_count = 0;
 614}
 615
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.