]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/dpdk/test/test-acl/main.c
update download target update for octopus release
[ceph.git] / ceph / src / spdk / dpdk / test / test-acl / main.c
CommitLineData
11fdf7f2
TL
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
7c673cae
FG
3 */
4
5#include <rte_acl.h>
6#include <getopt.h>
7#include <string.h>
8
9#include <rte_cycles.h>
10#include <rte_per_lcore.h>
11#include <rte_lcore.h>
12#include <rte_ip.h>
13
14#define PRINT_USAGE_START "%s [EAL options]\n"
15
16#define RTE_LOGTYPE_TESTACL RTE_LOGTYPE_USER1
17
18#define APP_NAME "TESTACL"
19
20#define GET_CB_FIELD(in, fd, base, lim, dlm) do { \
21 unsigned long val; \
22 char *end_fld; \
23 errno = 0; \
24 val = strtoul((in), &end_fld, (base)); \
25 if (errno != 0 || end_fld[0] != (dlm) || val > (lim)) \
26 return -EINVAL; \
27 (fd) = (typeof(fd))val; \
28 (in) = end_fld + 1; \
29} while (0)
30
31#define OPT_RULE_FILE "rulesf"
32#define OPT_TRACE_FILE "tracef"
33#define OPT_RULE_NUM "rulenum"
34#define OPT_TRACE_NUM "tracenum"
35#define OPT_TRACE_STEP "tracestep"
36#define OPT_SEARCH_ALG "alg"
37#define OPT_BLD_CATEGORIES "bldcat"
38#define OPT_RUN_CATEGORIES "runcat"
39#define OPT_MAX_SIZE "maxsize"
40#define OPT_ITER_NUM "iter"
41#define OPT_VERBOSE "verbose"
42#define OPT_IPV6 "ipv6"
43
44#define TRACE_DEFAULT_NUM 0x10000
45#define TRACE_STEP_MAX 0x1000
46#define TRACE_STEP_DEF 0x100
47
48#define RULE_NUM 0x10000
49
50enum {
51 DUMP_NONE,
52 DUMP_SEARCH,
53 DUMP_PKT,
54 DUMP_MAX
55};
56
57struct acl_alg {
58 const char *name;
59 enum rte_acl_classify_alg alg;
60};
61
62static const struct acl_alg acl_alg[] = {
63 {
64 .name = "scalar",
65 .alg = RTE_ACL_CLASSIFY_SCALAR,
66 },
67 {
68 .name = "sse",
69 .alg = RTE_ACL_CLASSIFY_SSE,
70 },
71 {
72 .name = "avx2",
73 .alg = RTE_ACL_CLASSIFY_AVX2,
74 },
75 {
76 .name = "neon",
77 .alg = RTE_ACL_CLASSIFY_NEON,
78 },
79 {
80 .name = "altivec",
81 .alg = RTE_ACL_CLASSIFY_ALTIVEC,
82 },
83};
84
85static struct {
86 const char *prgname;
87 const char *rule_file;
88 const char *trace_file;
89 size_t max_size;
90 uint32_t bld_categories;
91 uint32_t run_categories;
92 uint32_t nb_rules;
93 uint32_t nb_traces;
94 uint32_t trace_step;
95 uint32_t trace_sz;
96 uint32_t iter_num;
97 uint32_t verbose;
98 uint32_t ipv6;
99 struct acl_alg alg;
100 uint32_t used_traces;
101 void *traces;
102 struct rte_acl_ctx *acx;
103} config = {
104 .bld_categories = 3,
105 .run_categories = 1,
106 .nb_rules = RULE_NUM,
107 .nb_traces = TRACE_DEFAULT_NUM,
108 .trace_step = TRACE_STEP_DEF,
109 .iter_num = 1,
110 .verbose = DUMP_MAX,
111 .alg = {
112 .name = "default",
113 .alg = RTE_ACL_CLASSIFY_DEFAULT,
114 },
115 .ipv6 = 0
116};
117
118static struct rte_acl_param prm = {
119 .name = APP_NAME,
120 .socket_id = SOCKET_ID_ANY,
121};
122
123/*
124 * Rule and trace formats definitions.
125 */
126
127struct ipv4_5tuple {
128 uint8_t proto;
129 uint32_t ip_src;
130 uint32_t ip_dst;
131 uint16_t port_src;
132 uint16_t port_dst;
133};
134
135enum {
136 PROTO_FIELD_IPV4,
137 SRC_FIELD_IPV4,
138 DST_FIELD_IPV4,
139 SRCP_FIELD_IPV4,
140 DSTP_FIELD_IPV4,
141 NUM_FIELDS_IPV4
142};
143
144/*
145 * That effectively defines order of IPV4VLAN classifications:
146 * - PROTO
147 * - VLAN (TAG and DOMAIN)
148 * - SRC IP ADDRESS
149 * - DST IP ADDRESS
150 * - PORTS (SRC and DST)
151 */
152enum {
153 RTE_ACL_IPV4VLAN_PROTO,
154 RTE_ACL_IPV4VLAN_VLAN,
155 RTE_ACL_IPV4VLAN_SRC,
156 RTE_ACL_IPV4VLAN_DST,
157 RTE_ACL_IPV4VLAN_PORTS,
158 RTE_ACL_IPV4VLAN_NUM
159};
160
161struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
162 {
163 .type = RTE_ACL_FIELD_TYPE_BITMASK,
164 .size = sizeof(uint8_t),
165 .field_index = PROTO_FIELD_IPV4,
166 .input_index = RTE_ACL_IPV4VLAN_PROTO,
167 .offset = offsetof(struct ipv4_5tuple, proto),
168 },
169 {
170 .type = RTE_ACL_FIELD_TYPE_MASK,
171 .size = sizeof(uint32_t),
172 .field_index = SRC_FIELD_IPV4,
173 .input_index = RTE_ACL_IPV4VLAN_SRC,
174 .offset = offsetof(struct ipv4_5tuple, ip_src),
175 },
176 {
177 .type = RTE_ACL_FIELD_TYPE_MASK,
178 .size = sizeof(uint32_t),
179 .field_index = DST_FIELD_IPV4,
180 .input_index = RTE_ACL_IPV4VLAN_DST,
181 .offset = offsetof(struct ipv4_5tuple, ip_dst),
182 },
183 {
184 .type = RTE_ACL_FIELD_TYPE_RANGE,
185 .size = sizeof(uint16_t),
186 .field_index = SRCP_FIELD_IPV4,
187 .input_index = RTE_ACL_IPV4VLAN_PORTS,
188 .offset = offsetof(struct ipv4_5tuple, port_src),
189 },
190 {
191 .type = RTE_ACL_FIELD_TYPE_RANGE,
192 .size = sizeof(uint16_t),
193 .field_index = DSTP_FIELD_IPV4,
194 .input_index = RTE_ACL_IPV4VLAN_PORTS,
195 .offset = offsetof(struct ipv4_5tuple, port_dst),
196 },
197};
198
199#define IPV6_ADDR_LEN 16
200#define IPV6_ADDR_U16 (IPV6_ADDR_LEN / sizeof(uint16_t))
201#define IPV6_ADDR_U32 (IPV6_ADDR_LEN / sizeof(uint32_t))
202
203struct ipv6_5tuple {
204 uint8_t proto;
205 uint32_t ip_src[IPV6_ADDR_U32];
206 uint32_t ip_dst[IPV6_ADDR_U32];
207 uint16_t port_src;
208 uint16_t port_dst;
209};
210
211enum {
212 PROTO_FIELD_IPV6,
213 SRC1_FIELD_IPV6,
214 SRC2_FIELD_IPV6,
215 SRC3_FIELD_IPV6,
216 SRC4_FIELD_IPV6,
217 DST1_FIELD_IPV6,
218 DST2_FIELD_IPV6,
219 DST3_FIELD_IPV6,
220 DST4_FIELD_IPV6,
221 SRCP_FIELD_IPV6,
222 DSTP_FIELD_IPV6,
223 NUM_FIELDS_IPV6
224};
225
226struct rte_acl_field_def ipv6_defs[NUM_FIELDS_IPV6] = {
227 {
228 .type = RTE_ACL_FIELD_TYPE_BITMASK,
229 .size = sizeof(uint8_t),
230 .field_index = PROTO_FIELD_IPV6,
231 .input_index = PROTO_FIELD_IPV6,
232 .offset = offsetof(struct ipv6_5tuple, proto),
233 },
234 {
235 .type = RTE_ACL_FIELD_TYPE_MASK,
236 .size = sizeof(uint32_t),
237 .field_index = SRC1_FIELD_IPV6,
238 .input_index = SRC1_FIELD_IPV6,
239 .offset = offsetof(struct ipv6_5tuple, ip_src[0]),
240 },
241 {
242 .type = RTE_ACL_FIELD_TYPE_MASK,
243 .size = sizeof(uint32_t),
244 .field_index = SRC2_FIELD_IPV6,
245 .input_index = SRC2_FIELD_IPV6,
246 .offset = offsetof(struct ipv6_5tuple, ip_src[1]),
247 },
248 {
249 .type = RTE_ACL_FIELD_TYPE_MASK,
250 .size = sizeof(uint32_t),
251 .field_index = SRC3_FIELD_IPV6,
252 .input_index = SRC3_FIELD_IPV6,
253 .offset = offsetof(struct ipv6_5tuple, ip_src[2]),
254 },
255 {
256 .type = RTE_ACL_FIELD_TYPE_MASK,
257 .size = sizeof(uint32_t),
258 .field_index = SRC4_FIELD_IPV6,
259 .input_index = SRC4_FIELD_IPV6,
260 .offset = offsetof(struct ipv6_5tuple, ip_src[3]),
261 },
262 {
263 .type = RTE_ACL_FIELD_TYPE_MASK,
264 .size = sizeof(uint32_t),
265 .field_index = DST1_FIELD_IPV6,
266 .input_index = DST1_FIELD_IPV6,
267 .offset = offsetof(struct ipv6_5tuple, ip_dst[0]),
268 },
269 {
270 .type = RTE_ACL_FIELD_TYPE_MASK,
271 .size = sizeof(uint32_t),
272 .field_index = DST2_FIELD_IPV6,
273 .input_index = DST2_FIELD_IPV6,
274 .offset = offsetof(struct ipv6_5tuple, ip_dst[1]),
275 },
276 {
277 .type = RTE_ACL_FIELD_TYPE_MASK,
278 .size = sizeof(uint32_t),
279 .field_index = DST3_FIELD_IPV6,
280 .input_index = DST3_FIELD_IPV6,
281 .offset = offsetof(struct ipv6_5tuple, ip_dst[2]),
282 },
283 {
284 .type = RTE_ACL_FIELD_TYPE_MASK,
285 .size = sizeof(uint32_t),
286 .field_index = DST4_FIELD_IPV6,
287 .input_index = DST4_FIELD_IPV6,
288 .offset = offsetof(struct ipv6_5tuple, ip_dst[3]),
289 },
290 {
291 .type = RTE_ACL_FIELD_TYPE_RANGE,
292 .size = sizeof(uint16_t),
293 .field_index = SRCP_FIELD_IPV6,
294 .input_index = SRCP_FIELD_IPV6,
295 .offset = offsetof(struct ipv6_5tuple, port_src),
296 },
297 {
298 .type = RTE_ACL_FIELD_TYPE_RANGE,
299 .size = sizeof(uint16_t),
300 .field_index = DSTP_FIELD_IPV6,
301 .input_index = SRCP_FIELD_IPV6,
302 .offset = offsetof(struct ipv6_5tuple, port_dst),
303 },
304};
305
306
307enum {
308 CB_FLD_SRC_ADDR,
309 CB_FLD_DST_ADDR,
310 CB_FLD_SRC_PORT_LOW,
311 CB_FLD_SRC_PORT_DLM,
312 CB_FLD_SRC_PORT_HIGH,
313 CB_FLD_DST_PORT_LOW,
314 CB_FLD_DST_PORT_DLM,
315 CB_FLD_DST_PORT_HIGH,
316 CB_FLD_PROTO,
317 CB_FLD_NUM,
318};
319
320enum {
321 CB_TRC_SRC_ADDR,
322 CB_TRC_DST_ADDR,
323 CB_TRC_SRC_PORT,
324 CB_TRC_DST_PORT,
325 CB_TRC_PROTO,
326 CB_TRC_NUM,
327};
328
329RTE_ACL_RULE_DEF(acl_rule, RTE_ACL_MAX_FIELDS);
330
331static const char cb_port_delim[] = ":";
332
333static char line[LINE_MAX];
334
335#define dump_verbose(lvl, fh, fmt, args...) do { \
336 if ((lvl) <= (int32_t)config.verbose) \
337 fprintf(fh, fmt, ##args); \
338} while (0)
339
340
341/*
342 * Parse ClassBench input trace (test vectors and expected results) file.
343 * Expected format:
344 * <src_ipv4_addr> <space> <dst_ipv4_addr> <space> \
345 * <src_port> <space> <dst_port> <space> <proto>
346 */
347static int
348parse_cb_ipv4_trace(char *str, struct ipv4_5tuple *v)
349{
350 int i;
351 char *s, *sp, *in[CB_TRC_NUM];
352 static const char *dlm = " \t\n";
353
354 s = str;
355 for (i = 0; i != RTE_DIM(in); i++) {
356 in[i] = strtok_r(s, dlm, &sp);
357 if (in[i] == NULL)
358 return -EINVAL;
359 s = NULL;
360 }
361
362 GET_CB_FIELD(in[CB_TRC_SRC_ADDR], v->ip_src, 0, UINT32_MAX, 0);
363 GET_CB_FIELD(in[CB_TRC_DST_ADDR], v->ip_dst, 0, UINT32_MAX, 0);
364 GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0);
365 GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0);
366 GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0);
367
368 /* convert to network byte order. */
369 v->ip_src = rte_cpu_to_be_32(v->ip_src);
370 v->ip_dst = rte_cpu_to_be_32(v->ip_dst);
371 v->port_src = rte_cpu_to_be_16(v->port_src);
372 v->port_dst = rte_cpu_to_be_16(v->port_dst);
373
374 return 0;
375}
376
377/*
378 * Parses IPV6 address, exepcts the following format:
379 * XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX (where X - is a hexedecimal digit).
380 */
381static int
382parse_ipv6_addr(const char *in, const char **end, uint32_t v[IPV6_ADDR_U32],
383 char dlm)
384{
385 uint32_t addr[IPV6_ADDR_U16];
386
387 GET_CB_FIELD(in, addr[0], 16, UINT16_MAX, ':');
388 GET_CB_FIELD(in, addr[1], 16, UINT16_MAX, ':');
389 GET_CB_FIELD(in, addr[2], 16, UINT16_MAX, ':');
390 GET_CB_FIELD(in, addr[3], 16, UINT16_MAX, ':');
391 GET_CB_FIELD(in, addr[4], 16, UINT16_MAX, ':');
392 GET_CB_FIELD(in, addr[5], 16, UINT16_MAX, ':');
393 GET_CB_FIELD(in, addr[6], 16, UINT16_MAX, ':');
394 GET_CB_FIELD(in, addr[7], 16, UINT16_MAX, dlm);
395
396 *end = in;
397
398 v[0] = (addr[0] << 16) + addr[1];
399 v[1] = (addr[2] << 16) + addr[3];
400 v[2] = (addr[4] << 16) + addr[5];
401 v[3] = (addr[6] << 16) + addr[7];
402
403 return 0;
404}
405
406static int
407parse_cb_ipv6_addr_trace(const char *in, uint32_t v[IPV6_ADDR_U32])
408{
409 int32_t rc;
410 const char *end;
411
412 rc = parse_ipv6_addr(in, &end, v, 0);
413 if (rc != 0)
414 return rc;
415
416 v[0] = rte_cpu_to_be_32(v[0]);
417 v[1] = rte_cpu_to_be_32(v[1]);
418 v[2] = rte_cpu_to_be_32(v[2]);
419 v[3] = rte_cpu_to_be_32(v[3]);
420
421 return 0;
422}
423
424/*
425 * Parse ClassBench input trace (test vectors and expected results) file.
426 * Expected format:
427 * <src_ipv6_addr> <space> <dst_ipv6_addr> <space> \
428 * <src_port> <space> <dst_port> <space> <proto>
429 */
430static int
431parse_cb_ipv6_trace(char *str, struct ipv6_5tuple *v)
432{
433 int32_t i, rc;
434 char *s, *sp, *in[CB_TRC_NUM];
435 static const char *dlm = " \t\n";
436
437 s = str;
438 for (i = 0; i != RTE_DIM(in); i++) {
439 in[i] = strtok_r(s, dlm, &sp);
440 if (in[i] == NULL)
441 return -EINVAL;
442 s = NULL;
443 }
444
445 /* get ip6 src address. */
446 rc = parse_cb_ipv6_addr_trace(in[CB_TRC_SRC_ADDR], v->ip_src);
447 if (rc != 0)
448 return rc;
449
450 /* get ip6 dst address. */
451 rc = parse_cb_ipv6_addr_trace(in[CB_TRC_DST_ADDR], v->ip_dst);
452 if (rc != 0)
453 return rc;
454
455 GET_CB_FIELD(in[CB_TRC_SRC_PORT], v->port_src, 0, UINT16_MAX, 0);
456 GET_CB_FIELD(in[CB_TRC_DST_PORT], v->port_dst, 0, UINT16_MAX, 0);
457 GET_CB_FIELD(in[CB_TRC_PROTO], v->proto, 0, UINT8_MAX, 0);
458
459 /* convert to network byte order. */
460 v->port_src = rte_cpu_to_be_16(v->port_src);
461 v->port_dst = rte_cpu_to_be_16(v->port_dst);
462
463 return 0;
464}
465
466static void
467tracef_init(void)
468{
469 static const char name[] = APP_NAME;
470 FILE *f;
471 size_t sz;
472 uint32_t n;
473 struct ipv4_5tuple *v;
474 struct ipv6_5tuple *w;
475
476 sz = config.nb_traces * (config.ipv6 ? sizeof(*w) : sizeof(*v));
477 config.traces = rte_zmalloc_socket(name, sz, RTE_CACHE_LINE_SIZE,
478 SOCKET_ID_ANY);
479 if (config.traces == NULL)
480 rte_exit(EXIT_FAILURE, "Cannot allocate %zu bytes for "
481 "requested %u number of trace records\n",
482 sz, config.nb_traces);
483
484 f = fopen(config.trace_file, "r");
485 if (f == NULL)
486 rte_exit(-EINVAL, "failed to open file: %s\n",
487 config.trace_file);
488
489 v = config.traces;
490 w = config.traces;
491 for (n = 0; n != config.nb_traces; n++) {
492
493 if (fgets(line, sizeof(line), f) == NULL)
494 break;
495
496 if (config.ipv6) {
497 if (parse_cb_ipv6_trace(line, w + n) != 0)
498 rte_exit(EXIT_FAILURE,
499 "%s: failed to parse ipv6 trace "
500 "record at line %u\n",
501 config.trace_file, n + 1);
502 } else {
503 if (parse_cb_ipv4_trace(line, v + n) != 0)
504 rte_exit(EXIT_FAILURE,
505 "%s: failed to parse ipv4 trace "
506 "record at line %u\n",
507 config.trace_file, n + 1);
508 }
509 }
510
511 config.used_traces = n;
512 fclose(f);
513}
514
515static int
516parse_ipv6_net(const char *in, struct rte_acl_field field[4])
517{
518 int32_t rc;
519 const char *mp;
520 uint32_t i, m, v[4];
521 const uint32_t nbu32 = sizeof(uint32_t) * CHAR_BIT;
522
523 /* get address. */
524 rc = parse_ipv6_addr(in, &mp, v, '/');
525 if (rc != 0)
526 return rc;
527
528 /* get mask. */
529 GET_CB_FIELD(mp, m, 0, CHAR_BIT * sizeof(v), 0);
530
531 /* put all together. */
532 for (i = 0; i != RTE_DIM(v); i++) {
533 if (m >= (i + 1) * nbu32)
534 field[i].mask_range.u32 = nbu32;
535 else
536 field[i].mask_range.u32 = m > (i * nbu32) ?
537 m - (i * 32) : 0;
538
539 field[i].value.u32 = v[i];
540 }
541
542 return 0;
543}
544
545
546static int
547parse_cb_ipv6_rule(char *str, struct acl_rule *v)
548{
549 int i, rc;
550 char *s, *sp, *in[CB_FLD_NUM];
551 static const char *dlm = " \t\n";
552
553 /*
554 * Skip leading '@'
555 */
556 if (strchr(str, '@') != str)
557 return -EINVAL;
558
559 s = str + 1;
560
561 for (i = 0; i != RTE_DIM(in); i++) {
562 in[i] = strtok_r(s, dlm, &sp);
563 if (in[i] == NULL)
564 return -EINVAL;
565 s = NULL;
566 }
567
568 rc = parse_ipv6_net(in[CB_FLD_SRC_ADDR], v->field + SRC1_FIELD_IPV6);
569 if (rc != 0) {
570 RTE_LOG(ERR, TESTACL,
571 "failed to read source address/mask: %s\n",
572 in[CB_FLD_SRC_ADDR]);
573 return rc;
574 }
575
576 rc = parse_ipv6_net(in[CB_FLD_DST_ADDR], v->field + DST1_FIELD_IPV6);
577 if (rc != 0) {
578 RTE_LOG(ERR, TESTACL,
579 "failed to read destination address/mask: %s\n",
580 in[CB_FLD_DST_ADDR]);
581 return rc;
582 }
583
584 /* source port. */
585 GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW],
586 v->field[SRCP_FIELD_IPV6].value.u16,
587 0, UINT16_MAX, 0);
588 GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH],
589 v->field[SRCP_FIELD_IPV6].mask_range.u16,
590 0, UINT16_MAX, 0);
591
592 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
593 sizeof(cb_port_delim)) != 0)
594 return -EINVAL;
595
596 /* destination port. */
597 GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW],
598 v->field[DSTP_FIELD_IPV6].value.u16,
599 0, UINT16_MAX, 0);
600 GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH],
601 v->field[DSTP_FIELD_IPV6].mask_range.u16,
602 0, UINT16_MAX, 0);
603
604 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
605 sizeof(cb_port_delim)) != 0)
606 return -EINVAL;
607
608 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV6].value.u8,
609 0, UINT8_MAX, '/');
610 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV6].mask_range.u8,
611 0, UINT8_MAX, 0);
612
613 return 0;
614}
615
616static int
617parse_ipv4_net(const char *in, uint32_t *addr, uint32_t *mask_len)
618{
619 uint8_t a, b, c, d, m;
620
621 GET_CB_FIELD(in, a, 0, UINT8_MAX, '.');
622 GET_CB_FIELD(in, b, 0, UINT8_MAX, '.');
623 GET_CB_FIELD(in, c, 0, UINT8_MAX, '.');
624 GET_CB_FIELD(in, d, 0, UINT8_MAX, '/');
625 GET_CB_FIELD(in, m, 0, sizeof(uint32_t) * CHAR_BIT, 0);
626
627 addr[0] = IPv4(a, b, c, d);
628 mask_len[0] = m;
629
630 return 0;
631}
632/*
633 * Parse ClassBench rules file.
634 * Expected format:
635 * '@'<src_ipv4_addr>'/'<masklen> <space> \
636 * <dst_ipv4_addr>'/'<masklen> <space> \
637 * <src_port_low> <space> ":" <src_port_high> <space> \
638 * <dst_port_low> <space> ":" <dst_port_high> <space> \
639 * <proto>'/'<mask>
640 */
641static int
642parse_cb_ipv4_rule(char *str, struct acl_rule *v)
643{
644 int i, rc;
645 char *s, *sp, *in[CB_FLD_NUM];
646 static const char *dlm = " \t\n";
647
648 /*
649 * Skip leading '@'
650 */
651 if (strchr(str, '@') != str)
652 return -EINVAL;
653
654 s = str + 1;
655
656 for (i = 0; i != RTE_DIM(in); i++) {
657 in[i] = strtok_r(s, dlm, &sp);
658 if (in[i] == NULL)
659 return -EINVAL;
660 s = NULL;
661 }
662
663 rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR],
664 &v->field[SRC_FIELD_IPV4].value.u32,
665 &v->field[SRC_FIELD_IPV4].mask_range.u32);
666 if (rc != 0) {
667 RTE_LOG(ERR, TESTACL,
668 "failed to read source address/mask: %s\n",
669 in[CB_FLD_SRC_ADDR]);
670 return rc;
671 }
672
673 rc = parse_ipv4_net(in[CB_FLD_DST_ADDR],
674 &v->field[DST_FIELD_IPV4].value.u32,
675 &v->field[DST_FIELD_IPV4].mask_range.u32);
676 if (rc != 0) {
677 RTE_LOG(ERR, TESTACL,
678 "failed to read destination address/mask: %s\n",
679 in[CB_FLD_DST_ADDR]);
680 return rc;
681 }
682
683 /* source port. */
684 GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW],
685 v->field[SRCP_FIELD_IPV4].value.u16,
686 0, UINT16_MAX, 0);
687 GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH],
688 v->field[SRCP_FIELD_IPV4].mask_range.u16,
689 0, UINT16_MAX, 0);
690
691 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
692 sizeof(cb_port_delim)) != 0)
693 return -EINVAL;
694
695 /* destination port. */
696 GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW],
697 v->field[DSTP_FIELD_IPV4].value.u16,
698 0, UINT16_MAX, 0);
699 GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH],
700 v->field[DSTP_FIELD_IPV4].mask_range.u16,
701 0, UINT16_MAX, 0);
702
703 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
704 sizeof(cb_port_delim)) != 0)
705 return -EINVAL;
706
707 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].value.u8,
708 0, UINT8_MAX, '/');
709 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].mask_range.u8,
710 0, UINT8_MAX, 0);
711
712 return 0;
713}
714
715typedef int (*parse_5tuple)(char *text, struct acl_rule *rule);
716
717static int
718add_cb_rules(FILE *f, struct rte_acl_ctx *ctx)
719{
720 int rc;
721 uint32_t n;
722 struct acl_rule v;
723 parse_5tuple parser;
724
725 memset(&v, 0, sizeof(v));
726 parser = (config.ipv6 != 0) ? parse_cb_ipv6_rule : parse_cb_ipv4_rule;
727
728 for (n = 1; fgets(line, sizeof(line), f) != NULL; n++) {
729
730 rc = parser(line, &v);
731 if (rc != 0) {
732 RTE_LOG(ERR, TESTACL, "line %u: parse_cb_ipv4vlan_rule"
733 " failed, error code: %d (%s)\n",
734 n, rc, strerror(-rc));
735 return rc;
736 }
737
738 v.data.category_mask = RTE_LEN2MASK(RTE_ACL_MAX_CATEGORIES,
739 typeof(v.data.category_mask));
740 v.data.priority = RTE_ACL_MAX_PRIORITY - n;
741 v.data.userdata = n;
742
743 rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&v, 1);
744 if (rc != 0) {
745 RTE_LOG(ERR, TESTACL, "line %u: failed to add rules "
746 "into ACL context, error code: %d (%s)\n",
747 n, rc, strerror(-rc));
748 return rc;
749 }
750 }
751
752 return 0;
753}
754
755static void
756acx_init(void)
757{
758 int ret;
759 FILE *f;
760 struct rte_acl_config cfg;
761
762 memset(&cfg, 0, sizeof(cfg));
763
764 /* setup ACL build config. */
765 if (config.ipv6) {
766 cfg.num_fields = RTE_DIM(ipv6_defs);
767 memcpy(&cfg.defs, ipv6_defs, sizeof(ipv6_defs));
768 } else {
769 cfg.num_fields = RTE_DIM(ipv4_defs);
770 memcpy(&cfg.defs, ipv4_defs, sizeof(ipv4_defs));
771 }
772 cfg.num_categories = config.bld_categories;
773 cfg.max_size = config.max_size;
774
775 /* setup ACL creation parameters. */
776 prm.rule_size = RTE_ACL_RULE_SZ(cfg.num_fields);
777 prm.max_rule_num = config.nb_rules;
778
779 config.acx = rte_acl_create(&prm);
780 if (config.acx == NULL)
781 rte_exit(rte_errno, "failed to create ACL context\n");
782
783 /* set default classify method for this context. */
784 if (config.alg.alg != RTE_ACL_CLASSIFY_DEFAULT) {
785 ret = rte_acl_set_ctx_classify(config.acx, config.alg.alg);
786 if (ret != 0)
787 rte_exit(ret, "failed to setup %s method "
788 "for ACL context\n", config.alg.name);
789 }
790
791 /* add ACL rules. */
792 f = fopen(config.rule_file, "r");
793 if (f == NULL)
794 rte_exit(-EINVAL, "failed to open file %s\n",
795 config.rule_file);
796
797 ret = add_cb_rules(f, config.acx);
798 if (ret != 0)
799 rte_exit(ret, "failed to add rules into ACL context\n");
800
801 fclose(f);
802
803 /* perform build. */
804 ret = rte_acl_build(config.acx, &cfg);
805
806 dump_verbose(DUMP_NONE, stdout,
807 "rte_acl_build(%u) finished with %d\n",
808 config.bld_categories, ret);
809
810 rte_acl_dump(config.acx);
811
812 if (ret != 0)
813 rte_exit(ret, "failed to build search context\n");
814}
815
816static uint32_t
817search_ip5tuples_once(uint32_t categories, uint32_t step, const char *alg)
818{
819 int ret;
820 uint32_t i, j, k, n, r;
821 const uint8_t *data[step], *v;
822 uint32_t results[step * categories];
823
824 v = config.traces;
825 for (i = 0; i != config.used_traces; i += n) {
826
827 n = RTE_MIN(step, config.used_traces - i);
828
829 for (j = 0; j != n; j++) {
830 data[j] = v;
831 v += config.trace_sz;
832 }
833
834 ret = rte_acl_classify(config.acx, data, results,
835 n, categories);
836
837 if (ret != 0)
838 rte_exit(ret, "classify for ipv%c_5tuples returns %d\n",
839 config.ipv6 ? '6' : '4', ret);
840
841 for (r = 0, j = 0; j != n; j++) {
842 for (k = 0; k != categories; k++, r++) {
843 dump_verbose(DUMP_PKT, stdout,
844 "ipv%c_5tuple: %u, category: %u, "
845 "result: %u\n",
846 config.ipv6 ? '6' : '4',
847 i + j + 1, k, results[r] - 1);
848 }
849
850 }
851 }
852
853 dump_verbose(DUMP_SEARCH, stdout,
854 "%s(%u, %u, %s) returns %u\n", __func__,
855 categories, step, alg, i);
856 return i;
857}
858
859static int
860search_ip5tuples(__attribute__((unused)) void *arg)
861{
862 uint64_t pkt, start, tm;
863 uint32_t i, lcore;
864
865 lcore = rte_lcore_id();
866 start = rte_rdtsc();
867 pkt = 0;
868
869 for (i = 0; i != config.iter_num; i++) {
870 pkt += search_ip5tuples_once(config.run_categories,
871 config.trace_step, config.alg.name);
872 }
873
874 tm = rte_rdtsc() - start;
875 dump_verbose(DUMP_NONE, stdout,
876 "%s @lcore %u: %" PRIu32 " iterations, %" PRIu64 " pkts, %"
877 PRIu32 " categories, %" PRIu64 " cycles, %#Lf cycles/pkt\n",
878 __func__, lcore, i, pkt, config.run_categories,
879 tm, (pkt == 0) ? 0 : (long double)tm / pkt);
880
881 return 0;
882}
883
884static unsigned long
885get_ulong_opt(const char *opt, const char *name, size_t min, size_t max)
886{
887 unsigned long val;
888 char *end;
889
890 errno = 0;
891 val = strtoul(opt, &end, 0);
892 if (errno != 0 || end[0] != 0 || val > max || val < min)
893 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
894 opt, name);
895 return val;
896}
897
898static void
899get_alg_opt(const char *opt, const char *name)
900{
901 uint32_t i;
902
903 for (i = 0; i != RTE_DIM(acl_alg); i++) {
904 if (strcmp(opt, acl_alg[i].name) == 0) {
905 config.alg = acl_alg[i];
906 return;
907 }
908 }
909
910 rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
911 opt, name);
912}
913
914static void
915print_usage(const char *prgname)
916{
917 uint32_t i, n, rc;
918 char buf[PATH_MAX];
919
920 n = 0;
921 buf[0] = 0;
922
923 for (i = 0; i < RTE_DIM(acl_alg) - 1; i++) {
924 rc = snprintf(buf + n, sizeof(buf) - n, "%s|",
925 acl_alg[i].name);
926 if (rc > sizeof(buf) - n)
927 break;
928 n += rc;
929 }
930
931 snprintf(buf + n, sizeof(buf) - n, "%s", acl_alg[i].name);
932
933 fprintf(stdout,
934 PRINT_USAGE_START
935 "--" OPT_RULE_FILE "=<rules set file>\n"
936 "[--" OPT_TRACE_FILE "=<input traces file>]\n"
937 "[--" OPT_RULE_NUM
938 "=<maximum number of rules for ACL context>]\n"
939 "[--" OPT_TRACE_NUM
940 "=<number of traces to read binary file in>]\n"
941 "[--" OPT_TRACE_STEP
942 "=<number of traces to classify per one call>]\n"
943 "[--" OPT_BLD_CATEGORIES
944 "=<number of categories to build with>]\n"
945 "[--" OPT_RUN_CATEGORIES
946 "=<number of categories to run with> "
947 "should be either 1 or multiple of %zu, "
948 "but not greater then %u]\n"
949 "[--" OPT_MAX_SIZE
950 "=<size limit (in bytes) for runtime ACL strucutures> "
951 "leave 0 for default behaviour]\n"
952 "[--" OPT_ITER_NUM "=<number of iterations to perform>]\n"
953 "[--" OPT_VERBOSE "=<verbose level>]\n"
954 "[--" OPT_SEARCH_ALG "=%s]\n"
955 "[--" OPT_IPV6 "=<IPv6 rules and trace files>]\n",
956 prgname, RTE_ACL_RESULTS_MULTIPLIER,
957 (uint32_t)RTE_ACL_MAX_CATEGORIES,
958 buf);
959}
960
961static void
962dump_config(FILE *f)
963{
964 fprintf(f, "%s:\n", __func__);
965 fprintf(f, "%s:%s\n", OPT_RULE_FILE, config.rule_file);
966 fprintf(f, "%s:%s\n", OPT_TRACE_FILE, config.trace_file);
967 fprintf(f, "%s:%u\n", OPT_RULE_NUM, config.nb_rules);
968 fprintf(f, "%s:%u\n", OPT_TRACE_NUM, config.nb_traces);
969 fprintf(f, "%s:%u\n", OPT_TRACE_STEP, config.trace_step);
970 fprintf(f, "%s:%u\n", OPT_BLD_CATEGORIES, config.bld_categories);
971 fprintf(f, "%s:%u\n", OPT_RUN_CATEGORIES, config.run_categories);
972 fprintf(f, "%s:%zu\n", OPT_MAX_SIZE, config.max_size);
973 fprintf(f, "%s:%u\n", OPT_ITER_NUM, config.iter_num);
974 fprintf(f, "%s:%u\n", OPT_VERBOSE, config.verbose);
975 fprintf(f, "%s:%u(%s)\n", OPT_SEARCH_ALG, config.alg.alg,
976 config.alg.name);
977 fprintf(f, "%s:%u\n", OPT_IPV6, config.ipv6);
978}
979
980static void
981check_config(void)
982{
983 if (config.rule_file == NULL) {
984 print_usage(config.prgname);
985 rte_exit(-EINVAL, "mandatory option %s is not specified\n",
986 OPT_RULE_FILE);
987 }
988}
989
990
991static void
992get_input_opts(int argc, char **argv)
993{
994 static struct option lgopts[] = {
995 {OPT_RULE_FILE, 1, 0, 0},
996 {OPT_TRACE_FILE, 1, 0, 0},
997 {OPT_TRACE_NUM, 1, 0, 0},
998 {OPT_RULE_NUM, 1, 0, 0},
999 {OPT_MAX_SIZE, 1, 0, 0},
1000 {OPT_TRACE_STEP, 1, 0, 0},
1001 {OPT_BLD_CATEGORIES, 1, 0, 0},
1002 {OPT_RUN_CATEGORIES, 1, 0, 0},
1003 {OPT_ITER_NUM, 1, 0, 0},
1004 {OPT_VERBOSE, 1, 0, 0},
1005 {OPT_SEARCH_ALG, 1, 0, 0},
1006 {OPT_IPV6, 0, 0, 0},
1007 {NULL, 0, 0, 0}
1008 };
1009
1010 int opt, opt_idx;
1011
1012 while ((opt = getopt_long(argc, argv, "", lgopts, &opt_idx)) != EOF) {
1013
1014 if (opt != 0) {
1015 print_usage(config.prgname);
1016 rte_exit(-EINVAL, "unknown option: %c", opt);
1017 }
1018
1019 if (strcmp(lgopts[opt_idx].name, OPT_RULE_FILE) == 0) {
1020 config.rule_file = optarg;
1021 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_FILE) == 0) {
1022 config.trace_file = optarg;
1023 } else if (strcmp(lgopts[opt_idx].name, OPT_RULE_NUM) == 0) {
1024 config.nb_rules = get_ulong_opt(optarg,
1025 lgopts[opt_idx].name, 1, RTE_ACL_MAX_INDEX + 1);
1026 } else if (strcmp(lgopts[opt_idx].name, OPT_MAX_SIZE) == 0) {
1027 config.max_size = get_ulong_opt(optarg,
1028 lgopts[opt_idx].name, 0, SIZE_MAX);
1029 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_NUM) == 0) {
1030 config.nb_traces = get_ulong_opt(optarg,
1031 lgopts[opt_idx].name, 1, UINT32_MAX);
1032 } else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_STEP) == 0) {
1033 config.trace_step = get_ulong_opt(optarg,
1034 lgopts[opt_idx].name, 1, TRACE_STEP_MAX);
1035 } else if (strcmp(lgopts[opt_idx].name,
1036 OPT_BLD_CATEGORIES) == 0) {
1037 config.bld_categories = get_ulong_opt(optarg,
1038 lgopts[opt_idx].name, 1,
1039 RTE_ACL_MAX_CATEGORIES);
1040 } else if (strcmp(lgopts[opt_idx].name,
1041 OPT_RUN_CATEGORIES) == 0) {
1042 config.run_categories = get_ulong_opt(optarg,
1043 lgopts[opt_idx].name, 1,
1044 RTE_ACL_MAX_CATEGORIES);
1045 } else if (strcmp(lgopts[opt_idx].name, OPT_ITER_NUM) == 0) {
1046 config.iter_num = get_ulong_opt(optarg,
1047 lgopts[opt_idx].name, 1, INT32_MAX);
1048 } else if (strcmp(lgopts[opt_idx].name, OPT_VERBOSE) == 0) {
1049 config.verbose = get_ulong_opt(optarg,
1050 lgopts[opt_idx].name, DUMP_NONE, DUMP_MAX);
1051 } else if (strcmp(lgopts[opt_idx].name,
1052 OPT_SEARCH_ALG) == 0) {
1053 get_alg_opt(optarg, lgopts[opt_idx].name);
1054 } else if (strcmp(lgopts[opt_idx].name, OPT_IPV6) == 0) {
1055 config.ipv6 = 1;
1056 }
1057 }
1058 config.trace_sz = config.ipv6 ? sizeof(struct ipv6_5tuple) :
1059 sizeof(struct ipv4_5tuple);
1060
1061}
1062
1063int
1064main(int argc, char **argv)
1065{
1066 int ret;
1067 uint32_t lcore;
1068
1069 ret = rte_eal_init(argc, argv);
1070 if (ret < 0)
1071 rte_panic("Cannot init EAL\n");
1072
1073 argc -= ret;
1074 argv += ret;
1075
1076 config.prgname = argv[0];
1077
1078 get_input_opts(argc, argv);
1079 dump_config(stdout);
1080 check_config();
1081
1082 acx_init();
1083
1084 if (config.trace_file != NULL)
1085 tracef_init();
1086
1087 RTE_LCORE_FOREACH_SLAVE(lcore)
1088 rte_eal_remote_launch(search_ip5tuples, NULL, lcore);
1089
1090 search_ip5tuples(NULL);
1091
1092 rte_eal_mp_wait_lcore();
1093
1094 rte_acl_free(config.acx);
1095 return 0;
1096}