diff options
Diffstat (limited to 'net/tipc/node.c')
-rw-r--r-- | net/tipc/node.c | 135 |
1 files changed, 65 insertions, 70 deletions
diff --git a/net/tipc/node.c b/net/tipc/node.c index 9d7a16fc5ca4..9aaa1bc566ae 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
@@ -41,6 +41,7 @@ | |||
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 | #include "netlink.h" | ||
44 | 45 | ||
45 | #define INVALID_NODE_SIG 0x10000 | 46 | #define INVALID_NODE_SIG 0x10000 |
46 | 47 | ||
@@ -164,28 +165,6 @@ struct tipc_sock_conn { | |||
164 | struct list_head list; | 165 | struct list_head list; |
165 | }; | 166 | }; |
166 | 167 | ||
167 | static const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = { | ||
168 | [TIPC_NLA_LINK_UNSPEC] = { .type = NLA_UNSPEC }, | ||
169 | [TIPC_NLA_LINK_NAME] = { | ||
170 | .type = NLA_STRING, | ||
171 | .len = TIPC_MAX_LINK_NAME | ||
172 | }, | ||
173 | [TIPC_NLA_LINK_MTU] = { .type = NLA_U32 }, | ||
174 | [TIPC_NLA_LINK_BROADCAST] = { .type = NLA_FLAG }, | ||
175 | [TIPC_NLA_LINK_UP] = { .type = NLA_FLAG }, | ||
176 | [TIPC_NLA_LINK_ACTIVE] = { .type = NLA_FLAG }, | ||
177 | [TIPC_NLA_LINK_PROP] = { .type = NLA_NESTED }, | ||
178 | [TIPC_NLA_LINK_STATS] = { .type = NLA_NESTED }, | ||
179 | [TIPC_NLA_LINK_RX] = { .type = NLA_U32 }, | ||
180 | [TIPC_NLA_LINK_TX] = { .type = NLA_U32 } | ||
181 | }; | ||
182 | |||
183 | static const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = { | ||
184 | [TIPC_NLA_NODE_UNSPEC] = { .type = NLA_UNSPEC }, | ||
185 | [TIPC_NLA_NODE_ADDR] = { .type = NLA_U32 }, | ||
186 | [TIPC_NLA_NODE_UP] = { .type = NLA_FLAG } | ||
187 | }; | ||
188 | |||
189 | static struct tipc_link *node_active_link(struct tipc_node *n, int sel) | 168 | static struct tipc_link *node_active_link(struct tipc_node *n, int sel) |
190 | { | 169 | { |
191 | int bearer_id = n->active_links[sel & 1]; | 170 | int bearer_id = n->active_links[sel & 1]; |
@@ -225,9 +204,10 @@ static unsigned int tipc_hashfn(u32 addr) | |||
225 | 204 | ||
226 | static void tipc_node_kref_release(struct kref *kref) | 205 | static void tipc_node_kref_release(struct kref *kref) |
227 | { | 206 | { |
228 | struct tipc_node *node = container_of(kref, struct tipc_node, kref); | 207 | struct tipc_node *n = container_of(kref, struct tipc_node, kref); |
229 | 208 | ||
230 | tipc_node_delete(node); | 209 | kfree(n->bc_entry.link); |
210 | kfree_rcu(n, rcu); | ||
231 | } | 211 | } |
232 | 212 | ||
233 | static void tipc_node_put(struct tipc_node *node) | 213 | static void tipc_node_put(struct tipc_node *node) |
@@ -245,23 +225,23 @@ static void tipc_node_get(struct tipc_node *node) | |||
245 | */ | 225 | */ |
246 | static struct tipc_node *tipc_node_find(struct net *net, u32 addr) | 226 | static struct tipc_node *tipc_node_find(struct net *net, u32 addr) |
247 | { | 227 | { |
248 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 228 | struct tipc_net *tn = tipc_net(net); |
249 | struct tipc_node *node; | 229 | struct tipc_node *node; |
230 | unsigned int thash = tipc_hashfn(addr); | ||
250 | 231 | ||
251 | if (unlikely(!in_own_cluster_exact(net, addr))) | 232 | if (unlikely(!in_own_cluster_exact(net, addr))) |
252 | return NULL; | 233 | return NULL; |
253 | 234 | ||
254 | rcu_read_lock(); | 235 | rcu_read_lock(); |
255 | hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)], | 236 | hlist_for_each_entry_rcu(node, &tn->node_htable[thash], hash) { |
256 | hash) { | 237 | if (node->addr != addr) |
257 | if (node->addr == addr) { | 238 | continue; |
258 | tipc_node_get(node); | 239 | if (!kref_get_unless_zero(&node->kref)) |
259 | rcu_read_unlock(); | 240 | node = NULL; |
260 | return node; | 241 | break; |
261 | } | ||
262 | } | 242 | } |
263 | rcu_read_unlock(); | 243 | rcu_read_unlock(); |
264 | return NULL; | 244 | return node; |
265 | } | 245 | } |
266 | 246 | ||
267 | static void tipc_node_read_lock(struct tipc_node *n) | 247 | static void tipc_node_read_lock(struct tipc_node *n) |
@@ -395,21 +375,20 @@ static void tipc_node_delete(struct tipc_node *node) | |||
395 | { | 375 | { |
396 | list_del_rcu(&node->list); | 376 | list_del_rcu(&node->list); |
397 | hlist_del_rcu(&node->hash); | 377 | hlist_del_rcu(&node->hash); |
398 | kfree(node->bc_entry.link); | 378 | tipc_node_put(node); |
399 | kfree_rcu(node, rcu); | 379 | |
380 | del_timer_sync(&node->timer); | ||
381 | tipc_node_put(node); | ||
400 | } | 382 | } |
401 | 383 | ||
402 | void tipc_node_stop(struct net *net) | 384 | void tipc_node_stop(struct net *net) |
403 | { | 385 | { |
404 | struct tipc_net *tn = net_generic(net, tipc_net_id); | 386 | struct tipc_net *tn = tipc_net(net); |
405 | struct tipc_node *node, *t_node; | 387 | struct tipc_node *node, *t_node; |
406 | 388 | ||
407 | spin_lock_bh(&tn->node_list_lock); | 389 | spin_lock_bh(&tn->node_list_lock); |
408 | list_for_each_entry_safe(node, t_node, &tn->node_list, list) { | 390 | list_for_each_entry_safe(node, t_node, &tn->node_list, list) |
409 | if (del_timer(&node->timer)) | 391 | tipc_node_delete(node); |
410 | tipc_node_put(node); | ||
411 | tipc_node_put(node); | ||
412 | } | ||
413 | spin_unlock_bh(&tn->node_list_lock); | 392 | spin_unlock_bh(&tn->node_list_lock); |
414 | } | 393 | } |
415 | 394 | ||
@@ -530,9 +509,7 @@ static void tipc_node_timeout(unsigned long data) | |||
530 | if (rc & TIPC_LINK_DOWN_EVT) | 509 | if (rc & TIPC_LINK_DOWN_EVT) |
531 | tipc_node_link_down(n, bearer_id, false); | 510 | tipc_node_link_down(n, bearer_id, false); |
532 | } | 511 | } |
533 | if (!mod_timer(&n->timer, jiffies + n->keepalive_intv)) | 512 | mod_timer(&n->timer, jiffies + n->keepalive_intv); |
534 | tipc_node_get(n); | ||
535 | tipc_node_put(n); | ||
536 | } | 513 | } |
537 | 514 | ||
538 | /** | 515 | /** |
@@ -845,7 +822,7 @@ void tipc_node_check_dest(struct net *net, u32 onode, | |||
845 | memcpy(&le->maddr, maddr, sizeof(*maddr)); | 822 | memcpy(&le->maddr, maddr, sizeof(*maddr)); |
846 | exit: | 823 | exit: |
847 | tipc_node_write_unlock(n); | 824 | tipc_node_write_unlock(n); |
848 | if (reset && !tipc_link_is_reset(l)) | 825 | if (reset && l && !tipc_link_is_reset(l)) |
849 | tipc_node_link_down(n, b->identity, false); | 826 | tipc_node_link_down(n, b->identity, false); |
850 | tipc_node_put(n); | 827 | tipc_node_put(n); |
851 | } | 828 | } |
@@ -1166,7 +1143,7 @@ msg_full: | |||
1166 | * @dnode: address of destination node | 1143 | * @dnode: address of destination node |
1167 | * @selector: a number used for deterministic link selection | 1144 | * @selector: a number used for deterministic link selection |
1168 | * Consumes the buffer chain, except when returning -ELINKCONG | 1145 | * Consumes the buffer chain, except when returning -ELINKCONG |
1169 | * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE | 1146 | * Returns 0 if success, otherwise: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE,-ENOBUF |
1170 | */ | 1147 | */ |
1171 | int tipc_node_xmit(struct net *net, struct sk_buff_head *list, | 1148 | int tipc_node_xmit(struct net *net, struct sk_buff_head *list, |
1172 | u32 dnode, int selector) | 1149 | u32 dnode, int selector) |
@@ -1174,33 +1151,43 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list, | |||
1174 | struct tipc_link_entry *le = NULL; | 1151 | struct tipc_link_entry *le = NULL; |
1175 | struct tipc_node *n; | 1152 | struct tipc_node *n; |
1176 | struct sk_buff_head xmitq; | 1153 | struct sk_buff_head xmitq; |
1177 | int bearer_id = -1; | 1154 | int bearer_id; |
1178 | int rc = -EHOSTUNREACH; | 1155 | int rc; |
1156 | |||
1157 | if (in_own_node(net, dnode)) { | ||
1158 | tipc_sk_rcv(net, list); | ||
1159 | return 0; | ||
1160 | } | ||
1179 | 1161 | ||
1180 | __skb_queue_head_init(&xmitq); | ||
1181 | n = tipc_node_find(net, dnode); | 1162 | n = tipc_node_find(net, dnode); |
1182 | if (likely(n)) { | 1163 | if (unlikely(!n)) { |
1183 | tipc_node_read_lock(n); | 1164 | skb_queue_purge(list); |
1184 | bearer_id = n->active_links[selector & 1]; | 1165 | return -EHOSTUNREACH; |
1185 | if (bearer_id >= 0) { | 1166 | } |
1186 | le = &n->links[bearer_id]; | 1167 | |
1187 | spin_lock_bh(&le->lock); | 1168 | tipc_node_read_lock(n); |
1188 | rc = tipc_link_xmit(le->link, list, &xmitq); | 1169 | bearer_id = n->active_links[selector & 1]; |
1189 | spin_unlock_bh(&le->lock); | 1170 | if (unlikely(bearer_id == INVALID_BEARER_ID)) { |
1190 | } | ||
1191 | tipc_node_read_unlock(n); | 1171 | tipc_node_read_unlock(n); |
1192 | if (likely(!rc)) | ||
1193 | tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr); | ||
1194 | else if (rc == -ENOBUFS) | ||
1195 | tipc_node_link_down(n, bearer_id, false); | ||
1196 | tipc_node_put(n); | 1172 | tipc_node_put(n); |
1197 | return rc; | 1173 | skb_queue_purge(list); |
1174 | return -EHOSTUNREACH; | ||
1198 | } | 1175 | } |
1199 | 1176 | ||
1200 | if (likely(in_own_node(net, dnode))) { | 1177 | __skb_queue_head_init(&xmitq); |
1201 | tipc_sk_rcv(net, list); | 1178 | le = &n->links[bearer_id]; |
1202 | return 0; | 1179 | spin_lock_bh(&le->lock); |
1203 | } | 1180 | rc = tipc_link_xmit(le->link, list, &xmitq); |
1181 | spin_unlock_bh(&le->lock); | ||
1182 | tipc_node_read_unlock(n); | ||
1183 | |||
1184 | if (likely(rc == 0)) | ||
1185 | tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr); | ||
1186 | else if (rc == -ENOBUFS) | ||
1187 | tipc_node_link_down(n, bearer_id, false); | ||
1188 | |||
1189 | tipc_node_put(n); | ||
1190 | |||
1204 | return rc; | 1191 | return rc; |
1205 | } | 1192 | } |
1206 | 1193 | ||
@@ -1457,6 +1444,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b) | |||
1457 | int bearer_id = b->identity; | 1444 | int bearer_id = b->identity; |
1458 | struct tipc_link_entry *le; | 1445 | struct tipc_link_entry *le; |
1459 | u16 bc_ack = msg_bcast_ack(hdr); | 1446 | u16 bc_ack = msg_bcast_ack(hdr); |
1447 | u32 self = tipc_own_addr(net); | ||
1460 | int rc = 0; | 1448 | int rc = 0; |
1461 | 1449 | ||
1462 | __skb_queue_head_init(&xmitq); | 1450 | __skb_queue_head_init(&xmitq); |
@@ -1473,6 +1461,10 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b) | |||
1473 | return tipc_node_bc_rcv(net, skb, bearer_id); | 1461 | return tipc_node_bc_rcv(net, skb, bearer_id); |
1474 | } | 1462 | } |
1475 | 1463 | ||
1464 | /* Discard unicast link messages destined for another node */ | ||
1465 | if (unlikely(!msg_short(hdr) && (msg_destnode(hdr) != self))) | ||
1466 | goto discard; | ||
1467 | |||
1476 | /* Locate neighboring node that sent packet */ | 1468 | /* Locate neighboring node that sent packet */ |
1477 | n = tipc_node_find(net, msg_prevnode(hdr)); | 1469 | n = tipc_node_find(net, msg_prevnode(hdr)); |
1478 | if (unlikely(!n)) | 1470 | if (unlikely(!n)) |
@@ -1637,9 +1629,12 @@ int tipc_nl_node_set_link(struct sk_buff *skb, struct genl_info *info) | |||
1637 | char *name; | 1629 | char *name; |
1638 | struct tipc_link *link; | 1630 | struct tipc_link *link; |
1639 | struct tipc_node *node; | 1631 | struct tipc_node *node; |
1632 | struct sk_buff_head xmitq; | ||
1640 | struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; | 1633 | struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; |
1641 | struct net *net = sock_net(skb->sk); | 1634 | struct net *net = sock_net(skb->sk); |
1642 | 1635 | ||
1636 | __skb_queue_head_init(&xmitq); | ||
1637 | |||
1643 | if (!info->attrs[TIPC_NLA_LINK]) | 1638 | if (!info->attrs[TIPC_NLA_LINK]) |
1644 | return -EINVAL; | 1639 | return -EINVAL; |
1645 | 1640 | ||
@@ -1683,13 +1678,13 @@ int tipc_nl_node_set_link(struct sk_buff *skb, struct genl_info *info) | |||
1683 | u32 tol; | 1678 | u32 tol; |
1684 | 1679 | ||
1685 | tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]); | 1680 | tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]); |
1686 | tipc_link_set_tolerance(link, tol); | 1681 | tipc_link_set_tolerance(link, tol, &xmitq); |
1687 | } | 1682 | } |
1688 | if (props[TIPC_NLA_PROP_PRIO]) { | 1683 | if (props[TIPC_NLA_PROP_PRIO]) { |
1689 | u32 prio; | 1684 | u32 prio; |
1690 | 1685 | ||
1691 | prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); | 1686 | prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); |
1692 | tipc_link_set_prio(link, prio); | 1687 | tipc_link_set_prio(link, prio, &xmitq); |
1693 | } | 1688 | } |
1694 | if (props[TIPC_NLA_PROP_WIN]) { | 1689 | if (props[TIPC_NLA_PROP_WIN]) { |
1695 | u32 win; | 1690 | u32 win; |
@@ -1701,7 +1696,7 @@ int tipc_nl_node_set_link(struct sk_buff *skb, struct genl_info *info) | |||
1701 | 1696 | ||
1702 | out: | 1697 | out: |
1703 | tipc_node_read_unlock(node); | 1698 | tipc_node_read_unlock(node); |
1704 | 1699 | tipc_bearer_xmit(net, bearer_id, &xmitq, &node->links[bearer_id].maddr); | |
1705 | return res; | 1700 | return res; |
1706 | } | 1701 | } |
1707 | 1702 | ||