Skip to content

Commit 5b7066c

Browse files
Jon Paul Maloydavem330
Jon Paul Maloy
authored andcommitted
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 <[email protected]> Signed-off-by: Jon Maloy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4e801fa commit 5b7066c

File tree

2 files changed

+38
-17
lines changed

2 files changed

+38
-17
lines changed

net/tipc/bearer.c

+33-17
Original file line numberDiff line numberDiff line change
@@ -337,23 +337,16 @@ static int tipc_reset_bearer(struct net *net, struct tipc_bearer *b)
337337
*/
338338
static void bearer_disable(struct net *net, struct tipc_bearer *b)
339339
{
340-
struct tipc_net *tn = net_generic(net, tipc_net_id);
341-
u32 i;
340+
struct tipc_net *tn = tipc_net(net);
341+
int bearer_id = b->identity;
342342

343343
pr_info("Disabling bearer <%s>\n", b->name);
344344
b->media->disable_media(b);
345-
346-
tipc_node_delete_links(net, b->identity);
345+
tipc_node_delete_links(net, bearer_id);
347346
RCU_INIT_POINTER(b->media_ptr, NULL);
348347
if (b->link_req)
349348
tipc_disc_delete(b->link_req);
350-
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-
}
349+
RCU_INIT_POINTER(tn->bearer_list[bearer_id], NULL);
357350
kfree_rcu(b, rcu);
358351
}
359352

@@ -396,7 +389,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b)
396389

397390
/**
398391
* 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
400393
* @b: the bearer through which the packet is to be sent
401394
* @dest: peer destination address
402395
*/
@@ -405,17 +398,21 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
405398
{
406399
struct net_device *dev;
407400
int delta;
401+
void *tipc_ptr;
408402

409403
dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
410404
if (!dev)
411405
return 0;
412406

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+
413412
delta = dev->hard_header_len - skb_headroom(skb);
414413
if ((delta > 0) &&
415-
pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
416-
kfree_skb(skb);
417-
return 0;
418-
}
414+
pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC))
415+
goto drop;
419416

420417
skb_reset_network_header(skb);
421418
skb->dev = dev;
@@ -424,6 +421,9 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
424421
dev->dev_addr, skb->len);
425422
dev_queue_xmit(skb);
426423
return 0;
424+
drop:
425+
kfree_skb(skb);
426+
return 0;
427427
}
428428

429429
int 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,
549549
{
550550
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
551551
struct net *net = dev_net(dev);
552+
struct tipc_net *tn = tipc_net(net);
552553
struct tipc_bearer *b;
554+
int i;
553555

554556
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+
}
555564
if (!b)
556565
return NOTIFY_DONE;
557566

@@ -561,13 +570,20 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
561570
case NETDEV_CHANGE:
562571
if (netif_carrier_ok(dev))
563572
break;
573+
case NETDEV_UP:
574+
rcu_assign_pointer(dev->tipc_ptr, b);
575+
break;
564576
case NETDEV_GOING_DOWN:
577+
RCU_INIT_POINTER(dev->tipc_ptr, NULL);
578+
synchronize_net();
579+
tipc_reset_bearer(net, b);
580+
break;
565581
case NETDEV_CHANGEMTU:
566582
tipc_reset_bearer(net, b);
567583
break;
568584
case NETDEV_CHANGEADDR:
569585
b->media->raw2addr(b, &b->addr,
570-
(char *)dev->dev_addr);
586+
(char *)dev->dev_addr);
571587
tipc_reset_bearer(net, b);
572588
break;
573589
case NETDEV_UNREGISTER:

net/tipc/msg.h

+5
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,11 @@ static inline bool msg_peer_node_is_up(struct tipc_msg *m)
779779
return msg_redundant_link(m);
780780
}
781781

782+
static inline bool msg_is_reset(struct tipc_msg *hdr)
783+
{
784+
return (msg_user(hdr) == LINK_PROTOCOL) && (msg_type(hdr) == RESET_MSG);
785+
}
786+
782787
struct sk_buff *tipc_buf_acquire(u32 size);
783788
bool tipc_msg_validate(struct sk_buff *skb);
784789
bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err);

0 commit comments

Comments
 (0)