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