linux/net/tipc/node.c
<<
>>
Prefs
   1/*
   2 * net/tipc/node.c: TIPC node management routines
   3 *
   4 * Copyright (c) 2000-2006, Ericsson AB
   5 * Copyright (c) 2005-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 "node.h"
  40#include "name_distr.h"
  41
  42#define NODE_HTABLE_SIZE 512
  43
  44static void node_lost_contact(struct tipc_node *n_ptr);
  45static void node_established_contact(struct tipc_node *n_ptr);
  46
  47static DEFINE_SPINLOCK(node_create_lock);
  48
  49static struct hlist_head node_htable[NODE_HTABLE_SIZE];
  50LIST_HEAD(tipc_node_list);
  51static u32 tipc_num_nodes;
  52
  53static atomic_t tipc_num_links = ATOMIC_INIT(0);
  54
  55/*
  56 * A trivial power-of-two bitmask technique is used for speed, since this
  57 * operation is done for every incoming TIPC packet. The number of hash table
  58 * entries has been chosen so that no hash chain exceeds 8 nodes and will
  59 * usually be much smaller (typically only a single node).
  60 */
  61static unsigned int tipc_hashfn(u32 addr)
  62{
  63        return addr & (NODE_HTABLE_SIZE - 1);
  64}
  65
  66/*
  67 * tipc_node_find - locate specified node object, if it exists
  68 */
  69struct tipc_node *tipc_node_find(u32 addr)
  70{
  71        struct tipc_node *node;
  72        struct hlist_node *pos;
  73
  74        if (unlikely(!in_own_cluster_exact(addr)))
  75                return NULL;
  76
  77        hlist_for_each_entry(node, pos, &node_htable[tipc_hashfn(addr)], hash) {
  78                if (node->addr == addr)
  79                        return node;
  80        }
  81        return NULL;
  82}
  83
  84/**
  85 * tipc_node_create - create neighboring node
  86 *
  87 * Currently, this routine is called by neighbor discovery code, which holds
  88 * net_lock for reading only.  We must take node_create_lock to ensure a node
  89 * isn't created twice if two different bearers discover the node at the same
  90 * time.  (It would be preferable to switch to holding net_lock in write mode,
  91 * but this is a non-trivial change.)
  92 */
  93struct tipc_node *tipc_node_create(u32 addr)
  94{
  95        struct tipc_node *n_ptr, *temp_node;
  96
  97        spin_lock_bh(&node_create_lock);
  98
  99        n_ptr = tipc_node_find(addr);
 100        if (n_ptr) {
 101                spin_unlock_bh(&node_create_lock);
 102                return n_ptr;
 103        }
 104
 105        n_ptr = kzalloc(sizeof(*n_ptr), GFP_ATOMIC);
 106        if (!n_ptr) {
 107                spin_unlock_bh(&node_create_lock);
 108                pr_warn("Node creation failed, no memory\n");
 109                return NULL;
 110        }
 111
 112        n_ptr->addr = addr;
 113        spin_lock_init(&n_ptr->lock);
 114        INIT_HLIST_NODE(&n_ptr->hash);
 115        INIT_LIST_HEAD(&n_ptr->list);
 116        INIT_LIST_HEAD(&n_ptr->nsub);
 117
 118        hlist_add_head(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]);
 119
 120        list_for_each_entry(temp_node, &tipc_node_list, list) {
 121                if (n_ptr->addr < temp_node->addr)
 122                        break;
 123        }
 124        list_add_tail(&n_ptr->list, &temp_node->list);
 125        n_ptr->block_setup = WAIT_PEER_DOWN;
 126        n_ptr->signature = INVALID_NODE_SIG;
 127
 128        tipc_num_nodes++;
 129
 130        spin_unlock_bh(&node_create_lock);
 131        return n_ptr;
 132}
 133
 134void tipc_node_delete(struct tipc_node *n_ptr)
 135{
 136        list_del(&n_ptr->list);
 137        hlist_del(&n_ptr->hash);
 138        kfree(n_ptr);
 139
 140        tipc_num_nodes--;
 141}
 142
 143/**
 144 * tipc_node_link_up - handle addition of link
 145 *
 146 * Link becomes active (alone or shared) or standby, depending on its priority.
 147 */
 148void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 149{
 150        struct tipc_link **active = &n_ptr->active_links[0];
 151
 152        n_ptr->working_links++;
 153
 154        pr_info("Established link <%s> on network plane %c\n",
 155                l_ptr->name, l_ptr->b_ptr->net_plane);
 156
 157        if (!active[0]) {
 158                active[0] = active[1] = l_ptr;
 159                node_established_contact(n_ptr);
 160                return;
 161        }
 162        if (l_ptr->priority < active[0]->priority) {
 163                pr_info("New link <%s> becomes standby\n", l_ptr->name);
 164                return;
 165        }
 166        tipc_link_send_duplicate(active[0], l_ptr);
 167        if (l_ptr->priority == active[0]->priority) {
 168                active[0] = l_ptr;
 169                return;
 170        }
 171        pr_info("Old link <%s> becomes standby\n", active[0]->name);
 172        if (active[1] != active[0])
 173                pr_info("Old link <%s> becomes standby\n", active[1]->name);
 174        active[0] = active[1] = l_ptr;
 175}
 176
 177/**
 178 * node_select_active_links - select active link
 179 */
 180static void node_select_active_links(struct tipc_node *n_ptr)
 181{
 182        struct tipc_link **active = &n_ptr->active_links[0];
 183        u32 i;
 184        u32 highest_prio = 0;
 185
 186        active[0] = active[1] = NULL;
 187
 188        for (i = 0; i < MAX_BEARERS; i++) {
 189                struct tipc_link *l_ptr = n_ptr->links[i];
 190
 191                if (!l_ptr || !tipc_link_is_up(l_ptr) ||
 192                    (l_ptr->priority < highest_prio))
 193                        continue;
 194
 195                if (l_ptr->priority > highest_prio) {
 196                        highest_prio = l_ptr->priority;
 197                        active[0] = active[1] = l_ptr;
 198                } else {
 199                        active[1] = l_ptr;
 200                }
 201        }
 202}
 203
 204/**
 205 * tipc_node_link_down - handle loss of link
 206 */
 207void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 208{
 209        struct tipc_link **active;
 210
 211        n_ptr->working_links--;
 212
 213        if (!tipc_link_is_active(l_ptr)) {
 214                pr_info("Lost standby link <%s> on network plane %c\n",
 215                        l_ptr->name, l_ptr->b_ptr->net_plane);
 216                return;
 217        }
 218        pr_info("Lost link <%s> on network plane %c\n",
 219                l_ptr->name, l_ptr->b_ptr->net_plane);
 220
 221        active = &n_ptr->active_links[0];
 222        if (active[0] == l_ptr)
 223                active[0] = active[1];
 224        if (active[1] == l_ptr)
 225                active[1] = active[0];
 226        if (active[0] == l_ptr)
 227                node_select_active_links(n_ptr);
 228        if (tipc_node_is_up(n_ptr))
 229                tipc_link_changeover(l_ptr);
 230        else
 231                node_lost_contact(n_ptr);
 232}
 233
 234int tipc_node_active_links(struct tipc_node *n_ptr)
 235{
 236        return n_ptr->active_links[0] != NULL;
 237}
 238
 239int tipc_node_redundant_links(struct tipc_node *n_ptr)
 240{
 241        return n_ptr->working_links > 1;
 242}
 243
 244int tipc_node_is_up(struct tipc_node *n_ptr)
 245{
 246        return tipc_node_active_links(n_ptr);
 247}
 248
 249void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 250{
 251        n_ptr->links[l_ptr->b_ptr->identity] = l_ptr;
 252        atomic_inc(&tipc_num_links);
 253        n_ptr->link_cnt++;
 254}
 255
 256void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 257{
 258        n_ptr->links[l_ptr->b_ptr->identity] = NULL;
 259        atomic_dec(&tipc_num_links);
 260        n_ptr->link_cnt--;
 261}
 262
 263static void node_established_contact(struct tipc_node *n_ptr)
 264{
 265        tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr);
 266
 267        if (n_ptr->bclink.supportable) {
 268                n_ptr->bclink.acked = tipc_bclink_get_last_sent();
 269                tipc_bclink_add_node(n_ptr->addr);
 270                n_ptr->bclink.supported = 1;
 271        }
 272}
 273
 274static void node_name_purge_complete(unsigned long node_addr)
 275{
 276        struct tipc_node *n_ptr;
 277
 278        read_lock_bh(&tipc_net_lock);
 279        n_ptr = tipc_node_find(node_addr);
 280        if (n_ptr) {
 281                tipc_node_lock(n_ptr);
 282                n_ptr->block_setup &= ~WAIT_NAMES_GONE;
 283                tipc_node_unlock(n_ptr);
 284        }
 285        read_unlock_bh(&tipc_net_lock);
 286}
 287
 288static void node_lost_contact(struct tipc_node *n_ptr)
 289{
 290        char addr_string[16];
 291        u32 i;
 292
 293        pr_info("Lost contact with %s\n",
 294                tipc_addr_string_fill(addr_string, n_ptr->addr));
 295
 296        /* Flush broadcast link info associated with lost node */
 297        if (n_ptr->bclink.supported) {
 298                while (n_ptr->bclink.deferred_head) {
 299                        struct sk_buff *buf = n_ptr->bclink.deferred_head;
 300                        n_ptr->bclink.deferred_head = buf->next;
 301                        kfree_skb(buf);
 302                }
 303                n_ptr->bclink.deferred_size = 0;
 304
 305                if (n_ptr->bclink.defragm) {
 306                        kfree_skb(n_ptr->bclink.defragm);
 307                        n_ptr->bclink.defragm = NULL;
 308                }
 309
 310                tipc_bclink_remove_node(n_ptr->addr);
 311                tipc_bclink_acknowledge(n_ptr, INVALID_LINK_SEQ);
 312
 313                n_ptr->bclink.supported = 0;
 314        }
 315
 316        /* Abort link changeover */
 317        for (i = 0; i < MAX_BEARERS; i++) {
 318                struct tipc_link *l_ptr = n_ptr->links[i];
 319                if (!l_ptr)
 320                        continue;
 321                l_ptr->reset_checkpoint = l_ptr->next_in_no;
 322                l_ptr->exp_msg_count = 0;
 323                tipc_link_reset_fragments(l_ptr);
 324        }
 325
 326        /* Notify subscribers */
 327        tipc_nodesub_notify(n_ptr);
 328
 329        /* Prevent re-contact with node until cleanup is done */
 330        n_ptr->block_setup = WAIT_PEER_DOWN | WAIT_NAMES_GONE;
 331        tipc_k_signal((Handler)node_name_purge_complete, n_ptr->addr);
 332}
 333
 334struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
 335{
 336        u32 domain;
 337        struct sk_buff *buf;
 338        struct tipc_node *n_ptr;
 339        struct tipc_node_info node_info;
 340        u32 payload_size;
 341
 342        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
 343                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 344
 345        domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 346        if (!tipc_addr_domain_valid(domain))
 347                return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 348                                                   " (network address)");
 349
 350        read_lock_bh(&tipc_net_lock);
 351        if (!tipc_num_nodes) {
 352                read_unlock_bh(&tipc_net_lock);
 353                return tipc_cfg_reply_none();
 354        }
 355
 356        /* For now, get space for all other nodes */
 357        payload_size = TLV_SPACE(sizeof(node_info)) * tipc_num_nodes;
 358        if (payload_size > 32768u) {
 359                read_unlock_bh(&tipc_net_lock);
 360                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 361                                                   " (too many nodes)");
 362        }
 363        buf = tipc_cfg_reply_alloc(payload_size);
 364        if (!buf) {
 365                read_unlock_bh(&tipc_net_lock);
 366                return NULL;
 367        }
 368
 369        /* Add TLVs for all nodes in scope */
 370        list_for_each_entry(n_ptr, &tipc_node_list, list) {
 371                if (!tipc_in_scope(domain, n_ptr->addr))
 372                        continue;
 373                node_info.addr = htonl(n_ptr->addr);
 374                node_info.up = htonl(tipc_node_is_up(n_ptr));
 375                tipc_cfg_append_tlv(buf, TIPC_TLV_NODE_INFO,
 376                                    &node_info, sizeof(node_info));
 377        }
 378
 379        read_unlock_bh(&tipc_net_lock);
 380        return buf;
 381}
 382
 383struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
 384{
 385        u32 domain;
 386        struct sk_buff *buf;
 387        struct tipc_node *n_ptr;
 388        struct tipc_link_info link_info;
 389        u32 payload_size;
 390
 391        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
 392                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 393
 394        domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 395        if (!tipc_addr_domain_valid(domain))
 396                return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 397                                                   " (network address)");
 398
 399        if (!tipc_own_addr)
 400                return tipc_cfg_reply_none();
 401
 402        read_lock_bh(&tipc_net_lock);
 403
 404        /* Get space for all unicast links + broadcast link */
 405        payload_size = TLV_SPACE(sizeof(link_info)) *
 406                (atomic_read(&tipc_num_links) + 1);
 407        if (payload_size > 32768u) {
 408                read_unlock_bh(&tipc_net_lock);
 409                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 410                                                   " (too many links)");
 411        }
 412        buf = tipc_cfg_reply_alloc(payload_size);
 413        if (!buf) {
 414                read_unlock_bh(&tipc_net_lock);
 415                return NULL;
 416        }
 417
 418        /* Add TLV for broadcast link */
 419        link_info.dest = htonl(tipc_cluster_mask(tipc_own_addr));
 420        link_info.up = htonl(1);
 421        strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME);
 422        tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
 423
 424        /* Add TLVs for any other links in scope */
 425        list_for_each_entry(n_ptr, &tipc_node_list, list) {
 426                u32 i;
 427
 428                if (!tipc_in_scope(domain, n_ptr->addr))
 429                        continue;
 430                tipc_node_lock(n_ptr);
 431                for (i = 0; i < MAX_BEARERS; i++) {
 432                        if (!n_ptr->links[i])
 433                                continue;
 434                        link_info.dest = htonl(n_ptr->addr);
 435                        link_info.up = htonl(tipc_link_is_up(n_ptr->links[i]));
 436                        strcpy(link_info.str, n_ptr->links[i]->name);
 437                        tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO,
 438                                            &link_info, sizeof(link_info));
 439                }
 440                tipc_node_unlock(n_ptr);
 441        }
 442
 443        read_unlock_bh(&tipc_net_lock);
 444        return buf;
 445}
 446
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.