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:
Родитель
c63cbc4604
Коммит
01886bd91f
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче