From patchwork Wed May 17 22:38:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "John Daley (johndale)" X-Patchwork-Id: 24355 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 603EA4BE1; Thu, 18 May 2017 00:38:33 +0200 (CEST) Received: from rcdn-iport-9.cisco.com (rcdn-iport-9.cisco.com [173.37.86.80]) by dpdk.org (Postfix) with ESMTP id 9BB563250 for ; Thu, 18 May 2017 00:38:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=cisco.com; i=@cisco.com; l=7855; q=dns/txt; s=iport; t=1495060696; x=1496270296; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=1YyD6tjr13yQPsV5lulKkDGazBFUgyLLXG7tyL0+0Ts=; b=S2SgwDiy2LdGAVQF36YCBV1btLRvqZmR5tuhjN37eHmYPDwM+mq7+pIp HX/EWW/iJ43jUj59go47Hz7t5irvoD0Li9ZLBKjMHnBYg/uprIin6B4sv dyZiUuxyG7YyD07EGGvzNyxNhnTQlbMV5LubqsAfnHRVGJyrEh+uNbHzR o=; X-IronPort-AV: E=Sophos;i="5.38,356,1491264000"; d="scan'208";a="244559910" Received: from rcdn-core-12.cisco.com ([173.37.93.148]) by rcdn-iport-9.cisco.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 17 May 2017 22:38:15 +0000 Received: from cisco.com (savbu-usnic-a.cisco.com [10.193.184.48]) by rcdn-core-12.cisco.com (8.14.5/8.14.5) with ESMTP id v4HMcFsc016241; Wed, 17 May 2017 22:38:15 GMT Received: by cisco.com (Postfix, from userid 392789) id C261F3FAAF21; Wed, 17 May 2017 15:38:14 -0700 (PDT) From: John Daley To: ferruh.yigit@intel.com Cc: dev@dpdk.org, John Daley Date: Wed, 17 May 2017 15:38:09 -0700 Message-Id: <20170517223811.6150-7-johndale@cisco.com> X-Mailer: git-send-email 2.12.0 In-Reply-To: <20170517223811.6150-1-johndale@cisco.com> References: <1480ef9e-a5fd-6fd9-a990-df3bed147bfc@intel.com> <20170517223811.6150-1-johndale@cisco.com> Subject: [dpdk-dev] [PATCH v4 6/8] net/enic: flow API for Legacy NICs 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" 5-tuple exact Flow support for 1200 series adapters. This allows: Attributes: ingress Items: ipv4, ipv6, udp, tcp (must exactly match src/dst IP addresses and ports and all must be specified). Actions: queue and void Selectors: 'is' Signed-off-by: John Daley Reviewed-by: Nelson Escobar --- copy functions return positive errnos because they are then used in rte_flow_error_set() which takes a positive errno. checkpatch flags these as warnings, but in my option the implementation should be acceptable in this case. drivers/net/enic/enic_flow.c | 206 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 201 insertions(+), 5 deletions(-) diff --git a/drivers/net/enic/enic_flow.c b/drivers/net/enic/enic_flow.c index a32e25ef9..c20ff86b1 100644 --- a/drivers/net/enic/enic_flow.c +++ b/drivers/net/enic/enic_flow.c @@ -89,6 +89,9 @@ struct enic_action_cap { }; /* Forward declarations */ +static enic_copy_item_fn enic_copy_item_ipv4_v1; +static enic_copy_item_fn enic_copy_item_udp_v1; +static enic_copy_item_fn enic_copy_item_tcp_v1; static enic_copy_item_fn enic_copy_item_eth_v2; static enic_copy_item_fn enic_copy_item_vlan_v2; static enic_copy_item_fn enic_copy_item_ipv4_v2; @@ -102,6 +105,36 @@ static copy_action_fn enic_copy_action_v1; static copy_action_fn enic_copy_action_v2; /** + * Legacy NICs or NICs with outdated firmware. Only 5-tuple perfect match + * is supported. + */ +static const struct enic_items enic_items_v1[] = { + [RTE_FLOW_ITEM_TYPE_IPV4] = { + .copy_item = enic_copy_item_ipv4_v1, + .valid_start_item = 1, + .prev_items = (const enum rte_flow_item_type[]) { + RTE_FLOW_ITEM_TYPE_END, + }, + }, + [RTE_FLOW_ITEM_TYPE_UDP] = { + .copy_item = enic_copy_item_udp_v1, + .valid_start_item = 0, + .prev_items = (const enum rte_flow_item_type[]) { + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_END, + }, + }, + [RTE_FLOW_ITEM_TYPE_TCP] = { + .copy_item = enic_copy_item_tcp_v1, + .valid_start_item = 0, + .prev_items = (const enum rte_flow_item_type[]) { + RTE_FLOW_ITEM_TYPE_IPV4, + RTE_FLOW_ITEM_TYPE_END, + }, + }, +}; + +/** * NICs have Advanced Filters capability but they are disabled. This means * that layer 3 must be specified. */ @@ -252,6 +285,9 @@ static const struct enic_items enic_items_v3[] = { /** Filtering capabilities indexed this NICs supported filter type. */ static const struct enic_filter_cap enic_filter_cap[] = { + [FILTER_IPV4_5TUPLE] = { + .item_info = enic_items_v1, + }, [FILTER_USNIC_IP] = { .item_info = enic_items_v2, }, @@ -285,6 +321,171 @@ static const struct enic_action_cap enic_action_cap[] = { .copy_fn = enic_copy_action_v2, }, }; + +static int +mask_exact_match(const u8 *supported, const u8 *supplied, + unsigned int size) +{ + unsigned int i; + for (i = 0; i < size; i++) { + if (supported[i] != supplied[i]) + return 0; + } + return 1; +} + +/** + * Copy IPv4 item into version 1 NIC filter. + * + * @param item[in] + * Item specification. + * @param enic_filter[out] + * Partially filled in NIC filter structure. + * @param inner_ofst[in] + * Should always be 0 for version 1. + */ +static int +enic_copy_item_ipv4_v1(const struct rte_flow_item *item, + struct filter_v2 *enic_filter, u8 *inner_ofst) +{ + const struct rte_flow_item_ipv4 *spec = item->spec; + const struct rte_flow_item_ipv4 *mask = item->mask; + struct filter_ipv4_5tuple *enic_5tup = &enic_filter->u.ipv4; + struct ipv4_hdr supported_mask = { + .src_addr = 0xffffffff, + .dst_addr = 0xffffffff, + }; + + FLOW_TRACE(); + + if (*inner_ofst) + return ENOTSUP; + + if (!mask) + mask = &rte_flow_item_ipv4_mask; + + /* This is an exact match filter, both fields must be set */ + if (!spec || !spec->hdr.src_addr || !spec->hdr.dst_addr) { + FLOW_LOG(ERR, "IPv4 exact match src/dst addr"); + return ENOTSUP; + } + + /* check that the suppied mask exactly matches capabilty */ + if (!mask_exact_match((const u8 *)&supported_mask, + (const u8 *)item->mask, sizeof(*mask))) { + FLOW_LOG(ERR, "IPv4 exact match mask"); + return ENOTSUP; + } + + enic_filter->u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE; + enic_5tup->src_addr = spec->hdr.src_addr; + enic_5tup->dst_addr = spec->hdr.dst_addr; + + return 0; +} + +/** + * Copy UDP item into version 1 NIC filter. + * + * @param item[in] + * Item specification. + * @param enic_filter[out] + * Partially filled in NIC filter structure. + * @param inner_ofst[in] + * Should always be 0 for version 1. + */ +static int +enic_copy_item_udp_v1(const struct rte_flow_item *item, + struct filter_v2 *enic_filter, u8 *inner_ofst) +{ + const struct rte_flow_item_udp *spec = item->spec; + const struct rte_flow_item_udp *mask = item->mask; + struct filter_ipv4_5tuple *enic_5tup = &enic_filter->u.ipv4; + struct udp_hdr supported_mask = { + .src_port = 0xffff, + .dst_port = 0xffff, + }; + + FLOW_TRACE(); + + if (*inner_ofst) + return ENOTSUP; + + if (!mask) + mask = &rte_flow_item_udp_mask; + + /* This is an exact match filter, both ports must be set */ + if (!spec || !spec->hdr.src_port || !spec->hdr.dst_port) { + FLOW_LOG(ERR, "UDP exact match src/dst addr"); + return ENOTSUP; + } + + /* check that the suppied mask exactly matches capabilty */ + if (!mask_exact_match((const u8 *)&supported_mask, + (const u8 *)item->mask, sizeof(*mask))) { + FLOW_LOG(ERR, "UDP exact match mask"); + return ENOTSUP; + } + + enic_filter->u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE; + enic_5tup->src_port = spec->hdr.src_port; + enic_5tup->dst_port = spec->hdr.dst_port; + enic_5tup->protocol = PROTO_UDP; + + return 0; +} + +/** + * Copy TCP item into version 1 NIC filter. + * + * @param item[in] + * Item specification. + * @param enic_filter[out] + * Partially filled in NIC filter structure. + * @param inner_ofst[in] + * Should always be 0 for version 1. + */ +static int +enic_copy_item_tcp_v1(const struct rte_flow_item *item, + struct filter_v2 *enic_filter, u8 *inner_ofst) +{ + const struct rte_flow_item_tcp *spec = item->spec; + const struct rte_flow_item_tcp *mask = item->mask; + struct filter_ipv4_5tuple *enic_5tup = &enic_filter->u.ipv4; + struct tcp_hdr supported_mask = { + .src_port = 0xffff, + .dst_port = 0xffff, + }; + + FLOW_TRACE(); + + if (*inner_ofst) + return ENOTSUP; + + if (!mask) + mask = &rte_flow_item_tcp_mask; + + /* This is an exact match filter, both ports must be set */ + if (!spec || !spec->hdr.src_port || !spec->hdr.dst_port) { + FLOW_LOG(ERR, "TCPIPv4 exact match src/dst addr"); + return ENOTSUP; + } + + /* check that the suppied mask exactly matches capabilty */ + if (!mask_exact_match((const u8 *)&supported_mask, + (const u8 *)item->mask, sizeof(*mask))) { + FLOW_LOG(ERR, "TCP exact match mask"); + return ENOTSUP; + } + + enic_filter->u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE; + enic_5tup->src_port = spec->hdr.src_port; + enic_5tup->dst_port = spec->hdr.dst_port; + enic_5tup->protocol = PROTO_TCP; + + return 0; +} + /** * Copy ETH item into version 2 NIC filter. * @@ -878,11 +1079,6 @@ enic_match_action(const struct rte_flow_action *action, static const struct enic_filter_cap * enic_get_filter_cap(struct enic *enic) { - /* FIXME: only support advanced filters for now */ - if ((enic->flow_filter_mode != FILTER_DPDK_1) && - (enic->flow_filter_mode != FILTER_USNIC_IP)) - return (const struct enic_filter_cap *)NULL; - if (enic->flow_filter_mode) return &enic_filter_cap[enic->flow_filter_mode];