aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2016-04-07 10:09:14 -0400
committerDavid S. Miller <davem@davemloft.net>2016-04-07 17:00:13 -0400
commit5b7066c3dd24c7d538e5ee402eb24bb182c16dab (patch)
tree4c48098cd2b13be2819e1e6a4918b4dced748ab1 /net/tipc
parent4e801fa14f68223d36480bced975ebf0c5f9a284 (diff)
tipc: stricter filtering of packets in bearer layer
Resetting a bearer/interface, with the consequence of resetting all its pertaining links, is not an atomic action. This becomes particularly evident in very large clusters, where a lot of traffic may happen on the remaining links while we are busy shutting them down. In extreme cases, we may even see links being re-created and re-established before we are finished with the job. To solve this, we now introduce a solution where we temporarily detach the bearer from the interface when the bearer is reset. This inhibits all packet reception, while sending still is possible. For the latter, we use the fact that the device's user pointer now is zero to filter out which packets can be sent during this situation; i.e., outgoing RESET messages only. This filtering serves to speed up the neighbors' detection of the loss event, and saves us from unnecessary probing. Acked-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>
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/bearer.c50
-rw-r--r--net/tipc/msg.h5
2 files changed, 38 insertions, 17 deletions
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 20566e9a1369..6f11c62bc8f9 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -337,23 +337,16 @@ static int tipc_reset_bearer(struct net *net, struct tipc_bearer *b)
337 */ 337 */
338static void bearer_disable(struct net *net, struct tipc_bearer *b) 338static void bearer_disable(struct net *net, struct tipc_bearer *b)
339{ 339{
340 struct tipc_net *tn = net_generic(net, tipc_net_id); 340 struct tipc_net *tn = tipc_net(net);
341 u32 i; 341 int bearer_id = b->identity;
342 342
343 pr_info("Disabling bearer <%s>\n", b->name); 343 pr_info("Disabling bearer <%s>\n", b->name);
344 b->media->disable_media(b); 344 b->media->disable_media(b);
345 345 tipc_node_delete_links(net, bearer_id);
346 tipc_node_delete_links(net, b->identity);
347 RCU_INIT_POINTER(b->media_ptr, NULL); 346 RCU_INIT_POINTER(b->media_ptr, NULL);
348 if (b->link_req) 347 if (b->link_req)
349 tipc_disc_delete(b->link_req); 348 tipc_disc_delete(b->link_req);
350 349 RCU_INIT_POINTER(tn->bearer_list[bearer_id], NULL);
351 for (i = 0; i < MAX_BEARERS; i++) {
352 if (b == rtnl_dereference(tn->bearer_list[i])) {
353 RCU_INIT_POINTER(tn->bearer_list[i], NULL);
354 break;
355 }
356 }
357 kfree_rcu(b, rcu); 350 kfree_rcu(b, rcu);
358} 351}
359 352
@@ -396,7 +389,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b)
396 389
397/** 390/**
398 * tipc_l2_send_msg - send a TIPC packet out over an L2 interface 391 * tipc_l2_send_msg - send a TIPC packet out over an L2 interface
399 * @buf: the packet to be sent 392 * @skb: the packet to be sent
400 * @b: the bearer through which the packet is to be sent 393 * @b: the bearer through which the packet is to be sent
401 * @dest: peer destination address 394 * @dest: peer destination address
402 */ 395 */
@@ -405,17 +398,21 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
405{ 398{
406 struct net_device *dev; 399 struct net_device *dev;
407 int delta; 400 int delta;
401 void *tipc_ptr;
408 402
409 dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr); 403 dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
410 if (!dev) 404 if (!dev)
411 return 0; 405 return 0;
412 406
407 /* Send RESET message even if bearer is detached from device */
408 tipc_ptr = rtnl_dereference(dev->tipc_ptr);
409 if (unlikely(!tipc_ptr && !msg_is_reset(buf_msg(skb))))
410 goto drop;
411
413 delta = dev->hard_header_len - skb_headroom(skb); 412 delta = dev->hard_header_len - skb_headroom(skb);
414 if ((delta > 0) && 413 if ((delta > 0) &&
415 pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { 414 pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC))
416 kfree_skb(skb); 415 goto drop;
417 return 0;
418 }
419 416
420 skb_reset_network_header(skb); 417 skb_reset_network_header(skb);
421 skb->dev = dev; 418 skb->dev = dev;
@@ -424,6 +421,9 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
424 dev->dev_addr, skb->len); 421 dev->dev_addr, skb->len);
425 dev_queue_xmit(skb); 422 dev_queue_xmit(skb);
426 return 0; 423 return 0;
424drop:
425 kfree_skb(skb);
426 return 0;
427} 427}
428 428
429int tipc_bearer_mtu(struct net *net, u32 bearer_id) 429int tipc_bearer_mtu(struct net *net, u32 bearer_id)
@@ -549,9 +549,18 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
549{ 549{
550 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 550 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
551 struct net *net = dev_net(dev); 551 struct net *net = dev_net(dev);
552 struct tipc_net *tn = tipc_net(net);
552 struct tipc_bearer *b; 553 struct tipc_bearer *b;
554 int i;
553 555
554 b = rtnl_dereference(dev->tipc_ptr); 556 b = rtnl_dereference(dev->tipc_ptr);
557 if (!b) {
558 for (i = 0; i < MAX_BEARERS; b = NULL, i++) {
559 b = rtnl_dereference(tn->bearer_list[i]);
560 if (b && (b->media_ptr == dev))
561 break;
562 }
563 }
555 if (!b) 564 if (!b)
556 return NOTIFY_DONE; 565 return NOTIFY_DONE;
557 566
@@ -561,13 +570,20 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
561 case NETDEV_CHANGE: 570 case NETDEV_CHANGE:
562 if (netif_carrier_ok(dev)) 571 if (netif_carrier_ok(dev))
563 break; 572 break;
573 case NETDEV_UP:
574 rcu_assign_pointer(dev->tipc_ptr, b);
575 break;
564 case NETDEV_GOING_DOWN: 576 case NETDEV_GOING_DOWN:
577 RCU_INIT_POINTER(dev->tipc_ptr, NULL);
578 synchronize_net();
579 tipc_reset_bearer(net, b);
580 break;
565 case NETDEV_CHANGEMTU: 581 case NETDEV_CHANGEMTU:
566 tipc_reset_bearer(net, b); 582 tipc_reset_bearer(net, b);
567 break; 583 break;
568 case NETDEV_CHANGEADDR: 584 case NETDEV_CHANGEADDR:
569 b->media->raw2addr(b, &b->addr, 585 b->media->raw2addr(b, &b->addr,
570 (char *)dev->dev_addr); 586 (char *)dev->dev_addr);
571 tipc_reset_bearer(net, b); 587 tipc_reset_bearer(net, b);
572 break; 588 break;
573 case NETDEV_UNREGISTER: 589 case NETDEV_UNREGISTER:
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index 55778a0aebf3..f34f639df643 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -779,6 +779,11 @@ static inline bool msg_peer_node_is_up(struct tipc_msg *m)
779 return msg_redundant_link(m); 779 return msg_redundant_link(m);
780} 780}
781 781
782static inline bool msg_is_reset(struct tipc_msg *hdr)
783{
784 return (msg_user(hdr) == LINK_PROTOCOL) && (msg_type(hdr) == RESET_MSG);
785}
786
782struct sk_buff *tipc_buf_acquire(u32 size); 787struct sk_buff *tipc_buf_acquire(u32 size);
783bool tipc_msg_validate(struct sk_buff *skb); 788bool tipc_msg_validate(struct sk_buff *skb);
784bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err); 789bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err);