1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
3 */
4
5 #include <string.h>
6 #include <errno.h>
7
8 #include "test.h"
9
10 #include <rte_string_fns.h>
11 #include <rte_mbuf.h>
12 #include <rte_byteorder.h>
13 #include <rte_ip.h>
14
15 #ifdef RTE_EXEC_ENV_WINDOWS
16 static int
test_acl(void)17 test_acl(void)
18 {
19 printf("ACL not supported on Windows, skipping test\n");
20 return TEST_SKIPPED;
21 }
22
23 #else
24 #include <rte_acl.h>
25 #include <rte_common.h>
26
27 #include "test_acl.h"
28
29 #define BIT_SIZEOF(x) (sizeof(x) * CHAR_BIT)
30
31 #define LEN RTE_ACL_MAX_CATEGORIES
32
33 RTE_ACL_RULE_DEF(acl_ipv4vlan_rule, RTE_ACL_IPV4VLAN_NUM_FIELDS);
34
35 struct rte_acl_param acl_param = {
36 .name = "acl_ctx",
37 .socket_id = SOCKET_ID_ANY,
38 .rule_size = RTE_ACL_IPV4VLAN_RULE_SZ,
39 .max_rule_num = 0x30000,
40 };
41
42 struct rte_acl_ipv4vlan_rule acl_rule = {
43 .data = { .priority = 1, .category_mask = 0xff },
44 .src_port_low = 0,
45 .src_port_high = UINT16_MAX,
46 .dst_port_low = 0,
47 .dst_port_high = UINT16_MAX,
48 };
49
50 const uint32_t ipv4_7tuple_layout[RTE_ACL_IPV4VLAN_NUM] = {
51 offsetof(struct ipv4_7tuple, proto),
52 offsetof(struct ipv4_7tuple, vlan),
53 offsetof(struct ipv4_7tuple, ip_src),
54 offsetof(struct ipv4_7tuple, ip_dst),
55 offsetof(struct ipv4_7tuple, port_src),
56 };
57
58
59 /* byteswap to cpu or network order */
60 static void
bswap_test_data(struct ipv4_7tuple * data,int len,int to_be)61 bswap_test_data(struct ipv4_7tuple *data, int len, int to_be)
62 {
63 int i;
64
65 for (i = 0; i < len; i++) {
66
67 if (to_be) {
68 /* swap all bytes so that they are in network order */
69 data[i].ip_dst = rte_cpu_to_be_32(data[i].ip_dst);
70 data[i].ip_src = rte_cpu_to_be_32(data[i].ip_src);
71 data[i].port_dst = rte_cpu_to_be_16(data[i].port_dst);
72 data[i].port_src = rte_cpu_to_be_16(data[i].port_src);
73 data[i].vlan = rte_cpu_to_be_16(data[i].vlan);
74 data[i].domain = rte_cpu_to_be_16(data[i].domain);
75 } else {
76 data[i].ip_dst = rte_be_to_cpu_32(data[i].ip_dst);
77 data[i].ip_src = rte_be_to_cpu_32(data[i].ip_src);
78 data[i].port_dst = rte_be_to_cpu_16(data[i].port_dst);
79 data[i].port_src = rte_be_to_cpu_16(data[i].port_src);
80 data[i].vlan = rte_be_to_cpu_16(data[i].vlan);
81 data[i].domain = rte_be_to_cpu_16(data[i].domain);
82 }
83 }
84 }
85
86 static int
acl_ipv4vlan_check_rule(const struct rte_acl_ipv4vlan_rule * rule)87 acl_ipv4vlan_check_rule(const struct rte_acl_ipv4vlan_rule *rule)
88 {
89 if (rule->src_port_low > rule->src_port_high ||
90 rule->dst_port_low > rule->dst_port_high ||
91 rule->src_mask_len > BIT_SIZEOF(rule->src_addr) ||
92 rule->dst_mask_len > BIT_SIZEOF(rule->dst_addr))
93 return -EINVAL;
94 return 0;
95 }
96
97 static void
acl_ipv4vlan_convert_rule(const struct rte_acl_ipv4vlan_rule * ri,struct acl_ipv4vlan_rule * ro)98 acl_ipv4vlan_convert_rule(const struct rte_acl_ipv4vlan_rule *ri,
99 struct acl_ipv4vlan_rule *ro)
100 {
101 ro->data = ri->data;
102
103 ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].value.u8 = ri->proto;
104 ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].value.u16 = ri->vlan;
105 ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].value.u16 = ri->domain;
106 ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = ri->src_addr;
107 ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = ri->dst_addr;
108 ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].value.u16 = ri->src_port_low;
109 ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].value.u16 = ri->dst_port_low;
110
111 ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].mask_range.u8 = ri->proto_mask;
112 ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].mask_range.u16 = ri->vlan_mask;
113 ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].mask_range.u16 =
114 ri->domain_mask;
115 ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 =
116 ri->src_mask_len;
117 ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = ri->dst_mask_len;
118 ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].mask_range.u16 =
119 ri->src_port_high;
120 ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].mask_range.u16 =
121 ri->dst_port_high;
122 }
123
124 /*
125 * Add ipv4vlan rules to an existing ACL context.
126 * This function is not multi-thread safe.
127 *
128 * @param ctx
129 * ACL context to add patterns to.
130 * @param rules
131 * Array of rules to add to the ACL context.
132 * Note that all fields in rte_acl_ipv4vlan_rule structures are expected
133 * to be in host byte order.
134 * @param num
135 * Number of elements in the input array of rules.
136 * @return
137 * - -ENOMEM if there is no space in the ACL context for these rules.
138 * - -EINVAL if the parameters are invalid.
139 * - Zero if operation completed successfully.
140 */
141 static int
rte_acl_ipv4vlan_add_rules(struct rte_acl_ctx * ctx,const struct rte_acl_ipv4vlan_rule * rules,uint32_t num)142 rte_acl_ipv4vlan_add_rules(struct rte_acl_ctx *ctx,
143 const struct rte_acl_ipv4vlan_rule *rules,
144 uint32_t num)
145 {
146 int32_t rc;
147 uint32_t i;
148 struct acl_ipv4vlan_rule rv;
149
150 if (ctx == NULL || rules == NULL)
151 return -EINVAL;
152
153 /* check input rules. */
154 for (i = 0; i != num; i++) {
155 rc = acl_ipv4vlan_check_rule(rules + i);
156 if (rc != 0) {
157 fprintf(stderr, "%s: rule #%u is invalid\n",
158 __func__, i + 1);
159 return rc;
160 }
161 }
162
163 /* perform conversion to the internal format and add to the context. */
164 for (i = 0, rc = 0; i != num && rc == 0; i++) {
165 acl_ipv4vlan_convert_rule(rules + i, &rv);
166 rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&rv, 1);
167 }
168
169 return rc;
170 }
171
172 static void
acl_ipv4vlan_config(struct rte_acl_config * cfg,const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],uint32_t num_categories)173 acl_ipv4vlan_config(struct rte_acl_config *cfg,
174 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],
175 uint32_t num_categories)
176 {
177 static const struct rte_acl_field_def
178 ipv4_defs[RTE_ACL_IPV4VLAN_NUM_FIELDS] = {
179 {
180 .type = RTE_ACL_FIELD_TYPE_BITMASK,
181 .size = sizeof(uint8_t),
182 .field_index = RTE_ACL_IPV4VLAN_PROTO_FIELD,
183 .input_index = RTE_ACL_IPV4VLAN_PROTO,
184 },
185 {
186 .type = RTE_ACL_FIELD_TYPE_BITMASK,
187 .size = sizeof(uint16_t),
188 .field_index = RTE_ACL_IPV4VLAN_VLAN1_FIELD,
189 .input_index = RTE_ACL_IPV4VLAN_VLAN,
190 },
191 {
192 .type = RTE_ACL_FIELD_TYPE_BITMASK,
193 .size = sizeof(uint16_t),
194 .field_index = RTE_ACL_IPV4VLAN_VLAN2_FIELD,
195 .input_index = RTE_ACL_IPV4VLAN_VLAN,
196 },
197 {
198 .type = RTE_ACL_FIELD_TYPE_MASK,
199 .size = sizeof(uint32_t),
200 .field_index = RTE_ACL_IPV4VLAN_SRC_FIELD,
201 .input_index = RTE_ACL_IPV4VLAN_SRC,
202 },
203 {
204 .type = RTE_ACL_FIELD_TYPE_MASK,
205 .size = sizeof(uint32_t),
206 .field_index = RTE_ACL_IPV4VLAN_DST_FIELD,
207 .input_index = RTE_ACL_IPV4VLAN_DST,
208 },
209 {
210 .type = RTE_ACL_FIELD_TYPE_RANGE,
211 .size = sizeof(uint16_t),
212 .field_index = RTE_ACL_IPV4VLAN_SRCP_FIELD,
213 .input_index = RTE_ACL_IPV4VLAN_PORTS,
214 },
215 {
216 .type = RTE_ACL_FIELD_TYPE_RANGE,
217 .size = sizeof(uint16_t),
218 .field_index = RTE_ACL_IPV4VLAN_DSTP_FIELD,
219 .input_index = RTE_ACL_IPV4VLAN_PORTS,
220 },
221 };
222
223 memcpy(&cfg->defs, ipv4_defs, sizeof(ipv4_defs));
224 cfg->num_fields = RTE_DIM(ipv4_defs);
225
226 cfg->defs[RTE_ACL_IPV4VLAN_PROTO_FIELD].offset =
227 layout[RTE_ACL_IPV4VLAN_PROTO];
228 cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].offset =
229 layout[RTE_ACL_IPV4VLAN_VLAN];
230 cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].offset =
231 layout[RTE_ACL_IPV4VLAN_VLAN] +
232 cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].size;
233 cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].offset =
234 layout[RTE_ACL_IPV4VLAN_SRC];
235 cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset =
236 layout[RTE_ACL_IPV4VLAN_DST];
237 cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset =
238 layout[RTE_ACL_IPV4VLAN_PORTS];
239 cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset =
240 layout[RTE_ACL_IPV4VLAN_PORTS] +
241 cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size;
242
243 cfg->num_categories = num_categories;
244 }
245
246 /*
247 * Analyze set of ipv4vlan rules and build required internal
248 * run-time structures.
249 * This function is not multi-thread safe.
250 *
251 * @param ctx
252 * ACL context to build.
253 * @param layout
254 * Layout of input data to search through.
255 * @param num_categories
256 * Maximum number of categories to use in that build.
257 * @return
258 * - -ENOMEM if couldn't allocate enough memory.
259 * - -EINVAL if the parameters are invalid.
260 * - Negative error code if operation failed.
261 * - Zero if operation completed successfully.
262 */
263 static int
rte_acl_ipv4vlan_build(struct rte_acl_ctx * ctx,const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],uint32_t num_categories)264 rte_acl_ipv4vlan_build(struct rte_acl_ctx *ctx,
265 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],
266 uint32_t num_categories)
267 {
268 struct rte_acl_config cfg;
269
270 if (ctx == NULL || layout == NULL)
271 return -EINVAL;
272
273 memset(&cfg, 0, sizeof(cfg));
274 acl_ipv4vlan_config(&cfg, layout, num_categories);
275 return rte_acl_build(ctx, &cfg);
276 }
277
278 /*
279 * Test ACL lookup (selected alg).
280 */
281 static int
test_classify_alg(struct rte_acl_ctx * acx,struct ipv4_7tuple test_data[],const uint8_t * data[],size_t dim,enum rte_acl_classify_alg alg)282 test_classify_alg(struct rte_acl_ctx *acx, struct ipv4_7tuple test_data[],
283 const uint8_t *data[], size_t dim, enum rte_acl_classify_alg alg)
284 {
285 int32_t ret;
286 uint32_t i, result, count;
287 uint32_t results[dim * RTE_ACL_MAX_CATEGORIES];
288
289 /* set given classify alg, skip test if alg is not supported */
290 ret = rte_acl_set_ctx_classify(acx, alg);
291 if (ret != 0)
292 return (ret == -ENOTSUP) ? 0 : ret;
293
294 /**
295 * these will run quite a few times, it's necessary to test code paths
296 * from num=0 to num>8
297 */
298 for (count = 0; count <= dim; count++) {
299 ret = rte_acl_classify(acx, data, results,
300 count, RTE_ACL_MAX_CATEGORIES);
301 if (ret != 0) {
302 printf("Line %i: classify(alg=%d) failed!\n",
303 __LINE__, alg);
304 return ret;
305 }
306
307 /* check if we allow everything we should allow */
308 for (i = 0; i < count; i++) {
309 result =
310 results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW];
311 if (result != test_data[i].allow) {
312 printf("Line %i: Error in allow results at %i "
313 "(expected %"PRIu32" got %"PRIu32")!\n",
314 __LINE__, i, test_data[i].allow,
315 result);
316 return -EINVAL;
317 }
318 }
319
320 /* check if we deny everything we should deny */
321 for (i = 0; i < count; i++) {
322 result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY];
323 if (result != test_data[i].deny) {
324 printf("Line %i: Error in deny results at %i "
325 "(expected %"PRIu32" got %"PRIu32")!\n",
326 __LINE__, i, test_data[i].deny,
327 result);
328 return -EINVAL;
329 }
330 }
331 }
332
333 /* restore default classify alg */
334 return rte_acl_set_ctx_classify(acx, RTE_ACL_CLASSIFY_DEFAULT);
335 }
336
337 /*
338 * Test ACL lookup (all possible methods).
339 */
340 static int
test_classify_run(struct rte_acl_ctx * acx,struct ipv4_7tuple test_data[],size_t dim)341 test_classify_run(struct rte_acl_ctx *acx, struct ipv4_7tuple test_data[],
342 size_t dim)
343 {
344 int32_t ret;
345 uint32_t i;
346 const uint8_t *data[dim];
347
348 static const enum rte_acl_classify_alg alg[] = {
349 RTE_ACL_CLASSIFY_SCALAR,
350 RTE_ACL_CLASSIFY_SSE,
351 RTE_ACL_CLASSIFY_AVX2,
352 RTE_ACL_CLASSIFY_NEON,
353 RTE_ACL_CLASSIFY_ALTIVEC,
354 RTE_ACL_CLASSIFY_AVX512X16,
355 RTE_ACL_CLASSIFY_AVX512X32,
356 };
357
358 /* swap all bytes in the data to network order */
359 bswap_test_data(test_data, dim, 1);
360
361 /* store pointers to test data */
362 for (i = 0; i < dim; i++)
363 data[i] = (uint8_t *)&test_data[i];
364
365 ret = 0;
366 for (i = 0; i != RTE_DIM(alg); i++) {
367 ret = test_classify_alg(acx, test_data, data, dim, alg[i]);
368 if (ret < 0) {
369 printf("Line %i: %s() for alg=%d failed, errno=%d\n",
370 __LINE__, __func__, alg[i], -ret);
371 break;
372 }
373 }
374
375 /* swap data back to cpu order so that next time tests don't fail */
376 bswap_test_data(test_data, dim, 0);
377 return ret;
378 }
379
380 static int
test_classify_buid(struct rte_acl_ctx * acx,const struct rte_acl_ipv4vlan_rule * rules,uint32_t num)381 test_classify_buid(struct rte_acl_ctx *acx,
382 const struct rte_acl_ipv4vlan_rule *rules, uint32_t num)
383 {
384 int ret;
385
386 /* add rules to the context */
387 ret = rte_acl_ipv4vlan_add_rules(acx, rules, num);
388 if (ret != 0) {
389 printf("Line %i: Adding rules to ACL context failed!\n",
390 __LINE__);
391 return ret;
392 }
393
394 /* try building the context */
395 ret = rte_acl_ipv4vlan_build(acx, ipv4_7tuple_layout,
396 RTE_ACL_MAX_CATEGORIES);
397 if (ret != 0) {
398 printf("Line %i: Building ACL context failed!\n", __LINE__);
399 return ret;
400 }
401
402 return 0;
403 }
404
405 #define TEST_CLASSIFY_ITER 4
406
407 /*
408 * Test scalar and SSE ACL lookup.
409 */
410 static int
test_classify(void)411 test_classify(void)
412 {
413 struct rte_acl_ctx *acx;
414 int i, ret;
415
416 acx = rte_acl_create(&acl_param);
417 if (acx == NULL) {
418 printf("Line %i: Error creating ACL context!\n", __LINE__);
419 return -1;
420 }
421
422 ret = 0;
423 for (i = 0; i != TEST_CLASSIFY_ITER; i++) {
424
425 if ((i & 1) == 0)
426 rte_acl_reset(acx);
427 else
428 rte_acl_reset_rules(acx);
429
430 ret = test_classify_buid(acx, acl_test_rules,
431 RTE_DIM(acl_test_rules));
432 if (ret != 0) {
433 printf("Line %i, iter: %d: "
434 "Adding rules to ACL context failed!\n",
435 __LINE__, i);
436 break;
437 }
438
439 ret = test_classify_run(acx, acl_test_data,
440 RTE_DIM(acl_test_data));
441 if (ret != 0) {
442 printf("Line %i, iter: %d: %s failed!\n",
443 __LINE__, i, __func__);
444 break;
445 }
446
447 /* reset rules and make sure that classify still works ok. */
448 rte_acl_reset_rules(acx);
449 ret = test_classify_run(acx, acl_test_data,
450 RTE_DIM(acl_test_data));
451 if (ret != 0) {
452 printf("Line %i, iter: %d: %s failed!\n",
453 __LINE__, i, __func__);
454 break;
455 }
456 }
457
458 rte_acl_free(acx);
459 return ret;
460 }
461
462 static int
test_build_ports_range(void)463 test_build_ports_range(void)
464 {
465 static const struct rte_acl_ipv4vlan_rule test_rules[] = {
466 {
467 /* match all packets. */
468 .data = {
469 .userdata = 1,
470 .category_mask = ACL_ALLOW_MASK,
471 .priority = 101,
472 },
473 .src_port_low = 0,
474 .src_port_high = UINT16_MAX,
475 .dst_port_low = 0,
476 .dst_port_high = UINT16_MAX,
477 },
478 {
479 /* match all packets with dst ports [54-65280]. */
480 .data = {
481 .userdata = 2,
482 .category_mask = ACL_ALLOW_MASK,
483 .priority = 102,
484 },
485 .src_port_low = 0,
486 .src_port_high = UINT16_MAX,
487 .dst_port_low = 54,
488 .dst_port_high = 65280,
489 },
490 {
491 /* match all packets with dst ports [0-52]. */
492 .data = {
493 .userdata = 3,
494 .category_mask = ACL_ALLOW_MASK,
495 .priority = 103,
496 },
497 .src_port_low = 0,
498 .src_port_high = UINT16_MAX,
499 .dst_port_low = 0,
500 .dst_port_high = 52,
501 },
502 {
503 /* match all packets with dst ports [53]. */
504 .data = {
505 .userdata = 4,
506 .category_mask = ACL_ALLOW_MASK,
507 .priority = 99,
508 },
509 .src_port_low = 0,
510 .src_port_high = UINT16_MAX,
511 .dst_port_low = 53,
512 .dst_port_high = 53,
513 },
514 {
515 /* match all packets with dst ports [65279-65535]. */
516 .data = {
517 .userdata = 5,
518 .category_mask = ACL_ALLOW_MASK,
519 .priority = 98,
520 },
521 .src_port_low = 0,
522 .src_port_high = UINT16_MAX,
523 .dst_port_low = 65279,
524 .dst_port_high = UINT16_MAX,
525 },
526 };
527
528 static struct ipv4_7tuple test_data[] = {
529 {
530 .proto = 6,
531 .ip_src = RTE_IPV4(10, 1, 1, 1),
532 .ip_dst = RTE_IPV4(192, 168, 0, 33),
533 .port_dst = 53,
534 .allow = 1,
535 },
536 {
537 .proto = 6,
538 .ip_src = RTE_IPV4(127, 84, 33, 1),
539 .ip_dst = RTE_IPV4(1, 2, 3, 4),
540 .port_dst = 65281,
541 .allow = 1,
542 },
543 };
544
545 struct rte_acl_ctx *acx;
546 int32_t ret, i, j;
547 uint32_t results[RTE_DIM(test_data)];
548 const uint8_t *data[RTE_DIM(test_data)];
549
550 acx = rte_acl_create(&acl_param);
551 if (acx == NULL) {
552 printf("Line %i: Error creating ACL context!\n", __LINE__);
553 return -1;
554 }
555
556 /* swap all bytes in the data to network order */
557 bswap_test_data(test_data, RTE_DIM(test_data), 1);
558
559 /* store pointers to test data */
560 for (i = 0; i != RTE_DIM(test_data); i++)
561 data[i] = (uint8_t *)&test_data[i];
562
563 for (i = 0; i != RTE_DIM(test_rules); i++) {
564 rte_acl_reset(acx);
565 ret = test_classify_buid(acx, test_rules, i + 1);
566 if (ret != 0) {
567 printf("Line %i, iter: %d: "
568 "Adding rules to ACL context failed!\n",
569 __LINE__, i);
570 break;
571 }
572 ret = rte_acl_classify(acx, data, results,
573 RTE_DIM(data), 1);
574 if (ret != 0) {
575 printf("Line %i, iter: %d: classify failed!\n",
576 __LINE__, i);
577 break;
578 }
579
580 /* check results */
581 for (j = 0; j != RTE_DIM(results); j++) {
582 if (results[j] != test_data[j].allow) {
583 printf("Line %i: Error in allow results at %i "
584 "(expected %"PRIu32" got %"PRIu32")!\n",
585 __LINE__, j, test_data[j].allow,
586 results[j]);
587 ret = -EINVAL;
588 }
589 }
590 }
591
592 bswap_test_data(test_data, RTE_DIM(test_data), 0);
593
594 rte_acl_free(acx);
595 return ret;
596 }
597
598 static void
convert_rule(const struct rte_acl_ipv4vlan_rule * ri,struct acl_ipv4vlan_rule * ro)599 convert_rule(const struct rte_acl_ipv4vlan_rule *ri,
600 struct acl_ipv4vlan_rule *ro)
601 {
602 ro->data = ri->data;
603
604 ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].value.u8 = ri->proto;
605 ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].value.u16 = ri->vlan;
606 ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].value.u16 = ri->domain;
607 ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = ri->src_addr;
608 ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = ri->dst_addr;
609 ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].value.u16 = ri->src_port_low;
610 ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].value.u16 = ri->dst_port_low;
611
612 ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].mask_range.u8 = ri->proto_mask;
613 ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].mask_range.u16 = ri->vlan_mask;
614 ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].mask_range.u16 =
615 ri->domain_mask;
616 ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 =
617 ri->src_mask_len;
618 ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = ri->dst_mask_len;
619 ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].mask_range.u16 =
620 ri->src_port_high;
621 ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].mask_range.u16 =
622 ri->dst_port_high;
623 }
624
625 /*
626 * Convert IPV4 source and destination from RTE_ACL_FIELD_TYPE_MASK to
627 * RTE_ACL_FIELD_TYPE_BITMASK.
628 */
629 static void
convert_rule_1(const struct rte_acl_ipv4vlan_rule * ri,struct acl_ipv4vlan_rule * ro)630 convert_rule_1(const struct rte_acl_ipv4vlan_rule *ri,
631 struct acl_ipv4vlan_rule *ro)
632 {
633 uint32_t v;
634
635 convert_rule(ri, ro);
636 v = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32;
637 ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 =
638 RTE_ACL_MASKLEN_TO_BITMASK(v, sizeof(v));
639 v = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32;
640 ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 =
641 RTE_ACL_MASKLEN_TO_BITMASK(v, sizeof(v));
642 }
643
644 /*
645 * Convert IPV4 source and destination from RTE_ACL_FIELD_TYPE_MASK to
646 * RTE_ACL_FIELD_TYPE_RANGE.
647 */
648 static void
convert_rule_2(const struct rte_acl_ipv4vlan_rule * ri,struct acl_ipv4vlan_rule * ro)649 convert_rule_2(const struct rte_acl_ipv4vlan_rule *ri,
650 struct acl_ipv4vlan_rule *ro)
651 {
652 uint32_t hi, lo, mask;
653
654 convert_rule(ri, ro);
655
656 mask = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32;
657 mask = RTE_ACL_MASKLEN_TO_BITMASK(mask, sizeof(mask));
658 lo = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 & mask;
659 hi = lo + ~mask;
660 ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = lo;
661 ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 = hi;
662
663 mask = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32;
664 mask = RTE_ACL_MASKLEN_TO_BITMASK(mask, sizeof(mask));
665 lo = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 & mask;
666 hi = lo + ~mask;
667 ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = lo;
668 ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = hi;
669 }
670
671 /*
672 * Convert rte_acl_ipv4vlan_rule: swap VLAN and PORTS rule fields.
673 */
674 static void
convert_rule_3(const struct rte_acl_ipv4vlan_rule * ri,struct acl_ipv4vlan_rule * ro)675 convert_rule_3(const struct rte_acl_ipv4vlan_rule *ri,
676 struct acl_ipv4vlan_rule *ro)
677 {
678 struct rte_acl_field t1, t2;
679
680 convert_rule(ri, ro);
681
682 t1 = ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD];
683 t2 = ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD];
684
685 ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD] =
686 ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD];
687 ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD] =
688 ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD];
689
690 ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD] = t1;
691 ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD] = t2;
692 }
693
694 /*
695 * Convert rte_acl_ipv4vlan_rule: swap SRC and DST IPv4 address rules.
696 */
697 static void
convert_rule_4(const struct rte_acl_ipv4vlan_rule * ri,struct acl_ipv4vlan_rule * ro)698 convert_rule_4(const struct rte_acl_ipv4vlan_rule *ri,
699 struct acl_ipv4vlan_rule *ro)
700 {
701 struct rte_acl_field t;
702
703 convert_rule(ri, ro);
704
705 t = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD];
706 ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD] =
707 ro->field[RTE_ACL_IPV4VLAN_DST_FIELD];
708
709 ro->field[RTE_ACL_IPV4VLAN_DST_FIELD] = t;
710 }
711
712 static void
ipv4vlan_config(struct rte_acl_config * cfg,const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],uint32_t num_categories)713 ipv4vlan_config(struct rte_acl_config *cfg,
714 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],
715 uint32_t num_categories)
716 {
717 static const struct rte_acl_field_def
718 ipv4_defs[RTE_ACL_IPV4VLAN_NUM_FIELDS] = {
719 {
720 .type = RTE_ACL_FIELD_TYPE_BITMASK,
721 .size = sizeof(uint8_t),
722 .field_index = RTE_ACL_IPV4VLAN_PROTO_FIELD,
723 .input_index = RTE_ACL_IPV4VLAN_PROTO,
724 },
725 {
726 .type = RTE_ACL_FIELD_TYPE_BITMASK,
727 .size = sizeof(uint16_t),
728 .field_index = RTE_ACL_IPV4VLAN_VLAN1_FIELD,
729 .input_index = RTE_ACL_IPV4VLAN_VLAN,
730 },
731 {
732 .type = RTE_ACL_FIELD_TYPE_BITMASK,
733 .size = sizeof(uint16_t),
734 .field_index = RTE_ACL_IPV4VLAN_VLAN2_FIELD,
735 .input_index = RTE_ACL_IPV4VLAN_VLAN,
736 },
737 {
738 .type = RTE_ACL_FIELD_TYPE_MASK,
739 .size = sizeof(uint32_t),
740 .field_index = RTE_ACL_IPV4VLAN_SRC_FIELD,
741 .input_index = RTE_ACL_IPV4VLAN_SRC,
742 },
743 {
744 .type = RTE_ACL_FIELD_TYPE_MASK,
745 .size = sizeof(uint32_t),
746 .field_index = RTE_ACL_IPV4VLAN_DST_FIELD,
747 .input_index = RTE_ACL_IPV4VLAN_DST,
748 },
749 {
750 .type = RTE_ACL_FIELD_TYPE_RANGE,
751 .size = sizeof(uint16_t),
752 .field_index = RTE_ACL_IPV4VLAN_SRCP_FIELD,
753 .input_index = RTE_ACL_IPV4VLAN_PORTS,
754 },
755 {
756 .type = RTE_ACL_FIELD_TYPE_RANGE,
757 .size = sizeof(uint16_t),
758 .field_index = RTE_ACL_IPV4VLAN_DSTP_FIELD,
759 .input_index = RTE_ACL_IPV4VLAN_PORTS,
760 },
761 };
762
763 memcpy(&cfg->defs, ipv4_defs, sizeof(ipv4_defs));
764 cfg->num_fields = RTE_DIM(ipv4_defs);
765
766 cfg->defs[RTE_ACL_IPV4VLAN_PROTO_FIELD].offset =
767 layout[RTE_ACL_IPV4VLAN_PROTO];
768 cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].offset =
769 layout[RTE_ACL_IPV4VLAN_VLAN];
770 cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].offset =
771 layout[RTE_ACL_IPV4VLAN_VLAN] +
772 cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].size;
773 cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].offset =
774 layout[RTE_ACL_IPV4VLAN_SRC];
775 cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset =
776 layout[RTE_ACL_IPV4VLAN_DST];
777 cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset =
778 layout[RTE_ACL_IPV4VLAN_PORTS];
779 cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset =
780 layout[RTE_ACL_IPV4VLAN_PORTS] +
781 cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size;
782
783 cfg->num_categories = num_categories;
784 }
785
786 static int
convert_rules(struct rte_acl_ctx * acx,void (* convert)(const struct rte_acl_ipv4vlan_rule *,struct acl_ipv4vlan_rule *),const struct rte_acl_ipv4vlan_rule * rules,uint32_t num)787 convert_rules(struct rte_acl_ctx *acx,
788 void (*convert)(const struct rte_acl_ipv4vlan_rule *,
789 struct acl_ipv4vlan_rule *),
790 const struct rte_acl_ipv4vlan_rule *rules, uint32_t num)
791 {
792 int32_t rc;
793 uint32_t i;
794 struct acl_ipv4vlan_rule r;
795
796 for (i = 0; i != num; i++) {
797 convert(rules + i, &r);
798 rc = rte_acl_add_rules(acx, (struct rte_acl_rule *)&r, 1);
799 if (rc != 0) {
800 printf("Line %i: Adding rule %u to ACL context "
801 "failed with error code: %d\n",
802 __LINE__, i, rc);
803 return rc;
804 }
805 }
806
807 return 0;
808 }
809
810 static void
convert_config(struct rte_acl_config * cfg)811 convert_config(struct rte_acl_config *cfg)
812 {
813 ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
814 }
815
816 /*
817 * Convert rte_acl_ipv4vlan_rule to use RTE_ACL_FIELD_TYPE_BITMASK.
818 */
819 static void
convert_config_1(struct rte_acl_config * cfg)820 convert_config_1(struct rte_acl_config *cfg)
821 {
822 ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
823 cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].type = RTE_ACL_FIELD_TYPE_BITMASK;
824 cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = RTE_ACL_FIELD_TYPE_BITMASK;
825 }
826
827 /*
828 * Convert rte_acl_ipv4vlan_rule to use RTE_ACL_FIELD_TYPE_RANGE.
829 */
830 static void
convert_config_2(struct rte_acl_config * cfg)831 convert_config_2(struct rte_acl_config *cfg)
832 {
833 ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
834 cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].type = RTE_ACL_FIELD_TYPE_RANGE;
835 cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = RTE_ACL_FIELD_TYPE_RANGE;
836 }
837
838 /*
839 * Convert rte_acl_ipv4vlan_rule: swap VLAN and PORTS rule definitions.
840 */
841 static void
convert_config_3(struct rte_acl_config * cfg)842 convert_config_3(struct rte_acl_config *cfg)
843 {
844 struct rte_acl_field_def t1, t2;
845
846 ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
847
848 t1 = cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD];
849 t2 = cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD];
850
851 /* swap VLAN1 and SRCP rule definition. */
852 cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD] =
853 cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD];
854 cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].field_index = t1.field_index;
855 cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].input_index = t1.input_index;
856
857 /* swap VLAN2 and DSTP rule definition. */
858 cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD] =
859 cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD];
860 cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].field_index = t2.field_index;
861 cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].input_index = t2.input_index;
862
863 cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].type = t1.type;
864 cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size = t1.size;
865 cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset = t1.offset;
866
867 cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].type = t2.type;
868 cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].size = t2.size;
869 cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset = t2.offset;
870 }
871
872 /*
873 * Convert rte_acl_ipv4vlan_rule: swap SRC and DST ip address rule definitions.
874 */
875 static void
convert_config_4(struct rte_acl_config * cfg)876 convert_config_4(struct rte_acl_config *cfg)
877 {
878 struct rte_acl_field_def t;
879
880 ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
881
882 t = cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD];
883
884 cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD] =
885 cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD];
886 cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].field_index = t.field_index;
887 cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].input_index = t.input_index;
888
889 cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = t.type;
890 cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].size = t.size;
891 cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset = t.offset;
892 }
893
894
895 static int
build_convert_rules(struct rte_acl_ctx * acx,void (* config)(struct rte_acl_config *),size_t max_size)896 build_convert_rules(struct rte_acl_ctx *acx,
897 void (*config)(struct rte_acl_config *),
898 size_t max_size)
899 {
900 struct rte_acl_config cfg;
901
902 memset(&cfg, 0, sizeof(cfg));
903 config(&cfg);
904 cfg.max_size = max_size;
905 return rte_acl_build(acx, &cfg);
906 }
907
908 static int
test_convert_rules(const char * desc,void (* config)(struct rte_acl_config *),void (* convert)(const struct rte_acl_ipv4vlan_rule *,struct acl_ipv4vlan_rule *))909 test_convert_rules(const char *desc,
910 void (*config)(struct rte_acl_config *),
911 void (*convert)(const struct rte_acl_ipv4vlan_rule *,
912 struct acl_ipv4vlan_rule *))
913 {
914 struct rte_acl_ctx *acx;
915 int32_t rc;
916 uint32_t i;
917 static const size_t mem_sizes[] = {0, -1};
918
919 printf("running %s(%s)\n", __func__, desc);
920
921 acx = rte_acl_create(&acl_param);
922 if (acx == NULL) {
923 printf("Line %i: Error creating ACL context!\n", __LINE__);
924 return -1;
925 }
926
927 rc = convert_rules(acx, convert, acl_test_rules,
928 RTE_DIM(acl_test_rules));
929 if (rc != 0)
930 printf("Line %i: Error converting ACL rules!\n", __LINE__);
931
932 for (i = 0; rc == 0 && i != RTE_DIM(mem_sizes); i++) {
933
934 rc = build_convert_rules(acx, config, mem_sizes[i]);
935 if (rc != 0) {
936 printf("Line %i: Error @ build_convert_rules(%zu)!\n",
937 __LINE__, mem_sizes[i]);
938 break;
939 }
940
941 rc = test_classify_run(acx, acl_test_data,
942 RTE_DIM(acl_test_data));
943 if (rc != 0)
944 printf("%s failed at line %i, max_size=%zu\n",
945 __func__, __LINE__, mem_sizes[i]);
946 }
947
948 rte_acl_free(acx);
949 return rc;
950 }
951
952 static int
test_convert(void)953 test_convert(void)
954 {
955 static const struct {
956 const char *desc;
957 void (*config)(struct rte_acl_config *);
958 void (*convert)(const struct rte_acl_ipv4vlan_rule *,
959 struct acl_ipv4vlan_rule *);
960 } convert_param[] = {
961 {
962 "acl_ipv4vlan_tuple",
963 convert_config,
964 convert_rule,
965 },
966 {
967 "acl_ipv4vlan_tuple, RTE_ACL_FIELD_TYPE_BITMASK type "
968 "for IPv4",
969 convert_config_1,
970 convert_rule_1,
971 },
972 {
973 "acl_ipv4vlan_tuple, RTE_ACL_FIELD_TYPE_RANGE type "
974 "for IPv4",
975 convert_config_2,
976 convert_rule_2,
977 },
978 {
979 "acl_ipv4vlan_tuple: swap VLAN and PORTs order",
980 convert_config_3,
981 convert_rule_3,
982 },
983 {
984 "acl_ipv4vlan_tuple: swap SRC and DST IPv4 order",
985 convert_config_4,
986 convert_rule_4,
987 },
988 };
989
990 uint32_t i;
991 int32_t rc;
992
993 for (i = 0; i != RTE_DIM(convert_param); i++) {
994 rc = test_convert_rules(convert_param[i].desc,
995 convert_param[i].config,
996 convert_param[i].convert);
997 if (rc != 0) {
998 printf("%s for test-case: %s failed, error code: %d;\n",
999 __func__, convert_param[i].desc, rc);
1000 return rc;
1001 }
1002 }
1003
1004 return 0;
1005 }
1006
1007 /*
1008 * Test wrong layout behavior
1009 * This test supplies the ACL context with invalid layout, which results in
1010 * ACL matching the wrong stuff. However, it should match the wrong stuff
1011 * the right way. We switch around source and destination addresses,
1012 * source and destination ports, and protocol will point to first byte of
1013 * destination port.
1014 */
1015 static int
test_invalid_layout(void)1016 test_invalid_layout(void)
1017 {
1018 struct rte_acl_ctx *acx;
1019 int ret, i;
1020
1021 uint32_t results[RTE_DIM(invalid_layout_data)];
1022 const uint8_t *data[RTE_DIM(invalid_layout_data)];
1023
1024 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {
1025 /* proto points to destination port's first byte */
1026 offsetof(struct ipv4_7tuple, port_dst),
1027
1028 0, /* VLAN not used */
1029
1030 /* src and dst addresses are swapped */
1031 offsetof(struct ipv4_7tuple, ip_dst),
1032 offsetof(struct ipv4_7tuple, ip_src),
1033
1034 /*
1035 * we can't swap ports here, so we will swap
1036 * them in the data
1037 */
1038 offsetof(struct ipv4_7tuple, port_src),
1039 };
1040
1041 acx = rte_acl_create(&acl_param);
1042 if (acx == NULL) {
1043 printf("Line %i: Error creating ACL context!\n", __LINE__);
1044 return -1;
1045 }
1046
1047 /* putting a lot of rules into the context results in greater
1048 * coverage numbers. it doesn't matter if they are identical */
1049 for (i = 0; i < 1000; i++) {
1050 /* add rules to the context */
1051 ret = rte_acl_ipv4vlan_add_rules(acx, invalid_layout_rules,
1052 RTE_DIM(invalid_layout_rules));
1053 if (ret != 0) {
1054 printf("Line %i: Adding rules to ACL context failed!\n",
1055 __LINE__);
1056 rte_acl_free(acx);
1057 return -1;
1058 }
1059 }
1060
1061 /* try building the context */
1062 ret = rte_acl_ipv4vlan_build(acx, layout, 1);
1063 if (ret != 0) {
1064 printf("Line %i: Building ACL context failed!\n", __LINE__);
1065 rte_acl_free(acx);
1066 return -1;
1067 }
1068
1069 /* swap all bytes in the data to network order */
1070 bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 1);
1071
1072 /* prepare data */
1073 for (i = 0; i < (int) RTE_DIM(invalid_layout_data); i++) {
1074 data[i] = (uint8_t *)&invalid_layout_data[i];
1075 }
1076
1077 /* classify tuples */
1078 ret = rte_acl_classify_alg(acx, data, results,
1079 RTE_DIM(results), 1, RTE_ACL_CLASSIFY_SCALAR);
1080 if (ret != 0) {
1081 printf("Line %i: SSE classify failed!\n", __LINE__);
1082 rte_acl_free(acx);
1083 return -1;
1084 }
1085
1086 for (i = 0; i < (int) RTE_DIM(results); i++) {
1087 if (results[i] != invalid_layout_data[i].allow) {
1088 printf("Line %i: Wrong results at %i "
1089 "(result=%u, should be %u)!\n",
1090 __LINE__, i, results[i],
1091 invalid_layout_data[i].allow);
1092 goto err;
1093 }
1094 }
1095
1096 /* classify tuples (scalar) */
1097 ret = rte_acl_classify_alg(acx, data, results, RTE_DIM(results), 1,
1098 RTE_ACL_CLASSIFY_SCALAR);
1099
1100 if (ret != 0) {
1101 printf("Line %i: Scalar classify failed!\n", __LINE__);
1102 rte_acl_free(acx);
1103 return -1;
1104 }
1105
1106 for (i = 0; i < (int) RTE_DIM(results); i++) {
1107 if (results[i] != invalid_layout_data[i].allow) {
1108 printf("Line %i: Wrong results at %i "
1109 "(result=%u, should be %u)!\n",
1110 __LINE__, i, results[i],
1111 invalid_layout_data[i].allow);
1112 goto err;
1113 }
1114 }
1115
1116 rte_acl_free(acx);
1117
1118 /* swap data back to cpu order so that next time tests don't fail */
1119 bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 0);
1120
1121 return 0;
1122 err:
1123
1124 /* swap data back to cpu order so that next time tests don't fail */
1125 bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 0);
1126
1127 rte_acl_free(acx);
1128
1129 return -1;
1130 }
1131
1132 /*
1133 * Test creating and finding ACL contexts, and adding rules
1134 */
1135 static int
test_create_find_add(void)1136 test_create_find_add(void)
1137 {
1138 struct rte_acl_param param;
1139 struct rte_acl_ctx *acx, *acx2, *tmp;
1140 struct rte_acl_ipv4vlan_rule rules[LEN];
1141
1142 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
1143
1144 const char *acx_name = "acx";
1145 const char *acx2_name = "acx2";
1146 int i, ret;
1147
1148 /* create two contexts */
1149 memcpy(¶m, &acl_param, sizeof(param));
1150 param.max_rule_num = 2;
1151
1152 param.name = acx_name;
1153 acx = rte_acl_create(¶m);
1154 if (acx == NULL) {
1155 printf("Line %i: Error creating %s!\n", __LINE__, acx_name);
1156 return -1;
1157 }
1158
1159 param.name = acx2_name;
1160 acx2 = rte_acl_create(¶m);
1161 if (acx2 == NULL || acx2 == acx) {
1162 printf("Line %i: Error creating %s!\n", __LINE__, acx2_name);
1163 rte_acl_free(acx);
1164 return -1;
1165 }
1166
1167 /* try to create third one, with an existing name */
1168 param.name = acx_name;
1169 tmp = rte_acl_create(¶m);
1170 if (tmp != acx) {
1171 printf("Line %i: Creating context with existing name "
1172 "test failed!\n",
1173 __LINE__);
1174 rte_acl_free(tmp);
1175 goto err;
1176 }
1177
1178 param.name = acx2_name;
1179 tmp = rte_acl_create(¶m);
1180 if (tmp != acx2) {
1181 printf("Line %i: Creating context with existing "
1182 "name test 2 failed!\n",
1183 __LINE__);
1184 rte_acl_free(tmp);
1185 goto err;
1186 }
1187
1188 /* try to find existing ACL contexts */
1189 tmp = rte_acl_find_existing(acx_name);
1190 if (tmp != acx) {
1191 printf("Line %i: Finding %s failed!\n", __LINE__, acx_name);
1192 rte_acl_free(tmp);
1193 goto err;
1194 }
1195
1196 tmp = rte_acl_find_existing(acx2_name);
1197 if (tmp != acx2) {
1198 printf("Line %i: Finding %s failed!\n", __LINE__, acx2_name);
1199 rte_acl_free(tmp);
1200 goto err;
1201 }
1202
1203 /* try to find non-existing context */
1204 tmp = rte_acl_find_existing("invalid");
1205 if (tmp != NULL) {
1206 printf("Line %i: Non-existent ACL context found!\n", __LINE__);
1207 goto err;
1208 }
1209
1210 /* free context */
1211 rte_acl_free(acx);
1212
1213
1214 /* create valid (but severely limited) acx */
1215 memcpy(¶m, &acl_param, sizeof(param));
1216 param.max_rule_num = LEN;
1217
1218 acx = rte_acl_create(¶m);
1219 if (acx == NULL) {
1220 printf("Line %i: Error creating %s!\n", __LINE__, param.name);
1221 goto err;
1222 }
1223
1224 /* create dummy acl */
1225 for (i = 0; i < LEN; i++) {
1226 memcpy(&rules[i], &acl_rule,
1227 sizeof(struct rte_acl_ipv4vlan_rule));
1228 /* skip zero */
1229 rules[i].data.userdata = i + 1;
1230 /* one rule per category */
1231 rules[i].data.category_mask = 1 << i;
1232 }
1233
1234 /* try filling up the context */
1235 ret = rte_acl_ipv4vlan_add_rules(acx, rules, LEN);
1236 if (ret != 0) {
1237 printf("Line %i: Adding %i rules to ACL context failed!\n",
1238 __LINE__, LEN);
1239 goto err;
1240 }
1241
1242 /* try adding to a (supposedly) full context */
1243 ret = rte_acl_ipv4vlan_add_rules(acx, rules, 1);
1244 if (ret == 0) {
1245 printf("Line %i: Adding rules to full ACL context should"
1246 "have failed!\n", __LINE__);
1247 goto err;
1248 }
1249
1250 /* try building the context */
1251 ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES);
1252 if (ret != 0) {
1253 printf("Line %i: Building ACL context failed!\n", __LINE__);
1254 goto err;
1255 }
1256
1257 rte_acl_free(acx);
1258 rte_acl_free(acx2);
1259
1260 return 0;
1261 err:
1262 rte_acl_free(acx);
1263 rte_acl_free(acx2);
1264 return -1;
1265 }
1266
1267 /*
1268 * test various invalid rules
1269 */
1270 static int
test_invalid_rules(void)1271 test_invalid_rules(void)
1272 {
1273 struct rte_acl_ctx *acx;
1274 int ret;
1275
1276 struct rte_acl_ipv4vlan_rule rule;
1277
1278 acx = rte_acl_create(&acl_param);
1279 if (acx == NULL) {
1280 printf("Line %i: Error creating ACL context!\n", __LINE__);
1281 return -1;
1282 }
1283
1284 /* test inverted high/low source and destination ports.
1285 * originally, there was a problem with memory consumption when using
1286 * such rules.
1287 */
1288 /* create dummy acl */
1289 memcpy(&rule, &acl_rule, sizeof(struct rte_acl_ipv4vlan_rule));
1290 rule.data.userdata = 1;
1291 rule.dst_port_low = 0xfff0;
1292 rule.dst_port_high = 0x0010;
1293
1294 /* add rules to context and try to build it */
1295 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1296 if (ret == 0) {
1297 printf("Line %i: Adding rules to ACL context "
1298 "should have failed!\n", __LINE__);
1299 goto err;
1300 }
1301
1302 rule.dst_port_low = 0x0;
1303 rule.dst_port_high = 0xffff;
1304 rule.src_port_low = 0xfff0;
1305 rule.src_port_high = 0x0010;
1306
1307 /* add rules to context and try to build it */
1308 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1309 if (ret == 0) {
1310 printf("Line %i: Adding rules to ACL context "
1311 "should have failed!\n", __LINE__);
1312 goto err;
1313 }
1314
1315 rule.dst_port_low = 0x0;
1316 rule.dst_port_high = 0xffff;
1317 rule.src_port_low = 0x0;
1318 rule.src_port_high = 0xffff;
1319
1320 rule.dst_mask_len = 33;
1321
1322 /* add rules to context and try to build it */
1323 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1324 if (ret == 0) {
1325 printf("Line %i: Adding rules to ACL context "
1326 "should have failed!\n", __LINE__);
1327 goto err;
1328 }
1329
1330 rule.dst_mask_len = 0;
1331 rule.src_mask_len = 33;
1332
1333 /* add rules to context and try to build it */
1334 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
1335 if (ret == 0) {
1336 printf("Line %i: Adding rules to ACL context "
1337 "should have failed!\n", __LINE__);
1338 goto err;
1339 }
1340
1341 rte_acl_free(acx);
1342
1343 return 0;
1344
1345 err:
1346 rte_acl_free(acx);
1347
1348 return -1;
1349 }
1350
1351 /*
1352 * test functions by passing invalid or
1353 * non-workable parameters.
1354 *
1355 * we do very limited testing of classify functions here
1356 * because those are performance-critical and
1357 * thus don't do much parameter checking.
1358 */
1359 static int
test_invalid_parameters(void)1360 test_invalid_parameters(void)
1361 {
1362 struct rte_acl_param param;
1363 struct rte_acl_ctx *acx;
1364 struct rte_acl_ipv4vlan_rule rule;
1365 int result;
1366
1367 uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
1368
1369
1370 /**
1371 * rte_ac_create()
1372 */
1373
1374 /* NULL param */
1375 acx = rte_acl_create(NULL);
1376 if (acx != NULL) {
1377 printf("Line %i: ACL context creation with NULL param "
1378 "should have failed!\n", __LINE__);
1379 rte_acl_free(acx);
1380 return -1;
1381 }
1382
1383 /* zero rule size */
1384 memcpy(¶m, &acl_param, sizeof(param));
1385 param.rule_size = 0;
1386
1387 acx = rte_acl_create(¶m);
1388 if (acx == NULL) {
1389 printf("Line %i: ACL context creation with zero rule len "
1390 "failed!\n", __LINE__);
1391 return -1;
1392 } else
1393 rte_acl_free(acx);
1394
1395 /* zero max rule num */
1396 memcpy(¶m, &acl_param, sizeof(param));
1397 param.max_rule_num = 0;
1398
1399 acx = rte_acl_create(¶m);
1400 if (acx == NULL) {
1401 printf("Line %i: ACL context creation with zero rule num "
1402 "failed!\n", __LINE__);
1403 return -1;
1404 } else
1405 rte_acl_free(acx);
1406
1407 if (rte_eal_has_hugepages()) {
1408 /* invalid NUMA node */
1409 memcpy(¶m, &acl_param, sizeof(param));
1410 param.socket_id = RTE_MAX_NUMA_NODES + 1;
1411
1412 acx = rte_acl_create(¶m);
1413 if (acx != NULL) {
1414 printf("Line %i: ACL context creation with invalid "
1415 "NUMA should have failed!\n", __LINE__);
1416 rte_acl_free(acx);
1417 return -1;
1418 }
1419 }
1420
1421 /* NULL name */
1422 memcpy(¶m, &acl_param, sizeof(param));
1423 param.name = NULL;
1424
1425 acx = rte_acl_create(¶m);
1426 if (acx != NULL) {
1427 printf("Line %i: ACL context creation with NULL name "
1428 "should have failed!\n", __LINE__);
1429 rte_acl_free(acx);
1430 return -1;
1431 }
1432
1433 /**
1434 * rte_acl_find_existing
1435 */
1436
1437 acx = rte_acl_find_existing(NULL);
1438 if (acx != NULL) {
1439 printf("Line %i: NULL ACL context found!\n", __LINE__);
1440 rte_acl_free(acx);
1441 return -1;
1442 }
1443
1444 /**
1445 * rte_acl_ipv4vlan_add_rules
1446 */
1447
1448 /* initialize everything */
1449 memcpy(¶m, &acl_param, sizeof(param));
1450 acx = rte_acl_create(¶m);
1451 if (acx == NULL) {
1452 printf("Line %i: ACL context creation failed!\n", __LINE__);
1453 return -1;
1454 }
1455
1456 memcpy(&rule, &acl_rule, sizeof(rule));
1457
1458 /* NULL context */
1459 result = rte_acl_ipv4vlan_add_rules(NULL, &rule, 1);
1460 if (result == 0) {
1461 printf("Line %i: Adding rules with NULL ACL context "
1462 "should have failed!\n", __LINE__);
1463 rte_acl_free(acx);
1464 return -1;
1465 }
1466
1467 /* NULL rule */
1468 result = rte_acl_ipv4vlan_add_rules(acx, NULL, 1);
1469 if (result == 0) {
1470 printf("Line %i: Adding NULL rule to ACL context "
1471 "should have failed!\n", __LINE__);
1472 rte_acl_free(acx);
1473 return -1;
1474 }
1475
1476 /* zero count (should succeed) */
1477 result = rte_acl_ipv4vlan_add_rules(acx, &rule, 0);
1478 if (result != 0) {
1479 printf("Line %i: Adding 0 rules to ACL context failed!\n",
1480 __LINE__);
1481 rte_acl_free(acx);
1482 return -1;
1483 }
1484
1485 /* free ACL context */
1486 rte_acl_free(acx);
1487
1488
1489 /**
1490 * rte_acl_ipv4vlan_build
1491 */
1492
1493 /* reinitialize context */
1494 memcpy(¶m, &acl_param, sizeof(param));
1495 acx = rte_acl_create(¶m);
1496 if (acx == NULL) {
1497 printf("Line %i: ACL context creation failed!\n", __LINE__);
1498 return -1;
1499 }
1500
1501 /* NULL context */
1502 result = rte_acl_ipv4vlan_build(NULL, layout, 1);
1503 if (result == 0) {
1504 printf("Line %i: Building with NULL context "
1505 "should have failed!\n", __LINE__);
1506 rte_acl_free(acx);
1507 return -1;
1508 }
1509
1510 /* NULL layout */
1511 result = rte_acl_ipv4vlan_build(acx, NULL, 1);
1512 if (result == 0) {
1513 printf("Line %i: Building with NULL layout "
1514 "should have failed!\n", __LINE__);
1515 rte_acl_free(acx);
1516 return -1;
1517 }
1518
1519 /* zero categories (should not fail) */
1520 result = rte_acl_ipv4vlan_build(acx, layout, 0);
1521 if (result == 0) {
1522 printf("Line %i: Building with 0 categories should fail!\n",
1523 __LINE__);
1524 rte_acl_free(acx);
1525 return -1;
1526 }
1527
1528 /* SSE classify test */
1529
1530 /* cover zero categories in classify (should not fail) */
1531 result = rte_acl_classify(acx, NULL, NULL, 0, 0);
1532 if (result != 0) {
1533 printf("Line %i: SSE classify with zero categories "
1534 "failed!\n", __LINE__);
1535 rte_acl_free(acx);
1536 return -1;
1537 }
1538
1539 /* cover invalid but positive categories in classify */
1540 result = rte_acl_classify(acx, NULL, NULL, 0, 3);
1541 if (result == 0) {
1542 printf("Line %i: SSE classify with 3 categories "
1543 "should have failed!\n", __LINE__);
1544 rte_acl_free(acx);
1545 return -1;
1546 }
1547
1548 /* scalar classify test */
1549
1550 /* cover zero categories in classify (should not fail) */
1551 result = rte_acl_classify_alg(acx, NULL, NULL, 0, 0,
1552 RTE_ACL_CLASSIFY_SCALAR);
1553 if (result != 0) {
1554 printf("Line %i: Scalar classify with zero categories "
1555 "failed!\n", __LINE__);
1556 rte_acl_free(acx);
1557 return -1;
1558 }
1559
1560 /* cover invalid but positive categories in classify */
1561 result = rte_acl_classify(acx, NULL, NULL, 0, 3);
1562 if (result == 0) {
1563 printf("Line %i: Scalar classify with 3 categories "
1564 "should have failed!\n", __LINE__);
1565 rte_acl_free(acx);
1566 return -1;
1567 }
1568
1569 /* free ACL context */
1570 rte_acl_free(acx);
1571
1572
1573 /**
1574 * make sure void functions don't crash with NULL parameters
1575 */
1576
1577 rte_acl_free(NULL);
1578
1579 rte_acl_dump(NULL);
1580
1581 return 0;
1582 }
1583
1584 /**
1585 * Various tests that don't test much but improve coverage
1586 */
1587 static int
test_misc(void)1588 test_misc(void)
1589 {
1590 struct rte_acl_param param;
1591 struct rte_acl_ctx *acx;
1592
1593 /* create context */
1594 memcpy(¶m, &acl_param, sizeof(param));
1595
1596 acx = rte_acl_create(¶m);
1597 if (acx == NULL) {
1598 printf("Line %i: Error creating ACL context!\n", __LINE__);
1599 return -1;
1600 }
1601
1602 /* dump context with rules - useful for coverage */
1603 rte_acl_list_dump();
1604
1605 rte_acl_dump(acx);
1606
1607 rte_acl_free(acx);
1608
1609 return 0;
1610 }
1611
1612 static uint32_t
get_u32_range_max(void)1613 get_u32_range_max(void)
1614 {
1615 uint32_t i, max;
1616
1617 max = 0;
1618 for (i = 0; i != RTE_DIM(acl_u32_range_test_rules); i++)
1619 max = RTE_MAX(max, acl_u32_range_test_rules[i].src_mask_len);
1620 return max;
1621 }
1622
1623 static uint32_t
get_u32_range_min(void)1624 get_u32_range_min(void)
1625 {
1626 uint32_t i, min;
1627
1628 min = UINT32_MAX;
1629 for (i = 0; i != RTE_DIM(acl_u32_range_test_rules); i++)
1630 min = RTE_MIN(min, acl_u32_range_test_rules[i].src_addr);
1631 return min;
1632 }
1633
1634 static const struct rte_acl_ipv4vlan_rule *
find_u32_range_rule(uint32_t val)1635 find_u32_range_rule(uint32_t val)
1636 {
1637 uint32_t i;
1638
1639 for (i = 0; i != RTE_DIM(acl_u32_range_test_rules); i++) {
1640 if (val >= acl_u32_range_test_rules[i].src_addr &&
1641 val <= acl_u32_range_test_rules[i].src_mask_len)
1642 return acl_u32_range_test_rules + i;
1643 }
1644 return NULL;
1645 }
1646
1647 static void
fill_u32_range_data(struct ipv4_7tuple tdata[],uint32_t start,uint32_t num)1648 fill_u32_range_data(struct ipv4_7tuple tdata[], uint32_t start, uint32_t num)
1649 {
1650 uint32_t i;
1651 const struct rte_acl_ipv4vlan_rule *r;
1652
1653 for (i = 0; i != num; i++) {
1654 tdata[i].ip_src = start + i;
1655 r = find_u32_range_rule(start + i);
1656 if (r != NULL)
1657 tdata[i].allow = r->data.userdata;
1658 }
1659 }
1660
1661 static int
test_u32_range(void)1662 test_u32_range(void)
1663 {
1664 int32_t rc;
1665 uint32_t i, k, max, min;
1666 struct rte_acl_ctx *acx;
1667 struct acl_ipv4vlan_rule r;
1668 struct ipv4_7tuple test_data[64];
1669
1670 acx = rte_acl_create(&acl_param);
1671 if (acx == NULL) {
1672 printf("%s#%i: Error creating ACL context!\n",
1673 __func__, __LINE__);
1674 return -1;
1675 }
1676
1677 for (i = 0; i != RTE_DIM(acl_u32_range_test_rules); i++) {
1678 convert_rule(&acl_u32_range_test_rules[i], &r);
1679 rc = rte_acl_add_rules(acx, (struct rte_acl_rule *)&r, 1);
1680 if (rc != 0) {
1681 printf("%s#%i: Adding rule to ACL context "
1682 "failed with error code: %d\n",
1683 __func__, __LINE__, rc);
1684 rte_acl_free(acx);
1685 return rc;
1686 }
1687 }
1688
1689 rc = build_convert_rules(acx, convert_config_2, 0);
1690 if (rc != 0) {
1691 printf("%s#%i Error @ build_convert_rules!\n",
1692 __func__, __LINE__);
1693 rte_acl_free(acx);
1694 return rc;
1695 }
1696
1697 max = get_u32_range_max();
1698 min = get_u32_range_min();
1699
1700 max = RTE_MAX(max, max + 1);
1701 min = RTE_MIN(min, min - 1);
1702
1703 printf("%s#%d starting range test from %u to %u\n",
1704 __func__, __LINE__, min, max);
1705
1706 for (i = min; i <= max; i += k) {
1707
1708 k = RTE_MIN(max - i + 1, RTE_DIM(test_data));
1709
1710 memset(test_data, 0, sizeof(test_data));
1711 fill_u32_range_data(test_data, i, k);
1712
1713 rc = test_classify_run(acx, test_data, k);
1714 if (rc != 0) {
1715 printf("%s#%d failed at [%u, %u) interval\n",
1716 __func__, __LINE__, i, i + k);
1717 break;
1718 }
1719 }
1720
1721 rte_acl_free(acx);
1722 return rc;
1723 }
1724
1725 static int
test_acl(void)1726 test_acl(void)
1727 {
1728 if (test_invalid_parameters() < 0)
1729 return -1;
1730 if (test_invalid_rules() < 0)
1731 return -1;
1732 if (test_create_find_add() < 0)
1733 return -1;
1734 if (test_invalid_layout() < 0)
1735 return -1;
1736 if (test_misc() < 0)
1737 return -1;
1738 if (test_classify() < 0)
1739 return -1;
1740 if (test_build_ports_range() < 0)
1741 return -1;
1742 if (test_convert() < 0)
1743 return -1;
1744 if (test_u32_range() < 0)
1745 return -1;
1746
1747 return 0;
1748 }
1749
1750 #endif /* !RTE_EXEC_ENV_WINDOWS */
1751
1752 REGISTER_FAST_TEST(acl_autotest, true, true, test_acl);
1753