netfilter: replace list_head with single linked list
[cascardo/linux.git] / include / linux / netfilter_ingress.h
index 6965ba0..33e37fb 100644 (file)
@@ -11,23 +11,30 @@ static inline bool nf_hook_ingress_active(const struct sk_buff *skb)
        if (!static_key_false(&nf_hooks_needed[NFPROTO_NETDEV][NF_NETDEV_INGRESS]))
                return false;
 #endif
-       return !list_empty(&skb->dev->nf_hooks_ingress);
+       return rcu_access_pointer(skb->dev->nf_hooks_ingress);
 }
 
 /* caller must hold rcu_read_lock */
 static inline int nf_hook_ingress(struct sk_buff *skb)
 {
+       struct nf_hook_entry *e = rcu_dereference(skb->dev->nf_hooks_ingress);
        struct nf_hook_state state;
 
-       nf_hook_state_init(&state, &skb->dev->nf_hooks_ingress,
-                          NF_NETDEV_INGRESS, INT_MIN, NFPROTO_NETDEV,
-                          skb->dev, NULL, NULL, dev_net(skb->dev), NULL);
+       /* Must recheck the ingress hook head, in the event it became NULL
+        * after the check in nf_hook_ingress_active evaluated to true.
+        */
+       if (unlikely(!e))
+               return 0;
+
+       nf_hook_state_init(&state, e, NF_NETDEV_INGRESS, INT_MIN,
+                          NFPROTO_NETDEV, skb->dev, NULL, NULL,
+                          dev_net(skb->dev), NULL);
        return nf_hook_slow(skb, &state);
 }
 
 static inline void nf_hook_ingress_init(struct net_device *dev)
 {
-       INIT_LIST_HEAD(&dev->nf_hooks_ingress);
+       RCU_INIT_POINTER(dev->nf_hooks_ingress, NULL);
 }
 #else /* CONFIG_NETFILTER_INGRESS */
 static inline int nf_hook_ingress_active(struct sk_buff *skb)