@@ -894,31 +894,64 @@ static void nf_ct_acct_merge(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
894
894
}
895
895
}
896
896
897
- /* Resolve race on insertion if this protocol allows this. */
897
+ /**
898
+ * nf_ct_resolve_clash - attempt to handle clash without packet drop
899
+ *
900
+ * @skb: skb that causes the clash
901
+ * @h: tuplehash of the clashing entry already in table
902
+ *
903
+ * A conntrack entry can be inserted to the connection tracking table
904
+ * if there is no existing entry with an identical tuple.
905
+ *
906
+ * If there is one, @skb (and the assocated, unconfirmed conntrack) has
907
+ * to be dropped. In case @skb is retransmitted, next conntrack lookup
908
+ * will find the already-existing entry.
909
+ *
910
+ * The major problem with such packet drop is the extra delay added by
911
+ * the packet loss -- it will take some time for a retransmit to occur
912
+ * (or the sender to time out when waiting for a reply).
913
+ *
914
+ * This function attempts to handle the situation without packet drop.
915
+ *
916
+ * If @skb has no NAT transformation or if the colliding entries are
917
+ * exactly the same, only the to-be-confirmed conntrack entry is discarded
918
+ * and @skb is associated with the conntrack entry already in the table.
919
+ *
920
+ * Returns NF_DROP if the clash could not be resolved.
921
+ */
898
922
static __cold noinline int
899
- nf_ct_resolve_clash (struct net * net , struct sk_buff * skb ,
900
- enum ip_conntrack_info ctinfo ,
901
- struct nf_conntrack_tuple_hash * h )
923
+ nf_ct_resolve_clash (struct sk_buff * skb , struct nf_conntrack_tuple_hash * h )
902
924
{
903
925
/* This is the conntrack entry already in hashes that won race. */
904
926
struct nf_conn * ct = nf_ct_tuplehash_to_ctrack (h );
905
927
const struct nf_conntrack_l4proto * l4proto ;
906
- enum ip_conntrack_info oldinfo ;
907
- struct nf_conn * loser_ct = nf_ct_get (skb , & oldinfo );
928
+ enum ip_conntrack_info ctinfo ;
929
+ struct nf_conn * loser_ct ;
930
+ struct net * net ;
931
+
932
+ loser_ct = nf_ct_get (skb , & ctinfo );
908
933
909
934
l4proto = nf_ct_l4proto_find (nf_ct_protonum (ct ));
910
- if (l4proto -> allow_clash &&
911
- !nf_ct_is_dying (ct ) &&
912
- atomic_inc_not_zero (& ct -> ct_general .use )) {
913
- if (((ct -> status & IPS_NAT_DONE_MASK ) == 0 ) ||
914
- nf_ct_match (ct , loser_ct )) {
915
- nf_ct_acct_merge (ct , ctinfo , loser_ct );
916
- nf_conntrack_put (& loser_ct -> ct_general );
917
- nf_ct_set (skb , ct , oldinfo );
918
- return NF_ACCEPT ;
919
- }
920
- nf_ct_put (ct );
935
+ if (!l4proto -> allow_clash )
936
+ goto drop ;
937
+
938
+ if (nf_ct_is_dying (ct ))
939
+ goto drop ;
940
+
941
+ if (!atomic_inc_not_zero (& ct -> ct_general .use ))
942
+ goto drop ;
943
+
944
+ if (((ct -> status & IPS_NAT_DONE_MASK ) == 0 ) ||
945
+ nf_ct_match (ct , loser_ct )) {
946
+ nf_ct_acct_merge (ct , ctinfo , loser_ct );
947
+ nf_conntrack_put (& loser_ct -> ct_general );
948
+ nf_ct_set (skb , ct , ctinfo );
949
+ return NF_ACCEPT ;
921
950
}
951
+
952
+ nf_ct_put (ct );
953
+ drop :
954
+ net = nf_ct_net (loser_ct );
922
955
NF_CT_STAT_INC (net , drop );
923
956
return NF_DROP ;
924
957
}
@@ -1036,7 +1069,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
1036
1069
1037
1070
out :
1038
1071
nf_ct_add_to_dying_list (ct );
1039
- ret = nf_ct_resolve_clash (net , skb , ctinfo , h );
1072
+ ret = nf_ct_resolve_clash (skb , h );
1040
1073
dying :
1041
1074
nf_conntrack_double_unlock (hash , reply_hash );
1042
1075
NF_CT_STAT_INC (net , insert_failed );
0 commit comments