tipc: use bearer index when looking up active links
[cascardo/linux.git] / net / tipc / node.c
index 0b1d61a..1972964 100644 (file)
@@ -132,6 +132,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr)
        INIT_LIST_HEAD(&n_ptr->list);
        INIT_LIST_HEAD(&n_ptr->publ_list);
        INIT_LIST_HEAD(&n_ptr->conn_sks);
+       skb_queue_head_init(&n_ptr->bclink.namedq);
        __skb_queue_head_init(&n_ptr->bclink.deferdq);
        hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]);
        list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
@@ -141,6 +142,8 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr)
        list_add_tail_rcu(&n_ptr->list, &temp_node->list);
        n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN;
        n_ptr->signature = INVALID_NODE_SIG;
+       n_ptr->active_links[0] = INVALID_BEARER_ID;
+       n_ptr->active_links[1] = INVALID_BEARER_ID;
        tipc_node_get(n_ptr);
 exit:
        spin_unlock_bh(&tn->node_list_lock);
@@ -224,126 +227,127 @@ void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port)
  *
  * Link becomes active (alone or shared) or standby, depending on its priority.
  */
-void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
+void tipc_node_link_up(struct tipc_node *n, int bearer_id)
 {
-       struct tipc_link **active = &n_ptr->active_links[0];
+       int *slot0 = &n->active_links[0];
+       int *slot1 = &n->active_links[1];
+       struct tipc_link_entry *links = n->links;
+       struct tipc_link *l = n->links[bearer_id].link;
 
-       n_ptr->working_links++;
-       n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP;
-       n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
+       /* Leave room for tunnel header when returning 'mtu' to users: */
+       links[bearer_id].mtu = l->mtu - INT_H_SIZE;
+
+       n->working_links++;
+       n->action_flags |= TIPC_NOTIFY_LINK_UP;
+       n->link_id = l->peer_bearer_id << 16 | l->bearer_id;
 
        pr_debug("Established link <%s> on network plane %c\n",
-                l_ptr->name, l_ptr->net_plane);
+                l->name, l->net_plane);
 
-       if (!active[0]) {
-               active[0] = active[1] = l_ptr;
-               node_established_contact(n_ptr);
-               goto exit;
+       /* No active links ? => take both active slots */
+       if (*slot0 < 0) {
+               *slot0 = bearer_id;
+               *slot1 = bearer_id;
+               node_established_contact(n);
+               return;
        }
-       if (l_ptr->priority < active[0]->priority) {
-               pr_debug("New link <%s> becomes standby\n", l_ptr->name);
-               goto exit;
+
+       /* Lower prio than current active ? => no slot */
+       if (l->priority < links[*slot0].link->priority) {
+               pr_debug("New link <%s> becomes standby\n", l->name);
+               return;
        }
-       tipc_link_dup_queue_xmit(active[0], l_ptr);
-       if (l_ptr->priority == active[0]->priority) {
-               active[0] = l_ptr;
-               goto exit;
+       tipc_link_dup_queue_xmit(links[*slot0].link, l);
+
+       /* Same prio as current active ? => take one slot */
+       if (l->priority == links[*slot0].link->priority) {
+               *slot0 = bearer_id;
+               return;
        }
-       pr_debug("Old link <%s> becomes standby\n", active[0]->name);
-       if (active[1] != active[0])
-               pr_debug("Old link <%s> becomes standby\n", active[1]->name);
-       active[0] = active[1] = l_ptr;
-exit:
-       /* Leave room for changeover header when returning 'mtu' to users: */
-       n_ptr->act_mtus[0] = active[0]->mtu - INT_H_SIZE;
-       n_ptr->act_mtus[1] = active[1]->mtu - INT_H_SIZE;
+
+       /* Higher prio than current active => take both active slots */
+       pr_debug("Old link <%s> now standby\n", links[*slot0].link->name);
+       *slot0 = bearer_id;
+       *slot1 = bearer_id;
 }
 
 /**
- * node_select_active_links - select active link
+ * tipc_node_link_down - handle loss of link
  */
-static void node_select_active_links(struct tipc_node *n_ptr)
+void tipc_node_link_down(struct tipc_node *n, int bearer_id)
 {
-       struct tipc_link **active = &n_ptr->active_links[0];
-       u32 i;
-       u32 highest_prio = 0;
+       int *slot0 = &n->active_links[0];
+       int *slot1 = &n->active_links[1];
+       int i, highest = 0;
+       struct tipc_link *l, *_l;
 
-       active[0] = active[1] = NULL;
+       l = n->links[bearer_id].link;
+       n->working_links--;
+       n->action_flags |= TIPC_NOTIFY_LINK_DOWN;
+       n->link_id = l->peer_bearer_id << 16 | l->bearer_id;
 
-       for (i = 0; i < MAX_BEARERS; i++) {
-               struct tipc_link *l_ptr = n_ptr->links[i];
+       pr_debug("Lost link <%s> on network plane %c\n",
+                l->name, l->net_plane);
 
-               if (!l_ptr || !tipc_link_is_up(l_ptr) ||
-                   (l_ptr->priority < highest_prio))
+       /* Select new active link if any available */
+       *slot0 = INVALID_BEARER_ID;
+       *slot1 = INVALID_BEARER_ID;
+       for (i = 0; i < MAX_BEARERS; i++) {
+               _l = n->links[i].link;
+               if (!_l || !tipc_link_is_up(_l))
+                       continue;
+               if (_l->priority < highest)
+                       continue;
+               if (_l->priority > highest) {
+                       highest = _l->priority;
+                       *slot0 = i;
+                       *slot1 = i;
                        continue;
-
-               if (l_ptr->priority > highest_prio) {
-                       highest_prio = l_ptr->priority;
-                       active[0] = active[1] = l_ptr;
-               } else {
-                       active[1] = l_ptr;
                }
+               *slot1 = i;
        }
+       if (tipc_node_is_up(n))
+               tipc_link_failover_send_queue(l);
+       else
+               node_lost_contact(n);
 }
 
-/**
- * tipc_node_link_down - handle loss of link
- */
-void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
+bool tipc_node_is_up(struct tipc_node *n)
 {
-       struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
-       struct tipc_link **active;
-
-       n_ptr->working_links--;
-       n_ptr->action_flags |= TIPC_NOTIFY_LINK_DOWN;
-       n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
-
-       if (!tipc_link_is_active(l_ptr)) {
-               pr_debug("Lost standby link <%s> on network plane %c\n",
-                        l_ptr->name, l_ptr->net_plane);
-               return;
-       }
-       pr_debug("Lost link <%s> on network plane %c\n",
-                l_ptr->name, l_ptr->net_plane);
-
-       active = &n_ptr->active_links[0];
-       if (active[0] == l_ptr)
-               active[0] = active[1];
-       if (active[1] == l_ptr)
-               active[1] = active[0];
-       if (active[0] == l_ptr)
-               node_select_active_links(n_ptr);
-       if (tipc_node_is_up(n_ptr))
-               tipc_link_failover_send_queue(l_ptr);
-       else
-               node_lost_contact(n_ptr);
-
-       /* Leave room for changeover header when returning 'mtu' to users: */
-       if (active[0]) {
-               n_ptr->act_mtus[0] = active[0]->mtu - INT_H_SIZE;
-               n_ptr->act_mtus[1] = active[1]->mtu - INT_H_SIZE;
-               return;
-       }
-       /* Loopback link went down? No fragmentation needed from now on. */
-       if (n_ptr->addr == tn->own_addr) {
-               n_ptr->act_mtus[0] = MAX_MSG_SIZE;
-               n_ptr->act_mtus[1] = MAX_MSG_SIZE;
-       }
+       return n->active_links[0] != INVALID_BEARER_ID;
 }
 
-int tipc_node_active_links(struct tipc_node *n_ptr)
+void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *b,
+                         bool *link_up, bool *addr_match,
+                         struct tipc_media_addr *maddr)
 {
-       return n_ptr->active_links[0] != NULL;
+       struct tipc_link *l = n->links[b->identity].link;
+       struct tipc_media_addr *curr = &n->links[b->identity].maddr;
+
+       *link_up = l && tipc_link_is_up(l);
+       *addr_match = l && !memcmp(curr, maddr, sizeof(*maddr));
 }
 
-int tipc_node_is_up(struct tipc_node *n_ptr)
+bool tipc_node_update_dest(struct tipc_node *n,  struct tipc_bearer *b,
+                          struct tipc_media_addr *maddr)
 {
-       return tipc_node_active_links(n_ptr);
+       struct tipc_link *l = n->links[b->identity].link;
+       struct tipc_media_addr *curr = &n->links[b->identity].maddr;
+       struct sk_buff_head *inputq = &n->links[b->identity].inputq;
+
+       if (!l)
+               l = tipc_link_create(n, b, maddr, inputq, &n->bclink.namedq);
+       if (!l)
+               return false;
+       memcpy(&l->media_addr, maddr, sizeof(*maddr));
+       memcpy(curr, maddr, sizeof(*maddr));
+       tipc_link_reset(l);
+       return true;
 }
 
 void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 {
-       n_ptr->links[l_ptr->bearer_id] = l_ptr;
+       n_ptr->links[l_ptr->bearer_id].link = l_ptr;
        n_ptr->link_cnt++;
 }
 
@@ -352,9 +356,9 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
        int i;
 
        for (i = 0; i < MAX_BEARERS; i++) {
-               if (l_ptr != n_ptr->links[i])
+               if (l_ptr != n_ptr->links[i].link)
                        continue;
-               n_ptr->links[i] = NULL;
+               n_ptr->links[i].link = NULL;
                n_ptr->link_cnt--;
        }
 }
@@ -396,7 +400,7 @@ static void node_lost_contact(struct tipc_node *n_ptr)
 
        /* Abort any ongoing link failover */
        for (i = 0; i < MAX_BEARERS; i++) {
-               struct tipc_link *l_ptr = n_ptr->links[i];
+               struct tipc_link *l_ptr = n_ptr->links[i].link;
                if (!l_ptr)
                        continue;
                l_ptr->flags &= ~LINK_FAILINGOVER;
@@ -453,7 +457,7 @@ int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr,
                goto exit;
 
        tipc_node_lock(node);
-       link = node->links[bearer_id];
+       link = node->links[bearer_id].link;
        if (link) {
                strncpy(linkname, link->name, len);
                err = 0;