From patchwork Tue Sep 18 08:36:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pieter Jansen van Vuuren X-Patchwork-Id: 971028 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=netronome.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="hIylCvyw"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42DxDj1SbQz9sBv for ; Tue, 18 Sep 2018 18:36:53 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 208DDD88; Tue, 18 Sep 2018 08:36:27 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id DD7C7D82 for ; Tue, 18 Sep 2018 08:36:25 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-qk1-f180.google.com (mail-qk1-f180.google.com [209.85.222.180]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 033FB42D for ; Tue, 18 Sep 2018 08:36:24 +0000 (UTC) Received: by mail-qk1-f180.google.com with SMTP id z125-v6so521010qkb.12 for ; Tue, 18 Sep 2018 01:36:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netronome-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=NmZ2WD0/Fl4DO3ZE6IKJsBB/6gDojrAvQSdT69d4mNI=; b=hIylCvywNP1BCQVwJ61FTm3IXZOoMq0QQea7SOWQmSeRIwCxmIdNujgdjtsPthN0NK hkEhjzpibdnZVzdoHA+uz/rNKS5E+fGxfmK+DjzyH1bH90l6eLFL7YFRNuNUnt30uQXi 3DEOmh5fxMkVVFLD9eJVZqFmqhbAkdo14A+EcpuqTBAM+BodogWPr++NKLwoDIWSNtaS Yi4NTGZuxdFhXv+ZgnzKhOXNNxWzAuaN96e/r/unbUGr0epTr1ypPMd3B78AMndnqsgn znhMuOiuTahxCsVEibQXrpHidGegvfdu2Lt0ZTYDtvlBOUSDfcgfKs8bM66PUGXB+BCa I+Aw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=NmZ2WD0/Fl4DO3ZE6IKJsBB/6gDojrAvQSdT69d4mNI=; b=oTOVHhid8taa1b2UxQy6p/Oq5H3T/G9osw6w2BGAC/6/W6Gp0KNSRpd8oA7MZrzwtw qsKtpMIBUZk7o3CpRuUKA4H6Fephe8ZShNxqji5vO5HlXD/Smp9ZUTYhdi+JzdBPRJya eOZQVI19f28d7x21OxW+kqeOUwCCvPSFfmtNbA8ov8kePyVAlGzxthUP77jsra1iIi7B 5/K+yskrSgPIZK0uN5le4ywzIPoIBj+GDDYngZsgaES2WTRBDBR11RrUyIPwYg0w3bH0 wehbp69d5T2soxtbWSnwLtSw7iB/PlQynyH+JZr7FwSPaaDJ//azbDarQWWejyD6u6zg v9Lg== X-Gm-Message-State: APzg51CxF59l2tG5N4hZfFIi6TaSDNl+OQ59Ou4UCvJzG7f/daKfYK2s lc+nDfHWbZy5Lg5sANqnzMNjXRf0tgw= X-Google-Smtp-Source: ANB0Vdb9TlrbVNq/wMNhCUbx6tpN/m2O6OwxxGIo1BudQres3JhtT6BAYSvTbQb32wFb6B3aQIMLfQ== X-Received: by 2002:a37:cb52:: with SMTP id d79-v6mr19283873qkj.16.1537259783902; Tue, 18 Sep 2018 01:36:23 -0700 (PDT) Received: from pieter-Netronome.netronome.com (host81-150-168-85.in-addr.btopenworld.com. [81.150.168.85]) by smtp.gmail.com with ESMTPSA id l132-v6sm10490647qke.33.2018.09.18.01.36.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 18 Sep 2018 01:36:23 -0700 (PDT) From: Pieter Jansen van Vuuren To: dev@openvswitch.org Date: Tue, 18 Sep 2018 09:36:19 +0100 Message-Id: <1537259780-9769-2-git-send-email-pieter.jansenvanvuuren@netronome.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1537259780-9769-1-git-send-email-pieter.jansenvanvuuren@netronome.com> References: <1537259780-9769-1-git-send-email-pieter.jansenvanvuuren@netronome.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: horms+renesas@verge.net.au, Pieter Jansen van Vuuren Subject: [ovs-dev] [PATCH v4 1/2] lib/tc: add geneve with option encap action offload X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Add TC offload support for encapsulating geneve tunnels with options. Signed-off-by: Pieter Jansen van Vuuren Reviewed-by: Simon Horman --- include/linux/tc_act/tc_tunnel_key.h | 23 ++++ lib/netdev-tc-offloads.c | 30 +++++ lib/tc.c | 157 ++++++++++++++++++++++++++- lib/tc.h | 2 + 4 files changed, 206 insertions(+), 6 deletions(-) diff --git a/include/linux/tc_act/tc_tunnel_key.h b/include/linux/tc_act/tc_tunnel_key.h index 26cbd2ff1..f13acf17d 100644 --- a/include/linux/tc_act/tc_tunnel_key.h +++ b/include/linux/tc_act/tc_tunnel_key.h @@ -47,6 +47,29 @@ enum { #define TCA_TUNNEL_KEY_MAX (__TCA_TUNNEL_KEY_MAX - 1) +enum { + TCA_TUNNEL_KEY_ENC_OPTS_UNSPEC, + TCA_TUNNEL_KEY_ENC_OPTS_GENEVE, /* Nested + * TCA_TUNNEL_KEY_ENC_OPTS_GENEVE + * attributes + */ + __TCA_TUNNEL_KEY_ENC_OPTS_MAX, +}; + +#define TCA_TUNNEL_KEY_ENC_OPTS_MAX (__TCA_TUNNEL_KEY_ENC_OPTS_MAX - 1) + +enum { + TCA_TUNNEL_KEY_ENC_OPT_GENEVE_UNSPEC, + TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS, /* be16 */ + TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE, /* u8 */ + TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA, /* 4 to 128 bytes */ + + __TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, +}; + +#define TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX \ + (__TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX - 1) + #endif /* __KERNEL__ || HAVE_TCA_TUNNEL_KEY_ENC_TTL */ #endif /* __LINUX_TC_ACT_TC_TUNNEL_KEY_WRAPPER_H */ diff --git a/lib/netdev-tc-offloads.c b/lib/netdev-tc-offloads.c index 03ffaba95..097893584 100644 --- a/lib/netdev-tc-offloads.c +++ b/lib/netdev-tc-offloads.c @@ -409,6 +409,29 @@ parse_flower_rewrite_to_netlink_action(struct ofpbuf *buf, } } +static void parse_tc_flower_geneve_opts(struct tc_action *action, + struct ofpbuf *buf) +{ + int tun_opt_len = action->encap.data.present.len; + size_t geneve_off; + int idx = 0; + + if (!tun_opt_len) { + return; + } + + geneve_off = nl_msg_start_nested(buf, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS); + while (tun_opt_len) { + struct geneve_opt *opt; + + opt = &action->encap.data.opts.gnv[idx]; + nl_msg_put(buf, opt, sizeof(struct geneve_opt) + opt->length * 4); + idx += sizeof(struct geneve_opt) / 4 + opt->length; + tun_opt_len -= sizeof(struct geneve_opt) + opt->length * 4; + } + nl_msg_end_nested(buf, geneve_off); +} + static int parse_tc_flower_to_match(struct tc_flower *flower, struct match *match, @@ -586,6 +609,7 @@ parse_tc_flower_to_match(struct tc_flower *flower, nl_msg_put_be16(buf, OVS_TUNNEL_KEY_ATTR_TP_DST, action->encap.tp_dst); + parse_tc_flower_geneve_opts(action, buf); nl_msg_end_nested(buf, tunnel_offset); nl_msg_end_nested(buf, set_offset); } @@ -792,6 +816,12 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action, action->encap.tp_dst = nl_attr_get_be16(tun_attr); } break; + case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS: { + memcpy(action->encap.data.opts.gnv, nl_attr_get(tun_attr), + nl_attr_get_size(tun_attr)); + action->encap.data.present.len = nl_attr_get_size(tun_attr); + } + break; } } diff --git a/lib/tc.c b/lib/tc.c index adcf31604..45e59e4d7 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -707,8 +707,110 @@ static const struct nl_policy tunnel_key_policy[] = { [TCA_TUNNEL_KEY_ENC_DST_PORT] = { .type = NL_A_U16, .optional = true, }, [TCA_TUNNEL_KEY_ENC_TOS] = { .type = NL_A_U8, .optional = true, }, [TCA_TUNNEL_KEY_ENC_TTL] = { .type = NL_A_U8, .optional = true, }, + [TCA_TUNNEL_KEY_ENC_OPTS] = { .type = NL_A_NESTED, .optional = true, }, }; +static int +nl_parse_act_geneve_opts(const struct nlattr *in_nlattr, + struct tc_action *action) +{ + struct geneve_opt *opt = NULL; + const struct ofpbuf *msg; + uint16_t last_opt_type; + struct nlattr *nla; + struct ofpbuf buf; + size_t left; + int cnt; + + nl_attr_get_nested(in_nlattr, &buf); + msg = &buf; + + last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_UNSPEC; + cnt = 0; + NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) { + uint16_t type = nl_attr_type(nla); + + switch (type) { + case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS: + if (cnt && last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA) { + VLOG_ERR_RL(&error_rl, + "failed to parse action geneve options class"); + return EINVAL; + } + + opt = &action->encap.data.opts.gnv[cnt]; + opt->opt_class = nl_attr_get_be16(nla); + cnt += sizeof(struct geneve_opt) / 4; + action->encap.data.present.len += sizeof(struct geneve_opt); + last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS; + break; + case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE: + if (last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS) { + VLOG_ERR_RL(&error_rl, + "failed to parse action geneve options type"); + return EINVAL; + } + + opt->type = nl_attr_get_u8(nla); + last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE; + break; + case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA: + if (last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE) { + VLOG_ERR_RL(&error_rl, + "failed to parse action geneve options data"); + return EINVAL; + } + + opt->length = nl_attr_get_size(nla) / 4; + memcpy(opt + 1, nl_attr_get_unspec(nla, 1), opt->length * 4); + cnt += opt->length; + action->encap.data.present.len += opt->length * 4; + last_opt_type = TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA; + break; + } + } + + if (last_opt_type != TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA) { + VLOG_ERR_RL(&error_rl, + "failed to parse action geneve options without data"); + return EINVAL; + } + + return 0; +} + +static int +nl_parse_act_tunnel_opts(struct nlattr *options, struct tc_action *action) +{ + const struct ofpbuf *msg; + struct nlattr *nla; + struct ofpbuf buf; + size_t left; + int err; + + if (!options) { + return 0; + } + + nl_attr_get_nested(options, &buf); + msg = &buf; + + NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) { + uint16_t type = nl_attr_type(nla); + switch (type) { + case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE: + err = nl_parse_act_geneve_opts(nla, action); + if (err) { + return err; + } + + break; + } + } + + return 0; +} + static int nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower) { @@ -716,6 +818,7 @@ nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower) const struct nlattr *tun_parms; const struct tc_tunnel_key *tun; struct tc_action *action; + int err; if (!nl_parse_nested(options, tunnel_key_policy, tun_attrs, ARRAY_SIZE(tunnel_key_policy))) { @@ -734,6 +837,7 @@ nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower) struct nlattr *ipv6_dst = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV6_DST]; struct nlattr *tos = tun_attrs[TCA_TUNNEL_KEY_ENC_TOS]; struct nlattr *ttl = tun_attrs[TCA_TUNNEL_KEY_ENC_TTL]; + struct nlattr *tun_opt = tun_attrs[TCA_TUNNEL_KEY_ENC_OPTS]; action = &flower->actions[flower->action_count++]; action->type = TC_ACT_ENCAP; @@ -749,6 +853,11 @@ nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower) action->encap.tp_dst = dst_port ? nl_attr_get_be16(dst_port) : 0; action->encap.tos = tos ? nl_attr_get_u8(tos) : 0; action->encap.ttl = ttl ? nl_attr_get_u8(ttl) : 0; + + err = nl_parse_act_tunnel_opts(tun_opt, action); + if (err) { + return err; + } } else if (tun->t_action == TCA_TUNNEL_KEY_ACT_RELEASE) { flower->tunnel = true; } else { @@ -1317,13 +1426,47 @@ nl_msg_put_act_tunnel_key_release(struct ofpbuf *request) nl_msg_end_nested(request, offset); } +static void +nl_msg_put_act_tunnel_geneve_option(struct ofpbuf *request, + struct tun_metadata tun_metadata) +{ + const struct geneve_opt *opt; + size_t outer, inner; + int len, cnt = 0; + + len = tun_metadata.present.len; + if (!len) { + return; + } + + outer = nl_msg_start_nested(request, TCA_TUNNEL_KEY_ENC_OPTS); + + while (len) { + opt = &tun_metadata.opts.gnv[cnt]; + inner = nl_msg_start_nested(request, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE); + + nl_msg_put_be16(request, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS, + opt->opt_class); + nl_msg_put_u8(request, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE, opt->type); + nl_msg_put_unspec(request, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA, opt + 1, + opt->length * 4); + + cnt += sizeof(struct geneve_opt) / 4 + opt->length; + len -= sizeof(struct geneve_opt) + opt->length * 4; + + nl_msg_end_nested(request, inner); + } + + nl_msg_end_nested(request, outer); +} + static void nl_msg_put_act_tunnel_key_set(struct ofpbuf *request, ovs_be64 id, - ovs_be32 ipv4_src, ovs_be32 ipv4_dst, - struct in6_addr *ipv6_src, - struct in6_addr *ipv6_dst, - ovs_be16 tp_dst, - uint8_t tos, uint8_t ttl) + ovs_be32 ipv4_src, ovs_be32 ipv4_dst, + struct in6_addr *ipv6_src, + struct in6_addr *ipv6_dst, + ovs_be16 tp_dst, uint8_t tos, uint8_t ttl, + struct tun_metadata tun_metadata) { size_t offset; @@ -1353,6 +1496,7 @@ nl_msg_put_act_tunnel_key_set(struct ofpbuf *request, ovs_be64 id, nl_msg_put_u8(request, TCA_TUNNEL_KEY_ENC_TTL, ttl); } nl_msg_put_be16(request, TCA_TUNNEL_KEY_ENC_DST_PORT, tp_dst); + nl_msg_put_act_tunnel_geneve_option(request, tun_metadata); } nl_msg_end_nested(request, offset); } @@ -1595,7 +1739,8 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) &action->encap.ipv6.ipv6_dst, action->encap.tp_dst, action->encap.tos, - action->encap.ttl); + action->encap.ttl, + action->encap.data); nl_msg_end_nested(request, act_offset); } break; diff --git a/lib/tc.h b/lib/tc.h index d41784a35..6c17ee391 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -27,6 +27,7 @@ #include "odp-netlink.h" #include "openvswitch/ofpbuf.h" #include "openvswitch/flow.h" +#include "openvswitch/tun-metadata.h" /* For backwards compatability with older kernels */ #ifndef TC_H_CLSACT @@ -157,6 +158,7 @@ struct tc_action { struct in6_addr ipv6_src; struct in6_addr ipv6_dst; } ipv6; + struct tun_metadata data; } encap; }; From patchwork Tue Sep 18 08:36:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pieter Jansen van Vuuren X-Patchwork-Id: 971029 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=netronome.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="aXWPSvLT"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42DxFD3ZRzz9sCS for ; Tue, 18 Sep 2018 18:37:20 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id E8483D8F; Tue, 18 Sep 2018 08:36:27 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 45D8DD8B for ; Tue, 18 Sep 2018 08:36:27 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-qk1-f180.google.com (mail-qk1-f180.google.com [209.85.222.180]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 3F93142D for ; Tue, 18 Sep 2018 08:36:26 +0000 (UTC) Received: by mail-qk1-f180.google.com with SMTP id g13-v6so539287qki.9 for ; Tue, 18 Sep 2018 01:36:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netronome-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=diWL3HA3dYO1nSS/N5o2VID0bbK4BaEaXqq2T5SsxAM=; b=aXWPSvLTiF8skJ74Rx446P88M/LTprt7bK2/SqzhsM5jhxramje5k07bmifBhK5MfP Xmq6uHYA4hzVXgWkbF9EvrOvCciK1NwajCxJscWKjCZUfZysFbuT+Mjz7CIj4G08GxUT zTwwN/imYRrRVkiAkBgFAlelfxiDmLr5JYumedSMTZ69bWSB5ag9pBOFBopy7PvsDNBp HKO9yy/9QqQmZpSTNq4JAR6KFvw1u1UdEWM/pOHJIvh16sT8CHHg6UXlWkxROwV2uFln HZSHKkg5a+Ck6ftCZLkQMqBgNsMwhocqoBrx0aJzObjcTUOHRw8iAbRkIV5AxDUzrgpl hMgQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=diWL3HA3dYO1nSS/N5o2VID0bbK4BaEaXqq2T5SsxAM=; b=lMpVd72+b9SGffvzA2OacULlT9nHIRNxI2P4PxRAziztuc8uIxx+EmZJVnf1jMPp9h d6bVCYYqwpeWYGya8wMIu0SuRlNA5QmqodLBVQnFL+K/tm7LwdNethnMeP/Cn9a4hm+O IpMgSA8+DsHCNrH7NuycoFhePIU0HpkOOT3ng8voBUKNOQOwIdox8KEh/emNqtCZEQYF yevwwFrq5dZ9TAYXqot+MFnNnaeIHVtO7Z3Z2PVlPksGyPF+WE0tXnjP471XXPu+KPm0 +SRD4upJdP69MNa3qX+yCvhxOab7ulzftPE8IlaxK9aSjXAjErfX8vDwaOirRLs0xbvJ 5HvQ== X-Gm-Message-State: APzg51ApH8W5QwMW4/BAt7fTHJychzKZovHEiIk4PDICTDvChR086LTi 9fOIp/aDrshjXmv1ok3V73Fj/ZacfpM= X-Google-Smtp-Source: ANB0VdZTn5qP4adMcNncqmgU5ynaYtDj9gxuGXoqCMOt1X+sJcxzQIjB4eyKb9a8hjZJ1rP+P7+Q2Q== X-Received: by 2002:a37:aa91:: with SMTP id t139-v6mr19922766qke.217.1537259785089; Tue, 18 Sep 2018 01:36:25 -0700 (PDT) Received: from pieter-Netronome.netronome.com (host81-150-168-85.in-addr.btopenworld.com. [81.150.168.85]) by smtp.gmail.com with ESMTPSA id l132-v6sm10490647qke.33.2018.09.18.01.36.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 18 Sep 2018 01:36:24 -0700 (PDT) From: Pieter Jansen van Vuuren To: dev@openvswitch.org Date: Tue, 18 Sep 2018 09:36:20 +0100 Message-Id: <1537259780-9769-3-git-send-email-pieter.jansenvanvuuren@netronome.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1537259780-9769-1-git-send-email-pieter.jansenvanvuuren@netronome.com> References: <1537259780-9769-1-git-send-email-pieter.jansenvanvuuren@netronome.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: horms+renesas@verge.net.au, Pieter Jansen van Vuuren Subject: [ovs-dev] [PATCH v4 2/2] lib/tc: add geneve with option match offload X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Add TC offload support for classifying geneve tunnels with options. Signed-off-by: Pieter Jansen van Vuuren Reviewed-by: Simon Horman --- include/linux/pkt_cls.h | 25 +++++ lib/netdev-tc-offloads.c | 64 +++++++++++++ lib/tc.c | 198 ++++++++++++++++++++++++++++++++++++++- lib/tc.h | 1 + 4 files changed, 286 insertions(+), 2 deletions(-) diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index a3300418e..1384d71f9 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -204,10 +204,35 @@ enum { TCA_FLOWER_KEY_ENC_IP_TOS_MASK, /* 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_MAX, }; +enum { + TCA_FLOWER_KEY_ENC_OPTS_UNSPEC, + TCA_FLOWER_KEY_ENC_OPTS_GENEVE, /* Nested + * TCA_TUNNEL_KEY_ENC_OPTS_GENEVE + * attributes + */ + __TCA_FLOWER_KEY_ENC_OPTS_MAX, +}; + +#define TCA_FLOWER_KEY_ENC_OPTS_MAX (__TCA_FLOWER_KEY_ENC_OPTS_MAX - 1) + +enum { + TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC, + TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, /* u16 */ + TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, /* u8 */ + TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, /* 4 to 128 bytes */ + + __TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX, +}; + +#define TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX \ + (__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX - 1) + enum { TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0), TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1), diff --git a/lib/netdev-tc-offloads.c b/lib/netdev-tc-offloads.c index 097893584..4894c0d0f 100644 --- a/lib/netdev-tc-offloads.c +++ b/lib/netdev-tc-offloads.c @@ -432,6 +432,38 @@ static void parse_tc_flower_geneve_opts(struct tc_action *action, nl_msg_end_nested(buf, geneve_off); } +static void +flower_tun_opt_to_match(struct match *match, struct tc_flower *flower) +{ + struct geneve_opt *opt, *opt_mask; + int len, cnt = 0; + + memcpy(match->flow.tunnel.metadata.opts.gnv, + flower->key.tunnel.metadata.opts.gnv, + flower->key.tunnel.metadata.present.len); + match->flow.tunnel.metadata.present.len = + flower->key.tunnel.metadata.present.len; + match->flow.tunnel.flags |= FLOW_TNL_F_UDPIF; + memcpy(match->wc.masks.tunnel.metadata.opts.gnv, + flower->mask.tunnel.metadata.opts.gnv, + flower->mask.tunnel.metadata.present.len); + + len = flower->key.tunnel.metadata.present.len; + while (len) { + opt = &match->flow.tunnel.metadata.opts.gnv[cnt]; + opt_mask = &match->wc.masks.tunnel.metadata.opts.gnv[cnt]; + + opt_mask->length = 0x1f; + + cnt += sizeof(struct geneve_opt) / 4 + opt->length; + len -= sizeof(struct geneve_opt) + opt->length * 4; + } + + match->wc.masks.tunnel.metadata.present.len = + flower->mask.tunnel.metadata.present.len; + match->wc.masks.tunnel.flags |= FLOW_TNL_F_UDPIF; +} + static int parse_tc_flower_to_match(struct tc_flower *flower, struct match *match, @@ -548,6 +580,9 @@ parse_tc_flower_to_match(struct tc_flower *flower, if (flower->key.tunnel.tp_dst) { match_set_tun_tp_dst(match, flower->key.tunnel.tp_dst); } + if (flower->key.tunnel.metadata.present.len) { + flower_tun_opt_to_match(match, flower); + } } act_off = nl_msg_start_nested(buf, OVS_FLOW_ATTR_ACTIONS); @@ -968,6 +1003,34 @@ test_key_and_mask(struct match *match) return 0; } +static void +flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl, + const struct flow_tnl *tnl_mask) +{ + struct geneve_opt *opt, *opt_mask; + int len, cnt = 0; + + memcpy(flower->key.tunnel.metadata.opts.gnv, tnl->metadata.opts.gnv, + tnl->metadata.present.len); + flower->key.tunnel.metadata.present.len = tnl->metadata.present.len; + + memcpy(flower->mask.tunnel.metadata.opts.gnv, tnl_mask->metadata.opts.gnv, + tnl->metadata.present.len); + + len = flower->key.tunnel.metadata.present.len; + while (len) { + opt = &flower->key.tunnel.metadata.opts.gnv[cnt]; + opt_mask = &flower->mask.tunnel.metadata.opts.gnv[cnt]; + + opt_mask->length = opt->length; + + cnt += sizeof(struct geneve_opt) / 4 + opt->length; + len -= sizeof(struct geneve_opt) + opt->length * 4; + } + + flower->mask.tunnel.metadata.present.len = tnl->metadata.present.len; +} + int netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct nlattr *actions, size_t actions_len, @@ -1016,6 +1079,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, flower.key.tunnel.tp_dst = tnl->tp_dst; flower.mask.tunnel.tos = tnl_mask->ip_tos; flower.mask.tunnel.ttl = tnl_mask->ip_ttl; + flower_match_to_tun_opt(&flower, tnl, tnl_mask); flower.tunnel = true; } memset(&mask->tunnel, 0, sizeof mask->tunnel); diff --git a/lib/tc.c b/lib/tc.c index 45e59e4d7..1cf305487 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -325,6 +325,9 @@ static const struct nl_policy tca_flower_policy[] = { .optional = true, }, [TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NL_A_U8, .optional = true, }, + [TCA_FLOWER_KEY_ENC_OPTS] = { .type = NL_A_NESTED, .optional = true, }, + [TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NL_A_NESTED, + .optional = true, }, }; static void @@ -431,9 +434,130 @@ nl_parse_flower_vlan(struct nlattr **attrs, struct tc_flower *flower) } } -static void +static int +nl_parse_geneve_key(const struct nlattr *in_nlattr, + struct tun_metadata *metadata) +{ + struct geneve_opt *opt = NULL; + const struct ofpbuf *msg; + uint16_t last_opt_type; + struct nlattr *nla; + struct ofpbuf buf; + size_t left; + int cnt; + + nl_attr_get_nested(in_nlattr, &buf); + msg = &buf; + + last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC; + cnt = 0; + NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) { + uint16_t type = nl_attr_type(nla); + + switch (type) { + case TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS: + if (cnt && last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA) { + VLOG_ERR_RL(&error_rl, "failed to parse tun options class"); + return EINVAL; + } + + opt = &metadata->opts.gnv[cnt]; + opt->opt_class = nl_attr_get_be16(nla); + cnt += sizeof(struct geneve_opt) / 4; + metadata->present.len += sizeof(struct geneve_opt); + last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS; + break; + case TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE: + if (last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS) { + VLOG_ERR_RL(&error_rl, "failed to parse tun options type"); + return EINVAL; + } + + opt->type = nl_attr_get_u8(nla); + last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE; + break; + case TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA: + if (last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE) { + VLOG_ERR_RL(&error_rl, "failed to parse tun options data"); + return EINVAL; + } + + opt->length = nl_attr_get_size(nla) / 4; + memcpy(opt + 1, nl_attr_get_unspec(nla, 1), opt->length * 4); + cnt += opt->length; + metadata->present.len += opt->length * 4; + last_opt_type = TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA; + break; + } + } + + if (last_opt_type != TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA) { + VLOG_ERR_RL(&error_rl, "failed to parse tun options without data"); + return EINVAL; + } + + return 0; +} + +static int +nl_parse_flower_tunnel_opts(struct nlattr *options, + struct tun_metadata *metadata) +{ + const struct ofpbuf *msg; + struct nlattr *nla; + struct ofpbuf buf; + size_t left; + int err; + + nl_attr_get_nested(options, &buf); + msg = &buf; + + NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, 0, 0), msg->size) { + uint16_t type = nl_attr_type(nla); + switch (type) { + case TCA_FLOWER_KEY_ENC_OPTS_GENEVE: + err = nl_parse_geneve_key(nla, metadata); + if (err) { + return err; + } + + break; + } + } + + return 0; +} + +static int +flower_tun_geneve_opt_check_len(struct tun_metadata *key, + struct tun_metadata *mask) +{ + const struct geneve_opt *opt, *opt_mask; + int len, cnt = 0; + + len = key->present.len; + while (len) { + opt = &key->opts.gnv[cnt]; + opt_mask = &mask->opts.gnv[cnt]; + + if (opt->length != opt_mask->length) { + VLOG_ERR_RL(&error_rl, + "failed to parse tun options; key/mask length differ"); + return EINVAL; + } + + cnt += sizeof(struct geneve_opt) / 4 + opt->length; + len -= sizeof(struct geneve_opt) + opt->length * 4; + } + + return 0; +} + +static int nl_parse_flower_tunnel(struct nlattr **attrs, struct tc_flower *flower) { + int err; + if (attrs[TCA_FLOWER_KEY_ENC_KEY_ID]) { ovs_be32 id = nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_KEY_ID]); @@ -471,6 +595,35 @@ 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 (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], + &flower->key.tunnel.metadata); + if (err) { + return err; + } + + err = nl_parse_flower_tunnel_opts(attrs[TCA_FLOWER_KEY_ENC_OPTS_MASK], + &flower->mask.tunnel.metadata); + if (err) { + return err; + } + + err = flower_tun_geneve_opt_check_len(&flower->key.tunnel.metadata, + &flower->mask.tunnel.metadata); + if (err) { + return err; + } + } else if (attrs[TCA_FLOWER_KEY_ENC_OPTS]) { + VLOG_ERR_RL(&error_rl, + "failed to parse tun options; no mask supplied"); + return EINVAL; + } else if (attrs[TCA_FLOWER_KEY_ENC_OPTS_MASK]) { + VLOG_ERR_RL(&error_rl, "failed to parse tun options; no key supplied"); + return EINVAL; + } + + return 0; } static void @@ -1184,6 +1337,7 @@ static int nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower) { struct nlattr *attrs[ARRAY_SIZE(tca_flower_policy)]; + int err; if (!nl_parse_nested(nl_options, tca_flower_policy, attrs, ARRAY_SIZE(tca_flower_policy))) { @@ -1195,7 +1349,11 @@ nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower) nl_parse_flower_mpls(attrs, flower); nl_parse_flower_vlan(attrs, flower); nl_parse_flower_ip(attrs, flower); - nl_parse_flower_tunnel(attrs, flower); + err = nl_parse_flower_tunnel(attrs, flower); + if (err) { + return err; + } + nl_parse_flower_flags(attrs, flower); return nl_parse_flower_actions(attrs, flower); } @@ -1806,6 +1964,38 @@ nl_msg_put_masked_value(struct ofpbuf *request, uint16_t type, nl_msg_put_unspec(request, type, data, len); } +static void +nl_msg_put_flower_tunnel_opts(struct ofpbuf *request, uint16_t type, + struct tun_metadata metadata) +{ + struct geneve_opt *opt; + size_t outer, inner; + int len, cnt = 0; + + len = metadata.present.len; + if (!len) { + return; + } + + outer = nl_msg_start_nested(request, type); + while (len) { + opt = &metadata.opts.gnv[cnt]; + inner = nl_msg_start_nested(request, TCA_FLOWER_KEY_ENC_OPTS_GENEVE); + + nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, + opt->opt_class); + nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, opt->type); + nl_msg_put_unspec(request, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, opt + 1, + opt->length * 4); + + cnt += sizeof(struct geneve_opt) / 4 + opt->length; + len -= sizeof(struct geneve_opt) + opt->length * 4; + + nl_msg_end_nested(request, inner); + } + nl_msg_end_nested(request, outer); +} + static void nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower) { @@ -1837,6 +2027,10 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower) } nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, tp_dst); nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_KEY_ID, id); + nl_msg_put_flower_tunnel_opts(request, TCA_FLOWER_KEY_ENC_OPTS, + flower->key.tunnel.metadata); + nl_msg_put_flower_tunnel_opts(request, TCA_FLOWER_KEY_ENC_OPTS_MASK, + flower->mask.tunnel.metadata); } #define FLOWER_PUT_MASKED_VALUE(member, type) \ diff --git a/lib/tc.h b/lib/tc.h index 6c17ee391..cff96c5c2 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -123,6 +123,7 @@ struct tc_flower_key { ovs_be16 tp_src; ovs_be16 tp_dst; ovs_be64 id; + struct tun_metadata metadata; } tunnel; };