On 07/08/2016 07:17 AM, Xue, Ying wrote: > > -----Original Message----- > From: Jon Maloy [mailto:jon.ma...@ericsson.com] > Sent: Friday, July 08, 2016 4:21 AM > To: tipc-discussion@lists.sourceforge.net; > parthasarathy.bhuvara...@ericsson.com; Xue, Ying; richard.a...@ericsson.com; > jon.ma...@ericsson.com > Cc: ma...@donjonn.com > Subject: [PATCH net-next v2 1/2] tipc: make bearer packet filtering generic > > In commit 5b7066c3dd24 ("tipc: stricter filtering of packets in bearer > layer") we introduced a method of filtering out messages while a bearer is > being reset, to avoid that links may be re-created and come back in working > state while we are still in the process of shutting them down. > > This solution works well, but is limited to only work with L2 media, which is > insufficient with the increasing use of UDP as carrier media. > > We now replace this solution with a more generic one, by introducing a new > boolean field "blocked" in the generic struct tipc_bearer. This field will be > set and reset at the same locations as with the previous solution, while the > packet filtering is moved to the generic code for the sending side. On the > receiving side, the filtering is still done in media specific code, but now > including the UDP bearer. > > Signed-off-by: Jon Maloy <jon.ma...@ericsson.com> > --- > net/tipc/bearer.c | 77 > ++++++++++++++++++++++++++-------------------------- > net/tipc/bearer.h | 1 + > net/tipc/udp_media.c | 2 +- > 3 files changed, 41 insertions(+), 39 deletions(-) > > diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index e7244d6..6d4c2b3 > 100644 > --- a/net/tipc/bearer.c > +++ b/net/tipc/bearer.c > @@ -56,6 +56,13 @@ static struct tipc_media * const media_info_array[] = { > NULL > }; > > +static struct tipc_bearer *bearer_get(struct net *net, int bearer_id) { > + struct tipc_net *tn = tipc_net(net); > + > + return rcu_dereference_rtnl(tn->bearer_list[bearer_id]); > +} > + > static void bearer_disable(struct net *net, struct tipc_bearer *b); > > /** > @@ -302,6 +309,7 @@ restart: > b->domain = disc_domain; > b->net_plane = bearer_id + 'A'; > b->priority = priority; > + b->up = true; > > res = tipc_disc_create(net, b, &b->bcast_addr, &skb); > if (res) { > @@ -339,16 +347,25 @@ static int tipc_reset_bearer(struct net *net, struct > tipc_bearer *b) > */ > void tipc_bearer_reset_all(struct net *net) { > - struct tipc_net *tn = tipc_net(net); > struct tipc_bearer *b; > int i; > > rcu_read_lock(); > for (i = 0; i < MAX_BEARERS; i++) { > - b = rcu_dereference_rtnl(tn->bearer_list[i]); > + b = bearer_get(net, i); > + if (b) > + b->up = false; > + } > + for (i = 0; i < MAX_BEARERS; i++) { > + b = bearer_get(net, i); > if (b) > tipc_reset_bearer(net, b); > } > + for (i = 0; i < MAX_BEARERS; i++) { > + b = bearer_get(net, i); > + if (b) > + b->up = true; > + } > > If we are under rcu_read lock, it means that we are staying on read side. > Regarding RCU locking semantic, we cannot modify RCU variable on read side. If we stick strictly to the letter, you are right. But what would be the consequences? As I see it, it would be no different than if we change a value in the read side of a wr-lock: some contexts will see the wrong value for a while, and eventually, when the cache is updated, they will all get the correct value. The consequences of obtaining a stale value in this particular case are minimal: there will be no crash or malfunction, only some contexts will let through packets that they shouldn't, and vice versa, and only for a short period of time. Anyway, we would be much better off than we are now, when this happens on a permanent base.
///jon > As you know, bearer instance is projected by RTNL lock. If we want to change > it, we must hold it on write side. However, as we must reset links on > reception path, it means that it's inappropriate to hold RTNL on the context. > I cannot figure more better approach except that we perform this in another > process context asynchronously like workqueue. But this is really not what we > want to do. > > Regards, > Ying > > rcu_read_unlock(); > } > > @@ -363,8 +380,9 @@ static void bearer_disable(struct net *net, struct > tipc_bearer *b) > int bearer_id = b->identity; > > pr_info("Disabling bearer <%s>\n", b->name); > - b->media->disable_media(b); > + b->up = false; > tipc_node_delete_links(net, bearer_id); > + b->media->disable_media(b); > RCU_INIT_POINTER(b->media_ptr, NULL); > if (b->link_req) > tipc_disc_delete(b->link_req); > @@ -421,22 +439,16 @@ 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 = rcu_dereference_rtnl(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)) > - goto drop; > - > + delta = SKB_DATA_ALIGN(dev->hard_header_len - skb_headroom(skb)); > + if ((delta > 0) && pskb_expand_head(skb, delta, 0, GFP_ATOMIC)) { > + kfree_skb(skb); > + return 0; > + } > skb_reset_network_header(skb); > skb->dev = dev; > skb->protocol = htons(ETH_P_TIPC); > @@ -444,9 +456,6 @@ 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) @@ -468,12 +477,12 @@ > void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id, > struct sk_buff *skb, > struct tipc_media_addr *dest) > { > - struct tipc_net *tn = tipc_net(net); > + struct tipc_msg *hdr = buf_msg(skb); > struct tipc_bearer *b; > > rcu_read_lock(); > - b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); > - if (likely(b)) > + b = bearer_get(net, bearer_id); > + if (likely(b && (b->up || msg_is_reset(hdr)))) > b->media->send_msg(net, skb, b, dest); > else > kfree_skb(skb); > @@ -486,7 +495,6 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id, > struct sk_buff_head *xmitq, > struct tipc_media_addr *dst) > { > - struct tipc_net *tn = net_generic(net, tipc_net_id); > struct tipc_bearer *b; > struct sk_buff *skb, *tmp; > > @@ -494,12 +502,15 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id, > return; > > rcu_read_lock(); > - b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); > + b = bearer_get(net, bearer_id); > if (unlikely(!b)) > __skb_queue_purge(xmitq); > skb_queue_walk_safe(xmitq, skb, tmp) { > __skb_dequeue(xmitq); > - b->media->send_msg(net, skb, b, dst); > + if (likely(b->up || msg_is_reset(buf_msg(skb)))) > + b->media->send_msg(net, skb, b, dst); > + else > + kfree(skb); > } > rcu_read_unlock(); > } > @@ -516,8 +527,8 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id, > struct tipc_msg *hdr; > > rcu_read_lock(); > - b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); > - if (unlikely(!b)) > + b = bearer_get(net, bearer_id); > + if (unlikely(!b || !b->up)) > __skb_queue_purge(xmitq); > skb_queue_walk_safe(xmitq, skb, tmp) { > hdr = buf_msg(skb); > @@ -547,7 +558,7 @@ static int tipc_l2_rcv_msg(struct sk_buff *skb, struct > net_device *dev, > > rcu_read_lock(); > b = rcu_dereference_rtnl(dev->tipc_ptr); > - if (likely(b && (skb->pkt_type <= PACKET_BROADCAST))) { > + if (likely(b && b->up && (skb->pkt_type <= PACKET_BROADCAST))) { > skb->next = NULL; > tipc_rcv(dev_net(dev), skb, b); > rcu_read_unlock(); > @@ -572,18 +583,9 @@ 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; > > @@ -594,11 +596,10 @@ static int tipc_l2_device_event(struct notifier_block > *nb, unsigned long evt, > if (netif_carrier_ok(dev)) > break; > case NETDEV_UP: > - rcu_assign_pointer(dev->tipc_ptr, b); > + b->up = true; > break; > case NETDEV_GOING_DOWN: > - RCU_INIT_POINTER(dev->tipc_ptr, NULL); > - synchronize_net(); > + b->up = false; > tipc_reset_bearer(net, b); > break; > case NETDEV_CHANGEMTU: > diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index f1e6db5..6f51ed8 > 100644 > --- a/net/tipc/bearer.h > +++ b/net/tipc/bearer.h > @@ -150,6 +150,7 @@ struct tipc_bearer { > u32 identity; > struct tipc_link_req *link_req; > char net_plane; > + bool up; > }; > > struct tipc_bearer_names { > diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index > b016c01..c7f52bf 100644 > --- a/net/tipc/udp_media.c > +++ b/net/tipc/udp_media.c > @@ -224,7 +224,7 @@ static int tipc_udp_recv(struct sock *sk, struct sk_buff > *skb) > rcu_read_lock(); > b = rcu_dereference_rtnl(ub->bearer); > > - if (b) { > + if (b && b->up) { > tipc_rcv(sock_net(sk), skb, b); > rcu_read_unlock(); > return 0; > -- > 1.9.1 > ------------------------------------------------------------------------------ Attend Shape: An AT&T Tech Expo July 15-16. Meet us at AT&T Park in San Francisco, CA to explore cutting-edge tech and listen to tech luminaries present their vision of the future. This family event has something for everyone, including kids. Get more information and register today. http://sdm.link/attshape _______________________________________________ tipc-discussion mailing list tipc-discussion@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tipc-discussion