dpdk/lib/flow_classify/rte_flow_classify_parse.c
<<
>>
Prefs
   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
   9struct classify_valid_pattern {
  10        enum rte_flow_item_type *items;
  11        parse_filter_t parse_filter;
  12};
  13
  14static struct classify_action action;
  15
  16/* Pattern for IPv4 5-tuple UDP filter */
  17static 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 */
  25static 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 */
  33static 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
  40static int
  41classify_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
  47static 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
  54struct classify_action *
  55classify_get_flow_action(void)
  56{
  57        return &action;
  58}
  59
  60/* Find the first VOID or non-VOID item pointer */
  61const struct rte_flow_item *
  62classify_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 */
  79void
  80classify_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 */
 112static bool
 113classify_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 */
 129parse_filter_t
 130classify_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 */
 199static int
 200classify_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