|
|
@@ -430,7 +430,7 @@ ovs_ct_get_info(const struct nf_conntrack_tuple_hash *h)
|
|
|
*/
|
|
|
static struct nf_conn *
|
|
|
ovs_ct_find_existing(struct net *net, const struct nf_conntrack_zone *zone,
|
|
|
- u8 l3num, struct sk_buff *skb)
|
|
|
+ u8 l3num, struct sk_buff *skb, bool natted)
|
|
|
{
|
|
|
struct nf_conntrack_l3proto *l3proto;
|
|
|
struct nf_conntrack_l4proto *l4proto;
|
|
|
@@ -453,6 +453,17 @@ ovs_ct_find_existing(struct net *net, const struct nf_conntrack_zone *zone,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+ /* Must invert the tuple if skb has been transformed by NAT. */
|
|
|
+ if (natted) {
|
|
|
+ struct nf_conntrack_tuple inverse;
|
|
|
+
|
|
|
+ if (!nf_ct_invert_tuple(&inverse, &tuple, l3proto, l4proto)) {
|
|
|
+ pr_debug("ovs_ct_find_existing: Inversion failed!\n");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ tuple = inverse;
|
|
|
+ }
|
|
|
+
|
|
|
/* look for tuple match */
|
|
|
h = nf_conntrack_find_get(net, zone, &tuple);
|
|
|
if (!h)
|
|
|
@@ -460,6 +471,13 @@ ovs_ct_find_existing(struct net *net, const struct nf_conntrack_zone *zone,
|
|
|
|
|
|
ct = nf_ct_tuplehash_to_ctrack(h);
|
|
|
|
|
|
+ /* Inverted packet tuple matches the reverse direction conntrack tuple,
|
|
|
+ * select the other tuplehash to get the right 'ctinfo' bits for this
|
|
|
+ * packet.
|
|
|
+ */
|
|
|
+ if (natted)
|
|
|
+ h = &ct->tuplehash[!h->tuple.dst.dir];
|
|
|
+
|
|
|
nf_ct_set(skb, ct, ovs_ct_get_info(h));
|
|
|
return ct;
|
|
|
}
|
|
|
@@ -482,7 +500,9 @@ static bool skb_nfct_cached(struct net *net,
|
|
|
if (!ct && key->ct.state & OVS_CS_F_TRACKED &&
|
|
|
!(key->ct.state & OVS_CS_F_INVALID) &&
|
|
|
key->ct.zone == info->zone.id)
|
|
|
- ct = ovs_ct_find_existing(net, &info->zone, info->family, skb);
|
|
|
+ ct = ovs_ct_find_existing(net, &info->zone, info->family, skb,
|
|
|
+ !!(key->ct.state
|
|
|
+ & OVS_CS_F_NAT_MASK));
|
|
|
if (!ct)
|
|
|
return false;
|
|
|
if (!net_eq(net, read_pnet(&ct->ct_net)))
|