|
@@ -514,10 +514,38 @@ ovs_ct_expect_find(struct net *net, const struct nf_conntrack_zone *zone,
|
|
|
u16 proto, const struct sk_buff *skb)
|
|
|
{
|
|
|
struct nf_conntrack_tuple tuple;
|
|
|
+ struct nf_conntrack_expect *exp;
|
|
|
|
|
|
if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, net, &tuple))
|
|
|
return NULL;
|
|
|
- return __nf_ct_expect_find(net, zone, &tuple);
|
|
|
+
|
|
|
+ exp = __nf_ct_expect_find(net, zone, &tuple);
|
|
|
+ if (exp) {
|
|
|
+ struct nf_conntrack_tuple_hash *h;
|
|
|
+
|
|
|
+ /* Delete existing conntrack entry, if it clashes with the
|
|
|
+ * expectation. This can happen since conntrack ALGs do not
|
|
|
+ * check for clashes between (new) expectations and existing
|
|
|
+ * conntrack entries. nf_conntrack_in() will check the
|
|
|
+ * expectations only if a conntrack entry can not be found,
|
|
|
+ * which can lead to OVS finding the expectation (here) in the
|
|
|
+ * init direction, but which will not be removed by the
|
|
|
+ * nf_conntrack_in() call, if a matching conntrack entry is
|
|
|
+ * found instead. In this case all init direction packets
|
|
|
+ * would be reported as new related packets, while reply
|
|
|
+ * direction packets would be reported as un-related
|
|
|
+ * established packets.
|
|
|
+ */
|
|
|
+ h = nf_conntrack_find_get(net, zone, &tuple);
|
|
|
+ if (h) {
|
|
|
+ struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
|
|
|
+
|
|
|
+ nf_ct_delete(ct, 0, 0);
|
|
|
+ nf_conntrack_put(&ct->ct_general);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return exp;
|
|
|
}
|
|
|
|
|
|
/* This replicates logic from nf_conntrack_core.c that is not exported. */
|