From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 369B2A04B5; Wed, 9 Sep 2020 16:00:57 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id AE4181C0D4; Wed, 9 Sep 2020 16:00:51 +0200 (CEST) Received: from alln-iport-5.cisco.com (alln-iport-5.cisco.com [173.37.142.92]) by dpdk.org (Postfix) with ESMTP id 9C784255 for ; Wed, 9 Sep 2020 16:00:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=cisco.com; i=@cisco.com; l=8334; q=dns/txt; s=iport; t=1599660049; x=1600869649; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=2jSc8sZc/E/Xk0GoPqX+WMIWuke6Z5rnz2N4GexGZ8M=; b=XOZS/UhYL3ZymJ+k47m12LASWvKLBbg1U/vQmALbzEwzwB4eVxiTCplV NjL1lhfFL9DBIBm2nga22Ib5d37ws27EwkrK5egnAWbsdxhZGN6z+xsIF Vf4Un91lTVjID0e32q+0vPnbA+zJs7B8oYj0Eo7EzyzXp/iXsgfJpmzz/ U=; X-IronPort-AV: E=Sophos;i="5.76,409,1592870400"; d="scan'208";a="551712241" Received: from rcdn-core-11.cisco.com ([173.37.93.147]) by alln-iport-5.cisco.com with ESMTP/TLS/DHE-RSA-SEED-SHA; 09 Sep 2020 14:00:48 +0000 Received: from cisco.com (savbu-usnic-a.cisco.com [10.193.184.48]) by rcdn-core-11.cisco.com (8.15.2/8.15.2) with ESMTP id 089E0lxP030171; Wed, 9 Sep 2020 14:00:48 GMT Received: by cisco.com (Postfix, from userid 508933) id BB71420F2005; Wed, 9 Sep 2020 07:00:47 -0700 (PDT) From: Hyong Youb Kim To: Ferruh Yigit Cc: dev@dpdk.org, Hyong Youb Kim , John Daley Date: Wed, 9 Sep 2020 07:00:02 -0700 Message-Id: <20200909140006.23788-3-hyonkim@cisco.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200909140006.23788-1-hyonkim@cisco.com> References: <20200909140006.23788-1-hyonkim@cisco.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Outbound-SMTP-Client: 10.193.184.48, savbu-usnic-a.cisco.com X-Outbound-Node: rcdn-core-11.cisco.com Subject: [dpdk-dev] [PATCH 2/6] net/enic: support egress PORT_ID action X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Use Flow Manager (flowman) to support egress PORT_ID action. It can steer egress packets from PFs and VFs to any uplink port as long as they are all on the same VIC adapter. It can also steer packets between ports on the same VIC adapter (i.e. loopback). Signed-off-by: Hyong Youb Kim Reviewed-by: John Daley --- doc/guides/rel_notes/release_20_11.rst | 1 + drivers/net/enic/enic_fm_flow.c | 154 +++++++++++++++++++++++++ 2 files changed, 155 insertions(+) diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst index 180ab8fa0..afe81711a 100644 --- a/doc/guides/rel_notes/release_20_11.rst +++ b/doc/guides/rel_notes/release_20_11.rst @@ -138,3 +138,4 @@ Tested Platforms * **Updated Cisco enic driver.** * Added support for VF representors with single-queue Tx/Rx and flow API + * Added support for egress PORT_ID action diff --git a/drivers/net/enic/enic_fm_flow.c b/drivers/net/enic/enic_fm_flow.c index 9255f2592..296e7e30d 100644 --- a/drivers/net/enic/enic_fm_flow.c +++ b/drivers/net/enic/enic_fm_flow.c @@ -97,6 +97,8 @@ struct enic_fm_flow { uint64_t action_handle; struct enic_fm_counter *counter; struct enic_fm_fet *fet; + /* Auto-added steer action for hairpin flows (e.g. vnic->vnic) */ + struct enic_fm_flow *hairpin_steer_flow; }; struct enic_fm_jump_flow { @@ -166,6 +168,9 @@ struct enic_flowman { int action_op_count; /* Tags used for representor flows */ uint8_t vf_rep_tag; + /* For auto-added steer action for hairpin */ + int need_hairpin_steer; + uint64_t hairpin_steer_vnic_h; }; static int enic_fm_tbl_free(struct enic_flowman *fm, uint64_t handle); @@ -244,6 +249,7 @@ static const enum rte_flow_action_type enic_fm_supported_eg_actions[] = { RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID, + RTE_FLOW_ACTION_TYPE_PORT_ID, RTE_FLOW_ACTION_TYPE_PASSTHRU, RTE_FLOW_ACTION_TYPE_VOID, RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP, @@ -1120,6 +1126,68 @@ enic_fm_find_vnic(struct enic *enic, const struct rte_pci_addr *addr, return 0; } +/* + * Egress: target port should be either PF uplink or VF. + * Supported cases + * 1. VF egress -> PF uplink + * PF may be this VF's PF, or another PF, as long as they are on the same VIC. + * 2. VF egress -> VF + * + * Unsupported cases + * 1. PF egress -> VF + * App should be using representor to pass packets to VF + */ +static int +vf_egress_port_id_action(struct enic_flowman *fm, + struct rte_eth_dev *dst_dev, + uint64_t dst_vnic_h, + struct fm_action_op *fm_op, + struct rte_flow_error *error) +{ + struct enic *src_enic, *dst_enic; + struct enic_vf_representor *vf; + uint8_t uif; + int ret; + + ENICPMD_FUNC_TRACE(); + src_enic = fm->user_enic; + dst_enic = pmd_priv(dst_dev); + if (!(src_enic->rte_dev->data->dev_flags & RTE_ETH_DEV_REPRESENTOR)) { + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, "source port is not VF representor"); + } + + /* VF -> PF uplink. dst is not VF representor */ + if (!(dst_dev->data->dev_flags & RTE_ETH_DEV_REPRESENTOR)) { + /* PF is the VF's PF? Then nothing to do */ + vf = VF_ENIC_TO_VF_REP(src_enic); + if (vf->pf == dst_enic) { + ENICPMD_LOG(DEBUG, "destination port is VF's PF"); + return 0; + } + /* If not, steer to the remote PF's uplink */ + uif = dst_enic->fm_vnic_uif; + ENICPMD_LOG(DEBUG, "steer to uplink %u", uif); + memset(fm_op, 0, sizeof(*fm_op)); + fm_op->fa_op = FMOP_SET_EGPORT; + fm_op->set_egport.egport = uif; + ret = enic_fm_append_action_op(fm, fm_op, error); + return ret; + } + + /* VF -> VF loopback. Hairpin and steer to vnic */ + memset(fm_op, 0, sizeof(*fm_op)); + fm_op->fa_op = FMOP_EG_HAIRPIN; + ret = enic_fm_append_action_op(fm, fm_op, error); + if (ret) + return ret; + ENICPMD_LOG(DEBUG, "egress hairpin"); + fm->hairpin_steer_vnic_h = dst_vnic_h; + fm->need_hairpin_steer = 1; + return 0; +} + /* Translate flow actions to flowman TCAM entry actions */ static int enic_fm_copy_action(struct enic_flowman *fm, @@ -1310,6 +1378,10 @@ enic_fm_copy_action(struct enic_flowman *fm, const struct rte_flow_action_port_id *port; struct rte_eth_dev *dev; + if (!ingress && (overlap & PORT_ID)) { + ENICPMD_LOG(DEBUG, "cannot have multiple egress PORT_ID actions"); + goto unsupported; + } port = actions->conf; if (port->original) { vnic_h = enic->fm_vnic_handle; /* This port */ @@ -1339,6 +1411,13 @@ enic_fm_copy_action(struct enic_flowman *fm, * Ingress. Nothing more to do. We add an implicit * steer at the end if needed. */ + if (ingress) + break; + /* Egress */ + ret = vf_egress_port_id_action(fm, dev, vnic_h, &fm_op, + error); + if (ret) + return ret; break; } case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: { @@ -1920,9 +1999,15 @@ __enic_fm_flow_free(struct enic_flowman *fm, struct enic_fm_flow *fm_flow) static void enic_fm_flow_free(struct enic_flowman *fm, struct rte_flow *flow) { + struct enic_fm_flow *steer = flow->fm->hairpin_steer_flow; + if (flow->fm->fet && flow->fm->fet->default_key) remove_jump_flow(fm, flow); __enic_fm_flow_free(fm, flow->fm); + if (steer) { + __enic_fm_flow_free(fm, steer); + free(steer); + } free(flow->fm); free(flow); } @@ -2173,11 +2258,71 @@ convert_jump_flows(struct enic_flowman *fm, struct enic_fm_fet *fet, } } +static int +add_hairpin_steer(struct enic_flowman *fm, struct rte_flow *flow, + struct rte_flow_error *error) +{ + struct fm_tcam_match_entry *fm_tcam_entry; + struct enic_fm_flow *fm_flow; + struct fm_action *fm_action; + struct fm_action_op fm_op; + int ret; + + ENICPMD_FUNC_TRACE(); + fm_flow = calloc(1, sizeof(*fm_flow)); + if (fm_flow == NULL) { + rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, "enic: cannot allocate rte_flow"); + return -ENOMEM; + } + /* Original egress hairpin flow */ + fm_tcam_entry = &fm->tcam_entry; + fm_action = &fm->action; + /* Use the match pattern of the egress flow as is, without counters */ + fm_tcam_entry->ftm_flags &= ~FMEF_COUNTER; + /* The only action is steer to vnic */ + fm->action_op_count = 0; + memset(fm_action, 0, sizeof(*fm_action)); + memset(&fm_op, 0, sizeof(fm_op)); + /* Always to queue 0 for now */ + fm_op.fa_op = FMOP_RQ_STEER; + fm_op.rq_steer.rq_index = 0; + fm_op.rq_steer.vnic_handle = fm->hairpin_steer_vnic_h; + ret = enic_fm_append_action_op(fm, &fm_op, error); + if (ret) + goto error_with_flow; + ENICPMD_LOG(DEBUG, "add steer op"); + /* Add required END */ + memset(&fm_op, 0, sizeof(fm_op)); + fm_op.fa_op = FMOP_END; + ret = enic_fm_append_action_op(fm, &fm_op, error); + if (ret) + goto error_with_flow; + /* Add the ingress flow */ + fm_flow->action_handle = FM_INVALID_HANDLE; + fm_flow->entry_handle = FM_INVALID_HANDLE; + ret = __enic_fm_flow_add_entry(fm, fm_flow, fm_tcam_entry, fm_action, + FM_TCAM_RTE_GROUP, 1 /* ingress */, error); + if (ret) { + ENICPMD_LOG(ERR, "cannot add hairpin-steer flow"); + goto error_with_flow; + } + /* The new flow is now the egress flow's paired flow */ + flow->fm->hairpin_steer_flow = fm_flow; + return 0; + +error_with_flow: + free(fm_flow); + return ret; +} + static void enic_fm_open_scratch(struct enic_flowman *fm) { fm->action_op_count = 0; fm->fet = NULL; + fm->need_hairpin_steer = 0; + fm->hairpin_steer_vnic_h = 0; memset(&fm->tcam_entry, 0, sizeof(fm->tcam_entry)); memset(&fm->action, 0, sizeof(fm->action)); } @@ -2325,6 +2470,15 @@ enic_fm_flow_create(struct rte_eth_dev *dev, flow = enic_fm_flow_add_entry(fm, fm_tcam_entry, fm_action, attrs, error); if (flow) { + /* Add ingress rule that pairs with hairpin rule */ + if (fm->need_hairpin_steer) { + ret = add_hairpin_steer(fm, flow, error); + if (ret) { + enic_fm_flow_free(fm, flow); + flow = NULL; + goto error_with_scratch; + } + } LIST_INSERT_HEAD(&enic->flows, flow, next); fet = flow->fm->fet; if (fet && fet->default_key) { -- 2.26.2