net/bnxt: use UINT64_MAX to initialize filter ids
[dpdk.git] / drivers / net / bnxt / bnxt_filter.c
index 9f171fd..9351460 100644 (file)
@@ -1,34 +1,6 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) Broadcom Limited.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Broadcom Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2014-2018 Broadcom
+ * All rights reserved.
  */
 
 #include <sys/queue.h>
@@ -56,7 +28,7 @@ struct bnxt_filter_info *bnxt_alloc_filter(struct bnxt *bp)
        /* Find the 1st unused filter from the free_filter_list pool*/
        filter = STAILQ_FIRST(&bp->free_filter_list);
        if (!filter) {
-               RTE_LOG(ERR, PMD, "No more free filter resources\n");
+               PMD_DRV_LOG(ERR, "No more free filter resources\n");
                return NULL;
        }
        STAILQ_REMOVE_HEAD(&bp->free_filter_list, next);
@@ -77,7 +49,7 @@ struct bnxt_filter_info *bnxt_alloc_vf_filter(struct bnxt *bp, uint16_t vf)
 
        filter = rte_zmalloc("bnxt_vf_filter_info", sizeof(*filter), 0);
        if (!filter) {
-               RTE_LOG(ERR, PMD, "Failed to alloc memory for VF %hu filters\n",
+               PMD_DRV_LOG(ERR, "Failed to alloc memory for VF %hu filters\n",
                        vf);
                return NULL;
        }
@@ -96,9 +68,9 @@ void bnxt_init_filters(struct bnxt *bp)
        STAILQ_INIT(&bp->free_filter_list);
        for (i = 0; i < max_filters; i++) {
                filter = &bp->filter_info[i];
-               filter->fw_l2_filter_id = -1;
-               filter->fw_em_filter_id = -1;
-               filter->fw_ntuple_filter_id = -1;
+               filter->fw_l2_filter_id = UINT64_MAX;
+               filter->fw_em_filter_id = UINT64_MAX;
+               filter->fw_ntuple_filter_id = UINT64_MAX;
                STAILQ_INSERT_TAIL(&bp->free_filter_list, filter, next);
        }
 }
@@ -145,11 +117,11 @@ void bnxt_free_filter_mem(struct bnxt *bp)
        for (i = 0; i < max_filters; i++) {
                filter = &bp->filter_info[i];
                if (filter->fw_l2_filter_id != ((uint64_t)-1)) {
-                       RTE_LOG(ERR, PMD, "HWRM filter is not freed??\n");
+                       PMD_DRV_LOG(ERR, "HWRM filter is not freed??\n");
                        /* Call HWRM to try to free filter again */
                        rc = bnxt_hwrm_clear_l2_filter(bp, filter);
                        if (rc)
-                               RTE_LOG(ERR, PMD,
+                               PMD_DRV_LOG(ERR,
                                       "HWRM filter cannot be freed rc = %d\n",
                                        rc);
                }
@@ -159,6 +131,14 @@ void bnxt_free_filter_mem(struct bnxt *bp)
 
        rte_free(bp->filter_info);
        bp->filter_info = NULL;
+
+       for (i = 0; i < bp->pf.max_vfs; i++) {
+               STAILQ_FOREACH(filter, &bp->pf.vf_info[i].filter, next) {
+                       rte_free(filter);
+                       STAILQ_REMOVE(&bp->pf.vf_info[i].filter, filter,
+                                     bnxt_filter_info, next);
+               }
+       }
 }
 
 int bnxt_alloc_filter_mem(struct bnxt *bp)
@@ -172,7 +152,7 @@ int bnxt_alloc_filter_mem(struct bnxt *bp)
                                 max_filters * sizeof(struct bnxt_filter_info),
                                 0);
        if (filter_mem == NULL) {
-               RTE_LOG(ERR, PMD, "Failed to alloc memory for %d filters",
+               PMD_DRV_LOG(ERR, "Failed to alloc memory for %d filters",
                        max_filters);
                return -ENOMEM;
        }
@@ -187,7 +167,7 @@ struct bnxt_filter_info *bnxt_get_unused_filter(struct bnxt *bp)
        /* Find the 1st unused filter from the free_filter_list pool*/
        filter = STAILQ_FIRST(&bp->free_filter_list);
        if (!filter) {
-               RTE_LOG(ERR, PMD, "No more free filter resources\n");
+               PMD_DRV_LOG(ERR, "No more free filter resources\n");
                return NULL;
        }
        STAILQ_REMOVE_HEAD(&bp->free_filter_list, next);
@@ -250,7 +230,7 @@ nxt_non_void_action(const struct rte_flow_action *cur)
        }
 }
 
-static inline int check_zero_bytes(const uint8_t *bytes, int len)
+int check_zero_bytes(const uint8_t *bytes, int len)
 {
        int i;
        for (i = 0; i < len; i++)
@@ -281,7 +261,7 @@ bnxt_filter_type_check(const struct rte_flow_item pattern[],
                        /* FALLTHROUGH */
                        /* need ntuple match, reset exact match */
                        if (!use_ntuple) {
-                               RTE_LOG(ERR, PMD,
+                               PMD_DRV_LOG(ERR,
                                        "VLAN flow cannot use NTUPLE filter\n");
                                rte_flow_error_set(error, EINVAL,
                                                   RTE_FLOW_ERROR_TYPE_ITEM,
@@ -292,7 +272,7 @@ bnxt_filter_type_check(const struct rte_flow_item pattern[],
                        use_ntuple |= 1;
                        break;
                default:
-                       RTE_LOG(ERR, PMD, "Unknown Flow type");
+                       PMD_DRV_LOG(ERR, "Unknown Flow type");
                        use_ntuple |= 1;
                }
                item++;
@@ -301,7 +281,8 @@ bnxt_filter_type_check(const struct rte_flow_item pattern[],
 }
 
 static int
-bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
+bnxt_validate_and_parse_flow_type(struct bnxt *bp,
+                                 const struct rte_flow_item pattern[],
                                  struct rte_flow_error *error,
                                  struct bnxt_filter_info *filter)
 {
@@ -318,14 +299,17 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
        const struct rte_flow_item_vxlan *vxlan_mask;
        uint8_t vni_mask[] = {0xFF, 0xFF, 0xFF};
        uint8_t tni_mask[] = {0xFF, 0xFF, 0xFF};
+       const struct rte_flow_item_vf *vf_spec;
        uint32_t tenant_id_be = 0;
        bool vni_masked = 0;
        bool tni_masked = 0;
+       uint32_t vf = 0;
        int use_ntuple;
        uint32_t en = 0;
+       int dflt_vnic;
 
        use_ntuple = bnxt_filter_type_check(pattern, error);
-       RTE_LOG(ERR, PMD, "Use NTUPLE %d\n", use_ntuple);
+       PMD_DRV_LOG(DEBUG, "Use NTUPLE %d\n", use_ntuple);
        if (use_ntuple < 0)
                return use_ntuple;
 
@@ -350,8 +334,8 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
                }
                switch (item->type) {
                case RTE_FLOW_ITEM_TYPE_ETH:
-                       eth_spec = (const struct rte_flow_item_eth *)item->spec;
-                       eth_mask = (const struct rte_flow_item_eth *)item->mask;
+                       eth_spec = item->spec;
+                       eth_mask = item->mask;
 
                        /* Source MAC address mask cannot be partially set.
                         * Should be All 0's or all 1's.
@@ -406,10 +390,8 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
 
                        break;
                case RTE_FLOW_ITEM_TYPE_VLAN:
-                       vlan_spec =
-                               (const struct rte_flow_item_vlan *)item->spec;
-                       vlan_mask =
-                               (const struct rte_flow_item_vlan *)item->mask;
+                       vlan_spec = item->spec;
+                       vlan_mask = item->mask;
                        if (vlan_mask->tci & 0xFFFF && !vlan_mask->tpid) {
                                /* Only the VLAN ID can be matched. */
                                filter->l2_ovlan =
@@ -427,10 +409,8 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
                        break;
                case RTE_FLOW_ITEM_TYPE_IPV4:
                        /* If mask is not involved, we could use EM filters. */
-                       ipv4_spec =
-                               (const struct rte_flow_item_ipv4 *)item->spec;
-                       ipv4_mask =
-                               (const struct rte_flow_item_ipv4 *)item->mask;
+                       ipv4_spec = item->spec;
+                       ipv4_mask = item->mask;
                        /* Only IP DST and SRC fields are maskable. */
                        if (ipv4_mask->hdr.version_ihl ||
                            ipv4_mask->hdr.type_of_service ||
@@ -479,10 +459,8 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
                        }
                        break;
                case RTE_FLOW_ITEM_TYPE_IPV6:
-                       ipv6_spec =
-                               (const struct rte_flow_item_ipv6 *)item->spec;
-                       ipv6_mask =
-                               (const struct rte_flow_item_ipv6 *)item->mask;
+                       ipv6_spec = item->spec;
+                       ipv6_mask = item->mask;
 
                        /* Only IP DST and SRC fields are maskable. */
                        if (ipv6_mask->hdr.vtc_flow ||
@@ -523,8 +501,8 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
                                EM_FLOW_ALLOC_INPUT_IP_ADDR_TYPE_IPV6;
                        break;
                case RTE_FLOW_ITEM_TYPE_TCP:
-                       tcp_spec = (const struct rte_flow_item_tcp *)item->spec;
-                       tcp_mask = (const struct rte_flow_item_tcp *)item->mask;
+                       tcp_spec = item->spec;
+                       tcp_mask = item->mask;
 
                        /* Check TCP mask. Only DST & SRC ports are maskable */
                        if (tcp_mask->hdr.sent_seq ||
@@ -560,8 +538,8 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
                        }
                        break;
                case RTE_FLOW_ITEM_TYPE_UDP:
-                       udp_spec = (const struct rte_flow_item_udp *)item->spec;
-                       udp_mask = (const struct rte_flow_item_udp *)item->mask;
+                       udp_spec = item->spec;
+                       udp_mask = item->mask;
 
                        if (udp_mask->hdr.dgram_len ||
                            udp_mask->hdr.dgram_cksum) {
@@ -593,10 +571,8 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
                        }
                        break;
                case RTE_FLOW_ITEM_TYPE_VXLAN:
-                       vxlan_spec =
-                               (const struct rte_flow_item_vxlan *)item->spec;
-                       vxlan_mask =
-                               (const struct rte_flow_item_vxlan *)item->mask;
+                       vxlan_spec = item->spec;
+                       vxlan_mask = item->mask;
                        /* Check if VXLAN item is used to describe protocol.
                         * If yes, both spec and mask should be NULL.
                         * If no, both spec and mask shouldn't be NULL.
@@ -642,10 +618,8 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
                        }
                        break;
                case RTE_FLOW_ITEM_TYPE_NVGRE:
-                       nvgre_spec =
-                               (const struct rte_flow_item_nvgre *)item->spec;
-                       nvgre_mask =
-                               (const struct rte_flow_item_nvgre *)item->mask;
+                       nvgre_spec = item->spec;
+                       nvgre_mask = item->mask;
                        /* Check if NVGRE item is used to describe protocol.
                         * If yes, both spec and mask should be NULL.
                         * If no, both spec and mask shouldn't be NULL.
@@ -687,6 +661,40 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_item pattern[],
                                 CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_NVGRE;
                        }
                        break;
+               case RTE_FLOW_ITEM_TYPE_VF:
+                       vf_spec = item->spec;
+                       vf = vf_spec->id;
+                       if (!BNXT_PF(bp)) {
+                               rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ITEM,
+                                          item,
+                                          "Configuring on a VF!");
+                               return -rte_errno;
+                       }
+
+                       if (vf >= bp->pdev->max_vfs) {
+                               rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ITEM,
+                                          item,
+                                          "Incorrect VF id!");
+                               return -rte_errno;
+                       }
+
+                       filter->mirror_vnic_id =
+                       dflt_vnic = bnxt_hwrm_func_qcfg_vf_dflt_vnic_id(bp, vf);
+                       if (dflt_vnic < 0) {
+                               /* This simply indicates there's no driver
+                                * loaded. This is not an error.
+                                */
+                               rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ITEM,
+                                          item,
+                                          "Unable to get default VNIC for VF");
+                               return -rte_errno;
+                       }
+                       filter->mirror_vnic_id = dflt_vnic;
+                       en |= NTUPLE_FLTR_ALLOC_INPUT_EN_MIRROR_VNIC_ID;
+                       break;
                default:
                        break;
                }
@@ -753,8 +761,10 @@ bnxt_get_l2_filter(struct bnxt *bp, struct bnxt_filter_info *nf,
                return f0;
 
        //This flow needs DST MAC which is not same as port/l2
-       RTE_LOG(DEBUG, PMD, "Create L2 filter for DST MAC\n");
+       PMD_DRV_LOG(DEBUG, "Create L2 filter for DST MAC\n");
        filter1 = bnxt_get_unused_filter(bp);
+       if (filter1 == NULL)
+               return NULL;
        filter1->flags = HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_PATH_RX;
        filter1->enables = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR |
                        L2_FILTER_ALLOC_INPUT_EN_L2_ADDR_MASK;
@@ -766,7 +776,6 @@ bnxt_get_l2_filter(struct bnxt *bp, struct bnxt_filter_info *nf,
                bnxt_free_filter(bp, filter1);
                return NULL;
        }
-       STAILQ_INSERT_TAIL(&vnic->filter, filter1, next);
        return filter1;
 }
 
@@ -781,12 +790,15 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev,
        const struct rte_flow_action *act = nxt_non_void_action(actions);
        struct bnxt *bp = (struct bnxt *)dev->data->dev_private;
        const struct rte_flow_action_queue *act_q;
+       const struct rte_flow_action_vf *act_vf;
        struct bnxt_vnic_info *vnic, *vnic0;
        struct bnxt_filter_info *filter1;
+       uint32_t vf = 0;
+       int dflt_vnic;
        int rc;
 
        if (bp->eth_dev->data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_RSS) {
-               RTE_LOG(ERR, PMD, "Cannot create flow on RSS queues\n");
+               PMD_DRV_LOG(ERR, "Cannot create flow on RSS queues\n");
                rte_flow_error_set(error, EINVAL,
                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
                                   "Cannot create flow on RSS queues");
@@ -794,7 +806,7 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev,
                goto ret;
        }
 
-       rc = bnxt_validate_and_parse_flow_type(pattern, error, filter);
+       rc = bnxt_validate_and_parse_flow_type(bp, pattern, error, filter);
        if (rc != 0)
                goto ret;
 
@@ -802,7 +814,8 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev,
        if (rc != 0)
                goto ret;
        //Since we support ingress attribute only - right now.
-       filter->flags = HWRM_CFA_EM_FLOW_ALLOC_INPUT_FLAGS_PATH_RX;
+       if (filter->filter_type == HWRM_CFA_EM_FILTER)
+               filter->flags = HWRM_CFA_EM_FLOW_ALLOC_INPUT_FLAGS_PATH_RX;
 
        switch (act->type) {
        case RTE_FLOW_ACTION_TYPE_QUEUE:
@@ -815,7 +828,7 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev,
                        rc = -rte_errno;
                        goto ret;
                }
-               RTE_LOG(ERR, PMD, "Queue index %d\n", act_q->index);
+               PMD_DRV_LOG(DEBUG, "Queue index %d\n", act_q->index);
 
                vnic0 = STAILQ_FIRST(&bp->ff_pool[0]);
                vnic = STAILQ_FIRST(&bp->ff_pool[act_q->index]);
@@ -828,12 +841,20 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev,
                }
                filter->dst_id = vnic->fw_vnic_id;
                filter1 = bnxt_get_l2_filter(bp, filter, vnic);
+               if (filter1 == NULL) {
+                       rc = -ENOSPC;
+                       goto ret;
+               }
                filter->fw_l2_filter_id = filter1->fw_l2_filter_id;
-               RTE_LOG(DEBUG, PMD, "VNIC found\n");
+               PMD_DRV_LOG(DEBUG, "VNIC found\n");
                break;
        case RTE_FLOW_ACTION_TYPE_DROP:
                vnic0 = STAILQ_FIRST(&bp->ff_pool[0]);
                filter1 = bnxt_get_l2_filter(bp, filter, vnic0);
+               if (filter1 == NULL) {
+                       rc = -ENOSPC;
+                       goto ret;
+               }
                filter->fw_l2_filter_id = filter1->fw_l2_filter_id;
                if (filter->filter_type == HWRM_CFA_EM_FILTER)
                        filter->flags =
@@ -845,9 +866,59 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev,
        case RTE_FLOW_ACTION_TYPE_COUNT:
                vnic0 = STAILQ_FIRST(&bp->ff_pool[0]);
                filter1 = bnxt_get_l2_filter(bp, filter, vnic0);
+               if (filter1 == NULL) {
+                       rc = -ENOSPC;
+                       goto ret;
+               }
                filter->fw_l2_filter_id = filter1->fw_l2_filter_id;
                filter->flags = HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_FLAGS_METER;
                break;
+       case RTE_FLOW_ACTION_TYPE_VF:
+               act_vf = (const struct rte_flow_action_vf *)act->conf;
+               vf = act_vf->id;
+               if (!BNXT_PF(bp)) {
+                       rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_ACTION,
+                                  act,
+                                  "Configuring on a VF!");
+                       rc = -rte_errno;
+                       goto ret;
+               }
+
+               if (vf >= bp->pdev->max_vfs) {
+                       rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_ACTION,
+                                  act,
+                                  "Incorrect VF id!");
+                       rc = -rte_errno;
+                       goto ret;
+               }
+
+               filter->mirror_vnic_id =
+               dflt_vnic = bnxt_hwrm_func_qcfg_vf_dflt_vnic_id(bp, vf);
+               if (dflt_vnic < 0) {
+                       /* This simply indicates there's no driver loaded.
+                        * This is not an error.
+                        */
+                       rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_ACTION,
+                                  act,
+                                  "Unable to get default VNIC for VF");
+                       rc = -rte_errno;
+                       goto ret;
+               }
+               filter->mirror_vnic_id = dflt_vnic;
+               filter->enables |= NTUPLE_FLTR_ALLOC_INPUT_EN_MIRROR_VNIC_ID;
+
+               vnic0 = STAILQ_FIRST(&bp->ff_pool[0]);
+               filter1 = bnxt_get_l2_filter(bp, filter, vnic0);
+               if (filter1 == NULL) {
+                       rc = -ENOSPC;
+                       goto ret;
+               }
+               filter->fw_l2_filter_id = filter1->fw_l2_filter_id;
+               break;
+
        default:
                rte_flow_error_set(error, EINVAL,
                                   RTE_FLOW_ERROR_TYPE_ACTION, act,
@@ -885,18 +956,83 @@ bnxt_flow_validate(struct rte_eth_dev *dev,
 
        filter = bnxt_get_unused_filter(bp);
        if (filter == NULL) {
-               RTE_LOG(ERR, PMD, "Not enough resources for a new flow.\n");
+               PMD_DRV_LOG(ERR, "Not enough resources for a new flow.\n");
                return -ENOMEM;
        }
 
        ret = bnxt_validate_and_parse_flow(dev, pattern, actions, attr,
                                           error, filter);
        /* No need to hold on to this filter if we are just validating flow */
+       filter->fw_l2_filter_id = UINT64_MAX;
        bnxt_free_filter(bp, filter);
 
        return ret;
 }
 
+static int
+bnxt_match_filter(struct bnxt *bp, struct bnxt_filter_info *nf)
+{
+       struct bnxt_filter_info *mf;
+       struct rte_flow *flow;
+       int i;
+
+       for (i = bp->nr_vnics - 1; i >= 0; i--) {
+               struct bnxt_vnic_info *vnic = &bp->vnic_info[i];
+
+               STAILQ_FOREACH(flow, &vnic->flow_list, next) {
+                       mf = flow->filter;
+
+                       if (mf->filter_type == nf->filter_type &&
+                           mf->flags == nf->flags &&
+                           mf->src_port == nf->src_port &&
+                           mf->src_port_mask == nf->src_port_mask &&
+                           mf->dst_port == nf->dst_port &&
+                           mf->dst_port_mask == nf->dst_port_mask &&
+                           mf->ip_protocol == nf->ip_protocol &&
+                           mf->ip_addr_type == nf->ip_addr_type &&
+                           mf->ethertype == nf->ethertype &&
+                           mf->vni == nf->vni &&
+                           mf->tunnel_type == nf->tunnel_type &&
+                           mf->l2_ovlan == nf->l2_ovlan &&
+                           mf->l2_ovlan_mask == nf->l2_ovlan_mask &&
+                           mf->l2_ivlan == nf->l2_ivlan &&
+                           mf->l2_ivlan_mask == nf->l2_ivlan_mask &&
+                           !memcmp(mf->l2_addr, nf->l2_addr, ETHER_ADDR_LEN) &&
+                           !memcmp(mf->l2_addr_mask, nf->l2_addr_mask,
+                                   ETHER_ADDR_LEN) &&
+                           !memcmp(mf->src_macaddr, nf->src_macaddr,
+                                   ETHER_ADDR_LEN) &&
+                           !memcmp(mf->dst_macaddr, nf->dst_macaddr,
+                                   ETHER_ADDR_LEN) &&
+                           !memcmp(mf->src_ipaddr, nf->src_ipaddr,
+                                   sizeof(nf->src_ipaddr)) &&
+                           !memcmp(mf->src_ipaddr_mask, nf->src_ipaddr_mask,
+                                   sizeof(nf->src_ipaddr_mask)) &&
+                           !memcmp(mf->dst_ipaddr, nf->dst_ipaddr,
+                                   sizeof(nf->dst_ipaddr)) &&
+                           !memcmp(mf->dst_ipaddr_mask, nf->dst_ipaddr_mask,
+                                   sizeof(nf->dst_ipaddr_mask))) {
+                               if (mf->dst_id == nf->dst_id)
+                                       return -EEXIST;
+                               /* Same Flow, Different queue
+                                * Clear the old ntuple filter
+                                */
+                               if (nf->filter_type == HWRM_CFA_EM_FILTER)
+                                       bnxt_hwrm_clear_em_filter(bp, mf);
+                               if (nf->filter_type == HWRM_CFA_NTUPLE_FILTER)
+                                       bnxt_hwrm_clear_ntuple_filter(bp, mf);
+                               /* Free the old filter, update flow
+                                * with new filter
+                                */
+                               bnxt_free_filter(bp, mf);
+                               flow->filter = nf;
+                               return -EXDEV;
+                       }
+               }
+       }
+       return 0;
+}
+
 static struct rte_flow *
 bnxt_flow_create(struct rte_eth_dev *dev,
                  const struct rte_flow_attr *attr,
@@ -907,6 +1043,7 @@ bnxt_flow_create(struct rte_eth_dev *dev,
        struct bnxt *bp = (struct bnxt *)dev->data->dev_private;
        struct bnxt_filter_info *filter;
        struct bnxt_vnic_info *vnic = NULL;
+       bool update_flow = false;
        struct rte_flow *flow;
        unsigned int i;
        int ret = 0;
@@ -921,13 +1058,13 @@ bnxt_flow_create(struct rte_eth_dev *dev,
 
        ret = bnxt_flow_agrs_validate(attr, pattern, actions, error);
        if (ret != 0) {
-               RTE_LOG(ERR, PMD, "Not a validate flow.\n");
+               PMD_DRV_LOG(ERR, "Not a validate flow.\n");
                goto free_flow;
        }
 
        filter = bnxt_get_unused_filter(bp);
        if (filter == NULL) {
-               RTE_LOG(ERR, PMD, "Not enough resources for a new flow.\n");
+               PMD_DRV_LOG(ERR, "Not enough resources for a new flow.\n");
                goto free_flow;
        }
 
@@ -936,6 +1073,20 @@ bnxt_flow_create(struct rte_eth_dev *dev,
        if (ret != 0)
                goto free_filter;
 
+       ret = bnxt_match_filter(bp, filter);
+       if (ret == -EEXIST) {
+               PMD_DRV_LOG(DEBUG, "Flow already exists.\n");
+               /* Clear the filter that was created as part of
+                * validate_and_parse_flow() above
+                */
+               bnxt_hwrm_clear_l2_filter(bp, filter);
+               goto free_filter;
+       } else if (ret == -EXDEV) {
+               PMD_DRV_LOG(DEBUG, "Flow with same pattern exists");
+               PMD_DRV_LOG(DEBUG, "Updating with different destination\n");
+               update_flow = true;
+       }
+
        if (filter->filter_type == HWRM_CFA_EM_FILTER) {
                filter->enables |=
                        HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_L2_FILTER_ID;
@@ -956,17 +1107,29 @@ bnxt_flow_create(struct rte_eth_dev *dev,
        if (!ret) {
                flow->filter = filter;
                flow->vnic = vnic;
-               RTE_LOG(ERR, PMD, "Successfully created flow.\n");
+               if (update_flow) {
+                       ret = -EXDEV;
+                       goto free_flow;
+               }
+               PMD_DRV_LOG(ERR, "Successfully created flow.\n");
                STAILQ_INSERT_TAIL(&vnic->flow_list, flow, next);
                return flow;
        }
 free_filter:
        bnxt_free_filter(bp, filter);
 free_flow:
-       RTE_LOG(ERR, PMD, "Failed to create flow.\n");
-       rte_flow_error_set(error, -ret,
-                          RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-                          "Failed to create flow.");
+       if (ret == -EEXIST)
+               rte_flow_error_set(error, ret,
+                                  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                  "Matching Flow exists.");
+       else if (ret == -EXDEV)
+               rte_flow_error_set(error, ret,
+                                  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                  "Flow with pattern exists, updating destination queue");
+       else
+               rte_flow_error_set(error, -ret,
+                                  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                  "Failed to create flow.");
        rte_free(flow);
        flow = NULL;
        return flow;
@@ -982,11 +1145,15 @@ bnxt_flow_destroy(struct rte_eth_dev *dev,
        struct bnxt_vnic_info *vnic = flow->vnic;
        int ret = 0;
 
+       ret = bnxt_match_filter(bp, filter);
+       if (ret == 0)
+               PMD_DRV_LOG(ERR, "Could not find matching flow\n");
        if (filter->filter_type == HWRM_CFA_EM_FILTER)
                ret = bnxt_hwrm_clear_em_filter(bp, filter);
        if (filter->filter_type == HWRM_CFA_NTUPLE_FILTER)
                ret = bnxt_hwrm_clear_ntuple_filter(bp, filter);
-
+       else
+               ret = bnxt_hwrm_clear_l2_filter(bp, filter);
        if (!ret) {
                STAILQ_REMOVE(&vnic->flow_list, flow, rte_flow, next);
                rte_free(flow);