test/crypto: skip null auth in ICV corrupt case
[dpdk.git] / app / test / test_rcu_qsbr.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2019-2020 Arm Limited
3  */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <rte_pause.h>
8 #include <rte_rcu_qsbr.h>
9 #include <rte_hash.h>
10 #include <rte_hash_crc.h>
11 #include <rte_malloc.h>
12 #include <rte_cycles.h>
13 #include <rte_random.h>
14 #include <unistd.h>
15
16 #include "test.h"
17
18 /* Check condition and return an error if true. */
19 #define TEST_RCU_QSBR_RETURN_IF_ERROR(cond, str, ...) \
20 do { \
21         if (cond) { \
22                 printf("ERROR file %s, line %d: " str "\n", __FILE__, \
23                         __LINE__, ##__VA_ARGS__); \
24                 return -1; \
25         } \
26 } while (0)
27
28 /* Check condition and go to label if true. */
29 #define TEST_RCU_QSBR_GOTO_IF_ERROR(label, cond, str, ...) \
30 do { \
31         if (cond) { \
32                 printf("ERROR file %s, line %d: " str "\n", __FILE__, \
33                         __LINE__, ##__VA_ARGS__); \
34                 goto label; \
35         } \
36 } while (0)
37
38 /* Make sure that this has the same value as __RTE_QSBR_CNT_INIT */
39 #define TEST_RCU_QSBR_CNT_INIT 1
40
41 static uint16_t enabled_core_ids[RTE_MAX_LCORE];
42 static unsigned int num_cores;
43
44 static uint32_t *keys;
45 #define TOTAL_ENTRY (1024 * 8)
46 #define COUNTER_VALUE 4096
47 static uint32_t *hash_data[RTE_MAX_LCORE][TOTAL_ENTRY];
48 static uint8_t writer_done;
49 static uint8_t cb_failed;
50
51 static struct rte_rcu_qsbr *t[RTE_MAX_LCORE];
52 static struct rte_hash *h[RTE_MAX_LCORE];
53 static char hash_name[RTE_MAX_LCORE][8];
54
55 struct test_rcu_thread_info {
56         /* Index in RCU array */
57         int ir;
58         /* Index in hash array */
59         int ih;
60         /* lcore IDs registered on the RCU variable */
61         uint16_t r_core_ids[2];
62 };
63 static struct test_rcu_thread_info thread_info[RTE_MAX_LCORE/4];
64
65 static int
66 alloc_rcu(void)
67 {
68         int i;
69         size_t sz;
70
71         sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
72
73         for (i = 0; i < RTE_MAX_LCORE; i++)
74                 t[i] = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz,
75                                                 RTE_CACHE_LINE_SIZE);
76
77         return 0;
78 }
79
80 static int
81 free_rcu(void)
82 {
83         int i;
84
85         for (i = 0; i < RTE_MAX_LCORE; i++)
86                 rte_free(t[i]);
87
88         return 0;
89 }
90
91 /*
92  * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
93  * reporting their quiescent state on a QS variable.
94  */
95 static int
96 test_rcu_qsbr_get_memsize(void)
97 {
98         size_t sz;
99
100         printf("\nTest rte_rcu_qsbr_thread_register()\n");
101
102         sz = rte_rcu_qsbr_get_memsize(0);
103         TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 1), "Get Memsize for 0 threads");
104
105         sz = rte_rcu_qsbr_get_memsize(128);
106         /* For 128 threads,
107          * for machines with cache line size of 64B - 8384
108          * for machines with cache line size of 128 - 16768
109          */
110         if (RTE_CACHE_LINE_SIZE == 64)
111                 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 8384),
112                         "Get Memsize for 128 threads");
113         else if (RTE_CACHE_LINE_SIZE == 128)
114                 TEST_RCU_QSBR_RETURN_IF_ERROR((sz != 16768),
115                         "Get Memsize for 128 threads");
116
117         return 0;
118 }
119
120 /*
121  * rte_rcu_qsbr_init: Initialize a QSBR variable.
122  */
123 static int
124 test_rcu_qsbr_init(void)
125 {
126         int r;
127
128         printf("\nTest rte_rcu_qsbr_init()\n");
129
130         r = rte_rcu_qsbr_init(NULL, RTE_MAX_LCORE);
131         TEST_RCU_QSBR_RETURN_IF_ERROR((r != 1), "NULL variable");
132
133         return 0;
134 }
135
136 /*
137  * rte_rcu_qsbr_thread_register: Add a reader thread, to the list of threads
138  * reporting their quiescent state on a QS variable.
139  */
140 static int
141 test_rcu_qsbr_thread_register(void)
142 {
143         int ret;
144
145         printf("\nTest rte_rcu_qsbr_thread_register()\n");
146
147         ret = rte_rcu_qsbr_thread_register(NULL, enabled_core_ids[0]);
148         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
149
150         ret = rte_rcu_qsbr_thread_register(NULL, 100000);
151         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
152                 "NULL variable, invalid thread id");
153
154         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
155
156         /* Register valid thread id */
157         ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
158         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Valid thread id");
159
160         /* Re-registering should not return error */
161         ret = rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
162         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
163                 "Already registered thread id");
164
165         /* Register valid thread id - max allowed thread id */
166         ret = rte_rcu_qsbr_thread_register(t[0], RTE_MAX_LCORE - 1);
167         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "Max thread id");
168
169         ret = rte_rcu_qsbr_thread_register(t[0], 100000);
170         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
171                 "NULL variable, invalid thread id");
172
173         return 0;
174 }
175
176 /*
177  * rte_rcu_qsbr_thread_unregister: Remove a reader thread, from the list of
178  * threads reporting their quiescent state on a QS variable.
179  */
180 static int
181 test_rcu_qsbr_thread_unregister(void)
182 {
183         unsigned int num_threads[3] = {1, RTE_MAX_LCORE, 1};
184         unsigned int i, j;
185         unsigned int skip_thread_id;
186         uint64_t token;
187         int ret;
188
189         printf("\nTest rte_rcu_qsbr_thread_unregister()\n");
190
191         ret = rte_rcu_qsbr_thread_unregister(NULL, enabled_core_ids[0]);
192         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "NULL variable check");
193
194         ret = rte_rcu_qsbr_thread_unregister(NULL, 100000);
195         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
196                 "NULL variable, invalid thread id");
197
198         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
199
200         rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
201
202         ret = rte_rcu_qsbr_thread_unregister(t[0], 100000);
203         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
204                 "NULL variable, invalid thread id");
205
206         /* Find first disabled core */
207         for (i = 0; i < RTE_MAX_LCORE; i++) {
208                 if (enabled_core_ids[i] == 0)
209                         break;
210         }
211         /* Test with disabled lcore */
212         ret = rte_rcu_qsbr_thread_unregister(t[0], i);
213         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
214                 "disabled thread id");
215         /* Unregister already unregistered core */
216         ret = rte_rcu_qsbr_thread_unregister(t[0], i);
217         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
218                 "Already unregistered core");
219
220         /* Test with enabled lcore */
221         ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
222         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
223                 "enabled thread id");
224         /* Unregister already unregistered core */
225         ret = rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[0]);
226         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1),
227                 "Already unregistered core");
228
229         /*
230          * Test with different thread_ids:
231          * 1 - thread_id = 0
232          * 2 - All possible thread_ids, from 0 to RTE_MAX_LCORE
233          * 3 - thread_id = RTE_MAX_LCORE - 1
234          */
235         for (j = 0; j < 3; j++) {
236                 rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
237
238                 for (i = 0; i < num_threads[j]; i++)
239                         rte_rcu_qsbr_thread_register(t[0],
240                                 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
241
242                 token = rte_rcu_qsbr_start(t[0]);
243                 TEST_RCU_QSBR_RETURN_IF_ERROR(
244                         (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
245                 skip_thread_id = rte_rand() % RTE_MAX_LCORE;
246                 /* Update quiescent state counter */
247                 for (i = 0; i < num_threads[j]; i++) {
248                         /* Skip one update */
249                         if ((j == 1) && (i == skip_thread_id))
250                                 continue;
251                         rte_rcu_qsbr_quiescent(t[0],
252                                 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
253                 }
254
255                 if (j == 1) {
256                         /* Validate the updates */
257                         ret = rte_rcu_qsbr_check(t[0], token, false);
258                         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
259                                                 "Non-blocking QSBR check");
260                         /* Update the previously skipped thread */
261                         rte_rcu_qsbr_quiescent(t[0], skip_thread_id);
262                 }
263
264                 /* Validate the updates */
265                 ret = rte_rcu_qsbr_check(t[0], token, false);
266                 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
267                                                 "Non-blocking QSBR check");
268
269                 for (i = 0; i < num_threads[j]; i++)
270                         rte_rcu_qsbr_thread_unregister(t[0],
271                                 (j == 2) ? (RTE_MAX_LCORE - 1) : i);
272
273                 /* Check with no thread registered */
274                 ret = rte_rcu_qsbr_check(t[0], token, true);
275                 TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0),
276                                                 "Blocking QSBR check");
277         }
278         return 0;
279 }
280
281 /*
282  * rte_rcu_qsbr_start: Ask the worker threads to report the quiescent state
283  * status.
284  */
285 static int
286 test_rcu_qsbr_start(void)
287 {
288         uint64_t token;
289         unsigned int i;
290
291         printf("\nTest rte_rcu_qsbr_start()\n");
292
293         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
294
295         for (i = 0; i < num_cores; i++)
296                 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
297
298         token = rte_rcu_qsbr_start(t[0]);
299         TEST_RCU_QSBR_RETURN_IF_ERROR(
300                 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
301         return 0;
302 }
303
304 static int
305 test_rcu_qsbr_check_reader(void *arg)
306 {
307         struct rte_rcu_qsbr *temp;
308         uint8_t read_type = (uint8_t)((uintptr_t)arg);
309         unsigned int i;
310
311         temp = t[read_type];
312
313         /* Update quiescent state counter */
314         for (i = 0; i < num_cores; i++) {
315                 if (i % 2 == 0)
316                         rte_rcu_qsbr_quiescent(temp, enabled_core_ids[i]);
317                 else
318                         rte_rcu_qsbr_thread_unregister(temp,
319                                                         enabled_core_ids[i]);
320         }
321         return 0;
322 }
323
324 /*
325  * rte_rcu_qsbr_check: Checks if all the worker threads have entered the queis-
326  * cent state 'n' number of times. 'n' is provided in rte_rcu_qsbr_start API.
327  */
328 static int
329 test_rcu_qsbr_check(void)
330 {
331         int ret;
332         unsigned int i;
333         uint64_t token;
334
335         printf("\nTest rte_rcu_qsbr_check()\n");
336
337         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
338
339         token = rte_rcu_qsbr_start(t[0]);
340         TEST_RCU_QSBR_RETURN_IF_ERROR(
341                 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
342
343
344         ret = rte_rcu_qsbr_check(t[0], 0, false);
345         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Token = 0");
346
347         ret = rte_rcu_qsbr_check(t[0], token, true);
348         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
349
350         for (i = 0; i < num_cores; i++)
351                 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
352
353         ret = rte_rcu_qsbr_check(t[0], token, false);
354         /* Threads are offline, hence this should pass */
355         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
356
357         token = rte_rcu_qsbr_start(t[0]);
358         TEST_RCU_QSBR_RETURN_IF_ERROR(
359                 (token != (TEST_RCU_QSBR_CNT_INIT + 2)), "QSBR Start");
360
361         ret = rte_rcu_qsbr_check(t[0], token, false);
362         /* Threads are offline, hence this should pass */
363         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Non-blocking QSBR check");
364
365         for (i = 0; i < num_cores; i++)
366                 rte_rcu_qsbr_thread_unregister(t[0], enabled_core_ids[i]);
367
368         ret = rte_rcu_qsbr_check(t[0], token, true);
369         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "Blocking QSBR check");
370
371         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
372
373         for (i = 0; i < num_cores; i++)
374                 rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[i]);
375
376         token = rte_rcu_qsbr_start(t[0]);
377         TEST_RCU_QSBR_RETURN_IF_ERROR(
378                 (token != (TEST_RCU_QSBR_CNT_INIT + 1)), "QSBR Start");
379
380         rte_eal_remote_launch(test_rcu_qsbr_check_reader, NULL,
381                                                         enabled_core_ids[0]);
382
383         rte_eal_mp_wait_lcore();
384         ret = rte_rcu_qsbr_check(t[0], token, true);
385         TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 1), "Blocking QSBR check");
386
387         return 0;
388 }
389
390 static int
391 test_rcu_qsbr_synchronize_reader(void *arg)
392 {
393         uint32_t lcore_id = rte_lcore_id();
394         (void)arg;
395
396         /* Register and become online */
397         rte_rcu_qsbr_thread_register(t[0], lcore_id);
398         rte_rcu_qsbr_thread_online(t[0], lcore_id);
399
400         while (!writer_done)
401                 rte_rcu_qsbr_quiescent(t[0], lcore_id);
402
403         rte_rcu_qsbr_thread_offline(t[0], lcore_id);
404         rte_rcu_qsbr_thread_unregister(t[0], lcore_id);
405
406         return 0;
407 }
408
409 /*
410  * rte_rcu_qsbr_synchronize: Wait till all the reader threads have entered
411  * the quiescent state.
412  */
413 static int
414 test_rcu_qsbr_synchronize(void)
415 {
416         unsigned int i;
417
418         printf("\nTest rte_rcu_qsbr_synchronize()\n");
419
420         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
421
422         /* Test if the API returns when there are no threads reporting
423          * QS on the variable.
424          */
425         rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
426
427         /* Test if the API returns when there are threads registered
428          * but not online.
429          */
430         for (i = 0; i < RTE_MAX_LCORE; i++)
431                 rte_rcu_qsbr_thread_register(t[0], i);
432         rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
433
434         /* Test if the API returns when the caller is also
435          * reporting the QS status.
436          */
437         rte_rcu_qsbr_thread_online(t[0], 0);
438         rte_rcu_qsbr_synchronize(t[0], 0);
439         rte_rcu_qsbr_thread_offline(t[0], 0);
440
441         /* Check the other boundary */
442         rte_rcu_qsbr_thread_online(t[0], RTE_MAX_LCORE - 1);
443         rte_rcu_qsbr_synchronize(t[0], RTE_MAX_LCORE - 1);
444         rte_rcu_qsbr_thread_offline(t[0], RTE_MAX_LCORE - 1);
445
446         /* Test if the API returns after unregistering all the threads */
447         for (i = 0; i < RTE_MAX_LCORE; i++)
448                 rte_rcu_qsbr_thread_unregister(t[0], i);
449         rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
450
451         /* Test if the API returns with the live threads */
452         writer_done = 0;
453         for (i = 0; i < num_cores; i++)
454                 rte_eal_remote_launch(test_rcu_qsbr_synchronize_reader,
455                         NULL, enabled_core_ids[i]);
456         rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
457         rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
458         rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
459         rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
460         rte_rcu_qsbr_synchronize(t[0], RTE_QSBR_THRID_INVALID);
461
462         writer_done = 1;
463         rte_eal_mp_wait_lcore();
464
465         return 0;
466 }
467
468 /*
469  * rte_rcu_qsbr_thread_online: Add a registered reader thread, to
470  * the list of threads reporting their quiescent state on a QS variable.
471  */
472 static int
473 test_rcu_qsbr_thread_online(void)
474 {
475         int i, ret;
476         uint64_t token;
477
478         printf("Test rte_rcu_qsbr_thread_online()\n");
479
480         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
481
482         /* Register 2 threads to validate that only the
483          * online thread is waited upon.
484          */
485         rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
486         rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[1]);
487
488         /* Use qsbr_start to verify that the thread_online API
489          * succeeded.
490          */
491         token = rte_rcu_qsbr_start(t[0]);
492
493         /* Make the thread online */
494         rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
495
496         /* Check if the thread is online */
497         ret = rte_rcu_qsbr_check(t[0], token, true);
498         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
499
500         /* Check if the online thread, can report QS */
501         token = rte_rcu_qsbr_start(t[0]);
502         rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
503         ret = rte_rcu_qsbr_check(t[0], token, true);
504         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
505
506         /* Make all the threads online */
507         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
508         token = rte_rcu_qsbr_start(t[0]);
509         for (i = 0; i < RTE_MAX_LCORE; i++) {
510                 rte_rcu_qsbr_thread_register(t[0], i);
511                 rte_rcu_qsbr_thread_online(t[0], i);
512         }
513         /* Check if all the threads are online */
514         ret = rte_rcu_qsbr_check(t[0], token, true);
515         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
516         /* Check if all the online threads can report QS */
517         token = rte_rcu_qsbr_start(t[0]);
518         for (i = 0; i < RTE_MAX_LCORE; i++)
519                 rte_rcu_qsbr_quiescent(t[0], i);
520         ret = rte_rcu_qsbr_check(t[0], token, true);
521         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread update");
522
523         return 0;
524 }
525
526 /*
527  * rte_rcu_qsbr_thread_offline: Remove a registered reader thread, from
528  * the list of threads reporting their quiescent state on a QS variable.
529  */
530 static int
531 test_rcu_qsbr_thread_offline(void)
532 {
533         int i, ret;
534         uint64_t token;
535
536         printf("\nTest rte_rcu_qsbr_thread_offline()\n");
537
538         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
539
540         rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
541
542         /* Make the thread offline */
543         rte_rcu_qsbr_thread_offline(t[0], enabled_core_ids[0]);
544
545         /* Use qsbr_start to verify that the thread_offline API
546          * succeeded.
547          */
548         token = rte_rcu_qsbr_start(t[0]);
549         /* Check if the thread is offline */
550         ret = rte_rcu_qsbr_check(t[0], token, true);
551         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread offline");
552
553         /* Bring an offline thread online and check if it can
554          * report QS.
555          */
556         rte_rcu_qsbr_thread_online(t[0], enabled_core_ids[0]);
557         /* Check if the online thread, can report QS */
558         token = rte_rcu_qsbr_start(t[0]);
559         rte_rcu_qsbr_quiescent(t[0], enabled_core_ids[0]);
560         ret = rte_rcu_qsbr_check(t[0], token, true);
561         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline to online");
562
563         /*
564          * Check a sequence of online/status/offline/status/online/status
565          */
566         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
567         token = rte_rcu_qsbr_start(t[0]);
568         /* Make the threads online */
569         for (i = 0; i < RTE_MAX_LCORE; i++) {
570                 rte_rcu_qsbr_thread_register(t[0], i);
571                 rte_rcu_qsbr_thread_online(t[0], i);
572         }
573
574         /* Check if all the threads are online */
575         ret = rte_rcu_qsbr_check(t[0], token, true);
576         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "thread online");
577
578         /* Check if all the online threads can report QS */
579         token = rte_rcu_qsbr_start(t[0]);
580         for (i = 0; i < RTE_MAX_LCORE; i++)
581                 rte_rcu_qsbr_quiescent(t[0], i);
582         ret = rte_rcu_qsbr_check(t[0], token, true);
583         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "report QS");
584
585         /* Make all the threads offline */
586         for (i = 0; i < RTE_MAX_LCORE; i++)
587                 rte_rcu_qsbr_thread_offline(t[0], i);
588         /* Make sure these threads are not being waited on */
589         token = rte_rcu_qsbr_start(t[0]);
590         ret = rte_rcu_qsbr_check(t[0], token, true);
591         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "offline QS");
592
593         /* Make the threads online */
594         for (i = 0; i < RTE_MAX_LCORE; i++)
595                 rte_rcu_qsbr_thread_online(t[0], i);
596         /* Check if all the online threads can report QS */
597         token = rte_rcu_qsbr_start(t[0]);
598         for (i = 0; i < RTE_MAX_LCORE; i++)
599                 rte_rcu_qsbr_quiescent(t[0], i);
600         ret = rte_rcu_qsbr_check(t[0], token, true);
601         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "online again");
602
603         return 0;
604 }
605
606 static void
607 test_rcu_qsbr_free_resource1(void *p, void *e, unsigned int n)
608 {
609         if (p != NULL || e != NULL || n != 1) {
610                 printf("%s: Test failed\n", __func__);
611                 cb_failed = 1;
612         }
613 }
614
615 static void
616 test_rcu_qsbr_free_resource2(void *p, void *e, unsigned int n)
617 {
618         if (p != NULL || e == NULL || n != 1) {
619                 printf("%s: Test failed\n", __func__);
620                 cb_failed = 1;
621         }
622 }
623
624 /*
625  * rte_rcu_qsbr_dq_create: create a queue used to store the data structure
626  * elements that can be freed later. This queue is referred to as 'defer queue'.
627  */
628 static int
629 test_rcu_qsbr_dq_create(void)
630 {
631         char rcu_dq_name[RTE_RCU_QSBR_DQ_NAMESIZE];
632         struct rte_rcu_qsbr_dq_parameters params;
633         struct rte_rcu_qsbr_dq *dq;
634
635         printf("\nTest rte_rcu_qsbr_dq_create()\n");
636
637         /* Pass invalid parameters */
638         dq = rte_rcu_qsbr_dq_create(NULL);
639         TEST_RCU_QSBR_RETURN_IF_ERROR((dq != NULL), "dq create invalid params");
640
641         memset(&params, 0, sizeof(struct rte_rcu_qsbr_dq_parameters));
642         dq = rte_rcu_qsbr_dq_create(&params);
643         TEST_RCU_QSBR_RETURN_IF_ERROR((dq != NULL), "dq create invalid params");
644
645         snprintf(rcu_dq_name, sizeof(rcu_dq_name), "TEST_RCU");
646         params.name = rcu_dq_name;
647         dq = rte_rcu_qsbr_dq_create(&params);
648         TEST_RCU_QSBR_RETURN_IF_ERROR((dq != NULL), "dq create invalid params");
649
650         params.free_fn = test_rcu_qsbr_free_resource1;
651         dq = rte_rcu_qsbr_dq_create(&params);
652         TEST_RCU_QSBR_RETURN_IF_ERROR((dq != NULL), "dq create invalid params");
653
654         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
655         params.v = t[0];
656         dq = rte_rcu_qsbr_dq_create(&params);
657         TEST_RCU_QSBR_RETURN_IF_ERROR((dq != NULL), "dq create invalid params");
658
659         params.size = 1;
660         dq = rte_rcu_qsbr_dq_create(&params);
661         TEST_RCU_QSBR_RETURN_IF_ERROR((dq != NULL), "dq create invalid params");
662
663         params.esize = 3;
664         dq = rte_rcu_qsbr_dq_create(&params);
665         TEST_RCU_QSBR_RETURN_IF_ERROR((dq != NULL), "dq create invalid params");
666
667         params.trigger_reclaim_limit = 0;
668         params.max_reclaim_size = 0;
669         dq = rte_rcu_qsbr_dq_create(&params);
670         TEST_RCU_QSBR_RETURN_IF_ERROR((dq != NULL), "dq create invalid params");
671
672         /* Pass all valid parameters */
673         params.esize = 16;
674         params.trigger_reclaim_limit = 0;
675         params.max_reclaim_size = params.size;
676         dq = rte_rcu_qsbr_dq_create(&params);
677         TEST_RCU_QSBR_RETURN_IF_ERROR((dq == NULL), "dq create valid params");
678         rte_rcu_qsbr_dq_delete(dq);
679
680         params.esize = 16;
681         params.flags = RTE_RCU_QSBR_DQ_MT_UNSAFE;
682         dq = rte_rcu_qsbr_dq_create(&params);
683         TEST_RCU_QSBR_RETURN_IF_ERROR((dq == NULL), "dq create valid params");
684         rte_rcu_qsbr_dq_delete(dq);
685
686         return 0;
687 }
688
689 /*
690  * rte_rcu_qsbr_dq_enqueue: enqueue one resource to the defer queue,
691  * to be freed later after at least one grace period is over.
692  */
693 static int
694 test_rcu_qsbr_dq_enqueue(void)
695 {
696         int ret;
697         uint64_t r;
698         char rcu_dq_name[RTE_RCU_QSBR_DQ_NAMESIZE];
699         struct rte_rcu_qsbr_dq_parameters params;
700         struct rte_rcu_qsbr_dq *dq;
701
702         printf("\nTest rte_rcu_qsbr_dq_enqueue()\n");
703
704         /* Create a queue with simple parameters */
705         memset(&params, 0, sizeof(struct rte_rcu_qsbr_dq_parameters));
706         snprintf(rcu_dq_name, sizeof(rcu_dq_name), "TEST_RCU");
707         params.name = rcu_dq_name;
708         params.free_fn = test_rcu_qsbr_free_resource1;
709         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
710         params.v = t[0];
711         params.size = 1;
712         params.esize = 16;
713         params.trigger_reclaim_limit = 0;
714         params.max_reclaim_size = params.size;
715         dq = rte_rcu_qsbr_dq_create(&params);
716         TEST_RCU_QSBR_RETURN_IF_ERROR((dq == NULL), "dq create valid params");
717
718         /* Pass invalid parameters */
719         ret = rte_rcu_qsbr_dq_enqueue(NULL, NULL);
720         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "dq enqueue invalid params");
721
722         ret = rte_rcu_qsbr_dq_enqueue(dq, NULL);
723         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "dq enqueue invalid params");
724
725         ret = rte_rcu_qsbr_dq_enqueue(NULL, &r);
726         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "dq enqueue invalid params");
727
728         ret = rte_rcu_qsbr_dq_delete(dq);
729         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 1), "dq delete valid params");
730
731         return 0;
732 }
733
734 /*
735  * rte_rcu_qsbr_dq_reclaim: Reclaim resources from the defer queue.
736  */
737 static int
738 test_rcu_qsbr_dq_reclaim(void)
739 {
740         int ret;
741         char rcu_dq_name[RTE_RCU_QSBR_DQ_NAMESIZE];
742         struct rte_rcu_qsbr_dq_parameters params;
743         struct rte_rcu_qsbr_dq *dq;
744
745         printf("\nTest rte_rcu_qsbr_dq_reclaim()\n");
746
747         /* Pass invalid parameters */
748         ret = rte_rcu_qsbr_dq_reclaim(NULL, 10, NULL, NULL, NULL);
749         TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 1), "dq reclaim invalid params");
750
751         /* Pass invalid parameters */
752         memset(&params, 0, sizeof(struct rte_rcu_qsbr_dq_parameters));
753         snprintf(rcu_dq_name, sizeof(rcu_dq_name), "TEST_RCU");
754         params.name = rcu_dq_name;
755         params.free_fn = test_rcu_qsbr_free_resource1;
756         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
757         params.v = t[0];
758         params.size = 1;
759         params.esize = 3;
760         params.trigger_reclaim_limit = 0;
761         params.max_reclaim_size = params.size;
762         dq = rte_rcu_qsbr_dq_create(&params);
763         ret = rte_rcu_qsbr_dq_reclaim(dq, 0, NULL, NULL, NULL);
764         TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 1), "dq reclaim invalid params");
765
766         return 0;
767 }
768
769 /*
770  * rte_rcu_qsbr_dq_delete: Delete a defer queue.
771  */
772 static int
773 test_rcu_qsbr_dq_delete(void)
774 {
775         int ret;
776         char rcu_dq_name[RTE_RCU_QSBR_DQ_NAMESIZE];
777         struct rte_rcu_qsbr_dq_parameters params;
778         struct rte_rcu_qsbr_dq *dq;
779
780         printf("\nTest rte_rcu_qsbr_dq_delete()\n");
781
782         /* Pass invalid parameters */
783         ret = rte_rcu_qsbr_dq_delete(NULL);
784         TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 0), "dq delete invalid params");
785
786         memset(&params, 0, sizeof(struct rte_rcu_qsbr_dq_parameters));
787         snprintf(rcu_dq_name, sizeof(rcu_dq_name), "TEST_RCU");
788         params.name = rcu_dq_name;
789         params.free_fn = test_rcu_qsbr_free_resource1;
790         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
791         params.v = t[0];
792         params.size = 1;
793         params.esize = 16;
794         params.trigger_reclaim_limit = 0;
795         params.max_reclaim_size = params.size;
796         dq = rte_rcu_qsbr_dq_create(&params);
797         TEST_RCU_QSBR_RETURN_IF_ERROR((dq == NULL), "dq create valid params");
798         ret = rte_rcu_qsbr_dq_delete(dq);
799         TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 0), "dq delete valid params");
800
801         return 0;
802 }
803
804 /*
805  * rte_rcu_qsbr_dq_enqueue: enqueue one resource to the defer queue,
806  * to be freed later after at least one grace period is over.
807  */
808 static int
809 test_rcu_qsbr_dq_functional(int32_t size, int32_t esize, uint32_t flags)
810 {
811         int i, j, ret;
812         char rcu_dq_name[RTE_RCU_QSBR_DQ_NAMESIZE];
813         struct rte_rcu_qsbr_dq_parameters params;
814         struct rte_rcu_qsbr_dq *dq;
815         uint64_t *e;
816         uint64_t sc = 200;
817         int max_entries;
818
819         printf("\nTest rte_rcu_qsbr_dq_xxx functional tests()\n");
820         printf("Size = %d, esize = %d, flags = 0x%x\n", size, esize, flags);
821
822         e = (uint64_t *)rte_zmalloc(NULL, esize, RTE_CACHE_LINE_SIZE);
823         if (e == NULL)
824                 return 0;
825         cb_failed = 0;
826
827         /* Initialize the RCU variable. No threads are registered */
828         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
829
830         /* Create a queue with simple parameters */
831         memset(&params, 0, sizeof(struct rte_rcu_qsbr_dq_parameters));
832         snprintf(rcu_dq_name, sizeof(rcu_dq_name), "TEST_RCU");
833         params.name = rcu_dq_name;
834         params.flags = flags;
835         params.free_fn = test_rcu_qsbr_free_resource2;
836         params.v = t[0];
837         params.size = size;
838         params.esize = esize;
839         params.trigger_reclaim_limit = size >> 3;
840         params.max_reclaim_size = (size >> 4)?(size >> 4):1;
841         dq = rte_rcu_qsbr_dq_create(&params);
842         TEST_RCU_QSBR_RETURN_IF_ERROR((dq == NULL), "dq create valid params");
843
844         /* Given the size calculate the maximum number of entries
845          * that can be stored on the defer queue (look at the logic used
846          * in capacity calculation of rte_ring).
847          */
848         max_entries = rte_align32pow2(size + 1) - 1;
849         printf("max_entries = %d\n", max_entries);
850
851         /* Enqueue few counters starting with the value 'sc' */
852         /* The queue size will be rounded up to 2. The enqueue API also
853          * reclaims if the queue size is above certain limit. Since, there
854          * are no threads registered, reclamation succeeds. Hence, it should
855          * be possible to enqueue more than the provided queue size.
856          */
857         for (i = 0; i < 10; i++) {
858                 ret = rte_rcu_qsbr_dq_enqueue(dq, e);
859                 TEST_RCU_QSBR_GOTO_IF_ERROR(end, (ret != 0),
860                         "dq enqueue functional, i = %d", i);
861                 for (j = 0; j < esize/8; j++)
862                         e[j] = sc++;
863         }
864
865         /* Validate that call back function did not return any error */
866         TEST_RCU_QSBR_GOTO_IF_ERROR(end, (cb_failed == 1), "CB failed");
867
868         /* Register a thread on the RCU QSBR variable. Reclamation will not
869          * succeed. It should not be possible to enqueue more than the size
870          * number of resources.
871          */
872         rte_rcu_qsbr_thread_register(t[0], 1);
873         rte_rcu_qsbr_thread_online(t[0], 1);
874
875         for (i = 0; i < max_entries; i++) {
876                 ret = rte_rcu_qsbr_dq_enqueue(dq, e);
877                 TEST_RCU_QSBR_GOTO_IF_ERROR(end, (ret != 0),
878                         "dq enqueue functional, max_entries = %d, i = %d",
879                         max_entries, i);
880                 for (j = 0; j < esize/8; j++)
881                         e[j] = sc++;
882         }
883
884         /* Enqueue fails as queue is full */
885         ret = rte_rcu_qsbr_dq_enqueue(dq, e);
886         TEST_RCU_QSBR_GOTO_IF_ERROR(end, (ret == 0), "defer queue is not full");
887
888         /* Delete should fail as there are elements in defer queue which
889          * cannot be reclaimed.
890          */
891         ret = rte_rcu_qsbr_dq_delete(dq);
892         TEST_RCU_QSBR_RETURN_IF_ERROR((ret == 0), "dq delete valid params");
893
894         /* Report quiescent state, enqueue should succeed */
895         rte_rcu_qsbr_quiescent(t[0], 1);
896         for (i = 0; i < max_entries; i++) {
897                 ret = rte_rcu_qsbr_dq_enqueue(dq, e);
898                 TEST_RCU_QSBR_GOTO_IF_ERROR(end, (ret != 0),
899                         "dq enqueue functional");
900                 for (j = 0; j < esize/8; j++)
901                         e[j] = sc++;
902         }
903
904         /* Validate that call back function did not return any error */
905         TEST_RCU_QSBR_GOTO_IF_ERROR(end, (cb_failed == 1), "CB failed");
906
907         /* Queue is full */
908         ret = rte_rcu_qsbr_dq_enqueue(dq, e);
909         TEST_RCU_QSBR_GOTO_IF_ERROR(end, (ret == 0), "defer queue is not full");
910
911         /* Report quiescent state, delete should succeed */
912         rte_rcu_qsbr_quiescent(t[0], 1);
913         ret = rte_rcu_qsbr_dq_delete(dq);
914         TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 0), "dq delete valid params");
915
916         rte_free(e);
917
918         /* Validate that call back function did not return any error */
919         TEST_RCU_QSBR_RETURN_IF_ERROR((cb_failed == 1), "CB failed");
920
921         return 0;
922
923 end:
924         rte_free(e);
925         ret = rte_rcu_qsbr_dq_delete(dq);
926         TEST_RCU_QSBR_RETURN_IF_ERROR((ret != 0), "dq delete valid params");
927         return -1;
928 }
929
930 /*
931  * rte_rcu_qsbr_dump: Dump status of a single QS variable to a file
932  */
933 static int
934 test_rcu_qsbr_dump(void)
935 {
936         unsigned int i;
937
938         printf("\nTest rte_rcu_qsbr_dump()\n");
939
940         /* Negative tests */
941         rte_rcu_qsbr_dump(NULL, t[0]);
942         rte_rcu_qsbr_dump(stdout, NULL);
943         rte_rcu_qsbr_dump(NULL, NULL);
944
945         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
946         rte_rcu_qsbr_init(t[1], RTE_MAX_LCORE);
947
948         /* QS variable with 0 core mask */
949         rte_rcu_qsbr_dump(stdout, t[0]);
950
951         rte_rcu_qsbr_thread_register(t[0], enabled_core_ids[0]);
952
953         for (i = 1; i < num_cores; i++)
954                 rte_rcu_qsbr_thread_register(t[1], enabled_core_ids[i]);
955
956         rte_rcu_qsbr_dump(stdout, t[0]);
957         rte_rcu_qsbr_dump(stdout, t[1]);
958         printf("\n");
959         return 0;
960 }
961
962 static int
963 test_rcu_qsbr_reader(void *arg)
964 {
965         struct rte_rcu_qsbr *temp;
966         struct rte_hash *hash = NULL;
967         int i;
968         uint32_t lcore_id = rte_lcore_id();
969         struct test_rcu_thread_info *ti;
970         uint32_t *pdata;
971
972         ti = (struct test_rcu_thread_info *)arg;
973         temp = t[ti->ir];
974         hash = h[ti->ih];
975
976         do {
977                 rte_rcu_qsbr_thread_register(temp, lcore_id);
978                 rte_rcu_qsbr_thread_online(temp, lcore_id);
979                 for (i = 0; i < TOTAL_ENTRY; i++) {
980                         rte_rcu_qsbr_lock(temp, lcore_id);
981                         if (rte_hash_lookup_data(hash, keys+i,
982                                         (void **)&pdata) != -ENOENT) {
983                                 pdata[lcore_id] = 0;
984                                 while (pdata[lcore_id] < COUNTER_VALUE)
985                                         pdata[lcore_id]++;
986                         }
987                         rte_rcu_qsbr_unlock(temp, lcore_id);
988                 }
989                 /* Update quiescent state counter */
990                 rte_rcu_qsbr_quiescent(temp, lcore_id);
991                 rte_rcu_qsbr_thread_offline(temp, lcore_id);
992                 rte_rcu_qsbr_thread_unregister(temp, lcore_id);
993         } while (!writer_done);
994
995         return 0;
996 }
997
998 static int
999 test_rcu_qsbr_writer(void *arg)
1000 {
1001         uint64_t token;
1002         int32_t i, pos, del;
1003         uint32_t c;
1004         struct rte_rcu_qsbr *temp;
1005         struct rte_hash *hash = NULL;
1006         struct test_rcu_thread_info *ti;
1007
1008         ti = (struct test_rcu_thread_info *)arg;
1009         temp = t[ti->ir];
1010         hash = h[ti->ih];
1011
1012         /* Delete element from the shared data structure */
1013         del = rte_lcore_id() % TOTAL_ENTRY;
1014         pos = rte_hash_del_key(hash, keys + del);
1015         if (pos < 0) {
1016                 printf("Delete key failed #%d\n", keys[del]);
1017                 return -1;
1018         }
1019         /* Start the quiescent state query process */
1020         token = rte_rcu_qsbr_start(temp);
1021         /* Check the quiescent state status */
1022         rte_rcu_qsbr_check(temp, token, true);
1023         for (i = 0; i < 2; i++) {
1024                 c = hash_data[ti->ih][del][ti->r_core_ids[i]];
1025                 if (c != COUNTER_VALUE && c != 0) {
1026                         printf("Reader lcore id %u did not complete = %u\t",
1027                                 rte_lcore_id(), c);
1028                         return -1;
1029                 }
1030         }
1031
1032         if (rte_hash_free_key_with_position(hash, pos) < 0) {
1033                 printf("Failed to free the key #%d\n", keys[del]);
1034                 return -1;
1035         }
1036         rte_free(hash_data[ti->ih][del]);
1037         hash_data[ti->ih][del] = NULL;
1038
1039         return 0;
1040 }
1041
1042 static struct rte_hash *
1043 init_hash(int hash_id)
1044 {
1045         int i;
1046         struct rte_hash *h = NULL;
1047
1048         sprintf(hash_name[hash_id], "hash%d", hash_id);
1049         struct rte_hash_parameters hash_params = {
1050                 .entries = TOTAL_ENTRY,
1051                 .key_len = sizeof(uint32_t),
1052                 .hash_func_init_val = 0,
1053                 .socket_id = rte_socket_id(),
1054                 .hash_func = rte_hash_crc,
1055                 .extra_flag =
1056                         RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF,
1057                 .name = hash_name[hash_id],
1058         };
1059
1060         h = rte_hash_create(&hash_params);
1061         if (h == NULL) {
1062                 printf("Hash create Failed\n");
1063                 return NULL;
1064         }
1065
1066         for (i = 0; i < TOTAL_ENTRY; i++) {
1067                 hash_data[hash_id][i] =
1068                         rte_zmalloc(NULL, sizeof(uint32_t) * RTE_MAX_LCORE, 0);
1069                 if (hash_data[hash_id][i] == NULL) {
1070                         printf("No memory\n");
1071                         return NULL;
1072                 }
1073         }
1074         keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0);
1075         if (keys == NULL) {
1076                 printf("No memory\n");
1077                 return NULL;
1078         }
1079
1080         for (i = 0; i < TOTAL_ENTRY; i++)
1081                 keys[i] = i;
1082
1083         for (i = 0; i < TOTAL_ENTRY; i++) {
1084                 if (rte_hash_add_key_data(h, keys + i,
1085                                 (void *)((uintptr_t)hash_data[hash_id][i]))
1086                                 < 0) {
1087                         printf("Hash key add Failed #%d\n", i);
1088                         return NULL;
1089                 }
1090         }
1091         return h;
1092 }
1093
1094 /*
1095  * Functional test:
1096  * Single writer, Single QS variable, simultaneous QSBR Queries
1097  */
1098 static int
1099 test_rcu_qsbr_sw_sv_3qs(void)
1100 {
1101         uint64_t token[3];
1102         uint32_t c;
1103         int i, num_readers;
1104         int32_t pos[3];
1105
1106         writer_done = 0;
1107
1108         printf("Test: 1 writer, 1 QSBR variable, simultaneous QSBR queries\n");
1109
1110         rte_rcu_qsbr_init(t[0], RTE_MAX_LCORE);
1111
1112         /* Shared data structure created */
1113         h[0] = init_hash(0);
1114         if (h[0] == NULL) {
1115                 printf("Hash init failed\n");
1116                 goto error;
1117         }
1118
1119         /* No need to fill the registered core IDs as the writer
1120          * thread is not launched.
1121          */
1122         thread_info[0].ir = 0;
1123         thread_info[0].ih = 0;
1124
1125         /* Reader threads are launched */
1126         /* Keep the number of reader threads low to reduce
1127          * the execution time.
1128          */
1129         num_readers = num_cores < 4 ? num_cores : 4;
1130         for (i = 0; i < num_readers; i++)
1131                 rte_eal_remote_launch(test_rcu_qsbr_reader, &thread_info[0],
1132                                         enabled_core_ids[i]);
1133
1134         /* Delete element from the shared data structure */
1135         pos[0] = rte_hash_del_key(h[0], keys + 0);
1136         if (pos[0] < 0) {
1137                 printf("Delete key failed #%d\n", keys[0]);
1138                 goto error;
1139         }
1140         /* Start the quiescent state query process */
1141         token[0] = rte_rcu_qsbr_start(t[0]);
1142
1143         /* Delete element from the shared data structure */
1144         pos[1] = rte_hash_del_key(h[0], keys + 3);
1145         if (pos[1] < 0) {
1146                 printf("Delete key failed #%d\n", keys[3]);
1147                 goto error;
1148         }
1149         /* Start the quiescent state query process */
1150         token[1] = rte_rcu_qsbr_start(t[0]);
1151
1152         /* Delete element from the shared data structure */
1153         pos[2] = rte_hash_del_key(h[0], keys + 6);
1154         if (pos[2] < 0) {
1155                 printf("Delete key failed #%d\n", keys[6]);
1156                 goto error;
1157         }
1158         /* Start the quiescent state query process */
1159         token[2] = rte_rcu_qsbr_start(t[0]);
1160
1161         /* Check the quiescent state status */
1162         rte_rcu_qsbr_check(t[0], token[0], true);
1163         for (i = 0; i < num_readers; i++) {
1164                 c = hash_data[0][0][enabled_core_ids[i]];
1165                 if (c != COUNTER_VALUE && c != 0) {
1166                         printf("Reader lcore %d did not complete #0 = %d\n",
1167                                 enabled_core_ids[i], c);
1168                         goto error;
1169                 }
1170         }
1171
1172         if (rte_hash_free_key_with_position(h[0], pos[0]) < 0) {
1173                 printf("Failed to free the key #%d\n", keys[0]);
1174                 goto error;
1175         }
1176         rte_free(hash_data[0][0]);
1177         hash_data[0][0] = NULL;
1178
1179         /* Check the quiescent state status */
1180         rte_rcu_qsbr_check(t[0], token[1], true);
1181         for (i = 0; i < num_readers; i++) {
1182                 c = hash_data[0][3][enabled_core_ids[i]];
1183                 if (c != COUNTER_VALUE && c != 0) {
1184                         printf("Reader lcore %d did not complete #3 = %d\n",
1185                                 enabled_core_ids[i], c);
1186                         goto error;
1187                 }
1188         }
1189
1190         if (rte_hash_free_key_with_position(h[0], pos[1]) < 0) {
1191                 printf("Failed to free the key #%d\n", keys[3]);
1192                 goto error;
1193         }
1194         rte_free(hash_data[0][3]);
1195         hash_data[0][3] = NULL;
1196
1197         /* Check the quiescent state status */
1198         rte_rcu_qsbr_check(t[0], token[2], true);
1199         for (i = 0; i < num_readers; i++) {
1200                 c = hash_data[0][6][enabled_core_ids[i]];
1201                 if (c != COUNTER_VALUE && c != 0) {
1202                         printf("Reader lcore %d did not complete #6 = %d\n",
1203                                 enabled_core_ids[i], c);
1204                         goto error;
1205                 }
1206         }
1207
1208         if (rte_hash_free_key_with_position(h[0], pos[2]) < 0) {
1209                 printf("Failed to free the key #%d\n", keys[6]);
1210                 goto error;
1211         }
1212         rte_free(hash_data[0][6]);
1213         hash_data[0][6] = NULL;
1214
1215         writer_done = 1;
1216
1217         /* Wait and check return value from reader threads */
1218         for (i = 0; i < num_readers; i++)
1219                 if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
1220                         goto error;
1221         rte_hash_free(h[0]);
1222         rte_free(keys);
1223
1224         return 0;
1225
1226 error:
1227         writer_done = 1;
1228         /* Wait until all readers have exited */
1229         rte_eal_mp_wait_lcore();
1230
1231         rte_hash_free(h[0]);
1232         rte_free(keys);
1233         for (i = 0; i < TOTAL_ENTRY; i++)
1234                 rte_free(hash_data[0][i]);
1235
1236         return -1;
1237 }
1238
1239 /*
1240  * Multi writer, Multiple QS variable, simultaneous QSBR queries
1241  */
1242 static int
1243 test_rcu_qsbr_mw_mv_mqs(void)
1244 {
1245         unsigned int i, j;
1246         unsigned int test_cores;
1247
1248         if (RTE_MAX_LCORE < 5 || num_cores < 4) {
1249                 printf("Not enough cores for %s, expecting at least 5\n",
1250                         __func__);
1251                 return TEST_SKIPPED;
1252         }
1253
1254         writer_done = 0;
1255         test_cores = num_cores / 4;
1256         test_cores = test_cores * 4;
1257
1258         printf("Test: %d writers, %d QSBR variable, simultaneous QSBR queries\n",
1259                test_cores / 2, test_cores / 4);
1260
1261         for (i = 0; i < test_cores / 4; i++) {
1262                 j = i * 4;
1263                 rte_rcu_qsbr_init(t[i], RTE_MAX_LCORE);
1264                 h[i] = init_hash(i);
1265                 if (h[i] == NULL) {
1266                         printf("Hash init failed\n");
1267                         goto error;
1268                 }
1269                 thread_info[i].ir = i;
1270                 thread_info[i].ih = i;
1271                 thread_info[i].r_core_ids[0] = enabled_core_ids[j];
1272                 thread_info[i].r_core_ids[1] = enabled_core_ids[j + 1];
1273
1274                 /* Reader threads are launched */
1275                 rte_eal_remote_launch(test_rcu_qsbr_reader,
1276                                         (void *)&thread_info[i],
1277                                         enabled_core_ids[j]);
1278                 rte_eal_remote_launch(test_rcu_qsbr_reader,
1279                                         (void *)&thread_info[i],
1280                                         enabled_core_ids[j + 1]);
1281
1282                 /* Writer threads are launched */
1283                 rte_eal_remote_launch(test_rcu_qsbr_writer,
1284                                         (void *)&thread_info[i],
1285                                         enabled_core_ids[j + 2]);
1286                 rte_eal_remote_launch(test_rcu_qsbr_writer,
1287                                         (void *)&thread_info[i],
1288                                         enabled_core_ids[j + 3]);
1289         }
1290
1291         /* Wait and check return value from writer threads */
1292         for (i = 0; i < test_cores / 4; i++) {
1293                 j = i * 4;
1294                 if (rte_eal_wait_lcore(enabled_core_ids[j + 2]) < 0)
1295                         goto error;
1296
1297                 if (rte_eal_wait_lcore(enabled_core_ids[j + 3]) < 0)
1298                         goto error;
1299         }
1300         writer_done = 1;
1301
1302         /* Wait and check return value from reader threads */
1303         for (i = 0; i < test_cores / 4; i++) {
1304                 j = i * 4;
1305                 if (rte_eal_wait_lcore(enabled_core_ids[j]) < 0)
1306                         goto error;
1307
1308                 if (rte_eal_wait_lcore(enabled_core_ids[j + 1]) < 0)
1309                         goto error;
1310         }
1311
1312         for (i = 0; i < test_cores / 4; i++)
1313                 rte_hash_free(h[i]);
1314
1315         rte_free(keys);
1316
1317         return 0;
1318
1319 error:
1320         writer_done = 1;
1321         /* Wait until all readers and writers have exited */
1322         rte_eal_mp_wait_lcore();
1323
1324         for (i = 0; i < test_cores / 4; i++)
1325                 rte_hash_free(h[i]);
1326         rte_free(keys);
1327         for (j = 0; j < test_cores / 4; j++)
1328                 for (i = 0; i < TOTAL_ENTRY; i++)
1329                         rte_free(hash_data[j][i]);
1330
1331         return -1;
1332 }
1333
1334 static int
1335 test_rcu_qsbr_main(void)
1336 {
1337         uint16_t core_id;
1338
1339         num_cores = 0;
1340         RTE_LCORE_FOREACH_WORKER(core_id) {
1341                 enabled_core_ids[num_cores] = core_id;
1342                 num_cores++;
1343         }
1344
1345         /* Error-checking test cases */
1346         if (test_rcu_qsbr_get_memsize() < 0)
1347                 goto test_fail;
1348
1349         if (test_rcu_qsbr_init() < 0)
1350                 goto test_fail;
1351
1352         alloc_rcu();
1353
1354         if (test_rcu_qsbr_thread_register() < 0)
1355                 goto test_fail;
1356
1357         if (test_rcu_qsbr_thread_unregister() < 0)
1358                 goto test_fail;
1359
1360         if (test_rcu_qsbr_start() < 0)
1361                 goto test_fail;
1362
1363         if (test_rcu_qsbr_check() < 0)
1364                 goto test_fail;
1365
1366         if (test_rcu_qsbr_synchronize() < 0)
1367                 goto test_fail;
1368
1369         if (test_rcu_qsbr_dump() < 0)
1370                 goto test_fail;
1371
1372         if (test_rcu_qsbr_thread_online() < 0)
1373                 goto test_fail;
1374
1375         if (test_rcu_qsbr_thread_offline() < 0)
1376                 goto test_fail;
1377
1378         if (test_rcu_qsbr_dq_create() < 0)
1379                 goto test_fail;
1380
1381         if (test_rcu_qsbr_dq_reclaim() < 0)
1382                 goto test_fail;
1383
1384         if (test_rcu_qsbr_dq_delete() < 0)
1385                 goto test_fail;
1386
1387         if (test_rcu_qsbr_dq_enqueue() < 0)
1388                 goto test_fail;
1389
1390         printf("\nFunctional tests\n");
1391
1392         if (test_rcu_qsbr_sw_sv_3qs() < 0)
1393                 goto test_fail;
1394
1395         if (test_rcu_qsbr_mw_mv_mqs() < 0)
1396                 goto test_fail;
1397
1398         if (test_rcu_qsbr_dq_functional(1, 8, 0) < 0)
1399                 goto test_fail;
1400
1401         if (test_rcu_qsbr_dq_functional(2, 8, RTE_RCU_QSBR_DQ_MT_UNSAFE) < 0)
1402                 goto test_fail;
1403
1404         if (test_rcu_qsbr_dq_functional(303, 16, 0) < 0)
1405                 goto test_fail;
1406
1407         if (test_rcu_qsbr_dq_functional(7, 128, RTE_RCU_QSBR_DQ_MT_UNSAFE) < 0)
1408                 goto test_fail;
1409
1410         free_rcu();
1411
1412         printf("\n");
1413         return 0;
1414
1415 test_fail:
1416         free_rcu();
1417
1418         return -1;
1419 }
1420
1421 REGISTER_TEST_COMMAND(rcu_qsbr_autotest, test_rcu_qsbr_main);