X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fbnxt%2Fbnxt_flow.c;h=8cc8c1367ae685c4f7b7b21f581fc28ba78cf4a9;hb=afef822b2e1bdf56a3e2a55d8f76025e0e1764fb;hp=13bdaf034032ab2964dc5d8c7274b0a69354596e;hpb=36024b2e7fe56ef496252e61c3eea337683e62c0;p=dpdk.git diff --git a/drivers/net/bnxt/bnxt_flow.c b/drivers/net/bnxt/bnxt_flow.c index 13bdaf0340..8cc8c1367a 100644 --- a/drivers/net/bnxt/bnxt_flow.c +++ b/drivers/net/bnxt/bnxt_flow.c @@ -14,6 +14,8 @@ #include "bnxt.h" #include "bnxt_filter.h" #include "bnxt_hwrm.h" +#include "bnxt_ring.h" +#include "bnxt_rxq.h" #include "bnxt_vnic.h" #include "bnxt_util.h" #include "hsi_struct_def_dpdk.h" @@ -81,14 +83,17 @@ bnxt_filter_type_check(const struct rte_flow_item pattern[], const struct rte_flow_item *item = bnxt_flow_non_void_item(pattern); int use_ntuple = 1; + bool has_vlan = 0; while (item->type != RTE_FLOW_ITEM_TYPE_END) { switch (item->type) { + case RTE_FLOW_ITEM_TYPE_ANY: case RTE_FLOW_ITEM_TYPE_ETH: - use_ntuple = 1; + use_ntuple = 0; break; case RTE_FLOW_ITEM_TYPE_VLAN: use_ntuple = 0; + has_vlan = 1; break; case RTE_FLOW_ITEM_TYPE_IPV4: case RTE_FLOW_ITEM_TYPE_IPV6: @@ -96,28 +101,25 @@ bnxt_filter_type_check(const struct rte_flow_item pattern[], case RTE_FLOW_ITEM_TYPE_UDP: /* FALLTHROUGH */ /* need ntuple match, reset exact match */ - if (!use_ntuple) { - PMD_DRV_LOG(ERR, - "VLAN flow cannot use NTUPLE filter\n"); - rte_flow_error_set - (error, - EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, - "Cannot use VLAN with NTUPLE"); - return -rte_errno; - } use_ntuple |= 1; break; - case RTE_FLOW_ITEM_TYPE_ANY: - use_ntuple = 0; - break; default: PMD_DRV_LOG(DEBUG, "Unknown Flow type\n"); use_ntuple |= 0; } item++; } + + if (has_vlan && use_ntuple) { + PMD_DRV_LOG(ERR, + "VLAN flow cannot use NTUPLE filter\n"); + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Cannot use VLAN with NTUPLE"); + return -rte_errno; + } + return use_ntuple; } @@ -144,30 +146,21 @@ bnxt_validate_and_parse_flow_type(struct bnxt *bp, 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; + uint32_t tenant_id_be = 0, valid_flags = 0; bool vni_masked = 0; bool tni_masked = 0; + uint32_t en_ethertype; + uint8_t inner = 0; uint32_t vf = 0; - int use_ntuple; uint32_t en = 0; - uint32_t en_ethertype; - int dflt_vnic, rc = 0; + int use_ntuple; + int dflt_vnic; use_ntuple = bnxt_filter_type_check(pattern, error); PMD_DRV_LOG(DEBUG, "Use NTUPLE %d\n", use_ntuple); if (use_ntuple < 0) return use_ntuple; - if (use_ntuple && (bp->eth_dev->data->dev_conf.rxmode.mq_mode & - ETH_MQ_RX_RSS)) { - PMD_DRV_LOG(ERR, "Cannot create ntuple flow on RSS queues\n"); - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, - "Cannot create flow on RSS queues"); - rc = -rte_errno; - return rc; - } - filter->filter_type = use_ntuple ? HWRM_CFA_NTUPLE_FILTER : HWRM_CFA_EM_FILTER; en_ethertype = use_ntuple ? @@ -185,6 +178,12 @@ bnxt_validate_and_parse_flow_type(struct bnxt *bp, } switch (item->type) { + case RTE_FLOW_ITEM_TYPE_ANY: + inner = + ((const struct rte_flow_item_any *)item->spec)->num > 3; + if (inner) + PMD_DRV_LOG(DEBUG, "Parse inner header\n"); + break; case RTE_FLOW_ITEM_TYPE_ETH: if (!item->spec || !item->mask) break; @@ -221,18 +220,24 @@ bnxt_validate_and_parse_flow_type(struct bnxt *bp, if (rte_is_broadcast_ether_addr(ð_mask->dst)) { rte_memcpy(filter->dst_macaddr, - ð_spec->dst, 6); + ð_spec->dst, RTE_ETHER_ADDR_LEN); en |= use_ntuple ? NTUPLE_FLTR_ALLOC_INPUT_EN_DST_MACADDR : EM_FLOW_ALLOC_INPUT_EN_DST_MACADDR; + valid_flags |= inner ? + BNXT_FLOW_L2_INNER_DST_VALID_FLAG : + BNXT_FLOW_L2_DST_VALID_FLAG; } if (rte_is_broadcast_ether_addr(ð_mask->src)) { rte_memcpy(filter->src_macaddr, - ð_spec->src, 6); + ð_spec->src, RTE_ETHER_ADDR_LEN); en |= use_ntuple ? NTUPLE_FLTR_ALLOC_INPUT_EN_SRC_MACADDR : EM_FLOW_ALLOC_INPUT_EN_SRC_MACADDR; + valid_flags |= inner ? + BNXT_FLOW_L2_INNER_SRC_VALID_FLAG : + BNXT_FLOW_L2_SRC_VALID_FLAG; } /* * else { * PMD_DRV_LOG(ERR, "Handle this condition\n"); @@ -677,6 +682,7 @@ bnxt_validate_and_parse_flow_type(struct bnxt *bp, item++; } filter->enables = en; + filter->valid_flags = valid_flags; return 0; } @@ -715,17 +721,6 @@ bnxt_flow_parse_attr(const struct rte_flow_attr *attr, "No support for priority."); return -rte_errno; } - - /* Not supported */ - if (attr->group) { - rte_flow_error_set(error, - EINVAL, - RTE_FLOW_ERROR_TYPE_ATTR_GROUP, - attr, - "No support for group."); - return -rte_errno; - } - return 0; } @@ -744,16 +739,45 @@ bnxt_get_l2_filter(struct bnxt *bp, struct bnxt_filter_info *nf, if (memcmp(f0->l2_addr, nf->dst_macaddr, RTE_ETHER_ADDR_LEN) == 0) return f0; - /* This flow needs DST MAC which is not same as port/l2 */ - PMD_DRV_LOG(DEBUG, "Create L2 filter for DST MAC\n"); + /* Alloc new L2 filter. + * This flow needs MAC filter which does not match port/l2 MAC. + */ filter1 = bnxt_get_unused_filter(bp); if (filter1 == NULL) return NULL; - filter1->flags = HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_PATH_RX; + filter1->flags = HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_XDP_DISABLE; + filter1->flags |= HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_PATH_RX; + if (nf->valid_flags & BNXT_FLOW_L2_SRC_VALID_FLAG || + nf->valid_flags & BNXT_FLOW_L2_DST_VALID_FLAG) { + filter1->flags |= + HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_OUTERMOST; + PMD_DRV_LOG(DEBUG, "Create Outer filter\n"); + } + + if (nf->filter_type == HWRM_CFA_L2_FILTER && + (nf->valid_flags & BNXT_FLOW_L2_SRC_VALID_FLAG || + nf->valid_flags & BNXT_FLOW_L2_INNER_SRC_VALID_FLAG)) { + PMD_DRV_LOG(DEBUG, "Create L2 filter for SRC MAC\n"); + filter1->flags |= + HWRM_CFA_L2_FILTER_ALLOC_INPUT_FLAGS_SOURCE_VALID; + memcpy(filter1->l2_addr, nf->src_macaddr, RTE_ETHER_ADDR_LEN); + } else { + PMD_DRV_LOG(DEBUG, "Create L2 filter for DST MAC\n"); + memcpy(filter1->l2_addr, nf->dst_macaddr, RTE_ETHER_ADDR_LEN); + } + + if (nf->valid_flags & BNXT_FLOW_L2_DST_VALID_FLAG || + nf->valid_flags & BNXT_FLOW_L2_INNER_DST_VALID_FLAG) { + /* Tell the FW where to place the filter in the table. */ + filter1->pri_hint = + HWRM_CFA_L2_FILTER_ALLOC_INPUT_PRI_HINT_BELOW_FILTER; + /* This will place the filter in TCAM */ + filter1->l2_filter_id_hint = (uint64_t)-1; + } + filter1->enables = HWRM_CFA_L2_FILTER_ALLOC_INPUT_ENABLES_L2_ADDR | L2_FILTER_ALLOC_INPUT_EN_L2_ADDR_MASK; - memcpy(filter1->l2_addr, nf->dst_macaddr, RTE_ETHER_ADDR_LEN); memset(filter1->l2_addr_mask, 0xff, RTE_ETHER_ADDR_LEN); rc = bnxt_hwrm_set_l2_filter(bp, vnic->fw_vnic_id, filter1); @@ -764,6 +788,50 @@ bnxt_get_l2_filter(struct bnxt *bp, struct bnxt_filter_info *nf, return filter1; } +static int bnxt_vnic_prep(struct bnxt *bp, struct bnxt_vnic_info *vnic) +{ + struct rte_eth_conf *dev_conf = &bp->eth_dev->data->dev_conf; + uint64_t rx_offloads = dev_conf->rxmode.offloads; + int rc; + + rc = bnxt_vnic_grp_alloc(bp, vnic); + if (rc) + goto ret; + + rc = bnxt_hwrm_vnic_alloc(bp, vnic); + if (rc) { + PMD_DRV_LOG(ERR, "HWRM vnic alloc failure rc: %x\n", rc); + goto ret; + } + bp->nr_vnics++; + + /* RSS context is required only when there is more than one RSS ring */ + if (vnic->rx_queue_cnt > 1) { + rc = bnxt_hwrm_vnic_ctx_alloc(bp, vnic, 0 /* ctx_idx 0 */); + if (rc) { + PMD_DRV_LOG(ERR, + "HWRM vnic ctx alloc failure: %x\n", rc); + goto ret; + } + } else { + PMD_DRV_LOG(DEBUG, "No RSS context required\n"); + } + + if (rx_offloads & DEV_RX_OFFLOAD_VLAN_STRIP) + vnic->vlan_strip = true; + else + vnic->vlan_strip = false; + + rc = bnxt_hwrm_vnic_cfg(bp, vnic); + if (rc) + goto ret; + + bnxt_hwrm_vnic_plcmode_cfg(bp, vnic); + +ret: + return rc; +} + static int bnxt_validate_and_parse_flow(struct rte_eth_dev *dev, const struct rte_flow_item pattern[], @@ -775,12 +843,14 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev, const struct rte_flow_action *act = bnxt_flow_non_void_action(actions); struct bnxt *bp = dev->data->dev_private; + struct rte_eth_conf *dev_conf = &bp->eth_dev->data->dev_conf; 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; + struct bnxt_rx_queue *rxq = NULL; + int dflt_vnic, vnic_id; uint32_t vf = 0; - int dflt_vnic; int rc; rc = @@ -800,7 +870,7 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_QUEUE: /* Allow this flow. Redirect to a VNIC. */ act_q = (const struct rte_flow_action_queue *)act->conf; - if (act_q->index >= bp->rx_nr_rings) { + if (!act_q->index || act_q->index >= bp->rx_nr_rings) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, @@ -811,18 +881,79 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev, } PMD_DRV_LOG(DEBUG, "Queue index %d\n", act_q->index); - vnic0 = &bp->vnic_info[0]; - vnic = &bp->vnic_info[act_q->index]; + vnic_id = attr->group; + if (!vnic_id) { + PMD_DRV_LOG(DEBUG, "Group id is 0\n"); + vnic_id = act_q->index; + } + PMD_DRV_LOG(DEBUG, "VNIC found\n"); + + vnic = &bp->vnic_info[vnic_id]; if (vnic == NULL) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, act, - "No matching VNIC for queue ID."); + "No matching VNIC found."); + rc = -rte_errno; + goto ret; + } + if (vnic->rx_queue_cnt) { + if (vnic->start_grp_id != act_q->index) { + PMD_DRV_LOG(ERR, + "VNIC already in use\n"); + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + act, + "VNIC already in use"); + rc = -rte_errno; + goto ret; + } + goto use_vnic; + } + + rxq = bp->rx_queues[act_q->index]; + + if (!(dev_conf->rxmode.mq_mode & ETH_MQ_RX_RSS) && rxq && + vnic->fw_vnic_id != INVALID_HW_RING_ID) + goto use_vnic; + + if (!rxq || + bp->vnic_info[0].fw_grp_ids[act_q->index] != + INVALID_HW_RING_ID || + !rxq->rx_deferred_start) { + PMD_DRV_LOG(ERR, + "Queue invalid or used with other VNIC\n"); + rte_flow_error_set(error, + EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + act, + "Queue invalid queue or in use"); rc = -rte_errno; goto ret; } +use_vnic: + rxq->vnic = vnic; + vnic->rx_queue_cnt++; + vnic->start_grp_id = act_q->index; + vnic->end_grp_id = act_q->index; + vnic->func_default = 0; //This is not a default VNIC. + + PMD_DRV_LOG(DEBUG, "VNIC found\n"); + + rc = bnxt_vnic_prep(bp, vnic); + if (rc) + goto ret; + + PMD_DRV_LOG(DEBUG, + "vnic[%d] = %p vnic->fw_grp_ids = %p\n", + act_q->index, vnic, vnic->fw_grp_ids); + + vnic->ff_pool_idx = vnic_id; + PMD_DRV_LOG(DEBUG, + "Setting vnic ff_idx %d\n", vnic->ff_pool_idx); filter->dst_id = vnic->fw_vnic_id; filter1 = bnxt_get_l2_filter(bp, filter, vnic); if (filter1 == NULL) { @@ -830,8 +961,20 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev, goto ret; } + if (!(filter->valid_flags & + ~(BNXT_FLOW_L2_DST_VALID_FLAG | + BNXT_FLOW_L2_SRC_VALID_FLAG | + BNXT_FLOW_L2_INNER_SRC_VALID_FLAG | + BNXT_FLOW_L2_INNER_DST_VALID_FLAG))) { + PMD_DRV_LOG(DEBUG, "L2 filter created\n"); + filter->flags = filter1->flags; + filter->enables = filter1->enables; + filter->filter_type = HWRM_CFA_L2_FILTER; + memset(filter->l2_addr_mask, 0xff, RTE_ETHER_ADDR_LEN); + filter->pri_hint = filter1->pri_hint; + filter->l2_filter_id_hint = filter1->l2_filter_id_hint; + } filter->fw_l2_filter_id = filter1->fw_l2_filter_id; - PMD_DRV_LOG(DEBUG, "VNIC found\n"); break; case RTE_FLOW_ACTION_TYPE_DROP: vnic0 = &bp->vnic_info[0]; @@ -922,6 +1065,15 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev, filter->fw_l2_filter_id = filter1->fw_l2_filter_id; break; + case RTE_FLOW_ACTION_TYPE_RSS: + rte_flow_error_set(error, + ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + act, + "This action is not supported right now."); + rc = -rte_errno; + goto ret; + //break; default: rte_flow_error_set(error, @@ -989,9 +1141,12 @@ bnxt_match_filter(struct bnxt *bp, struct bnxt_filter_info *nf) struct rte_flow *flow; int i; - for (i = bp->nr_vnics - 1; i >= 0; i--) { + for (i = bp->max_vnics; i >= 0; i--) { struct bnxt_vnic_info *vnic = &bp->vnic_info[i]; + if (vnic->fw_vnic_id == INVALID_VNIC_ID) + continue; + STAILQ_FOREACH(flow, &vnic->flow_list, next) { mf = flow->filter; @@ -1063,8 +1218,8 @@ bnxt_flow_create(struct rte_eth_dev *dev, struct rte_flow_error *error) { struct bnxt *bp = dev->data->dev_private; - struct bnxt_filter_info *filter; struct bnxt_vnic_info *vnic = NULL; + struct bnxt_filter_info *filter; bool update_flow = false; struct rte_flow *flow; unsigned int i; @@ -1168,12 +1323,35 @@ bnxt_flow_create(struct rte_eth_dev *dev, ret = bnxt_hwrm_set_ntuple_filter(bp, filter->dst_id, filter); } - for (i = 0; i < bp->nr_vnics; i++) { + for (i = 0; i < bp->max_vnics; i++) { vnic = &bp->vnic_info[i]; - if (filter->dst_id == vnic->fw_vnic_id) + if (vnic->fw_vnic_id != INVALID_VNIC_ID && + filter->dst_id == vnic->fw_vnic_id) { + PMD_DRV_LOG(ERR, "Found matching VNIC Id %d\n", + vnic->ff_pool_idx); break; + } } done: + if (!ret) { + flow->filter = filter; + flow->vnic = vnic; + /* VNIC is set only in case of queue or RSS action */ + if (vnic) { + /* + * RxQ0 is not used for flow filters. + */ + + if (update_flow) { + ret = -EXDEV; + goto free_flow; + } + STAILQ_INSERT_TAIL(&vnic->filter, filter, next); + } + PMD_DRV_LOG(ERR, "Successfully created flow.\n"); + STAILQ_INSERT_TAIL(&vnic->flow_list, flow, next); + return flow; + } if (!ret) { flow->filter = filter; flow->vnic = vnic; @@ -1196,7 +1374,7 @@ free_flow: rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "Flow with pattern exists, updating destination queue"); - else + else if (!rte_errno) rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "Failed to create flow.");