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

Reply via email to