Re: [PATCH] netfilter: replace list_head with single linked list
Aaron Conole writes: > The netfilter hook list never uses the prev pointer, and so can be trimmed to > be a simple singly-linked list. > > In addition to having a more light weight structure for hook traversal, > struct net becomes 5568 bytes (down from 6400) and struct net_device becomes > 2176 bytes (down from 2240). > > Signed-off-by: Aaron Conole > Signed-off-by: Florian Westphal Apologies, all. This subject prefix is incorrect. It should be: [PATCH nf-next v3 7/7] Should I repost? > --- > include/linux/netdevice.h | 2 +- > include/linux/netfilter.h | 61 + > include/linux/netfilter_ingress.h | 16 +++-- > include/net/netfilter/nf_queue.h | 3 +- > include/net/netns/netfilter.h | 2 +- > net/bridge/br_netfilter_hooks.c | 19 ++--- > net/netfilter/core.c | 141 > +- > net/netfilter/nf_internals.h | 10 +-- > net/netfilter/nf_queue.c | 18 ++--- > net/netfilter/nfnetlink_queue.c | 8 ++- > 10 files changed, 165 insertions(+), 115 deletions(-) > > diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h > index 67bb978..41f49f5 100644 > --- a/include/linux/netdevice.h > +++ b/include/linux/netdevice.h > @@ -1783,7 +1783,7 @@ struct net_device { > #endif > struct netdev_queue __rcu *ingress_queue; > #ifdef CONFIG_NETFILTER_INGRESS > - struct list_headnf_hooks_ingress; > + struct nf_hook_entry __rcu *nf_hooks_ingress; > #endif > > unsigned char broadcast[MAX_ADDR_LEN]; > diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h > index ad444f0..17c90b0 100644 > --- a/include/linux/netfilter.h > +++ b/include/linux/netfilter.h > @@ -55,12 +55,34 @@ struct nf_hook_state { > struct net_device *out; > struct sock *sk; > struct net *net; > - struct list_head *hook_list; > + struct nf_hook_entry __rcu *hook_entries; > int (*okfn)(struct net *, struct sock *, struct sk_buff *); > }; > > +typedef unsigned int nf_hookfn(void *priv, > +struct sk_buff *skb, > +const struct nf_hook_state *state); > +struct nf_hook_ops { > + struct list_headlist; > + > + /* User fills in from here down. */ > + nf_hookfn *hook; > + struct net_device *dev; > + void*priv; > + u_int8_tpf; > + unsigned inthooknum; > + /* Hooks are ordered in ascending priority. */ > + int priority; > +}; > + > +struct nf_hook_entry { > + struct nf_hook_entry __rcu *next; > + struct nf_hook_ops ops; > + const struct nf_hook_ops*orig_ops; > +}; > + > static inline void nf_hook_state_init(struct nf_hook_state *p, > - struct list_head *hook_list, > + struct nf_hook_entry *hook_entry, > unsigned int hook, > int thresh, u_int8_t pf, > struct net_device *indev, > @@ -76,26 +98,11 @@ static inline void nf_hook_state_init(struct > nf_hook_state *p, > p->out = outdev; > p->sk = sk; > p->net = net; > - p->hook_list = hook_list; > + RCU_INIT_POINTER(p->hook_entries, hook_entry); > p->okfn = okfn; > } > > -typedef unsigned int nf_hookfn(void *priv, > -struct sk_buff *skb, > -const struct nf_hook_state *state); > > -struct nf_hook_ops { > - struct list_headlist; > - > - /* User fills in from here down. */ > - nf_hookfn *hook; > - struct net_device *dev; > - void*priv; > - u_int8_tpf; > - unsigned inthooknum; > - /* Hooks are ordered in ascending priority. */ > - int priority; > -}; > > struct nf_sockopt_ops { > struct list_head list; > @@ -161,7 +168,8 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned > int hook, >int (*okfn)(struct net *, struct sock *, > struct sk_buff *), >int thresh) > { > - struct list_head *hook_list; > + struct nf_hook_entry *hook_head; > + int ret = 1; > > #ifdef HAVE_JUMP_LABEL > if (__builtin_constant_p(pf) && > @@ -170,22 +178,19 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned > int hook, > return 1; > #endif > > - hook_list = &net->nf.hooks[pf][hook]; > + rcu_read_lock(); > > - if (!list_empty(hook_list)) { > + hook_head = rcu_dereference(net->nf.hooks[pf][hook]); > + if (hook_head) { > struct nf_hook_state state; > - int ret; > > - /* We may already have this, but read-locks nest anyway */ > - rcu_rea
[PATCH] netfilter: replace list_head with single linked list
The netfilter hook list never uses the prev pointer, and so can be trimmed to be a simple singly-linked list. In addition to having a more light weight structure for hook traversal, struct net becomes 5568 bytes (down from 6400) and struct net_device becomes 2176 bytes (down from 2240). Signed-off-by: Aaron Conole Signed-off-by: Florian Westphal --- include/linux/netdevice.h | 2 +- include/linux/netfilter.h | 61 + include/linux/netfilter_ingress.h | 16 +++-- include/net/netfilter/nf_queue.h | 3 +- include/net/netns/netfilter.h | 2 +- net/bridge/br_netfilter_hooks.c | 19 ++--- net/netfilter/core.c | 141 +- net/netfilter/nf_internals.h | 10 +-- net/netfilter/nf_queue.c | 18 ++--- net/netfilter/nfnetlink_queue.c | 8 ++- 10 files changed, 165 insertions(+), 115 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 67bb978..41f49f5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1783,7 +1783,7 @@ struct net_device { #endif struct netdev_queue __rcu *ingress_queue; #ifdef CONFIG_NETFILTER_INGRESS - struct list_headnf_hooks_ingress; + struct nf_hook_entry __rcu *nf_hooks_ingress; #endif unsigned char broadcast[MAX_ADDR_LEN]; diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index ad444f0..17c90b0 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -55,12 +55,34 @@ struct nf_hook_state { struct net_device *out; struct sock *sk; struct net *net; - struct list_head *hook_list; + struct nf_hook_entry __rcu *hook_entries; int (*okfn)(struct net *, struct sock *, struct sk_buff *); }; +typedef unsigned int nf_hookfn(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state); +struct nf_hook_ops { + struct list_headlist; + + /* User fills in from here down. */ + nf_hookfn *hook; + struct net_device *dev; + void*priv; + u_int8_tpf; + unsigned inthooknum; + /* Hooks are ordered in ascending priority. */ + int priority; +}; + +struct nf_hook_entry { + struct nf_hook_entry __rcu *next; + struct nf_hook_ops ops; + const struct nf_hook_ops*orig_ops; +}; + static inline void nf_hook_state_init(struct nf_hook_state *p, - struct list_head *hook_list, + struct nf_hook_entry *hook_entry, unsigned int hook, int thresh, u_int8_t pf, struct net_device *indev, @@ -76,26 +98,11 @@ static inline void nf_hook_state_init(struct nf_hook_state *p, p->out = outdev; p->sk = sk; p->net = net; - p->hook_list = hook_list; + RCU_INIT_POINTER(p->hook_entries, hook_entry); p->okfn = okfn; } -typedef unsigned int nf_hookfn(void *priv, - struct sk_buff *skb, - const struct nf_hook_state *state); -struct nf_hook_ops { - struct list_headlist; - - /* User fills in from here down. */ - nf_hookfn *hook; - struct net_device *dev; - void*priv; - u_int8_tpf; - unsigned inthooknum; - /* Hooks are ordered in ascending priority. */ - int priority; -}; struct nf_sockopt_ops { struct list_head list; @@ -161,7 +168,8 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, int (*okfn)(struct net *, struct sock *, struct sk_buff *), int thresh) { - struct list_head *hook_list; + struct nf_hook_entry *hook_head; + int ret = 1; #ifdef HAVE_JUMP_LABEL if (__builtin_constant_p(pf) && @@ -170,22 +178,19 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, return 1; #endif - hook_list = &net->nf.hooks[pf][hook]; + rcu_read_lock(); - if (!list_empty(hook_list)) { + hook_head = rcu_dereference(net->nf.hooks[pf][hook]); + if (hook_head) { struct nf_hook_state state; - int ret; - /* We may already have this, but read-locks nest anyway */ - rcu_read_lock(); - nf_hook_state_init(&state, hook_list, hook, thresh, + nf_hook_state_init(&state, hook_head, hook, thresh, pf, indev, outdev, sk, net, okfn); ret = nf_hook_slow(skb, &state); -