netfilter: remove hook_entries field from nf_hook_state
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 3 Nov 2016 09:56:35 +0000 (10:56 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 3 Nov 2016 10:52:58 +0000 (11:52 +0100)
This field is only useful for nf_queue, so store it in the
nf_queue_entry structure instead, away from the core path. Pass
hook_head to nf_hook_slow().

Since we always have a valid entry on the first iteration in
nf_iterate(), we can use 'do { ... } while (entry)' loop instead.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/linux/netfilter.h
include/linux/netfilter_ingress.h
include/net/netfilter/nf_queue.h
net/bridge/br_netfilter_hooks.c
net/bridge/netfilter/ebtable_broute.c
net/netfilter/core.c
net/netfilter/nf_queue.c
net/netfilter/nfnetlink_queue.c

index e0d000f6c9bff3baf11f98f23bb16e96f8e6b604..69230140215b6f84a1fc3276bd7d2d7c155eecc8 100644 (file)
@@ -54,7 +54,6 @@ struct nf_hook_state {
        struct net_device *out;
        struct sock *sk;
        struct net *net;
-       struct nf_hook_entry __rcu *hook_entries;
        int (*okfn)(struct net *, struct sock *, struct sk_buff *);
 };
 
@@ -81,7 +80,6 @@ struct nf_hook_entry {
 };
 
 static inline void nf_hook_state_init(struct nf_hook_state *p,
-                                     struct nf_hook_entry *hook_entry,
                                      unsigned int hook,
                                      u_int8_t pf,
                                      struct net_device *indev,
@@ -96,7 +94,6 @@ static inline void nf_hook_state_init(struct nf_hook_state *p,
        p->out = outdev;
        p->sk = sk;
        p->net = net;
-       RCU_INIT_POINTER(p->hook_entries, hook_entry);
        p->okfn = okfn;
 }
 
@@ -150,7 +147,8 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
 extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 #endif
 
-int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state);
+int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
+                struct nf_hook_entry *entry);
 
 /**
  *     nf_hook - call a netfilter hook
@@ -179,10 +177,10 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net,
        if (hook_head) {
                struct nf_hook_state state;
 
-               nf_hook_state_init(&state, hook_head, hook, pf, indev, outdev,
+               nf_hook_state_init(&state, hook, pf, indev, outdev,
                                   sk, net, okfn);
 
-               ret = nf_hook_slow(skb, &state);
+               ret = nf_hook_slow(skb, &state, hook_head);
        }
        rcu_read_unlock();
 
index fd44e41317101312cf3c09f6e8ecb27b176a58bf..2dc3b49b804a32642b7b03827f57b0755c6fda36 100644 (file)
@@ -26,10 +26,10 @@ static inline int nf_hook_ingress(struct sk_buff *skb)
        if (unlikely(!e))
                return 0;
 
-       nf_hook_state_init(&state, e, NF_NETDEV_INGRESS,
+       nf_hook_state_init(&state, NF_NETDEV_INGRESS,
                           NFPROTO_NETDEV, skb->dev, NULL, NULL,
                           dev_net(skb->dev), NULL);
-       return nf_hook_slow(skb, &state);
+       return nf_hook_slow(skb, &state, e);
 }
 
 static inline void nf_hook_ingress_init(struct net_device *dev)
index 2280cfe86c56157f3ca1165baf6f4ad0e73a18be..09948d10e38e0b939b9764caafd7f3b9a9be41d5 100644 (file)
@@ -12,6 +12,7 @@ struct nf_queue_entry {
        unsigned int            id;
 
        struct nf_hook_state    state;
+       struct nf_hook_entry    *hook;
        u16                     size; /* sizeof(entry) + saved route keys */
 
        /* extra space to store route keys */
index 7e3645fa6339db43fc2e0a6e99bada3de8b76c14..8155bd2a5138431e09a31298b17d150df1f15e20 100644 (file)
@@ -1018,10 +1018,10 @@ int br_nf_hook_thresh(unsigned int hook, struct net *net,
 
        /* We may already have this, but read-locks nest anyway */
        rcu_read_lock();
-       nf_hook_state_init(&state, elem, hook, NFPROTO_BRIDGE, indev, outdev,
+       nf_hook_state_init(&state, hook, NFPROTO_BRIDGE, indev, outdev,
                           sk, net, okfn);
 
-       ret = nf_hook_slow(skb, &state);
+       ret = nf_hook_slow(skb, &state, elem);
        rcu_read_unlock();
        if (ret == 1)
                ret = okfn(net, sk, skb);
index 599679e3498d1dcab267c7e4722444fcbed629b1..8fe36dc3aab29ceac90443f229b9d745b6dfe5d6 100644 (file)
@@ -53,7 +53,7 @@ static int ebt_broute(struct sk_buff *skb)
        struct nf_hook_state state;
        int ret;
 
-       nf_hook_state_init(&state, NULL, NF_BR_BROUTING,
+       nf_hook_state_init(&state, NF_BR_BROUTING,
                           NFPROTO_BRIDGE, skb->dev, NULL, NULL,
                           dev_net(skb->dev), NULL);
 
index 64623374bc5f8f8f09d76c3c44f97562348a19e5..ebece48b8392a00aa8efe3a72ac6f8c1b8201dbc 100644 (file)
@@ -308,7 +308,7 @@ unsigned int nf_iterate(struct sk_buff *skb,
 {
        unsigned int verdict;
 
-       while (*entryp) {
+       do {
 repeat:
                verdict = (*entryp)->ops.hook((*entryp)->ops.priv, skb, state);
                if (verdict != NF_ACCEPT) {
@@ -317,20 +317,19 @@ repeat:
                        goto repeat;
                }
                *entryp = rcu_dereference((*entryp)->next);
-       }
+       } while (*entryp);
        return NF_ACCEPT;
 }
 
 
 /* Returns 1 if okfn() needs to be executed by the caller,
  * -EPERM for NF_DROP, 0 otherwise.  Caller must hold rcu_read_lock. */
-int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
+int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
+                struct nf_hook_entry *entry)
 {
-       struct nf_hook_entry *entry;
        unsigned int verdict;
        int ret;
 
-       entry = rcu_dereference(state->hook_entries);
 next_hook:
        verdict = nf_iterate(skb, state, &entry);
        switch (verdict & NF_VERDICT_MASK) {
index 0fb38966e5bf36993d3f17209b123a7b998b2e03..2e39e38ae1c7984b0f87cca6b8911e6df5b3f1e0 100644 (file)
@@ -108,7 +108,7 @@ void nf_queue_nf_hook_drop(struct net *net, const struct nf_hook_entry *entry)
 }
 
 static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
-                     unsigned int queuenum)
+                     struct nf_hook_entry *hook_entry, unsigned int queuenum)
 {
        int status = -ENOENT;
        struct nf_queue_entry *entry = NULL;
@@ -136,6 +136,7 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
        *entry = (struct nf_queue_entry) {
                .skb    = skb,
                .state  = *state,
+               .hook   = hook_entry,
                .size   = sizeof(*entry) + afinfo->route_key_size,
        };
 
@@ -163,8 +164,7 @@ int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
        struct nf_hook_entry *entry = *entryp;
        int ret;
 
-       RCU_INIT_POINTER(state->hook_entries, entry);
-       ret = __nf_queue(skb, state, verdict >> NF_VERDICT_QBITS);
+       ret = __nf_queue(skb, state, entry, verdict >> NF_VERDICT_QBITS);
        if (ret < 0) {
                if (ret == -ESRCH &&
                    (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS)) {
@@ -179,15 +179,12 @@ int nf_queue(struct sk_buff *skb, struct nf_hook_state *state,
 
 void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
 {
-       struct nf_hook_entry *hook_entry;
+       struct nf_hook_entry *hook_entry = entry->hook;
+       struct nf_hook_ops *elem = &hook_entry->ops;
        struct sk_buff *skb = entry->skb;
        const struct nf_afinfo *afinfo;
-       struct nf_hook_ops *elem;
        int err;
 
-       hook_entry = rcu_dereference(entry->state.hook_entries);
-       elem = &hook_entry->ops;
-
        nf_queue_entry_release_refs(entry);
 
        /* Continue traversal iff userspace said ok... */
index 5379f788a3721486a0406b54e093cbed4a7d1d89..1e33115b399fcdb90d2173fc282ab044b60d9520 100644 (file)
@@ -919,7 +919,7 @@ static struct notifier_block nfqnl_dev_notifier = {
 
 static int nf_hook_cmp(struct nf_queue_entry *entry, unsigned long entry_ptr)
 {
-       return rcu_access_pointer(entry->state.hook_entries) ==
+       return rcu_access_pointer(entry->hook) ==
                (struct nf_hook_entry *)entry_ptr;
 }