datapath: stt: Fix device list management.
[cascardo/ovs.git] / datapath / linux / compat / stt.c
index 8e00112..85ddbe7 100644 (file)
@@ -62,6 +62,7 @@ struct stt_dev {
        struct net_device       *dev;
        struct net              *net;
        struct list_head        next;
+       struct list_head        up_next;
        struct socket           *sock;
        __be16                  dst_port;
 };
@@ -150,6 +151,7 @@ struct frag_skb_cb {
 /* per-network namespace private data for this module */
 struct stt_net {
        struct list_head stt_list;
+       struct list_head stt_up_list;   /* Devices which are in IFF_UP state. */
        int n_tunnels;
 };
 
@@ -167,12 +169,12 @@ static DEFINE_PER_CPU(u32, pkt_seq_counter);
 static void clean_percpu(struct work_struct *work);
 static DECLARE_DELAYED_WORK(clean_percpu_wq, clean_percpu);
 
-static struct stt_dev *stt_find_sock(struct net *net, __be16 port)
+static struct stt_dev *stt_find_up_dev(struct net *net, __be16 port)
 {
        struct stt_net *sn = net_generic(net, stt_net_id);
        struct stt_dev *stt_dev;
 
-       list_for_each_entry_rcu(stt_dev, &sn->stt_list, next) {
+       list_for_each_entry_rcu(stt_dev, &sn->stt_up_list, up_next) {
                if (stt_dev->dst_port == port)
                        return stt_dev;
        }
@@ -1481,7 +1483,7 @@ static unsigned int nf_ip_hook(FIRST_PARAM, struct sk_buff *skb, LAST_PARAM)
 
        skb_set_transport_header(skb, ip_hdr_len);
 
-       stt_dev = stt_find_sock(dev_net(skb->dev), tcp_hdr(skb)->dest);
+       stt_dev = stt_find_up_dev(dev_net(skb->dev), tcp_hdr(skb)->dest);
        if (!stt_dev)
                return NF_ACCEPT;
 
@@ -1646,6 +1648,7 @@ static int stt_open(struct net_device *dev)
 {
        struct stt_dev *stt = netdev_priv(dev);
        struct net *net = stt->net;
+       struct stt_net *sn = net_generic(net, stt_net_id);
        int err;
 
        err = stt_start(net);
@@ -1655,6 +1658,7 @@ static int stt_open(struct net_device *dev)
        err = tcp_sock_create4(net, stt->dst_port, &stt->sock);
        if (err)
                return err;
+       list_add_rcu(&stt->up_next, &sn->stt_up_list);
        return 0;
 }
 
@@ -1663,6 +1667,7 @@ static int stt_stop(struct net_device *dev)
        struct stt_dev *stt_dev = netdev_priv(dev);
        struct net *net = stt_dev->net;
 
+       list_del_rcu(&stt_dev->up_next);
        tcp_sock_release(stt_dev->sock);
        stt_dev->sock = NULL;
        stt_cleanup(net);
@@ -1772,7 +1777,7 @@ static int stt_configure(struct net *net, struct net_device *dev,
        if (err)
                return err;
 
-       list_add_rcu(&stt->next, &sn->stt_list);
+       list_add(&stt->next, &sn->stt_list);
        return 0;
 }
 
@@ -1791,7 +1796,7 @@ static void stt_dellink(struct net_device *dev, struct list_head *head)
 {
        struct stt_dev *stt = netdev_priv(dev);
 
-       list_del_rcu(&stt->next);
+       list_del(&stt->next);
        unregister_netdevice_queue(dev, head);
 }
 
@@ -1853,6 +1858,7 @@ static int stt_init_net(struct net *net)
        struct stt_net *sn = net_generic(net, stt_net_id);
 
        INIT_LIST_HEAD(&sn->stt_list);
+       INIT_LIST_HEAD(&sn->stt_up_list);
        return 0;
 }