Add support AVF can be able to subscribe a flow from PF.

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>
---
 doc/guides/rel_notes/release_22_11.rst |   4 +
 drivers/net/iavf/iavf.h                |  10 +
 drivers/net/iavf/iavf_fdir.c           |   4 +
 drivers/net/iavf/iavf_fsub.c           | 746 +++++++++++++++++++++++++
 drivers/net/iavf/iavf_generic_flow.c   |  40 +-
 drivers/net/iavf/iavf_generic_flow.h   |   2 +
 drivers/net/iavf/iavf_hash.c           |   5 +
 drivers/net/iavf/iavf_ipsec_crypto.c   |  16 +-
 drivers/net/iavf/iavf_vchnl.c          | 133 +++++
 drivers/net/iavf/meson.build           |   1 +
 10 files changed, 944 insertions(+), 17 deletions(-)
 create mode 100644 drivers/net/iavf/iavf_fsub.c

diff --git a/doc/guides/rel_notes/release_22_11.rst 
b/doc/guides/rel_notes/release_22_11.rst
index 8c021cf050..bb77a03e24 100644
--- a/doc/guides/rel_notes/release_22_11.rst
+++ b/doc/guides/rel_notes/release_22_11.rst
@@ -55,6 +55,10 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Updated Intel iavf driver.**
+
+  * Added flow subscription support.
+
 
 Removed Items
 -------------
diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
index 025ab3ff60..6792c1de74 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;
@@ -482,4 +489,7 @@ int iavf_ipsec_crypto_request(struct iavf_adapter *adapter,
 extern const struct rte_tm_ops iavf_tm_ops;
 int iavf_get_ptp_cap(struct iavf_adapter *adapter);
 int iavf_get_phc_time(struct iavf_rx_queue *rxq);
+int iavf_flow_sub(struct iavf_adapter *adapter, struct iavf_fsub_conf *filter);
+int iavf_flow_unsub(struct iavf_adapter *adapter, struct iavf_fsub_conf 
*filter);
+int iavf_flow_sub_check(struct iavf_adapter *adapter, struct iavf_fsub_conf 
*filter);
 #endif /* _IAVF_ETHDEV_H_ */
diff --git a/drivers/net/iavf/iavf_fdir.c b/drivers/net/iavf/iavf_fdir.c
index 2e6b3a9097..f5e23da5bc 100644
--- a/drivers/net/iavf/iavf_fdir.c
+++ b/drivers/net/iavf/iavf_fdir.c
@@ -1551,6 +1551,7 @@ iavf_fdir_parse(struct iavf_adapter *ad,
                uint32_t array_len,
                const struct rte_flow_item pattern[],
                const struct rte_flow_action actions[],
+               uint32_t priority,
                void **meta,
                struct rte_flow_error *error)
 {
@@ -1561,6 +1562,9 @@ iavf_fdir_parse(struct iavf_adapter *ad,
 
        memset(filter, 0, sizeof(*filter));
 
+       if (priority >= 1)
+               return -rte_errno;
+
        item = iavf_search_pattern_match_item(pattern, array, array_len, error);
        if (!item)
                return -rte_errno;
diff --git a/drivers/net/iavf/iavf_fsub.c b/drivers/net/iavf/iavf_fsub.c
new file mode 100644
index 0000000000..910e519cc1
--- /dev/null
+++ b/drivers/net/iavf/iavf_fsub.c
@@ -0,0 +1,746 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_eth_ctrl.h>
+#include <rte_tailq.h>
+#include <rte_flow_driver.h>
+#include <rte_flow.h>
+#include <iavf.h>
+#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_FLTR_RX           BIT(0)
+#define IAVF_FLTR_TX           BIT(1)
+#define IAVF_FLTR_TX_RX                (IAVF_FLTR_RX | IAVF_FLTR_TX)
+
+#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[] = {
+       {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(struct iavf_adapter *ad, struct rte_flow *flow,
+                void *meta, struct rte_flow_error *error)
+{
+       struct iavf_fsub_conf *filter = meta;
+       struct iavf_fsub_conf *rule;
+       int ret;
+
+       rule = rte_zmalloc("fsub_entry", sizeof(*rule), 0);
+       if (!rule) {
+               rte_flow_error_set(error, ENOMEM,
+                               RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                               "Failed to allocate memory for fsub rule");
+               return -rte_errno;
+       }
+
+       ret = iavf_flow_sub(ad, filter);
+       if (ret) {
+               rte_flow_error_set(error, -ret,
+                                  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                  "Failed to subscribe flow rule.");
+               goto free_entry;
+       }
+
+       rte_memcpy(rule, filter, sizeof(*rule));
+       flow->rule = rule;
+
+       return 0;
+
+free_entry:
+       rte_free(rule);
+       return -rte_errno;
+}
+
+static int
+iavf_fsub_destroy(struct iavf_adapter *ad, struct rte_flow *flow,
+                 struct rte_flow_error *error)
+{
+       struct iavf_fsub_conf *filter;
+       int ret;
+
+       filter = (struct iavf_fsub_conf *)flow->rule;
+
+       ret = iavf_flow_unsub(ad, filter);
+       if (ret) {
+               rte_flow_error_set(error, -ret,
+                                  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                  "Failed to unsubscribe flow rule.");
+               return -rte_errno;
+       }
+
+       flow->rule = NULL;
+       rte_free(filter);
+
+       return ret;
+}
+
+static int
+iavf_fsub_validation(struct iavf_adapter *ad,
+                    __rte_unused struct rte_flow *flow,
+                    void *meta,
+                    struct rte_flow_error *error)
+{
+       struct iavf_fsub_conf *filter = meta;
+       int ret;
+
+       ret = iavf_flow_sub_check(ad, filter);
+       if (ret) {
+               rte_flow_error_set(error, -ret,
+                                  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                  "Failed to validate filter rule.");
+               return -rte_errno;
+       }
+
+       return 0;
+};
+
+static int
+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_vf *act_vf;
+       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;
+
+       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_VF:
+                       vf_num++;
+                       filter_action = &filter->sub_fltr.actions.actions[num];
+
+                       act_vf = action->conf;
+                       if (act_vf->id != ad->hw.device_id &&
+                               !act_vf->original) {
+                               rte_flow_error_set(error, EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ACTION,
+                                       actions, "Invalid vf id");
+                               return -rte_errno;
+                       }
+
+                       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 error;
+
+                       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 error;
+
+                       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 error;
+
+                       if ((act_qgrop->queue[0] + act_qgrop->queue_num) >
+                           ad->dev_data->nb_rx_queues)
+                               goto error1;
+
+                       for (i = 0; i < act_qgrop->queue_num - 1; i++)
+                               if (act_qgrop->queue[i + 1] !=
+                                   act_qgrop->queue[i] + 1)
+                                       goto error2;
+
+                       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;
+error:
+       rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                          "Invalid action type or queue number");
+       return -rte_errno;
+
+error1:
+       rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                          "Invalid queue region indexes");
+       return -rte_errno;
+
+error2:
+       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_VF:
+                       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[],
+               uint32_t priority,
+               void **meta,
+               struct rte_flow_error *error)
+{
+       struct iavf_fsub_conf *filter;
+       struct iavf_pattern_match_item *pattern_match_item = NULL;
+       int ret = 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)
+{
+       struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(ad);
+       struct iavf_flow_parser *parser;
+
+       if (!vf->vf_res)
+               return -EINVAL;
+
+       if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_FSUB_PF)
+               parser = &iavf_fsub_parser;
+       else
+               return -ENOTSUP;
+
+       return iavf_register_parser(parser, ad);
+}
+
+static void
+iavf_fsub_uninit(struct iavf_adapter *ad)
+{
+       iavf_unregister_parser(&iavf_fsub_parser, ad);
+}
+
+static struct
+iavf_flow_engine iavf_fsub_engine = {
+       .init = iavf_fsub_init,
+       .uninit = iavf_fsub_uninit,
+       .create = iavf_fsub_create,
+       .destroy = iavf_fsub_destroy,
+       .validation = iavf_fsub_validation,
+       .type = IAVF_FLOW_ENGINE_FSUB,
+};
+
+static struct
+iavf_flow_parser iavf_fsub_parser = {
+       .engine = &iavf_fsub_engine,
+       .array = iavf_fsub_pattern_list,
+       .array_len = RTE_DIM(iavf_fsub_pattern_list),
+       .parse_pattern_action = iavf_fsub_parse,
+       .stage = IAVF_FLOW_STAGE_DISTRIBUTOR,
+};
+
+RTE_INIT(iavf_fsub_engine_init)
+{
+       iavf_register_flow_engine(&iavf_fsub_engine);
+}
diff --git a/drivers/net/iavf/iavf_generic_flow.c 
b/drivers/net/iavf/iavf_generic_flow.c
index e1a611e319..f33c764764 100644
--- a/drivers/net/iavf/iavf_generic_flow.c
+++ b/drivers/net/iavf/iavf_generic_flow.c
@@ -1785,6 +1785,7 @@ enum rte_flow_item_type 
iavf_pattern_eth_ipv6_udp_l2tpv2_ppp_ipv6_tcp[] = {
 typedef struct iavf_flow_engine * (*parse_engine_t)(struct iavf_adapter *ad,
                struct rte_flow *flow,
                struct iavf_parser_list *parser_list,
+               uint32_t priority,
                const struct rte_flow_item pattern[],
                const struct rte_flow_action actions[],
                struct rte_flow_error *error);
@@ -1866,6 +1867,8 @@ iavf_register_parser(struct iavf_flow_parser *parser,
 {
        struct iavf_parser_list *list = NULL;
        struct iavf_flow_parser_node *parser_node;
+       struct iavf_flow_parser_node *existing_node;
+       void *temp;
        struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(ad);
 
        parser_node = rte_zmalloc("iavf_parser", sizeof(*parser_node), 0);
@@ -1880,14 +1883,26 @@ iavf_register_parser(struct iavf_flow_parser *parser,
                TAILQ_INSERT_TAIL(list, parser_node, node);
        } else if (parser->engine->type == IAVF_FLOW_ENGINE_FDIR) {
                list = &vf->dist_parser_list;
+               RTE_TAILQ_FOREACH_SAFE(existing_node, list, node, temp) {
+                       if (existing_node->parser->engine->type ==
+                           IAVF_FLOW_ENGINE_FSUB) {
+                               TAILQ_INSERT_AFTER(list, existing_node,
+                                                  parser_node, node);
+                               goto DONE;
+                       }
+               }
                TAILQ_INSERT_HEAD(list, parser_node, node);
        } else if (parser->engine->type == IAVF_FLOW_ENGINE_IPSEC_CRYPTO) {
                list = &vf->ipsec_crypto_parser_list;
                TAILQ_INSERT_HEAD(list, parser_node, node);
+       } else if (parser->engine->type == IAVF_FLOW_ENGINE_FSUB) {
+               list = &vf->dist_parser_list;
+               TAILQ_INSERT_HEAD(list, parser_node, node);
        } else {
                return -EINVAL;
        }
 
+DONE:
        return 0;
 }
 
@@ -1902,7 +1917,8 @@ iavf_unregister_parser(struct iavf_flow_parser *parser,
 
        if (parser->engine->type == IAVF_FLOW_ENGINE_HASH)
                list = &vf->rss_parser_list;
-       else if (parser->engine->type == IAVF_FLOW_ENGINE_FDIR)
+       else if ((parser->engine->type == IAVF_FLOW_ENGINE_FDIR) ||
+                (parser->engine->type == IAVF_FLOW_ENGINE_FSUB))
                list = &vf->dist_parser_list;
 
        if (list == NULL)
@@ -1936,11 +1952,11 @@ iavf_flow_valid_attr(const struct rte_flow_attr *attr,
                return -rte_errno;
        }
 
-       /* Not supported */
-       if (attr->priority) {
+       /* support priority for flow subscribe */
+       if (attr->priority > 1) {
                rte_flow_error_set(error, EINVAL,
                                RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
-                               attr, "Not support priority.");
+                               attr, "Only support priority 0 and 1.");
                return -rte_errno;
        }
 
@@ -2083,6 +2099,7 @@ static struct iavf_flow_engine *
 iavf_parse_engine_create(struct iavf_adapter *ad,
                struct rte_flow *flow,
                struct iavf_parser_list *parser_list,
+               uint32_t priority,
                const struct rte_flow_item pattern[],
                const struct rte_flow_action actions[],
                struct rte_flow_error *error)
@@ -2096,7 +2113,7 @@ iavf_parse_engine_create(struct iavf_adapter *ad,
                if (parser_node->parser->parse_pattern_action(ad,
                                parser_node->parser->array,
                                parser_node->parser->array_len,
-                               pattern, actions, &meta, error) < 0)
+                               pattern, actions, priority, &meta, error) < 0)
                        continue;
 
                engine = parser_node->parser->engine;
@@ -2112,6 +2129,7 @@ static struct iavf_flow_engine *
 iavf_parse_engine_validate(struct iavf_adapter *ad,
                struct rte_flow *flow,
                struct iavf_parser_list *parser_list,
+               uint32_t priority,
                const struct rte_flow_item pattern[],
                const struct rte_flow_action actions[],
                struct rte_flow_error *error)
@@ -2125,7 +2143,7 @@ iavf_parse_engine_validate(struct iavf_adapter *ad,
                if (parser_node->parser->parse_pattern_action(ad,
                                parser_node->parser->array,
                                parser_node->parser->array_len,
-                               pattern, actions, &meta,  error) < 0)
+                               pattern, actions, priority, &meta, error) < 0)
                        continue;
 
                engine = parser_node->parser->engine;
@@ -2186,18 +2204,18 @@ iavf_flow_process_filter(struct rte_eth_dev *dev,
        if (ret)
                return ret;
 
-       *engine = iavf_parse_engine(ad, flow, &vf->rss_parser_list, pattern,
-                                   actions, error);
+       *engine = iavf_parse_engine(ad, flow, &vf->rss_parser_list,
+                                   attr->priority, pattern, actions, error);
        if (*engine)
                return 0;
 
-       *engine = iavf_parse_engine(ad, flow, &vf->dist_parser_list, pattern,
-                                   actions, error);
+       *engine = iavf_parse_engine(ad, flow, &vf->dist_parser_list,
+                                   attr->priority, pattern, actions, error);
        if (*engine)
                return 0;
 
        *engine = iavf_parse_engine(ad, flow, &vf->ipsec_crypto_parser_list,
-                       pattern, actions, error);
+                                   attr->priority, pattern, actions, error);
        if (*engine)
                return 0;
 
diff --git a/drivers/net/iavf/iavf_generic_flow.h 
b/drivers/net/iavf/iavf_generic_flow.h
index 52eb1caf29..60d8ab02b4 100644
--- a/drivers/net/iavf/iavf_generic_flow.h
+++ b/drivers/net/iavf/iavf_generic_flow.h
@@ -471,6 +471,7 @@ typedef int (*parse_pattern_action_t)(struct iavf_adapter 
*ad,
                uint32_t array_len,
                const struct rte_flow_item pattern[],
                const struct rte_flow_action actions[],
+               uint32_t priority,
                void **meta,
                struct rte_flow_error *error);
 
@@ -480,6 +481,7 @@ enum iavf_flow_engine_type {
        IAVF_FLOW_ENGINE_IPSEC_CRYPTO,
        IAVF_FLOW_ENGINE_FDIR,
        IAVF_FLOW_ENGINE_HASH,
+       IAVF_FLOW_ENGINE_FSUB,
        IAVF_FLOW_ENGINE_MAX,
 };
 
diff --git a/drivers/net/iavf/iavf_hash.c b/drivers/net/iavf/iavf_hash.c
index 42df7c4e48..dea4e0aa0a 100644
--- a/drivers/net/iavf/iavf_hash.c
+++ b/drivers/net/iavf/iavf_hash.c
@@ -86,6 +86,7 @@ iavf_hash_parse_pattern_action(struct iavf_adapter *ad,
                               uint32_t array_len,
                               const struct rte_flow_item pattern[],
                               const struct rte_flow_action actions[],
+                              uint32_t priority,
                               void **meta,
                               struct rte_flow_error *error);
 
@@ -1509,6 +1510,7 @@ iavf_hash_parse_pattern_action(__rte_unused struct 
iavf_adapter *ad,
                               uint32_t array_len,
                               const struct rte_flow_item pattern[],
                               const struct rte_flow_action actions[],
+                              uint32_t priority,
                               void **meta,
                               struct rte_flow_error *error)
 {
@@ -1517,6 +1519,9 @@ iavf_hash_parse_pattern_action(__rte_unused struct 
iavf_adapter *ad,
        uint64_t phint = IAVF_PHINT_NONE;
        int ret = 0;
 
+       if (priority >= 1)
+               return -rte_errno;
+
        rss_meta_ptr = rte_zmalloc(NULL, sizeof(*rss_meta_ptr), 0);
        if (!rss_meta_ptr) {
                rte_flow_error_set(error, EINVAL,
diff --git a/drivers/net/iavf/iavf_ipsec_crypto.c 
b/drivers/net/iavf/iavf_ipsec_crypto.c
index 75f05ee558..322934b5f6 100644
--- a/drivers/net/iavf/iavf_ipsec_crypto.c
+++ b/drivers/net/iavf/iavf_ipsec_crypto.c
@@ -1932,16 +1932,20 @@ static struct iavf_flow_engine iavf_ipsec_flow_engine = 
{
 
 static int
 iavf_ipsec_flow_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_pattern_match_item *array,
+                     uint32_t array_len,
+                     const struct rte_flow_item pattern[],
+                     const struct rte_flow_action actions[],
+                     uint32_t priority,
+                     void **meta,
+                     struct rte_flow_error *error)
 {
        struct iavf_pattern_match_item *item = NULL;
        int ret = -1;
 
+       if (priority >= 1)
+               return -rte_errno;
+
        item = iavf_search_pattern_match_item(pattern, array, array_len, error);
        if (item && item->meta) {
                uint32_t type = (uint64_t)(item->meta);
diff --git a/drivers/net/iavf/iavf_vchnl.c b/drivers/net/iavf/iavf_vchnl.c
index 21bd1e2193..ea3e1e8bb2 100644
--- a/drivers/net/iavf/iavf_vchnl.c
+++ b/drivers/net/iavf/iavf_vchnl.c
@@ -502,6 +502,7 @@ iavf_get_vf_resource(struct iavf_adapter *adapter)
                VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC |
                VIRTCHNL_VF_OFFLOAD_FDIR_PF |
                VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF |
+               VIRTCHNL_VF_OFFLOAD_FSUB_PF |
                VIRTCHNL_VF_OFFLOAD_REQ_QUEUES |
                VIRTCHNL_VF_OFFLOAD_CRC |
                VIRTCHNL_VF_OFFLOAD_VLAN_V2 |
@@ -1533,6 +1534,138 @@ iavf_fdir_check(struct iavf_adapter *adapter,
        return 0;
 }
 
+int
+iavf_flow_sub(struct iavf_adapter *adapter, struct iavf_fsub_conf *filter)
+{
+       struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+       struct virtchnl_flow_sub *fsub_cfg;
+       struct iavf_cmd_info args;
+       int err;
+
+       filter->sub_fltr.vsi_id = vf->vsi_res->vsi_id;
+       filter->sub_fltr.validate_only = 0;
+
+       memset(&args, 0, sizeof(args));
+       args.ops = VIRTCHNL_OP_FLOW_SUBSCRIBE;
+       args.in_args = (uint8_t *)(&filter->sub_fltr);
+       args.in_args_size = sizeof(*(&filter->sub_fltr));
+       args.out_buffer = vf->aq_resp;
+       args.out_size = IAVF_AQ_BUF_SZ;
+
+       err = iavf_execute_vf_cmd(adapter, &args, 0);
+       if (err)
+               PMD_DRV_LOG(ERR, "Failed to execute command of "
+                                "OP_FLOW_SUBSCRIBE");
+
+       fsub_cfg = (struct virtchnl_flow_sub *)args.out_buffer;
+       filter->flow_id = fsub_cfg->flow_id;
+
+       if (fsub_cfg->status == VIRTCHNL_FSUB_SUCCESS) {
+               PMD_DRV_LOG(INFO, "Succeed in adding rule request by PF");
+       } else if (fsub_cfg->status == VIRTCHNL_FSUB_FAILURE_RULE_NORESOURCE) {
+               PMD_DRV_LOG(ERR, "Failed to add rule request due to no hw "
+                                "resource");
+               err = -1;
+       } else if (fsub_cfg->status == VIRTCHNL_FSUB_FAILURE_RULE_EXIST) {
+               PMD_DRV_LOG(ERR, "Failed to add rule request due to the rule "
+                                "is already existed");
+               err = -1;
+       } else if (fsub_cfg->status == VIRTCHNL_FSUB_FAILURE_RULE_INVALID) {
+               PMD_DRV_LOG(ERR, "Failed to add rule request due to the hw "
+                                "doesn't support");
+               err = -1;
+       } else {
+               PMD_DRV_LOG(ERR, "Failed to add rule request due to other "
+                                "reasons");
+               err = -1;
+       }
+
+       return err;
+}
+
+int
+iavf_flow_unsub(struct iavf_adapter *adapter, struct iavf_fsub_conf *filter)
+{
+       struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+       struct virtchnl_flow_unsub *unsub_cfg;
+       struct iavf_cmd_info args;
+       int err;
+
+       filter->unsub_fltr.vsi_id = vf->vsi_res->vsi_id;
+       filter->unsub_fltr.flow_id = filter->flow_id;
+
+       memset(&args, 0, sizeof(args));
+       args.ops = VIRTCHNL_OP_FLOW_UNSUBSCRIBE;
+       args.in_args = (uint8_t *)(&filter->unsub_fltr);
+       args.in_args_size = sizeof(filter->unsub_fltr);
+       args.out_buffer = vf->aq_resp;
+       args.out_size = IAVF_AQ_BUF_SZ;
+
+       err = iavf_execute_vf_cmd(adapter, &args, 0);
+       if (err)
+               PMD_DRV_LOG(ERR, "Failed to execute command of "
+                                "OP_FLOW_UNSUBSCRIBE");
+
+       unsub_cfg = (struct virtchnl_flow_unsub *)args.out_buffer;
+
+       if (unsub_cfg->status == VIRTCHNL_FSUB_SUCCESS) {
+               PMD_DRV_LOG(INFO, "Succeed in deleting rule request by PF");
+       } else if (unsub_cfg->status == VIRTCHNL_FSUB_FAILURE_RULE_NONEXIST) {
+               PMD_DRV_LOG(ERR, "Failed to delete rule request due to this "
+                                "rule doesn't exist");
+               err = -1;
+       } else {
+               PMD_DRV_LOG(ERR, "Failed to delete rule request due to other "
+                                "reasons");
+               err = -1;
+       }
+
+       return err;
+}
+
+int
+iavf_flow_sub_check(struct iavf_adapter *adapter,
+                   struct iavf_fsub_conf *filter)
+{
+       struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+       struct virtchnl_flow_sub *fsub_cfg;
+
+       struct iavf_cmd_info args;
+       int err;
+
+       filter->sub_fltr.vsi_id = vf->vsi_res->vsi_id;
+       filter->sub_fltr.validate_only = 1;
+
+       args.ops = VIRTCHNL_OP_FLOW_SUBSCRIBE;
+       args.in_args = (uint8_t *)(&filter->sub_fltr);
+       args.in_args_size = sizeof(*(&filter->sub_fltr));
+       args.out_buffer = vf->aq_resp;
+       args.out_size = IAVF_AQ_BUF_SZ;
+
+       err = iavf_execute_vf_cmd(adapter, &args, 0);
+       if (err) {
+               PMD_DRV_LOG(ERR, "fail to check flow director rule");
+               return err;
+       }
+
+       fsub_cfg = (struct virtchnl_flow_sub *)args.out_buffer;
+
+       if (fsub_cfg->status == VIRTCHNL_FSUB_SUCCESS) {
+               PMD_DRV_LOG(INFO, "Succeed in checking rule request by PF");
+       } else if (fsub_cfg->status == VIRTCHNL_FSUB_FAILURE_RULE_INVALID) {
+               PMD_DRV_LOG(ERR, "Failed to check rule request due to "
+                                "parameters validation or HW doesn't "
+                                "support");
+               err = -1;
+       } else {
+               PMD_DRV_LOG(ERR, "Failed to check rule request due to other "
+                                "reasons");
+               err = -1;
+       }
+
+       return 0;
+}
+
 int
 iavf_add_del_rss_cfg(struct iavf_adapter *adapter,
                     struct virtchnl_rss_cfg *rss_cfg, bool add)
diff --git a/drivers/net/iavf/meson.build b/drivers/net/iavf/meson.build
index 2da37de662..6df771f917 100644
--- a/drivers/net/iavf/meson.build
+++ b/drivers/net/iavf/meson.build
@@ -16,6 +16,7 @@ sources = files(
         'iavf_hash.c',
         'iavf_tm.c',
         'iavf_ipsec_crypto.c',
+        'iavf_fsub.c',
 )
 
 if arch_subdir == 'x86'
-- 
2.25.1

Reply via email to