Re: [PATCH] netfilter: replace list_head with single linked list

2016-09-21 Thread Aaron Conole
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

2016-09-21 Thread Aaron Conole
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);
-