1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2022 Intel Corporation 3 */ 4 5 #include "l3fwd.h" 6 #include "l3fwd_route.h" 7 8 /* 9 * Rule and trace formats definitions. 10 */ 11 12 enum { 13 PROTO_FIELD_IPV4, 14 SRC_FIELD_IPV4, 15 DST_FIELD_IPV4, 16 SRCP_FIELD_IPV4, 17 DSTP_FIELD_IPV4, 18 NUM_FIELDS_IPV4 19 }; 20 21 /* 22 * That effectively defines order of IPV4VLAN classifications: 23 * - PROTO 24 * - VLAN (TAG and DOMAIN) 25 * - SRC IP ADDRESS 26 * - DST IP ADDRESS 27 * - PORTS (SRC and DST) 28 */ 29 enum { 30 RTE_ACL_IPV4VLAN_PROTO, 31 RTE_ACL_IPV4VLAN_VLAN, 32 RTE_ACL_IPV4VLAN_SRC, 33 RTE_ACL_IPV4VLAN_DST, 34 RTE_ACL_IPV4VLAN_PORTS, 35 RTE_ACL_IPV4VLAN_NUM 36 }; 37 38 struct acl_algorithms acl_alg[] = { 39 { 40 .name = "scalar", 41 .alg = RTE_ACL_CLASSIFY_SCALAR, 42 }, 43 { 44 .name = "sse", 45 .alg = RTE_ACL_CLASSIFY_SSE, 46 }, 47 { 48 .name = "avx2", 49 .alg = RTE_ACL_CLASSIFY_AVX2, 50 }, 51 { 52 .name = "neon", 53 .alg = RTE_ACL_CLASSIFY_NEON, 54 }, 55 { 56 .name = "altivec", 57 .alg = RTE_ACL_CLASSIFY_ALTIVEC, 58 }, 59 { 60 .name = "avx512x16", 61 .alg = RTE_ACL_CLASSIFY_AVX512X16, 62 }, 63 { 64 .name = "avx512x32", 65 .alg = RTE_ACL_CLASSIFY_AVX512X32, 66 }, 67 }; 68 69 struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = { 70 { 71 .type = RTE_ACL_FIELD_TYPE_BITMASK, 72 .size = sizeof(uint8_t), 73 .field_index = PROTO_FIELD_IPV4, 74 .input_index = RTE_ACL_IPV4VLAN_PROTO, 75 .offset = 0, 76 }, 77 { 78 .type = RTE_ACL_FIELD_TYPE_MASK, 79 .size = sizeof(uint32_t), 80 .field_index = SRC_FIELD_IPV4, 81 .input_index = RTE_ACL_IPV4VLAN_SRC, 82 .offset = offsetof(struct rte_ipv4_hdr, src_addr) - 83 offsetof(struct rte_ipv4_hdr, next_proto_id), 84 }, 85 { 86 .type = RTE_ACL_FIELD_TYPE_MASK, 87 .size = sizeof(uint32_t), 88 .field_index = DST_FIELD_IPV4, 89 .input_index = RTE_ACL_IPV4VLAN_DST, 90 .offset = offsetof(struct rte_ipv4_hdr, dst_addr) - 91 offsetof(struct rte_ipv4_hdr, next_proto_id), 92 }, 93 { 94 .type = RTE_ACL_FIELD_TYPE_RANGE, 95 .size = sizeof(uint16_t), 96 .field_index = SRCP_FIELD_IPV4, 97 .input_index = RTE_ACL_IPV4VLAN_PORTS, 98 .offset = sizeof(struct rte_ipv4_hdr) - 99 offsetof(struct rte_ipv4_hdr, next_proto_id), 100 }, 101 { 102 .type = RTE_ACL_FIELD_TYPE_RANGE, 103 .size = sizeof(uint16_t), 104 .field_index = DSTP_FIELD_IPV4, 105 .input_index = RTE_ACL_IPV4VLAN_PORTS, 106 .offset = sizeof(struct rte_ipv4_hdr) - 107 offsetof(struct rte_ipv4_hdr, next_proto_id) + 108 sizeof(uint16_t), 109 }, 110 }; 111 112 enum { 113 PROTO_FIELD_IPV6, 114 SRC1_FIELD_IPV6, 115 SRC2_FIELD_IPV6, 116 SRC3_FIELD_IPV6, 117 SRC4_FIELD_IPV6, 118 DST1_FIELD_IPV6, 119 DST2_FIELD_IPV6, 120 DST3_FIELD_IPV6, 121 DST4_FIELD_IPV6, 122 SRCP_FIELD_IPV6, 123 DSTP_FIELD_IPV6, 124 NUM_FIELDS_IPV6 125 }; 126 127 struct rte_acl_field_def ipv6_defs[NUM_FIELDS_IPV6] = { 128 { 129 .type = RTE_ACL_FIELD_TYPE_BITMASK, 130 .size = sizeof(uint8_t), 131 .field_index = PROTO_FIELD_IPV6, 132 .input_index = PROTO_FIELD_IPV6, 133 .offset = 0, 134 }, 135 { 136 .type = RTE_ACL_FIELD_TYPE_MASK, 137 .size = sizeof(uint32_t), 138 .field_index = SRC1_FIELD_IPV6, 139 .input_index = SRC1_FIELD_IPV6, 140 .offset = offsetof(struct rte_ipv6_hdr, src_addr) - 141 offsetof(struct rte_ipv6_hdr, proto), 142 }, 143 { 144 .type = RTE_ACL_FIELD_TYPE_MASK, 145 .size = sizeof(uint32_t), 146 .field_index = SRC2_FIELD_IPV6, 147 .input_index = SRC2_FIELD_IPV6, 148 .offset = offsetof(struct rte_ipv6_hdr, src_addr) - 149 offsetof(struct rte_ipv6_hdr, proto) + sizeof(uint32_t), 150 }, 151 { 152 .type = RTE_ACL_FIELD_TYPE_MASK, 153 .size = sizeof(uint32_t), 154 .field_index = SRC3_FIELD_IPV6, 155 .input_index = SRC3_FIELD_IPV6, 156 .offset = offsetof(struct rte_ipv6_hdr, src_addr) - 157 offsetof(struct rte_ipv6_hdr, proto) + 158 2 * sizeof(uint32_t), 159 }, 160 { 161 .type = RTE_ACL_FIELD_TYPE_MASK, 162 .size = sizeof(uint32_t), 163 .field_index = SRC4_FIELD_IPV6, 164 .input_index = SRC4_FIELD_IPV6, 165 .offset = offsetof(struct rte_ipv6_hdr, src_addr) - 166 offsetof(struct rte_ipv6_hdr, proto) + 167 3 * sizeof(uint32_t), 168 }, 169 { 170 .type = RTE_ACL_FIELD_TYPE_MASK, 171 .size = sizeof(uint32_t), 172 .field_index = DST1_FIELD_IPV6, 173 .input_index = DST1_FIELD_IPV6, 174 .offset = offsetof(struct rte_ipv6_hdr, dst_addr) 175 - offsetof(struct rte_ipv6_hdr, proto), 176 }, 177 { 178 .type = RTE_ACL_FIELD_TYPE_MASK, 179 .size = sizeof(uint32_t), 180 .field_index = DST2_FIELD_IPV6, 181 .input_index = DST2_FIELD_IPV6, 182 .offset = offsetof(struct rte_ipv6_hdr, dst_addr) - 183 offsetof(struct rte_ipv6_hdr, proto) + sizeof(uint32_t), 184 }, 185 { 186 .type = RTE_ACL_FIELD_TYPE_MASK, 187 .size = sizeof(uint32_t), 188 .field_index = DST3_FIELD_IPV6, 189 .input_index = DST3_FIELD_IPV6, 190 .offset = offsetof(struct rte_ipv6_hdr, dst_addr) - 191 offsetof(struct rte_ipv6_hdr, proto) + 192 2 * sizeof(uint32_t), 193 }, 194 { 195 .type = RTE_ACL_FIELD_TYPE_MASK, 196 .size = sizeof(uint32_t), 197 .field_index = DST4_FIELD_IPV6, 198 .input_index = DST4_FIELD_IPV6, 199 .offset = offsetof(struct rte_ipv6_hdr, dst_addr) - 200 offsetof(struct rte_ipv6_hdr, proto) + 201 3 * sizeof(uint32_t), 202 }, 203 { 204 .type = RTE_ACL_FIELD_TYPE_RANGE, 205 .size = sizeof(uint16_t), 206 .field_index = SRCP_FIELD_IPV6, 207 .input_index = SRCP_FIELD_IPV6, 208 .offset = sizeof(struct rte_ipv6_hdr) - 209 offsetof(struct rte_ipv6_hdr, proto), 210 }, 211 { 212 .type = RTE_ACL_FIELD_TYPE_RANGE, 213 .size = sizeof(uint16_t), 214 .field_index = DSTP_FIELD_IPV6, 215 .input_index = SRCP_FIELD_IPV6, 216 .offset = sizeof(struct rte_ipv6_hdr) - 217 offsetof(struct rte_ipv6_hdr, proto) + sizeof(uint16_t), 218 }, 219 }; 220 221 enum { 222 CB_FLD_SRC_ADDR, 223 CB_FLD_DST_ADDR, 224 CB_FLD_SRC_PORT_LOW, 225 CB_FLD_SRC_PORT_DLM, 226 CB_FLD_SRC_PORT_HIGH, 227 CB_FLD_DST_PORT_LOW, 228 CB_FLD_DST_PORT_DLM, 229 CB_FLD_DST_PORT_HIGH, 230 CB_FLD_PROTO, 231 CB_FLD_USERDATA, 232 CB_FLD_NUM, 233 }; 234 235 RTE_ACL_RULE_DEF(acl4_rule, RTE_DIM(ipv4_defs)); 236 RTE_ACL_RULE_DEF(acl6_rule, RTE_DIM(ipv6_defs)); 237 238 static struct { 239 struct rte_acl_ctx *acx_ipv4[NB_SOCKETS]; 240 struct rte_acl_ctx *acx_ipv6[NB_SOCKETS]; 241 #ifdef L3FWDACL_DEBUG 242 struct acl4_rule *rule_ipv4; 243 struct acl6_rule *rule_ipv6; 244 #endif 245 } acl_config; 246 247 static const char cb_port_delim[] = ":"; 248 249 static struct rte_acl_rule *acl_base_ipv4, *route_base_ipv4, 250 *acl_base_ipv6, *route_base_ipv6; 251 static unsigned int acl_num_ipv4, route_num_ipv4, 252 acl_num_ipv6, route_num_ipv6; 253 254 #include "l3fwd_acl.h" 255 256 #include "l3fwd_acl_scalar.h" 257 258 /* 259 * Parse IPV6 address, expects the following format: 260 * XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX (where X is a hexadecimal digit). 261 */ 262 static int 263 parse_ipv6_addr(const char *in, const char **end, uint32_t v[IPV6_ADDR_U32], 264 char dlm) 265 { 266 uint32_t addr[IPV6_ADDR_U16]; 267 268 GET_CB_FIELD(in, addr[0], 16, UINT16_MAX, ':'); 269 GET_CB_FIELD(in, addr[1], 16, UINT16_MAX, ':'); 270 GET_CB_FIELD(in, addr[2], 16, UINT16_MAX, ':'); 271 GET_CB_FIELD(in, addr[3], 16, UINT16_MAX, ':'); 272 GET_CB_FIELD(in, addr[4], 16, UINT16_MAX, ':'); 273 GET_CB_FIELD(in, addr[5], 16, UINT16_MAX, ':'); 274 GET_CB_FIELD(in, addr[6], 16, UINT16_MAX, ':'); 275 GET_CB_FIELD(in, addr[7], 16, UINT16_MAX, dlm); 276 277 *end = in; 278 279 v[0] = (addr[0] << 16) + addr[1]; 280 v[1] = (addr[2] << 16) + addr[3]; 281 v[2] = (addr[4] << 16) + addr[5]; 282 v[3] = (addr[6] << 16) + addr[7]; 283 284 return 0; 285 } 286 287 static int 288 parse_ipv6_net(const char *in, struct rte_acl_field field[4]) 289 { 290 int32_t rc; 291 const char *mp; 292 uint32_t i, m, v[4]; 293 const uint32_t nbu32 = sizeof(uint32_t) * CHAR_BIT; 294 295 /* get address. */ 296 rc = parse_ipv6_addr(in, &mp, v, '/'); 297 if (rc != 0) 298 return rc; 299 300 /* get mask. */ 301 GET_CB_FIELD(mp, m, 0, CHAR_BIT * sizeof(v), 0); 302 303 /* put all together. */ 304 for (i = 0; i != RTE_DIM(v); i++) { 305 if (m >= (i + 1) * nbu32) 306 field[i].mask_range.u32 = nbu32; 307 else 308 field[i].mask_range.u32 = m > (i * nbu32) ? 309 m - (i * 32) : 0; 310 311 field[i].value.u32 = v[i]; 312 } 313 314 return 0; 315 } 316 317 static int 318 parse_cb_ipv6_rule(char *str, struct rte_acl_rule *v, int has_userdata) 319 { 320 int i, rc; 321 char *s, *sp, *in[CB_FLD_NUM]; 322 static const char *dlm = " \t\n"; 323 int dim = has_userdata ? CB_FLD_NUM : CB_FLD_USERDATA; 324 s = str; 325 326 for (i = 0; i != dim; i++, s = NULL) { 327 in[i] = strtok_r(s, dlm, &sp); 328 if (in[i] == NULL) 329 return -EINVAL; 330 } 331 332 rc = parse_ipv6_net(in[CB_FLD_SRC_ADDR], v->field + SRC1_FIELD_IPV6); 333 if (rc != 0) { 334 acl_log("failed to read source address/mask: %s\n", 335 in[CB_FLD_SRC_ADDR]); 336 return rc; 337 } 338 339 rc = parse_ipv6_net(in[CB_FLD_DST_ADDR], v->field + DST1_FIELD_IPV6); 340 if (rc != 0) { 341 acl_log("failed to read destination address/mask: %s\n", 342 in[CB_FLD_DST_ADDR]); 343 return rc; 344 } 345 346 /* source port. */ 347 GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW], 348 v->field[SRCP_FIELD_IPV6].value.u16, 349 0, UINT16_MAX, 0); 350 GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH], 351 v->field[SRCP_FIELD_IPV6].mask_range.u16, 352 0, UINT16_MAX, 0); 353 354 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim, 355 sizeof(cb_port_delim)) != 0) 356 return -EINVAL; 357 358 /* destination port. */ 359 GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW], 360 v->field[DSTP_FIELD_IPV6].value.u16, 361 0, UINT16_MAX, 0); 362 GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH], 363 v->field[DSTP_FIELD_IPV6].mask_range.u16, 364 0, UINT16_MAX, 0); 365 366 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim, 367 sizeof(cb_port_delim)) != 0) 368 return -EINVAL; 369 370 if (v->field[SRCP_FIELD_IPV6].mask_range.u16 371 < v->field[SRCP_FIELD_IPV6].value.u16 372 || v->field[DSTP_FIELD_IPV6].mask_range.u16 373 < v->field[DSTP_FIELD_IPV6].value.u16) 374 return -EINVAL; 375 376 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV6].value.u8, 377 0, UINT8_MAX, '/'); 378 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV6].mask_range.u8, 379 0, UINT8_MAX, 0); 380 381 if (has_userdata) 382 GET_CB_FIELD(in[CB_FLD_USERDATA], v->data.userdata, 383 0, UINT32_MAX, 0); 384 385 return 0; 386 } 387 388 /* 389 * Parse ClassBench rules file. 390 * Expected format: 391 * '@'<src_ipv4_addr>'/'<masklen> <space> \ 392 * <dst_ipv4_addr>'/'<masklen> <space> \ 393 * <src_port_low> <space> ":" <src_port_high> <space> \ 394 * <dst_port_low> <space> ":" <dst_port_high> <space> \ 395 * <proto>'/'<mask> 396 */ 397 static int 398 parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len) 399 { 400 char *sa, *sm, *sv; 401 const char *dlm = "/"; 402 403 sv = NULL; 404 sa = strtok_r(in, dlm, &sv); 405 if (sa == NULL) 406 return -EINVAL; 407 sm = strtok_r(NULL, dlm, &sv); 408 if (sm == NULL) 409 return -EINVAL; 410 411 if (inet_pton(AF_INET, sa, addr) != 1) 412 return -EINVAL; 413 414 GET_CB_FIELD(sm, *mask_len, 0, 32, 0); 415 *addr = ntohl(*addr); 416 return 0; 417 } 418 419 static int 420 parse_cb_ipv4vlan_rule(char *str, struct rte_acl_rule *v, int has_userdata) 421 { 422 int i, rc; 423 char *s, *sp, *in[CB_FLD_NUM]; 424 static const char *dlm = " \t\n"; 425 int dim = has_userdata ? CB_FLD_NUM : CB_FLD_USERDATA; 426 s = str; 427 428 for (i = 0; i != dim; i++, s = NULL) { 429 in[i] = strtok_r(s, dlm, &sp); 430 if (in[i] == NULL) 431 return -EINVAL; 432 } 433 434 rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR], 435 &v->field[SRC_FIELD_IPV4].value.u32, 436 &v->field[SRC_FIELD_IPV4].mask_range.u32); 437 if (rc != 0) { 438 acl_log("failed to read source address/mask: %s\n", 439 in[CB_FLD_SRC_ADDR]); 440 return rc; 441 } 442 443 rc = parse_ipv4_net(in[CB_FLD_DST_ADDR], 444 &v->field[DST_FIELD_IPV4].value.u32, 445 &v->field[DST_FIELD_IPV4].mask_range.u32); 446 if (rc != 0) { 447 acl_log("failed to read destination address/mask: %s\n", 448 in[CB_FLD_DST_ADDR]); 449 return rc; 450 } 451 452 GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW], 453 v->field[SRCP_FIELD_IPV4].value.u16, 454 0, UINT16_MAX, 0); 455 GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH], 456 v->field[SRCP_FIELD_IPV4].mask_range.u16, 457 0, UINT16_MAX, 0); 458 459 if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim, 460 sizeof(cb_port_delim)) != 0) { 461 return -EINVAL; 462 } 463 464 GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW], 465 v->field[DSTP_FIELD_IPV4].value.u16, 466 0, UINT16_MAX, 0); 467 GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH], 468 v->field[DSTP_FIELD_IPV4].mask_range.u16, 469 0, UINT16_MAX, 0); 470 471 if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim, 472 sizeof(cb_port_delim)) != 0) { 473 return -EINVAL; 474 } 475 476 if (v->field[SRCP_FIELD_IPV4].mask_range.u16 477 < v->field[SRCP_FIELD_IPV4].value.u16 478 || v->field[DSTP_FIELD_IPV4].mask_range.u16 479 < v->field[DSTP_FIELD_IPV4].value.u16) { 480 return -EINVAL; 481 } 482 483 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].value.u8, 484 0, UINT8_MAX, '/'); 485 GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV4].mask_range.u8, 486 0, UINT8_MAX, 0); 487 488 if (has_userdata) 489 GET_CB_FIELD(in[CB_FLD_USERDATA], v->data.userdata, 0, 490 UINT32_MAX, 0); 491 492 return 0; 493 } 494 495 static int 496 acl_add_rules(const char *rule_path, 497 struct rte_acl_rule **proute_base, 498 unsigned int *proute_num, 499 struct rte_acl_rule **pacl_base, 500 unsigned int *pacl_num, uint32_t rule_size, 501 int (*parser)(char *, struct rte_acl_rule*, int)) 502 { 503 uint8_t *acl_rules, *route_rules; 504 struct rte_acl_rule *next; 505 unsigned int acl_num = 0, route_num = 0, total_num = 0; 506 unsigned int acl_cnt = 0, route_cnt = 0; 507 char buff[LINE_MAX]; 508 FILE *fh = fopen(rule_path, "rb"); 509 unsigned int i = 0; 510 int val; 511 512 if (fh == NULL) 513 rte_exit(EXIT_FAILURE, "%s: Open %s failed\n", __func__, 514 rule_path); 515 516 while ((fgets(buff, LINE_MAX, fh) != NULL)) { 517 if (buff[0] == ROUTE_LEAD_CHAR) 518 route_num++; 519 else if (buff[0] == ACL_LEAD_CHAR) 520 acl_num++; 521 } 522 523 if (route_num == 0) 524 rte_exit(EXIT_FAILURE, "Not find any route entries in %s!\n", 525 rule_path); 526 527 val = fseek(fh, 0, SEEK_SET); 528 if (val < 0) { 529 rte_exit(EXIT_FAILURE, "%s: File seek operation failed\n", 530 __func__); 531 } 532 533 acl_rules = calloc(acl_num, rule_size); 534 535 if (acl_rules == NULL) 536 rte_exit(EXIT_FAILURE, "%s: failed to malloc memory\n", 537 __func__); 538 539 route_rules = calloc(route_num, rule_size); 540 541 if (route_rules == NULL) 542 rte_exit(EXIT_FAILURE, "%s: failed to malloc memory\n", 543 __func__); 544 545 i = 0; 546 while (fgets(buff, LINE_MAX, fh) != NULL) { 547 i++; 548 549 if (is_bypass_line(buff)) 550 continue; 551 552 char s = buff[0]; 553 554 /* Route entry */ 555 if (s == ROUTE_LEAD_CHAR) 556 next = (struct rte_acl_rule *)(route_rules + 557 route_cnt * rule_size); 558 559 /* ACL entry */ 560 else if (s == ACL_LEAD_CHAR) 561 next = (struct rte_acl_rule *)(acl_rules + 562 acl_cnt * rule_size); 563 564 /* Illegal line */ 565 else 566 rte_exit(EXIT_FAILURE, 567 "%s Line %u: should start with leading " 568 "char %c or %c\n", 569 rule_path, i, ROUTE_LEAD_CHAR, ACL_LEAD_CHAR); 570 571 if (parser(buff + 1, next, s == ROUTE_LEAD_CHAR) != 0) 572 rte_exit(EXIT_FAILURE, 573 "%s Line %u: parse rules error\n", 574 rule_path, i); 575 576 if (s == ROUTE_LEAD_CHAR) { 577 /* Check the forwarding port number */ 578 if ((enabled_port_mask & (1 << next->data.userdata)) == 579 0) 580 rte_exit(EXIT_FAILURE, 581 "%s Line %u: fwd number illegal:%u\n", 582 rule_path, i, next->data.userdata); 583 next->data.userdata += FWD_PORT_SHIFT; 584 route_cnt++; 585 } else { 586 next->data.userdata = ACL_DENY_SIGNATURE + acl_cnt; 587 acl_cnt++; 588 } 589 590 next->data.priority = RTE_ACL_MAX_PRIORITY - total_num; 591 next->data.category_mask = -1; 592 total_num++; 593 } 594 595 fclose(fh); 596 597 *pacl_base = (struct rte_acl_rule *)acl_rules; 598 *pacl_num = acl_num; 599 *proute_base = (struct rte_acl_rule *)route_rules; 600 *proute_num = route_cnt; 601 602 return 0; 603 } 604 605 enum rte_acl_classify_alg 606 parse_acl_alg(const char *alg) 607 { 608 uint32_t i; 609 610 for (i = 0; i != RTE_DIM(acl_alg); i++) { 611 if (strcmp(alg, acl_alg[i].name) == 0) 612 return acl_alg[i].alg; 613 } 614 615 return RTE_ACL_CLASSIFY_DEFAULT; 616 } 617 618 int 619 usage_acl_alg(char *buf, size_t sz) 620 { 621 uint32_t i, n, rc, tn; 622 623 n = 0; 624 tn = 0; 625 for (i = 0; i < RTE_DIM(acl_alg); i++) { 626 rc = snprintf(buf + n, sz - n, 627 i == RTE_DIM(acl_alg) - 1 ? "%s" : "%s|", 628 acl_alg[i].name); 629 tn += rc; 630 if (rc < sz - n) 631 n += rc; 632 } 633 634 return tn; 635 } 636 637 static const char * 638 str_acl_alg(enum rte_acl_classify_alg alg) 639 { 640 uint32_t i; 641 642 for (i = 0; i != RTE_DIM(acl_alg); i++) { 643 if (alg == acl_alg[i].alg) 644 return acl_alg[i].name; 645 } 646 647 return "default"; 648 } 649 650 static void 651 dump_acl_config(void) 652 { 653 printf("ACL options are:\n"); 654 printf("rule_ipv4: %s\n", parm_config.rule_ipv4_name); 655 printf("rule_ipv6: %s\n", parm_config.rule_ipv6_name); 656 printf("alg: %s\n", str_acl_alg(parm_config.alg)); 657 } 658 659 static int 660 check_acl_config(void) 661 { 662 if (parm_config.rule_ipv4_name == NULL) { 663 acl_log("ACL IPv4 rule file not specified\n"); 664 return -1; 665 } else if (parm_config.rule_ipv6_name == NULL) { 666 acl_log("ACL IPv6 rule file not specified\n"); 667 return -1; 668 } 669 670 return 0; 671 } 672 673 /* Setup ACL context. 8< */ 674 static struct rte_acl_ctx* 675 app_acl_init(struct rte_acl_rule *route_base, 676 struct rte_acl_rule *acl_base, unsigned int route_num, 677 unsigned int acl_num, int ipv6, int socketid) 678 { 679 char name[PATH_MAX]; 680 struct rte_acl_param acl_param; 681 struct rte_acl_config acl_build_param; 682 struct rte_acl_ctx *context; 683 int dim = ipv6 ? RTE_DIM(ipv6_defs) : RTE_DIM(ipv4_defs); 684 685 /* Create ACL contexts */ 686 snprintf(name, sizeof(name), "%s%d", 687 ipv6 ? L3FWD_ACL_IPV6_NAME : L3FWD_ACL_IPV4_NAME, 688 socketid); 689 690 acl_param.name = name; 691 acl_param.socket_id = socketid; 692 acl_param.rule_size = RTE_ACL_RULE_SZ(dim); 693 acl_param.max_rule_num = MAX_ACL_RULE_NUM; 694 695 context = rte_acl_create(&acl_param); 696 if (context == NULL) 697 rte_exit(EXIT_FAILURE, "Failed to create ACL context\n"); 698 699 if (parm_config.alg != RTE_ACL_CLASSIFY_DEFAULT && 700 rte_acl_set_ctx_classify(context, parm_config.alg) != 0) 701 rte_exit(EXIT_FAILURE, 702 "Failed to setup classify method for ACL context\n"); 703 704 if (rte_acl_add_rules(context, route_base, route_num) < 0) 705 rte_exit(EXIT_FAILURE, "add rules failed\n"); 706 707 if (rte_acl_add_rules(context, acl_base, acl_num) < 0) 708 rte_exit(EXIT_FAILURE, "add rules failed\n"); 709 710 /* Perform builds */ 711 memset(&acl_build_param, 0, sizeof(acl_build_param)); 712 713 acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES; 714 acl_build_param.num_fields = dim; 715 memcpy(&acl_build_param.defs, ipv6 ? ipv6_defs : ipv4_defs, 716 ipv6 ? sizeof(ipv6_defs) : sizeof(ipv4_defs)); 717 718 if (rte_acl_build(context, &acl_build_param) != 0) 719 rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n"); 720 721 rte_acl_dump(context); 722 723 return context; 724 } 725 /* >8 End of ACL context setup. */ 726 727 void 728 acl_free_routes(void) 729 { 730 free(route_base_ipv4); 731 free(route_base_ipv6); 732 route_base_ipv4 = NULL; 733 route_base_ipv6 = NULL; 734 route_num_ipv4 = 0; 735 route_num_ipv6 = 0; 736 free(acl_base_ipv4); 737 free(acl_base_ipv6); 738 acl_base_ipv4 = NULL; 739 acl_base_ipv6 = NULL; 740 acl_num_ipv4 = 0; 741 acl_num_ipv6 = 0; 742 } 743 744 /* Load rules from the input file */ 745 void 746 read_config_files_acl(void) 747 { 748 /* ipv4 check */ 749 if (parm_config.rule_ipv4_name != NULL) { 750 if (acl_add_rules(parm_config.rule_ipv4_name, &route_base_ipv4, 751 &route_num_ipv4, &acl_base_ipv4, &acl_num_ipv4, 752 sizeof(struct acl4_rule), &parse_cb_ipv4vlan_rule) < 0) { 753 acl_free_routes(); 754 rte_exit(EXIT_FAILURE, "Failed to add IPv4 rules\n"); 755 } 756 } else { 757 RTE_LOG(ERR, L3FWD, "IPv4 rule file not specified\n"); 758 rte_exit(EXIT_FAILURE, "Failed to get valid route options\n"); 759 } 760 761 /* ipv6 check */ 762 if (parm_config.rule_ipv6_name != NULL) { 763 if (acl_add_rules(parm_config.rule_ipv6_name, &route_base_ipv6, 764 &route_num_ipv6, 765 &acl_base_ipv6, &acl_num_ipv6, 766 sizeof(struct acl6_rule), &parse_cb_ipv6_rule) < 0) { 767 acl_free_routes(); 768 rte_exit(EXIT_FAILURE, "Failed to add IPv6 rules\n"); 769 } 770 } else { 771 RTE_LOG(ERR, L3FWD, "IPv6 rule file not specified\n"); 772 rte_exit(EXIT_FAILURE, "Failed to get valid route options\n"); 773 } 774 } 775 776 void 777 print_one_ipv4_rule(struct acl4_rule *rule, int extra) 778 { 779 char abuf[INET6_ADDRSTRLEN]; 780 uint32_t ipv4_addr; 781 ipv4_addr = ntohl(rule->field[SRC_FIELD_IPV4].value.u32); 782 printf("%s/%u ", inet_ntop(AF_INET, 783 &(ipv4_addr), abuf, 784 sizeof(abuf)), rule->field[SRC_FIELD_IPV4].mask_range.u32); 785 ipv4_addr = ntohl(rule->field[DST_FIELD_IPV4].value.u32); 786 printf("%s/%u ", inet_ntop(AF_INET, 787 &(ipv4_addr), abuf, 788 sizeof(abuf)), rule->field[DST_FIELD_IPV4].mask_range.u32); 789 printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ", 790 rule->field[SRCP_FIELD_IPV4].value.u16, 791 rule->field[SRCP_FIELD_IPV4].mask_range.u16, 792 rule->field[DSTP_FIELD_IPV4].value.u16, 793 rule->field[DSTP_FIELD_IPV4].mask_range.u16, 794 rule->field[PROTO_FIELD_IPV4].value.u8, 795 rule->field[PROTO_FIELD_IPV4].mask_range.u8); 796 if (extra) 797 printf("0x%x-0x%x-0x%x ", 798 rule->data.category_mask, 799 rule->data.priority, 800 rule->data.userdata); 801 } 802 803 void 804 print_one_ipv6_rule(struct acl6_rule *rule, int extra) 805 { 806 unsigned char a, b, c, d; 807 808 uint32_t_to_char(rule->field[SRC1_FIELD_IPV6].value.u32, 809 &a, &b, &c, &d); 810 printf("%.2x%.2x:%.2x%.2x", a, b, c, d); 811 uint32_t_to_char(rule->field[SRC2_FIELD_IPV6].value.u32, 812 &a, &b, &c, &d); 813 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 814 uint32_t_to_char(rule->field[SRC3_FIELD_IPV6].value.u32, 815 &a, &b, &c, &d); 816 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 817 uint32_t_to_char(rule->field[SRC4_FIELD_IPV6].value.u32, 818 &a, &b, &c, &d); 819 printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d, 820 rule->field[SRC1_FIELD_IPV6].mask_range.u32 821 + rule->field[SRC2_FIELD_IPV6].mask_range.u32 822 + rule->field[SRC3_FIELD_IPV6].mask_range.u32 823 + rule->field[SRC4_FIELD_IPV6].mask_range.u32); 824 825 uint32_t_to_char(rule->field[DST1_FIELD_IPV6].value.u32, 826 &a, &b, &c, &d); 827 printf("%.2x%.2x:%.2x%.2x", a, b, c, d); 828 uint32_t_to_char(rule->field[DST2_FIELD_IPV6].value.u32, 829 &a, &b, &c, &d); 830 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 831 uint32_t_to_char(rule->field[DST3_FIELD_IPV6].value.u32, 832 &a, &b, &c, &d); 833 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 834 uint32_t_to_char(rule->field[DST4_FIELD_IPV6].value.u32, 835 &a, &b, &c, &d); 836 printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d, 837 rule->field[DST1_FIELD_IPV6].mask_range.u32 838 + rule->field[DST2_FIELD_IPV6].mask_range.u32 839 + rule->field[DST3_FIELD_IPV6].mask_range.u32 840 + rule->field[DST4_FIELD_IPV6].mask_range.u32); 841 842 printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ", 843 rule->field[SRCP_FIELD_IPV6].value.u16, 844 rule->field[SRCP_FIELD_IPV6].mask_range.u16, 845 rule->field[DSTP_FIELD_IPV6].value.u16, 846 rule->field[DSTP_FIELD_IPV6].mask_range.u16, 847 rule->field[PROTO_FIELD_IPV6].value.u8, 848 rule->field[PROTO_FIELD_IPV6].mask_range.u8); 849 if (extra) 850 printf("0x%x-0x%x-0x%x ", 851 rule->data.category_mask, 852 rule->data.priority, 853 rule->data.userdata); 854 } 855 856 #ifdef L3FWDACL_DEBUG 857 static inline void 858 dump_acl4_rule(struct rte_mbuf *m, uint32_t sig) 859 { 860 char abuf[INET6_ADDRSTRLEN]; 861 uint32_t offset = sig & ~ACL_DENY_SIGNATURE; 862 struct rte_ipv4_hdr *ipv4_hdr = 863 rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, 864 sizeof(struct rte_ether_hdr)); 865 866 printf("Packet Src:%s ", inet_ntop(AF_INET, ipv4_hdr->src_addr, 867 abuf, sizeof(abuf))); 868 printf("Dst:%s ", inet_ntop(AF_INET, ipv4_hdr->dst_addr, 869 abuf, sizeof(abuf))); 870 871 printf("Src port:%hu,Dst port:%hu ", 872 rte_bswap16(*(uint16_t *)(ipv4_hdr + 1)), 873 rte_bswap16(*((uint16_t *)(ipv4_hdr + 1) + 1))); 874 printf("hit ACL %d - ", offset); 875 876 print_one_ipv4_rule(acl_config.rule_ipv4 + offset, 1); 877 878 printf("\n\n"); 879 } 880 881 static inline void 882 dump_acl6_rule(struct rte_mbuf *m, uint32_t sig) 883 { 884 char abuf[INET6_ADDRSTRLEN]; 885 uint32_t offset = sig & ~ACL_DENY_SIGNATURE; 886 struct rte_ipv6_hdr *ipv6_hdr = 887 rte_pktmbuf_mtod_offset(m, struct rte_ipv6_hdr *, 888 sizeof(struct rte_ether_hdr)); 889 890 printf("Packet Src"); 891 printf("%s", inet_ntop(AF_INET6, ipv6_hdr->src_addr, 892 abuf, sizeof(abuf))); 893 printf("\nDst"); 894 printf("%s", inet_ntop(AF_INET6, ipv6_hdr->dst_addr, 895 abuf, sizeof(abuf))); 896 897 printf("\nSrc port:%hu,Dst port:%hu ", 898 rte_bswap16(*(uint16_t *)(ipv6_hdr + 1)), 899 rte_bswap16(*((uint16_t *)(ipv6_hdr + 1) + 1))); 900 printf("hit ACL %d - ", offset); 901 902 print_one_ipv6_rule(acl_config.rule_ipv6 + offset, 1); 903 904 printf("\n\n"); 905 } 906 #endif /* L3FWDACL_DEBUG */ 907 908 static inline void 909 dump_ipv4_rules(struct acl4_rule *rule, int num, int extra) 910 { 911 int i; 912 913 for (i = 0; i < num; i++, rule++) { 914 printf("\t%d:", i + 1); 915 print_one_ipv4_rule(rule, extra); 916 printf("\n"); 917 } 918 } 919 920 static inline void 921 dump_ipv6_rules(struct acl6_rule *rule, int num, int extra) 922 { 923 int i; 924 925 for (i = 0; i < num; i++, rule++) { 926 printf("\t%d:", i + 1); 927 print_one_ipv6_rule(rule, extra); 928 printf("\n"); 929 } 930 } 931 932 /* Function to setup acl. */ 933 void 934 setup_acl(const int socket_id) 935 { 936 if (check_acl_config() != 0) 937 rte_exit(EXIT_FAILURE, "Failed to get valid ACL options\n"); 938 939 dump_acl_config(); 940 941 acl_log("IPv4 Route entries %u:\n", route_num_ipv4); 942 dump_ipv4_rules((struct acl4_rule *)route_base_ipv4, route_num_ipv4, 1); 943 944 acl_log("IPv4 ACL entries %u:\n", acl_num_ipv4); 945 dump_ipv4_rules((struct acl4_rule *)acl_base_ipv4, acl_num_ipv4, 1); 946 947 acl_log("IPv6 Route entries %u:\n", route_num_ipv6); 948 dump_ipv6_rules((struct acl6_rule *)route_base_ipv6, route_num_ipv6, 1); 949 950 acl_log("IPv6 ACL entries %u:\n", acl_num_ipv6); 951 dump_ipv6_rules((struct acl6_rule *)acl_base_ipv6, acl_num_ipv6, 1); 952 953 /* Check sockets a context should be created on */ 954 if (socket_id >= NB_SOCKETS) { 955 acl_log("Socket %d is out " 956 "of range %d\n", 957 socket_id, NB_SOCKETS); 958 acl_free_routes(); 959 return; 960 } 961 962 rte_acl_free(acl_config.acx_ipv4[socket_id]); 963 rte_acl_free(acl_config.acx_ipv6[socket_id]); 964 965 acl_config.acx_ipv4[socket_id] = app_acl_init(route_base_ipv4, 966 acl_base_ipv4, route_num_ipv4, acl_num_ipv4, 967 0, socket_id); 968 969 acl_config.acx_ipv6[socket_id] = app_acl_init(route_base_ipv6, 970 acl_base_ipv6, route_num_ipv6, acl_num_ipv6, 971 1, socket_id); 972 973 #ifdef L3FWDACL_DEBUG 974 acl_config.rule_ipv4 = (struct acl4_rule *)acl_base_ipv4; 975 acl_config.rule_ipv6 = (struct acl6_rule *)acl_base_ipv6; 976 #endif 977 978 } 979 980 static inline void 981 dump_denied_pkt(const struct rte_mbuf *pkt, uint32_t res) 982 { 983 #ifdef L3FWDACL_DEBUG 984 if ((res & ACL_DENY_SIGNATURE) != 0) { 985 if (RTE_ETH_IS_IPV4_HDR(pkt->packet_type)) 986 dump_acl4_rule(pkt, res); 987 else if (RTE_ETH_IS_IPV6_HDR(pkt[i]->packet_type)) 988 dump_acl6_rule(pkt[i], res[i]); 989 } 990 #else 991 RTE_SET_USED(pkt); 992 RTE_SET_USED(res); 993 #endif 994 } 995 996 /* 997 * run packets through ACL classify. 998 * returns number of packets to be dropped (hops[i] == BAD_PORT) 999 */ 1000 static inline uint32_t 1001 acl_process_pkts(struct rte_mbuf *pkts[MAX_PKT_BURST], 1002 uint16_t hops[MAX_PKT_BURST], uint32_t num, int32_t socketid) 1003 { 1004 uint32_t i, k, n4, n6, res; 1005 struct acl_search_t acl_search; 1006 1007 /* split packets burst depending on packet type (IPv4/IPv6) */ 1008 l3fwd_acl_prepare_acl_parameter(pkts, &acl_search, num); 1009 1010 if (acl_search.num_ipv4) 1011 rte_acl_classify(acl_config.acx_ipv4[socketid], 1012 acl_search.data_ipv4, 1013 acl_search.res_ipv4, 1014 acl_search.num_ipv4, 1015 DEFAULT_MAX_CATEGORIES); 1016 1017 if (acl_search.num_ipv6) 1018 rte_acl_classify(acl_config.acx_ipv6[socketid], 1019 acl_search.data_ipv6, 1020 acl_search.res_ipv6, 1021 acl_search.num_ipv6, 1022 DEFAULT_MAX_CATEGORIES); 1023 1024 /* combine lookup results back, into one array of next hops */ 1025 n4 = 0; 1026 n6 = 0; 1027 k = 0; 1028 for (i = 0; i != num; i++) { 1029 switch (acl_search.types[i]) { 1030 case TYPE_IPV4: 1031 res = acl_search.res_ipv4[n4++]; 1032 break; 1033 case TYPE_IPV6: 1034 res = acl_search.res_ipv6[n6++]; 1035 break; 1036 default: 1037 res = 0; 1038 } 1039 if (likely((res & ACL_DENY_SIGNATURE) == 0 && res != 0)) 1040 hops[i] = res - FWD_PORT_SHIFT; 1041 else { 1042 /* bad or denied by ACL rule packets */ 1043 hops[i] = BAD_PORT; 1044 dump_denied_pkt(pkts[i], res); 1045 k++; 1046 } 1047 } 1048 1049 return k; 1050 } 1051 1052 /* 1053 * send_packets_multi() can't deal properly with hops[i] == BAD_PORT 1054 * (it assumes input hops[] contain only valid port numbers), 1055 * so it is ok to use it only when there are no denied packets. 1056 */ 1057 static inline void 1058 acl_send_packets(struct lcore_conf *qconf, struct rte_mbuf *pkts[], 1059 uint16_t hops[], uint32_t num, uint32_t nb_drop) 1060 { 1061 #if defined ACL_SEND_MULTI 1062 if (nb_drop == 0) 1063 send_packets_multi(qconf, pkts, hops, num); 1064 else 1065 #else 1066 RTE_SET_USED(nb_drop); 1067 #endif 1068 send_packets_single(qconf, pkts, hops, num); 1069 } 1070 1071 /* main processing loop */ 1072 int 1073 acl_main_loop(__rte_unused void *dummy) 1074 { 1075 struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; 1076 uint16_t hops[SENDM_PORT_OVERHEAD(MAX_PKT_BURST)]; 1077 unsigned int lcore_id; 1078 uint64_t prev_tsc, diff_tsc, cur_tsc; 1079 int i, nb_drop, nb_rx; 1080 uint16_t portid; 1081 uint16_t queueid; 1082 struct lcore_conf *qconf; 1083 int socketid; 1084 const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) 1085 / US_PER_S * BURST_TX_DRAIN_US; 1086 1087 prev_tsc = 0; 1088 lcore_id = rte_lcore_id(); 1089 qconf = &lcore_conf[lcore_id]; 1090 socketid = rte_lcore_to_socket_id(lcore_id); 1091 1092 if (qconf->n_rx_queue == 0) { 1093 RTE_LOG(INFO, L3FWD, "lcore %u has nothing to do\n", lcore_id); 1094 return 0; 1095 } 1096 1097 RTE_LOG(INFO, L3FWD, "entering main loop on lcore %u\n", lcore_id); 1098 1099 for (i = 0; i < qconf->n_rx_queue; i++) { 1100 1101 portid = qconf->rx_queue_list[i].port_id; 1102 queueid = qconf->rx_queue_list[i].queue_id; 1103 RTE_LOG(INFO, L3FWD, 1104 " -- lcoreid=%u portid=%u rxqueueid=%" PRIu16 "\n", 1105 lcore_id, portid, queueid); 1106 } 1107 1108 while (!force_quit) { 1109 1110 cur_tsc = rte_rdtsc(); 1111 1112 /* 1113 * TX burst queue drain 1114 */ 1115 diff_tsc = cur_tsc - prev_tsc; 1116 if (unlikely(diff_tsc > drain_tsc)) { 1117 1118 for (i = 0; i < qconf->n_tx_port; ++i) { 1119 portid = qconf->tx_port_id[i]; 1120 if (qconf->tx_mbufs[portid].len == 0) 1121 continue; 1122 send_burst(qconf, 1123 qconf->tx_mbufs[portid].len, 1124 portid); 1125 qconf->tx_mbufs[portid].len = 0; 1126 } 1127 1128 prev_tsc = cur_tsc; 1129 } 1130 1131 /* 1132 * Read packet from RX queues and process them 1133 */ 1134 for (i = 0; i < qconf->n_rx_queue; ++i) { 1135 1136 portid = qconf->rx_queue_list[i].port_id; 1137 queueid = qconf->rx_queue_list[i].queue_id; 1138 nb_rx = rte_eth_rx_burst(portid, queueid, 1139 pkts_burst, nb_pkt_per_burst); 1140 1141 if (nb_rx > 0) { 1142 nb_drop = acl_process_pkts(pkts_burst, hops, 1143 nb_rx, socketid); 1144 acl_send_packets(qconf, pkts_burst, hops, 1145 nb_rx, nb_drop); 1146 } 1147 } 1148 } 1149 return 0; 1150 } 1151 1152 /* Not used by L3fwd ACL. */ 1153 void * 1154 acl_get_ipv4_l3fwd_lookup_struct(__rte_unused const int socketid) 1155 { 1156 return NULL; 1157 } 1158 1159 void * 1160 acl_get_ipv6_l3fwd_lookup_struct(__rte_unused const int socketid) 1161 { 1162 return NULL; 1163 } 1164