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