From patchwork Sun Dec 22 10:16:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1214631 X-Patchwork-Delegate: horms@verge.net.au 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 47gdhF6DqBz9sPn for ; Sun, 22 Dec 2019 21:17:17 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 3DBEB8818B; Sun, 22 Dec 2019 10:17:16 +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 cdvCdt0m+9MD; Sun, 22 Dec 2019 10:17:13 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 17DD5880CA; Sun, 22 Dec 2019 10:16:58 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 002E2C1D81; Sun, 22 Dec 2019 10:16:58 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id E710BC1D81 for ; Sun, 22 Dec 2019 10:16:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id C7FD5860F4 for ; Sun, 22 Dec 2019 10:16:51 +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 rQ0y5pvDo9q8 for ; Sun, 22 Dec 2019 10:16:49 +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 fraxinus.osuosl.org (Postfix) with ESMTP id 3FB1A860B2 for ; Sun, 22 Dec 2019 10:16:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 22 Dec 2019 12:16:46 +0200 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xBMAGkdl028294; Sun, 22 Dec 2019 12:16:46 +0200 From: Paul Blakey To: Paul Blakey , Roi Dayan , Simon Horman , Oz Shlomo , Marcelo Ricardo Leitner , Justin Pettit , Ilya Maximets , Ben Pfaff , dev@openvswitch.org Date: Sun, 22 Dec 2019 12:16:34 +0200 Message-Id: <1577009803-4331-2-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1577009803-4331-1-git-send-email-paulb@mellanox.com> References: <1577009803-4331-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v7 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" Sets zone in match. Signed-off-by: Paul Blakey Reviewed-by: Roi Dayan --- 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 05ecee7..eeabd5f 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 ae56828..0d1ec31 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 Sun Dec 22 10:16:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1214628 X-Patchwork-Delegate: horms@verge.net.au 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 47gdh62Y6vz9sPn for ; Sun, 22 Dec 2019 21:17:10 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 95DD02048F; Sun, 22 Dec 2019 10:17:08 +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 QM7RuXipY-Zj; Sun, 22 Dec 2019 10:17:02 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 5D70D20766; Sun, 22 Dec 2019 10:16:54 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 523AAC1D88; Sun, 22 Dec 2019 10:16:54 +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 488FEC1D81 for ; Sun, 22 Dec 2019 10:16:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 37FB8865E2 for ; Sun, 22 Dec 2019 10:16:51 +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 wszWJ3O9BJJc for ; Sun, 22 Dec 2019 10:16:49 +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 3299486759 for ; Sun, 22 Dec 2019 10:16:48 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 22 Dec 2019 12:16:46 +0200 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xBMAGkdm028294; Sun, 22 Dec 2019 12:16:46 +0200 From: Paul Blakey To: Paul Blakey , Roi Dayan , Simon Horman , Oz Shlomo , Marcelo Ricardo Leitner , Justin Pettit , Ilya Maximets , Ben Pfaff , dev@openvswitch.org Date: Sun, 22 Dec 2019 12:16:35 +0200 Message-Id: <1577009803-4331-3-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1577009803-4331-1-git-send-email-paulb@mellanox.com> References: <1577009803-4331-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v7 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" Update kernel UAPI to support conntrack matches, and the tc actions ct and goto chain. Signed-off-by: Paul Blakey Reviewed-by: Roi Dayan --- 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 c759186..8f063f4 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 55f3ef1..b0a5ce8 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 0000000..5fb1d7a --- /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 Sun Dec 22 10:16:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1214633 X-Patchwork-Delegate: horms@verge.net.au 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 47gdhh6hvRz9sPn for ; Sun, 22 Dec 2019 21:17:40 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 58655881DC; Sun, 22 Dec 2019 10:17: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 QcJp3aYHSwaw; Sun, 22 Dec 2019 10:17:29 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id E8B6888231; Sun, 22 Dec 2019 10:17:01 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C1A13C1D8D; Sun, 22 Dec 2019 10:17:01 +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 56E98C1D81 for ; Sun, 22 Dec 2019 10:16:52 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 39F37865E2 for ; Sun, 22 Dec 2019 10:16:52 +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 Waw0T5Yra7Zr for ; Sun, 22 Dec 2019 10:16:50 +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 3453D8687B for ; Sun, 22 Dec 2019 10:16:48 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 22 Dec 2019 12:16:46 +0200 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xBMAGkdn028294; Sun, 22 Dec 2019 12:16:46 +0200 From: Paul Blakey To: Paul Blakey , Roi Dayan , Simon Horman , Oz Shlomo , Marcelo Ricardo Leitner , Justin Pettit , Ilya Maximets , Ben Pfaff , dev@openvswitch.org Date: Sun, 22 Dec 2019 12:16:36 +0200 Message-Id: <1577009803-4331-4-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1577009803-4331-1-git-send-email-paulb@mellanox.com> References: <1577009803-4331-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v7 03/10] tc: Introduce tcf_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" Move all that is needed to identify a tc filter to a new structure, tcf_id. This removes a lot of duplication in accessing/creating tc filters. Signed-off-by: Paul Blakey Reviewed-by: Roi Dayan --- Changelog: V3->V4: Fix accidently removed Block_id in flow_put() V2->V3: Renamed *tc_id* -> *tcf_id* Renamed make_tc_id -> tc_make_tcf_id to be consistent with tc_make_* helpers 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 make_tc_id to be static inline in tc.h --- lib/netdev-linux.c | 6 +- lib/netdev-offload-tc.c | 205 ++++++++++++++++++++---------------------------- lib/tc.c | 109 ++++++++----------------- lib/tc.h | 51 +++++++++--- 4 files changed, 159 insertions(+), 212 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index f8e59ba..8a62f9d 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -2356,7 +2356,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 tcf_id id; int ifindex; int err; @@ -2365,8 +2367,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 = tc_make_tcf_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 1adbb32..460c27f 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 tcf_id key. * @ufid: ufid assigned to the flow - * @prio: tc priority - * @handle: tc handle - * @ifindex: netdev ifindex. + * @id: tc filter id (tcf_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 tcf_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 tcf_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 tcf_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 tcf_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 tcf_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 tcf_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_tcf_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 tcf_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 = tc_make_tcf_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 tcf_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 = tc_make_tcf_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 tcf_id id; + + id = tc_make_tcf_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 tcf_id id; size_t left; int prio = 0; - int handle; int ifindex; int err; @@ -1428,38 +1419,36 @@ 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); + block_id = get_block_id_from_netdev(netdev); + id = tc_make_tcf_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 +1457,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 tcf_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 +1493,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 tcf_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 +1519,9 @@ static void probe_multi_mask_per_prio(int ifindex) { struct tc_flower flower; + struct tcf_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 +1536,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 = tc_make_tcf_id(ifindex, block_id, prio, TC_INGRESS); + error = tc_replace_flower(&id1, &flower); if (error) { goto out; } @@ -1588,14 +1545,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 = tc_make_tcf_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 +1567,8 @@ probe_tc_block_support(int ifindex) { struct tc_flower flower; uint32_t block_id = 1; + struct tcf_id id; + int prio = 0; int error; error = tc_add_del_qdisc(ifindex, true, block_id, TC_INGRESS); @@ -1623,7 +1583,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 = tc_make_tcf_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 ba3e9d0..b2d8ca7 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_tcf_id(struct tcf_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 tcf_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 tcf_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_tcf_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 tcf_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_tcf_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 tcf_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_tcf_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 tcf_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_tcf_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 f4073c6..da9a766 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 tcf_id { + enum tc_qdisc_hook hook; + uint32_t block_id; + int ifindex; + uint16_t prio; uint32_t handle; - uint32_t prio; +}; + +static inline struct tcf_id +tc_make_tcf_id(int ifindex, uint32_t block_id, uint16_t prio, + enum tc_qdisc_hook hook) +{ + struct tcf_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_tcf_id_eq(struct tcf_id *id1, struct tcf_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 tcf_id *id, struct tc_flower *flower); +int tc_del_filter(struct tcf_id *id); +int tc_get_flower(struct tcf_id *id, struct tc_flower *flower); +int tc_dump_flower_start(struct tcf_id *id, struct nl_dump *dump); int parse_netlink_to_tc_flower(struct ofpbuf *reply, + struct tcf_id *id, struct tc_flower *flower); void tc_set_policy(const char *policy); From patchwork Sun Dec 22 10:16:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1214627 X-Patchwork-Delegate: horms@verge.net.au 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 47gdh41RH5z9sPn for ; Sun, 22 Dec 2019 21:17:08 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id ADF7F882A4; Sun, 22 Dec 2019 10:17:06 +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 Ge51IvdLcJoi; Sun, 22 Dec 2019 10:17:02 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 7EDB887FBF; Sun, 22 Dec 2019 10:16:55 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 236D7C1D89; Sun, 22 Dec 2019 10:16:55 +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 6158BC0881 for ; Sun, 22 Dec 2019 10:16:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 5DCB11FE2F for ; Sun, 22 Dec 2019 10:16:51 +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 fhJhM88PxgAY for ; Sun, 22 Dec 2019 10:16:49 +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 3F1F220131 for ; Sun, 22 Dec 2019 10:16:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 22 Dec 2019 12:16:47 +0200 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xBMAGkdo028294; Sun, 22 Dec 2019 12:16:46 +0200 From: Paul Blakey To: Paul Blakey , Roi Dayan , Simon Horman , Oz Shlomo , Marcelo Ricardo Leitner , Justin Pettit , Ilya Maximets , Ben Pfaff , dev@openvswitch.org Date: Sun, 22 Dec 2019 12:16:37 +0200 Message-Id: <1577009803-4331-5-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1577009803-4331-1-git-send-email-paulb@mellanox.com> References: <1577009803-4331-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v7 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" 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 Reviewed-by: Roi Dayan --- 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 460c27f..15b39e6 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 tcf_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 tcf_id key. * @ufid: ufid assigned to the flow * @id: tc filter id (tcf_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 tcf_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 tcf_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 tcf_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 tcf_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 tcf_id *id) return ENOENT; } -/* Find ufid entry in ufid_tc hashmap using tcf_id id. +/* Find ufid entry in ufid_to_tc hashmap using tcf_id id. * The result is saved in ufid. * * Returns true on success. @@ -250,7 +256,7 @@ find_ufid(struct netdev *netdev, struct tcf_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_tcf_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 tcf_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 = tc_make_tcf_id(ifindex, block_id, prio, hook); - return tc_del_filter(&id); + return 0; } static int From patchwork Sun Dec 22 10:16:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1214629 X-Patchwork-Delegate: horms@verge.net.au 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 47gdh80s9fz9sPn for ; Sun, 22 Dec 2019 21:17:12 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 63F2287FB2; Sun, 22 Dec 2019 10:17:10 +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 hx4xcYIKUqAh; Sun, 22 Dec 2019 10:17:03 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 219E987FE9; Sun, 22 Dec 2019 10:16:56 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0EBBFC0881; Sun, 22 Dec 2019 10:16:56 +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 746D5C1D81 for ; Sun, 22 Dec 2019 10:16:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 63E181FE2F for ; Sun, 22 Dec 2019 10:16:51 +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 HyIomfk7ae8O for ; Sun, 22 Dec 2019 10:16:49 +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 3F09820116 for ; Sun, 22 Dec 2019 10:16:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 22 Dec 2019 12:16:47 +0200 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xBMAGkdp028294; Sun, 22 Dec 2019 12:16:47 +0200 From: Paul Blakey To: Paul Blakey , Roi Dayan , Simon Horman , Oz Shlomo , Marcelo Ricardo Leitner , Justin Pettit , Ilya Maximets , Ben Pfaff , dev@openvswitch.org Date: Sun, 22 Dec 2019 12:16:38 +0200 Message-Id: <1577009803-4331-6-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1577009803-4331-1-git-send-email-paulb@mellanox.com> References: <1577009803-4331-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v7 05/10] dpif: Add support to set user features 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" This enables user features on the kernel datapath via the DP_CMD_SET command, and also retrieves them to check for actual support and not just an older kernel ignoring the requested features. This will be used in next patch to enable recirc_id sharing with tc. Signed-off-by: Paul Blakey Reviewed-by: Roi Dayan --- Changelog: V3->V4: Removed dpif pointer passing in offload info (not needed, and compilation issue fix) V2->V3: Refactored commit, to move it earlier Renamed commit from "netdev-offloads-tc: Probe recirc tc sharing feature on first recirc_id rule" --- datapath/linux/compat/include/linux/openvswitch.h | 3 ++ lib/dpif-netdev.c | 1 + lib/dpif-netlink.c | 52 +++++++++++++++++++++-- lib/dpif-provider.h | 2 + lib/dpif.c | 9 ++++ lib/dpif.h | 2 + 6 files changed, 66 insertions(+), 3 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 778827f..b9a7faa 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 3f21211..fd8280a 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -7627,6 +7627,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 e9a6887..ef06dd4 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) { @@ -3885,6 +3923,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 */ @@ -4202,6 +4241,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); @@ -4230,6 +4272,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 f8ca310..b77317b 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 c88b210..dc13655 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 d96f854..dfa7f2a 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. */ From patchwork Sun Dec 22 10:16:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1214624 X-Patchwork-Delegate: horms@verge.net.au 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 47gdgw6bhyz9sPn for ; Sun, 22 Dec 2019 21:17:00 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 32C26880D9; Sun, 22 Dec 2019 10:16:58 +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 m8XTWvUJflha; Sun, 22 Dec 2019 10:16:53 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 3432A87E3F; Sun, 22 Dec 2019 10:16:53 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 02F29C1D88; Sun, 22 Dec 2019 10:16:53 +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 DD4B0C1D81 for ; Sun, 22 Dec 2019 10:16:50 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id D813B2026D for ; Sun, 22 Dec 2019 10:16:50 +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 kxxHiBGkmogP for ; Sun, 22 Dec 2019 10:16:49 +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 36E5B1FE2F for ; Sun, 22 Dec 2019 10:16:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 22 Dec 2019 12:16:47 +0200 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xBMAGkdq028294; Sun, 22 Dec 2019 12:16:47 +0200 From: Paul Blakey To: Paul Blakey , Roi Dayan , Simon Horman , Oz Shlomo , Marcelo Ricardo Leitner , Justin Pettit , Ilya Maximets , Ben Pfaff , dev@openvswitch.org Date: Sun, 22 Dec 2019 12:16:39 +0200 Message-Id: <1577009803-4331-7-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1577009803-4331-1-git-send-email-paulb@mellanox.com> References: <1577009803-4331-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v7 06/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" 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 Reviewed-by: Roi Dayan --- Changelog: V3->V4: Fix: Set flower tunnel attribute to true, if any of the tunnel attributes exists (we used to rely on unset action). V2->V3: Actually removed old tunnel set if tunnel exists (instead of just adding a new one before a port) Moved patch earlier to help git bisect --- lib/tc.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/tc.c b/lib/tc.c index b2d8ca7..7a4acce 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -665,6 +665,12 @@ nl_parse_flower_tunnel(struct nlattr **attrs, struct tc_flower *flower) flower->mask.tunnel.ttl = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_ENC_IP_TTL_MASK]); } + + if (!is_all_zeros(&flower->mask.tunnel, sizeof flower->mask.tunnel) || + !is_all_zeros(&flower->key.tunnel, sizeof flower->key.tunnel)) { + flower->tunnel = true; + } + if (attrs[TCA_FLOWER_KEY_ENC_OPTS] && attrs[TCA_FLOWER_KEY_ENC_OPTS_MASK]) { err = nl_parse_flower_tunnel_opts(attrs[TCA_FLOWER_KEY_ENC_OPTS], @@ -2091,24 +2097,17 @@ 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); { int error; - if (flower->tunnel) { - act_offset = nl_msg_start_nested(request, act_index++); - nl_msg_put_act_tunnel_key_release(request); - nl_msg_put_act_flags(request); - nl_msg_end_nested(request, act_offset); - } - action = flower->actions; for (i = 0; i < flower->action_count; i++, action++) { switch (action->type) { @@ -2185,6 +2184,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 Sun Dec 22 10:16:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1214625 X-Patchwork-Delegate: horms@verge.net.au 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 47gdh14hY1z9sPn for ; Sun, 22 Dec 2019 21:17:05 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id E7FD8861C5; Sun, 22 Dec 2019 10:17:03 +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 GGWZUkAASMq1; Sun, 22 Dec 2019 10:17:01 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 7BC93862A5; Sun, 22 Dec 2019 10:17:00 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 586A9C1D89; Sun, 22 Dec 2019 10:17:00 +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 26048C0881 for ; Sun, 22 Dec 2019 10:16:52 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 1E72C1FE2F for ; Sun, 22 Dec 2019 10:16:52 +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 X21T9FcXwHy0 for ; Sun, 22 Dec 2019 10:16:49 +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 39A462002E for ; Sun, 22 Dec 2019 10:16:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 22 Dec 2019 12:16:47 +0200 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xBMAGkdr028294; Sun, 22 Dec 2019 12:16:47 +0200 From: Paul Blakey To: Paul Blakey , Roi Dayan , Simon Horman , Oz Shlomo , Marcelo Ricardo Leitner , Justin Pettit , Ilya Maximets , Ben Pfaff , dev@openvswitch.org Date: Sun, 22 Dec 2019 12:16:40 +0200 Message-Id: <1577009803-4331-8-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1577009803-4331-1-git-send-email-paulb@mellanox.com> References: <1577009803-4331-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v7 07/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" Each recirculation id will create a tc chain, and we translate the recirculation action to a tc goto chain action. 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 Reviewed-by: Roi Dayan --- Changelog: v6->V7: Fixed compilation issue with info->recirc_id_shared_with_tc V4->V5: Always enable recirc_id sharing to avoid bugs with opening an existing datapath, and enabling offload later. V3->V4: Always try to enable recirc_id sharing (on dpif_open) if hardware offload is enabled. V2->V3: Merged part of probe for recirc_id support in here to help future git bisect. Added tunnel released check to avoid bug with mirroring Removed cascading condition in netdev_tc_flow_put() check of recirc_id support 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 --- lib/dpif-netlink.c | 7 +++++++ lib/netdev-offload-tc.c | 42 ++++++++++++++++++++++++++++++++---------- lib/netdev-offload.h | 3 +++ lib/tc.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ lib/tc.h | 18 +++++++++++++++++- 5 files changed, 102 insertions(+), 17 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index ef06dd4..8073299 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -110,6 +110,8 @@ static int dpif_netlink_dp_transact(const struct dpif_netlink_dp *request, static int dpif_netlink_dp_get(const struct dpif *, struct dpif_netlink_dp *reply, struct ofpbuf **bufp); +static int +dpif_netlink_set_features(struct dpif *dpif_, uint32_t new_features); struct dpif_netlink_flow { /* Generic Netlink header. */ @@ -363,7 +365,9 @@ dpif_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name, } error = open_dpif(&dp, dpifp); + dpif_netlink_set_features(*dpifp, OVS_DP_F_TC_RECIRC_SHARING); ofpbuf_delete(buf); + return error; } @@ -1638,6 +1642,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; @@ -2082,6 +2087,8 @@ parse_flow_put(struct dpif_netlink *dpif, struct dpif_flow_put *put) info.dpif_class = dpif_class; info.tp_dst_port = dst_port; info.tunnel_csum_on = csum_on; + info.recirc_id_shared_with_tc = (dpif->user_features + & OVS_DP_F_TC_RECIRC_SHARING); err = netdev_flow_put(dev, &match, CONST_CAST(struct nlattr *, put->actions), put->actions_len, diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 15b39e6..dc721f8 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); @@ -206,9 +207,12 @@ static void add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid, struct tcf_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 +256,11 @@ get_ufid_tc_mapping(const ovs_u128 *ufid, struct tcf_id *id) static bool find_ufid(struct netdev *netdev, struct tcf_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 +746,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 +810,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 +995,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 +1162,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, uint32_t block_id = 0; struct nlattr *nla; struct tcf_id id; + bool recirc_act; + uint32_t chain; size_t left; int prio = 0; int ifindex; @@ -1170,6 +1178,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 +1431,11 @@ 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++; + recirc_act = true; } else { VLOG_DBG_RL(&rl, "unsupported put action type: %d", nl_attr_type(nla)); @@ -1427,6 +1443,11 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, } } + if ((chain || recirc_act) && !info->recirc_id_shared_with_tc) { + VLOG_ERR_RL(&error_rl, "flow_put: recirc_id sharing not supported"); + return EOPNOTSUPP; + } + if (get_ufid_tc_mapping(ufid, &id) == 0) { VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d", id.handle, id.prio); @@ -1443,7 +1464,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, flower.act_cookie.len = sizeof *ufid; block_id = get_block_id_from_netdev(netdev); - id = tc_make_tcf_id(ifindex, block_id, prio, hook); + id = tc_make_tcf_id_chain(ifindex, block_id, chain, prio, hook); err = tc_replace_flower(&id, &flower); if (!err) { if (stats) { @@ -1491,6 +1512,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/netdev-offload.h b/lib/netdev-offload.h index 97a5006..cd6dfdf 100644 --- a/lib/netdev-offload.h +++ b/lib/netdev-offload.h @@ -66,6 +66,9 @@ struct offload_info { ovs_be16 tp_dst_port; /* Destination port for tunnel in SET action */ uint8_t tunnel_csum_on; /* Tunnel header with checksum */ + bool recirc_id_shared_with_tc; /* Indicates whever tc chains will be in + * sync with datapath recirc ids. */ + /* * The flow mark id assigened to the flow. If any pkts hit the flow, * it will be in the pkt meta data. diff --git a/lib/tc.c b/lib/tc.c index 7a4acce..dafa90e 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_tcf_id(struct tcf_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, }, @@ -1135,12 +1141,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))) { @@ -1151,7 +1158,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; } @@ -1429,7 +1440,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")) { @@ -1580,6 +1591,10 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_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); @@ -1876,7 +1891,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; @@ -1885,6 +1900,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); @@ -2230,12 +2249,30 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) nl_msg_end_nested(request, act_offset); } break; + case TC_ACT_GOTO: { + if (released) { + /* We don't support tunnel release + output + goto + * for now, as next chain by default will try and match + * the tunnel metadata that was released/unset. + * + * This will happen with tunnel + mirror ports. + */ + return -EOPNOTSUPP; + } + + 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 da9a766..9154fd8 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 tcf_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_make_tcf_id(int ifindex, uint32_t block_id, uint16_t prio, return id; } +static inline struct tcf_id +tc_make_tcf_id_chain(int ifindex, uint32_t block_id, uint32_t chain, + uint16_t prio, enum tc_qdisc_hook hook) +{ + struct tcf_id id = tc_make_tcf_id(ifindex, block_id, prio, hook); + + id.chain = chain; + + return id; +} + static inline bool is_tcf_id_eq(struct tcf_id *id1, struct tcf_id *id2) { @@ -241,7 +256,8 @@ is_tcf_id_eq(struct tcf_id *id1, struct tcf_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 Sun Dec 22 10:16:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1214630 X-Patchwork-Delegate: horms@verge.net.au 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 47gdhD3Ppsz9sPn for ; Sun, 22 Dec 2019 21:17:16 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id EB2918831B; Sun, 22 Dec 2019 10:17:14 +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 kG53moLD-l-w; Sun, 22 Dec 2019 10:17:08 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 3A1208809E; Sun, 22 Dec 2019 10:16:57 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2BCA0C1D81; Sun, 22 Dec 2019 10:16:57 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id D91A0C0881 for ; Sun, 22 Dec 2019 10:16:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id C84D7860F6 for ; Sun, 22 Dec 2019 10:16:51 +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 AwaWm1TNsb2o for ; Sun, 22 Dec 2019 10:16:49 +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 fraxinus.osuosl.org (Postfix) with ESMTP id 41215860C8 for ; Sun, 22 Dec 2019 10:16:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 22 Dec 2019 12:16:47 +0200 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xBMAGkds028294; Sun, 22 Dec 2019 12:16:47 +0200 From: Paul Blakey To: Paul Blakey , Roi Dayan , Simon Horman , Oz Shlomo , Marcelo Ricardo Leitner , Justin Pettit , Ilya Maximets , Ben Pfaff , dev@openvswitch.org Date: Sun, 22 Dec 2019 12:16:41 +0200 Message-Id: <1577009803-4331-9-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1577009803-4331-1-git-send-email-paulb@mellanox.com> References: <1577009803-4331-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v7 08/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" Zone and ct_state first. Signed-off-by: Paul Blakey Reviewed-by: Roi Dayan --- Changelog: V4->V5: Removed unused int err in parse_put_flow_ct_action --- lib/dpif-netlink.c | 2 + lib/netdev-offload-tc.c | 135 ++++++++++++++++++++++++++++++++++++++++++++---- lib/tc.c | 122 +++++++++++++++++++++++++++++++++++++++++++ lib/tc.h | 11 ++++ 4 files changed, 260 insertions(+), 10 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 8073299..a3a9971 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -1643,6 +1643,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 dc721f8..a646801 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -595,6 +595,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) { @@ -746,6 +775,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); } @@ -835,6 +885,33 @@ 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; + + 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, @@ -1016,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; @@ -1365,6 +1432,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; @@ -1431,6 +1534,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 dafa90e..4358cb7 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 @@ -709,6 +714,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; @@ -805,6 +831,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 @@ -1225,6 +1253,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), @@ -1455,6 +1531,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; @@ -1910,6 +1988,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; @@ -2266,6 +2378,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; } } } @@ -2433,6 +2552,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 9154fd8..8200c20 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 Sun Dec 22 10:16:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1214626 X-Patchwork-Delegate: horms@verge.net.au 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 47gdh24rFjz9sQp for ; Sun, 22 Dec 2019 21:17:06 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 0C234220B2; Sun, 22 Dec 2019 10:17:05 +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 VSfa55trZnIZ; Sun, 22 Dec 2019 10:16:56 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id CFEE520521; Sun, 22 Dec 2019 10:16:53 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A4C17C1D84; Sun, 22 Dec 2019 10:16:53 +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 279CCC0881 for ; Sun, 22 Dec 2019 10:16:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 17C4B86797 for ; Sun, 22 Dec 2019 10:16:51 +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 xtzsI9J8bIdA for ; Sun, 22 Dec 2019 10:16:49 +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 31A0C865E2 for ; Sun, 22 Dec 2019 10:16:48 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 22 Dec 2019 12:16:47 +0200 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xBMAGkdt028294; Sun, 22 Dec 2019 12:16:47 +0200 From: Paul Blakey To: Paul Blakey , Roi Dayan , Simon Horman , Oz Shlomo , Marcelo Ricardo Leitner , Justin Pettit , Ilya Maximets , Ben Pfaff , dev@openvswitch.org Date: Sun, 22 Dec 2019 12:16:42 +0200 Message-Id: <1577009803-4331-10-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1577009803-4331-1-git-send-email-paulb@mellanox.com> References: <1577009803-4331-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v7 09/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" Signed-off-by: Paul Blakey Reviewed-by: Roi Dayan --- Changelog: V2->V3: Added missing match on ct_mark. --- lib/dpif-netlink.c | 2 ++ lib/netdev-offload-tc.c | 66 +++++++++++++++++++++++++++++++++++++++++-------- lib/tc.c | 53 +++++++++++++++++++++++++++++++++++++++ lib/tc.h | 6 +++++ 4 files changed, 117 insertions(+), 10 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index a3a9971..a08c237 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -1645,6 +1645,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 a646801..f9b0d34 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -624,6 +624,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) { @@ -793,6 +795,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, @@ -1468,6 +1502,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 4358cb7..de09c49 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 @@ -732,6 +737,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 @@ -1261,6 +1280,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 @@ -1289,11 +1316,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; @@ -2005,6 +2041,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) { @@ -2555,6 +2606,8 @@ 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_mark, TCA_FLOWER_KEY_CT_MARK); + 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 8200c20..bb7a078 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 Sun Dec 22 10:16:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1214632 X-Patchwork-Delegate: horms@verge.net.au 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 47gdhL3HK1z9sPn for ; Sun, 22 Dec 2019 21:17:22 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id EABA188094; Sun, 22 Dec 2019 10:17:20 +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 gxh-UEwcFeCs; Sun, 22 Dec 2019 10:17:17 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id C67AF88173; Sun, 22 Dec 2019 10:16:59 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A169DC1D81; Sun, 22 Dec 2019 10:16:59 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id EA197C1D84 for ; Sun, 22 Dec 2019 10:16:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id E3346860B2 for ; Sun, 22 Dec 2019 10:16:51 +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 OPWXSxbCKQey for ; Sun, 22 Dec 2019 10:16:49 +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 fraxinus.osuosl.org (Postfix) with ESMTP id 3FAC285B09 for ; Sun, 22 Dec 2019 10:16:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 22 Dec 2019 12:16:47 +0200 Received: from reg-r-vrt-019-180.mtr.labs.mlnx (reg-r-vrt-019-180.mtr.labs.mlnx [10.213.19.180]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xBMAGkdu028294; Sun, 22 Dec 2019 12:16:47 +0200 From: Paul Blakey To: Paul Blakey , Roi Dayan , Simon Horman , Oz Shlomo , Marcelo Ricardo Leitner , Justin Pettit , Ilya Maximets , Ben Pfaff , dev@openvswitch.org Date: Sun, 22 Dec 2019 12:16:43 +0200 Message-Id: <1577009803-4331-11-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1577009803-4331-1-git-send-email-paulb@mellanox.com> References: <1577009803-4331-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v7 10/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" Signed-off-by: Paul Blakey Reviewed-by: Roi Dayan --- Changelog: V4->V5: Moved the unused 'int err' from patch 4/10 to it's first usage here V2->V3: Ipv6 nat dump fix (missing unspec type in policy) Renamed tc range struct to be consistent with NL ATTRIBUTES and ovs V1->V2: Missing ntohs/htons on nat port range. --- lib/netdev-offload-tc.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/tc.c | 93 ++++++++++++++++++++++++++++++++++++++++++ lib/tc.h | 28 +++++++++++++ 3 files changed, 226 insertions(+) diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index f9b0d34..9e1c84d 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -815,6 +815,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.ipv4.min); + nl_msg_put_be32(buf, OVS_NAT_ATTR_IP_MAX, + action->ct.range.ipv4.max); + } else if (action->ct.range.ip_family == AF_INET6) { + nl_msg_put_in6_addr(buf, OVS_NAT_ATTR_IP_MIN, + &action->ct.range.ipv6.min); + nl_msg_put_in6_addr(buf, OVS_NAT_ATTR_IP_MAX, + &action->ct.range.ipv6.max); + } + + if (action->ct.range.port.min) { + nl_msg_put_u16(buf, OVS_NAT_ATTR_PROTO_MIN, + ntohs(action->ct.range.port.min)); + if (action->ct.range.port.max) { + nl_msg_put_u16(buf, OVS_NAT_ATTR_PROTO_MAX, + ntohs(action->ct.range.port.max)); + } + } + + nl_msg_end_nested(buf, nat_offset); + } + nl_msg_end_nested(buf, ct_offset); } break; @@ -907,6 +941,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.ipv4.min = addr; + action->ct.range.ip_family = AF_INET; + } else { + struct in6_addr addr = nl_attr_get_in6_addr(nat_attr); + + action->ct.range.ipv6.min = 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.ipv4.max = addr; + action->ct.range.ip_family = AF_INET; + } else { + struct in6_addr addr = nl_attr_get_in6_addr(nat_attr); + + action->ct.range.ipv6.max = addr; + action->ct.range.ip_family = AF_INET6; + } + }; + break; + case OVS_NAT_ATTR_PROTO_MIN: { + action->ct.range.port.min = htons(nl_attr_get_u16(nat_attr)); + }; + break; + case OVS_NAT_ATTR_PROTO_MAX: { + action->ct.range.port.max = 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, @@ -914,6 +1008,7 @@ parse_put_flow_ct_action(struct tc_flower *flower, { 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)) { @@ -925,6 +1020,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 de09c49..12af019 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -1288,6 +1288,20 @@ 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), + .type = NL_A_UNSPEC, + .optional = true }, + [TCA_CT_NAT_IPV6_MAX] = { .min_len = sizeof(struct in6_addr), + .type = NL_A_UNSPEC, + .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 @@ -1331,6 +1345,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 *port_min = ct_attrs[TCA_CT_NAT_PORT_MIN]; + struct nlattr *port_max = 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.ipv4.min = nl_attr_get_be32(ipv4_min); + if (ipv4_max) { + ovs_be32 addr = nl_attr_get_be32(ipv4_max); + + action->ct.range.ipv4.max = addr; + } + } else if (ipv6_min) { + action->ct.range.ip_family = AF_INET6; + action->ct.range.ipv6.min + = nl_attr_get_in6_addr(ipv6_min); + if (ipv6_max) { + struct in6_addr addr = nl_attr_get_in6_addr(ipv6_max); + + action->ct.range.ipv6.max = addr; + } + } + + if (port_min) { + action->ct.range.port.min = nl_attr_get_be16(port_min); + if (port_max) { + action->ct.range.port.max = nl_attr_get_be16(port_max); + } + } + } } action->type = TC_ACT_CT; @@ -2062,6 +2117,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.ipv4.min); + if (action->ct.range.ipv4.max) { + nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MAX, + action->ct.range.ipv4.max); + } + } else if (action->ct.range.ip_family == AF_INET6) { + size_t ipv6_sz = sizeof(action->ct.range.ipv6.max); + + nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MIN, + &action->ct.range.ipv6.min); + if (!is_all_zeros(&action->ct.range.ipv6.max, + ipv6_sz)) { + nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MAX, + &action->ct.range.ipv6.max); + } + } + + if (action->ct.range.port.min) { + nl_msg_put_be16(request, TCA_CT_NAT_PORT_MIN, + action->ct.range.port.min); + if (action->ct.range.port.max) { + nl_msg_put_be16(request, TCA_CT_NAT_PORT_MAX, + action->ct.range.port.max); + } + } + } } else { ct_action = TCA_CT_ACT_CLEAR; } diff --git a/lib/tc.h b/lib/tc.h index bb7a078..70e7f38 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,27 @@ 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 { + ovs_be32 min; + ovs_be32 max; + } ipv4; + struct { + struct in6_addr min; + struct in6_addr max; + } ipv6; + }; + + union { + ovs_be16 min; + ovs_be16 max; + } port; + + } range; bool clear; bool force; bool commit;