@@ -26,6 +26,8 @@ enum nf_ct_helper_flags {
struct nf_conntrack_helper {
struct hlist_node hnode; /* Internal use. */
+ possible_net_t net;
+
char name[NF_CT_HELPER_NAME_LEN]; /* name of the module */
refcount_t refcnt;
struct module *me; /* pointer to self */
@@ -75,10 +77,17 @@ struct nf_conn_help {
#define NF_CT_HELPER_BUILD_BUG_ON(structsize) \
BUILD_BUG_ON((structsize) > FIELD_SIZEOF(struct nf_conn_help, data))
-struct nf_conntrack_helper *__nf_conntrack_helper_find(const char *name,
+static inline struct net *nf_ct_helper_net(struct nf_conntrack_helper *helper)
+{
+ return read_pnet(&helper->net);
+}
+
+struct nf_conntrack_helper *__nf_conntrack_helper_find(struct net *net,
+ const char *name,
u16 l3num, u8 protonum);
-struct nf_conntrack_helper *nf_conntrack_helper_try_module_get(const char *name,
+struct nf_conntrack_helper *nf_conntrack_helper_try_module_get(struct net *net,
+ const char *name,
u16 l3num,
u8 protonum);
void nf_conntrack_helper_put(struct nf_conntrack_helper *helper);
@@ -111,6 +111,8 @@ struct netns_ct {
int sysctl_tstamp;
int sysctl_checksum;
+ unsigned int nf_ct_helper_count;
+
struct ct_pcpu __percpu *pcpu_lists;
struct ip_conntrack_stat __percpu *stat;
struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb;
@@ -36,7 +36,6 @@ struct hlist_head *nf_ct_helper_hash __read_mostly;
EXPORT_SYMBOL_GPL(nf_ct_helper_hash);
unsigned int nf_ct_helper_hsize __read_mostly;
EXPORT_SYMBOL_GPL(nf_ct_helper_hsize);
-static unsigned int nf_ct_helper_count __read_mostly;
static bool nf_ct_auto_assign_helper __read_mostly = false;
module_param_named(nf_conntrack_helper, nf_ct_auto_assign_helper, bool, 0644);
@@ -106,24 +105,33 @@ static void nf_conntrack_helper_fini_sysctl(struct net *net)
/* Stupid hash, but collision free for the default registrations of the
* helpers currently in the kernel. */
-static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
+static unsigned int helper_hash(struct net *net,
+ const struct nf_conntrack_tuple *tuple)
{
- return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^
- (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize;
+ unsigned int hash;
+
+ hash = ((tuple->src.l3num << 8) | tuple->dst.protonum) ^
+ (__force __u16)tuple->src.u.all;
+ hash ^= net_hash_mix(net);
+
+ return hash % nf_ct_helper_hsize;
}
static struct nf_conntrack_helper *
-__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
+__nf_ct_helper_find(struct net *net, const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_helper *helper;
struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
unsigned int h;
- if (!nf_ct_helper_count)
+ if (!net->ct.nf_ct_helper_count)
return NULL;
- h = helper_hash(tuple);
+ h = helper_hash(net, tuple);
hlist_for_each_entry_rcu(helper, &nf_ct_helper_hash[h], hnode) {
+ if (!net_eq(net, nf_ct_helper_net(helper)))
+ continue;
+
if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask))
return helper;
}
@@ -131,13 +139,17 @@ __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
}
struct nf_conntrack_helper *
-__nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum)
+__nf_conntrack_helper_find(struct net *net, const char *name,
+ u16 l3num, u8 protonum)
{
struct nf_conntrack_helper *h;
unsigned int i;
for (i = 0; i < nf_ct_helper_hsize; i++) {
hlist_for_each_entry_rcu(h, &nf_ct_helper_hash[i], hnode) {
+ if (!net_eq(net, nf_ct_helper_net(h)))
+ continue;
+
if (strcmp(h->name, name))
continue;
@@ -154,19 +166,21 @@ __nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum)
EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find);
struct nf_conntrack_helper *
-nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
+nf_conntrack_helper_try_module_get(struct net *net, const char *name,
+ u16 l3num, u8 protonum)
{
struct nf_conntrack_helper *h;
rcu_read_lock();
- h = __nf_conntrack_helper_find(name, l3num, protonum);
+ h = __nf_conntrack_helper_find(net, name, l3num, protonum);
#ifdef CONFIG_MODULES
if (h == NULL) {
rcu_read_unlock();
if (request_module("nfct-helper-%s", name) == 0) {
rcu_read_lock();
- h = __nf_conntrack_helper_find(name, l3num, protonum);
+ h = __nf_conntrack_helper_find(net, name, l3num,
+ protonum);
} else {
return h;
}
@@ -213,7 +227,8 @@ nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)
if (!net->ct.sysctl_auto_assign_helper) {
if (net->ct.auto_assign_helper_warned)
return NULL;
- if (!__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple))
+ if (!__nf_ct_helper_find(net,
+ &ct->tuplehash[IP_CT_DIR_REPLY].tuple))
return NULL;
pr_info("nf_conntrack: default automatic helper assignment "
"has been turned off for security reasons and CT-based "
@@ -223,7 +238,7 @@ nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)
return NULL;
}
- return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+ return __nf_ct_helper_find(net, &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
}
@@ -395,7 +410,7 @@ int nf_conntrack_helper_register(struct net *net,
struct nf_conntrack_helper *me)
{
struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
- unsigned int h = helper_hash(&me->tuple);
+ unsigned int h = helper_hash(net, &me->tuple);
struct nf_conntrack_helper *cur;
int ret = 0, i;
@@ -412,6 +427,9 @@ int nf_conntrack_helper_register(struct net *net,
mutex_lock(&nf_ct_helper_mutex);
for (i = 0; i < nf_ct_helper_hsize; i++) {
hlist_for_each_entry(cur, &nf_ct_helper_hash[i], hnode) {
+ if (!net_eq(net, nf_ct_helper_net(cur)))
+ continue;
+
if (!strcmp(cur->name, me->name) &&
(cur->tuple.src.l3num == NFPROTO_UNSPEC ||
cur->tuple.src.l3num == me->tuple.src.l3num) &&
@@ -425,6 +443,9 @@ int nf_conntrack_helper_register(struct net *net,
/* avoid unpredictable behaviour for auto_assign_helper */
if (!(me->flags & NF_CT_HELPER_F_USERSPACE)) {
hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) {
+ if (!net_eq(net, nf_ct_helper_net(cur)))
+ continue;
+
if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple,
&mask)) {
ret = -EEXIST;
@@ -432,9 +453,11 @@ int nf_conntrack_helper_register(struct net *net,
}
}
}
+
+ write_pnet(&me->net, net);
refcount_set(&me->refcnt, 1);
hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
- nf_ct_helper_count++;
+ net->ct.nf_ct_helper_count++;
out:
mutex_unlock(&nf_ct_helper_mutex);
return ret;
@@ -453,7 +476,7 @@ void nf_conntrack_helper_unregister(struct net *net,
mutex_lock(&nf_ct_helper_mutex);
hlist_del_rcu(&me->hnode);
- nf_ct_helper_count--;
+ net->ct.nf_ct_helper_count--;
mutex_unlock(&nf_ct_helper_mutex);
/* Make sure every nothing is still using the helper unless its a
@@ -476,7 +499,7 @@ void nf_conntrack_helper_unregister(struct net *net,
}
spin_unlock_bh(&nf_conntrack_expect_lock);
- nf_ct_iterate_destroy(unhelp, me);
+ nf_ct_iterate_cleanup_net(net, unhelp, me, 0, 0);
}
EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
@@ -1529,7 +1529,8 @@ static int ctnetlink_change_helper(struct nf_conn *ct,
}
rcu_read_lock();
- helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
+ helper = __nf_conntrack_helper_find(nf_ct_net(ct),
+ helpname, nf_ct_l3num(ct),
nf_ct_protonum(ct));
if (helper == NULL) {
rcu_read_unlock();
@@ -1777,7 +1778,8 @@ ctnetlink_create_conntrack(struct net *net,
if (err < 0)
goto err2;
- helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
+ helper = __nf_conntrack_helper_find(net,
+ helpname, nf_ct_l3num(ct),
nf_ct_protonum(ct));
if (helper == NULL) {
rcu_read_unlock();
@@ -1788,7 +1790,7 @@ ctnetlink_create_conntrack(struct net *net,
}
rcu_read_lock();
- helper = __nf_conntrack_helper_find(helpname,
+ helper = __nf_conntrack_helper_find(net, helpname,
nf_ct_l3num(ct),
nf_ct_protonum(ct));
if (helper) {
@@ -2409,7 +2411,8 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
if (cda[CTA_EXPECT_HELP_NAME]) {
const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
- helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
+ helper = __nf_conntrack_helper_find(nf_ct_net(ct),
+ helpname, nf_ct_l3num(ct),
nf_ct_protonum(ct));
if (helper == NULL)
return -EOPNOTSUPP;
@@ -3145,7 +3148,7 @@ ctnetlink_create_expect(struct net *net,
if (cda[CTA_EXPECT_HELP_NAME]) {
const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
- helper = __nf_conntrack_helper_find(helpname, u3,
+ helper = __nf_conntrack_helper_find(net, helpname, u3,
nf_ct_protonum(ct));
if (helper == NULL) {
rcu_read_unlock();
@@ -3155,7 +3158,7 @@ ctnetlink_create_expect(struct net *net,
goto err_ct;
}
rcu_read_lock();
- helper = __nf_conntrack_helper_find(helpname, u3,
+ helper = __nf_conntrack_helper_find(net, helpname, u3,
nf_ct_protonum(ct));
if (helper) {
err = -EAGAIN;
@@ -789,22 +789,26 @@ static int nft_ct_helper_obj_init(const struct nft_ctx *ctx,
if (ctx->afi->family == NFPROTO_IPV6)
return -EINVAL;
- help4 = nf_conntrack_helper_try_module_get(name, family,
+ help4 = nf_conntrack_helper_try_module_get(ctx->net,
+ name, family,
priv->l4proto);
break;
case NFPROTO_IPV6:
if (ctx->afi->family == NFPROTO_IPV4)
return -EINVAL;
- help6 = nf_conntrack_helper_try_module_get(name, family,
+ help6 = nf_conntrack_helper_try_module_get(ctx->net,
+ name, family,
priv->l4proto);
break;
case NFPROTO_NETDEV: /* fallthrough */
case NFPROTO_BRIDGE: /* same */
case NFPROTO_INET:
- help4 = nf_conntrack_helper_try_module_get(name, NFPROTO_IPV4,
+ help4 = nf_conntrack_helper_try_module_get(ctx->net,
+ name, NFPROTO_IPV4,
priv->l4proto);
- help6 = nf_conntrack_helper_try_module_get(name, NFPROTO_IPV6,
+ help6 = nf_conntrack_helper_try_module_get(ctx->net,
+ name, NFPROTO_IPV6,
priv->l4proto);
break;
default:
@@ -87,7 +87,8 @@ xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
return -ENOENT;
}
- helper = nf_conntrack_helper_try_module_get(helper_name, par->family,
+ helper = nf_conntrack_helper_try_module_get(par->net,
+ helper_name, par->family,
proto);
if (helper == NULL) {
pr_info("No such helper \"%s\"\n", helper_name);
@@ -1108,13 +1108,14 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
return err;
}
-static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name,
+static int ovs_ct_add_helper(struct net *net,
+ struct ovs_conntrack_info *info, const char *name,
const struct sw_flow_key *key, bool log)
{
struct nf_conntrack_helper *helper;
struct nf_conn_help *help;
- helper = nf_conntrack_helper_try_module_get(name, info->family,
+ helper = nf_conntrack_helper_try_module_get(net, name, info->family,
key->ip.proto);
if (!helper) {
OVS_NLERR(log, "Unknown helper \"%s\"", name);
@@ -1447,7 +1448,7 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
nf_conntrack_get(&ct_info.ct->ct_general);
if (helper) {
- err = ovs_ct_add_helper(&ct_info, helper, key, log);
+ err = ovs_ct_add_helper(net, &ct_info, helper, key, log);
if (err)
goto err_free_ct;
}