All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC 00/15] Netfilter pernet hook support
@ 2015-06-15 15:46 Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 01/15] net: include missing headers in net/net_namespace.h Pablo Neira Ayuso
                   ` (14 more replies)
  0 siblings, 15 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

Hi,

This is a first version RFC patchset to add pernet hook support to Netfilter,
with basically almost no testing here so far.

The initial three patches try to address a problem in the existing netfilter
netns header files. Basically, it's not a good idea to include
linux/netfilter.h from net/netns/netfilter.h. This is pulling quite a lot of
definitions from everything that includes net/net_namespace.h that are not
required.

It follows the initial patch to introduce of the pernet support for
nf_register_hook(). Initially, all callers are converted to use init_net.
Unlike Eric Bierderman's approach, there is no new parameter struct net from
any of the NF_HOOK(), NF_HOOK_COND() and nf_hook() but I prefer his approach
since we can avoid the dev_net(indev) ? ... branch.

Then, you get the bunch converted to use the pernet hooks by introducing the
boiler plate code to duplicate the existing nf_hooks_ops struct and register
it.

Pablo Neira Ayuso (15):
  net: include missing headers in net/net_namespace.h
  netfilter: use forward declaration instead of including linux/proc_fs.h
  netfilter: don't pull include/linux/netfilter.h from netns headers
  netfilter: add pernet hook support
  netfilter: ipt_CLUSTERIP: adapt it to support pernet hooks
  netfilter: x_tables: adapt xt_hook_link() to support pernet hooks
  netfilter: x_tables: adapt tables to pernet hooks
  netfilter: nf_conntrack: adapt IPv4 and IPv6 trackers to pernet hooks
  netfilter: synproxy: adapt IPv4 and IPv6 targets to pernet hooks
  netfilter: defrag: add pernet hook support
  ipvs: adapt it to pernet hooks
  netfilter: ebtables: adapt the filter and nat table to pernet hooks
  netfilter: nf_tables: adapt it to pernet hooks
  security: adapt it to pernet hooks
  netfilter: bridge: adapt it to pernet hooks

 include/linux/netfilter.h                      |   33 +++--
 include/linux/netfilter/x_tables.h             |    5 +-
 include/linux/netfilter_arp/arp_tables.h       |    3 +-
 include/linux/netfilter_defs.h                 |    9 ++
 include/linux/netfilter_ingress.h              |    6 +-
 include/linux/netfilter_ipv4/ip_tables.h       |    8 +-
 include/linux/netfilter_ipv6/ip6_tables.h      |    8 +-
 include/net/ip_vs.h                            |    3 +
 include/net/net_namespace.h                    |    2 +
 include/net/netfilter/br_netfilter.h           |   52 +++++++
 include/net/netns/conntrack.h                  |    4 +
 include/net/netns/netfilter.h                  |   27 +++-
 include/net/netns/x_tables.h                   |    4 +-
 include/uapi/linux/netfilter.h                 |    3 +-
 net/bridge/br_netfilter.c                      |  171 ++++++++++++++----------
 net/bridge/netfilter/ebtable_filter.c          |   41 ++++--
 net/bridge/netfilter/ebtable_nat.c             |   41 ++++--
 net/core/dev.c                                 |    6 +-
 net/decnet/netfilter/dn_rtmsg.c                |    2 +-
 net/ipv4/netfilter/arp_tables.c                |   15 ++-
 net/ipv4/netfilter/arptable_filter.c           |   25 +---
 net/ipv4/netfilter/ip_tables.c                 |   46 ++++++-
 net/ipv4/netfilter/ipt_CLUSTERIP.c             |   31 +++--
 net/ipv4/netfilter/ipt_SYNPROXY.c              |   51 ++++++-
 net/ipv4/netfilter/iptable_filter.c            |   21 +--
 net/ipv4/netfilter/iptable_mangle.c            |   21 +--
 net/ipv4/netfilter/iptable_nat.c               |   54 +++++---
 net/ipv4/netfilter/iptable_raw.c               |   20 +--
 net/ipv4/netfilter/iptable_security.c          |   24 +---
 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c |   36 +++--
 net/ipv4/netfilter/nf_defrag_ipv4.c            |   37 ++++-
 net/ipv6/netfilter/ip6_tables.c                |   42 +++++-
 net/ipv6/netfilter/ip6t_SYNPROXY.c             |   52 ++++++-
 net/ipv6/netfilter/ip6table_filter.c           |   25 +---
 net/ipv6/netfilter/ip6table_mangle.c           |   24 +---
 net/ipv6/netfilter/ip6table_nat.c              |   54 +++++---
 net/ipv6/netfilter/ip6table_raw.c              |   24 +---
 net/ipv6/netfilter/ip6table_security.c         |   24 +---
 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |   45 ++++---
 net/ipv6/netfilter/nf_defrag_ipv6_hooks.c      |   40 +++++-
 net/ipv6/output_core.c                         |    1 +
 net/netfilter/core.c                           |   26 ++--
 net/netfilter/ipvs/ip_vs_core.c                |   42 ++++--
 net/netfilter/nf_queue.c                       |    2 +-
 net/netfilter/nf_synproxy_core.c               |    1 +
 net/netfilter/nf_tables_api.c                  |   12 +-
 net/netfilter/x_tables.c                       |    5 +-
 security/selinux/hooks.c                       |   41 +++++-
 security/smack/smack_netfilter.c               |    3 +-
 49 files changed, 845 insertions(+), 427 deletions(-)
 create mode 100644 include/linux/netfilter_defs.h

-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH RFC 01/15] net: include missing headers in net/net_namespace.h
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 02/15] netfilter: use forward declaration instead of including linux/proc_fs.h Pablo Neira Ayuso
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

Include linux/idr.h and linux/skbuff.h since they are required by objects that
are declared in the net structure.

 struct net {
	...
	struct idr		netns_ids;
	...
	struct sk_buff_head	wext_nlevents;
	...

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/net_namespace.h |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 72eb237..e951453 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -28,6 +28,8 @@
 #include <net/netns/xfrm.h>
 #include <net/netns/mpls.h>
 #include <linux/ns_common.h>
+#include <linux/idr.h>
+#include <linux/skbuff.h>
 
 struct user_namespace;
 struct proc_dir_entry;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 02/15] netfilter: use forward declaration instead of including linux/proc_fs.h
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 01/15] net: include missing headers in net/net_namespace.h Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 03/15] netfilter: don't pull include/linux/netfilter.h from netns headers Pablo Neira Ayuso
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

We don't need to pull the full definitions in that file, a simple forward
declaration is enough.

Moreover, include linux/procfs.h from nf_synproxy_core, otherwise this hits a
compilation error due to missing declarations, ie.

net/netfilter/nf_synproxy_core.c: In function ‘synproxy_proc_init’:
net/netfilter/nf_synproxy_core.c:326:2: error: implicit declaration of function ‘proc_create’ [-Werror=implicit-function-declaration]
  if (!proc_create("synproxy", S_IRUGO, net->proc_net_stat,
  ^

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netns/netfilter.h    |    2 +-
 net/netfilter/nf_synproxy_core.c |    1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h
index 8874002..cf25b5e 100644
--- a/include/net/netns/netfilter.h
+++ b/include/net/netns/netfilter.h
@@ -1,9 +1,9 @@
 #ifndef __NETNS_NETFILTER_H
 #define __NETNS_NETFILTER_H
 
-#include <linux/proc_fs.h>
 #include <linux/netfilter.h>
 
+struct proc_dir_entry;
 struct nf_logger;
 
 struct netns_nf {
diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c
index 52e20c9..789feea 100644
--- a/net/netfilter/nf_synproxy_core.c
+++ b/net/netfilter/nf_synproxy_core.c
@@ -11,6 +11,7 @@
 #include <asm/unaligned.h>
 #include <net/tcp.h>
 #include <net/netns/generic.h>
+#include <linux/proc_fs.h>
 
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter/x_tables.h>
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 03/15] netfilter: don't pull include/linux/netfilter.h from netns headers
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 01/15] net: include missing headers in net/net_namespace.h Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 02/15] netfilter: use forward declaration instead of including linux/proc_fs.h Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 04/15] netfilter: add pernet hook support Pablo Neira Ayuso
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

This pulls the full hook netfilter definitions from all those that include
net_namespace.h.

Instead let's just include the bare minimum required in the new
linux/netfilter_defs.h file, and use it from the netfilter netns header files.

I also needed to include in.h and in6.h from linux/netfilter.h otherwise we hit
this compilation error:

In file included from include/linux/netfilter_defs.h:4:0,
                 from include/net/netns/netfilter.h:4,
                 from include/net/net_namespace.h:22,
                 from include/linux/netdevice.h:43,
                 from net/netfilter/nfnetlink_queue_core.c:23:
include/uapi/linux/netfilter.h:76:17: error: field ‘in’ has incomplete type struct in_addr in;

And also explicit include linux/netfilter.h in several spots.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/linux/netfilter.h      |    6 ++----
 include/linux/netfilter_defs.h |    9 +++++++++
 include/net/netns/netfilter.h  |    2 +-
 include/net/netns/x_tables.h   |    2 +-
 include/uapi/linux/netfilter.h |    3 ++-
 net/ipv6/output_core.c         |    1 +
 6 files changed, 16 insertions(+), 7 deletions(-)
 create mode 100644 include/linux/netfilter_defs.h

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index f5ff5d1..00050df 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -10,7 +10,8 @@
 #include <linux/wait.h>
 #include <linux/list.h>
 #include <linux/static_key.h>
-#include <uapi/linux/netfilter.h>
+#include <linux/netfilter_defs.h>
+
 #ifdef CONFIG_NETFILTER
 static inline int NF_DROP_GETERR(int verdict)
 {
@@ -38,9 +39,6 @@ static inline void nf_inet_addr_mask(const union nf_inet_addr *a1,
 
 int netfilter_init(void);
 
-/* Largest hook number + 1 */
-#define NF_MAX_HOOKS 8
-
 struct sk_buff;
 
 struct nf_hook_ops;
diff --git a/include/linux/netfilter_defs.h b/include/linux/netfilter_defs.h
new file mode 100644
index 0000000..d3a7f85
--- /dev/null
+++ b/include/linux/netfilter_defs.h
@@ -0,0 +1,9 @@
+#ifndef __LINUX_NETFILTER_CORE_H_
+#define __LINUX_NETFILTER_CORE_H_
+
+#include <uapi/linux/netfilter.h>
+
+/* Largest hook number + 1, see uapi/linux/netfilter_decnet.h */
+#define NF_MAX_HOOKS 8
+
+#endif
diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h
index cf25b5e..532e4ba 100644
--- a/include/net/netns/netfilter.h
+++ b/include/net/netns/netfilter.h
@@ -1,7 +1,7 @@
 #ifndef __NETNS_NETFILTER_H
 #define __NETNS_NETFILTER_H
 
-#include <linux/netfilter.h>
+#include <linux/netfilter_defs.h>
 
 struct proc_dir_entry;
 struct nf_logger;
diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
index 4d6597a..c8a7681 100644
--- a/include/net/netns/x_tables.h
+++ b/include/net/netns/x_tables.h
@@ -2,7 +2,7 @@
 #define __NETNS_X_TABLES_H
 
 #include <linux/list.h>
-#include <linux/netfilter.h>
+#include <linux/netfilter_defs.h>
 
 struct ebt_table;
 
diff --git a/include/uapi/linux/netfilter.h b/include/uapi/linux/netfilter.h
index 177027c..d93f949 100644
--- a/include/uapi/linux/netfilter.h
+++ b/include/uapi/linux/netfilter.h
@@ -4,7 +4,8 @@
 #include <linux/types.h>
 #include <linux/compiler.h>
 #include <linux/sysctl.h>
-
+#include <linux/in.h>
+#include <linux/in6.h>
 
 /* Responses from hook functions. */
 #define NF_DROP 0
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
index 21678ac..928a0fb 100644
--- a/net/ipv6/output_core.c
+++ b/net/ipv6/output_core.c
@@ -8,6 +8,7 @@
 #include <net/ip6_fib.h>
 #include <net/addrconf.h>
 #include <net/secure_seq.h>
+#include <linux/netfilter.h>
 
 static u32 __ipv6_select_ident(struct net *net, u32 hashrnd,
 			       const struct in6_addr *dst,
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 04/15] netfilter: add pernet hook support
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (2 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 03/15] netfilter: don't pull include/linux/netfilter.h from netns headers Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-16  1:01   ` Eric W. Biederman
  2015-06-15 15:46 ` [PATCH RFC 05/15] netfilter: ipt_CLUSTERIP: adapt it to support pernet hooks Pablo Neira Ayuso
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

This patch modifies the nf_register_hook() and nf_register_hooks() interfaces
to allow to register hooks at a pernet level.

This starts using init_net for all the existing callers though, so the full
conversion of existing netfilter hook clients to comes in follow up patches.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/linux/netfilter.h                      |   27 +++++++++++++++---------
 include/linux/netfilter_ingress.h              |    6 +++---
 include/net/netns/netfilter.h                  |    1 +
 net/bridge/br_netfilter.c                      |    2 +-
 net/bridge/netfilter/ebtable_filter.c          |    3 ++-
 net/bridge/netfilter/ebtable_nat.c             |    3 ++-
 net/core/dev.c                                 |    6 ++++--
 net/decnet/netfilter/dn_rtmsg.c                |    2 +-
 net/ipv4/netfilter/ipt_CLUSTERIP.c             |    2 +-
 net/ipv4/netfilter/ipt_SYNPROXY.c              |    2 +-
 net/ipv4/netfilter/iptable_nat.c               |    3 ++-
 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c |    2 +-
 net/ipv4/netfilter/nf_defrag_ipv4.c            |    3 ++-
 net/ipv6/netfilter/ip6t_SYNPROXY.c             |    2 +-
 net/ipv6/netfilter/ip6table_nat.c              |    3 ++-
 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |    2 +-
 net/ipv6/netfilter/nf_defrag_ipv6_hooks.c      |    3 ++-
 net/netfilter/core.c                           |   26 +++++++++++------------
 net/netfilter/ipvs/ip_vs_core.c                |    2 +-
 net/netfilter/nf_queue.c                       |    2 +-
 net/netfilter/nf_tables_api.c                  |    6 ++++--
 net/netfilter/x_tables.c                       |    2 +-
 security/selinux/hooks.c                       |    6 ++++--
 security/smack/smack_netfilter.c               |    3 ++-
 24 files changed, 70 insertions(+), 49 deletions(-)

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 00050df..f3c1c21 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -52,11 +52,13 @@ struct nf_hook_state {
 	struct net_device *in;
 	struct net_device *out;
 	struct sock *sk;
+	struct net *net;
 	struct list_head *hook_list;
 	int (*okfn)(struct sock *, struct sk_buff *);
 };
 
 static inline void nf_hook_state_init(struct nf_hook_state *p,
+				      struct net *net,
 				      struct list_head *hook_list,
 				      unsigned int hook,
 				      int thresh, u_int8_t pf,
@@ -65,6 +67,7 @@ static inline void nf_hook_state_init(struct nf_hook_state *p,
 				      struct sock *sk,
 				      int (*okfn)(struct sock *, struct sk_buff *))
 {
+	p->net = net;
 	p->hook = hook;
 	p->thresh = thresh;
 	p->pf = pf;
@@ -118,9 +121,9 @@ struct nf_sockopt_ops {
 };
 
 /* Function to register/unregister hook points. */
-int nf_register_hook(struct nf_hook_ops *reg);
+int nf_register_hook(struct net *net, struct nf_hook_ops *reg);
 void nf_unregister_hook(struct nf_hook_ops *reg);
-int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n);
+int nf_register_hooks(struct net *net, struct nf_hook_ops *reg, unsigned int n);
 void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
 
 /* Functions to register get/setsockopt ranges (non-inclusive).  You
@@ -128,8 +131,6 @@ void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
 int nf_register_sockopt(struct nf_sockopt_ops *reg);
 void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
 
-extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
-
 #ifdef HAVE_JUMP_LABEL
 extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 
@@ -150,9 +151,12 @@ static inline bool nf_hook_list_active(struct list_head *nf_hook_list,
 }
 #endif
 
-static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook)
+#include <linux/netdevice.h>
+
+static inline bool nf_hooks_active(struct net *net, u_int8_t pf,
+				   unsigned int hook)
 {
-	return nf_hook_list_active(&nf_hooks[pf][hook], pf, hook);
+	return nf_hook_list_active(&net->nf.hooks[pf][hook], pf, hook);
 }
 
 int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state);
@@ -172,11 +176,13 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
 				 int (*okfn)(struct sock *, struct sk_buff *),
 				 int thresh)
 {
-	if (nf_hooks_active(pf, hook)) {
+	struct net *net = indev ? dev_net(indev) : dev_net(outdev);
+
+	if (nf_hooks_active(net, pf, hook)) {
 		struct nf_hook_state state;
 
-		nf_hook_state_init(&state, &nf_hooks[pf][hook], hook, thresh,
-				   pf, indev, outdev, sk, okfn);
+		nf_hook_state_init(&state, net, &net->nf.hooks[pf][hook], hook,
+				   thresh, pf, indev, outdev, sk, okfn);
 		return nf_hook_slow(skb, &state);
 	}
 	return 1;
@@ -339,7 +345,8 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
 #else /* !CONFIG_NETFILTER */
 #define NF_HOOK(pf, hook, sk, skb, indev, outdev, okfn) (okfn)(sk, skb)
 #define NF_HOOK_COND(pf, hook, sk, skb, indev, outdev, okfn, cond) (okfn)(sk, skb)
-static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
+static inline int nf_hook_thresh(struct net *net,
+				 u_int8_t pf, unsigned int hook,
 				 struct sock *sk,
 				 struct sk_buff *skb,
 				 struct net_device *indev,
diff --git a/include/linux/netfilter_ingress.h b/include/linux/netfilter_ingress.h
index cb0727f..99a78e9 100644
--- a/include/linux/netfilter_ingress.h
+++ b/include/linux/netfilter_ingress.h
@@ -5,17 +5,17 @@
 #include <linux/netdevice.h>
 
 #ifdef CONFIG_NETFILTER_INGRESS
-static inline int nf_hook_ingress_active(struct sk_buff *skb)
+static inline int nf_hook_ingress_active(struct net *net, struct sk_buff *skb)
 {
 	return nf_hook_list_active(&skb->dev->nf_hooks_ingress,
 				   NFPROTO_NETDEV, NF_NETDEV_INGRESS);
 }
 
-static inline int nf_hook_ingress(struct sk_buff *skb)
+static inline int nf_hook_ingress(struct net *net, struct sk_buff *skb)
 {
 	struct nf_hook_state state;
 
-	nf_hook_state_init(&state, &skb->dev->nf_hooks_ingress,
+	nf_hook_state_init(&state, net, &skb->dev->nf_hooks_ingress,
 			   NF_NETDEV_INGRESS, INT_MIN, NFPROTO_NETDEV, NULL,
 			   skb->dev, NULL, NULL);
 	return nf_hook_slow(skb, &state);
diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h
index 532e4ba..38aa498 100644
--- a/include/net/netns/netfilter.h
+++ b/include/net/netns/netfilter.h
@@ -14,5 +14,6 @@ struct netns_nf {
 #ifdef CONFIG_SYSCTL
 	struct ctl_table_header *nf_log_dir_header;
 #endif
+	struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 };
 #endif
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index e4e5f2f..af14ef1 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -1246,7 +1246,7 @@ static int __init br_netfilter_init(void)
 {
 	int ret;
 
-	ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+	ret = nf_register_hooks(&init_net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
 	if (ret < 0)
 		return ret;
 
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index 8a3f63b..9a5a798 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -119,7 +119,8 @@ static int __init ebtable_filter_init(void)
 	ret = register_pernet_subsys(&frame_filter_net_ops);
 	if (ret < 0)
 		return ret;
-	ret = nf_register_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
+	ret = nf_register_hooks(&init_net, ebt_ops_filter,
+				ARRAY_SIZE(ebt_ops_filter));
 	if (ret < 0)
 		unregister_pernet_subsys(&frame_filter_net_ops);
 	return ret;
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index c5ef5b1..3d2759d 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -119,7 +119,8 @@ static int __init ebtable_nat_init(void)
 	ret = register_pernet_subsys(&frame_nat_net_ops);
 	if (ret < 0)
 		return ret;
-	ret = nf_register_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
+	ret = nf_register_hooks(&init_net, ebt_ops_nat,
+				ARRAY_SIZE(ebt_ops_nat));
 	if (ret < 0)
 		unregister_pernet_subsys(&frame_nat_net_ops);
 	return ret;
diff --git a/net/core/dev.c b/net/core/dev.c
index 6778a99..a176606 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3741,13 +3741,15 @@ static inline int nf_ingress(struct sk_buff *skb, struct packet_type **pt_prev,
 			     int *ret, struct net_device *orig_dev)
 {
 #ifdef CONFIG_NETFILTER_INGRESS
-	if (nf_hook_ingress_active(skb)) {
+	struct net *net = dev_net(orig_dev);
+
+	if (nf_hook_ingress_active(net, skb)) {
 		if (*pt_prev) {
 			*ret = deliver_skb(skb, *pt_prev, orig_dev);
 			*pt_prev = NULL;
 		}
 
-		return nf_hook_ingress(skb);
+		return nf_hook_ingress(net, skb);
 	}
 #endif /* CONFIG_NETFILTER_INGRESS */
 	return 0;
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index af34fc9..ba02eac 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -134,7 +134,7 @@ static int __init dn_rtmsg_init(void)
 		return -ENOMEM;
 	}
 
-	rv = nf_register_hook(&dnrmg_ops);
+	rv = nf_register_hook(&init_net, &dnrmg_ops);
 	if (rv) {
 		netlink_kernel_release(dnrmg);
 	}
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 45cb16a..cf23858 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -767,7 +767,7 @@ static int __init clusterip_tg_init(void)
 	if (ret < 0)
 		goto cleanup_subsys;
 
-	ret = nf_register_hook(&cip_arp_ops);
+	ret = nf_register_hook(&init_net, &cip_arp_ops);
 	if (ret < 0)
 		goto cleanup_target;
 
diff --git a/net/ipv4/netfilter/ipt_SYNPROXY.c b/net/ipv4/netfilter/ipt_SYNPROXY.c
index fe8cc18..a57d3d1 100644
--- a/net/ipv4/netfilter/ipt_SYNPROXY.c
+++ b/net/ipv4/netfilter/ipt_SYNPROXY.c
@@ -450,7 +450,7 @@ static int __init synproxy_tg4_init(void)
 {
 	int err;
 
-	err = nf_register_hooks(ipv4_synproxy_ops,
+	err = nf_register_hooks(&init_net, ipv4_synproxy_ops,
 				ARRAY_SIZE(ipv4_synproxy_ops));
 	if (err < 0)
 		goto err1;
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index 0d4d9cd..5ef83d3 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -131,7 +131,8 @@ static int __init iptable_nat_init(void)
 	if (err < 0)
 		goto err1;
 
-	err = nf_register_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
+	err = nf_register_hooks(&init_net, nf_nat_ipv4_ops,
+				ARRAY_SIZE(nf_nat_ipv4_ops));
 	if (err < 0)
 		goto err2;
 	return 0;
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 30ad955..2384975 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -467,7 +467,7 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
 		goto cleanup_sockopt;
 	}
 
-	ret = nf_register_hooks(ipv4_conntrack_ops,
+	ret = nf_register_hooks(&init_net, ipv4_conntrack_ops,
 				ARRAY_SIZE(ipv4_conntrack_ops));
 	if (ret < 0) {
 		pr_err("nf_conntrack_ipv4: can't register hooks.\n");
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index c88b7d4..ad74929 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -110,7 +110,8 @@ static struct nf_hook_ops ipv4_defrag_ops[] = {
 
 static int __init nf_defrag_init(void)
 {
-	return nf_register_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops));
+	return nf_register_hooks(&init_net, ipv4_defrag_ops,
+				 ARRAY_SIZE(ipv4_defrag_ops));
 }
 
 static void __exit nf_defrag_fini(void)
diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c
index 6edb7b1..ed5d4a6 100644
--- a/net/ipv6/netfilter/ip6t_SYNPROXY.c
+++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c
@@ -473,7 +473,7 @@ static int __init synproxy_tg6_init(void)
 {
 	int err;
 
-	err = nf_register_hooks(ipv6_synproxy_ops,
+	err = nf_register_hooks(&init_net, ipv6_synproxy_ops,
 				ARRAY_SIZE(ipv6_synproxy_ops));
 	if (err < 0)
 		goto err1;
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index c3a7f7a..ecb0511 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -133,7 +133,8 @@ static int __init ip6table_nat_init(void)
 	if (err < 0)
 		goto err1;
 
-	err = nf_register_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops));
+	err = nf_register_hooks(&init_net, nf_nat_ipv6_ops,
+				ARRAY_SIZE(nf_nat_ipv6_ops));
 	if (err < 0)
 		goto err2;
 	return 0;
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 4ba0c34..8bcf625 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -407,7 +407,7 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
 	if (ret < 0)
 		goto cleanup_sockopt;
 
-	ret = nf_register_hooks(ipv6_conntrack_ops,
+	ret = nf_register_hooks(&init_net, ipv6_conntrack_ops,
 				ARRAY_SIZE(ipv6_conntrack_ops));
 	if (ret < 0) {
 		pr_err("nf_conntrack_ipv6: can't register pre-routing defrag "
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
index a45db0b..7bc330f 100644
--- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -108,7 +108,8 @@ static int __init nf_defrag_init(void)
 		pr_err("nf_defrag_ipv6: can't initialize frag6.\n");
 		return ret;
 	}
-	ret = nf_register_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops));
+	ret = nf_register_hooks(&init_net, ipv6_defrag_ops,
+				ARRAY_SIZE(ipv6_defrag_ops));
 	if (ret < 0) {
 		pr_err("nf_defrag_ipv6: can't register hooks\n");
 		goto cleanup_frag6;
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 653e32e..73c8ecb 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -52,9 +52,6 @@ void nf_unregister_afinfo(const struct nf_afinfo *afinfo)
 }
 EXPORT_SYMBOL_GPL(nf_unregister_afinfo);
 
-struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;
-EXPORT_SYMBOL(nf_hooks);
-
 #ifdef HAVE_JUMP_LABEL
 struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 EXPORT_SYMBOL(nf_hooks_needed);
@@ -62,7 +59,7 @@ EXPORT_SYMBOL(nf_hooks_needed);
 
 static DEFINE_MUTEX(nf_hook_mutex);
 
-int nf_register_hook(struct nf_hook_ops *reg)
+int nf_register_hook(struct net *net, struct nf_hook_ops *reg)
 {
 	struct list_head *nf_hook_list;
 	struct nf_hook_ops *elem;
@@ -80,7 +77,7 @@ int nf_register_hook(struct nf_hook_ops *reg)
 #endif
 		/* Fall through. */
 	default:
-		nf_hook_list = &nf_hooks[reg->pf][reg->hooknum];
+		nf_hook_list = &net->nf.hooks[reg->pf][reg->hooknum];
 		break;
 	}
 
@@ -121,13 +118,13 @@ void nf_unregister_hook(struct nf_hook_ops *reg)
 }
 EXPORT_SYMBOL(nf_unregister_hook);
 
-int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n)
+int nf_register_hooks(struct net *net, struct nf_hook_ops *reg, unsigned int n)
 {
 	unsigned int i;
 	int err = 0;
 
 	for (i = 0; i < n; i++) {
-		err = nf_register_hook(&reg[i]);
+		err = nf_register_hook(net, &reg[i]);
 		if (err)
 			goto err;
 	}
@@ -296,6 +293,13 @@ EXPORT_SYMBOL(nf_nat_decode_session_hook);
 
 static int __net_init netfilter_net_init(struct net *net)
 {
+	int i, h;
+
+	for (i = 0; i < NFPROTO_NUMPROTO; i++) {
+		for (h = 0; h < NF_MAX_HOOKS; h++)
+			INIT_LIST_HEAD(&net->nf.hooks[i][h]);
+	}
+
 #ifdef CONFIG_PROC_FS
 	net->nf.proc_netfilter = proc_net_mkdir(net, "netfilter",
 						net->proc_net);
@@ -306,6 +310,7 @@ static int __net_init netfilter_net_init(struct net *net)
 		return -ENOMEM;
 	}
 #endif
+
 	return 0;
 }
 
@@ -321,12 +326,7 @@ static struct pernet_operations netfilter_net_ops = {
 
 int __init netfilter_init(void)
 {
-	int i, h, ret;
-
-	for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) {
-		for (h = 0; h < NF_MAX_HOOKS; h++)
-			INIT_LIST_HEAD(&nf_hooks[i][h]);
-	}
+	int ret;
 
 	ret = register_pernet_subsys(&netfilter_net_ops);
 	if (ret < 0)
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 5d2b806..2751d5a 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -2088,7 +2088,7 @@ static int __init ip_vs_init(void)
 	if (ret < 0)
 		goto cleanup_sub;
 
-	ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
+	ret = nf_register_hooks(&init_net, ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
 	if (ret < 0) {
 		pr_err("can't register hooks.\n");
 		goto cleanup_dev;
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 2e88032..ab077fe 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -196,7 +196,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
 
 	if (verdict == NF_ACCEPT) {
 	next_hook:
-		verdict = nf_iterate(&nf_hooks[entry->state.pf][entry->state.hook],
+		verdict = nf_iterate(entry->state.hook_list,
 				     skb, &entry->state, &elem);
 	}
 
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 4528f12..a8d4044 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -566,7 +566,8 @@ static int nf_tables_table_enable(const struct nft_af_info *afi,
 		if (!(chain->flags & NFT_BASE_CHAIN))
 			continue;
 
-		err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
+		err = nf_register_hooks(&init_net, nft_base_chain(chain)->ops,
+					afi->nops);
 		if (err < 0)
 			goto err;
 
@@ -1418,7 +1419,8 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
 
 	if (!(table->flags & NFT_TABLE_F_DORMANT) &&
 	    chain->flags & NFT_BASE_CHAIN) {
-		err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
+		err = nf_register_hooks(&init_net, nft_base_chain(chain)->ops,
+					afi->nops);
 		if (err < 0)
 			goto err1;
 	}
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 6062ce3..0891564 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1201,7 +1201,7 @@ struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
 		++i;
 	}
 
-	ret = nf_register_hooks(ops, num_hooks);
+	ret = nf_register_hooks(&init_net, ops, num_hooks);
 	if (ret < 0) {
 		kfree(ops);
 		return ERR_PTR(ret);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7dade28..7246654 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6156,7 +6156,8 @@ static int __init selinux_nf_ip_init(void)
 
 	printk(KERN_DEBUG "SELinux:  Registering netfilter hooks\n");
 
-	err = nf_register_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
+	err = nf_register_hooks(&init_net, selinux_nf_ops,
+				ARRAY_SIZE(selinux_nf_ops));
 	if (err)
 		panic("SELinux: nf_register_hooks: error %d\n", err);
 
@@ -6170,7 +6171,8 @@ static void selinux_nf_ip_exit(void)
 {
 	printk(KERN_DEBUG "SELinux:  Unregistering netfilter hooks\n");
 
-	nf_unregister_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
+	nf_unregister_hooks(&init_net, selinux_nf_ops,
+			    ARRAY_SIZE(selinux_nf_ops));
 }
 #endif
 
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index a455cfc..e39f79e 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -82,7 +82,8 @@ static int __init smack_nf_ip_init(void)
 
 	printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
 
-	err = nf_register_hooks(smack_nf_ops, ARRAY_SIZE(smack_nf_ops));
+	err = nf_register_hooks(&init_net, smack_nf_ops,
+				ARRAY_SIZE(smack_nf_ops));
 	if (err)
 		pr_info("Smack: nf_register_hooks: error %d\n", err);
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 05/15] netfilter: ipt_CLUSTERIP: adapt it to support pernet hooks
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (3 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 04/15] netfilter: add pernet hook support Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 06/15] netfilter: x_tables: adapt xt_hook_link() " Pablo Neira Ayuso
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

This target is deprecated, but let's adapt this so it doesn't break existing
users.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/ipv4/netfilter/ipt_CLUSTERIP.c |   31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index cf23858..0baa7f9 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -69,6 +69,8 @@ struct clusterip_net {
 	/* lock protects the configs list */
 	spinlock_t lock;
 
+	struct nf_hook_ops *ops;
+
 #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *procdir;
 #endif
@@ -724,6 +726,7 @@ static const struct file_operations clusterip_proc_fops = {
 static int clusterip_net_init(struct net *net)
 {
 	struct clusterip_net *cn = net_generic(net, clusterip_net_id);
+	int err;
 
 	INIT_LIST_HEAD(&cn->configs);
 
@@ -737,13 +740,32 @@ static int clusterip_net_init(struct net *net)
 	}
 #endif /* CONFIG_PROC_FS */
 
+	err = -ENOMEM;
+	cn->ops = kmemdup(&cip_arp_ops, sizeof(cip_arp_ops), GFP_KERNEL);
+	if (cn->ops == NULL)
+		goto err1;
+
+	err = nf_register_hook(net, cn->ops);
+	if (err < 0)
+		goto err2;
+
 	return 0;
+err2:
+	kfree(cn->ops);
+err1:
+	proc_remove(cn->procdir);
+
+	return err;
 }
 
 static void clusterip_net_exit(struct net *net)
 {
-#ifdef CONFIG_PROC_FS
 	struct clusterip_net *cn = net_generic(net, clusterip_net_id);
+
+	nf_unregister_hook(cn->ops);
+	kfree(cn->ops);
+
+#ifdef CONFIG_PROC_FS
 	proc_remove(cn->procdir);
 #endif
 }
@@ -767,17 +789,11 @@ static int __init clusterip_tg_init(void)
 	if (ret < 0)
 		goto cleanup_subsys;
 
-	ret = nf_register_hook(&init_net, &cip_arp_ops);
-	if (ret < 0)
-		goto cleanup_target;
-
 	pr_info("ClusterIP Version %s loaded successfully\n",
 		CLUSTERIP_VERSION);
 
 	return 0;
 
-cleanup_target:
-	xt_unregister_target(&clusterip_tg_reg);
 cleanup_subsys:
 	unregister_pernet_subsys(&clusterip_net_ops);
 	return ret;
@@ -787,7 +803,6 @@ static void __exit clusterip_tg_exit(void)
 {
 	pr_info("ClusterIP Version %s unloading\n", CLUSTERIP_VERSION);
 
-	nf_unregister_hook(&cip_arp_ops);
 	xt_unregister_target(&clusterip_tg_reg);
 	unregister_pernet_subsys(&clusterip_net_ops);
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 06/15] netfilter: x_tables: adapt xt_hook_link() to support pernet hooks
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (4 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 05/15] netfilter: ipt_CLUSTERIP: adapt it to support pernet hooks Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 07/15] netfilter: x_tables: adapt tables to " Pablo Neira Ayuso
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

This prepares the port of the existing tables to the pernet hooks.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/linux/netfilter/x_tables.h     |    3 ++-
 net/ipv4/netfilter/arptable_filter.c   |    3 ++-
 net/ipv4/netfilter/iptable_filter.c    |    3 ++-
 net/ipv4/netfilter/iptable_mangle.c    |    3 ++-
 net/ipv4/netfilter/iptable_raw.c       |    2 +-
 net/ipv4/netfilter/iptable_security.c  |    3 ++-
 net/ipv6/netfilter/ip6table_filter.c   |    3 ++-
 net/ipv6/netfilter/ip6table_mangle.c   |    3 ++-
 net/ipv6/netfilter/ip6table_raw.c      |    2 +-
 net/ipv6/netfilter/ip6table_security.c |    3 ++-
 net/netfilter/x_tables.c               |    5 +++--
 11 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 9969d79..8344092 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -402,7 +402,8 @@ xt_get_per_cpu_counter(struct xt_counters *cnt, unsigned int cpu)
 	return cnt;
 }
 
-struct nf_hook_ops *xt_hook_link(const struct xt_table *, nf_hookfn *);
+struct nf_hook_ops *xt_hook_link(struct net *net, const struct xt_table *,
+				 nf_hookfn *);
 void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
 
 #ifdef CONFIG_COMPAT
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 93876d0..c7a7729 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -69,7 +69,8 @@ static int __init arptable_filter_init(void)
 	if (ret < 0)
 		return ret;
 
-	arpfilter_ops = xt_hook_link(&packet_filter, arptable_filter_hook);
+	arpfilter_ops = xt_hook_link(&init_net, &packet_filter,
+				     arptable_filter_hook);
 	if (IS_ERR(arpfilter_ops)) {
 		ret = PTR_ERR(arpfilter_ops);
 		goto cleanup_table;
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index a0f3bec..f0faa27 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -90,7 +90,8 @@ static int __init iptable_filter_init(void)
 		return ret;
 
 	/* Register hooks */
-	filter_ops = xt_hook_link(&packet_filter, iptable_filter_hook);
+	filter_ops = xt_hook_link(&init_net, &packet_filter,
+				  iptable_filter_hook);
 	if (IS_ERR(filter_ops)) {
 		ret = PTR_ERR(filter_ops);
 		unregister_pernet_subsys(&iptable_filter_net_ops);
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 62cbb8c..bd294b4 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -128,7 +128,8 @@ static int __init iptable_mangle_init(void)
 		return ret;
 
 	/* Register hooks */
-	mangle_ops = xt_hook_link(&packet_mangler, iptable_mangle_hook);
+	mangle_ops = xt_hook_link(&init_net, &packet_mangler,
+				  iptable_mangle_hook);
 	if (IS_ERR(mangle_ops)) {
 		ret = PTR_ERR(mangle_ops);
 		unregister_pernet_subsys(&iptable_mangle_net_ops);
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 0356e6d..2541383 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -69,7 +69,7 @@ static int __init iptable_raw_init(void)
 		return ret;
 
 	/* Register hooks */
-	rawtable_ops = xt_hook_link(&packet_raw, iptable_raw_hook);
+	rawtable_ops = xt_hook_link(&init_net, &packet_raw, iptable_raw_hook);
 	if (IS_ERR(rawtable_ops)) {
 		ret = PTR_ERR(rawtable_ops);
 		unregister_pernet_subsys(&iptable_raw_net_ops);
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
index 4bce398..0a0ddc7 100644
--- a/net/ipv4/netfilter/iptable_security.c
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -86,7 +86,8 @@ static int __init iptable_security_init(void)
         if (ret < 0)
 		return ret;
 
-	sectbl_ops = xt_hook_link(&security_table, iptable_security_hook);
+	sectbl_ops = xt_hook_link(&init_net, &security_table,
+				  iptable_security_hook);
 	if (IS_ERR(sectbl_ops)) {
 		ret = PTR_ERR(sectbl_ops);
 		goto cleanup_table;
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 5c33d8a..fe0bf52 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -82,7 +82,8 @@ static int __init ip6table_filter_init(void)
 		return ret;
 
 	/* Register hooks */
-	filter_ops = xt_hook_link(&packet_filter, ip6table_filter_hook);
+	filter_ops = xt_hook_link(&init_net, &packet_filter,
+				  ip6table_filter_hook);
 	if (IS_ERR(filter_ops)) {
 		ret = PTR_ERR(filter_ops);
 		goto cleanup_table;
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index b551f5b..50fea9e 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -122,7 +122,8 @@ static int __init ip6table_mangle_init(void)
 		return ret;
 
 	/* Register hooks */
-	mangle_ops = xt_hook_link(&packet_mangler, ip6table_mangle_hook);
+	mangle_ops = xt_hook_link(&init_net, &packet_mangler,
+				  ip6table_mangle_hook);
 	if (IS_ERR(mangle_ops)) {
 		ret = PTR_ERR(mangle_ops);
 		goto cleanup_table;
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index 0b33caa..141604f 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -61,7 +61,7 @@ static int __init ip6table_raw_init(void)
 		return ret;
 
 	/* Register hooks */
-	rawtable_ops = xt_hook_link(&packet_raw, ip6table_raw_hook);
+	rawtable_ops = xt_hook_link(&init_net, &packet_raw, ip6table_raw_hook);
 	if (IS_ERR(rawtable_ops)) {
 		ret = PTR_ERR(rawtable_ops);
 		goto cleanup_table;
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
index fcef83c..8d252f8 100644
--- a/net/ipv6/netfilter/ip6table_security.c
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -78,7 +78,8 @@ static int __init ip6table_security_init(void)
 	if (ret < 0)
 		return ret;
 
-	sectbl_ops = xt_hook_link(&security_table, ip6table_security_hook);
+	sectbl_ops = xt_hook_link(&init_net, &security_table,
+				  ip6table_security_hook);
 	if (IS_ERR(sectbl_ops)) {
 		ret = PTR_ERR(sectbl_ops);
 		goto cleanup_table;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 0891564..fb846d6 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1177,7 +1177,8 @@ static const struct file_operations xt_target_ops = {
  * This function will take care of creating and registering the necessary
  * Netfilter hooks for XT tables.
  */
-struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
+struct nf_hook_ops *xt_hook_link(struct net *net, const struct xt_table *table,
+				 nf_hookfn *fn)
 {
 	unsigned int hook_mask = table->valid_hooks;
 	uint8_t i, num_hooks = hweight32(hook_mask);
@@ -1201,7 +1202,7 @@ struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
 		++i;
 	}
 
-	ret = nf_register_hooks(&init_net, ops, num_hooks);
+	ret = nf_register_hooks(net, ops, num_hooks);
 	if (ret < 0) {
 		kfree(ops);
 		return ERR_PTR(ret);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 07/15] netfilter: x_tables: adapt tables to pernet hooks
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (5 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 06/15] netfilter: x_tables: adapt xt_hook_link() " Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 08/15] netfilter: nf_conntrack: adapt IPv4 and IPv6 trackers " Pablo Neira Ayuso
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

To achieve this, this patch moves struct nf_hook_ops to the xt_table struct.
This has a nice side effect since this simplifies the boiler plate code that
registers a table.

There is one exception though, since NAT tables are special given that
their hooks have different priorities. To address this, they use the new
__ip{6}t_register_table() and __ip{6}_unregister_table() that don't call
xt_hook_link(). Then, these table manually register the hooks and attach
the nf_hooks_ops to the new xt_table field.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/linux/netfilter/x_tables.h        |    2 ++
 include/linux/netfilter_arp/arp_tables.h  |    3 +-
 include/linux/netfilter_ipv4/ip_tables.h  |    8 ++++-
 include/linux/netfilter_ipv6/ip6_tables.h |    8 ++++-
 net/ipv4/netfilter/arp_tables.c           |   15 +++++++-
 net/ipv4/netfilter/arptable_filter.c      |   26 +++-----------
 net/ipv4/netfilter/ip_tables.c            |   46 +++++++++++++++++++++---
 net/ipv4/netfilter/iptable_filter.c       |   22 ++----------
 net/ipv4/netfilter/iptable_mangle.c       |   22 ++----------
 net/ipv4/netfilter/iptable_nat.c          |   55 ++++++++++++++++++-----------
 net/ipv4/netfilter/iptable_raw.c          |   20 ++---------
 net/ipv4/netfilter/iptable_security.c     |   25 ++-----------
 net/ipv6/netfilter/ip6_tables.c           |   42 ++++++++++++++++++++--
 net/ipv6/netfilter/ip6table_filter.c      |   26 ++------------
 net/ipv6/netfilter/ip6table_mangle.c      |   25 ++-----------
 net/ipv6/netfilter/ip6table_nat.c         |   55 ++++++++++++++++++-----------
 net/ipv6/netfilter/ip6table_raw.c         |   24 ++-----------
 net/ipv6/netfilter/ip6table_security.c    |   25 ++-----------
 18 files changed, 210 insertions(+), 239 deletions(-)

diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 8344092..7d6c808 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -192,6 +192,8 @@ struct xt_table {
 	/* Man behind the curtain... */
 	struct xt_table_info *private;
 
+	struct nf_hook_ops *ops;
+
 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
 	struct module *me;
 
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index c22a7fb..9d8d25d 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -50,7 +50,8 @@ struct arpt_error {
 extern void *arpt_alloc_initial_table(const struct xt_table *);
 extern struct xt_table *arpt_register_table(struct net *net,
 					    const struct xt_table *table,
-					    const struct arpt_replace *repl);
+					    const struct arpt_replace *repl,
+					    nf_hookfn *hookfn);
 extern void arpt_unregister_table(struct xt_table *table);
 extern unsigned int arpt_do_table(struct sk_buff *skb,
 				  unsigned int hook,
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index 4073510..aae5b92 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -26,9 +26,15 @@ extern void ipt_init(void) __init;
 
 extern struct xt_table *ipt_register_table(struct net *net,
 					   const struct xt_table *table,
-					   const struct ipt_replace *repl);
+					   const struct ipt_replace *repl,
+					   nf_hookfn *hookfn);
 extern void ipt_unregister_table(struct net *net, struct xt_table *table);
 
+extern struct xt_table *__ipt_register_table(struct net *net,
+					     const struct xt_table *table,
+					     const struct ipt_replace *repl);
+extern void __ipt_unregister_table(struct net *net, struct xt_table *table);
+
 /* Standard entry. */
 struct ipt_standard {
 	struct ipt_entry entry;
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index b40d2b6..2fdabe2 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -27,8 +27,14 @@ extern void ip6t_init(void) __init;
 extern void *ip6t_alloc_initial_table(const struct xt_table *);
 extern struct xt_table *ip6t_register_table(struct net *net,
 					    const struct xt_table *table,
-					    const struct ip6t_replace *repl);
+					    const struct ip6t_replace *repl,
+					    nf_hookfn *hookfn);
 extern void ip6t_unregister_table(struct net *net, struct xt_table *table);
+extern struct xt_table *__ip6t_register_table(struct net *net,
+					      const struct xt_table *table,
+					      const struct ip6t_replace *repl);
+extern void __ip6t_unregister_table(struct net *net, struct xt_table *table);
+
 extern unsigned int ip6t_do_table(struct sk_buff *skb,
 				  unsigned int hook,
 				  const struct nf_hook_state *state,
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index d75c139..7d1f327 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -1779,13 +1779,15 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
 
 struct xt_table *arpt_register_table(struct net *net,
 				     const struct xt_table *table,
-				     const struct arpt_replace *repl)
+				     const struct arpt_replace *repl,
+				     nf_hookfn *hookfn)
 {
 	int ret;
 	struct xt_table_info *newinfo;
 	struct xt_table_info bootstrap = {0};
 	void *loc_cpu_entry;
 	struct xt_table *new_table;
+	struct nf_hook_ops *ops;
 
 	newinfo = xt_alloc_table_info(repl->size);
 	if (!newinfo) {
@@ -1806,8 +1808,17 @@ struct xt_table *arpt_register_table(struct net *net,
 		ret = PTR_ERR(new_table);
 		goto out_free;
 	}
+
+	ops = xt_hook_link(net, table, hookfn);
+	if (IS_ERR(ops)) {
+		ret = PTR_ERR(ops);
+		goto out_unregister_table;
+	}
+
 	return new_table;
 
+out_unregister_table:
+	xt_unregister_table(new_table);
 out_free:
 	xt_free_table_info(newinfo);
 out:
@@ -1821,6 +1832,8 @@ void arpt_unregister_table(struct xt_table *table)
 	struct module *table_owner = table->me;
 	struct arpt_entry *iter;
 
+	xt_hook_unlink(table, table->ops);
+
 	private = xt_unregister_table(table);
 
 	/* Decrease module usage counts and free resources */
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index c7a7729..eb2c514 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -36,17 +36,16 @@ arptable_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
 			     net->ipv4.arptable_filter);
 }
 
-static struct nf_hook_ops *arpfilter_ops __read_mostly;
-
 static int __net_init arptable_filter_net_init(struct net *net)
 {
 	struct arpt_replace *repl;
-	
+
 	repl = arpt_alloc_initial_table(&packet_filter);
 	if (repl == NULL)
 		return -ENOMEM;
 	net->ipv4.arptable_filter =
-		arpt_register_table(net, &packet_filter, repl);
+		arpt_register_table(net, &packet_filter, repl,
+				    arptable_filter_hook);
 	kfree(repl);
 	return PTR_ERR_OR_ZERO(net->ipv4.arptable_filter);
 }
@@ -63,28 +62,11 @@ static struct pernet_operations arptable_filter_net_ops = {
 
 static int __init arptable_filter_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&arptable_filter_net_ops);
-	if (ret < 0)
-		return ret;
-
-	arpfilter_ops = xt_hook_link(&init_net, &packet_filter,
-				     arptable_filter_hook);
-	if (IS_ERR(arpfilter_ops)) {
-		ret = PTR_ERR(arpfilter_ops);
-		goto cleanup_table;
-	}
-	return ret;
-
-cleanup_table:
-	unregister_pernet_subsys(&arptable_filter_net_ops);
-	return ret;
+	return register_pernet_subsys(&arptable_filter_net_ops);
 }
 
 static void __exit arptable_filter_fini(void)
 {
-	xt_hook_unlink(&packet_filter, arpfilter_ops);
 	unregister_pernet_subsys(&arptable_filter_net_ops);
 }
 
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 6151500..3a3048e 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -2057,9 +2057,10 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 	return ret;
 }
 
-struct xt_table *ipt_register_table(struct net *net,
-				    const struct xt_table *table,
-				    const struct ipt_replace *repl)
+/* Just like ipt_register_table() but no hook in registered. */
+struct xt_table *__ipt_register_table(struct net *net,
+				      const struct xt_table *table,
+				      const struct ipt_replace *repl)
 {
 	int ret;
 	struct xt_table_info *newinfo;
@@ -2093,8 +2094,38 @@ out_free:
 out:
 	return ERR_PTR(ret);
 }
+EXPORT_SYMBOL_GPL(__ipt_register_table);
 
-void ipt_unregister_table(struct net *net, struct xt_table *table)
+struct xt_table *ipt_register_table(struct net *net,
+				    const struct xt_table *table,
+				    const struct ipt_replace *repl,
+				    nf_hookfn *hookfn)
+{
+	struct xt_table *new_table;
+	struct nf_hook_ops *ops;
+	int ret;
+
+	new_table = __ipt_register_table(net, table, repl);
+	if (IS_ERR(new_table)) {
+		ret = PTR_ERR(new_table);
+		goto out;
+	}
+
+	ops = xt_hook_link(net, table, hookfn);
+	if (IS_ERR(ops)) {
+		ret = PTR_ERR(ops);
+		goto out_free;
+	}
+
+	return new_table;
+out_free:
+	__ipt_unregister_table(net, new_table);
+out:
+	return ERR_PTR(ret);
+}
+
+/* Just like ipt_unregister_table() but no hook in unregistered. */
+void __ipt_unregister_table(struct net *net, struct xt_table *table)
 {
 	struct xt_table_info *private;
 	void *loc_cpu_entry;
@@ -2111,6 +2142,13 @@ void ipt_unregister_table(struct net *net, struct xt_table *table)
 		module_put(table_owner);
 	xt_free_table_info(private);
 }
+EXPORT_SYMBOL_GPL(__ipt_unregister_table);
+
+void ipt_unregister_table(struct net *net, struct xt_table *table)
+{
+	xt_hook_unlink(table, table->ops);
+	__ipt_unregister_table(net, table);
+}
 
 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
 static inline bool
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index f0faa27..4cddbd7 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -48,8 +48,6 @@ iptable_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
 	return ipt_do_table(skb, ops->hooknum, state, net->ipv4.iptable_filter);
 }
 
-static struct nf_hook_ops *filter_ops __read_mostly;
-
 /* Default to forward because I got too much mail already. */
 static bool forward = true;
 module_param(forward, bool, 0000);
@@ -66,7 +64,8 @@ static int __net_init iptable_filter_net_init(struct net *net)
 		forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
 
 	net->ipv4.iptable_filter =
-		ipt_register_table(net, &packet_filter, repl);
+		ipt_register_table(net, &packet_filter, repl,
+				   iptable_filter_hook);
 	kfree(repl);
 	return PTR_ERR_OR_ZERO(net->ipv4.iptable_filter);
 }
@@ -83,26 +82,11 @@ static struct pernet_operations iptable_filter_net_ops = {
 
 static int __init iptable_filter_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&iptable_filter_net_ops);
-	if (ret < 0)
-		return ret;
-
-	/* Register hooks */
-	filter_ops = xt_hook_link(&init_net, &packet_filter,
-				  iptable_filter_hook);
-	if (IS_ERR(filter_ops)) {
-		ret = PTR_ERR(filter_ops);
-		unregister_pernet_subsys(&iptable_filter_net_ops);
-	}
-
-	return ret;
+	return register_pernet_subsys(&iptable_filter_net_ops);
 }
 
 static void __exit iptable_filter_fini(void)
 {
-	xt_hook_unlink(&packet_filter, filter_ops);
 	unregister_pernet_subsys(&iptable_filter_net_ops);
 }
 
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index bd294b4..f97a86b 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -94,8 +94,6 @@ iptable_mangle_hook(const struct nf_hook_ops *ops,
 			    dev_net(state->in)->ipv4.iptable_mangle);
 }
 
-static struct nf_hook_ops *mangle_ops __read_mostly;
-
 static int __net_init iptable_mangle_net_init(struct net *net)
 {
 	struct ipt_replace *repl;
@@ -104,7 +102,8 @@ static int __net_init iptable_mangle_net_init(struct net *net)
 	if (repl == NULL)
 		return -ENOMEM;
 	net->ipv4.iptable_mangle =
-		ipt_register_table(net, &packet_mangler, repl);
+		ipt_register_table(net, &packet_mangler, repl,
+				   iptable_mangle_hook);
 	kfree(repl);
 	return PTR_ERR_OR_ZERO(net->ipv4.iptable_mangle);
 }
@@ -121,26 +120,11 @@ static struct pernet_operations iptable_mangle_net_ops = {
 
 static int __init iptable_mangle_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&iptable_mangle_net_ops);
-	if (ret < 0)
-		return ret;
-
-	/* Register hooks */
-	mangle_ops = xt_hook_link(&init_net, &packet_mangler,
-				  iptable_mangle_hook);
-	if (IS_ERR(mangle_ops)) {
-		ret = PTR_ERR(mangle_ops);
-		unregister_pernet_subsys(&iptable_mangle_net_ops);
-	}
-
-	return ret;
+	return register_pernet_subsys(&iptable_mangle_net_ops);
 }
 
 static void __exit iptable_mangle_fini(void)
 {
-	xt_hook_unlink(&packet_mangler, mangle_ops);
 	unregister_pernet_subsys(&iptable_mangle_net_ops);
 }
 
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index 5ef83d3..0bb164e 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -104,18 +104,49 @@ static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
 static int __net_init iptable_nat_net_init(struct net *net)
 {
 	struct ipt_replace *repl;
+	int err;
 
 	repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
 	if (repl == NULL)
 		return -ENOMEM;
-	net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl);
+
+	net->ipv4.nat_table = __ipt_register_table(net, &nf_nat_ipv4_table,
+						   repl);
+	if (IS_ERR(net->ipv4.nat_table)) {
+		err = PTR_ERR(net->ipv4.nat_table);
+		goto err1;
+	}
 	kfree(repl);
-	return PTR_ERR_OR_ZERO(net->ipv4.nat_table);
+
+	net->ipv4.nat_table->ops = kmemdup(nf_nat_ipv4_ops,
+					   sizeof(nf_nat_ipv4_ops), GFP_KERNEL);
+	if (net->ipv4.nat_table->ops == NULL) {
+		err = -ENOMEM;
+		goto err2;
+	}
+
+	err = nf_register_hooks(net, net->ipv4.nat_table->ops,
+				ARRAY_SIZE(nf_nat_ipv4_ops));
+	if (err < 0)
+		goto err3;
+
+	return 0;
+err3:
+	kfree(net->ipv4.nat_table->ops);
+err2:
+	__ipt_unregister_table(net, net->ipv4.nat_table);
+err1:
+	kfree(repl);
+
+	return err;
 }
 
 static void __net_exit iptable_nat_net_exit(struct net *net)
 {
-	ipt_unregister_table(net, net->ipv4.nat_table);
+	nf_unregister_hooks(net->ipv4.nat_table->ops,
+			    ARRAY_SIZE(nf_nat_ipv4_ops));
+	kfree(net->ipv4.nat_table->ops);
+	__ipt_unregister_table(net, net->ipv4.nat_table);
 }
 
 static struct pernet_operations iptable_nat_net_ops = {
@@ -125,27 +156,11 @@ static struct pernet_operations iptable_nat_net_ops = {
 
 static int __init iptable_nat_init(void)
 {
-	int err;
-
-	err = register_pernet_subsys(&iptable_nat_net_ops);
-	if (err < 0)
-		goto err1;
-
-	err = nf_register_hooks(&init_net, nf_nat_ipv4_ops,
-				ARRAY_SIZE(nf_nat_ipv4_ops));
-	if (err < 0)
-		goto err2;
-	return 0;
-
-err2:
-	unregister_pernet_subsys(&iptable_nat_net_ops);
-err1:
-	return err;
+	return register_pernet_subsys(&iptable_nat_net_ops);
 }
 
 static void __exit iptable_nat_exit(void)
 {
-	nf_unregister_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
 	unregister_pernet_subsys(&iptable_nat_net_ops);
 }
 
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 2541383..908f34c 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -35,8 +35,6 @@ iptable_raw_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
 	return ipt_do_table(skb, ops->hooknum, state, net->ipv4.iptable_raw);
 }
 
-static struct nf_hook_ops *rawtable_ops __read_mostly;
-
 static int __net_init iptable_raw_net_init(struct net *net)
 {
 	struct ipt_replace *repl;
@@ -45,7 +43,7 @@ static int __net_init iptable_raw_net_init(struct net *net)
 	if (repl == NULL)
 		return -ENOMEM;
 	net->ipv4.iptable_raw =
-		ipt_register_table(net, &packet_raw, repl);
+		ipt_register_table(net, &packet_raw, repl, iptable_raw_hook);
 	kfree(repl);
 	return PTR_ERR_OR_ZERO(net->ipv4.iptable_raw);
 }
@@ -62,25 +60,11 @@ static struct pernet_operations iptable_raw_net_ops = {
 
 static int __init iptable_raw_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&iptable_raw_net_ops);
-	if (ret < 0)
-		return ret;
-
-	/* Register hooks */
-	rawtable_ops = xt_hook_link(&init_net, &packet_raw, iptable_raw_hook);
-	if (IS_ERR(rawtable_ops)) {
-		ret = PTR_ERR(rawtable_ops);
-		unregister_pernet_subsys(&iptable_raw_net_ops);
-	}
-
-	return ret;
+	return register_pernet_subsys(&iptable_raw_net_ops);
 }
 
 static void __exit iptable_raw_fini(void)
 {
-	xt_hook_unlink(&packet_raw, rawtable_ops);
 	unregister_pernet_subsys(&iptable_raw_net_ops);
 }
 
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
index 0a0ddc7..d4c8729 100644
--- a/net/ipv4/netfilter/iptable_security.c
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -53,8 +53,6 @@ iptable_security_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
 			    net->ipv4.iptable_security);
 }
 
-static struct nf_hook_ops *sectbl_ops __read_mostly;
-
 static int __net_init iptable_security_net_init(struct net *net)
 {
 	struct ipt_replace *repl;
@@ -63,7 +61,8 @@ static int __net_init iptable_security_net_init(struct net *net)
 	if (repl == NULL)
 		return -ENOMEM;
 	net->ipv4.iptable_security =
-		ipt_register_table(net, &security_table, repl);
+		ipt_register_table(net, &security_table, repl,
+				   iptable_security_hook);
 	kfree(repl);
 	return PTR_ERR_OR_ZERO(net->ipv4.iptable_security);
 }
@@ -80,29 +79,11 @@ static struct pernet_operations iptable_security_net_ops = {
 
 static int __init iptable_security_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&iptable_security_net_ops);
-        if (ret < 0)
-		return ret;
-
-	sectbl_ops = xt_hook_link(&init_net, &security_table,
-				  iptable_security_hook);
-	if (IS_ERR(sectbl_ops)) {
-		ret = PTR_ERR(sectbl_ops);
-		goto cleanup_table;
-	}
-
-	return ret;
-
-cleanup_table:
-	unregister_pernet_subsys(&iptable_security_net_ops);
-	return ret;
+	return register_pernet_subsys(&iptable_security_net_ops);
 }
 
 static void __exit iptable_security_fini(void)
 {
-	xt_hook_unlink(&security_table, sectbl_ops);
 	unregister_pernet_subsys(&iptable_security_net_ops);
 }
 
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 80a7f0d..3cbc37d 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -2067,7 +2067,8 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 	return ret;
 }
 
-struct xt_table *ip6t_register_table(struct net *net,
+/* Just like ip6t_register_table() but no hook is registered. */
+struct xt_table *__ip6t_register_table(struct net *net,
 				     const struct xt_table *table,
 				     const struct ip6t_replace *repl)
 {
@@ -2102,8 +2103,38 @@ out_free:
 out:
 	return ERR_PTR(ret);
 }
+EXPORT_SYMBOL_GPL(__ip6t_register_table);
 
-void ip6t_unregister_table(struct net *net, struct xt_table *table)
+struct xt_table *ip6t_register_table(struct net *net,
+				     const struct xt_table *table,
+				     const struct ip6t_replace *repl,
+				     nf_hookfn *hookfn)
+{
+	struct xt_table *new_table;
+	struct nf_hook_ops *ops;
+	int err;
+
+	new_table = __ip6t_register_table(net, table, repl);
+	if (IS_ERR(new_table)) {
+		err = PTR_ERR(new_table);
+		goto err1;
+	}
+
+	ops = xt_hook_link(net, table, hookfn);
+	if (IS_ERR(ops)) {
+		err = PTR_ERR(ops);
+		goto err2;
+	}
+
+	return 0;
+err2:
+	__ip6t_unregister_table(net, new_table);
+err1:
+	return ERR_PTR(err);
+}
+
+/* Just like ip6t_unregister_table() but no hook is unregistered. */
+void __ip6t_unregister_table(struct net *net, struct xt_table *table)
 {
 	struct xt_table_info *private;
 	void *loc_cpu_entry;
@@ -2120,6 +2151,13 @@ void ip6t_unregister_table(struct net *net, struct xt_table *table)
 		module_put(table_owner);
 	xt_free_table_info(private);
 }
+EXPORT_SYMBOL_GPL(__ip6t_unregister_table);
+
+void ip6t_unregister_table(struct net *net, struct xt_table *table)
+{
+	__ip6t_unregister_table(net, table);
+	xt_hook_unlink(table, table->ops);
+}
 
 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
 static inline bool
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index fe0bf52..77d237b 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -40,8 +40,6 @@ ip6table_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
 	return ip6t_do_table(skb, ops->hooknum, state, net->ipv6.ip6table_filter);
 }
 
-static struct nf_hook_ops *filter_ops __read_mostly;
-
 /* Default to forward because I got too much mail already. */
 static bool forward = true;
 module_param(forward, bool, 0000);
@@ -58,7 +56,8 @@ static int __net_init ip6table_filter_net_init(struct net *net)
 		forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
 
 	net->ipv6.ip6table_filter =
-		ip6t_register_table(net, &packet_filter, repl);
+		ip6t_register_table(net, &packet_filter, repl,
+				    ip6table_filter_hook);
 	kfree(repl);
 	return PTR_ERR_OR_ZERO(net->ipv6.ip6table_filter);
 }
@@ -75,30 +74,11 @@ static struct pernet_operations ip6table_filter_net_ops = {
 
 static int __init ip6table_filter_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&ip6table_filter_net_ops);
-	if (ret < 0)
-		return ret;
-
-	/* Register hooks */
-	filter_ops = xt_hook_link(&init_net, &packet_filter,
-				  ip6table_filter_hook);
-	if (IS_ERR(filter_ops)) {
-		ret = PTR_ERR(filter_ops);
-		goto cleanup_table;
-	}
-
-	return ret;
-
- cleanup_table:
-	unregister_pernet_subsys(&ip6table_filter_net_ops);
-	return ret;
+	return register_pernet_subsys(&ip6table_filter_net_ops);
 }
 
 static void __exit ip6table_filter_fini(void)
 {
-	xt_hook_unlink(&packet_filter, filter_ops);
 	unregister_pernet_subsys(&ip6table_filter_net_ops);
 }
 
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 50fea9e..f2d7355 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -89,7 +89,6 @@ ip6table_mangle_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
 			     dev_net(state->in)->ipv6.ip6table_mangle);
 }
 
-static struct nf_hook_ops *mangle_ops __read_mostly;
 static int __net_init ip6table_mangle_net_init(struct net *net)
 {
 	struct ip6t_replace *repl;
@@ -98,7 +97,8 @@ static int __net_init ip6table_mangle_net_init(struct net *net)
 	if (repl == NULL)
 		return -ENOMEM;
 	net->ipv6.ip6table_mangle =
-		ip6t_register_table(net, &packet_mangler, repl);
+		ip6t_register_table(net, &packet_mangler, repl,
+				    ip6table_mangle_hook);
 	kfree(repl);
 	return PTR_ERR_OR_ZERO(net->ipv6.ip6table_mangle);
 }
@@ -115,30 +115,11 @@ static struct pernet_operations ip6table_mangle_net_ops = {
 
 static int __init ip6table_mangle_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&ip6table_mangle_net_ops);
-	if (ret < 0)
-		return ret;
-
-	/* Register hooks */
-	mangle_ops = xt_hook_link(&init_net, &packet_mangler,
-				  ip6table_mangle_hook);
-	if (IS_ERR(mangle_ops)) {
-		ret = PTR_ERR(mangle_ops);
-		goto cleanup_table;
-	}
-
-	return ret;
-
- cleanup_table:
-	unregister_pernet_subsys(&ip6table_mangle_net_ops);
-	return ret;
+	return register_pernet_subsys(&ip6table_mangle_net_ops);
 }
 
 static void __exit ip6table_mangle_fini(void)
 {
-	xt_hook_unlink(&packet_mangler, mangle_ops);
 	unregister_pernet_subsys(&ip6table_mangle_net_ops);
 }
 
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index ecb0511..44e755a 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -106,18 +106,49 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = {
 static int __net_init ip6table_nat_net_init(struct net *net)
 {
 	struct ip6t_replace *repl;
+	int err;
 
 	repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
 	if (repl == NULL)
 		return -ENOMEM;
-	net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl);
+
+	net->ipv6.ip6table_nat =
+		__ip6t_register_table(net, &nf_nat_ipv6_table, repl);
+	if (IS_ERR(net->ipv6.ip6table_nat)) {
+		err = PTR_ERR(net->ipv6.ip6table_nat);
+		goto err1;
+	}
 	kfree(repl);
-	return PTR_ERR_OR_ZERO(net->ipv6.ip6table_nat);
+
+	net->ipv6.ip6table_nat->ops =
+		kmemdup(nf_nat_ipv6_ops, sizeof(nf_nat_ipv6_ops), GFP_KERNEL);
+	if (net->ipv6.ip6table_nat->ops == NULL) {
+		err = -ENOMEM;
+		goto err2;
+	}
+
+	err = nf_register_hooks(net, net->ipv6.ip6table_nat->ops,
+				ARRAY_SIZE(nf_nat_ipv6_ops));
+	if (err < 0)
+		goto err3;
+
+	return 0;
+err3:
+	kfree(net->ipv6.ip6table_nat->ops);
+err2:
+	__ip6t_unregister_table(net, net->ipv6.ip6table_nat);
+err1:
+	kfree(repl);
+
+	return err;
 }
 
 static void __net_exit ip6table_nat_net_exit(struct net *net)
 {
-	ip6t_unregister_table(net, net->ipv6.ip6table_nat);
+	nf_unregister_hooks(net->ipv6.ip6table_nat->ops,
+			    ARRAY_SIZE(nf_nat_ipv6_ops));
+	kfree(net->ipv6.ip6table_nat->ops);
+	__ip6t_unregister_table(net, net->ipv6.ip6table_nat);
 }
 
 static struct pernet_operations ip6table_nat_net_ops = {
@@ -127,27 +158,11 @@ static struct pernet_operations ip6table_nat_net_ops = {
 
 static int __init ip6table_nat_init(void)
 {
-	int err;
-
-	err = register_pernet_subsys(&ip6table_nat_net_ops);
-	if (err < 0)
-		goto err1;
-
-	err = nf_register_hooks(&init_net, nf_nat_ipv6_ops,
-				ARRAY_SIZE(nf_nat_ipv6_ops));
-	if (err < 0)
-		goto err2;
-	return 0;
-
-err2:
-	unregister_pernet_subsys(&ip6table_nat_net_ops);
-err1:
-	return err;
+	return register_pernet_subsys(&ip6table_nat_net_ops);
 }
 
 static void __exit ip6table_nat_exit(void)
 {
-	nf_unregister_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops));
 	unregister_pernet_subsys(&ip6table_nat_net_ops);
 }
 
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index 141604f..4c7e496 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -27,8 +27,6 @@ ip6table_raw_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
 	return ip6t_do_table(skb, ops->hooknum, state, net->ipv6.ip6table_raw);
 }
 
-static struct nf_hook_ops *rawtable_ops __read_mostly;
-
 static int __net_init ip6table_raw_net_init(struct net *net)
 {
 	struct ip6t_replace *repl;
@@ -37,7 +35,7 @@ static int __net_init ip6table_raw_net_init(struct net *net)
 	if (repl == NULL)
 		return -ENOMEM;
 	net->ipv6.ip6table_raw =
-		ip6t_register_table(net, &packet_raw, repl);
+		ip6t_register_table(net, &packet_raw, repl, ip6table_raw_hook);
 	kfree(repl);
 	return PTR_ERR_OR_ZERO(net->ipv6.ip6table_raw);
 }
@@ -54,29 +52,11 @@ static struct pernet_operations ip6table_raw_net_ops = {
 
 static int __init ip6table_raw_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&ip6table_raw_net_ops);
-	if (ret < 0)
-		return ret;
-
-	/* Register hooks */
-	rawtable_ops = xt_hook_link(&init_net, &packet_raw, ip6table_raw_hook);
-	if (IS_ERR(rawtable_ops)) {
-		ret = PTR_ERR(rawtable_ops);
-		goto cleanup_table;
-	}
-
-	return ret;
-
- cleanup_table:
-	unregister_pernet_subsys(&ip6table_raw_net_ops);
-	return ret;
+	return register_pernet_subsys(&ip6table_raw_net_ops);
 }
 
 static void __exit ip6table_raw_fini(void)
 {
-	xt_hook_unlink(&packet_raw, rawtable_ops);
 	unregister_pernet_subsys(&ip6table_raw_net_ops);
 }
 
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
index 8d252f8..8a224ca 100644
--- a/net/ipv6/netfilter/ip6table_security.c
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -45,8 +45,6 @@ ip6table_security_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
 			     net->ipv6.ip6table_security);
 }
 
-static struct nf_hook_ops *sectbl_ops __read_mostly;
-
 static int __net_init ip6table_security_net_init(struct net *net)
 {
 	struct ip6t_replace *repl;
@@ -55,7 +53,8 @@ static int __net_init ip6table_security_net_init(struct net *net)
 	if (repl == NULL)
 		return -ENOMEM;
 	net->ipv6.ip6table_security =
-		ip6t_register_table(net, &security_table, repl);
+		ip6t_register_table(net, &security_table, repl,
+				    ip6table_security_hook);
 	kfree(repl);
 	return PTR_ERR_OR_ZERO(net->ipv6.ip6table_security);
 }
@@ -72,29 +71,11 @@ static struct pernet_operations ip6table_security_net_ops = {
 
 static int __init ip6table_security_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&ip6table_security_net_ops);
-	if (ret < 0)
-		return ret;
-
-	sectbl_ops = xt_hook_link(&init_net, &security_table,
-				  ip6table_security_hook);
-	if (IS_ERR(sectbl_ops)) {
-		ret = PTR_ERR(sectbl_ops);
-		goto cleanup_table;
-	}
-
-	return ret;
-
-cleanup_table:
-	unregister_pernet_subsys(&ip6table_security_net_ops);
-	return ret;
+	return register_pernet_subsys(&ip6table_security_net_ops);
 }
 
 static void __exit ip6table_security_fini(void)
 {
-	xt_hook_unlink(&security_table, sectbl_ops);
 	unregister_pernet_subsys(&ip6table_security_net_ops);
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 08/15] netfilter: nf_conntrack: adapt IPv4 and IPv6 trackers to pernet hooks
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (6 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 07/15] netfilter: x_tables: adapt tables to " Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 09/15] netfilter: synproxy: adapt IPv4 and IPv6 targets " Pablo Neira Ayuso
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

Since pernet hooks, we need to register the hook for each netnamespace space.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netns/conntrack.h                  |    4 +++
 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c |   36 +++++++++++++------
 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |   45 ++++++++++++++++--------
 3 files changed, 59 insertions(+), 26 deletions(-)

diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index 29d6a94..b175886 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -104,6 +104,10 @@ struct netns_ct {
 	struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb;
 	struct nf_exp_event_notifier __rcu *nf_expect_event_cb;
 	struct nf_ip_net	nf_ct_proto;
+
+	struct nf_hook_ops	*ipv4_conntrack_ops;
+	struct nf_hook_ops	*ipv6_conntrack_ops;
+
 #if defined(CONFIG_NF_CONNTRACK_LABELS)
 	unsigned int		labels_used;
 	u8			label_words;
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 2384975..ba96348 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -424,7 +424,28 @@ static int ipv4_net_init(struct net *net)
 		pr_err("nf_conntrack_ipv4: pernet registration failed\n");
 		goto out_ipv4;
 	}
+
+	net->ct.ipv4_conntrack_ops =
+		kmemdup(&ipv4_conntrack_ops, sizeof(ipv4_conntrack_ops),
+			GFP_KERNEL);
+	if (net->ct.ipv4_conntrack_ops == NULL) {
+		ret = -ENOMEM;
+		goto out_kmemdup;
+	}
+
+	ret = nf_register_hooks(net, net->ct.ipv4_conntrack_ops,
+				ARRAY_SIZE(ipv4_conntrack_ops));
+	if (ret < 0) {
+		pr_err("nf_conntrack_ipv4: can't register hooks.\n");
+		goto out_hook;
+	}
+
 	return 0;
+
+out_hook:
+	kfree(net->ct.ipv4_conntrack_ops);
+out_kmemdup:
+	nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv4);
 out_ipv4:
 	nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmp);
 out_icmp:
@@ -437,6 +458,9 @@ out_tcp:
 
 static void ipv4_net_exit(struct net *net)
 {
+	nf_unregister_hooks(net->ct.ipv4_conntrack_ops,
+			    ARRAY_SIZE(ipv4_conntrack_ops));
+	kfree(net->ct.ipv4_conntrack_ops);
 	nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv4);
 	nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmp);
 	nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp4);
@@ -467,17 +491,10 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
 		goto cleanup_sockopt;
 	}
 
-	ret = nf_register_hooks(&init_net, ipv4_conntrack_ops,
-				ARRAY_SIZE(ipv4_conntrack_ops));
-	if (ret < 0) {
-		pr_err("nf_conntrack_ipv4: can't register hooks.\n");
-		goto cleanup_pernet;
-	}
-
 	ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp4);
 	if (ret < 0) {
 		pr_err("nf_conntrack_ipv4: can't register tcp4 proto.\n");
-		goto cleanup_hooks;
+		goto cleanup_pernet;
 	}
 
 	ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp4);
@@ -514,8 +531,6 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
 	nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp4);
  cleanup_tcp4:
 	nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp4);
- cleanup_hooks:
-	nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
  cleanup_pernet:
 	unregister_pernet_subsys(&ipv4_net_ops);
  cleanup_sockopt:
@@ -533,7 +548,6 @@ static void __exit nf_conntrack_l3proto_ipv4_fini(void)
 	nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmp);
 	nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp4);
 	nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp4);
-	nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
 	unregister_pernet_subsys(&ipv4_net_ops);
 	nf_unregister_sockopt(&so_getorigdst);
 }
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 8bcf625..47a5862 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -366,19 +366,43 @@ static int ipv6_net_init(struct net *net)
 		pr_err("nf_conntrack_ipv6: pernet registration failed.\n");
 		goto cleanup_icmpv6;
 	}
+
+	net->ct.ipv6_conntrack_ops =
+		kmemdup(&ipv6_conntrack_ops, sizeof(ipv6_conntrack_ops),
+			GFP_KERNEL);
+	if (net->ct.ipv6_conntrack_ops == NULL) {
+		ret = -ENOMEM;
+		goto cleanup_ipv6;
+	}
+
+	ret = nf_register_hooks(net, net->ct.ipv6_conntrack_ops,
+				ARRAY_SIZE(ipv6_conntrack_ops));
+	if (ret < 0) {
+		pr_err("nf_conntrack_ipv6: can't register pre-routing defrag hook.\n");
+		goto cleanup_kmemdup;
+	}
+
 	return 0;
- cleanup_icmpv6:
+
+cleanup_kmemdup:
+	kfree(net->ct.ipv6_conntrack_ops);
+cleanup_ipv6:
+	nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv6);
+cleanup_icmpv6:
 	nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6);
- cleanup_udp6:
+cleanup_udp6:
 	nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6);
- cleanup_tcp6:
+cleanup_tcp6:
 	nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6);
- out:
+out:
 	return ret;
 }
 
 static void ipv6_net_exit(struct net *net)
 {
+	nf_unregister_hooks(net->ct.ipv6_conntrack_ops,
+			    ARRAY_SIZE(ipv6_conntrack_ops));
+	kfree(net->ct.ipv6_conntrack_ops);
 	nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv6);
 	nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6);
 	nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6);
@@ -407,18 +431,10 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
 	if (ret < 0)
 		goto cleanup_sockopt;
 
-	ret = nf_register_hooks(&init_net, ipv6_conntrack_ops,
-				ARRAY_SIZE(ipv6_conntrack_ops));
-	if (ret < 0) {
-		pr_err("nf_conntrack_ipv6: can't register pre-routing defrag "
-		       "hook.\n");
-		goto cleanup_pernet;
-	}
-
 	ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp6);
 	if (ret < 0) {
 		pr_err("nf_conntrack_ipv6: can't register tcp6 proto.\n");
-		goto cleanup_hooks;
+		goto cleanup_pernet;
 	}
 
 	ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp6);
@@ -438,6 +454,7 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
 		pr_err("nf_conntrack_ipv6: can't register ipv6 proto.\n");
 		goto cleanup_icmpv6;
 	}
+
 	return ret;
 
  cleanup_icmpv6:
@@ -446,8 +463,6 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
 	nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6);
  cleanup_tcp6:
 	nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
- cleanup_hooks:
-	nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
  cleanup_pernet:
 	unregister_pernet_subsys(&ipv6_net_ops);
  cleanup_sockopt:
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 09/15] netfilter: synproxy: adapt IPv4 and IPv6 targets to pernet hooks
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (7 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 08/15] netfilter: nf_conntrack: adapt IPv4 and IPv6 trackers " Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 10/15] netfilter: defrag: add pernet hook support Pablo Neira Ayuso
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

Since pernet hooks, we need to register the hook for each netnamespace space.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/ipv4/netfilter/ipt_SYNPROXY.c  |   51 ++++++++++++++++++++++++++++++++---
 net/ipv6/netfilter/ip6t_SYNPROXY.c |   52 +++++++++++++++++++++++++++++++++---
 2 files changed, 95 insertions(+), 8 deletions(-)

diff --git a/net/ipv4/netfilter/ipt_SYNPROXY.c b/net/ipv4/netfilter/ipt_SYNPROXY.c
index a57d3d1..f38276f 100644
--- a/net/ipv4/netfilter/ipt_SYNPROXY.c
+++ b/net/ipv4/netfilter/ipt_SYNPROXY.c
@@ -446,15 +446,58 @@ static struct nf_hook_ops ipv4_synproxy_ops[] __read_mostly = {
 	},
 };
 
-static int __init synproxy_tg4_init(void)
+struct synproxy_tg4_net {
+	struct nf_hook_ops *ipv4_synproxy_ops;
+};
+
+static int synproxy_tg4_net_id __read_mostly;
+
+static int synproxy_tg4_net_init(struct net *net)
 {
+	struct synproxy_tg4_net *sn = net_generic(net, synproxy_tg4_net_id);
 	int err;
 
-	err = nf_register_hooks(&init_net, ipv4_synproxy_ops,
+	sn->ipv4_synproxy_ops =
+		kmemdup(ipv4_synproxy_ops, sizeof(ipv4_synproxy_ops),
+			GFP_KERNEL);
+	if (sn->ipv4_synproxy_ops == NULL)
+		return -ENOMEM;
+
+	err = nf_register_hooks(net, sn->ipv4_synproxy_ops,
 				ARRAY_SIZE(ipv4_synproxy_ops));
 	if (err < 0)
 		goto err1;
 
+err1:
+	kfree(sn->ipv4_synproxy_ops);
+
+	return err;
+}
+
+static void synproxy_tg4_net_exit(struct net *net)
+{
+	struct synproxy_tg4_net *sn = net_generic(net, synproxy_tg4_net_id);
+
+	nf_unregister_hooks(sn->ipv4_synproxy_ops,
+			    ARRAY_SIZE(ipv4_synproxy_ops));
+	kfree(sn->ipv4_synproxy_ops);
+}
+
+static struct pernet_operations synproxy_tg4_net_ops = {
+	.init = synproxy_tg4_net_init,
+	.exit = synproxy_tg4_net_exit,
+	.id = &synproxy_tg4_net_id,
+	.size = sizeof(struct synproxy_tg4_net),
+};
+
+static int __init synproxy_tg4_init(void)
+{
+	int err;
+
+	err = register_pernet_subsys(&synproxy_tg4_net_ops);
+	if (err < 0)
+		goto err1;
+
 	err = xt_register_target(&synproxy_tg4_reg);
 	if (err < 0)
 		goto err2;
@@ -462,7 +505,7 @@ static int __init synproxy_tg4_init(void)
 	return 0;
 
 err2:
-	nf_unregister_hooks(ipv4_synproxy_ops, ARRAY_SIZE(ipv4_synproxy_ops));
+	unregister_pernet_subsys(&synproxy_tg4_net_ops);
 err1:
 	return err;
 }
@@ -470,7 +513,7 @@ err1:
 static void __exit synproxy_tg4_exit(void)
 {
 	xt_unregister_target(&synproxy_tg4_reg);
-	nf_unregister_hooks(ipv4_synproxy_ops, ARRAY_SIZE(ipv4_synproxy_ops));
+	unregister_pernet_subsys(&synproxy_tg4_net_ops);
 }
 
 module_init(synproxy_tg4_init);
diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c
index ed5d4a6..57fbd44 100644
--- a/net/ipv6/netfilter/ip6t_SYNPROXY.c
+++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c
@@ -469,15 +469,59 @@ static struct nf_hook_ops ipv6_synproxy_ops[] __read_mostly = {
 	},
 };
 
-static int __init synproxy_tg6_init(void)
+struct synproxy_tg6_net {
+	struct nf_hook_ops *ipv6_synproxy_ops;
+};
+
+static int synproxy_tg6_net_id __read_mostly;
+
+static int synproxy_tg6_net_init(struct net *net)
 {
+	struct synproxy_tg6_net *sn = net_generic(net, synproxy_tg6_net_id);
 	int err;
 
-	err = nf_register_hooks(&init_net, ipv6_synproxy_ops,
+	sn->ipv6_synproxy_ops =
+		kmemdup(ipv6_synproxy_ops, sizeof(ipv6_synproxy_ops),
+			GFP_KERNEL);
+	if (sn->ipv6_synproxy_ops == NULL)
+		return -ENOMEM;
+
+	err = nf_register_hooks(net, sn->ipv6_synproxy_ops,
 				ARRAY_SIZE(ipv6_synproxy_ops));
 	if (err < 0)
 		goto err1;
 
+	return 0;
+err1:
+	kfree(sn->ipv6_synproxy_ops);
+
+	return err;
+}
+
+static void synproxy_tg6_net_exit(struct net *net)
+{
+	struct synproxy_tg6_net *sn = net_generic(net, synproxy_tg6_net_id);
+
+	nf_unregister_hooks(sn->ipv6_synproxy_ops,
+			    ARRAY_SIZE(ipv6_synproxy_ops));
+	kfree(sn->ipv6_synproxy_ops);
+}
+
+static struct pernet_operations synproxy_tg6_net_ops = {
+	.init = synproxy_tg6_net_init,
+	.exit = synproxy_tg6_net_exit,
+	.id = &synproxy_tg6_net_id,
+	.size = sizeof(struct synproxy_tg6_net),
+};
+
+static int __init synproxy_tg6_init(void)
+{
+	int err;
+
+	err = register_pernet_subsys(&synproxy_tg6_net_ops);
+	if (err < 0)
+		goto err1;
+
 	err = xt_register_target(&synproxy_tg6_reg);
 	if (err < 0)
 		goto err2;
@@ -485,7 +529,7 @@ static int __init synproxy_tg6_init(void)
 	return 0;
 
 err2:
-	nf_unregister_hooks(ipv6_synproxy_ops, ARRAY_SIZE(ipv6_synproxy_ops));
+	unregister_pernet_subsys(&synproxy_tg6_net_ops);
 err1:
 	return err;
 }
@@ -493,7 +537,7 @@ err1:
 static void __exit synproxy_tg6_exit(void)
 {
 	xt_unregister_target(&synproxy_tg6_reg);
-	nf_unregister_hooks(ipv6_synproxy_ops, ARRAY_SIZE(ipv6_synproxy_ops));
+	unregister_pernet_subsys(&synproxy_tg6_net_ops);
 }
 
 module_init(synproxy_tg6_init);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 10/15] netfilter: defrag: add pernet hook support
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (8 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 09/15] netfilter: synproxy: adapt IPv4 and IPv6 targets " Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 11/15] ipvs: adapt it to pernet hooks Pablo Neira Ayuso
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

Since pernet hooks, we need to register the hook for each netnamespace space.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netns/netfilter.h             |    6 +++++
 net/ipv4/netfilter/nf_defrag_ipv4.c       |   38 +++++++++++++++++++++++---
 net/ipv6/netfilter/nf_defrag_ipv6_hooks.c |   41 ++++++++++++++++++++++++++---
 3 files changed, 78 insertions(+), 7 deletions(-)

diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h
index 38aa498..f2b513d 100644
--- a/include/net/netns/netfilter.h
+++ b/include/net/netns/netfilter.h
@@ -15,5 +15,11 @@ struct netns_nf {
 	struct ctl_table_header *nf_log_dir_header;
 #endif
 	struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
+#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
+	struct nf_hook_ops *ipv4_defrag_ops;
+#endif
+#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
+	struct nf_hook_ops *ipv6_defrag_ops;
+#endif
 };
 #endif
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index ad74929..084a995 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -108,15 +108,47 @@ static struct nf_hook_ops ipv4_defrag_ops[] = {
 	},
 };
 
+static int ipv4_defrag_net_init(struct net *net)
+{
+	int err;
+
+	net->nf.ipv4_defrag_ops =
+		kmemdup(ipv4_defrag_ops, sizeof(ipv4_defrag_ops), GFP_KERNEL);
+	if (net->nf.ipv4_defrag_ops == NULL)
+		return -ENOMEM;
+
+	err = nf_register_hooks(net, net->nf.ipv4_defrag_ops,
+				ARRAY_SIZE(ipv4_defrag_ops));
+	if (err < 0)
+		goto err1;
+
+	return 0;
+err1:
+	kfree(net->nf.ipv4_defrag_ops);
+
+	return err;
+}
+
+static void ipv4_defrag_net_exit(struct net *net)
+{
+	nf_unregister_hooks(net->nf.ipv4_defrag_ops,
+			    ARRAY_SIZE(ipv4_defrag_ops));
+	kfree(net->nf.ipv4_defrag_ops);
+}
+
+static struct pernet_operations ipv4_defrag_net_ops = {
+	.init = ipv4_defrag_net_init,
+	.exit = ipv4_defrag_net_exit,
+};
+
 static int __init nf_defrag_init(void)
 {
-	return nf_register_hooks(&init_net, ipv4_defrag_ops,
-				 ARRAY_SIZE(ipv4_defrag_ops));
+	return register_pernet_subsys(&ipv4_defrag_net_ops);
 }
 
 static void __exit nf_defrag_fini(void)
 {
-	nf_unregister_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops));
+	unregister_pernet_subsys(&ipv4_defrag_net_ops);
 }
 
 void nf_defrag_ipv4_enable(void)
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
index 7bc330f..2745f9c 100644
--- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -99,6 +99,39 @@ static struct nf_hook_ops ipv6_defrag_ops[] = {
 	},
 };
 
+static int ipv6_defrag_net_init(struct net *net)
+{
+	int err;
+
+	net->nf.ipv6_defrag_ops =
+		kmemdup(ipv6_defrag_ops, sizeof(ipv6_defrag_ops), GFP_KERNEL);
+	if (net->nf.ipv6_defrag_ops == NULL)
+		return -ENOMEM;
+
+	err = nf_register_hooks(net, net->nf.ipv6_defrag_ops,
+				ARRAY_SIZE(ipv6_defrag_ops));
+	if (err < 0)
+		goto err1;
+
+	return 0;
+err1:
+	kfree(net->nf.ipv6_defrag_ops);
+
+	return err;
+}
+
+static void ipv6_defrag_net_exit(struct net *net)
+{
+	nf_unregister_hooks(net->nf.ipv6_defrag_ops,
+			    ARRAY_SIZE(ipv6_defrag_ops));
+	kfree(net->nf.ipv6_defrag_ops);
+}
+
+static struct pernet_operations ipv6_defrag_net_ops = {
+	.init = ipv6_defrag_net_init,
+	.exit = ipv6_defrag_net_exit,
+};
+
 static int __init nf_defrag_init(void)
 {
 	int ret = 0;
@@ -108,10 +141,10 @@ static int __init nf_defrag_init(void)
 		pr_err("nf_defrag_ipv6: can't initialize frag6.\n");
 		return ret;
 	}
-	ret = nf_register_hooks(&init_net, ipv6_defrag_ops,
-				ARRAY_SIZE(ipv6_defrag_ops));
+
+	ret = register_pernet_subsys(&ipv6_defrag_net_ops);
 	if (ret < 0) {
-		pr_err("nf_defrag_ipv6: can't register hooks\n");
+		pr_err("nf_defrag_ipv6: can't register pernet\n");
 		goto cleanup_frag6;
 	}
 	return ret;
@@ -124,7 +157,7 @@ cleanup_frag6:
 
 static void __exit nf_defrag_fini(void)
 {
-	nf_unregister_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops));
+	unregister_pernet_subsys(&ipv6_defrag_net_ops);
 	nf_ct_frag6_cleanup();
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 11/15] ipvs: adapt it to pernet hooks
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (9 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 10/15] netfilter: defrag: add pernet hook support Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 12/15] netfilter: ebtables: adapt the filter and nat table " Pablo Neira Ayuso
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/ip_vs.h             |    3 +++
 net/netfilter/ipvs/ip_vs_core.c |   42 +++++++++++++++++++++++++++++----------
 2 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 4e3731e..406dbe3 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -850,6 +850,9 @@ struct ipvs_master_sync_state {
 struct netns_ipvs {
 	int			gen;		/* Generation */
 	int			enable;		/* enable like nf_hooks do */
+
+	struct nf_hook_ops	*ip_vs_ops;
+
 	/* Hash table: for real service lookups */
 	#define IP_VS_RTAB_BITS 4
 	#define IP_VS_RTAB_SIZE (1 << IP_VS_RTAB_BITS)
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 2751d5a..65cd930 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -2039,9 +2039,39 @@ static void __net_exit __ip_vs_cleanup(struct net *net)
 	net->ipvs = NULL;
 }
 
+static int ip_vs_dev_init(struct net *net)
+{
+	struct netns_ipvs *ipvs_net = net_ipvs(net);
+	int err;
+
+	ipvs_net->ip_vs_ops =
+		kmemdup(ip_vs_ops, sizeof(ip_vs_ops), GFP_KERNEL);
+	if (ipvs_net->ip_vs_ops == NULL) {
+		err = -ENOMEM;
+		goto err1;
+	}
+
+	err = nf_register_hooks(net, ipvs_net->ip_vs_ops,
+				ARRAY_SIZE(ip_vs_ops));
+	if (err < 0) {
+		pr_err("can't register hooks.\n");
+		goto err2;
+	}
+
+	return 0;
+err2:
+	kfree(ipvs_net->ip_vs_ops);
+err1:
+	return err;
+}
+
 static void __net_exit __ip_vs_dev_cleanup(struct net *net)
 {
+	struct netns_ipvs *ipvs_net = net_ipvs(net);
+
 	EnterFunction(2);
+	nf_unregister_hooks(ipvs_net->ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
+	kfree(ipvs_net->ip_vs_ops);
 	net_ipvs(net)->enable = 0;	/* Disable packet reception */
 	smp_wmb();
 	ip_vs_sync_net_cleanup(net);
@@ -2056,6 +2086,7 @@ static struct pernet_operations ipvs_core_ops = {
 };
 
 static struct pernet_operations ipvs_core_dev_ops = {
+	.init = ip_vs_dev_init,
 	.exit = __ip_vs_dev_cleanup,
 };
 
@@ -2088,24 +2119,16 @@ static int __init ip_vs_init(void)
 	if (ret < 0)
 		goto cleanup_sub;
 
-	ret = nf_register_hooks(&init_net, ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
-	if (ret < 0) {
-		pr_err("can't register hooks.\n");
-		goto cleanup_dev;
-	}
-
 	ret = ip_vs_register_nl_ioctl();
 	if (ret < 0) {
 		pr_err("can't register netlink/ioctl.\n");
-		goto cleanup_hooks;
+		goto cleanup_dev;
 	}
 
 	pr_info("ipvs loaded.\n");
 
 	return ret;
 
-cleanup_hooks:
-	nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
 cleanup_dev:
 	unregister_pernet_device(&ipvs_core_dev_ops);
 cleanup_sub:
@@ -2122,7 +2145,6 @@ exit:
 static void __exit ip_vs_cleanup(void)
 {
 	ip_vs_unregister_nl_ioctl();
-	nf_unregister_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
 	unregister_pernet_device(&ipvs_core_dev_ops);
 	unregister_pernet_subsys(&ipvs_core_ops);	/* free ip_vs struct */
 	ip_vs_conn_cleanup();
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 12/15] netfilter: ebtables: adapt the filter and nat table to pernet hooks
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (10 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 11/15] ipvs: adapt it to pernet hooks Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 13/15] netfilter: nf_tables: adapt it " Pablo Neira Ayuso
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

This adapts the filter and nat tables to register the hooks for each
netnamespace.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netns/x_tables.h          |    2 ++
 net/bridge/netfilter/ebtable_filter.c |   42 +++++++++++++++++++++++----------
 net/bridge/netfilter/ebtable_nat.c    |   42 +++++++++++++++++++++++----------
 3 files changed, 62 insertions(+), 24 deletions(-)

diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
index c8a7681..831af42 100644
--- a/include/net/netns/x_tables.h
+++ b/include/net/netns/x_tables.h
@@ -14,7 +14,9 @@ struct netns_xt {
     defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE)
 	struct ebt_table *broute_table;
 	struct ebt_table *frame_filter;
+	struct nf_hook_ops *frame_filter_ops;
 	struct ebt_table *frame_nat;
+	struct nf_hook_ops *frame_nat_ops;
 #endif
 };
 #endif
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index 9a5a798..2ee938c 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -98,12 +98,40 @@ static struct nf_hook_ops ebt_ops_filter[] __read_mostly = {
 
 static int __net_init frame_filter_net_init(struct net *net)
 {
+	int err;
+
 	net->xt.frame_filter = ebt_register_table(net, &frame_filter);
-	return PTR_ERR_OR_ZERO(net->xt.frame_filter);
+	if (IS_ERR(net->xt.frame_filter)) {
+		err = PTR_ERR(net->xt.frame_filter);
+		goto err1;
+	}
+
+	net->xt.frame_filter_ops =
+		kmemdup(ebt_ops_filter, sizeof(ebt_ops_filter), GFP_KERNEL);
+	if (net->xt.frame_filter_ops == NULL) {
+		err = -ENOMEM;
+		goto err2;
+	}
+
+	err = nf_register_hooks(net, net->xt.frame_filter_ops,
+				ARRAY_SIZE(ebt_ops_filter));
+	if (err < 0)
+		goto err3;
+
+	return 0;
+err3:
+	kfree(net->xt.frame_filter_ops);
+err2:
+	ebt_unregister_table(net, net->xt.frame_filter);
+err1:
+	return err;
 }
 
 static void __net_exit frame_filter_net_exit(struct net *net)
 {
+	nf_unregister_hooks(net->xt.frame_filter_ops,
+			    ARRAY_SIZE(ebt_ops_filter));
+	kfree(net->xt.frame_filter_ops);
 	ebt_unregister_table(net, net->xt.frame_filter);
 }
 
@@ -114,21 +142,11 @@ static struct pernet_operations frame_filter_net_ops = {
 
 static int __init ebtable_filter_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&frame_filter_net_ops);
-	if (ret < 0)
-		return ret;
-	ret = nf_register_hooks(&init_net, ebt_ops_filter,
-				ARRAY_SIZE(ebt_ops_filter));
-	if (ret < 0)
-		unregister_pernet_subsys(&frame_filter_net_ops);
-	return ret;
+	return register_pernet_subsys(&frame_filter_net_ops);
 }
 
 static void __exit ebtable_filter_fini(void)
 {
-	nf_unregister_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
 	unregister_pernet_subsys(&frame_filter_net_ops);
 }
 
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index 3d2759d..a787126 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -98,12 +98,40 @@ static struct nf_hook_ops ebt_ops_nat[] __read_mostly = {
 
 static int __net_init frame_nat_net_init(struct net *net)
 {
+	int err;
+
 	net->xt.frame_nat = ebt_register_table(net, &frame_nat);
-	return PTR_ERR_OR_ZERO(net->xt.frame_nat);
+	if (IS_ERR(net->xt.frame_nat)) {
+		err = PTR_ERR(net->xt.frame_nat);
+		goto err1;
+	}
+
+	net->xt.frame_nat_ops =
+		kmemdup(ebt_ops_nat, sizeof(ebt_ops_nat), GFP_KERNEL);
+	if (net->xt.frame_nat_ops == NULL) {
+		err = -ENOMEM;
+		goto err2;
+	}
+
+	err = nf_register_hooks(net, net->xt.frame_nat_ops,
+				ARRAY_SIZE(ebt_ops_nat));
+	if (err < 0)
+		goto err3;
+
+	return 0;
+err3:
+	kfree(net->xt.frame_nat_ops);
+err2:
+	ebt_unregister_table(net, net->xt.frame_nat);
+err1:
+	return err;
 }
 
 static void __net_exit frame_nat_net_exit(struct net *net)
 {
+	nf_unregister_hooks(net->xt.frame_nat_ops,
+			    ARRAY_SIZE(ebt_ops_nat));
+	kfree(net->xt.frame_nat_ops);
 	ebt_unregister_table(net, net->xt.frame_nat);
 }
 
@@ -114,21 +142,11 @@ static struct pernet_operations frame_nat_net_ops = {
 
 static int __init ebtable_nat_init(void)
 {
-	int ret;
-
-	ret = register_pernet_subsys(&frame_nat_net_ops);
-	if (ret < 0)
-		return ret;
-	ret = nf_register_hooks(&init_net, ebt_ops_nat,
-				ARRAY_SIZE(ebt_ops_nat));
-	if (ret < 0)
-		unregister_pernet_subsys(&frame_nat_net_ops);
-	return ret;
+	return register_pernet_subsys(&frame_nat_net_ops);
 }
 
 static void __exit ebtable_nat_fini(void)
 {
-	nf_unregister_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
 	unregister_pernet_subsys(&frame_nat_net_ops);
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 13/15] netfilter: nf_tables: adapt it to pernet hooks
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (11 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 12/15] netfilter: ebtables: adapt the filter and nat table " Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 14/15] security: " Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 15/15] netfilter: bridge: " Pablo Neira Ayuso
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

Since pernet hooks, we need to register the hook for each netnamespace space.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/nf_tables_api.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index a8d4044..48c4844 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -556,7 +556,7 @@ err:
 	return err;
 }
 
-static int nf_tables_table_enable(const struct nft_af_info *afi,
+static int nf_tables_table_enable(const struct nft_ctx *ctx,
 				  struct nft_table *table)
 {
 	struct nft_chain *chain;
@@ -566,8 +566,8 @@ static int nf_tables_table_enable(const struct nft_af_info *afi,
 		if (!(chain->flags & NFT_BASE_CHAIN))
 			continue;
 
-		err = nf_register_hooks(&init_net, nft_base_chain(chain)->ops,
-					afi->nops);
+		err = nf_register_hooks(ctx->net, nft_base_chain(chain)->ops,
+					ctx->afi->nops);
 		if (err < 0)
 			goto err;
 
@@ -582,7 +582,7 @@ err:
 		if (i-- <= 0)
 			break;
 
-		nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
+		nf_unregister_hooks(nft_base_chain(chain)->ops, ctx->afi->nops);
 	}
 	return err;
 }
@@ -630,7 +630,7 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
 		nft_trans_table_enable(trans) = false;
 	} else if (!(flags & NFT_TABLE_F_DORMANT) &&
 		   ctx->table->flags & NFT_TABLE_F_DORMANT) {
-		ret = nf_tables_table_enable(ctx->afi, ctx->table);
+		ret = nf_tables_table_enable(ctx, ctx->table);
 		if (ret >= 0) {
 			ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
 			nft_trans_table_enable(trans) = true;
@@ -1419,7 +1419,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
 
 	if (!(table->flags & NFT_TABLE_F_DORMANT) &&
 	    chain->flags & NFT_BASE_CHAIN) {
-		err = nf_register_hooks(&init_net, nft_base_chain(chain)->ops,
+		err = nf_register_hooks(net, nft_base_chain(chain)->ops,
 					afi->nops);
 		if (err < 0)
 			goto err1;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 14/15] security: adapt it to pernet hooks
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (12 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 13/15] netfilter: nf_tables: adapt it " Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  2015-06-15 15:46 ` [PATCH RFC 15/15] netfilter: bridge: " Pablo Neira Ayuso
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

Since pernet hooks, we need to register the hook for each netnamespace space.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netns/netfilter.h |    3 +++
 security/selinux/hooks.c      |   43 +++++++++++++++++++++++++++++++++++------
 2 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h
index f2b513d..89925e3 100644
--- a/include/net/netns/netfilter.h
+++ b/include/net/netns/netfilter.h
@@ -21,5 +21,8 @@ struct netns_nf {
 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
 	struct nf_hook_ops *ipv6_defrag_ops;
 #endif
+#ifdef CONFIG_SECURITY
+	struct nf_hook_ops *selinux_ops;
+#endif
 };
 #endif
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7246654..c10a5b1 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6147,6 +6147,40 @@ static struct nf_hook_ops selinux_nf_ops[] = {
 #endif	/* IPV6 */
 };
 
+static int selinux_net_init(struct net *net)
+{
+	int err;
+
+	net->nf.selinux_ops =
+		kmemdup(selinux_nf_ops, sizeof(selinux_nf_ops), GFP_KERNEL);
+	if (net->nf.selinux_ops == NULL) {
+		err = -ENOMEM;
+		goto err1;
+	}
+
+	err = nf_register_hooks(net, net->nf.selinux_ops,
+				ARRAY_SIZE(selinux_nf_ops));
+	if (err < 0)
+		goto err2;
+
+	return 0;
+err2:
+	kfree(net->nf.selinux_ops);
+err1:
+	return err;
+}
+
+static void selinux_net_exit(struct net *net)
+{
+	nf_unregister_hooks(net->nf.selinux_ops, ARRAY_SIZE(selinux_nf_ops));
+	kfree(net->nf.selinux_ops);
+}
+
+static struct pernet_operations selinux_net_ops = {
+	.init = selinux_net_init,
+	.exit = selinux_net_exit,
+};
+
 static int __init selinux_nf_ip_init(void)
 {
 	int err;
@@ -6156,9 +6190,8 @@ static int __init selinux_nf_ip_init(void)
 
 	printk(KERN_DEBUG "SELinux:  Registering netfilter hooks\n");
 
-	err = nf_register_hooks(&init_net, selinux_nf_ops,
-				ARRAY_SIZE(selinux_nf_ops));
-	if (err)
+	err = register_pernet_subsys(&selinux_net_ops);
+	if (err < 0)
 		panic("SELinux: nf_register_hooks: error %d\n", err);
 
 	return 0;
@@ -6170,9 +6203,7 @@ __initcall(selinux_nf_ip_init);
 static void selinux_nf_ip_exit(void)
 {
 	printk(KERN_DEBUG "SELinux:  Unregistering netfilter hooks\n");
-
-	nf_unregister_hooks(&init_net, selinux_nf_ops,
-			    ARRAY_SIZE(selinux_nf_ops));
+	unregister_pernet_subsys(&selinux_net_ops);
 }
 #endif
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH RFC 15/15] netfilter: bridge: adapt it to pernet hooks
  2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
                   ` (13 preceding siblings ...)
  2015-06-15 15:46 ` [PATCH RFC 14/15] security: " Pablo Neira Ayuso
@ 2015-06-15 15:46 ` Pablo Neira Ayuso
  14 siblings, 0 replies; 17+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-15 15:46 UTC (permalink / raw
  To: netfilter-devel; +Cc: ebiederm, aschultz, kaber

This patch replaces the global brnf_call_* variables to make them per
netnamespace. Moreover, this registers hooks at pernet level too.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netfilter/br_netfilter.h |   52 +++++++++++
 include/net/netns/netfilter.h        |   13 +++
 net/bridge/br_netfilter.c            |  171 +++++++++++++++++++++-------------
 3 files changed, 169 insertions(+), 67 deletions(-)

diff --git a/include/net/netfilter/br_netfilter.h b/include/net/netfilter/br_netfilter.h
index 2aa6048..26b3591 100644
--- a/include/net/netfilter/br_netfilter.h
+++ b/include/net/netfilter/br_netfilter.h
@@ -3,4 +3,56 @@
 
 void br_netfilter_enable(void);
 
+#ifdef CONFIG_SYSCTL
+static inline bool brnf_call_iptables(struct net_device *dev)
+{
+	return dev_net(dev)->nf.brnf_call_iptables;
+}
+static inline bool brnf_call_ip6tables(struct net_device *dev)
+{
+	return dev_net(dev)->nf.brnf_call_ip6tables;
+}
+static inline bool brnf_call_arptables(struct net_device *dev)
+{
+	return dev_net(dev)->nf.brnf_call_arptables;
+}
+static inline bool brnf_filter_vlan_tagged(struct net_device *dev)
+{
+	return dev_net(dev)->nf.brnf_filter_vlan_tagged;
+}
+static inline bool brnf_filter_pppoe_tagged(struct net_device *dev)
+{
+	return dev_net(dev)->nf.brnf_filter_pppoe_tagged;
+}
+static inline bool brnf_pass_vlan_indev(struct net_device *dev)
+{
+	return dev_net(dev)->nf.brnf_pass_vlan_indev;
+}
+#else
+static inline bool brnf_call_iptables(void)
+{
+	return true;
+}
+static inline bool brnf_call_ip6tables(void)
+{
+	return true;
+}
+static inline bool brnf_call_arptables(void)
+{
+	return true;
+}
+static inline bool brnf_filter_vlan_tagged(void)
+{
+	return false;
+}
+static inline bool brnf_filter_pppoe_tagged(void)
+{
+	return false;
+}
+static inline bool brnf_pass_vlan_indev(void)
+{
+	return false;
+}
+#endif /* CONFIG_SYSCTL */
+
 #endif /* _BR_NETFILTER_H_ */
diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h
index 89925e3..604b8f0 100644
--- a/include/net/netns/netfilter.h
+++ b/include/net/netns/netfilter.h
@@ -24,5 +24,18 @@ struct netns_nf {
 #ifdef CONFIG_SECURITY
 	struct nf_hook_ops *selinux_ops;
 #endif
+#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
+#ifdef CONFIG_SYSCTL
+	struct ctl_table *brnf_table;
+	struct ctl_table_header *brnf_sysctl_header;
+	int brnf_call_iptables;
+	int brnf_call_ip6tables;
+	int brnf_call_arptables;
+	int brnf_filter_vlan_tagged;
+	int brnf_filter_pppoe_tagged;
+	int brnf_pass_vlan_indev;
+#endif
+	struct nf_hook_ops *brnf_ops;
+#endif
 };
 #endif
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index af14ef1..af47cfe 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -44,23 +44,6 @@
 #include <linux/sysctl.h>
 #endif
 
-#ifdef CONFIG_SYSCTL
-static struct ctl_table_header *brnf_sysctl_header;
-static int brnf_call_iptables __read_mostly = 1;
-static int brnf_call_ip6tables __read_mostly = 1;
-static int brnf_call_arptables __read_mostly = 1;
-static int brnf_filter_vlan_tagged __read_mostly = 0;
-static int brnf_filter_pppoe_tagged __read_mostly = 0;
-static int brnf_pass_vlan_indev __read_mostly = 0;
-#else
-#define brnf_call_iptables 1
-#define brnf_call_ip6tables 1
-#define brnf_call_arptables 1
-#define brnf_filter_vlan_tagged 0
-#define brnf_filter_pppoe_tagged 0
-#define brnf_pass_vlan_indev 0
-#endif
-
 #define IS_IP(skb) \
 	(!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_IP))
 
@@ -80,17 +63,17 @@ static inline __be16 vlan_proto(const struct sk_buff *skb)
 		return 0;
 }
 
-#define IS_VLAN_IP(skb) \
+#define IS_VLAN_IP(skb, dev) \
 	(vlan_proto(skb) == htons(ETH_P_IP) && \
-	 brnf_filter_vlan_tagged)
+	 brnf_filter_vlan_tagged(dev))
 
-#define IS_VLAN_IPV6(skb) \
+#define IS_VLAN_IPV6(skb, dev) \
 	(vlan_proto(skb) == htons(ETH_P_IPV6) && \
-	 brnf_filter_vlan_tagged)
+	 brnf_filter_vlan_tagged(dev))
 
-#define IS_VLAN_ARP(skb) \
+#define IS_VLAN_ARP(skb, dev) \
 	(vlan_proto(skb) == htons(ETH_P_ARP) &&	\
-	 brnf_filter_vlan_tagged)
+	 brnf_filter_vlan_tagged(dev))
 
 static inline __be16 pppoe_proto(const struct sk_buff *skb)
 {
@@ -98,15 +81,15 @@ static inline __be16 pppoe_proto(const struct sk_buff *skb)
 			    sizeof(struct pppoe_hdr)));
 }
 
-#define IS_PPPOE_IP(skb) \
+#define IS_PPPOE_IP(skb, dev) \
 	(skb->protocol == htons(ETH_P_PPP_SES) && \
 	 pppoe_proto(skb) == htons(PPP_IP) && \
-	 brnf_filter_pppoe_tagged)
+	 brnf_filter_pppoe_tagged(dev))
 
-#define IS_PPPOE_IPV6(skb) \
+#define IS_PPPOE_IPV6(skb, dev) \
 	(skb->protocol == htons(ETH_P_PPP_SES) && \
 	 pppoe_proto(skb) == htons(PPP_IPV6) && \
-	 brnf_filter_pppoe_tagged)
+	 brnf_filter_pppoe_tagged(dev))
 
 /* largest possible L2 header, see br_nf_dev_queue_xmit() */
 #define NF_BRIDGE_MAX_MAC_HEADER_LENGTH (PPPOE_SES_HLEN + ETH_HLEN)
@@ -626,7 +609,8 @@ static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct
 	struct net_device *vlan, *br;
 
 	br = bridge_parent(dev);
-	if (brnf_pass_vlan_indev == 0 || !skb_vlan_tag_present(skb))
+	if (dev_net(dev)->nf.brnf_pass_vlan_indev == 0 ||
+	    !skb_vlan_tag_present(skb))
 		return br;
 
 	vlan = __vlan_find_dev_deep_rcu(br, skb->vlan_proto,
@@ -711,18 +695,22 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops,
 		return NF_DROP;
 	br = p->br;
 
-	if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) {
-		if (!brnf_call_ip6tables && !br->nf_call_ip6tables)
+	if (IS_IPV6(skb) ||
+	    IS_VLAN_IPV6(skb, state->in) ||
+	    IS_PPPOE_IPV6(skb, state->in)) {
+		if (!brnf_call_ip6tables(state->in) && !br->nf_call_ip6tables)
 			return NF_ACCEPT;
 
 		nf_bridge_pull_encap_header_rcsum(skb);
 		return br_nf_pre_routing_ipv6(ops, skb, state);
 	}
 
-	if (!brnf_call_iptables && !br->nf_call_iptables)
+	if (!brnf_call_iptables(state->in) && !br->nf_call_iptables)
 		return NF_ACCEPT;
 
-	if (!IS_IP(skb) && !IS_VLAN_IP(skb) && !IS_PPPOE_IP(skb))
+	if (!IS_IP(skb) &&
+	    !IS_VLAN_IP(skb, state->in) &&
+	    !IS_PPPOE_IP(skb, state->in))
 		return NF_ACCEPT;
 
 	nf_bridge_pull_encap_header_rcsum(skb);
@@ -770,8 +758,7 @@ static int br_nf_forward_finish(struct sock *sk, struct sk_buff *skb)
 	struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
 	struct net_device *in;
 
-	if (!IS_ARP(skb) && !IS_VLAN_ARP(skb)) {
-
+	if (!IS_ARP(skb) && !IS_VLAN_ARP(skb, skb->dev)) {
 		if (skb->protocol == htons(ETH_P_IP))
 			nf_bridge->frag_max_size = IPCB(skb)->frag_max_size;
 
@@ -824,9 +811,13 @@ static unsigned int br_nf_forward_ip(const struct nf_hook_ops *ops,
 	if (!parent)
 		return NF_DROP;
 
-	if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
+	if (IS_IP(skb) ||
+	    IS_VLAN_IP(skb, state->out) ||
+	    IS_PPPOE_IP(skb, state->out))
 		pf = NFPROTO_IPV4;
-	else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
+	else if (IS_IPV6(skb) ||
+		 IS_VLAN_IPV6(skb, state->out) ||
+		 IS_PPPOE_IPV6(skb, state->out))
 		pf = NFPROTO_IPV6;
 	else
 		return NF_ACCEPT;
@@ -876,17 +867,17 @@ static unsigned int br_nf_forward_arp(const struct nf_hook_ops *ops,
 		return NF_ACCEPT;
 	br = p->br;
 
-	if (!brnf_call_arptables && !br->nf_call_arptables)
+	if (!brnf_call_arptables(state->out) && !br->nf_call_arptables)
 		return NF_ACCEPT;
 
 	if (!IS_ARP(skb)) {
-		if (!IS_VLAN_ARP(skb))
+		if (!IS_VLAN_ARP(skb, state->out))
 			return NF_ACCEPT;
 		nf_bridge_pull_encap_header(skb);
 	}
 
 	if (arp_hdr(skb)->ar_pln != 4) {
-		if (IS_VLAN_ARP(skb))
+		if (IS_VLAN_ARP(skb, state->out))
 			nf_bridge_push_encap_header(skb);
 		return NF_ACCEPT;
 	}
@@ -1040,9 +1031,13 @@ static unsigned int br_nf_post_routing(const struct nf_hook_ops *ops,
 	if (!realoutdev)
 		return NF_DROP;
 
-	if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
+	if (IS_IP(skb) ||
+	    IS_VLAN_IP(skb, state->out) ||
+	    IS_PPPOE_IP(skb, state->out))
 		pf = NFPROTO_IPV4;
-	else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
+	else if (IS_IPV6(skb) ||
+		 IS_VLAN_IPV6(skb, state->out) ||
+		 IS_PPPOE_IPV6(skb, state->out))
 		pf = NFPROTO_IPV6;
 	else
 		return NF_ACCEPT;
@@ -1196,44 +1191,38 @@ int brnf_sysctl_call_tables(struct ctl_table *ctl, int write,
 }
 
 static struct ctl_table brnf_table[] = {
-	{
+	[0] = {
 		.procname	= "bridge-nf-call-arptables",
-		.data		= &brnf_call_arptables,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= brnf_sysctl_call_tables,
 	},
-	{
+	[1] = {
 		.procname	= "bridge-nf-call-iptables",
-		.data		= &brnf_call_iptables,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= brnf_sysctl_call_tables,
 	},
-	{
+	[2] = {
 		.procname	= "bridge-nf-call-ip6tables",
-		.data		= &brnf_call_ip6tables,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= brnf_sysctl_call_tables,
 	},
-	{
+	[3] = {
 		.procname	= "bridge-nf-filter-vlan-tagged",
-		.data		= &brnf_filter_vlan_tagged,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= brnf_sysctl_call_tables,
 	},
-	{
+	[4] = {
 		.procname	= "bridge-nf-filter-pppoe-tagged",
-		.data		= &brnf_filter_pppoe_tagged,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= brnf_sysctl_call_tables,
 	},
-	{
+	[5] = {
 		.procname	= "bridge-nf-pass-vlan-input-dev",
-		.data		= &brnf_pass_vlan_indev,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= brnf_sysctl_call_tables,
@@ -1242,23 +1231,75 @@ static struct ctl_table brnf_table[] = {
 };
 #endif
 
+static int __net_init br_nf_net_init(struct net *net)
+{
+	int err = -ENOMEM;
+#ifdef CONFIG_SYSCTL
+	struct ctl_table *brnf_table_net;
+
+	net->nf.brnf_call_arptables = 1;
+	net->nf.brnf_call_iptables = 1;
+	net->nf.brnf_call_ip6tables = 1;
+
+	brnf_table_net = kmemdup(brnf_table, sizeof(brnf_table), GFP_KERNEL);
+	if (brnf_table_net == NULL)
+		return -ENOMEM;
+
+	net->nf.brnf_table[0].data = &net->nf.brnf_call_arptables;
+	net->nf.brnf_table[1].data = &net->nf.brnf_call_iptables;
+	net->nf.brnf_table[2].data = &net->nf.brnf_call_ip6tables;
+	net->nf.brnf_table[3].data = &net->nf.brnf_filter_vlan_tagged;
+	net->nf.brnf_table[4].data = &net->nf.brnf_filter_pppoe_tagged;
+	net->nf.brnf_table[5].data = &net->nf.brnf_pass_vlan_indev;
+
+	net->nf.brnf_sysctl_header =
+		register_net_sysctl(net, "net/bridge", brnf_table_net);
+	if (net->nf.brnf_sysctl_header == NULL)
+		goto err1;
+#endif
+
+	net->nf.brnf_ops = kmemdup(br_nf_ops, sizeof(br_nf_ops), GFP_KERNEL);
+	if (net->nf.brnf_ops == NULL)
+		goto err2;
+
+	err = nf_register_hooks(net, net->nf.brnf_ops, ARRAY_SIZE(br_nf_ops));
+	if (err < 0)
+		goto err3;
+
+	return 0;
+err3:
+	kfree(net->nf.brnf_ops);
+err2:
+	unregister_net_sysctl_table(net->nf.brnf_sysctl_header);
+#ifdef CONFIG_SYSCTL
+err1:
+	kfree(brnf_table_net);
+#endif
+	return err;
+}
+
+static void __net_exit br_nf_net_exit(struct net *net)
+{
+#ifdef CONFIG_SYSCTL
+	unregister_net_sysctl_table(net->nf.brnf_sysctl_header);
+#endif
+	nf_unregister_hooks(net->nf.brnf_ops, ARRAY_SIZE(br_nf_ops));
+	kfree(net->nf.brnf_ops);
+}
+
+static struct pernet_operations br_nf_net_ops = {
+	.init = br_nf_net_init,
+	.exit = br_nf_net_exit,
+};
+
 static int __init br_netfilter_init(void)
 {
 	int ret;
 
-	ret = nf_register_hooks(&init_net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
+	ret = register_pernet_subsys(&br_nf_net_ops);
 	if (ret < 0)
 		return ret;
 
-#ifdef CONFIG_SYSCTL
-	brnf_sysctl_header = register_net_sysctl(&init_net, "net/bridge", brnf_table);
-	if (brnf_sysctl_header == NULL) {
-		printk(KERN_WARNING
-		       "br_netfilter: can't register to sysctl.\n");
-		nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
-		return -ENOMEM;
-	}
-#endif
 	RCU_INIT_POINTER(nf_br_ops, &br_ops);
 	printk(KERN_NOTICE "Bridge firewalling registered\n");
 	return 0;
@@ -1267,10 +1308,6 @@ static int __init br_netfilter_init(void)
 static void __exit br_netfilter_fini(void)
 {
 	RCU_INIT_POINTER(nf_br_ops, NULL);
-	nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
-#ifdef CONFIG_SYSCTL
-	unregister_net_sysctl_table(brnf_sysctl_header);
-#endif
 }
 
 module_init(br_netfilter_init);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH RFC 04/15] netfilter: add pernet hook support
  2015-06-15 15:46 ` [PATCH RFC 04/15] netfilter: add pernet hook support Pablo Neira Ayuso
@ 2015-06-16  1:01   ` Eric W. Biederman
  0 siblings, 0 replies; 17+ messages in thread
From: Eric W. Biederman @ 2015-06-16  1:01 UTC (permalink / raw
  To: Pablo Neira Ayuso; +Cc: netfilter-devel, aschultz, kaber

Pablo Neira Ayuso <pablo@netfilter.org> writes:

> This patch modifies the nf_register_hook() and nf_register_hooks() interfaces
> to allow to register hooks at a pernet level.
>
> This starts using init_net for all the existing callers though, so the full
> conversion of existing netfilter hook clients to comes in follow up
> patches.

There is one issue with the approach this takes to per net network
namespace hooks.

nf_unregister_hook calls syncrhonize_net().

Which depending on which netfilter modules are loaded is going
to result in a nasty reduction in connections per second of vsftp,
because of the serialized nature of network namespace cleanup.

That should be something we can solve on top of the patches,
but I want to bring it up now so that other people are aware of it.

Eric

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2015-06-16  1:06 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-06-15 15:46 [PATCH RFC 00/15] Netfilter pernet hook support Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 01/15] net: include missing headers in net/net_namespace.h Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 02/15] netfilter: use forward declaration instead of including linux/proc_fs.h Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 03/15] netfilter: don't pull include/linux/netfilter.h from netns headers Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 04/15] netfilter: add pernet hook support Pablo Neira Ayuso
2015-06-16  1:01   ` Eric W. Biederman
2015-06-15 15:46 ` [PATCH RFC 05/15] netfilter: ipt_CLUSTERIP: adapt it to support pernet hooks Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 06/15] netfilter: x_tables: adapt xt_hook_link() " Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 07/15] netfilter: x_tables: adapt tables to " Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 08/15] netfilter: nf_conntrack: adapt IPv4 and IPv6 trackers " Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 09/15] netfilter: synproxy: adapt IPv4 and IPv6 targets " Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 10/15] netfilter: defrag: add pernet hook support Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 11/15] ipvs: adapt it to pernet hooks Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 12/15] netfilter: ebtables: adapt the filter and nat table " Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 13/15] netfilter: nf_tables: adapt it " Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 14/15] security: " Pablo Neira Ayuso
2015-06-15 15:46 ` [PATCH RFC 15/15] netfilter: bridge: " Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.