1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2017 Intel Corporation 3 */ 4 5 #include <rte_flow_classify.h> 6 #include "rte_flow_classify_parse.h" 7 #include <rte_flow_driver.h> 8 9 struct classify_valid_pattern { 10 enum rte_flow_item_type *items; 11 parse_filter_t parse_filter; 12 }; 13 14 static struct classify_action action; 15 16 /* Pattern for IPv4 5-tuple UDP filter */ 17 static enum rte_flow_item_type pattern_ntuple_1[] = { 18 RTE_FLOW_ITEM_TYPE_ETH, 19 RTE_FLOW_ITEM_TYPE_IPV4, 20 RTE_FLOW_ITEM_TYPE_UDP, 21 RTE_FLOW_ITEM_TYPE_END, 22 }; 23 24 /* Pattern for IPv4 5-tuple TCP filter */ 25 static enum rte_flow_item_type pattern_ntuple_2[] = { 26 RTE_FLOW_ITEM_TYPE_ETH, 27 RTE_FLOW_ITEM_TYPE_IPV4, 28 RTE_FLOW_ITEM_TYPE_TCP, 29 RTE_FLOW_ITEM_TYPE_END, 30 }; 31 32 /* Pattern for IPv4 5-tuple SCTP filter */ 33 static enum rte_flow_item_type pattern_ntuple_3[] = { 34 RTE_FLOW_ITEM_TYPE_ETH, 35 RTE_FLOW_ITEM_TYPE_IPV4, 36 RTE_FLOW_ITEM_TYPE_SCTP, 37 RTE_FLOW_ITEM_TYPE_END, 38 }; 39 40 static int 41 classify_parse_ntuple_filter(const struct rte_flow_attr *attr, 42 const struct rte_flow_item pattern[], 43 const struct rte_flow_action actions[], 44 struct rte_eth_ntuple_filter *filter, 45 struct rte_flow_error *error); 46 47 static struct classify_valid_pattern classify_supported_patterns[] = { 48 /* ntuple */ 49 { pattern_ntuple_1, classify_parse_ntuple_filter }, 50 { pattern_ntuple_2, classify_parse_ntuple_filter }, 51 { pattern_ntuple_3, classify_parse_ntuple_filter }, 52 }; 53 54 struct classify_action * 55 classify_get_flow_action(void) 56 { 57 return &action; 58 } 59 60 /* Find the first VOID or non-VOID item pointer */ 61 const struct rte_flow_item * 62 classify_find_first_item(const struct rte_flow_item *item, bool is_void) 63 { 64 bool is_find; 65 66 while (item->type != RTE_FLOW_ITEM_TYPE_END) { 67 if (is_void) 68 is_find = item->type == RTE_FLOW_ITEM_TYPE_VOID; 69 else 70 is_find = item->type != RTE_FLOW_ITEM_TYPE_VOID; 71 if (is_find) 72 break; 73 item++; 74 } 75 return item; 76 } 77 78 /* Skip all VOID items of the pattern */ 79 void 80 classify_pattern_skip_void_item(struct rte_flow_item *items, 81 const struct rte_flow_item *pattern) 82 { 83 uint32_t cpy_count = 0; 84 const struct rte_flow_item *pb = pattern, *pe = pattern; 85 86 for (;;) { 87 /* Find a non-void item first */ 88 pb = classify_find_first_item(pb, false); 89 if (pb->type == RTE_FLOW_ITEM_TYPE_END) { 90 pe = pb; 91 break; 92 } 93 94 /* Find a void item */ 95 pe = classify_find_first_item(pb + 1, true); 96 97 cpy_count = pe - pb; 98 rte_memcpy(items, pb, sizeof(struct rte_flow_item) * cpy_count); 99 100 items += cpy_count; 101 102 if (pe->type == RTE_FLOW_ITEM_TYPE_END) { 103 pb = pe; 104 break; 105 } 106 } 107 /* Copy the END item. */ 108 rte_memcpy(items, pe, sizeof(struct rte_flow_item)); 109 } 110 111 /* Check if the pattern matches a supported item type array */ 112 static bool 113 classify_match_pattern(enum rte_flow_item_type *item_array, 114 struct rte_flow_item *pattern) 115 { 116 struct rte_flow_item *item = pattern; 117 118 while ((*item_array == item->type) && 119 (*item_array != RTE_FLOW_ITEM_TYPE_END)) { 120 item_array++; 121 item++; 122 } 123 124 return (*item_array == RTE_FLOW_ITEM_TYPE_END && 125 item->type == RTE_FLOW_ITEM_TYPE_END); 126 } 127 128 /* Find if there's parse filter function matched */ 129 parse_filter_t 130 classify_find_parse_filter_func(struct rte_flow_item *pattern) 131 { 132 parse_filter_t parse_filter = NULL; 133 uint8_t i = 0; 134 135 for (; i < RTE_DIM(classify_supported_patterns); i++) { 136 if (classify_match_pattern(classify_supported_patterns[i].items, 137 pattern)) { 138 parse_filter = 139 classify_supported_patterns[i].parse_filter; 140 break; 141 } 142 } 143 144 return parse_filter; 145 } 146 147 #define FLOW_RULE_MIN_PRIORITY 8 148 #define FLOW_RULE_MAX_PRIORITY 0 149 150 #define NEXT_ITEM_OF_PATTERN(item, pattern, index)\ 151 do {\ 152 item = pattern + index;\ 153 while (item->type == RTE_FLOW_ITEM_TYPE_VOID) {\ 154 index++;\ 155 item = pattern + index;\ 156 } \ 157 } while (0) 158 159 #define NEXT_ITEM_OF_ACTION(act, actions, index)\ 160 do {\ 161 act = actions + index;\ 162 while (act->type == RTE_FLOW_ACTION_TYPE_VOID) {\ 163 index++;\ 164 act = actions + index;\ 165 } \ 166 } while (0) 167 168 /** 169 * Please aware there's an assumption for all the parsers. 170 * rte_flow_item is using big endian, rte_flow_attr and 171 * rte_flow_action are using CPU order. 172 * Because the pattern is used to describe the packets, 173 * normally the packets should use network order. 174 */ 175 176 /** 177 * Parse the rule to see if it is a n-tuple rule. 178 * And get the n-tuple filter info BTW. 179 * pattern: 180 * The first not void item can be ETH or IPV4. 181 * The second not void item must be IPV4 if the first one is ETH. 182 * The third not void item must be UDP or TCP. 183 * The next not void item must be END. 184 * action: 185 * The first not void action should be QUEUE. 186 * The next not void action should be END. 187 * pattern example: 188 * ITEM Spec Mask 189 * ETH NULL NULL 190 * IPV4 src_addr 192.168.1.20 0xFFFFFFFF 191 * dst_addr 192.167.3.50 0xFFFFFFFF 192 * next_proto_id 17 0xFF 193 * UDP/TCP/ src_port 80 0xFFFF 194 * SCTP dst_port 80 0xFFFF 195 * END 196 * other members in mask and spec should set to 0x00. 197 * item->last should be NULL. 198 */ 199 static int 200 classify_parse_ntuple_filter(const struct rte_flow_attr *attr, 201 const struct rte_flow_item pattern[], 202 const struct rte_flow_action actions[], 203 struct rte_eth_ntuple_filter *filter, 204 struct rte_flow_error *error) 205 { 206 const struct rte_flow_item *item; 207 const struct rte_flow_action *act; 208 const struct rte_flow_item_ipv4 *ipv4_spec; 209 const struct rte_flow_item_ipv4 *ipv4_mask; 210 const struct rte_flow_item_tcp *tcp_spec; 211 const struct rte_flow_item_tcp *tcp_mask; 212 const struct rte_flow_item_udp *udp_spec; 213 const struct rte_flow_item_udp *udp_mask; 214 const struct rte_flow_item_sctp *sctp_spec; 215 const struct rte_flow_item_sctp *sctp_mask; 216 const struct rte_flow_action_count *count; 217 const struct rte_flow_action_mark *mark_spec; 218 uint32_t index; 219 220 /* parse pattern */ 221 index = 0; 222 223 /* the first not void item can be MAC or IPv4 */ 224 NEXT_ITEM_OF_PATTERN(item, pattern, index); 225 226 if (item->type != RTE_FLOW_ITEM_TYPE_ETH && 227 item->type != RTE_FLOW_ITEM_TYPE_IPV4) { 228 rte_flow_error_set(error, EINVAL, 229 RTE_FLOW_ERROR_TYPE_ITEM, 230 item, "Not supported by ntuple filter"); 231 return -EINVAL; 232 } 233 /* Skip Ethernet */ 234 if (item->type == RTE_FLOW_ITEM_TYPE_ETH) { 235 /*Not supported last point for range*/ 236 if (item->last) { 237 rte_flow_error_set(error, EINVAL, 238 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 239 item, 240 "Not supported last point for range"); 241 return -EINVAL; 242 243 } 244 /* if the first item is MAC, the content should be NULL */ 245 if (item->spec || item->mask) { 246 rte_flow_error_set(error, EINVAL, 247 RTE_FLOW_ERROR_TYPE_ITEM, 248 item, 249 "Not supported by ntuple filter"); 250 return -EINVAL; 251 } 252 /* check if the next not void item is IPv4 */ 253 index++; 254 NEXT_ITEM_OF_PATTERN(item, pattern, index); 255 if (item->type != RTE_FLOW_ITEM_TYPE_IPV4) { 256 rte_flow_error_set(error, EINVAL, 257 RTE_FLOW_ERROR_TYPE_ITEM, 258 item, 259 "Not supported by ntuple filter"); 260 return -EINVAL; 261 } 262 } 263 264 /* get the IPv4 info */ 265 if (!item->spec || !item->mask) { 266 rte_flow_error_set(error, EINVAL, 267 RTE_FLOW_ERROR_TYPE_ITEM, 268 item, "Invalid ntuple mask"); 269 return -EINVAL; 270 } 271 /*Not supported last point for range*/ 272 if (item->last) { 273 rte_flow_error_set(error, EINVAL, 274 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 275 item, "Not supported last point for range"); 276 return -EINVAL; 277 278 } 279 280 ipv4_mask = item->mask; 281 /** 282 * Only support src & dst addresses, protocol, 283 * others should be masked. 284 */ 285 if (ipv4_mask->hdr.version_ihl || 286 ipv4_mask->hdr.type_of_service || 287 ipv4_mask->hdr.total_length || 288 ipv4_mask->hdr.packet_id || 289 ipv4_mask->hdr.fragment_offset || 290 ipv4_mask->hdr.time_to_live || 291 ipv4_mask->hdr.hdr_checksum) { 292 rte_flow_error_set(error, 293 EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, 294 item, "Not supported by ntuple filter"); 295 return -EINVAL; 296 } 297 298 filter->dst_ip_mask = ipv4_mask->hdr.dst_addr; 299 filter->src_ip_mask = ipv4_mask->hdr.src_addr; 300 filter->proto_mask = ipv4_mask->hdr.next_proto_id; 301 302 ipv4_spec = item->spec; 303 filter->dst_ip = ipv4_spec->hdr.dst_addr; 304 filter->src_ip = ipv4_spec->hdr.src_addr; 305 filter->proto = ipv4_spec->hdr.next_proto_id; 306 307 /* check if the next not void item is TCP or UDP or SCTP */ 308 index++; 309 NEXT_ITEM_OF_PATTERN(item, pattern, index); 310 if (item->type != RTE_FLOW_ITEM_TYPE_TCP && 311 item->type != RTE_FLOW_ITEM_TYPE_UDP && 312 item->type != RTE_FLOW_ITEM_TYPE_SCTP) { 313 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 314 rte_flow_error_set(error, EINVAL, 315 RTE_FLOW_ERROR_TYPE_ITEM, 316 item, "Not supported by ntuple filter"); 317 return -EINVAL; 318 } 319 320 /* get the TCP/UDP info */ 321 if (!item->spec || !item->mask) { 322 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 323 rte_flow_error_set(error, EINVAL, 324 RTE_FLOW_ERROR_TYPE_ITEM, 325 item, "Invalid ntuple mask"); 326 return -EINVAL; 327 } 328 329 /*Not supported last point for range*/ 330 if (item->last) { 331 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 332 rte_flow_error_set(error, EINVAL, 333 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 334 item, "Not supported last point for range"); 335 return -EINVAL; 336 337 } 338 339 if (item->type == RTE_FLOW_ITEM_TYPE_TCP) { 340 tcp_mask = item->mask; 341 342 /** 343 * Only support src & dst ports, tcp flags, 344 * others should be masked. 345 */ 346 if (tcp_mask->hdr.sent_seq || 347 tcp_mask->hdr.recv_ack || 348 tcp_mask->hdr.data_off || 349 tcp_mask->hdr.rx_win || 350 tcp_mask->hdr.cksum || 351 tcp_mask->hdr.tcp_urp) { 352 memset(filter, 0, 353 sizeof(struct rte_eth_ntuple_filter)); 354 rte_flow_error_set(error, EINVAL, 355 RTE_FLOW_ERROR_TYPE_ITEM, 356 item, "Not supported by ntuple filter"); 357 return -EINVAL; 358 } 359 360 filter->dst_port_mask = tcp_mask->hdr.dst_port; 361 filter->src_port_mask = tcp_mask->hdr.src_port; 362 if (tcp_mask->hdr.tcp_flags == 0xFF) { 363 filter->flags |= RTE_NTUPLE_FLAGS_TCP_FLAG; 364 } else if (!tcp_mask->hdr.tcp_flags) { 365 filter->flags &= ~RTE_NTUPLE_FLAGS_TCP_FLAG; 366 } else { 367 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 368 rte_flow_error_set(error, EINVAL, 369 RTE_FLOW_ERROR_TYPE_ITEM, 370 item, "Not supported by ntuple filter"); 371 return -EINVAL; 372 } 373 374 tcp_spec = item->spec; 375 filter->dst_port = tcp_spec->hdr.dst_port; 376 filter->src_port = tcp_spec->hdr.src_port; 377 filter->tcp_flags = tcp_spec->hdr.tcp_flags; 378 } else if (item->type == RTE_FLOW_ITEM_TYPE_UDP) { 379 udp_mask = item->mask; 380 381 /** 382 * Only support src & dst ports, 383 * others should be masked. 384 */ 385 if (udp_mask->hdr.dgram_len || 386 udp_mask->hdr.dgram_cksum) { 387 memset(filter, 0, 388 sizeof(struct rte_eth_ntuple_filter)); 389 rte_flow_error_set(error, EINVAL, 390 RTE_FLOW_ERROR_TYPE_ITEM, 391 item, "Not supported by ntuple filter"); 392 return -EINVAL; 393 } 394 395 filter->dst_port_mask = udp_mask->hdr.dst_port; 396 filter->src_port_mask = udp_mask->hdr.src_port; 397 398 udp_spec = item->spec; 399 filter->dst_port = udp_spec->hdr.dst_port; 400 filter->src_port = udp_spec->hdr.src_port; 401 } else { 402 sctp_mask = item->mask; 403 404 /** 405 * Only support src & dst ports, 406 * others should be masked. 407 */ 408 if (sctp_mask->hdr.tag || 409 sctp_mask->hdr.cksum) { 410 memset(filter, 0, 411 sizeof(struct rte_eth_ntuple_filter)); 412 rte_flow_error_set(error, EINVAL, 413 RTE_FLOW_ERROR_TYPE_ITEM, 414 item, "Not supported by ntuple filter"); 415 return -EINVAL; 416 } 417 418 filter->dst_port_mask = sctp_mask->hdr.dst_port; 419 filter->src_port_mask = sctp_mask->hdr.src_port; 420 421 sctp_spec = item->spec; 422 filter->dst_port = sctp_spec->hdr.dst_port; 423 filter->src_port = sctp_spec->hdr.src_port; 424 } 425 426 /* check if the next not void item is END */ 427 index++; 428 NEXT_ITEM_OF_PATTERN(item, pattern, index); 429 if (item->type != RTE_FLOW_ITEM_TYPE_END) { 430 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 431 rte_flow_error_set(error, EINVAL, 432 RTE_FLOW_ERROR_TYPE_ITEM, 433 item, "Not supported by ntuple filter"); 434 return -EINVAL; 435 } 436 437 table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE; 438 439 /* parse attr */ 440 /* must be input direction */ 441 if (!attr->ingress) { 442 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 443 rte_flow_error_set(error, EINVAL, 444 RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, 445 attr, "Only support ingress."); 446 return -EINVAL; 447 } 448 449 /* not supported */ 450 if (attr->egress) { 451 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 452 rte_flow_error_set(error, EINVAL, 453 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, 454 attr, "Not support egress."); 455 return -EINVAL; 456 } 457 458 if (attr->priority > 0xFFFF) { 459 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 460 rte_flow_error_set(error, EINVAL, 461 RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, 462 attr, "Error priority."); 463 return -EINVAL; 464 } 465 filter->priority = (uint16_t)attr->priority; 466 if (attr->priority > FLOW_RULE_MIN_PRIORITY) 467 filter->priority = FLOW_RULE_MAX_PRIORITY; 468 469 /* parse action */ 470 index = 0; 471 472 /** 473 * n-tuple only supports count and Mark, 474 * check if the first not void action is COUNT or MARK. 475 */ 476 memset(&action, 0, sizeof(action)); 477 NEXT_ITEM_OF_ACTION(act, actions, index); 478 switch (act->type) { 479 case RTE_FLOW_ACTION_TYPE_COUNT: 480 action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT; 481 count = act->conf; 482 memcpy(&action.act.counter, count, sizeof(action.act.counter)); 483 break; 484 case RTE_FLOW_ACTION_TYPE_MARK: 485 action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK; 486 mark_spec = act->conf; 487 memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark)); 488 break; 489 default: 490 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 491 rte_flow_error_set(error, EINVAL, 492 RTE_FLOW_ERROR_TYPE_ACTION, act, 493 "Invalid action."); 494 return -EINVAL; 495 } 496 497 /* check if the next not void item is MARK or COUNT or END */ 498 index++; 499 NEXT_ITEM_OF_ACTION(act, actions, index); 500 switch (act->type) { 501 case RTE_FLOW_ACTION_TYPE_COUNT: 502 action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT; 503 count = act->conf; 504 memcpy(&action.act.counter, count, sizeof(action.act.counter)); 505 break; 506 case RTE_FLOW_ACTION_TYPE_MARK: 507 action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK; 508 mark_spec = act->conf; 509 memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark)); 510 break; 511 case RTE_FLOW_ACTION_TYPE_END: 512 return 0; 513 default: 514 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 515 rte_flow_error_set(error, EINVAL, 516 RTE_FLOW_ERROR_TYPE_ACTION, act, 517 "Invalid action."); 518 return -EINVAL; 519 } 520 521 /* check if the next not void item is END */ 522 index++; 523 NEXT_ITEM_OF_ACTION(act, actions, index); 524 if (act->type != RTE_FLOW_ACTION_TYPE_END) { 525 memset(filter, 0, sizeof(struct rte_eth_ntuple_filter)); 526 rte_flow_error_set(error, EINVAL, 527 RTE_FLOW_ERROR_TYPE_ACTION, act, 528 "Invalid action."); 529 return -EINVAL; 530 } 531 532 return 0; 533 } 534