Patrick Schaaf writes:
 > > Everybody, have a look at http://bei.bof.de/ex1/. There's a bunch of
 > > pictures, which may become legible together with reading my recent
 > > mails on this thread.

The only thing that looks really suspicious to me is the lump in
original for large table sizes.

I tried this myself:
 # time ./cttest -u -f ../ip_conntrack.2 -s 131073
 filename: ../ip_conntrack.2
 hash function: original
 number of buckets: 131073
 maximum bucket list length: 24
 total number of entries: 32866
 Count  Length  CT
 1      24      0.07%
 1      19      0.13%
 1      14      0.17%
 2      8       0.22%
 13     7       0.50%
 31     6       1.06%
 130    5       3.04%
 276    4       6.40%
 821    3       13.90%
 3392   2       34.54%
 21515  1       100.00%
 104890 0       100.00%

BTW 5 is already at the low end of the probability, as you see for the
other two hashes.

Then, as usual, show the data for the longest bucket, read it into my
lisp program and take differences ...
  > (loop for x in data do (print (loop for z in (first data) as y in x collect (- z 
y))))

  (0 0 0 0 0) 
  (0 0 0 2 2) 
  (0 0 0 4 4) 
  (0 0 0 6 6) 
  (0 0 0 8 8) 
  (0 0 0 10 10) 
  (0 0 0 12 12) 
  (0 0 0 14 14) 
  (0 -498354813 738840907 37187 38280) 
  (0 0 0 -6 -6) 
  (0 0 0 -20 -20) 
  (0 0 0 -27 -27) 
  (0 0 0 -2 -2) 
  (0 0 0 -16 -16) 
  (0 0 0 -37 -37) 
  (0 0 0 -12 -12) 
  (0 0 0 -33 -33) 
  (0 0 0 -8 -8) 
  (0 0 0 -29 -29) 
  (0 0 0 -18 -18) 
  (0 0 0 -25 -25) 
  (0 0 0 -4 -4) 
  (0 0 0 -35 -35) 
  (0 0 0 -31 -31) 

I also changed cttest to print hash data (all hex):
sip 100ce87 dip 100ce87 sport d995 dport d895 proto 6 result 3e4f98db
sip 100ce87 dip 100ce87 sport d795 dport d695 proto 6 result 3e4b98d9
sip 100ce87 dip 100ce87 sport d595 dport d495 proto 6 result 3e4798d7
sip 100ce87 dip 100ce87 sport d395 dport d295 proto 6 result 3e4398d5
sip 100ce87 dip 100ce87 sport d195 dport d095 proto 6 result 3e3f98d3
sip 100ce87 dip 100ce87 sport cf95 dport ce95 proto 6 result 3e3b98d1
sip 100ce87 dip 100ce87 sport cd95 dport cc95 proto 6 result 3e3798cf
sip 100ce87 dip 100ce87 sport cb95 dport ca95 proto 6 result 3e3398cd
sip 7e4a82a5 dip b62ec45b sport 9604 dport 5000 proto 6 result a2d7eca
sip 100ce87 dip 100ce87 sport df95 dport de95 proto 6 result 3e5b98e1
sip 100ce87 dip 100ce87 sport ed95 dport ec95 proto 6 result 3e7798ef
sip 100ce87 dip 100ce87 sport f495 dport f395 proto 6 result 3e8598f6
sip 100ce87 dip 100ce87 sport db95 dport da95 proto 6 result 3e5398dd
sip 100ce87 dip 100ce87 sport e995 dport e895 proto 6 result 3e6f98eb
sip 100ce87 dip 100ce87 sport fe95 dport fd95 proto 6 result 3e999900
sip 100ce87 dip 100ce87 sport e595 dport e495 proto 6 result 3e6798e7
sip 100ce87 dip 100ce87 sport fa95 dport f995 proto 6 result 3e9198fc
sip 100ce87 dip 100ce87 sport e195 dport e095 proto 6 result 3e5f98e3
sip 100ce87 dip 100ce87 sport f695 dport f595 proto 6 result 3e8998f8
sip 100ce87 dip 100ce87 sport eb95 dport ea95 proto 6 result 3e7398ed
sip 100ce87 dip 100ce87 sport f295 dport f195 proto 6 result 3e8198f4
sip 100ce87 dip 100ce87 sport dd95 dport dc95 proto 6 result 3e5798df
sip 100ce87 dip 100ce87 sport fc95 dport fb95 proto 6 result 3e9598fe
sip 100ce87 dip 100ce87 sport f895 dport f795 proto 6 result 3e8d98fa


It seems that adding n to the two ports (which is what happens almost
every time here) gives a difference in the hash function of n*131073 !!

static u32 hash_conntrack(struct ct_key *key)
{
  u32 ans;
  ans= ntohl(key->sip + key->dip
                + key->sport + key->dport
                + key->proto)
                + ntohs(key->sport);
  printf("sip %x dip %x sport %x dport %x proto %x result %x\n", 
         key->sip, key->dip, key->sport, key->dport, key->proto, ans);
  return ans;
}

I think this is related to the ntohl and ntohs.  If all the data were 0
the sum would be 0.  When you add 1 to sport and dport you get something
like 2^16 + 2 ?
which is 2 x our unlucky table size, right?
Or something like that.
And similar things happen with table size 2^n-1.
Basically the problem with this sort of hash function is that you get 
collisions when you have a lot of IP and port pairs that are close to
each other with the wrong sort of correlation.

Have you tried the ABCD suggestion I posted?
Just as a quick test:
static u32 hash_conntrack(struct ct_key *key)
{
 return
   0x47441DFB * key->sip
   + 0x57655A7D * key->dip
   + 0x1C7F1D2D * key->sport
   + 0xDF91D738 * key->dport
   + key->proto;

coefficients chosen at random from [0, 2^32)

# time ./cttest -u -f ../ip_conntrack.2 -s 131073
filename: ../ip_conntrack.2
hash function: original
number of buckets: 131073
maximum bucket list length: 5
total number of entries: 32866
Count   Length  CT
1       5       0.02%
15      4       0.20%
253     3       2.51%
3180    2       21.86%
25682   1       100.00%
101942  0       100.00%

Longest bucket with 131071 is also 5, with 131072 is 36 (as
advertised!).

Reply via email to