LCOV - code coverage report
Current view: top level - drivers/net/enic - enic_fm_flow.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 1489 0.0 %
Date: 2024-12-01 18:57:19 Functions: 0 71 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 791 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright 2008-2019 Cisco Systems, Inc.  All rights reserved.
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <errno.h>
       6                 :            : #include <stdint.h>
       7                 :            : #include <rte_log.h>
       8                 :            : #include <ethdev_driver.h>
       9                 :            : #include <rte_flow_driver.h>
      10                 :            : #include <rte_ether.h>
      11                 :            : #include <rte_geneve.h>
      12                 :            : #include <rte_hash.h>
      13                 :            : #include <rte_jhash.h>
      14                 :            : #include <rte_ip.h>
      15                 :            : #include <rte_udp.h>
      16                 :            : #include <rte_memzone.h>
      17                 :            : 
      18                 :            : #include "enic_compat.h"
      19                 :            : #include "enic.h"
      20                 :            : #include "vnic_dev.h"
      21                 :            : #include "vnic_nic.h"
      22                 :            : 
      23                 :            : #define IP_DEFTTL  64   /* from RFC 1340. */
      24                 :            : #define IP6_VTC_FLOW 0x60000000
      25                 :            : 
      26                 :            : /* Up to 1024 TCAM entries */
      27                 :            : #define FM_MAX_TCAM_TABLE_SIZE 1024
      28                 :            : 
      29                 :            : /* Up to 4096 entries per exact match table */
      30                 :            : #define FM_MAX_EXACT_TABLE_SIZE 4096
      31                 :            : 
      32                 :            : /* Number of counters to increase on for each increment */
      33                 :            : #define FM_COUNTERS_EXPAND  100
      34                 :            : 
      35                 :            : #define FM_INVALID_HANDLE 0
      36                 :            : 
      37                 :            : /* Low priority used for implicit VF -> representor flow */
      38                 :            : #define FM_LOWEST_PRIORITY 100000
      39                 :            : 
      40                 :            : /* High priority used for implicit representor -> VF flow */
      41                 :            : #define FM_HIGHEST_PRIORITY 0
      42                 :            : 
      43                 :            : /* Tag used for implicit VF <-> representor flows */
      44                 :            : #define FM_VF_REP_TAG 1
      45                 :            : 
      46                 :            : /* Max number of actions supported by VIC is 2K. Make hash table double that. */
      47                 :            : #define FM_MAX_ACTION_TABLE_SIZE 4096
      48                 :            : 
      49                 :            : /*
      50                 :            :  * Flow exact match tables (FET) in the VIC and rte_flow groups.
      51                 :            :  * Use a simple scheme to map groups to tables.
      52                 :            :  * Group 0 uses the single TCAM tables, one for each direction.
      53                 :            :  * Group 1, 2, ... uses its own exact match table.
      54                 :            :  *
      55                 :            :  * The TCAM tables are allocated upfront during init.
      56                 :            :  *
      57                 :            :  * Exact match tables are allocated on demand. 3 paths that lead allocations.
      58                 :            :  *
      59                 :            :  * 1. Add a flow that jumps from group 0 to group N.
      60                 :            :  *
      61                 :            :  * If N does not exist, we allocate an exact match table for it, using
      62                 :            :  * a dummy key. A key is required for the table.
      63                 :            :  *
      64                 :            :  * 2. Add a flow that uses group N.
      65                 :            :  *
      66                 :            :  * If N does not exist, we allocate an exact match table for it, using
      67                 :            :  * the flow's key. Subsequent flows to the same group all should have
      68                 :            :  * the same key.
      69                 :            :  *
      70                 :            :  * Without a jump flow to N, N is not reachable in hardware. No packets
      71                 :            :  * reach N and match.
      72                 :            :  *
      73                 :            :  * 3. Add a flow to an empty group N.
      74                 :            :  *
      75                 :            :  * N has been created via (1) and the dummy key. We free that table, allocate
      76                 :            :  * a new table using the new flow's key. Also re-do the existing jump flow to
      77                 :            :  * point to the new table.
      78                 :            :  */
      79                 :            : #define FM_TCAM_RTE_GROUP 0
      80                 :            : 
      81                 :            : struct enic_fm_fet {
      82                 :            :         TAILQ_ENTRY(enic_fm_fet) list;
      83                 :            :         uint32_t group; /* rte_flow group ID */
      84                 :            :         uint64_t handle; /* Exact match table handle from flowman */
      85                 :            :         uint8_t ingress;
      86                 :            :         uint8_t default_key;
      87                 :            :         int ref; /* Reference count via get/put */
      88                 :            :         struct fm_key_template key; /* Key associated with the table */
      89                 :            : };
      90                 :            : 
      91                 :            : struct enic_fm_counter {
      92                 :            :         SLIST_ENTRY(enic_fm_counter) next;
      93                 :            :         uint32_t handle;
      94                 :            : };
      95                 :            : 
      96                 :            : struct enic_fm_action {
      97                 :            :         int ref;
      98                 :            :         uint64_t handle;
      99                 :            :         struct fm_action key;
     100                 :            : };
     101                 :            : 
     102                 :            : /* rte_flow.fm */
     103                 :            : struct enic_fm_flow {
     104                 :            :         bool counter_valid;
     105                 :            :         uint64_t entry_handle;
     106                 :            :         struct enic_fm_action  *action;
     107                 :            :         struct enic_fm_counter *counter;
     108                 :            :         struct enic_fm_fet *fet;
     109                 :            :         /* Auto-added steer action for hairpin flows (e.g. vnic->vnic) */
     110                 :            :         struct enic_fm_flow *hairpin_steer_flow;
     111                 :            : };
     112                 :            : 
     113                 :            : struct enic_fm_jump_flow {
     114                 :            :         TAILQ_ENTRY(enic_fm_jump_flow) list;
     115                 :            :         struct rte_flow *flow;
     116                 :            :         uint32_t group;
     117                 :            :         struct fm_tcam_match_entry match;
     118                 :            :         struct fm_action action;
     119                 :            : };
     120                 :            : 
     121                 :            : /*
     122                 :            :  * Flowman uses host memory for commands. This structure is allocated
     123                 :            :  * in DMA-able memory.
     124                 :            :  */
     125                 :            : union enic_flowman_cmd_mem {
     126                 :            :         struct fm_tcam_match_table fm_tcam_match_table;
     127                 :            :         struct fm_exact_match_table fm_exact_match_table;
     128                 :            :         struct fm_tcam_match_entry fm_tcam_match_entry;
     129                 :            :         struct fm_exact_match_entry fm_exact_match_entry;
     130                 :            :         struct fm_action fm_action;
     131                 :            : };
     132                 :            : 
     133                 :            : /*
     134                 :            :  * PF has a flowman instance, and VF representors share it with PF.
     135                 :            :  * PF allocates this structure and owns it. VF representors borrow
     136                 :            :  * the PF's structure during API calls (e.g. create, query).
     137                 :            :  */
     138                 :            : struct enic_flowman {
     139                 :            :         struct enic *owner_enic; /* PF */
     140                 :            :         struct enic *user_enic;  /* API caller (PF or representor) */
     141                 :            :         /*
     142                 :            :          * Representors and PF share the same underlying flowman.
     143                 :            :          * Lock API calls to serialize accesses from them. Only used
     144                 :            :          * when VF representors are present.
     145                 :            :          */
     146                 :            :         rte_spinlock_t lock;
     147                 :            :         /* Command buffer */
     148                 :            :         struct {
     149                 :            :                 union enic_flowman_cmd_mem *va;
     150                 :            :                 dma_addr_t pa;
     151                 :            :         } cmd;
     152                 :            :         /* TCAM tables allocated upfront, used for group 0 */
     153                 :            :         uint64_t ig_tcam_hndl;
     154                 :            :         uint64_t eg_tcam_hndl;
     155                 :            :         /* Counters */
     156                 :            :         SLIST_HEAD(enic_free_counters, enic_fm_counter) counters;
     157                 :            :         void *counter_stack;
     158                 :            :         uint32_t counters_alloced;
     159                 :            :         /* Exact match tables for groups != 0, dynamically allocated */
     160                 :            :         TAILQ_HEAD(fet_list, enic_fm_fet) fet_list;
     161                 :            :         /*
     162                 :            :          * Default exact match tables used for jump actions to
     163                 :            :          * non-existent groups.
     164                 :            :          */
     165                 :            :         struct enic_fm_fet *default_eg_fet;
     166                 :            :         struct enic_fm_fet *default_ig_fet;
     167                 :            :         /* hash table for Action reuse */
     168                 :            :         struct rte_hash *action_hash;
     169                 :            :         /* Flows that jump to the default table above */
     170                 :            :         TAILQ_HEAD(jump_flow_list, enic_fm_jump_flow) jump_list;
     171                 :            :         /*
     172                 :            :          * Scratch data used during each invocation of flow_create
     173                 :            :          * and flow_validate.
     174                 :            :          */
     175                 :            :         struct enic_fm_fet *fet;
     176                 :            :         struct fm_tcam_match_entry tcam_entry;
     177                 :            :         struct fm_action action;
     178                 :            :         struct fm_action action_tmp; /* enic_fm_reorder_action_op */
     179                 :            :         int action_op_count;
     180                 :            :         /* Tags used for representor flows */
     181                 :            :         uint8_t vf_rep_tag;
     182                 :            :         /* For auto-added steer action for hairpin */
     183                 :            :         int need_hairpin_steer;
     184                 :            :         uint64_t hairpin_steer_vnic_h;
     185                 :            : };
     186                 :            : 
     187                 :            : static int enic_fm_tbl_free(struct enic_flowman *fm, uint64_t handle);
     188                 :            : /*
     189                 :            :  * API functions (create, destroy, validate, flush) call begin_fm()
     190                 :            :  * upon entering to save the caller enic (PF or VF representor) and
     191                 :            :  * lock. Upon exit, they call end_fm() to unlock.
     192                 :            :  */
     193                 :            : static struct enic_flowman *begin_fm(struct enic *enic);
     194                 :            : static void end_fm(struct enic_flowman *fm);
     195                 :            : /* Delete internal flows created for representor paths */
     196                 :            : static void delete_rep_flows(struct enic *enic);
     197                 :            : 
     198                 :            : /*
     199                 :            :  * Common arguments passed to copy_item functions. Use this structure
     200                 :            :  * so we can easily add new arguments.
     201                 :            :  * item: Item specification.
     202                 :            :  * fm_tcam_entry: Flowman TCAM match entry.
     203                 :            :  * header_level: 0 for outer header, 1 for inner header.
     204                 :            :  */
     205                 :            : struct copy_item_args {
     206                 :            :         const struct rte_flow_item *item;
     207                 :            :         struct fm_tcam_match_entry *fm_tcam_entry;
     208                 :            :         uint8_t header_level;
     209                 :            :         struct rte_flow_error *error;
     210                 :            : };
     211                 :            : 
     212                 :            : /* functions for copying items into flowman match */
     213                 :            : typedef int (enic_copy_item_fn)(struct copy_item_args *arg);
     214                 :            : 
     215                 :            : /* Info about how to copy items into flowman match */
     216                 :            : struct enic_fm_items {
     217                 :            :         /* Function for copying and validating an item. */
     218                 :            :         enic_copy_item_fn * const copy_item;
     219                 :            :         /* List of valid previous items. */
     220                 :            :         const enum rte_flow_item_type * const prev_items;
     221                 :            :         /*
     222                 :            :          * True if it's OK for this item to be the first item. For some NIC
     223                 :            :          * versions, it's invalid to start the stack above layer 3.
     224                 :            :          */
     225                 :            :         const uint8_t valid_start_item;
     226                 :            : };
     227                 :            : 
     228                 :            : static enic_copy_item_fn enic_fm_copy_item_eth;
     229                 :            : static enic_copy_item_fn enic_fm_copy_item_ipv4;
     230                 :            : static enic_copy_item_fn enic_fm_copy_item_ipv6;
     231                 :            : static enic_copy_item_fn enic_fm_copy_item_raw;
     232                 :            : static enic_copy_item_fn enic_fm_copy_item_sctp;
     233                 :            : static enic_copy_item_fn enic_fm_copy_item_tcp;
     234                 :            : static enic_copy_item_fn enic_fm_copy_item_udp;
     235                 :            : static enic_copy_item_fn enic_fm_copy_item_vlan;
     236                 :            : static enic_copy_item_fn enic_fm_copy_item_vxlan;
     237                 :            : static enic_copy_item_fn enic_fm_copy_item_gtp;
     238                 :            : static enic_copy_item_fn enic_fm_copy_item_geneve;
     239                 :            : static enic_copy_item_fn enic_fm_copy_item_geneve_opt;
     240                 :            : static enic_copy_item_fn enic_fm_copy_item_ecpri;
     241                 :            : 
     242                 :            : /* Ingress actions */
     243                 :            : static const enum rte_flow_action_type enic_fm_supported_ig_actions[] = {
     244                 :            :         RTE_FLOW_ACTION_TYPE_COUNT,
     245                 :            :         RTE_FLOW_ACTION_TYPE_DROP,
     246                 :            :         RTE_FLOW_ACTION_TYPE_FLAG,
     247                 :            :         RTE_FLOW_ACTION_TYPE_JUMP,
     248                 :            :         RTE_FLOW_ACTION_TYPE_MARK,
     249                 :            :         RTE_FLOW_ACTION_TYPE_OF_POP_VLAN,
     250                 :            :         RTE_FLOW_ACTION_TYPE_PORT_ID,
     251                 :            :         RTE_FLOW_ACTION_TYPE_PASSTHRU,
     252                 :            :         RTE_FLOW_ACTION_TYPE_QUEUE,
     253                 :            :         RTE_FLOW_ACTION_TYPE_RSS,
     254                 :            :         RTE_FLOW_ACTION_TYPE_VOID,
     255                 :            :         RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP,
     256                 :            :         RTE_FLOW_ACTION_TYPE_VXLAN_DECAP,
     257                 :            :         RTE_FLOW_ACTION_TYPE_END, /* END must be the last entry */
     258                 :            : };
     259                 :            : 
     260                 :            : /* Egress actions */
     261                 :            : static const enum rte_flow_action_type enic_fm_supported_eg_actions[] = {
     262                 :            :         RTE_FLOW_ACTION_TYPE_COUNT,
     263                 :            :         RTE_FLOW_ACTION_TYPE_DROP,
     264                 :            :         RTE_FLOW_ACTION_TYPE_JUMP,
     265                 :            :         RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN,
     266                 :            :         RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP,
     267                 :            :         RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID,
     268                 :            :         RTE_FLOW_ACTION_TYPE_PORT_ID,
     269                 :            :         RTE_FLOW_ACTION_TYPE_PASSTHRU,
     270                 :            :         RTE_FLOW_ACTION_TYPE_VOID,
     271                 :            :         RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP,
     272                 :            :         RTE_FLOW_ACTION_TYPE_END,
     273                 :            : };
     274                 :            : 
     275                 :            : static const struct enic_fm_items enic_fm_items[] = {
     276                 :            :         [RTE_FLOW_ITEM_TYPE_RAW] = {
     277                 :            :                 .copy_item = enic_fm_copy_item_raw,
     278                 :            :                 .valid_start_item = 0,
     279                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     280                 :            :                                RTE_FLOW_ITEM_TYPE_UDP,
     281                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     282                 :            :                 },
     283                 :            :         },
     284                 :            :         [RTE_FLOW_ITEM_TYPE_ETH] = {
     285                 :            :                 .copy_item = enic_fm_copy_item_eth,
     286                 :            :                 .valid_start_item = 1,
     287                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     288                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     289                 :            :                 },
     290                 :            :         },
     291                 :            :         [RTE_FLOW_ITEM_TYPE_VLAN] = {
     292                 :            :                 .copy_item = enic_fm_copy_item_vlan,
     293                 :            :                 .valid_start_item = 1,
     294                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     295                 :            :                                RTE_FLOW_ITEM_TYPE_ETH,
     296                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     297                 :            :                 },
     298                 :            :         },
     299                 :            :         [RTE_FLOW_ITEM_TYPE_IPV4] = {
     300                 :            :                 .copy_item = enic_fm_copy_item_ipv4,
     301                 :            :                 .valid_start_item = 1,
     302                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     303                 :            :                                RTE_FLOW_ITEM_TYPE_ETH,
     304                 :            :                                RTE_FLOW_ITEM_TYPE_VLAN,
     305                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     306                 :            :                 },
     307                 :            :         },
     308                 :            :         [RTE_FLOW_ITEM_TYPE_IPV6] = {
     309                 :            :                 .copy_item = enic_fm_copy_item_ipv6,
     310                 :            :                 .valid_start_item = 1,
     311                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     312                 :            :                                RTE_FLOW_ITEM_TYPE_ETH,
     313                 :            :                                RTE_FLOW_ITEM_TYPE_VLAN,
     314                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     315                 :            :                 },
     316                 :            :         },
     317                 :            :         [RTE_FLOW_ITEM_TYPE_UDP] = {
     318                 :            :                 .copy_item = enic_fm_copy_item_udp,
     319                 :            :                 .valid_start_item = 1,
     320                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     321                 :            :                                RTE_FLOW_ITEM_TYPE_IPV4,
     322                 :            :                                RTE_FLOW_ITEM_TYPE_IPV6,
     323                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     324                 :            :                 },
     325                 :            :         },
     326                 :            :         [RTE_FLOW_ITEM_TYPE_TCP] = {
     327                 :            :                 .copy_item = enic_fm_copy_item_tcp,
     328                 :            :                 .valid_start_item = 1,
     329                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     330                 :            :                                RTE_FLOW_ITEM_TYPE_IPV4,
     331                 :            :                                RTE_FLOW_ITEM_TYPE_IPV6,
     332                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     333                 :            :                 },
     334                 :            :         },
     335                 :            :         [RTE_FLOW_ITEM_TYPE_SCTP] = {
     336                 :            :                 .copy_item = enic_fm_copy_item_sctp,
     337                 :            :                 .valid_start_item = 0,
     338                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     339                 :            :                                RTE_FLOW_ITEM_TYPE_IPV4,
     340                 :            :                                RTE_FLOW_ITEM_TYPE_IPV6,
     341                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     342                 :            :                 },
     343                 :            :         },
     344                 :            :         [RTE_FLOW_ITEM_TYPE_VXLAN] = {
     345                 :            :                 .copy_item = enic_fm_copy_item_vxlan,
     346                 :            :                 .valid_start_item = 1,
     347                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     348                 :            :                                RTE_FLOW_ITEM_TYPE_UDP,
     349                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     350                 :            :                 },
     351                 :            :         },
     352                 :            :         [RTE_FLOW_ITEM_TYPE_GTP] = {
     353                 :            :                 .copy_item = enic_fm_copy_item_gtp,
     354                 :            :                 .valid_start_item = 0,
     355                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     356                 :            :                                RTE_FLOW_ITEM_TYPE_UDP,
     357                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     358                 :            :                 },
     359                 :            :         },
     360                 :            :         [RTE_FLOW_ITEM_TYPE_GTPC] = {
     361                 :            :                 .copy_item = enic_fm_copy_item_gtp,
     362                 :            :                 .valid_start_item = 1,
     363                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     364                 :            :                                RTE_FLOW_ITEM_TYPE_UDP,
     365                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     366                 :            :                 },
     367                 :            :         },
     368                 :            :         [RTE_FLOW_ITEM_TYPE_GTPU] = {
     369                 :            :                 .copy_item = enic_fm_copy_item_gtp,
     370                 :            :                 .valid_start_item = 1,
     371                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     372                 :            :                                RTE_FLOW_ITEM_TYPE_UDP,
     373                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     374                 :            :                 },
     375                 :            :         },
     376                 :            :         [RTE_FLOW_ITEM_TYPE_GENEVE] = {
     377                 :            :                 .copy_item = enic_fm_copy_item_geneve,
     378                 :            :                 .valid_start_item = 1,
     379                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     380                 :            :                                RTE_FLOW_ITEM_TYPE_ETH,
     381                 :            :                                RTE_FLOW_ITEM_TYPE_IPV4,
     382                 :            :                                RTE_FLOW_ITEM_TYPE_IPV6,
     383                 :            :                                RTE_FLOW_ITEM_TYPE_UDP,
     384                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     385                 :            :                 },
     386                 :            :         },
     387                 :            :         [RTE_FLOW_ITEM_TYPE_GENEVE_OPT] = {
     388                 :            :                 .copy_item = enic_fm_copy_item_geneve_opt,
     389                 :            :                 .valid_start_item = 1,
     390                 :            :                 /* Can match at most 1 option */
     391                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     392                 :            :                                RTE_FLOW_ITEM_TYPE_GENEVE,
     393                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     394                 :            :                 },
     395                 :            :         },
     396                 :            :         [RTE_FLOW_ITEM_TYPE_ECPRI] = {
     397                 :            :                 .copy_item = enic_fm_copy_item_ecpri,
     398                 :            :                 .valid_start_item = 1,
     399                 :            :                 .prev_items = (const enum rte_flow_item_type[]) {
     400                 :            :                                RTE_FLOW_ITEM_TYPE_ETH,
     401                 :            :                                RTE_FLOW_ITEM_TYPE_UDP,
     402                 :            :                                RTE_FLOW_ITEM_TYPE_END,
     403                 :            :                 },
     404                 :            :         },
     405                 :            : };
     406                 :            : 
     407                 :            : static int
     408                 :          0 : enic_fm_copy_item_eth(struct copy_item_args *arg)
     409                 :            : {
     410                 :          0 :         const struct rte_flow_item *item = arg->item;
     411                 :          0 :         const struct rte_flow_item_eth *spec = item->spec;
     412                 :          0 :         const struct rte_flow_item_eth *mask = item->mask;
     413                 :          0 :         const uint8_t lvl = arg->header_level;
     414                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     415                 :            :         struct fm_header_set *fm_data, *fm_mask;
     416                 :            : 
     417                 :          0 :         ENICPMD_FUNC_TRACE();
     418                 :            :         /* Match all if no spec */
     419         [ #  # ]:          0 :         if (!spec)
     420                 :            :                 return 0;
     421         [ #  # ]:          0 :         if (!mask)
     422                 :            :                 mask = &rte_flow_item_eth_mask;
     423                 :          0 :         fm_data = &entry->ftm_data.fk_hdrset[lvl];
     424                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
     425                 :          0 :         fm_data->fk_header_select |= FKH_ETHER;
     426                 :          0 :         fm_mask->fk_header_select |= FKH_ETHER;
     427                 :          0 :         memcpy(&fm_data->l2.eth, spec, sizeof(struct rte_ether_hdr));
     428                 :          0 :         memcpy(&fm_mask->l2.eth, mask, sizeof(struct rte_ether_hdr));
     429                 :          0 :         return 0;
     430                 :            : }
     431                 :            : 
     432                 :            : static int
     433                 :          0 : enic_fm_copy_item_vlan(struct copy_item_args *arg)
     434                 :            : {
     435                 :          0 :         const struct rte_flow_item *item = arg->item;
     436                 :          0 :         const struct rte_flow_item_vlan *spec = item->spec;
     437                 :          0 :         const struct rte_flow_item_vlan *mask = item->mask;
     438                 :          0 :         const uint8_t lvl = arg->header_level;
     439                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     440                 :            :         struct fm_header_set *fm_data, *fm_mask;
     441                 :            :         struct rte_ether_hdr *eth_mask;
     442                 :            :         struct rte_ether_hdr *eth_val;
     443                 :            :         uint32_t meta;
     444                 :            : 
     445                 :          0 :         ENICPMD_FUNC_TRACE();
     446                 :          0 :         fm_data = &entry->ftm_data.fk_hdrset[lvl];
     447                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
     448                 :            :         /* Outer and inner packet vlans need different flags */
     449                 :            :         meta = FKM_VLAN_PRES;
     450         [ #  # ]:          0 :         if (lvl > 0)
     451                 :            :                 meta = FKM_QTAG;
     452                 :          0 :         fm_data->fk_metadata |= meta;
     453                 :          0 :         fm_mask->fk_metadata |= meta;
     454                 :            : 
     455                 :            :         /* Match all if no spec */
     456         [ #  # ]:          0 :         if (!spec)
     457                 :            :                 return 0;
     458         [ #  # ]:          0 :         if (!mask)
     459                 :            :                 mask = &rte_flow_item_vlan_mask;
     460                 :            : 
     461                 :          0 :         eth_mask = (void *)&fm_mask->l2.eth;
     462                 :          0 :         eth_val = (void *)&fm_data->l2.eth;
     463                 :            : 
     464                 :            :         /*
     465                 :            :          * Outer TPID cannot be matched. If protocol is 0, use what is
     466                 :            :          * in the eth header.
     467                 :            :          */
     468   [ #  #  #  # ]:          0 :         if (eth_mask->ether_type && mask->hdr.eth_proto)
     469                 :            :                 return -ENOTSUP;
     470                 :            : 
     471                 :            :         /*
     472                 :            :          * When packet matching, the VIC always compares vlan-stripped
     473                 :            :          * L2, regardless of vlan stripping settings. So, the inner type
     474                 :            :          * from vlan becomes the ether type of the eth header.
     475                 :            :          */
     476         [ #  # ]:          0 :         if (mask->hdr.eth_proto) {
     477                 :          0 :                 eth_mask->ether_type = mask->hdr.eth_proto;
     478                 :          0 :                 eth_val->ether_type = spec->hdr.eth_proto;
     479                 :            :         }
     480                 :          0 :         fm_data->fk_header_select |= FKH_ETHER | FKH_QTAG;
     481                 :          0 :         fm_mask->fk_header_select |= FKH_ETHER | FKH_QTAG;
     482         [ #  # ]:          0 :         fm_data->fk_vlan = rte_be_to_cpu_16(spec->hdr.vlan_tci);
     483         [ #  # ]:          0 :         fm_mask->fk_vlan = rte_be_to_cpu_16(mask->hdr.vlan_tci);
     484                 :          0 :         return 0;
     485                 :            : }
     486                 :            : 
     487                 :            : static int
     488                 :          0 : enic_fm_copy_item_ipv4(struct copy_item_args *arg)
     489                 :            : {
     490                 :          0 :         const struct rte_flow_item *item = arg->item;
     491                 :          0 :         const struct rte_flow_item_ipv4 *spec = item->spec;
     492                 :          0 :         const struct rte_flow_item_ipv4 *mask = item->mask;
     493                 :          0 :         const uint8_t lvl = arg->header_level;
     494                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     495                 :            :         struct fm_header_set *fm_data, *fm_mask;
     496                 :            : 
     497                 :          0 :         ENICPMD_FUNC_TRACE();
     498                 :          0 :         fm_data = &entry->ftm_data.fk_hdrset[lvl];
     499                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
     500                 :          0 :         fm_data->fk_metadata |= FKM_IPV4;
     501                 :          0 :         fm_mask->fk_metadata |= FKM_IPV4;
     502                 :            : 
     503         [ #  # ]:          0 :         if (!spec)
     504                 :            :                 return 0;
     505         [ #  # ]:          0 :         if (!mask)
     506                 :            :                 mask = &rte_flow_item_ipv4_mask;
     507                 :            : 
     508                 :          0 :         fm_data->fk_header_select |= FKH_IPV4;
     509                 :          0 :         fm_mask->fk_header_select |= FKH_IPV4;
     510                 :          0 :         memcpy(&fm_data->l3.ip4, spec, sizeof(*spec));
     511                 :          0 :         memcpy(&fm_mask->l3.ip4, mask, sizeof(*mask));
     512                 :          0 :         return 0;
     513                 :            : }
     514                 :            : 
     515                 :            : static int
     516                 :          0 : enic_fm_copy_item_ipv6(struct copy_item_args *arg)
     517                 :            : {
     518                 :          0 :         const struct rte_flow_item *item = arg->item;
     519                 :          0 :         const struct rte_flow_item_ipv6 *spec = item->spec;
     520                 :          0 :         const struct rte_flow_item_ipv6 *mask = item->mask;
     521                 :          0 :         const uint8_t lvl = arg->header_level;
     522                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     523                 :            :         struct fm_header_set *fm_data, *fm_mask;
     524                 :            : 
     525                 :          0 :         ENICPMD_FUNC_TRACE();
     526                 :          0 :         fm_data = &entry->ftm_data.fk_hdrset[lvl];
     527                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
     528                 :          0 :         fm_data->fk_metadata |= FKM_IPV6;
     529                 :          0 :         fm_mask->fk_metadata |= FKM_IPV6;
     530                 :            : 
     531         [ #  # ]:          0 :         if (!spec)
     532                 :            :                 return 0;
     533         [ #  # ]:          0 :         if (!mask)
     534                 :            :                 mask = &rte_flow_item_ipv6_mask;
     535                 :            : 
     536                 :          0 :         fm_data->fk_header_select |= FKH_IPV6;
     537                 :          0 :         fm_mask->fk_header_select |= FKH_IPV6;
     538                 :          0 :         memcpy(&fm_data->l3.ip6, spec, sizeof(struct rte_ipv6_hdr));
     539                 :          0 :         memcpy(&fm_mask->l3.ip6, mask, sizeof(struct rte_ipv6_hdr));
     540                 :          0 :         return 0;
     541                 :            : }
     542                 :            : 
     543                 :            : static int
     544                 :          0 : enic_fm_copy_item_udp(struct copy_item_args *arg)
     545                 :            : {
     546                 :          0 :         const struct rte_flow_item *item = arg->item;
     547                 :          0 :         const struct rte_flow_item_udp *spec = item->spec;
     548                 :          0 :         const struct rte_flow_item_udp *mask = item->mask;
     549                 :          0 :         const uint8_t lvl = arg->header_level;
     550                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     551                 :            :         struct fm_header_set *fm_data, *fm_mask;
     552                 :            : 
     553                 :          0 :         ENICPMD_FUNC_TRACE();
     554                 :          0 :         fm_data = &entry->ftm_data.fk_hdrset[lvl];
     555                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
     556                 :          0 :         fm_data->fk_metadata |= FKM_UDP;
     557                 :          0 :         fm_mask->fk_metadata |= FKM_UDP;
     558                 :            : 
     559         [ #  # ]:          0 :         if (!spec)
     560                 :            :                 return 0;
     561         [ #  # ]:          0 :         if (!mask)
     562                 :            :                 mask = &rte_flow_item_udp_mask;
     563                 :            : 
     564                 :          0 :         fm_data->fk_header_select |= FKH_UDP;
     565                 :          0 :         fm_mask->fk_header_select |= FKH_UDP;
     566                 :          0 :         memcpy(&fm_data->l4.udp, spec, sizeof(*spec));
     567                 :          0 :         memcpy(&fm_mask->l4.udp, mask, sizeof(*mask));
     568                 :          0 :         return 0;
     569                 :            : }
     570                 :            : 
     571                 :            : static int
     572                 :          0 : enic_fm_copy_item_tcp(struct copy_item_args *arg)
     573                 :            : {
     574                 :          0 :         const struct rte_flow_item *item = arg->item;
     575                 :          0 :         const struct rte_flow_item_tcp *spec = item->spec;
     576                 :          0 :         const struct rte_flow_item_tcp *mask = item->mask;
     577                 :          0 :         const uint8_t lvl = arg->header_level;
     578                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     579                 :            :         struct fm_header_set *fm_data, *fm_mask;
     580                 :            : 
     581                 :          0 :         ENICPMD_FUNC_TRACE();
     582                 :          0 :         fm_data = &entry->ftm_data.fk_hdrset[lvl];
     583                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
     584                 :          0 :         fm_data->fk_metadata |= FKM_TCP;
     585                 :          0 :         fm_mask->fk_metadata |= FKM_TCP;
     586                 :            : 
     587         [ #  # ]:          0 :         if (!spec)
     588                 :            :                 return 0;
     589         [ #  # ]:          0 :         if (!mask)
     590                 :            :                 mask = &rte_flow_item_tcp_mask;
     591                 :            : 
     592                 :          0 :         fm_data->fk_header_select |= FKH_TCP;
     593                 :          0 :         fm_mask->fk_header_select |= FKH_TCP;
     594                 :          0 :         memcpy(&fm_data->l4.tcp, spec, sizeof(*spec));
     595                 :          0 :         memcpy(&fm_mask->l4.tcp, mask, sizeof(*mask));
     596                 :          0 :         return 0;
     597                 :            : }
     598                 :            : 
     599                 :            : static int
     600                 :          0 : enic_fm_copy_item_sctp(struct copy_item_args *arg)
     601                 :            : {
     602                 :          0 :         const struct rte_flow_item *item = arg->item;
     603                 :          0 :         const struct rte_flow_item_sctp *spec = item->spec;
     604                 :          0 :         const struct rte_flow_item_sctp *mask = item->mask;
     605                 :          0 :         const uint8_t lvl = arg->header_level;
     606                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     607                 :            :         struct fm_header_set *fm_data, *fm_mask;
     608                 :            :         uint8_t *ip_proto_mask = NULL;
     609                 :            :         uint8_t *ip_proto = NULL;
     610                 :            :         uint32_t l3_fkh;
     611                 :            : 
     612                 :          0 :         ENICPMD_FUNC_TRACE();
     613                 :          0 :         fm_data = &entry->ftm_data.fk_hdrset[lvl];
     614                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
     615                 :            :         /*
     616                 :            :          * The NIC filter API has no flags for "match sctp", so explicitly
     617                 :            :          * set the protocol number in the IP pattern.
     618                 :            :          */
     619         [ #  # ]:          0 :         if (fm_data->fk_metadata & FKM_IPV4) {
     620                 :            :                 struct rte_ipv4_hdr *ip;
     621                 :          0 :                 ip = (struct rte_ipv4_hdr *)&fm_mask->l3.ip4;
     622                 :          0 :                 ip_proto_mask = &ip->next_proto_id;
     623                 :          0 :                 ip = (struct rte_ipv4_hdr *)&fm_data->l3.ip4;
     624                 :          0 :                 ip_proto = &ip->next_proto_id;
     625                 :            :                 l3_fkh = FKH_IPV4;
     626         [ #  # ]:          0 :         } else if (fm_data->fk_metadata & FKM_IPV6) {
     627                 :            :                 struct rte_ipv6_hdr *ip;
     628                 :          0 :                 ip = (struct rte_ipv6_hdr *)&fm_mask->l3.ip6;
     629                 :          0 :                 ip_proto_mask = &ip->proto;
     630                 :          0 :                 ip = (struct rte_ipv6_hdr *)&fm_data->l3.ip6;
     631                 :          0 :                 ip_proto = &ip->proto;
     632                 :            :                 l3_fkh = FKH_IPV6;
     633                 :            :         } else {
     634                 :            :                 /* Need IPv4/IPv6 pattern first */
     635                 :            :                 return -EINVAL;
     636                 :            :         }
     637                 :          0 :         *ip_proto = IPPROTO_SCTP;
     638                 :          0 :         *ip_proto_mask = 0xff;
     639                 :          0 :         fm_data->fk_header_select |= l3_fkh;
     640                 :          0 :         fm_mask->fk_header_select |= l3_fkh;
     641                 :            : 
     642         [ #  # ]:          0 :         if (!spec)
     643                 :            :                 return 0;
     644         [ #  # ]:          0 :         if (!mask)
     645                 :            :                 mask = &rte_flow_item_sctp_mask;
     646                 :            : 
     647                 :          0 :         fm_data->fk_header_select |= FKH_L4RAW;
     648                 :          0 :         fm_mask->fk_header_select |= FKH_L4RAW;
     649                 :          0 :         memcpy(fm_data->l4.rawdata, spec, sizeof(*spec));
     650                 :          0 :         memcpy(fm_mask->l4.rawdata, mask, sizeof(*mask));
     651                 :          0 :         return 0;
     652                 :            : }
     653                 :            : 
     654                 :            : static int
     655                 :          0 : enic_fm_copy_item_vxlan(struct copy_item_args *arg)
     656                 :            : {
     657                 :          0 :         const struct rte_flow_item *item = arg->item;
     658                 :          0 :         const struct rte_flow_item_vxlan *spec = item->spec;
     659                 :          0 :         const struct rte_flow_item_vxlan *mask = item->mask;
     660                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     661                 :            :         struct fm_header_set *fm_data, *fm_mask;
     662                 :            : 
     663                 :          0 :         ENICPMD_FUNC_TRACE();
     664                 :            :         /* Only 2 header levels (outer and inner) allowed */
     665         [ #  # ]:          0 :         if (arg->header_level > 0)
     666                 :            :                 return -EINVAL;
     667                 :            : 
     668                 :            :         fm_data = &entry->ftm_data.fk_hdrset[0];
     669                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[0];
     670                 :          0 :         fm_data->fk_metadata |= FKM_VXLAN;
     671                 :          0 :         fm_mask->fk_metadata |= FKM_VXLAN;
     672                 :            :         /* items from here on out are inner header items */
     673                 :          0 :         arg->header_level = 1;
     674                 :            : 
     675                 :            :         /* Match all if no spec */
     676         [ #  # ]:          0 :         if (!spec)
     677                 :            :                 return 0;
     678         [ #  # ]:          0 :         if (!mask)
     679                 :            :                 mask = &rte_flow_item_vxlan_mask;
     680                 :            : 
     681                 :          0 :         fm_data->fk_header_select |= FKH_VXLAN;
     682                 :          0 :         fm_mask->fk_header_select |= FKH_VXLAN;
     683                 :          0 :         memcpy(&fm_data->vxlan, spec, sizeof(*spec));
     684                 :          0 :         memcpy(&fm_mask->vxlan, mask, sizeof(*mask));
     685                 :          0 :         return 0;
     686                 :            : }
     687                 :            : 
     688                 :            : static int
     689                 :          0 : enic_fm_copy_item_gtp(struct copy_item_args *arg)
     690                 :            : {
     691                 :          0 :         const struct rte_flow_item *item = arg->item;
     692                 :          0 :         const struct rte_flow_item_gtp *spec = item->spec;
     693                 :          0 :         const struct rte_flow_item_gtp *mask = item->mask;
     694                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     695                 :            :         struct fm_header_set *fm_data, *fm_mask;
     696                 :            :         int off;
     697                 :            :         uint16_t udp_gtp_uc_port_be = 0;
     698                 :            : 
     699                 :          0 :         ENICPMD_FUNC_TRACE();
     700                 :            :         /* Only 2 header levels (outer and inner) allowed */
     701         [ #  # ]:          0 :         if (arg->header_level > 0)
     702                 :            :                 return -EINVAL;
     703                 :            : 
     704                 :            :         fm_data = &entry->ftm_data.fk_hdrset[0];
     705                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[0];
     706                 :            : 
     707   [ #  #  #  # ]:          0 :         switch (item->type) {
     708                 :          0 :         case RTE_FLOW_ITEM_TYPE_GTP:
     709                 :            :         {
     710                 :            :                 /* For vanilla GTP, the UDP destination port must be specified
     711                 :            :                  * but value of the port is not enforced here.
     712                 :            :                  */
     713         [ #  # ]:          0 :                 if (!(fm_data->fk_metadata & FKM_UDP) ||
     714         [ #  # ]:          0 :                     !(fm_data->fk_header_select & FKH_UDP) ||
     715         [ #  # ]:          0 :                     fm_data->l4.udp.fk_dest == 0)
     716                 :            :                         return -EINVAL;
     717         [ #  # ]:          0 :                 if (!(fm_mask->fk_metadata & FKM_UDP) ||
     718         [ #  # ]:          0 :                     !(fm_mask->fk_header_select & FKH_UDP) ||
     719         [ #  # ]:          0 :                     fm_mask->l4.udp.fk_dest != 0xFFFF)
     720                 :            :                         return -EINVAL;
     721                 :            :                 break;
     722                 :            :         }
     723                 :            :         case RTE_FLOW_ITEM_TYPE_GTPC:
     724                 :            :         {
     725                 :            :                 udp_gtp_uc_port_be = rte_cpu_to_be_16(RTE_GTPC_UDP_PORT);
     726                 :            :                 break;
     727                 :            :         }
     728                 :            :         case RTE_FLOW_ITEM_TYPE_GTPU:
     729                 :            :         {
     730                 :            :                 udp_gtp_uc_port_be = rte_cpu_to_be_16(RTE_GTPU_UDP_PORT);
     731                 :            :                 break;
     732                 :            :         }
     733                 :            :         default:
     734                 :            :                 RTE_ASSERT(0);
     735                 :            :         }
     736                 :            : 
     737                 :            :         /* The GTP-C or GTP-U UDP destination port must be matched. */
     738                 :            :         if (udp_gtp_uc_port_be) {
     739         [ #  # ]:          0 :                 if (fm_data->fk_metadata & FKM_UDP &&
     740         [ #  # ]:          0 :                     fm_data->fk_header_select & FKH_UDP &&
     741         [ #  # ]:          0 :                     fm_data->l4.udp.fk_dest != udp_gtp_uc_port_be)
     742                 :            :                         return -EINVAL;
     743         [ #  # ]:          0 :                 if (fm_mask->fk_metadata & FKM_UDP &&
     744         [ #  # ]:          0 :                     fm_mask->fk_header_select & FKH_UDP &&
     745         [ #  # ]:          0 :                     fm_mask->l4.udp.fk_dest != 0xFFFF)
     746                 :            :                         return -EINVAL;
     747                 :            : 
     748                 :            :                 /* In any case, add match for GTP-C GTP-U UDP dst port */
     749                 :          0 :                 fm_data->fk_metadata |= FKM_UDP;
     750                 :          0 :                 fm_data->fk_header_select |= FKH_UDP;
     751                 :          0 :                 fm_data->l4.udp.fk_dest = udp_gtp_uc_port_be;
     752                 :          0 :                 fm_mask->fk_metadata |= FKM_UDP;
     753                 :          0 :                 fm_mask->fk_header_select |= FKH_UDP;
     754                 :          0 :                 fm_mask->l4.udp.fk_dest = 0xFFFF;
     755                 :            :         }
     756                 :            : 
     757                 :            :         /* NIC does not support GTP tunnels. No Items are allowed after this.
     758                 :            :          * This prevents the specification of further items.
     759                 :            :          */
     760                 :          0 :         arg->header_level = 0;
     761                 :            : 
     762                 :            :         /* Match all if no spec */
     763         [ #  # ]:          0 :         if (!spec)
     764                 :            :                 return 0;
     765         [ #  # ]:          0 :         if (!mask)
     766                 :            :                 mask = &rte_flow_item_gtp_mask;
     767                 :            : 
     768                 :            :         /*
     769                 :            :          * Use the raw L4 buffer to match GTP as fm_header_set does not have
     770                 :            :          * GTP header. UDP dst port must be specific. Using the raw buffer
     771                 :            :          * does not affect such UDP item, since we skip UDP in the raw buffer.
     772                 :            :          */
     773                 :          0 :         fm_data->fk_header_select |= FKH_L4RAW;
     774                 :          0 :         fm_mask->fk_header_select |= FKH_L4RAW;
     775                 :            :         off = sizeof(fm_data->l4.udp);
     776                 :          0 :         memcpy(&fm_data->l4.rawdata[off], spec, sizeof(*spec));
     777                 :          0 :         memcpy(&fm_mask->l4.rawdata[off], mask, sizeof(*mask));
     778                 :          0 :         return 0;
     779                 :            : }
     780                 :            : 
     781                 :            : static int
     782                 :          0 : enic_fm_copy_item_geneve(struct copy_item_args *arg)
     783                 :            : {
     784                 :          0 :         const struct rte_flow_item *item = arg->item;
     785                 :          0 :         const struct rte_flow_item_geneve *spec = item->spec;
     786                 :          0 :         const struct rte_flow_item_geneve *mask = item->mask;
     787                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     788                 :            :         struct fm_header_set *fm_data, *fm_mask;
     789                 :            :         int off;
     790                 :            : 
     791                 :          0 :         ENICPMD_FUNC_TRACE();
     792                 :            :         /* Only 2 header levels (outer and inner) allowed */
     793         [ #  # ]:          0 :         if (arg->header_level > 0)
     794                 :            :                 return -EINVAL;
     795                 :            : 
     796                 :            :         fm_data = &entry->ftm_data.fk_hdrset[0];
     797                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[0];
     798                 :          0 :         fm_data->fk_metadata |= FKM_GENEVE;
     799                 :          0 :         fm_mask->fk_metadata |= FKM_GENEVE;
     800                 :            :         /* items from here on out are inner header items, except options */
     801                 :          0 :         arg->header_level = 1;
     802                 :            : 
     803                 :            :         /* Match all if no spec */
     804         [ #  # ]:          0 :         if (!spec)
     805                 :            :                 return 0;
     806         [ #  # ]:          0 :         if (!mask)
     807                 :            :                 mask = &rte_flow_item_geneve_mask;
     808                 :            : 
     809                 :            :         /*
     810                 :            :          * Use the raw L4 buffer to match geneve as fm_header_set does
     811                 :            :          * not have geneve header. A UDP item may precede the geneve
     812                 :            :          * item. Using the raw buffer does not affect such UDP item,
     813                 :            :          * since we skip UDP in the raw buffer.
     814                 :            :          */
     815                 :          0 :         fm_data->fk_header_select |= FKH_L4RAW;
     816                 :          0 :         fm_mask->fk_header_select |= FKH_L4RAW;
     817                 :            :         off = sizeof(fm_data->l4.udp);
     818                 :          0 :         memcpy(&fm_data->l4.rawdata[off], spec, sizeof(struct rte_geneve_hdr));
     819                 :          0 :         memcpy(&fm_mask->l4.rawdata[off], mask, sizeof(struct rte_geneve_hdr));
     820                 :          0 :         return 0;
     821                 :            : }
     822                 :            : 
     823                 :            : static int
     824                 :          0 : enic_fm_copy_item_geneve_opt(struct copy_item_args *arg)
     825                 :            : {
     826                 :          0 :         const struct rte_flow_item *item = arg->item;
     827                 :          0 :         const struct rte_flow_item_geneve_opt *spec = item->spec;
     828                 :          0 :         const struct rte_flow_item_geneve_opt *mask = item->mask;
     829                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     830                 :            :         struct fm_header_set *fm_data, *fm_mask;
     831                 :            :         struct rte_geneve_hdr *geneve;
     832                 :            :         int off, len;
     833                 :            : 
     834                 :          0 :         ENICPMD_FUNC_TRACE();
     835                 :            :         fm_data = &entry->ftm_data.fk_hdrset[0];
     836                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[0];
     837                 :            :         /* Match all if no spec */
     838         [ #  # ]:          0 :         if (!spec)
     839                 :            :                 return 0;
     840         [ #  # ]:          0 :         if (!mask)
     841                 :            :                 mask = &rte_flow_item_geneve_opt_mask;
     842                 :            : 
     843         [ #  # ]:          0 :         if (spec->option_len > 0 &&
     844   [ #  #  #  # ]:          0 :             (spec->data == NULL || mask->data == NULL)) {
     845                 :          0 :                 return rte_flow_error_set(arg->error, EINVAL,
     846                 :            :                         RTE_FLOW_ERROR_TYPE_ITEM,
     847                 :            :                         NULL, "enic: geneve_opt unexpected null data");
     848                 :            :         }
     849                 :            :         /*
     850                 :            :          * Geneve item must already be in the raw buffer. Append the
     851                 :            :          * option pattern to it. There are two limitations.
     852                 :            :          * (1) Can match only the 1st option, the first one following Geneve
     853                 :            :          * (2) Geneve header must specify option length, as HW does not
     854                 :            :          *     have "has Geneve option" flag.
     855                 :            :          */
     856                 :            :         RTE_ASSERT((fm_data->fk_header_select & FKH_L4RAW) != 0);
     857                 :            :         RTE_ASSERT((fm_mask->fk_header_select & FKH_L4RAW) != 0);
     858                 :            :         off = sizeof(fm_data->l4.udp);
     859                 :            :         geneve = (struct rte_geneve_hdr *)&fm_data->l4.rawdata[off];
     860         [ #  # ]:          0 :         if (geneve->opt_len == 0) {
     861                 :          0 :                 return rte_flow_error_set(arg->error, EINVAL,
     862                 :            :                         RTE_FLOW_ERROR_TYPE_ITEM,
     863                 :            :                         NULL, "enic: geneve_opt requires non-zero geneve option length");
     864                 :            :         }
     865                 :            :         geneve = (struct rte_geneve_hdr *)&fm_mask->l4.rawdata[off];
     866         [ #  # ]:          0 :         if (geneve->opt_len == 0) {
     867                 :          0 :                 return rte_flow_error_set(arg->error, EINVAL,
     868                 :            :                         RTE_FLOW_ERROR_TYPE_ITEM,
     869                 :            :                         NULL, "enic: geneve_opt requires non-zero geneve option length mask");
     870                 :            :         }
     871                 :            :         off = sizeof(fm_data->l4.udp) + sizeof(struct rte_geneve_hdr);
     872         [ #  # ]:          0 :         if (off + (spec->option_len + 1) * 4 > FM_LAYER_SIZE) {
     873                 :          0 :                 return rte_flow_error_set(arg->error, EINVAL,
     874                 :            :                         RTE_FLOW_ERROR_TYPE_ITEM,
     875                 :            :                         NULL, "enic: geneve_opt too large");
     876                 :            :         }
     877                 :            :         /* Copy option header */
     878         [ #  # ]:          0 :         memcpy(&fm_data->l4.rawdata[off], spec, 4);
     879                 :          0 :         memcpy(&fm_mask->l4.rawdata[off], mask, 4);
     880                 :            :         /* Copy option data */
     881         [ #  # ]:          0 :         if (spec->option_len > 0) {
     882                 :            :                 off += 4;
     883                 :          0 :                 len = spec->option_len * 4;
     884                 :          0 :                 memcpy(&fm_data->l4.rawdata[off], spec->data, len);
     885                 :          0 :                 memcpy(&fm_mask->l4.rawdata[off], mask->data, len);
     886                 :            :         }
     887                 :            :         return 0;
     888                 :            : }
     889                 :            : 
     890                 :            : /* Match eCPRI combined message header */
     891                 :            : static int
     892                 :          0 : enic_fm_copy_item_ecpri(struct copy_item_args *arg)
     893                 :            : {
     894                 :          0 :         const struct rte_flow_item *item = arg->item;
     895                 :          0 :         const struct rte_flow_item_ecpri *spec = item->spec;
     896                 :          0 :         const struct rte_flow_item_ecpri *mask = item->mask;
     897                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     898                 :            :         struct fm_header_set *fm_data, *fm_mask;
     899                 :            :         uint8_t *fm_data_to, *fm_mask_to;
     900                 :            : 
     901                 :          0 :         ENICPMD_FUNC_TRACE();
     902                 :            : 
     903                 :            :         /* Tunneling not supported- only matching on inner eCPRI fields. */
     904         [ #  # ]:          0 :         if (arg->header_level > 0)
     905                 :            :                 return -EINVAL;
     906                 :            : 
     907                 :            :         /* Need both spec and mask */
     908         [ #  # ]:          0 :         if (!spec || !mask)
     909                 :            :                 return -EINVAL;
     910                 :            : 
     911                 :            :         fm_data = &entry->ftm_data.fk_hdrset[0];
     912                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[0];
     913                 :            : 
     914                 :            :         /* eCPRI can only follow L2/VLAN layer if ethernet type is 0xAEFE. */
     915         [ #  # ]:          0 :         if (!(fm_data->fk_metadata & FKM_UDP) &&
     916   [ #  #  #  # ]:          0 :             (fm_mask->l2.eth.fk_ethtype != UINT16_MAX ||
     917   [ #  #  #  # ]:          0 :             rte_cpu_to_be_16(fm_data->l2.eth.fk_ethtype) !=
     918                 :            :             RTE_ETHER_TYPE_ECPRI))
     919                 :            :                 return -EINVAL;
     920                 :            : 
     921         [ #  # ]:          0 :         if (fm_data->fk_metadata & FKM_UDP) {
     922                 :            :                 /* eCPRI on UDP */
     923                 :          0 :                 fm_data->fk_header_select |= FKH_L4RAW;
     924                 :          0 :                 fm_mask->fk_header_select |= FKH_L4RAW;
     925                 :          0 :                 fm_data_to = &fm_data->l4.rawdata[sizeof(fm_data->l4.udp)];
     926                 :          0 :                 fm_mask_to = &fm_mask->l4.rawdata[sizeof(fm_data->l4.udp)];
     927                 :            :         } else {
     928                 :            :                 /* eCPRI directly after Etherent header */
     929                 :          0 :                 fm_data->fk_header_select |= FKH_L3RAW;
     930                 :          0 :                 fm_mask->fk_header_select |= FKH_L3RAW;
     931                 :          0 :                 fm_data_to = &fm_data->l3.rawdata[0];
     932                 :          0 :                 fm_mask_to = &fm_mask->l3.rawdata[0];
     933                 :            :         }
     934                 :            : 
     935                 :            :         /*
     936                 :            :          * Use the raw L3 or L4 buffer to match eCPRI since fm_header_set does
     937                 :            :          * not have eCPRI header. Only 1st message header of PDU can be matched.
     938                 :            :          * "C" * bit ignored.
     939                 :            :          */
     940                 :            :         memcpy(fm_data_to, spec, sizeof(*spec));
     941                 :            :         memcpy(fm_mask_to, mask, sizeof(*mask));
     942                 :          0 :         return 0;
     943                 :            : }
     944                 :            : 
     945                 :            : /*
     946                 :            :  * Currently, raw pattern match is very limited. It is intended for matching
     947                 :            :  * UDP tunnel header (e.g. vxlan or geneve).
     948                 :            :  */
     949                 :            : static int
     950                 :          0 : enic_fm_copy_item_raw(struct copy_item_args *arg)
     951                 :            : {
     952                 :          0 :         const struct rte_flow_item *item = arg->item;
     953                 :          0 :         const struct rte_flow_item_raw *spec = item->spec;
     954                 :          0 :         const struct rte_flow_item_raw *mask = item->mask;
     955                 :          0 :         const uint8_t lvl = arg->header_level;
     956                 :          0 :         struct fm_tcam_match_entry *entry = arg->fm_tcam_entry;
     957                 :            :         struct fm_header_set *fm_data, *fm_mask;
     958                 :            : 
     959                 :          0 :         ENICPMD_FUNC_TRACE();
     960                 :            :         /* Cannot be used for inner packet */
     961         [ #  # ]:          0 :         if (lvl > 0)
     962                 :            :                 return -EINVAL;
     963                 :            :         /* Need both spec and mask */
     964         [ #  # ]:          0 :         if (!spec || !mask)
     965                 :            :                 return -EINVAL;
     966                 :            :         /* Only supports relative with offset 0 */
     967         [ #  # ]:          0 :         if (!spec->relative || spec->offset != 0 || spec->search ||
     968         [ #  # ]:          0 :             spec->limit)
     969                 :            :                 return -EINVAL;
     970                 :            :         /* Need non-null pattern that fits within the NIC's filter pattern */
     971         [ #  # ]:          0 :         if (spec->length == 0 ||
     972         [ #  # ]:          0 :             spec->length + sizeof(struct rte_udp_hdr) > FM_LAYER_SIZE ||
     973   [ #  #  #  # ]:          0 :             !spec->pattern || !mask->pattern)
     974                 :            :                 return -EINVAL;
     975                 :            :         /*
     976                 :            :          * Mask fields, including length, are often set to zero. Assume that
     977                 :            :          * means "same as spec" to avoid breaking existing apps. If length
     978                 :            :          * is not zero, then it should be >= spec length.
     979                 :            :          *
     980                 :            :          * No more pattern follows this, so append to the L4 layer instead of
     981                 :            :          * L5 to work with both recent and older VICs.
     982                 :            :          */
     983   [ #  #  #  # ]:          0 :         if (mask->length != 0 && mask->length < spec->length)
     984                 :            :                 return -EINVAL;
     985                 :            : 
     986                 :            :         fm_data = &entry->ftm_data.fk_hdrset[lvl];
     987                 :            :         fm_mask = &entry->ftm_mask.fk_hdrset[lvl];
     988                 :          0 :         fm_data->fk_header_select |= FKH_L4RAW;
     989                 :          0 :         fm_mask->fk_header_select |= FKH_L4RAW;
     990                 :          0 :         fm_data->fk_header_select &= ~FKH_UDP;
     991                 :          0 :         fm_mask->fk_header_select &= ~FKH_UDP;
     992                 :          0 :         memcpy(fm_data->l4.rawdata + sizeof(struct rte_udp_hdr),
     993                 :            :                spec->pattern, spec->length);
     994                 :          0 :         memcpy(fm_mask->l4.rawdata + sizeof(struct rte_udp_hdr),
     995                 :          0 :                mask->pattern, spec->length);
     996                 :          0 :         return 0;
     997                 :            : }
     998                 :            : 
     999                 :            : static int
    1000                 :            : flowman_cmd(struct enic_flowman *fm, uint64_t *args, int nargs)
    1001                 :            : {
    1002                 :          0 :         return vnic_dev_flowman_cmd(fm->owner_enic->vdev, args, nargs);
    1003                 :            : }
    1004                 :            : 
    1005                 :            : static int
    1006                 :          0 : enic_fet_alloc(struct enic_flowman *fm, uint8_t ingress,
    1007                 :            :                struct fm_key_template *key, int entries,
    1008                 :            :                struct enic_fm_fet **fet_out)
    1009                 :            : {
    1010                 :            :         struct fm_exact_match_table *cmd;
    1011                 :            :         struct fm_header_set *hdr;
    1012                 :            :         struct enic_fm_fet *fet;
    1013                 :            :         uint64_t args[3];
    1014                 :            :         int ret;
    1015                 :            : 
    1016                 :          0 :         ENICPMD_FUNC_TRACE();
    1017                 :          0 :         fet = calloc(1, sizeof(struct enic_fm_fet));
    1018         [ #  # ]:          0 :         if (fet == NULL)
    1019                 :            :                 return -ENOMEM;
    1020         [ #  # ]:          0 :         cmd = &fm->cmd.va->fm_exact_match_table;
    1021                 :            :         memset(cmd, 0, sizeof(*cmd));
    1022                 :          0 :         cmd->fet_direction = ingress ? FM_INGRESS : FM_EGRESS;
    1023                 :          0 :         cmd->fet_stage = FM_STAGE_LAST;
    1024         [ #  # ]:          0 :         cmd->fet_max_entries = entries ? entries : FM_MAX_EXACT_TABLE_SIZE;
    1025         [ #  # ]:          0 :         if (key == NULL) {
    1026                 :          0 :                 hdr = &cmd->fet_key.fk_hdrset[0];
    1027                 :            :                 memset(hdr, 0, sizeof(*hdr));
    1028                 :          0 :                 hdr->fk_header_select = FKH_IPV4 | FKH_UDP;
    1029                 :          0 :                 hdr->l3.ip4.fk_saddr = 0xFFFFFFFF;
    1030                 :          0 :                 hdr->l3.ip4.fk_daddr = 0xFFFFFFFF;
    1031                 :          0 :                 hdr->l4.udp.fk_source = 0xFFFF;
    1032                 :          0 :                 hdr->l4.udp.fk_dest = 0xFFFF;
    1033                 :          0 :                 fet->default_key = 1;
    1034                 :            :         } else {
    1035                 :          0 :                 memcpy(&cmd->fet_key, key, sizeof(*key));
    1036                 :          0 :                 memcpy(&fet->key, key, sizeof(*key));
    1037                 :          0 :                 fet->default_key = 0;
    1038                 :            :         }
    1039                 :          0 :         cmd->fet_key.fk_packet_tag = 1;
    1040                 :            : 
    1041                 :          0 :         args[0] = FM_EXACT_TABLE_ALLOC;
    1042                 :          0 :         args[1] = fm->cmd.pa;
    1043                 :            :         ret = flowman_cmd(fm, args, 2);
    1044         [ #  # ]:          0 :         if (ret) {
    1045                 :          0 :                 ENICPMD_LOG(ERR, "cannot alloc exact match table: rc=%d", ret);
    1046                 :          0 :                 free(fet);
    1047                 :          0 :                 return ret;
    1048                 :            :         }
    1049                 :          0 :         fet->handle = args[0];
    1050                 :          0 :         fet->ingress = ingress;
    1051                 :          0 :         ENICPMD_LOG(DEBUG, "allocated exact match table: handle=0x%" PRIx64,
    1052                 :            :                     fet->handle);
    1053                 :          0 :         *fet_out = fet;
    1054                 :          0 :         return 0;
    1055                 :            : }
    1056                 :            : 
    1057                 :            : static void
    1058                 :          0 : enic_fet_free(struct enic_flowman *fm, struct enic_fm_fet *fet)
    1059                 :            : {
    1060                 :          0 :         ENICPMD_FUNC_TRACE();
    1061                 :          0 :         enic_fm_tbl_free(fm, fet->handle);
    1062         [ #  # ]:          0 :         if (!fet->default_key)
    1063         [ #  # ]:          0 :                 TAILQ_REMOVE(&fm->fet_list, fet, list);
    1064                 :          0 :         free(fet);
    1065                 :          0 : }
    1066                 :            : 
    1067                 :            : /*
    1068                 :            :  * Get the exact match table for the given combination of
    1069                 :            :  * <group, ingress, key>. Allocate one on the fly as necessary.
    1070                 :            :  */
    1071                 :            : static int
    1072                 :          0 : enic_fet_get(struct enic_flowman *fm,
    1073                 :            :              uint32_t group,
    1074                 :            :              uint8_t ingress,
    1075                 :            :              struct fm_key_template *key,
    1076                 :            :              struct enic_fm_fet **fet_out,
    1077                 :            :              struct rte_flow_error *error)
    1078                 :            : {
    1079                 :            :         struct enic_fm_fet *fet;
    1080                 :            : 
    1081                 :          0 :         ENICPMD_FUNC_TRACE();
    1082                 :            :         /* See if we already have this table open */
    1083         [ #  # ]:          0 :         TAILQ_FOREACH(fet, &fm->fet_list, list) {
    1084   [ #  #  #  # ]:          0 :                 if (fet->group == group && fet->ingress == ingress)
    1085                 :            :                         break;
    1086                 :            :         }
    1087         [ #  # ]:          0 :         if (fet == NULL) {
    1088                 :            :                 /* Jumping to a non-existing group? Use the default table */
    1089         [ #  # ]:          0 :                 if (key == NULL) {
    1090         [ #  # ]:          0 :                         fet = ingress ? fm->default_ig_fet : fm->default_eg_fet;
    1091         [ #  # ]:          0 :                 } else if (enic_fet_alloc(fm, ingress, key, 0, &fet)) {
    1092                 :          0 :                         return rte_flow_error_set(error, EINVAL,
    1093                 :            :                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
    1094                 :            :                                 NULL, "enic: cannot get exact match table");
    1095                 :            :                 }
    1096                 :          0 :                 fet->group = group;
    1097                 :            :                 /* Default table is never on the open table list */
    1098         [ #  # ]:          0 :                 if (!fet->default_key)
    1099         [ #  # ]:          0 :                         TAILQ_INSERT_HEAD(&fm->fet_list, fet, list);
    1100                 :            :         }
    1101                 :          0 :         fet->ref++;
    1102                 :          0 :         *fet_out = fet;
    1103   [ #  #  #  # ]:          0 :         ENICPMD_LOG(DEBUG, "fet_get: %s %s group=%u ref=%u",
    1104                 :            :                     fet->default_key ? "default" : "",
    1105                 :            :                     fet->ingress ? "ingress" : "egress",
    1106                 :            :                     fet->group, fet->ref);
    1107                 :          0 :         return 0;
    1108                 :            : }
    1109                 :            : 
    1110                 :            : static void
    1111                 :          0 : enic_fet_put(struct enic_flowman *fm, struct enic_fm_fet *fet)
    1112                 :            : {
    1113                 :          0 :         ENICPMD_FUNC_TRACE();
    1114                 :            :         RTE_ASSERT(fet->ref > 0);
    1115                 :          0 :         fet->ref--;
    1116   [ #  #  #  # ]:          0 :         ENICPMD_LOG(DEBUG, "fet_put: %s %s group=%u ref=%u",
    1117                 :            :                     fet->default_key ? "default" : "",
    1118                 :            :                     fet->ingress ? "ingress" : "egress",
    1119                 :            :                     fet->group, fet->ref);
    1120         [ #  # ]:          0 :         if (fet->ref == 0)
    1121                 :          0 :                 enic_fet_free(fm, fet);
    1122                 :          0 : }
    1123                 :            : 
    1124                 :            : /* Return 1 if current item is valid on top of the previous one. */
    1125                 :            : static int
    1126                 :          0 : fm_item_stacking_valid(enum rte_flow_item_type prev_item,
    1127                 :            :                        const struct enic_fm_items *item_info,
    1128                 :            :                        uint8_t is_first_item)
    1129                 :            : {
    1130                 :          0 :         enum rte_flow_item_type const *allowed_items = item_info->prev_items;
    1131                 :            : 
    1132                 :          0 :         ENICPMD_FUNC_TRACE();
    1133         [ #  # ]:          0 :         for (; *allowed_items != RTE_FLOW_ITEM_TYPE_END; allowed_items++) {
    1134         [ #  # ]:          0 :                 if (prev_item == *allowed_items)
    1135                 :            :                         return 1;
    1136                 :            :         }
    1137                 :            : 
    1138                 :            :         /* This is the first item in the stack. Check if that's cool */
    1139   [ #  #  #  # ]:          0 :         if (is_first_item && item_info->valid_start_item)
    1140                 :          0 :                 return 1;
    1141                 :            :         return 0;
    1142                 :            : }
    1143                 :            : 
    1144                 :            : /*
    1145                 :            :  * Build the flow manager match entry structure from the provided pattern.
    1146                 :            :  * The pattern is validated as the items are copied.
    1147                 :            :  */
    1148                 :            : static int
    1149                 :          0 : enic_fm_copy_entry(struct enic_flowman *fm,
    1150                 :            :                    const struct rte_flow_item pattern[],
    1151                 :            :                    struct rte_flow_error *error)
    1152                 :            : {
    1153                 :            :         const struct enic_fm_items *item_info;
    1154                 :            :         enum rte_flow_item_type prev_item;
    1155                 :            :         const struct rte_flow_item *item;
    1156                 :            :         struct copy_item_args args;
    1157                 :            :         uint8_t prev_header_level;
    1158                 :            :         uint8_t is_first_item;
    1159                 :            :         int ret;
    1160                 :            : 
    1161                 :          0 :         ENICPMD_FUNC_TRACE();
    1162                 :            :         item = pattern;
    1163                 :            :         is_first_item = 1;
    1164                 :            :         prev_item = RTE_FLOW_ITEM_TYPE_END;
    1165                 :            : 
    1166                 :          0 :         args.fm_tcam_entry = &fm->tcam_entry;
    1167                 :          0 :         args.header_level = 0;
    1168                 :            :         prev_header_level = 0;
    1169         [ #  # ]:          0 :         for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
    1170                 :            :                 /*
    1171                 :            :                  * Get info about how to validate and copy the item. If NULL
    1172                 :            :                  * is returned the nic does not support the item.
    1173                 :            :                  */
    1174         [ #  # ]:          0 :                 if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
    1175                 :          0 :                         continue;
    1176                 :            : 
    1177                 :          0 :                 item_info = &enic_fm_items[item->type];
    1178                 :            : 
    1179         [ #  # ]:          0 :                 if (item->type >= RTE_DIM(enic_fm_items) ||
    1180         [ #  # ]:          0 :                     item_info->copy_item == NULL) {
    1181                 :          0 :                         return rte_flow_error_set(error, ENOTSUP,
    1182                 :            :                                 RTE_FLOW_ERROR_TYPE_ITEM,
    1183                 :            :                                 NULL, "enic: unsupported item");
    1184                 :            :                 }
    1185                 :            :                 /*
    1186                 :            :                  * Check vNIC feature dependencies. Geneve item needs
    1187                 :            :                  * Geneve offload feature
    1188                 :            :                  */
    1189         [ #  # ]:          0 :                 if (item->type == RTE_FLOW_ITEM_TYPE_GENEVE &&
    1190         [ #  # ]:          0 :                     !fm->user_enic->geneve) {
    1191                 :          0 :                         return rte_flow_error_set(error, ENOTSUP,
    1192                 :            :                                 RTE_FLOW_ERROR_TYPE_ITEM,
    1193                 :            :                                 NULL, "enic: geneve not supported");
    1194                 :            :                 }
    1195                 :            :                 /* check to see if item stacking is valid */
    1196         [ #  # ]:          0 :                 if (!fm_item_stacking_valid(prev_item, item_info,
    1197                 :            :                                             is_first_item))
    1198                 :          0 :                         goto stacking_error;
    1199                 :            : 
    1200                 :          0 :                 args.item = item;
    1201                 :          0 :                 args.error = error;
    1202         [ #  # ]:          0 :                 if (error)
    1203                 :          0 :                         error->type = RTE_FLOW_ERROR_TYPE_NONE;
    1204                 :          0 :                 ret = item_info->copy_item(&args);
    1205         [ #  # ]:          0 :                 if (ret) {
    1206                 :            :                         /* If copy_item set the error, return that */
    1207   [ #  #  #  # ]:          0 :                         if (error && error->type != RTE_FLOW_ERROR_TYPE_NONE)
    1208                 :            :                                 return ret;
    1209                 :          0 :                         goto item_not_supported;
    1210                 :            :                 }
    1211                 :            :                 /* Going from outer to inner? Treat it as a new packet start */
    1212         [ #  # ]:          0 :                 if (prev_header_level != args.header_level) {
    1213                 :            :                         prev_item = RTE_FLOW_ITEM_TYPE_END;
    1214                 :            :                         is_first_item = 1;
    1215                 :            :                 } else {
    1216                 :          0 :                         prev_item = item->type;
    1217                 :            :                         is_first_item = 0;
    1218                 :            :                 }
    1219                 :            :                 prev_header_level = args.header_level;
    1220                 :            :         }
    1221                 :            :         return 0;
    1222                 :            : 
    1223                 :            : item_not_supported:
    1224                 :          0 :         return rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_ITEM,
    1225                 :            :                                   NULL, "enic: unsupported item type");
    1226                 :            : 
    1227                 :            : stacking_error:
    1228                 :          0 :         return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
    1229                 :            :                                   item, "enic: unsupported item stack");
    1230                 :            : }
    1231                 :            : 
    1232                 :            : static void
    1233                 :            : flow_item_skip_void(const struct rte_flow_item **item)
    1234                 :            : {
    1235                 :          0 :         for ( ; ; (*item)++)
    1236   [ #  #  #  #  :          0 :                 if ((*item)->type != RTE_FLOW_ITEM_TYPE_VOID)
          #  #  #  #  #  
                      # ]
    1237                 :            :                         return;
    1238                 :            : }
    1239                 :            : 
    1240                 :            : static void
    1241                 :            : append_template(void **template, uint8_t *off, const void *data, int len)
    1242                 :            : {
    1243                 :            :         memcpy(*template, data, len);
    1244                 :          0 :         *template = (char *)*template + len;
    1245                 :          0 :         *off = *off + len;
    1246                 :            : }
    1247                 :            : 
    1248                 :            : static int
    1249                 :          0 : enic_fm_append_action_op(struct enic_flowman *fm,
    1250                 :            :                          struct fm_action_op *fm_op,
    1251                 :            :                          struct rte_flow_error *error)
    1252                 :            : {
    1253                 :            :         int count;
    1254                 :            : 
    1255                 :          0 :         count = fm->action_op_count;
    1256                 :          0 :         ENICPMD_LOG(DEBUG, "append action op: idx=%d op=%u",
    1257                 :            :                     count, fm_op->fa_op);
    1258         [ #  # ]:          0 :         if (count == FM_ACTION_OP_MAX) {
    1259                 :          0 :                 return rte_flow_error_set(error, EINVAL,
    1260                 :            :                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
    1261                 :            :                         "too many action operations");
    1262                 :            :         }
    1263                 :          0 :         fm->action.fma_action_ops[count] = *fm_op;
    1264                 :          0 :         fm->action_op_count = count + 1;
    1265                 :          0 :         return 0;
    1266                 :            : }
    1267                 :            : 
    1268                 :            : static struct fm_action_op *
    1269                 :            : find_prev_action_op(struct enic_flowman *fm, uint32_t opcode)
    1270                 :            : {
    1271                 :            :         struct fm_action_op *op;
    1272                 :            :         int i;
    1273                 :            : 
    1274         [ #  # ]:          0 :         for (i = 0; i < fm->action_op_count; i++) {
    1275                 :          0 :                 op = &fm->action.fma_action_ops[i];
    1276         [ #  # ]:          0 :                 if (op->fa_op == opcode)
    1277                 :            :                         return op;
    1278                 :            :         }
    1279                 :            :         return NULL;
    1280                 :            : }
    1281                 :            : 
    1282                 :            : /* NIC requires that 1st steer appear before decap.
    1283                 :            :  * Correct example: steer, decap, steer, steer, ...
    1284                 :            :  */
    1285                 :            : static void
    1286                 :          0 : enic_fm_reorder_action_op(struct enic_flowman *fm)
    1287                 :            : {
    1288                 :            :         struct fm_action_op *op, *steer, *decap;
    1289                 :            :         struct fm_action_op tmp_op;
    1290                 :            : 
    1291                 :          0 :         ENICPMD_FUNC_TRACE();
    1292                 :            :         /* Find 1st steer and decap */
    1293                 :          0 :         op = fm->action.fma_action_ops;
    1294                 :            :         steer = NULL;
    1295                 :            :         decap = NULL;
    1296         [ #  # ]:          0 :         while (op->fa_op != FMOP_END) {
    1297   [ #  #  #  # ]:          0 :                 if (!decap && (op->fa_op == FMOP_DECAP_NOSTRIP ||
    1298                 :            :                                op->fa_op == FMOP_DECAP_STRIP))
    1299                 :            :                         decap = op;
    1300   [ #  #  #  # ]:          0 :                 else if (!steer && op->fa_op == FMOP_RQ_STEER)
    1301                 :            :                         steer = op;
    1302                 :          0 :                 op++;
    1303                 :            :         }
    1304                 :            :         /* If decap is before steer, swap */
    1305   [ #  #  #  # ]:          0 :         if (steer && decap && decap < steer) {
    1306                 :            :                 op = fm->action.fma_action_ops;
    1307                 :          0 :                 ENICPMD_LOG(DEBUG, "swap decap %ld <-> steer %ld",
    1308                 :            :                             (long)(decap - op), (long)(steer - op));
    1309                 :          0 :                 tmp_op = *decap;
    1310                 :          0 :                 *decap = *steer;
    1311                 :          0 :                 *steer = tmp_op;
    1312                 :            :         }
    1313                 :          0 : }
    1314                 :            : 
    1315                 :            : /* VXLAN decap is done via flowman compound action */
    1316                 :            : static int
    1317                 :          0 : enic_fm_copy_vxlan_decap(struct enic_flowman *fm,
    1318                 :            :                          struct fm_tcam_match_entry *fmt,
    1319                 :            :                          const struct rte_flow_action *action,
    1320                 :            :                          struct rte_flow_error *error)
    1321                 :            : {
    1322                 :            :         struct fm_header_set *fm_data;
    1323                 :            :         struct fm_action_op fm_op;
    1324                 :            : 
    1325                 :          0 :         ENICPMD_FUNC_TRACE();
    1326                 :            :         fm_data = &fmt->ftm_data.fk_hdrset[0];
    1327         [ #  # ]:          0 :         if (!(fm_data->fk_metadata & FKM_VXLAN)) {
    1328                 :          0 :                 return rte_flow_error_set(error, EINVAL,
    1329                 :            :                         RTE_FLOW_ERROR_TYPE_ACTION, action,
    1330                 :            :                         "vxlan-decap: vxlan must be in pattern");
    1331                 :            :         }
    1332                 :            : 
    1333                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    1334                 :          0 :         fm_op.fa_op = FMOP_DECAP_NOSTRIP;
    1335                 :          0 :         return enic_fm_append_action_op(fm, &fm_op, error);
    1336                 :            : }
    1337                 :            : 
    1338                 :            : /* Generate a reasonable source port number */
    1339                 :            : static uint16_t
    1340                 :            : gen_src_port(void)
    1341                 :            : {
    1342                 :            :         /* Min/max below are the default values in OVS-DPDK and Linux */
    1343                 :          0 :         uint16_t p = rte_rand();
    1344                 :          0 :         p = RTE_MAX(p, 32768);
    1345                 :          0 :         p = RTE_MIN(p, 61000);
    1346         [ #  # ]:          0 :         return rte_cpu_to_be_16(p);
    1347                 :            : }
    1348                 :            : 
    1349                 :            : /* VXLAN encap is done via flowman compound action */
    1350                 :            : static int
    1351                 :          0 : enic_fm_copy_vxlan_encap(struct enic_flowman *fm,
    1352                 :            :                          const struct rte_flow_item *item,
    1353                 :            :                          struct rte_flow_error *error)
    1354                 :            : {
    1355                 :            :         struct fm_action_op fm_op;
    1356                 :            :         struct rte_ether_hdr *eth;
    1357                 :            :         struct rte_udp_hdr *udp;
    1358                 :            :         uint16_t *ethertype;
    1359                 :            :         void *template;
    1360                 :            :         uint8_t off;
    1361                 :            : 
    1362                 :          0 :         ENICPMD_FUNC_TRACE();
    1363                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    1364                 :          0 :         fm_op.fa_op = FMOP_ENCAP;
    1365                 :          0 :         template = fm->action.fma_data;
    1366                 :            :         off = 0;
    1367                 :            :         /*
    1368                 :            :          * Copy flow items to the flowman template starting L2.
    1369                 :            :          * L2 must be ethernet.
    1370                 :            :          */
    1371                 :            :         flow_item_skip_void(&item);
    1372         [ #  # ]:          0 :         if (item->type != RTE_FLOW_ITEM_TYPE_ETH)
    1373                 :          0 :                 return rte_flow_error_set(error, EINVAL,
    1374                 :            :                         RTE_FLOW_ERROR_TYPE_ITEM, item,
    1375                 :            :                         "vxlan-encap: first item should be ethernet");
    1376                 :            :         eth = (struct rte_ether_hdr *)template;
    1377                 :            :         ethertype = &eth->ether_type;
    1378                 :          0 :         append_template(&template, &off, item->spec,
    1379                 :            :                         sizeof(struct rte_ether_hdr));
    1380                 :          0 :         item++;
    1381                 :            :         flow_item_skip_void(&item);
    1382                 :            :         /* Optional VLAN */
    1383         [ #  # ]:          0 :         if (item->type == RTE_FLOW_ITEM_TYPE_VLAN) {
    1384                 :            :                 const struct rte_flow_item_vlan *spec;
    1385                 :            : 
    1386                 :          0 :                 ENICPMD_LOG(DEBUG, "vxlan-encap: vlan");
    1387                 :          0 :                 spec = item->spec;
    1388         [ #  # ]:          0 :                 fm_op.encap.outer_vlan = rte_be_to_cpu_16(spec->hdr.vlan_tci);
    1389                 :          0 :                 item++;
    1390                 :            :                 flow_item_skip_void(&item);
    1391                 :            :         }
    1392                 :            :         /* L3 must be IPv4, IPv6 */
    1393      [ #  #  # ]:          0 :         switch (item->type) {
    1394                 :          0 :         case RTE_FLOW_ITEM_TYPE_IPV4:
    1395                 :            :         {
    1396                 :            :                 struct rte_ipv4_hdr *ip4;
    1397                 :            : 
    1398                 :          0 :                 ENICPMD_LOG(DEBUG, "vxlan-encap: ipv4");
    1399                 :          0 :                 *ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
    1400                 :            :                 ip4 = (struct rte_ipv4_hdr *)template;
    1401                 :            :                 /*
    1402                 :            :                  * Offset of IPv4 length field and its initial value
    1403                 :            :                  * (IP + UDP + VXLAN) are specified in the action. The NIC
    1404                 :            :                  * will add inner packet length.
    1405                 :            :                  */
    1406                 :          0 :                 fm_op.encap.len1_offset = off +
    1407                 :            :                         offsetof(struct rte_ipv4_hdr, total_length);
    1408                 :          0 :                 fm_op.encap.len1_delta = sizeof(struct rte_ipv4_hdr) +
    1409                 :            :                         sizeof(struct rte_udp_hdr) +
    1410                 :            :                         sizeof(struct rte_vxlan_hdr);
    1411         [ #  # ]:          0 :                 append_template(&template, &off, item->spec,
    1412                 :            :                                 sizeof(struct rte_ipv4_hdr));
    1413                 :          0 :                 ip4->version_ihl = RTE_IPV4_VHL_DEF;
    1414         [ #  # ]:          0 :                 if (ip4->time_to_live == 0)
    1415                 :          0 :                         ip4->time_to_live = IP_DEFTTL;
    1416                 :          0 :                 ip4->next_proto_id = IPPROTO_UDP;
    1417                 :          0 :                 break;
    1418                 :            :         }
    1419                 :          0 :         case RTE_FLOW_ITEM_TYPE_IPV6:
    1420                 :            :         {
    1421                 :            :                 struct rte_ipv6_hdr *ip6;
    1422                 :            : 
    1423                 :          0 :                 ENICPMD_LOG(DEBUG, "vxlan-encap: ipv6");
    1424                 :          0 :                 *ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
    1425                 :            :                 ip6 = (struct rte_ipv6_hdr *)template;
    1426                 :          0 :                 fm_op.encap.len1_offset = off +
    1427                 :            :                         offsetof(struct rte_ipv6_hdr, payload_len);
    1428                 :          0 :                 fm_op.encap.len1_delta = sizeof(struct rte_udp_hdr) +
    1429                 :            :                         sizeof(struct rte_vxlan_hdr);
    1430         [ #  # ]:          0 :                 append_template(&template, &off, item->spec,
    1431                 :            :                                 sizeof(struct rte_ipv6_hdr));
    1432                 :          0 :                 ip6->vtc_flow |= rte_cpu_to_be_32(IP6_VTC_FLOW);
    1433         [ #  # ]:          0 :                 if (ip6->hop_limits == 0)
    1434                 :          0 :                         ip6->hop_limits = IP_DEFTTL;
    1435                 :          0 :                 ip6->proto = IPPROTO_UDP;
    1436                 :          0 :                 break;
    1437                 :            :         }
    1438                 :          0 :         default:
    1439                 :          0 :                 return rte_flow_error_set(error,
    1440                 :            :                         EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item,
    1441                 :            :                         "vxlan-encap: L3 must be IPv4/IPv6");
    1442                 :            :         }
    1443                 :          0 :         item++;
    1444                 :            :         flow_item_skip_void(&item);
    1445                 :            : 
    1446                 :            :         /* L4 is UDP */
    1447         [ #  # ]:          0 :         if (item->type != RTE_FLOW_ITEM_TYPE_UDP)
    1448                 :          0 :                 return rte_flow_error_set(error, EINVAL,
    1449                 :            :                         RTE_FLOW_ERROR_TYPE_ITEM, item,
    1450                 :            :                         "vxlan-encap: UDP must follow IPv4/IPv6");
    1451                 :            :         /* UDP length = UDP + VXLAN. NIC will add inner packet length. */
    1452                 :          0 :         fm_op.encap.len2_offset =
    1453                 :          0 :                 off + offsetof(struct rte_udp_hdr, dgram_len);
    1454                 :          0 :         fm_op.encap.len2_delta =
    1455                 :            :                 sizeof(struct rte_udp_hdr) + sizeof(struct rte_vxlan_hdr);
    1456                 :            :         udp = (struct rte_udp_hdr *)template;
    1457         [ #  # ]:          0 :         append_template(&template, &off, item->spec,
    1458                 :            :                         sizeof(struct rte_udp_hdr));
    1459                 :            :         /*
    1460                 :            :          * Firmware does not hash/fill source port yet. Generate a
    1461                 :            :          * random port, as there is *usually* one rte_flow for the
    1462                 :            :          * given inner packet stream (i.e. a single stream has one
    1463                 :            :          * random port).
    1464                 :            :          */
    1465         [ #  # ]:          0 :         if (udp->src_port == 0)
    1466                 :          0 :                 udp->src_port = gen_src_port();
    1467                 :          0 :         item++;
    1468                 :            :         flow_item_skip_void(&item);
    1469                 :            : 
    1470                 :            :         /* Finally VXLAN */
    1471         [ #  # ]:          0 :         if (item->type != RTE_FLOW_ITEM_TYPE_VXLAN)
    1472                 :          0 :                 return rte_flow_error_set(error,
    1473                 :            :                         EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item,
    1474                 :            :                         "vxlan-encap: VXLAN must follow UDP");
    1475                 :          0 :         append_template(&template, &off, item->spec,
    1476                 :            :                         sizeof(struct rte_flow_item_vxlan));
    1477                 :            : 
    1478                 :            :         /*
    1479                 :            :          * Fill in the rest of the action structure.
    1480                 :            :          * Indicate that we want to encap with vxlan at packet start.
    1481                 :            :          */
    1482                 :          0 :         fm_op.encap.template_offset = 0;
    1483                 :          0 :         fm_op.encap.template_len = off;
    1484                 :          0 :         return enic_fm_append_action_op(fm, &fm_op, error);
    1485                 :            : }
    1486                 :            : 
    1487                 :            : static int
    1488                 :          0 : enic_fm_find_vnic(struct enic *enic, const struct rte_pci_addr *addr,
    1489                 :            :                   uint64_t *handle)
    1490                 :            : {
    1491                 :            :         uint32_t bdf;
    1492                 :            :         uint64_t args[2];
    1493                 :            :         int rc;
    1494                 :            : 
    1495                 :          0 :         ENICPMD_FUNC_TRACE();
    1496                 :          0 :         ENICPMD_LOG(DEBUG, "bdf=%x:%x:%x", addr->bus, addr->devid,
    1497                 :            :                     addr->function);
    1498                 :          0 :         bdf = addr->bus << 8 | addr->devid << 3 | addr->function;
    1499                 :          0 :         args[0] = FM_VNIC_FIND;
    1500                 :          0 :         args[1] = bdf;
    1501                 :          0 :         rc = vnic_dev_flowman_cmd(enic->vdev, args, 2);
    1502         [ #  # ]:          0 :         if (rc != 0) {
    1503                 :            :                 /* Expected to fail if BDF is not on the adapter */
    1504                 :          0 :                 ENICPMD_LOG(DEBUG, "cannot find vnic handle: rc=%d", rc);
    1505                 :          0 :                 return rc;
    1506                 :            :         }
    1507                 :          0 :         *handle = args[0];
    1508                 :          0 :         ENICPMD_LOG(DEBUG, "found vnic: handle=0x%" PRIx64, *handle);
    1509                 :          0 :         return 0;
    1510                 :            : }
    1511                 :            : 
    1512                 :            : /*
    1513                 :            :  * Egress: target port should be either PF uplink or VF.
    1514                 :            :  * Supported cases
    1515                 :            :  * 1. VF egress -> PF uplink
    1516                 :            :  *   PF may be this VF's PF, or another PF, as long as they are on the same VIC.
    1517                 :            :  * 2. VF egress -> VF
    1518                 :            :  *
    1519                 :            :  * Unsupported cases
    1520                 :            :  * 1. PF egress -> VF
    1521                 :            :  *   App should be using representor to pass packets to VF
    1522                 :            :  */
    1523                 :            : static int
    1524                 :          0 : vf_egress_port_id_action(struct enic_flowman *fm,
    1525                 :            :                          struct rte_eth_dev *dst_dev,
    1526                 :            :                          uint64_t dst_vnic_h,
    1527                 :            :                          struct fm_action_op *fm_op,
    1528                 :            :                          struct rte_flow_error *error)
    1529                 :            : {
    1530                 :            :         struct enic *src_enic, *dst_enic;
    1531                 :            :         struct enic_vf_representor *vf;
    1532                 :            :         uint8_t uif;
    1533                 :            :         int ret;
    1534                 :            : 
    1535                 :          0 :         ENICPMD_FUNC_TRACE();
    1536         [ #  # ]:          0 :         src_enic = fm->user_enic;
    1537                 :            :         dst_enic = pmd_priv(dst_dev);
    1538         [ #  # ]:          0 :         if (!rte_eth_dev_is_repr(src_enic->rte_dev)) {
    1539                 :          0 :                 return rte_flow_error_set(error, EINVAL,
    1540                 :            :                         RTE_FLOW_ERROR_TYPE_ACTION,
    1541                 :            :                         NULL, "source port is not VF representor");
    1542                 :            :         }
    1543                 :            : 
    1544                 :            :         /* VF -> PF uplink. dst is not VF representor */
    1545         [ #  # ]:          0 :         if (!rte_eth_dev_is_repr(dst_dev)) {
    1546                 :            :                 /* PF is the VF's PF? Then nothing to do */
    1547                 :            :                 vf = VF_ENIC_TO_VF_REP(src_enic);
    1548         [ #  # ]:          0 :                 if (vf->pf == dst_enic) {
    1549                 :          0 :                         ENICPMD_LOG(DEBUG, "destination port is VF's PF");
    1550                 :          0 :                         return 0;
    1551                 :            :                 }
    1552                 :            :                 /* If not, steer to the remote PF's uplink */
    1553                 :          0 :                 uif = dst_enic->fm_vnic_uif;
    1554                 :          0 :                 ENICPMD_LOG(DEBUG, "steer to uplink %u", uif);
    1555                 :            :                 memset(fm_op, 0, sizeof(*fm_op));
    1556                 :          0 :                 fm_op->fa_op = FMOP_SET_EGPORT;
    1557                 :          0 :                 fm_op->set_egport.egport = uif;
    1558                 :          0 :                 ret = enic_fm_append_action_op(fm, fm_op, error);
    1559                 :          0 :                 return ret;
    1560                 :            :         }
    1561                 :            : 
    1562                 :            :         /* VF -> VF loopback. Hairpin and steer to vnic */
    1563                 :            :         memset(fm_op, 0, sizeof(*fm_op));
    1564                 :          0 :         fm_op->fa_op = FMOP_EG_HAIRPIN;
    1565                 :          0 :         ret = enic_fm_append_action_op(fm, fm_op, error);
    1566         [ #  # ]:          0 :         if (ret)
    1567                 :            :                 return ret;
    1568                 :          0 :         ENICPMD_LOG(DEBUG, "egress hairpin");
    1569                 :          0 :         fm->hairpin_steer_vnic_h = dst_vnic_h;
    1570                 :          0 :         fm->need_hairpin_steer = 1;
    1571                 :          0 :         return 0;
    1572                 :            : }
    1573                 :            : 
    1574                 :            : static int
    1575                 :          0 : enic_fm_check_transfer_dst(struct enic *enic, uint16_t dst_port_id,
    1576                 :            :                            struct rte_eth_dev **dst_dev,
    1577                 :            :                            struct rte_flow_error *error)
    1578                 :            : {
    1579                 :            :         struct rte_eth_dev *dev;
    1580                 :            : 
    1581                 :          0 :         ENICPMD_LOG(DEBUG, "port id %u", dst_port_id);
    1582         [ #  # ]:          0 :         if (!rte_eth_dev_is_valid_port(dst_port_id)) {
    1583                 :          0 :                 return rte_flow_error_set(error, EINVAL,
    1584                 :            :                         RTE_FLOW_ERROR_TYPE_ACTION,
    1585                 :            :                         NULL, "invalid port_id");
    1586                 :            :         }
    1587                 :          0 :         dev = &rte_eth_devices[dst_port_id];
    1588         [ #  # ]:          0 :         if (!dev_is_enic(dev)) {
    1589                 :          0 :                 return rte_flow_error_set(error, EINVAL,
    1590                 :            :                         RTE_FLOW_ERROR_TYPE_ACTION,
    1591                 :            :                         NULL, "port_id is not enic");
    1592                 :            :         }
    1593         [ #  # ]:          0 :         if (enic->switch_domain_id != pmd_priv(dev)->switch_domain_id) {
    1594                 :          0 :                 return rte_flow_error_set(error, EINVAL,
    1595                 :            :                         RTE_FLOW_ERROR_TYPE_ACTION,
    1596                 :            :                         NULL, "destination and source ports are not in the same switch domain");
    1597                 :            :         }
    1598                 :            : 
    1599                 :          0 :         *dst_dev = dev;
    1600                 :          0 :         return 0;
    1601                 :            : }
    1602                 :            : 
    1603                 :            : /* Translate flow actions to flowman TCAM entry actions */
    1604                 :            : static int
    1605                 :          0 : enic_fm_copy_action(struct enic_flowman *fm,
    1606                 :            :                     const struct rte_flow_action actions[],
    1607                 :            :                     uint8_t ingress,
    1608                 :            :                     struct rte_flow_error *error)
    1609                 :            : {
    1610                 :            :         enum {
    1611                 :            :                 FATE = 1 << 0,
    1612                 :            :                 DECAP = 1 << 1,
    1613                 :            :                 PASSTHRU = 1 << 2,
    1614                 :            :                 COUNT = 1 << 3,
    1615                 :            :                 ENCAP = 1 << 4,
    1616                 :            :                 PUSH_VLAN = 1 << 5,
    1617                 :            :                 PORT_ID = 1 << 6,
    1618                 :            :         };
    1619                 :            :         struct fm_tcam_match_entry *fmt;
    1620                 :            :         struct fm_action_op fm_op;
    1621                 :            :         bool need_ovlan_action;
    1622                 :            :         struct enic *enic;
    1623                 :            :         uint32_t overlap;
    1624                 :            :         uint64_t vnic_h;
    1625                 :            :         uint16_t ovlan;
    1626                 :            :         bool first_rq;
    1627                 :            :         bool steer;
    1628                 :            :         int ret;
    1629                 :            : 
    1630                 :          0 :         ENICPMD_FUNC_TRACE();
    1631                 :          0 :         fmt = &fm->tcam_entry;
    1632                 :            :         need_ovlan_action = false;
    1633                 :            :         ovlan = 0;
    1634                 :            :         first_rq = true;
    1635                 :            :         steer = false;
    1636                 :          0 :         enic = fm->user_enic;
    1637                 :            :         overlap = 0;
    1638                 :          0 :         vnic_h = enic->fm_vnic_handle;
    1639                 :            : 
    1640         [ #  # ]:          0 :         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
    1641   [ #  #  #  #  :          0 :                 switch (actions->type) {
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1642                 :          0 :                 case RTE_FLOW_ACTION_TYPE_VOID:
    1643                 :          0 :                         continue;
    1644                 :          0 :                 case RTE_FLOW_ACTION_TYPE_PASSTHRU: {
    1645         [ #  # ]:          0 :                         if (overlap & PASSTHRU)
    1646                 :          0 :                                 goto unsupported;
    1647                 :          0 :                         overlap |= PASSTHRU;
    1648                 :          0 :                         break;
    1649                 :            :                 }
    1650                 :          0 :                 case RTE_FLOW_ACTION_TYPE_JUMP: {
    1651                 :          0 :                         const struct rte_flow_action_jump *jump =
    1652                 :            :                                 actions->conf;
    1653                 :            :                         struct enic_fm_fet *fet;
    1654                 :            : 
    1655         [ #  # ]:          0 :                         if (overlap & FATE)
    1656                 :          0 :                                 goto unsupported;
    1657                 :          0 :                         ret = enic_fet_get(fm, jump->group, ingress, NULL,
    1658                 :            :                                            &fet, error);
    1659         [ #  # ]:          0 :                         if (ret)
    1660                 :          0 :                                 return ret;
    1661                 :          0 :                         overlap |= FATE;
    1662                 :            :                         memset(&fm_op, 0, sizeof(fm_op));
    1663                 :          0 :                         fm_op.fa_op = FMOP_EXACT_MATCH;
    1664                 :          0 :                         fm_op.exact.handle = fet->handle;
    1665                 :          0 :                         fm->fet = fet;
    1666                 :          0 :                         ret = enic_fm_append_action_op(fm, &fm_op, error);
    1667         [ #  # ]:          0 :                         if (ret)
    1668                 :          0 :                                 return ret;
    1669                 :          0 :                         break;
    1670                 :            :                 }
    1671                 :          0 :                 case RTE_FLOW_ACTION_TYPE_MARK: {
    1672                 :          0 :                         const struct rte_flow_action_mark *mark =
    1673                 :            :                                 actions->conf;
    1674                 :            : 
    1675         [ #  # ]:          0 :                         if (enic->use_noscatter_vec_rx_handler)
    1676                 :          0 :                                 goto unsupported;
    1677         [ #  # ]:          0 :                         if (mark->id >= ENIC_MAGIC_FILTER_ID - 1)
    1678                 :          0 :                                 return rte_flow_error_set(error, EINVAL,
    1679                 :            :                                         RTE_FLOW_ERROR_TYPE_ACTION,
    1680                 :            :                                         NULL, "invalid mark id");
    1681                 :            :                         memset(&fm_op, 0, sizeof(fm_op));
    1682                 :          0 :                         fm_op.fa_op = FMOP_MARK;
    1683                 :          0 :                         fm_op.mark.mark = mark->id + 1;
    1684                 :          0 :                         ret = enic_fm_append_action_op(fm, &fm_op, error);
    1685         [ #  # ]:          0 :                         if (ret)
    1686                 :          0 :                                 return ret;
    1687                 :            :                         break;
    1688                 :            :                 }
    1689                 :          0 :                 case RTE_FLOW_ACTION_TYPE_FLAG: {
    1690         [ #  # ]:          0 :                         if (enic->use_noscatter_vec_rx_handler)
    1691                 :          0 :                                 goto unsupported;
    1692                 :            :                         /* ENIC_MAGIC_FILTER_ID is reserved for flagging */
    1693                 :            :                         memset(&fm_op, 0, sizeof(fm_op));
    1694                 :          0 :                         fm_op.fa_op = FMOP_MARK;
    1695                 :          0 :                         fm_op.mark.mark = ENIC_MAGIC_FILTER_ID;
    1696                 :          0 :                         ret = enic_fm_append_action_op(fm, &fm_op, error);
    1697         [ #  # ]:          0 :                         if (ret)
    1698                 :          0 :                                 return ret;
    1699                 :            :                         break;
    1700                 :            :                 }
    1701                 :          0 :                 case RTE_FLOW_ACTION_TYPE_QUEUE: {
    1702                 :          0 :                         const struct rte_flow_action_queue *queue =
    1703                 :            :                                 actions->conf;
    1704                 :            : 
    1705                 :            :                         /*
    1706                 :            :                          * If fate other than QUEUE or RSS, fail. Multiple
    1707                 :            :                          * rss and queue actions are ok.
    1708                 :            :                          */
    1709   [ #  #  #  # ]:          0 :                         if ((overlap & FATE) && first_rq)
    1710                 :          0 :                                 goto unsupported;
    1711                 :            :                         first_rq = false;
    1712                 :          0 :                         overlap |= FATE;
    1713                 :            :                         memset(&fm_op, 0, sizeof(fm_op));
    1714                 :          0 :                         fm_op.fa_op = FMOP_RQ_STEER;
    1715                 :          0 :                         fm_op.rq_steer.rq_index =
    1716                 :          0 :                                 enic_rte_rq_idx_to_sop_idx(queue->index);
    1717                 :          0 :                         fm_op.rq_steer.rq_count = 1;
    1718                 :          0 :                         fm_op.rq_steer.vnic_handle = vnic_h;
    1719                 :          0 :                         ret = enic_fm_append_action_op(fm, &fm_op, error);
    1720         [ #  # ]:          0 :                         if (ret)
    1721                 :          0 :                                 return ret;
    1722                 :          0 :                         ENICPMD_LOG(DEBUG, "create QUEUE action rq: %u",
    1723                 :            :                                     fm_op.rq_steer.rq_index);
    1724                 :            :                         steer = true;
    1725                 :          0 :                         break;
    1726                 :            :                 }
    1727                 :          0 :                 case RTE_FLOW_ACTION_TYPE_DROP: {
    1728         [ #  # ]:          0 :                         if (overlap & FATE)
    1729                 :          0 :                                 goto unsupported;
    1730                 :          0 :                         overlap |= FATE;
    1731                 :            :                         memset(&fm_op, 0, sizeof(fm_op));
    1732                 :          0 :                         fm_op.fa_op = FMOP_DROP;
    1733                 :          0 :                         ret = enic_fm_append_action_op(fm, &fm_op, error);
    1734         [ #  # ]:          0 :                         if (ret)
    1735                 :          0 :                                 return ret;
    1736                 :          0 :                         ENICPMD_LOG(DEBUG, "create DROP action");
    1737                 :          0 :                         break;
    1738                 :            :                 }
    1739                 :          0 :                 case RTE_FLOW_ACTION_TYPE_COUNT: {
    1740         [ #  # ]:          0 :                         if (overlap & COUNT)
    1741                 :          0 :                                 goto unsupported;
    1742                 :          0 :                         overlap |= COUNT;
    1743                 :            :                         /* Count is associated with entry not action on VIC. */
    1744                 :          0 :                         fmt->ftm_flags |= FMEF_COUNTER;
    1745                 :          0 :                         break;
    1746                 :            :                 }
    1747                 :          0 :                 case RTE_FLOW_ACTION_TYPE_RSS: {
    1748                 :          0 :                         const struct rte_flow_action_rss *rss = actions->conf;
    1749                 :            :                         bool allow;
    1750                 :            :                         uint16_t i;
    1751                 :            : 
    1752                 :            :                         /*
    1753                 :            :                          * If fate other than QUEUE or RSS, fail. Multiple
    1754                 :            :                          * rss and queue actions are ok.
    1755                 :            :                          */
    1756   [ #  #  #  # ]:          0 :                         if ((overlap & FATE) && first_rq)
    1757                 :          0 :                                 goto unsupported;
    1758                 :            :                         first_rq = false;
    1759                 :          0 :                         overlap |= FATE;
    1760                 :            : 
    1761                 :            :                         /*
    1762                 :            :                          * Hardware only supports RSS actions on outer level
    1763                 :            :                          * with default type and function. Queues must be
    1764                 :            :                          * sequential.
    1765                 :            :                          */
    1766                 :          0 :                         allow = rss->func == RTE_ETH_HASH_FUNCTION_DEFAULT &&
    1767         [ #  # ]:          0 :                                 rss->level == 0 && (rss->types == 0 ||
    1768         [ #  # ]:          0 :                                 rss->types == enic->rss_hf) &&
    1769   [ #  #  #  # ]:          0 :                                 rss->queue_num <= enic->rq_count &&
    1770         [ #  # ]:          0 :                                 rss->queue[rss->queue_num - 1] < enic->rq_count;
    1771                 :            : 
    1772                 :            : 
    1773                 :            :                         /* Identity queue map needs to be sequential */
    1774         [ #  # ]:          0 :                         for (i = 1; i < rss->queue_num; i++)
    1775         [ #  # ]:          0 :                                 allow = allow && (rss->queue[i] ==
    1776         [ #  # ]:          0 :                                         rss->queue[i - 1] + 1);
    1777         [ #  # ]:          0 :                         if (!allow)
    1778                 :          0 :                                 goto unsupported;
    1779                 :            : 
    1780                 :            :                         memset(&fm_op, 0, sizeof(fm_op));
    1781                 :          0 :                         fm_op.fa_op = FMOP_RQ_STEER;
    1782                 :          0 :                         fm_op.rq_steer.rq_index =
    1783                 :          0 :                                 enic_rte_rq_idx_to_sop_idx(rss->queue[0]);
    1784                 :          0 :                         fm_op.rq_steer.rq_count = rss->queue_num;
    1785                 :          0 :                         fm_op.rq_steer.vnic_handle = vnic_h;
    1786                 :          0 :                         ret = enic_fm_append_action_op(fm, &fm_op, error);
    1787         [ #  # ]:          0 :                         if (ret)
    1788                 :          0 :                                 return ret;
    1789                 :          0 :                         ENICPMD_LOG(DEBUG, "create QUEUE action rq: %u",
    1790                 :            :                                     fm_op.rq_steer.rq_index);
    1791                 :            :                         steer = true;
    1792                 :          0 :                         break;
    1793                 :            :                 }
    1794                 :          0 :                 case RTE_FLOW_ACTION_TYPE_PORT_ID: {
    1795                 :            :                         const struct rte_flow_action_port_id *port;
    1796                 :          0 :                         struct rte_eth_dev *dev = NULL;
    1797                 :            : 
    1798   [ #  #  #  # ]:          0 :                         if (!ingress && (overlap & PORT_ID)) {
    1799                 :          0 :                                 ENICPMD_LOG(DEBUG, "cannot have multiple egress PORT_ID actions");
    1800                 :          0 :                                 goto unsupported;
    1801                 :            :                         }
    1802                 :          0 :                         port = actions->conf;
    1803         [ #  # ]:          0 :                         if (port->original) {
    1804                 :          0 :                                 vnic_h = enic->fm_vnic_handle; /* This port */
    1805                 :          0 :                                 break;
    1806                 :            :                         }
    1807                 :          0 :                         ret = enic_fm_check_transfer_dst(enic, port->id, &dev,
    1808                 :            :                                                          error);
    1809         [ #  # ]:          0 :                         if (ret)
    1810                 :          0 :                                 return ret;
    1811         [ #  # ]:          0 :                         vnic_h = pmd_priv(dev)->fm_vnic_handle;
    1812                 :          0 :                         overlap |= PORT_ID;
    1813                 :            :                         /*
    1814                 :            :                          * Ingress. Nothing more to do. We add an implicit
    1815                 :            :                          * steer at the end if needed.
    1816                 :            :                          */
    1817         [ #  # ]:          0 :                         if (ingress)
    1818                 :            :                                 break;
    1819                 :            :                         /* Egress */
    1820                 :          0 :                         ret = vf_egress_port_id_action(fm, dev, vnic_h, &fm_op,
    1821                 :            :                                 error);
    1822         [ #  # ]:          0 :                         if (ret)
    1823                 :          0 :                                 return ret;
    1824                 :            :                         break;
    1825                 :            :                 }
    1826                 :          0 :                 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: {
    1827         [ #  # ]:          0 :                         if (overlap & DECAP)
    1828                 :          0 :                                 goto unsupported;
    1829                 :          0 :                         overlap |= DECAP;
    1830                 :            : 
    1831                 :          0 :                         ret = enic_fm_copy_vxlan_decap(fm, fmt, actions,
    1832                 :            :                                 error);
    1833         [ #  # ]:          0 :                         if (ret != 0)
    1834                 :          0 :                                 return ret;
    1835                 :            :                         break;
    1836                 :            :                 }
    1837                 :          0 :                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: {
    1838                 :            :                         const struct rte_flow_action_vxlan_encap *encap;
    1839                 :            : 
    1840                 :          0 :                         encap = actions->conf;
    1841         [ #  # ]:          0 :                         if (overlap & ENCAP)
    1842                 :          0 :                                 goto unsupported;
    1843                 :          0 :                         overlap |= ENCAP;
    1844                 :          0 :                         ret = enic_fm_copy_vxlan_encap(fm, encap->definition,
    1845                 :            :                                 error);
    1846         [ #  # ]:          0 :                         if (ret != 0)
    1847                 :          0 :                                 return ret;
    1848                 :            :                         break;
    1849                 :            :                 }
    1850                 :            :                 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: {
    1851                 :            :                         struct fm_action_op *decap;
    1852                 :            : 
    1853                 :            :                         /*
    1854                 :            :                          * If decap-nostrip appears before pop vlan, this pop
    1855                 :            :                          * applies to the inner packet vlan. Turn it into
    1856                 :            :                          * decap-strip.
    1857                 :            :                          */
    1858                 :            :                         decap = find_prev_action_op(fm, FMOP_DECAP_NOSTRIP);
    1859         [ #  # ]:          0 :                         if (decap) {
    1860                 :          0 :                                 ENICPMD_LOG(DEBUG, "pop-vlan inner: decap-nostrip => decap-strip");
    1861                 :          0 :                                 decap->fa_op = FMOP_DECAP_STRIP;
    1862                 :          0 :                                 break;
    1863                 :            :                         }
    1864                 :            :                         memset(&fm_op, 0, sizeof(fm_op));
    1865                 :          0 :                         fm_op.fa_op = FMOP_POP_VLAN;
    1866                 :          0 :                         ret = enic_fm_append_action_op(fm, &fm_op, error);
    1867         [ #  # ]:          0 :                         if (ret)
    1868                 :          0 :                                 return ret;
    1869                 :            :                         break;
    1870                 :            :                 }
    1871                 :          0 :                 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: {
    1872                 :            :                         const struct rte_flow_action_of_push_vlan *vlan;
    1873                 :            : 
    1874         [ #  # ]:          0 :                         if (overlap & PASSTHRU)
    1875                 :          0 :                                 goto unsupported;
    1876                 :          0 :                         vlan = actions->conf;
    1877         [ #  # ]:          0 :                         if (vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN)) {
    1878                 :          0 :                                 return rte_flow_error_set(error, EINVAL,
    1879                 :            :                                         RTE_FLOW_ERROR_TYPE_ACTION,
    1880                 :            :                                         NULL, "unexpected push_vlan ethertype");
    1881                 :            :                         }
    1882                 :          0 :                         overlap |= PUSH_VLAN;
    1883                 :            :                         need_ovlan_action = true;
    1884                 :          0 :                         break;
    1885                 :            :                 }
    1886                 :          0 :                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: {
    1887                 :            :                         const struct rte_flow_action_of_set_vlan_pcp *pcp;
    1888                 :            : 
    1889                 :          0 :                         pcp = actions->conf;
    1890         [ #  # ]:          0 :                         if (pcp->vlan_pcp > 7) {
    1891                 :          0 :                                 return rte_flow_error_set(error, EINVAL,
    1892                 :            :                                         RTE_FLOW_ERROR_TYPE_ACTION,
    1893                 :            :                                         NULL, "invalid vlan_pcp");
    1894                 :            :                         }
    1895                 :            :                         need_ovlan_action = true;
    1896                 :          0 :                         ovlan |= ((uint16_t)pcp->vlan_pcp) << 13;
    1897                 :          0 :                         break;
    1898                 :            :                 }
    1899                 :          0 :                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: {
    1900                 :            :                         const struct rte_flow_action_of_set_vlan_vid *vid;
    1901                 :            : 
    1902                 :          0 :                         vid = actions->conf;
    1903                 :            :                         need_ovlan_action = true;
    1904         [ #  # ]:          0 :                         ovlan |= rte_be_to_cpu_16(vid->vlan_vid);
    1905                 :          0 :                         break;
    1906                 :            :                 }
    1907                 :          0 :                 case RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR: {
    1908                 :            :                         const struct rte_flow_action_ethdev *ethdev;
    1909                 :          0 :                         struct rte_eth_dev *dev = NULL;
    1910                 :            : 
    1911                 :          0 :                         ethdev = actions->conf;
    1912                 :          0 :                         ret = enic_fm_check_transfer_dst(enic, ethdev->port_id,
    1913                 :            :                                                          &dev, error);
    1914         [ #  # ]:          0 :                         if (ret)
    1915                 :          0 :                                 return ret;
    1916                 :          0 :                         vnic_h = pmd_priv(dev)->fm_vnic_handle;
    1917                 :          0 :                         overlap |= PORT_ID;
    1918                 :            :                         /*
    1919                 :            :                          * Action PORT_REPRESENTOR implies ingress destination.
    1920                 :            :                          * Noting to do. We add an implicit stree at the
    1921                 :            :                          * end if needed.
    1922                 :            :                          */
    1923                 :            :                         ingress = 1;
    1924                 :          0 :                         break;
    1925                 :            :                 }
    1926                 :          0 :                 case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: {
    1927                 :            :                         const struct rte_flow_action_ethdev *ethdev;
    1928                 :          0 :                         struct rte_eth_dev *dev = NULL;
    1929                 :            : 
    1930         [ #  # ]:          0 :                         if (overlap & PORT_ID) {
    1931                 :          0 :                                 ENICPMD_LOG(DEBUG, "cannot have multiple egress PORT_ID actions");
    1932                 :          0 :                                 goto unsupported;
    1933                 :            :                         }
    1934                 :          0 :                         ethdev = actions->conf;
    1935                 :          0 :                         ret = enic_fm_check_transfer_dst(enic, ethdev->port_id,
    1936                 :            :                                                          &dev, error);
    1937         [ #  # ]:          0 :                         if (ret)
    1938                 :          0 :                                 return ret;
    1939                 :          0 :                         vnic_h = pmd_priv(dev)->fm_vnic_handle;
    1940                 :          0 :                         overlap |= PORT_ID;
    1941                 :            :                         /* Action REPRESENTED_PORT: always egress destination */
    1942                 :            :                         ingress = 0;
    1943                 :          0 :                         ret = vf_egress_port_id_action(fm, dev, vnic_h, &fm_op,
    1944                 :            :                                 error);
    1945         [ #  # ]:          0 :                         if (ret)
    1946                 :          0 :                                 return ret;
    1947                 :          0 :                         break;
    1948                 :            :                 }
    1949                 :          0 :                 default:
    1950                 :          0 :                         goto unsupported;
    1951                 :            :                 }
    1952                 :            :         }
    1953                 :            : 
    1954         [ #  # ]:          0 :         if (!(overlap & (FATE | PASSTHRU | COUNT | PORT_ID)))
    1955                 :          0 :                 goto unsupported;
    1956                 :            :         /* Egress from VF: need implicit WQ match */
    1957   [ #  #  #  # ]:          0 :         if (rte_eth_dev_is_repr(enic->rte_dev) && !ingress) {
    1958                 :          0 :                 fmt->ftm_data.fk_wq_id = 0;
    1959                 :          0 :                 fmt->ftm_mask.fk_wq_id = 0xffff;
    1960                 :          0 :                 fmt->ftm_data.fk_wq_vnic = enic->fm_vnic_handle;
    1961                 :          0 :                 ENICPMD_LOG(DEBUG, "add implicit wq id match for vf %d",
    1962                 :            :                             VF_ENIC_TO_VF_REP(enic)->vf_id);
    1963                 :            :         }
    1964         [ #  # ]:          0 :         if (need_ovlan_action) {
    1965                 :            :                 memset(&fm_op, 0, sizeof(fm_op));
    1966                 :          0 :                 fm_op.fa_op = FMOP_SET_OVLAN;
    1967                 :          0 :                 fm_op.ovlan.vlan = ovlan;
    1968                 :          0 :                 ret = enic_fm_append_action_op(fm, &fm_op, error);
    1969         [ #  # ]:          0 :                 if (ret)
    1970                 :            :                         return ret;
    1971                 :            :         }
    1972                 :            :         /* Add steer op for PORT_ID without QUEUE */
    1973   [ #  #  #  # ]:          0 :         if ((overlap & PORT_ID) && !steer && ingress) {
    1974                 :            :                 memset(&fm_op, 0, sizeof(fm_op));
    1975                 :            :                 /* Always to queue 0 for now as generic RSS is not available */
    1976                 :          0 :                 fm_op.fa_op = FMOP_RQ_STEER;
    1977                 :            :                 fm_op.rq_steer.rq_index = 0;
    1978                 :          0 :                 fm_op.rq_steer.vnic_handle = vnic_h;
    1979                 :          0 :                 ret = enic_fm_append_action_op(fm, &fm_op, error);
    1980         [ #  # ]:          0 :                 if (ret)
    1981                 :            :                         return ret;
    1982                 :          0 :                 ENICPMD_LOG(DEBUG, "add implicit steer op");
    1983                 :            :         }
    1984                 :            :         /* Add required END */
    1985                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    1986                 :          0 :         fm_op.fa_op = FMOP_END;
    1987                 :          0 :         ret = enic_fm_append_action_op(fm, &fm_op, error);
    1988         [ #  # ]:          0 :         if (ret)
    1989                 :            :                 return ret;
    1990                 :          0 :         enic_fm_reorder_action_op(fm);
    1991                 :          0 :         return 0;
    1992                 :            : 
    1993                 :          0 : unsupported:
    1994                 :          0 :         return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
    1995                 :            :                                   NULL, "enic: unsupported action");
    1996                 :            : }
    1997                 :            : 
    1998                 :            : /** Check if the action is supported */
    1999                 :            : static int
    2000                 :            : enic_fm_match_action(const struct rte_flow_action *action,
    2001                 :            :                      const enum rte_flow_action_type *supported_actions)
    2002                 :            : {
    2003         [ #  # ]:          0 :         for (; *supported_actions != RTE_FLOW_ACTION_TYPE_END;
    2004                 :          0 :              supported_actions++) {
    2005         [ #  # ]:          0 :                 if (action->type == *supported_actions)
    2006                 :            :                         return 1;
    2007                 :            :         }
    2008                 :            :         return 0;
    2009                 :            : }
    2010                 :            : 
    2011                 :            : /* Debug function to dump internal NIC action structure. */
    2012                 :            : static void
    2013                 :          0 : enic_fm_dump_tcam_actions(const struct fm_action *fm_action)
    2014                 :            : {
    2015                 :            :         /* Manually keep in sync with FMOP commands */
    2016                 :          0 :         const char *fmop_str[FMOP_OP_MAX] = {
    2017                 :            :                 [FMOP_END] = "end",
    2018                 :            :                 [FMOP_DROP] = "drop",
    2019                 :            :                 [FMOP_RQ_STEER] = "steer",
    2020                 :            :                 [FMOP_EXACT_MATCH] = "exmatch",
    2021                 :            :                 [FMOP_MARK] = "mark",
    2022                 :            :                 [FMOP_EXT_MARK] = "ext_mark",
    2023                 :            :                 [FMOP_TAG] = "tag",
    2024                 :            :                 [FMOP_EG_HAIRPIN] = "eg_hairpin",
    2025                 :            :                 [FMOP_IG_HAIRPIN] = "ig_hairpin",
    2026                 :            :                 [FMOP_ENCAP_IVLAN] = "encap_ivlan",
    2027                 :            :                 [FMOP_ENCAP_NOIVLAN] = "encap_noivlan",
    2028                 :            :                 [FMOP_ENCAP] = "encap",
    2029                 :            :                 [FMOP_SET_OVLAN] = "set_ovlan",
    2030                 :            :                 [FMOP_DECAP_NOSTRIP] = "decap_nostrip",
    2031                 :            :                 [FMOP_DECAP_STRIP] = "decap_strip",
    2032                 :            :                 [FMOP_POP_VLAN] = "pop_vlan",
    2033                 :            :                 [FMOP_SET_EGPORT] = "set_egport",
    2034                 :            :                 [FMOP_RQ_STEER_ONLY] = "rq_steer_only",
    2035                 :            :                 [FMOP_SET_ENCAP_VLAN] = "set_encap_vlan",
    2036                 :            :                 [FMOP_EMIT] = "emit",
    2037                 :            :                 [FMOP_MODIFY] = "modify",
    2038                 :            :         };
    2039                 :          0 :         const struct fm_action_op *op = &fm_action->fma_action_ops[0];
    2040                 :            :         char buf[128], *bp = buf;
    2041                 :            :         const char *op_str;
    2042                 :            :         int i, n, buf_len;
    2043                 :            : 
    2044                 :          0 :         buf[0] = '\0';
    2045                 :            :         buf_len = sizeof(buf);
    2046         [ #  # ]:          0 :         for (i = 0; i < FM_ACTION_OP_MAX; i++) {
    2047         [ #  # ]:          0 :                 if (op->fa_op == FMOP_END)
    2048                 :            :                         break;
    2049         [ #  # ]:          0 :                 if (op->fa_op >= FMOP_OP_MAX)
    2050                 :            :                         op_str = "unknown";
    2051                 :            :                 else
    2052                 :          0 :                         op_str = fmop_str[op->fa_op];
    2053         [ #  # ]:          0 :                 n = snprintf(bp, buf_len, "%s,", op_str);
    2054         [ #  # ]:          0 :                 if (n > 0 && n < buf_len) {
    2055                 :          0 :                         bp += n;
    2056                 :          0 :                         buf_len -= n;
    2057                 :            :                 }
    2058                 :          0 :                 op++;
    2059                 :            :         }
    2060                 :            :         /* Remove trailing comma */
    2061         [ #  # ]:          0 :         if (buf[0])
    2062                 :          0 :                 *(bp - 1) = '\0';
    2063                 :          0 :         ENICPMD_LOG(DEBUG, "       Actions: %s", buf);
    2064                 :          0 : }
    2065                 :            : 
    2066                 :            : static int
    2067                 :          0 : bits_to_str(uint32_t bits, const char *strings[], int max,
    2068                 :            :             char *buf, int buf_len)
    2069                 :            : {
    2070                 :            :         int i, n = 0, len = 0;
    2071                 :            : 
    2072         [ #  # ]:          0 :         for (i = 0; i < max; i++) {
    2073         [ #  # ]:          0 :                 if (bits & (1 << i)) {
    2074         [ #  # ]:          0 :                         n = snprintf(buf, buf_len, "%s,", strings[i]);
    2075         [ #  # ]:          0 :                         if (n > 0 && n < buf_len) {
    2076                 :          0 :                                 buf += n;
    2077                 :          0 :                                 buf_len -= n;
    2078                 :          0 :                                 len += n;
    2079                 :            :                         }
    2080                 :            :                 }
    2081                 :            :         }
    2082                 :            :         /* Remove trailing comma */
    2083         [ #  # ]:          0 :         if (len) {
    2084                 :          0 :                 *(buf - 1) = '\0';
    2085                 :          0 :                 len--;
    2086                 :            :         }
    2087                 :          0 :         return len;
    2088                 :            : }
    2089                 :            : 
    2090                 :            : /* Debug function to dump internal NIC filter structure. */
    2091                 :            : static void
    2092                 :          0 : __enic_fm_dump_tcam_match(const struct fm_header_set *fk_hdrset, char *buf,
    2093                 :            :                           int buf_len)
    2094                 :            : {
    2095                 :            :         /* Manually keep in sync with FKM_BITS */
    2096                 :          0 :         const char *fm_fkm_str[FKM_BIT_COUNT] = {
    2097                 :            :                 [FKM_QTAG_BIT] = "qtag",
    2098                 :            :                 [FKM_CMD_BIT] = "cmd",
    2099                 :            :                 [FKM_IPV4_BIT] = "ip4",
    2100                 :            :                 [FKM_IPV6_BIT] = "ip6",
    2101                 :            :                 [FKM_ROCE_BIT] = "roce",
    2102                 :            :                 [FKM_UDP_BIT] = "udp",
    2103                 :            :                 [FKM_TCP_BIT] = "tcp",
    2104                 :            :                 [FKM_TCPORUDP_BIT] = "tcpportudp",
    2105                 :            :                 [FKM_IPFRAG_BIT] = "ipfrag",
    2106                 :            :                 [FKM_NVGRE_BIT] = "nvgre",
    2107                 :            :                 [FKM_VXLAN_BIT] = "vxlan",
    2108                 :            :                 [FKM_GENEVE_BIT] = "geneve",
    2109                 :            :                 [FKM_NSH_BIT] = "nsh",
    2110                 :            :                 [FKM_ROCEV2_BIT] = "rocev2",
    2111                 :            :                 [FKM_VLAN_PRES_BIT] = "vlan_pres",
    2112                 :            :                 [FKM_IPOK_BIT] = "ipok",
    2113                 :            :                 [FKM_L4OK_BIT] = "l4ok",
    2114                 :            :                 [FKM_ROCEOK_BIT] = "roceok",
    2115                 :            :                 [FKM_FCSOK_BIT] = "fcsok",
    2116                 :            :                 [FKM_EG_SPAN_BIT] = "eg_span",
    2117                 :            :                 [FKM_IG_SPAN_BIT] = "ig_span",
    2118                 :            :                 [FKM_EG_HAIRPINNED_BIT] = "eg_hairpinned",
    2119                 :            :         };
    2120                 :            :         /* Manually keep in sync with FKH_BITS */
    2121                 :          0 :         const char *fm_fkh_str[FKH_BIT_COUNT] = {
    2122                 :            :                 [FKH_ETHER_BIT] = "eth",
    2123                 :            :                 [FKH_QTAG_BIT] = "qtag",
    2124                 :            :                 [FKH_L2RAW_BIT] = "l2raw",
    2125                 :            :                 [FKH_IPV4_BIT] = "ip4",
    2126                 :            :                 [FKH_IPV6_BIT] = "ip6",
    2127                 :            :                 [FKH_L3RAW_BIT] = "l3raw",
    2128                 :            :                 [FKH_UDP_BIT] = "udp",
    2129                 :            :                 [FKH_TCP_BIT] = "tcp",
    2130                 :            :                 [FKH_ICMP_BIT] = "icmp",
    2131                 :            :                 [FKH_VXLAN_BIT] = "vxlan",
    2132                 :            :                 [FKH_L4RAW_BIT] = "l4raw",
    2133                 :            :         };
    2134                 :          0 :         uint32_t fkh_bits = fk_hdrset->fk_header_select;
    2135                 :          0 :         uint32_t fkm_bits = fk_hdrset->fk_metadata;
    2136                 :            :         int n;
    2137                 :            : 
    2138         [ #  # ]:          0 :         if (!fkm_bits && !fkh_bits)
    2139                 :          0 :                 return;
    2140         [ #  # ]:          0 :         n = snprintf(buf, buf_len, "metadata(");
    2141         [ #  # ]:          0 :         if (n > 0 && n < buf_len) {
    2142                 :          0 :                 buf += n;
    2143                 :          0 :                 buf_len -= n;
    2144                 :            :         }
    2145                 :          0 :         n = bits_to_str(fkm_bits, fm_fkm_str, FKM_BIT_COUNT, buf, buf_len);
    2146         [ #  # ]:          0 :         if (n > 0 && n < buf_len) {
    2147                 :          0 :                 buf += n;
    2148                 :          0 :                 buf_len -= n;
    2149                 :            :         }
    2150         [ #  # ]:          0 :         n = snprintf(buf, buf_len, ") valid hdr fields(");
    2151         [ #  # ]:          0 :         if (n > 0 && n < buf_len) {
    2152                 :          0 :                 buf += n;
    2153                 :          0 :                 buf_len -= n;
    2154                 :            :         }
    2155                 :          0 :         n = bits_to_str(fkh_bits, fm_fkh_str, FKH_BIT_COUNT, buf, buf_len);
    2156         [ #  # ]:          0 :         if (n > 0 && n < buf_len) {
    2157                 :          0 :                 buf += n;
    2158                 :          0 :                 buf_len -= n;
    2159                 :            :         }
    2160                 :          0 :         snprintf(buf, buf_len, ")");
    2161                 :            : }
    2162                 :            : 
    2163                 :            : static void
    2164                 :          0 : enic_fm_dump_tcam_match(const struct fm_tcam_match_entry *match,
    2165                 :            :                         uint8_t ingress)
    2166                 :            : {
    2167                 :            :         char buf[256];
    2168                 :            : 
    2169                 :            :         memset(buf, 0, sizeof(buf));
    2170                 :          0 :         __enic_fm_dump_tcam_match(&match->ftm_mask.fk_hdrset[0],
    2171                 :            :                                   buf, sizeof(buf));
    2172   [ #  #  #  # ]:          0 :         ENICPMD_LOG(DEBUG, " TCAM %s Outer: %s %scounter position %u",
    2173                 :            :                     (ingress) ? "IG" : "EG", buf,
    2174                 :            :                     (match->ftm_flags & FMEF_COUNTER) ? "" : "no ",
    2175                 :            :                     match->ftm_position);
    2176                 :            :         memset(buf, 0, sizeof(buf));
    2177                 :          0 :         __enic_fm_dump_tcam_match(&match->ftm_mask.fk_hdrset[1],
    2178                 :            :                                   buf, sizeof(buf));
    2179         [ #  # ]:          0 :         if (buf[0])
    2180                 :          0 :                 ENICPMD_LOG(DEBUG, "         Inner: %s", buf);
    2181                 :          0 : }
    2182                 :            : 
    2183                 :            : /* Debug function to dump internal NIC flow structures. */
    2184                 :            : static void
    2185                 :          0 : enic_fm_dump_tcam_entry(const struct fm_tcam_match_entry *fm_match,
    2186                 :            :                         const struct fm_action *fm_action,
    2187                 :            :                         uint8_t ingress)
    2188                 :            : {
    2189         [ #  # ]:          0 :         if (!rte_log_can_log(enic_pmd_logtype, RTE_LOG_DEBUG))
    2190                 :            :                 return;
    2191                 :          0 :         enic_fm_dump_tcam_match(fm_match, ingress);
    2192                 :          0 :         enic_fm_dump_tcam_actions(fm_action);
    2193                 :            : }
    2194                 :            : 
    2195                 :            : static int
    2196                 :          0 : enic_fm_flow_parse(struct enic_flowman *fm,
    2197                 :            :                    const struct rte_flow_attr *attrs,
    2198                 :            :                    const struct rte_flow_item pattern[],
    2199                 :            :                    const struct rte_flow_action actions[],
    2200                 :            :                    struct rte_flow_error *error)
    2201                 :            : {
    2202                 :            :         const struct rte_flow_action *action;
    2203                 :            :         unsigned int ret;
    2204                 :            :         static const enum rte_flow_action_type *sa;
    2205                 :            : 
    2206                 :          0 :         ENICPMD_FUNC_TRACE();
    2207                 :            :         ret = 0;
    2208         [ #  # ]:          0 :         if (!pattern) {
    2209                 :          0 :                 rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_NUM,
    2210                 :            :                                    NULL, "no pattern specified");
    2211                 :          0 :                 return -rte_errno;
    2212                 :            :         }
    2213                 :            : 
    2214         [ #  # ]:          0 :         if (!actions) {
    2215                 :          0 :                 rte_flow_error_set(error, EINVAL,
    2216                 :            :                                    RTE_FLOW_ERROR_TYPE_ACTION_NUM,
    2217                 :            :                                    NULL, "no action specified");
    2218                 :          0 :                 return -rte_errno;
    2219                 :            :         }
    2220                 :            : 
    2221         [ #  # ]:          0 :         if (attrs) {
    2222   [ #  #  #  # ]:          0 :                 if (attrs->group != FM_TCAM_RTE_GROUP && attrs->priority) {
    2223                 :          0 :                         rte_flow_error_set(error, ENOTSUP,
    2224                 :            :                                            RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
    2225                 :            :                                            NULL,
    2226                 :            :                                            "priorities are not supported for non-default (0) groups");
    2227                 :          0 :                         return -rte_errno;
    2228   [ #  #  #  # ]:          0 :                 } else if (!fm->owner_enic->switchdev_mode && attrs->transfer) {
    2229                 :          0 :                         rte_flow_error_set(error, ENOTSUP,
    2230                 :            :                                            RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
    2231                 :            :                                            NULL,
    2232                 :            :                                            "transfer is not supported");
    2233                 :          0 :                         return -rte_errno;
    2234         [ #  # ]:          0 :                 } else if (attrs->ingress && attrs->egress) {
    2235                 :          0 :                         rte_flow_error_set(error, ENOTSUP,
    2236                 :            :                                            RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
    2237                 :            :                                            NULL,
    2238                 :            :                                            "bidirectional rules not supported");
    2239                 :          0 :                         return -rte_errno;
    2240                 :            :                 }
    2241                 :            : 
    2242                 :            :         } else {
    2243                 :          0 :                 rte_flow_error_set(error, EINVAL,
    2244                 :            :                                    RTE_FLOW_ERROR_TYPE_ATTR,
    2245                 :            :                                    NULL, "no attribute specified");
    2246                 :          0 :                 return -rte_errno;
    2247                 :            :         }
    2248                 :            : 
    2249                 :            :         /* Verify Actions. */
    2250         [ #  # ]:          0 :         sa = (attrs->ingress) ? enic_fm_supported_ig_actions :
    2251                 :            :              enic_fm_supported_eg_actions;
    2252         [ #  # ]:          0 :         for (action = &actions[0]; action->type != RTE_FLOW_ACTION_TYPE_END;
    2253                 :          0 :              action++) {
    2254         [ #  # ]:          0 :                 if (action->type == RTE_FLOW_ACTION_TYPE_VOID)
    2255                 :          0 :                         continue;
    2256         [ #  # ]:          0 :                 else if (!enic_fm_match_action(action, sa))
    2257                 :            :                         break;
    2258                 :            :         }
    2259         [ #  # ]:          0 :         if (action->type != RTE_FLOW_ACTION_TYPE_END) {
    2260                 :          0 :                 rte_flow_error_set(error, EPERM, RTE_FLOW_ERROR_TYPE_ACTION,
    2261                 :            :                                    action, "invalid action");
    2262                 :          0 :                 return -rte_errno;
    2263                 :            :         }
    2264                 :          0 :         ret = enic_fm_copy_entry(fm, pattern, error);
    2265         [ #  # ]:          0 :         if (ret)
    2266                 :            :                 return ret;
    2267                 :          0 :         ret = enic_fm_copy_action(fm, actions, attrs->ingress, error);
    2268                 :          0 :         return ret;
    2269                 :            : }
    2270                 :            : 
    2271                 :            : static void
    2272                 :            : enic_fm_counter_free(struct enic_flowman *fm, struct enic_fm_flow *fm_flow)
    2273                 :            : {
    2274         [ #  # ]:          0 :         if (!fm_flow->counter_valid)
    2275                 :            :                 return;
    2276                 :          0 :         SLIST_INSERT_HEAD(&fm->counters, fm_flow->counter, next);
    2277                 :          0 :         fm_flow->counter_valid = false;
    2278                 :            : }
    2279                 :            : 
    2280                 :            : static int
    2281                 :          0 : enic_fm_more_counters(struct enic_flowman *fm)
    2282                 :            : {
    2283                 :            :         struct enic_fm_counter *new_stack;
    2284                 :            :         struct enic_fm_counter *ctrs;
    2285                 :            :         int i, rc;
    2286                 :            :         uint64_t args[2];
    2287                 :            : 
    2288                 :          0 :         ENICPMD_FUNC_TRACE();
    2289                 :          0 :         new_stack = rte_realloc(fm->counter_stack, (fm->counters_alloced +
    2290                 :            :                                 FM_COUNTERS_EXPAND) *
    2291                 :            :                                 sizeof(struct enic_fm_counter), 0);
    2292         [ #  # ]:          0 :         if (new_stack == NULL) {
    2293                 :          0 :                 ENICPMD_LOG(ERR, "cannot alloc counter memory");
    2294                 :          0 :                 return -ENOMEM;
    2295                 :            :         }
    2296                 :          0 :         fm->counter_stack = new_stack;
    2297                 :            : 
    2298                 :          0 :         args[0] = FM_COUNTER_BRK;
    2299                 :          0 :         args[1] = fm->counters_alloced + FM_COUNTERS_EXPAND;
    2300                 :            :         rc = flowman_cmd(fm, args, 2);
    2301         [ #  # ]:          0 :         if (rc != 0) {
    2302                 :          0 :                 ENICPMD_LOG(ERR, "cannot alloc counters rc=%d", rc);
    2303                 :          0 :                 return rc;
    2304                 :            :         }
    2305                 :          0 :         ctrs = (struct enic_fm_counter *)fm->counter_stack +
    2306                 :          0 :                 fm->counters_alloced;
    2307         [ #  # ]:          0 :         for (i = 0; i < FM_COUNTERS_EXPAND; i++, ctrs++) {
    2308                 :          0 :                 ctrs->handle = fm->counters_alloced + i;
    2309                 :          0 :                 SLIST_INSERT_HEAD(&fm->counters, ctrs, next);
    2310                 :            :         }
    2311                 :          0 :         fm->counters_alloced += FM_COUNTERS_EXPAND;
    2312                 :          0 :         ENICPMD_LOG(DEBUG, "%u counters allocated, total: %u",
    2313                 :            :                     FM_COUNTERS_EXPAND, fm->counters_alloced);
    2314                 :          0 :         return 0;
    2315                 :            : }
    2316                 :            : 
    2317                 :            : static int
    2318                 :          0 : enic_fm_counter_zero(struct enic_flowman *fm, struct enic_fm_counter *c)
    2319                 :            : {
    2320                 :            :         uint64_t args[3];
    2321                 :            :         int ret;
    2322                 :            : 
    2323                 :          0 :         ENICPMD_FUNC_TRACE();
    2324                 :          0 :         args[0] = FM_COUNTER_QUERY;
    2325                 :          0 :         args[1] = c->handle;
    2326                 :          0 :         args[2] = 1; /* clear */
    2327                 :            :         ret = flowman_cmd(fm, args, 3);
    2328         [ #  # ]:          0 :         if (ret) {
    2329                 :          0 :                 ENICPMD_LOG(ERR, "counter init: rc=%d handle=0x%x",
    2330                 :            :                             ret, c->handle);
    2331                 :          0 :                 return ret;
    2332                 :            :         }
    2333                 :            :         return 0;
    2334                 :            : }
    2335                 :            : 
    2336                 :            : static int
    2337                 :          0 : enic_fm_counter_alloc(struct enic_flowman *fm, struct rte_flow_error *error,
    2338                 :            :                       struct enic_fm_counter **ctr)
    2339                 :            : {
    2340                 :            :         struct enic_fm_counter *c;
    2341                 :            :         int ret;
    2342                 :            : 
    2343                 :          0 :         ENICPMD_FUNC_TRACE();
    2344                 :          0 :         *ctr = NULL;
    2345         [ #  # ]:          0 :         if (SLIST_EMPTY(&fm->counters)) {
    2346                 :          0 :                 ret = enic_fm_more_counters(fm);
    2347         [ #  # ]:          0 :                 if (ret)
    2348                 :          0 :                         return rte_flow_error_set(error, -ret,
    2349                 :            :                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
    2350                 :            :                                 NULL, "enic: out of counters");
    2351                 :            :         }
    2352                 :          0 :         c = SLIST_FIRST(&fm->counters);
    2353                 :          0 :         SLIST_REMOVE_HEAD(&fm->counters, next);
    2354                 :          0 :         *ctr = c;
    2355                 :          0 :         return 0;
    2356                 :            : }
    2357                 :            : 
    2358                 :            : static int
    2359                 :          0 : enic_fm_action_free(struct enic_flowman *fm, struct enic_fm_action *ah)
    2360                 :            : {
    2361                 :            :         uint64_t args[2];
    2362                 :            :         int ret = 0;
    2363                 :            : 
    2364                 :          0 :         ENICPMD_FUNC_TRACE();
    2365                 :            :         RTE_ASSERT(ah->ref > 0);
    2366                 :          0 :         ah->ref--;
    2367         [ #  # ]:          0 :         if (ah->ref == 0) {
    2368                 :          0 :                 args[0] = FM_ACTION_FREE;
    2369                 :          0 :                 args[1] = ah->handle;
    2370                 :            :                 ret = flowman_cmd(fm, args, 2);
    2371         [ #  # ]:          0 :                 if (ret)
    2372                 :            :                         /* This is a "should never happen" error. */
    2373                 :          0 :                         ENICPMD_LOG(ERR, "freeing action rc=%d handle=0x%"
    2374                 :            :                                     PRIx64, ret, ah->handle);
    2375                 :          0 :                 rte_hash_del_key(fm->action_hash, (const void *)&ah->key);
    2376                 :          0 :                 free(ah);
    2377                 :            :         }
    2378                 :          0 :         return ret;
    2379                 :            : }
    2380                 :            : 
    2381                 :            : static int
    2382                 :          0 : enic_fm_entry_free(struct enic_flowman *fm, uint64_t handle)
    2383                 :            : {
    2384                 :            :         uint64_t args[2];
    2385                 :            :         int rc;
    2386                 :            : 
    2387                 :          0 :         ENICPMD_FUNC_TRACE();
    2388                 :          0 :         args[0] = FM_MATCH_ENTRY_REMOVE;
    2389                 :          0 :         args[1] = handle;
    2390                 :            :         rc = flowman_cmd(fm, args, 2);
    2391         [ #  # ]:          0 :         if (rc)
    2392                 :          0 :                 ENICPMD_LOG(ERR, "cannot free match entry: rc=%d"
    2393                 :            :                             " handle=0x%" PRIx64, rc, handle);
    2394                 :          0 :         return rc;
    2395                 :            : }
    2396                 :            : 
    2397                 :            : static struct enic_fm_jump_flow *
    2398                 :          0 : find_jump_flow(struct enic_flowman *fm, uint32_t group)
    2399                 :            : {
    2400                 :            :         struct enic_fm_jump_flow *j;
    2401                 :            : 
    2402                 :          0 :         ENICPMD_FUNC_TRACE();
    2403         [ #  # ]:          0 :         TAILQ_FOREACH(j, &fm->jump_list, list) {
    2404         [ #  # ]:          0 :                 if (j->group == group)
    2405                 :          0 :                         return j;
    2406                 :            :         }
    2407                 :            :         return NULL;
    2408                 :            : }
    2409                 :            : 
    2410                 :            : static void
    2411                 :          0 : remove_jump_flow(struct enic_flowman *fm, struct rte_flow *flow)
    2412                 :            : {
    2413                 :            :         struct enic_fm_jump_flow *j;
    2414                 :            : 
    2415                 :          0 :         ENICPMD_FUNC_TRACE();
    2416         [ #  # ]:          0 :         TAILQ_FOREACH(j, &fm->jump_list, list) {
    2417         [ #  # ]:          0 :                 if (j->flow == flow) {
    2418         [ #  # ]:          0 :                         TAILQ_REMOVE(&fm->jump_list, j, list);
    2419                 :          0 :                         free(j);
    2420                 :          0 :                         return;
    2421                 :            :                 }
    2422                 :            :         }
    2423                 :            : }
    2424                 :            : 
    2425                 :            : static int
    2426                 :          0 : save_jump_flow(struct enic_flowman *fm,
    2427                 :            :                struct rte_flow *flow,
    2428                 :            :                uint32_t group,
    2429                 :            :                struct fm_tcam_match_entry *match,
    2430                 :            :                struct fm_action *action)
    2431                 :            : {
    2432                 :            :         struct enic_fm_jump_flow *j;
    2433                 :            : 
    2434                 :          0 :         ENICPMD_FUNC_TRACE();
    2435                 :          0 :         j = calloc(1, sizeof(struct enic_fm_jump_flow));
    2436         [ #  # ]:          0 :         if (j == NULL)
    2437                 :            :                 return -ENOMEM;
    2438                 :          0 :         j->flow = flow;
    2439                 :          0 :         j->group = group;
    2440                 :          0 :         j->match = *match;
    2441                 :          0 :         j->action = *action;
    2442         [ #  # ]:          0 :         TAILQ_INSERT_HEAD(&fm->jump_list, j, list);
    2443                 :          0 :         ENICPMD_LOG(DEBUG, "saved jump flow: flow=%p group=%u", flow, group);
    2444                 :          0 :         return 0;
    2445                 :            : }
    2446                 :            : 
    2447                 :            : static void
    2448                 :          0 : __enic_fm_flow_free(struct enic_flowman *fm, struct enic_fm_flow *fm_flow)
    2449                 :            : {
    2450         [ #  # ]:          0 :         if (fm_flow->entry_handle != FM_INVALID_HANDLE) {
    2451                 :          0 :                 enic_fm_entry_free(fm, fm_flow->entry_handle);
    2452                 :          0 :                 fm_flow->entry_handle = FM_INVALID_HANDLE;
    2453                 :            :         }
    2454         [ #  # ]:          0 :         if (fm_flow->action != NULL) {
    2455                 :          0 :                 enic_fm_action_free(fm, fm_flow->action);
    2456                 :          0 :                 fm_flow->action = NULL;
    2457                 :            :         }
    2458                 :            :         enic_fm_counter_free(fm, fm_flow);
    2459         [ #  # ]:          0 :         if (fm_flow->fet) {
    2460                 :          0 :                 enic_fet_put(fm, fm_flow->fet);
    2461                 :          0 :                 fm_flow->fet = NULL;
    2462                 :            :         }
    2463                 :          0 : }
    2464                 :            : 
    2465                 :            : static void
    2466                 :          0 : enic_fm_flow_free(struct enic_flowman *fm, struct rte_flow *flow)
    2467                 :            : {
    2468                 :          0 :         struct enic_fm_flow *steer = flow->fm->hairpin_steer_flow;
    2469                 :            : 
    2470   [ #  #  #  # ]:          0 :         if (flow->fm->fet && flow->fm->fet->default_key)
    2471                 :          0 :                 remove_jump_flow(fm, flow);
    2472                 :          0 :         __enic_fm_flow_free(fm, flow->fm);
    2473         [ #  # ]:          0 :         if (steer) {
    2474                 :          0 :                 __enic_fm_flow_free(fm, steer);
    2475                 :          0 :                 free(steer);
    2476                 :            :         }
    2477                 :          0 :         free(flow->fm);
    2478                 :          0 :         free(flow);
    2479                 :          0 : }
    2480                 :            : 
    2481                 :            : static int
    2482                 :          0 : enic_fm_add_tcam_entry(struct enic_flowman *fm,
    2483                 :            :                        struct fm_tcam_match_entry *match_in,
    2484                 :            :                        uint64_t *entry_handle,
    2485                 :            :                        uint8_t ingress,
    2486                 :            :                        struct rte_flow_error *error)
    2487                 :            : {
    2488                 :            :         struct fm_tcam_match_entry *ftm;
    2489                 :            :         uint64_t args[3];
    2490                 :            :         int ret;
    2491                 :            : 
    2492                 :          0 :         ENICPMD_FUNC_TRACE();
    2493                 :            :         /* Copy entry to the command buffer */
    2494         [ #  # ]:          0 :         ftm = &fm->cmd.va->fm_tcam_match_entry;
    2495                 :            :         memcpy(ftm, match_in, sizeof(*ftm));
    2496                 :            :         /* Add TCAM entry */
    2497                 :          0 :         args[0] = FM_TCAM_ENTRY_INSTALL;
    2498         [ #  # ]:          0 :         args[1] = ingress ? fm->ig_tcam_hndl : fm->eg_tcam_hndl;
    2499                 :          0 :         args[2] = fm->cmd.pa;
    2500                 :            :         ret = flowman_cmd(fm, args, 3);
    2501         [ #  # ]:          0 :         if (ret != 0) {
    2502         [ #  # ]:          0 :                 ENICPMD_LOG(ERR, "cannot add %s TCAM entry: rc=%d",
    2503                 :            :                             ingress ? "ingress" : "egress", ret);
    2504                 :          0 :                 rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
    2505                 :            :                         NULL, "enic: devcmd(tcam-entry-install)");
    2506                 :          0 :                 return ret;
    2507                 :            :         }
    2508         [ #  # ]:          0 :         ENICPMD_LOG(DEBUG, "installed %s TCAM entry: handle=0x%" PRIx64,
    2509                 :            :                     ingress ? "ingress" : "egress", (uint64_t)args[0]);
    2510                 :          0 :         *entry_handle = args[0];
    2511                 :          0 :         return 0;
    2512                 :            : }
    2513                 :            : 
    2514                 :            : static int
    2515                 :          0 : enic_fm_add_exact_entry(struct enic_flowman *fm,
    2516                 :            :                         struct fm_tcam_match_entry *match_in,
    2517                 :            :                         uint64_t *entry_handle,
    2518                 :            :                         struct enic_fm_fet *fet,
    2519                 :            :                         struct rte_flow_error *error)
    2520                 :            : {
    2521                 :            :         struct fm_exact_match_entry *fem;
    2522                 :            :         uint64_t args[3];
    2523                 :            :         int ret;
    2524                 :            : 
    2525                 :          0 :         ENICPMD_FUNC_TRACE();
    2526                 :            :         /* The new entry must have the table's key */
    2527         [ #  # ]:          0 :         if (memcmp(fet->key.fk_hdrset, match_in->ftm_mask.fk_hdrset,
    2528                 :            :                    sizeof(struct fm_header_set) * FM_HDRSET_MAX)) {
    2529                 :          0 :                 return rte_flow_error_set(error, EINVAL,
    2530                 :            :                         RTE_FLOW_ERROR_TYPE_ITEM, NULL,
    2531                 :            :                         "enic: key does not match group's key");
    2532                 :            :         }
    2533                 :            : 
    2534                 :            :         /* Copy entry to the command buffer */
    2535                 :          0 :         fem = &fm->cmd.va->fm_exact_match_entry;
    2536                 :            :         /*
    2537                 :            :          * Translate TCAM entry to exact entry. As is only need to drop
    2538                 :            :          * position and mask. The mask is part of the exact match table.
    2539                 :            :          * Position (aka priority) is not supported in the exact match table.
    2540                 :            :          */
    2541                 :          0 :         fem->fem_data = match_in->ftm_data;
    2542                 :          0 :         fem->fem_flags = match_in->ftm_flags;
    2543                 :          0 :         fem->fem_action = match_in->ftm_action;
    2544                 :          0 :         fem->fem_counter = match_in->ftm_counter;
    2545                 :            : 
    2546                 :            :         /* Add exact entry */
    2547                 :          0 :         args[0] = FM_EXACT_ENTRY_INSTALL;
    2548                 :          0 :         args[1] = fet->handle;
    2549                 :          0 :         args[2] = fm->cmd.pa;
    2550                 :            :         ret = flowman_cmd(fm, args, 3);
    2551         [ #  # ]:          0 :         if (ret != 0) {
    2552         [ #  # ]:          0 :                 ENICPMD_LOG(ERR, "cannot add %s exact entry: group=%u",
    2553                 :            :                             fet->ingress ? "ingress" : "egress", fet->group);
    2554                 :          0 :                 rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
    2555                 :            :                         NULL, "enic: devcmd(exact-entry-install)");
    2556                 :          0 :                 return ret;
    2557                 :            :         }
    2558         [ #  # ]:          0 :         ENICPMD_LOG(DEBUG, "installed %s exact entry: group=%u"
    2559                 :            :                     " handle=0x%" PRIx64,
    2560                 :            :                     fet->ingress ? "ingress" : "egress", fet->group,
    2561                 :            :                     (uint64_t)args[0]);
    2562                 :          0 :         *entry_handle = args[0];
    2563                 :          0 :         return 0;
    2564                 :            : }
    2565                 :            : 
    2566                 :            : static int
    2567                 :          0 : enic_action_handle_get(struct enic_flowman *fm, struct fm_action *action_in,
    2568                 :            :                        struct rte_flow_error *error,
    2569                 :            :                        struct enic_fm_action **ah_o)
    2570                 :            : {
    2571                 :            :         struct enic_fm_action *ah;
    2572                 :            :         struct fm_action *fma;
    2573                 :            :         uint64_t args[2];
    2574                 :            :         int ret = 0;
    2575                 :            : 
    2576                 :          0 :         ret = rte_hash_lookup_data(fm->action_hash, action_in,
    2577                 :            :                                    (void **)&ah);
    2578         [ #  # ]:          0 :         if (ret < 0 && ret != -ENOENT)
    2579                 :          0 :                 return rte_flow_error_set(error, -ret,
    2580                 :            :                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
    2581                 :            :                                    NULL, "enic: rte_hash_lookup(action)");
    2582                 :            : 
    2583         [ #  # ]:          0 :         if (ret == -ENOENT) {
    2584                 :            :                 /* Allocate a new action on the NIC. */
    2585         [ #  # ]:          0 :                 fma = &fm->cmd.va->fm_action;
    2586                 :            :                 memcpy(fma, action_in, sizeof(*fma));
    2587                 :            : 
    2588                 :          0 :                 ah = calloc(1, sizeof(*ah));
    2589         [ #  # ]:          0 :                 if (ah == NULL)
    2590                 :          0 :                         return rte_flow_error_set(error, ENOMEM,
    2591                 :            :                                            RTE_FLOW_ERROR_TYPE_HANDLE,
    2592                 :            :                                            NULL, "enic: calloc(fm-action)");
    2593                 :          0 :                 memcpy(&ah->key, action_in, sizeof(struct fm_action));
    2594                 :          0 :                 args[0] = FM_ACTION_ALLOC;
    2595                 :          0 :                 args[1] = fm->cmd.pa;
    2596                 :            :                 ret = flowman_cmd(fm, args, 2);
    2597         [ #  # ]:          0 :                 if (ret != 0) {
    2598                 :          0 :                         rte_flow_error_set(error, -ret,
    2599                 :            :                                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
    2600                 :            :                                            NULL, "enic: devcmd(action-alloc)");
    2601                 :          0 :                         goto error_with_ah;
    2602                 :            :                 }
    2603                 :          0 :                 ah->handle = args[0];
    2604                 :          0 :                 ret = rte_hash_add_key_data(fm->action_hash,
    2605                 :            :                                             (const void *)action_in,
    2606                 :            :                                             (void *)ah);
    2607         [ #  # ]:          0 :                 if (ret != 0) {
    2608                 :          0 :                         rte_flow_error_set(error, -ret,
    2609                 :            :                                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
    2610                 :            :                                            NULL,
    2611                 :            :                                            "enic: rte_hash_add_key_data(actn)");
    2612                 :          0 :                         goto error_with_action_handle;
    2613                 :            :                 }
    2614                 :          0 :                 ENICPMD_LOG(DEBUG, "action allocated: handle=0x%" PRIx64,
    2615                 :            :                             ah->handle);
    2616                 :            :         }
    2617                 :            : 
    2618                 :            :         /* Action handle struct is valid, increment reference count. */
    2619                 :          0 :         ah->ref++;
    2620                 :          0 :         *ah_o = ah;
    2621                 :          0 :         return 0;
    2622                 :            : error_with_action_handle:
    2623                 :          0 :         args[0] = FM_ACTION_FREE;
    2624                 :          0 :         args[1] = ah->handle;
    2625                 :            :         ret = flowman_cmd(fm, args, 2);
    2626         [ #  # ]:          0 :         if (ret != 0)
    2627                 :          0 :                 rte_flow_error_set(error, -ret,
    2628                 :            :                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
    2629                 :            :                                    NULL, "enic: devcmd(action-free)");
    2630                 :          0 : error_with_ah:
    2631                 :          0 :         free(ah);
    2632                 :          0 :         return ret;
    2633                 :            : }
    2634                 :            : 
    2635                 :            : /* Push match-action to the NIC. */
    2636                 :            : static int
    2637                 :          0 : __enic_fm_flow_add_entry(struct enic_flowman *fm,
    2638                 :            :                          struct enic_fm_flow *fm_flow,
    2639                 :            :                          struct fm_tcam_match_entry *match_in,
    2640                 :            :                          struct fm_action *action_in,
    2641                 :            :                          uint32_t group,
    2642                 :            :                          uint8_t ingress,
    2643                 :            :                          struct rte_flow_error *error)
    2644                 :            : {
    2645                 :            :         struct enic_fm_counter *ctr;
    2646                 :          0 :         struct enic_fm_action *ah = NULL;
    2647                 :            :         uint64_t entry_h;
    2648                 :            :         int ret;
    2649                 :            : 
    2650                 :          0 :         ENICPMD_FUNC_TRACE();
    2651                 :            : 
    2652                 :            :         /* Get or create an action handle. */
    2653                 :          0 :         ret = enic_action_handle_get(fm, action_in, error, &ah);
    2654         [ #  # ]:          0 :         if (ret)
    2655                 :            :                 return ret;
    2656                 :          0 :         match_in->ftm_action = ah->handle;
    2657                 :          0 :         fm_flow->action = ah;
    2658                 :            : 
    2659                 :            :         /* Allocate counter if requested. */
    2660         [ #  # ]:          0 :         if (match_in->ftm_flags & FMEF_COUNTER) {
    2661                 :          0 :                 ret = enic_fm_counter_alloc(fm, error, &ctr);
    2662         [ #  # ]:          0 :                 if (ret) /* error has been filled in */
    2663                 :            :                         return ret;
    2664                 :          0 :                 fm_flow->counter_valid = true;
    2665                 :          0 :                 fm_flow->counter = ctr;
    2666                 :          0 :                 match_in->ftm_counter = ctr->handle;
    2667                 :            :         }
    2668                 :            : 
    2669                 :            :         /*
    2670                 :            :          * Get the group's table (either TCAM or exact match table) and
    2671                 :            :          * add entry to it. If we use the exact match table, the handler
    2672                 :            :          * will translate the TCAM entry (match_in) to the appropriate
    2673                 :            :          * exact match entry and use that instead.
    2674                 :            :          */
    2675                 :          0 :         entry_h = FM_INVALID_HANDLE;
    2676         [ #  # ]:          0 :         if (group == FM_TCAM_RTE_GROUP) {
    2677                 :          0 :                 ret = enic_fm_add_tcam_entry(fm, match_in, &entry_h, ingress,
    2678                 :            :                                              error);
    2679         [ #  # ]:          0 :                 if (ret)
    2680                 :            :                         return ret;
    2681                 :            :                 /* Jump action might have a ref to fet */
    2682                 :          0 :                 fm_flow->fet = fm->fet;
    2683                 :          0 :                 fm->fet = NULL;
    2684                 :            :         } else {
    2685                 :          0 :                 struct enic_fm_fet *fet = NULL;
    2686                 :            : 
    2687                 :          0 :                 ret = enic_fet_get(fm, group, ingress,
    2688                 :            :                                    &match_in->ftm_mask, &fet, error);
    2689         [ #  # ]:          0 :                 if (ret)
    2690                 :          0 :                         return ret;
    2691                 :          0 :                 fm_flow->fet = fet;
    2692                 :          0 :                 ret = enic_fm_add_exact_entry(fm, match_in, &entry_h, fet,
    2693                 :            :                                               error);
    2694         [ #  # ]:          0 :                 if (ret)
    2695                 :            :                         return ret;
    2696                 :            :         }
    2697                 :            :         /* Clear counter after adding entry, as it requires in-use counter */
    2698         [ #  # ]:          0 :         if (fm_flow->counter_valid) {
    2699                 :          0 :                 ret = enic_fm_counter_zero(fm, fm_flow->counter);
    2700         [ #  # ]:          0 :                 if (ret)
    2701                 :            :                         return ret;
    2702                 :            :         }
    2703                 :          0 :         fm_flow->entry_handle = entry_h;
    2704                 :          0 :         return 0;
    2705                 :            : }
    2706                 :            : 
    2707                 :            : /* Push match-action to the NIC. */
    2708                 :            : static struct rte_flow *
    2709                 :          0 : enic_fm_flow_add_entry(struct enic_flowman *fm,
    2710                 :            :                        struct fm_tcam_match_entry *match_in,
    2711                 :            :                        struct fm_action *action_in,
    2712                 :            :                        const struct rte_flow_attr *attrs,
    2713                 :            :                        struct rte_flow_error *error)
    2714                 :            : {
    2715                 :            :         struct enic_fm_flow *fm_flow;
    2716                 :            :         struct rte_flow *flow;
    2717                 :            : 
    2718                 :          0 :         ENICPMD_FUNC_TRACE();
    2719                 :          0 :         match_in->ftm_position = attrs->priority;
    2720                 :          0 :         enic_fm_dump_tcam_entry(match_in, action_in, attrs->ingress);
    2721                 :          0 :         flow = calloc(1, sizeof(*flow));
    2722                 :          0 :         fm_flow = calloc(1, sizeof(*fm_flow));
    2723         [ #  # ]:          0 :         if (flow == NULL || fm_flow == NULL) {
    2724                 :          0 :                 rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
    2725                 :            :                         NULL, "enic: cannot allocate rte_flow");
    2726                 :          0 :                 free(flow);
    2727                 :          0 :                 free(fm_flow);
    2728                 :          0 :                 return NULL;
    2729                 :            :         }
    2730                 :          0 :         flow->fm = fm_flow;
    2731                 :          0 :         fm_flow->action = NULL;
    2732                 :          0 :         fm_flow->entry_handle = FM_INVALID_HANDLE;
    2733         [ #  # ]:          0 :         if (__enic_fm_flow_add_entry(fm, fm_flow, match_in, action_in,
    2734                 :          0 :                                      attrs->group, attrs->ingress, error)) {
    2735                 :          0 :                 enic_fm_flow_free(fm, flow);
    2736                 :          0 :                 return NULL;
    2737                 :            :         }
    2738                 :            :         return flow;
    2739                 :            : }
    2740                 :            : 
    2741                 :            : static void
    2742                 :          0 : convert_jump_flows(struct enic_flowman *fm, struct enic_fm_fet *fet,
    2743                 :            :                    struct rte_flow_error *error)
    2744                 :            : {
    2745                 :            :         struct enic_fm_flow *fm_flow;
    2746                 :            :         struct enic_fm_jump_flow *j;
    2747                 :            :         struct fm_action *fma;
    2748                 :            :         uint32_t group;
    2749                 :            : 
    2750                 :          0 :         ENICPMD_FUNC_TRACE();
    2751                 :            :         /*
    2752                 :            :          * Find the saved flows that should jump to the new table (fet).
    2753                 :            :          * Then delete the old TCAM entry that jumps to the default table,
    2754                 :            :          * and add a new one that jumps to the new table.
    2755                 :            :          */
    2756                 :          0 :         group = fet->group;
    2757                 :          0 :         j = find_jump_flow(fm, group);
    2758         [ #  # ]:          0 :         while (j) {
    2759                 :          0 :                 ENICPMD_LOG(DEBUG, "convert jump flow: flow=%p group=%u",
    2760                 :            :                             j->flow, group);
    2761                 :            :                 /* Delete old entry */
    2762                 :          0 :                 fm_flow = j->flow->fm;
    2763                 :          0 :                 __enic_fm_flow_free(fm, fm_flow);
    2764                 :            : 
    2765                 :            :                 /* Add new entry */
    2766                 :          0 :                 fma = &j->action;
    2767                 :          0 :                 fma->fma_action_ops[0].exact.handle = fet->handle;
    2768         [ #  # ]:          0 :                 if (__enic_fm_flow_add_entry(fm, fm_flow, &j->match, fma,
    2769                 :          0 :                         FM_TCAM_RTE_GROUP, fet->ingress, error)) {
    2770                 :            :                         /* Cannot roll back changes at the moment */
    2771                 :          0 :                         ENICPMD_LOG(ERR, "cannot convert jump flow: flow=%p",
    2772                 :            :                                     j->flow);
    2773                 :            :                 } else {
    2774                 :          0 :                         fm_flow->fet = fet;
    2775                 :          0 :                         fet->ref++;
    2776                 :          0 :                         ENICPMD_LOG(DEBUG, "convert ok: group=%u ref=%u",
    2777                 :            :                                     fet->group, fet->ref);
    2778                 :            :                 }
    2779                 :            : 
    2780         [ #  # ]:          0 :                 TAILQ_REMOVE(&fm->jump_list, j, list);
    2781                 :          0 :                 free(j);
    2782                 :          0 :                 j = find_jump_flow(fm, group);
    2783                 :            :         }
    2784                 :          0 : }
    2785                 :            : 
    2786                 :            : static int
    2787                 :          0 : add_hairpin_steer(struct enic_flowman *fm, struct rte_flow *flow,
    2788                 :            :                   struct rte_flow_error *error)
    2789                 :            : {
    2790                 :            :         struct fm_tcam_match_entry *fm_tcam_entry;
    2791                 :            :         struct enic_fm_flow *fm_flow;
    2792                 :            :         struct fm_action *fm_action;
    2793                 :            :         struct fm_action_op fm_op;
    2794                 :            :         int ret;
    2795                 :            : 
    2796                 :          0 :         ENICPMD_FUNC_TRACE();
    2797                 :          0 :         fm_flow = calloc(1, sizeof(*fm_flow));
    2798         [ #  # ]:          0 :         if (fm_flow == NULL) {
    2799                 :          0 :                 rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
    2800                 :            :                         NULL, "enic: cannot allocate rte_flow");
    2801                 :          0 :                 return -ENOMEM;
    2802                 :            :         }
    2803                 :            :         /* Original egress hairpin flow */
    2804                 :          0 :         fm_tcam_entry = &fm->tcam_entry;
    2805                 :          0 :         fm_action = &fm->action;
    2806                 :            :         /* Use the match pattern of the egress flow as is, without counters */
    2807                 :          0 :         fm_tcam_entry->ftm_flags &= ~FMEF_COUNTER;
    2808                 :            :         /* The only action is steer to vnic */
    2809                 :          0 :         fm->action_op_count = 0;
    2810                 :            :         memset(fm_action, 0, sizeof(*fm_action));
    2811                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    2812                 :            :         /* Always to queue 0 for now */
    2813                 :          0 :         fm_op.fa_op = FMOP_RQ_STEER;
    2814                 :            :         fm_op.rq_steer.rq_index = 0;
    2815                 :          0 :         fm_op.rq_steer.vnic_handle = fm->hairpin_steer_vnic_h;
    2816                 :          0 :         ret = enic_fm_append_action_op(fm, &fm_op, error);
    2817         [ #  # ]:          0 :         if (ret)
    2818                 :          0 :                 goto error_with_flow;
    2819                 :          0 :         ENICPMD_LOG(DEBUG, "add steer op");
    2820                 :            :         /* Add required END */
    2821                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    2822                 :          0 :         fm_op.fa_op = FMOP_END;
    2823                 :          0 :         ret = enic_fm_append_action_op(fm, &fm_op, error);
    2824         [ #  # ]:          0 :         if (ret)
    2825                 :          0 :                 goto error_with_flow;
    2826                 :            :         /* Add the ingress flow */
    2827                 :          0 :         fm_flow->action = NULL;
    2828                 :          0 :         fm_flow->entry_handle = FM_INVALID_HANDLE;
    2829                 :          0 :         ret = __enic_fm_flow_add_entry(fm, fm_flow, fm_tcam_entry, fm_action,
    2830                 :            :                                        FM_TCAM_RTE_GROUP, 1 /* ingress */, error);
    2831         [ #  # ]:          0 :         if (ret) {
    2832                 :          0 :                 ENICPMD_LOG(ERR, "cannot add hairpin-steer flow");
    2833                 :          0 :                 goto error_with_flow;
    2834                 :            :         }
    2835                 :            :         /* The new flow is now the egress flow's paired flow */
    2836                 :          0 :         flow->fm->hairpin_steer_flow = fm_flow;
    2837                 :          0 :         return 0;
    2838                 :            : 
    2839                 :          0 : error_with_flow:
    2840                 :          0 :         free(fm_flow);
    2841                 :          0 :         return ret;
    2842                 :            : }
    2843                 :            : 
    2844                 :            : static void
    2845                 :          0 : enic_fm_open_scratch(struct enic_flowman *fm)
    2846                 :            : {
    2847                 :          0 :         fm->action_op_count = 0;
    2848                 :          0 :         fm->fet = NULL;
    2849                 :          0 :         fm->need_hairpin_steer = 0;
    2850                 :          0 :         fm->hairpin_steer_vnic_h = 0;
    2851                 :          0 :         memset(&fm->tcam_entry, 0, sizeof(fm->tcam_entry));
    2852                 :          0 :         memset(&fm->action, 0, sizeof(fm->action));
    2853                 :          0 : }
    2854                 :            : 
    2855                 :            : static void
    2856                 :            : enic_fm_close_scratch(struct enic_flowman *fm)
    2857                 :            : {
    2858   [ #  #  #  #  :          0 :         if (fm->fet) {
          #  #  #  #  #  
                      # ]
    2859                 :          0 :                 enic_fet_put(fm, fm->fet);
    2860                 :          0 :                 fm->fet = NULL;
    2861                 :            :         }
    2862                 :          0 :         fm->action_op_count = 0;
    2863                 :            : }
    2864                 :            : 
    2865                 :            : static int
    2866                 :          0 : enic_fm_flow_validate(struct rte_eth_dev *dev,
    2867                 :            :                       const struct rte_flow_attr *attrs,
    2868                 :            :                       const struct rte_flow_item pattern[],
    2869                 :            :                       const struct rte_flow_action actions[],
    2870                 :            :                       struct rte_flow_error *error)
    2871                 :            : {
    2872                 :            :         struct fm_tcam_match_entry *fm_tcam_entry;
    2873                 :            :         struct fm_action *fm_action;
    2874                 :            :         struct enic_flowman *fm;
    2875                 :            :         int ret;
    2876                 :            : 
    2877                 :          0 :         ENICPMD_FUNC_TRACE();
    2878                 :          0 :         fm = begin_fm(pmd_priv(dev));
    2879         [ #  # ]:          0 :         if (fm == NULL)
    2880                 :            :                 return -ENOTSUP;
    2881                 :          0 :         enic_fm_open_scratch(fm);
    2882                 :          0 :         ret = enic_fm_flow_parse(fm, attrs, pattern, actions, error);
    2883         [ #  # ]:          0 :         if (!ret) {
    2884                 :          0 :                 fm_tcam_entry = &fm->tcam_entry;
    2885                 :          0 :                 fm_action = &fm->action;
    2886                 :          0 :                 enic_fm_dump_tcam_entry(fm_tcam_entry, fm_action,
    2887                 :          0 :                                         attrs->ingress);
    2888                 :            :         }
    2889                 :            :         enic_fm_close_scratch(fm);
    2890                 :            :         end_fm(fm);
    2891                 :            :         return ret;
    2892                 :            : }
    2893                 :            : 
    2894                 :            : static int
    2895                 :          0 : enic_fm_flow_query_count(struct rte_eth_dev *dev,
    2896                 :            :                          struct rte_flow *flow, void *data,
    2897                 :            :                          struct rte_flow_error *error)
    2898                 :            : {
    2899                 :            :         struct rte_flow_query_count *query;
    2900                 :            :         struct enic_fm_flow *fm_flow;
    2901                 :            :         struct enic_flowman *fm;
    2902                 :            :         uint64_t args[3];
    2903                 :            :         int rc;
    2904                 :            : 
    2905                 :          0 :         ENICPMD_FUNC_TRACE();
    2906                 :          0 :         fm = begin_fm(pmd_priv(dev));
    2907                 :            :         query = data;
    2908                 :          0 :         fm_flow = flow->fm;
    2909         [ #  # ]:          0 :         if (!fm_flow->counter_valid) {
    2910                 :          0 :                 rc = rte_flow_error_set(error, ENOTSUP,
    2911                 :            :                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
    2912                 :            :                         "enic: flow does not have counter");
    2913                 :          0 :                 goto exit;
    2914                 :            :         }
    2915                 :            : 
    2916                 :          0 :         args[0] = FM_COUNTER_QUERY;
    2917                 :          0 :         args[1] = fm_flow->counter->handle;
    2918                 :          0 :         args[2] = query->reset;
    2919                 :            :         rc = flowman_cmd(fm, args, 3);
    2920         [ #  # ]:          0 :         if (rc) {
    2921                 :          0 :                 ENICPMD_LOG(ERR, "cannot query counter: rc=%d handle=0x%x",
    2922                 :            :                             rc, fm_flow->counter->handle);
    2923                 :          0 :                 goto exit;
    2924                 :            :         }
    2925                 :          0 :         query->hits_set = 1;
    2926                 :          0 :         query->hits = args[0];
    2927                 :          0 :         query->bytes_set = 1;
    2928                 :          0 :         query->bytes = args[1];
    2929                 :            :         rc = 0;
    2930                 :          0 : exit:
    2931                 :            :         end_fm(fm);
    2932                 :          0 :         return rc;
    2933                 :            : }
    2934                 :            : 
    2935                 :            : static int
    2936                 :          0 : enic_fm_flow_query(struct rte_eth_dev *dev,
    2937                 :            :                    struct rte_flow *flow,
    2938                 :            :                    const struct rte_flow_action *actions,
    2939                 :            :                    void *data,
    2940                 :            :                    struct rte_flow_error *error)
    2941                 :            : {
    2942                 :            :         int ret = 0;
    2943                 :            : 
    2944                 :          0 :         ENICPMD_FUNC_TRACE();
    2945         [ #  # ]:          0 :         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
    2946      [ #  #  # ]:          0 :                 switch (actions->type) {
    2947                 :            :                 case RTE_FLOW_ACTION_TYPE_VOID:
    2948                 :            :                         break;
    2949                 :          0 :                 case RTE_FLOW_ACTION_TYPE_COUNT:
    2950                 :          0 :                         ret = enic_fm_flow_query_count(dev, flow, data, error);
    2951                 :          0 :                         break;
    2952                 :          0 :                 default:
    2953                 :          0 :                         return rte_flow_error_set(error, ENOTSUP,
    2954                 :            :                                                   RTE_FLOW_ERROR_TYPE_ACTION,
    2955                 :            :                                                   actions,
    2956                 :            :                                                   "action not supported");
    2957                 :            :                 }
    2958         [ #  # ]:          0 :                 if (ret < 0)
    2959                 :          0 :                         return ret;
    2960                 :            :         }
    2961                 :            :         return 0;
    2962                 :            : }
    2963                 :            : 
    2964                 :            : static struct rte_flow *
    2965                 :          0 : enic_fm_flow_create(struct rte_eth_dev *dev,
    2966                 :            :                     const struct rte_flow_attr *attrs,
    2967                 :            :                     const struct rte_flow_item pattern[],
    2968                 :            :                     const struct rte_flow_action actions[],
    2969                 :            :                     struct rte_flow_error *error)
    2970                 :            : {
    2971                 :            :         struct fm_tcam_match_entry *fm_tcam_entry;
    2972                 :            :         struct fm_action *fm_action;
    2973                 :            :         struct enic_flowman *fm;
    2974                 :            :         struct enic_fm_fet *fet;
    2975                 :            :         struct rte_flow *flow;
    2976                 :            :         struct enic *enic;
    2977                 :            :         int ret;
    2978                 :            : 
    2979                 :          0 :         ENICPMD_FUNC_TRACE();
    2980                 :            :         enic = pmd_priv(dev);
    2981                 :          0 :         fm = begin_fm(enic);
    2982         [ #  # ]:          0 :         if (fm == NULL) {
    2983                 :          0 :                 rte_flow_error_set(error, ENOTSUP,
    2984                 :            :                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
    2985                 :            :                         "flowman is not initialized");
    2986                 :          0 :                 return NULL;
    2987                 :            :         }
    2988                 :          0 :         enic_fm_open_scratch(fm);
    2989                 :            :         flow = NULL;
    2990                 :          0 :         ret = enic_fm_flow_parse(fm, attrs, pattern, actions, error);
    2991         [ #  # ]:          0 :         if (ret < 0)
    2992                 :          0 :                 goto error_with_scratch;
    2993                 :          0 :         fm_tcam_entry = &fm->tcam_entry;
    2994                 :          0 :         fm_action = &fm->action;
    2995                 :          0 :         flow = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action,
    2996                 :            :                                       attrs, error);
    2997         [ #  # ]:          0 :         if (flow) {
    2998                 :            :                 /* Add ingress rule that pairs with hairpin rule */
    2999         [ #  # ]:          0 :                 if (fm->need_hairpin_steer) {
    3000                 :          0 :                         ret = add_hairpin_steer(fm, flow, error);
    3001         [ #  # ]:          0 :                         if (ret) {
    3002                 :          0 :                                 enic_fm_flow_free(fm, flow);
    3003                 :            :                                 flow = NULL;
    3004                 :          0 :                                 goto error_with_scratch;
    3005                 :            :                         }
    3006                 :            :                 }
    3007         [ #  # ]:          0 :                 LIST_INSERT_HEAD(&enic->flows, flow, next);
    3008                 :          0 :                 fet = flow->fm->fet;
    3009   [ #  #  #  # ]:          0 :                 if (fet && fet->default_key) {
    3010                 :            :                         /*
    3011                 :            :                          * Jump to non-existent group? Save the relevant info
    3012                 :            :                          * so we can convert this flow when that group
    3013                 :            :                          * materializes.
    3014                 :            :                          */
    3015                 :          0 :                         save_jump_flow(fm, flow, fet->group,
    3016                 :            :                                        fm_tcam_entry, fm_action);
    3017   [ #  #  #  # ]:          0 :                 } else if (fet && fet->ref == 1) {
    3018                 :            :                         /*
    3019                 :            :                          * A new table is created. Convert the saved flows
    3020                 :            :                          * that should jump to this group.
    3021                 :            :                          */
    3022                 :          0 :                         convert_jump_flows(fm, fet, error);
    3023                 :            :                 }
    3024                 :            :         }
    3025                 :            : 
    3026         [ #  # ]:          0 : error_with_scratch:
    3027                 :            :         enic_fm_close_scratch(fm);
    3028                 :            :         end_fm(fm);
    3029                 :            :         return flow;
    3030                 :            : }
    3031                 :            : 
    3032                 :            : static int
    3033                 :          0 : enic_fm_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
    3034                 :            :                      __rte_unused struct rte_flow_error *error)
    3035                 :            : {
    3036                 :            :         struct enic *enic = pmd_priv(dev);
    3037                 :            :         struct enic_flowman *fm;
    3038                 :            : 
    3039                 :          0 :         ENICPMD_FUNC_TRACE();
    3040                 :          0 :         fm = begin_fm(enic);
    3041         [ #  # ]:          0 :         if (fm == NULL)
    3042                 :            :                 return 0;
    3043         [ #  # ]:          0 :         LIST_REMOVE(flow, next);
    3044                 :          0 :         enic_fm_flow_free(fm, flow);
    3045                 :            :         end_fm(fm);
    3046                 :            :         return 0;
    3047                 :            : }
    3048                 :            : 
    3049                 :            : static int
    3050                 :          0 : enic_fm_flow_flush(struct rte_eth_dev *dev,
    3051                 :            :                    __rte_unused struct rte_flow_error *error)
    3052                 :            : {
    3053                 :            :         LIST_HEAD(enic_flows, rte_flow) internal;
    3054                 :            :         struct enic_fm_flow *fm_flow;
    3055                 :            :         struct enic_flowman *fm;
    3056                 :            :         struct rte_flow *flow;
    3057                 :            :         struct enic *enic = pmd_priv(dev);
    3058                 :            : 
    3059                 :          0 :         ENICPMD_FUNC_TRACE();
    3060                 :            : 
    3061                 :          0 :         fm = begin_fm(enic);
    3062         [ #  # ]:          0 :         if (fm == NULL)
    3063                 :            :                 return 0;
    3064                 :            :         /* Destroy all non-internal flows */
    3065                 :          0 :         LIST_INIT(&internal);
    3066         [ #  # ]:          0 :         while (!LIST_EMPTY(&enic->flows)) {
    3067                 :            :                 flow = LIST_FIRST(&enic->flows);
    3068                 :          0 :                 fm_flow = flow->fm;
    3069         [ #  # ]:          0 :                 LIST_REMOVE(flow, next);
    3070         [ #  # ]:          0 :                 if (flow->internal) {
    3071         [ #  # ]:          0 :                         LIST_INSERT_HEAD(&internal, flow, next);
    3072                 :          0 :                         continue;
    3073                 :            :                 }
    3074                 :            :                 /*
    3075                 :            :                  * If tables are null, then vNIC is closing, and the firmware
    3076                 :            :                  * has already cleaned up flowman state. So do not try to free
    3077                 :            :                  * resources, as it only causes errors.
    3078                 :            :                  */
    3079         [ #  # ]:          0 :                 if (fm->ig_tcam_hndl == FM_INVALID_HANDLE) {
    3080                 :          0 :                         fm_flow->entry_handle = FM_INVALID_HANDLE;
    3081                 :          0 :                         fm_flow->action = NULL;
    3082                 :          0 :                         fm_flow->fet = NULL;
    3083                 :            :                 }
    3084                 :          0 :                 enic_fm_flow_free(fm, flow);
    3085                 :            :         }
    3086         [ #  # ]:          0 :         while (!LIST_EMPTY(&internal)) {
    3087                 :            :                 flow = LIST_FIRST(&internal);
    3088         [ #  # ]:          0 :                 LIST_REMOVE(flow, next);
    3089         [ #  # ]:          0 :                 LIST_INSERT_HEAD(&enic->flows, flow, next);
    3090                 :            :         }
    3091                 :            :         end_fm(fm);
    3092                 :            :         return 0;
    3093                 :            : }
    3094                 :            : 
    3095                 :            : static int
    3096                 :          0 : enic_fm_tbl_free(struct enic_flowman *fm, uint64_t handle)
    3097                 :            : {
    3098                 :            :         uint64_t args[2];
    3099                 :            :         int rc;
    3100                 :            : 
    3101                 :          0 :         args[0] = FM_MATCH_TABLE_FREE;
    3102                 :          0 :         args[1] = handle;
    3103                 :            :         rc = flowman_cmd(fm, args, 2);
    3104         [ #  # ]:          0 :         if (rc)
    3105                 :          0 :                 ENICPMD_LOG(ERR, "cannot free table: rc=%d handle=0x%" PRIx64,
    3106                 :            :                             rc, handle);
    3107                 :          0 :         return rc;
    3108                 :            : }
    3109                 :            : 
    3110                 :            : static int
    3111                 :          0 : enic_fm_tcam_tbl_alloc(struct enic_flowman *fm, uint32_t direction,
    3112                 :            :                         uint32_t max_entries, uint64_t *handle)
    3113                 :            : {
    3114                 :            :         struct fm_tcam_match_table *tcam_tbl;
    3115                 :            :         uint64_t args[2];
    3116                 :            :         int rc;
    3117                 :            : 
    3118                 :          0 :         ENICPMD_FUNC_TRACE();
    3119                 :          0 :         tcam_tbl = &fm->cmd.va->fm_tcam_match_table;
    3120                 :          0 :         tcam_tbl->ftt_direction = direction;
    3121                 :          0 :         tcam_tbl->ftt_stage = FM_STAGE_LAST;
    3122                 :          0 :         tcam_tbl->ftt_max_entries = max_entries;
    3123                 :          0 :         args[0] = FM_TCAM_TABLE_ALLOC;
    3124                 :          0 :         args[1] = fm->cmd.pa;
    3125                 :            :         rc = flowman_cmd(fm, args, 2);
    3126         [ #  # ]:          0 :         if (rc) {
    3127         [ #  # ]:          0 :                 ENICPMD_LOG(ERR, "cannot alloc %s TCAM table: rc=%d",
    3128                 :            :                             (direction == FM_INGRESS) ? "IG" : "EG", rc);
    3129                 :          0 :                 return rc;
    3130                 :            :         }
    3131                 :          0 :         *handle = args[0];
    3132         [ #  # ]:          0 :         ENICPMD_LOG(DEBUG, "%s TCAM table allocated, handle=0x%" PRIx64,
    3133                 :            :                     (direction == FM_INGRESS) ? "IG" : "EG", *handle);
    3134                 :          0 :         return 0;
    3135                 :            : }
    3136                 :            : 
    3137                 :            : static int
    3138                 :          0 : enic_fm_init_actions(struct enic_flowman *fm)
    3139                 :            : {
    3140                 :            :         struct rte_hash *a_hash;
    3141                 :            :         char name[RTE_HASH_NAMESIZE];
    3142                 :          0 :         struct rte_hash_parameters params = {
    3143                 :            :                 .entries = FM_MAX_ACTION_TABLE_SIZE,
    3144                 :            :                 .key_len = sizeof(struct fm_action),
    3145                 :            :                 .hash_func = rte_jhash,
    3146                 :            :                 .hash_func_init_val = 0,
    3147                 :          0 :                 .socket_id = rte_socket_id(),
    3148                 :            :         };
    3149                 :            : 
    3150                 :          0 :         ENICPMD_FUNC_TRACE();
    3151                 :            :         snprintf((char *)name, sizeof(name), "fm-ah-%s",
    3152                 :          0 :                  fm->owner_enic->bdf_name);
    3153                 :          0 :         params.name = name;
    3154                 :            : 
    3155                 :          0 :         a_hash = rte_hash_create(&params);
    3156         [ #  # ]:          0 :         if (a_hash == NULL)
    3157                 :          0 :                 return -rte_errno;
    3158                 :          0 :         fm->action_hash = a_hash;
    3159                 :          0 :         return 0;
    3160                 :            : }
    3161                 :            : 
    3162                 :            : static int
    3163                 :          0 : enic_fm_init_counters(struct enic_flowman *fm)
    3164                 :            : {
    3165                 :          0 :         ENICPMD_FUNC_TRACE();
    3166                 :          0 :         SLIST_INIT(&fm->counters);
    3167                 :          0 :         return enic_fm_more_counters(fm);
    3168                 :            : }
    3169                 :            : 
    3170                 :            : static void
    3171                 :          0 : enic_fm_free_all_counters(struct enic_flowman *fm)
    3172                 :            : {
    3173                 :            :         uint64_t args[2];
    3174                 :            :         int rc;
    3175                 :            : 
    3176                 :          0 :         args[0] = FM_COUNTER_BRK;
    3177                 :          0 :         args[1] = 0;
    3178                 :            :         rc = flowman_cmd(fm, args, 2);
    3179         [ #  # ]:          0 :         if (rc != 0)
    3180                 :          0 :                 ENICPMD_LOG(ERR, "cannot free counters: rc=%d", rc);
    3181                 :          0 :         rte_free(fm->counter_stack);
    3182                 :          0 : }
    3183                 :            : 
    3184                 :            : static int
    3185                 :          0 : enic_fm_alloc_tcam_tables(struct enic_flowman *fm)
    3186                 :            : {
    3187                 :            :         int rc;
    3188                 :            : 
    3189                 :          0 :         ENICPMD_FUNC_TRACE();
    3190                 :          0 :         rc = enic_fm_tcam_tbl_alloc(fm, FM_INGRESS, FM_MAX_TCAM_TABLE_SIZE,
    3191                 :            :                                     &fm->ig_tcam_hndl);
    3192         [ #  # ]:          0 :         if (rc)
    3193                 :            :                 return rc;
    3194                 :          0 :         rc = enic_fm_tcam_tbl_alloc(fm, FM_EGRESS, FM_MAX_TCAM_TABLE_SIZE,
    3195                 :            :                                     &fm->eg_tcam_hndl);
    3196                 :          0 :         return rc;
    3197                 :            : }
    3198                 :            : 
    3199                 :            : static void
    3200                 :          0 : enic_fm_free_tcam_tables(struct enic_flowman *fm)
    3201                 :            : {
    3202                 :          0 :         ENICPMD_FUNC_TRACE();
    3203         [ #  # ]:          0 :         if (fm->ig_tcam_hndl) {
    3204                 :          0 :                 ENICPMD_LOG(DEBUG, "free IG TCAM table handle=0x%" PRIx64,
    3205                 :            :                             fm->ig_tcam_hndl);
    3206                 :          0 :                 enic_fm_tbl_free(fm, fm->ig_tcam_hndl);
    3207                 :          0 :                 fm->ig_tcam_hndl = FM_INVALID_HANDLE;
    3208                 :            :         }
    3209         [ #  # ]:          0 :         if (fm->eg_tcam_hndl) {
    3210                 :          0 :                 ENICPMD_LOG(DEBUG, "free EG TCAM table handle=0x%" PRIx64,
    3211                 :            :                             fm->eg_tcam_hndl);
    3212                 :          0 :                 enic_fm_tbl_free(fm, fm->eg_tcam_hndl);
    3213                 :          0 :                 fm->eg_tcam_hndl = FM_INVALID_HANDLE;
    3214                 :            :         }
    3215                 :          0 : }
    3216                 :            : 
    3217                 :            : int
    3218                 :          0 : enic_fm_init(struct enic *enic)
    3219                 :            : {
    3220                 :            :         const struct rte_pci_addr *addr;
    3221                 :            :         struct enic_flowman *fm;
    3222                 :            :         uint8_t name[RTE_MEMZONE_NAMESIZE];
    3223                 :            :         int rc;
    3224                 :            : 
    3225         [ #  # ]:          0 :         if (enic->flow_filter_mode != FILTER_FLOWMAN)
    3226                 :            :                 return 0;
    3227                 :          0 :         ENICPMD_FUNC_TRACE();
    3228                 :            :         /* Get vnic handle and save for port-id action */
    3229         [ #  # ]:          0 :         if (rte_eth_dev_is_repr(enic->rte_dev))
    3230                 :          0 :                 addr = &VF_ENIC_TO_VF_REP(enic)->bdf;
    3231                 :            :         else
    3232                 :          0 :                 addr = &RTE_ETH_DEV_TO_PCI(enic->rte_dev)->addr;
    3233                 :          0 :         rc = enic_fm_find_vnic(enic, addr, &enic->fm_vnic_handle);
    3234         [ #  # ]:          0 :         if (rc) {
    3235                 :          0 :                 ENICPMD_LOG(ERR, "cannot find vnic handle for %x:%x:%x",
    3236                 :            :                             addr->bus, addr->devid, addr->function);
    3237                 :          0 :                 return rc;
    3238                 :            :         }
    3239                 :            :         /* Save UIF for egport action */
    3240                 :          0 :         enic->fm_vnic_uif = vnic_dev_uif(enic->vdev);
    3241                 :          0 :         ENICPMD_LOG(DEBUG, "uif %u", enic->fm_vnic_uif);
    3242                 :            :         /* Nothing else to do for representor. It will share the PF flowman */
    3243         [ #  # ]:          0 :         if (rte_eth_dev_is_repr(enic->rte_dev))
    3244                 :            :                 return 0;
    3245                 :          0 :         fm = calloc(1, sizeof(*fm));
    3246         [ #  # ]:          0 :         if (fm == NULL) {
    3247                 :          0 :                 ENICPMD_LOG(ERR, "cannot alloc flowman struct");
    3248                 :          0 :                 return -ENOMEM;
    3249                 :            :         }
    3250                 :          0 :         fm->owner_enic = enic;
    3251                 :            :         rte_spinlock_init(&fm->lock);
    3252                 :          0 :         TAILQ_INIT(&fm->fet_list);
    3253                 :          0 :         TAILQ_INIT(&fm->jump_list);
    3254                 :            :         /* Allocate host memory for flowman commands */
    3255                 :          0 :         snprintf((char *)name, sizeof(name), "fm-cmd-%s", enic->bdf_name);
    3256                 :          0 :         fm->cmd.va = enic_alloc_consistent(enic,
    3257                 :            :                 sizeof(union enic_flowman_cmd_mem), &fm->cmd.pa, name);
    3258         [ #  # ]:          0 :         if (!fm->cmd.va) {
    3259                 :          0 :                 ENICPMD_LOG(ERR, "cannot allocate flowman command memory");
    3260                 :            :                 rc = -ENOMEM;
    3261                 :          0 :                 goto error_fm;
    3262                 :            :         }
    3263                 :            :         /* Allocate TCAM tables upfront as they are the main tables */
    3264                 :          0 :         rc = enic_fm_alloc_tcam_tables(fm);
    3265         [ #  # ]:          0 :         if (rc) {
    3266                 :          0 :                 ENICPMD_LOG(ERR, "cannot alloc TCAM tables");
    3267                 :          0 :                 goto error_cmd;
    3268                 :            :         }
    3269                 :            :         /* Then a number of counters */
    3270                 :          0 :         rc = enic_fm_init_counters(fm);
    3271         [ #  # ]:          0 :         if (rc) {
    3272                 :          0 :                 ENICPMD_LOG(ERR, "cannot alloc counters");
    3273                 :          0 :                 goto error_tables;
    3274                 :            :         }
    3275                 :            :         /* set up action handle hash */
    3276                 :          0 :         rc = enic_fm_init_actions(fm);
    3277         [ #  # ]:          0 :         if (rc) {
    3278                 :          0 :                 ENICPMD_LOG(ERR, "cannot create action hash, error:%d", rc);
    3279                 :          0 :                 goto error_counters;
    3280                 :            :         }
    3281                 :            :         /*
    3282                 :            :          * One default exact match table for each direction. We hold onto
    3283                 :            :          * it until close.
    3284                 :            :          */
    3285                 :          0 :         rc = enic_fet_alloc(fm, 1, NULL, 128, &fm->default_ig_fet);
    3286         [ #  # ]:          0 :         if (rc) {
    3287                 :          0 :                 ENICPMD_LOG(ERR, "cannot alloc default IG exact match table");
    3288                 :          0 :                 goto error_actions;
    3289                 :            :         }
    3290                 :          0 :         fm->default_ig_fet->ref = 1;
    3291                 :          0 :         rc = enic_fet_alloc(fm, 0, NULL, 128, &fm->default_eg_fet);
    3292         [ #  # ]:          0 :         if (rc) {
    3293                 :          0 :                 ENICPMD_LOG(ERR, "cannot alloc default EG exact match table");
    3294                 :          0 :                 goto error_ig_fet;
    3295                 :            :         }
    3296                 :          0 :         fm->default_eg_fet->ref = 1;
    3297                 :          0 :         fm->vf_rep_tag = FM_VF_REP_TAG;
    3298                 :          0 :         enic->fm = fm;
    3299                 :          0 :         return 0;
    3300                 :            : 
    3301                 :            : error_ig_fet:
    3302                 :          0 :         enic_fet_free(fm, fm->default_ig_fet);
    3303                 :          0 : error_actions:
    3304                 :          0 :         rte_hash_free(fm->action_hash);
    3305                 :          0 : error_counters:
    3306                 :          0 :         enic_fm_free_all_counters(fm);
    3307                 :          0 : error_tables:
    3308                 :          0 :         enic_fm_free_tcam_tables(fm);
    3309                 :          0 : error_cmd:
    3310                 :          0 :         enic_free_consistent(enic, sizeof(union enic_flowman_cmd_mem),
    3311                 :          0 :                 fm->cmd.va, fm->cmd.pa);
    3312                 :          0 : error_fm:
    3313                 :          0 :         free(fm);
    3314                 :          0 :         return rc;
    3315                 :            : }
    3316                 :            : 
    3317                 :            : void
    3318                 :          0 : enic_fm_destroy(struct enic *enic)
    3319                 :            : {
    3320                 :            :         struct enic_flowman *fm;
    3321                 :            :         struct enic_fm_fet *fet;
    3322                 :            : 
    3323                 :          0 :         ENICPMD_FUNC_TRACE();
    3324         [ #  # ]:          0 :         if (rte_eth_dev_is_repr(enic->rte_dev)) {
    3325                 :          0 :                 delete_rep_flows(enic);
    3326                 :          0 :                 return;
    3327                 :            :         }
    3328         [ #  # ]:          0 :         if (enic->fm == NULL)
    3329                 :            :                 return;
    3330                 :            :         fm = enic->fm;
    3331                 :          0 :         enic_fm_flow_flush(enic->rte_dev, NULL);
    3332                 :          0 :         enic_fet_free(fm, fm->default_eg_fet);
    3333                 :          0 :         enic_fet_free(fm, fm->default_ig_fet);
    3334                 :            :         /* Free all exact match tables still open */
    3335         [ #  # ]:          0 :         while (!TAILQ_EMPTY(&fm->fet_list)) {
    3336                 :            :                 fet = TAILQ_FIRST(&fm->fet_list);
    3337                 :          0 :                 enic_fet_free(fm, fet);
    3338                 :            :         }
    3339                 :          0 :         enic_fm_free_tcam_tables(fm);
    3340                 :          0 :         enic_fm_free_all_counters(fm);
    3341                 :          0 :         rte_hash_free(fm->action_hash);
    3342                 :          0 :         enic_free_consistent(enic, sizeof(union enic_flowman_cmd_mem),
    3343                 :          0 :                 fm->cmd.va, fm->cmd.pa);
    3344                 :            :         fm->cmd.va = NULL;
    3345                 :          0 :         free(fm);
    3346                 :          0 :         enic->fm = NULL;
    3347                 :            : }
    3348                 :            : 
    3349                 :            : int
    3350                 :          0 : enic_fm_allocate_switch_domain(struct enic *pf)
    3351                 :            : {
    3352                 :            :         const struct rte_pci_addr *cur_a, *prev_a;
    3353                 :            :         struct rte_eth_dev *dev;
    3354                 :            :         struct enic *cur, *prev;
    3355                 :            :         uint16_t domain_id;
    3356                 :            :         uint64_t vnic_h;
    3357                 :            :         uint16_t pid;
    3358                 :            :         int ret;
    3359                 :            : 
    3360                 :          0 :         ENICPMD_FUNC_TRACE();
    3361         [ #  # ]:          0 :         if (rte_eth_dev_is_repr(pf->rte_dev))
    3362                 :            :                 return -EINVAL;
    3363                 :            :         cur = pf;
    3364                 :          0 :         cur_a = &RTE_ETH_DEV_TO_PCI(cur->rte_dev)->addr;
    3365                 :            :         /* Go through ports and find another PF that is on the same adapter */
    3366         [ #  # ]:          0 :         RTE_ETH_FOREACH_DEV(pid) {
    3367                 :          0 :                 dev = &rte_eth_devices[pid];
    3368         [ #  # ]:          0 :                 if (!dev_is_enic(dev))
    3369                 :          0 :                         continue;
    3370         [ #  # ]:          0 :                 if (rte_eth_dev_is_repr(dev))
    3371                 :          0 :                         continue;
    3372         [ #  # ]:          0 :                 if (dev == cur->rte_dev)
    3373                 :          0 :                         continue;
    3374                 :            :                 /* dev is another PF. Is it on the same adapter? */
    3375                 :            :                 prev = pmd_priv(dev);
    3376                 :          0 :                 prev_a = &RTE_ETH_DEV_TO_PCI(dev)->addr;
    3377         [ #  # ]:          0 :                 if (!enic_fm_find_vnic(cur, prev_a, &vnic_h)) {
    3378                 :          0 :                         ENICPMD_LOG(DEBUG, "Port %u (PF BDF %x:%x:%x) and port %u (PF BDF %x:%x:%x domain %u) are on the same VIC",
    3379                 :            :                                 cur->rte_dev->data->port_id,
    3380                 :            :                                 cur_a->bus, cur_a->devid, cur_a->function,
    3381                 :            :                                 dev->data->port_id,
    3382                 :            :                                 prev_a->bus, prev_a->devid, prev_a->function,
    3383                 :            :                                 prev->switch_domain_id);
    3384                 :          0 :                         cur->switch_domain_id = prev->switch_domain_id;
    3385                 :          0 :                         return 0;
    3386                 :            :                 }
    3387                 :            :         }
    3388                 :          0 :         ret = rte_eth_switch_domain_alloc(&domain_id);
    3389         [ #  # ]:          0 :         if (ret) {
    3390                 :          0 :                 ENICPMD_LOG(WARNING, "failed to allocate switch domain for device %d",
    3391                 :            :                             ret);
    3392                 :            :         }
    3393                 :          0 :         cur->switch_domain_id = domain_id;
    3394                 :          0 :         ENICPMD_LOG(DEBUG, "Port %u (PF BDF %x:%x:%x) is the 1st PF on the VIC. Allocated switch domain id %u",
    3395                 :            :                     cur->rte_dev->data->port_id,
    3396                 :            :                     cur_a->bus, cur_a->devid, cur_a->function,
    3397                 :            :                     domain_id);
    3398                 :          0 :         return ret;
    3399                 :            : }
    3400                 :            : 
    3401                 :            : const struct rte_flow_ops enic_fm_flow_ops = {
    3402                 :            :         .validate = enic_fm_flow_validate,
    3403                 :            :         .create = enic_fm_flow_create,
    3404                 :            :         .destroy = enic_fm_flow_destroy,
    3405                 :            :         .flush = enic_fm_flow_flush,
    3406                 :            :         .query = enic_fm_flow_query,
    3407                 :            : };
    3408                 :            : 
    3409                 :            : /* Add a high priority flow that loops representor packets to VF */
    3410                 :            : int
    3411                 :          0 : enic_fm_add_rep2vf_flow(struct enic_vf_representor *vf)
    3412                 :            : {
    3413                 :            :         struct fm_tcam_match_entry *fm_tcam_entry;
    3414                 :            :         struct rte_flow *flow0, *flow1;
    3415                 :            :         struct fm_action *fm_action;
    3416                 :            :         struct rte_flow_error error;
    3417                 :            :         struct rte_flow_attr attrs;
    3418                 :            :         struct fm_action_op fm_op;
    3419                 :            :         struct enic_flowman *fm;
    3420                 :            :         struct enic *pf;
    3421                 :            :         uint8_t tag;
    3422                 :            : 
    3423                 :          0 :         pf = vf->pf;
    3424                 :          0 :         fm = pf->fm;
    3425                 :          0 :         tag = fm->vf_rep_tag;
    3426                 :          0 :         enic_fm_open_scratch(fm);
    3427                 :          0 :         fm_tcam_entry = &fm->tcam_entry;
    3428                 :          0 :         fm_action = &fm->action;
    3429                 :            :         /* Egress rule: match WQ ID and tag+hairpin */
    3430                 :          0 :         fm_tcam_entry->ftm_data.fk_wq_id = vf->pf_wq_idx;
    3431                 :          0 :         fm_tcam_entry->ftm_mask.fk_wq_id = 0xffff;
    3432                 :          0 :         fm_tcam_entry->ftm_flags |= FMEF_COUNTER;
    3433                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    3434                 :          0 :         fm_op.fa_op = FMOP_TAG;
    3435                 :          0 :         fm_op.tag.tag = tag;
    3436                 :          0 :         enic_fm_append_action_op(fm, &fm_op, &error);
    3437                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    3438                 :          0 :         fm_op.fa_op = FMOP_EG_HAIRPIN;
    3439                 :          0 :         enic_fm_append_action_op(fm, &fm_op, &error);
    3440                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    3441                 :          0 :         fm_op.fa_op = FMOP_END;
    3442                 :          0 :         enic_fm_append_action_op(fm, &fm_op, &error);
    3443                 :          0 :         attrs.group = 0;
    3444                 :          0 :         attrs.ingress = 0;
    3445                 :          0 :         attrs.egress = 1;
    3446                 :          0 :         attrs.priority = FM_HIGHEST_PRIORITY;
    3447                 :          0 :         flow0 = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action,
    3448                 :            :                                        &attrs, &error);
    3449                 :            :         enic_fm_close_scratch(fm);
    3450         [ #  # ]:          0 :         if (flow0 == NULL) {
    3451                 :          0 :                 ENICPMD_LOG(ERR, "Cannot create flow 0 for representor->VF");
    3452                 :          0 :                 return -EINVAL;
    3453                 :            :         }
    3454         [ #  # ]:          0 :         LIST_INSERT_HEAD(&pf->flows, flow0, next);
    3455                 :            :         /* Make this flow internal, so the user app cannot delete it */
    3456                 :          0 :         flow0->internal = 1;
    3457                 :          0 :         ENICPMD_LOG(DEBUG, "representor->VF %d flow created: wq %d -> tag %d hairpin",
    3458                 :            :                     vf->vf_id, vf->pf_wq_idx, tag);
    3459                 :            : 
    3460                 :            :         /* Ingress: steer hairpinned to VF RQ 0 */
    3461                 :          0 :         enic_fm_open_scratch(fm);
    3462                 :          0 :         fm_tcam_entry->ftm_flags |= FMEF_COUNTER;
    3463                 :          0 :         fm_tcam_entry->ftm_data.fk_hdrset[0].fk_metadata |= FKM_EG_HAIRPINNED;
    3464                 :          0 :         fm_tcam_entry->ftm_mask.fk_hdrset[0].fk_metadata |= FKM_EG_HAIRPINNED;
    3465                 :          0 :         fm_tcam_entry->ftm_data.fk_packet_tag = tag;
    3466                 :          0 :         fm_tcam_entry->ftm_mask.fk_packet_tag = 0xff;
    3467                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    3468                 :          0 :         fm_op.fa_op = FMOP_RQ_STEER;
    3469                 :            :         fm_op.rq_steer.rq_index = 0;
    3470                 :          0 :         fm_op.rq_steer.vnic_handle = vf->enic.fm_vnic_handle;
    3471                 :          0 :         enic_fm_append_action_op(fm, &fm_op, &error);
    3472                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    3473                 :          0 :         fm_op.fa_op = FMOP_END;
    3474                 :          0 :         enic_fm_append_action_op(fm, &fm_op, &error);
    3475                 :          0 :         attrs.group = 0;
    3476                 :          0 :         attrs.ingress = 1;
    3477                 :          0 :         attrs.egress = 0;
    3478                 :          0 :         attrs.priority = FM_HIGHEST_PRIORITY;
    3479                 :          0 :         flow1 = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action,
    3480                 :            :                                        &attrs, &error);
    3481                 :            :         enic_fm_close_scratch(fm);
    3482         [ #  # ]:          0 :         if (flow1 == NULL) {
    3483                 :          0 :                 ENICPMD_LOG(ERR, "Cannot create flow 1 for representor->VF");
    3484                 :          0 :                 enic_fm_flow_destroy(pf->rte_dev, flow0, &error);
    3485                 :          0 :                 return -EINVAL;
    3486                 :            :         }
    3487         [ #  # ]:          0 :         LIST_INSERT_HEAD(&pf->flows, flow1, next);
    3488                 :          0 :         flow1->internal = 1;
    3489                 :          0 :         ENICPMD_LOG(DEBUG, "representor->VF %d flow created: tag %d hairpinned -> VF RQ %d",
    3490                 :            :                     vf->vf_id, tag, fm_op.rq_steer.rq_index);
    3491                 :          0 :         vf->rep2vf_flow[0] = flow0;
    3492                 :          0 :         vf->rep2vf_flow[1] = flow1;
    3493                 :            :         /* Done with this tag, use a different one next time */
    3494                 :          0 :         fm->vf_rep_tag++;
    3495                 :          0 :         return 0;
    3496                 :            : }
    3497                 :            : 
    3498                 :            : /*
    3499                 :            :  * Add a low priority flow that matches all packets from VF and loops them
    3500                 :            :  * back to the representor.
    3501                 :            :  */
    3502                 :            : int
    3503                 :          0 : enic_fm_add_vf2rep_flow(struct enic_vf_representor *vf)
    3504                 :            : {
    3505                 :            :         struct fm_tcam_match_entry *fm_tcam_entry;
    3506                 :            :         struct rte_flow *flow0, *flow1;
    3507                 :            :         struct fm_action *fm_action;
    3508                 :            :         struct rte_flow_error error;
    3509                 :            :         struct rte_flow_attr attrs;
    3510                 :            :         struct fm_action_op fm_op;
    3511                 :            :         struct enic_flowman *fm;
    3512                 :            :         struct enic *pf;
    3513                 :            :         uint8_t tag;
    3514                 :            : 
    3515                 :          0 :         pf = vf->pf;
    3516                 :          0 :         fm = pf->fm;
    3517                 :          0 :         tag = fm->vf_rep_tag;
    3518                 :          0 :         enic_fm_open_scratch(fm);
    3519                 :          0 :         fm_tcam_entry = &fm->tcam_entry;
    3520                 :          0 :         fm_action = &fm->action;
    3521                 :            :         /* Egress rule: match-any and tag+hairpin */
    3522                 :          0 :         fm_tcam_entry->ftm_data.fk_wq_id = 0;
    3523                 :          0 :         fm_tcam_entry->ftm_mask.fk_wq_id = 0xffff;
    3524                 :          0 :         fm_tcam_entry->ftm_data.fk_wq_vnic = vf->enic.fm_vnic_handle;
    3525                 :          0 :         fm_tcam_entry->ftm_flags |= FMEF_COUNTER;
    3526                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    3527                 :          0 :         fm_op.fa_op = FMOP_TAG;
    3528                 :          0 :         fm_op.tag.tag = tag;
    3529                 :          0 :         enic_fm_append_action_op(fm, &fm_op, &error);
    3530                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    3531                 :          0 :         fm_op.fa_op = FMOP_EG_HAIRPIN;
    3532                 :          0 :         enic_fm_append_action_op(fm, &fm_op, &error);
    3533                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    3534                 :          0 :         fm_op.fa_op = FMOP_END;
    3535                 :          0 :         enic_fm_append_action_op(fm, &fm_op, &error);
    3536                 :          0 :         attrs.group = 0;
    3537                 :          0 :         attrs.ingress = 0;
    3538                 :          0 :         attrs.egress = 1;
    3539                 :          0 :         attrs.priority = FM_LOWEST_PRIORITY;
    3540                 :          0 :         flow0 = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action,
    3541                 :            :                                        &attrs, &error);
    3542                 :            :         enic_fm_close_scratch(fm);
    3543         [ #  # ]:          0 :         if (flow0 == NULL) {
    3544                 :          0 :                 ENICPMD_LOG(ERR, "Cannot create flow 0 for VF->representor");
    3545                 :          0 :                 return -EINVAL;
    3546                 :            :         }
    3547         [ #  # ]:          0 :         LIST_INSERT_HEAD(&pf->flows, flow0, next);
    3548                 :            :         /* Make this flow internal, so the user app cannot delete it */
    3549                 :          0 :         flow0->internal = 1;
    3550                 :          0 :         ENICPMD_LOG(DEBUG, "VF %d->representor flow created: wq %d (low prio) -> tag %d hairpin",
    3551                 :            :                     vf->vf_id, fm_tcam_entry->ftm_data.fk_wq_id, tag);
    3552                 :            : 
    3553                 :            :         /* Ingress: steer hairpinned to VF rep RQ */
    3554                 :          0 :         enic_fm_open_scratch(fm);
    3555                 :          0 :         fm_tcam_entry->ftm_flags |= FMEF_COUNTER;
    3556                 :          0 :         fm_tcam_entry->ftm_data.fk_hdrset[0].fk_metadata |= FKM_EG_HAIRPINNED;
    3557                 :          0 :         fm_tcam_entry->ftm_mask.fk_hdrset[0].fk_metadata |= FKM_EG_HAIRPINNED;
    3558                 :          0 :         fm_tcam_entry->ftm_data.fk_packet_tag = tag;
    3559                 :          0 :         fm_tcam_entry->ftm_mask.fk_packet_tag = 0xff;
    3560                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    3561                 :          0 :         fm_op.fa_op = FMOP_RQ_STEER;
    3562                 :          0 :         fm_op.rq_steer.rq_index = vf->pf_rq_sop_idx;
    3563                 :          0 :         fm_op.rq_steer.vnic_handle = pf->fm_vnic_handle;
    3564                 :          0 :         enic_fm_append_action_op(fm, &fm_op, &error);
    3565                 :            :         memset(&fm_op, 0, sizeof(fm_op));
    3566                 :          0 :         fm_op.fa_op = FMOP_END;
    3567                 :          0 :         enic_fm_append_action_op(fm, &fm_op, &error);
    3568                 :          0 :         attrs.group = 0;
    3569                 :          0 :         attrs.ingress = 1;
    3570                 :          0 :         attrs.egress = 0;
    3571                 :          0 :         attrs.priority = FM_HIGHEST_PRIORITY;
    3572                 :          0 :         flow1 = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action,
    3573                 :            :                                        &attrs, &error);
    3574                 :            :         enic_fm_close_scratch(fm);
    3575         [ #  # ]:          0 :         if (flow1 == NULL) {
    3576                 :          0 :                 ENICPMD_LOG(ERR, "Cannot create flow 1 for VF->representor");
    3577                 :          0 :                 enic_fm_flow_destroy(pf->rte_dev, flow0, &error);
    3578                 :          0 :                 return -EINVAL;
    3579                 :            :         }
    3580         [ #  # ]:          0 :         LIST_INSERT_HEAD(&pf->flows, flow1, next);
    3581                 :          0 :         flow1->internal = 1;
    3582                 :          0 :         ENICPMD_LOG(DEBUG, "VF %d->representor flow created: tag %d hairpinned -> PF RQ %d",
    3583                 :            :                     vf->vf_id, tag, vf->pf_rq_sop_idx);
    3584                 :          0 :         vf->vf2rep_flow[0] = flow0;
    3585                 :          0 :         vf->vf2rep_flow[1] = flow1;
    3586                 :            :         /* Done with this tag, use a different one next time */
    3587                 :          0 :         fm->vf_rep_tag++;
    3588                 :          0 :         return 0;
    3589                 :            : }
    3590                 :            : 
    3591                 :            : /* Destroy representor flows created by enic_fm_add_{rep2vf,vf2rep}_flow */
    3592                 :            : static void
    3593                 :          0 : delete_rep_flows(struct enic *enic)
    3594                 :            : {
    3595                 :            :         struct enic_vf_representor *vf;
    3596                 :            :         struct rte_flow_error error;
    3597                 :            :         struct rte_eth_dev *dev;
    3598                 :            :         uint32_t i;
    3599                 :            : 
    3600                 :            :         RTE_ASSERT(rte_eth_dev_is_repr(enic->rte_dev));
    3601                 :            :         vf = VF_ENIC_TO_VF_REP(enic);
    3602                 :          0 :         dev = vf->pf->rte_dev;
    3603         [ #  # ]:          0 :         for (i = 0; i < ARRAY_SIZE(vf->vf2rep_flow); i++) {
    3604         [ #  # ]:          0 :                 if (vf->vf2rep_flow[i])
    3605                 :          0 :                         enic_fm_flow_destroy(dev, vf->vf2rep_flow[i], &error);
    3606                 :            :         }
    3607         [ #  # ]:          0 :         for (i = 0; i < ARRAY_SIZE(vf->rep2vf_flow); i++) {
    3608         [ #  # ]:          0 :                 if (vf->rep2vf_flow[i])
    3609                 :          0 :                         enic_fm_flow_destroy(dev, vf->rep2vf_flow[i], &error);
    3610                 :            :         }
    3611                 :          0 : }
    3612                 :            : 
    3613                 :            : static struct enic_flowman *
    3614                 :          0 : begin_fm(struct enic *enic)
    3615                 :            : {
    3616                 :            :         struct enic_vf_representor *vf;
    3617                 :            :         struct enic_flowman *fm;
    3618                 :            : 
    3619                 :            :         /* Representor uses PF flowman */
    3620         [ #  # ]:          0 :         if (rte_eth_dev_is_repr(enic->rte_dev)) {
    3621                 :            :                 vf = VF_ENIC_TO_VF_REP(enic);
    3622                 :          0 :                 fm = vf->pf->fm;
    3623                 :            :         } else {
    3624                 :          0 :                 fm = enic->fm;
    3625                 :            :         }
    3626                 :            :         /* Save the API caller and lock if representors exist */
    3627         [ #  # ]:          0 :         if (fm) {
    3628         [ #  # ]:          0 :                 if (fm->owner_enic->switchdev_mode)
    3629                 :          0 :                         rte_spinlock_lock(&fm->lock);
    3630                 :          0 :                 fm->user_enic = enic;
    3631                 :            :         }
    3632                 :          0 :         return fm;
    3633                 :            : }
    3634                 :            : 
    3635                 :            : static void
    3636                 :            : end_fm(struct enic_flowman *fm)
    3637                 :            : {
    3638                 :          0 :         fm->user_enic = NULL;
    3639   [ #  #  #  #  :          0 :         if (fm->owner_enic->switchdev_mode)
          #  #  #  #  #  
                      # ]
    3640                 :          0 :                 rte_spinlock_unlock(&fm->lock);
    3641                 :            : }

Generated by: LCOV version 1.14