1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2020 Mellanox Technologies, Ltd
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdint.h>
9 #include <stdbool.h>
10 #include <stdarg.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <getopt.h>
14 #include <signal.h>
15
16 #include <rte_eal.h>
17 #include <rte_common.h>
18 #include <rte_malloc.h>
19 #include <rte_mempool.h>
20 #include <rte_mbuf.h>
21 #include <rte_cycles.h>
22 #include <rte_regexdev.h>
23
24 #define MAX_FILE_NAME 255
25 #define MBUF_CACHE_SIZE 256
26 #define MBUF_SIZE (1 << 8)
27 #define START_BURST_SIZE 32u
28 #define MAX_MATCH_MODE 2
29
30 enum app_args {
31 ARG_HELP,
32 ARG_RULES_FILE_NAME,
33 ARG_DATA_FILE_NAME,
34 ARG_NUM_OF_JOBS,
35 ARG_PERF_MODE,
36 ARG_NUM_OF_ITERATIONS,
37 ARG_NUM_OF_QPS,
38 ARG_NUM_OF_LCORES,
39 ARG_NUM_OF_MBUF_SEGS,
40 ARG_NUM_OF_MATCH_MODE,
41 };
42
43 struct job_ctx {
44 struct rte_mbuf *mbuf;
45 };
46
47 struct qp_params {
48 uint32_t total_enqueue;
49 uint32_t total_dequeue;
50 uint32_t total_matches;
51 struct rte_regex_ops **ops;
52 struct job_ctx *jobs_ctx;
53 char *buf;
54 uint64_t start;
55 uint64_t cycles;
56 };
57
58 struct qps_per_lcore {
59 unsigned int lcore_id;
60 int socket;
61 uint16_t qp_id_base;
62 uint16_t nb_qps;
63 };
64
65 struct regex_conf {
66 uint32_t nb_jobs;
67 bool perf_mode;
68 uint32_t nb_iterations;
69 char *data_file;
70 uint8_t nb_max_matches;
71 uint32_t nb_qps;
72 uint16_t qp_id_base;
73 char *data_buf;
74 long data_len;
75 long job_len;
76 uint32_t nb_segs;
77 uint32_t match_mode;
78 };
79
80 static void
usage(const char * prog_name)81 usage(const char *prog_name)
82 {
83 printf("%s [EAL options] --\n"
84 " --rules NAME: precompiled rules file\n"
85 " --data NAME: data file to use\n"
86 " --nb_jobs: number of jobs to use\n"
87 " --perf N: only outputs the performance data\n"
88 " --nb_iter N: number of iteration to run\n"
89 " --nb_qps N: number of queues to use\n"
90 " --nb_lcores N: number of lcores to use\n"
91 " --nb_segs N: number of mbuf segments\n"
92 " --match_mode N: match mode: 0 - None (default),"
93 " 1 - Highest Priority, 2 - Stop On Any\n",
94 prog_name);
95 }
96
97 static void
args_parse(int argc,char ** argv,char * rules_file,char * data_file,uint32_t * nb_jobs,bool * perf_mode,uint32_t * nb_iterations,uint32_t * nb_qps,uint32_t * nb_lcores,uint32_t * nb_segs,uint32_t * match_mode)98 args_parse(int argc, char **argv, char *rules_file, char *data_file,
99 uint32_t *nb_jobs, bool *perf_mode, uint32_t *nb_iterations,
100 uint32_t *nb_qps, uint32_t *nb_lcores, uint32_t *nb_segs,
101 uint32_t *match_mode)
102 {
103 char **argvopt;
104 int opt;
105 int opt_idx;
106 size_t len;
107 static struct option lgopts[] = {
108 { "help", 0, 0, ARG_HELP},
109 /* Rules database file to load. */
110 { "rules", 1, 0, ARG_RULES_FILE_NAME},
111 /* Data file to load. */
112 { "data", 1, 0, ARG_DATA_FILE_NAME},
113 /* Number of jobs to create. */
114 { "nb_jobs", 1, 0, ARG_NUM_OF_JOBS},
115 /* Perf test only */
116 { "perf", 0, 0, ARG_PERF_MODE},
117 /* Number of iterations to run with perf test */
118 { "nb_iter", 1, 0, ARG_NUM_OF_ITERATIONS},
119 /* Number of QPs. */
120 { "nb_qps", 1, 0, ARG_NUM_OF_QPS},
121 /* Number of lcores. */
122 { "nb_lcores", 1, 0, ARG_NUM_OF_LCORES},
123 /* Number of mbuf segments. */
124 { "nb_segs", 1, 0, ARG_NUM_OF_MBUF_SEGS},
125 /* Match mode. */
126 { "match_mode", 1, 0, ARG_NUM_OF_MATCH_MODE},
127 /* End of options */
128 { 0, 0, 0, 0 }
129 };
130
131 argvopt = argv;
132 while ((opt = getopt_long(argc, argvopt, "",
133 lgopts, &opt_idx)) != EOF) {
134 switch (opt) {
135 case ARG_RULES_FILE_NAME:
136 len = strnlen(optarg, MAX_FILE_NAME - 1);
137 if (len == MAX_FILE_NAME)
138 rte_exit(EXIT_FAILURE,
139 "Rule file name to long max %d\n",
140 MAX_FILE_NAME - 1);
141 strncpy(rules_file, optarg, MAX_FILE_NAME - 1);
142 break;
143 case ARG_DATA_FILE_NAME:
144 len = strnlen(optarg, MAX_FILE_NAME - 1);
145 if (len == MAX_FILE_NAME)
146 rte_exit(EXIT_FAILURE,
147 "Data file name to long max %d\n",
148 MAX_FILE_NAME - 1);
149 strncpy(data_file, optarg, MAX_FILE_NAME - 1);
150 break;
151 case ARG_NUM_OF_JOBS:
152 *nb_jobs = atoi(optarg);
153 break;
154 case ARG_PERF_MODE:
155 *perf_mode = true;
156 break;
157 case ARG_NUM_OF_ITERATIONS:
158 *nb_iterations = atoi(optarg);
159 break;
160 case ARG_NUM_OF_QPS:
161 *nb_qps = atoi(optarg);
162 break;
163 case ARG_NUM_OF_LCORES:
164 *nb_lcores = atoi(optarg);
165 break;
166 case ARG_NUM_OF_MBUF_SEGS:
167 *nb_segs = atoi(optarg);
168 break;
169 case ARG_NUM_OF_MATCH_MODE:
170 *match_mode = atoi(optarg);
171 if (*match_mode > MAX_MATCH_MODE)
172 rte_exit(EXIT_FAILURE,
173 "Invalid match mode value\n");
174 break;
175 case ARG_HELP:
176 usage(argv[0]);
177 break;
178 default:
179 usage(argv[0]);
180 rte_exit(EXIT_FAILURE, "Invalid option: %s\n", argv[optind]);
181 break;
182 }
183 }
184
185 if (!perf_mode)
186 *nb_iterations = 1;
187 }
188
189 static long
read_file(char * file,char ** buf)190 read_file(char *file, char **buf)
191 {
192 FILE *fp;
193 long buf_len = 0;
194 size_t read_len;
195 int res = 0;
196
197 fp = fopen(file, "r");
198 if (!fp)
199 return -EIO;
200 if (fseek(fp, 0L, SEEK_END) == 0) {
201 buf_len = ftell(fp);
202 if (buf_len == -1) {
203 res = EIO;
204 goto error;
205 }
206 *buf = rte_malloc(NULL, sizeof(char) * (buf_len + 1), 4096);
207 if (!*buf) {
208 res = ENOMEM;
209 goto error;
210 }
211 if (fseek(fp, 0L, SEEK_SET) != 0) {
212 res = EIO;
213 goto error;
214 }
215 read_len = fread(*buf, sizeof(char), buf_len, fp);
216 if (read_len != (unsigned long)buf_len) {
217 res = EIO;
218 goto error;
219 }
220 }
221 fclose(fp);
222 return buf_len;
223 error:
224 printf("Error, can't open file %s\n, err = %d", file, res);
225 if (fp)
226 fclose(fp);
227 rte_free(*buf);
228 return -res;
229 }
230
231 static int
clone_buf(char * data_buf,char ** buf,long data_len)232 clone_buf(char *data_buf, char **buf, long data_len)
233 {
234 char *dest_buf;
235 dest_buf =
236 rte_malloc(NULL, sizeof(char) * (data_len + 1), 4096);
237 if (!dest_buf)
238 return -ENOMEM;
239 memcpy(dest_buf, data_buf, data_len + 1);
240 *buf = dest_buf;
241 return 0;
242 }
243
244 static int
init_port(uint16_t * nb_max_payload,char * rules_file,uint8_t * nb_max_matches,uint32_t nb_qps)245 init_port(uint16_t *nb_max_payload, char *rules_file, uint8_t *nb_max_matches,
246 uint32_t nb_qps)
247 {
248 uint16_t id;
249 uint16_t qp_id;
250 uint16_t num_devs;
251 char *rules = NULL;
252 long rules_len;
253 struct rte_regexdev_info info;
254 struct rte_regexdev_config dev_conf = {
255 .nb_queue_pairs = nb_qps,
256 .nb_groups = 1,
257 };
258 struct rte_regexdev_qp_conf qp_conf = {
259 .nb_desc = 1024,
260 .qp_conf_flags = 0,
261 };
262 int res = 0;
263
264 num_devs = rte_regexdev_count();
265 if (num_devs == 0) {
266 printf("Error, no devices detected.\n");
267 return -EINVAL;
268 }
269
270 rules_len = read_file(rules_file, &rules);
271 if (rules_len < 0) {
272 printf("Error, can't read rules files.\n");
273 res = -EIO;
274 goto error;
275 }
276
277 for (id = 0; id < num_devs; id++) {
278 res = rte_regexdev_info_get(id, &info);
279 if (res != 0) {
280 printf("Error, can't get device info.\n");
281 goto error;
282 }
283 printf(":: initializing dev: %d\n", id);
284 *nb_max_matches = info.max_matches;
285 *nb_max_payload = info.max_payload_size;
286 if (info.regexdev_capa & RTE_REGEXDEV_SUPP_MATCH_AS_END_F)
287 dev_conf.dev_cfg_flags |=
288 RTE_REGEXDEV_CFG_MATCH_AS_END_F;
289 dev_conf.nb_max_matches = info.max_matches;
290 dev_conf.nb_rules_per_group = info.max_rules_per_group;
291 dev_conf.rule_db_len = rules_len;
292 dev_conf.rule_db = rules;
293 res = rte_regexdev_configure(id, &dev_conf);
294 if (res < 0) {
295 printf("Error, can't configure device %d.\n", id);
296 goto error;
297 }
298 if (info.regexdev_capa & RTE_REGEXDEV_CAPA_QUEUE_PAIR_OOS_F)
299 qp_conf.qp_conf_flags |=
300 RTE_REGEX_QUEUE_PAIR_CFG_OOS_F;
301 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
302 res = rte_regexdev_queue_pair_setup(id, qp_id,
303 &qp_conf);
304 if (res < 0) {
305 printf("Error, can't setup queue pair %u for "
306 "device %d.\n", qp_id, id);
307 goto error;
308 }
309 }
310 printf(":: initializing device: %d done\n", id);
311 }
312 rte_free(rules);
313 return 0;
314 error:
315 rte_free(rules);
316 return res;
317 }
318
319 static void
extbuf_free_cb(void * addr __rte_unused,void * fcb_opaque __rte_unused)320 extbuf_free_cb(void *addr __rte_unused, void *fcb_opaque __rte_unused)
321 {
322 }
323
324 static inline struct rte_mbuf *
regex_create_segmented_mbuf(struct rte_mempool * mbuf_pool,int pkt_len,int nb_segs,void * buf)325 regex_create_segmented_mbuf(struct rte_mempool *mbuf_pool, int pkt_len,
326 int nb_segs, void *buf) {
327
328 struct rte_mbuf *m = NULL, *mbuf = NULL;
329 uint8_t *dst;
330 char *src = buf;
331 int data_len = 0;
332 int i, size;
333 int t_len;
334
335 if (pkt_len < 1) {
336 printf("Packet size must be 1 or more (is %d)\n", pkt_len);
337 return NULL;
338 }
339
340 if (nb_segs < 1) {
341 printf("Number of segments must be 1 or more (is %d)\n",
342 nb_segs);
343 return NULL;
344 }
345
346 t_len = pkt_len >= nb_segs ? (pkt_len / nb_segs +
347 !!(pkt_len % nb_segs)) : 1;
348 size = pkt_len;
349
350 /* Create chained mbuf_src and fill it with buf data */
351 for (i = 0; size > 0; i++) {
352
353 m = rte_pktmbuf_alloc(mbuf_pool);
354 if (i == 0)
355 mbuf = m;
356
357 if (m == NULL) {
358 printf("Cannot create segment for source mbuf");
359 goto fail;
360 }
361
362 data_len = size > t_len ? t_len : size;
363 memset(rte_pktmbuf_mtod(m, uint8_t *), 0,
364 rte_pktmbuf_tailroom(m));
365 memcpy(rte_pktmbuf_mtod(m, uint8_t *), src, data_len);
366 dst = (uint8_t *)rte_pktmbuf_append(m, data_len);
367 if (dst == NULL) {
368 printf("Cannot append %d bytes to the mbuf\n",
369 data_len);
370 goto fail;
371 }
372
373 if (mbuf != m)
374 rte_pktmbuf_chain(mbuf, m);
375 src += data_len;
376 size -= data_len;
377
378 }
379 return mbuf;
380
381 fail:
382 rte_pktmbuf_free(mbuf);
383 return NULL;
384 }
385
386 static int
run_regex(void * args)387 run_regex(void *args)
388 {
389 struct regex_conf *rgxc = args;
390 uint32_t nb_jobs = rgxc->nb_jobs;
391 uint32_t nb_segs = rgxc->nb_segs;
392 uint32_t nb_iterations = rgxc->nb_iterations;
393 uint8_t nb_max_matches = rgxc->nb_max_matches;
394 uint32_t nb_qps = rgxc->nb_qps;
395 uint16_t qp_id_base = rgxc->qp_id_base;
396 char *data_buf = rgxc->data_buf;
397 long data_len = rgxc->data_len;
398 long job_len = rgxc->job_len;
399 uint32_t match_mode = rgxc->match_mode;
400 long remainder;
401 long act_job_len = 0;
402 bool last_job = false;
403 char *buf = NULL;
404 uint32_t actual_jobs = 0;
405 uint32_t i;
406 uint32_t job_id;
407 uint16_t qp_id;
408 uint16_t dev_id = 0;
409 uint8_t nb_matches;
410 uint16_t rsp_flags = 0;
411 struct rte_regexdev_match *match;
412 long pos;
413 unsigned long d_ind = 0;
414 struct rte_mbuf_ext_shared_info shinfo;
415 int res = 0;
416 long double time;
417 struct rte_mempool *mbuf_mp;
418 struct qp_params *qp;
419 struct qp_params *qps = NULL;
420 bool update;
421 uint16_t qps_used = 0;
422 char mbuf_pool[16];
423
424 shinfo.free_cb = extbuf_free_cb;
425 snprintf(mbuf_pool,
426 sizeof(mbuf_pool),
427 "mbuf_pool_%2u", qp_id_base);
428 mbuf_mp = rte_pktmbuf_pool_create(mbuf_pool,
429 rte_align32pow2(nb_jobs * nb_qps * nb_segs),
430 0, 0, (nb_segs == 1) ? MBUF_SIZE :
431 (rte_align32pow2(job_len + (data_len % nb_jobs)) /
432 nb_segs + RTE_PKTMBUF_HEADROOM),
433 rte_socket_id());
434 if (mbuf_mp == NULL) {
435 printf("Error, can't create memory pool\n");
436 return -ENOMEM;
437 }
438
439 qps = rte_malloc(NULL, sizeof(*qps) * nb_qps, 0);
440 if (!qps) {
441 printf("Error, can't allocate memory for QPs\n");
442 res = -ENOMEM;
443 goto end;
444 }
445
446 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
447 struct rte_regex_ops **ops;
448 struct job_ctx *jobs_ctx;
449
450 qps_used++;
451 qp = &qps[qp_id];
452 qp->jobs_ctx = NULL;
453 qp->buf = NULL;
454 qp->ops = ops = rte_malloc(NULL, sizeof(*ops) * nb_jobs, 0);
455 if (!ops) {
456 printf("Error, can't allocate memory for ops.\n");
457 res = -ENOMEM;
458 goto end;
459 }
460
461 qp->jobs_ctx = jobs_ctx =
462 rte_malloc(NULL, sizeof(*jobs_ctx) * nb_jobs, 0);
463 if (!jobs_ctx) {
464 printf("Error, can't allocate memory for jobs_ctx.\n");
465 res = -ENOMEM;
466 goto end;
467 }
468
469 if (clone_buf(data_buf, &buf, data_len)) {
470 printf("Error, can't clone buf.\n");
471 res = -EXIT_FAILURE;
472 goto end;
473 }
474
475 /* Assign each mbuf with the data to handle. */
476 actual_jobs = 0;
477 pos = 0;
478 remainder = data_len % nb_jobs;
479
480 /* Allocate the jobs and assign each job with an mbuf. */
481 for (i = 0; (pos < data_len) && (i < nb_jobs) ; i++) {
482 act_job_len = RTE_MIN(job_len, data_len - pos);
483
484 if (i == (nb_jobs - 1)) {
485 last_job = true;
486 act_job_len += remainder;
487 }
488
489 ops[i] = rte_malloc(NULL, sizeof(*ops[0]) +
490 nb_max_matches *
491 sizeof(struct rte_regexdev_match), 0);
492 if (!ops[i]) {
493 printf("Error, can't allocate "
494 "memory for op.\n");
495 res = -ENOMEM;
496 goto end;
497 }
498 if (nb_segs > 1) {
499 ops[i]->mbuf = regex_create_segmented_mbuf
500 (mbuf_mp, act_job_len,
501 nb_segs, &buf[pos]);
502 } else {
503 ops[i]->mbuf = rte_pktmbuf_alloc(mbuf_mp);
504 if (ops[i]->mbuf) {
505 rte_pktmbuf_attach_extbuf(ops[i]->mbuf,
506 &buf[pos], 0, act_job_len, &shinfo);
507
508 if (!last_job)
509 ops[i]->mbuf->data_len = job_len;
510 else
511 ops[i]->mbuf->data_len = act_job_len;
512
513 ops[i]->mbuf->pkt_len = act_job_len;
514 }
515 }
516 if (!ops[i]->mbuf) {
517 printf("Error, can't add mbuf.\n");
518 res = -ENOMEM;
519 goto end;
520 }
521
522 jobs_ctx[i].mbuf = ops[i]->mbuf;
523 ops[i]->user_id = i;
524 ops[i]->group_id0 = 1;
525 switch (match_mode) {
526 case 0:
527 /* Nothing to set in req_flags */
528 break;
529 case 1:
530 ops[i]->req_flags |= RTE_REGEX_OPS_REQ_MATCH_HIGH_PRIORITY_F;
531 break;
532 case 2:
533 ops[i]->req_flags |= RTE_REGEX_OPS_REQ_STOP_ON_MATCH_F;
534 break;
535 default:
536 rte_exit(EXIT_FAILURE,
537 "Invalid match mode value\n");
538 break;
539 }
540 pos += act_job_len;
541 actual_jobs++;
542 }
543
544 qp->buf = buf;
545 qp->total_matches = 0;
546 qp->start = 0;
547 qp->cycles = 0;
548 }
549
550 for (i = 0; i < nb_iterations; i++) {
551 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
552 qp = &qps[qp_id];
553 qp->total_enqueue = 0;
554 qp->total_dequeue = 0;
555 /* Re-set user id after dequeue to match data in mbuf. */
556 for (job_id = 0 ; job_id < nb_jobs; job_id++)
557 qp->ops[job_id]->user_id = job_id;
558 }
559 do {
560 update = false;
561 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
562 qp = &qps[qp_id];
563 if (qp->total_dequeue < actual_jobs) {
564 qp->start = rte_rdtsc_precise();
565 struct rte_regex_ops **
566 cur_ops_to_enqueue = qp->ops +
567 qp->total_enqueue;
568
569 if (actual_jobs - qp->total_enqueue)
570 qp->total_enqueue +=
571 rte_regexdev_enqueue_burst
572 (dev_id,
573 qp_id_base + qp_id,
574 cur_ops_to_enqueue,
575 actual_jobs -
576 qp->total_enqueue);
577 }
578 }
579 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
580 qp = &qps[qp_id];
581 if (qp->total_dequeue < actual_jobs) {
582 struct rte_regex_ops **
583 cur_ops_to_dequeue = qp->ops +
584 qp->total_dequeue;
585
586 qp->total_dequeue +=
587 rte_regexdev_dequeue_burst
588 (dev_id,
589 qp_id_base + qp_id,
590 cur_ops_to_dequeue,
591 qp->total_enqueue -
592 qp->total_dequeue);
593 qp->cycles +=
594 (rte_rdtsc_precise() - qp->start);
595 update = true;
596 }
597 }
598 } while (update);
599 }
600 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
601 qp = &qps[qp_id];
602 time = (long double)qp->cycles / rte_get_timer_hz();
603 printf("Core=%u QP=%u Job=%ld Bytes Last Job=%ld Bytes Time=%Lf sec Perf=%Lf "
604 "Gbps\n", rte_lcore_id(), qp_id + qp_id_base,
605 job_len, act_job_len, time,
606 (((double)data_len * nb_iterations * 8)
607 / time) / 1000000000.0);
608 }
609
610 if (rgxc->perf_mode)
611 goto end;
612 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
613 printf("\n############ Core=%u QP=%u ############\n",
614 rte_lcore_id(), qp_id + qp_id_base);
615 qp = &qps[qp_id];
616 /* Log results per job. */
617 for (d_ind = 0; d_ind < qp->total_dequeue; d_ind++) {
618 nb_matches = qp->ops[d_ind % actual_jobs]->nb_matches;
619 rsp_flags = qp->ops[d_ind % actual_jobs]->rsp_flags;
620 printf("Job id %"PRIu64" number of matches = %d, rsp flags = 0x%x\n",
621 qp->ops[d_ind]->user_id, nb_matches, rsp_flags);
622 qp->total_matches += nb_matches;
623 match = qp->ops[d_ind % actual_jobs]->matches;
624 for (i = 0; i < nb_matches; i++) {
625 printf("match %d, rule = %d, "
626 "start = %d,len = %d\n",
627 i, match->rule_id, match->start_offset,
628 match->len);
629 match++;
630 }
631 }
632 printf("Total matches = %d\n", qp->total_matches);
633 printf("All Matches:\n");
634 /* Log absolute results. */
635 for (d_ind = 0; d_ind < qp->total_dequeue; d_ind++) {
636 nb_matches = qp->ops[d_ind % actual_jobs]->nb_matches;
637 qp->total_matches += nb_matches;
638 match = qp->ops[d_ind % actual_jobs]->matches;
639 for (i = 0; i < nb_matches; i++) {
640 printf("start = %d, len = %d, rule = %d\n",
641 match->start_offset +
642 (int)(qp->ops[d_ind % actual_jobs]->user_id * job_len),
643 match->len, match->rule_id);
644 match++;
645 }
646 }
647 }
648 end:
649 for (qp_id = 0; qp_id < qps_used; qp_id++) {
650 qp = &qps[qp_id];
651 for (i = 0; i < actual_jobs && qp->ops; i++)
652 rte_free(qp->ops[i]);
653 rte_free(qp->ops);
654 qp->ops = NULL;
655 for (i = 0; i < actual_jobs && qp->jobs_ctx; i++)
656 rte_pktmbuf_free(qp->jobs_ctx[i].mbuf);
657 rte_free(qp->jobs_ctx);
658 qp->jobs_ctx = NULL;
659 rte_free(qp->buf);
660 qp->buf = NULL;
661 }
662 rte_mempool_free(mbuf_mp);
663 rte_free(qps);
664 return res;
665 }
666
667 static int
distribute_qps_to_lcores(uint32_t nb_cores,uint32_t nb_qps,struct qps_per_lcore ** qpl)668 distribute_qps_to_lcores(uint32_t nb_cores, uint32_t nb_qps,
669 struct qps_per_lcore **qpl)
670 {
671 int socket;
672 unsigned lcore_id;
673 uint32_t i;
674 uint16_t min_qp_id;
675 uint16_t max_qp_id;
676 struct qps_per_lcore *qps_per_lcore;
677 uint32_t detected_lcores;
678
679 if (nb_qps < nb_cores) {
680 nb_cores = nb_qps;
681 printf("Reducing number of cores to number of QPs (%u)\n",
682 nb_cores);
683 }
684 /* Allocate qps_per_lcore array */
685 qps_per_lcore =
686 rte_malloc(NULL, sizeof(*qps_per_lcore) * nb_cores, 0);
687 if (!qps_per_lcore)
688 rte_exit(EXIT_FAILURE, "Failed to create qps_per_lcore array\n");
689 *qpl = qps_per_lcore;
690 detected_lcores = 0;
691 min_qp_id = 0;
692
693 RTE_LCORE_FOREACH_WORKER(lcore_id) {
694 if (detected_lcores >= nb_cores)
695 break;
696 qps_per_lcore[detected_lcores].lcore_id = lcore_id;
697 socket = rte_lcore_to_socket_id(lcore_id);
698 if (socket == SOCKET_ID_ANY)
699 socket = 0;
700 qps_per_lcore[detected_lcores].socket = socket;
701 qps_per_lcore[detected_lcores].qp_id_base = min_qp_id;
702 max_qp_id = min_qp_id + nb_qps / nb_cores - 1;
703 if (nb_qps % nb_cores > detected_lcores)
704 max_qp_id++;
705 qps_per_lcore[detected_lcores].nb_qps = max_qp_id -
706 min_qp_id + 1;
707 min_qp_id = max_qp_id + 1;
708 detected_lcores++;
709 }
710 if (detected_lcores != nb_cores)
711 return -1;
712
713 for (i = 0; i < detected_lcores; i++) {
714 printf("===> Core %d: allocated queues: ",
715 qps_per_lcore[i].lcore_id);
716 min_qp_id = qps_per_lcore[i].qp_id_base;
717 max_qp_id =
718 qps_per_lcore[i].qp_id_base + qps_per_lcore[i].nb_qps;
719 while (min_qp_id < max_qp_id) {
720 printf("%u ", min_qp_id);
721 min_qp_id++;
722 }
723 printf("\n");
724 }
725 return 0;
726 }
727
728 int
main(int argc,char ** argv)729 main(int argc, char **argv)
730 {
731 char rules_file[MAX_FILE_NAME];
732 char data_file[MAX_FILE_NAME];
733 uint32_t nb_jobs = 0;
734 bool perf_mode = 0;
735 uint32_t nb_iterations = 0;
736 int ret;
737 uint16_t nb_max_payload = 0;
738 uint8_t nb_max_matches = 0;
739 uint32_t nb_qps = 1;
740 char *data_buf;
741 long data_len;
742 long job_len;
743 uint32_t nb_lcores = 1, nb_segs = 1;
744 uint32_t match_mode = 0;
745 struct regex_conf *rgxc;
746 uint32_t i;
747 struct qps_per_lcore *qps_per_lcore;
748
749 /* Init EAL. */
750 ret = rte_eal_init(argc, argv);
751 if (ret < 0)
752 rte_exit(EXIT_FAILURE, "EAL init failed\n");
753 argc -= ret;
754 argv += ret;
755 if (argc > 1)
756 args_parse(argc, argv, rules_file, data_file, &nb_jobs,
757 &perf_mode, &nb_iterations, &nb_qps,
758 &nb_lcores, &nb_segs, &match_mode);
759
760 if (nb_qps == 0)
761 rte_exit(EXIT_FAILURE, "Number of QPs must be greater than 0\n");
762 if (nb_lcores == 0)
763 rte_exit(EXIT_FAILURE, "Number of lcores must be greater than 0\n");
764 if (nb_jobs == 0)
765 rte_exit(EXIT_FAILURE, "Number of jobs must be greater than 0\n");
766 if (distribute_qps_to_lcores(nb_lcores, nb_qps, &qps_per_lcore) < 0)
767 rte_exit(EXIT_FAILURE, "Failed to distribute queues to lcores!\n");
768 ret = init_port(&nb_max_payload, rules_file,
769 &nb_max_matches, nb_qps);
770 if (ret < 0)
771 rte_exit(EXIT_FAILURE, "init port failed\n");
772
773 data_len = read_file(data_file, &data_buf);
774 if (data_len <= 0)
775 rte_exit(EXIT_FAILURE, "Error, can't read file, or file is empty.\n");
776
777 job_len = data_len / nb_jobs;
778 if (job_len == 0)
779 rte_exit(EXIT_FAILURE, "Error, To many jobs, for the given input.\n");
780
781 if (job_len > nb_max_payload)
782 rte_exit(EXIT_FAILURE, "Error, not enough jobs to cover input.\n");
783
784 rgxc = rte_malloc(NULL, sizeof(*rgxc) * nb_lcores, 0);
785 if (!rgxc)
786 rte_exit(EXIT_FAILURE, "Failed to create Regex Conf\n");
787 for (i = 0; i < nb_lcores; i++) {
788 rgxc[i] = (struct regex_conf){
789 .nb_jobs = nb_jobs,
790 .nb_segs = nb_segs,
791 .perf_mode = perf_mode,
792 .nb_iterations = nb_iterations,
793 .nb_max_matches = nb_max_matches,
794 .nb_qps = qps_per_lcore[i].nb_qps,
795 .qp_id_base = qps_per_lcore[i].qp_id_base,
796 .data_buf = data_buf,
797 .data_len = data_len,
798 .job_len = job_len,
799 .match_mode = match_mode,
800 };
801 rte_eal_remote_launch(run_regex, &rgxc[i],
802 qps_per_lcore[i].lcore_id);
803 }
804 rte_eal_mp_wait_lcore();
805 rte_free(data_buf);
806 rte_free(rgxc);
807 rte_free(qps_per_lcore);
808 return EXIT_SUCCESS;
809 }
810