mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
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: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
@@ -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,
|
|||||||
/* 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),
|
|||||||
* 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 @@ found:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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),
|
|||||||
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);
|
|||||||
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)
|
|||||||
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);
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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 @@ i_see_dead_people:
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 @@ retry:
|
|||||||
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)
|
|||||||
|
|
||||||
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);
|
|||||||
|
|
||||||
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);
|
||||||
|
Reference in New Issue
Block a user