dpdk/drivers/net/softnic/rte_eth_softnic_flow.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2018 Intel Corporation
   3 */
   4#include <stdint.h>
   5#include <stdlib.h>
   6#include <string.h>
   7
   8#include <rte_common.h>
   9#include <rte_byteorder.h>
  10#include <rte_malloc.h>
  11#include <rte_string_fns.h>
  12#include <rte_flow.h>
  13#include <rte_flow_driver.h>
  14#include <rte_tailq.h>
  15
  16#include "rte_eth_softnic_internals.h"
  17#include "rte_eth_softnic.h"
  18
  19#define rte_htons rte_cpu_to_be_16
  20#define rte_htonl rte_cpu_to_be_32
  21
  22#define rte_ntohs rte_be_to_cpu_16
  23#define rte_ntohl rte_be_to_cpu_32
  24
  25static struct rte_flow *
  26softnic_flow_find(struct softnic_table *table,
  27        struct softnic_table_rule_match *rule_match)
  28{
  29        struct rte_flow *flow;
  30
  31        TAILQ_FOREACH(flow, &table->flows, node)
  32                if (memcmp(&flow->match, rule_match, sizeof(*rule_match)) == 0)
  33                        return flow;
  34
  35        return NULL;
  36}
  37
  38int
  39flow_attr_map_set(struct pmd_internals *softnic,
  40                uint32_t group_id,
  41                int ingress,
  42                const char *pipeline_name,
  43                uint32_t table_id)
  44{
  45        struct pipeline *pipeline;
  46        struct flow_attr_map *map;
  47
  48        if (group_id >= SOFTNIC_FLOW_MAX_GROUPS ||
  49                        pipeline_name == NULL)
  50                return -1;
  51
  52        pipeline = softnic_pipeline_find(softnic, pipeline_name);
  53        if (pipeline == NULL ||
  54                        table_id >= pipeline->n_tables)
  55                return -1;
  56
  57        map = (ingress) ? &softnic->flow.ingress_map[group_id] :
  58                &softnic->flow.egress_map[group_id];
  59        strlcpy(map->pipeline_name, pipeline_name, sizeof(map->pipeline_name));
  60        map->table_id = table_id;
  61        map->valid = 1;
  62
  63        return 0;
  64}
  65
  66struct flow_attr_map *
  67flow_attr_map_get(struct pmd_internals *softnic,
  68                uint32_t group_id,
  69                int ingress)
  70{
  71        if (group_id >= SOFTNIC_FLOW_MAX_GROUPS)
  72                return NULL;
  73
  74        return (ingress) ? &softnic->flow.ingress_map[group_id] :
  75                &softnic->flow.egress_map[group_id];
  76}
  77
  78static int
  79flow_pipeline_table_get(struct pmd_internals *softnic,
  80                const struct rte_flow_attr *attr,
  81                const char **pipeline_name,
  82                uint32_t *table_id,
  83                struct rte_flow_error *error)
  84{
  85        struct flow_attr_map *map;
  86
  87        if (attr == NULL)
  88                return rte_flow_error_set(error,
  89                                EINVAL,
  90                                RTE_FLOW_ERROR_TYPE_ATTR,
  91                                NULL,
  92                                "Null attr");
  93
  94        if (!attr->ingress && !attr->egress)
  95                return rte_flow_error_set(error,
  96                                EINVAL,
  97                                RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
  98                                attr,
  99                                "Ingress/egress not specified");
 100
 101        if (attr->ingress && attr->egress)
 102                return rte_flow_error_set(error,
 103                                EINVAL,
 104                                RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
 105                                attr,
 106                                "Setting both ingress and egress is not allowed");
 107
 108        map = flow_attr_map_get(softnic,
 109                        attr->group,
 110                        attr->ingress);
 111        if (map == NULL ||
 112                        map->valid == 0)
 113                return rte_flow_error_set(error,
 114                                EINVAL,
 115                                RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
 116                                attr,
 117                                "Invalid group ID");
 118
 119        if (pipeline_name)
 120                *pipeline_name = map->pipeline_name;
 121
 122        if (table_id)
 123                *table_id = map->table_id;
 124
 125        return 0;
 126}
 127
 128union flow_item {
 129        uint8_t raw[TABLE_RULE_MATCH_SIZE_MAX];
 130        struct rte_flow_item_eth eth;
 131        struct rte_flow_item_vlan vlan;
 132        struct rte_flow_item_ipv4 ipv4;
 133        struct rte_flow_item_ipv6 ipv6;
 134        struct rte_flow_item_icmp icmp;
 135        struct rte_flow_item_udp udp;
 136        struct rte_flow_item_tcp tcp;
 137        struct rte_flow_item_sctp sctp;
 138        struct rte_flow_item_vxlan vxlan;
 139        struct rte_flow_item_e_tag e_tag;
 140        struct rte_flow_item_nvgre nvgre;
 141        struct rte_flow_item_mpls mpls;
 142        struct rte_flow_item_gre gre;
 143        struct rte_flow_item_gtp gtp;
 144        struct rte_flow_item_esp esp;
 145        struct rte_flow_item_geneve geneve;
 146        struct rte_flow_item_vxlan_gpe vxlan_gpe;
 147        struct rte_flow_item_arp_eth_ipv4 arp_eth_ipv4;
 148        struct rte_flow_item_ipv6_ext ipv6_ext;
 149        struct rte_flow_item_icmp6 icmp6;
 150        struct rte_flow_item_icmp6_nd_ns icmp6_nd_ns;
 151        struct rte_flow_item_icmp6_nd_na icmp6_nd_na;
 152        struct rte_flow_item_icmp6_nd_opt icmp6_nd_opt;
 153        struct rte_flow_item_icmp6_nd_opt_sla_eth icmp6_nd_opt_sla_eth;
 154        struct rte_flow_item_icmp6_nd_opt_tla_eth icmp6_nd_opt_tla_eth;
 155};
 156
 157static const union flow_item flow_item_raw_mask;
 158
 159static int
 160flow_item_is_proto(enum rte_flow_item_type type,
 161        const void **mask,
 162        size_t *size)
 163{
 164        switch (type) {
 165        case RTE_FLOW_ITEM_TYPE_RAW:
 166                *mask = &flow_item_raw_mask;
 167                *size = sizeof(flow_item_raw_mask);
 168                return 1; /* TRUE */
 169
 170        case RTE_FLOW_ITEM_TYPE_ETH:
 171                *mask = &rte_flow_item_eth_mask;
 172                *size = sizeof(struct rte_ether_hdr);
 173                return 1; /* TRUE */
 174
 175        case RTE_FLOW_ITEM_TYPE_VLAN:
 176                *mask = &rte_flow_item_vlan_mask;
 177                *size = sizeof(struct rte_vlan_hdr);
 178                return 1;
 179
 180        case RTE_FLOW_ITEM_TYPE_IPV4:
 181                *mask = &rte_flow_item_ipv4_mask;
 182                *size = sizeof(struct rte_ipv4_hdr);
 183                return 1;
 184
 185        case RTE_FLOW_ITEM_TYPE_IPV6:
 186                *mask = &rte_flow_item_ipv6_mask;
 187                *size = sizeof(struct rte_ipv6_hdr);
 188                return 1;
 189
 190        case RTE_FLOW_ITEM_TYPE_ICMP:
 191                *mask = &rte_flow_item_icmp_mask;
 192                *size = sizeof(struct rte_flow_item_icmp);
 193                return 1;
 194
 195        case RTE_FLOW_ITEM_TYPE_UDP:
 196                *mask = &rte_flow_item_udp_mask;
 197                *size = sizeof(struct rte_flow_item_udp);
 198                return 1;
 199
 200        case RTE_FLOW_ITEM_TYPE_TCP:
 201                *mask = &rte_flow_item_tcp_mask;
 202                *size = sizeof(struct rte_flow_item_tcp);
 203                return 1;
 204
 205        case RTE_FLOW_ITEM_TYPE_SCTP:
 206                *mask = &rte_flow_item_sctp_mask;
 207                *size = sizeof(struct rte_flow_item_sctp);
 208                return 1;
 209
 210        case RTE_FLOW_ITEM_TYPE_VXLAN:
 211                *mask = &rte_flow_item_vxlan_mask;
 212                *size = sizeof(struct rte_flow_item_vxlan);
 213                return 1;
 214
 215        case RTE_FLOW_ITEM_TYPE_E_TAG:
 216                *mask = &rte_flow_item_e_tag_mask;
 217                *size = sizeof(struct rte_flow_item_e_tag);
 218                return 1;
 219
 220        case RTE_FLOW_ITEM_TYPE_NVGRE:
 221                *mask = &rte_flow_item_nvgre_mask;
 222                *size = sizeof(struct rte_flow_item_nvgre);
 223                return 1;
 224
 225        case RTE_FLOW_ITEM_TYPE_MPLS:
 226                *mask = &rte_flow_item_mpls_mask;
 227                *size = sizeof(struct rte_flow_item_mpls);
 228                return 1;
 229
 230        case RTE_FLOW_ITEM_TYPE_GRE:
 231                *mask = &rte_flow_item_gre_mask;
 232                *size = sizeof(struct rte_flow_item_gre);
 233                return 1;
 234
 235        case RTE_FLOW_ITEM_TYPE_GTP:
 236        case RTE_FLOW_ITEM_TYPE_GTPC:
 237        case RTE_FLOW_ITEM_TYPE_GTPU:
 238                *mask = &rte_flow_item_gtp_mask;
 239                *size = sizeof(struct rte_flow_item_gtp);
 240                return 1;
 241
 242        case RTE_FLOW_ITEM_TYPE_ESP:
 243                *mask = &rte_flow_item_esp_mask;
 244                *size = sizeof(struct rte_flow_item_esp);
 245                return 1;
 246
 247        case RTE_FLOW_ITEM_TYPE_GENEVE:
 248                *mask = &rte_flow_item_geneve_mask;
 249                *size = sizeof(struct rte_flow_item_geneve);
 250                return 1;
 251
 252        case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
 253                *mask = &rte_flow_item_vxlan_gpe_mask;
 254                *size = sizeof(struct rte_flow_item_vxlan_gpe);
 255                return 1;
 256
 257        case RTE_FLOW_ITEM_TYPE_ARP_ETH_IPV4:
 258                *mask = &rte_flow_item_arp_eth_ipv4_mask;
 259                *size = sizeof(struct rte_flow_item_arp_eth_ipv4);
 260                return 1;
 261
 262        case RTE_FLOW_ITEM_TYPE_IPV6_EXT:
 263                *mask = &rte_flow_item_ipv6_ext_mask;
 264                *size = sizeof(struct rte_flow_item_ipv6_ext);
 265                return 1;
 266
 267        case RTE_FLOW_ITEM_TYPE_ICMP6:
 268                *mask = &rte_flow_item_icmp6_mask;
 269                *size = sizeof(struct rte_flow_item_icmp6);
 270                return 1;
 271
 272        case RTE_FLOW_ITEM_TYPE_ICMP6_ND_NS:
 273                *mask = &rte_flow_item_icmp6_nd_ns_mask;
 274                *size = sizeof(struct rte_flow_item_icmp6_nd_ns);
 275                return 1;
 276
 277        case RTE_FLOW_ITEM_TYPE_ICMP6_ND_NA:
 278                *mask = &rte_flow_item_icmp6_nd_na_mask;
 279                *size = sizeof(struct rte_flow_item_icmp6_nd_na);
 280                return 1;
 281
 282        case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT:
 283                *mask = &rte_flow_item_icmp6_nd_opt_mask;
 284                *size = sizeof(struct rte_flow_item_icmp6_nd_opt);
 285                return 1;
 286
 287        case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT_SLA_ETH:
 288                *mask = &rte_flow_item_icmp6_nd_opt_sla_eth_mask;
 289                *size = sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth);
 290                return 1;
 291
 292        case RTE_FLOW_ITEM_TYPE_ICMP6_ND_OPT_TLA_ETH:
 293                *mask = &rte_flow_item_icmp6_nd_opt_tla_eth_mask;
 294                *size = sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth);
 295                return 1;
 296
 297        default: return 0; /* FALSE */
 298        }
 299}
 300
 301static int
 302flow_item_raw_preprocess(const struct rte_flow_item *item,
 303        union flow_item *item_spec,
 304        union flow_item *item_mask,
 305        size_t *item_size,
 306        int *item_disabled,
 307        struct rte_flow_error *error)
 308{
 309        const struct rte_flow_item_raw *item_raw_spec = item->spec;
 310        const struct rte_flow_item_raw *item_raw_mask = item->mask;
 311        const uint8_t *pattern;
 312        const uint8_t *pattern_mask;
 313        uint8_t *spec = (uint8_t *)item_spec;
 314        uint8_t *mask = (uint8_t *)item_mask;
 315        size_t pattern_length, pattern_offset, i;
 316        int disabled;
 317
 318        if (!item->spec)
 319                return rte_flow_error_set(error,
 320                        ENOTSUP,
 321                        RTE_FLOW_ERROR_TYPE_ITEM,
 322                        item,
 323                        "RAW: Null specification");
 324
 325        if (item->last)
 326                return rte_flow_error_set(error,
 327                        ENOTSUP,
 328                        RTE_FLOW_ERROR_TYPE_ITEM,
 329                        item,
 330                        "RAW: Range not allowed (last must be NULL)");
 331
 332        if (item_raw_spec->relative == 0)
 333                return rte_flow_error_set(error,
 334                        ENOTSUP,
 335                        RTE_FLOW_ERROR_TYPE_ITEM,
 336                        item,
 337                        "RAW: Absolute offset not supported");
 338
 339        if (item_raw_spec->search)
 340                return rte_flow_error_set(error,
 341                        ENOTSUP,
 342                        RTE_FLOW_ERROR_TYPE_ITEM,
 343                        item,
 344                        "RAW: Search not supported");
 345
 346        if (item_raw_spec->offset < 0)
 347                return rte_flow_error_set(error,
 348                        ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
 349                        item,
 350                        "RAW: Negative offset not supported");
 351
 352        if (item_raw_spec->length == 0)
 353                return rte_flow_error_set(error,
 354                        ENOTSUP,
 355                        RTE_FLOW_ERROR_TYPE_ITEM,
 356                        item,
 357                        "RAW: Zero pattern length");
 358
 359        if (item_raw_spec->offset + item_raw_spec->length >
 360                TABLE_RULE_MATCH_SIZE_MAX)
 361                return rte_flow_error_set(error,
 362                        ENOTSUP,
 363                        RTE_FLOW_ERROR_TYPE_ITEM,
 364                        item,
 365                        "RAW: Item too big");
 366
 367        if (!item_raw_spec->pattern && item_raw_mask && item_raw_mask->pattern)
 368                return rte_flow_error_set(error,
 369                        ENOTSUP,
 370                        RTE_FLOW_ERROR_TYPE_ITEM,
 371                        item,
 372                        "RAW: Non-NULL pattern mask not allowed with NULL pattern");
 373
 374        pattern = item_raw_spec->pattern;
 375        pattern_mask = (item_raw_mask) ? item_raw_mask->pattern : NULL;
 376        pattern_length = (size_t)item_raw_spec->length;
 377        pattern_offset = (size_t)item_raw_spec->offset;
 378
 379        disabled = 0;
 380        if (pattern_mask == NULL)
 381                disabled = 1;
 382        else
 383                for (i = 0; i < pattern_length; i++)
 384                        if ((pattern)[i])
 385                                disabled = 1;
 386
 387        memset(spec, 0, TABLE_RULE_MATCH_SIZE_MAX);
 388        if (pattern)
 389                memcpy(&spec[pattern_offset], pattern, pattern_length);
 390
 391        memset(mask, 0, TABLE_RULE_MATCH_SIZE_MAX);
 392        if (pattern_mask)
 393                memcpy(&mask[pattern_offset], pattern_mask, pattern_length);
 394
 395        *item_size = pattern_offset + pattern_length;
 396        *item_disabled = disabled;
 397
 398        return 0;
 399}
 400
 401static int
 402flow_item_proto_preprocess(const struct rte_flow_item *item,
 403        union flow_item *item_spec,
 404        union flow_item *item_mask,
 405        size_t *item_size,
 406        int *item_disabled,
 407        struct rte_flow_error *error)
 408{
 409        const void *mask_default;
 410        uint8_t *spec = (uint8_t *)item_spec;
 411        uint8_t *mask = (uint8_t *)item_mask;
 412        size_t size, i;
 413
 414        if (!flow_item_is_proto(item->type, &mask_default, &size))
 415                return rte_flow_error_set(error,
 416                        ENOTSUP,
 417                        RTE_FLOW_ERROR_TYPE_ITEM,
 418                        item,
 419                        "Item type not supported");
 420
 421        if (item->type == RTE_FLOW_ITEM_TYPE_RAW)
 422                return flow_item_raw_preprocess(item,
 423                        item_spec,
 424                        item_mask,
 425                        item_size,
 426                        item_disabled,
 427                        error);
 428
 429        /* spec */
 430        if (!item->spec) {
 431                /* If spec is NULL, then last and mask also have to be NULL. */
 432                if (item->last || item->mask)
 433                        return rte_flow_error_set(error,
 434                                EINVAL,
 435                                RTE_FLOW_ERROR_TYPE_ITEM,
 436                                item,
 437                                "Invalid item (NULL spec with non-NULL last or mask)");
 438
 439                memset(item_spec, 0, size);
 440                memset(item_mask, 0, size);
 441                *item_size = size;
 442                *item_disabled = 1; /* TRUE */
 443                return 0;
 444        }
 445
 446        memcpy(spec, item->spec, size);
 447        *item_size = size;
 448
 449        /* mask */
 450        if (item->mask)
 451                memcpy(mask, item->mask, size);
 452        else
 453                memcpy(mask, mask_default, size);
 454
 455        /* disabled */
 456        for (i = 0; i < size; i++)
 457                if (mask[i])
 458                        break;
 459        *item_disabled = (i == size) ? 1 : 0;
 460
 461        /* Apply mask over spec. */
 462        for (i = 0; i < size; i++)
 463                spec[i] &= mask[i];
 464
 465        /* last */
 466        if (item->last) {
 467                uint8_t last[size];
 468
 469                /* init last */
 470                memcpy(last, item->last, size);
 471                for (i = 0; i < size; i++)
 472                        last[i] &= mask[i];
 473
 474                /* check for range */
 475                for (i = 0; i < size; i++)
 476                        if (last[i] != spec[i])
 477                                return rte_flow_error_set(error,
 478                                        ENOTSUP,
 479                                        RTE_FLOW_ERROR_TYPE_ITEM,
 480                                        item,
 481                                        "Range not supported");
 482        }
 483
 484        return 0;
 485}
 486
 487/***
 488 * Skip disabled protocol items and VOID items
 489 * until any of the mutually exclusive conditions
 490 * from the list below takes place:
 491 *    (A) A protocol present in the proto_mask
 492 *        is met (either ENABLED or DISABLED);
 493 *    (B) A protocol NOT present in the proto_mask is met in ENABLED state;
 494 *    (C) The END item is met.
 495 */
 496static int
 497flow_item_skip_disabled_protos(const struct rte_flow_item **item,
 498        uint64_t proto_mask,
 499        size_t *length,
 500        struct rte_flow_error *error)
 501{
 502        size_t len = 0;
 503
 504        for ( ; (*item)->type != RTE_FLOW_ITEM_TYPE_END; (*item)++) {
 505                union flow_item spec, mask;
 506                size_t size;
 507                int disabled = 0, status;
 508
 509                if ((*item)->type == RTE_FLOW_ITEM_TYPE_VOID)
 510                        continue;
 511
 512                status = flow_item_proto_preprocess(*item,
 513                                &spec,
 514                                &mask,
 515                                &size,
 516                                &disabled,
 517                                error);
 518                if (status)
 519                        return status;
 520
 521                if ((proto_mask & (1LLU << (*item)->type)) ||
 522                                !disabled)
 523                        break;
 524
 525                len += size;
 526        }
 527
 528        if (length)
 529                *length = len;
 530
 531        return 0;
 532}
 533
 534#define FLOW_ITEM_PROTO_IP \
 535        ((1LLU << RTE_FLOW_ITEM_TYPE_IPV4) | \
 536         (1LLU << RTE_FLOW_ITEM_TYPE_IPV6))
 537
 538static void
 539flow_item_skip_void(const struct rte_flow_item **item)
 540{
 541        for ( ; ; (*item)++)
 542                if ((*item)->type != RTE_FLOW_ITEM_TYPE_VOID)
 543                        return;
 544}
 545
 546#define IP_PROTOCOL_TCP 0x06
 547#define IP_PROTOCOL_UDP 0x11
 548#define IP_PROTOCOL_SCTP 0x84
 549
 550static int
 551mask_to_depth(uint64_t mask,
 552                uint32_t *depth)
 553{
 554        uint64_t n;
 555
 556        if (mask == UINT64_MAX) {
 557                if (depth)
 558                        *depth = 64;
 559
 560                return 0;
 561        }
 562
 563        mask = ~mask;
 564
 565        if (mask & (mask + 1))
 566                return -1;
 567
 568        n = __builtin_popcountll(mask);
 569        if (depth)
 570                *depth = (uint32_t)(64 - n);
 571
 572        return 0;
 573}
 574
 575static int
 576ipv4_mask_to_depth(uint32_t mask,
 577                uint32_t *depth)
 578{
 579        uint32_t d;
 580        int status;
 581
 582        status = mask_to_depth(mask | (UINT64_MAX << 32), &d);
 583        if (status)
 584                return status;
 585
 586        d -= 32;
 587        if (depth)
 588                *depth = d;
 589
 590        return 0;
 591}
 592
 593static int
 594ipv6_mask_to_depth(uint8_t *mask,
 595        uint32_t *depth)
 596{
 597        uint64_t *m = (uint64_t *)mask;
 598        uint64_t m0 = rte_be_to_cpu_64(m[0]);
 599        uint64_t m1 = rte_be_to_cpu_64(m[1]);
 600        uint32_t d0, d1;
 601        int status;
 602
 603        status = mask_to_depth(m0, &d0);
 604        if (status)
 605                return status;
 606
 607        status = mask_to_depth(m1, &d1);
 608        if (status)
 609                return status;
 610
 611        if (d0 < 64 && d1)
 612                return -1;
 613
 614        if (depth)
 615                *depth = d0 + d1;
 616
 617        return 0;
 618}
 619
 620static int
 621port_mask_to_range(uint16_t port,
 622        uint16_t port_mask,
 623        uint16_t *port0,
 624        uint16_t *port1)
 625{
 626        int status;
 627        uint16_t p0, p1;
 628
 629        status = mask_to_depth(port_mask | (UINT64_MAX << 16), NULL);
 630        if (status)
 631                return -1;
 632
 633        p0 = port & port_mask;
 634        p1 = p0 | ~port_mask;
 635
 636        if (port0)
 637                *port0 = p0;
 638
 639        if (port1)
 640                *port1 = p1;
 641
 642        return 0;
 643}
 644
 645static int
 646flow_rule_match_acl_get(struct pmd_internals *softnic __rte_unused,
 647                struct pipeline *pipeline __rte_unused,
 648                struct softnic_table *table __rte_unused,
 649                const struct rte_flow_attr *attr,
 650                const struct rte_flow_item *item,
 651                struct softnic_table_rule_match *rule_match,
 652                struct rte_flow_error *error)
 653{
 654        union flow_item spec, mask;
 655        size_t size, length = 0;
 656        int disabled = 0, status;
 657        uint8_t ip_proto, ip_proto_mask;
 658
 659        memset(rule_match, 0, sizeof(*rule_match));
 660        rule_match->match_type = TABLE_ACL;
 661        rule_match->match.acl.priority = attr->priority;
 662
 663        /* VOID or disabled protos only, if any. */
 664        status = flow_item_skip_disabled_protos(&item,
 665                        FLOW_ITEM_PROTO_IP, &length, error);
 666        if (status)
 667                return status;
 668
 669        /* IP only. */
 670        status = flow_item_proto_preprocess(item, &spec, &mask,
 671                        &size, &disabled, error);
 672        if (status)
 673                return status;
 674
 675        switch (item->type) {
 676        case RTE_FLOW_ITEM_TYPE_IPV4:
 677        {
 678                uint32_t sa_depth, da_depth;
 679
 680                status = ipv4_mask_to_depth(rte_ntohl(mask.ipv4.hdr.src_addr),
 681                                &sa_depth);
 682                if (status)
 683                        return rte_flow_error_set(error,
 684                                EINVAL,
 685                                RTE_FLOW_ERROR_TYPE_ITEM,
 686                                item,
 687                                "ACL: Illegal IPv4 header source address mask");
 688
 689                status = ipv4_mask_to_depth(rte_ntohl(mask.ipv4.hdr.dst_addr),
 690                                &da_depth);
 691                if (status)
 692                        return rte_flow_error_set(error,
 693                                EINVAL,
 694                                RTE_FLOW_ERROR_TYPE_ITEM,
 695                                item,
 696                                "ACL: Illegal IPv4 header destination address mask");
 697
 698                ip_proto = spec.ipv4.hdr.next_proto_id;
 699                ip_proto_mask = mask.ipv4.hdr.next_proto_id;
 700
 701                rule_match->match.acl.ip_version = 1;
 702                rule_match->match.acl.ipv4.sa =
 703                        rte_ntohl(spec.ipv4.hdr.src_addr);
 704                rule_match->match.acl.ipv4.da =
 705                        rte_ntohl(spec.ipv4.hdr.dst_addr);
 706                rule_match->match.acl.sa_depth = sa_depth;
 707                rule_match->match.acl.da_depth = da_depth;
 708                rule_match->match.acl.proto = ip_proto;
 709                rule_match->match.acl.proto_mask = ip_proto_mask;
 710                break;
 711        } /* RTE_FLOW_ITEM_TYPE_IPV4 */
 712
 713        case RTE_FLOW_ITEM_TYPE_IPV6:
 714        {
 715                uint32_t sa_depth, da_depth;
 716
 717                status = ipv6_mask_to_depth(mask.ipv6.hdr.src_addr, &sa_depth);
 718                if (status)
 719                        return rte_flow_error_set(error,
 720                                EINVAL,
 721                                RTE_FLOW_ERROR_TYPE_ITEM,
 722                                item,
 723                                "ACL: Illegal IPv6 header source address mask");
 724
 725                status = ipv6_mask_to_depth(mask.ipv6.hdr.dst_addr, &da_depth);
 726                if (status)
 727                        return rte_flow_error_set(error,
 728                                EINVAL,
 729                                RTE_FLOW_ERROR_TYPE_ITEM,
 730                                item,
 731                                "ACL: Illegal IPv6 header destination address mask");
 732
 733                ip_proto = spec.ipv6.hdr.proto;
 734                ip_proto_mask = mask.ipv6.hdr.proto;
 735
 736                rule_match->match.acl.ip_version = 0;
 737                memcpy(rule_match->match.acl.ipv6.sa,
 738                        spec.ipv6.hdr.src_addr,
 739                        sizeof(spec.ipv6.hdr.src_addr));
 740                memcpy(rule_match->match.acl.ipv6.da,
 741                        spec.ipv6.hdr.dst_addr,
 742                        sizeof(spec.ipv6.hdr.dst_addr));
 743                rule_match->match.acl.sa_depth = sa_depth;
 744                rule_match->match.acl.da_depth = da_depth;
 745                rule_match->match.acl.proto = ip_proto;
 746                rule_match->match.acl.proto_mask = ip_proto_mask;
 747                break;
 748        } /* RTE_FLOW_ITEM_TYPE_IPV6 */
 749
 750        default:
 751                return rte_flow_error_set(error,
 752                        ENOTSUP,
 753                        RTE_FLOW_ERROR_TYPE_ITEM,
 754                        item,
 755                        "ACL: IP protocol required");
 756        } /* switch */
 757
 758        if (ip_proto_mask != UINT8_MAX)
 759                return rte_flow_error_set(error,
 760                        EINVAL,
 761                        RTE_FLOW_ERROR_TYPE_ITEM,
 762                        item,
 763                        "ACL: Illegal IP protocol mask");
 764
 765        item++;
 766
 767        /* VOID only, if any. */
 768        flow_item_skip_void(&item);
 769
 770        /* TCP/UDP/SCTP only. */
 771        status = flow_item_proto_preprocess(item, &spec, &mask,
 772                        &size, &disabled, error);
 773        if (status)
 774                return status;
 775
 776        switch (item->type) {
 777        case RTE_FLOW_ITEM_TYPE_TCP:
 778        {
 779                uint16_t sp0, sp1, dp0, dp1;
 780
 781                if (ip_proto != IP_PROTOCOL_TCP)
 782                        return rte_flow_error_set(error,
 783                                EINVAL,
 784                                RTE_FLOW_ERROR_TYPE_ITEM,
 785                                item,
 786                                "ACL: Item type is TCP, but IP protocol is not");
 787
 788                status = port_mask_to_range(rte_ntohs(spec.tcp.hdr.src_port),
 789                                rte_ntohs(mask.tcp.hdr.src_port),
 790                                &sp0,
 791                                &sp1);
 792
 793                if (status)
 794                        return rte_flow_error_set(error,
 795                                EINVAL,
 796                                RTE_FLOW_ERROR_TYPE_ITEM,
 797                                item,
 798                                "ACL: Illegal TCP source port mask");
 799
 800                status = port_mask_to_range(rte_ntohs(spec.tcp.hdr.dst_port),
 801                                rte_ntohs(mask.tcp.hdr.dst_port),
 802                                &dp0,
 803                                &dp1);
 804
 805                if (status)
 806                        return rte_flow_error_set(error,
 807                                EINVAL,
 808                                RTE_FLOW_ERROR_TYPE_ITEM,
 809                                item,
 810                                "ACL: Illegal TCP destination port mask");
 811
 812                rule_match->match.acl.sp0 = sp0;
 813                rule_match->match.acl.sp1 = sp1;
 814                rule_match->match.acl.dp0 = dp0;
 815                rule_match->match.acl.dp1 = dp1;
 816
 817                break;
 818        } /* RTE_FLOW_ITEM_TYPE_TCP */
 819
 820        case RTE_FLOW_ITEM_TYPE_UDP:
 821        {
 822                uint16_t sp0, sp1, dp0, dp1;
 823
 824                if (ip_proto != IP_PROTOCOL_UDP)
 825                        return rte_flow_error_set(error,
 826                                EINVAL,
 827                                RTE_FLOW_ERROR_TYPE_ITEM,
 828                                item,
 829                                "ACL: Item type is UDP, but IP protocol is not");
 830
 831                status = port_mask_to_range(rte_ntohs(spec.udp.hdr.src_port),
 832                        rte_ntohs(mask.udp.hdr.src_port),
 833                        &sp0,
 834                        &sp1);
 835                if (status)
 836                        return rte_flow_error_set(error,
 837                                EINVAL,
 838                                RTE_FLOW_ERROR_TYPE_ITEM,
 839                                item,
 840                                "ACL: Illegal UDP source port mask");
 841
 842                status = port_mask_to_range(rte_ntohs(spec.udp.hdr.dst_port),
 843                        rte_ntohs(mask.udp.hdr.dst_port),
 844                        &dp0,
 845                        &dp1);
 846                if (status)
 847                        return rte_flow_error_set(error,
 848                                EINVAL,
 849                                RTE_FLOW_ERROR_TYPE_ITEM,
 850                                item,
 851                                "ACL: Illegal UDP destination port mask");
 852
 853                rule_match->match.acl.sp0 = sp0;
 854                rule_match->match.acl.sp1 = sp1;
 855                rule_match->match.acl.dp0 = dp0;
 856                rule_match->match.acl.dp1 = dp1;
 857
 858                break;
 859        } /* RTE_FLOW_ITEM_TYPE_UDP */
 860
 861        case RTE_FLOW_ITEM_TYPE_SCTP:
 862        {
 863                uint16_t sp0, sp1, dp0, dp1;
 864
 865                if (ip_proto != IP_PROTOCOL_SCTP)
 866                        return rte_flow_error_set(error,
 867                                EINVAL,
 868                                RTE_FLOW_ERROR_TYPE_ITEM,
 869                                item,
 870                                "ACL: Item type is SCTP, but IP protocol is not");
 871
 872                status = port_mask_to_range(rte_ntohs(spec.sctp.hdr.src_port),
 873                        rte_ntohs(mask.sctp.hdr.src_port),
 874                        &sp0,
 875                        &sp1);
 876
 877                if (status)
 878                        return rte_flow_error_set(error,
 879                                EINVAL,
 880                                RTE_FLOW_ERROR_TYPE_ITEM,
 881                                item,
 882                                "ACL: Illegal SCTP source port mask");
 883
 884                status = port_mask_to_range(rte_ntohs(spec.sctp.hdr.dst_port),
 885                        rte_ntohs(mask.sctp.hdr.dst_port),
 886                        &dp0,
 887                        &dp1);
 888                if (status)
 889                        return rte_flow_error_set(error,
 890                                EINVAL,
 891                                RTE_FLOW_ERROR_TYPE_ITEM,
 892                                item,
 893                                "ACL: Illegal SCTP destination port mask");
 894
 895                rule_match->match.acl.sp0 = sp0;
 896                rule_match->match.acl.sp1 = sp1;
 897                rule_match->match.acl.dp0 = dp0;
 898                rule_match->match.acl.dp1 = dp1;
 899
 900                break;
 901        } /* RTE_FLOW_ITEM_TYPE_SCTP */
 902
 903        default:
 904                return rte_flow_error_set(error,
 905                        ENOTSUP,
 906                        RTE_FLOW_ERROR_TYPE_ITEM,
 907                        item,
 908                        "ACL: TCP/UDP/SCTP required");
 909        } /* switch */
 910
 911        item++;
 912
 913        /* VOID or disabled protos only, if any. */
 914        status = flow_item_skip_disabled_protos(&item, 0, NULL, error);
 915        if (status)
 916                return status;
 917
 918        /* END only. */
 919        if (item->type != RTE_FLOW_ITEM_TYPE_END)
 920                return rte_flow_error_set(error,
 921                        EINVAL,
 922                        RTE_FLOW_ERROR_TYPE_ITEM,
 923                        item,
 924                        "ACL: Expecting END item");
 925
 926        return 0;
 927}
 928
 929/***
 930 * Both *tmask* and *fmask* are byte arrays of size *tsize* and *fsize*
 931 * respectively.
 932 * They are located within a larger buffer at offsets *toffset* and *foffset*
 933 * respectivelly. Both *tmask* and *fmask* represent bitmasks for the larger
 934 * buffer.
 935 * Question: are the two masks equivalent?
 936 *
 937 * Notes:
 938 * 1. Offset basically indicates that the first offset bytes in the buffer
 939 *    are "don't care", so offset is equivalent to pre-pending an "all-zeros"
 940 *    array of *offset* bytes to the *mask*.
 941 * 2. Each *mask* might contain a number of zero bytes at the beginning or
 942 *    at the end.
 943 * 3. Bytes in the larger buffer after the end of the *mask* are also considered
 944 *    "don't care", so they are equivalent to appending an "all-zeros" array of
 945 *    bytes to the *mask*.
 946 *
 947 * Example:
 948 * Buffer = [xx xx xx xx xx xx xx xx], buffer size = 8 bytes
 949 * tmask = [00 22 00 33 00], toffset = 2, tsize = 5
 950 *    => buffer mask = [00 00 00 22 00 33 00 00]
 951 * fmask = [22 00 33], foffset = 3, fsize = 3 =>
 952 *    => buffer mask = [00 00 00 22 00 33 00 00]
 953 * Therefore, the tmask and fmask from this example are equivalent.
 954 */
 955static int
 956hash_key_mask_is_same(uint8_t *tmask,
 957        size_t toffset,
 958        size_t tsize,
 959        uint8_t *fmask,
 960        size_t foffset,
 961        size_t fsize,
 962        size_t *toffset_plus,
 963        size_t *foffset_plus)
 964{
 965        size_t tpos; /* Position of first non-zero byte in the tmask buffer. */
 966        size_t fpos; /* Position of first non-zero byte in the fmask buffer. */
 967
 968        /* Compute tpos and fpos. */
 969        for (tpos = 0; tmask[tpos] == 0; tpos++)
 970                ;
 971        for (fpos = 0; fmask[fpos] == 0; fpos++)
 972                ;
 973
 974        if (toffset + tpos != foffset + fpos)
 975                return 0; /* FALSE */
 976
 977        tsize -= tpos;
 978        fsize -= fpos;
 979
 980        if (tsize < fsize) {
 981                size_t i;
 982
 983                for (i = 0; i < tsize; i++)
 984                        if (tmask[tpos + i] != fmask[fpos + i])
 985                                return 0; /* FALSE */
 986
 987                for ( ; i < fsize; i++)
 988                        if (fmask[fpos + i])
 989                                return 0; /* FALSE */
 990        } else {
 991                size_t i;
 992
 993                for (i = 0; i < fsize; i++)
 994                        if (tmask[tpos + i] != fmask[fpos + i])
 995                                return 0; /* FALSE */
 996
 997                for ( ; i < tsize; i++)
 998                        if (tmask[tpos + i])
 999                                return 0; /* FALSE */
1000        }
1001
1002        if (toffset_plus)
1003                *toffset_plus = tpos;
1004
1005        if (foffset_plus)
1006                *foffset_plus = fpos;
1007
1008        return 1; /* TRUE */
1009}
1010
1011static int
1012flow_rule_match_hash_get(struct pmd_internals *softnic __rte_unused,
1013        struct pipeline *pipeline __rte_unused,
1014        struct softnic_table *table,
1015        const struct rte_flow_attr *attr __rte_unused,
1016        const struct rte_flow_item *item,
1017        struct softnic_table_rule_match *rule_match,
1018        struct rte_flow_error *error)
1019{
1020        struct softnic_table_rule_match_hash key, key_mask;
1021        struct softnic_table_hash_params *params = &table->params.match.hash;
1022        size_t offset = 0, length = 0, tpos, fpos;
1023        int status;
1024
1025        memset(&key, 0, sizeof(key));
1026        memset(&key_mask, 0, sizeof(key_mask));
1027
1028        /* VOID or disabled protos only, if any. */
1029        status = flow_item_skip_disabled_protos(&item, 0, &offset, error);
1030        if (status)
1031                return status;
1032
1033        if (item->type == RTE_FLOW_ITEM_TYPE_END)
1034                return rte_flow_error_set(error,
1035                        EINVAL,
1036                        RTE_FLOW_ERROR_TYPE_ITEM,
1037                        item,
1038                        "HASH: END detected too early");
1039
1040        /* VOID or any protocols (enabled or disabled). */
1041        for ( ; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
1042                union flow_item spec, mask;
1043                size_t size;
1044                int disabled, status;
1045
1046                if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
1047                        continue;
1048
1049                status = flow_item_proto_preprocess(item,
1050                        &spec,
1051                        &mask,
1052                        &size,
1053                        &disabled,
1054                        error);
1055                if (status)
1056                        return status;
1057
1058                if (length + size > sizeof(key)) {
1059                        if (disabled)
1060                                break;
1061
1062                        return rte_flow_error_set(error,
1063                                ENOTSUP,
1064                                RTE_FLOW_ERROR_TYPE_ITEM,
1065                                item,
1066                                "HASH: Item too big");
1067                }
1068
1069                memcpy(&key.key[length], &spec, size);
1070                memcpy(&key_mask.key[length], &mask, size);
1071                length += size;
1072        }
1073
1074        if (item->type != RTE_FLOW_ITEM_TYPE_END) {
1075                /* VOID or disabled protos only, if any. */
1076                status = flow_item_skip_disabled_protos(&item, 0, NULL, error);
1077                if (status)
1078                        return status;
1079
1080                /* END only. */
1081                if (item->type != RTE_FLOW_ITEM_TYPE_END)
1082                        return rte_flow_error_set(error,
1083                                EINVAL,
1084                                RTE_FLOW_ERROR_TYPE_ITEM,
1085                                item,
1086                                "HASH: Expecting END item");
1087        }
1088
1089        /* Compare flow key mask against table key mask. */
1090        offset += sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM;
1091
1092        if (!hash_key_mask_is_same(params->key_mask,
1093                params->key_offset,
1094                params->key_size,
1095                key_mask.key,
1096                offset,
1097                length,
1098                &tpos,
1099                &fpos))
1100                return rte_flow_error_set(error,
1101                        EINVAL,
1102                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1103                        NULL,
1104                        "HASH: Item list is not observing the match format");
1105
1106        /* Rule match. */
1107        memset(rule_match, 0, sizeof(*rule_match));
1108        rule_match->match_type = TABLE_HASH;
1109        memcpy(&rule_match->match.hash.key[tpos],
1110                &key.key[fpos],
1111                RTE_MIN(sizeof(rule_match->match.hash.key) - tpos,
1112                        length - fpos));
1113
1114        return 0;
1115}
1116
1117static int
1118flow_rule_match_get(struct pmd_internals *softnic,
1119                struct pipeline *pipeline,
1120                struct softnic_table *table,
1121                const struct rte_flow_attr *attr,
1122                const struct rte_flow_item *item,
1123                struct softnic_table_rule_match *rule_match,
1124                struct rte_flow_error *error)
1125{
1126        switch (table->params.match_type) {
1127        case TABLE_ACL:
1128                return flow_rule_match_acl_get(softnic,
1129                        pipeline,
1130                        table,
1131                        attr,
1132                        item,
1133                        rule_match,
1134                        error);
1135
1136                /* FALLTHROUGH */
1137
1138        case TABLE_HASH:
1139                return flow_rule_match_hash_get(softnic,
1140                        pipeline,
1141                        table,
1142                        attr,
1143                        item,
1144                        rule_match,
1145                        error);
1146
1147                /* FALLTHROUGH */
1148
1149        default:
1150                return rte_flow_error_set(error,
1151                        ENOTSUP,
1152                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1153                        NULL,
1154                        "Unsupported pipeline table match type");
1155        }
1156}
1157
1158static int
1159flow_rule_action_get(struct pmd_internals *softnic,
1160        struct pipeline *pipeline,
1161        struct softnic_table *table,
1162        const struct rte_flow_attr *attr,
1163        const struct rte_flow_action *action,
1164        struct softnic_table_rule_action *rule_action,
1165        struct rte_flow_error *error)
1166{
1167        struct softnic_table_action_profile *profile;
1168        struct softnic_table_action_profile_params *params;
1169        struct softnic_mtr_meter_policy *policy;
1170        int n_jump_queue_rss_drop = 0;
1171        int n_count = 0;
1172        int n_mark = 0;
1173        int n_vxlan_decap = 0;
1174
1175        profile = softnic_table_action_profile_find(softnic,
1176                table->params.action_profile_name);
1177        if (profile == NULL)
1178                return rte_flow_error_set(error,
1179                        EINVAL,
1180                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1181                        action,
1182                        "JUMP: Table action profile");
1183
1184        params = &profile->params;
1185
1186        for ( ; action->type != RTE_FLOW_ACTION_TYPE_END; action++) {
1187                if (action->type == RTE_FLOW_ACTION_TYPE_VOID)
1188                        continue;
1189
1190                switch (action->type) {
1191                case RTE_FLOW_ACTION_TYPE_JUMP:
1192                {
1193                        const struct rte_flow_action_jump *conf = action->conf;
1194                        struct flow_attr_map *map;
1195
1196                        if (conf == NULL)
1197                                return rte_flow_error_set(error,
1198                                        EINVAL,
1199                                        RTE_FLOW_ERROR_TYPE_ACTION,
1200                                        action,
1201                                        "JUMP: Null configuration");
1202
1203                        if (n_jump_queue_rss_drop)
1204                                return rte_flow_error_set(error,
1205                                        EINVAL,
1206                                        RTE_FLOW_ERROR_TYPE_ACTION,
1207                                        action,
1208                                        "Only one termination action is"
1209                                        " allowed per flow");
1210
1211                        if ((params->action_mask &
1212                                (1LLU << RTE_TABLE_ACTION_FWD)) == 0)
1213                                return rte_flow_error_set(error,
1214                                        EINVAL,
1215                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1216                                        NULL,
1217                                        "JUMP action not enabled for this table");
1218
1219                        n_jump_queue_rss_drop = 1;
1220
1221                        map = flow_attr_map_get(softnic,
1222                                conf->group,
1223                                attr->ingress);
1224                        if (map == NULL || map->valid == 0)
1225                                return rte_flow_error_set(error,
1226                                        EINVAL,
1227                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1228                                        NULL,
1229                                        "JUMP: Invalid group mapping");
1230
1231                        if (strcmp(pipeline->name, map->pipeline_name) != 0)
1232                                return rte_flow_error_set(error,
1233                                        ENOTSUP,
1234                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1235                                        NULL,
1236                                        "JUMP: Jump to table in different pipeline");
1237
1238                        /* RTE_TABLE_ACTION_FWD */
1239                        rule_action->fwd.action = RTE_PIPELINE_ACTION_TABLE;
1240                        rule_action->fwd.id = map->table_id;
1241                        rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1242                        break;
1243                } /* RTE_FLOW_ACTION_TYPE_JUMP */
1244
1245                case RTE_FLOW_ACTION_TYPE_QUEUE:
1246                {
1247                        char name[NAME_SIZE];
1248                        struct rte_eth_dev *dev;
1249                        const struct rte_flow_action_queue *conf = action->conf;
1250                        uint32_t port_id;
1251                        int status;
1252
1253                        if (conf == NULL)
1254                                return rte_flow_error_set(error,
1255                                        EINVAL,
1256                                        RTE_FLOW_ERROR_TYPE_ACTION,
1257                                        action,
1258                                        "QUEUE: Null configuration");
1259
1260                        if (n_jump_queue_rss_drop)
1261                                return rte_flow_error_set(error,
1262                                        EINVAL,
1263                                        RTE_FLOW_ERROR_TYPE_ACTION,
1264                                        action,
1265                                        "Only one termination action is allowed"
1266                                        " per flow");
1267
1268                        if ((params->action_mask &
1269                                (1LLU << RTE_TABLE_ACTION_FWD)) == 0)
1270                                return rte_flow_error_set(error,
1271                                        EINVAL,
1272                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1273                                        NULL,
1274                                        "QUEUE action not enabled for this table");
1275
1276                        n_jump_queue_rss_drop = 1;
1277
1278                        dev = ETHDEV(softnic);
1279                        if (dev == NULL ||
1280                                conf->index >= dev->data->nb_rx_queues)
1281                                return rte_flow_error_set(error,
1282                                        EINVAL,
1283                                        RTE_FLOW_ERROR_TYPE_ACTION,
1284                                        action,
1285                                        "QUEUE: Invalid RX queue ID");
1286
1287                        snprintf(name, sizeof(name), "RXQ%u",
1288                                        (uint32_t)conf->index);
1289
1290                        status = softnic_pipeline_port_out_find(softnic,
1291                                pipeline->name,
1292                                name,
1293                                &port_id);
1294                        if (status)
1295                                return rte_flow_error_set(error,
1296                                        ENOTSUP,
1297                                        RTE_FLOW_ERROR_TYPE_ACTION,
1298                                        action,
1299                                        "QUEUE: RX queue not accessible from this pipeline");
1300
1301                        /* RTE_TABLE_ACTION_FWD */
1302                        rule_action->fwd.action = RTE_PIPELINE_ACTION_PORT;
1303                        rule_action->fwd.id = port_id;
1304                        rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1305                        break;
1306                } /*RTE_FLOW_ACTION_TYPE_QUEUE */
1307
1308                case RTE_FLOW_ACTION_TYPE_RSS:
1309                {
1310                        const struct rte_flow_action_rss *conf = action->conf;
1311                        uint32_t i;
1312
1313                        if (conf == NULL)
1314                                return rte_flow_error_set(error,
1315                                        EINVAL,
1316                                        RTE_FLOW_ERROR_TYPE_ACTION,
1317                                        action,
1318                                        "RSS: Null configuration");
1319
1320                        if (!rte_is_power_of_2(conf->queue_num))
1321                                return rte_flow_error_set(error,
1322                                        EINVAL,
1323                                        RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1324                                        conf,
1325                                        "RSS: Number of queues must be a power of 2");
1326
1327                        if (conf->queue_num > RTE_DIM(rule_action->lb.out))
1328                                return rte_flow_error_set(error,
1329                                        EINVAL,
1330                                        RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1331                                        conf,
1332                                        "RSS: Number of queues too big");
1333
1334                        if (n_jump_queue_rss_drop)
1335                                return rte_flow_error_set(error,
1336                                        EINVAL,
1337                                        RTE_FLOW_ERROR_TYPE_ACTION,
1338                                        action,
1339                                        "Only one termination action is allowed per flow");
1340
1341                        if (((params->action_mask &
1342                                (1LLU << RTE_TABLE_ACTION_FWD)) == 0) ||
1343                                ((params->action_mask &
1344                                (1LLU << RTE_TABLE_ACTION_LB)) == 0))
1345                                return rte_flow_error_set(error,
1346                                        ENOTSUP,
1347                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1348                                        NULL,
1349                                        "RSS action not supported by this table");
1350
1351                        if (params->lb.out_offset !=
1352                                pipeline->params.offset_port_id)
1353                                return rte_flow_error_set(error,
1354                                        EINVAL,
1355                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1356                                        NULL,
1357                                        "RSS action not supported by this pipeline");
1358
1359                        n_jump_queue_rss_drop = 1;
1360
1361                        /* RTE_TABLE_ACTION_LB */
1362                        for (i = 0; i < conf->queue_num; i++) {
1363                                char name[NAME_SIZE];
1364                                struct rte_eth_dev *dev;
1365                                uint32_t port_id;
1366                                int status;
1367
1368                                dev = ETHDEV(softnic);
1369                                if (dev == NULL ||
1370                                        conf->queue[i] >=
1371                                                dev->data->nb_rx_queues)
1372                                        return rte_flow_error_set(error,
1373                                                EINVAL,
1374                                                RTE_FLOW_ERROR_TYPE_ACTION,
1375                                                action,
1376                                                "RSS: Invalid RX queue ID");
1377
1378                                snprintf(name, sizeof(name), "RXQ%u",
1379                                        (uint32_t)conf->queue[i]);
1380
1381                                status = softnic_pipeline_port_out_find(softnic,
1382                                        pipeline->name,
1383                                        name,
1384                                        &port_id);
1385                                if (status)
1386                                        return rte_flow_error_set(error,
1387                                                ENOTSUP,
1388                                                RTE_FLOW_ERROR_TYPE_ACTION,
1389                                                action,
1390                                                "RSS: RX queue not accessible from this pipeline");
1391
1392                                rule_action->lb.out[i] = port_id;
1393                        }
1394
1395                        for ( ; i < RTE_DIM(rule_action->lb.out); i++)
1396                                rule_action->lb.out[i] =
1397                                rule_action->lb.out[i % conf->queue_num];
1398
1399                        rule_action->action_mask |= 1 << RTE_TABLE_ACTION_LB;
1400
1401                        /* RTE_TABLE_ACTION_FWD */
1402                        rule_action->fwd.action = RTE_PIPELINE_ACTION_PORT_META;
1403                        rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1404                        break;
1405                } /* RTE_FLOW_ACTION_TYPE_RSS */
1406
1407                case RTE_FLOW_ACTION_TYPE_DROP:
1408                {
1409                        const void *conf = action->conf;
1410
1411                        if (conf != NULL)
1412                                return rte_flow_error_set(error,
1413                                        EINVAL,
1414                                        RTE_FLOW_ERROR_TYPE_ACTION,
1415                                        action,
1416                                        "DROP: No configuration required");
1417
1418                        if (n_jump_queue_rss_drop)
1419                                return rte_flow_error_set(error,
1420                                        EINVAL,
1421                                        RTE_FLOW_ERROR_TYPE_ACTION,
1422                                        action,
1423                                        "Only one termination action is allowed per flow");
1424                        if ((params->action_mask &
1425                                (1LLU << RTE_TABLE_ACTION_FWD)) == 0)
1426                                return rte_flow_error_set(error,
1427                                        ENOTSUP,
1428                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1429                                        NULL,
1430                                        "DROP action not supported by this table");
1431
1432                        n_jump_queue_rss_drop = 1;
1433
1434                        /* RTE_TABLE_ACTION_FWD */
1435                        rule_action->fwd.action = RTE_PIPELINE_ACTION_DROP;
1436                        rule_action->action_mask |= 1 << RTE_TABLE_ACTION_FWD;
1437                        break;
1438                } /* RTE_FLOW_ACTION_TYPE_DROP */
1439
1440                case RTE_FLOW_ACTION_TYPE_COUNT:
1441                {
1442                        const struct rte_flow_action_count *conf = action->conf;
1443
1444                        if (conf == NULL)
1445                                return rte_flow_error_set(error,
1446                                        EINVAL,
1447                                        RTE_FLOW_ERROR_TYPE_ACTION,
1448                                        action,
1449                                        "COUNT: Null configuration");
1450
1451                        if (conf->shared)
1452                                return rte_flow_error_set(error,
1453                                        ENOTSUP,
1454                                        RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1455                                        conf,
1456                                        "COUNT: Shared counters not supported");
1457
1458                        if (n_count)
1459                                return rte_flow_error_set(error,
1460                                        ENOTSUP,
1461                                        RTE_FLOW_ERROR_TYPE_ACTION,
1462                                        action,
1463                                        "Only one COUNT action per flow");
1464
1465                        if ((params->action_mask &
1466                                (1LLU << RTE_TABLE_ACTION_STATS)) == 0)
1467                                return rte_flow_error_set(error,
1468                                        ENOTSUP,
1469                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1470                                        NULL,
1471                                        "COUNT action not supported by this table");
1472
1473                        n_count = 1;
1474
1475                        /* RTE_TABLE_ACTION_STATS */
1476                        rule_action->stats.n_packets = 0;
1477                        rule_action->stats.n_bytes = 0;
1478                        rule_action->action_mask |= 1 << RTE_TABLE_ACTION_STATS;
1479                        break;
1480                } /* RTE_FLOW_ACTION_TYPE_COUNT */
1481
1482                case RTE_FLOW_ACTION_TYPE_MARK:
1483                {
1484                        const struct rte_flow_action_mark *conf = action->conf;
1485
1486                        if (conf == NULL)
1487                                return rte_flow_error_set(error,
1488                                        EINVAL,
1489                                        RTE_FLOW_ERROR_TYPE_ACTION,
1490                                        action,
1491                                        "MARK: Null configuration");
1492
1493                        if (n_mark)
1494                                return rte_flow_error_set(error,
1495                                        ENOTSUP,
1496                                        RTE_FLOW_ERROR_TYPE_ACTION,
1497                                        action,
1498                                        "Only one MARK action per flow");
1499
1500                        if ((params->action_mask &
1501                                (1LLU << RTE_TABLE_ACTION_TAG)) == 0)
1502                                return rte_flow_error_set(error,
1503                                        ENOTSUP,
1504                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1505                                        NULL,
1506                                        "MARK action not supported by this table");
1507
1508                        n_mark = 1;
1509
1510                        /* RTE_TABLE_ACTION_TAG */
1511                        rule_action->tag.tag = conf->id;
1512                        rule_action->action_mask |= 1 << RTE_TABLE_ACTION_TAG;
1513                        break;
1514                } /* RTE_FLOW_ACTION_TYPE_MARK */
1515
1516                case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
1517                {
1518                        const struct rte_flow_action_mark *conf = action->conf;
1519
1520                        if (conf)
1521                                return rte_flow_error_set(error,
1522                                        EINVAL,
1523                                        RTE_FLOW_ERROR_TYPE_ACTION,
1524                                        action,
1525                                        "VXLAN DECAP: Non-null configuration");
1526
1527                        if (n_vxlan_decap)
1528                                return rte_flow_error_set(error,
1529                                        ENOTSUP,
1530                                        RTE_FLOW_ERROR_TYPE_ACTION,
1531                                        action,
1532                                        "Only one VXLAN DECAP action per flow");
1533
1534                        if ((params->action_mask &
1535                                (1LLU << RTE_TABLE_ACTION_DECAP)) == 0)
1536                                return rte_flow_error_set(error,
1537                                        ENOTSUP,
1538                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1539                                        NULL,
1540                                        "VXLAN DECAP action not supported by this table");
1541
1542                        n_vxlan_decap = 1;
1543
1544                        /* RTE_TABLE_ACTION_DECAP */
1545                        rule_action->decap.n = 50; /* Ether/IPv4/UDP/VXLAN */
1546                        rule_action->action_mask |= 1 << RTE_TABLE_ACTION_DECAP;
1547                        break;
1548                } /* RTE_FLOW_ACTION_TYPE_VXLAN_DECAP */
1549
1550                case RTE_FLOW_ACTION_TYPE_METER:
1551                {
1552                        const struct rte_flow_action_meter *conf = action->conf;
1553                        struct softnic_mtr_meter_profile *mp;
1554                        struct softnic_mtr *m;
1555                        uint32_t table_id = table - pipeline->table;
1556                        uint32_t meter_profile_id;
1557                        int status;
1558
1559                        if ((params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) == 0)
1560                                return rte_flow_error_set(error,
1561                                        EINVAL,
1562                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1563                                        NULL,
1564                                        "METER: Table action not supported");
1565
1566                        if (params->mtr.n_tc != 1)
1567                                return rte_flow_error_set(error,
1568                                        EINVAL,
1569                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1570                                        NULL,
1571                                        "METER: Multiple TCs not supported");
1572
1573                        if (conf == NULL)
1574                                return rte_flow_error_set(error,
1575                                        EINVAL,
1576                                        RTE_FLOW_ERROR_TYPE_ACTION,
1577                                        action,
1578                                        "METER: Null configuration");
1579
1580                        m = softnic_mtr_find(softnic, conf->mtr_id);
1581
1582                        if (m == NULL)
1583                                return rte_flow_error_set(error,
1584                                        EINVAL,
1585                                        RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1586                                        NULL,
1587                                        "METER: Invalid meter ID");
1588
1589                        if (m->flow)
1590                                return rte_flow_error_set(error,
1591                                        EINVAL,
1592                                        RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1593                                        NULL,
1594                                        "METER: Meter already attached to a flow");
1595
1596                        meter_profile_id = m->params.meter_profile_id;
1597                        mp = softnic_mtr_meter_profile_find(softnic, meter_profile_id);
1598
1599                        /* Add meter profile to pipeline table */
1600                        if (!softnic_pipeline_table_meter_profile_find(table,
1601                                        meter_profile_id)) {
1602                                struct rte_table_action_meter_profile profile;
1603
1604                                memset(&profile, 0, sizeof(profile));
1605                                profile.alg = RTE_TABLE_ACTION_METER_TRTCM;
1606                                profile.trtcm.cir = mp->params.trtcm_rfc2698.cir;
1607                                profile.trtcm.pir = mp->params.trtcm_rfc2698.pir;
1608                                profile.trtcm.cbs = mp->params.trtcm_rfc2698.cbs;
1609                                profile.trtcm.pbs = mp->params.trtcm_rfc2698.pbs;
1610
1611                                status = softnic_pipeline_table_mtr_profile_add(softnic,
1612                                                pipeline->name,
1613                                                table_id,
1614                                                meter_profile_id,
1615                                                &profile);
1616                                if (status) {
1617                                        rte_flow_error_set(error,
1618                                                EINVAL,
1619                                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1620                                                NULL,
1621                                                "METER: Table meter profile add failed");
1622                                        return -1;
1623                                }
1624                        }
1625                        /* Meter policy must exist */
1626                        policy = softnic_mtr_meter_policy_find(softnic,
1627                                        m->params.meter_policy_id);
1628                        if (policy == NULL) {
1629                                rte_flow_error_set(error,
1630                                                EINVAL,
1631                                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1632                                                NULL,
1633                                                "METER: fail to find meter policy");
1634                                return -1;
1635                        }
1636                        /* RTE_TABLE_ACTION_METER */
1637                        rule_action->mtr.mtr[0].meter_profile_id = meter_profile_id;
1638                        rule_action->mtr.mtr[0].policer[RTE_COLOR_GREEN] =
1639                                policy->policer[RTE_COLOR_GREEN];
1640                        rule_action->mtr.mtr[0].policer[RTE_COLOR_YELLOW] =
1641                                policy->policer[RTE_COLOR_YELLOW];
1642                        rule_action->mtr.mtr[0].policer[RTE_COLOR_RED] =
1643                                policy->policer[RTE_COLOR_RED];
1644                        rule_action->mtr.tc_mask = 1;
1645                        rule_action->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
1646                        break;
1647                } /* RTE_FLOW_ACTION_TYPE_METER */
1648
1649                case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
1650                {
1651                        const struct rte_flow_action_vxlan_encap *conf =
1652                                action->conf;
1653                        const struct rte_flow_item *item;
1654                        union flow_item spec, mask;
1655                        int disabled = 0, status;
1656                        size_t size;
1657
1658                        if (conf == NULL)
1659                                return rte_flow_error_set(error,
1660                                        EINVAL,
1661                                        RTE_FLOW_ERROR_TYPE_ACTION,
1662                                        action,
1663                                        "VXLAN ENCAP: Null configuration");
1664
1665                        item = conf->definition;
1666                        if (item == NULL)
1667                                return rte_flow_error_set(error,
1668                                        EINVAL,
1669                                        RTE_FLOW_ERROR_TYPE_ACTION,
1670                                        action,
1671                                        "VXLAN ENCAP: Null configuration definition");
1672
1673                        if (!(params->action_mask &
1674                                        (1LLU << RTE_TABLE_ACTION_ENCAP)))
1675                                return rte_flow_error_set(error,
1676                                        EINVAL,
1677                                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1678                                        NULL,
1679                                        "VXLAN ENCAP: Encap action not enabled for this table");
1680
1681                        /* Check for Ether. */
1682                        flow_item_skip_void(&item);
1683                        status = flow_item_proto_preprocess(item, &spec, &mask,
1684                                &size, &disabled, error);
1685                        if (status)
1686                                return status;
1687
1688                        if (item->type != RTE_FLOW_ITEM_TYPE_ETH) {
1689                                return rte_flow_error_set(error,
1690                                        EINVAL,
1691                                        RTE_FLOW_ERROR_TYPE_ITEM,
1692                                        item,
1693                                        "VXLAN ENCAP: first encap item should be ether");
1694                        }
1695                        rte_ether_addr_copy(&spec.eth.dst,
1696                                        &rule_action->encap.vxlan.ether.da);
1697                        rte_ether_addr_copy(&spec.eth.src,
1698                                        &rule_action->encap.vxlan.ether.sa);
1699
1700                        item++;
1701
1702                        /* Check for VLAN. */
1703                        flow_item_skip_void(&item);
1704                        status = flow_item_proto_preprocess(item, &spec, &mask,
1705                                        &size, &disabled, error);
1706                        if (status)
1707                                return status;
1708
1709                        if (item->type == RTE_FLOW_ITEM_TYPE_VLAN) {
1710                                if (!params->encap.vxlan.vlan)
1711                                        return rte_flow_error_set(error,
1712                                                ENOTSUP,
1713                                                RTE_FLOW_ERROR_TYPE_ITEM,
1714                                                item,
1715                                                "VXLAN ENCAP: vlan encap not supported by table");
1716
1717                                uint16_t tci = rte_ntohs(spec.vlan.tci);
1718                                rule_action->encap.vxlan.vlan.pcp =
1719                                        tci >> 13;
1720                                rule_action->encap.vxlan.vlan.dei =
1721                                        (tci >> 12) & 0x1;
1722                                rule_action->encap.vxlan.vlan.vid =
1723                                        tci & 0xfff;
1724
1725                                item++;
1726
1727                                flow_item_skip_void(&item);
1728                                status = flow_item_proto_preprocess(item, &spec,
1729                                                &mask, &size, &disabled, error);
1730                                if (status)
1731                                        return status;
1732                        } else {
1733                                if (params->encap.vxlan.vlan)
1734                                        return rte_flow_error_set(error,
1735                                                ENOTSUP,
1736                                                RTE_FLOW_ERROR_TYPE_ITEM,
1737                                                item,
1738                                                "VXLAN ENCAP: expecting vlan encap item");
1739                        }
1740
1741                        /* Check for IPV4/IPV6. */
1742                        switch (item->type) {
1743                        case RTE_FLOW_ITEM_TYPE_IPV4:
1744                        {
1745                                rule_action->encap.vxlan.ipv4.sa =
1746                                        rte_ntohl(spec.ipv4.hdr.src_addr);
1747                                rule_action->encap.vxlan.ipv4.da =
1748                                        rte_ntohl(spec.ipv4.hdr.dst_addr);
1749                                rule_action->encap.vxlan.ipv4.dscp =
1750                                        spec.ipv4.hdr.type_of_service >> 2;
1751                                rule_action->encap.vxlan.ipv4.ttl =
1752                                        spec.ipv4.hdr.time_to_live;
1753                                break;
1754                        }
1755                        case RTE_FLOW_ITEM_TYPE_IPV6:
1756                        {
1757                                uint32_t vtc_flow;
1758
1759                                memcpy(&rule_action->encap.vxlan.ipv6.sa,
1760                                                &spec.ipv6.hdr.src_addr,
1761                                                sizeof(spec.ipv6.hdr.src_addr));
1762                                memcpy(&rule_action->encap.vxlan.ipv6.da,
1763                                                &spec.ipv6.hdr.dst_addr,
1764                                                sizeof(spec.ipv6.hdr.dst_addr));
1765                                vtc_flow = rte_ntohl(spec.ipv6.hdr.vtc_flow);
1766                                rule_action->encap.vxlan.ipv6.flow_label =
1767                                                vtc_flow & 0xfffff;
1768                                rule_action->encap.vxlan.ipv6.dscp =
1769                                                (vtc_flow >> 22) & 0x3f;
1770                                rule_action->encap.vxlan.ipv6.hop_limit =
1771                                        spec.ipv6.hdr.hop_limits;
1772                                break;
1773                        }
1774                        default:
1775                                return rte_flow_error_set(error,
1776                                        EINVAL,
1777                                        RTE_FLOW_ERROR_TYPE_ITEM,
1778                                        item,
1779                                        "VXLAN ENCAP: encap item after ether should be ipv4/ipv6");
1780                        }
1781
1782                        item++;
1783
1784                        /* Check for UDP. */
1785                        flow_item_skip_void(&item);
1786                        status = flow_item_proto_preprocess(item, &spec, &mask,
1787                                        &size, &disabled, error);
1788                        if (status)
1789                                return status;
1790
1791                        if (item->type != RTE_FLOW_ITEM_TYPE_UDP) {
1792                                return rte_flow_error_set(error,
1793                                        EINVAL,
1794                                        RTE_FLOW_ERROR_TYPE_ITEM,
1795                                        item,
1796                                        "VXLAN ENCAP: encap item after ipv4/ipv6 should be udp");
1797                        }
1798                        rule_action->encap.vxlan.udp.sp =
1799                                rte_ntohs(spec.udp.hdr.src_port);
1800                        rule_action->encap.vxlan.udp.dp =
1801                                rte_ntohs(spec.udp.hdr.dst_port);
1802
1803                        item++;
1804
1805                        /* Check for VXLAN. */
1806                        flow_item_skip_void(&item);
1807                        status = flow_item_proto_preprocess(item, &spec, &mask,
1808                                        &size, &disabled, error);
1809                        if (status)
1810                                return status;
1811
1812                        if (item->type != RTE_FLOW_ITEM_TYPE_VXLAN) {
1813                                return rte_flow_error_set(error,
1814                                        EINVAL,
1815                                        RTE_FLOW_ERROR_TYPE_ITEM,
1816                                        item,
1817                                        "VXLAN ENCAP: encap item after udp should be vxlan");
1818                        }
1819                        rule_action->encap.vxlan.vxlan.vni =
1820                                (spec.vxlan.vni[0] << 16U |
1821                                        spec.vxlan.vni[1] << 8U
1822                                        | spec.vxlan.vni[2]);
1823
1824                        item++;
1825
1826                        /* Check for END. */
1827                        flow_item_skip_void(&item);
1828
1829                        if (item->type != RTE_FLOW_ITEM_TYPE_END)
1830                                return rte_flow_error_set(error,
1831                                        EINVAL,
1832                                        RTE_FLOW_ERROR_TYPE_ITEM,
1833                                        item,
1834                                        "VXLAN ENCAP: expecting END item");
1835
1836                        rule_action->encap.type = RTE_TABLE_ACTION_ENCAP_VXLAN;
1837                        rule_action->action_mask |= 1 << RTE_TABLE_ACTION_ENCAP;
1838                        break;
1839                } /* RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP */
1840
1841                default:
1842                        return -ENOTSUP;
1843                }
1844        }
1845
1846        if (n_jump_queue_rss_drop == 0)
1847                return rte_flow_error_set(error,
1848                        EINVAL,
1849                        RTE_FLOW_ERROR_TYPE_ACTION,
1850                        action,
1851                        "Flow does not have any terminating action");
1852
1853        return 0;
1854}
1855
1856static int
1857pmd_flow_validate(struct rte_eth_dev *dev,
1858                const struct rte_flow_attr *attr,
1859                const struct rte_flow_item item[],
1860                const struct rte_flow_action action[],
1861                struct rte_flow_error *error)
1862{
1863        struct softnic_table_rule_match rule_match;
1864        struct softnic_table_rule_action rule_action;
1865
1866        struct pmd_internals *softnic = dev->data->dev_private;
1867        struct pipeline *pipeline;
1868        struct softnic_table *table;
1869        const char *pipeline_name = NULL;
1870        uint32_t table_id = 0;
1871        int status;
1872
1873        /* Check input parameters. */
1874        if (attr == NULL)
1875                return rte_flow_error_set(error,
1876                                EINVAL,
1877                                RTE_FLOW_ERROR_TYPE_ATTR,
1878                                NULL, "Null attr");
1879
1880        if (item == NULL)
1881                return rte_flow_error_set(error,
1882                                EINVAL,
1883                                RTE_FLOW_ERROR_TYPE_ITEM,
1884                                NULL,
1885                                "Null item");
1886
1887        if (action == NULL)
1888                return rte_flow_error_set(error,
1889                                EINVAL,
1890                                RTE_FLOW_ERROR_TYPE_ACTION,
1891                                NULL,
1892                                "Null action");
1893
1894        /* Identify the pipeline table to add this flow to. */
1895        status = flow_pipeline_table_get(softnic, attr, &pipeline_name,
1896                                        &table_id, error);
1897        if (status)
1898                return status;
1899
1900        pipeline = softnic_pipeline_find(softnic, pipeline_name);
1901        if (pipeline == NULL)
1902                return rte_flow_error_set(error,
1903                                EINVAL,
1904                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1905                                NULL,
1906                                "Invalid pipeline name");
1907
1908        if (table_id >= pipeline->n_tables)
1909                return rte_flow_error_set(error,
1910                                EINVAL,
1911                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1912                                NULL,
1913                                "Invalid pipeline table ID");
1914
1915        table = &pipeline->table[table_id];
1916
1917        /* Rule match. */
1918        memset(&rule_match, 0, sizeof(rule_match));
1919        status = flow_rule_match_get(softnic,
1920                        pipeline,
1921                        table,
1922                        attr,
1923                        item,
1924                        &rule_match,
1925                        error);
1926        if (status)
1927                return status;
1928
1929        /* Rule action. */
1930        memset(&rule_action, 0, sizeof(rule_action));
1931        status = flow_rule_action_get(softnic,
1932                pipeline,
1933                table,
1934                attr,
1935                action,
1936                &rule_action,
1937                error);
1938        if (status)
1939                return status;
1940
1941        return 0;
1942}
1943
1944static struct softnic_mtr *
1945flow_action_meter_get(struct pmd_internals *softnic,
1946        const struct rte_flow_action *action)
1947{
1948        for ( ; action->type != RTE_FLOW_ACTION_TYPE_END; action++)
1949                if (action->type == RTE_FLOW_ACTION_TYPE_METER) {
1950                        const struct rte_flow_action_meter *conf = action->conf;
1951
1952                        if (conf == NULL)
1953                                return NULL;
1954
1955                        return softnic_mtr_find(softnic, conf->mtr_id);
1956                }
1957
1958        return NULL;
1959}
1960
1961static void
1962flow_meter_owner_reset(struct pmd_internals *softnic,
1963        struct rte_flow *flow)
1964{
1965        struct softnic_mtr_list *ml = &softnic->mtr.mtrs;
1966        struct softnic_mtr *m;
1967
1968        TAILQ_FOREACH(m, ml, node)
1969                if (m->flow == flow) {
1970                        m->flow = NULL;
1971                        break;
1972                }
1973}
1974
1975static void
1976flow_meter_owner_set(struct pmd_internals *softnic,
1977        struct rte_flow *flow,
1978        struct softnic_mtr *mtr)
1979{
1980        /* Reset current flow meter  */
1981        flow_meter_owner_reset(softnic, flow);
1982
1983        /* Set new flow meter */
1984        mtr->flow = flow;
1985}
1986
1987static int
1988is_meter_action_enable(struct pmd_internals *softnic,
1989        struct softnic_table *table)
1990{
1991        struct softnic_table_action_profile *profile =
1992                softnic_table_action_profile_find(softnic,
1993                        table->params.action_profile_name);
1994        struct softnic_table_action_profile_params *params = &profile->params;
1995
1996        return (params->action_mask & (1LLU << RTE_TABLE_ACTION_MTR)) ? 1 : 0;
1997}
1998
1999static struct rte_flow *
2000pmd_flow_create(struct rte_eth_dev *dev,
2001        const struct rte_flow_attr *attr,
2002        const struct rte_flow_item item[],
2003        const struct rte_flow_action action[],
2004        struct rte_flow_error *error)
2005{
2006        struct softnic_table_rule_match rule_match;
2007        struct softnic_table_rule_action rule_action;
2008        void *rule_data;
2009
2010        struct pmd_internals *softnic = dev->data->dev_private;
2011        struct pipeline *pipeline;
2012        struct softnic_table *table;
2013        struct rte_flow *flow;
2014        struct softnic_mtr *mtr;
2015        const char *pipeline_name = NULL;
2016        uint32_t table_id = 0;
2017        int new_flow, status;
2018
2019        /* Check input parameters. */
2020        if (attr == NULL) {
2021                rte_flow_error_set(error,
2022                        EINVAL,
2023                        RTE_FLOW_ERROR_TYPE_ATTR,
2024                        NULL,
2025                        "Null attr");
2026                return NULL;
2027        }
2028
2029        if (item == NULL) {
2030                rte_flow_error_set(error,
2031                        EINVAL,
2032                        RTE_FLOW_ERROR_TYPE_ITEM,
2033                        NULL,
2034                        "Null item");
2035                return NULL;
2036        }
2037
2038        if (action == NULL) {
2039                rte_flow_error_set(error,
2040                        EINVAL,
2041                        RTE_FLOW_ERROR_TYPE_ACTION,
2042                        NULL,
2043                        "Null action");
2044                return NULL;
2045        }
2046
2047        /* Identify the pipeline table to add this flow to. */
2048        status = flow_pipeline_table_get(softnic, attr, &pipeline_name,
2049                                        &table_id, error);
2050        if (status)
2051                return NULL;
2052
2053        pipeline = softnic_pipeline_find(softnic, pipeline_name);
2054        if (pipeline == NULL) {
2055                rte_flow_error_set(error,
2056                        EINVAL,
2057                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2058                        NULL,
2059                        "Invalid pipeline name");
2060                return NULL;
2061        }
2062
2063        if (table_id >= pipeline->n_tables) {
2064                rte_flow_error_set(error,
2065                        EINVAL,
2066                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2067                        NULL,
2068                        "Invalid pipeline table ID");
2069                return NULL;
2070        }
2071
2072        table = &pipeline->table[table_id];
2073
2074        /* Rule match. */
2075        memset(&rule_match, 0, sizeof(rule_match));
2076        status = flow_rule_match_get(softnic,
2077                pipeline,
2078                table,
2079                attr,
2080                item,
2081                &rule_match,
2082                error);
2083        if (status)
2084                return NULL;
2085
2086        /* Rule action. */
2087        memset(&rule_action, 0, sizeof(rule_action));
2088        status = flow_rule_action_get(softnic,
2089                pipeline,
2090                table,
2091                attr,
2092                action,
2093                &rule_action,
2094                error);
2095        if (status)
2096                return NULL;
2097
2098        /* Flow find/allocate. */
2099        new_flow = 0;
2100        flow = softnic_flow_find(table, &rule_match);
2101        if (flow == NULL) {
2102                new_flow = 1;
2103                flow = calloc(1, sizeof(struct rte_flow));
2104                if (flow == NULL) {
2105                        rte_flow_error_set(error,
2106                                ENOMEM,
2107                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2108                                NULL,
2109                                "Not enough memory for new flow");
2110                        return NULL;
2111                }
2112        }
2113
2114        /* Rule add. */
2115        status = softnic_pipeline_table_rule_add(softnic,
2116                pipeline_name,
2117                table_id,
2118                &rule_match,
2119                &rule_action,
2120                &rule_data);
2121        if (status) {
2122                if (new_flow)
2123                        free(flow);
2124
2125                rte_flow_error_set(error,
2126                        EINVAL,
2127                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2128                        NULL,
2129                        "Pipeline table rule add failed");
2130                return NULL;
2131        }
2132
2133        /* Flow fill in. */
2134        memcpy(&flow->match, &rule_match, sizeof(rule_match));
2135        memcpy(&flow->action, &rule_action, sizeof(rule_action));
2136        flow->data = rule_data;
2137        flow->pipeline = pipeline;
2138        flow->table_id = table_id;
2139
2140        mtr = flow_action_meter_get(softnic, action);
2141        if (mtr)
2142                flow_meter_owner_set(softnic, flow, mtr);
2143
2144        /* Flow add to list. */
2145        if (new_flow)
2146                TAILQ_INSERT_TAIL(&table->flows, flow, node);
2147
2148        return flow;
2149}
2150
2151static int
2152pmd_flow_destroy(struct rte_eth_dev *dev,
2153        struct rte_flow *flow,
2154        struct rte_flow_error *error)
2155{
2156        struct pmd_internals *softnic = dev->data->dev_private;
2157        struct softnic_table *table;
2158        int status;
2159
2160        /* Check input parameters. */
2161        if (flow == NULL)
2162                return rte_flow_error_set(error,
2163                        EINVAL,
2164                        RTE_FLOW_ERROR_TYPE_HANDLE,
2165                        NULL,
2166                        "Null flow");
2167
2168        table = &flow->pipeline->table[flow->table_id];
2169
2170        /* Rule delete. */
2171        status = softnic_pipeline_table_rule_delete(softnic,
2172                flow->pipeline->name,
2173                flow->table_id,
2174                &flow->match);
2175        if (status)
2176                return rte_flow_error_set(error,
2177                        EINVAL,
2178                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2179                        NULL,
2180                        "Pipeline table rule delete failed");
2181
2182        /* Update dependencies */
2183        if (is_meter_action_enable(softnic, table))
2184                flow_meter_owner_reset(softnic, flow);
2185
2186        /* Flow delete. */
2187        TAILQ_REMOVE(&table->flows, flow, node);
2188        free(flow);
2189
2190        return 0;
2191}
2192
2193static int
2194pmd_flow_flush(struct rte_eth_dev *dev,
2195        struct rte_flow_error *error)
2196{
2197        struct pmd_internals *softnic = dev->data->dev_private;
2198        struct pipeline *pipeline;
2199        int fail_to_del_rule = 0;
2200        uint32_t i;
2201
2202        TAILQ_FOREACH(pipeline, &softnic->pipeline_list, node) {
2203                /* Remove all the flows added to the tables. */
2204                for (i = 0; i < pipeline->n_tables; i++) {
2205                        struct softnic_table *table = &pipeline->table[i];
2206                        struct rte_flow *flow;
2207                        void *temp;
2208                        int status;
2209
2210                        TAILQ_FOREACH_SAFE(flow, &table->flows, node, temp) {
2211                                /* Rule delete. */
2212                                status = softnic_pipeline_table_rule_delete
2213                                                (softnic,
2214                                                pipeline->name,
2215                                                i,
2216                                                &flow->match);
2217                                if (status)
2218                                        fail_to_del_rule = 1;
2219                                /* Update dependencies */
2220                                if (is_meter_action_enable(softnic, table))
2221                                        flow_meter_owner_reset(softnic, flow);
2222
2223                                /* Flow delete. */
2224                                TAILQ_REMOVE(&table->flows, flow, node);
2225                                free(flow);
2226                        }
2227                }
2228        }
2229
2230        if (fail_to_del_rule)
2231                return rte_flow_error_set(error,
2232                        EINVAL,
2233                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2234                        NULL,
2235                        "Some of the rules could not be deleted");
2236
2237        return 0;
2238}
2239
2240static int
2241pmd_flow_query(struct rte_eth_dev *dev __rte_unused,
2242        struct rte_flow *flow,
2243        const struct rte_flow_action *action __rte_unused,
2244        void *data,
2245        struct rte_flow_error *error)
2246{
2247        struct rte_table_action_stats_counters stats;
2248        struct softnic_table *table;
2249        struct rte_flow_query_count *flow_stats = data;
2250        int status;
2251
2252        /* Check input parameters. */
2253        if (flow == NULL)
2254                return rte_flow_error_set(error,
2255                        EINVAL,
2256                        RTE_FLOW_ERROR_TYPE_HANDLE,
2257                        NULL,
2258                        "Null flow");
2259
2260        if (data == NULL)
2261                return rte_flow_error_set(error,
2262                        EINVAL,
2263                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2264                        NULL,
2265                        "Null data");
2266
2267        table = &flow->pipeline->table[flow->table_id];
2268
2269        /* Rule stats read. */
2270        status = rte_table_action_stats_read(table->a,
2271                flow->data,
2272                &stats,
2273                flow_stats->reset);
2274        if (status)
2275                return rte_flow_error_set(error,
2276                        EINVAL,
2277                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2278                        NULL,
2279                        "Pipeline table rule stats read failed");
2280
2281        /* Fill in flow stats. */
2282        flow_stats->hits_set =
2283                (table->ap->params.stats.n_packets_enabled) ? 1 : 0;
2284        flow_stats->bytes_set =
2285                (table->ap->params.stats.n_bytes_enabled) ? 1 : 0;
2286        flow_stats->hits = stats.n_packets;
2287        flow_stats->bytes = stats.n_bytes;
2288
2289        return 0;
2290}
2291
2292const struct rte_flow_ops pmd_flow_ops = {
2293        .validate = pmd_flow_validate,
2294        .create = pmd_flow_create,
2295        .destroy = pmd_flow_destroy,
2296        .flush = pmd_flow_flush,
2297        .query = pmd_flow_query,
2298        .isolate = NULL,
2299};
2300