netfilter: remove hook_entries field from nf_hook_state

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>
This commit is contained in:
Pablo Neira Ayuso 2016-11-03 10:56:35 +01:00
Родитель c63cbc4604
Коммит 01886bd91f
8 изменённых файлов: 20 добавлений и 25 удалений

Просмотреть файл

@ -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();

Просмотреть файл

@ -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)

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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... */

Просмотреть файл

@ -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;
}