From patchwork Wed Nov 27 12:55:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201580 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=whitealder.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLNj45pPz9sT7 for ; Wed, 27 Nov 2019 23:55:49 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id C562387727; Wed, 27 Nov 2019 12:55:47 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id TNBgKUSRmKNm; Wed, 27 Nov 2019 12:55:43 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by whitealder.osuosl.org (Postfix) with ESMTP id DA3B3876B8; Wed, 27 Nov 2019 12:55:41 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C9506C1DE0; Wed, 27 Nov 2019 12:55:41 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 92136C0881 for ; Wed, 27 Nov 2019 12:55:37 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 8AF14882A3 for ; Wed, 27 Nov 2019 12:55:37 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id dUavWYCuPwbx for ; Wed, 27 Nov 2019 12:55:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id 7811B8829A for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:29 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRm016501; Wed, 27 Nov 2019 14:55:29 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:07 +0200 Message-Id: <20191127125516.5135-2-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 01/10] match: Add match_set_ct_zone_masked helper X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey Sets zone in match. Signed-off-by: Paul Blakey --- include/openvswitch/match.h | 2 ++ lib/match.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/openvswitch/match.h b/include/openvswitch/match.h index 05ecee7fc7cd..eeabd5f470a7 100644 --- a/include/openvswitch/match.h +++ b/include/openvswitch/match.h @@ -127,6 +127,8 @@ void match_set_pkt_mark_masked(struct match *, uint32_t pkt_mark, uint32_t mask) void match_set_ct_state(struct match *, uint32_t ct_state); void match_set_ct_state_masked(struct match *, uint32_t ct_state, uint32_t mask); void match_set_ct_zone(struct match *, uint16_t ct_zone); +void match_set_ct_zone_masked(struct match *match, uint16_t ct_zone, + uint16_t mask); void match_set_ct_mark(struct match *, uint32_t ct_mark); void match_set_ct_mark_masked(struct match *, uint32_t ct_mark, uint32_t mask); void match_set_ct_label(struct match *, ovs_u128 ct_label); diff --git a/lib/match.c b/lib/match.c index 052daee146f2..5415251741b4 100644 --- a/lib/match.c +++ b/lib/match.c @@ -417,8 +417,14 @@ match_set_ct_state_masked(struct match *match, uint32_t ct_state, uint32_t mask) void match_set_ct_zone(struct match *match, uint16_t ct_zone) { - match->flow.ct_zone = ct_zone; - match->wc.masks.ct_zone = UINT16_MAX; + match_set_ct_zone_masked(match, ct_zone, UINT16_MAX); +} + +void +match_set_ct_zone_masked(struct match *match, uint16_t ct_zone, uint16_t mask) +{ + match->flow.ct_zone = ct_zone & mask; + match->wc.masks.ct_zone = mask; } void From patchwork Wed Nov 27 12:55:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201579 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLNg5TSrz9sTB for ; Wed, 27 Nov 2019 23:55:47 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 8B285882D3; Wed, 27 Nov 2019 12:55:45 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id o9N9I+gHA4Oi; Wed, 27 Nov 2019 12:55:44 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id E3167882B1; Wed, 27 Nov 2019 12:55:44 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C7633C1DE0; Wed, 27 Nov 2019 12:55:44 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 565D5C0881 for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 3F2F88829A for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id nYzY5HcI7vif for ; Wed, 27 Nov 2019 12:55:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id 8146E8829F for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:29 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRn016501; Wed, 27 Nov 2019 14:55:29 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:08 +0200 Message-Id: <20191127125516.5135-3-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 02/10] compat: Add tc ct action and flower matches defines for older kernels X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey Update kernel UAPI to support conntrack matches, and the tc actions ct and goto chain. Signed-off-by: Paul Blakey --- include/linux/automake.mk | 3 ++- include/linux/pkt_cls.h | 46 +++++++++++++++++++++++++++++++++++++++++--- include/linux/tc_act/tc_ct.h | 41 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 include/linux/tc_act/tc_ct.h diff --git a/include/linux/automake.mk b/include/linux/automake.mk index c75918626043..8f063f482e15 100644 --- a/include/linux/automake.mk +++ b/include/linux/automake.mk @@ -6,4 +6,5 @@ noinst_HEADERS += \ include/linux/tc_act/tc_pedit.h \ include/linux/tc_act/tc_skbedit.h \ include/linux/tc_act/tc_tunnel_key.h \ - include/linux/tc_act/tc_vlan.h + include/linux/tc_act/tc_vlan.h \ + include/linux/tc_act/tc_ct.h diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 55f3ef17c521..b0a5ce8bec2d 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -44,7 +44,21 @@ enum { #define TC_ACT_QUEUED 5 #define TC_ACT_REPEAT 6 #define TC_ACT_REDIRECT 7 -#define TC_ACT_JUMP 0x10000000 + +/* There is a special kind of actions called "extended actions", + * which need a value parameter. These have a local opcode located in + * the highest nibble, starting from 1. The rest of the bits + * are used to carry the value. These two parts together make + * a combined opcode. + */ +#define __TC_ACT_EXT_SHIFT 28 +#define __TC_ACT_EXT(local) ((local) << __TC_ACT_EXT_SHIFT) +#define TC_ACT_EXT_VAL_MASK ((1 << __TC_ACT_EXT_SHIFT) - 1) +#define TC_ACT_EXT_CMP(combined, opcode) \ + (((combined) & (~TC_ACT_EXT_VAL_MASK)) == opcode) + +#define TC_ACT_JUMP __TC_ACT_EXT(1) +#define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2) struct tc_police { __u32 index; @@ -207,16 +221,42 @@ enum { TCA_FLOWER_KEY_CVLAN_PRIO, /* u8 */ TCA_FLOWER_KEY_CVLAN_ETH_TYPE, /* be16 */ - TCA_FLOWER_KEY_ENC_IP_TOS, /* u8 */ + TCA_FLOWER_KEY_ENC_IP_TOS, /* u8 */ TCA_FLOWER_KEY_ENC_IP_TOS_MASK, /* u8 */ - TCA_FLOWER_KEY_ENC_IP_TTL, /* u8 */ + TCA_FLOWER_KEY_ENC_IP_TTL, /* u8 */ TCA_FLOWER_KEY_ENC_IP_TTL_MASK, /* u8 */ + TCA_FLOWER_KEY_ENC_OPTS, TCA_FLOWER_KEY_ENC_OPTS_MASK, + TCA_FLOWER_IN_HW_COUNT, + + TCA_FLOWER_KEY_PORT_SRC_MIN, /* be16 */ + TCA_FLOWER_KEY_PORT_SRC_MAX, /* be16 */ + TCA_FLOWER_KEY_PORT_DST_MIN, /* be16 */ + TCA_FLOWER_KEY_PORT_DST_MAX, /* be16 */ + + TCA_FLOWER_KEY_CT_STATE, /* u16 */ + TCA_FLOWER_KEY_CT_STATE_MASK, /* u16 */ + TCA_FLOWER_KEY_CT_ZONE, /* u16 */ + TCA_FLOWER_KEY_CT_ZONE_MASK, /* u16 */ + TCA_FLOWER_KEY_CT_MARK, /* u32 */ + TCA_FLOWER_KEY_CT_MARK_MASK, /* u32 */ + TCA_FLOWER_KEY_CT_LABELS, /* u128 */ + TCA_FLOWER_KEY_CT_LABELS_MASK, /* u128 */ + __TCA_FLOWER_MAX, }; +#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) + +enum { + TCA_FLOWER_KEY_CT_FLAGS_NEW = 1 << 0, /* Beginning of a new connection. */ + TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED = 1 << 1, /* Part of an existing connection. */ + TCA_FLOWER_KEY_CT_FLAGS_RELATED = 1 << 2, /* Related to an established connection. */ + TCA_FLOWER_KEY_CT_FLAGS_TRACKED = 1 << 3, /* Conntrack has occurred. */ +}; + enum { TCA_FLOWER_KEY_ENC_OPTS_UNSPEC, TCA_FLOWER_KEY_ENC_OPTS_GENEVE, /* Nested diff --git a/include/linux/tc_act/tc_ct.h b/include/linux/tc_act/tc_ct.h new file mode 100644 index 000000000000..5fb1d7ac1027 --- /dev/null +++ b/include/linux/tc_act/tc_ct.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __UAPI_TC_CT_H +#define __UAPI_TC_CT_H + +#include +#include + +enum { + TCA_CT_UNSPEC, + TCA_CT_PARMS, + TCA_CT_TM, + TCA_CT_ACTION, /* u16 */ + TCA_CT_ZONE, /* u16 */ + TCA_CT_MARK, /* u32 */ + TCA_CT_MARK_MASK, /* u32 */ + TCA_CT_LABELS, /* u128 */ + TCA_CT_LABELS_MASK, /* u128 */ + TCA_CT_NAT_IPV4_MIN, /* be32 */ + TCA_CT_NAT_IPV4_MAX, /* be32 */ + TCA_CT_NAT_IPV6_MIN, /* struct in6_addr */ + TCA_CT_NAT_IPV6_MAX, /* struct in6_addr */ + TCA_CT_NAT_PORT_MIN, /* be16 */ + TCA_CT_NAT_PORT_MAX, /* be16 */ + TCA_CT_PAD, + __TCA_CT_MAX +}; + +#define TCA_CT_MAX (__TCA_CT_MAX - 1) + +#define TCA_CT_ACT_COMMIT (1 << 0) +#define TCA_CT_ACT_FORCE (1 << 1) +#define TCA_CT_ACT_CLEAR (1 << 2) +#define TCA_CT_ACT_NAT (1 << 3) +#define TCA_CT_ACT_NAT_SRC (1 << 4) +#define TCA_CT_ACT_NAT_DST (1 << 5) + +struct tc_ct { + tc_gen; +}; + +#endif /* __UAPI_TC_CT_H */ From patchwork Wed Nov 27 12:55:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201586 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=whitealder.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLPH5Vm6z9s3Z for ; Wed, 27 Nov 2019 23:56:19 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 337CC87749; Wed, 27 Nov 2019 12:56:18 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 4zyfpTPDiVsa; Wed, 27 Nov 2019 12:56:03 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by whitealder.osuosl.org (Postfix) with ESMTP id 1A1AB8773E; Wed, 27 Nov 2019 12:55:50 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C4F2DC1DEE; Wed, 27 Nov 2019 12:55:49 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id E27CFC0881 for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id D191B20494 for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ybOefa4y6Sl7 for ; Wed, 27 Nov 2019 12:55:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by silver.osuosl.org (Postfix) with ESMTP id 786142048B for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:29 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRo016501; Wed, 27 Nov 2019 14:55:29 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:09 +0200 Message-Id: <20191127125516.5135-4-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 03/10] tc: Introduce tc_id to specify a tc filter X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey Move all that is needed to identify a tc filter to a new structure, tc_id. This removes a lot of duplication in accessing/creating tc filters. --- Changelog: V1->V2: In tc_del_matchall_policer - reverse xmas param order Added and used helper is_tc_id_eq(id1, id2) in find_ufid In netdev_tc_flow_dump_next - use make_tc_id() instead of manualy filling id In netdev_tc_flow_put - use if (get_ufid_tc_mapping(ufid, &id) == 0) to be mor explict we found the mapping not failed to get In make_tc_id - fill id explictily and removed memset. Moved tc_make_id to be static inline in tc.h Signed-off-by: Paul Blakey --- lib/netdev-linux.c | 6 +- lib/netdev-offload-tc.c | 204 +++++++++++++++++++----------------------------- lib/tc.c | 109 ++++++++------------------ lib/tc.h | 51 +++++++++--- 4 files changed, 158 insertions(+), 212 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index f4819237370a..dd431f05ef2c 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -2347,7 +2347,9 @@ tc_add_matchall_policer(struct netdev *netdev, uint32_t kbits_rate, static int tc_del_matchall_policer(struct netdev *netdev) { + int prio = TC_RESERVED_PRIORITY_POLICE; uint32_t block_id = 0; + struct tc_id id; int ifindex; int err; @@ -2356,8 +2358,8 @@ tc_del_matchall_policer(struct netdev *netdev) return err; } - err = tc_del_filter(ifindex, TC_RESERVED_PRIORITY_POLICE, 1, block_id, - TC_INGRESS); + id = make_tc_id(ifindex, block_id, prio, TC_INGRESS); + err = tc_del_filter(&id); if (err) { return err; } diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 1adbb325b94f..6354ad59676a 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -145,20 +145,16 @@ static struct ovs_mutex ufid_lock = OVS_MUTEX_INITIALIZER; /** * struct ufid_tc_data - data entry for ufid_tc hmap. * @ufid_node: Element in @ufid_tc hash table by ufid key. - * @tc_node: Element in @ufid_tc hash table by prio/handle/ifindex key. + * @tc_node: Element in @ufid_tc hash table by tc_id key. * @ufid: ufid assigned to the flow - * @prio: tc priority - * @handle: tc handle - * @ifindex: netdev ifindex. + * @id: tc id * @netdev: netdev associated with the tc rule */ struct ufid_tc_data { struct hmap_node ufid_node; struct hmap_node tc_node; ovs_u128 ufid; - uint16_t prio; - uint32_t handle; - int ifindex; + struct tc_id id; struct netdev *netdev; }; @@ -190,32 +186,27 @@ del_ufid_tc_mapping(const ovs_u128 *ufid) /* Wrapper function to delete filter and ufid tc mapping */ static int -del_filter_and_ufid_mapping(int ifindex, int prio, int handle, - uint32_t block_id, const ovs_u128 *ufid, - enum tc_qdisc_hook hook) +del_filter_and_ufid_mapping(struct tc_id *id, const ovs_u128 *ufid) { int err; - err = tc_del_filter(ifindex, prio, handle, block_id, hook); + err = tc_del_filter(id); del_ufid_tc_mapping(ufid); - return err; } /* Add ufid entry to ufid_tc hashmap. */ static void -add_ufid_tc_mapping(const ovs_u128 *ufid, int prio, int handle, - struct netdev *netdev, int ifindex) +add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid, + struct tc_id *id) { size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0); - size_t tc_hash = hash_int(hash_int(prio, handle), ifindex); + size_t tc_hash = hash_int(hash_int(id->prio, id->handle), id->ifindex); struct ufid_tc_data *new_data = xzalloc(sizeof *new_data); new_data->ufid = *ufid; - new_data->prio = prio; - new_data->handle = handle; + new_data->id = *id; new_data->netdev = netdev_ref(netdev); - new_data->ifindex = ifindex; ovs_mutex_lock(&ufid_lock); hmap_insert(&ufid_tc, &new_data->ufid_node, ufid_hash); @@ -223,56 +214,44 @@ add_ufid_tc_mapping(const ovs_u128 *ufid, int prio, int handle, ovs_mutex_unlock(&ufid_lock); } -/* Get ufid from ufid_tc hashmap. +/* Get tc id from ufid_tc hashmap. * - * If netdev output param is not NULL then the function will return - * associated netdev on success and a refcount is taken on that netdev. - * The caller is then responsible to close the netdev. - * - * Returns handle if successful and fill prio and netdev for that ufid. - * Otherwise returns 0. + * Returns 0 if successful and fills id. + * Otherwise returns the error. */ static int -get_ufid_tc_mapping(const ovs_u128 *ufid, int *prio, struct netdev **netdev) +get_ufid_tc_mapping(const ovs_u128 *ufid, struct tc_id *id) { size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0); struct ufid_tc_data *data; - int handle = 0; ovs_mutex_lock(&ufid_lock); HMAP_FOR_EACH_WITH_HASH(data, ufid_node, ufid_hash, &ufid_tc) { if (ovs_u128_equals(*ufid, data->ufid)) { - if (prio) { - *prio = data->prio; - } - if (netdev) { - *netdev = netdev_ref(data->netdev); - } - handle = data->handle; - break; + *id = data->id; + ovs_mutex_unlock(&ufid_lock); + return 0; } } ovs_mutex_unlock(&ufid_lock); - return handle; + return ENOENT; } -/* Find ufid entry in ufid_tc hashmap using prio, handle and netdev. +/* Find ufid entry in ufid_tc hashmap using tc_id id. * The result is saved in ufid. * * Returns true on success. */ static bool -find_ufid(int prio, int handle, struct netdev *netdev, ovs_u128 *ufid) +find_ufid(struct netdev *netdev, struct tc_id *id, ovs_u128 *ufid) { - int ifindex = netdev_get_ifindex(netdev); + size_t tc_hash = hash_int(hash_int(id->prio, id->handle), id->ifindex); struct ufid_tc_data *data; - size_t tc_hash = hash_int(hash_int(prio, handle), ifindex); ovs_mutex_lock(&ufid_lock); HMAP_FOR_EACH_WITH_HASH(data, tc_node, tc_hash, &ufid_tc) { - if (data->prio == prio && data->handle == handle - && data->ifindex == ifindex) { + if (netdev == data->netdev && is_tc_id_eq(&data->id, id)) { *ufid = data->ufid; break; } @@ -356,6 +335,8 @@ netdev_tc_flow_flush(struct netdev *netdev) enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev); int ifindex = netdev_get_ifindex(netdev); uint32_t block_id = 0; + struct tc_id id; + int prio = 0; if (ifindex < 0) { VLOG_ERR_RL(&error_rl, "flow_flush: failed to get ifindex for %s: %s", @@ -364,8 +345,8 @@ netdev_tc_flow_flush(struct netdev *netdev) } block_id = get_block_id_from_netdev(netdev); - - return tc_flush(ifindex, block_id, hook); + id = make_tc_id(ifindex, block_id, prio, hook); + return tc_del_filter(&id); } static int @@ -375,6 +356,8 @@ netdev_tc_flow_dump_create(struct netdev *netdev, enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev); struct netdev_flow_dump *dump; uint32_t block_id = 0; + struct tc_id id; + int prio = 0; int ifindex; ifindex = netdev_get_ifindex(netdev); @@ -388,7 +371,9 @@ netdev_tc_flow_dump_create(struct netdev *netdev, dump = xzalloc(sizeof *dump); dump->nl_dump = xzalloc(sizeof *dump->nl_dump); dump->netdev = netdev_ref(netdev); - tc_dump_flower_start(ifindex, dump->nl_dump, block_id, hook); + + id = make_tc_id(ifindex, block_id, prio, hook); + tc_dump_flower_start(&id, dump->nl_dump); *dump_out = dump; @@ -777,13 +762,19 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, struct ofpbuf *rbuffer, struct ofpbuf *wbuffer) { + struct netdev *netdev = dump->netdev; struct ofpbuf nl_flow; + struct tc_id id; + + id = make_tc_id(netdev_get_ifindex(netdev), + get_block_id_from_netdev(netdev), + 0, /* prio */ + get_tc_qdisc_hook(netdev)); while (nl_dump_next(dump->nl_dump, &nl_flow, rbuffer)) { struct tc_flower flower; - struct netdev *netdev = dump->netdev; - if (parse_netlink_to_tc_flower(&nl_flow, &flower)) { + if (parse_netlink_to_tc_flower(&nl_flow, &id, &flower)) { continue; } @@ -794,7 +785,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, if (flower.act_cookie.len) { *ufid = *((ovs_u128 *) flower.act_cookie.data); - } else if (!find_ufid(flower.prio, flower.handle, netdev, ufid)) { + } else if (!find_ufid(netdev, &id, ufid)) { continue; } @@ -1156,9 +1147,9 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct tc_action *action; uint32_t block_id = 0; struct nlattr *nla; + struct tc_id id; size_t left; int prio = 0; - int handle; int ifindex; int err; @@ -1428,38 +1419,35 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, } } - block_id = get_block_id_from_netdev(netdev); - handle = get_ufid_tc_mapping(ufid, &prio, NULL); - if (handle && prio) { - VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d", handle, prio); - del_filter_and_ufid_mapping(ifindex, prio, handle, block_id, ufid, - hook); - } - - if (!prio) { - prio = get_prio_for_tc_flower(&flower); - if (prio == 0) { - VLOG_ERR_RL(&rl, "couldn't get tc prio: %s", ovs_strerror(ENOSPC)); - return ENOSPC; - } + if (get_ufid_tc_mapping(ufid, &id) == 0) { + VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d", + id.handle, id.prio); + del_filter_and_ufid_mapping(&id, ufid); + } + + prio = get_prio_for_tc_flower(&flower); + if (prio == 0) { + VLOG_ERR_RL(&rl, "couldn't get tc prio: %s", ovs_strerror(ENOSPC)); + return ENOSPC; } flower.act_cookie.data = ufid; flower.act_cookie.len = sizeof *ufid; - err = tc_replace_flower(ifindex, prio, handle, &flower, block_id, hook); + id = make_tc_id(ifindex, block_id, prio, hook); + err = tc_replace_flower(&id, &flower); if (!err) { if (stats) { memset(stats, 0, sizeof *stats); } - add_ufid_tc_mapping(ufid, flower.prio, flower.handle, netdev, ifindex); + add_ufid_tc_mapping(netdev, ufid, &id); } return err; } static int -netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED, +netdev_tc_flow_get(struct netdev *netdev, struct match *match, struct nlattr **actions, const ovs_u128 *ufid, @@ -1468,43 +1456,28 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED, struct ofpbuf *buf) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); - struct netdev *dev; struct tc_flower flower; - enum tc_qdisc_hook hook; - uint32_t block_id = 0; odp_port_t in_port; - int prio = 0; - int ifindex; - int handle; + struct tc_id id; int err; - handle = get_ufid_tc_mapping(ufid, &prio, &dev); - if (!handle) { - return ENOENT; - } - - hook = get_tc_qdisc_hook(dev); - - ifindex = netdev_get_ifindex(dev); - if (ifindex < 0) { - VLOG_ERR_RL(&error_rl, "flow_get: failed to get ifindex for %s: %s", - netdev_get_name(dev), ovs_strerror(-ifindex)); - netdev_close(dev); - return -ifindex; + err = get_ufid_tc_mapping(ufid, &id); + if (err) { + return err; } - block_id = get_block_id_from_netdev(dev); VLOG_DBG_RL(&rl, "flow get (dev %s prio %d handle %d block_id %d)", - netdev_get_name(dev), prio, handle, block_id); - err = tc_get_flower(ifindex, prio, handle, &flower, block_id, hook); - netdev_close(dev); + netdev_get_name(netdev), id.prio, id.handle, id.block_id); + + err = tc_get_flower(&id, &flower); if (err) { VLOG_ERR_RL(&error_rl, "flow get failed (dev %s prio %d handle %d): %s", - netdev_get_name(dev), prio, handle, ovs_strerror(err)); + netdev_get_name(netdev), id.prio, id.handle, + ovs_strerror(err)); return err; } - in_port = netdev_ifindex_to_odp_port(ifindex); + in_port = netdev_ifindex_to_odp_port(id.ifindex); parse_tc_flower_to_match(&flower, match, actions, stats, attrs, buf); match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX); @@ -1519,44 +1492,24 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, struct dpif_flow_stats *stats) { struct tc_flower flower; - enum tc_qdisc_hook hook; - uint32_t block_id = 0; - struct netdev *dev; - int prio = 0; - int ifindex; - int handle; + struct tc_id id; int error; - handle = get_ufid_tc_mapping(ufid, &prio, &dev); - if (!handle) { - return ENOENT; - } - - hook = get_tc_qdisc_hook(dev); - - ifindex = netdev_get_ifindex(dev); - if (ifindex < 0) { - VLOG_ERR_RL(&error_rl, "flow_del: failed to get ifindex for %s: %s", - netdev_get_name(dev), ovs_strerror(-ifindex)); - netdev_close(dev); - return -ifindex; + error = get_ufid_tc_mapping(ufid, &id); + if (error) { + return error; } - block_id = get_block_id_from_netdev(dev); - if (stats) { memset(stats, 0, sizeof *stats); - if (!tc_get_flower(ifindex, prio, handle, &flower, block_id, hook)) { + if (!tc_get_flower(&id, &flower)) { stats->n_packets = get_32aligned_u64(&flower.stats.n_packets); stats->n_bytes = get_32aligned_u64(&flower.stats.n_bytes); stats->used = flower.lastused; } } - error = del_filter_and_ufid_mapping(ifindex, prio, handle, block_id, ufid, - hook); - - netdev_close(dev); + error = del_filter_and_ufid_mapping(&id, ufid); return error; } @@ -1565,7 +1518,9 @@ static void probe_multi_mask_per_prio(int ifindex) { struct tc_flower flower; + struct tc_id id1, id2; int block_id = 0; + int prio = 1; int error; error = tc_add_del_qdisc(ifindex, true, block_id, TC_INGRESS); @@ -1580,7 +1535,8 @@ probe_multi_mask_per_prio(int ifindex) memset(&flower.key.dst_mac, 0x11, sizeof flower.key.dst_mac); memset(&flower.mask.dst_mac, 0xff, sizeof flower.mask.dst_mac); - error = tc_replace_flower(ifindex, 1, 1, &flower, block_id, TC_INGRESS); + id1 = make_tc_id(ifindex, block_id, prio, TC_INGRESS); + error = tc_replace_flower(&id1, &flower); if (error) { goto out; } @@ -1588,14 +1544,15 @@ probe_multi_mask_per_prio(int ifindex) memset(&flower.key.src_mac, 0x11, sizeof flower.key.src_mac); memset(&flower.mask.src_mac, 0xff, sizeof flower.mask.src_mac); - error = tc_replace_flower(ifindex, 1, 2, &flower, block_id, TC_INGRESS); - tc_del_filter(ifindex, 1, 1, block_id, TC_INGRESS); + id2 = make_tc_id(ifindex, block_id, prio, TC_INGRESS); + error = tc_replace_flower(&id2, &flower); + tc_del_filter(&id1); if (error) { goto out; } - tc_del_filter(ifindex, 1, 2, block_id, TC_INGRESS); + tc_del_filter(&id2); multi_mask_per_prio = true; VLOG_INFO("probe tc: multiple masks on single tc prio is supported."); @@ -1609,6 +1566,8 @@ probe_tc_block_support(int ifindex) { struct tc_flower flower; uint32_t block_id = 1; + struct tc_id id; + int prio = 0; int error; error = tc_add_del_qdisc(ifindex, true, block_id, TC_INGRESS); @@ -1623,7 +1582,8 @@ probe_tc_block_support(int ifindex) memset(&flower.key.dst_mac, 0x11, sizeof flower.key.dst_mac); memset(&flower.mask.dst_mac, 0xff, sizeof flower.mask.dst_mac); - error = tc_replace_flower(ifindex, 1, 1, &flower, block_id, TC_INGRESS); + id = make_tc_id(ifindex, block_id, prio, TC_INGRESS); + error = tc_replace_flower(&id, &flower); tc_add_del_qdisc(ifindex, false, block_id, TC_INGRESS); diff --git a/lib/tc.c b/lib/tc.c index ba3e9d09dabe..36a93b164158 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -194,6 +194,21 @@ tc_make_request(int ifindex, int type, unsigned int flags, return tcmsg; } +static void request_from_tc_id(struct tc_id *id, uint16_t eth_type, + int type, unsigned int flags, + struct ofpbuf *request) +{ + int ifindex = id->block_id ? TCM_IFINDEX_MAGIC_BLOCK : id->ifindex; + uint32_t ingress_parent = id->block_id ? : TC_INGRESS_PARENT; + struct tcmsg *tcmsg; + + tcmsg = tc_make_request(ifindex, type, flags, request); + tcmsg->tcm_parent = (id->hook == TC_EGRESS) ? + TC_EGRESS_PARENT : ingress_parent; + tcmsg->tcm_info = tc_make_handle(id->prio, eth_type); + tcmsg->tcm_handle = id->handle; +} + int tc_transact(struct ofpbuf *request, struct ofpbuf **replyp) { @@ -1525,7 +1540,8 @@ nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower) } int -parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_flower *flower) +parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_id *id, + struct tc_flower *flower) { struct tcmsg *tc; struct nlattr *ta[ARRAY_SIZE(tca_policy)]; @@ -1538,16 +1554,17 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_flower *flower) memset(flower, 0, sizeof *flower); tc = ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tc); - flower->handle = tc->tcm_handle; + flower->key.eth_type = (OVS_FORCE ovs_be16) tc_get_minor(tc->tcm_info); flower->mask.eth_type = OVS_BE16_MAX; - flower->prio = tc_get_major(tc->tcm_info); + id->prio = tc_get_major(tc->tcm_info); + id->handle = tc->tcm_handle; - if (flower->prio == TC_RESERVED_PRIORITY_POLICE) { + if (id->prio == TC_RESERVED_PRIORITY_POLICE) { return 0; } - if (!flower->handle) { + if (!id->handle) { return EAGAIN; } @@ -1567,20 +1584,11 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_flower *flower) } int -tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id, - enum tc_qdisc_hook hook) +tc_dump_flower_start(struct tc_id *id, struct nl_dump *dump) { struct ofpbuf request; - struct tcmsg *tcmsg; - int index; - - index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex; - tcmsg = tc_make_request(index, RTM_GETTFILTER, NLM_F_DUMP, &request); - tcmsg->tcm_parent = (hook == TC_EGRESS) ? - TC_EGRESS_PARENT : (block_id ? : TC_INGRESS_PARENT); - tcmsg->tcm_info = TC_H_UNSPEC; - tcmsg->tcm_handle = 0; + request_from_tc_id(id, 0, RTM_GETTFILTER, NLM_F_DUMP, &request); nl_dump_start(dump, NETLINK_ROUTE, &request); ofpbuf_uninit(&request); @@ -1588,68 +1596,28 @@ tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id, } int -tc_flush(int ifindex, uint32_t block_id, enum tc_qdisc_hook hook) +tc_del_filter(struct tc_id *id) { struct ofpbuf request; - struct tcmsg *tcmsg; - int index; - - index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex; - tcmsg = tc_make_request(index, RTM_DELTFILTER, NLM_F_ACK, &request); - tcmsg->tcm_parent = (hook == TC_EGRESS) ? - TC_EGRESS_PARENT : (block_id ? : TC_INGRESS_PARENT); - tcmsg->tcm_info = TC_H_UNSPEC; + request_from_tc_id(id, 0, RTM_DELTFILTER, NLM_F_ACK, &request); return tc_transact(&request, NULL); } int -tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id, - enum tc_qdisc_hook hook) -{ - struct ofpbuf request; - struct tcmsg *tcmsg; - struct ofpbuf *reply; - int error; - int index; - - index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex; - tcmsg = tc_make_request(index, RTM_DELTFILTER, NLM_F_ECHO, &request); - tcmsg->tcm_parent = (hook == TC_EGRESS) ? - TC_EGRESS_PARENT : (block_id ? : TC_INGRESS_PARENT); - tcmsg->tcm_info = tc_make_handle(prio, 0); - tcmsg->tcm_handle = handle; - - error = tc_transact(&request, &reply); - if (!error) { - ofpbuf_delete(reply); - } - return error; -} - -int -tc_get_flower(int ifindex, int prio, int handle, struct tc_flower *flower, - uint32_t block_id, enum tc_qdisc_hook hook) +tc_get_flower(struct tc_id *id, struct tc_flower *flower) { struct ofpbuf request; - struct tcmsg *tcmsg; struct ofpbuf *reply; int error; - int index; - - index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex; - tcmsg = tc_make_request(index, RTM_GETTFILTER, NLM_F_ECHO, &request); - tcmsg->tcm_parent = (hook == TC_EGRESS) ? - TC_EGRESS_PARENT : (block_id ? : TC_INGRESS_PARENT); - tcmsg->tcm_info = tc_make_handle(prio, 0); - tcmsg->tcm_handle = handle; + request_from_tc_id(id, 0, RTM_GETTFILTER, NLM_F_ECHO, &request); error = tc_transact(&request, &reply); if (error) { return error; } - error = parse_netlink_to_tc_flower(reply, flower); + error = parse_netlink_to_tc_flower(reply, id, flower); ofpbuf_delete(reply); return error; } @@ -2493,25 +2461,16 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower) } int -tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle, - struct tc_flower *flower, uint32_t block_id, - enum tc_qdisc_hook hook) +tc_replace_flower(struct tc_id *id, struct tc_flower *flower) { struct ofpbuf request; - struct tcmsg *tcmsg; struct ofpbuf *reply; int error = 0; size_t basic_offset; uint16_t eth_type = (OVS_FORCE uint16_t) flower->key.eth_type; - int index; - index = block_id ? TCM_IFINDEX_MAGIC_BLOCK : ifindex; - tcmsg = tc_make_request(index, RTM_NEWTFILTER, NLM_F_CREATE | NLM_F_ECHO, - &request); - tcmsg->tcm_parent = (hook == TC_EGRESS) ? - TC_EGRESS_PARENT : (block_id ? : TC_INGRESS_PARENT); - tcmsg->tcm_info = tc_make_handle(prio, eth_type); - tcmsg->tcm_handle = handle; + request_from_tc_id(id, eth_type, RTM_NEWTFILTER, + NLM_F_CREATE | NLM_F_ECHO, &request); nl_msg_put_string(&request, TCA_KIND, "flower"); basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS); @@ -2530,8 +2489,8 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle, struct tcmsg *tc = ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tc); - flower->prio = tc_get_major(tc->tcm_info); - flower->handle = tc->tcm_handle; + id->prio = tc_get_major(tc->tcm_info); + id->handle = tc->tcm_handle; ofpbuf_delete(reply); } diff --git a/lib/tc.h b/lib/tc.h index f4073c6c47e6..b48e10c352ab 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -210,10 +210,41 @@ enum tc_offloaded_state { #define TCA_ACT_MAX_NUM 16 -struct tc_flower { +struct tc_id { + enum tc_qdisc_hook hook; + uint32_t block_id; + int ifindex; + uint16_t prio; uint32_t handle; - uint32_t prio; +}; + +static inline struct +tc_id make_tc_id(int ifindex, uint32_t block_id, uint16_t prio, + enum tc_qdisc_hook hook) +{ + struct tc_id id; + + id.block_id = block_id; + id.ifindex = ifindex; + id.prio = prio; + id.hook = hook; + id.handle = 0; + return id; +} + +static inline bool +is_tc_id_eq(struct tc_id *id1, struct tc_id *id2) +{ + return id1->prio == id2->prio + && id1->handle == id2->handle + && id1->handle == id2->handle + && id1->hook == id2->hook + && id1->block_id == id2->block_id + && id1->ifindex == id2->ifindex; +} + +struct tc_flower { struct tc_flower_key key; struct tc_flower_key mask; @@ -247,18 +278,12 @@ BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite) + MEMBER_SIZEOF(struct tc_flower, rewrite) + sizeof(uint32_t) - 2 < sizeof(struct tc_flower)); -int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle, - struct tc_flower *flower, uint32_t block_id, - enum tc_qdisc_hook hook); -int tc_del_filter(int ifindex, int prio, int handle, uint32_t block_id, - enum tc_qdisc_hook hook); -int tc_get_flower(int ifindex, int prio, int handle, - struct tc_flower *flower, uint32_t block_id, - enum tc_qdisc_hook hook); -int tc_flush(int ifindex, uint32_t block_id, enum tc_qdisc_hook hook); -int tc_dump_flower_start(int ifindex, struct nl_dump *dump, uint32_t block_id, - enum tc_qdisc_hook hook); +int tc_replace_flower(struct tc_id *id, struct tc_flower *flower); +int tc_del_filter(struct tc_id *id); +int tc_get_flower(struct tc_id *id, struct tc_flower *flower); +int tc_dump_flower_start(struct tc_id *id, struct nl_dump *dump); int parse_netlink_to_tc_flower(struct ofpbuf *reply, + struct tc_id *id, struct tc_flower *flower); void tc_set_policy(const char *policy); From patchwork Wed Nov 27 12:55:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201584 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=silver.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLP83TKnz9sT7 for ; Wed, 27 Nov 2019 23:56:11 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 89BB222E20; Wed, 27 Nov 2019 12:56:09 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 95feV5CdR0RS; Wed, 27 Nov 2019 12:56:03 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 79D5A20494; Wed, 27 Nov 2019 12:55:47 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6E952C1DE1; Wed, 27 Nov 2019 12:55:47 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id A08D5C0881 for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 903628829A for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id T2jUbWuG2D15 for ; Wed, 27 Nov 2019 12:55:37 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id 83482882A1 for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:29 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRp016501; Wed, 27 Nov 2019 14:55:29 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:10 +0200 Message-Id: <20191127125516.5135-5-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 04/10] netdev-offload-tc: Implement netdev tc flush via tc filter del X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey To be consistent with our tc-ufid mapping after flush, and to support tc chains flushing in the next commit, implement flush operation via deleting all the filters we actually added and delete their mappings. This will also not delete the configured qos policing via matchall filters, while old code did. Signed-off-by: Paul Blakey --- lib/netdev-offload-tc.c | 74 +++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 6354ad59676a..66b42f2066ed 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -43,7 +43,8 @@ VLOG_DEFINE_THIS_MODULE(netdev_offload_tc); static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5); -static struct hmap ufid_tc = HMAP_INITIALIZER(&ufid_tc); +static struct hmap ufid_to_tc = HMAP_INITIALIZER(&ufid_to_tc); +static struct hmap tc_to_ufid = HMAP_INITIALIZER(&tc_to_ufid); static bool multi_mask_per_prio = false; static bool block_support = false; @@ -143,44 +144,49 @@ static struct netlink_field set_flower_map[][4] = { static struct ovs_mutex ufid_lock = OVS_MUTEX_INITIALIZER; /** - * struct ufid_tc_data - data entry for ufid_tc hmap. - * @ufid_node: Element in @ufid_tc hash table by ufid key. - * @tc_node: Element in @ufid_tc hash table by tc_id key. + * struct ufid_tc_data - data entry for ufid-tc hashmaps. + * @ufid_to_tc_node: Element in @ufid_to_tc hash table by ufid key. + * @tc_to_ufid_node: Element in @tc_to_ufid hash table by tc_id key. * @ufid: ufid assigned to the flow * @id: tc id * @netdev: netdev associated with the tc rule */ struct ufid_tc_data { - struct hmap_node ufid_node; - struct hmap_node tc_node; + struct hmap_node ufid_to_tc_node; + struct hmap_node tc_to_ufid_node; ovs_u128 ufid; struct tc_id id; struct netdev *netdev; }; -/* Remove matching ufid entry from ufid_tc hashmap. */ static void -del_ufid_tc_mapping(const ovs_u128 *ufid) +del_ufid_tc_mapping_unlocked(const ovs_u128 *ufid) { size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0); struct ufid_tc_data *data; - ovs_mutex_lock(&ufid_lock); - HMAP_FOR_EACH_WITH_HASH(data, ufid_node, ufid_hash, &ufid_tc) { + HMAP_FOR_EACH_WITH_HASH (data, ufid_to_tc_node, ufid_hash, &ufid_to_tc) { if (ovs_u128_equals(*ufid, data->ufid)) { break; } } if (!data) { - ovs_mutex_unlock(&ufid_lock); return; } - hmap_remove(&ufid_tc, &data->ufid_node); - hmap_remove(&ufid_tc, &data->tc_node); + hmap_remove(&ufid_to_tc, &data->ufid_to_tc_node); + hmap_remove(&tc_to_ufid, &data->tc_to_ufid_node); netdev_close(data->netdev); free(data); +} + +/* Remove matching ufid entry from ufid-tc hashmaps. */ +static void +del_ufid_tc_mapping(const ovs_u128 *ufid) +{ + ovs_mutex_lock(&ufid_lock); + del_ufid_tc_mapping_unlocked(ufid); ovs_mutex_unlock(&ufid_lock); } @@ -195,7 +201,7 @@ del_filter_and_ufid_mapping(struct tc_id *id, const ovs_u128 *ufid) return err; } -/* Add ufid entry to ufid_tc hashmap. */ +/* Add ufid entry to ufid_to_tc hashmap. */ static void add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid, struct tc_id *id) @@ -209,12 +215,12 @@ add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid, new_data->netdev = netdev_ref(netdev); ovs_mutex_lock(&ufid_lock); - hmap_insert(&ufid_tc, &new_data->ufid_node, ufid_hash); - hmap_insert(&ufid_tc, &new_data->tc_node, tc_hash); + hmap_insert(&ufid_to_tc, &new_data->ufid_to_tc_node, ufid_hash); + hmap_insert(&tc_to_ufid, &new_data->tc_to_ufid_node, tc_hash); ovs_mutex_unlock(&ufid_lock); } -/* Get tc id from ufid_tc hashmap. +/* Get tc id from ufid_to_tc hashmap. * * Returns 0 if successful and fills id. * Otherwise returns the error. @@ -226,7 +232,7 @@ get_ufid_tc_mapping(const ovs_u128 *ufid, struct tc_id *id) struct ufid_tc_data *data; ovs_mutex_lock(&ufid_lock); - HMAP_FOR_EACH_WITH_HASH(data, ufid_node, ufid_hash, &ufid_tc) { + HMAP_FOR_EACH_WITH_HASH (data, ufid_to_tc_node, ufid_hash, &ufid_to_tc) { if (ovs_u128_equals(*ufid, data->ufid)) { *id = data->id; ovs_mutex_unlock(&ufid_lock); @@ -238,7 +244,7 @@ get_ufid_tc_mapping(const ovs_u128 *ufid, struct tc_id *id) return ENOENT; } -/* Find ufid entry in ufid_tc hashmap using tc_id id. +/* Find ufid entry in ufid_to_tc hashmap using tc_id id. * The result is saved in ufid. * * Returns true on success. @@ -250,7 +256,7 @@ find_ufid(struct netdev *netdev, struct tc_id *id, ovs_u128 *ufid) struct ufid_tc_data *data; ovs_mutex_lock(&ufid_lock); - HMAP_FOR_EACH_WITH_HASH(data, tc_node, tc_hash, &ufid_tc) { + HMAP_FOR_EACH_WITH_HASH (data, tc_to_ufid_node, tc_hash, &tc_to_ufid) { if (netdev == data->netdev && is_tc_id_eq(&data->id, id)) { *ufid = data->ufid; break; @@ -293,7 +299,7 @@ get_prio_for_tc_flower(struct tc_flower *flower) * different prio if not. Flower classifier will reject same prio for * different mask combination unless multi mask per prio is supported. */ ovs_mutex_lock(&prios_lock); - HMAP_FOR_EACH_WITH_HASH(data, node, hash, &prios) { + HMAP_FOR_EACH_WITH_HASH (data, node, hash, &prios) { if ((multi_mask_per_prio || !memcmp(&flower->mask, &data->mask, key_len)) && data->protocol == flower->key.eth_type) { @@ -332,21 +338,23 @@ get_block_id_from_netdev(struct netdev *netdev) static int netdev_tc_flow_flush(struct netdev *netdev) { - enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev); - int ifindex = netdev_get_ifindex(netdev); - uint32_t block_id = 0; - struct tc_id id; - int prio = 0; + struct ufid_tc_data *data, *next; + int err; - if (ifindex < 0) { - VLOG_ERR_RL(&error_rl, "flow_flush: failed to get ifindex for %s: %s", - netdev_get_name(netdev), ovs_strerror(-ifindex)); - return -ifindex; + ovs_mutex_lock(&ufid_lock); + HMAP_FOR_EACH_SAFE (data, next, tc_to_ufid_node, &tc_to_ufid) { + if (data->netdev != netdev) { + continue; + } + + err = tc_del_filter(&data->id); + if (!err) { + del_ufid_tc_mapping_unlocked(&data->ufid); + } } + ovs_mutex_unlock(&ufid_lock); - block_id = get_block_id_from_netdev(netdev); - id = make_tc_id(ifindex, block_id, prio, hook); - return tc_del_filter(&id); + return 0; } static int From patchwork Wed Nov 27 12:55:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201585 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=silver.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLPJ0ynRz9sPv for ; Wed, 27 Nov 2019 23:56:20 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id A8B9E22855; Wed, 27 Nov 2019 12:56:18 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id vSi15Vj9FnOi; Wed, 27 Nov 2019 12:56:09 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id B1E7422879; Wed, 27 Nov 2019 12:55:48 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 69E16C1DE8; Wed, 27 Nov 2019 12:55:48 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id C67C8C1DDA for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id B22B08829A for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id SRHIyxWeSR76 for ; Wed, 27 Nov 2019 12:55:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id 82490882A0 for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:29 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRq016501; Wed, 27 Nov 2019 14:55:29 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:11 +0200 Message-Id: <20191127125516.5135-6-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 05/10] netdev-offload-tc: Add recirculation support via tc chains X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey Each recirculation id will create a tc chain, and we translate the recirculation action to a tc goto chain action. --- Changelog: V1->V2: moved make_tc_id_chain helper to tc.h as static inline updated is_tc_id_eq with chain compare instead of find_ufid Signed-off-by: Paul Blakey --- lib/dpif-netlink.c | 1 + lib/netdev-offload-tc.c | 34 ++++++++++++++++++++++++---------- lib/tc.c | 39 +++++++++++++++++++++++++++++++++------ lib/tc.h | 18 +++++++++++++++++- 4 files changed, 75 insertions(+), 17 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index d1f9b81db84f..034b0acf49c4 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -1600,6 +1600,7 @@ dpif_netlink_netdev_match_to_dpif_flow(struct match *match, .mask = &match->wc.masks, .support = { .max_vlan_headers = 2, + .recirc = true, }, }; size_t offset; diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 66b42f2066ed..954e64a445e8 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -206,9 +206,12 @@ static void add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid, struct tc_id *id) { - size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0); - size_t tc_hash = hash_int(hash_int(id->prio, id->handle), id->ifindex); struct ufid_tc_data *new_data = xzalloc(sizeof *new_data); + size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0); + size_t tc_hash; + + tc_hash = hash_int(hash_int(id->prio, id->handle), id->ifindex); + tc_hash = hash_int(id->chain, tc_hash); new_data->ufid = *ufid; new_data->id = *id; @@ -252,8 +255,11 @@ get_ufid_tc_mapping(const ovs_u128 *ufid, struct tc_id *id) static bool find_ufid(struct netdev *netdev, struct tc_id *id, ovs_u128 *ufid) { - size_t tc_hash = hash_int(hash_int(id->prio, id->handle), id->ifindex); struct ufid_tc_data *data; + size_t tc_hash; + + tc_hash = hash_int(hash_int(id->prio, id->handle), id->ifindex); + tc_hash = hash_int(id->chain, tc_hash); ovs_mutex_lock(&ufid_lock); HMAP_FOR_EACH_WITH_HASH (data, tc_to_ufid_node, tc_hash, &tc_to_ufid) { @@ -739,6 +745,10 @@ parse_tc_flower_to_match(struct tc_flower *flower, nl_msg_put_u32(buf, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(outport)); } break; + case TC_ACT_GOTO: { + nl_msg_put_u32(buf, OVS_ACTION_ATTR_RECIRC, action->chain); + } + break; } } } @@ -799,6 +809,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX); match->flow.in_port.odp_port = dump->port; + match_set_recirc_id(match, id.chain); return true; } @@ -983,12 +994,6 @@ test_key_and_mask(struct match *match) return EOPNOTSUPP; } - if (mask->recirc_id && key->recirc_id) { - VLOG_DBG_RL(&rl, "offloading attribute recirc_id isn't supported"); - return EOPNOTSUPP; - } - mask->recirc_id = 0; - if (mask->dp_hash) { VLOG_DBG_RL(&rl, "offloading attribute dp_hash isn't supported"); return EOPNOTSUPP; @@ -1156,6 +1161,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, uint32_t block_id = 0; struct nlattr *nla; struct tc_id id; + uint32_t chain; size_t left; int prio = 0; int ifindex; @@ -1170,6 +1176,9 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, memset(&flower, 0, sizeof flower); + chain = key->recirc_id; + mask->recirc_id = 0; + if (flow_tnl_dst_is_set(&key->tunnel)) { VLOG_DBG_RL(&rl, "tunnel: id %#" PRIx64 " src " IP_FMT @@ -1420,6 +1429,10 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, if (err) { return err; } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) { + action->type = TC_ACT_GOTO; + action->chain = nl_attr_get_u32(nla); + flower.action_count++; } else { VLOG_DBG_RL(&rl, "unsupported put action type: %d", nl_attr_type(nla)); @@ -1442,7 +1455,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, flower.act_cookie.data = ufid; flower.act_cookie.len = sizeof *ufid; - id = make_tc_id(ifindex, block_id, prio, hook); + id = make_tc_id_chain(ifindex, block_id, chain, prio, hook); err = tc_replace_flower(&id, &flower); if (!err) { if (stats) { @@ -1490,6 +1503,7 @@ netdev_tc_flow_get(struct netdev *netdev, match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX); match->flow.in_port.odp_port = in_port; + match_set_recirc_id(match, id.chain); return 0; } diff --git a/lib/tc.c b/lib/tc.c index 36a93b164158..cc58320fce2c 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -51,6 +51,7 @@ #endif #if TCA_MAX < 14 +#define TCA_CHAIN 11 #define TCA_INGRESS_BLOCK 13 #endif @@ -207,6 +208,10 @@ static void request_from_tc_id(struct tc_id *id, uint16_t eth_type, TC_EGRESS_PARENT : ingress_parent; tcmsg->tcm_info = tc_make_handle(id->prio, eth_type); tcmsg->tcm_handle = id->handle; + + if (id->chain) { + nl_msg_put_u32(request, TCA_CHAIN, id->chain); + } } int @@ -286,6 +291,7 @@ tc_add_del_qdisc(int ifindex, bool add, uint32_t block_id, static const struct nl_policy tca_policy[] = { [TCA_KIND] = { .type = NL_A_STRING, .optional = false, }, [TCA_OPTIONS] = { .type = NL_A_NESTED, .optional = false, }, + [TCA_CHAIN] = { .type = NL_A_U32, .optional = true, }, [TCA_STATS] = { .type = NL_A_UNSPEC, .min_len = sizeof(struct tc_stats), .optional = true, }, [TCA_STATS2] = { .type = NL_A_NESTED, .optional = true, }, @@ -1129,12 +1135,13 @@ nl_parse_tcf(const struct tcf_t *tm, struct tc_flower *flower) } static int -nl_parse_act_drop(struct nlattr *options, struct tc_flower *flower) +nl_parse_act_gact(struct nlattr *options, struct tc_flower *flower) { struct nlattr *gact_attrs[ARRAY_SIZE(gact_policy)]; const struct tc_gact *p; struct nlattr *gact_parms; const struct tcf_t *tm; + struct tc_action *action; if (!nl_parse_nested(options, gact_policy, gact_attrs, ARRAY_SIZE(gact_policy))) { @@ -1145,7 +1152,11 @@ nl_parse_act_drop(struct nlattr *options, struct tc_flower *flower) gact_parms = gact_attrs[TCA_GACT_PARMS]; p = nl_attr_get_unspec(gact_parms, sizeof *p); - if (p->action != TC_ACT_SHOT) { + if (TC_ACT_EXT_CMP(p->action, TC_ACT_GOTO_CHAIN)) { + action = &flower->actions[flower->action_count++]; + action->chain = p->action & TC_ACT_EXT_VAL_MASK; + action->type = TC_ACT_GOTO; + } else if (p->action != TC_ACT_SHOT) { VLOG_ERR_RL(&error_rl, "unknown gact action: %d", p->action); return EINVAL; } @@ -1423,7 +1434,7 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower) act_cookie = action_attrs[TCA_ACT_COOKIE]; if (!strcmp(act_kind, "gact")) { - err = nl_parse_act_drop(act_options, flower); + err = nl_parse_act_gact(act_options, flower); } else if (!strcmp(act_kind, "mirred")) { err = nl_parse_act_mirred(act_options, flower); } else if (!strcmp(act_kind, "vlan")) { @@ -1574,6 +1585,10 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_id *id, return EPROTO; } + if (ta[TCA_CHAIN]) { + id->chain = nl_attr_get_u32(ta[TCA_CHAIN]); + } + kind = nl_attr_get_string(ta[TCA_KIND]); if (strcmp(kind, "flower")) { VLOG_DBG_ONCE("Unsupported filter: %s", kind); @@ -1870,7 +1885,7 @@ nl_msg_put_act_tunnel_key_set(struct ofpbuf *request, bool id_present, } static void -nl_msg_put_act_drop(struct ofpbuf *request) +nl_msg_put_act_gact(struct ofpbuf *request, uint32_t chain) { size_t offset; @@ -1879,6 +1894,10 @@ nl_msg_put_act_drop(struct ofpbuf *request) { struct tc_gact p = { .action = TC_ACT_SHOT }; + if (chain) { + p.action = TC_ACT_GOTO_CHAIN | chain; + } + nl_msg_put_unspec(request, TCA_GACT_PARMS, &p, sizeof p); } nl_msg_end_nested(request, offset); @@ -2224,12 +2243,20 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) nl_msg_end_nested(request, act_offset); } break; + case TC_ACT_GOTO: { + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_gact(request, action->chain); + nl_msg_put_act_cookie(request, &flower->act_cookie); + nl_msg_end_nested(request, act_offset); + } + break; } } } - if (!ifindex) { + + if (!flower->action_count) { act_offset = nl_msg_start_nested(request, act_index++); - nl_msg_put_act_drop(request); + nl_msg_put_act_gact(request, 0); nl_msg_put_act_cookie(request, &flower->act_cookie); nl_msg_put_act_flags(request); nl_msg_end_nested(request, act_offset); diff --git a/lib/tc.h b/lib/tc.h index b48e10c352ab..42fd1b1b9588 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -156,10 +156,13 @@ enum tc_action_type { TC_ACT_MPLS_POP, TC_ACT_MPLS_PUSH, TC_ACT_MPLS_SET, + TC_ACT_GOTO, }; struct tc_action { union { + int chain; + struct { int ifindex_out; bool ingress; @@ -214,6 +217,7 @@ struct tc_id { enum tc_qdisc_hook hook; uint32_t block_id; int ifindex; + uint32_t chain; uint16_t prio; uint32_t handle; }; @@ -233,6 +237,17 @@ tc_id make_tc_id(int ifindex, uint32_t block_id, uint16_t prio, return id; } +static inline struct tc_id +make_tc_id_chain(int ifindex, uint32_t block_id, uint32_t chain, + uint16_t prio, enum tc_qdisc_hook hook) +{ + struct tc_id id = make_tc_id(ifindex, block_id, prio, hook); + + id.chain = chain; + + return id; +} + static inline bool is_tc_id_eq(struct tc_id *id1, struct tc_id *id2) { @@ -241,7 +256,8 @@ is_tc_id_eq(struct tc_id *id1, struct tc_id *id2) && id1->handle == id2->handle && id1->hook == id2->hook && id1->block_id == id2->block_id - && id1->ifindex == id2->ifindex; + && id1->ifindex == id2->ifindex + && id1->chain == id2->chain; } struct tc_flower { From patchwork Wed Nov 27 12:55:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201581 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLNq5Hq9z9sT7 for ; Wed, 27 Nov 2019 23:55:55 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 3EF27868D1; Wed, 27 Nov 2019 12:55:54 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id kx5dv3uWEmk9; Wed, 27 Nov 2019 12:55:50 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 093B2866E5; Wed, 27 Nov 2019 12:55:47 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8DCC4C1DE2; Wed, 27 Nov 2019 12:55:46 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6F3A3C1DE0 for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 5E3C38829A for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id mUKKrXz6cSfg for ; Wed, 27 Nov 2019 12:55:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id 7AECF8829D for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:30 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRr016501; Wed, 27 Nov 2019 14:55:29 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:12 +0200 Message-Id: <20191127125516.5135-7-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 06/10] netdev-offload-tc: Add conntrack support X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey Zone and ct_state first. Signed-off-by: Paul Blakey --- lib/dpif-netlink.c | 2 + lib/netdev-offload-tc.c | 136 ++++++++++++++++++++++++++++++++++++++++++++---- lib/tc.c | 122 +++++++++++++++++++++++++++++++++++++++++++ lib/tc.h | 11 ++++ 4 files changed, 261 insertions(+), 10 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 034b0acf49c4..620e94ea4bfc 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -1601,6 +1601,8 @@ dpif_netlink_netdev_match_to_dpif_flow(struct match *match, .support = { .max_vlan_headers = 2, .recirc = true, + .ct_state = true, + .ct_zone = true, }, }; size_t offset; diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 954e64a445e8..8dd48ab7c421 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -594,6 +594,35 @@ parse_tc_flower_to_match(struct tc_flower *flower, match_set_tp_dst_masked(match, key->sctp_dst, mask->sctp_dst); match_set_tp_src_masked(match, key->sctp_src, mask->sctp_src); } + + if (mask->ct_state) { + uint8_t ct_statev = 0, ct_statem = 0; + + if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_NEW) { + if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_NEW) { + ct_statev |= OVS_CS_F_NEW; + } + ct_statem |= OVS_CS_F_NEW; + } + + if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) { + if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) { + ct_statev |= OVS_CS_F_ESTABLISHED; + } + ct_statem |= OVS_CS_F_ESTABLISHED; + } + + if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED) { + if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED) { + ct_statev |= OVS_CS_F_TRACKED; + } + ct_statem |= OVS_CS_F_TRACKED; + } + + match_set_ct_state_masked(match, ct_statev, ct_statem); + } + + match_set_ct_zone_masked(match, key->ct_zone, mask->ct_zone); } if (flower->tunnel) { @@ -745,6 +774,27 @@ parse_tc_flower_to_match(struct tc_flower *flower, nl_msg_put_u32(buf, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(outport)); } break; + case TC_ACT_CT: { + size_t ct_offset; + + if (action->ct.clear) { + nl_msg_put_flag(buf, OVS_ACTION_ATTR_CT_CLEAR); + break; + } + + ct_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_CT); + + if (action->ct.commit) { + nl_msg_put_flag(buf, OVS_CT_ATTR_COMMIT); + } + + if (action->ct.zone) { + nl_msg_put_u16(buf, OVS_CT_ATTR_ZONE, action->ct.zone); + } + + nl_msg_end_nested(buf, ct_offset); + } + break; case TC_ACT_GOTO: { nl_msg_put_u32(buf, OVS_ACTION_ATTR_RECIRC, action->chain); } @@ -834,6 +884,34 @@ parse_mpls_set_action(struct tc_flower *flower, struct tc_action *action, } static int +parse_put_flow_ct_action(struct tc_flower *flower, + struct tc_action *action, + const struct nlattr *ct, + size_t ct_len) +{ + const struct nlattr *ct_attr; + size_t ct_left; + int err; + + NL_ATTR_FOR_EACH_UNSAFE (ct_attr, ct_left, ct, ct_len) { + switch (nl_attr_type(ct_attr)) { + case OVS_CT_ATTR_COMMIT: { + action->ct.commit = true; + } + break; + case OVS_CT_ATTR_ZONE: { + action->ct.zone = nl_attr_get_u16(ct_attr); + } + break; + } + } + + action->type = TC_ACT_CT; + flower->action_count++; + return 0; +} + +static int parse_put_flow_set_masked_action(struct tc_flower *flower, struct tc_action *action, const struct nlattr *set, @@ -1015,16 +1093,6 @@ test_key_and_mask(struct match *match) return EOPNOTSUPP; } - if (mask->ct_state) { - VLOG_DBG_RL(&rl, "offloading attribute ct_state isn't supported"); - return EOPNOTSUPP; - } - - if (mask->ct_zone) { - VLOG_DBG_RL(&rl, "offloading attribute ct_zone isn't supported"); - return EOPNOTSUPP; - } - if (mask->ct_mark) { VLOG_DBG_RL(&rl, "offloading attribute ct_mark isn't supported"); return EOPNOTSUPP; @@ -1363,6 +1431,42 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, } } + if (mask->ct_state) { + if (mask->ct_state & OVS_CS_F_NEW) { + if (key->ct_state & OVS_CS_F_NEW) { + flower.key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_NEW; + } + flower.mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_NEW; + } + + if (mask->ct_state & OVS_CS_F_ESTABLISHED) { + if (key->ct_state & OVS_CS_F_ESTABLISHED) { + flower.key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED; + } + flower.mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED; + } + + if (mask->ct_state & OVS_CS_F_TRACKED) { + if (key->ct_state & OVS_CS_F_TRACKED) { + flower.key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_TRACKED; + } + flower.mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_TRACKED; + } + + if (flower.key.ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) { + flower.key.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW); + flower.mask.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW); + } + + mask->ct_state = 0; + } + + if (mask->ct_zone) { + flower.key.ct_zone = key->ct_zone; + flower.mask.ct_zone = mask->ct_zone; + mask->ct_zone = 0; + } + err = test_key_and_mask(match); if (err) { return err; @@ -1429,6 +1533,18 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, if (err) { return err; } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT) { + const struct nlattr *ct = nl_attr_get(nla); + const size_t ct_len = nl_attr_get_size(nla); + + err = parse_put_flow_ct_action(&flower, action, ct, ct_len); + if (err) { + return err; + } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT_CLEAR) { + action->type = TC_ACT_CT; + action->ct.clear = true; + flower.action_count++; } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) { action->type = TC_ACT_GOTO; action->chain = nl_attr_get_u32(nla); diff --git a/lib/tc.c b/lib/tc.c index cc58320fce2c..841552e1e4a6 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -399,6 +400,10 @@ static const struct nl_policy tca_flower_policy[] = { [TCA_FLOWER_KEY_ENC_OPTS] = { .type = NL_A_NESTED, .optional = true, }, [TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NL_A_NESTED, .optional = true, }, + [TCA_FLOWER_KEY_CT_STATE] = { .type = NL_A_U16, .optional = true, }, + [TCA_FLOWER_KEY_CT_STATE_MASK] = { .type = NL_A_U16, .optional = true, }, + [TCA_FLOWER_KEY_CT_ZONE] = { .type = NL_A_U16, .optional = true, }, + [TCA_FLOWER_KEY_CT_ZONE_MASK] = { .type = NL_A_U16, .optional = true, }, }; static void @@ -703,6 +708,27 @@ nl_parse_flower_tunnel(struct nlattr **attrs, struct tc_flower *flower) } static void +nl_parse_flower_ct_match(struct nlattr **attrs, struct tc_flower *flower) { + struct tc_flower_key *key = &flower->key; + struct tc_flower_key *mask = &flower->mask; + struct nlattr *attr_key, *attr_mask; + + attr_key = attrs[TCA_FLOWER_KEY_CT_STATE]; + attr_mask = attrs[TCA_FLOWER_KEY_CT_STATE_MASK]; + if (attr_mask) { + key->ct_state = nl_attr_get_u16(attr_key); + mask->ct_state = nl_attr_get_u16(attr_mask); + } + + attr_key = attrs[TCA_FLOWER_KEY_CT_ZONE]; + attr_mask = attrs[TCA_FLOWER_KEY_CT_ZONE_MASK]; + if (attrs[TCA_FLOWER_KEY_CT_ZONE_MASK]) { + key->ct_zone = nl_attr_get_u16(attr_key); + mask->ct_zone = nl_attr_get_u16(attr_mask); + } +} + +static void nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) { uint8_t ip_proto = 0; struct tc_flower_key *key = &flower->key; @@ -799,6 +825,8 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) { key->ip_tos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TOS]); mask->ip_tos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TOS_MASK]); } + + nl_parse_flower_ct_match(attrs, flower); } static enum tc_offloaded_state @@ -1219,6 +1247,54 @@ nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower) return 0; } +static const struct nl_policy ct_policy[] = { + [TCA_CT_PARMS] = { .type = NL_A_UNSPEC, + .min_len = sizeof(struct tc_ct), + .optional = false, }, + [TCA_CT_ACTION] = { .type = NL_A_U16, + .optional = true, }, + [TCA_CT_ZONE] = { .type = NL_A_U16, + .optional = true, }, +}; + +static int +nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower) +{ + struct nlattr *ct_attrs[ARRAY_SIZE(ct_policy)]; + const struct nlattr *ct_parms; + struct tc_action *action; + const struct tc_ct *ct; + uint16_t ct_action = 0; + + if (!nl_parse_nested(options, ct_policy, ct_attrs, + ARRAY_SIZE(ct_policy))) { + VLOG_ERR_RL(&error_rl, "failed to parse ct action options"); + return EPROTO; + } + + ct_parms = ct_attrs[TCA_CT_PARMS]; + ct = nl_attr_get_unspec(ct_parms, sizeof *ct); + + if (ct_attrs[TCA_CT_ACTION]) { + ct_action = nl_attr_get_u16(ct_attrs[TCA_CT_ACTION]); + } + + action = &flower->actions[flower->action_count++]; + action->ct.clear = ct_action & TCA_CT_ACT_CLEAR; + if (!action->ct.clear) { + struct nlattr *zone = ct_attrs[TCA_CT_ZONE]; + + action->ct.commit = ct_action & TCA_CT_ACT_COMMIT; + action->ct.force = ct_action & TCA_CT_ACT_FORCE; + + action->ct.zone = zone ? nl_attr_get_u16(zone) : 0; + + } + action->type = TC_ACT_CT; + + return 0; +} + static const struct nl_policy vlan_policy[] = { [TCA_VLAN_PARMS] = { .type = NL_A_UNSPEC, .min_len = sizeof(struct tc_vlan), @@ -1449,6 +1525,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower) nl_parse_act_csum(act_options, flower); } else if (!strcmp(act_kind, "skbedit")) { /* Added for TC rule only (not in OvS rule) so ignore. */ + } else if (!strcmp(act_kind, "ct")) { + nl_parse_act_ct(act_options, flower); } else { VLOG_ERR_RL(&error_rl, "unknown tc action kind: %s", act_kind); err = EINVAL; @@ -1904,6 +1982,40 @@ nl_msg_put_act_gact(struct ofpbuf *request, uint32_t chain) } static void +nl_msg_put_act_ct(struct ofpbuf *request, struct tc_action *action) +{ + uint16_t ct_action = 0; + size_t offset; + + nl_msg_put_string(request, TCA_ACT_KIND, "ct"); + offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED); + { + struct tc_ct ct = { + .action = TC_ACT_PIPE, + }; + + if (!action->ct.clear) { + if (action->ct.zone) { + nl_msg_put_u16(request, TCA_CT_ZONE, action->ct.zone); + } + + if (action->ct.commit) { + ct_action = TCA_CT_ACT_COMMIT; + if (action->ct.force) { + ct_action |= TCA_CT_ACT_FORCE; + } + } + } else { + ct_action = TCA_CT_ACT_CLEAR; + } + + nl_msg_put_u16(request, TCA_CT_ACTION, ct_action); + nl_msg_put_unspec(request, TCA_CT_PARMS, &ct, sizeof ct); + } + nl_msg_end_nested(request, offset); +} + +static void nl_msg_put_act_skbedit_to_host(struct ofpbuf *request) { size_t offset; @@ -2250,6 +2362,13 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) nl_msg_end_nested(request, act_offset); } break; + case TC_ACT_CT: { + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_ct(request, action); + nl_msg_put_act_cookie(request, &flower->act_cookie); + nl_msg_end_nested(request, act_offset); + } + break; } } } @@ -2417,6 +2536,9 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower) FLOWER_PUT_MASKED_VALUE(sctp_src, TCA_FLOWER_KEY_SCTP_SRC); FLOWER_PUT_MASKED_VALUE(sctp_dst, TCA_FLOWER_KEY_SCTP_DST); } + + FLOWER_PUT_MASKED_VALUE(ct_state, TCA_FLOWER_KEY_CT_STATE); + FLOWER_PUT_MASKED_VALUE(ct_zone, TCA_FLOWER_KEY_CT_ZONE); } if (host_eth_type == ETH_P_IP) { diff --git a/lib/tc.h b/lib/tc.h index 42fd1b1b9588..b1e2174b7369 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -116,6 +116,9 @@ struct tc_flower_key { uint8_t ip_ttl; uint8_t ip_tos; + uint16_t ct_state; + uint16_t ct_zone; + struct { ovs_be32 ipv4_src; ovs_be32 ipv4_dst; @@ -157,6 +160,7 @@ enum tc_action_type { TC_ACT_MPLS_PUSH, TC_ACT_MPLS_SET, TC_ACT_GOTO, + TC_ACT_CT, }; struct tc_action { @@ -200,6 +204,13 @@ struct tc_action { } ipv6; struct tun_metadata data; } encap; + + struct { + uint16_t zone; + bool clear; + bool force; + bool commit; + } ct; }; enum tc_action_type type; From patchwork Wed Nov 27 12:55:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201583 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLNy6BS1z9sT7 for ; Wed, 27 Nov 2019 23:56:02 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 2E30A8692B; Wed, 27 Nov 2019 12:56:01 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ejsQoxmpqGV1; Wed, 27 Nov 2019 12:55:59 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 3DF5086702; Wed, 27 Nov 2019 12:55:51 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 21E8DC1DEA; Wed, 27 Nov 2019 12:55:51 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 05846C1DDA for ; Wed, 27 Nov 2019 12:55:39 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id F1C532048B for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id mIexx8pYK+j8 for ; Wed, 27 Nov 2019 12:55:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by silver.osuosl.org (Postfix) with ESMTP id 7D86720519 for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:30 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRs016501; Wed, 27 Nov 2019 14:55:30 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:13 +0200 Message-Id: <20191127125516.5135-8-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 07/10] netdev-offload-tc: Add conntrack label and mark support X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey Signed-off-by: Paul Blakey --- lib/dpif-netlink.c | 2 ++ lib/netdev-offload-tc.c | 66 +++++++++++++++++++++++++++++++++++++++++-------- lib/tc.c | 52 ++++++++++++++++++++++++++++++++++++++ lib/tc.h | 6 +++++ 4 files changed, 116 insertions(+), 10 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 620e94ea4bfc..22ba7cb360fb 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -1603,6 +1603,8 @@ dpif_netlink_netdev_match_to_dpif_flow(struct match *match, .recirc = true, .ct_state = true, .ct_zone = true, + .ct_mark = true, + .ct_label = true, }, }; size_t offset; diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 8dd48ab7c421..2b4ecfb9ca48 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -623,6 +623,8 @@ parse_tc_flower_to_match(struct tc_flower *flower, } match_set_ct_zone_masked(match, key->ct_zone, mask->ct_zone); + match_set_ct_mark_masked(match, key->ct_mark, mask->ct_mark); + match_set_ct_label_masked(match, key->ct_label, mask->ct_label); } if (flower->tunnel) { @@ -792,6 +794,26 @@ parse_tc_flower_to_match(struct tc_flower *flower, nl_msg_put_u16(buf, OVS_CT_ATTR_ZONE, action->ct.zone); } + if (action->ct.mark_mask) { + uint32_t mark_and_mask[2] = { action->ct.mark, + action->ct.mark_mask }; + nl_msg_put_unspec(buf, OVS_CT_ATTR_MARK, &mark_and_mask, + sizeof mark_and_mask); + } + + if (!ovs_u128_is_zero(action->ct.label_mask)) { + struct { + ovs_u128 key; + ovs_u128 mask; + } *ct_label; + + ct_label = nl_msg_put_unspec_uninit(buf, + OVS_CT_ATTR_LABELS, + sizeof *ct_label); + ct_label->key = action->ct.label; + ct_label->mask = action->ct.label_mask; + } + nl_msg_end_nested(buf, ct_offset); } break; @@ -903,6 +925,28 @@ parse_put_flow_ct_action(struct tc_flower *flower, action->ct.zone = nl_attr_get_u16(ct_attr); } break; + case OVS_CT_ATTR_MARK: { + const struct { + uint32_t key; + uint32_t mask; + } *ct_mark; + + ct_mark = nl_attr_get_unspec(ct_attr, sizeof *ct_mark); + action->ct.mark = ct_mark->key; + action->ct.mark_mask = ct_mark->mask; + } + break; + case OVS_CT_ATTR_LABELS: { + const struct { + ovs_u128 key; + ovs_u128 mask; + } *ct_label; + + ct_label = nl_attr_get_unspec(ct_attr, sizeof *ct_label); + action->ct.label = ct_label->key; + action->ct.label_mask = ct_label->mask; + } + break; } } @@ -1093,22 +1137,12 @@ test_key_and_mask(struct match *match) return EOPNOTSUPP; } - if (mask->ct_mark) { - VLOG_DBG_RL(&rl, "offloading attribute ct_mark isn't supported"); - return EOPNOTSUPP; - } - if (mask->packet_type && key->packet_type) { VLOG_DBG_RL(&rl, "offloading attribute packet_type isn't supported"); return EOPNOTSUPP; } mask->packet_type = 0; - if (!ovs_u128_is_zero(mask->ct_label)) { - VLOG_DBG_RL(&rl, "offloading attribute ct_label isn't supported"); - return EOPNOTSUPP; - } - for (int i = 0; i < FLOW_N_REGS; i++) { if (mask->regs[i]) { VLOG_DBG_RL(&rl, @@ -1467,6 +1501,18 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, mask->ct_zone = 0; } + if (mask->ct_mark) { + flower.key.ct_mark = key->ct_mark; + flower.mask.ct_mark = mask->ct_mark; + mask->ct_mark = 0; + } + + if (!ovs_u128_is_zero(mask->ct_label)) { + flower.key.ct_label = key->ct_label; + flower.mask.ct_label = mask->ct_label; + mask->ct_label = OVS_U128_ZERO; + } + err = test_key_and_mask(match); if (err) { return err; diff --git a/lib/tc.c b/lib/tc.c index 841552e1e4a6..1062326d4b86 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -404,6 +404,11 @@ static const struct nl_policy tca_flower_policy[] = { [TCA_FLOWER_KEY_CT_STATE_MASK] = { .type = NL_A_U16, .optional = true, }, [TCA_FLOWER_KEY_CT_ZONE] = { .type = NL_A_U16, .optional = true, }, [TCA_FLOWER_KEY_CT_ZONE_MASK] = { .type = NL_A_U16, .optional = true, }, + [TCA_FLOWER_KEY_CT_MARK] = { .type = NL_A_U32, .optional = true, }, + [TCA_FLOWER_KEY_CT_MARK_MASK] = { .type = NL_A_U32, .optional = true, }, + [TCA_FLOWER_KEY_CT_LABELS] = { .type = NL_A_U128, .optional = true, }, + [TCA_FLOWER_KEY_CT_LABELS_MASK] = { .type = NL_A_U128, + .optional = true, }, }; static void @@ -726,6 +731,20 @@ nl_parse_flower_ct_match(struct nlattr **attrs, struct tc_flower *flower) { key->ct_zone = nl_attr_get_u16(attr_key); mask->ct_zone = nl_attr_get_u16(attr_mask); } + + attr_key = attrs[TCA_FLOWER_KEY_CT_MARK]; + attr_mask = attrs[TCA_FLOWER_KEY_CT_MARK_MASK]; + if (attrs[TCA_FLOWER_KEY_CT_MARK_MASK]) { + key->ct_mark = nl_attr_get_u32(attr_key); + mask->ct_mark = nl_attr_get_u32(attr_mask); + } + + attr_key = attrs[TCA_FLOWER_KEY_CT_LABELS]; + attr_mask = attrs[TCA_FLOWER_KEY_CT_LABELS_MASK]; + if (attrs[TCA_FLOWER_KEY_CT_LABELS_MASK]) { + key->ct_label = nl_attr_get_u128(attr_key); + mask->ct_label = nl_attr_get_u128(attr_mask); + } } static void @@ -1255,6 +1274,14 @@ static const struct nl_policy ct_policy[] = { .optional = true, }, [TCA_CT_ZONE] = { .type = NL_A_U16, .optional = true, }, + [TCA_CT_MARK] = { .type = NL_A_U32, + .optional = true, }, + [TCA_CT_MARK_MASK] = { .type = NL_A_U32, + .optional = true, }, + [TCA_CT_LABELS] = { .type = NL_A_UNSPEC, + .optional = true, }, + [TCA_CT_LABELS_MASK] = { .type = NL_A_UNSPEC, + .optional = true, }, }; static int @@ -1283,11 +1310,20 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower) action->ct.clear = ct_action & TCA_CT_ACT_CLEAR; if (!action->ct.clear) { struct nlattr *zone = ct_attrs[TCA_CT_ZONE]; + struct nlattr *mark = ct_attrs[TCA_CT_MARK]; + struct nlattr *mark_mask = ct_attrs[TCA_CT_MARK_MASK]; + struct nlattr *label = ct_attrs[TCA_CT_LABELS]; + struct nlattr *label_mask = ct_attrs[TCA_CT_LABELS_MASK]; action->ct.commit = ct_action & TCA_CT_ACT_COMMIT; action->ct.force = ct_action & TCA_CT_ACT_FORCE; action->ct.zone = zone ? nl_attr_get_u16(zone) : 0; + action->ct.mark = mark ? nl_attr_get_u32(mark) : 0; + action->ct.mark_mask = mark_mask ? nl_attr_get_u32(mark_mask) : 0; + action->ct.label = label? nl_attr_get_u128(label) : OVS_U128_ZERO; + action->ct.label_mask = label_mask ? + nl_attr_get_u128(label_mask) : OVS_U128_ZERO; } action->type = TC_ACT_CT; @@ -1999,6 +2035,21 @@ nl_msg_put_act_ct(struct ofpbuf *request, struct tc_action *action) nl_msg_put_u16(request, TCA_CT_ZONE, action->ct.zone); } + if (!is_all_zeros(&action->ct.label_mask, + sizeof action->ct.label_mask)) { + nl_msg_put_u128(request, TCA_CT_LABELS, + action->ct.label); + nl_msg_put_u128(request, TCA_CT_LABELS_MASK, + action->ct.label_mask); + } + + if (action->ct.mark_mask) { + nl_msg_put_u32(request, TCA_CT_MARK, + action->ct.mark); + nl_msg_put_u32(request, TCA_CT_MARK_MASK, + action->ct.mark_mask); + } + if (action->ct.commit) { ct_action = TCA_CT_ACT_COMMIT; if (action->ct.force) { @@ -2539,6 +2590,7 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower) FLOWER_PUT_MASKED_VALUE(ct_state, TCA_FLOWER_KEY_CT_STATE); FLOWER_PUT_MASKED_VALUE(ct_zone, TCA_FLOWER_KEY_CT_ZONE); + FLOWER_PUT_MASKED_VALUE(ct_label, TCA_FLOWER_KEY_CT_LABELS); } if (host_eth_type == ETH_P_IP) { diff --git a/lib/tc.h b/lib/tc.h index b1e2174b7369..e853aeb77468 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -118,6 +118,8 @@ struct tc_flower_key { uint16_t ct_state; uint16_t ct_zone; + uint32_t ct_mark; + ovs_u128 ct_label; struct { ovs_be32 ipv4_src; @@ -207,6 +209,10 @@ struct tc_action { struct { uint16_t zone; + uint32_t mark; + uint32_t mark_mask; + ovs_u128 label; + ovs_u128 label_mask; bool clear; bool force; bool commit; From patchwork Wed Nov 27 12:55:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201577 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLNd2DgGz9sTB for ; Wed, 27 Nov 2019 23:55:45 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 968DA86521; Wed, 27 Nov 2019 12:55:42 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 61QOJt1x_8aL; Wed, 27 Nov 2019 12:55:40 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 596FC86463; Wed, 27 Nov 2019 12:55:40 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 38D48C1DE1; Wed, 27 Nov 2019 12:55:40 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4A8DFC0881 for ; Wed, 27 Nov 2019 12:55:37 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 3CBE48761B for ; Wed, 27 Nov 2019 12:55:37 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qlsUe4VlwlQb for ; Wed, 27 Nov 2019 12:55:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by whitealder.osuosl.org (Postfix) with ESMTP id 72F028760E for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:30 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRt016501; Wed, 27 Nov 2019 14:55:30 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:14 +0200 Message-Id: <20191127125516.5135-9-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 08/10] netdev-offload-tc: Add conntrack nat support X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey Changelog: V1->V2: Missing ntohs/htons on nat port range. Signed-off-by: Paul Blakey --- lib/netdev-offload-tc.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/tc.c | 91 ++++++++++++++++++++++++++++++++++++++++++ lib/tc.h | 24 +++++++++++ 3 files changed, 219 insertions(+) diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 2b4ecfb9ca48..3a9b9e144311 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -814,6 +814,40 @@ parse_tc_flower_to_match(struct tc_flower *flower, ct_label->mask = action->ct.label_mask; } + if (action->ct.nat_type) { + size_t nat_offset = nl_msg_start_nested(buf, + OVS_CT_ATTR_NAT); + + if (action->ct.nat_type == TC_NAT_SRC) { + nl_msg_put_flag(buf, OVS_NAT_ATTR_SRC); + } else if (action->ct.nat_type == TC_NAT_DST) { + nl_msg_put_flag(buf, OVS_NAT_ATTR_DST); + } + + if (action->ct.range.ip_family == AF_INET) { + nl_msg_put_be32(buf, OVS_NAT_ATTR_IP_MIN, + action->ct.range.min_addr.ipv4); + nl_msg_put_be32(buf, OVS_NAT_ATTR_IP_MAX, + action->ct.range.max_addr.ipv4); + } else if (action->ct.range.ip_family == AF_INET6) { + nl_msg_put_in6_addr(buf, OVS_NAT_ATTR_IP_MIN, + &action->ct.range.min_addr.ipv6); + nl_msg_put_in6_addr(buf, OVS_NAT_ATTR_IP_MAX, + &action->ct.range.max_addr.ipv6); + } + + if (action->ct.range.min_port) { + nl_msg_put_u16(buf, OVS_NAT_ATTR_PROTO_MIN, + ntohs(action->ct.range.min_port)); + if (action->ct.range.max_port) { + nl_msg_put_u16(buf, OVS_NAT_ATTR_PROTO_MAX, + ntohs(action->ct.range.max_port)); + } + } + + nl_msg_end_nested(buf, nat_offset); + } + nl_msg_end_nested(buf, ct_offset); } break; @@ -906,6 +940,66 @@ parse_mpls_set_action(struct tc_flower *flower, struct tc_action *action, } static int +parse_put_flow_nat_action(struct tc_action *action, + const struct nlattr *nat, + size_t nat_len) +{ + const struct nlattr *nat_attr; + size_t nat_left; + + action->ct.nat_type = TC_NAT_RESTORE; + NL_ATTR_FOR_EACH_UNSAFE (nat_attr, nat_left, nat, nat_len) { + switch (nl_attr_type(nat_attr)) { + case OVS_NAT_ATTR_SRC: { + action->ct.nat_type = TC_NAT_SRC; + }; + break; + case OVS_NAT_ATTR_DST: { + action->ct.nat_type = TC_NAT_DST; + }; + break; + case OVS_NAT_ATTR_IP_MIN: { + if (nl_attr_get_size(nat_attr) == sizeof(ovs_be32)) { + ovs_be32 addr = nl_attr_get_be32(nat_attr); + + action->ct.range.min_addr.ipv4 = addr; + action->ct.range.ip_family = AF_INET; + } else { + struct in6_addr addr = nl_attr_get_in6_addr(nat_attr); + + action->ct.range.min_addr.ipv6 = addr; + action->ct.range.ip_family = AF_INET6; + } + }; + break; + case OVS_NAT_ATTR_IP_MAX: { + if (nl_attr_get_size(nat_attr) == sizeof(ovs_be32)) { + ovs_be32 addr = nl_attr_get_be32(nat_attr); + + action->ct.range.max_addr.ipv4 = addr; + action->ct.range.ip_family = AF_INET; + } else { + struct in6_addr addr = nl_attr_get_in6_addr(nat_attr); + + action->ct.range.max_addr.ipv6 = addr; + action->ct.range.ip_family = AF_INET6; + } + }; + break; + case OVS_NAT_ATTR_PROTO_MIN: { + action->ct.range.min_port = htons(nl_attr_get_u16(nat_attr)); + }; + break; + case OVS_NAT_ATTR_PROTO_MAX: { + action->ct.range.max_port = htons(nl_attr_get_u16(nat_attr)); + }; + break; + } + } + return 0; +} + +static int parse_put_flow_ct_action(struct tc_flower *flower, struct tc_action *action, const struct nlattr *ct, @@ -925,6 +1019,16 @@ parse_put_flow_ct_action(struct tc_flower *flower, action->ct.zone = nl_attr_get_u16(ct_attr); } break; + case OVS_CT_ATTR_NAT: { + const struct nlattr *nat = nl_attr_get(ct_attr); + const size_t nat_len = nl_attr_get_size(ct_attr); + + err = parse_put_flow_nat_action(action, nat, nat_len); + if (err) { + return err; + } + } + break; case OVS_CT_ATTR_MARK: { const struct { uint32_t key; diff --git a/lib/tc.c b/lib/tc.c index 1062326d4b86..83ee0f6473aa 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -1282,6 +1282,18 @@ static const struct nl_policy ct_policy[] = { .optional = true, }, [TCA_CT_LABELS_MASK] = { .type = NL_A_UNSPEC, .optional = true, }, + [TCA_CT_NAT_IPV4_MIN] = { .type = NL_A_U32, + .optional = true, }, + [TCA_CT_NAT_IPV4_MAX] = { .type = NL_A_U32, + .optional = true, }, + [TCA_CT_NAT_IPV6_MIN] = { .min_len = sizeof(struct in6_addr), + .optional = true, }, + [TCA_CT_NAT_IPV6_MAX] = { .min_len = sizeof(struct in6_addr), + .optional = true, }, + [TCA_CT_NAT_PORT_MIN] = { .type = NL_A_U16, + .optional = true, }, + [TCA_CT_NAT_PORT_MAX] = { .type = NL_A_U16, + .optional = true, }, }; static int @@ -1325,6 +1337,47 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower) action->ct.label_mask = label_mask ? nl_attr_get_u128(label_mask) : OVS_U128_ZERO; + if (ct_action & TCA_CT_ACT_NAT) { + struct nlattr *ipv4_min = ct_attrs[TCA_CT_NAT_IPV4_MIN]; + struct nlattr *ipv4_max = ct_attrs[TCA_CT_NAT_IPV4_MAX]; + struct nlattr *ipv6_min = ct_attrs[TCA_CT_NAT_IPV6_MIN]; + struct nlattr *ipv6_max = ct_attrs[TCA_CT_NAT_IPV6_MAX]; + struct nlattr *min_port = ct_attrs[TCA_CT_NAT_PORT_MIN]; + struct nlattr *max_port = ct_attrs[TCA_CT_NAT_PORT_MAX]; + + action->ct.nat_type = TC_NAT_RESTORE; + if (ct_action & TCA_CT_ACT_NAT_SRC) { + action->ct.nat_type = TC_NAT_SRC; + } else if (ct_action & TCA_CT_ACT_NAT_DST) { + action->ct.nat_type = TC_NAT_DST; + } + + if (ipv4_min) { + action->ct.range.ip_family = AF_INET; + action->ct.range.min_addr.ipv4 = nl_attr_get_be32(ipv4_min); + if (ipv4_max) { + ovs_be32 port = nl_attr_get_be32(ipv4_max); + + action->ct.range.max_addr.ipv4 = port; + } + } else if (ipv6_min) { + action->ct.range.ip_family = AF_INET6; + action->ct.range.min_addr.ipv6 + = nl_attr_get_in6_addr(ipv6_min); + if (ipv6_max) { + struct in6_addr addr = nl_attr_get_in6_addr(ipv6_max); + + action->ct.range.max_addr.ipv6 = addr; + } + } + + if (min_port) { + action->ct.range.min_port = nl_attr_get_be16(min_port); + if (max_port) { + action->ct.range.max_port = nl_attr_get_be16(max_port); + } + } + } } action->type = TC_ACT_CT; @@ -2056,6 +2109,44 @@ nl_msg_put_act_ct(struct ofpbuf *request, struct tc_action *action) ct_action |= TCA_CT_ACT_FORCE; } } + + if (action->ct.nat_type) { + ct_action |= TCA_CT_ACT_NAT; + + if (action->ct.nat_type == TC_NAT_SRC) { + ct_action |= TCA_CT_ACT_NAT_SRC; + } else if (action->ct.nat_type == TC_NAT_DST) { + ct_action |= TCA_CT_ACT_NAT_DST; + } + + if (action->ct.range.ip_family == AF_INET) { + nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MIN, + action->ct.range.min_addr.ipv4); + if (action->ct.range.max_addr.ipv4) { + nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MAX, + action->ct.range.max_addr.ipv4); + } + } else if (action->ct.range.ip_family == AF_INET6) { + size_t ipv6_sz = sizeof(action->ct.range.max_addr.ipv6); + + nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MIN, + &action->ct.range.min_addr.ipv6); + if (!is_all_zeros(&action->ct.range.max_addr.ipv6, + ipv6_sz)) { + nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MAX, + &action->ct.range.max_addr.ipv6); + } + } + + if (action->ct.range.min_port) { + nl_msg_put_be16(request, TCA_CT_NAT_PORT_MIN, + action->ct.range.min_port); + if (action->ct.range.max_port) { + nl_msg_put_be16(request, TCA_CT_NAT_PORT_MAX, + action->ct.range.max_port); + } + } + } } else { ct_action = TCA_CT_ACT_CLEAR; } diff --git a/lib/tc.h b/lib/tc.h index e853aeb77468..15e58f88acb9 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -165,6 +165,13 @@ enum tc_action_type { TC_ACT_CT, }; +enum nat_type { + TC_NO_NAT = 0, + TC_NAT_SRC, + TC_NAT_DST, + TC_NAT_RESTORE, +}; + struct tc_action { union { int chain; @@ -213,6 +220,23 @@ struct tc_action { uint32_t mark_mask; ovs_u128 label; ovs_u128 label_mask; + uint8_t nat_type; + struct { + uint8_t ip_family; + + union { + struct in6_addr ipv6; + ovs_be32 ipv4; + } min_addr; + + union { + struct in6_addr ipv6; + ovs_be32 ipv4; + } max_addr; + + ovs_be16 min_port; + ovs_be16 max_port; + } range; bool clear; bool force; bool commit; From patchwork Wed Nov 27 12:55:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201576 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLNb3tDFz9sT7 for ; Wed, 27 Nov 2019 23:55:43 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 3AD5F864D0; Wed, 27 Nov 2019 12:55:41 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id n2klb9XwNA_H; Wed, 27 Nov 2019 12:55:39 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 6B121863BB; Wed, 27 Nov 2019 12:55:39 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 35EC3C1DDA; Wed, 27 Nov 2019 12:55:39 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4EFD3C1DDA for ; Wed, 27 Nov 2019 12:55:37 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 3CD8587657 for ; Wed, 27 Nov 2019 12:55:37 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Qtv9UNHXDXdl for ; Wed, 27 Nov 2019 12:55:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by whitealder.osuosl.org (Postfix) with ESMTP id 70CAE875A9 for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:30 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRu016501; Wed, 27 Nov 2019 14:55:30 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:15 +0200 Message-Id: <20191127125516.5135-10-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 09/10] tc: Move tunnel_key unset action before output ports X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey Since OvS datapath gets packets already decapsulated from tunnel devices, it doesn't explicitly decapsulate them. So in a recirculation setup, the tunnel matching continues in the recirculation as the tunnel metadata still exists on the SKB. Tunnel key unset action unsets this metadata. Some drivers might rely on this explicit tunnel key unset to know when to decapsulate the packet instead of the device type. So instead of removing it completly, we move it near the output actions. This way, we also keep SKB metadata through recirculation, and for non-recirculation rules, the resulting tc rules should remain the same. Signed-off-by: Paul Blakey --- lib/tc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/tc.c b/lib/tc.c index 83ee0f6473aa..1541629a58e8 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -2364,12 +2364,12 @@ nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request, static int nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) { + bool ingress, released = false; size_t offset; size_t act_offset; uint16_t act_index = 1; struct tc_action *action; int i, ifindex = 0; - bool ingress; offset = nl_msg_start_nested(request, TCA_FLOWER_ACT); { @@ -2458,6 +2458,13 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) } break; case TC_ACT_OUTPUT: { + if (!released && flower->tunnel) { + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_tunnel_key_release(request); + nl_msg_end_nested(request, act_offset); + released = true; + } + ingress = action->out.ingress; ifindex = action->out.ifindex_out; if (ifindex < 1) { From patchwork Wed Nov 27 12:55:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201582 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=whitealder.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLNt1DQFz9sT7 for ; Wed, 27 Nov 2019 23:55:58 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 9825C876D4; Wed, 27 Nov 2019 12:55:56 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id EcZHqQkvOW4M; Wed, 27 Nov 2019 12:55:49 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by whitealder.osuosl.org (Postfix) with ESMTP id F0EFE876B2; Wed, 27 Nov 2019 12:55:45 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8E573C1DE8; Wed, 27 Nov 2019 12:55:45 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 68920C1DDA for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 657158829D for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id id+iyP0rngHD for ; Wed, 27 Nov 2019 12:55:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id 7ADD68829B for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:30 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRv016501; Wed, 27 Nov 2019 14:55:30 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:16 +0200 Message-Id: <20191127125516.5135-11-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 10/10] netdev-offloads-tc: Probe recirc tc sharing feature on first recirc_id rule X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey Since recirculations splits the datapath processing into multiple rules, and we offload them to tc, when we are done processing in tc, we need to continue in the correct recirc_id in OvS. For that, tc needs to pass the recirculation id back to OvS. We check for kernel support for this by probing OvS Datapath for the tc recirc id sharing feature. If supported, we can offload rules that match on recirc_id, and recirculation action safely. Signed-off-by: Paul Blakey --- datapath/linux/compat/include/linux/openvswitch.h | 3 ++ lib/dpif-netdev.c | 1 + lib/dpif-netlink.c | 59 ++++++++++++++++++++--- lib/dpif-provider.h | 2 + lib/dpif.c | 9 ++++ lib/dpif.h | 2 + lib/netdev-offload-tc.c | 36 ++++++++++++-- lib/netdev-offload.h | 2 +- 8 files changed, 103 insertions(+), 11 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 7b16b1d5bfe0..3fa95dfe7a41 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -143,6 +143,9 @@ struct ovs_vport_stats { /* Allow datapath to associate multiple Netlink PIDs to each vport */ #define OVS_DP_F_VPORT_PIDS (1 << 1) +/* Allow tc offload recirc sharing */ +#define OVS_DP_F_TC_RECIRC_SHARING (1 << 2) + /* Fixed logical ports. */ #define OVSP_LOCAL ((__u32)0) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 4720ba1ab21b..77cf1672571c 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -7535,6 +7535,7 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_run, dpif_netdev_wait, dpif_netdev_get_stats, + NULL, /* set_features */ dpif_netdev_port_add, dpif_netdev_port_del, dpif_netdev_port_set_config, diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 22ba7cb360fb..68e45c4af111 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -193,6 +193,7 @@ struct dpif_handler { struct dpif_netlink { struct dpif dpif; int dp_ifindex; + uint32_t user_features; /* Upcall messages. */ struct fat_rwlock upcall_lock; @@ -334,15 +335,26 @@ dpif_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name, /* Create or look up datapath. */ dpif_netlink_dp_init(&dp_request); + upcall_pid = 0; + dp_request.upcall_pid = &upcall_pid; + dp_request.name = name; + if (create) { dp_request.cmd = OVS_DP_CMD_NEW; - upcall_pid = 0; - dp_request.upcall_pid = &upcall_pid; } else { + dp_request.cmd = OVS_DP_CMD_GET; + + error = dpif_netlink_dp_transact(&dp_request, &dp, &buf); + if (error) { + return error; + } + dp_request.user_features = dp.user_features; + ofpbuf_delete(buf); + /* Use OVS_DP_CMD_SET to report user features */ dp_request.cmd = OVS_DP_CMD_SET; } - dp_request.name = name; + dp_request.user_features |= OVS_DP_F_UNALIGNED; dp_request.user_features |= OVS_DP_F_VPORT_PIDS; error = dpif_netlink_dp_transact(&dp_request, &dp, &buf); @@ -368,6 +380,7 @@ open_dpif(const struct dpif_netlink_dp *dp, struct dpif **dpifp) dp->dp_ifindex, dp->dp_ifindex); dpif->dp_ifindex = dp->dp_ifindex; + dpif->user_features = dp->user_features; *dpifp = &dpif->dpif; return 0; @@ -664,6 +677,31 @@ dpif_netlink_get_stats(const struct dpif *dpif_, struct dpif_dp_stats *stats) return error; } +static int +dpif_netlink_set_features(struct dpif *dpif_, uint32_t new_features) +{ + struct dpif_netlink *dpif = dpif_netlink_cast(dpif_); + struct dpif_netlink_dp request, reply; + struct ofpbuf *bufp; + int error; + + dpif_netlink_dp_init(&request); + request.cmd = OVS_DP_CMD_SET; + request.dp_ifindex = dpif->dp_ifindex; + request.user_features = dpif->user_features | new_features; + + error = dpif_netlink_dp_transact(&request, &reply, &bufp); + if (!error) { + dpif->user_features = reply.user_features; + ofpbuf_delete(bufp); + if (!(dpif->user_features & new_features)) { + return -EOPNOTSUPP; + } + } + + return error; +} + static const char * get_vport_type(const struct dpif_netlink_vport *vport) { @@ -1991,7 +2029,6 @@ static int parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); - const struct dpif_class *dpif_class = dpif->dpif.dpif_class; struct match match; odp_port_t in_port; const struct nlattr *nla; @@ -2013,7 +2050,7 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put) } in_port = match.flow.in_port.odp_port; - dev = netdev_ports_get(in_port, dpif_class); + dev = netdev_ports_get(in_port, dpif->dpif.dpif_class); if (!dev) { return EOPNOTSUPP; } @@ -2026,7 +2063,7 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put) odp_port_t out_port; out_port = nl_attr_get_odp_port(nla); - outdev = netdev_ports_get(out_port, dpif_class); + outdev = netdev_ports_get(out_port, dpif->dpif.dpif_class); if (!outdev) { err = EOPNOTSUPP; goto out; @@ -2042,7 +2079,7 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put) } } - info.dpif_class = dpif_class; + info.dpif = &dpif->dpif; info.tp_dst_port = dst_port; info.tunnel_csum_on = csum_on; err = netdev_flow_put(dev, &match, @@ -3884,6 +3921,7 @@ const struct dpif_class dpif_netlink_class = { dpif_netlink_run, NULL, /* wait */ dpif_netlink_get_stats, + dpif_netlink_set_features, dpif_netlink_port_add, dpif_netlink_port_del, NULL, /* port_set_config */ @@ -4201,6 +4239,9 @@ dpif_netlink_dp_from_ofpbuf(struct dpif_netlink_dp *dp, const struct ofpbuf *buf [OVS_DP_ATTR_MEGAFLOW_STATS] = { NL_POLICY_FOR(struct ovs_dp_megaflow_stats), .optional = true }, + [OVS_DP_ATTR_USER_FEATURES] = { + .type = NL_A_U32, + .optional = true }, }; dpif_netlink_dp_init(dp); @@ -4229,6 +4270,10 @@ dpif_netlink_dp_from_ofpbuf(struct dpif_netlink_dp *dp, const struct ofpbuf *buf dp->megaflow_stats = nl_attr_get(a[OVS_DP_ATTR_MEGAFLOW_STATS]); } + if (a[OVS_DP_ATTR_USER_FEATURES]) { + dp->user_features = nl_attr_get_u32(a[OVS_DP_ATTR_USER_FEATURES]); + } + return 0; } diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index f8ca310d0fa5..b77317bca18b 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -188,6 +188,8 @@ struct dpif_class { /* Retrieves statistics for 'dpif' into 'stats'. */ int (*get_stats)(const struct dpif *dpif, struct dpif_dp_stats *stats); + int (*set_features)(struct dpif *dpif, uint32_t user_features); + /* Adds 'netdev' as a new port in 'dpif'. If '*port_no' is not * ODPP_NONE, attempts to use that as the port's port number. * diff --git a/lib/dpif.c b/lib/dpif.c index c88b2106f086..dc13655aa832 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -543,6 +543,15 @@ dpif_get_dp_stats(const struct dpif *dpif, struct dpif_dp_stats *stats) return error; } +int +dpif_set_features(struct dpif *dpif, uint32_t new_features) +{ + int error = dpif->dpif_class->set_features(dpif, new_features); + + log_operation(dpif, "set_features", error); + return error; +} + const char * dpif_port_open_type(const char *datapath_type, const char *port_type) { diff --git a/lib/dpif.h b/lib/dpif.h index 289d574a01f8..c7bb48f8b9c4 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -435,6 +435,8 @@ struct dpif_dp_stats { }; int dpif_get_dp_stats(const struct dpif *, struct dpif_dp_stats *); +int dpif_set_features(struct dpif *, uint32_t new_features); + /* Port operations. */ diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 3a9b9e144311..6d3bc57eccd2 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -38,6 +38,7 @@ #include "tc.h" #include "unaligned.h" #include "util.h" +#include "dpif-provider.h" VLOG_DEFINE_THIS_MODULE(netdev_offload_tc); @@ -1350,6 +1351,25 @@ flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl, flower->mask.tunnel.metadata.present.len = tnl->metadata.present.len; } +static bool +recirc_id_sharing_support(struct dpif *dpif) +{ + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + static bool supported = false; + int err; + + if (ovsthread_once_start(&once)) { + err = dpif_set_features(dpif, OVS_DP_F_TC_RECIRC_SHARING); + supported = err ? false : true; + if (supported) { + VLOG_INFO("probe tc: tc recirc id sharing with OvS datapath is supported."); + } + ovsthread_once_done(&once); + } + + return supported; +} + static int netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct nlattr *actions, size_t actions_len, @@ -1367,7 +1387,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, uint32_t block_id = 0; struct nlattr *nla; struct tc_id id; - uint32_t chain; + uint32_t chain = 0; size_t left; int prio = 0; int ifindex; @@ -1382,7 +1402,13 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, memset(&flower, 0, sizeof flower); - chain = key->recirc_id; + if (key->recirc_id) { + if (recirc_id_sharing_support(info->dpif)) { + chain = key->recirc_id; + } else { + return EOPNOTSUPP; + } + } mask->recirc_id = 0; if (flow_tnl_dst_is_set(&key->tunnel)) { @@ -1630,7 +1656,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, action = &flower.actions[flower.action_count]; if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) { odp_port_t port = nl_attr_get_odp_port(nla); - struct netdev *outdev = netdev_ports_get(port, info->dpif_class); + struct netdev *outdev = netdev_ports_get(port, + info->dpif->dpif_class); action->out.ifindex_out = netdev_get_ifindex(outdev); action->out.ingress = is_internal_port(netdev_get_type(outdev)); @@ -1696,6 +1723,9 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, action->ct.clear = true; flower.action_count++; } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) { + if (!recirc_id_sharing_support(info->dpif)) { + return EOPNOTSUPP; + } action->type = TC_ACT_GOTO; action->chain = nl_attr_get_u32(nla); flower.action_count++; diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h index 97a50064715d..d852fe2acd90 100644 --- a/lib/netdev-offload.h +++ b/lib/netdev-offload.h @@ -62,7 +62,7 @@ struct netdev_flow_dump { /* Flow offloading. */ struct offload_info { - const struct dpif_class *dpif_class; + struct dpif *dpif; ovs_be16 tp_dst_port; /* Destination port for tunnel in SET action */ uint8_t tunnel_csum_on; /* Tunnel header with checksum */