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