netfilter: allow exp not to be removed in nf_ct_find_expectation
authorXin Long <lucien.xin@gmail.com>
Sun, 16 Jul 2023 21:09:17 +0000 (17:09 -0400)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 20 Jul 2023 08:06:36 +0000 (10:06 +0200)
Currently nf_conntrack_in() calling nf_ct_find_expectation() will
remove the exp from the hash table. However, in some scenario, we
expect the exp not to be removed when the created ct will not be
confirmed, like in OVS and TC conntrack in the following patches.

This patch allows exp not to be removed by setting IPS_CONFIRMED
in the status of the tmpl.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Aaron Conole <aconole@redhat.com>
Acked-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
include/net/netfilter/nf_conntrack_expect.h
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nft_ct.c

index cf0d81be5a96ea3ff09fa33806c8a0e852e58aa2..165e7a03b8e9dccf67f315d80c81a362cbb7e5bf 100644 (file)
@@ -100,7 +100,7 @@ nf_ct_expect_find_get(struct net *net,
 struct nf_conntrack_expect *
 nf_ct_find_expectation(struct net *net,
                       const struct nf_conntrack_zone *zone,
-                      const struct nf_conntrack_tuple *tuple);
+                      const struct nf_conntrack_tuple *tuple, bool unlink);
 
 void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
                                u32 portid, int report);
index 992393102d5f536bcf6e0807ce284601d0051c9a..9f6f2e6435758e2505a934adc0067a11f3dae68c 100644 (file)
@@ -1756,7 +1756,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
        cnet = nf_ct_pernet(net);
        if (cnet->expect_count) {
                spin_lock_bh(&nf_conntrack_expect_lock);
-               exp = nf_ct_find_expectation(net, zone, tuple);
+               exp = nf_ct_find_expectation(net, zone, tuple, !tmpl || nf_ct_is_confirmed(tmpl));
                if (exp) {
                        /* Welcome, Mr. Bond.  We've been expecting you... */
                        __set_bit(IPS_EXPECTED_BIT, &ct->status);
index 96948e98ec53ddaf8e364e3365204fa3301853e9..81ca348915c98c95200c0b4ae69d4a081978058c 100644 (file)
@@ -171,7 +171,7 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
 struct nf_conntrack_expect *
 nf_ct_find_expectation(struct net *net,
                       const struct nf_conntrack_zone *zone,
-                      const struct nf_conntrack_tuple *tuple)
+                      const struct nf_conntrack_tuple *tuple, bool unlink)
 {
        struct nf_conntrack_net *cnet = nf_ct_pernet(net);
        struct nf_conntrack_expect *i, *exp = NULL;
@@ -211,7 +211,7 @@ nf_ct_find_expectation(struct net *net,
                     !refcount_inc_not_zero(&exp->master->ct_general.use)))
                return NULL;
 
-       if (exp->flags & NF_CT_EXPECT_PERMANENT) {
+       if (exp->flags & NF_CT_EXPECT_PERMANENT || !unlink) {
                refcount_inc(&exp->use);
                return exp;
        } else if (del_timer(&exp->timeout)) {
index 38958e067aa8a872512879526ea9a03c337f8010..e87fd4314c68626e1e90ceb98ae570c34c948a09 100644 (file)
@@ -262,6 +262,7 @@ static void nft_ct_set_zone_eval(const struct nft_expr *expr,
                        regs->verdict.code = NF_DROP;
                        return;
                }
+               __set_bit(IPS_CONFIRMED_BIT, &ct->status);
        }
 
        nf_ct_set(skb, ct, IP_CT_NEW);
@@ -368,6 +369,7 @@ static bool nft_ct_tmpl_alloc_pcpu(void)
                        return false;
                }
 
+               __set_bit(IPS_CONFIRMED_BIT, &tmp->status);
                per_cpu(nft_ct_pcpu_template, cpu) = tmp;
        }