On 03/31/2016 08:06 AM, Jon Maloy wrote: > 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. > > Signed-off-by: Jon Maloy <jon.ma...@ericsson.com> > --- > net/tipc/bearer.c | 38 ++++++++++++++++++++++++++++++-------- > net/tipc/msg.h | 5 +++++ > 2 files changed, 35 insertions(+), 8 deletions(-) > > diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c > index 20566e9..f5c6b80 100644 > --- a/net/tipc/bearer.c > +++ b/net/tipc/bearer.c > @@ -342,8 +342,6 @@ static void bearer_disable(struct net *net, struct > tipc_bearer *b) > > pr_info("Disabling bearer <%s>\n", b->name); > b->media->disable_media(b); > - > - tipc_node_delete_links(net, b->identity);
I cannot understand why we postpone the action of deleting links until tn->bearer_list[] is set to NULL. > RCU_INIT_POINTER(b->media_ptr, NULL); > if (b->link_req) > tipc_disc_delete(b->link_req); > @@ -354,6 +352,7 @@ static void bearer_disable(struct net *net, struct > tipc_bearer *b) > break; > } > } > + tipc_node_delete_links(net, b->identity); > kfree_rcu(b, rcu); > } > > @@ -396,7 +395,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b) > > /** > * tipc_l2_send_msg - send a TIPC packet out over an L2 interface > - * @buf: the packet to be sent > + * @skb: the packet to be sent > * @b: the bearer through which the packet is to be sent > * @dest: peer destination address > */ > @@ -405,17 +404,21 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff > *skb, > { > struct net_device *dev; > int delta; > + void *tipc_ptr; > > dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr); > if (!dev) > return 0; > > + /* Send RESET message even if bearer is detached from device */ > + tipc_ptr = rtnl_dereference(dev->tipc_ptr); > + if (unlikely(!tipc_ptr && !msg_is_reset(buf_msg(skb)))) > + goto drop; > + > delta = dev->hard_header_len - skb_headroom(skb); > if ((delta > 0) && > - pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { > - kfree_skb(skb); > - return 0; > - } > + pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) > + goto drop; > > skb_reset_network_header(skb); > skb->dev = dev; > @@ -424,6 +427,9 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb, > dev->dev_addr, skb->len); > dev_queue_xmit(skb); > return 0; > +drop: > + kfree_skb(skb); > + return 0; > } > > int tipc_bearer_mtu(struct net *net, u32 bearer_id) > @@ -549,9 +555,18 @@ static int tipc_l2_device_event(struct notifier_block > *nb, unsigned long evt, > { > struct net_device *dev = netdev_notifier_info_to_dev(ptr); > struct net *net = dev_net(dev); > + struct tipc_net *tn = tipc_net(net); > struct tipc_bearer *b; > + int i; > > b = rtnl_dereference(dev->tipc_ptr); > + if (!b) { > + for (i = 0; i < MAX_BEARERS; b = NULL, i++) { > + b = rtnl_dereference(tn->bearer_list[i]); > + if (b && (b->media_ptr == dev)) > + break; > + } > + } > if (!b) > return NOTIFY_DONE; > > @@ -561,13 +576,20 @@ static int tipc_l2_device_event(struct notifier_block > *nb, unsigned long evt, > case NETDEV_CHANGE: > if (netif_carrier_ok(dev)) > break; > + case NETDEV_UP: > + rcu_assign_pointer(dev->tipc_ptr, b); > + break; > case NETDEV_GOING_DOWN: > + RCU_INIT_POINTER(dev->tipc_ptr, NULL); > + synchronize_net(); Why do we place synchronize_net() before tipc_reset_bearer()? In my opinion, it seems better to exchange their orders between synchronize_net() and tipc_reset_bearer(). Regards, Ying > + tipc_reset_bearer(net, b); > + break; > case NETDEV_CHANGEMTU: > tipc_reset_bearer(net, b); > break; > case NETDEV_CHANGEADDR: > b->media->raw2addr(b, &b->addr, > - (char *)dev->dev_addr); > + (char *)dev->dev_addr); > tipc_reset_bearer(net, b); > break; > case NETDEV_UNREGISTER: > diff --git a/net/tipc/msg.h b/net/tipc/msg.h > index 55778a0..f34f639 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) > return msg_redundant_link(m); > } > > +static inline bool msg_is_reset(struct tipc_msg *hdr) > +{ > + return (msg_user(hdr) == LINK_PROTOCOL) && (msg_type(hdr) == RESET_MSG); > +} > + > struct sk_buff *tipc_buf_acquire(u32 size); > bool tipc_msg_validate(struct sk_buff *skb); > bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err); > ------------------------------------------------------------------------------ Transform Data into Opportunity. Accelerate data analysis in your applications with Intel Data Analytics Acceleration Library. Click to learn more. http://pubads.g.doubleclick.net/gampad/clk?id=278785471&iu=/4140 _______________________________________________ tipc-discussion mailing list tipc-discussion@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tipc-discussion