c1bd13fae8cb694cb8a39730e6b87151226a2e7b
[vpp.git] / src / vppinfra / test / toeplitz.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright(c) 2021 Cisco Systems, Inc.
3  */
4
5 #include <vppinfra/format.h>
6 #include <vppinfra/test/test.h>
7 #include <vppinfra/vector/toeplitz.h>
8
9 /* secret key and test cases taken from:
10  * https://docs.microsoft.com/en-us/windows-hardware/drivers/network/verifying-the-rss-hash-calculation
11  */
12
13 typedef struct
14 {
15   u32 sip, dip;
16   u16 sport, dport;
17 } __clib_packed ip4_key_t;
18
19 typedef struct
20 {
21   ip4_key_t key;
22   u32 hash_2t, hash_4t;
23 } ip4_test_t;
24
25 typedef struct
26 {
27   u16 sip[8], dip[8];
28   u16 sport, dport;
29 } __clib_packed ip6_key_t;
30
31 typedef struct
32 {
33   ip6_key_t key;
34   u32 hash_2t, hash_4t;
35 } ip6_test_t;
36
37 #define N_IP4_TESTS    5
38 #define N_IP6_TESTS    3
39 #define N_LENGTH_TESTS 240
40
41 #ifndef CLIB_MARCH_VARIANT
42 #define _IP4(a, b, c, d) ((d) << 24 | (c) << 16 | (b) << 8 | (a))
43 #define _IP6(a, b, c, d, e, f, g, h)                                          \
44   {                                                                           \
45     (u16) ((a) << 8) | (u8) ((a) >> 8), (u16) ((b) << 8) | (u8) ((b) >> 8),   \
46       (u16) ((c) << 8) | (u8) ((c) >> 8), (u16) ((d) << 8) | (u8) ((d) >> 8), \
47       (u16) ((e) << 8) | (u8) ((e) >> 8), (u16) ((f) << 8) | (u8) ((f) >> 8), \
48       (u16) ((g) << 8) | (u8) ((g) >> 8), (u16) ((h) << 8) | (u8) ((h) >> 8), \
49   }
50 #define _PORT(a) ((a) >> 8 | (((a) &0xff) << 8))
51
52 const ip4_test_t ip4_tests[N_IP4_TESTS] = {
53   /* ipv4 tests */
54   {
55     .key.sip = _IP4 (66, 9, 149, 187),
56     .key.dip = _IP4 (161, 142, 100, 80),
57     .key.sport = _PORT (2794),
58     .key.dport = _PORT (1766),
59     .hash_2t = 0x323e8fc2,
60     .hash_4t = 0x51ccc178,
61   },
62   {
63     .key.sip = _IP4 (199, 92, 111, 2),
64     .key.dip = _IP4 (65, 69, 140, 83),
65     .key.sport = _PORT (14230),
66     .key.dport = _PORT (4739),
67     .hash_2t = 0xd718262a,
68     .hash_4t = 0xc626b0ea,
69   },
70   {
71     .key.sip = _IP4 (24, 19, 198, 95),
72     .key.dip = _IP4 (12, 22, 207, 184),
73     .key.sport = _PORT (12898),
74     .key.dport = _PORT (38024),
75     .hash_2t = 0xd2d0a5de,
76     .hash_4t = 0x5c2b394a,
77   },
78   {
79     .key.sip = _IP4 (38, 27, 205, 30),
80     .key.dip = _IP4 (209, 142, 163, 6),
81     .key.sport = _PORT (48228),
82     .key.dport = _PORT (2217),
83     .hash_2t = 0x82989176,
84     .hash_4t = 0xafc7327f,
85   },
86   {
87     .key.sip = _IP4 (153, 39, 163, 191),
88     .key.dip = _IP4 (202, 188, 127, 2),
89     .key.sport = _PORT (44251),
90     .key.dport = _PORT (1303),
91     .hash_2t = 0x5d1809c5,
92     .hash_4t = 0x10e828a2,
93   }
94 };
95
96 const ip6_test_t ip6_tests[N_IP6_TESTS] = {
97   {
98     .key.sip = _IP6 (0x3ffe, 0x2501, 0x200, 0x1fff, 0, 0, 0, 7),
99     .key.dip = _IP6 (0x3ffe, 0x2501, 0x200, 3, 0, 0, 0, 1),
100     .key.sport = _PORT (2794),
101     .key.dport = _PORT (1766),
102     .hash_2t = 0x2cc18cd5,
103     .hash_4t = 0x40207d3d,
104   },
105   {
106     .key.sip = _IP6 (0x3ffe, 0x501, 8, 0, 0x260, 0x97ff, 0xfe40, 0xefab),
107     .key.dip = _IP6 (0xff02, 0, 0, 0, 0, 0, 0, 1),
108     .key.sport = _PORT (14230),
109     .key.dport = _PORT (4739),
110     .hash_2t = 0x0f0c461c,
111     .hash_4t = 0xdde51bbf,
112   },
113   {
114     .key.sip = _IP6 (0x3ffe, 0x1900, 0x4545, 3, 0x200, 0xf8ff, 0xfe21, 0x67cf),
115     .key.dip = _IP6 (0xfe80, 0, 0, 0, 0x200, 0xf8ff, 0xfe21, 0x67cf),
116     .key.sport = _PORT (44251),
117     .key.dport = _PORT (38024),
118     .hash_2t = 0x4b61e985,
119     .hash_4t = 0x02d1feef,
120   }
121 };
122
123 const u32 length_test_hashes[N_LENGTH_TESTS] = {
124   0x00000000, 0x00000000, 0x2b6d12ad, 0x9de4446e, 0x061f00bf, 0xad7ed8f7,
125   0x4bc7b068, 0x231fc545, 0xdbd97a33, 0xcdab29e7, 0x2d665c0c, 0x31e28ed7,
126   0x14e19218, 0x5aa89f0f, 0xd47de07f, 0x355ec712, 0x7e1cbfc0, 0xf84de19d,
127   0xbcf66bd3, 0x104086c6, 0x71900b34, 0xcd2f9819, 0xeae68ebb, 0x54d63b4c,
128   0x5f865a2c, 0x9d6ded08, 0xe00b0912, 0x3fcf07a6, 0x3bd9ca93, 0x3f4f3bbb,
129   0xd0b82624, 0xa28a08e1, 0xa585969f, 0x0c8f4a71, 0x5dce7bdd, 0x4fcf2a6d,
130   0x91c89ae9, 0xbef8a24d, 0x8e3d30fe, 0xc8027848, 0xc1e7e513, 0xa12bd3d9,
131   0x46700bb4, 0xc6339dab, 0x970805ad, 0xfcb50ac8, 0xc6db4f44, 0x792e2987,
132   0xacfb7836, 0xa25ec529, 0x957d7beb, 0x6732809a, 0x891836ed, 0xeefb83b2,
133   0xca96b40b, 0x93fd5abd, 0x9076f922, 0x59adb4eb, 0x9705aafb, 0x282719b1,
134   0xdda9cb8a, 0x3f499131, 0x47491130, 0x30ef0759, 0xad1cf855, 0x428aa312,
135   0x4200240a, 0x71a72857, 0x16b30c36, 0x10cca9a3, 0x166f091e, 0x30e00560,
136   0x8acd20ba, 0xfa633d76, 0x0fe32eb7, 0xdcc0122f, 0x20aa8ab0, 0x62b2a9af,
137   0x7a6c80a6, 0x27e87268, 0x95b797a8, 0x25d18ccd, 0x68a7fb00, 0xc54bcdad,
138   0x3bd0e717, 0xf0df54c9, 0x780daadf, 0x7b435605, 0x150c1e10, 0x8a892e54,
139   0x9d27cb25, 0xe23383a5, 0x57aac408, 0x83b8abf8, 0x560f33af, 0xd5cb3307,
140   0x79ae8edc, 0x9b127665, 0x320f18bd, 0x385d636b, 0xbd1b2dbf, 0x97679888,
141   0x738894a4, 0xeba2afb0, 0xfa7c2d50, 0xb6741aa1, 0x28922bba, 0x7783242b,
142   0xa694cca2, 0xa32781c0, 0x696cd670, 0xa714d72f, 0xea34d35a, 0xc5aed81e,
143   0x0438433a, 0xc1939ab2, 0xb51c123a, 0x121426b9, 0x1add93ba, 0x50c56b6a,
144   0x7e90902a, 0xae3abd85, 0x2f7a0088, 0xb45cf6f9, 0x80070094, 0x8bd46467,
145   0xdfd1b762, 0x0bb25856, 0x48eefe84, 0x0989dbb9, 0xfc32472b, 0x965fec6b,
146   0x5a256bd0, 0x6df7127a, 0x7856d0d6, 0xedc82bd3, 0x1b563b96, 0xc73eace7,
147   0xba4c0a93, 0xdfd6dd97, 0x923c41db, 0x14926ca6, 0x22e52ab1, 0x22852a66,
148   0x79606b9c, 0xb0f22b23, 0xb46354ba, 0x9c3cd931, 0x03a92bd6, 0x84000834,
149   0x5425df65, 0xf4dd3fc9, 0x391cc873, 0xa560b52e, 0x828037d9, 0x31323dd5,
150   0x5c6e3147, 0x28e21f85, 0xa431eb51, 0xf468c4a3, 0x9bea1d2e, 0x43d9109c,
151   0x5bb9b081, 0xe0825675, 0xc9c92591, 0xd29fc812, 0x03136bc9, 0x5e005a1f,
152   0x6d821ed8, 0x3f0bfcc4, 0x24774162, 0x893bde94, 0x6475efea, 0x6711538e,
153   0xc4755f6d, 0x9425ebe2, 0xacf471b4, 0xb947ab0c, 0x1f78c455, 0x372b3ed7,
154   0xb3ec24d7, 0x18c4459f, 0xa8ff3695, 0xe4aa2b85, 0x8a52ad7e, 0xe05e8177,
155   0x7aa348ed, 0x3e4ac6aa, 0x17dcf8a5, 0x93b933b0, 0x8f7413ec, 0xc77bfe61,
156   0xfdb72874, 0x4370f138, 0xdf3462ad, 0xc8970a59, 0xb4a9fed8, 0xa2ddc39b,
157   0xd61db62a, 0x95c5fc1b, 0x7b22e6e0, 0x1969702c, 0x7992aebb, 0x59d7c225,
158   0x0e16db0b, 0x9f2afc21, 0x246cf66b, 0xb3d6569d, 0x29c532d7, 0xe155747a,
159   0xe38d7872, 0xea704969, 0xb69095b0, 0x1b198efd, 0x55daab76, 0xa2a377b6,
160   0xb31aa2fa, 0x48b73c41, 0xf0cc501a, 0x9c9ca831, 0x1b591b99, 0xb2d8d22f,
161   0xab4b5f69, 0x4fe00e71, 0xdf5480bd, 0x982540d7, 0x7f34ea4f, 0xd7be66e1,
162   0x9d2ab1ba, 0x1ba62e12, 0xee3fb36c, 0xf28d7c5a, 0x756311eb, 0xc68567f2,
163   0x7b6ea177, 0xc398d9f3
164 };
165
166 #else
167 extern const ip4_test_t ip4_tests[N_IP4_TESTS];
168 extern const ip6_test_t ip6_tests[N_IP6_TESTS];
169 extern const u32 length_test_hashes[N_LENGTH_TESTS];
170 #endif
171
172 __test_funct_fn u32
173 wrapper (clib_toeplitz_hash_key_t *k, u8 *data, u32 n_bytes)
174 {
175   return clib_toeplitz_hash (k, data, n_bytes);
176 }
177
178 __test_funct_fn void
179 wrapper_x4 (clib_toeplitz_hash_key_t *k, u8 *d0, u8 *d1, u8 *d2, u8 *d3,
180             u32 *h0, u32 *h1, u32 *h2, u32 *h3, u32 n_bytes)
181 {
182   clib_toeplitz_hash_x4 (k, d0, d1, d2, d3, h0, h1, h2, h3, n_bytes);
183 }
184
185 static clib_error_t *
186 test_clib_toeplitz_hash (clib_error_t *err)
187 {
188   u32 r;
189   int n_key_copies, bigkey_len, bigdata_len;
190   u8 *bigkey, *bigdata;
191   clib_toeplitz_hash_key_t *k;
192
193   k = clib_toeplitz_hash_key_init (0, 0);
194
195   for (int i = 0; i < N_IP4_TESTS; i++)
196     {
197       r = wrapper (k, (u8 *) &ip4_tests[i].key, 8);
198       if (ip4_tests[i].hash_2t != r)
199         return clib_error_return (err,
200                                   "wrong IPv4 2 tuple hash for test %u, "
201                                   "calculated 0x%08x expected 0x%08x",
202                                   i, ip4_tests[i].hash_2t, r);
203
204       r = wrapper (k, (u8 *) &ip4_tests[i].key, 12);
205       if (ip4_tests[i].hash_4t != r)
206         return clib_error_return (err,
207                                   "wrong IPv4 4 tuple hash for test %u, "
208                                   "calculated 0x%08x expected 0x%08x",
209                                   i, ip4_tests[i].hash_4t, r);
210     }
211
212   for (int i = 0; i < N_IP6_TESTS; i++)
213     {
214       r = wrapper (k, (u8 *) &ip6_tests[i].key, 32);
215       if (ip6_tests[i].hash_2t != r)
216         return clib_error_return (err,
217                                   "wrong IPv6 2 tuple hash for test %u, "
218                                   "calculated 0x%08x expected 0x%08x",
219                                   i, ip6_tests[i].hash_2t, r);
220
221       r = wrapper (k, (u8 *) &ip6_tests[i].key, 36);
222       if (ip6_tests[i].hash_4t != r)
223         return clib_error_return (err,
224                                   "wrong IPv6 4 tuple hash for test %u, "
225                                   "calculated 0x%08x expected 0x%08x",
226                                   i, ip6_tests[i].hash_4t, r);
227     }
228
229   n_key_copies = 6;
230   bigkey_len = k->key_length * n_key_copies;
231   bigdata_len = bigkey_len - 4;
232   bigkey = test_mem_alloc_and_splat (k->key_length, n_key_copies, k->data);
233   bigdata = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
234   u32 key_len = k->key_length;
235
236   clib_toeplitz_hash_key_free (k);
237   k = clib_toeplitz_hash_key_init (bigkey, n_key_copies * key_len);
238
239   for (int i = 0; i < N_LENGTH_TESTS - 4; i++)
240     {
241       r = wrapper (k, bigdata, i);
242       if (length_test_hashes[i] != r)
243         {
244           err = clib_error_return (err,
245                                    "wrong length test hash for length %u, "
246                                    "calculated 0x%08x expected 0x%08x "
247                                    "xor 0x%08x",
248                                    i, r, length_test_hashes[i],
249                                    r ^ length_test_hashes[i]);
250           goto done;
251         }
252     }
253
254 done:
255   clib_toeplitz_hash_key_free (k);
256   test_mem_free (bigkey);
257   test_mem_free (bigdata);
258   return err;
259 }
260
261 void __test_perf_fn
262 perftest_fixed_12byte (test_perf_t *tp)
263 {
264   u32 n = tp->n_ops;
265   u8 *data = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[0].key);
266   u8 *res = test_mem_alloc (4 * n);
267   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
268
269   test_perf_event_enable (tp);
270   for (int i = 0; i < n; i++)
271     ((u32 *) res)[i] = clib_toeplitz_hash (k, data + i * 12, 12);
272   test_perf_event_disable (tp);
273
274   clib_toeplitz_hash_key_free (k);
275   test_mem_free (data);
276   test_mem_free (res);
277 }
278
279 void __test_perf_fn
280 perftest_fixed_36byte (test_perf_t *tp)
281 {
282   u32 n = tp->n_ops;
283   u8 *data = test_mem_alloc_and_splat (36, n, (void *) &ip6_tests[0].key);
284   u8 *res = test_mem_alloc (4 * n);
285   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
286
287   test_perf_event_enable (tp);
288   for (int i = 0; i < n; i++)
289     ((u32 *) res)[i] = clib_toeplitz_hash (k, data + i * 36, 36);
290   test_perf_event_disable (tp);
291
292   clib_toeplitz_hash_key_free (k);
293   test_mem_free (data);
294   test_mem_free (res);
295 }
296
297 void __test_perf_fn
298 perftest_variable_size (test_perf_t *tp)
299 {
300   u32 key_len, n_keys, n = tp->n_ops;
301   u8 *key, *data = test_mem_alloc (n);
302   u32 *res = test_mem_alloc (sizeof (u32));
303   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
304
305   k = clib_toeplitz_hash_key_init (0, 0);
306   key_len = k->key_length;
307   n_keys = ((n + 4) / k->key_length) + 1;
308   key = test_mem_alloc_and_splat (n_keys, key_len, k->data);
309   clib_toeplitz_hash_key_free (k);
310   k = clib_toeplitz_hash_key_init (key, key_len * n_keys);
311
312   test_perf_event_enable (tp);
313   res[0] = clib_toeplitz_hash (k, data, n);
314   test_perf_event_disable (tp);
315
316   clib_toeplitz_hash_key_free (k);
317   test_mem_free (data);
318   test_mem_free (res);
319   test_mem_free (key);
320 }
321
322 REGISTER_TEST (clib_toeplitz_hash) = {
323   .name = "clib_toeplitz_hash",
324   .fn = test_clib_toeplitz_hash,
325   .perf_tests = PERF_TESTS ({ .name = "fixed (per 12 byte tuple)",
326                               .n_ops = 1024,
327                               .fn = perftest_fixed_12byte },
328                             { .name = "fixed (per 36 byte tuple)",
329                               .n_ops = 1024,
330                               .fn = perftest_fixed_36byte },
331                             { .name = "variable size (per byte)",
332                               .n_ops = 16384,
333                               .fn = perftest_variable_size }),
334 };
335
336 static clib_error_t *
337 test_clib_toeplitz_hash_x4 (clib_error_t *err)
338 {
339   u32 r[4];
340   int n_key_copies, bigkey_len, bigdata_len;
341   u8 *bigkey, *bigdata0, *bigdata1, *bigdata2, *bigdata3;
342   clib_toeplitz_hash_key_t *k;
343
344   k = clib_toeplitz_hash_key_init (0, 0);
345
346   wrapper_x4 (k, (u8 *) &ip4_tests[0].key, (u8 *) &ip4_tests[1].key,
347               (u8 *) &ip4_tests[2].key, (u8 *) &ip4_tests[3].key, r, r + 1,
348               r + 2, r + 3, 8);
349
350   if (ip4_tests[0].hash_2t != r[0] || ip4_tests[1].hash_2t != r[1] ||
351       ip4_tests[2].hash_2t != r[2] || ip4_tests[3].hash_2t != r[3])
352     return clib_error_return (err,
353                               "wrong IPv4 2 tuple x4 hash "
354                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
355                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
356                               ip4_tests[0].hash_2t, ip4_tests[1].hash_2t,
357                               ip4_tests[2].hash_2t, ip4_tests[3].hash_2t, r[0],
358                               r[1], r[2], r[3]);
359
360   wrapper_x4 (k, (u8 *) &ip4_tests[0].key, (u8 *) &ip4_tests[1].key,
361               (u8 *) &ip4_tests[2].key, (u8 *) &ip4_tests[3].key, r, r + 1,
362               r + 2, r + 3, 12);
363
364   if (ip4_tests[0].hash_4t != r[0] || ip4_tests[1].hash_4t != r[1] ||
365       ip4_tests[2].hash_4t != r[2] || ip4_tests[3].hash_4t != r[3])
366     return clib_error_return (err,
367                               "wrong IPv4 4 tuple x4 hash "
368                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
369                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
370                               ip4_tests[0].hash_4t, ip4_tests[1].hash_4t,
371                               ip4_tests[2].hash_4t, ip4_tests[3].hash_4t, r[0],
372                               r[1], r[2], r[3]);
373
374   wrapper_x4 (k, (u8 *) &ip6_tests[0].key, (u8 *) &ip6_tests[1].key,
375               (u8 *) &ip6_tests[2].key, (u8 *) &ip6_tests[0].key, r, r + 1,
376               r + 2, r + 3, 32);
377
378   if (ip6_tests[0].hash_2t != r[0] || ip6_tests[1].hash_2t != r[1] ||
379       ip6_tests[2].hash_2t != r[2] || ip6_tests[0].hash_2t != r[3])
380     return clib_error_return (err,
381                               "wrong IPv6 2 tuple x4 hash "
382                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
383                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
384                               ip6_tests[0].hash_2t, ip6_tests[1].hash_2t,
385                               ip6_tests[2].hash_2t, ip6_tests[0].hash_2t, r[0],
386                               r[1], r[2], r[3]);
387
388   wrapper_x4 (k, (u8 *) &ip6_tests[0].key, (u8 *) &ip6_tests[1].key,
389               (u8 *) &ip6_tests[2].key, (u8 *) &ip6_tests[0].key, r, r + 1,
390               r + 2, r + 3, 36);
391
392   if (ip6_tests[0].hash_4t != r[0] || ip6_tests[1].hash_4t != r[1] ||
393       ip6_tests[2].hash_4t != r[2] || ip6_tests[0].hash_4t != r[3])
394     return clib_error_return (err,
395                               "wrong IPv6 4 tuple x4 hash "
396                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
397                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
398                               ip6_tests[0].hash_4t, ip6_tests[1].hash_4t,
399                               ip6_tests[2].hash_4t, ip6_tests[0].hash_4t, r[0],
400                               r[1], r[2], r[3]);
401
402   n_key_copies = 6;
403   bigkey_len = k->key_length * n_key_copies;
404   bigdata_len = bigkey_len - 4;
405   bigkey = test_mem_alloc_and_splat (k->key_length, n_key_copies, k->data);
406   bigdata0 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
407   bigdata1 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
408   bigdata2 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
409   bigdata3 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
410   u32 key_len = k->key_length;
411
412   clib_toeplitz_hash_key_free (k);
413   k = clib_toeplitz_hash_key_init (bigkey, n_key_copies * key_len);
414
415   for (int i = 0; i < N_LENGTH_TESTS - 4; i++)
416     {
417       wrapper_x4 (k, bigdata0, bigdata1, bigdata2, bigdata3, r, r + 1, r + 2,
418                   r + 3, i);
419       if (length_test_hashes[i] != r[0] || length_test_hashes[i] != r[1] ||
420           length_test_hashes[i] != r[2] || length_test_hashes[i] != r[3])
421         {
422           err = clib_error_return (
423             err,
424             "wrong length test hash x4 for length %u, "
425             "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x }, expected 0x%08x",
426             i, r[0], r[1], r[2], r[3], length_test_hashes[i]);
427           goto done;
428         }
429     }
430
431 done:
432   clib_toeplitz_hash_key_free (k);
433   test_mem_free (bigkey);
434   test_mem_free (bigdata0);
435   test_mem_free (bigdata1);
436   test_mem_free (bigdata2);
437   test_mem_free (bigdata3);
438   return err;
439 }
440
441 void __test_perf_fn
442 perftest_fixed_12byte_x4 (test_perf_t *tp)
443 {
444   u32 n = tp->n_ops / 4;
445   u8 *d0 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[0].key);
446   u8 *d1 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[1].key);
447   u8 *d2 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[2].key);
448   u8 *d3 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[3].key);
449   u32 *h0 = test_mem_alloc (4 * n);
450   u32 *h1 = test_mem_alloc (4 * n);
451   u32 *h2 = test_mem_alloc (4 * n);
452   u32 *h3 = test_mem_alloc (4 * n);
453   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
454
455   test_perf_event_enable (tp);
456   for (int i = 0; i < n; i++)
457     clib_toeplitz_hash_x4 (k, d0 + i * 12, d1 + i * 12, d2 + i * 12,
458                            d3 + i * 12, h0 + i, h1 + i, h2 + i, h3 + i, 12);
459   test_perf_event_disable (tp);
460
461   clib_toeplitz_hash_key_free (k);
462   test_mem_free (d0);
463   test_mem_free (d1);
464   test_mem_free (d2);
465   test_mem_free (d3);
466   test_mem_free (h0);
467   test_mem_free (h1);
468   test_mem_free (h2);
469   test_mem_free (h3);
470 }
471
472 void __test_perf_fn
473 perftest_fixed_36byte_x4 (test_perf_t *tp)
474 {
475   u32 n = tp->n_ops / 4;
476   u8 *d0 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[0].key);
477   u8 *d1 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[1].key);
478   u8 *d2 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[2].key);
479   u8 *d3 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[3].key);
480   u32 *h0 = test_mem_alloc (4 * n);
481   u32 *h1 = test_mem_alloc (4 * n);
482   u32 *h2 = test_mem_alloc (4 * n);
483   u32 *h3 = test_mem_alloc (4 * n);
484   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
485
486   test_perf_event_enable (tp);
487   for (int i = 0; i < n; i++)
488     clib_toeplitz_hash_x4 (k, d0 + i * 36, d1 + i * 36, d2 + i * 36,
489                            d3 + i * 36, h0 + i, h1 + i, h2 + i, h3 + i, 36);
490   test_perf_event_disable (tp);
491
492   clib_toeplitz_hash_key_free (k);
493   test_mem_free (d0);
494   test_mem_free (d1);
495   test_mem_free (d2);
496   test_mem_free (d3);
497   test_mem_free (h0);
498   test_mem_free (h1);
499   test_mem_free (h2);
500   test_mem_free (h3);
501 }
502
503 void __test_perf_fn
504 perftest_variable_size_x4 (test_perf_t *tp)
505 {
506   u32 key_len, n_keys, n = tp->n_ops / 4;
507   u8 *key;
508   u8 *d0 = test_mem_alloc (n);
509   u8 *d1 = test_mem_alloc (n);
510   u8 *d2 = test_mem_alloc (n);
511   u8 *d3 = test_mem_alloc (n);
512   u32 *h0 = test_mem_alloc (sizeof (u32));
513   u32 *h1 = test_mem_alloc (sizeof (u32));
514   u32 *h2 = test_mem_alloc (sizeof (u32));
515   u32 *h3 = test_mem_alloc (sizeof (u32));
516   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
517
518   k = clib_toeplitz_hash_key_init (0, 0);
519   key_len = k->key_length;
520   n_keys = ((n + 4) / k->key_length) + 1;
521   key = test_mem_alloc_and_splat (n_keys, key_len, k->data);
522   clib_toeplitz_hash_key_free (k);
523   k = clib_toeplitz_hash_key_init (key, key_len * n_keys);
524
525   test_perf_event_enable (tp);
526   clib_toeplitz_hash_x4 (k, d0, d1, d2, d3, h0, h1, h2, h3, n);
527   test_perf_event_disable (tp);
528
529   clib_toeplitz_hash_key_free (k);
530   test_mem_free (key);
531   test_mem_free (d0);
532   test_mem_free (d1);
533   test_mem_free (d2);
534   test_mem_free (d3);
535   test_mem_free (h0);
536   test_mem_free (h1);
537   test_mem_free (h2);
538   test_mem_free (h3);
539 }
540
541 REGISTER_TEST (clib_toeplitz_hash_x4) = {
542   .name = "clib_toeplitz_hash_x4",
543   .fn = test_clib_toeplitz_hash_x4,
544   .perf_tests = PERF_TESTS ({ .name = "fixed (per 12 byte tuple)",
545                               .n_ops = 1024,
546                               .fn = perftest_fixed_12byte_x4 },
547                             { .name = "fixed (per 36 byte tuple)",
548                               .n_ops = 1024,
549                               .fn = perftest_fixed_36byte_x4 },
550                             { .name = "variable size (per byte)",
551                               .n_ops = 16384,
552                               .fn = perftest_variable_size_x4 }),
553 };