Commit 66996b6c47ed7f6bbb01a768e23fae262c7db8e0
Committed by
David S. Miller
1 parent
655fb243b8
tipc: extend node FSM
In the next commit, we will move link synch/failover orchestration to the link aggregation level. In order to do this, we first need to extend the node FSM with two more states, NODE_SYNCHING and NODE_FAILINGOVER, plus four new events to enter and leave those states. This commit introduces this change, without yet making use of it. The node FSM now looks as follows: +-----------------------------------------+ | PEER_DOWN_EVT| | | +------------------------+----------------+ | |SELF_DOWN_EVT | | | | | | | | +-----------+ +-----------+ | | |NODE_ | |NODE_ | | | +----------|FAILINGOVER|<---------|SYNCHING |------------+ | | |SELF_ +-----------+ FAILOVER_+-----------+ PEER_ | | | |DOWN_EVT | A BEGIN_EVT A | DOWN_EVT| | | | | | | | | | | | | | | | | | | | |FAILOVER_|FAILOVER_ |SYNCH_ |SYNCH_ | | | | |END_EVT |BEGIN_EVT |BEGIN_EVT|END_EVT | | | | | | | | | | | | | | | | | | | | | +--------------+ | | | | | +------->| SELF_UP_ |<-------+ | | | | +----------------| PEER_UP |------------------+ | | | | |SELF_DOWN_EVT +--------------+ PEER_DOWN_EVT| | | | | | A A | | | | | | | | | | | | | | PEER_UP_EVT| |SELF_UP_EVT | | | | | | | | | | | V V V | | V V V +------------+ +-----------+ +-----------+ +------------+ |SELF_DOWN_ | |SELF_UP_ | |PEER_UP_ | |PEER_DOWN | |PEER_LEAVING|<------|PEER_COMING| |SELF_COMING|------>|SELF_LEAVING| +------------+ SELF_ +-----------+ +-----------+ PEER_ +------------+ | DOWN_EVT A A DOWN_EVT | | | | | | | | | | SELF_UP_EVT| |PEER_UP_EVT | | | | | | | | | |PEER_DOWN_EVT +--------------+ SELF_DOWN_EVT| +------------------->| SELF_DOWN_ |<--------------------+ | PEER_DOWN | +--------------+ Tested-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 2 changed files with 92 additions and 11 deletions Inline Diff
net/tipc/node.c
1 | /* | 1 | /* |
2 | * net/tipc/node.c: TIPC node management routines | 2 | * net/tipc/node.c: TIPC node management routines |
3 | * | 3 | * |
4 | * Copyright (c) 2000-2006, 2012-2015, Ericsson AB | 4 | * Copyright (c) 2000-2006, 2012-2015, Ericsson AB |
5 | * Copyright (c) 2005-2006, 2010-2014, Wind River Systems | 5 | * Copyright (c) 2005-2006, 2010-2014, Wind River Systems |
6 | * All rights reserved. | 6 | * All rights reserved. |
7 | * | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions are met: | 9 | * modification, are permitted provided that the following conditions are met: |
10 | * | 10 | * |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. | 15 | * documentation and/or other materials provided with the distribution. |
16 | * 3. Neither the names of the copyright holders nor the names of its | 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 | 17 | * contributors may be used to endorse or promote products derived from |
18 | * this software without specific prior written permission. | 18 | * this software without specific prior written permission. |
19 | * | 19 | * |
20 | * Alternatively, this software may be distributed under the terms of the | 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 | 21 | * GNU General Public License ("GPL") version 2 as published by the Free |
22 | * Software Foundation. | 22 | * Software Foundation. |
23 | * | 23 | * |
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 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 | 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 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 | 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
34 | * POSSIBILITY OF SUCH DAMAGE. | 34 | * POSSIBILITY OF SUCH DAMAGE. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "link.h" | 38 | #include "link.h" |
39 | #include "node.h" | 39 | #include "node.h" |
40 | #include "name_distr.h" | 40 | #include "name_distr.h" |
41 | #include "socket.h" | 41 | #include "socket.h" |
42 | #include "bcast.h" | 42 | #include "bcast.h" |
43 | #include "discover.h" | 43 | #include "discover.h" |
44 | 44 | ||
45 | static void node_lost_contact(struct tipc_node *n_ptr); | 45 | static void node_lost_contact(struct tipc_node *n_ptr); |
46 | static void node_established_contact(struct tipc_node *n_ptr); | 46 | static void node_established_contact(struct tipc_node *n_ptr); |
47 | static void tipc_node_delete(struct tipc_node *node); | 47 | static void tipc_node_delete(struct tipc_node *node); |
48 | static void tipc_node_timeout(unsigned long data); | 48 | static void tipc_node_timeout(unsigned long data); |
49 | static void tipc_node_fsm_evt(struct tipc_node *n, int evt); | 49 | static void tipc_node_fsm_evt(struct tipc_node *n, int evt); |
50 | 50 | ||
51 | struct tipc_sock_conn { | 51 | struct tipc_sock_conn { |
52 | u32 port; | 52 | u32 port; |
53 | u32 peer_port; | 53 | u32 peer_port; |
54 | u32 peer_node; | 54 | u32 peer_node; |
55 | struct list_head list; | 55 | struct list_head list; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | static const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = { | 58 | static const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = { |
59 | [TIPC_NLA_NODE_UNSPEC] = { .type = NLA_UNSPEC }, | 59 | [TIPC_NLA_NODE_UNSPEC] = { .type = NLA_UNSPEC }, |
60 | [TIPC_NLA_NODE_ADDR] = { .type = NLA_U32 }, | 60 | [TIPC_NLA_NODE_ADDR] = { .type = NLA_U32 }, |
61 | [TIPC_NLA_NODE_UP] = { .type = NLA_FLAG } | 61 | [TIPC_NLA_NODE_UP] = { .type = NLA_FLAG } |
62 | }; | 62 | }; |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * A trivial power-of-two bitmask technique is used for speed, since this | 65 | * A trivial power-of-two bitmask technique is used for speed, since this |
66 | * operation is done for every incoming TIPC packet. The number of hash table | 66 | * operation is done for every incoming TIPC packet. The number of hash table |
67 | * entries has been chosen so that no hash chain exceeds 8 nodes and will | 67 | * entries has been chosen so that no hash chain exceeds 8 nodes and will |
68 | * usually be much smaller (typically only a single node). | 68 | * usually be much smaller (typically only a single node). |
69 | */ | 69 | */ |
70 | static unsigned int tipc_hashfn(u32 addr) | 70 | static unsigned int tipc_hashfn(u32 addr) |
71 | { | 71 | { |
72 | return addr & (NODE_HTABLE_SIZE - 1); | 72 | return addr & (NODE_HTABLE_SIZE - 1); |
73 | } | 73 | } |
74 | 74 | ||
75 | static void tipc_node_kref_release(struct kref *kref) | 75 | static void tipc_node_kref_release(struct kref *kref) |
76 | { | 76 | { |
77 | struct tipc_node *node = container_of(kref, struct tipc_node, kref); | 77 | struct tipc_node *node = container_of(kref, struct tipc_node, kref); |
78 | 78 | ||
79 | tipc_node_delete(node); | 79 | tipc_node_delete(node); |
80 | } | 80 | } |
81 | 81 | ||
82 | void tipc_node_put(struct tipc_node *node) | 82 | void tipc_node_put(struct tipc_node *node) |
83 | { | 83 | { |
84 | kref_put(&node->kref, tipc_node_kref_release); | 84 | kref_put(&node->kref, tipc_node_kref_release); |
85 | } | 85 | } |
86 | 86 | ||
87 | static void tipc_node_get(struct tipc_node *node) | 87 | static void tipc_node_get(struct tipc_node *node) |
88 | { | 88 | { |
89 | kref_get(&node->kref); | 89 | kref_get(&node->kref); |
90 | } | 90 | } |
91 | 91 | ||
92 | /* | 92 | /* |
93 | * tipc_node_find - locate specified node object, if it exists | 93 | * tipc_node_find - locate specified node object, if it exists |
94 | */ | 94 | */ |
95 | struct tipc_node *tipc_node_find(struct net *net, u32 addr) | 95 | struct tipc_node *tipc_node_find(struct net *net, u32 addr) |
96 | { | 96 | { |
97 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 97 | struct tipc_net *tn = net_generic(net, tipc_net_id); |
98 | struct tipc_node *node; | 98 | struct tipc_node *node; |
99 | 99 | ||
100 | if (unlikely(!in_own_cluster_exact(net, addr))) | 100 | if (unlikely(!in_own_cluster_exact(net, addr))) |
101 | return NULL; | 101 | return NULL; |
102 | 102 | ||
103 | rcu_read_lock(); | 103 | rcu_read_lock(); |
104 | hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)], | 104 | hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)], |
105 | hash) { | 105 | hash) { |
106 | if (node->addr == addr) { | 106 | if (node->addr == addr) { |
107 | tipc_node_get(node); | 107 | tipc_node_get(node); |
108 | rcu_read_unlock(); | 108 | rcu_read_unlock(); |
109 | return node; | 109 | return node; |
110 | } | 110 | } |
111 | } | 111 | } |
112 | rcu_read_unlock(); | 112 | rcu_read_unlock(); |
113 | return NULL; | 113 | return NULL; |
114 | } | 114 | } |
115 | 115 | ||
116 | struct tipc_node *tipc_node_create(struct net *net, u32 addr) | 116 | struct tipc_node *tipc_node_create(struct net *net, u32 addr) |
117 | { | 117 | { |
118 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 118 | struct tipc_net *tn = net_generic(net, tipc_net_id); |
119 | struct tipc_node *n_ptr, *temp_node; | 119 | struct tipc_node *n_ptr, *temp_node; |
120 | 120 | ||
121 | spin_lock_bh(&tn->node_list_lock); | 121 | spin_lock_bh(&tn->node_list_lock); |
122 | n_ptr = tipc_node_find(net, addr); | 122 | n_ptr = tipc_node_find(net, addr); |
123 | if (n_ptr) | 123 | if (n_ptr) |
124 | goto exit; | 124 | goto exit; |
125 | n_ptr = kzalloc(sizeof(*n_ptr), GFP_ATOMIC); | 125 | n_ptr = kzalloc(sizeof(*n_ptr), GFP_ATOMIC); |
126 | if (!n_ptr) { | 126 | if (!n_ptr) { |
127 | pr_warn("Node creation failed, no memory\n"); | 127 | pr_warn("Node creation failed, no memory\n"); |
128 | goto exit; | 128 | goto exit; |
129 | } | 129 | } |
130 | n_ptr->addr = addr; | 130 | n_ptr->addr = addr; |
131 | n_ptr->net = net; | 131 | n_ptr->net = net; |
132 | kref_init(&n_ptr->kref); | 132 | kref_init(&n_ptr->kref); |
133 | spin_lock_init(&n_ptr->lock); | 133 | spin_lock_init(&n_ptr->lock); |
134 | INIT_HLIST_NODE(&n_ptr->hash); | 134 | INIT_HLIST_NODE(&n_ptr->hash); |
135 | INIT_LIST_HEAD(&n_ptr->list); | 135 | INIT_LIST_HEAD(&n_ptr->list); |
136 | INIT_LIST_HEAD(&n_ptr->publ_list); | 136 | INIT_LIST_HEAD(&n_ptr->publ_list); |
137 | INIT_LIST_HEAD(&n_ptr->conn_sks); | 137 | INIT_LIST_HEAD(&n_ptr->conn_sks); |
138 | skb_queue_head_init(&n_ptr->bclink.namedq); | 138 | skb_queue_head_init(&n_ptr->bclink.namedq); |
139 | __skb_queue_head_init(&n_ptr->bclink.deferdq); | 139 | __skb_queue_head_init(&n_ptr->bclink.deferdq); |
140 | hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]); | 140 | hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]); |
141 | list_for_each_entry_rcu(temp_node, &tn->node_list, list) { | 141 | list_for_each_entry_rcu(temp_node, &tn->node_list, list) { |
142 | if (n_ptr->addr < temp_node->addr) | 142 | if (n_ptr->addr < temp_node->addr) |
143 | break; | 143 | break; |
144 | } | 144 | } |
145 | list_add_tail_rcu(&n_ptr->list, &temp_node->list); | 145 | list_add_tail_rcu(&n_ptr->list, &temp_node->list); |
146 | n_ptr->state = SELF_DOWN_PEER_LEAVING; | 146 | n_ptr->state = SELF_DOWN_PEER_LEAVING; |
147 | n_ptr->signature = INVALID_NODE_SIG; | 147 | n_ptr->signature = INVALID_NODE_SIG; |
148 | n_ptr->active_links[0] = INVALID_BEARER_ID; | 148 | n_ptr->active_links[0] = INVALID_BEARER_ID; |
149 | n_ptr->active_links[1] = INVALID_BEARER_ID; | 149 | n_ptr->active_links[1] = INVALID_BEARER_ID; |
150 | tipc_node_get(n_ptr); | 150 | tipc_node_get(n_ptr); |
151 | setup_timer(&n_ptr->timer, tipc_node_timeout, (unsigned long)n_ptr); | 151 | setup_timer(&n_ptr->timer, tipc_node_timeout, (unsigned long)n_ptr); |
152 | n_ptr->keepalive_intv = U32_MAX; | 152 | n_ptr->keepalive_intv = U32_MAX; |
153 | exit: | 153 | exit: |
154 | spin_unlock_bh(&tn->node_list_lock); | 154 | spin_unlock_bh(&tn->node_list_lock); |
155 | return n_ptr; | 155 | return n_ptr; |
156 | } | 156 | } |
157 | 157 | ||
158 | static void tipc_node_calculate_timer(struct tipc_node *n, struct tipc_link *l) | 158 | static void tipc_node_calculate_timer(struct tipc_node *n, struct tipc_link *l) |
159 | { | 159 | { |
160 | unsigned long tol = l->tolerance; | 160 | unsigned long tol = l->tolerance; |
161 | unsigned long intv = ((tol / 4) > 500) ? 500 : tol / 4; | 161 | unsigned long intv = ((tol / 4) > 500) ? 500 : tol / 4; |
162 | unsigned long keepalive_intv = msecs_to_jiffies(intv); | 162 | unsigned long keepalive_intv = msecs_to_jiffies(intv); |
163 | 163 | ||
164 | /* Link with lowest tolerance determines timer interval */ | 164 | /* Link with lowest tolerance determines timer interval */ |
165 | if (keepalive_intv < n->keepalive_intv) | 165 | if (keepalive_intv < n->keepalive_intv) |
166 | n->keepalive_intv = keepalive_intv; | 166 | n->keepalive_intv = keepalive_intv; |
167 | 167 | ||
168 | /* Ensure link's abort limit corresponds to current interval */ | 168 | /* Ensure link's abort limit corresponds to current interval */ |
169 | l->abort_limit = l->tolerance / jiffies_to_msecs(n->keepalive_intv); | 169 | l->abort_limit = l->tolerance / jiffies_to_msecs(n->keepalive_intv); |
170 | } | 170 | } |
171 | 171 | ||
172 | static void tipc_node_delete(struct tipc_node *node) | 172 | static void tipc_node_delete(struct tipc_node *node) |
173 | { | 173 | { |
174 | list_del_rcu(&node->list); | 174 | list_del_rcu(&node->list); |
175 | hlist_del_rcu(&node->hash); | 175 | hlist_del_rcu(&node->hash); |
176 | kfree_rcu(node, rcu); | 176 | kfree_rcu(node, rcu); |
177 | } | 177 | } |
178 | 178 | ||
179 | void tipc_node_stop(struct net *net) | 179 | void tipc_node_stop(struct net *net) |
180 | { | 180 | { |
181 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 181 | struct tipc_net *tn = net_generic(net, tipc_net_id); |
182 | struct tipc_node *node, *t_node; | 182 | struct tipc_node *node, *t_node; |
183 | 183 | ||
184 | spin_lock_bh(&tn->node_list_lock); | 184 | spin_lock_bh(&tn->node_list_lock); |
185 | list_for_each_entry_safe(node, t_node, &tn->node_list, list) { | 185 | list_for_each_entry_safe(node, t_node, &tn->node_list, list) { |
186 | if (del_timer(&node->timer)) | 186 | if (del_timer(&node->timer)) |
187 | tipc_node_put(node); | 187 | tipc_node_put(node); |
188 | tipc_node_put(node); | 188 | tipc_node_put(node); |
189 | } | 189 | } |
190 | spin_unlock_bh(&tn->node_list_lock); | 190 | spin_unlock_bh(&tn->node_list_lock); |
191 | } | 191 | } |
192 | 192 | ||
193 | int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port) | 193 | int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port) |
194 | { | 194 | { |
195 | struct tipc_node *node; | 195 | struct tipc_node *node; |
196 | struct tipc_sock_conn *conn; | 196 | struct tipc_sock_conn *conn; |
197 | int err = 0; | 197 | int err = 0; |
198 | 198 | ||
199 | if (in_own_node(net, dnode)) | 199 | if (in_own_node(net, dnode)) |
200 | return 0; | 200 | return 0; |
201 | 201 | ||
202 | node = tipc_node_find(net, dnode); | 202 | node = tipc_node_find(net, dnode); |
203 | if (!node) { | 203 | if (!node) { |
204 | pr_warn("Connecting sock to node 0x%x failed\n", dnode); | 204 | pr_warn("Connecting sock to node 0x%x failed\n", dnode); |
205 | return -EHOSTUNREACH; | 205 | return -EHOSTUNREACH; |
206 | } | 206 | } |
207 | conn = kmalloc(sizeof(*conn), GFP_ATOMIC); | 207 | conn = kmalloc(sizeof(*conn), GFP_ATOMIC); |
208 | if (!conn) { | 208 | if (!conn) { |
209 | err = -EHOSTUNREACH; | 209 | err = -EHOSTUNREACH; |
210 | goto exit; | 210 | goto exit; |
211 | } | 211 | } |
212 | conn->peer_node = dnode; | 212 | conn->peer_node = dnode; |
213 | conn->port = port; | 213 | conn->port = port; |
214 | conn->peer_port = peer_port; | 214 | conn->peer_port = peer_port; |
215 | 215 | ||
216 | tipc_node_lock(node); | 216 | tipc_node_lock(node); |
217 | list_add_tail(&conn->list, &node->conn_sks); | 217 | list_add_tail(&conn->list, &node->conn_sks); |
218 | tipc_node_unlock(node); | 218 | tipc_node_unlock(node); |
219 | exit: | 219 | exit: |
220 | tipc_node_put(node); | 220 | tipc_node_put(node); |
221 | return err; | 221 | return err; |
222 | } | 222 | } |
223 | 223 | ||
224 | void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port) | 224 | void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port) |
225 | { | 225 | { |
226 | struct tipc_node *node; | 226 | struct tipc_node *node; |
227 | struct tipc_sock_conn *conn, *safe; | 227 | struct tipc_sock_conn *conn, *safe; |
228 | 228 | ||
229 | if (in_own_node(net, dnode)) | 229 | if (in_own_node(net, dnode)) |
230 | return; | 230 | return; |
231 | 231 | ||
232 | node = tipc_node_find(net, dnode); | 232 | node = tipc_node_find(net, dnode); |
233 | if (!node) | 233 | if (!node) |
234 | return; | 234 | return; |
235 | 235 | ||
236 | tipc_node_lock(node); | 236 | tipc_node_lock(node); |
237 | list_for_each_entry_safe(conn, safe, &node->conn_sks, list) { | 237 | list_for_each_entry_safe(conn, safe, &node->conn_sks, list) { |
238 | if (port != conn->port) | 238 | if (port != conn->port) |
239 | continue; | 239 | continue; |
240 | list_del(&conn->list); | 240 | list_del(&conn->list); |
241 | kfree(conn); | 241 | kfree(conn); |
242 | } | 242 | } |
243 | tipc_node_unlock(node); | 243 | tipc_node_unlock(node); |
244 | tipc_node_put(node); | 244 | tipc_node_put(node); |
245 | } | 245 | } |
246 | 246 | ||
247 | /* tipc_node_timeout - handle expiration of node timer | 247 | /* tipc_node_timeout - handle expiration of node timer |
248 | */ | 248 | */ |
249 | static void tipc_node_timeout(unsigned long data) | 249 | static void tipc_node_timeout(unsigned long data) |
250 | { | 250 | { |
251 | struct tipc_node *n = (struct tipc_node *)data; | 251 | struct tipc_node *n = (struct tipc_node *)data; |
252 | struct sk_buff_head xmitq; | 252 | struct sk_buff_head xmitq; |
253 | struct tipc_link *l; | 253 | struct tipc_link *l; |
254 | struct tipc_media_addr *maddr; | 254 | struct tipc_media_addr *maddr; |
255 | int bearer_id; | 255 | int bearer_id; |
256 | int rc = 0; | 256 | int rc = 0; |
257 | 257 | ||
258 | __skb_queue_head_init(&xmitq); | 258 | __skb_queue_head_init(&xmitq); |
259 | 259 | ||
260 | for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) { | 260 | for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) { |
261 | tipc_node_lock(n); | 261 | tipc_node_lock(n); |
262 | l = n->links[bearer_id].link; | 262 | l = n->links[bearer_id].link; |
263 | if (l) { | 263 | if (l) { |
264 | /* Link tolerance may change asynchronously: */ | 264 | /* Link tolerance may change asynchronously: */ |
265 | tipc_node_calculate_timer(n, l); | 265 | tipc_node_calculate_timer(n, l); |
266 | rc = tipc_link_timeout(l, &xmitq); | 266 | rc = tipc_link_timeout(l, &xmitq); |
267 | if (rc & TIPC_LINK_DOWN_EVT) | 267 | if (rc & TIPC_LINK_DOWN_EVT) |
268 | tipc_node_link_down(n, bearer_id); | 268 | tipc_node_link_down(n, bearer_id); |
269 | } | 269 | } |
270 | tipc_node_unlock(n); | 270 | tipc_node_unlock(n); |
271 | maddr = &n->links[bearer_id].maddr; | 271 | maddr = &n->links[bearer_id].maddr; |
272 | tipc_bearer_xmit(n->net, bearer_id, &xmitq, maddr); | 272 | tipc_bearer_xmit(n->net, bearer_id, &xmitq, maddr); |
273 | } | 273 | } |
274 | if (!mod_timer(&n->timer, jiffies + n->keepalive_intv)) | 274 | if (!mod_timer(&n->timer, jiffies + n->keepalive_intv)) |
275 | tipc_node_get(n); | 275 | tipc_node_get(n); |
276 | tipc_node_put(n); | 276 | tipc_node_put(n); |
277 | } | 277 | } |
278 | 278 | ||
279 | /** | 279 | /** |
280 | * tipc_node_link_up - handle addition of link | 280 | * tipc_node_link_up - handle addition of link |
281 | * | 281 | * |
282 | * Link becomes active (alone or shared) or standby, depending on its priority. | 282 | * Link becomes active (alone or shared) or standby, depending on its priority. |
283 | */ | 283 | */ |
284 | void tipc_node_link_up(struct tipc_node *n, int bearer_id) | 284 | void tipc_node_link_up(struct tipc_node *n, int bearer_id) |
285 | { | 285 | { |
286 | int *slot0 = &n->active_links[0]; | 286 | int *slot0 = &n->active_links[0]; |
287 | int *slot1 = &n->active_links[1]; | 287 | int *slot1 = &n->active_links[1]; |
288 | struct tipc_link_entry *links = n->links; | 288 | struct tipc_link_entry *links = n->links; |
289 | struct tipc_link *l = n->links[bearer_id].link; | 289 | struct tipc_link *l = n->links[bearer_id].link; |
290 | 290 | ||
291 | /* Leave room for tunnel header when returning 'mtu' to users: */ | 291 | /* Leave room for tunnel header when returning 'mtu' to users: */ |
292 | links[bearer_id].mtu = l->mtu - INT_H_SIZE; | 292 | links[bearer_id].mtu = l->mtu - INT_H_SIZE; |
293 | 293 | ||
294 | n->working_links++; | 294 | n->working_links++; |
295 | n->action_flags |= TIPC_NOTIFY_LINK_UP; | 295 | n->action_flags |= TIPC_NOTIFY_LINK_UP; |
296 | n->link_id = l->peer_bearer_id << 16 | l->bearer_id; | 296 | n->link_id = l->peer_bearer_id << 16 | l->bearer_id; |
297 | 297 | ||
298 | tipc_bearer_add_dest(n->net, bearer_id, n->addr); | 298 | tipc_bearer_add_dest(n->net, bearer_id, n->addr); |
299 | 299 | ||
300 | pr_debug("Established link <%s> on network plane %c\n", | 300 | pr_debug("Established link <%s> on network plane %c\n", |
301 | l->name, l->net_plane); | 301 | l->name, l->net_plane); |
302 | 302 | ||
303 | /* No active links ? => take both active slots */ | 303 | /* No active links ? => take both active slots */ |
304 | if (!tipc_node_is_up(n)) { | 304 | if (!tipc_node_is_up(n)) { |
305 | *slot0 = bearer_id; | 305 | *slot0 = bearer_id; |
306 | *slot1 = bearer_id; | 306 | *slot1 = bearer_id; |
307 | node_established_contact(n); | 307 | node_established_contact(n); |
308 | return; | 308 | return; |
309 | } | 309 | } |
310 | 310 | ||
311 | /* Lower prio than current active ? => no slot */ | 311 | /* Lower prio than current active ? => no slot */ |
312 | if (l->priority < links[*slot0].link->priority) { | 312 | if (l->priority < links[*slot0].link->priority) { |
313 | pr_debug("New link <%s> becomes standby\n", l->name); | 313 | pr_debug("New link <%s> becomes standby\n", l->name); |
314 | return; | 314 | return; |
315 | } | 315 | } |
316 | tipc_link_dup_queue_xmit(links[*slot0].link, l); | 316 | tipc_link_dup_queue_xmit(links[*slot0].link, l); |
317 | 317 | ||
318 | /* Same prio as current active ? => take one slot */ | 318 | /* Same prio as current active ? => take one slot */ |
319 | if (l->priority == links[*slot0].link->priority) { | 319 | if (l->priority == links[*slot0].link->priority) { |
320 | *slot0 = bearer_id; | 320 | *slot0 = bearer_id; |
321 | return; | 321 | return; |
322 | } | 322 | } |
323 | 323 | ||
324 | /* Higher prio than current active => take both active slots */ | 324 | /* Higher prio than current active => take both active slots */ |
325 | pr_debug("Old link <%s> now standby\n", links[*slot0].link->name); | 325 | pr_debug("Old link <%s> now standby\n", links[*slot0].link->name); |
326 | *slot0 = bearer_id; | 326 | *slot0 = bearer_id; |
327 | *slot1 = bearer_id; | 327 | *slot1 = bearer_id; |
328 | } | 328 | } |
329 | 329 | ||
330 | /** | 330 | /** |
331 | * tipc_node_link_down - handle loss of link | 331 | * tipc_node_link_down - handle loss of link |
332 | */ | 332 | */ |
333 | void tipc_node_link_down(struct tipc_node *n, int bearer_id) | 333 | void tipc_node_link_down(struct tipc_node *n, int bearer_id) |
334 | { | 334 | { |
335 | int *slot0 = &n->active_links[0]; | 335 | int *slot0 = &n->active_links[0]; |
336 | int *slot1 = &n->active_links[1]; | 336 | int *slot1 = &n->active_links[1]; |
337 | int i, highest = 0; | 337 | int i, highest = 0; |
338 | struct tipc_link *l, *_l; | 338 | struct tipc_link *l, *_l; |
339 | 339 | ||
340 | l = n->links[bearer_id].link; | 340 | l = n->links[bearer_id].link; |
341 | if (!l || !tipc_link_is_up(l)) | 341 | if (!l || !tipc_link_is_up(l)) |
342 | return; | 342 | return; |
343 | 343 | ||
344 | n->working_links--; | 344 | n->working_links--; |
345 | n->action_flags |= TIPC_NOTIFY_LINK_DOWN; | 345 | n->action_flags |= TIPC_NOTIFY_LINK_DOWN; |
346 | n->link_id = l->peer_bearer_id << 16 | l->bearer_id; | 346 | n->link_id = l->peer_bearer_id << 16 | l->bearer_id; |
347 | 347 | ||
348 | tipc_bearer_remove_dest(n->net, l->bearer_id, n->addr); | 348 | tipc_bearer_remove_dest(n->net, l->bearer_id, n->addr); |
349 | 349 | ||
350 | pr_debug("Lost link <%s> on network plane %c\n", | 350 | pr_debug("Lost link <%s> on network plane %c\n", |
351 | l->name, l->net_plane); | 351 | l->name, l->net_plane); |
352 | 352 | ||
353 | /* Select new active link if any available */ | 353 | /* Select new active link if any available */ |
354 | *slot0 = INVALID_BEARER_ID; | 354 | *slot0 = INVALID_BEARER_ID; |
355 | *slot1 = INVALID_BEARER_ID; | 355 | *slot1 = INVALID_BEARER_ID; |
356 | for (i = 0; i < MAX_BEARERS; i++) { | 356 | for (i = 0; i < MAX_BEARERS; i++) { |
357 | _l = n->links[i].link; | 357 | _l = n->links[i].link; |
358 | if (!_l || !tipc_link_is_up(_l)) | 358 | if (!_l || !tipc_link_is_up(_l)) |
359 | continue; | 359 | continue; |
360 | if (_l == l) | 360 | if (_l == l) |
361 | continue; | 361 | continue; |
362 | if (_l->priority < highest) | 362 | if (_l->priority < highest) |
363 | continue; | 363 | continue; |
364 | if (_l->priority > highest) { | 364 | if (_l->priority > highest) { |
365 | highest = _l->priority; | 365 | highest = _l->priority; |
366 | *slot0 = i; | 366 | *slot0 = i; |
367 | *slot1 = i; | 367 | *slot1 = i; |
368 | continue; | 368 | continue; |
369 | } | 369 | } |
370 | *slot1 = i; | 370 | *slot1 = i; |
371 | } | 371 | } |
372 | 372 | ||
373 | if (tipc_node_is_up(n)) | 373 | if (tipc_node_is_up(n)) |
374 | tipc_link_failover_send_queue(l); | 374 | tipc_link_failover_send_queue(l); |
375 | 375 | ||
376 | tipc_link_reset(l); | 376 | tipc_link_reset(l); |
377 | 377 | ||
378 | if (!tipc_node_is_up(n)) | 378 | if (!tipc_node_is_up(n)) |
379 | node_lost_contact(n); | 379 | node_lost_contact(n); |
380 | } | 380 | } |
381 | 381 | ||
382 | bool tipc_node_is_up(struct tipc_node *n) | 382 | bool tipc_node_is_up(struct tipc_node *n) |
383 | { | 383 | { |
384 | return n->active_links[0] != INVALID_BEARER_ID; | 384 | return n->active_links[0] != INVALID_BEARER_ID; |
385 | } | 385 | } |
386 | 386 | ||
387 | void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *b, | 387 | void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *b, |
388 | bool *link_up, bool *addr_match, | 388 | bool *link_up, bool *addr_match, |
389 | struct tipc_media_addr *maddr) | 389 | struct tipc_media_addr *maddr) |
390 | { | 390 | { |
391 | struct tipc_link *l = n->links[b->identity].link; | 391 | struct tipc_link *l = n->links[b->identity].link; |
392 | struct tipc_media_addr *curr = &n->links[b->identity].maddr; | 392 | struct tipc_media_addr *curr = &n->links[b->identity].maddr; |
393 | 393 | ||
394 | *link_up = l && tipc_link_is_up(l); | 394 | *link_up = l && tipc_link_is_up(l); |
395 | *addr_match = l && !memcmp(curr, maddr, sizeof(*maddr)); | 395 | *addr_match = l && !memcmp(curr, maddr, sizeof(*maddr)); |
396 | } | 396 | } |
397 | 397 | ||
398 | bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *b, | 398 | bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *b, |
399 | struct tipc_media_addr *maddr) | 399 | struct tipc_media_addr *maddr) |
400 | { | 400 | { |
401 | struct tipc_link *l = n->links[b->identity].link; | 401 | struct tipc_link *l = n->links[b->identity].link; |
402 | struct tipc_media_addr *curr = &n->links[b->identity].maddr; | 402 | struct tipc_media_addr *curr = &n->links[b->identity].maddr; |
403 | struct sk_buff_head *inputq = &n->links[b->identity].inputq; | 403 | struct sk_buff_head *inputq = &n->links[b->identity].inputq; |
404 | 404 | ||
405 | if (!l) { | 405 | if (!l) { |
406 | l = tipc_link_create(n, b, maddr, inputq, &n->bclink.namedq); | 406 | l = tipc_link_create(n, b, maddr, inputq, &n->bclink.namedq); |
407 | if (!l) | 407 | if (!l) |
408 | return false; | 408 | return false; |
409 | tipc_node_calculate_timer(n, l); | 409 | tipc_node_calculate_timer(n, l); |
410 | if (n->link_cnt == 1) { | 410 | if (n->link_cnt == 1) { |
411 | if (!mod_timer(&n->timer, jiffies + n->keepalive_intv)) | 411 | if (!mod_timer(&n->timer, jiffies + n->keepalive_intv)) |
412 | tipc_node_get(n); | 412 | tipc_node_get(n); |
413 | } | 413 | } |
414 | } | 414 | } |
415 | memcpy(&l->media_addr, maddr, sizeof(*maddr)); | 415 | memcpy(&l->media_addr, maddr, sizeof(*maddr)); |
416 | memcpy(curr, maddr, sizeof(*maddr)); | 416 | memcpy(curr, maddr, sizeof(*maddr)); |
417 | tipc_node_link_down(n, b->identity); | 417 | tipc_node_link_down(n, b->identity); |
418 | return true; | 418 | return true; |
419 | } | 419 | } |
420 | 420 | ||
421 | void tipc_node_delete_links(struct net *net, int bearer_id) | 421 | void tipc_node_delete_links(struct net *net, int bearer_id) |
422 | { | 422 | { |
423 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 423 | struct tipc_net *tn = net_generic(net, tipc_net_id); |
424 | struct tipc_link *l; | 424 | struct tipc_link *l; |
425 | struct tipc_node *n; | 425 | struct tipc_node *n; |
426 | 426 | ||
427 | rcu_read_lock(); | 427 | rcu_read_lock(); |
428 | list_for_each_entry_rcu(n, &tn->node_list, list) { | 428 | list_for_each_entry_rcu(n, &tn->node_list, list) { |
429 | tipc_node_lock(n); | 429 | tipc_node_lock(n); |
430 | l = n->links[bearer_id].link; | 430 | l = n->links[bearer_id].link; |
431 | if (l) { | 431 | if (l) { |
432 | tipc_node_link_down(n, bearer_id); | 432 | tipc_node_link_down(n, bearer_id); |
433 | n->links[bearer_id].link = NULL; | 433 | n->links[bearer_id].link = NULL; |
434 | n->link_cnt--; | 434 | n->link_cnt--; |
435 | } | 435 | } |
436 | tipc_node_unlock(n); | 436 | tipc_node_unlock(n); |
437 | kfree(l); | 437 | kfree(l); |
438 | } | 438 | } |
439 | rcu_read_unlock(); | 439 | rcu_read_unlock(); |
440 | } | 440 | } |
441 | 441 | ||
442 | static void tipc_node_reset_links(struct tipc_node *n) | 442 | static void tipc_node_reset_links(struct tipc_node *n) |
443 | { | 443 | { |
444 | char addr_string[16]; | 444 | char addr_string[16]; |
445 | u32 i; | 445 | u32 i; |
446 | 446 | ||
447 | tipc_node_lock(n); | 447 | tipc_node_lock(n); |
448 | 448 | ||
449 | pr_warn("Resetting all links to %s\n", | 449 | pr_warn("Resetting all links to %s\n", |
450 | tipc_addr_string_fill(addr_string, n->addr)); | 450 | tipc_addr_string_fill(addr_string, n->addr)); |
451 | 451 | ||
452 | for (i = 0; i < MAX_BEARERS; i++) { | 452 | for (i = 0; i < MAX_BEARERS; i++) { |
453 | if (!n->links[i].link) | 453 | if (!n->links[i].link) |
454 | continue; | 454 | continue; |
455 | tipc_node_link_down(n, i); | 455 | tipc_node_link_down(n, i); |
456 | } | 456 | } |
457 | tipc_node_unlock(n); | 457 | tipc_node_unlock(n); |
458 | } | 458 | } |
459 | 459 | ||
460 | void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | 460 | void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) |
461 | { | 461 | { |
462 | n_ptr->links[l_ptr->bearer_id].link = l_ptr; | 462 | n_ptr->links[l_ptr->bearer_id].link = l_ptr; |
463 | n_ptr->link_cnt++; | 463 | n_ptr->link_cnt++; |
464 | } | 464 | } |
465 | 465 | ||
466 | void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | 466 | void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) |
467 | { | 467 | { |
468 | int i; | 468 | int i; |
469 | 469 | ||
470 | for (i = 0; i < MAX_BEARERS; i++) { | 470 | for (i = 0; i < MAX_BEARERS; i++) { |
471 | if (l_ptr != n_ptr->links[i].link) | 471 | if (l_ptr != n_ptr->links[i].link) |
472 | continue; | 472 | continue; |
473 | n_ptr->links[i].link = NULL; | 473 | n_ptr->links[i].link = NULL; |
474 | n_ptr->link_cnt--; | 474 | n_ptr->link_cnt--; |
475 | } | 475 | } |
476 | } | 476 | } |
477 | 477 | ||
478 | /* tipc_node_fsm_evt - node finite state machine | 478 | /* tipc_node_fsm_evt - node finite state machine |
479 | * Determines when contact is allowed with peer node | 479 | * Determines when contact is allowed with peer node |
480 | */ | 480 | */ |
481 | static void tipc_node_fsm_evt(struct tipc_node *n, int evt) | 481 | static void tipc_node_fsm_evt(struct tipc_node *n, int evt) |
482 | { | 482 | { |
483 | int state = n->state; | 483 | int state = n->state; |
484 | 484 | ||
485 | switch (state) { | 485 | switch (state) { |
486 | case SELF_DOWN_PEER_DOWN: | 486 | case SELF_DOWN_PEER_DOWN: |
487 | switch (evt) { | 487 | switch (evt) { |
488 | case SELF_ESTABL_CONTACT_EVT: | 488 | case SELF_ESTABL_CONTACT_EVT: |
489 | state = SELF_UP_PEER_COMING; | 489 | state = SELF_UP_PEER_COMING; |
490 | break; | 490 | break; |
491 | case PEER_ESTABL_CONTACT_EVT: | 491 | case PEER_ESTABL_CONTACT_EVT: |
492 | state = SELF_COMING_PEER_UP; | 492 | state = SELF_COMING_PEER_UP; |
493 | break; | 493 | break; |
494 | case SELF_LOST_CONTACT_EVT: | 494 | case SELF_LOST_CONTACT_EVT: |
495 | case PEER_LOST_CONTACT_EVT: | 495 | case PEER_LOST_CONTACT_EVT: |
496 | break; | 496 | break; |
497 | case NODE_SYNCH_END_EVT: | ||
498 | case NODE_SYNCH_BEGIN_EVT: | ||
499 | case NODE_FAILOVER_BEGIN_EVT: | ||
500 | case NODE_FAILOVER_END_EVT: | ||
497 | default: | 501 | default: |
498 | pr_err("Unknown node fsm evt %x/%x\n", state, evt); | 502 | goto illegal_evt; |
499 | } | 503 | } |
500 | break; | 504 | break; |
501 | case SELF_UP_PEER_UP: | 505 | case SELF_UP_PEER_UP: |
502 | switch (evt) { | 506 | switch (evt) { |
503 | case SELF_LOST_CONTACT_EVT: | 507 | case SELF_LOST_CONTACT_EVT: |
504 | state = SELF_DOWN_PEER_LEAVING; | 508 | state = SELF_DOWN_PEER_LEAVING; |
505 | break; | 509 | break; |
506 | case PEER_LOST_CONTACT_EVT: | 510 | case PEER_LOST_CONTACT_EVT: |
507 | state = SELF_LEAVING_PEER_DOWN; | 511 | state = SELF_LEAVING_PEER_DOWN; |
508 | break; | 512 | break; |
513 | case NODE_SYNCH_BEGIN_EVT: | ||
514 | state = NODE_SYNCHING; | ||
515 | break; | ||
516 | case NODE_FAILOVER_BEGIN_EVT: | ||
517 | state = NODE_FAILINGOVER; | ||
518 | break; | ||
509 | case SELF_ESTABL_CONTACT_EVT: | 519 | case SELF_ESTABL_CONTACT_EVT: |
510 | case PEER_ESTABL_CONTACT_EVT: | 520 | case PEER_ESTABL_CONTACT_EVT: |
521 | case NODE_SYNCH_END_EVT: | ||
522 | case NODE_FAILOVER_END_EVT: | ||
511 | break; | 523 | break; |
512 | default: | 524 | default: |
513 | pr_err("Unknown node fsm evt %x/%x\n", state, evt); | 525 | goto illegal_evt; |
514 | } | 526 | } |
515 | break; | 527 | break; |
516 | case SELF_DOWN_PEER_LEAVING: | 528 | case SELF_DOWN_PEER_LEAVING: |
517 | switch (evt) { | 529 | switch (evt) { |
518 | case PEER_LOST_CONTACT_EVT: | 530 | case PEER_LOST_CONTACT_EVT: |
519 | state = SELF_DOWN_PEER_DOWN; | 531 | state = SELF_DOWN_PEER_DOWN; |
520 | break; | 532 | break; |
521 | case SELF_ESTABL_CONTACT_EVT: | 533 | case SELF_ESTABL_CONTACT_EVT: |
522 | case PEER_ESTABL_CONTACT_EVT: | 534 | case PEER_ESTABL_CONTACT_EVT: |
523 | case SELF_LOST_CONTACT_EVT: | 535 | case SELF_LOST_CONTACT_EVT: |
524 | break; | 536 | break; |
537 | case NODE_SYNCH_END_EVT: | ||
538 | case NODE_SYNCH_BEGIN_EVT: | ||
539 | case NODE_FAILOVER_BEGIN_EVT: | ||
540 | case NODE_FAILOVER_END_EVT: | ||
525 | default: | 541 | default: |
526 | pr_err("Unknown node fsm evt %x/%x\n", state, evt); | 542 | goto illegal_evt; |
527 | } | 543 | } |
528 | break; | 544 | break; |
529 | case SELF_UP_PEER_COMING: | 545 | case SELF_UP_PEER_COMING: |
530 | switch (evt) { | 546 | switch (evt) { |
531 | case PEER_ESTABL_CONTACT_EVT: | 547 | case PEER_ESTABL_CONTACT_EVT: |
532 | state = SELF_UP_PEER_UP; | 548 | state = SELF_UP_PEER_UP; |
533 | break; | 549 | break; |
534 | case SELF_LOST_CONTACT_EVT: | 550 | case SELF_LOST_CONTACT_EVT: |
535 | state = SELF_DOWN_PEER_LEAVING; | 551 | state = SELF_DOWN_PEER_LEAVING; |
536 | break; | 552 | break; |
537 | case SELF_ESTABL_CONTACT_EVT: | 553 | case SELF_ESTABL_CONTACT_EVT: |
538 | case PEER_LOST_CONTACT_EVT: | 554 | case PEER_LOST_CONTACT_EVT: |
539 | break; | 555 | break; |
556 | case NODE_SYNCH_END_EVT: | ||
557 | case NODE_SYNCH_BEGIN_EVT: | ||
558 | case NODE_FAILOVER_BEGIN_EVT: | ||
559 | case NODE_FAILOVER_END_EVT: | ||
540 | default: | 560 | default: |
541 | pr_err("Unknown node fsm evt %x/%x\n", state, evt); | 561 | goto illegal_evt; |
542 | } | 562 | } |
543 | break; | 563 | break; |
544 | case SELF_COMING_PEER_UP: | 564 | case SELF_COMING_PEER_UP: |
545 | switch (evt) { | 565 | switch (evt) { |
546 | case SELF_ESTABL_CONTACT_EVT: | 566 | case SELF_ESTABL_CONTACT_EVT: |
547 | state = SELF_UP_PEER_UP; | 567 | state = SELF_UP_PEER_UP; |
548 | break; | 568 | break; |
549 | case PEER_LOST_CONTACT_EVT: | 569 | case PEER_LOST_CONTACT_EVT: |
550 | state = SELF_LEAVING_PEER_DOWN; | 570 | state = SELF_LEAVING_PEER_DOWN; |
551 | break; | 571 | break; |
552 | case SELF_LOST_CONTACT_EVT: | 572 | case SELF_LOST_CONTACT_EVT: |
553 | case PEER_ESTABL_CONTACT_EVT: | 573 | case PEER_ESTABL_CONTACT_EVT: |
554 | break; | 574 | break; |
575 | case NODE_SYNCH_END_EVT: | ||
576 | case NODE_SYNCH_BEGIN_EVT: | ||
577 | case NODE_FAILOVER_BEGIN_EVT: | ||
578 | case NODE_FAILOVER_END_EVT: | ||
555 | default: | 579 | default: |
556 | pr_err("Unknown node fsm evt %x/%x\n", state, evt); | 580 | goto illegal_evt; |
557 | } | 581 | } |
558 | break; | 582 | break; |
559 | case SELF_LEAVING_PEER_DOWN: | 583 | case SELF_LEAVING_PEER_DOWN: |
560 | switch (evt) { | 584 | switch (evt) { |
561 | case SELF_LOST_CONTACT_EVT: | 585 | case SELF_LOST_CONTACT_EVT: |
562 | state = SELF_DOWN_PEER_DOWN; | 586 | state = SELF_DOWN_PEER_DOWN; |
563 | break; | 587 | break; |
564 | case SELF_ESTABL_CONTACT_EVT: | 588 | case SELF_ESTABL_CONTACT_EVT: |
565 | case PEER_ESTABL_CONTACT_EVT: | 589 | case PEER_ESTABL_CONTACT_EVT: |
566 | case PEER_LOST_CONTACT_EVT: | 590 | case PEER_LOST_CONTACT_EVT: |
567 | break; | 591 | break; |
592 | case NODE_SYNCH_END_EVT: | ||
593 | case NODE_SYNCH_BEGIN_EVT: | ||
594 | case NODE_FAILOVER_BEGIN_EVT: | ||
595 | case NODE_FAILOVER_END_EVT: | ||
568 | default: | 596 | default: |
569 | pr_err("Unknown node fsm evt %x/%x\n", state, evt); | 597 | goto illegal_evt; |
570 | } | 598 | } |
571 | break; | 599 | break; |
600 | case NODE_FAILINGOVER: | ||
601 | switch (evt) { | ||
602 | case SELF_LOST_CONTACT_EVT: | ||
603 | state = SELF_DOWN_PEER_LEAVING; | ||
604 | break; | ||
605 | case PEER_LOST_CONTACT_EVT: | ||
606 | state = SELF_LEAVING_PEER_DOWN; | ||
607 | break; | ||
608 | case NODE_FAILOVER_END_EVT: | ||
609 | state = SELF_UP_PEER_UP; | ||
610 | break; | ||
611 | case NODE_FAILOVER_BEGIN_EVT: | ||
612 | case SELF_ESTABL_CONTACT_EVT: | ||
613 | case PEER_ESTABL_CONTACT_EVT: | ||
614 | break; | ||
615 | case NODE_SYNCH_BEGIN_EVT: | ||
616 | case NODE_SYNCH_END_EVT: | ||
617 | default: | ||
618 | goto illegal_evt; | ||
619 | } | ||
620 | break; | ||
621 | case NODE_SYNCHING: | ||
622 | switch (evt) { | ||
623 | case SELF_LOST_CONTACT_EVT: | ||
624 | state = SELF_DOWN_PEER_LEAVING; | ||
625 | break; | ||
626 | case PEER_LOST_CONTACT_EVT: | ||
627 | state = SELF_LEAVING_PEER_DOWN; | ||
628 | break; | ||
629 | case NODE_SYNCH_END_EVT: | ||
630 | state = SELF_UP_PEER_UP; | ||
631 | break; | ||
632 | case NODE_FAILOVER_BEGIN_EVT: | ||
633 | state = NODE_FAILINGOVER; | ||
634 | break; | ||
635 | case NODE_SYNCH_BEGIN_EVT: | ||
636 | case SELF_ESTABL_CONTACT_EVT: | ||
637 | case PEER_ESTABL_CONTACT_EVT: | ||
638 | break; | ||
639 | case NODE_FAILOVER_END_EVT: | ||
640 | default: | ||
641 | goto illegal_evt; | ||
642 | } | ||
643 | break; | ||
572 | default: | 644 | default: |
573 | pr_err("Unknown node fsm state %x\n", state); | 645 | pr_err("Unknown node fsm state %x\n", state); |
574 | break; | 646 | break; |
575 | } | 647 | } |
576 | |||
577 | n->state = state; | 648 | n->state = state; |
649 | return; | ||
650 | |||
651 | illegal_evt: | ||
652 | pr_err("Illegal node fsm evt %x in state %x\n", evt, state); | ||
578 | } | 653 | } |
579 | 654 | ||
580 | bool tipc_node_filter_skb(struct tipc_node *n, struct tipc_link *l, | 655 | bool tipc_node_filter_skb(struct tipc_node *n, struct tipc_link *l, |
581 | struct tipc_msg *hdr) | 656 | struct tipc_msg *hdr) |
582 | { | 657 | { |
583 | int state = n->state; | 658 | int state = n->state; |
584 | 659 | ||
585 | if (likely(state == SELF_UP_PEER_UP)) | 660 | if (likely(state == SELF_UP_PEER_UP)) |
586 | return true; | 661 | return true; |
587 | 662 | ||
588 | if (state == SELF_DOWN_PEER_DOWN) | 663 | if (state == SELF_DOWN_PEER_DOWN) |
589 | return true; | 664 | return true; |
590 | 665 | ||
591 | if (state == SELF_UP_PEER_COMING) { | 666 | if (state == SELF_UP_PEER_COMING) { |
592 | /* If not traffic msg, peer may still be ESTABLISHING */ | 667 | /* If not traffic msg, peer may still be ESTABLISHING */ |
593 | if (tipc_link_is_up(l) && msg_is_traffic(hdr)) | 668 | if (tipc_link_is_up(l) && msg_is_traffic(hdr)) |
594 | tipc_node_fsm_evt(n, PEER_ESTABL_CONTACT_EVT); | 669 | tipc_node_fsm_evt(n, PEER_ESTABL_CONTACT_EVT); |
595 | return true; | 670 | return true; |
596 | } | 671 | } |
597 | 672 | ||
598 | if (state == SELF_COMING_PEER_UP) | 673 | if (state == SELF_COMING_PEER_UP) |
599 | return true; | 674 | return true; |
600 | 675 | ||
601 | if (state == SELF_LEAVING_PEER_DOWN) | 676 | if (state == SELF_LEAVING_PEER_DOWN) |
602 | return false; | 677 | return false; |
603 | 678 | ||
604 | if (state == SELF_DOWN_PEER_LEAVING) { | 679 | if (state == SELF_DOWN_PEER_LEAVING) { |
605 | if (msg_peer_is_up(hdr)) | 680 | if (msg_peer_is_up(hdr)) |
606 | return false; | 681 | return false; |
607 | tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT); | 682 | tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT); |
608 | return true; | 683 | return true; |
609 | } | 684 | } |
610 | return false; | 685 | return false; |
611 | } | 686 | } |
612 | 687 | ||
613 | static void node_established_contact(struct tipc_node *n_ptr) | 688 | static void node_established_contact(struct tipc_node *n_ptr) |
614 | { | 689 | { |
615 | tipc_node_fsm_evt(n_ptr, SELF_ESTABL_CONTACT_EVT); | 690 | tipc_node_fsm_evt(n_ptr, SELF_ESTABL_CONTACT_EVT); |
616 | n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP; | 691 | n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP; |
617 | n_ptr->bclink.oos_state = 0; | 692 | n_ptr->bclink.oos_state = 0; |
618 | n_ptr->bclink.acked = tipc_bclink_get_last_sent(n_ptr->net); | 693 | n_ptr->bclink.acked = tipc_bclink_get_last_sent(n_ptr->net); |
619 | tipc_bclink_add_node(n_ptr->net, n_ptr->addr); | 694 | tipc_bclink_add_node(n_ptr->net, n_ptr->addr); |
620 | } | 695 | } |
621 | 696 | ||
622 | static void node_lost_contact(struct tipc_node *n_ptr) | 697 | static void node_lost_contact(struct tipc_node *n_ptr) |
623 | { | 698 | { |
624 | char addr_string[16]; | 699 | char addr_string[16]; |
625 | struct tipc_sock_conn *conn, *safe; | 700 | struct tipc_sock_conn *conn, *safe; |
626 | struct list_head *conns = &n_ptr->conn_sks; | 701 | struct list_head *conns = &n_ptr->conn_sks; |
627 | struct sk_buff *skb; | 702 | struct sk_buff *skb; |
628 | struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id); | 703 | struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id); |
629 | uint i; | 704 | uint i; |
630 | 705 | ||
631 | pr_debug("Lost contact with %s\n", | 706 | pr_debug("Lost contact with %s\n", |
632 | tipc_addr_string_fill(addr_string, n_ptr->addr)); | 707 | tipc_addr_string_fill(addr_string, n_ptr->addr)); |
633 | 708 | ||
634 | /* Flush broadcast link info associated with lost node */ | 709 | /* Flush broadcast link info associated with lost node */ |
635 | if (n_ptr->bclink.recv_permitted) { | 710 | if (n_ptr->bclink.recv_permitted) { |
636 | __skb_queue_purge(&n_ptr->bclink.deferdq); | 711 | __skb_queue_purge(&n_ptr->bclink.deferdq); |
637 | 712 | ||
638 | if (n_ptr->bclink.reasm_buf) { | 713 | if (n_ptr->bclink.reasm_buf) { |
639 | kfree_skb(n_ptr->bclink.reasm_buf); | 714 | kfree_skb(n_ptr->bclink.reasm_buf); |
640 | n_ptr->bclink.reasm_buf = NULL; | 715 | n_ptr->bclink.reasm_buf = NULL; |
641 | } | 716 | } |
642 | 717 | ||
643 | tipc_bclink_remove_node(n_ptr->net, n_ptr->addr); | 718 | tipc_bclink_remove_node(n_ptr->net, n_ptr->addr); |
644 | tipc_bclink_acknowledge(n_ptr, INVALID_LINK_SEQ); | 719 | tipc_bclink_acknowledge(n_ptr, INVALID_LINK_SEQ); |
645 | 720 | ||
646 | n_ptr->bclink.recv_permitted = false; | 721 | n_ptr->bclink.recv_permitted = false; |
647 | } | 722 | } |
648 | 723 | ||
649 | /* Abort any ongoing link failover */ | 724 | /* Abort any ongoing link failover */ |
650 | for (i = 0; i < MAX_BEARERS; i++) { | 725 | for (i = 0; i < MAX_BEARERS; i++) { |
651 | struct tipc_link *l_ptr = n_ptr->links[i].link; | 726 | struct tipc_link *l_ptr = n_ptr->links[i].link; |
652 | if (!l_ptr) | 727 | if (!l_ptr) |
653 | continue; | 728 | continue; |
654 | l_ptr->exec_mode = TIPC_LINK_OPEN; | 729 | l_ptr->exec_mode = TIPC_LINK_OPEN; |
655 | l_ptr->failover_checkpt = 0; | 730 | l_ptr->failover_checkpt = 0; |
656 | l_ptr->failover_pkts = 0; | 731 | l_ptr->failover_pkts = 0; |
657 | kfree_skb(l_ptr->failover_skb); | 732 | kfree_skb(l_ptr->failover_skb); |
658 | l_ptr->failover_skb = NULL; | 733 | l_ptr->failover_skb = NULL; |
659 | tipc_link_reset_fragments(l_ptr); | 734 | tipc_link_reset_fragments(l_ptr); |
660 | } | 735 | } |
661 | /* Prevent re-contact with node until cleanup is done */ | 736 | /* Prevent re-contact with node until cleanup is done */ |
662 | tipc_node_fsm_evt(n_ptr, SELF_LOST_CONTACT_EVT); | 737 | tipc_node_fsm_evt(n_ptr, SELF_LOST_CONTACT_EVT); |
663 | 738 | ||
664 | /* Notify publications from this node */ | 739 | /* Notify publications from this node */ |
665 | n_ptr->action_flags |= TIPC_NOTIFY_NODE_DOWN; | 740 | n_ptr->action_flags |= TIPC_NOTIFY_NODE_DOWN; |
666 | 741 | ||
667 | /* Notify sockets connected to node */ | 742 | /* Notify sockets connected to node */ |
668 | list_for_each_entry_safe(conn, safe, conns, list) { | 743 | list_for_each_entry_safe(conn, safe, conns, list) { |
669 | skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG, | 744 | skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG, |
670 | SHORT_H_SIZE, 0, tn->own_addr, | 745 | SHORT_H_SIZE, 0, tn->own_addr, |
671 | conn->peer_node, conn->port, | 746 | conn->peer_node, conn->port, |
672 | conn->peer_port, TIPC_ERR_NO_NODE); | 747 | conn->peer_port, TIPC_ERR_NO_NODE); |
673 | if (likely(skb)) { | 748 | if (likely(skb)) { |
674 | skb_queue_tail(n_ptr->inputq, skb); | 749 | skb_queue_tail(n_ptr->inputq, skb); |
675 | n_ptr->action_flags |= TIPC_MSG_EVT; | 750 | n_ptr->action_flags |= TIPC_MSG_EVT; |
676 | } | 751 | } |
677 | list_del(&conn->list); | 752 | list_del(&conn->list); |
678 | kfree(conn); | 753 | kfree(conn); |
679 | } | 754 | } |
680 | } | 755 | } |
681 | 756 | ||
682 | /** | 757 | /** |
683 | * tipc_node_get_linkname - get the name of a link | 758 | * tipc_node_get_linkname - get the name of a link |
684 | * | 759 | * |
685 | * @bearer_id: id of the bearer | 760 | * @bearer_id: id of the bearer |
686 | * @node: peer node address | 761 | * @node: peer node address |
687 | * @linkname: link name output buffer | 762 | * @linkname: link name output buffer |
688 | * | 763 | * |
689 | * Returns 0 on success | 764 | * Returns 0 on success |
690 | */ | 765 | */ |
691 | int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr, | 766 | int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr, |
692 | char *linkname, size_t len) | 767 | char *linkname, size_t len) |
693 | { | 768 | { |
694 | struct tipc_link *link; | 769 | struct tipc_link *link; |
695 | int err = -EINVAL; | 770 | int err = -EINVAL; |
696 | struct tipc_node *node = tipc_node_find(net, addr); | 771 | struct tipc_node *node = tipc_node_find(net, addr); |
697 | 772 | ||
698 | if (!node) | 773 | if (!node) |
699 | return err; | 774 | return err; |
700 | 775 | ||
701 | if (bearer_id >= MAX_BEARERS) | 776 | if (bearer_id >= MAX_BEARERS) |
702 | goto exit; | 777 | goto exit; |
703 | 778 | ||
704 | tipc_node_lock(node); | 779 | tipc_node_lock(node); |
705 | link = node->links[bearer_id].link; | 780 | link = node->links[bearer_id].link; |
706 | if (link) { | 781 | if (link) { |
707 | strncpy(linkname, link->name, len); | 782 | strncpy(linkname, link->name, len); |
708 | err = 0; | 783 | err = 0; |
709 | } | 784 | } |
710 | exit: | 785 | exit: |
711 | tipc_node_unlock(node); | 786 | tipc_node_unlock(node); |
712 | tipc_node_put(node); | 787 | tipc_node_put(node); |
713 | return err; | 788 | return err; |
714 | } | 789 | } |
715 | 790 | ||
716 | void tipc_node_unlock(struct tipc_node *node) | 791 | void tipc_node_unlock(struct tipc_node *node) |
717 | { | 792 | { |
718 | struct net *net = node->net; | 793 | struct net *net = node->net; |
719 | u32 addr = 0; | 794 | u32 addr = 0; |
720 | u32 flags = node->action_flags; | 795 | u32 flags = node->action_flags; |
721 | u32 link_id = 0; | 796 | u32 link_id = 0; |
722 | struct list_head *publ_list; | 797 | struct list_head *publ_list; |
723 | struct sk_buff_head *inputq = node->inputq; | 798 | struct sk_buff_head *inputq = node->inputq; |
724 | struct sk_buff_head *namedq; | 799 | struct sk_buff_head *namedq; |
725 | 800 | ||
726 | if (likely(!flags || (flags == TIPC_MSG_EVT))) { | 801 | if (likely(!flags || (flags == TIPC_MSG_EVT))) { |
727 | node->action_flags = 0; | 802 | node->action_flags = 0; |
728 | spin_unlock_bh(&node->lock); | 803 | spin_unlock_bh(&node->lock); |
729 | if (flags == TIPC_MSG_EVT) | 804 | if (flags == TIPC_MSG_EVT) |
730 | tipc_sk_rcv(net, inputq); | 805 | tipc_sk_rcv(net, inputq); |
731 | return; | 806 | return; |
732 | } | 807 | } |
733 | 808 | ||
734 | addr = node->addr; | 809 | addr = node->addr; |
735 | link_id = node->link_id; | 810 | link_id = node->link_id; |
736 | namedq = node->namedq; | 811 | namedq = node->namedq; |
737 | publ_list = &node->publ_list; | 812 | publ_list = &node->publ_list; |
738 | 813 | ||
739 | node->action_flags &= ~(TIPC_MSG_EVT | | 814 | node->action_flags &= ~(TIPC_MSG_EVT | |
740 | TIPC_NOTIFY_NODE_DOWN | TIPC_NOTIFY_NODE_UP | | 815 | TIPC_NOTIFY_NODE_DOWN | TIPC_NOTIFY_NODE_UP | |
741 | TIPC_NOTIFY_LINK_DOWN | TIPC_NOTIFY_LINK_UP | | 816 | TIPC_NOTIFY_LINK_DOWN | TIPC_NOTIFY_LINK_UP | |
742 | TIPC_WAKEUP_BCAST_USERS | TIPC_BCAST_MSG_EVT | | 817 | TIPC_WAKEUP_BCAST_USERS | TIPC_BCAST_MSG_EVT | |
743 | TIPC_NAMED_MSG_EVT | TIPC_BCAST_RESET); | 818 | TIPC_NAMED_MSG_EVT | TIPC_BCAST_RESET); |
744 | 819 | ||
745 | spin_unlock_bh(&node->lock); | 820 | spin_unlock_bh(&node->lock); |
746 | 821 | ||
747 | if (flags & TIPC_NOTIFY_NODE_DOWN) | 822 | if (flags & TIPC_NOTIFY_NODE_DOWN) |
748 | tipc_publ_notify(net, publ_list, addr); | 823 | tipc_publ_notify(net, publ_list, addr); |
749 | 824 | ||
750 | if (flags & TIPC_WAKEUP_BCAST_USERS) | 825 | if (flags & TIPC_WAKEUP_BCAST_USERS) |
751 | tipc_bclink_wakeup_users(net); | 826 | tipc_bclink_wakeup_users(net); |
752 | 827 | ||
753 | if (flags & TIPC_NOTIFY_NODE_UP) | 828 | if (flags & TIPC_NOTIFY_NODE_UP) |
754 | tipc_named_node_up(net, addr); | 829 | tipc_named_node_up(net, addr); |
755 | 830 | ||
756 | if (flags & TIPC_NOTIFY_LINK_UP) | 831 | if (flags & TIPC_NOTIFY_LINK_UP) |
757 | tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr, | 832 | tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr, |
758 | TIPC_NODE_SCOPE, link_id, addr); | 833 | TIPC_NODE_SCOPE, link_id, addr); |
759 | 834 | ||
760 | if (flags & TIPC_NOTIFY_LINK_DOWN) | 835 | if (flags & TIPC_NOTIFY_LINK_DOWN) |
761 | tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr, | 836 | tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr, |
762 | link_id, addr); | 837 | link_id, addr); |
763 | 838 | ||
764 | if (flags & TIPC_MSG_EVT) | 839 | if (flags & TIPC_MSG_EVT) |
765 | tipc_sk_rcv(net, inputq); | 840 | tipc_sk_rcv(net, inputq); |
766 | 841 | ||
767 | if (flags & TIPC_NAMED_MSG_EVT) | 842 | if (flags & TIPC_NAMED_MSG_EVT) |
768 | tipc_named_rcv(net, namedq); | 843 | tipc_named_rcv(net, namedq); |
769 | 844 | ||
770 | if (flags & TIPC_BCAST_MSG_EVT) | 845 | if (flags & TIPC_BCAST_MSG_EVT) |
771 | tipc_bclink_input(net); | 846 | tipc_bclink_input(net); |
772 | 847 | ||
773 | if (flags & TIPC_BCAST_RESET) | 848 | if (flags & TIPC_BCAST_RESET) |
774 | tipc_node_reset_links(node); | 849 | tipc_node_reset_links(node); |
775 | } | 850 | } |
776 | 851 | ||
777 | /* Caller should hold node lock for the passed node */ | 852 | /* Caller should hold node lock for the passed node */ |
778 | static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node) | 853 | static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node) |
779 | { | 854 | { |
780 | void *hdr; | 855 | void *hdr; |
781 | struct nlattr *attrs; | 856 | struct nlattr *attrs; |
782 | 857 | ||
783 | hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, | 858 | hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, |
784 | NLM_F_MULTI, TIPC_NL_NODE_GET); | 859 | NLM_F_MULTI, TIPC_NL_NODE_GET); |
785 | if (!hdr) | 860 | if (!hdr) |
786 | return -EMSGSIZE; | 861 | return -EMSGSIZE; |
787 | 862 | ||
788 | attrs = nla_nest_start(msg->skb, TIPC_NLA_NODE); | 863 | attrs = nla_nest_start(msg->skb, TIPC_NLA_NODE); |
789 | if (!attrs) | 864 | if (!attrs) |
790 | goto msg_full; | 865 | goto msg_full; |
791 | 866 | ||
792 | if (nla_put_u32(msg->skb, TIPC_NLA_NODE_ADDR, node->addr)) | 867 | if (nla_put_u32(msg->skb, TIPC_NLA_NODE_ADDR, node->addr)) |
793 | goto attr_msg_full; | 868 | goto attr_msg_full; |
794 | if (tipc_node_is_up(node)) | 869 | if (tipc_node_is_up(node)) |
795 | if (nla_put_flag(msg->skb, TIPC_NLA_NODE_UP)) | 870 | if (nla_put_flag(msg->skb, TIPC_NLA_NODE_UP)) |
796 | goto attr_msg_full; | 871 | goto attr_msg_full; |
797 | 872 | ||
798 | nla_nest_end(msg->skb, attrs); | 873 | nla_nest_end(msg->skb, attrs); |
799 | genlmsg_end(msg->skb, hdr); | 874 | genlmsg_end(msg->skb, hdr); |
800 | 875 | ||
801 | return 0; | 876 | return 0; |
802 | 877 | ||
803 | attr_msg_full: | 878 | attr_msg_full: |
804 | nla_nest_cancel(msg->skb, attrs); | 879 | nla_nest_cancel(msg->skb, attrs); |
805 | msg_full: | 880 | msg_full: |
806 | genlmsg_cancel(msg->skb, hdr); | 881 | genlmsg_cancel(msg->skb, hdr); |
807 | 882 | ||
808 | return -EMSGSIZE; | 883 | return -EMSGSIZE; |
809 | } | 884 | } |
810 | 885 | ||
811 | static struct tipc_link *tipc_node_select_link(struct tipc_node *n, int sel, | 886 | static struct tipc_link *tipc_node_select_link(struct tipc_node *n, int sel, |
812 | int *bearer_id, | 887 | int *bearer_id, |
813 | struct tipc_media_addr **maddr) | 888 | struct tipc_media_addr **maddr) |
814 | { | 889 | { |
815 | int id = n->active_links[sel & 1]; | 890 | int id = n->active_links[sel & 1]; |
816 | 891 | ||
817 | if (unlikely(id < 0)) | 892 | if (unlikely(id < 0)) |
818 | return NULL; | 893 | return NULL; |
819 | 894 | ||
820 | *bearer_id = id; | 895 | *bearer_id = id; |
821 | *maddr = &n->links[id].maddr; | 896 | *maddr = &n->links[id].maddr; |
822 | return n->links[id].link; | 897 | return n->links[id].link; |
823 | } | 898 | } |
824 | 899 | ||
825 | /** | 900 | /** |
826 | * tipc_node_xmit() is the general link level function for message sending | 901 | * tipc_node_xmit() is the general link level function for message sending |
827 | * @net: the applicable net namespace | 902 | * @net: the applicable net namespace |
828 | * @list: chain of buffers containing message | 903 | * @list: chain of buffers containing message |
829 | * @dnode: address of destination node | 904 | * @dnode: address of destination node |
830 | * @selector: a number used for deterministic link selection | 905 | * @selector: a number used for deterministic link selection |
831 | * Consumes the buffer chain, except when returning -ELINKCONG | 906 | * Consumes the buffer chain, except when returning -ELINKCONG |
832 | * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE | 907 | * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE |
833 | */ | 908 | */ |
834 | int tipc_node_xmit(struct net *net, struct sk_buff_head *list, | 909 | int tipc_node_xmit(struct net *net, struct sk_buff_head *list, |
835 | u32 dnode, int selector) | 910 | u32 dnode, int selector) |
836 | { | 911 | { |
837 | struct tipc_link *l = NULL; | 912 | struct tipc_link *l = NULL; |
838 | struct tipc_node *n; | 913 | struct tipc_node *n; |
839 | struct sk_buff_head xmitq; | 914 | struct sk_buff_head xmitq; |
840 | struct tipc_media_addr *maddr; | 915 | struct tipc_media_addr *maddr; |
841 | int bearer_id; | 916 | int bearer_id; |
842 | int rc = -EHOSTUNREACH; | 917 | int rc = -EHOSTUNREACH; |
843 | 918 | ||
844 | __skb_queue_head_init(&xmitq); | 919 | __skb_queue_head_init(&xmitq); |
845 | n = tipc_node_find(net, dnode); | 920 | n = tipc_node_find(net, dnode); |
846 | if (likely(n)) { | 921 | if (likely(n)) { |
847 | tipc_node_lock(n); | 922 | tipc_node_lock(n); |
848 | l = tipc_node_select_link(n, selector, &bearer_id, &maddr); | 923 | l = tipc_node_select_link(n, selector, &bearer_id, &maddr); |
849 | if (likely(l)) | 924 | if (likely(l)) |
850 | rc = tipc_link_xmit(l, list, &xmitq); | 925 | rc = tipc_link_xmit(l, list, &xmitq); |
851 | if (unlikely(rc == -ENOBUFS)) | 926 | if (unlikely(rc == -ENOBUFS)) |
852 | tipc_node_link_down(n, bearer_id); | 927 | tipc_node_link_down(n, bearer_id); |
853 | tipc_node_unlock(n); | 928 | tipc_node_unlock(n); |
854 | tipc_node_put(n); | 929 | tipc_node_put(n); |
855 | } | 930 | } |
856 | if (likely(!rc)) { | 931 | if (likely(!rc)) { |
857 | tipc_bearer_xmit(net, bearer_id, &xmitq, maddr); | 932 | tipc_bearer_xmit(net, bearer_id, &xmitq, maddr); |
858 | return 0; | 933 | return 0; |
859 | } | 934 | } |
860 | if (likely(in_own_node(net, dnode))) { | 935 | if (likely(in_own_node(net, dnode))) { |
861 | tipc_sk_rcv(net, list); | 936 | tipc_sk_rcv(net, list); |
862 | return 0; | 937 | return 0; |
863 | } | 938 | } |
864 | return rc; | 939 | return rc; |
865 | } | 940 | } |
866 | 941 | ||
867 | /* tipc_node_xmit_skb(): send single buffer to destination | 942 | /* tipc_node_xmit_skb(): send single buffer to destination |
868 | * Buffers sent via this functon are generally TIPC_SYSTEM_IMPORTANCE | 943 | * Buffers sent via this functon are generally TIPC_SYSTEM_IMPORTANCE |
869 | * messages, which will not be rejected | 944 | * messages, which will not be rejected |
870 | * The only exception is datagram messages rerouted after secondary | 945 | * The only exception is datagram messages rerouted after secondary |
871 | * lookup, which are rare and safe to dispose of anyway. | 946 | * lookup, which are rare and safe to dispose of anyway. |
872 | * TODO: Return real return value, and let callers use | 947 | * TODO: Return real return value, and let callers use |
873 | * tipc_wait_for_sendpkt() where applicable | 948 | * tipc_wait_for_sendpkt() where applicable |
874 | */ | 949 | */ |
875 | int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode, | 950 | int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode, |
876 | u32 selector) | 951 | u32 selector) |
877 | { | 952 | { |
878 | struct sk_buff_head head; | 953 | struct sk_buff_head head; |
879 | int rc; | 954 | int rc; |
880 | 955 | ||
881 | skb_queue_head_init(&head); | 956 | skb_queue_head_init(&head); |
882 | __skb_queue_tail(&head, skb); | 957 | __skb_queue_tail(&head, skb); |
883 | rc = tipc_node_xmit(net, &head, dnode, selector); | 958 | rc = tipc_node_xmit(net, &head, dnode, selector); |
884 | if (rc == -ELINKCONG) | 959 | if (rc == -ELINKCONG) |
885 | kfree_skb(skb); | 960 | kfree_skb(skb); |
886 | return 0; | 961 | return 0; |
887 | } | 962 | } |
888 | 963 | ||
889 | /* tipc_node_tnl_init(): handle a received TUNNEL_PROTOCOL packet, | 964 | /* tipc_node_tnl_init(): handle a received TUNNEL_PROTOCOL packet, |
890 | * in order to control parallel link failover or synchronization | 965 | * in order to control parallel link failover or synchronization |
891 | */ | 966 | */ |
892 | static void tipc_node_tnl_init(struct tipc_node *n, int bearer_id, | 967 | static void tipc_node_tnl_init(struct tipc_node *n, int bearer_id, |
893 | struct sk_buff *skb) | 968 | struct sk_buff *skb) |
894 | { | 969 | { |
895 | struct tipc_link *tnl, *pl; | 970 | struct tipc_link *tnl, *pl; |
896 | struct tipc_msg *hdr = buf_msg(skb); | 971 | struct tipc_msg *hdr = buf_msg(skb); |
897 | u16 oseqno = msg_seqno(hdr); | 972 | u16 oseqno = msg_seqno(hdr); |
898 | int pb_id = msg_bearer_id(hdr); | 973 | int pb_id = msg_bearer_id(hdr); |
899 | 974 | ||
900 | if (pb_id >= MAX_BEARERS) | 975 | if (pb_id >= MAX_BEARERS) |
901 | return; | 976 | return; |
902 | 977 | ||
903 | tnl = n->links[bearer_id].link; | 978 | tnl = n->links[bearer_id].link; |
904 | if (!tnl) | 979 | if (!tnl) |
905 | return; | 980 | return; |
906 | 981 | ||
907 | /* Ignore if duplicate */ | 982 | /* Ignore if duplicate */ |
908 | if (less(oseqno, tnl->rcv_nxt)) | 983 | if (less(oseqno, tnl->rcv_nxt)) |
909 | return; | 984 | return; |
910 | 985 | ||
911 | pl = n->links[pb_id].link; | 986 | pl = n->links[pb_id].link; |
912 | if (!pl) | 987 | if (!pl) |
913 | return; | 988 | return; |
914 | 989 | ||
915 | if (msg_type(hdr) == FAILOVER_MSG) { | 990 | if (msg_type(hdr) == FAILOVER_MSG) { |
916 | if (tipc_link_is_up(pl)) { | 991 | if (tipc_link_is_up(pl)) { |
917 | tipc_node_link_down(n, pb_id); | 992 | tipc_node_link_down(n, pb_id); |
918 | pl->exec_mode = TIPC_LINK_BLOCKED; | 993 | pl->exec_mode = TIPC_LINK_BLOCKED; |
919 | } | 994 | } |
920 | } | 995 | } |
921 | } | 996 | } |
922 | 997 | ||
923 | /** | 998 | /** |
924 | * tipc_rcv - process TIPC packets/messages arriving from off-node | 999 | * tipc_rcv - process TIPC packets/messages arriving from off-node |
925 | * @net: the applicable net namespace | 1000 | * @net: the applicable net namespace |
926 | * @skb: TIPC packet | 1001 | * @skb: TIPC packet |
927 | * @bearer: pointer to bearer message arrived on | 1002 | * @bearer: pointer to bearer message arrived on |
928 | * | 1003 | * |
929 | * Invoked with no locks held. Bearer pointer must point to a valid bearer | 1004 | * Invoked with no locks held. Bearer pointer must point to a valid bearer |
930 | * structure (i.e. cannot be NULL), but bearer can be inactive. | 1005 | * structure (i.e. cannot be NULL), but bearer can be inactive. |
931 | */ | 1006 | */ |
932 | void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b) | 1007 | void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b) |
933 | { | 1008 | { |
934 | struct sk_buff_head xmitq; | 1009 | struct sk_buff_head xmitq; |
935 | struct tipc_node *n; | 1010 | struct tipc_node *n; |
936 | struct tipc_link *l; | 1011 | struct tipc_link *l; |
937 | struct tipc_msg *hdr; | 1012 | struct tipc_msg *hdr; |
938 | struct tipc_media_addr *maddr; | 1013 | struct tipc_media_addr *maddr; |
939 | int bearer_id = b->identity; | 1014 | int bearer_id = b->identity; |
940 | int rc = 0; | 1015 | int rc = 0; |
941 | int usr; | 1016 | int usr; |
942 | 1017 | ||
943 | __skb_queue_head_init(&xmitq); | 1018 | __skb_queue_head_init(&xmitq); |
944 | 1019 | ||
945 | /* Ensure message is well-formed */ | 1020 | /* Ensure message is well-formed */ |
946 | if (unlikely(!tipc_msg_validate(skb))) | 1021 | if (unlikely(!tipc_msg_validate(skb))) |
947 | goto discard; | 1022 | goto discard; |
948 | 1023 | ||
949 | /* Handle arrival of a non-unicast link packet */ | 1024 | /* Handle arrival of a non-unicast link packet */ |
950 | hdr = buf_msg(skb); | 1025 | hdr = buf_msg(skb); |
951 | usr = msg_user(hdr); | 1026 | usr = msg_user(hdr); |
952 | if (unlikely(msg_non_seq(hdr))) { | 1027 | if (unlikely(msg_non_seq(hdr))) { |
953 | if (usr == LINK_CONFIG) | 1028 | if (usr == LINK_CONFIG) |
954 | tipc_disc_rcv(net, skb, b); | 1029 | tipc_disc_rcv(net, skb, b); |
955 | else | 1030 | else |
956 | tipc_bclink_rcv(net, skb); | 1031 | tipc_bclink_rcv(net, skb); |
957 | return; | 1032 | return; |
958 | } | 1033 | } |
959 | 1034 | ||
960 | /* Locate neighboring node that sent packet */ | 1035 | /* Locate neighboring node that sent packet */ |
961 | n = tipc_node_find(net, msg_prevnode(hdr)); | 1036 | n = tipc_node_find(net, msg_prevnode(hdr)); |
962 | if (unlikely(!n)) | 1037 | if (unlikely(!n)) |
963 | goto discard; | 1038 | goto discard; |
964 | tipc_node_lock(n); | 1039 | tipc_node_lock(n); |
965 | 1040 | ||
966 | /* Prepare links for tunneled reception if applicable */ | 1041 | /* Prepare links for tunneled reception if applicable */ |
967 | if (unlikely(usr == TUNNEL_PROTOCOL)) | 1042 | if (unlikely(usr == TUNNEL_PROTOCOL)) |
968 | tipc_node_tnl_init(n, bearer_id, skb); | 1043 | tipc_node_tnl_init(n, bearer_id, skb); |
969 | 1044 | ||
970 | /* Locate link endpoint that should handle packet */ | 1045 | /* Locate link endpoint that should handle packet */ |
971 | l = n->links[bearer_id].link; | 1046 | l = n->links[bearer_id].link; |
972 | if (unlikely(!l)) | 1047 | if (unlikely(!l)) |
973 | goto unlock; | 1048 | goto unlock; |
974 | 1049 | ||
975 | /* Is reception of this packet permitted at the moment ? */ | 1050 | /* Is reception of this packet permitted at the moment ? */ |
976 | if (unlikely(n->state != SELF_UP_PEER_UP)) | 1051 | if (unlikely(n->state != SELF_UP_PEER_UP)) |
977 | if (!tipc_node_filter_skb(n, l, hdr)) | 1052 | if (!tipc_node_filter_skb(n, l, hdr)) |
978 | goto unlock; | 1053 | goto unlock; |
979 | 1054 | ||
980 | if (unlikely(usr == LINK_PROTOCOL)) | 1055 | if (unlikely(usr == LINK_PROTOCOL)) |
981 | tipc_bclink_sync_state(n, hdr); | 1056 | tipc_bclink_sync_state(n, hdr); |
982 | 1057 | ||
983 | /* Release acked broadcast messages */ | 1058 | /* Release acked broadcast messages */ |
984 | if (unlikely(n->bclink.acked != msg_bcast_ack(hdr))) | 1059 | if (unlikely(n->bclink.acked != msg_bcast_ack(hdr))) |
985 | tipc_bclink_acknowledge(n, msg_bcast_ack(hdr)); | 1060 | tipc_bclink_acknowledge(n, msg_bcast_ack(hdr)); |
986 | 1061 | ||
987 | /* Check protocol and update link state */ | 1062 | /* Check protocol and update link state */ |
988 | rc = tipc_link_rcv(l, skb, &xmitq); | 1063 | rc = tipc_link_rcv(l, skb, &xmitq); |
989 | 1064 | ||
990 | if (unlikely(rc & TIPC_LINK_UP_EVT)) | 1065 | if (unlikely(rc & TIPC_LINK_UP_EVT)) |
991 | tipc_node_link_up(n, bearer_id); | 1066 | tipc_node_link_up(n, bearer_id); |
992 | if (unlikely(rc & TIPC_LINK_DOWN_EVT)) | 1067 | if (unlikely(rc & TIPC_LINK_DOWN_EVT)) |
993 | tipc_node_link_down(n, bearer_id); | 1068 | tipc_node_link_down(n, bearer_id); |
994 | skb = NULL; | 1069 | skb = NULL; |
995 | unlock: | 1070 | unlock: |
996 | tipc_node_unlock(n); | 1071 | tipc_node_unlock(n); |
997 | tipc_sk_rcv(net, &n->links[bearer_id].inputq); | 1072 | tipc_sk_rcv(net, &n->links[bearer_id].inputq); |
998 | maddr = &n->links[bearer_id].maddr; | 1073 | maddr = &n->links[bearer_id].maddr; |
999 | tipc_bearer_xmit(net, bearer_id, &xmitq, maddr); | 1074 | tipc_bearer_xmit(net, bearer_id, &xmitq, maddr); |
1000 | tipc_node_put(n); | 1075 | tipc_node_put(n); |
1001 | discard: | 1076 | discard: |
1002 | kfree_skb(skb); | 1077 | kfree_skb(skb); |
1003 | } | 1078 | } |
1004 | 1079 | ||
1005 | int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb) | 1080 | int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb) |
1006 | { | 1081 | { |
1007 | int err; | 1082 | int err; |
1008 | struct net *net = sock_net(skb->sk); | 1083 | struct net *net = sock_net(skb->sk); |
1009 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 1084 | struct tipc_net *tn = net_generic(net, tipc_net_id); |
1010 | int done = cb->args[0]; | 1085 | int done = cb->args[0]; |
1011 | int last_addr = cb->args[1]; | 1086 | int last_addr = cb->args[1]; |
1012 | struct tipc_node *node; | 1087 | struct tipc_node *node; |
1013 | struct tipc_nl_msg msg; | 1088 | struct tipc_nl_msg msg; |
1014 | 1089 | ||
1015 | if (done) | 1090 | if (done) |
1016 | return 0; | 1091 | return 0; |
1017 | 1092 | ||
1018 | msg.skb = skb; | 1093 | msg.skb = skb; |
1019 | msg.portid = NETLINK_CB(cb->skb).portid; | 1094 | msg.portid = NETLINK_CB(cb->skb).portid; |
1020 | msg.seq = cb->nlh->nlmsg_seq; | 1095 | msg.seq = cb->nlh->nlmsg_seq; |
1021 | 1096 | ||
1022 | rcu_read_lock(); | 1097 | rcu_read_lock(); |
1023 | if (last_addr) { | 1098 | if (last_addr) { |
1024 | node = tipc_node_find(net, last_addr); | 1099 | node = tipc_node_find(net, last_addr); |
1025 | if (!node) { | 1100 | if (!node) { |
1026 | rcu_read_unlock(); | 1101 | rcu_read_unlock(); |
1027 | /* We never set seq or call nl_dump_check_consistent() | 1102 | /* We never set seq or call nl_dump_check_consistent() |
1028 | * this means that setting prev_seq here will cause the | 1103 | * this means that setting prev_seq here will cause the |
1029 | * consistence check to fail in the netlink callback | 1104 | * consistence check to fail in the netlink callback |
1030 | * handler. Resulting in the NLMSG_DONE message having | 1105 | * handler. Resulting in the NLMSG_DONE message having |
1031 | * the NLM_F_DUMP_INTR flag set if the node state | 1106 | * the NLM_F_DUMP_INTR flag set if the node state |
1032 | * changed while we released the lock. | 1107 | * changed while we released the lock. |
1033 | */ | 1108 | */ |
1034 | cb->prev_seq = 1; | 1109 | cb->prev_seq = 1; |
1035 | return -EPIPE; | 1110 | return -EPIPE; |
1036 | } | 1111 | } |
1037 | tipc_node_put(node); | 1112 | tipc_node_put(node); |
1038 | } | 1113 | } |
1039 | 1114 | ||
1040 | list_for_each_entry_rcu(node, &tn->node_list, list) { | 1115 | list_for_each_entry_rcu(node, &tn->node_list, list) { |
1041 | if (last_addr) { | 1116 | if (last_addr) { |
1042 | if (node->addr == last_addr) | 1117 | if (node->addr == last_addr) |
1043 | last_addr = 0; | 1118 | last_addr = 0; |
1044 | else | 1119 | else |
1045 | continue; | 1120 | continue; |
1046 | } | 1121 | } |
1047 | 1122 | ||
1048 | tipc_node_lock(node); | 1123 | tipc_node_lock(node); |
1049 | err = __tipc_nl_add_node(&msg, node); | 1124 | err = __tipc_nl_add_node(&msg, node); |
1050 | if (err) { | 1125 | if (err) { |
1051 | last_addr = node->addr; | 1126 | last_addr = node->addr; |
1052 | tipc_node_unlock(node); | 1127 | tipc_node_unlock(node); |
1053 | goto out; | 1128 | goto out; |
1054 | } | 1129 | } |
1055 | 1130 | ||
1056 | tipc_node_unlock(node); | 1131 | tipc_node_unlock(node); |
1057 | } | 1132 | } |
1058 | done = 1; | 1133 | done = 1; |
1059 | out: | 1134 | out: |
1060 | cb->args[0] = done; | 1135 | cb->args[0] = done; |
1061 | cb->args[1] = last_addr; | 1136 | cb->args[1] = last_addr; |
1062 | rcu_read_unlock(); | 1137 | rcu_read_unlock(); |
1063 | 1138 | ||
1064 | return skb->len; | 1139 | return skb->len; |
1065 | } | 1140 | } |
net/tipc/node.h
1 | /* | 1 | /* |
2 | * net/tipc/node.h: Include file for TIPC node management routines | 2 | * net/tipc/node.h: Include file for TIPC node management routines |
3 | * | 3 | * |
4 | * Copyright (c) 2000-2006, 2014-2015, Ericsson AB | 4 | * Copyright (c) 2000-2006, 2014-2015, Ericsson AB |
5 | * Copyright (c) 2005, 2010-2014, Wind River Systems | 5 | * Copyright (c) 2005, 2010-2014, Wind River Systems |
6 | * All rights reserved. | 6 | * All rights reserved. |
7 | * | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions are met: | 9 | * modification, are permitted provided that the following conditions are met: |
10 | * | 10 | * |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. | 15 | * documentation and/or other materials provided with the distribution. |
16 | * 3. Neither the names of the copyright holders nor the names of its | 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 | 17 | * contributors may be used to endorse or promote products derived from |
18 | * this software without specific prior written permission. | 18 | * this software without specific prior written permission. |
19 | * | 19 | * |
20 | * Alternatively, this software may be distributed under the terms of the | 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 | 21 | * GNU General Public License ("GPL") version 2 as published by the Free |
22 | * Software Foundation. | 22 | * Software Foundation. |
23 | * | 23 | * |
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 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 | 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 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 | 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 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 | 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
34 | * POSSIBILITY OF SUCH DAMAGE. | 34 | * POSSIBILITY OF SUCH DAMAGE. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #ifndef _TIPC_NODE_H | 37 | #ifndef _TIPC_NODE_H |
38 | #define _TIPC_NODE_H | 38 | #define _TIPC_NODE_H |
39 | 39 | ||
40 | #include "addr.h" | 40 | #include "addr.h" |
41 | #include "net.h" | 41 | #include "net.h" |
42 | #include "bearer.h" | 42 | #include "bearer.h" |
43 | #include "msg.h" | 43 | #include "msg.h" |
44 | 44 | ||
45 | /* Out-of-range value for node signature */ | 45 | /* Out-of-range value for node signature */ |
46 | #define INVALID_NODE_SIG 0x10000 | 46 | #define INVALID_NODE_SIG 0x10000 |
47 | 47 | ||
48 | #define INVALID_BEARER_ID -1 | 48 | #define INVALID_BEARER_ID -1 |
49 | 49 | ||
50 | /* Node FSM states and events: | 50 | /* Node FSM states and events: |
51 | */ | 51 | */ |
52 | enum { | 52 | enum { |
53 | SELF_DOWN_PEER_DOWN = 0xdd, | 53 | SELF_DOWN_PEER_DOWN = 0xdd, |
54 | SELF_UP_PEER_UP = 0xaa, | 54 | SELF_UP_PEER_UP = 0xaa, |
55 | SELF_DOWN_PEER_LEAVING = 0xd1, | 55 | SELF_DOWN_PEER_LEAVING = 0xd1, |
56 | SELF_UP_PEER_COMING = 0xac, | 56 | SELF_UP_PEER_COMING = 0xac, |
57 | SELF_COMING_PEER_UP = 0xca, | 57 | SELF_COMING_PEER_UP = 0xca, |
58 | SELF_LEAVING_PEER_DOWN = 0x1d, | 58 | SELF_LEAVING_PEER_DOWN = 0x1d, |
59 | NODE_FAILINGOVER = 0xf0, | ||
60 | NODE_SYNCHING = 0xcc | ||
59 | }; | 61 | }; |
60 | 62 | ||
61 | enum { | 63 | enum { |
62 | SELF_ESTABL_CONTACT_EVT = 0xec, | 64 | SELF_ESTABL_CONTACT_EVT = 0xece, |
63 | SELF_LOST_CONTACT_EVT = 0x1c, | 65 | SELF_LOST_CONTACT_EVT = 0x1ce, |
64 | PEER_ESTABL_CONTACT_EVT = 0xfec, | 66 | PEER_ESTABL_CONTACT_EVT = 0xfece, |
65 | PEER_LOST_CONTACT_EVT = 0xf1c | 67 | PEER_LOST_CONTACT_EVT = 0xf1ce, |
68 | NODE_FAILOVER_BEGIN_EVT = 0xfbe, | ||
69 | NODE_FAILOVER_END_EVT = 0xfee, | ||
70 | NODE_SYNCH_BEGIN_EVT = 0xcbe, | ||
71 | NODE_SYNCH_END_EVT = 0xcee | ||
66 | }; | 72 | }; |
67 | 73 | ||
68 | /* Flags used to take different actions according to flag type | 74 | /* Flags used to take different actions according to flag type |
69 | * TIPC_WAIT_PEER_LINKS_DOWN: wait to see that peer's links are down | 75 | * TIPC_WAIT_PEER_LINKS_DOWN: wait to see that peer's links are down |
70 | * TIPC_WAIT_OWN_LINKS_DOWN: wait until peer node is declared down | 76 | * TIPC_WAIT_OWN_LINKS_DOWN: wait until peer node is declared down |
71 | * TIPC_NOTIFY_NODE_DOWN: notify node is down | 77 | * TIPC_NOTIFY_NODE_DOWN: notify node is down |
72 | * TIPC_NOTIFY_NODE_UP: notify node is up | 78 | * TIPC_NOTIFY_NODE_UP: notify node is up |
73 | * TIPC_DISTRIBUTE_NAME: publish or withdraw link state name type | 79 | * TIPC_DISTRIBUTE_NAME: publish or withdraw link state name type |
74 | */ | 80 | */ |
75 | enum { | 81 | enum { |
76 | TIPC_MSG_EVT = 1, | 82 | TIPC_MSG_EVT = 1, |
77 | TIPC_NOTIFY_NODE_DOWN = (1 << 3), | 83 | TIPC_NOTIFY_NODE_DOWN = (1 << 3), |
78 | TIPC_NOTIFY_NODE_UP = (1 << 4), | 84 | TIPC_NOTIFY_NODE_UP = (1 << 4), |
79 | TIPC_WAKEUP_BCAST_USERS = (1 << 5), | 85 | TIPC_WAKEUP_BCAST_USERS = (1 << 5), |
80 | TIPC_NOTIFY_LINK_UP = (1 << 6), | 86 | TIPC_NOTIFY_LINK_UP = (1 << 6), |
81 | TIPC_NOTIFY_LINK_DOWN = (1 << 7), | 87 | TIPC_NOTIFY_LINK_DOWN = (1 << 7), |
82 | TIPC_NAMED_MSG_EVT = (1 << 8), | 88 | TIPC_NAMED_MSG_EVT = (1 << 8), |
83 | TIPC_BCAST_MSG_EVT = (1 << 9), | 89 | TIPC_BCAST_MSG_EVT = (1 << 9), |
84 | TIPC_BCAST_RESET = (1 << 10) | 90 | TIPC_BCAST_RESET = (1 << 10) |
85 | }; | 91 | }; |
86 | 92 | ||
87 | /** | 93 | /** |
88 | * struct tipc_node_bclink - TIPC node bclink structure | 94 | * struct tipc_node_bclink - TIPC node bclink structure |
89 | * @acked: sequence # of last outbound b'cast message acknowledged by node | 95 | * @acked: sequence # of last outbound b'cast message acknowledged by node |
90 | * @last_in: sequence # of last in-sequence b'cast message received from node | 96 | * @last_in: sequence # of last in-sequence b'cast message received from node |
91 | * @last_sent: sequence # of last b'cast message sent by node | 97 | * @last_sent: sequence # of last b'cast message sent by node |
92 | * @oos_state: state tracker for handling OOS b'cast messages | 98 | * @oos_state: state tracker for handling OOS b'cast messages |
93 | * @deferred_queue: deferred queue saved OOS b'cast message received from node | 99 | * @deferred_queue: deferred queue saved OOS b'cast message received from node |
94 | * @reasm_buf: broadcast reassembly queue head from node | 100 | * @reasm_buf: broadcast reassembly queue head from node |
95 | * @inputq_map: bitmap indicating which inqueues should be kicked | 101 | * @inputq_map: bitmap indicating which inqueues should be kicked |
96 | * @recv_permitted: true if node is allowed to receive b'cast messages | 102 | * @recv_permitted: true if node is allowed to receive b'cast messages |
97 | */ | 103 | */ |
98 | struct tipc_node_bclink { | 104 | struct tipc_node_bclink { |
99 | u32 acked; | 105 | u32 acked; |
100 | u32 last_in; | 106 | u32 last_in; |
101 | u32 last_sent; | 107 | u32 last_sent; |
102 | u32 oos_state; | 108 | u32 oos_state; |
103 | u32 deferred_size; | 109 | u32 deferred_size; |
104 | struct sk_buff_head deferdq; | 110 | struct sk_buff_head deferdq; |
105 | struct sk_buff *reasm_buf; | 111 | struct sk_buff *reasm_buf; |
106 | struct sk_buff_head namedq; | 112 | struct sk_buff_head namedq; |
107 | bool recv_permitted; | 113 | bool recv_permitted; |
108 | }; | 114 | }; |
109 | 115 | ||
110 | struct tipc_link_entry { | 116 | struct tipc_link_entry { |
111 | struct tipc_link *link; | 117 | struct tipc_link *link; |
112 | u32 mtu; | 118 | u32 mtu; |
113 | struct sk_buff_head inputq; | 119 | struct sk_buff_head inputq; |
114 | struct tipc_media_addr maddr; | 120 | struct tipc_media_addr maddr; |
115 | }; | 121 | }; |
116 | 122 | ||
117 | /** | 123 | /** |
118 | * struct tipc_node - TIPC node structure | 124 | * struct tipc_node - TIPC node structure |
119 | * @addr: network address of node | 125 | * @addr: network address of node |
120 | * @ref: reference counter to node object | 126 | * @ref: reference counter to node object |
121 | * @lock: spinlock governing access to structure | 127 | * @lock: spinlock governing access to structure |
122 | * @net: the applicable net namespace | 128 | * @net: the applicable net namespace |
123 | * @hash: links to adjacent nodes in unsorted hash chain | 129 | * @hash: links to adjacent nodes in unsorted hash chain |
124 | * @inputq: pointer to input queue containing messages for msg event | 130 | * @inputq: pointer to input queue containing messages for msg event |
125 | * @namedq: pointer to name table input queue with name table messages | 131 | * @namedq: pointer to name table input queue with name table messages |
126 | * @active_links: bearer ids of active links, used as index into links[] array | 132 | * @active_links: bearer ids of active links, used as index into links[] array |
127 | * @links: array containing references to all links to node | 133 | * @links: array containing references to all links to node |
128 | * @action_flags: bit mask of different types of node actions | 134 | * @action_flags: bit mask of different types of node actions |
129 | * @bclink: broadcast-related info | 135 | * @bclink: broadcast-related info |
130 | * @list: links to adjacent nodes in sorted list of cluster's nodes | 136 | * @list: links to adjacent nodes in sorted list of cluster's nodes |
131 | * @working_links: number of working links to node (both active and standby) | 137 | * @working_links: number of working links to node (both active and standby) |
132 | * @link_cnt: number of links to node | 138 | * @link_cnt: number of links to node |
133 | * @capabilities: bitmap, indicating peer node's functional capabilities | 139 | * @capabilities: bitmap, indicating peer node's functional capabilities |
134 | * @signature: node instance identifier | 140 | * @signature: node instance identifier |
135 | * @link_id: local and remote bearer ids of changing link, if any | 141 | * @link_id: local and remote bearer ids of changing link, if any |
136 | * @publ_list: list of publications | 142 | * @publ_list: list of publications |
137 | * @rcu: rcu struct for tipc_node | 143 | * @rcu: rcu struct for tipc_node |
138 | */ | 144 | */ |
139 | struct tipc_node { | 145 | struct tipc_node { |
140 | u32 addr; | 146 | u32 addr; |
141 | struct kref kref; | 147 | struct kref kref; |
142 | spinlock_t lock; | 148 | spinlock_t lock; |
143 | struct net *net; | 149 | struct net *net; |
144 | struct hlist_node hash; | 150 | struct hlist_node hash; |
145 | struct sk_buff_head *inputq; | 151 | struct sk_buff_head *inputq; |
146 | struct sk_buff_head *namedq; | 152 | struct sk_buff_head *namedq; |
147 | int active_links[2]; | 153 | int active_links[2]; |
148 | struct tipc_link_entry links[MAX_BEARERS]; | 154 | struct tipc_link_entry links[MAX_BEARERS]; |
149 | int action_flags; | 155 | int action_flags; |
150 | struct tipc_node_bclink bclink; | 156 | struct tipc_node_bclink bclink; |
151 | struct list_head list; | 157 | struct list_head list; |
152 | int state; | 158 | int state; |
153 | int link_cnt; | 159 | int link_cnt; |
154 | u16 working_links; | 160 | u16 working_links; |
155 | u16 capabilities; | 161 | u16 capabilities; |
156 | u32 signature; | 162 | u32 signature; |
157 | u32 link_id; | 163 | u32 link_id; |
158 | struct list_head publ_list; | 164 | struct list_head publ_list; |
159 | struct list_head conn_sks; | 165 | struct list_head conn_sks; |
160 | unsigned long keepalive_intv; | 166 | unsigned long keepalive_intv; |
161 | struct timer_list timer; | 167 | struct timer_list timer; |
162 | struct rcu_head rcu; | 168 | struct rcu_head rcu; |
163 | }; | 169 | }; |
164 | 170 | ||
165 | struct tipc_node *tipc_node_find(struct net *net, u32 addr); | 171 | struct tipc_node *tipc_node_find(struct net *net, u32 addr); |
166 | void tipc_node_put(struct tipc_node *node); | 172 | void tipc_node_put(struct tipc_node *node); |
167 | struct tipc_node *tipc_node_create(struct net *net, u32 addr); | 173 | struct tipc_node *tipc_node_create(struct net *net, u32 addr); |
168 | void tipc_node_stop(struct net *net); | 174 | void tipc_node_stop(struct net *net); |
169 | void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *bearer, | 175 | void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *bearer, |
170 | bool *link_up, bool *addr_match, | 176 | bool *link_up, bool *addr_match, |
171 | struct tipc_media_addr *maddr); | 177 | struct tipc_media_addr *maddr); |
172 | bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *bearer, | 178 | bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *bearer, |
173 | struct tipc_media_addr *maddr); | 179 | struct tipc_media_addr *maddr); |
174 | void tipc_node_delete_links(struct net *net, int bearer_id); | 180 | void tipc_node_delete_links(struct net *net, int bearer_id); |
175 | void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); | 181 | void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); |
176 | void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); | 182 | void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); |
177 | void tipc_node_link_down(struct tipc_node *n_ptr, int bearer_id); | 183 | void tipc_node_link_down(struct tipc_node *n_ptr, int bearer_id); |
178 | void tipc_node_link_up(struct tipc_node *n_ptr, int bearer_id); | 184 | void tipc_node_link_up(struct tipc_node *n_ptr, int bearer_id); |
179 | bool tipc_node_is_up(struct tipc_node *n); | 185 | bool tipc_node_is_up(struct tipc_node *n); |
180 | int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node, | 186 | int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node, |
181 | char *linkname, size_t len); | 187 | char *linkname, size_t len); |
182 | void tipc_node_unlock(struct tipc_node *node); | 188 | void tipc_node_unlock(struct tipc_node *node); |
183 | int tipc_node_xmit(struct net *net, struct sk_buff_head *list, u32 dnode, | 189 | int tipc_node_xmit(struct net *net, struct sk_buff_head *list, u32 dnode, |
184 | int selector); | 190 | int selector); |
185 | int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest, | 191 | int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest, |
186 | u32 selector); | 192 | u32 selector); |
187 | int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port); | 193 | int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port); |
188 | void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port); | 194 | void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port); |
189 | int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb); | 195 | int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb); |
190 | 196 | ||
191 | static inline void tipc_node_lock(struct tipc_node *node) | 197 | static inline void tipc_node_lock(struct tipc_node *node) |
192 | { | 198 | { |
193 | spin_lock_bh(&node->lock); | 199 | spin_lock_bh(&node->lock); |
194 | } | 200 | } |
195 | 201 | ||
196 | static inline struct tipc_link *node_active_link(struct tipc_node *n, int sel) | 202 | static inline struct tipc_link *node_active_link(struct tipc_node *n, int sel) |
197 | { | 203 | { |
198 | int bearer_id = n->active_links[sel & 1]; | 204 | int bearer_id = n->active_links[sel & 1]; |
199 | 205 | ||
200 | if (unlikely(bearer_id == INVALID_BEARER_ID)) | 206 | if (unlikely(bearer_id == INVALID_BEARER_ID)) |
201 | return NULL; | 207 | return NULL; |
202 | 208 | ||
203 | return n->links[bearer_id].link; | 209 | return n->links[bearer_id].link; |
204 | } | 210 | } |
205 | 211 | ||
206 | static inline unsigned int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel) | 212 | static inline unsigned int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel) |
207 | { | 213 | { |
208 | struct tipc_node *n; | 214 | struct tipc_node *n; |
209 | int bearer_id; | 215 | int bearer_id; |
210 | unsigned int mtu = MAX_MSG_SIZE; | 216 | unsigned int mtu = MAX_MSG_SIZE; |
211 | 217 | ||
212 | n = tipc_node_find(net, addr); | 218 | n = tipc_node_find(net, addr); |
213 | if (unlikely(!n)) | 219 | if (unlikely(!n)) |
214 | return mtu; | 220 | return mtu; |
215 | 221 | ||
216 | bearer_id = n->active_links[sel & 1]; | 222 | bearer_id = n->active_links[sel & 1]; |
217 | if (likely(bearer_id != INVALID_BEARER_ID)) | 223 | if (likely(bearer_id != INVALID_BEARER_ID)) |
218 | mtu = n->links[bearer_id].mtu; | 224 | mtu = n->links[bearer_id].mtu; |
219 | tipc_node_put(n); | 225 | tipc_node_put(n); |
220 | return mtu; | 226 | return mtu; |
221 | } | 227 | } |
222 | 228 | ||
223 | #endif | 229 | #endif |
224 | 230 |