From patchwork Mon Apr 27 10:27:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xin Long X-Patchwork-Id: 220511 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C11CC55199 for ; Mon, 27 Apr 2020 10:28:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3CD572064C for ; Mon, 27 Apr 2020 10:28:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="WGakBinn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726910AbgD0K2L (ORCPT ); Mon, 27 Apr 2020 06:28:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52898 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726485AbgD0K2K (ORCPT ); Mon, 27 Apr 2020 06:28:10 -0400 Received: from mail-pj1-x102f.google.com (mail-pj1-x102f.google.com [IPv6:2607:f8b0:4864:20::102f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EA1AEC0610D5 for ; Mon, 27 Apr 2020 03:28:09 -0700 (PDT) Received: by mail-pj1-x102f.google.com with SMTP id fu13so6683101pjb.5 for ; Mon, 27 Apr 2020 03:28:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=HGmAurgiw7FOggcadAdXMkYsyzuikCAgMNna3+Rzf6o=; b=WGakBinn5W8o5UvaSrF7PCZz5kY8bexnfe+mS/mHF28Tcb44Q4ujuS2Tts4x79BZYy hWm5rJOwmDCFgifQCzZgBKGhPGlZHEt6zXfir8x2k3/hY7rWKpIESeT7kLw4ybVs6uyE c3mMyJzOw4r5kXz38pbequIzdcge8lvUewU4dseqO/9koCW67XGYw86zA2ThKDOEMcTx zhImmysstl6CR2QUAKJ6TNtWa3nBfdLm0H0YL0FnnYmloqbcMdwYhb6Kgl5T+prCXXb0 znhAgSRjMtgObce8i4sH6NNn6EXyPA4hQllvjapH3se/GJxcShMYxrpCSmSjIChwW+Fc pztQ== 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:in-reply-to:references; bh=HGmAurgiw7FOggcadAdXMkYsyzuikCAgMNna3+Rzf6o=; b=tqTSD0cIhda93xe3lhDj5IzID447WKjI61s+r35XS7CtqgguiibW0/xtSRG/BoQKZ4 ciFfwmGQt4W1Vf4zCPmJ9ovoxAzuo/tjPScaWz3wOzunxpUSuCJDUTGnTrjQl8w3qpXJ /NfBEotR2KIuuzOf/jRuErNGEW1Gth1liI0k5RtfBxXVWjufhZSZybBzT/X8K/Pja/EE 5O6dcfw5PREqZhGd29RIpjbUI2QFmsw4HX5Vo65iYIIc0ZkXgeWnLeAtA1KPafUV3OZ6 9Vqsc4M72nlCXSlEvFQgpVls4iFr8asa3EZZn37+n4JR9EzD16fKtgITtUE4bycSGf1W 3PSw== X-Gm-Message-State: AGi0PuafnCAAqLtHz3UoEx+rTK4GttTuBcEqDObdtW1a0TTsCqsNqsB2 ylrE1iPR95BY0J/MxykLRsDZmTEo X-Google-Smtp-Source: APiQypLSyjkyNT43VfVf6jzzdkjKSVOtGe2R6UA3KgNuUoN2lRHqVAJRP2ILfnfy2tBqVkxRgL361A== X-Received: by 2002:a17:90a:23e2:: with SMTP id g89mr23078791pje.105.1587983289043; Mon, 27 Apr 2020 03:28:09 -0700 (PDT) Received: from localhost ([209.132.188.80]) by smtp.gmail.com with ESMTPSA id j7sm3053829pfi.160.2020.04.27.03.28.07 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 27 Apr 2020 03:28:08 -0700 (PDT) From: Xin Long To: network dev , stephen@networkplumber.org Cc: David Ahern , Jakub Kicinski Subject: [PATCHv4 iproute2-next 1/7] iproute_lwtunnel: add options support for geneve metadata Date: Mon, 27 Apr 2020 18:27:45 +0800 Message-Id: X-Mailer: git-send-email 2.1.0 In-Reply-To: References: In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch is to add LWTUNNEL_IP(6)_OPTS and LWTUNNEL_IP_OPTS_GENEVE's parse and print to implement geneve options support in iproute_lwtunnel. Options are expressed as class:type:data and multiple options may be listed using a comma delimiter, class and type are numbers and data is a hex string. With this patch, users can add and dump geneve options like: # ip netns add a # ip netns add b # ip -n a link add eth0 type veth peer name eth0 netns b # ip -n a link set eth0 up; ip -n b link set eth0 up # ip -n a addr add 10.1.0.1/24 dev eth0 # ip -n b addr add 10.1.0.2/24 dev eth0 # ip -n b link add geneve1 type geneve id 1 remote 10.1.0.1 ttl 64 # ip -n b addr add 1.1.1.1/24 dev geneve1 # ip -n b link set geneve1 up # ip -n b route add 2.1.1.0/24 dev geneve1 # ip -n a link add geneve1 type geneve external # ip -n a addr add 2.1.1.1/24 dev geneve1 # ip -n a link set geneve1 up # ip -n a route add 1.1.1.0/24 encap ip id 1 geneve_opts \ 1:1:1212121234567890,1:1:1212121234567890,1:1:1212121234567890 \ dst 10.1.0.2 dev geneve1 # ip -n a route show # ip netns exec a ping 1.1.1.1 -c 1 1.1.1.0/24 encap ip id 1 src 0.0.0.0 dst 10.1.0.2 ttl 0 tos 0 geneve_opts 1:1:1212121234567890,1:1:1212121234567890 ... PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. 64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=0.079 ms v1->v2: - improve the changelog. - use PRINT_ANY to support dumping with json format. v2->v3: - implement proper JSON array for opts instead of just bunch of strings. v3->v4: - keep the same format between input and output, json and non json. - print class and type as uint and print data as hex string. Signed-off-by: Xin Long --- ip/iproute_lwtunnel.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 2 deletions(-) diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 0d7d714..8599853 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -294,6 +294,54 @@ static void print_encap_mpls(FILE *fp, struct rtattr *encap) rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL])); } +static void lwtunnel_print_geneve_opts(struct rtattr *attr) +{ + struct rtattr *tb[LWTUNNEL_IP_OPT_GENEVE_MAX + 1]; + struct rtattr *i = RTA_DATA(attr); + int rem = RTA_PAYLOAD(attr); + char *name = "geneve_opts"; + int data_len, offset = 0; + char data[rem * 2 + 1]; + __u16 class; + __u8 type; + + print_nl(); + print_string(PRINT_FP, name, "\t%s ", name); + open_json_array(PRINT_JSON, name); + + while (rem) { + parse_rtattr(tb, LWTUNNEL_IP_OPT_GENEVE_MAX, i, rem); + class = rta_getattr_be16(tb[LWTUNNEL_IP_OPT_GENEVE_CLASS]); + type = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_GENEVE_TYPE]); + data_len = RTA_PAYLOAD(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]); + hexstring_n2a(RTA_DATA(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]), + data_len, data, sizeof(data)); + offset += data_len + 20; + rem -= data_len + 20; + i = RTA_DATA(attr) + offset; + + open_json_object(NULL); + print_uint(PRINT_ANY, "class", "%u", class); + print_uint(PRINT_ANY, "type", ":%u", type); + if (rem) + print_string(PRINT_ANY, "data", ":%s,", data); + else + print_string(PRINT_ANY, "data", ":%s ", data); + close_json_object(); + } + + close_json_array(PRINT_JSON, name); +} + +static void lwtunnel_print_opts(struct rtattr *attr) +{ + struct rtattr *tb_opt[LWTUNNEL_IP_OPTS_MAX + 1]; + + parse_rtattr_nested(tb_opt, LWTUNNEL_IP_OPTS_MAX, attr); + if (tb_opt[LWTUNNEL_IP_OPTS_GENEVE]) + lwtunnel_print_geneve_opts(tb_opt[LWTUNNEL_IP_OPTS_GENEVE]); +} + static void print_encap_ip(FILE *fp, struct rtattr *encap) { struct rtattr *tb[LWTUNNEL_IP_MAX+1]; @@ -332,6 +380,9 @@ static void print_encap_ip(FILE *fp, struct rtattr *encap) if (flags & TUNNEL_SEQ) print_bool(PRINT_ANY, "seq", "seq ", true); } + + if (tb[LWTUNNEL_IP_OPTS]) + lwtunnel_print_opts(tb[LWTUNNEL_IP_OPTS]); } static void print_encap_ila(FILE *fp, struct rtattr *encap) @@ -404,6 +455,9 @@ static void print_encap_ip6(FILE *fp, struct rtattr *encap) if (flags & TUNNEL_SEQ) print_bool(PRINT_ANY, "seq", "seq ", true); } + + if (tb[LWTUNNEL_IP6_OPTS]) + lwtunnel_print_opts(tb[LWTUNNEL_IP6_OPTS]); } static void print_encap_bpf(FILE *fp, struct rtattr *encap) @@ -798,11 +852,97 @@ static int parse_encap_mpls(struct rtattr *rta, size_t len, return 0; } +static int lwtunnel_parse_geneve_opt(char *str, size_t len, struct rtattr *rta) +{ + struct rtattr *nest; + char *token; + int i, err; + + nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_GENEVE | NLA_F_NESTED); + i = 1; + token = strsep(&str, ":"); + while (token) { + switch (i) { + case LWTUNNEL_IP_OPT_GENEVE_CLASS: + { + __be16 opt_class; + + if (!strlen(token)) + break; + err = get_be16(&opt_class, token, 0); + if (err) + return err; + + rta_addattr16(rta, len, i, opt_class); + break; + } + case LWTUNNEL_IP_OPT_GENEVE_TYPE: + { + __u8 opt_type; + + if (!strlen(token)) + break; + err = get_u8(&opt_type, token, 0); + if (err) + return err; + + rta_addattr8(rta, len, i, opt_type); + break; + } + case LWTUNNEL_IP_OPT_GENEVE_DATA: + { + size_t token_len = strlen(token); + __u8 *opts; + + if (!token_len) + break; + opts = malloc(token_len / 2); + if (!opts) + return -1; + if (hex2mem(token, opts, token_len / 2) < 0) { + free(opts); + return -1; + } + rta_addattr_l(rta, len, i, opts, token_len / 2); + free(opts); + + break; + } + default: + fprintf(stderr, "Unknown \"geneve_opts\" type\n"); + return -1; + } + + token = strsep(&str, ":"); + i++; + } + rta_nest_end(rta, nest); + + return 0; +} + +static int lwtunnel_parse_geneve_opts(char *str, size_t len, struct rtattr *rta) +{ + char *token; + int err; + + token = strsep(&str, ","); + while (token) { + err = lwtunnel_parse_geneve_opt(token, len, rta); + if (err) + return err; + + token = strsep(&str, ","); + } + + return 0; +} + static int parse_encap_ip(struct rtattr *rta, size_t len, int *argcp, char ***argvp) { int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0; - int key_ok = 0, csum_ok = 0, seq_ok = 0; + int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0; char **argv = *argvp; int argc = *argcp; int ret = 0; @@ -854,6 +994,21 @@ static int parse_encap_ip(struct rtattr *rta, size_t len, if (get_u8(&ttl, *argv, 0)) invarg("\"ttl\" value is invalid\n", *argv); ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl); + } else if (strcmp(*argv, "geneve_opts") == 0) { + struct rtattr *nest; + + if (opts_ok++) + duparg2("opts", *argv); + + NEXT_ARG(); + + nest = rta_nest(rta, len, + LWTUNNEL_IP_OPTS | NLA_F_NESTED); + ret = lwtunnel_parse_geneve_opts(*argv, len, rta); + if (ret) + invarg("\"geneve_opts\" value is invalid\n", + *argv); + rta_nest_end(rta, nest); } else if (strcmp(*argv, "key") == 0) { if (key_ok++) duparg2("key", *argv); @@ -969,7 +1124,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len, int *argcp, char ***argvp) { int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0; - int key_ok = 0, csum_ok = 0, seq_ok = 0; + int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0; char **argv = *argvp; int argc = *argcp; int ret = 0; @@ -1023,6 +1178,21 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len, *argv); ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit); + } else if (strcmp(*argv, "geneve_opts") == 0) { + struct rtattr *nest; + + if (opts_ok++) + duparg2("opts", *argv); + + NEXT_ARG(); + + nest = rta_nest(rta, len, + LWTUNNEL_IP_OPTS | NLA_F_NESTED); + ret = lwtunnel_parse_geneve_opts(*argv, len, rta); + if (ret) + invarg("\"geneve_opts\" value is invalid\n", + *argv); + rta_nest_end(rta, nest); } else if (strcmp(*argv, "key") == 0) { if (key_ok++) duparg2("key", *argv); From patchwork Mon Apr 27 10:27:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xin Long X-Patchwork-Id: 220510 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BB1FFC54FD0 for ; Mon, 27 Apr 2020 10:28:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8DF02206D4 for ; Mon, 27 Apr 2020 10:28:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="nQv2pqc7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726974AbgD0K21 (ORCPT ); Mon, 27 Apr 2020 06:28:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726485AbgD0K21 (ORCPT ); Mon, 27 Apr 2020 06:28:27 -0400 Received: from mail-pj1-x102c.google.com (mail-pj1-x102c.google.com [IPv6:2607:f8b0:4864:20::102c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 23C12C0610D5 for ; Mon, 27 Apr 2020 03:28:27 -0700 (PDT) Received: by mail-pj1-x102c.google.com with SMTP id a31so5389889pje.1 for ; Mon, 27 Apr 2020 03:28:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=USkkXEPoOKED/JJ4CrOpmmsSHb2eVX4V2P7UD7R62BY=; b=nQv2pqc7H9fO7elEHAjP9CZVls3sQKXQ42JChK8gLKQbHdj4OY5pTtaIQ17Sy4d77T u3dDfiGy9aC0Ai4KpvoJcvExCEveQwTaz7Vk7vH3/EyaTKC8EDmStGZX6o9bCqAk1vUF GJ0nAKoGt80gS0qQhyn7IhDKF6L5TVSP5Kt3F7SYulzeaz63Nc29yM2L24hXVkjeUEAZ nNjRB/I0bMjr3bkyEw/nbEn1zrkHPgvflwNF95Xy14bAaagWejhuCXeDFNx3CVMn6l4z Xx3Q1hJ6Y9BOzPB2CHVRupWc2fyH6mRJ5Le2P0AViF1lZavZF67xohPyhsxTMlCSeLHL BWTA== 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:in-reply-to:references; bh=USkkXEPoOKED/JJ4CrOpmmsSHb2eVX4V2P7UD7R62BY=; b=jM84XKUucrZ/hVnIagRt2yAb4hHF6Ybgn4YLJeI8UHidzqPv4vaJx+s0StWZuRHq3G 3J9zpOzRpqVlohtxz5i21FGuGXrqTsiuMMMUkWZm8ZzR5tOhytCkSl141tPbb8NU5zGU GMbjpF3ECBZtQcyn8s8zZ0V5H500o+S9TtovVwnNqbFyFF6JDC+8bdnMU+Z7vNzJotGj SzHvLzcQyCUY/sYnUKIJCTHzwAbLUjeSBEQ/hiDqTLidDrHtaM8a8O/P8GsepshuWvhe d8VAGAhOvR/AN/ksyqgZJ6F43NLqy9RVGYo7DE72hxbMt6lgSk2OCItL235q2hbCkQK9 JSGg== X-Gm-Message-State: AGi0PubAlxLkeGj3mAQUfJyZBQb9Rcp0l3cbCBtoT+emwtOrknGZegzH Huo6p1JOGibJ/doKQfbUJU08WZV4 X-Google-Smtp-Source: APiQypIZ/b0claxdw+oHzIsxlfAImCdCy4Bp/ob3jxaHFLcPVleouj4q1imFA41HriKQFtEkirAa7A== X-Received: by 2002:a17:90a:ea05:: with SMTP id w5mr24100912pjy.143.1587983306157; Mon, 27 Apr 2020 03:28:26 -0700 (PDT) Received: from localhost ([209.132.188.80]) by smtp.gmail.com with ESMTPSA id c2sm12254090pfp.118.2020.04.27.03.28.24 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 27 Apr 2020 03:28:25 -0700 (PDT) From: Xin Long To: network dev , stephen@networkplumber.org Cc: David Ahern , Jakub Kicinski Subject: [PATCHv4 iproute2-next 3/7] iproute_lwtunnel: add options support for erspan metadata Date: Mon, 27 Apr 2020 18:27:47 +0800 Message-Id: <4ae2ca59ac4262b19212a16ee7474189ae5eca72.1587983178.git.lucien.xin@gmail.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <838c55576eabd17db407a95bc6609c05bf5e174b.1587983178.git.lucien.xin@gmail.com> References: <838c55576eabd17db407a95bc6609c05bf5e174b.1587983178.git.lucien.xin@gmail.com> In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch is to add LWTUNNEL_IP_OPTS_ERSPAN's parse and print to implement erspan options support in iproute_lwtunnel. Option is expressed as version:index:dir:hwid, dir and hwid will be parsed when version is 2, while index will be parsed when version is 1. All of these are numbers. erspan doesn't support multiple options. With this patch, users can add and dump erspan options like: # ip netns add a # ip netns add b # ip -n a link add eth0 type veth peer name eth0 netns b # ip -n a link set eth0 up # ip -n b link set eth0 up # ip -n a addr add 10.1.0.1/24 dev eth0 # ip -n b addr add 10.1.0.2/24 dev eth0 # ip -n b link add erspan1 type erspan key 1 seq erspan 123 \ local 10.1.0.2 remote 10.1.0.1 # ip -n b addr add 1.1.1.1/24 dev erspan1 # ip -n b link set erspan1 up # ip -n b route add 2.1.1.0/24 dev erspan1 # ip -n a link add erspan1 type erspan key 1 seq local 10.1.0.1 external # ip -n a addr add 2.1.1.1/24 dev erspan1 # ip -n a link set erspan1 up # ip -n a route add 1.1.1.0/24 encap ip id 1 \ erspan_opts 2:123:1:2 dst 10.1.0.2 dev erspan1 # ip -n a route show # ip netns exec a ping 1.1.1.1 -c 1 1.1.1.0/24 encap ip id 1 src 0.0.0.0 dst 10.1.0.2 ttl 0 tos 0 erspan_opts 2:0:1:2 dev erspan1 scope link PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. 64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=0.124 ms v1->v2: - improve the changelog. - use PRINT_ANY to support dumping with json format. v2->v3: - implement proper JSON object for opts instead of just bunch of strings. v3->v4: - keep the same format between input and output, json and non json. - print version, index, dir and hwid as uint. Signed-off-by: Xin Long --- ip/iproute_lwtunnel.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 9945c86..d413e19 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -353,6 +353,38 @@ static void lwtunnel_print_vxlan_opts(struct rtattr *attr) close_json_array(PRINT_JSON, name); } +static void lwtunnel_print_erspan_opts(struct rtattr *attr) +{ + struct rtattr *tb[LWTUNNEL_IP_OPT_ERSPAN_MAX + 1]; + struct rtattr *i = RTA_DATA(attr); + char *name = "erspan_opts"; + __u8 ver, hwid, dir; + __u32 idx; + + parse_rtattr(tb, LWTUNNEL_IP_OPT_ERSPAN_MAX, i, RTA_PAYLOAD(attr)); + ver = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_VER]); + if (ver == 1) { + idx = rta_getattr_be32(tb[LWTUNNEL_IP_OPT_ERSPAN_INDEX]); + dir = 0; + hwid = 0; + } else { + idx = 0; + dir = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_DIR]); + hwid = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_HWID]); + } + + print_nl(); + print_string(PRINT_FP, name, "\t%s ", name); + open_json_array(PRINT_JSON, name); + open_json_object(NULL); + print_uint(PRINT_ANY, "ver", "%u", ver); + print_uint(PRINT_ANY, "index", ":%u", idx); + print_uint(PRINT_ANY, "dir", ":%u", dir); + print_uint(PRINT_ANY, "hwid", ":%u ", hwid); + close_json_object(); + close_json_array(PRINT_JSON, name); +} + static void lwtunnel_print_opts(struct rtattr *attr) { struct rtattr *tb_opt[LWTUNNEL_IP_OPTS_MAX + 1]; @@ -362,6 +394,8 @@ static void lwtunnel_print_opts(struct rtattr *attr) lwtunnel_print_geneve_opts(tb_opt[LWTUNNEL_IP_OPTS_GENEVE]); else if (tb_opt[LWTUNNEL_IP_OPTS_VXLAN]) lwtunnel_print_vxlan_opts(tb_opt[LWTUNNEL_IP_OPTS_VXLAN]); + else if (tb_opt[LWTUNNEL_IP_OPTS_ERSPAN]) + lwtunnel_print_erspan_opts(tb_opt[LWTUNNEL_IP_OPTS_ERSPAN]); } static void print_encap_ip(FILE *fp, struct rtattr *encap) @@ -976,6 +1010,82 @@ static int lwtunnel_parse_vxlan_opts(char *str, size_t len, struct rtattr *rta) return 0; } +static int lwtunnel_parse_erspan_opts(char *str, size_t len, struct rtattr *rta) +{ + struct rtattr *nest; + char *token; + int i, err; + + nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_ERSPAN | NLA_F_NESTED); + i = 1; + token = strsep(&str, ":"); + while (token) { + switch (i) { + case LWTUNNEL_IP_OPT_ERSPAN_VER: + { + __u8 opt_type; + + if (!strlen(token)) + break; + err = get_u8(&opt_type, token, 0); + if (err) + return err; + + rta_addattr8(rta, len, i, opt_type); + break; + } + case LWTUNNEL_IP_OPT_ERSPAN_INDEX: + { + __be32 opt_class; + + if (!strlen(token)) + break; + err = get_be32(&opt_class, token, 0); + if (err) + return err; + + rta_addattr32(rta, len, i, opt_class); + break; + } + case LWTUNNEL_IP_OPT_ERSPAN_DIR: + { + __u8 opt_type; + + if (!strlen(token)) + break; + err = get_u8(&opt_type, token, 0); + if (err) + return err; + + rta_addattr8(rta, len, i, opt_type); + break; + } + case LWTUNNEL_IP_OPT_ERSPAN_HWID: + { + __u8 opt_type; + + if (!strlen(token)) + break; + err = get_u8(&opt_type, token, 0); + if (err) + return err; + + rta_addattr8(rta, len, i, opt_type); + break; + } + default: + fprintf(stderr, "Unknown \"geneve_opts\" type\n"); + return -1; + } + + token = strsep(&str, ":"); + i++; + } + + rta_nest_end(rta, nest); + return 0; +} + static int parse_encap_ip(struct rtattr *rta, size_t len, int *argcp, char ***argvp) { @@ -1062,6 +1172,21 @@ static int parse_encap_ip(struct rtattr *rta, size_t len, invarg("\"vxlan_opts\" value is invalid\n", *argv); rta_nest_end(rta, nest); + } else if (strcmp(*argv, "erspan_opts") == 0) { + struct rtattr *nest; + + if (opts_ok++) + duparg2("opts", *argv); + + NEXT_ARG(); + + nest = rta_nest(rta, len, + LWTUNNEL_IP_OPTS | NLA_F_NESTED); + ret = lwtunnel_parse_erspan_opts(*argv, len, rta); + if (ret) + invarg("\"erspan_opts\" value is invalid\n", + *argv); + rta_nest_end(rta, nest); } else if (strcmp(*argv, "key") == 0) { if (key_ok++) duparg2("key", *argv); @@ -1261,6 +1386,21 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len, invarg("\"vxlan_opts\" value is invalid\n", *argv); rta_nest_end(rta, nest); + } else if (strcmp(*argv, "erspan_opts") == 0) { + struct rtattr *nest; + + if (opts_ok++) + duparg2("opts", *argv); + + NEXT_ARG(); + + nest = rta_nest(rta, len, + LWTUNNEL_IP_OPTS | NLA_F_NESTED); + ret = lwtunnel_parse_erspan_opts(*argv, len, rta); + if (ret) + invarg("\"erspan_opts\" value is invalid\n", + *argv); + rta_nest_end(rta, nest); } else if (strcmp(*argv, "key") == 0) { if (key_ok++) duparg2("key", *argv); From patchwork Mon Apr 27 10:27:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xin Long X-Patchwork-Id: 220509 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1B84FC5519B for ; Mon, 27 Apr 2020 10:28:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E2508206CD for ; Mon, 27 Apr 2020 10:28:43 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lmsY+bCk" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727022AbgD0K2n (ORCPT ); Mon, 27 Apr 2020 06:28:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52990 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1727015AbgD0K2l (ORCPT ); Mon, 27 Apr 2020 06:28:41 -0400 Received: from mail-pg1-x530.google.com (mail-pg1-x530.google.com [IPv6:2607:f8b0:4864:20::530]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1B746C0610D5 for ; Mon, 27 Apr 2020 03:28:41 -0700 (PDT) Received: by mail-pg1-x530.google.com with SMTP id h69so8499940pgc.8 for ; Mon, 27 Apr 2020 03:28:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=BgXpzzOB5OtOu3Qgjg87TBST69OVi4QcEqcXnUkKtnA=; b=lmsY+bCkhwAYLl/CsIog7v7t75V3mog/aTPoCXVTF0Uhtf8Z+vStrWYSOnJMgJV7bj l0rLu7r743aHs4KkNJrkosqmv1D0DQhpr8YueWmTAe6kemdUeYUhYJc887hle2iZCJEA /sSrQYMHs8ja4l5q5WObf72maNRB8ggmdldHaZk3KmiA8SIi2dDFLLsY5Sa1cnceYCtp 5ERmWc0a5zt6l3L/r409JIUhpbneyXrwdVyDl9bDhJh7cSu1tyZxUXRNtS+z84AkRMFN 2F/UOsxBJDxv3tr+jQ8VrpsruvqAmP3XkPRixars7OO5FP2BQl6vnrCdysC7wFc/jC9X jsyQ== 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:in-reply-to:references; bh=BgXpzzOB5OtOu3Qgjg87TBST69OVi4QcEqcXnUkKtnA=; b=KSOL2whHY8UcZpxnj5sNeHqgbUg+ir517jXkLwKUXo3s9ip9+Dnlo8dUnpqwcY0dcu +9eI+K6lmCFiFsEjxG7LUGvZ5us9Yosk0UzYxMKf3c3ZsKQdaViDi7ihej0QIaGJXEaj PpCID3bmOPvYrCdqcMofVFvKtwudmZuRQs/FK0b6sVrlG1k4b+IqtXLeMYo6vtodtqyu sHK2iVT3vUyTNDLK6lJAdD9VjFslfjoYqR++RlCjogCtHEOE8S7R9twTl70DCLPntHqw 4I9yRHZU/anuNhEgB5hHtcErQZAs0Iv5AGFCDpubCFtbQ3SnXOLcte14KRB7NMrpsaNJ PKYw== X-Gm-Message-State: AGi0PuZYtRTqXQoVLEu3ObQTmEWrCG4/APDWEAfZmGhU6WsOOJPf0kpr 06Fp1qaHAiZvD/b7J4VrUC1PB4ir X-Google-Smtp-Source: APiQypJkPJBJDR0jaaEcr4VpQkW2PaskeAO7v64/i+f9Yn4j5QxPpYLEKakuGkjK6h8uUSZJ4KbHlg== X-Received: by 2002:aa7:979b:: with SMTP id o27mr10775154pfp.192.1587983319978; Mon, 27 Apr 2020 03:28:39 -0700 (PDT) Received: from localhost ([209.132.188.80]) by smtp.gmail.com with ESMTPSA id o12sm10188054pgl.87.2020.04.27.03.28.38 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 27 Apr 2020 03:28:39 -0700 (PDT) From: Xin Long To: network dev , stephen@networkplumber.org Cc: David Ahern , Jakub Kicinski Subject: [PATCHv4 iproute2-next 5/7] tc: m_tunnel_key: add options support for erpsan Date: Mon, 27 Apr 2020 18:27:49 +0800 Message-Id: <0225abc4c546f25972bd31fcab52511c54f96ba1.1587983178.git.lucien.xin@gmail.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <916fda0179fa618e310a672314dc6091452b0d97.1587983178.git.lucien.xin@gmail.com> References: <838c55576eabd17db407a95bc6609c05bf5e174b.1587983178.git.lucien.xin@gmail.com> <4ae2ca59ac4262b19212a16ee7474189ae5eca72.1587983178.git.lucien.xin@gmail.com> <916fda0179fa618e310a672314dc6091452b0d97.1587983178.git.lucien.xin@gmail.com> In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch is to add TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN's parse and print to implement erspan options support in m_tunnel_key, like Commit 6217917a3826 ("tc: m_tunnel_key: Add tunnel option support to act_tunnel_key") for geneve options support. Option is expressed as version:index:dir:hwid, dir and hwid will be parsed when version is 2, while index will be parsed when version is 1. erspan doesn't support multiple options. With this patch, users can add and dump erspan options like: # ip link add name erspan1 type erspan external # tc qdisc add dev eth0 ingress # tc filter add dev eth0 protocol ip parent ffff: \ flower indev eth0 \ ip_proto udp \ action tunnel_key \ set src_ip 10.0.99.192 \ dst_ip 10.0.99.193 \ dst_port 6081 \ id 11 \ erspan_opts 1:2:0:0 \ action mirred egress redirect dev erspan1 # tc -s filter show dev eth0 parent ffff: filter protocol ip pref 49151 flower chain 0 handle 0x1 indev eth0 eth_type ipv4 ip_proto udp not_in_hw action order 1: tunnel_key set src_ip 10.0.99.192 dst_ip 10.0.99.193 key_id 11 dst_port 6081 erspan_opts 1:2:0:0 csum pipe index 2 ref 1 bind 1 ... v1->v2: - no change. v2->v3: - no change. v3->v4: - keep the same format between input and output, json and non json. - print version, index, dir and hwid as uint. Signed-off-by: Xin Long --- man/man8/tc-tunnel_key.8 | 12 ++++- tc/m_tunnel_key.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/man/man8/tc-tunnel_key.8 b/man/man8/tc-tunnel_key.8 index c208e2c..ad99724 100644 --- a/man/man8/tc-tunnel_key.8 +++ b/man/man8/tc-tunnel_key.8 @@ -68,8 +68,10 @@ options. .B dst_port , .B geneve_opts -and +, .B vxlan_opts +and +.B erspan_opts are optional. .RS .TP @@ -99,6 +101,14 @@ Vxlan metatdata options. is specified in the form GBP, as a 32bit number. Multiple options is not supported. .TP +.B erspan_opts +Erspan metatdata options. +.B erspan_opts +is specified in the form VERSION:INDEX:DIR:HWID, where VERSION is represented +as a 8bit number, INDEX as an 32bit number, DIR and HWID as a 8bit number. +Multiple options is not supported. Note INDEX is used when VERSION is 1, +and DIR and HWID are used when VERSION is 2. +.TP .B tos Outer header TOS .TP diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c index 11ec55d..2ebf2ed 100644 --- a/tc/m_tunnel_key.c +++ b/tc/m_tunnel_key.c @@ -29,7 +29,7 @@ static void explain(void) "src_ip (mandatory)\n" "dst_ip (mandatory)\n" "dst_port \n" - "geneve_opts | vxlan_opts \n" + "geneve_opts | vxlan_opts | erspan_opts \n" "csum | nocsum (default is \"csum\")\n"); } @@ -97,6 +97,21 @@ static int tunnel_key_parse_be16(char *str, int base, int type, return 0; } +static int tunnel_key_parse_be32(char *str, int base, int type, + struct nlmsghdr *n) +{ + __be32 value; + int ret; + + ret = get_be32(&value, str, base); + if (ret) + return ret; + + addattr32(n, MAX_MSG, type, value); + + return 0; +} + static int tunnel_key_parse_u8(char *str, int base, int type, struct nlmsghdr *n) { @@ -226,6 +241,63 @@ static int tunnel_key_parse_vxlan_opt(char *str, struct nlmsghdr *n) return 0; } +static int tunnel_key_parse_erspan_opt(char *str, struct nlmsghdr *n) +{ + char *token, *saveptr = NULL; + struct rtattr *encap, *nest; + int i, ret; + + encap = addattr_nest(n, MAX_MSG, + TCA_TUNNEL_KEY_ENC_OPTS | NLA_F_NESTED); + nest = addattr_nest(n, MAX_MSG, + TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN | NLA_F_NESTED); + + token = strtok_r(str, ":", &saveptr); + i = 1; + while (token) { + switch (i) { + case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER: + { + ret = tunnel_key_parse_u8(token, 0, i, n); + if (ret) + return ret; + break; + } + case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX: + { + ret = tunnel_key_parse_be32(token, 0, i, n); + if (ret) + return ret; + break; + } + case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR: + { + ret = tunnel_key_parse_u8(token, 0, i, n); + if (ret) + return ret; + break; + } + case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID: + { + ret = tunnel_key_parse_u8(token, 0, i, n); + if (ret) + return ret; + break; + } + default: + return -1; + } + + token = strtok_r(NULL, ":", &saveptr); + i++; + } + + addattr_nest_end(n, nest); + addattr_nest_end(n, encap); + + return 0; +} + static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n) { int ret; @@ -330,6 +402,13 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p, fprintf(stderr, "Illegal \"vxlan_opts\"\n"); return -1; } + } else if (matches(*argv, "erspan_opts") == 0) { + NEXT_ARG(); + + if (tunnel_key_parse_erspan_opt(*argv, n)) { + fprintf(stderr, "Illegal \"erspan_opts\"\n"); + return -1; + } } else if (matches(*argv, "tos") == 0) { NEXT_ARG(); ret = tunnel_key_parse_tos_ttl(*argv, @@ -517,6 +596,39 @@ static void tunnel_key_print_vxlan_options(struct rtattr *attr) close_json_array(PRINT_JSON, name); } +static void tunnel_key_print_erspan_options(struct rtattr *attr) +{ + struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1]; + struct rtattr *i = RTA_DATA(attr); + int rem = RTA_PAYLOAD(attr); + char *name = "erspan_opts"; + __u8 ver, hwid, dir; + __u32 idx; + + parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, i, rem); + ver = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]); + if (ver == 1) { + idx = rta_getattr_be32(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]); + dir = 0; + hwid = 0; + } else { + idx = 0; + dir = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR]); + hwid = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]); + } + + print_nl(); + print_string(PRINT_FP, name, "\t%s ", name); + open_json_array(PRINT_JSON, name); + open_json_object(NULL); + print_uint(PRINT_ANY, "ver", "%u", ver); + print_uint(PRINT_ANY, "index", ":%u", idx); + print_uint(PRINT_ANY, "dir", ":%u", dir); + print_uint(PRINT_ANY, "hwid", ":%u", hwid); + close_json_object(); + close_json_array(PRINT_JSON, name); +} + static void tunnel_key_print_key_opt(struct rtattr *attr) { struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1]; @@ -531,6 +643,9 @@ static void tunnel_key_print_key_opt(struct rtattr *attr) else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]) tunnel_key_print_vxlan_options( tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]); + else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN]) + tunnel_key_print_erspan_options( + tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN]); } static void tunnel_key_print_tos_ttl(FILE *f, char *name, From patchwork Mon Apr 27 10:27:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xin Long X-Patchwork-Id: 220508 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EEE7AC55199 for ; Mon, 27 Apr 2020 10:29:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C14E320663 for ; Mon, 27 Apr 2020 10:29:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ffAXOJbb" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727074AbgD0K3A (ORCPT ); Mon, 27 Apr 2020 06:29:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53036 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726728AbgD0K26 (ORCPT ); Mon, 27 Apr 2020 06:28:58 -0400 Received: from mail-pf1-x433.google.com (mail-pf1-x433.google.com [IPv6:2607:f8b0:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 46734C0610D5 for ; Mon, 27 Apr 2020 03:28:58 -0700 (PDT) Received: by mail-pf1-x433.google.com with SMTP id f7so8799621pfa.9 for ; Mon, 27 Apr 2020 03:28:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=kr4Urnjn1CjxS2jwfu9ArvRGJcwZXvIYuLiiU5AR44Q=; b=ffAXOJbb7QHGuDoG5B201YCKPkFfROneB8lfF1rRTq/lVUd5sj0srY52tRYFLql/DK fp3TuKw8Aaz8xBm5zffdC+1sHS6eTGr++vMau7Uv/46kxw0Vp/v9uxjnlgienU6laFEO NlXuuSzndivFacF2mgSQgw2ntaSWffXJQKUto8VJfRYlmPDknQf61Q3tYFS+4/iiE+jY jHc5Ak9DQTf/TCxRVqJNB8sfi5z3CUI7vjJ96fLuOBbFVkQ56J3G4pQAzhGgabI4gkVU D71esZ9rmxGHjYI/Lp6tyf1OIHQILKd6b5uG93sZIp5Cj5JAxRyx3MGGKEVv7sFfRXIG ny8w== 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:in-reply-to:references; bh=kr4Urnjn1CjxS2jwfu9ArvRGJcwZXvIYuLiiU5AR44Q=; b=C9mc9ISqRciw4q1ICGTCYz+rOVhJKQ6l81bCO06wpBkIns/KAzQNDFYKQVcT9NXuMq 7V/H1a1hdO22eCxPs448yvOo1lF8bot2eQSMlbE2j/7KZfZJkKvYhLImfM+RJe1T8RL+ NmQVdpo3if4U0Rss0MeIBJaga7B1AAizqEDMyxBoPiMO2IPxqvFaKVhw0p9lkLrd8d3t iUb4OoonJPqdH+2g7NlR79NYtTsnWItdd6VGAYLsrIC7YPeRvlBHNO23mw1//l+FyK+F 7Tza95ZtdaqhsFgrgINllqEcc6K0LKwOwJIsn0ZaM274lEx1xNxUOZbnaFrNWHaUaYgK ox6A== X-Gm-Message-State: AGi0PuaZg4EKEZT/C+nYkvNJkRrXXc4CHqX4dnXCNnlMxhDzCfSxdqVK gpIA9sF2Q/b+ughOpZctSS+aCHDV X-Google-Smtp-Source: APiQypLwxp3J4NSKqjoYFVY/2cahmPTFof7jXnTAIwo6K7BAHHci5D4QDwPBy/Wqz0UhCmVOKGn9SQ== X-Received: by 2002:a62:2783:: with SMTP id n125mr24704959pfn.133.1587983337351; Mon, 27 Apr 2020 03:28:57 -0700 (PDT) Received: from localhost ([209.132.188.80]) by smtp.gmail.com with ESMTPSA id w2sm12115218pfc.194.2020.04.27.03.28.56 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 27 Apr 2020 03:28:56 -0700 (PDT) From: Xin Long To: network dev , stephen@networkplumber.org Cc: David Ahern , Jakub Kicinski Subject: [PATCHv4 iproute2-next 7/7] tc: f_flower: add options support for erspan Date: Mon, 27 Apr 2020 18:27:51 +0800 Message-Id: <7a76753305795e59f8214d5082f51bb687f52665.1587983178.git.lucien.xin@gmail.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: References: <838c55576eabd17db407a95bc6609c05bf5e174b.1587983178.git.lucien.xin@gmail.com> <4ae2ca59ac4262b19212a16ee7474189ae5eca72.1587983178.git.lucien.xin@gmail.com> <916fda0179fa618e310a672314dc6091452b0d97.1587983178.git.lucien.xin@gmail.com> <0225abc4c546f25972bd31fcab52511c54f96ba1.1587983178.git.lucien.xin@gmail.com> In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch is to add TCA_FLOWER_KEY_ENC_OPTS_ERSPAN's parse and print to implement erspan options support in m_tunnel_key, like Commit 56155d4df86d ("tc: f_flower: add geneve option match support to flower") for geneve options support. Option is expressed as version:index:dir:hwid, dir and hwid will be parsed when version is 2, while index will be parsed when version is 1. erspan doesn't support multiple options. With this patch, users can add and dump erspan options like: # ip link add name erspan1 type erspan external # tc qdisc add dev erspan1 ingress # tc filter add dev erspan1 protocol ip parent ffff: \ flower \ enc_src_ip 10.0.99.192 \ enc_dst_ip 10.0.99.193 \ enc_key_id 11 \ erspan_opts 1:2:0:0/1:255:0:0 \ ip_proto udp \ action mirred egress redirect dev eth1 # tc -s filter show dev erspan1 parent ffff: filter protocol ip pref 49152 flower chain 0 handle 0x1 eth_type ipv4 ip_proto udp enc_dst_ip 10.0.99.193 enc_src_ip 10.0.99.192 enc_key_id 11 erspan_opts 1:2:0:0/1:255:0:0 not_in_hw action order 1: mirred (Egress Redirect to device eth1) stolen index 1 ref 1 bind 1 Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 v1->v2: - no change. v2->v3: - no change. v3->v4: - keep the same format between input and output, json and non json. - print version, index, dir and hwid as uint. Signed-off-by: Xin Long --- man/man8/tc-flower.8 | 13 ++++ tc/f_flower.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+) diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8 index 3c7246b..b3dfcf6 100644 --- a/man/man8/tc-flower.8 +++ b/man/man8/tc-flower.8 @@ -85,6 +85,8 @@ flower \- flow based traffic control filter .B geneve_opts | .B vxlan_opts +| +.B erspan_opts } .IR OPTIONS " | " .BR ip_flags @@ -332,6 +334,8 @@ Match the connection zone, and can be masked. .BI geneve_opts " OPTIONS" .TQ .BI vxlan_opts " OPTIONS" +.TQ +.BI erspan_opts " OPTIONS" Match on IP tunnel metadata. Key id .I NUMBER is a 32 bit tunnel key id (e.g. VNI for VXLAN tunnel). @@ -358,6 +362,15 @@ doesn't support multiple options, and it consists of a key followed by a slash and corresponding mask. If the mask is missing, \fBtc\fR assumes a full-length match. The option can be described in the form GBP/GBP_MASK, where GBP is represented as a 32bit number. +erspan_opts +.I OPTIONS +doesn't support multiple options, and it consists of a key followed by a slash +and corresponding mask. If the mask is missing, \fBtc\fR assumes a full-length +match. The option can be described in the form +VERSION:INDEX:DIR:HWID/VERSION:INDEX_MASK:DIR_MASK:HWID_MASK, where VERSION is +represented as a 8bit number, INDEX as an 32bit number, DIR and HWID as a 8bit +number. Multiple options is not supported. Note INDEX/INDEX_MASK is used when +VERSION is 1, and DIR/DIR_MASK and HWID/HWID_MASK are used when VERSION is 2. .TP .BI ip_flags " IP_FLAGS" .I IP_FLAGS diff --git a/tc/f_flower.c b/tc/f_flower.c index 502d2ad..fc13691 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -82,6 +82,7 @@ static void explain(void) " enc_ttl MASKED-IP_TTL |\n" " geneve_opts MASKED-OPTIONS |\n" " vxlan_opts MASKED-OPTIONS |\n" + " erspan_opts MASKED-OPTIONS |\n" " ip_flags IP-FLAGS | \n" " enc_dst_port [ port_number ] |\n" " ct_state MASKED_CT_STATE |\n" @@ -937,6 +938,84 @@ static int flower_parse_vxlan_opt(char *str, struct nlmsghdr *n) return 0; } +static int flower_parse_erspan_opt(char *str, struct nlmsghdr *n) +{ + struct rtattr *nest; + char *token; + int i, err; + + nest = addattr_nest(n, MAX_MSG, + TCA_FLOWER_KEY_ENC_OPTS_ERSPAN | NLA_F_NESTED); + + i = 1; + token = strsep(&str, ":"); + while (token) { + switch (i) { + case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER: + { + __u8 opt_type; + + if (!strlen(token)) + break; + err = get_u8(&opt_type, token, 0); + if (err) + return err; + + addattr8(n, MAX_MSG, i, opt_type); + break; + } + case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX: + { + __be32 opt_index; + + if (!strlen(token)) + break; + err = get_be32(&opt_index, token, 0); + if (err) + return err; + + addattr32(n, MAX_MSG, i, opt_index); + break; + } + case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR: + { + __u8 opt_type; + + if (!strlen(token)) + break; + err = get_u8(&opt_type, token, 0); + if (err) + return err; + + addattr8(n, MAX_MSG, i, opt_type); + break; + } + case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID: + { + __u8 opt_type; + + if (!strlen(token)) + break; + err = get_u8(&opt_type, token, 0); + if (err) + return err; + + addattr8(n, MAX_MSG, i, opt_type); + break; + } + default: + fprintf(stderr, "Unknown \"geneve_opts\" type\n"); + return -1; + } + + token = strsep(&str, ":"); + i++; + } + addattr_nest_end(n, nest); + + return 0; +} + static int flower_parse_geneve_opts(char *str, struct nlmsghdr *n) { char *token; @@ -1077,6 +1156,49 @@ static int flower_parse_enc_opts_vxlan(char *str, struct nlmsghdr *n) return 0; } +static int flower_parse_enc_opts_erspan(char *str, struct nlmsghdr *n) +{ + char key[XATTR_SIZE_MAX], mask[XATTR_SIZE_MAX]; + struct rtattr *nest; + char *slash; + int err; + + + slash = strchr(str, '/'); + if (slash) { + *slash++ = '\0'; + if (strlen(slash) > XATTR_SIZE_MAX) + return -1; + strcpy(mask, slash); + } else { + int index; + + slash = strchr(str, ':'); + index = (int)(slash - str); + memcpy(mask, str, index); + strcpy(mask + index, ":0xffffffff:0xff:0xff"); + } + + if (strlen(str) > XATTR_SIZE_MAX) + return -1; + strcpy(key, str); + + nest = addattr_nest(n, MAX_MSG, TCA_FLOWER_KEY_ENC_OPTS | NLA_F_NESTED); + err = flower_parse_erspan_opt(key, n); + if (err) + return err; + addattr_nest_end(n, nest); + + nest = addattr_nest(n, MAX_MSG, + TCA_FLOWER_KEY_ENC_OPTS_MASK | NLA_F_NESTED); + err = flower_parse_erspan_opt(mask, n); + if (err) + return err; + addattr_nest_end(n, nest); + + return 0; +} + static int flower_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) { @@ -1571,6 +1693,13 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, fprintf(stderr, "Illegal \"vxlan_opts\"\n"); return -1; } + } else if (matches(*argv, "erspan_opts") == 0) { + NEXT_ARG(); + ret = flower_parse_enc_opts_erspan(*argv, n); + if (ret < 0) { + fprintf(stderr, "Illegal \"erspan_opts\"\n"); + return -1; + } } else if (matches(*argv, "action") == 0) { NEXT_ARG(); ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n); @@ -2024,6 +2153,38 @@ static void flower_print_vxlan_opts(const char *name, struct rtattr *attr, sprintf(strbuf, "%u", gbp); } +static void flower_print_erspan_opts(const char *name, struct rtattr *attr, + char *strbuf) +{ + struct rtattr *tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1]; + __u8 ver, hwid, dir; + __u32 idx; + + parse_rtattr(tb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX, RTA_DATA(attr), + RTA_PAYLOAD(attr)); + ver = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]); + if (ver == 1) { + idx = rta_getattr_be32(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]); + hwid = 0; + dir = 0; + } else { + idx = 0; + hwid = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]); + dir = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]); + } + + open_json_array(PRINT_JSON, name); + open_json_object(NULL); + print_uint(PRINT_JSON, "ver", NULL, ver); + print_uint(PRINT_JSON, "index", NULL, idx); + print_uint(PRINT_JSON, "dir", NULL, dir); + print_uint(PRINT_JSON, "hwid", NULL, hwid); + close_json_object(); + close_json_array(PRINT_JSON, name); + + sprintf(strbuf, "%u:%u:%u:%u", ver, idx, dir, hwid); +} + static void flower_print_enc_parts(const char *name, const char *namefrm, struct rtattr *attr, char *key, char *mask) { @@ -2090,6 +2251,16 @@ static void flower_print_enc_opts(const char *name, struct rtattr *attr, flower_print_enc_parts(name, " vxlan_opts %s", attr, key, msk); + } else if (key_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN]) { + flower_print_erspan_opts("erspan_opt_key", + key_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN], key); + + if (msk_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN]) + flower_print_erspan_opts("erspan_opt_mask", + msk_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN], msk); + + flower_print_enc_parts(name, " erspan_opts %s", attr, key, + msk); } free(msk);