[ovs-dev] [PATCH 3/3] lisp: avoid using stale lisp socket.
Pravin B Shelar
pshelar at ovn.org
Sun Oct 30 04:33:06 UTC 2016
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 <pshelar at 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
More information about the dev
mailing list