From patchwork Tue Sep 26 05:36:31 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuanhan Liu X-Patchwork-Id: 818456 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=fridaylinux-org.20150623.gappssmtp.com header.i=@fridaylinux-org.20150623.gappssmtp.com header.b="KFKtnLKf"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y1V9L57tkz9t30 for ; Tue, 26 Sep 2017 15:38:14 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 87F82B5D; Tue, 26 Sep 2017 05:38:11 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id D2A11B13 for ; Tue, 26 Sep 2017 05:38:10 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f47.google.com (mail-pg0-f47.google.com [74.125.83.47]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 297CDD3 for ; Tue, 26 Sep 2017 05:38:10 +0000 (UTC) Received: by mail-pg0-f47.google.com with SMTP id p5so5358784pgn.7 for ; Mon, 25 Sep 2017 22:38:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fridaylinux-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=hbLoeIdpU7FHgEp+drPGWc9ybiGBWF+mAcK/J5A5/Dk=; b=KFKtnLKfFheO1st2vETXFzux70IFxT2ooEZtYeoyztojVo9uSPX7FhCEyA3CArx3D6 ibmjUDWlyf/WXMADo2+U326e1KisBv19Cyb3a6UqmGjoyxyUZ8uhayEeVgG7coWXAdMF KIhS6/x75pbHg7rEBL8EV0MU0MwxipOAQZUzApWful9Fnr/Y9o7kXcthtcOcTMTFcmAM eVPYXtDafAeqdqEAMDvZzhKzlTcHUa2PLAqhcnNz1WnbNC7aCJypdykyAJmCljsxHZJF W48yc0PvZl/15X2ouKPjLtNkWWCVznk29UorPDEsbrTJpJEpdqJsiGso8HVzh3PNG36g Fddw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=hbLoeIdpU7FHgEp+drPGWc9ybiGBWF+mAcK/J5A5/Dk=; b=ua6Nk3clV+eAtqaRPjCBwa1/vQUGOo4OCmc28fJ/h76oUlv1kApseoaLTT+w5FnBut /4QbaJHTpYGrsv5ZX0863A2oS9Ao8Ff4ykPPDAl71uLZea6AVd+5bzW5yCW004TbBU1Y SFz5wuVQM19qENhwnuUfwG//0FbkLhipi5xxYujZ+6r0XBibDLcR2BNXUQW+lFoNXBtG 3aMUkM+gxG7g6oZGsv1e545Bs+nL9M8FGQMWZBukR1jh3enCvvq2CuKzpKaWPDee2tNJ foKkx1n3dVB9mPJivlRUlMGEd8/TabMUlr7CsOSc4YjaPcd2hIs8ytCeZRPAygqfefY9 kTLQ== X-Gm-Message-State: AHPjjUhlCdPrwCWhwSzvq5vB+Cn2W/Tf3RsfuwY8cyuT/04s9uDb5vZw Lf+ssX7uiboi/v1Ivv2Cdy6Q/dUfuObBdQ== X-Google-Smtp-Source: AOwi7QDdB4O6C91dZ0jMetu7n6OhasM8LjQBiKQYPU5emqp5F/UDtoD+DsvDIQHYTo3KFigwOuO2XQ== X-Received: by 10.99.185.26 with SMTP id z26mr9788097pge.438.1506404289302; Mon, 25 Sep 2017 22:38:09 -0700 (PDT) Received: from localhost.localdomain ([101.228.205.132]) by smtp.gmail.com with ESMTPSA id o79sm13180077pfi.108.2017.09.25.22.37.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Sep 2017 22:38:08 -0700 (PDT) From: Yuanhan Liu To: dev@openvswitch.org Date: Tue, 26 Sep 2017 13:36:31 +0800 Message-Id: <1506404199-23579-2-git-send-email-yliu@fridaylinux.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> References: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> X-Spam-Status: No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Simon Horman Subject: [ovs-dev] [PATCH v3 1/9] dpif-netdev: associate flow with a mark id X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This patch associate a flow with a mark id (a uint32_t number) by a direct array. The array is initiated with 1024 slots at the begninning, and it will be enlarged when it's not big enough. The mark id is allocated with the help of id-pool. It re-uses the flow API (more precisely, the ->flow_put method) to setup the hw flow. The flow_put implementation then is supposed to create a flow with MARK action for current stage, which is, only partial offload is supported. Co-authored-by: Finn Christensen Signed-off-by: Yuanhan Liu Signed-off-by: Finn Christensen --- lib/dpif-netdev.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/netdev.h | 6 +++ 2 files changed, 146 insertions(+) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 071ec14..f417b25 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -453,6 +453,9 @@ struct dp_netdev_flow { struct ovs_refcount ref_cnt; bool dead; + bool has_mark; /* A flag to tell whether this flow has a + valid mark asscoiated with it. */ + uint32_t mark; /* Unique flow mark assiged to a flow */ /* Statistics. */ struct dp_netdev_flow_stats stats; @@ -1833,6 +1836,82 @@ dp_netdev_pmd_find_dpcls(struct dp_netdev_pmd_thread *pmd, return cls; } +/* + * An array to map from the flow mark (the index) to dp netdev flow. + * Initial size is set to 1024, it will be resized when it's not + * big enough. + */ +struct flow_mark_map { + size_t max; + struct ovs_mutex mutex; + struct id_pool *mark_pool; + struct dp_netdev_flow **flows; +}; + +static struct flow_mark_map flow_mark_map = { + .max = 1024, + .mutex = OVS_MUTEX_INITIALIZER, +}; + +static bool +dp_netdev_alloc_flow_mark(uint32_t *mark) +{ + bool succeed = true; + + ovs_mutex_lock(&flow_mark_map.mutex); + + /* Haven't initiated yet, do it here */ + if (!flow_mark_map.flows) { + flow_mark_map.flows = xzalloc(sizeof(struct dp_netdev_flow *) * + flow_mark_map.max); + flow_mark_map.mark_pool = id_pool_create(0, UINT32_MAX / 2); + } + + do { + if (!id_pool_alloc_id(flow_mark_map.mark_pool, mark)) { + succeed = false; + break; + } + + if (*mark >= flow_mark_map.max) { + flow_mark_map.flows = xrealloc(flow_mark_map.flows, + flow_mark_map.max * 2 * + sizeof(struct dp_netdev_flow *)); + memset(&flow_mark_map.flows[flow_mark_map.max], 0, + flow_mark_map.max * sizeof(struct dp_netdev_flow *)); + flow_mark_map.max *= 2; + + break; + } + } while (flow_mark_map.flows[*mark]); + + ovs_mutex_unlock(&flow_mark_map.mutex); + + return succeed; +} + +static void +dp_netdev_install_flow_mark_map(const uint32_t mark, + struct dp_netdev_flow *netdev_flow) +{ + ovs_mutex_lock(&flow_mark_map.mutex); + if (mark < flow_mark_map.max) { + flow_mark_map.flows[mark] = netdev_flow; + } + ovs_mutex_unlock(&flow_mark_map.mutex); +} + +static void +dp_netdev_remove_flow_mark_map(const uint32_t mark) +{ + ovs_mutex_lock(&flow_mark_map.mutex); + id_pool_free_id(flow_mark_map.mark_pool, mark); + if (mark < flow_mark_map.max) { + flow_mark_map.flows[mark] = NULL; + } + ovs_mutex_unlock(&flow_mark_map.mutex); +} + static void dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, struct dp_netdev_flow *flow) @@ -1846,6 +1925,10 @@ dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, ovs_assert(cls != NULL); dpcls_remove(cls, &flow->cr); cmap_remove(&pmd->flow_table, node, dp_netdev_flow_hash(&flow->ufid)); + if (flow->has_mark) { + dp_netdev_remove_flow_mark_map(flow->mark); + flow->has_mark = false; + } flow->dead = true; dp_netdev_flow_unref(flow); @@ -2425,6 +2508,55 @@ out: return error; } +static void +try_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, odp_port_t in_port, + struct dp_netdev_flow *flow, struct match *match, + const ovs_u128 *ufid, const struct nlattr *actions, + size_t actions_len) +{ + struct offload_info info; + struct dp_netdev_port *port; + bool modification = flow->has_mark; + const char *op = modification ? "modify" : "install"; + int ret; + + port = dp_netdev_lookup_port(pmd->dp, in_port); + if (!port) { + return; + } + + if (modification) { + info.flow_mark = flow->mark; + } else { + if (!netdev_is_flow_api_enabled()) { + return; + } + + if (!dp_netdev_alloc_flow_mark(&info.flow_mark)) { + VLOG_ERR("failed to allocate flow mark!\n"); + return; + } + } + + ret = netdev_flow_put(port->netdev, match, + CONST_CAST(struct nlattr *, actions), + actions_len, ufid, &info, NULL); + if (ret) { + VLOG_ERR("failed to %s netdev flow with mark %u\n", + op, info.flow_mark); + return; + } + + if (!modification) { + flow->has_mark = true; + flow->mark = info.flow_mark; + dp_netdev_install_flow_mark_map(info.flow_mark, flow); + } + + VLOG_INFO("succeed to %s netdev flow with mark %u\n", + op, flow->mark); +} + static struct dp_netdev_flow * dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, struct match *match, const ovs_u128 *ufid, @@ -2460,6 +2592,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, memset(&flow->stats, 0, sizeof flow->stats); flow->dead = false; flow->batch = NULL; + flow->has_mark = false; *CONST_CAST(unsigned *, &flow->pmd_id) = pmd->core_id; *CONST_CAST(struct flow *, &flow->flow) = match->flow; *CONST_CAST(ovs_u128 *, &flow->ufid) = *ufid; @@ -2475,6 +2608,9 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, cmap_insert(&pmd->flow_table, CONST_CAST(struct cmap_node *, &flow->node), dp_netdev_flow_hash(&flow->ufid)); + try_netdev_flow_put(pmd, in_port, flow, match, ufid, + actions, actions_len); + if (OVS_UNLIKELY(!VLOG_DROP_DBG((&upcall_rl)))) { struct ds ds = DS_EMPTY_INITIALIZER; struct ofpbuf key_buf, mask_buf; @@ -2555,6 +2691,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, if (put->flags & DPIF_FP_MODIFY) { struct dp_netdev_actions *new_actions; struct dp_netdev_actions *old_actions; + odp_port_t in_port = netdev_flow->flow.in_port.odp_port; new_actions = dp_netdev_actions_create(put->actions, put->actions_len); @@ -2562,6 +2699,9 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, old_actions = dp_netdev_flow_get_actions(netdev_flow); ovsrcu_set(&netdev_flow->actions, new_actions); + try_netdev_flow_put(pmd, in_port, netdev_flow, match, ufid, + put->actions, put->actions_len); + if (stats) { get_dpif_flow_stats(netdev_flow, stats); } diff --git a/lib/netdev.h b/lib/netdev.h index f8482f7..2003165 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -188,6 +188,12 @@ void netdev_send_wait(struct netdev *, int qid); struct offload_info { const struct dpif_class *dpif_class; ovs_be16 tp_dst_port; /* Destination port for tunnel in SET action */ + + /* + * The flow mark id assigened to the flow. If any pkts hit the flow, + * it will be in the pkt meta data. + */ + uint32_t flow_mark; }; struct dpif_class; struct netdev_flow_dump; From patchwork Tue Sep 26 05:36:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuanhan Liu X-Patchwork-Id: 818457 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=fridaylinux-org.20150623.gappssmtp.com header.i=@fridaylinux-org.20150623.gappssmtp.com header.b="qfjKkgrd"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y1VB31gCRz9t3R for ; Tue, 26 Sep 2017 15:38:51 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 85266BC2; Tue, 26 Sep 2017 05:38:36 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 6DB54B13 for ; Tue, 26 Sep 2017 05:38:34 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f41.google.com (mail-pg0-f41.google.com [74.125.83.41]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id ADDBF367 for ; Tue, 26 Sep 2017 05:38:32 +0000 (UTC) Received: by mail-pg0-f41.google.com with SMTP id i195so5359858pgd.9 for ; Mon, 25 Sep 2017 22:38:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fridaylinux-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=6k6dGeZxKBsUvhexApcbQGpxDWkoa57zrtOQK5LlCj8=; b=qfjKkgrdpj4JIuIHFxqh+2zZtq5E5OTutgv+dvM972TYWeI32U7y+0HRebf1AiIkKR aWaLSX8fF1IMqQ1FJVgXURlXPlIB+KguByqN9IXFEMcojz6gq6QzQvwKuBSxSUPUXKkc r6wbfBN7Gq4c9WuQHSg8X7bPSSP+SkHntEnQgTfNMqoqh6ErjTopa1Nvp5oU1bNC93Tg o/lIW7Xa5iqDfvk5hgptVqlH2BxdUSrrrA/H8Mgm2pKBm+3XmMiri33xOHx5Apo3NQ8l qjk9amPz/SSlfH4odJLhWpfV0FYke1LyhqoAv8j8OQuF/CTR+eAM/P3q8+vNBVm5bdfE qpTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=6k6dGeZxKBsUvhexApcbQGpxDWkoa57zrtOQK5LlCj8=; b=tZNMhVA7uXpfqPlpn0c7+Hjqlau/Iz2QGURnxfN4Zvv0SEd7aRzozNrq1usBKQM16g 6zUeiPdmyM/v9jzGohvBl5sKJ3MQZTHbZJbVBks7qETmRYXFIU2I6qql7AtZTnMTiPWC pYgb+Jdutky8AvGlbvBpe6ZKGXqhqx7m3ghCalGXDd984/XTZdaozZbTmoo6YyVFS3v1 NG8xwbDxNtyVjQwhP1KDGF0IhYs03qUjA2KCZcsPIhRiQjg4jdYLk3oH/ouve76iBO2o 7YukIBp/ua6ktKJibV0pocCFmi6hxYH9PKlYAJyxKe0ps2DXTDg0lTS4psOD8abkNoZc vZ6A== X-Gm-Message-State: AHPjjUi4HMqT6bIrf5oWwUkHLktNHGTHdQijI586uLosSYn6vAz5pWd7 C3JApUA2emaANH1bkPyb49Up3fUjruy/tQ== X-Google-Smtp-Source: AOwi7QCQe+BoeqN9Q/sd+gzapGcNdEW4i2Kz0gPq32X8735y1vJeRHSAla0WUVoYjn0A/wzG6z/dGQ== X-Received: by 10.98.15.13 with SMTP id x13mr9833289pfi.249.1506404311746; Mon, 25 Sep 2017 22:38:31 -0700 (PDT) Received: from localhost.localdomain ([101.228.205.132]) by smtp.gmail.com with ESMTPSA id o79sm13180077pfi.108.2017.09.25.22.38.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Sep 2017 22:38:30 -0700 (PDT) From: Yuanhan Liu To: dev@openvswitch.org Date: Tue, 26 Sep 2017 13:36:32 +0800 Message-Id: <1506404199-23579-3-git-send-email-yliu@fridaylinux.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> References: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> X-Spam-Status: No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Simon Horman Subject: [ovs-dev] [PATCH v3 2/9] dpif-netdev: retrieve flow directly from the flow mark X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org So that we could skip the heavy emc processing, notably, the miniflow_extract function. A simple PHY-PHY forwarding testing (with one core, one queue and one flow) shows about 70% performance improvement. The retrievement is done at datapath, which should be light. Unfortunately, the pthread lock is too heavy for that. Instead, RCU is chosen. The major race issue is that the flows array might have been resized, aka, the address might have been changed. For example, assume the size of the flows array is 4. And then it's resized to 8. Then a thread might reference the 6th item of the old array, which is wrong. RCU firstly makes sure the flows address update is atomic. Also it provides an barrier. Setting the new array size after the ovsrcu_set() makes sure above issue will not happen. Note that though the heavy miniflow_extract is skipped, we still have to do per packet checking, due to we have to check the tcp_flags. Co-authored-by: Finn Christensen Signed-off-by: Yuanhan Liu Signed-off-by: Finn Christensen --- v3: - replace CMAP with array, which futhure improves the performance from 50% to 70% - introduce some common help functions for parse_tcp_flags v2: update tcp_flags, which also fixes the build warnings --- lib/dp-packet.h | 13 +++++ lib/dpif-netdev.c | 91 +++++++++++++++++++++++++------- lib/flow.c | 155 +++++++++++++++++++++++++++++++++++++++++++----------- lib/flow.h | 1 + 4 files changed, 209 insertions(+), 51 deletions(-) diff --git a/lib/dp-packet.h b/lib/dp-packet.h index 046f3ab..a7a062f 100644 --- a/lib/dp-packet.h +++ b/lib/dp-packet.h @@ -691,6 +691,19 @@ reset_dp_packet_checksum_ol_flags(struct dp_packet *p) #define reset_dp_packet_checksum_ol_flags(arg) #endif +static inline bool +dp_packet_has_flow_mark(struct dp_packet *p OVS_UNUSED, + uint32_t *mark OVS_UNUSED) +{ +#ifdef DPDK_NETDEV + if (p->mbuf.ol_flags & PKT_RX_FDIR_ID) { + *mark = p->mbuf.hash.fdir.hi; + return true; + } +#endif + return false; +} + enum { NETDEV_MAX_BURST = 32 }; /* Maximum number packets in a batch. */ struct dp_packet_batch { diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index f417b25..5c33c74 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1845,7 +1845,7 @@ struct flow_mark_map { size_t max; struct ovs_mutex mutex; struct id_pool *mark_pool; - struct dp_netdev_flow **flows; + OVSRCU_TYPE(struct dp_netdev_flow **) flows; }; static struct flow_mark_map flow_mark_map = { @@ -1857,16 +1857,20 @@ static bool dp_netdev_alloc_flow_mark(uint32_t *mark) { bool succeed = true; + struct dp_netdev_flow **flows; ovs_mutex_lock(&flow_mark_map.mutex); /* Haven't initiated yet, do it here */ - if (!flow_mark_map.flows) { - flow_mark_map.flows = xzalloc(sizeof(struct dp_netdev_flow *) * - flow_mark_map.max); + if (!flow_mark_map.mark_pool) { flow_mark_map.mark_pool = id_pool_create(0, UINT32_MAX / 2); + + flows = xzalloc(sizeof(struct dp_netdev_flow *) * flow_mark_map.max); + ovsrcu_set(&flow_mark_map.flows, flows); } + flows = ovsrcu_get_protected(struct dp_netdev_flow **, + &flow_mark_map.flows); do { if (!id_pool_alloc_id(flow_mark_map.mark_pool, mark)) { succeed = false; @@ -1874,16 +1878,28 @@ dp_netdev_alloc_flow_mark(uint32_t *mark) } if (*mark >= flow_mark_map.max) { - flow_mark_map.flows = xrealloc(flow_mark_map.flows, - flow_mark_map.max * 2 * - sizeof(struct dp_netdev_flow *)); - memset(&flow_mark_map.flows[flow_mark_map.max], 0, - flow_mark_map.max * sizeof(struct dp_netdev_flow *)); + struct dp_netdev_flow **new_flows; + + new_flows = xmalloc(2 * flow_mark_map.max * + sizeof(struct dp_netdev_flow *)); + memcpy(new_flows, flows, sizeof(struct dp_netdev_flow *) * + flow_mark_map.max); + memset(&new_flows[flow_mark_map.max], 0, + sizeof(struct dp_netdev_flow *) * flow_mark_map.max); + ovsrcu_set(&flow_mark_map.flows, new_flows); + /* + * Set the new size after above ovsrcu_set, which will make + * sure the thread still referencing the old array will not + * go beyond the old max. + */ flow_mark_map.max *= 2; + ovsrcu_synchronize(); + free(flows); + flows = new_flows; break; } - } while (flow_mark_map.flows[*mark]); + } while (flows[*mark]); ovs_mutex_unlock(&flow_mark_map.mutex); @@ -1894,9 +1910,13 @@ static void dp_netdev_install_flow_mark_map(const uint32_t mark, struct dp_netdev_flow *netdev_flow) { + struct dp_netdev_flow **flows; + ovs_mutex_lock(&flow_mark_map.mutex); - if (mark < flow_mark_map.max) { - flow_mark_map.flows[mark] = netdev_flow; + if (OVS_LIKELY(mark < flow_mark_map.max)) { + flows = ovsrcu_get_protected(struct dp_netdev_flow **, + &flow_mark_map.flows); + flows[mark] = netdev_flow; } ovs_mutex_unlock(&flow_mark_map.mutex); } @@ -1904,14 +1924,32 @@ dp_netdev_install_flow_mark_map(const uint32_t mark, static void dp_netdev_remove_flow_mark_map(const uint32_t mark) { + struct dp_netdev_flow **flows; + ovs_mutex_lock(&flow_mark_map.mutex); id_pool_free_id(flow_mark_map.mark_pool, mark); if (mark < flow_mark_map.max) { - flow_mark_map.flows[mark] = NULL; + flows = ovsrcu_get_protected(struct dp_netdev_flow **, + &flow_mark_map.flows); + flows[mark] = NULL; } ovs_mutex_unlock(&flow_mark_map.mutex); } +static struct dp_netdev_flow * +dp_netdev_pmd_find_flow_by_mark(const uint32_t mark) +{ + struct dp_netdev_flow **flows; + + if (OVS_LIKELY(mark < flow_mark_map.max)) { + flows = ovsrcu_get(struct dp_netdev_flow **, &flow_mark_map.flows); + return flows[mark]; + } + + return NULL; +} + + static void dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, struct dp_netdev_flow *flow) @@ -4938,10 +4976,10 @@ struct packet_batch_per_flow { static inline void packet_batch_per_flow_update(struct packet_batch_per_flow *batch, struct dp_packet *packet, - const struct miniflow *mf) + uint16_t tcp_flags) { batch->byte_count += dp_packet_size(packet); - batch->tcp_flags |= miniflow_get_tcp_flags(mf); + batch->tcp_flags |= tcp_flags; batch->array.packets[batch->array.count++] = packet; } @@ -4976,7 +5014,7 @@ packet_batch_per_flow_execute(struct packet_batch_per_flow *batch, static inline void dp_netdev_queue_batches(struct dp_packet *pkt, - struct dp_netdev_flow *flow, const struct miniflow *mf, + struct dp_netdev_flow *flow, uint16_t tcp_flags, struct packet_batch_per_flow *batches, size_t *n_batches) { @@ -4987,7 +5025,7 @@ dp_netdev_queue_batches(struct dp_packet *pkt, packet_batch_per_flow_init(batch, flow); } - packet_batch_per_flow_update(batch, pkt, mf); + packet_batch_per_flow_update(batch, pkt, tcp_flags); } /* Try to process all ('cnt') the 'packets' using only the exact match cache @@ -5015,11 +5053,13 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, const size_t size = dp_packet_batch_size(packets_); uint32_t cur_min; int i; + uint16_t tcp_flags; atomic_read_relaxed(&pmd->dp->emc_insert_min, &cur_min); DP_PACKET_BATCH_REFILL_FOR_EACH (i, size, packet, packets_) { struct dp_netdev_flow *flow; + uint32_t flow_mark; if (OVS_UNLIKELY(dp_packet_size(packet) < ETH_HEADER_LEN)) { dp_packet_delete(packet); @@ -5027,6 +5067,16 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, continue; } + if (dp_packet_has_flow_mark(packet, &flow_mark)) { + flow = dp_netdev_pmd_find_flow_by_mark(flow_mark); + if (flow) { + tcp_flags = parse_tcp_flags(packet); + dp_netdev_queue_batches(packet, flow, tcp_flags, batches, + n_batches); + continue; + } + } + if (i != size - 1) { struct dp_packet **packets = packets_->packets; /* Prefetch next packet data and metadata. */ @@ -5044,7 +5094,8 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, /* If EMC is disabled skip emc_lookup */ flow = (cur_min == 0) ? NULL: emc_lookup(flow_cache, key); if (OVS_LIKELY(flow)) { - dp_netdev_queue_batches(packet, flow, &key->mf, batches, + tcp_flags = miniflow_get_tcp_flags(&key->mf); + dp_netdev_queue_batches(packet, flow, tcp_flags, batches, n_batches); } else { /* Exact match cache missed. Group missed packets together at @@ -5221,7 +5272,9 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, flow = dp_netdev_flow_cast(rules[i]); emc_probabilistic_insert(pmd, &keys[i], flow); - dp_netdev_queue_batches(packet, flow, &keys[i].mf, batches, n_batches); + dp_netdev_queue_batches(packet, flow, + miniflow_get_tcp_flags(&keys[i].mf), + batches, n_batches); } dp_netdev_count_packet(pmd, DP_STAT_MASKED_HIT, cnt - miss_cnt); diff --git a/lib/flow.c b/lib/flow.c index b2b10aa..df2b879 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -626,6 +626,70 @@ flow_extract(struct dp_packet *packet, struct flow *flow) miniflow_expand(&m.mf, flow); } +static inline bool +ipv4_sanity_check(const struct ip_header *nh, size_t size, + int *ip_lenp, uint16_t *tot_lenp) +{ + int ip_len; + uint16_t tot_len; + + if (OVS_UNLIKELY(size < IP_HEADER_LEN)) { + return false; + } + ip_len = IP_IHL(nh->ip_ihl_ver) * 4; + + if (OVS_UNLIKELY(ip_len < IP_HEADER_LEN || size < ip_len)) { + return false; + } + + tot_len = ntohs(nh->ip_tot_len); + if (OVS_UNLIKELY(tot_len > size || ip_len > tot_len || + size - tot_len > UINT8_MAX)) { + return false; + } + + *ip_lenp = ip_len; + *tot_lenp = tot_len; + + return true; +} + +static inline uint8_t +ipv4_get_nw_frag(const struct ip_header *nh) +{ + uint8_t nw_frag = 0; + + if (OVS_UNLIKELY(IP_IS_FRAGMENT(nh->ip_frag_off))) { + nw_frag = FLOW_NW_FRAG_ANY; + if (nh->ip_frag_off & htons(IP_FRAG_OFF_MASK)) { + nw_frag |= FLOW_NW_FRAG_LATER; + } + } + + return nw_frag; +} + +static inline bool +ipv6_sanity_check(const struct ovs_16aligned_ip6_hdr *nh, size_t size) +{ + uint16_t plen; + + if (OVS_UNLIKELY(size < sizeof *nh)) { + return false; + } + + plen = ntohs(nh->ip6_plen); + if (OVS_UNLIKELY(plen > size)) { + return false; + } + /* Jumbo Payload option not supported yet. */ + if (OVS_UNLIKELY(size - plen > UINT8_MAX)) { + return false; + } + + return true; +} + /* Caller is responsible for initializing 'dst' with enough storage for * FLOW_U64S * 8 bytes. */ void @@ -750,22 +814,7 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) int ip_len; uint16_t tot_len; - if (OVS_UNLIKELY(size < IP_HEADER_LEN)) { - goto out; - } - ip_len = IP_IHL(nh->ip_ihl_ver) * 4; - - if (OVS_UNLIKELY(ip_len < IP_HEADER_LEN)) { - goto out; - } - if (OVS_UNLIKELY(size < ip_len)) { - goto out; - } - tot_len = ntohs(nh->ip_tot_len); - if (OVS_UNLIKELY(tot_len > size || ip_len > tot_len)) { - goto out; - } - if (OVS_UNLIKELY(size - tot_len > UINT8_MAX)) { + if (OVS_UNLIKELY(!ipv4_sanity_check(nh, size, &ip_len, &tot_len))) { goto out; } dp_packet_set_l2_pad_size(packet, size - tot_len); @@ -788,31 +837,19 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst) nw_tos = nh->ip_tos; nw_ttl = nh->ip_ttl; nw_proto = nh->ip_proto; - if (OVS_UNLIKELY(IP_IS_FRAGMENT(nh->ip_frag_off))) { - nw_frag = FLOW_NW_FRAG_ANY; - if (nh->ip_frag_off & htons(IP_FRAG_OFF_MASK)) { - nw_frag |= FLOW_NW_FRAG_LATER; - } - } + nw_frag = ipv4_get_nw_frag(nh); data_pull(&data, &size, ip_len); } else if (dl_type == htons(ETH_TYPE_IPV6)) { - const struct ovs_16aligned_ip6_hdr *nh; + const struct ovs_16aligned_ip6_hdr *nh = data; ovs_be32 tc_flow; uint16_t plen; - if (OVS_UNLIKELY(size < sizeof *nh)) { + if (OVS_UNLIKELY(!ipv6_sanity_check(nh, size))) { goto out; } - nh = data_pull(&data, &size, sizeof *nh); + data_pull(&data, &size, sizeof *nh); plen = ntohs(nh->ip6_plen); - if (OVS_UNLIKELY(plen > size)) { - goto out; - } - /* Jumbo Payload option not supported yet. */ - if (OVS_UNLIKELY(size - plen > UINT8_MAX)) { - goto out; - } dp_packet_set_l2_pad_size(packet, size - plen); size = plen; /* Never pull padding. */ @@ -991,6 +1028,60 @@ parse_dl_type(const struct eth_header *data_, size_t size) return parse_ethertype(&data, &size); } +uint16_t +parse_tcp_flags(struct dp_packet *packet) +{ + const void *data = dp_packet_data(packet); + size_t size = dp_packet_size(packet); + ovs_be16 dl_type; + uint8_t nw_frag = 0, nw_proto = 0; + + if (packet->packet_type != htonl(PT_ETH)) { + return 0; + } + + data_pull(&data, &size, ETH_ADDR_LEN * 2); + dl_type = parse_ethertype(&data, &size); + if (OVS_LIKELY(dl_type == htons(ETH_TYPE_IP))) { + const struct ip_header *nh = data; + int ip_len; + uint16_t tot_len; + + if (OVS_UNLIKELY(!ipv4_sanity_check(nh, size, &ip_len, &tot_len))) { + return 0; + } + nw_proto = nh->ip_proto; + nw_frag = ipv4_get_nw_frag(nh); + + size = tot_len; /* Never pull padding. */ + data_pull(&data, &size, ip_len); + } else if (dl_type == htons(ETH_TYPE_IPV6)) { + const struct ovs_16aligned_ip6_hdr *nh = data; + + if (OVS_UNLIKELY(!ipv6_sanity_check(nh, size))) { + return 0; + } + data_pull(&data, &size, sizeof *nh); + + size = ntohs(nh->ip6_plen); /* Never pull padding. */ + if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag)) { + return 0; + } + nw_proto = nh->ip6_nxt; + } else { + return 0; + } + + if (!(nw_frag & FLOW_NW_FRAG_LATER) && nw_proto == IPPROTO_TCP && + size >= TCP_HEADER_LEN) { + const struct tcp_header *tcp = data; + + return TCP_FLAGS_BE32(tcp->tcp_ctl); + } + + return 0; +} + /* For every bit of a field that is wildcarded in 'wildcards', sets the * corresponding bit in 'flow' to zero. */ void diff --git a/lib/flow.h b/lib/flow.h index 6ae5a67..f113ec4 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -130,6 +130,7 @@ bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto, uint8_t *nw_frag); ovs_be16 parse_dl_type(const struct eth_header *data_, size_t size); bool parse_nsh(const void **datap, size_t *sizep, struct flow_nsh *key); +uint16_t parse_tcp_flags(struct dp_packet *packet); static inline uint64_t flow_get_xreg(const struct flow *flow, int idx) From patchwork Tue Sep 26 05:36:33 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuanhan Liu X-Patchwork-Id: 818458 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=fridaylinux-org.20150623.gappssmtp.com header.i=@fridaylinux-org.20150623.gappssmtp.com header.b="fHz2tGBd"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y1VCK50fTz9t30 for ; Tue, 26 Sep 2017 15:39:56 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id B8EB9B0B; Tue, 26 Sep 2017 05:38:58 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 6EBF3BAE for ; Tue, 26 Sep 2017 05:38:58 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f43.google.com (mail-pg0-f43.google.com [74.125.83.43]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id EB34E3D5 for ; Tue, 26 Sep 2017 05:38:57 +0000 (UTC) Received: by mail-pg0-f43.google.com with SMTP id m30so5357565pgn.6 for ; Mon, 25 Sep 2017 22:38:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fridaylinux-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Fx62Sf5QTG/BlHmlZ/7HUf3Lo11Xi/s9JIYKjaxTL5k=; b=fHz2tGBdS2Ao1Ve15Me3RobFt0NcYD/LJFW0u1u/PlzfKur/Sa1vRFN/4bz3bc3jQO xspCNcOvXkQEoiKelSu8Q0t3YGNNyX0X8PWtOjdl3fcnXyGulpO3RD9oCC35I+E2Gm5o sWFlH6G1v8SxaxSfTE4w7GqTxiuJ0Czf90mkBwLm6aYe4OF4dFTRqqn7BRTPOUfI6T4i 9DmgNJgLhtTGkcjDgqpAAhESZbaDwhMBC6KubzR4A65pU8DSdt1kwCTjYdNwg+oKOYGE F+qt8fLOxuy1DQaxO8nN5PL7kQ4XnAMvCAbnTmkcfBCdx/9JeX8QpqG6ulgdVjqL/3ur JAhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Fx62Sf5QTG/BlHmlZ/7HUf3Lo11Xi/s9JIYKjaxTL5k=; b=DvxMStfgMuvF6CwMY4TkuNnnIhLyqadv8RsYCJfhOZPhEr4gbUGvqdh2bFVumcGDUV oO0/8/hqvG0BcwdTE3XiSvNokKeyvGMS+reB5qOKQD6n8TRtLqh4yDnpPo7UULI3W3J0 3MwB0xn8t248/5jTBs/JcenhcQkcRxfsKXGLOjw7DhYewY7J/AyeKiLgXcL/OcO/Ox3v sP+SfNo7AmVawN01BPOUc6YI6kYOT9yM+BHkFn+KxaRYIUmWVLToqluggZxqPCXRjlYo ApthBOV5aXY4PIilG5xuKuyG7PIEDT+/QOfV07bPdht4ga1jcXXcM4PLhGxFW1jkf5lA tfbQ== X-Gm-Message-State: AHPjjUiXcwc1ZSHXjPAPIBroQ1ERGGhOvad9q+Ta1gm2DTD30eSC2CD8 /2qk5Xxg4XO5P6NE2Ts6tzouhBFkdH4rBA== X-Google-Smtp-Source: AOwi7QC29QCgIABtfwzYe906rAiLB9Z9v0QPPT6Zx7SARdCKquI2fZQDYQ7Z1d8DDjlGk7dwiamftA== X-Received: by 10.98.178.204 with SMTP id z73mr9841139pfl.107.1506404337115; Mon, 25 Sep 2017 22:38:57 -0700 (PDT) Received: from localhost.localdomain ([101.228.205.132]) by smtp.gmail.com with ESMTPSA id o79sm13180077pfi.108.2017.09.25.22.38.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Sep 2017 22:38:56 -0700 (PDT) From: Yuanhan Liu To: dev@openvswitch.org Date: Tue, 26 Sep 2017 13:36:33 +0800 Message-Id: <1506404199-23579-4-git-send-email-yliu@fridaylinux.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> References: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> X-Spam-Status: No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Simon Horman Subject: [ovs-dev] [PATCH v3 3/9] netdev-dpdk: convert ufid to dpdk flow X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Flows offloaded to DPDK are identified by rte_flow pointer while OVS flows are identified by ufid. This patches adds a hmap to convert ufid to dpdk flow (rte_flow). Most of the code are stolen from netdev-tc-offloads.c, with some modificatons. Some functions are marked as "inline", which is a trick to workaround the temp "functiond defined but not used" warnings. Co-authored-by: Finn Christensen Signed-off-by: Yuanhan Liu Signed-off-by: Finn Christensen --- v3: warn on failed to find ufi_data_flow_data now assocociated with ufid --- lib/netdev-dpdk.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index f58e9be..1be9131 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "dirs.h" #include "dp-packet.h" @@ -58,6 +59,7 @@ #include "sset.h" #include "unaligned.h" #include "timeval.h" +#include "uuid.h" #include "unixctl.h" enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM}; @@ -3312,6 +3314,96 @@ unlock: return err; } +/* + * A mapping from ufid to dpdk rte_flow pointer + */ + +static struct hmap ufid_dpdk_flow = HMAP_INITIALIZER(&ufid_dpdk_flow); +static struct ovs_mutex ufid_lock = OVS_MUTEX_INITIALIZER; + +struct ufid_dpdk_flow_data { + struct hmap_node node; + ovs_u128 ufid; + struct rte_flow *rte_flow; +}; + +/* + * Find ufid_dpdk_flow_data node associated with @ufid + */ +static struct ufid_dpdk_flow_data * +find_ufid_dpdk_flow_mapping(const ovs_u128 *ufid) +{ + size_t hash = hash_bytes(ufid, sizeof(*ufid), 0); + struct ufid_dpdk_flow_data *data = NULL; + + ovs_mutex_lock(&ufid_lock); + HMAP_FOR_EACH_WITH_HASH (data, node, hash, &ufid_dpdk_flow) { + if (ovs_u128_equals(*ufid, data->ufid)) { + break; + } + } + ovs_mutex_unlock(&ufid_lock); + + return data; +} + +/* + * Remove ufid_dpdk_flow_data node associated with @ufid + */ +static inline void +del_ufid_dpdk_flow_mapping(const ovs_u128 *ufid) +{ + struct ufid_dpdk_flow_data *data; + + data = find_ufid_dpdk_flow_mapping(ufid); + if (data) { + ovs_mutex_lock(&ufid_lock); + hmap_remove(&ufid_dpdk_flow, &data->node); + free(data); + ovs_mutex_unlock(&ufid_lock); + } else { + VLOG_WARN("ufid "UUID_FMT"is not installed in the dpdk flow mapping\n", + UUID_ARGS((struct uuid *)ufid)); + } +} + +/* Add ufid to dpdk_flow mapping */ +static inline void +add_ufid_dpdk_flow_mapping(const ovs_u128 *ufid, struct rte_flow *rte_flow) +{ + size_t hash = hash_bytes(ufid, sizeof(*ufid), 0); + struct ufid_dpdk_flow_data *data = xzalloc(sizeof(*data)); + + /* + * We should not simply overwrite an existing rte flow. + * We should have deleted it first before re-adding it. + * Thus, if following assert triggers, something is wrong: + * the rte_flow is not destroyed. + */ + ovs_assert(find_ufid_dpdk_flow_mapping(ufid) == NULL); + + data->ufid = *ufid; + data->rte_flow = rte_flow; + + ovs_mutex_lock(&ufid_lock); + hmap_insert(&ufid_dpdk_flow, &data->node, hash); + ovs_mutex_unlock(&ufid_lock); +} + +/* Get rte_flow by ufid. + * + * Returns rte rte_flow if successful. Otherwise returns 0. + */ +static inline struct rte_flow * +get_rte_flow_by_ufid(const ovs_u128 *ufid) +{ + struct ufid_dpdk_flow_data *data; + + data = find_ufid_dpdk_flow_mapping(ufid); + return data ? data->rte_flow : NULL; +} + + #define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, DESTRUCT, \ SET_CONFIG, SET_TX_MULTIQ, SEND, \ GET_CARRIER, GET_STATS, \ From patchwork Tue Sep 26 05:36:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuanhan Liu X-Patchwork-Id: 818460 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=fridaylinux-org.20150623.gappssmtp.com header.i=@fridaylinux-org.20150623.gappssmtp.com header.b="my3othAl"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y1VDq5zLkz9t30 for ; Tue, 26 Sep 2017 15:41:15 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 700CDBE0; Tue, 26 Sep 2017 05:39:54 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 216EBB79 for ; Tue, 26 Sep 2017 05:39:53 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f182.google.com (mail-pf0-f182.google.com [209.85.192.182]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 9A4BDD3 for ; Tue, 26 Sep 2017 05:39:51 +0000 (UTC) Received: by mail-pf0-f182.google.com with SMTP id l188so5037662pfc.6 for ; Mon, 25 Sep 2017 22:39:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fridaylinux-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=0WFbuYNnho0/TzQKS+zAiOqAYz88NJcWs4w8oTJbBiM=; b=my3othAlOP8W1StoMdEsDTZ1q/e9nm8WnJDV2Ty8+5TYmAe3ERM7lnbMOgyOGmCz7m yhWRYG3EpfvAiHpiEWyK9cLrIp0nqCzmDFDFxZ32B4xExtg4AUo54T6sNEbNytYWnKxm ZE0R07CQ1eDzO32gzDC24CgVeebBsbbGh2UxACeQzlfW5gaKnlsDu+IGBZ5HTQwRQjgQ +G/d5fux9QbAqZdTg76DZDPAZtY5Pc0Iis5zYUt24yWVvZefVSGDUju/ONj/wmQN2heF rQ5y2Kbk5w+o0ZBE3S7Im/QQgWuAQpRImCGQzONgl/dTXte3N0BE4NbfmIcIsvXS646w jzaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=0WFbuYNnho0/TzQKS+zAiOqAYz88NJcWs4w8oTJbBiM=; b=Hv7r2F2EDfoVa4dYxQDS1ZRcn+dyDwtuMwwipsHVScDKiC6qzP58sN9t8kYfej+19H DMBYdMjD7uPqbByYjHUELxf25cNgQM1V4p3vWBntplImbPeTO8OuPUH9/CxxylGz6aPp DYf2wm+bsafkQM9gaLGqf0Ml9cc6/9HAlaPf50VbmWq7zLNwq6n3cW222lh6Fy/yrzy8 frtbZr9aOvOKNm88XP6Eg2Jnez/pCJBk8NZNsPHsN+ryBYKURtBxq2ZAIXhC62YicfqM nb+6t46fM1Ein/IOHEcB1IqyXS1uCJ1T/2dL+XPjNhX3iLeQTczFhmSwV4gqL3Qc20wb Db6g== X-Gm-Message-State: AHPjjUiGCncJFjSOJBhbelD/2U8sC+RVPnm0LkPbzGXATgmHy1DZP+nO 1UtniDoSsdcPVRh1XIhH/ylktUu2Hq6l1w== X-Google-Smtp-Source: AOwi7QDzcGeAgyeUSrLrEw2yDbr5csoDzkL9Alrabe+t1iUO/sZ1REWqzL3HJ3qPmsfQJQsYe4wO4Q== X-Received: by 10.98.218.18 with SMTP id c18mr9676535pfh.256.1506404390658; Mon, 25 Sep 2017 22:39:50 -0700 (PDT) Received: from localhost.localdomain ([101.228.205.132]) by smtp.gmail.com with ESMTPSA id o79sm13180077pfi.108.2017.09.25.22.38.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Sep 2017 22:39:49 -0700 (PDT) From: Yuanhan Liu To: dev@openvswitch.org Date: Tue, 26 Sep 2017 13:36:34 +0800 Message-Id: <1506404199-23579-5-git-send-email-yliu@fridaylinux.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> References: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> X-Spam-Status: No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Simon Horman Subject: [ovs-dev] [PATCH v3 4/9] netdev-dpdk: implement flow put with rte flow X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org From: Finn Christensen The basic yet the major part of this patch is to translate the "match" to rte flow patterns. And then, we create a rte flow with a MARK action. Afterwards, all pkts matches the flow will have the mark id in the mbuf. For any unsupported flows, such as MPLS, -1 is returned, meaning the flow offload is failed and then skipped. Co-authored-by: Yuanhan Liu Signed-off-by: Finn Christensen Signed-off-by: Yuanhan Liu --- v3: - fix duplicate (and wrong) TOS assignment - zero the pattern spec as well - remove macros - add missing unsupported fields v2: - convert some macros to functions - do not hardcode the max number of flow/action - fix L2 patterns for Intel nic - add comments for not implemented offload methods --- lib/netdev-dpdk.c | 441 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 440 insertions(+), 1 deletion(-) diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index 1be9131..525536a 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -3404,6 +3404,445 @@ get_rte_flow_by_ufid(const ovs_u128 *ufid) } +struct flow_patterns { + struct rte_flow_item *items; + int cnt; + int max; +}; + +struct flow_actions { + struct rte_flow_action *actions; + int cnt; + int max; +}; + +static void +add_flow_pattern(struct flow_patterns *patterns, enum rte_flow_item_type type, + const void *spec, const void *mask) +{ + int cnt = patterns->cnt; + + if (cnt == 0) { + patterns->max = 8; + patterns->items = xcalloc(patterns->max, sizeof(struct rte_flow_item)); + } else if (cnt == patterns->max) { + patterns->max *= 2; + patterns->items = xrealloc(patterns->items, patterns->max * + sizeof(struct rte_flow_item)); + } + + patterns->items[cnt].type = type; + patterns->items[cnt].spec = spec; + patterns->items[cnt].mask = mask; + patterns->items[cnt].last = NULL; + patterns->cnt++; +} + +static void +add_flow_action(struct flow_actions *actions, enum rte_flow_action_type type, + const void *conf) +{ + int cnt = actions->cnt; + + if (cnt == 0) { + actions->max = 8; + actions->actions = xcalloc(actions->max, + sizeof(struct rte_flow_action)); + } else if (cnt == actions->max) { + actions->max *= 2; + actions->actions = xrealloc(actions->actions, actions->max * + sizeof(struct rte_flow_action)); + } + + actions->actions[cnt].type = type; + actions->actions[cnt].conf = conf; + actions->cnt++; +} + +static int +netdev_dpdk_add_rte_flow_offload(struct netdev *netdev, + const struct match *match, + struct nlattr *nl_actions OVS_UNUSED, + size_t actions_len OVS_UNUSED, + const ovs_u128 *ufid, + struct offload_info *info) +{ + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); + const struct rte_flow_attr flow_attr = { + .group = 0, + .priority = 0, + .ingress = 1, + .egress = 0 + }; + struct flow_patterns patterns = { .items = NULL, .cnt = 0 }; + struct flow_actions actions = { .actions = NULL, .cnt = 0 }; + struct rte_flow *flow; + struct rte_flow_error error; + uint8_t *ipv4_next_proto_mask = NULL; + int ret = 0; + + /* Eth */ + struct rte_flow_item_eth eth_spec; + struct rte_flow_item_eth eth_mask; + memset(ð_spec, 0, sizeof(eth_spec)); + memset(ð_mask, 0, sizeof(eth_mask)); + if (!eth_addr_is_zero(match->wc.masks.dl_src) || + !eth_addr_is_zero(match->wc.masks.dl_dst)) { + rte_memcpy(ð_spec.dst, &match->flow.dl_dst, sizeof(eth_spec.dst)); + rte_memcpy(ð_spec.src, &match->flow.dl_src, sizeof(eth_spec.src)); + eth_spec.type = match->flow.dl_type; + + rte_memcpy(ð_mask.dst, &match->wc.masks.dl_dst, + sizeof(eth_mask.dst)); + rte_memcpy(ð_mask.src, &match->wc.masks.dl_src, + sizeof(eth_mask.src)); + eth_mask.type = match->wc.masks.dl_type; + + add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH, + ð_spec, ð_mask); + } else { + /* + * If user specifies a flow (like UDP flow) without L2 patterns, + * OVS will at least set the dl_type. Normally, it's enough to + * create an eth pattern just with it. Unluckily, some Intel's + * NIC (such as XL710) doesn't support that. Below is a workaround, + * which simply matches any L2 pkts. + */ + add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH, NULL, NULL); + } + + /* VLAN */ + struct rte_flow_item_vlan vlan_spec; + struct rte_flow_item_vlan vlan_mask; + memset(&vlan_spec, 0, sizeof(vlan_spec)); + memset(&vlan_mask, 0, sizeof(vlan_mask)); + if (match->wc.masks.vlans[0].tci && match->flow.vlans[0].tci) { + vlan_spec.tci = match->flow.vlans[0].tci; + vlan_mask.tci = match->wc.masks.vlans[0].tci; + + /* match any protocols */ + vlan_mask.tpid = 0; + + add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_VLAN, + &vlan_spec, &vlan_mask); + } + + /* IP v4 */ + uint8_t proto = 0; + struct rte_flow_item_ipv4 ipv4_spec; + struct rte_flow_item_ipv4 ipv4_mask; + memset(&ipv4_spec, 0, sizeof(ipv4_spec)); + memset(&ipv4_mask, 0, sizeof(ipv4_mask)); + if (match->flow.dl_type == ntohs(ETH_TYPE_IP) && + (match->wc.masks.nw_src || match->wc.masks.nw_dst || + match->wc.masks.nw_tos || match->wc.masks.nw_ttl || + match->wc.masks.nw_proto)) { + ipv4_spec.hdr.type_of_service = match->flow.nw_tos; + ipv4_spec.hdr.time_to_live = match->flow.nw_ttl; + ipv4_spec.hdr.next_proto_id = match->flow.nw_proto; + ipv4_spec.hdr.src_addr = match->flow.nw_src; + ipv4_spec.hdr.dst_addr = match->flow.nw_dst; + + ipv4_mask.hdr.type_of_service = match->wc.masks.nw_tos; + ipv4_mask.hdr.time_to_live = match->wc.masks.nw_ttl; + ipv4_mask.hdr.next_proto_id = match->wc.masks.nw_proto; + ipv4_mask.hdr.src_addr = match->wc.masks.nw_src; + ipv4_mask.hdr.dst_addr = match->wc.masks.nw_dst; + + add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_IPV4, + &ipv4_spec, &ipv4_mask); + + /* Save proto for L4 protocol setup */ + proto = ipv4_spec.hdr.next_proto_id & ipv4_mask.hdr.next_proto_id; + + /* Remember proto mask address for later modification */ + ipv4_next_proto_mask = &ipv4_mask.hdr.next_proto_id; + } + + if (proto != IPPROTO_ICMP && proto != IPPROTO_UDP && + proto != IPPROTO_SCTP && proto != IPPROTO_TCP && + (match->wc.masks.tp_src || + match->wc.masks.tp_dst || + match->wc.masks.tcp_flags)) { + VLOG_INFO("L4 Protocol (%u) not supported", proto); + ret = -1; + goto out; + } + + struct rte_flow_item_udp udp_spec; + struct rte_flow_item_udp udp_mask; + memset(&udp_spec, 0, sizeof(udp_spec)); + memset(&udp_mask, 0, sizeof(udp_mask)); + if (proto == IPPROTO_UDP && + (match->wc.masks.tp_src || match->wc.masks.tp_dst)) { + udp_spec.hdr.src_port = match->flow.tp_src; + udp_spec.hdr.dst_port = match->flow.tp_dst; + + udp_mask.hdr.src_port = match->wc.masks.tp_src; + udp_mask.hdr.dst_port = match->wc.masks.tp_dst; + + add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_UDP, + &udp_spec, &udp_mask); + + /* proto == UDP and ITEM_TYPE_UDP, thus no need for proto match */ + if (ipv4_next_proto_mask) { + *ipv4_next_proto_mask = 0; + } + } + + struct rte_flow_item_sctp sctp_spec; + struct rte_flow_item_sctp sctp_mask; + memset(&sctp_spec, 0, sizeof(sctp_spec)); + memset(&sctp_mask, 0, sizeof(sctp_mask)); + if (proto == IPPROTO_SCTP && + (match->wc.masks.tp_src || match->wc.masks.tp_dst)) { + sctp_spec.hdr.src_port = match->flow.tp_src; + sctp_spec.hdr.dst_port = match->flow.tp_dst; + + sctp_mask.hdr.src_port = match->wc.masks.tp_src; + sctp_mask.hdr.dst_port = match->wc.masks.tp_dst; + + add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_SCTP, + &sctp_spec, &sctp_mask); + + /* proto == SCTP and ITEM_TYPE_SCTP, thus no need for proto match */ + if (ipv4_next_proto_mask) { + *ipv4_next_proto_mask = 0; + } + } + + struct rte_flow_item_icmp icmp_spec; + struct rte_flow_item_icmp icmp_mask; + memset(&icmp_spec, 0, sizeof(icmp_spec)); + memset(&icmp_mask, 0, sizeof(icmp_mask)); + if (proto == IPPROTO_ICMP && + (match->wc.masks.tp_src || match->wc.masks.tp_dst)) { + icmp_spec.hdr.icmp_type = (uint8_t)ntohs(match->flow.tp_src); + icmp_spec.hdr.icmp_code = (uint8_t)ntohs(match->flow.tp_dst); + + icmp_mask.hdr.icmp_type = (uint8_t)ntohs(match->wc.masks.tp_src); + icmp_mask.hdr.icmp_code = (uint8_t)ntohs(match->wc.masks.tp_dst); + + add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ICMP, + &icmp_spec, &icmp_mask); + + /* proto == ICMP and ITEM_TYPE_ICMP, thus no need for proto match */ + if (ipv4_next_proto_mask) { + *ipv4_next_proto_mask = 0; + } + } + + struct rte_flow_item_tcp tcp_spec; + struct rte_flow_item_tcp tcp_mask; + memset(&tcp_spec, 0, sizeof(tcp_spec)); + memset(&tcp_mask, 0, sizeof(tcp_mask)); + if (proto == IPPROTO_TCP && + (match->wc.masks.tp_src || + match->wc.masks.tp_dst || + match->wc.masks.tcp_flags)) { + tcp_spec.hdr.src_port = match->flow.tp_src; + tcp_spec.hdr.dst_port = match->flow.tp_dst; + tcp_spec.hdr.data_off = ntohs(match->flow.tcp_flags) >> 8; + tcp_spec.hdr.tcp_flags = ntohs(match->flow.tcp_flags) & 0xff; + + tcp_mask.hdr.src_port = match->wc.masks.tp_src; + tcp_mask.hdr.dst_port = match->wc.masks.tp_dst; + tcp_mask.hdr.data_off = ntohs(match->wc.masks.tcp_flags) >> 8; + tcp_mask.hdr.tcp_flags = ntohs(match->wc.masks.tcp_flags) & 0xff; + + add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_TCP, + &tcp_spec, &tcp_mask); + + /* proto == TCP and ITEM_TYPE_TCP, thus no need for proto match */ + if (ipv4_next_proto_mask) { + *ipv4_next_proto_mask = 0; + } + } + add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_END, NULL, NULL); + + struct rte_flow_action_mark mark; + mark.id = info->flow_mark; + add_flow_action(&actions, RTE_FLOW_ACTION_TYPE_MARK, &mark); + add_flow_action(&actions, RTE_FLOW_ACTION_TYPE_END, NULL); + + flow = rte_flow_create(dev->port_id, &flow_attr, patterns.items, + actions.actions, &error); + if (!flow) { + VLOG_ERR("rte flow creat error: %u : message : %s\n", + error.type, error.message); + ret = -1; + goto out; + } + add_ufid_dpdk_flow_mapping(ufid, flow); + VLOG_INFO("installed flow %p by ufid "UUID_FMT"\n", + flow, UUID_ARGS((struct uuid *)ufid)); + +out: + free(patterns.items); + free(actions.actions); + return ret; +} + +static bool +is_all_zero(const void *addr, size_t n) +{ + size_t i = 0; + const uint8_t *p = (uint8_t *)addr; + + for (i = 0; i < n; i++) { + if (p[i] != 0) { + return false; + } + } + + return true; +} + +/* + * Check if any unsupported flow patterns are specified. + */ +static int +netdev_dpdk_validate_flow(const struct match *match) +{ + struct match match_zero_wc; + + /* Create a wc-zeroed version of flow */ + match_init(&match_zero_wc, &match->flow, &match->wc); + + if (!is_all_zero(&match_zero_wc.flow.tunnel, + sizeof(match_zero_wc.flow.tunnel))) { + goto err; + } + + if (match->wc.masks.metadata || + match->wc.masks.skb_priority || + match->wc.masks.pkt_mark || + match->wc.masks.dp_hash) { + goto err; + } + + /* recirc id must be zero */ + if (match_zero_wc.flow.recirc_id) { + goto err; + } + + if (match->wc.masks.ct_state || + match->wc.masks.ct_nw_proto || + match->wc.masks.ct_zone || + match->wc.masks.ct_mark || + match->wc.masks.ct_label.u64.hi || + match->wc.masks.ct_label.u64.lo) { + goto err; + } + + if (match->wc.masks.conj_id || + match->wc.masks.actset_output) { + goto err; + } + + /* unsupported L2 */ + if (!is_all_zero(&match->wc.masks.mpls_lse, + sizeof(match_zero_wc.flow.mpls_lse))) { + goto err; + } + + /* unsupported L3 */ + if (match->wc.masks.ipv6_label || + match->wc.masks.ct_nw_src || + match->wc.masks.ct_nw_dst || + !is_all_zero(&match->wc.masks.ipv6_src, sizeof(struct in6_addr)) || + !is_all_zero(&match->wc.masks.ipv6_dst, sizeof(struct in6_addr)) || + !is_all_zero(&match->wc.masks.ct_ipv6_src, sizeof(struct in6_addr)) || + !is_all_zero(&match->wc.masks.ct_ipv6_dst, sizeof(struct in6_addr)) || + !is_all_zero(&match->wc.masks.nd_target, sizeof(struct in6_addr)) || + !is_all_zero(&match->wc.masks.nsh, sizeof(struct flow_nsh)) || + !is_all_zero(&match->wc.masks.arp_sha, sizeof(struct eth_addr)) || + !is_all_zero(&match->wc.masks.arp_tha, sizeof(struct eth_addr))) { + goto err; + } + + /* If fragmented, then don't HW accelerate - for now */ + if (match_zero_wc.flow.nw_frag) { + goto err; + } + + /* unsupported L4 */ + if (match->wc.masks.igmp_group_ip4 || + match->wc.masks.ct_tp_src || + match->wc.masks.ct_tp_dst) { + goto err; + } + + return 0; + +err: + VLOG_ERR("cannot HW accelerate this flow due to unsupported protocols"); + return -1; +} + +static int +netdev_dpdk_destroy_rte_flow(struct netdev_dpdk *dev, + const ovs_u128 *ufid, + struct rte_flow *rte_flow) +{ + struct rte_flow_error error; + int ret; + + ret = rte_flow_destroy(dev->port_id, rte_flow, &error); + if (ret == 0) { + del_ufid_dpdk_flow_mapping(ufid); + VLOG_INFO("removed rte flow %p associated with ufid " UUID_FMT "\n", + rte_flow, UUID_ARGS((struct uuid *)ufid)); + } else { + VLOG_ERR("rte flow destroy error: %u : message : %s\n", + error.type, error.message); + } + + return ret; +} + +static int +netdev_dpdk_flow_put(struct netdev *netdev, struct match *match, + struct nlattr *actions, size_t actions_len, + const ovs_u128 *ufid, struct offload_info *info, + struct dpif_flow_stats *stats OVS_UNUSED) +{ + struct rte_flow *rte_flow; + int ret; + + /* + * If an old rte_flow exists, it means it's a flow modification. + * Here destroy the old rte flow first before adding a new one. + */ + rte_flow = get_rte_flow_by_ufid(ufid); + if (rte_flow) { + ret = netdev_dpdk_destroy_rte_flow(netdev_dpdk_cast(netdev), + ufid, rte_flow); + if (ret < 0) { + return ret; + } + } + + ret = netdev_dpdk_validate_flow(match); + if (ret < 0) { + return ret; + } + + return netdev_dpdk_add_rte_flow_offload(netdev, match, actions, + actions_len, ufid, info); +} + +#define DPDK_FLOW_OFFLOAD_API \ + NULL, /* flow_flush */ \ + NULL, /* flow_dump_create */ \ + NULL, /* flow_dump_destroy */ \ + NULL, /* flow_dump_next */ \ + netdev_dpdk_flow_put, \ + NULL, /* flow_get */ \ + NULL, /* flow_del */ \ + NULL /* init_flow_api */ + + #define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, DESTRUCT, \ SET_CONFIG, SET_TX_MULTIQ, SEND, \ GET_CARRIER, GET_STATS, \ @@ -3476,7 +3915,7 @@ get_rte_flow_by_ufid(const ovs_u128 *ufid) RXQ_RECV, \ NULL, /* rx_wait */ \ NULL, /* rxq_drain */ \ - NO_OFFLOAD_API \ + DPDK_FLOW_OFFLOAD_API \ } static const struct netdev_class dpdk_class = From patchwork Tue Sep 26 05:36:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuanhan Liu X-Patchwork-Id: 818461 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=fridaylinux-org.20150623.gappssmtp.com header.i=@fridaylinux-org.20150623.gappssmtp.com header.b="IT6GHfL1"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y1VFb21mtz9t30 for ; Tue, 26 Sep 2017 15:41:55 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 6454FBE9; Tue, 26 Sep 2017 05:40:11 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 2AE0BB92 for ; Tue, 26 Sep 2017 05:40:10 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f46.google.com (mail-pg0-f46.google.com [74.125.83.46]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 4045D3DB for ; Tue, 26 Sep 2017 05:40:08 +0000 (UTC) Received: by mail-pg0-f46.google.com with SMTP id 7so5350832pgd.13 for ; Mon, 25 Sep 2017 22:40:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fridaylinux-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=q/8Fjx//5ZP7u/wxOreXurq9lTAKjfoxrV7jsXIR7cA=; b=IT6GHfL1byfzV+TZ1aADPmhugaxHxAdtyZgL1oIyq5BZz3b8/vNiKv+DlNAqqGXhLf kX7SBMGqA3dB8QtRyY2IRhQYe+X0tFS2APi3PFHKothlOzaEUFEGvNK0dKwNXf1QfGq+ qv4Ys01Dyk/LX9cOj1BK+plkAymbtIapglMVsVrB4FPAogi/PutAUSZaUhPZQpm2lYff EJwQNxPqRaRjszG3oW6ZHNq4nK304f/Na3VqHU96O5sZDumlG4/KEVTrAOHSQBFzTb0h dRfVuittughYl1Sb27v+xMrLGa7oSMdGxZoNlLe66Hbr+x2WDPUV01cbAuwyUQdWoS8m 1fgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=q/8Fjx//5ZP7u/wxOreXurq9lTAKjfoxrV7jsXIR7cA=; b=iqOKQfGquI2f3HX2FimKDnVNUJ+qkUfRNs6bFZamCzoePSvlSsrXi5ZRqLqoGorvWp QEE1dUi7gO6L4Gi836UVQnlHxcgJqdOfVlz0/Z8fmaXAVfEadfUd1ly8LT1n3vDv0JEX wvG+0CsyQOSwpBWsx1jtg2+h1QxetFilb1HO6/eE/C2O55faT72YrksEvZ2LVO3yBZa1 a02Usvw+Xh4PBcC6EBptwN6xVP955g+XykaOJury6HRrUZRXcx9ISFqk7FIOhQX4Zx0/ JdOFAYo1i0Z4U6+QsotY9FAn9wxBlP+o+pWHDtYasYtSrhkkZqANZzJFs193txNLYNBn E4/w== X-Gm-Message-State: AHPjjUjxhvsLctYq8XUOL/15NQAvTPZRtGKmVYB/OLdqM+z9FSoyHdQ+ flwRVQMKMGGudABxZPGSlcES68p4MEtVXA== X-Google-Smtp-Source: AOwi7QAqk1sVQms/nt8srH7haxSWwmRfriSCZbA0Q292aonWGAv1c+QFDXyUUK+ne+4jcj3hIJX/Eg== X-Received: by 10.101.73.129 with SMTP id r1mr10052868pgs.411.1506404407434; Mon, 25 Sep 2017 22:40:07 -0700 (PDT) Received: from localhost.localdomain ([101.228.205.132]) by smtp.gmail.com with ESMTPSA id o79sm13180077pfi.108.2017.09.25.22.39.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Sep 2017 22:40:05 -0700 (PDT) From: Yuanhan Liu To: dev@openvswitch.org Date: Tue, 26 Sep 2017 13:36:35 +0800 Message-Id: <1506404199-23579-6-git-send-email-yliu@fridaylinux.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> References: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> X-Spam-Status: No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Simon Horman Subject: [ovs-dev] [PATCH v3 5/9] dpif-netdev: record rx queue id for the upcall X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org From: Shachar Beiser For the DPDK flow offload, which basically just binds a MARK action to a flow, the MARK is required to be used together with a QUEUE action for the most NICs I'm aware of. The QUEUE action then needs a queue index, which is not given in the flow content. Here we record the rx queue while recieving the pkts to solve above issue. Co-authored-by: Yuanhan Liu Signed-off-by: Shachar Beiser Signed-off-by: Yuanhan Liu --- lib/dp-packet.h | 1 + lib/dpif-netdev.c | 19 +++++++++++-------- lib/netdev.c | 1 + lib/netdev.h | 1 + 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/dp-packet.h b/lib/dp-packet.h index a7a062f..479a734 100644 --- a/lib/dp-packet.h +++ b/lib/dp-packet.h @@ -709,6 +709,7 @@ enum { NETDEV_MAX_BURST = 32 }; /* Maximum number packets in a batch. */ struct dp_packet_batch { size_t count; bool trunc; /* true if the batch needs truncate. */ + int rxq; struct dp_packet *packets[NETDEV_MAX_BURST]; }; diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 5c33c74..1a70af6 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -2550,7 +2550,7 @@ static void try_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, odp_port_t in_port, struct dp_netdev_flow *flow, struct match *match, const ovs_u128 *ufid, const struct nlattr *actions, - size_t actions_len) + size_t actions_len, int rxq) { struct offload_info info; struct dp_netdev_port *port; @@ -2562,6 +2562,7 @@ try_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, odp_port_t in_port, if (!port) { return; } + info.rxq = rxq; if (modification) { info.flow_mark = flow->mark; @@ -2598,7 +2599,8 @@ try_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, odp_port_t in_port, static struct dp_netdev_flow * dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, struct match *match, const ovs_u128 *ufid, - const struct nlattr *actions, size_t actions_len) + const struct nlattr *actions, size_t actions_len, + int rxq) OVS_REQUIRES(pmd->flow_mutex) { struct dp_netdev_flow *flow; @@ -2647,7 +2649,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, dp_netdev_flow_hash(&flow->ufid)); try_netdev_flow_put(pmd, in_port, flow, match, ufid, - actions, actions_len); + actions, actions_len, rxq); if (OVS_UNLIKELY(!VLOG_DROP_DBG((&upcall_rl)))) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -2717,7 +2719,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, if (put->flags & DPIF_FP_CREATE) { if (cmap_count(&pmd->flow_table) < MAX_FLOWS) { dp_netdev_flow_add(pmd, match, ufid, put->actions, - put->actions_len); + put->actions_len, -1); error = 0; } else { error = EFBIG; @@ -2738,7 +2740,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, ovsrcu_set(&netdev_flow->actions, new_actions); try_netdev_flow_put(pmd, in_port, netdev_flow, match, ufid, - put->actions, put->actions_len); + put->actions, put->actions_len, -1); if (stats) { get_dpif_flow_stats(netdev_flow, stats); @@ -5119,7 +5121,7 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd, struct dp_packet *packet, const struct netdev_flow_key *key, struct ofpbuf *actions, struct ofpbuf *put_actions, - int *lost_cnt, long long now) + int *lost_cnt, long long now, int rxq) { struct ofpbuf *add_actions; struct dp_packet_batch b; @@ -5175,7 +5177,8 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd, if (OVS_LIKELY(!netdev_flow)) { netdev_flow = dp_netdev_flow_add(pmd, &match, &ufid, add_actions->data, - add_actions->size); + add_actions->size, + rxq); } ovs_mutex_unlock(&pmd->flow_mutex); emc_probabilistic_insert(pmd, key, netdev_flow); @@ -5245,7 +5248,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, miss_cnt++; handle_packet_upcall(pmd, packets[i], &keys[i], &actions, - &put_actions, &lost_cnt, now); + &put_actions, &lost_cnt, now, packets_->rxq); } ofpbuf_uninit(&actions); diff --git a/lib/netdev.c b/lib/netdev.c index b4e570b..c9b7019 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -700,6 +700,7 @@ netdev_rxq_recv(struct netdev_rxq *rx, struct dp_packet_batch *batch) retval = rx->netdev->netdev_class->rxq_recv(rx, batch); if (!retval) { + batch->rxq = rx->queue_id; COVERAGE_INC(netdev_received); } else { batch->count = 0; diff --git a/lib/netdev.h b/lib/netdev.h index 2003165..28ad39d 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -194,6 +194,7 @@ struct offload_info { * it will be in the pkt meta data. */ uint32_t flow_mark; + int rxq; }; struct dpif_class; struct netdev_flow_dump; From patchwork Tue Sep 26 05:36:36 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuanhan Liu X-Patchwork-Id: 818462 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=fridaylinux-org.20150623.gappssmtp.com header.i=@fridaylinux-org.20150623.gappssmtp.com header.b="kDG+XUMK"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y1VGQ2QFGz9t30 for ; Tue, 26 Sep 2017 15:42:38 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 9E979BFA; Tue, 26 Sep 2017 05:40:21 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id B6E47BD7 for ; Tue, 26 Sep 2017 05:40:20 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f170.google.com (mail-pf0-f170.google.com [209.85.192.170]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 46B94D3 for ; Tue, 26 Sep 2017 05:40:20 +0000 (UTC) Received: by mail-pf0-f170.google.com with SMTP id d187so5031819pfg.11 for ; Mon, 25 Sep 2017 22:40:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fridaylinux-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=rZzys5P5Qb9qUuQqIYkm3GUlaA9bioDy/ONdg5vGU6M=; b=kDG+XUMK0fzuVysNSFClYQFVJnCwM1DFgkN3k4gq4pTZYLE6A4hMob2EK3Bq5WFypS 35EXBwiG4GUjBhx3UKkwjgVJjPrtG9TagayeZJ9OeNo0Ikti8HcSAyYsc1qG4ok4v3mq duegiHu8vAx/qVU4si/qvdqqDevr9hyzSNo3CgNAss5wPW+fao6SUxnh7FRArSfAjXlI bXHZGFdu2mU7JI1YZ5WxD3bQZTbNK0RK332iZ+ZIkk+zLwQh6zT65GGtmokD1eI9QOz3 N37o35WL4IRuNiBRBkTWypqRrO9eC/YfW2kPj8AvTL3yVBhzqteSVJ0Q3hpHv/vgAV/S b98Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=rZzys5P5Qb9qUuQqIYkm3GUlaA9bioDy/ONdg5vGU6M=; b=S8oVqubYCkwIJF6cqQyoFxR5XprSaz0D+8YVUposkkeh1sPE3uNXqSAribctBZ2uYZ XwOwvDBQpHo6yUd1Fzq3zHgf12ZrirQhTxeSiNE6DRgkmc61Z8liZWdi35FPuSsYfHWG ATBYEzl/nRfNpJichaHez1gr1c3j9G0Ih0GpRmk685hLOAhVwSFg3FjDtYYBDcedoooo 0//k+HWZ1s+uvNYeDzKTuBxtnr4UlTUz+VGS7ykbpPbCoNlWuTikxQ8Qe2jihGKefqau rW22lvO4g6RH+s4ho6aSbsy6DLFV0vNaXRYECIT62Al6vwIYmHUlT3llyFb7M81kWaFv lkkw== X-Gm-Message-State: AHPjjUhhwSo8r9bt7H12PnAnHjOBW72CWZEALSQ/4YFO+xv9gjnPbL8l fsUzHQGY1juxnvQtcHBn5IWNaVYonUiTxA== X-Google-Smtp-Source: AOwi7QCFl2fhyLvbZr3uZ5pUpHTu6x6gsoIccnGm/9JBl/CxwSP/ACmTdeEAOAbkU0nna0W26zTCvg== X-Received: by 10.99.3.208 with SMTP id 199mr10116809pgd.111.1506404419338; Mon, 25 Sep 2017 22:40:19 -0700 (PDT) Received: from localhost.localdomain ([101.228.205.132]) by smtp.gmail.com with ESMTPSA id o79sm13180077pfi.108.2017.09.25.22.40.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Sep 2017 22:40:17 -0700 (PDT) From: Yuanhan Liu To: dev@openvswitch.org Date: Tue, 26 Sep 2017 13:36:36 +0800 Message-Id: <1506404199-23579-7-git-send-email-yliu@fridaylinux.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> References: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> X-Spam-Status: No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Simon Horman Subject: [ovs-dev] [PATCH v3 6/9] netdev-dpdk: retry with queue action X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org From: Finn Christensen AFAIK, most (if not all) NICs (including Mellanox and Intel) do not support a pure MARK action. It's required to be used together with some other actions, like QUEUE. To workaround it, retry with a queue action when first try failed. Moreover, some Intel's NIC (say XL710) needs the QUEUE action set before the MARK action. Co-authored-by: Yuanhan Liu Signed-off-by: Finn Christensen Signed-off-by: Yuanhan Liu --- v3: - retry when 2 specific errors are met v2: - workarounded the queue action issue, which sets the queue index to 0 blindly. - added some comments regarding to the retry with queue action --- lib/netdev-dpdk.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index 525536a..3e2b96b 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -3324,6 +3324,7 @@ static struct ovs_mutex ufid_lock = OVS_MUTEX_INITIALIZER; struct ufid_dpdk_flow_data { struct hmap_node node; ovs_u128 ufid; + int rxq; struct rte_flow *rte_flow; }; @@ -3369,7 +3370,8 @@ del_ufid_dpdk_flow_mapping(const ovs_u128 *ufid) /* Add ufid to dpdk_flow mapping */ static inline void -add_ufid_dpdk_flow_mapping(const ovs_u128 *ufid, struct rte_flow *rte_flow) +add_ufid_dpdk_flow_mapping(const ovs_u128 *ufid, struct rte_flow *rte_flow, + int rxq) { size_t hash = hash_bytes(ufid, sizeof(*ufid), 0); struct ufid_dpdk_flow_data *data = xzalloc(sizeof(*data)); @@ -3384,6 +3386,7 @@ add_ufid_dpdk_flow_mapping(const ovs_u128 *ufid, struct rte_flow *rte_flow) data->ufid = *ufid; data->rte_flow = rte_flow; + data->rxq = rxq; ovs_mutex_lock(&ufid_lock); hmap_insert(&ufid_dpdk_flow, &data->node, hash); @@ -3665,15 +3668,55 @@ netdev_dpdk_add_rte_flow_offload(struct netdev *netdev, add_flow_action(&actions, RTE_FLOW_ACTION_TYPE_MARK, &mark); add_flow_action(&actions, RTE_FLOW_ACTION_TYPE_END, NULL); + bool tried = 0; + struct rte_flow_action_queue queue; +again: flow = rte_flow_create(dev->port_id, &flow_attr, patterns.items, actions.actions, &error); - if (!flow) { + if (!flow && !tried && + (error.type == RTE_FLOW_ERROR_TYPE_ACTION || + error.type == RTE_FLOW_ERROR_TYPE_HANDLE)) { + /* + * Seems most (if not all) NICs do not support a pure MARK + * action. It's required to be used together with some other + * actions, such as QUEUE. + * + * Thus, if flow creation fails (more precisely, if above 2 + * errors are met), here we try again with QUEUE action. + * + * The reason why there are 2 error codes is DPDK drivers are + * not quite consistent on error report for this case. + */ + if (info->rxq < 0 || info->rxq >= netdev->n_rxq) { + VLOG_ERR("invalid queue index: %d\n", info->rxq); + ret = -1; + goto out; + } + queue.index = info->rxq; + + /* re-build the action */ + actions.cnt = 0; + /* + * NOTE: Intel PMD driver needs the QUEUE action set before + * the MARK action. + */ + add_flow_action(&actions, RTE_FLOW_ACTION_TYPE_QUEUE, &queue); + add_flow_action(&actions, RTE_FLOW_ACTION_TYPE_MARK, &mark); + add_flow_action(&actions, RTE_FLOW_ACTION_TYPE_END, NULL); + + VLOG_INFO("failed to create rte flow, " + "try again with QUEUE action (queue index = %d)\n", + info->rxq); + tried = true; + + goto again; + } else if (!flow) { VLOG_ERR("rte flow creat error: %u : message : %s\n", error.type, error.message); ret = -1; goto out; } - add_ufid_dpdk_flow_mapping(ufid, flow); + add_ufid_dpdk_flow_mapping(ufid, flow, info->rxq); VLOG_INFO("installed flow %p by ufid "UUID_FMT"\n", flow, UUID_ARGS((struct uuid *)ufid)); @@ -3807,17 +3850,23 @@ netdev_dpdk_flow_put(struct netdev *netdev, struct match *match, const ovs_u128 *ufid, struct offload_info *info, struct dpif_flow_stats *stats OVS_UNUSED) { - struct rte_flow *rte_flow; + struct ufid_dpdk_flow_data *flow_data; int ret; /* * If an old rte_flow exists, it means it's a flow modification. * Here destroy the old rte flow first before adding a new one. */ - rte_flow = get_rte_flow_by_ufid(ufid); - if (rte_flow) { + flow_data = find_ufid_dpdk_flow_mapping(ufid); + if (flow_data && flow_data->rte_flow) { + /* + * there is no rxq given for flow modification. Instead, we + * retrieve it from the rxq firstly registered here (by flow + * add operation). + */ + info->rxq = flow_data->rxq; ret = netdev_dpdk_destroy_rte_flow(netdev_dpdk_cast(netdev), - ufid, rte_flow); + ufid, flow_data->rte_flow); if (ret < 0) { return ret; } From patchwork Tue Sep 26 05:36:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuanhan Liu X-Patchwork-Id: 818463 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=fridaylinux-org.20150623.gappssmtp.com header.i=@fridaylinux-org.20150623.gappssmtp.com header.b="zJEalViS"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y1VH920Gmz9t30 for ; Tue, 26 Sep 2017 15:43:17 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id A841DBED; Tue, 26 Sep 2017 05:40:33 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 8C822BEA for ; Tue, 26 Sep 2017 05:40:32 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f172.google.com (mail-pf0-f172.google.com [209.85.192.172]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 26AD93D4 for ; Tue, 26 Sep 2017 05:40:32 +0000 (UTC) Received: by mail-pf0-f172.google.com with SMTP id x78so5028568pff.10 for ; Mon, 25 Sep 2017 22:40:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fridaylinux-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=8IuJSwyzAF/5D3NKQtPLOn/Zzq6urWYztIzVW4cPzIM=; b=zJEalViSdmAuDGxsVXQ/HnWIqSASLKmbQSn44enyJY4ZFojnksjhKRP7YfPk58+Jhb nfNG0S9sBL/sBXSQQkXQuJUdQVAkl1VlKKiWJ3TRJf1vqxIVz4Dj+b9mmBvNaoweHtRp RyLqGMW8om2IBPEs8c+o7u7RLZWQZrc4CVaVt2UoddtUWeyqEboYqkBlzkqy9VHqJ/Et cM4mvm1Ds9kwumBrAy4nhoNogs2W9wrxu94Y3vDAm/jeoFHq9XIdYZPvk+HOfpw8BZ6U qj7ecQCfSWPaQTERtdE9Cog5ykDx85ykwWdbt6vUrONvMLKxsZu+S4VhY9ZFbAaCsBmD 94ug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=8IuJSwyzAF/5D3NKQtPLOn/Zzq6urWYztIzVW4cPzIM=; b=amSmX+pcYhrTPz1SpovUw97OXnBGk6QBnPG4DiCyRfmof64iJnMIybBG3PsmD1e4+a oHTVjXbjGdzMRVkRmts2bWxFvZ3uuP0Oyd0dFMVABUFDw8riuC7L7uEQiLIT8NqbW6YJ vPYjYCF9CituS3dRFwk9+uAo1tYKXs1mvW/qmpK9mnMkss9TqcI/Kfxy3g0DgI2Jv6MH ZxIGYiO0/H2C/nEf1+qx3aWYKLuXjhZZcvSfz0ZEIIWoZA0Xqxsz1orXuEb/zEDEqjrE nm2e6DS+Lyai1xXcwt9ZsqIT8VMH/W6ZhR0YIWOSEhvLvkoFx6DrdhhEWLiPRaXUqiLO qCLA== X-Gm-Message-State: AHPjjUhURm+3054okBxHO2P+qvARCtIq53C8bAGLW7FZJzQ1VuHEVG5x ICv3bID6a4+7RI6icFXPe9VmhZVjkXX3uQ== X-Google-Smtp-Source: AOwi7QD4xCySTFSIaC3jdKnLhogxFgjYIJ6aC1KHQtnraUMz+Xvi1juRhswd7h1p7ZH9D2Ct90GtAA== X-Received: by 10.99.121.135 with SMTP id u129mr10098233pgc.260.1506404431367; Mon, 25 Sep 2017 22:40:31 -0700 (PDT) Received: from localhost.localdomain ([101.228.205.132]) by smtp.gmail.com with ESMTPSA id o79sm13180077pfi.108.2017.09.25.22.40.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Sep 2017 22:40:30 -0700 (PDT) From: Yuanhan Liu To: dev@openvswitch.org Date: Tue, 26 Sep 2017 13:36:37 +0800 Message-Id: <1506404199-23579-8-git-send-email-yliu@fridaylinux.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> References: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> X-Spam-Status: No, score=0.5 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Simon Horman Subject: [ovs-dev] [PATCH v3 7/9] netdev-dpdk: remove offloaded flow on deletion X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Inovke netdev class '->flow_del' method on flow deletion. The dpdk netdev implementation will then remove the rte flow associated with the ufid. Co-authored-by: Finn Christensen Signed-off-by: Yuanhan Liu Signed-off-by: Finn Christensen --- v2: - check the returned "port" from dp_netdev_lookup_port - error log when flow is not found --- lib/dpif-netdev.c | 6 ++++++ lib/netdev-dpdk.c | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 1a70af6..13fd012 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1964,6 +1964,12 @@ dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, dpcls_remove(cls, &flow->cr); cmap_remove(&pmd->flow_table, node, dp_netdev_flow_hash(&flow->ufid)); if (flow->has_mark) { + struct dp_netdev_port *port; + + port = dp_netdev_lookup_port(pmd->dp, in_port); + if (port) { + netdev_flow_del(port->netdev, &flow->ufid, NULL); + } dp_netdev_remove_flow_mark_map(flow->mark); flow->has_mark = false; } diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index 3e2b96b..02c3677 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -3881,6 +3881,23 @@ netdev_dpdk_flow_put(struct netdev *netdev, struct match *match, actions_len, ufid, info); } +static int +netdev_dpdk_flow_del(struct netdev *netdev, const ovs_u128 *ufid, + struct dpif_flow_stats *stats OVS_UNUSED) +{ + + struct rte_flow *rte_flow = get_rte_flow_by_ufid(ufid); + + if (!rte_flow) { + VLOG_ERR("failed to find flow associated with ufid " UUID_FMT "\n", + UUID_ARGS((struct uuid *)ufid)); + return -1; + } + + return netdev_dpdk_destroy_rte_flow(netdev_dpdk_cast(netdev), + ufid, rte_flow); +} + #define DPDK_FLOW_OFFLOAD_API \ NULL, /* flow_flush */ \ NULL, /* flow_dump_create */ \ @@ -3888,7 +3905,7 @@ netdev_dpdk_flow_put(struct netdev *netdev, struct match *match, NULL, /* flow_dump_next */ \ netdev_dpdk_flow_put, \ NULL, /* flow_get */ \ - NULL, /* flow_del */ \ + netdev_dpdk_flow_del, \ NULL /* init_flow_api */ From patchwork Tue Sep 26 05:36:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuanhan Liu X-Patchwork-Id: 818464 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=fridaylinux-org.20150623.gappssmtp.com header.i=@fridaylinux-org.20150623.gappssmtp.com header.b="sh/zqera"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y1VHx1brgz9t30 for ; Tue, 26 Sep 2017 15:43:57 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 9CEEBC0D; Tue, 26 Sep 2017 05:40:44 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id F1291AB9 for ; Tue, 26 Sep 2017 05:40:43 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f179.google.com (mail-pf0-f179.google.com [209.85.192.179]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 5043A367 for ; Tue, 26 Sep 2017 05:40:43 +0000 (UTC) Received: by mail-pf0-f179.google.com with SMTP id m63so5038410pfk.7 for ; Mon, 25 Sep 2017 22:40:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fridaylinux-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=eD5JKmVjWaJIytIv7Spg+jRu1XQO/2O5LsmidoH+dto=; b=sh/zqerazyJjfDmGZpvIoiTDEUEt5FKDiA43b139Wi9O+qMRWBZclU5q9ISMhfVvCy Djnbg39SeSAwhZMSZUqttiDDyaF+e//8M4XgXPo/zrnh+Q1EFgwk7CN8JiMAx5lyEUM1 w3etdEaU/Hb1SogguTtoODKCN5KFfdQNiGl/4ZtwF6P4q61qraEUBL2vFQC9rpw05WrN YMmBkjuiHHzUNJ5Y+BfUPjqV7MihZyZhZY00CClqLrveWqIijH6vIRC453YGOlv6e/8j L65UurbMxUmYvyr7+7BNIxu34nPgccNk2CxpwfIxlfMwy23m/BK3zh+Tr7Rqv+8tkNV5 b99g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=eD5JKmVjWaJIytIv7Spg+jRu1XQO/2O5LsmidoH+dto=; b=tia+AgV4As32zLmBVDTqDYPBR8uoBrRZN1XmUSrY1XDfURhXuhqhwCHgepX9die6gQ UWLTy1R4JXeuvcR9gjN3kOzN+l5TuHFeqcmXGHLb/MU7zyFTKFjTuXjCoK+ie811r5LE OqxICbr105nnO77rncnQJKTc9ivC1SYjXWclDgBYFI8iknItyhehAgouWTdZTnzoSqvJ gAMC2te9MM8G1WEjcwQh7OHn3e3nl0o1+9SKOu6a9YK4m76tjJlOcFKsSw4vKmVnNSRk g+rHtHK9z3254wVgbROUHcOHD+fBrwKV/8Wnr8PoxrDP2h4gVc425+NwkioNMK6Ytf/y 4SjA== X-Gm-Message-State: AHPjjUjmcx8D0rKHOV8g3bxRceAi3Ozny+ei0sRxxliBOzVHTHqBOoSP iyBzcjWRDNHS9+eWGEfb2dsT3VNC3AJxdQ== X-Google-Smtp-Source: AOwi7QCEC2COWQq7HRqKq1dZkN617IxZq44l/QHuZs2lLoiNSNdGBJQpKpEVGWfVU7FgPMplOgBiuA== X-Received: by 10.84.160.204 with SMTP id v12mr9646863plg.382.1506404442552; Mon, 25 Sep 2017 22:40:42 -0700 (PDT) Received: from localhost.localdomain ([101.228.205.132]) by smtp.gmail.com with ESMTPSA id o79sm13180077pfi.108.2017.09.25.22.40.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Sep 2017 22:40:41 -0700 (PDT) From: Yuanhan Liu To: dev@openvswitch.org Date: Tue, 26 Sep 2017 13:36:38 +0800 Message-Id: <1506404199-23579-9-git-send-email-yliu@fridaylinux.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> References: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> X-Spam-Status: No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Simon Horman Subject: [ovs-dev] [PATCH v3 8/9] netdev-dpdk: add debug for rte flow patterns X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org The log level will be set to DBG when this patchset is close to being merged. Co-authored-by: Finn Christensen Signed-off-by: Yuanhan Liu Signed-off-by: Finn Christensen --- lib/netdev-dpdk.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index 02c3677..80fd64b 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -3420,6 +3420,182 @@ struct flow_actions { }; static void +dump_flow_pattern(struct rte_flow_item *item) +{ + if (item->type == RTE_FLOW_ITEM_TYPE_ETH) { + const struct rte_flow_item_eth *eth_spec = item->spec; + const struct rte_flow_item_eth *eth_mask = item->mask; + + VLOG_INFO("rte flow eth pattern:\n"); + if (eth_spec) { + VLOG_INFO("spec: src="ETH_ADDR_FMT", dst="ETH_ADDR_FMT", " + "type=0x%04" PRIx16"\n", + eth_spec->src.addr_bytes[0], eth_spec->src.addr_bytes[1], + eth_spec->src.addr_bytes[2], eth_spec->src.addr_bytes[3], + eth_spec->src.addr_bytes[4], eth_spec->src.addr_bytes[5], + eth_spec->dst.addr_bytes[0], eth_spec->dst.addr_bytes[1], + eth_spec->dst.addr_bytes[2], eth_spec->dst.addr_bytes[3], + eth_spec->dst.addr_bytes[4], eth_spec->dst.addr_bytes[5], + ntohs(eth_spec->type)); + } else { + VLOG_INFO("spec = null\n"); + } + if (eth_mask) { + VLOG_INFO("mask: src="ETH_ADDR_FMT", dst="ETH_ADDR_FMT", " + "type=0x%04"PRIx16"\n", + eth_mask->src.addr_bytes[0], eth_mask->src.addr_bytes[1], + eth_mask->src.addr_bytes[2], eth_mask->src.addr_bytes[3], + eth_mask->src.addr_bytes[4], eth_mask->src.addr_bytes[5], + eth_mask->dst.addr_bytes[0], eth_mask->dst.addr_bytes[1], + eth_mask->dst.addr_bytes[2], eth_mask->dst.addr_bytes[3], + eth_mask->dst.addr_bytes[4], eth_mask->dst.addr_bytes[5], + eth_mask->type); + } else { + VLOG_INFO("mask = null\n"); + } + } + + if (item->type == RTE_FLOW_ITEM_TYPE_VLAN) { + const struct rte_flow_item_vlan *vlan_spec = item->spec; + const struct rte_flow_item_vlan *vlan_mask = item->mask; + + VLOG_INFO("rte flow vlan pattern:\n"); + if (vlan_spec) { + VLOG_INFO("spec: tpid=0x%"PRIx16", tci=0x%"PRIx16"\n", + ntohs(vlan_spec->tpid), ntohs(vlan_spec->tci)); + } else { + VLOG_INFO("spec = null\n"); + } + + if (vlan_mask) { + VLOG_INFO("mask: tpid=0x%"PRIx16", tci=0x%"PRIx16"\n", + vlan_mask->tpid, vlan_mask->tci); + } else { + VLOG_INFO("mask = null\n"); + } + } + + if (item->type == RTE_FLOW_ITEM_TYPE_IPV4) { + const struct rte_flow_item_ipv4 *ipv4_spec = item->spec; + const struct rte_flow_item_ipv4 *ipv4_mask = item->mask; + + VLOG_INFO("rte flow ipv4 pattern:\n"); + if (ipv4_spec) { + VLOG_INFO("spec: tos=0x%"PRIx8", ttl=%"PRIx8", proto=0x%"PRIx8 + ", src="IP_FMT", dst="IP_FMT"\n", + ipv4_spec->hdr.type_of_service, + ipv4_spec->hdr.time_to_live, + ipv4_spec->hdr.next_proto_id, + IP_ARGS(ipv4_spec->hdr.src_addr), + IP_ARGS(ipv4_spec->hdr.dst_addr)); + } else { + VLOG_INFO("spec = null\n"); + } + if (ipv4_mask) { + VLOG_INFO("mask: tos=0x%"PRIx8", ttl=%"PRIx8", proto=0x%"PRIx8 + ", src="IP_FMT", dst="IP_FMT"\n", + ipv4_mask->hdr.type_of_service, + ipv4_mask->hdr.time_to_live, + ipv4_mask->hdr.next_proto_id, + IP_ARGS(ipv4_mask->hdr.src_addr), + IP_ARGS(ipv4_mask->hdr.dst_addr)); + } else { + VLOG_INFO("mask = null\n"); + } + } + + if (item->type == RTE_FLOW_ITEM_TYPE_UDP) { + const struct rte_flow_item_udp *udp_spec = item->spec; + const struct rte_flow_item_udp *udp_mask = item->mask; + + VLOG_INFO("rte flow udp pattern:\n"); + if (udp_spec) { + VLOG_INFO("spec: src_port=%"PRIu16", dst_port=%"PRIu16"\n", + ntohs(udp_spec->hdr.src_port), + ntohs(udp_spec->hdr.dst_port)); + } else { + VLOG_INFO("spec = null\n"); + } + if (udp_mask) { + VLOG_INFO("mask: src_port=0x%"PRIx16", dst_port=0x%"PRIx16"\n", + udp_mask->hdr.src_port, + udp_mask->hdr.dst_port); + } else { + VLOG_INFO("mask = null\n"); + } + } + + if (item->type == RTE_FLOW_ITEM_TYPE_SCTP) { + const struct rte_flow_item_sctp *sctp_spec = item->spec; + const struct rte_flow_item_sctp *sctp_mask = item->mask; + + VLOG_INFO("rte flow sctp pattern:\n"); + if (sctp_spec) { + VLOG_INFO("spec: src_port=%"PRIu16", dst_port=%"PRIu16"\n", + ntohs(sctp_spec->hdr.src_port), + ntohs(sctp_spec->hdr.dst_port)); + } else { + VLOG_INFO("spec = null\n"); + } + if (sctp_mask) { + VLOG_INFO("mask: src_port=0x%"PRIx16", dst_port=0x%"PRIx16"\n", + sctp_mask->hdr.src_port, + sctp_mask->hdr.dst_port); + } else { + VLOG_INFO("mask = null\n"); + } + } + + if (item->type == RTE_FLOW_ITEM_TYPE_ICMP) { + const struct rte_flow_item_icmp *icmp_spec = item->spec; + const struct rte_flow_item_icmp *icmp_mask = item->mask; + + VLOG_INFO("rte flow icmp pattern:\n"); + if (icmp_spec) { + VLOG_INFO("spec: icmp_type=%"PRIu8", icmp_code=%"PRIu8"\n", + ntohs(icmp_spec->hdr.icmp_type), + ntohs(icmp_spec->hdr.icmp_code)); + } else { + VLOG_INFO("spec = null\n"); + } + if (icmp_mask) { + VLOG_INFO("mask: icmp_type=0x%"PRIx8", icmp_code=0x%"PRIx8"\n", + icmp_spec->hdr.icmp_type, + icmp_spec->hdr.icmp_code); + } else { + VLOG_INFO("mask = null\n"); + } + } + + if (item->type == RTE_FLOW_ITEM_TYPE_TCP) { + const struct rte_flow_item_tcp *tcp_spec = item->spec; + const struct rte_flow_item_tcp *tcp_mask = item->mask; + + VLOG_INFO("rte flow tcp pattern:\n"); + if (tcp_spec) { + VLOG_INFO("spec: src_port=%"PRIu16", dst_port=%"PRIu16 + ", data_off=0x%"PRIx8", tcp_flags=0x%"PRIx8"\n", + ntohs(tcp_spec->hdr.src_port), + ntohs(tcp_spec->hdr.dst_port), + tcp_spec->hdr.data_off, + tcp_spec->hdr.tcp_flags); + } else { + VLOG_INFO("spec = null\n"); + } + if (tcp_mask) { + VLOG_INFO("mask: src_port=%"PRIx16", dst_port=%"PRIx16 + ", data_off=0x%"PRIx8", tcp_flags=0x%"PRIx8"\n", + tcp_mask->hdr.src_port, + tcp_mask->hdr.dst_port, + tcp_mask->hdr.data_off, + tcp_mask->hdr.tcp_flags); + } else { + VLOG_INFO("mask = null\n"); + } + } +} + +static void add_flow_pattern(struct flow_patterns *patterns, enum rte_flow_item_type type, const void *spec, const void *mask) { @@ -3438,6 +3614,7 @@ add_flow_pattern(struct flow_patterns *patterns, enum rte_flow_item_type type, patterns->items[cnt].spec = spec; patterns->items[cnt].mask = mask; patterns->items[cnt].last = NULL; + dump_flow_pattern(&patterns->items[cnt]); patterns->cnt++; } From patchwork Tue Sep 26 05:36:39 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuanhan Liu X-Patchwork-Id: 818465 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=fridaylinux-org.20150623.gappssmtp.com header.i=@fridaylinux-org.20150623.gappssmtp.com header.b="yRKUStA7"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y1VJv74N9z9t1t for ; Tue, 26 Sep 2017 15:44:47 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id A23B7C09; Tue, 26 Sep 2017 05:40:55 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 519C9BEA for ; Tue, 26 Sep 2017 05:40:54 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f43.google.com (mail-pg0-f43.google.com [74.125.83.43]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 85C95367 for ; Tue, 26 Sep 2017 05:40:53 +0000 (UTC) Received: by mail-pg0-f43.google.com with SMTP id 7so5351569pgd.13 for ; Mon, 25 Sep 2017 22:40:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fridaylinux-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=St7axmU79AXmtWRugAfa/hkjJQFBa8Jlx0AsVRSFMWw=; b=yRKUStA7UYwYjAL6NlaeQkHBsr8ruquHPM3LVpo6X1SuCWRHcpeHc4JgtniJg1yA3L NycDYTSm/h9PkCW/XAXWILjTv4CC930tcCxVKcMyRkzOH5kxB8aUNgFFWyMkWDwamrwF gbSLHaJFeFGe23v58kGNkxJp/zLnYJKWiszGqf8MguPaDBhadg180ZQbFINJf6Km9xLg mS6ZmcS5yQW52XJk3D/M0BlXgftC2rMpaeYYa4j9XyHWEdmZGUKL9TUppjVOw0HTmUhh LeJflNWyW6XSXaF5CnZpZs4i5J3XBDrB3RLLYsYiDvnDWoI8d2RBB1hGC00U3tOd6N1H EFIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=St7axmU79AXmtWRugAfa/hkjJQFBa8Jlx0AsVRSFMWw=; b=Bz8q7DB5QkNhLlhO4hjM2W/vekDh/FImbmoI6aDT7eb27dDWwitH+NPXDnVIKWOROx uiEZp81CO+kqO4XPouCiWaUqSBxX4mHWCqAYEMwvTfKxIvi+C2Sqrv6W8N2Tegql/4XQ eU/wuoYX3/ML64guBokPKnpt3d7irT1uCqsdWiGZuoa/rdC+vwpnLviRV8qWRVVrmPWh Xqrnt7NGS5vf1NLFSlQ1qcr2ayMUBZXTH4eEHN8foUl0z/ACgRGImB9RvZVse4cNEkgn M9/lEWaPIOrPIcLMDFtXJENIorGhXU7Ltu2VXO10zvmMiyg80AbNlovZ1A/8fxWWzlLM 3r7A== X-Gm-Message-State: AHPjjUgGvdgQbpdcSePWZXzm+/oRBUijQJefpgE3tOvFceug7JFYeI93 QF9LQ8nkSmGEAOll4vPQNYK+FpOkL7DQOw== X-Google-Smtp-Source: AOwi7QCoMsqTpaBM+3BE1WfFRd+qDoQfIryAPLJS5NTlBgtFhf8RZYDGSph0l6HUVrONL2cPIA5iCw== X-Received: by 10.99.114.19 with SMTP id n19mr9516237pgc.300.1506404452750; Mon, 25 Sep 2017 22:40:52 -0700 (PDT) Received: from localhost.localdomain ([101.228.205.132]) by smtp.gmail.com with ESMTPSA id o79sm13180077pfi.108.2017.09.25.22.40.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 25 Sep 2017 22:40:51 -0700 (PDT) From: Yuanhan Liu To: dev@openvswitch.org Date: Tue, 26 Sep 2017 13:36:39 +0800 Message-Id: <1506404199-23579-10-git-send-email-yliu@fridaylinux.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> References: <1506404199-23579-1-git-send-email-yliu@fridaylinux.org> X-Spam-Status: No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Simon Horman Subject: [ovs-dev] [PATCH v3 9/9] dpif-netdev: do hw flow offload in another thread X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Currently, the major trigger for hw flow offload is at upcall handling, which is actually in the datapath. Moreover, the hw offload installation and modification is not that lightweight. Meaning, if there are so many flows being added or modified frequently, it could stall the datapath, which could result to packet loss. To diminish that, all those flow operations will be recorded and appended to a list. A thread is then introduced to process this list (to do the real flow offloading put/del operations). This could leave the datapath as lightweight as possible. Signed-off-by: Yuanhan Liu --- lib/dpif-netdev.c | 301 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 249 insertions(+), 52 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 13fd012..ef5c2e9 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1949,6 +1949,223 @@ dp_netdev_pmd_find_flow_by_mark(const uint32_t mark) return NULL; } +struct dp_flow_offload_item { + struct dp_netdev_pmd_thread *pmd; + odp_port_t in_port; + struct dp_netdev_flow *flow; + ovs_u128 ufid; + int op; + struct match match; + struct nlattr *actions; + size_t actions_len; + int rxq; + uint32_t flow_mark; + + struct ovs_list node; +}; + +struct dp_flow_offload { + struct ovs_mutex mutex; + struct ovs_list list; + pthread_cond_t cond; +}; + +static struct dp_flow_offload dp_flow_offload = { + .mutex = OVS_MUTEX_INITIALIZER, + .list = OVS_LIST_INITIALIZER(&dp_flow_offload.list), +}; + +static struct ovsthread_once offload_thread_once + = OVSTHREAD_ONCE_INITIALIZER; + +enum { + DP_NETDEV_FLOW_OFFLOAD_OP_ADD, + DP_NETDEV_FLOW_OFFLOAD_OP_MOD, + DP_NETDEV_FLOW_OFFLOAD_OP_DEL, +}; + +static struct dp_flow_offload_item * +dp_netdev_alloc_flow_offload(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_flow *flow, + odp_port_t in_port, const ovs_u128 *ufid, + int op) +{ + struct dp_flow_offload_item *offload; + + offload = xzalloc(sizeof(*offload)); + offload->pmd = pmd; + offload->flow = flow; + offload->in_port = in_port; + offload->ufid = *ufid; + offload->op = op; + + ovs_refcount_ref(&pmd->ref_cnt); + ovs_refcount_ref(&flow->ref_cnt); + + return offload; +} + +static void +dp_netdev_free_flow_offload(struct dp_flow_offload_item *offload) +{ + ovs_refcount_unref(&offload->pmd->ref_cnt); + ovs_refcount_unref(&offload->flow->ref_cnt); + + free(offload->actions); + free(offload); +} + +static void +dp_netdev_append_flow_offload(struct dp_flow_offload_item *offload) +{ + ovs_mutex_lock(&dp_flow_offload.mutex); + ovs_list_push_back(&dp_flow_offload.list, &offload->node); + ovs_mutex_unlock(&dp_flow_offload.mutex); + + pthread_cond_signal(&dp_flow_offload.cond); +} + +static int +dp_netdev_flow_offload_del(struct dp_flow_offload_item *offload) +{ + struct dp_netdev_flow *flow = offload->flow; + struct dp_netdev_port *port; + int ret = -1; + + ovs_mutex_lock(&offload->pmd->flow_mutex); + port = dp_netdev_lookup_port(offload->pmd->dp, offload->in_port); + if (flow->has_mark && port) { + ret = netdev_flow_del(port->netdev, &offload->ufid, NULL); + } + + dp_netdev_remove_flow_mark_map(flow->mark); + ovsrcu_quiesce_start(); + flow->has_mark = false; + ovs_mutex_unlock(&offload->pmd->flow_mutex); + + return ret; +} + +static int +dp_netdev_flow_offload_put(struct dp_flow_offload_item *offload) +{ + struct dp_netdev_port *port; + struct dp_netdev_flow *flow = offload->flow; + bool create = offload->op == DP_NETDEV_FLOW_OFFLOAD_OP_ADD; + struct offload_info info; + int ret; + + port = dp_netdev_lookup_port(offload->pmd->dp, offload->in_port); + if (!port) { + return -1; + } + + if (create) { + if (!dp_netdev_alloc_flow_mark(&info.flow_mark)) { + VLOG_ERR("failed to allocate flow mark!\n"); + return -1; + } + offload->flow_mark = info.flow_mark; + } else { + info.flow_mark = offload->flow_mark; + } + info.rxq = offload->rxq; + + ret = netdev_flow_put(port->netdev, &offload->match, + offload->actions, offload->actions_len, + &offload->ufid, &info, NULL); + if (ret) { + if (create) { + dp_netdev_remove_flow_mark_map(info.flow_mark); + } + return ret; + } + + ovs_mutex_lock(&offload->pmd->flow_mutex); + if (create) { + flow->has_mark = true; + flow->mark = info.flow_mark; + if (!flow->dead) { + /* + * A flow could have been dead after we regain the lock, + * while the flow has offloaded to the netdev. When that + * happens, there should be an offload item in the offload + * list for the flow removal. To make sure the flow will + * be deleted successfully later, above 2 fields (has_mark + * and mark) have to be set properly. + */ + dp_netdev_install_flow_mark_map(flow->mark, flow); + ovsrcu_quiesce_start(); + } + } + ovs_mutex_unlock(&offload->pmd->flow_mutex); + + return 0; +} + +static void * +dp_netdev_flow_offload_main(void *data OVS_UNUSED) +{ + struct dp_flow_offload_item *offload; + struct ovs_list *list; + const char *op; + int ret; + + for (;;) { + ovs_mutex_lock(&dp_flow_offload.mutex); + if (ovs_list_is_empty(&dp_flow_offload.list)) { + pthread_cond_wait(&dp_flow_offload.cond, + &dp_flow_offload.mutex.lock); + } + list = ovs_list_pop_front(&dp_flow_offload.list); + offload = CONTAINER_OF(list, struct dp_flow_offload_item, node); + ovs_mutex_unlock(&dp_flow_offload.mutex); + + switch (offload->op) { + case DP_NETDEV_FLOW_OFFLOAD_OP_ADD: + op = "install"; + ret = dp_netdev_flow_offload_put(offload); + break; + case DP_NETDEV_FLOW_OFFLOAD_OP_MOD: + op = "modify"; + ret = dp_netdev_flow_offload_put(offload); + break; + case DP_NETDEV_FLOW_OFFLOAD_OP_DEL: + op = "delete"; + ret = dp_netdev_flow_offload_del(offload); + break; + default: + OVS_NOT_REACHED(); + } + + VLOG_INFO("%s to %s netdev flow with mark %u\n", + ret == 0 ? "succeed" : "failed", + op, offload->flow_mark); + dp_netdev_free_flow_offload(offload); + } + + return NULL; +} + +static void +queue_netdev_flow_del(struct dp_netdev_pmd_thread *pmd, + struct dp_netdev_flow *flow, + odp_port_t in_port, const ovs_u128 *ufid, + int op) +{ + struct dp_flow_offload_item *offload; + + if (ovsthread_once_start(&offload_thread_once)) { + pthread_cond_init(&dp_flow_offload.cond, NULL); + ovs_thread_create("dp_netdev_flow_offload", + dp_netdev_flow_offload_main, NULL); + ovsthread_once_done(&offload_thread_once); + } + + offload = dp_netdev_alloc_flow_offload(pmd, flow, in_port, ufid, op); + offload->flow_mark = flow->mark; + dp_netdev_append_flow_offload(offload); +} static void dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, @@ -1963,16 +2180,8 @@ dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd, ovs_assert(cls != NULL); dpcls_remove(cls, &flow->cr); cmap_remove(&pmd->flow_table, node, dp_netdev_flow_hash(&flow->ufid)); - if (flow->has_mark) { - struct dp_netdev_port *port; - - port = dp_netdev_lookup_port(pmd->dp, in_port); - if (port) { - netdev_flow_del(port->netdev, &flow->ufid, NULL); - } - dp_netdev_remove_flow_mark_map(flow->mark); - flow->has_mark = false; - } + queue_netdev_flow_del(pmd, flow, in_port, &flow->ufid, + DP_NETDEV_FLOW_OFFLOAD_OP_DEL); flow->dead = true; dp_netdev_flow_unref(flow); @@ -2553,53 +2762,41 @@ out: } static void -try_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, odp_port_t in_port, - struct dp_netdev_flow *flow, struct match *match, - const ovs_u128 *ufid, const struct nlattr *actions, - size_t actions_len, int rxq) +queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd, odp_port_t in_port, + struct dp_netdev_flow *flow, struct match *match, + const ovs_u128 *ufid, const struct nlattr *actions, + size_t actions_len, int rxq) { - struct offload_info info; - struct dp_netdev_port *port; - bool modification = flow->has_mark; - const char *op = modification ? "modify" : "install"; - int ret; + struct dp_flow_offload_item *offload; + int op; - port = dp_netdev_lookup_port(pmd->dp, in_port); - if (!port) { + if (!netdev_is_flow_api_enabled()) { return; } - info.rxq = rxq; - - if (modification) { - info.flow_mark = flow->mark; - } else { - if (!netdev_is_flow_api_enabled()) { - return; - } - - if (!dp_netdev_alloc_flow_mark(&info.flow_mark)) { - VLOG_ERR("failed to allocate flow mark!\n"); - return; - } - } - ret = netdev_flow_put(port->netdev, match, - CONST_CAST(struct nlattr *, actions), - actions_len, ufid, &info, NULL); - if (ret) { - VLOG_ERR("failed to %s netdev flow with mark %u\n", - op, info.flow_mark); - return; + if (ovsthread_once_start(&offload_thread_once)) { + pthread_cond_init(&dp_flow_offload.cond, NULL); + ovs_thread_create("dp_netdev_flow_offload", + dp_netdev_flow_offload_main, NULL); + ovsthread_once_done(&offload_thread_once); } - if (!modification) { - flow->has_mark = true; - flow->mark = info.flow_mark; - dp_netdev_install_flow_mark_map(info.flow_mark, flow); + if (flow->has_mark) { + op = DP_NETDEV_FLOW_OFFLOAD_OP_MOD; + } else { + op = DP_NETDEV_FLOW_OFFLOAD_OP_ADD; + } + offload = dp_netdev_alloc_flow_offload(pmd, flow, in_port, ufid, op); + offload->match = *match; + offload->rxq = rxq; + offload->actions = xmalloc(actions_len); + memcpy(offload->actions, actions, actions_len); + offload->actions_len = actions_len; + if (flow->has_mark) { + offload->flow_mark = flow->mark; } - VLOG_INFO("succeed to %s netdev flow with mark %u\n", - op, flow->mark); + dp_netdev_append_flow_offload(offload); } static struct dp_netdev_flow * @@ -2654,8 +2851,8 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, cmap_insert(&pmd->flow_table, CONST_CAST(struct cmap_node *, &flow->node), dp_netdev_flow_hash(&flow->ufid)); - try_netdev_flow_put(pmd, in_port, flow, match, ufid, - actions, actions_len, rxq); + queue_netdev_flow_put(pmd, in_port, flow, match, ufid, + actions, actions_len, rxq); if (OVS_UNLIKELY(!VLOG_DROP_DBG((&upcall_rl)))) { struct ds ds = DS_EMPTY_INITIALIZER; @@ -2745,8 +2942,8 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd, old_actions = dp_netdev_flow_get_actions(netdev_flow); ovsrcu_set(&netdev_flow->actions, new_actions); - try_netdev_flow_put(pmd, in_port, netdev_flow, match, ufid, - put->actions, put->actions_len, -1); + queue_netdev_flow_put(pmd, in_port, netdev_flow, match, ufid, + put->actions, put->actions_len, -1); if (stats) { get_dpif_flow_stats(netdev_flow, stats);