datapath: stt: Fix device list management.
authorPravin B Shelar <pshelar@nicira.com>
Mon, 21 Dec 2015 01:05:24 +0000 (17:05 -0800)
committerPravin B Shelar <pshelar@nicira.com>
Mon, 21 Dec 2015 22:59:04 +0000 (14:59 -0800)
STT receive can accept packet on device which is not UP state.
Following patch fixes this issue by introducing another list
of devices which contains only devices in up state. This list can
be used for searching stt devices on packet receive.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Jesse Gross <jesse@kernel.org>
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;
 }