Skip to content

Commit 960632e

Browse files
apconoleummakynes
authored andcommitted
netfilter: convert hook list to an array
This converts the storage and layout of netfilter hook entries from a linked list to an array. After this commit, hook entries will be stored adjacent in memory. The next pointer is no longer required. The ops pointers are stored at the end of the array as they are only used in the register/unregister path and in the legacy br_netfilter code. nf_unregister_net_hooks() is slower than needed as it just calls nf_unregister_net_hook in a loop (i.e. at least n synchronize_net() calls), this will be addressed in followup patch. Test setup: - ixgbe 10gbit - netperf UDP_STREAM, 64 byte packets - 5 hooks: (raw + mangle prerouting, mangle+filter input, inet filter): empty mangle and raw prerouting, mangle and filter input hooks: 353.9 this patch: 364.2 Signed-off-by: Aaron Conole <aconole@bytheb.org> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent 5fd02eb commit 960632e

File tree

9 files changed

+307
-134
lines changed

9 files changed

+307
-134
lines changed

include/linux/netdevice.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1811,7 +1811,7 @@ struct net_device {
18111811
#endif
18121812
struct netdev_queue __rcu *ingress_queue;
18131813
#ifdef CONFIG_NETFILTER_INGRESS
1814-
struct nf_hook_entry __rcu *nf_hooks_ingress;
1814+
struct nf_hook_entries __rcu *nf_hooks_ingress;
18151815
#endif
18161816

18171817
unsigned char broadcast[MAX_ADDR_LEN];

include/linux/netfilter.h

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -72,25 +72,32 @@ struct nf_hook_ops {
7272
};
7373

7474
struct nf_hook_entry {
75-
struct nf_hook_entry __rcu *next;
7675
nf_hookfn *hook;
7776
void *priv;
78-
const struct nf_hook_ops *orig_ops;
7977
};
8078

81-
static inline void
82-
nf_hook_entry_init(struct nf_hook_entry *entry, const struct nf_hook_ops *ops)
83-
{
84-
entry->next = NULL;
85-
entry->hook = ops->hook;
86-
entry->priv = ops->priv;
87-
entry->orig_ops = ops;
88-
}
79+
struct nf_hook_entries {
80+
u16 num_hook_entries;
81+
/* padding */
82+
struct nf_hook_entry hooks[];
83+
84+
/* trailer: pointers to original orig_ops of each hook.
85+
*
86+
* This is not part of struct nf_hook_entry since its only
87+
* needed in slow path (hook register/unregister).
88+
*
89+
* const struct nf_hook_ops *orig_ops[]
90+
*/
91+
};
8992

90-
static inline int
91-
nf_hook_entry_priority(const struct nf_hook_entry *entry)
93+
static inline struct nf_hook_ops **nf_hook_entries_get_hook_ops(const struct nf_hook_entries *e)
9294
{
93-
return entry->orig_ops->priority;
95+
unsigned int n = e->num_hook_entries;
96+
const void *hook_end;
97+
98+
hook_end = &e->hooks[n]; /* this is *past* ->hooks[]! */
99+
100+
return (struct nf_hook_ops **)hook_end;
94101
}
95102

96103
static inline int
@@ -100,12 +107,6 @@ nf_hook_entry_hookfn(const struct nf_hook_entry *entry, struct sk_buff *skb,
100107
return entry->hook(entry->priv, skb, state);
101108
}
102109

103-
static inline const struct nf_hook_ops *
104-
nf_hook_entry_ops(const struct nf_hook_entry *entry)
105-
{
106-
return entry->orig_ops;
107-
}
108-
109110
static inline void nf_hook_state_init(struct nf_hook_state *p,
110111
unsigned int hook,
111112
u_int8_t pf,
@@ -168,7 +169,7 @@ extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
168169
#endif
169170

170171
int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
171-
struct nf_hook_entry *entry);
172+
const struct nf_hook_entries *e, unsigned int i);
172173

173174
/**
174175
* nf_hook - call a netfilter hook
@@ -182,7 +183,7 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net,
182183
struct net_device *indev, struct net_device *outdev,
183184
int (*okfn)(struct net *, struct sock *, struct sk_buff *))
184185
{
185-
struct nf_hook_entry *hook_head;
186+
struct nf_hook_entries *hook_head;
186187
int ret = 1;
187188

188189
#ifdef HAVE_JUMP_LABEL
@@ -200,7 +201,7 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net,
200201
nf_hook_state_init(&state, hook, pf, indev, outdev,
201202
sk, net, okfn);
202203

203-
ret = nf_hook_slow(skb, &state, hook_head);
204+
ret = nf_hook_slow(skb, &state, hook_head, 0);
204205
}
205206
rcu_read_unlock();
206207

include/linux/netfilter_ingress.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ static inline bool nf_hook_ingress_active(const struct sk_buff *skb)
1717
/* caller must hold rcu_read_lock */
1818
static inline int nf_hook_ingress(struct sk_buff *skb)
1919
{
20-
struct nf_hook_entry *e = rcu_dereference(skb->dev->nf_hooks_ingress);
20+
struct nf_hook_entries *e = rcu_dereference(skb->dev->nf_hooks_ingress);
2121
struct nf_hook_state state;
2222
int ret;
2323

@@ -30,7 +30,7 @@ static inline int nf_hook_ingress(struct sk_buff *skb)
3030
nf_hook_state_init(&state, NF_NETDEV_INGRESS,
3131
NFPROTO_NETDEV, skb->dev, NULL, NULL,
3232
dev_net(skb->dev), NULL);
33-
ret = nf_hook_slow(skb, &state, e);
33+
ret = nf_hook_slow(skb, &state, e, 0);
3434
if (ret == 0)
3535
return -1;
3636

include/net/netfilter/nf_queue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ struct nf_queue_entry {
1010
struct list_head list;
1111
struct sk_buff *skb;
1212
unsigned int id;
13+
unsigned int hook_index; /* index in hook_entries->hook[] */
1314

1415
struct nf_hook_state state;
15-
struct nf_hook_entry *hook;
1616
u16 size; /* sizeof(entry) + saved route keys */
1717

1818
/* extra space to store route keys */

include/net/netns/netfilter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct netns_nf {
1616
#ifdef CONFIG_SYSCTL
1717
struct ctl_table_header *nf_log_dir_header;
1818
#endif
19-
struct nf_hook_entry __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
19+
struct nf_hook_entries __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
2020
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
2121
bool defrag_ipv4;
2222
#endif

net/bridge/br_netfilter_hooks.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -985,22 +985,25 @@ int br_nf_hook_thresh(unsigned int hook, struct net *net,
985985
int (*okfn)(struct net *, struct sock *,
986986
struct sk_buff *))
987987
{
988-
struct nf_hook_entry *elem;
988+
const struct nf_hook_entries *e;
989989
struct nf_hook_state state;
990+
struct nf_hook_ops **ops;
991+
unsigned int i;
990992
int ret;
991993

992-
for (elem = rcu_dereference(net->nf.hooks[NFPROTO_BRIDGE][hook]);
993-
elem && nf_hook_entry_priority(elem) <= NF_BR_PRI_BRNF;
994-
elem = rcu_dereference(elem->next))
995-
;
996-
997-
if (!elem)
994+
e = rcu_dereference(net->nf.hooks[NFPROTO_BRIDGE][hook]);
995+
if (!e)
998996
return okfn(net, sk, skb);
999997

998+
ops = nf_hook_entries_get_hook_ops(e);
999+
for (i = 0; i < e->num_hook_entries &&
1000+
ops[i]->priority <= NF_BR_PRI_BRNF; i++)
1001+
;
1002+
10001003
nf_hook_state_init(&state, hook, NFPROTO_BRIDGE, indev, outdev,
10011004
sk, net, okfn);
10021005

1003-
ret = nf_hook_slow(skb, &state, elem);
1006+
ret = nf_hook_slow(skb, &state, e, i);
10041007
if (ret == 1)
10051008
ret = okfn(net, sk, skb);
10061009

0 commit comments

Comments
 (0)