From patchwork Thu Dec 19 14:57:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1213501 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 47dw3n2Pw5z9sP3 for ; Fri, 20 Dec 2019 01:58:13 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id A2C2923730; Thu, 19 Dec 2019 14:58:11 +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 GR8LjRV-aCTM; Thu, 19 Dec 2019 14:58:05 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id A82962353A; Thu, 19 Dec 2019 14:57:54 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8CC30C1D84; Thu, 19 Dec 2019 14:57:54 +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 23F71C077D for ; Thu, 19 Dec 2019 14:57:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 172E520429 for ; Thu, 19 Dec 2019 14:57: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 Tl7ZVY6-lnaK for ; Thu, 19 Dec 2019 14:57: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 541F720517 for ; Thu, 19 Dec 2019 14:57:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 19 Dec 2019 16:57:43 +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 xBJEvgcb014053; Thu, 19 Dec 2019 16:57:42 +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: Thu, 19 Dec 2019 16:57:31 +0200 Message-Id: <1576767460-17430-2-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1576767460-17430-1-git-send-email-paulb@mellanox.com> References: <1576767460-17430-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v6 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 Thu Dec 19 14:57:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1213497 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 47dw3b0gfGz9sPc for ; Fri, 20 Dec 2019 01:58:02 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 75D6F86E7A; Thu, 19 Dec 2019 14:58:00 +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 nfbAIT-d8uQO; Thu, 19 Dec 2019 14:57:56 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 61B3C86F05; Thu, 19 Dec 2019 14:57:55 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 52DAFC1D84; Thu, 19 Dec 2019 14:57:55 +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 3BA96C1AE8 for ; Thu, 19 Dec 2019 14:57:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 28ED28589C for ; Thu, 19 Dec 2019 14:57: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 NXO89WLARIyw for ; Thu, 19 Dec 2019 14:57: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 53C8880C93 for ; Thu, 19 Dec 2019 14:57:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 19 Dec 2019 16:57:43 +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 xBJEvgcc014053; Thu, 19 Dec 2019 16:57:42 +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: Thu, 19 Dec 2019 16:57:32 +0200 Message-Id: <1576767460-17430-3-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1576767460-17430-1-git-send-email-paulb@mellanox.com> References: <1576767460-17430-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v6 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 Thu Dec 19 14:57:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 1213504 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 47dw4J25MLz9sP3 for ; Fri, 20 Dec 2019 01:58:40 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id C141225C66; Thu, 19 Dec 2019 14:58:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id tNYWsXRycs8f; Thu, 19 Dec 2019 14:58:24 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id D266124A82; Thu, 19 Dec 2019 14:57:58 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A6523C1D83; Thu, 19 Dec 2019 14:57: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 96A44C1AE8 for ; Thu, 19 Dec 2019 14:57:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 93EFF8589C for ; Thu, 19 Dec 2019 14:57: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 iNIPXTdIFZnZ for ; Thu, 19 Dec 2019 14:57: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 fraxinus.osuosl.org (Postfix) with ESMTP id 52EBE80C8B for ; Thu, 19 Dec 2019 14:57:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 19 Dec 2019 16:57:43 +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 xBJEvgcd014053; Thu, 19 Dec 2019 16:57:43 +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: Thu, 19 Dec 2019 16:57:33 +0200 Message-Id: <1576767460-17430-4-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1576767460-17430-1-git-send-email-paulb@mellanox.com> References: <1576767460-17430-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v6 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 Thu Dec 19 14:57: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: 1213502 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 47dw3t6G6Cz9sP3 for ; Fri, 20 Dec 2019 01:58:18 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 12B7D23E84; Thu, 19 Dec 2019 14:58:17 +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 ZYcvennMX+fZ; Thu, 19 Dec 2019 14:58:11 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 3A64323B9B; Thu, 19 Dec 2019 14:57:56 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 062A6C1D84; Thu, 19 Dec 2019 14:57:56 +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 5EFB2C077D for ; Thu, 19 Dec 2019 14:57:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 4EB9380CFA for ; Thu, 19 Dec 2019 14:57: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 dG-ysBdudSrY for ; Thu, 19 Dec 2019 14:57: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 4F00285F96 for ; Thu, 19 Dec 2019 14:57:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 19 Dec 2019 16:57:43 +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 xBJEvgce014053; Thu, 19 Dec 2019 16:57:43 +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: Thu, 19 Dec 2019 16:57:34 +0200 Message-Id: <1576767460-17430-5-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1576767460-17430-1-git-send-email-paulb@mellanox.com> References: <1576767460-17430-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v6 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 Thu Dec 19 14:57: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: 1213503 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 47dw3z3PMhz9sR0 for ; Fri, 20 Dec 2019 01:58:23 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 77CFE255A6; Thu, 19 Dec 2019 14:58:21 +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 4xaTHuvEKYbl; Thu, 19 Dec 2019 14:58:16 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 2A26D24214; Thu, 19 Dec 2019 14:57:57 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 10919C1D88; Thu, 19 Dec 2019 14:57:57 +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 681FBC1AE8 for ; Thu, 19 Dec 2019 14:57:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 4FA4285BD3 for ; Thu, 19 Dec 2019 14:57: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 ySXNYN5sd9fS for ; Thu, 19 Dec 2019 14:57: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 51645860A3 for ; Thu, 19 Dec 2019 14:57:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 19 Dec 2019 16:57:43 +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 xBJEvgcf014053; Thu, 19 Dec 2019 16:57:43 +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: Thu, 19 Dec 2019 16:57:35 +0200 Message-Id: <1576767460-17430-6-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1576767460-17430-1-git-send-email-paulb@mellanox.com> References: <1576767460-17430-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v6 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 Thu Dec 19 14:57: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: 1213498 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 47dw3f5vsMz9sPc for ; Fri, 20 Dec 2019 01:58:06 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 2453B25248; Thu, 19 Dec 2019 14:58: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 ZoLGSlP9aOem; Thu, 19 Dec 2019 14:57:57 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id A6B2D23459; Thu, 19 Dec 2019 14:57:53 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 81F29C1D84; Thu, 19 Dec 2019 14:57: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 187A4C1AE8 for ; Thu, 19 Dec 2019 14:57:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 084F880CFA for ; Thu, 19 Dec 2019 14:57: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 krIY-zvDo1lt for ; Thu, 19 Dec 2019 14:57: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 532FB860ED for ; Thu, 19 Dec 2019 14:57:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 19 Dec 2019 16:57:43 +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 xBJEvgcg014053; Thu, 19 Dec 2019 16:57:43 +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: Thu, 19 Dec 2019 16:57:36 +0200 Message-Id: <1576767460-17430-7-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1576767460-17430-1-git-send-email-paulb@mellanox.com> References: <1576767460-17430-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v6 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 Thu Dec 19 14:57: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: 1213499 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 47dw3g4KRpz9sQp for ; Fri, 20 Dec 2019 01:58:07 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 6C22A86F85; Thu, 19 Dec 2019 14:58:05 +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 1cI_-DG3glWd; Thu, 19 Dec 2019 14:58:00 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 036B286F51; Thu, 19 Dec 2019 14:57:58 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C94B0C1D84; Thu, 19 Dec 2019 14:57:57 +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 8CBCCC077D for ; Thu, 19 Dec 2019 14:57:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 8821320517 for ; Thu, 19 Dec 2019 14:57: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 Rhl5PunvZcfl for ; Thu, 19 Dec 2019 14:57: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 silver.osuosl.org (Postfix) with ESMTP id 58BAB231CB for ; Thu, 19 Dec 2019 14:57:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 19 Dec 2019 16:57:43 +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 xBJEvgch014053; Thu, 19 Dec 2019 16:57:43 +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: Thu, 19 Dec 2019 16:57:37 +0200 Message-Id: <1576767460-17430-8-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1576767460-17430-1-git-send-email-paulb@mellanox.com> References: <1576767460-17430-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v6 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: V5->V6: Moved testing recirc_id sharing support to netdev tc via offload info flag (Ilya suggestion) 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..b54a7ab 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 Thu Dec 19 14:57: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: 1213507 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 47dw4c6QTFz9sR0 for ; Fri, 20 Dec 2019 01:58:56 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 5C42924F51; Thu, 19 Dec 2019 14:58:55 +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 cdGY5CL2opDN; Thu, 19 Dec 2019 14:58:47 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 5C18924F43; Thu, 19 Dec 2019 14:58:01 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 39D75C1D83; Thu, 19 Dec 2019 14:58:01 +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 E0697C077D for ; Thu, 19 Dec 2019 14:57:53 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id BF70F23492 for ; Thu, 19 Dec 2019 14:57:53 +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 xJUdEQqv5uFp for ; Thu, 19 Dec 2019 14:57: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 silver.osuosl.org (Postfix) with ESMTP id 58A3B21577 for ; Thu, 19 Dec 2019 14:57:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 19 Dec 2019 16:57:43 +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 xBJEvgci014053; Thu, 19 Dec 2019 16:57:43 +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: Thu, 19 Dec 2019 16:57:38 +0200 Message-Id: <1576767460-17430-9-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1576767460-17430-1-git-send-email-paulb@mellanox.com> References: <1576767460-17430-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v6 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 b54a7ab..fb930ad 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 Thu Dec 19 14:57: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: 1213500 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 47dw3h4T2Zz9sPc for ; Fri, 20 Dec 2019 01:58:08 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 22F5786FD5; Thu, 19 Dec 2019 14:58:07 +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 jvz4JpgW7SoJ; Thu, 19 Dec 2019 14:58:04 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id EDC1086F27; Thu, 19 Dec 2019 14:57:59 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C1B48C1D88; Thu, 19 Dec 2019 14:57: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 AAFE1C1D89 for ; Thu, 19 Dec 2019 14:57:53 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 86E3686D10 for ; Thu, 19 Dec 2019 14:57:53 +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 57wxHkxpHdvR for ; Thu, 19 Dec 2019 14:57: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 fraxinus.osuosl.org (Postfix) with ESMTP id 56D7F80EAC for ; Thu, 19 Dec 2019 14:57:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 19 Dec 2019 16:57:43 +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 xBJEvgcj014053; Thu, 19 Dec 2019 16:57:43 +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: Thu, 19 Dec 2019 16:57:39 +0200 Message-Id: <1576767460-17430-10-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1576767460-17430-1-git-send-email-paulb@mellanox.com> References: <1576767460-17430-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v6 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 fb930ad..389551c 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 Thu Dec 19 14:57: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: 1213495 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 47dw3S5Bpnz9sPc for ; Fri, 20 Dec 2019 01:57:55 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 55DA888686; Thu, 19 Dec 2019 14:57:54 +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 ykT48ehXtTs1; Thu, 19 Dec 2019 14:57:52 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id CE54D88642; Thu, 19 Dec 2019 14:57:52 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id B4A5BC1D84; Thu, 19 Dec 2019 14:57:52 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id F20BEC077D for ; Thu, 19 Dec 2019 14:57:50 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id DF0C08863E for ; Thu, 19 Dec 2019 14:57:50 +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 JK+XkD8gOdzk for ; Thu, 19 Dec 2019 14:57: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 hemlock.osuosl.org (Postfix) with ESMTP id 56CF98839E for ; Thu, 19 Dec 2019 14:57:49 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 19 Dec 2019 16:57:43 +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 xBJEvgck014053; Thu, 19 Dec 2019 16:57:43 +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: Thu, 19 Dec 2019 16:57:40 +0200 Message-Id: <1576767460-17430-11-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1576767460-17430-1-git-send-email-paulb@mellanox.com> References: <1576767460-17430-1-git-send-email-paulb@mellanox.com> Subject: [ovs-dev] [PATCH v6 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 389551c..7252265 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;