]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: openvswitch: Fix ct_state nat flags for conns arriving from tc
authorPaul Blakey <paulb@nvidia.com>
Thu, 6 Jan 2022 15:38:04 +0000 (17:38 +0200)
committerJakub Kicinski <kuba@kernel.org>
Mon, 10 Jan 2022 00:24:12 +0000 (16:24 -0800)
Netfilter conntrack maintains NAT flags per connection indicating
whether NAT was configured for the connection. Openvswitch maintains
NAT flags on the per packet flow key ct_state field, indicating
whether NAT was actually executed on the packet.

When a packet misses from tc to ovs the conntrack NAT flags are set.
However, NAT was not necessarily executed on the packet because the
connection's state might still be in NEW state. As such, openvswitch
wrongly assumes that NAT was executed and sets an incorrect flow key
NAT flags.

Fix this, by flagging to openvswitch which NAT was actually done in
act_ct via tc_skb_ext and tc_skb_cb to the openvswitch module, so
the packet flow key NAT flags will be correctly set.

Fixes: 1a23a38cf53c ("net/sched: Introduce action ct")
Signed-off-by: Paul Blakey <paulb@nvidia.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Link: https://lore.kernel.org/r/20220106153804.26451-1-paulb@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/linux/skbuff.h
include/net/pkt_sched.h
net/openvswitch/flow.c
net/sched/act_ct.c
net/sched/cls_api.c

index 4507d77d6941f2f0182bb8245890e14a6e5e199e..60ab0c2fe56740042e67ce24e43313aaf185ea1b 100644 (file)
@@ -287,7 +287,9 @@ struct tc_skb_ext {
        __u32 chain;
        __u16 mru;
        __u16 zone;
-       bool post_ct;
+       u8 post_ct:1;
+       u8 post_ct_snat:1;
+       u8 post_ct_dnat:1;
 };
 #endif
 
index 9e71691c491b7a1a00c5fb4ab55cb409704a3f3a..9e7b21c0b3a6de1eeaab533b5fe2fdb3d1794343 100644 (file)
@@ -197,7 +197,9 @@ struct tc_skb_cb {
        struct qdisc_skb_cb qdisc_cb;
 
        u16 mru;
-       bool post_ct;
+       u8 post_ct:1;
+       u8 post_ct_snat:1;
+       u8 post_ct_dnat:1;
        u16 zone; /* Only valid if post_ct = true */
 };
 
index 6d262d9aa10ea1ad48a8bed44b4f65cdb16920db..02096f2ec678468ae92e19538c2b30cea6d21e92 100644 (file)
@@ -859,7 +859,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
 #if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
        struct tc_skb_ext *tc_ext;
 #endif
-       bool post_ct = false;
+       bool post_ct = false, post_ct_snat = false, post_ct_dnat = false;
        int res, err;
        u16 zone = 0;
 
@@ -900,6 +900,8 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
                key->recirc_id = tc_ext ? tc_ext->chain : 0;
                OVS_CB(skb)->mru = tc_ext ? tc_ext->mru : 0;
                post_ct = tc_ext ? tc_ext->post_ct : false;
+               post_ct_snat = post_ct ? tc_ext->post_ct_snat : false;
+               post_ct_dnat = post_ct ? tc_ext->post_ct_dnat : false;
                zone = post_ct ? tc_ext->zone : 0;
        } else {
                key->recirc_id = 0;
@@ -911,8 +913,16 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
        err = key_extract(skb, key);
        if (!err) {
                ovs_ct_fill_key(skb, key, post_ct);   /* Must be after key_extract(). */
-               if (post_ct && !skb_get_nfct(skb))
-                       key->ct_zone = zone;
+               if (post_ct) {
+                       if (!skb_get_nfct(skb)) {
+                               key->ct_zone = zone;
+                       } else {
+                               if (!post_ct_dnat)
+                                       key->ct_state &= ~OVS_CS_F_DST_NAT;
+                               if (!post_ct_snat)
+                                       key->ct_state &= ~OVS_CS_F_SRC_NAT;
+                       }
+               }
        }
        return err;
 }
index ab3591408419ff54ec249266da3a364bb62fad94..2a17eb77c9049fd67571bc92911e43ab2d1d8360 100644 (file)
@@ -839,6 +839,12 @@ static int ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct,
        }
 
        err = nf_nat_packet(ct, ctinfo, hooknum, skb);
+       if (err == NF_ACCEPT) {
+               if (maniptype == NF_NAT_MANIP_SRC)
+                       tc_skb_cb(skb)->post_ct_snat = 1;
+               if (maniptype == NF_NAT_MANIP_DST)
+                       tc_skb_cb(skb)->post_ct_dnat = 1;
+       }
 out:
        return err;
 }
index 35c74bdde848e2d3e100ffd6589946ce9d3d10eb..cc9409aa755eb8224234f8345aa3d5bbdcbeb554 100644 (file)
@@ -1625,6 +1625,8 @@ int tcf_classify(struct sk_buff *skb,
                ext->chain = last_executed_chain;
                ext->mru = cb->mru;
                ext->post_ct = cb->post_ct;
+               ext->post_ct_snat = cb->post_ct_snat;
+               ext->post_ct_dnat = cb->post_ct_dnat;
                ext->zone = cb->zone;
        }