X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fbnxt%2Fbnxt_filter.c;h=9351460c25117b1841170f164ce7d6c0031dd1d5;hb=b22cd7b3c679118ccf817697c4a6839a601d1655;hp=9f171fd99563fc42c2767d9fd1d49c7a53c912ee;hpb=08731368c9fc5effbb6286437da4b6825e305ca7;p=dpdk.git diff --git a/drivers/net/bnxt/bnxt_filter.c b/drivers/net/bnxt/bnxt_filter.c index 9f171fd995..9351460c25 100644 --- a/drivers/net/bnxt/bnxt_filter.c +++ b/drivers/net/bnxt/bnxt_filter.c @@ -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 @@ -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);