Add flow subscription pattern support for AVF.

The supported patterns are listed below:
eth/vlan/ipv4
eth/ipv4(6)
eth/ipv4(6)/udp
eth/ipv4(6)/tcp

Signed-off-by: Jie Wang <jie1x.w...@intel.com>
---
 drivers/net/iavf/iavf.h      |   7 +
 drivers/net/iavf/iavf_fsub.c | 598 ++++++++++++++++++++++++++++++++++-
 2 files changed, 597 insertions(+), 8 deletions(-)

diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
index 025ab3ff60..f79c7f9f6e 100644
--- a/drivers/net/iavf/iavf.h
+++ b/drivers/net/iavf/iavf.h
@@ -148,6 +148,13 @@ struct iavf_fdir_info {
        struct iavf_fdir_conf conf;
 };
 
+struct iavf_fsub_conf {
+       struct virtchnl_flow_sub sub_fltr;
+       struct virtchnl_flow_unsub unsub_fltr;
+       uint64_t input_set;
+       uint32_t flow_id;
+};
+
 struct iavf_qv_map {
        uint16_t queue_id;
        uint16_t vector_id;
diff --git a/drivers/net/iavf/iavf_fsub.c b/drivers/net/iavf/iavf_fsub.c
index 17f9bb2976..89e60c5d57 100644
--- a/drivers/net/iavf/iavf_fsub.c
+++ b/drivers/net/iavf/iavf_fsub.c
@@ -22,9 +22,51 @@
 #include "iavf_generic_flow.h"
 
 
+#define MAX_QGRP_NUM_TYPE      7
+#define IAVF_IPV6_ADDR_LENGTH  16
+#define MAX_INPUT_SET_BYTE     32
+
+#define IAVF_SW_INSET_ETHER ( \
+       IAVF_INSET_DMAC | IAVF_INSET_SMAC | IAVF_INSET_ETHERTYPE)
+#define IAVF_SW_INSET_MAC_IPV4 ( \
+       IAVF_INSET_DMAC | IAVF_INSET_IPV4_DST | IAVF_INSET_IPV4_SRC | \
+       IAVF_INSET_IPV4_PROTO | IAVF_INSET_IPV4_TTL | IAVF_INSET_IPV4_TOS)
+#define IAVF_SW_INSET_MAC_VLAN_IPV4 ( \
+       IAVF_SW_INSET_MAC_IPV4 | IAVF_INSET_VLAN_OUTER)
+#define IAVF_SW_INSET_MAC_IPV4_TCP ( \
+       IAVF_INSET_DMAC | IAVF_INSET_IPV4_DST | IAVF_INSET_IPV4_SRC | \
+       IAVF_INSET_IPV4_TTL | IAVF_INSET_IPV4_TOS | \
+       IAVF_INSET_TCP_DST_PORT | IAVF_INSET_TCP_SRC_PORT)
+#define IAVF_SW_INSET_MAC_IPV4_UDP ( \
+       IAVF_INSET_DMAC | IAVF_INSET_IPV4_DST | IAVF_INSET_IPV4_SRC | \
+       IAVF_INSET_IPV4_TTL | IAVF_INSET_IPV4_TOS | \
+       IAVF_INSET_UDP_DST_PORT | IAVF_INSET_UDP_SRC_PORT)
+#define IAVF_SW_INSET_MAC_IPV6 ( \
+       IAVF_INSET_DMAC | IAVF_INSET_IPV6_DST | IAVF_INSET_IPV6_SRC | \
+       IAVF_INSET_IPV6_TC | IAVF_INSET_IPV6_HOP_LIMIT | \
+       IAVF_INSET_IPV6_NEXT_HDR)
+#define IAVF_SW_INSET_MAC_IPV6_TCP ( \
+       IAVF_INSET_DMAC | IAVF_INSET_IPV6_DST | IAVF_INSET_IPV6_SRC | \
+       IAVF_INSET_IPV6_HOP_LIMIT | IAVF_INSET_IPV6_TC | \
+       IAVF_INSET_TCP_DST_PORT | IAVF_INSET_TCP_SRC_PORT)
+#define IAVF_SW_INSET_MAC_IPV6_UDP ( \
+       IAVF_INSET_DMAC | IAVF_INSET_IPV6_DST | IAVF_INSET_IPV6_SRC | \
+       IAVF_INSET_IPV6_HOP_LIMIT | IAVF_INSET_IPV6_TC | \
+       IAVF_INSET_UDP_DST_PORT | IAVF_INSET_UDP_SRC_PORT)
+
 static struct iavf_flow_parser iavf_fsub_parser;
 
-static struct iavf_pattern_match_item iavf_fsub_pattern_list[] = {};
+static struct
+iavf_pattern_match_item iavf_fsub_pattern_list[] = {
+       {iavf_pattern_ethertype,                        IAVF_SW_INSET_ETHER,    
                IAVF_INSET_NONE},
+       {iavf_pattern_eth_ipv4,                         IAVF_SW_INSET_MAC_IPV4, 
                IAVF_INSET_NONE},
+       {iavf_pattern_eth_vlan_ipv4,                    
IAVF_SW_INSET_MAC_VLAN_IPV4,            IAVF_INSET_NONE},
+       {iavf_pattern_eth_ipv4_udp,                     
IAVF_SW_INSET_MAC_IPV4_UDP,             IAVF_INSET_NONE},
+       {iavf_pattern_eth_ipv4_tcp,                     
IAVF_SW_INSET_MAC_IPV4_TCP,             IAVF_INSET_NONE},
+       {iavf_pattern_eth_ipv6,                         IAVF_SW_INSET_MAC_IPV6, 
                IAVF_INSET_NONE},
+       {iavf_pattern_eth_ipv6_udp,                     
IAVF_SW_INSET_MAC_IPV6_UDP,             IAVF_INSET_NONE},
+       {iavf_pattern_eth_ipv6_tcp,                     
IAVF_SW_INSET_MAC_IPV6_TCP,             IAVF_INSET_NONE},
+};
 
 static int
 iavf_fsub_create(__rte_unused struct iavf_adapter *ad,
@@ -53,17 +95,557 @@ iavf_fsub_validation(__rte_unused struct iavf_adapter *ad,
 };
 
 static int
-iavf_fsub_parse(__rte_unused struct iavf_adapter *ad,
-               __rte_unused struct iavf_pattern_match_item *array,
-               __rte_unused uint32_t array_len,
-               __rte_unused const struct rte_flow_item pattern[],
-               __rte_unused const struct rte_flow_action actions[],
-               __rte_unused void **meta,
-               __rte_unused struct rte_flow_error *error)
+iavf_fsub_parse_pattern(const struct rte_flow_item pattern[],
+                       const uint64_t input_set_mask,
+                       struct rte_flow_error *error,
+                       struct iavf_fsub_conf *filter)
+{
+       struct virtchnl_proto_hdrs *hdrs = &filter->sub_fltr.proto_hdrs;
+       enum rte_flow_item_type item_type;
+       const struct rte_flow_item_eth *eth_spec, *eth_mask;
+       const struct rte_flow_item_ipv4 *ipv4_spec, *ipv4_mask;
+       const struct rte_flow_item_ipv6 *ipv6_spec, *ipv6_mask;
+       const struct rte_flow_item_tcp *tcp_spec, *tcp_mask;
+       const struct rte_flow_item_udp *udp_spec, *udp_mask;
+       const struct rte_flow_item_vlan *vlan_spec, *vlan_mask;
+       const struct rte_flow_item *item = pattern;
+       struct virtchnl_proto_hdr_w_msk *hdr, *hdr1 = NULL;
+       uint64_t outer_input_set = IAVF_INSET_NONE;
+       uint64_t *input = NULL;
+       uint16_t input_set_byte = 0;
+       uint16_t j;
+       uint32_t layer = 0;
+
+       for (item = pattern; item->type !=
+                       RTE_FLOW_ITEM_TYPE_END; item++) {
+               if (item->last) {
+                       rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ITEM,
+                                          item, "Not support range");
+                       return false;
+               }
+               item_type = item->type;
+
+               switch (item_type) {
+               case RTE_FLOW_ITEM_TYPE_ETH:
+                       eth_spec = item->spec;
+                       eth_mask = item->mask;
+
+                       hdr1 = &hdrs->proto_hdr_w_msk[layer];
+
+                       VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, ETH);
+
+                       if (eth_spec && eth_mask) {
+                               input = &outer_input_set;
+
+                               if (!rte_is_zero_ether_addr(&eth_mask->dst)) {
+                                       *input |= IAVF_INSET_DMAC;
+                                       input_set_byte += 6;
+                               } else {
+                                       /* flow subscribe filter will add dst 
mac in kernel */
+                                       input_set_byte += 6;
+                               }
+
+                               if (!rte_is_zero_ether_addr(&eth_mask->src)) {
+                                       *input |= IAVF_INSET_DMAC;
+                                       input_set_byte += 6;
+                               }
+
+                               if (eth_mask->type) {
+                                       *input |= IAVF_INSET_ETHERTYPE;
+                                       input_set_byte += 2;
+                               }
+
+                               rte_memcpy(hdr1->buffer_spec, eth_spec,
+                                          sizeof(struct rte_ether_hdr));
+                               rte_memcpy(hdr1->buffer_mask, eth_mask,
+                                          sizeof(struct rte_ether_hdr));
+                       } else {
+                               /* flow subscribe filter will add dst mac in 
kernel */
+                               input_set_byte += 6;
+                       }
+
+                       hdrs->count = ++layer;
+                       break;
+               case RTE_FLOW_ITEM_TYPE_IPV4:
+                       ipv4_spec = item->spec;
+                       ipv4_mask = item->mask;
+
+                       hdr = &hdrs->proto_hdr_w_msk[layer];
+
+                       VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4);
+
+                       if (ipv4_spec && ipv4_mask) {
+                               input = &outer_input_set;
+                               /* Check IPv4 mask and update input set */
+                               if (ipv4_mask->hdr.version_ihl ||
+                                       ipv4_mask->hdr.total_length ||
+                                       ipv4_mask->hdr.packet_id ||
+                                       ipv4_mask->hdr.hdr_checksum) {
+                                       rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM,
+                                               item, "Invalid IPv4 mask.");
+                                       return false;
+                               }
+
+                               if (ipv4_mask->hdr.src_addr) {
+                                       *input |= IAVF_INSET_IPV4_SRC;
+                                       input_set_byte += 2;
+                               }
+                               if (ipv4_mask->hdr.dst_addr) {
+                                       *input |= IAVF_INSET_IPV4_DST;
+                                       input_set_byte += 2;
+                               }
+                               if (ipv4_mask->hdr.time_to_live) {
+                                       *input |= IAVF_INSET_IPV4_TTL;
+                                       input_set_byte++;
+                               }
+                               if (ipv4_mask->hdr.next_proto_id) {
+                                       *input |= IAVF_INSET_IPV4_PROTO;
+                                       input_set_byte++;
+                               }
+                               if (ipv4_mask->hdr.type_of_service) {
+                                       *input |= IAVF_INSET_IPV4_TOS;
+                                       input_set_byte++;
+                               }
+
+                               rte_memcpy(hdr->buffer_spec, &ipv4_spec->hdr,
+                                          sizeof(ipv4_spec->hdr));
+                               rte_memcpy(hdr->buffer_mask, &ipv4_mask->hdr,
+                                          sizeof(ipv4_spec->hdr));
+                       }
+
+                       hdrs->count = ++layer;
+                       break;
+               case RTE_FLOW_ITEM_TYPE_IPV6:
+                       ipv6_spec = item->spec;
+                       ipv6_mask = item->mask;
+
+                       hdr = &hdrs->proto_hdr_w_msk[layer];
+
+                       VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);
+
+                       if (ipv6_spec && ipv6_mask) {
+                               input = &outer_input_set;
+
+                               if (ipv6_mask->hdr.payload_len) {
+                                       rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM,
+                                               item, "Invalid IPv6 mask");
+                                       return false;
+                               }
+
+                               for (j = 0; j < IAVF_IPV6_ADDR_LENGTH; j++) {
+                                       if (ipv6_mask->hdr.src_addr[j]) {
+                                               *input |= IAVF_INSET_IPV6_SRC;
+                                               break;
+                                       }
+                               }
+                               for (j = 0; j < IAVF_IPV6_ADDR_LENGTH; j++) {
+                                       if (ipv6_mask->hdr.dst_addr[j]) {
+                                               *input |= IAVF_INSET_IPV6_DST;
+                                               break;
+                                       }
+                               }
+
+                               for (j = 0; j < IAVF_IPV6_ADDR_LENGTH; j++) {
+                                       if (ipv6_mask->hdr.src_addr[j])
+                                               input_set_byte++;
+
+                                       if (ipv6_mask->hdr.dst_addr[j])
+                                               input_set_byte++;
+                               }
+
+                               if (ipv6_mask->hdr.proto) {
+                                       *input |= IAVF_INSET_IPV6_NEXT_HDR;
+                                       input_set_byte++;
+                               }
+                               if (ipv6_mask->hdr.hop_limits) {
+                                       *input |= IAVF_INSET_IPV6_HOP_LIMIT;
+                                       input_set_byte++;
+                               }
+                               if (ipv6_mask->hdr.vtc_flow &
+                                   rte_cpu_to_be_32(RTE_IPV6_HDR_TC_MASK)) {
+                                       *input |= IAVF_INSET_IPV6_TC;
+                                       input_set_byte += 4;
+                               }
+
+                               rte_memcpy(hdr->buffer_spec, &ipv6_spec->hdr,
+                                          sizeof(ipv6_spec->hdr));
+                               rte_memcpy(hdr->buffer_mask, &ipv6_mask->hdr,
+                                          sizeof(ipv6_spec->hdr));
+                       }
+
+                       hdrs->count = ++layer;
+                       break;
+               case RTE_FLOW_ITEM_TYPE_UDP:
+                       udp_spec = item->spec;
+                       udp_mask = item->mask;
+
+                       hdr = &hdrs->proto_hdr_w_msk[layer];
+
+                       VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP);
+
+                       if (udp_spec && udp_mask) {
+                               input = &outer_input_set;
+                               /* Check UDP mask and update input set*/
+                               if (udp_mask->hdr.dgram_len ||
+                                   udp_mask->hdr.dgram_cksum) {
+                                       rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM,
+                                               item, "Invalid UDP mask");
+                                       return false;
+                               }
+
+                               if (udp_mask->hdr.src_port) {
+                                       *input |= IAVF_INSET_UDP_SRC_PORT;
+                                       input_set_byte += 2;
+                               }
+                               if (udp_mask->hdr.dst_port) {
+                                       *input |= IAVF_INSET_UDP_DST_PORT;
+                                       input_set_byte += 2;
+                               }
+
+                               rte_memcpy(hdr->buffer_spec, &udp_spec->hdr,
+                                          sizeof(udp_spec->hdr));
+                               rte_memcpy(hdr->buffer_mask, &udp_mask->hdr,
+                                          sizeof(udp_mask->hdr));
+                       }
+
+                       hdrs->count = ++layer;
+                       break;
+               case RTE_FLOW_ITEM_TYPE_TCP:
+                       tcp_spec = item->spec;
+                       tcp_mask = item->mask;
+
+                       hdr = &hdrs->proto_hdr_w_msk[layer];
+
+                       VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP);
+
+                       if (tcp_spec && tcp_mask) {
+                               input = &outer_input_set;
+                               /* Check TCP mask and update input set */
+                               if (tcp_mask->hdr.sent_seq ||
+                                       tcp_mask->hdr.recv_ack ||
+                                       tcp_mask->hdr.data_off ||
+                                       tcp_mask->hdr.tcp_flags ||
+                                       tcp_mask->hdr.rx_win ||
+                                       tcp_mask->hdr.cksum ||
+                                       tcp_mask->hdr.tcp_urp) {
+                                       rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM,
+                                               item, "Invalid TCP mask");
+                                       return false;
+                               }
+
+                               if (tcp_mask->hdr.src_port) {
+                                       *input |= IAVF_INSET_TCP_SRC_PORT;
+                                       input_set_byte += 2;
+                               }
+                               if (tcp_mask->hdr.dst_port) {
+                                       *input |= IAVF_INSET_TCP_DST_PORT;
+                                       input_set_byte += 2;
+                               }
+
+                               rte_memcpy(hdr->buffer_spec, &tcp_spec->hdr,
+                                          sizeof(tcp_spec->hdr));
+                               rte_memcpy(hdr->buffer_mask, &tcp_mask->hdr,
+                                          sizeof(tcp_mask->hdr));
+                       }
+
+                       hdrs->count = ++layer;
+                       break;
+               case RTE_FLOW_ITEM_TYPE_VLAN:
+                       vlan_spec = item->spec;
+                       vlan_mask = item->mask;
+
+                       hdr = &hdrs->proto_hdr_w_msk[layer];
+
+                       VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, S_VLAN);
+
+                       if (vlan_spec && vlan_spec) {
+                               input = &outer_input_set;
+
+                               *input |= IAVF_INSET_VLAN_OUTER;
+
+                               if (vlan_mask->tci)
+                                       input_set_byte += 2;
+
+                               if (vlan_mask->inner_type) {
+                                       rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM,
+                                               item,
+                                               "Invalid VLAN input set.");
+                                       return false;
+                               }
+
+                               rte_memcpy(hdr->buffer_spec, &vlan_spec->hdr,
+                                          sizeof(vlan_spec->hdr));
+                               rte_memcpy(hdr->buffer_mask, &vlan_mask->hdr,
+                                          sizeof(vlan_mask->hdr));
+                       }
+
+                       hdrs->count = ++layer;
+                       break;
+               case RTE_FLOW_ITEM_TYPE_VOID:
+                       break;
+               default:
+                       rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ITEM, pattern,
+                                          "Invalid pattern item.");
+                       return -rte_errno;
+               }
+       }
+
+       hdrs->count += VIRTCHNL_MAX_NUM_PROTO_HDRS;
+
+       if (input_set_byte > MAX_INPUT_SET_BYTE) {
+               rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
+                                  item, "too much input set");
+               return -rte_errno;
+       }
+
+       if (!outer_input_set || (outer_input_set & ~input_set_mask))
+               return -rte_errno;
+
+       return 0;
+}
+
+static int
+iavf_fsub_parse_action(struct iavf_adapter *ad,
+                      const struct rte_flow_action *actions,
+                      uint32_t priority,
+                      struct rte_flow_error *error,
+                      struct iavf_fsub_conf *filter)
 {
+       const struct rte_flow_action *action;
+       const struct rte_flow_action_ethdev *act_ethdev;
+       const struct rte_flow_action_queue *act_q;
+       const struct rte_flow_action_rss *act_qgrop;
+       struct virtchnl_filter_action *filter_action;
+       uint16_t valid_qgrop_number[MAX_QGRP_NUM_TYPE] = {
+               2, 4, 8, 16, 32, 64, 128};
+       uint16_t i, num = 0, dest_num = 0, vf_num = 0;
+       uint16_t rule_port_id;
+
+       for (action = actions; action->type !=
+                               RTE_FLOW_ACTION_TYPE_END; action++) {
+               switch (action->type) {
+               case RTE_FLOW_ACTION_TYPE_VOID:
+                       break;
+
+               case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
+                       vf_num++;
+                       filter_action = &filter->sub_fltr.actions.actions[num];
+
+                       act_ethdev = action->conf;
+                       rule_port_id = ad->dev_data->port_id;
+                       if (rule_port_id != act_ethdev->port_id)
+                               goto error1;
+
+                       filter->sub_fltr.actions.count = ++num;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_QUEUE:
+                       dest_num++;
+                       filter_action = &filter->sub_fltr.actions.actions[num];
+
+                       act_q = action->conf;
+                       if (act_q->index >= ad->dev_data->nb_rx_queues)
+                               goto error2;
+
+                       filter_action->type = VIRTCHNL_ACTION_QUEUE;
+                       filter_action->act_conf.queue.index = act_q->index;
+                       filter->sub_fltr.actions.count = ++num;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_RSS:
+                       dest_num++;
+                       filter_action = &filter->sub_fltr.actions.actions[num];
+
+                       act_qgrop = action->conf;
+                       if (act_qgrop->queue_num <= 1)
+                               goto error2;
+
+                       filter_action->type = VIRTCHNL_ACTION_Q_REGION;
+                       filter_action->act_conf.queue.index =
+                                                       act_qgrop->queue[0];
+                       for (i = 0; i < MAX_QGRP_NUM_TYPE; i++) {
+                               if (act_qgrop->queue_num ==
+                                   valid_qgrop_number[i])
+                                       break;
+                       }
+
+                       if (i == MAX_QGRP_NUM_TYPE)
+                               goto error2;
+
+                       if ((act_qgrop->queue[0] + act_qgrop->queue_num) >
+                           ad->dev_data->nb_rx_queues)
+                               goto error3;
+
+                       for (i = 0; i < act_qgrop->queue_num - 1; i++)
+                               if (act_qgrop->queue[i + 1] !=
+                                   act_qgrop->queue[i] + 1)
+                                       goto error4;
+
+                       filter_action->act_conf.queue.region = 
act_qgrop->queue_num;
+                       filter->sub_fltr.actions.count = ++num;
+                       break;
+               default:
+                       rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ACTION,
+                                          actions, "Invalid action type");
+                       return -rte_errno;
+               }
+       }
+
+       /* 0 denotes lowest priority of recipe and highest priority
+        * of rte_flow. Change rte_flow priority into recipe priority.
+        */
+       filter->sub_fltr.priority = priority;
+
+       if (num > VIRTCHNL_MAX_NUM_ACTIONS) {
+               rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                                  "Action numbers exceed the maximum value");
+               return -rte_errno;
+       }
+
+       if (vf_num == 0) {
+               rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                                  "Invalid action, vf action must be added");
+               return -rte_errno;
+       }
+
+       if (dest_num >= 2) {
+               rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                                  "Unsupported action combination");
+               return -rte_errno;
+       }
+
+       return 0;
+
+error1:
+       rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                          "Invalid ethdev_port_id");
+       return -rte_errno;
+
+error2:
+       rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                          "Invalid action type or queue number");
+       return -rte_errno;
+
+error3:
+       rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                          "Invalid queue region indexes");
+       return -rte_errno;
+
+error4:
+       rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                          "Discontinuous queue region");
        return -rte_errno;
 }
 
+static int
+iavf_fsub_check_action(const struct rte_flow_action *actions,
+                      struct rte_flow_error *error)
+{
+       const struct rte_flow_action *action;
+       enum rte_flow_action_type action_type;
+       uint16_t actions_num = 0;
+       bool vf_valid = false;
+       bool queue_valid = false;
+
+       for (action = actions; action->type !=
+                               RTE_FLOW_ACTION_TYPE_END; action++) {
+               action_type = action->type;
+               switch (action_type) {
+               case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
+                       vf_valid = true;
+                       actions_num++;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_RSS:
+               case RTE_FLOW_ACTION_TYPE_QUEUE:
+                       queue_valid = true;
+                       actions_num++;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_DROP:
+                       actions_num++;
+                       break;
+               case RTE_FLOW_ACTION_TYPE_VOID:
+                       continue;
+               default:
+                       rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ACTION,
+                                          actions, "Invalid action type");
+                       return -rte_errno;
+               }
+       }
+
+       if (!((actions_num == 1 && !queue_valid) ||
+             (actions_num == 2 && vf_valid && queue_valid))) {
+               rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+                                  actions, "Invalid action number");
+               return -rte_errno;
+       }
+
+       return 0;
+}
+
+static int
+iavf_fsub_parse(struct iavf_adapter *ad,
+               struct iavf_pattern_match_item *array,
+               uint32_t array_len,
+               const struct rte_flow_item pattern[],
+               const struct rte_flow_action actions[],
+               void **meta,
+               struct rte_flow_error *error)
+{
+       struct iavf_fsub_conf *filter;
+       struct iavf_pattern_match_item *pattern_match_item = NULL;
+       int ret = 0;
+       uint32_t priority = 0;
+
+       filter = rte_zmalloc(NULL, sizeof(*filter), 0);
+       if (!filter) {
+               rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                  "No memory for iavf_fsub_conf_ptr");
+               goto error;
+       }
+
+       /* search flow subscribe pattern */
+       pattern_match_item = iavf_search_pattern_match_item(pattern, array,
+                                                           array_len, error);
+       if (!pattern_match_item)
+               return -rte_errno;
+
+       /* parse flow subscribe pattern */
+       ret = iavf_fsub_parse_pattern(pattern,
+                                     pattern_match_item->input_set_mask,
+                                     error, filter);
+       if (ret)
+               goto error;
+
+       /* check flow subscribe pattern action */
+       ret = iavf_fsub_check_action(actions, error);
+       if (ret)
+               goto error;
+
+       /* parse flow subscribe pattern action */
+       ret = iavf_fsub_parse_action((void *)ad, actions, priority,
+                                    error, filter);
+       if (ret)
+               goto error;
+
+       if (meta)
+               *meta = filter;
+
+error:
+       rte_free(pattern_match_item);
+       return ret;
+}
+
 static int
 iavf_fsub_init(struct iavf_adapter *ad)
 {
-- 
2.25.1

Reply via email to