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