Commit 8169ff58 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: conntrack: add nf_ct_iter_data object for nf_ct_iterate_cleanup*()

This patch adds a structure to collect all the context data that is
passed to the cleanup iterator.

 struct nf_ct_iter_data {
       struct net *net;
       void *data;
       u32 portid;
       int report;
 };

There is a netns field that allows to clean up conntrack entries
specifically owned by the specified netns.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 0bcfbafb
...@@ -236,10 +236,16 @@ static inline bool nf_ct_kill(struct nf_conn *ct) ...@@ -236,10 +236,16 @@ static inline bool nf_ct_kill(struct nf_conn *ct)
return nf_ct_delete(ct, 0, 0); return nf_ct_delete(ct, 0, 0);
} }
struct nf_ct_iter_data {
struct net *net;
void *data;
u32 portid;
int report;
};
/* Iterate over all conntracks: if iter returns true, it's deleted. */ /* Iterate over all conntracks: if iter returns true, it's deleted. */
void nf_ct_iterate_cleanup_net(struct net *net, void nf_ct_iterate_cleanup_net(int (*iter)(struct nf_conn *i, void *data),
int (*iter)(struct nf_conn *i, void *data), const struct nf_ct_iter_data *iter_data);
void *data, u32 portid, int report);
/* also set unconfirmed conntracks as dying. Only use in module exit path. */ /* also set unconfirmed conntracks as dying. Only use in module exit path. */
void nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data),
......
...@@ -2335,7 +2335,7 @@ static bool nf_conntrack_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple, ...@@ -2335,7 +2335,7 @@ static bool nf_conntrack_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple,
/* Bring out ya dead! */ /* Bring out ya dead! */
static struct nf_conn * static struct nf_conn *
get_next_corpse(int (*iter)(struct nf_conn *i, void *data), get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
void *data, unsigned int *bucket) const struct nf_ct_iter_data *iter_data, unsigned int *bucket)
{ {
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct; struct nf_conn *ct;
...@@ -2366,7 +2366,12 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data), ...@@ -2366,7 +2366,12 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
* tuple while iterating. * tuple while iterating.
*/ */
ct = nf_ct_tuplehash_to_ctrack(h); ct = nf_ct_tuplehash_to_ctrack(h);
if (iter(ct, data))
if (iter_data->net &&
!net_eq(iter_data->net, nf_ct_net(ct)))
continue;
if (iter(ct, iter_data->data))
goto found; goto found;
} }
spin_unlock(lockp); spin_unlock(lockp);
...@@ -2383,7 +2388,7 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data), ...@@ -2383,7 +2388,7 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
} }
static void nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), static void nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data),
void *data, u32 portid, int report) const struct nf_ct_iter_data *iter_data)
{ {
unsigned int bucket = 0; unsigned int bucket = 0;
struct nf_conn *ct; struct nf_conn *ct;
...@@ -2391,49 +2396,28 @@ static void nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), ...@@ -2391,49 +2396,28 @@ static void nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data),
might_sleep(); might_sleep();
mutex_lock(&nf_conntrack_mutex); mutex_lock(&nf_conntrack_mutex);
while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) { while ((ct = get_next_corpse(iter, iter_data, &bucket)) != NULL) {
/* Time to push up daises... */ /* Time to push up daises... */
nf_ct_delete(ct, portid, report); nf_ct_delete(ct, iter_data->portid, iter_data->report);
nf_ct_put(ct); nf_ct_put(ct);
cond_resched(); cond_resched();
} }
mutex_unlock(&nf_conntrack_mutex); mutex_unlock(&nf_conntrack_mutex);
} }
struct iter_data { void nf_ct_iterate_cleanup_net(int (*iter)(struct nf_conn *i, void *data),
int (*iter)(struct nf_conn *i, void *data); const struct nf_ct_iter_data *iter_data)
void *data;
struct net *net;
};
static int iter_net_only(struct nf_conn *i, void *data)
{
struct iter_data *d = data;
if (!net_eq(d->net, nf_ct_net(i)))
return 0;
return d->iter(i, d->data);
}
void nf_ct_iterate_cleanup_net(struct net *net,
int (*iter)(struct nf_conn *i, void *data),
void *data, u32 portid, int report)
{ {
struct net *net = iter_data->net;
struct nf_conntrack_net *cnet = nf_ct_pernet(net); struct nf_conntrack_net *cnet = nf_ct_pernet(net);
struct iter_data d;
might_sleep(); might_sleep();
if (atomic_read(&cnet->count) == 0) if (atomic_read(&cnet->count) == 0)
return; return;
d.iter = iter; nf_ct_iterate_cleanup(iter, iter_data);
d.data = data;
d.net = net;
nf_ct_iterate_cleanup(iter_net_only, &d, portid, report);
} }
EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup_net); EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup_net);
...@@ -2451,6 +2435,7 @@ EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup_net); ...@@ -2451,6 +2435,7 @@ EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup_net);
void void
nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void *data) nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void *data)
{ {
struct nf_ct_iter_data iter_data = {};
struct net *net; struct net *net;
down_read(&net_rwsem); down_read(&net_rwsem);
...@@ -2478,7 +2463,8 @@ nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void *data) ...@@ -2478,7 +2463,8 @@ nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void *data)
synchronize_net(); synchronize_net();
nf_ct_ext_bump_genid(); nf_ct_ext_bump_genid();
nf_ct_iterate_cleanup(iter, data, 0, 0); iter_data.data = data;
nf_ct_iterate_cleanup(iter, &iter_data);
/* Another cpu might be in a rcu read section with /* Another cpu might be in a rcu read section with
* rcu protected pointer cleared in iter callback * rcu protected pointer cleared in iter callback
...@@ -2492,7 +2478,7 @@ EXPORT_SYMBOL_GPL(nf_ct_iterate_destroy); ...@@ -2492,7 +2478,7 @@ EXPORT_SYMBOL_GPL(nf_ct_iterate_destroy);
static int kill_all(struct nf_conn *i, void *data) static int kill_all(struct nf_conn *i, void *data)
{ {
return net_eq(nf_ct_net(i), data); return 1;
} }
void nf_conntrack_cleanup_start(void) void nf_conntrack_cleanup_start(void)
...@@ -2527,8 +2513,9 @@ void nf_conntrack_cleanup_net(struct net *net) ...@@ -2527,8 +2513,9 @@ void nf_conntrack_cleanup_net(struct net *net)
void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list) void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list)
{ {
int busy; struct nf_ct_iter_data iter_data = {};
struct net *net; struct net *net;
int busy;
/* /*
* This makes sure all current packets have passed through * This makes sure all current packets have passed through
...@@ -2541,7 +2528,8 @@ void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list) ...@@ -2541,7 +2528,8 @@ void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list)
list_for_each_entry(net, net_exit_list, exit_list) { list_for_each_entry(net, net_exit_list, exit_list) {
struct nf_conntrack_net *cnet = nf_ct_pernet(net); struct nf_conntrack_net *cnet = nf_ct_pernet(net);
nf_ct_iterate_cleanup(kill_all, net, 0, 0); iter_data.net = net;
nf_ct_iterate_cleanup_net(kill_all, &iter_data);
if (atomic_read(&cnet->count) != 0) if (atomic_read(&cnet->count) != 0)
busy = 1; busy = 1;
} }
......
...@@ -1559,6 +1559,11 @@ static int ctnetlink_flush_conntrack(struct net *net, ...@@ -1559,6 +1559,11 @@ static int ctnetlink_flush_conntrack(struct net *net,
u32 portid, int report, u8 family) u32 portid, int report, u8 family)
{ {
struct ctnetlink_filter *filter = NULL; struct ctnetlink_filter *filter = NULL;
struct nf_ct_iter_data iter = {
.net = net,
.portid = portid,
.report = report,
};
if (ctnetlink_needs_filter(family, cda)) { if (ctnetlink_needs_filter(family, cda)) {
if (cda[CTA_FILTER]) if (cda[CTA_FILTER])
...@@ -1567,10 +1572,11 @@ static int ctnetlink_flush_conntrack(struct net *net, ...@@ -1567,10 +1572,11 @@ static int ctnetlink_flush_conntrack(struct net *net,
filter = ctnetlink_alloc_filter(cda, family); filter = ctnetlink_alloc_filter(cda, family);
if (IS_ERR(filter)) if (IS_ERR(filter))
return PTR_ERR(filter); return PTR_ERR(filter);
iter.data = filter;
} }
nf_ct_iterate_cleanup_net(net, ctnetlink_flush_iterate, filter, nf_ct_iterate_cleanup_net(ctnetlink_flush_iterate, &iter);
portid, report);
kfree(filter); kfree(filter);
return 0; return 0;
......
...@@ -538,9 +538,13 @@ static int nf_ct_netns_do_get(struct net *net, u8 nfproto) ...@@ -538,9 +538,13 @@ static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
out_unlock: out_unlock:
mutex_unlock(&nf_ct_proto_mutex); mutex_unlock(&nf_ct_proto_mutex);
if (fixup_needed) if (fixup_needed) {
nf_ct_iterate_cleanup_net(net, nf_ct_tcp_fixup, struct nf_ct_iter_data iter_data = {
(void *)(unsigned long)nfproto, 0, 0); .net = net,
.data = (void *)(unsigned long)nfproto,
};
nf_ct_iterate_cleanup_net(nf_ct_tcp_fixup, &iter_data);
}
return err; return err;
} }
......
...@@ -38,7 +38,12 @@ static int untimeout(struct nf_conn *ct, void *timeout) ...@@ -38,7 +38,12 @@ static int untimeout(struct nf_conn *ct, void *timeout)
void nf_ct_untimeout(struct net *net, struct nf_ct_timeout *timeout) void nf_ct_untimeout(struct net *net, struct nf_ct_timeout *timeout)
{ {
nf_ct_iterate_cleanup_net(net, untimeout, timeout, 0, 0); struct nf_ct_iter_data iter_data = {
.net = net,
.data = timeout,
};
nf_ct_iterate_cleanup_net(untimeout, &iter_data);
} }
EXPORT_SYMBOL_GPL(nf_ct_untimeout); EXPORT_SYMBOL_GPL(nf_ct_untimeout);
......
...@@ -77,11 +77,14 @@ EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4); ...@@ -77,11 +77,14 @@ EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4);
static void iterate_cleanup_work(struct work_struct *work) static void iterate_cleanup_work(struct work_struct *work)
{ {
struct nf_ct_iter_data iter_data = {};
struct masq_dev_work *w; struct masq_dev_work *w;
w = container_of(work, struct masq_dev_work, work); w = container_of(work, struct masq_dev_work, work);
nf_ct_iterate_cleanup_net(w->net, w->iter, (void *)w, 0, 0); iter_data.net = w->net;
iter_data.data = (void *)w;
nf_ct_iterate_cleanup_net(w->iter, &iter_data);
put_net_track(w->net, &w->ns_tracker); put_net_track(w->net, &w->ns_tracker);
kfree(w); kfree(w);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment