netfilter: conntrack: add nf_ct_iter_data object for nf_ct_iterate_cleanup*()
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 8 Apr 2022 11:10:19 +0000 (13:10 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 13 May 2022 16:56:27 +0000 (18:56 +0200)
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>
include/net/netfilter/nf_conntrack.h
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto.c
net/netfilter/nf_conntrack_timeout.c
net/netfilter/nf_nat_masquerade.c

index 3ce9a5b..a32be8a 100644 (file)
@@ -236,10 +236,16 @@ static inline bool nf_ct_kill(struct nf_conn *ct)
        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. */
-void nf_ct_iterate_cleanup_net(struct net *net,
-                              int (*iter)(struct nf_conn *i, void *data),
-                              void *data, u32 portid, int report);
+void nf_ct_iterate_cleanup_net(int (*iter)(struct nf_conn *i, void *data),
+                              const struct nf_ct_iter_data *iter_data);
 
 /* 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),
index 22492f7..efbfd67 100644 (file)
@@ -2335,7 +2335,7 @@ static bool nf_conntrack_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple,
 /* Bring out ya dead! */
 static struct nf_conn *
 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_conn *ct;
@@ -2366,7 +2366,12 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
                         * tuple while iterating.
                         */
                        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;
                }
                spin_unlock(lockp);
@@ -2383,7 +2388,7 @@ found:
 }
 
 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;
        struct nf_conn *ct;
@@ -2391,49 +2396,28 @@ static void nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data),
        might_sleep();
 
        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... */
 
-               nf_ct_delete(ct, portid, report);
+               nf_ct_delete(ct, iter_data->portid, iter_data->report);
                nf_ct_put(ct);
                cond_resched();
        }
        mutex_unlock(&nf_conntrack_mutex);
 }
 
-struct iter_data {
-       int (*iter)(struct nf_conn *i, void *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)
+void nf_ct_iterate_cleanup_net(int (*iter)(struct nf_conn *i, void *data),
+                              const struct nf_ct_iter_data *iter_data)
 {
+       struct net *net = iter_data->net;
        struct nf_conntrack_net *cnet = nf_ct_pernet(net);
-       struct iter_data d;
 
        might_sleep();
 
        if (atomic_read(&cnet->count) == 0)
                return;
 
-       d.iter = iter;
-       d.data = data;
-       d.net = net;
-
-       nf_ct_iterate_cleanup(iter_net_only, &d, portid, report);
+       nf_ct_iterate_cleanup(iter, iter_data);
 }
 EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup_net);
 
@@ -2451,6 +2435,7 @@ EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup_net);
 void
 nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void *data)
 {
+       struct nf_ct_iter_data iter_data = {};
        struct net *net;
 
        down_read(&net_rwsem);
@@ -2478,7 +2463,8 @@ nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data), void *data)
        synchronize_net();
 
        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
         * 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)
 {
-       return net_eq(nf_ct_net(i), data);
+       return 1;
 }
 
 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)
 {
-       int busy;
+       struct nf_ct_iter_data iter_data = {};
        struct net *net;
+       int busy;
 
        /*
         * 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) {
                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)
                        busy = 1;
        }
index eafe640..e768f59 100644 (file)
@@ -1559,6 +1559,11 @@ static int ctnetlink_flush_conntrack(struct net *net,
                                     u32 portid, int report, u8 family)
 {
        struct ctnetlink_filter *filter = NULL;
+       struct nf_ct_iter_data iter = {
+               .net            = net,
+               .portid         = portid,
+               .report         = report,
+       };
 
        if (ctnetlink_needs_filter(family, cda)) {
                if (cda[CTA_FILTER])
@@ -1567,10 +1572,11 @@ static int ctnetlink_flush_conntrack(struct net *net,
                filter = ctnetlink_alloc_filter(cda, family);
                if (IS_ERR(filter))
                        return PTR_ERR(filter);
+
+               iter.data = filter;
        }
 
-       nf_ct_iterate_cleanup_net(net, ctnetlink_flush_iterate, filter,
-                                 portid, report);
+       nf_ct_iterate_cleanup_net(ctnetlink_flush_iterate, &iter);
        kfree(filter);
 
        return 0;
index d1f2d3c..895b09c 100644 (file)
@@ -538,9 +538,13 @@ retry:
  out_unlock:
        mutex_unlock(&nf_ct_proto_mutex);
 
-       if (fixup_needed)
-               nf_ct_iterate_cleanup_net(net, nf_ct_tcp_fixup,
-                                         (void *)(unsigned long)nfproto, 0, 0);
+       if (fixup_needed) {
+               struct nf_ct_iter_data iter_data = {
+                       .net    = net,
+                       .data   = (void *)(unsigned long)nfproto,
+               };
+               nf_ct_iterate_cleanup_net(nf_ct_tcp_fixup, &iter_data);
+       }
 
        return err;
 }
index cec166e..0f828d0 100644 (file)
@@ -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)
 {
-       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);
 
index e32fac3..1a506b0 100644 (file)
@@ -77,11 +77,14 @@ EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4);
 
 static void iterate_cleanup_work(struct work_struct *work)
 {
+       struct nf_ct_iter_data iter_data = {};
        struct masq_dev_work *w;
 
        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);
        kfree(w);