Skip to contentSkip to conversation

remove module dependency between ctnetlink and nf_nat

PATCH In review Pablo Neira Ayuso 2 participants 2 messages Oct 13, 2008 – Oct 14, 2008

Subsystems (2)
lore
Share & tools
lore

Pablo Neira Ayuso

author maintainer
#0 lore raw

PATCH 1/1 remove module dependency between ctnetlink and nf_nat

This patch removes the module dependency between ctnetlink and nf_nat by means of an indirect call that is initialized when nf_nat is loaded. Now, nf_conntrack_netlink only requires nf_conntrack and nfnetlink.

This patch puts nfnetlink_parse_nat_setup_hook into the nf_conntrack_core to avoid dependencies between ctnetlink, nf_conntrack_ipv4 and nf_conntrack_ipv6.

This patch also introduces the function ctnetlink_change_nat that is only invoked from the creation path. Actually, the nat handling cannot be invoked from the update path since this is not allowed. By introducing this function, we remove the useless nat handling in the update path and we avoid deadlock-prone code.

This patch also adds the required EAGAIN logic for nfnetlink.

---

 include/linux/netfilter/nfnetlink.h  |    3 +
 include/net/netfilter/nf_nat_core.h  |    8 ++
 net/ipv4/netfilter/nf_nat_core.c     |   97 ++++++++++++++++++++++
 net/netfilter/nf_conntrack_core.c    |    7 ++
 net/netfilter/nf_conntrack_netlink.c |  153 ++++++++++++++--------------------
 net/netfilter/nfnetlink.c            |   12 ++-
 6 files changed, 187 insertions(+), 93 deletions(-)
include/linux/netfilter/nfnetlink.h +3 -0
index 0d8424f..7d8e045 100644
@@ -78,6 +78,9 @@ extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group,
 			  int echo);
 extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
 
+extern void nfnl_lock(void);
+extern void nfnl_unlock(void);
+
 #define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
 	MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
 
include/net/netfilter/nf_nat_core.h +8 -0
index f29eeb9..5868406 100644
@@ -25,4 +25,12 @@ static inline int nf_nat_initialized(struct nf_conn *ct,
 	else
 		return test_bit(IPS_DST_NAT_DONE_BIT, &ct->status);
 }
+
+struct nlattr;
+
+extern int
+(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
+				  enum nf_nat_manip_type manip,
+				  struct nlattr *attr);
+
 #endif /* _NF_NAT_CORE_H */
net/ipv4/netfilter/nf_nat_core.c +97 -0

119 lines not on this page · raw message

net/netfilter/nf_conntrack_core.c +7 -0
index 27de3c7..622d7c6 100644
@@ -38,9 +38,16 @@
 #include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/nf_conntrack_extend.h>
 #include <net/netfilter/nf_conntrack_acct.h>
+#include <net/netfilter/nf_nat.h>
 
 #define NF_CONNTRACK_VERSION	"0.5.0"
 
+unsigned int
+(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
+				  enum nf_nat_manip_type manip,
+				  struct nlattr *attr) __read_mostly;
+EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook);
+
 DEFINE_SPINLOCK(nf_conntrack_lock);
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
net/netfilter/nf_conntrack_netlink.c +63 -90

183 lines not on this page · raw message

net/netfilter/nfnetlink.c +9 -3
index b75c9c4..4739f9f 100644
@@ -44,15 +44,17 @@ static struct sock *nfnl = NULL;
 static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT];
 static DEFINE_MUTEX(nfnl_mutex);
 
-static inline void nfnl_lock(void)
+void nfnl_lock(void)
 {
 	mutex_lock(&nfnl_mutex);
 }
+EXPORT_SYMBOL_GPL(nfnl_lock);
 
-static inline void nfnl_unlock(void)
+void nfnl_unlock(void)
 {
 	mutex_unlock(&nfnl_mutex);
 }
+EXPORT_SYMBOL_GPL(nfnl_unlock);
 
 int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
 {
@@ -132,6 +134,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 		return 0;
 
 	type = nlh->nlmsg_type;
+replay:
 	ss = nfnetlink_get_subsys(type);
 	if (!ss) {
 #ifdef CONFIG_KMOD
@@ -165,7 +168,10 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 		} else
 			return -EINVAL;
 
-		return nc->call(nfnl, skb, nlh, cda);
+		err = nc->call(nfnl, skb, nlh, cda);
+		if (err == -EAGAIN)
+			goto replay;
+		return err;
 	}
 }
 
#1 lore raw
Quoted 9 lines · Pablo Neira Ayuso

This patch removes the module dependency between ctnetlink and nf_nat by means of an indirect call that is initialized when nf_nat is loaded. Now, nf_conntrack_netlink only requires nf_conntrack and nfnetlink.

This patch puts nfnetlink_parse_nat_setup_hook into the nf_conntrack_core to avoid dependencies between ctnetlink, nf_conntrack_ipv4 and nf_conntrack_ipv6.

Quoted 8 lines

This patch also introduces the function ctnetlink_change_nat that is only invoked from the creation path. Actually, the nat handling cannot be invoked from the update path since this is not allowed. By introducing this function, we remove the useless nat handling in the update path and we avoid deadlock-prone code.

This patch also adds the required EAGAIN logic for nfnetlink.

This looks great, I've applied it with one minor change, thanks!

Quoted 12 lines
(quoted diff) +12 -0
+ctnetlink_parse_nat_setup(struct nf_conn *ct,
+			  enum nf_nat_manip_type manip,
+			  struct nlattr *attr)
+{
+	typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup;
+
+	parse_nat_setup = rcu_dereference(nfnetlink_parse_nat_setup_hook);
+	if (!parse_nat_setup) {
+#ifdef CONFIG_KMOD
+		rcu_read_unlock();
+		nfnl_unlock();
+		if (request_module("nf-nat-ipv4") < 0) {

Review

Quoted 10 lines
(quoted diff) +10 -0
+			nfnl_lock();
+			rcu_read_lock();
+			return -EOPNOTSUPP;
+		}
+		nfnl_lock();
+		rcu_read_lock();
+		parse_nat_setup =
+			rcu_dereference(nfnetlink_parse_nat_setup_hook);
+		if (parse_nat_setup)
+			return -EAGAIN;

The rcu_dereference here isn't necessary because the pointer isn't actually dereferenced. It doesn't matter much, but removing it also looks slightly nicer :)

net/netfilter/nf_conntrack_netlink.c +1 -3
index b132124..08e82d6 100644
@@ -832,9 +832,7 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
 		}
 		nfnl_lock();
 		rcu_read_lock();
-		parse_nat_setup =
-			rcu_dereference(nfnetlink_parse_nat_setup_hook);
-		if (parse_nat_setup)
+		if (nfnetlink_parse_nat_setup_hook)
 			return -EAGAIN;
 #endif
 		return -EOPNOTSUPP;