This patch is similar to earlier vxlan patch. Lisp device close operation frees lisp socket. This operation can race with lisp-xmit function which dereferences lisp socket. Following patch uses RCU mechanism to avoid this situation.
Signed-off-by: Pravin B Shelar <pshe...@ovn.org> --- datapath/linux/compat/lisp.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/datapath/linux/compat/lisp.c b/datapath/linux/compat/lisp.c index 3a4bebc..193196c 100644 --- a/datapath/linux/compat/lisp.c +++ b/datapath/linux/compat/lisp.c @@ -49,7 +49,7 @@ static int lisp_net_id; struct lisp_dev { struct net *net; /* netns for packet i/o */ struct net_device *dev; /* netdev for lisp tunnel */ - struct socket *sock; + struct socket __rcu *sock; __be16 dst_port; struct list_head next; }; @@ -318,9 +318,10 @@ netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb) int network_offset = skb_network_offset(skb); struct ip_tunnel_info *info; struct ip_tunnel_key *tun_key; + __be16 src_port, dst_port; struct rtable *rt; int min_headroom; - __be16 src_port, dst_port; + struct socket *sock; struct flowi4 fl; __be16 df; int err; @@ -331,6 +332,12 @@ netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb) goto error; } + sock = rcu_dereference(lisp_dev->sock); + if (!sock) { + err = -EIO; + goto error; + } + if (skb->protocol != htons(ETH_P_IP) && skb->protocol != htons(ETH_P_IPV6)) { err = 0; @@ -381,7 +388,7 @@ netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb) ovs_skb_set_inner_protocol(skb, skb->protocol); df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; - udp_tunnel_xmit_skb(rt, lisp_dev->sock->sk, skb, + udp_tunnel_xmit_skb(rt, sock->sk, skb, fl.saddr, tun_key->u.ipv4.dst, tun_key->tos, tun_key->ttl, df, src_port, dst_port, false, true); @@ -442,11 +449,13 @@ static int lisp_open(struct net_device *dev) struct lisp_dev *lisp = netdev_priv(dev); struct udp_tunnel_sock_cfg tunnel_cfg; struct net *net = lisp->net; + struct socket *sock; - lisp->sock = create_sock(net, false, lisp->dst_port); - if (IS_ERR(lisp->sock)) - return PTR_ERR(lisp->sock); + sock = create_sock(net, false, lisp->dst_port); + if (IS_ERR(sock)) + return PTR_ERR(sock); + rcu_assign_pointer(lisp->sock, sock); /* Mark socket as an encapsulation socket */ tunnel_cfg.sk_user_data = dev; tunnel_cfg.encap_type = 1; @@ -459,9 +468,16 @@ static int lisp_open(struct net_device *dev) static int lisp_stop(struct net_device *dev) { struct lisp_dev *lisp = netdev_priv(dev); + struct socket *socket; + + socket = rtnl_dereference(lisp->sock); + if (!socket) + return 0; + + rcu_assign_pointer(lisp->sock, NULL); - udp_tunnel_sock_release(lisp->sock); - lisp->sock = NULL; + synchronize_net(); + udp_tunnel_sock_release(socket); return 0; } -- 1.8.3.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev