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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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