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