From patchwork Sun Nov 8 21:14:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889871 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 E6BFCC5517A for ; Sun, 8 Nov 2020 21:15:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B1D9C206DC for ; Sun, 8 Nov 2020 21:15:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="pygXoumB" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728593AbgKHVOl (ORCPT ); Sun, 8 Nov 2020 16:14:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43810 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727910AbgKHVOl (ORCPT ); Sun, 8 Nov 2020 16:14:41 -0500 Received: from mout-p-102.mailbox.org (mout-p-102.mailbox.org [IPv6:2001:67c:2050::465:102]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C542DC0613CF for ; Sun, 8 Nov 2020 13:14:40 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [80.241.60.241]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4CTn264bXQzQlWp; Sun, 8 Nov 2020 22:14:38 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870076; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=I7QPqgldd5bRpbnFKP5pPO4Fyu4g+hlUXzRjdqHYhf4=; b=pygXoumB08pKzIPD2+zEbGOr7noUf4PJ+E4dDVkvPTiAhxSWveNp71LXw0rzIXynSWmFt3 v0gU0bZ4Ias54z4tYFOKjn5pmhxUHclwsSZ11D7AEh1BQ3BUMvFh3Yb4gDf7Fw3YaMO6nM 0nwGYFrLLXc+KqvnkxPYTnR7vvvcqweR/EnrPvz2r2YsiNGCAv/f8LCOTWI42UaWU+iVO/ wh4VngNGYi+ScxdRtbEOok8tJgkq4tYxHyczQaGqJP20FvNeV+Siutla/Idm0ybsPudyT6 TzDdLBHpZoZHwJPwZ+o4V+jEG6EXxx5y/2FHfNSriH09ieJI0H60Mssz3s9sWQ== Received: from smtp2.mailbox.org ([80.241.60.241]) by hefe.heinlein-support.de (hefe.heinlein-support.de [91.198.250.172]) (amavisd-new, port 10030) with ESMTP id JuCpHiGpfvFU; Sun, 8 Nov 2020 22:14:35 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 01/11] Unify batch processing across tools Date: Sun, 8 Nov 2020 22:14:06 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 1.14 / 15.00 / 15.00 X-Rspamd-Queue-Id: 90CF416FE X-Rspamd-UID: b8957f Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The code for handling batches is largely the same across iproute2 tools. Extract a helper to handle the batch, and adjust the tools to dispatch to this helper. Sandwitch the invocation between prologue / epilogue code specific for each tool. Signed-off-by: Petr Machata --- bridge/bridge.c | 38 +++++++------------------------------- devlink/devlink.c | 41 +++++++---------------------------------- include/utils.h | 3 +++ ip/ip.c | 46 ++++++++++------------------------------------ lib/utils.c | 40 ++++++++++++++++++++++++++++++++++++++++ rdma/rdma.c | 38 +++++++------------------------------- tc/tc.c | 38 +++++++------------------------------- 7 files changed, 81 insertions(+), 163 deletions(-) diff --git a/bridge/bridge.c b/bridge/bridge.c index 453d689732bd..8f691cfdd466 100644 --- a/bridge/bridge.c +++ b/bridge/bridge.c @@ -77,20 +77,14 @@ static int do_cmd(const char *argv0, int argc, char **argv) return -1; } -static int batch(const char *name) +static int br_batch_cmd(int argc, char *argv[], void *data) { - char *line = NULL; - size_t len = 0; - int ret = EXIT_SUCCESS; + return do_cmd(argv[0], argc, argv); +} - if (name && strcmp(name, "-") != 0) { - if (freopen(name, "r", stdin) == NULL) { - fprintf(stderr, - "Cannot open file \"%s\" for reading: %s\n", - name, strerror(errno)); - return EXIT_FAILURE; - } - } +static int batch(const char *name) +{ + int ret; if (rtnl_open(&rth, 0) < 0) { fprintf(stderr, "Cannot open rtnetlink\n"); @@ -99,25 +93,7 @@ static int batch(const char *name) rtnl_set_strict_dump(&rth); - cmdlineno = 0; - while (getcmdline(&line, &len, stdin) != -1) { - char *largv[100]; - int largc; - - largc = makeargs(line, largv, 100); - if (largc == 0) - continue; /* blank line */ - - if (do_cmd(largv[0], largc, largv)) { - fprintf(stderr, "Command failed %s:%d\n", - name, cmdlineno); - ret = EXIT_FAILURE; - if (!force) - break; - } - } - if (line) - free(line); + ret = do_batch(name, force, br_batch_cmd, NULL); rtnl_close(&rth); return ret; diff --git a/devlink/devlink.c b/devlink/devlink.c index 1ff865bc5c22..5bb00b3a5b8c 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -7912,43 +7912,16 @@ static void dl_free(struct dl *dl) free(dl); } -static int dl_batch(struct dl *dl, const char *name, bool force) +static int dl_batch_cmd(int argc, char *argv[], void *data) { - char *line = NULL; - size_t len = 0; - int ret = EXIT_SUCCESS; - - if (name && strcmp(name, "-") != 0) { - if (freopen(name, "r", stdin) == NULL) { - fprintf(stderr, - "Cannot open file \"%s\" for reading: %s\n", - name, strerror(errno)); - return EXIT_FAILURE; - } - } - - cmdlineno = 0; - while (getcmdline(&line, &len, stdin) != -1) { - char *largv[100]; - int largc; - - largc = makeargs(line, largv, 100); - if (!largc) - continue; /* blank line */ - - if (dl_cmd(dl, largc, largv)) { - fprintf(stderr, "Command failed %s:%d\n", - name, cmdlineno); - ret = EXIT_FAILURE; - if (!force) - break; - } - } + struct dl *dl = data; - if (line) - free(line); + return dl_cmd(dl, argc, argv); +} - return ret; +static int dl_batch(struct dl *dl, const char *name, bool force) +{ + return do_batch(name, force, dl_batch_cmd, dl); } int main(int argc, char **argv) diff --git a/include/utils.h b/include/utils.h index 7041c4612e46..085b17b1f6e3 100644 --- a/include/utils.h +++ b/include/utils.h @@ -322,4 +322,7 @@ int get_time64(__s64 *time, const char *str); char *sprint_time(__u32 time, char *buf); char *sprint_time64(__s64 time, char *buf); +int do_batch(const char *name, bool force, + int (*cmd)(int argc, char *argv[], void *user), void *user); + #endif /* __UTILS_H__ */ diff --git a/ip/ip.c b/ip/ip.c index ac4450235370..5e31957f2420 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -121,56 +121,30 @@ static int do_cmd(const char *argv0, int argc, char **argv) return EXIT_FAILURE; } -static int batch(const char *name) +static int ip_batch_cmd(int argc, char *argv[], void *data) { - char *line = NULL; - size_t len = 0; - int ret = EXIT_SUCCESS; - int orig_family = preferred_family; + const int *orig_family = data; - batch_mode = 1; + preferred_family = *orig_family; + return do_cmd(argv[0], argc, argv); +} - if (name && strcmp(name, "-") != 0) { - if (freopen(name, "r", stdin) == NULL) { - fprintf(stderr, - "Cannot open file \"%s\" for reading: %s\n", - name, strerror(errno)); - return EXIT_FAILURE; - } - } +static int batch(const char *name) +{ + int orig_family = preferred_family; + int ret; if (rtnl_open(&rth, 0) < 0) { fprintf(stderr, "Cannot open rtnetlink\n"); return EXIT_FAILURE; } - cmdlineno = 0; - while (getcmdline(&line, &len, stdin) != -1) { - char *largv[100]; - int largc; - - preferred_family = orig_family; - - largc = makeargs(line, largv, 100); - if (largc == 0) - continue; /* blank line */ - - if (do_cmd(largv[0], largc, largv)) { - fprintf(stderr, "Command failed %s:%d\n", - name, cmdlineno); - ret = EXIT_FAILURE; - if (!force) - break; - } - } - if (line) - free(line); + ret = do_batch(name, force, ip_batch_cmd, &orig_family); rtnl_close(&rth); return ret; } - int main(int argc, char **argv) { char *basename; diff --git a/lib/utils.c b/lib/utils.c index c98021d6ecad..9815e328c9e0 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1695,3 +1695,43 @@ char *sprint_time64(__s64 time, char *buf) print_time64(buf, SPRINT_BSIZE-1, time); return buf; } + +int do_batch(const char *name, bool force, + int (*cmd)(int argc, char *argv[], void *data), void *data) +{ + char *line = NULL; + size_t len = 0; + int ret = EXIT_SUCCESS; + + if (name && strcmp(name, "-") != 0) { + if (freopen(name, "r", stdin) == NULL) { + fprintf(stderr, + "Cannot open file \"%s\" for reading: %s\n", + name, strerror(errno)); + return EXIT_FAILURE; + } + } + + cmdlineno = 0; + while (getcmdline(&line, &len, stdin) != -1) { + char *largv[100]; + int largc; + + largc = makeargs(line, largv, 100); + if (!largc) + continue; /* blank line */ + + if (cmd(largc, largv, data)) { + fprintf(stderr, "Command failed %s:%d\n", + name, cmdlineno); + ret = EXIT_FAILURE; + if (!force) + break; + } + } + + if (line) + free(line); + + return ret; +} diff --git a/rdma/rdma.c b/rdma/rdma.c index 9ea2d17ffe9e..8dc2d3e344be 100644 --- a/rdma/rdma.c +++ b/rdma/rdma.c @@ -41,40 +41,16 @@ static int rd_cmd(struct rd *rd, int argc, char **argv) return rd_exec_cmd(rd, cmds, "object"); } -static int rd_batch(struct rd *rd, const char *name, bool force) +static int rd_batch_cmd(int argc, char *argv[], void *data) { - char *line = NULL; - size_t len = 0; - int ret = 0; - - if (name && strcmp(name, "-") != 0) { - if (!freopen(name, "r", stdin)) { - pr_err("Cannot open file \"%s\" for reading: %s\n", - name, strerror(errno)); - return errno; - } - } + struct rd *rd = data; - cmdlineno = 0; - while (getcmdline(&line, &len, stdin) != -1) { - char *largv[512]; - int largc; - - largc = makeargs(line, largv, ARRAY_SIZE(largv)); - if (!largc) - continue; /* blank line */ - - ret = rd_cmd(rd, largc, largv); - if (ret) { - pr_err("Command failed %s:%d\n", name, cmdlineno); - if (!force) - break; - } - } - - free(line); + return rd_cmd(rd, argc, argv); +} - return ret; +static int rd_batch(struct rd *rd, const char *name, bool force) +{ + return do_batch(name, force, rd_batch_cmd, rd); } static int rd_init(struct rd *rd, char *filename) diff --git a/tc/tc.c b/tc/tc.c index 5d57054b45fb..01fe58d06202 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -231,22 +231,16 @@ static int do_cmd(int argc, char **argv) return -1; } +static int tc_batch_cmd(int argc, char *argv[], void *data) +{ + return do_cmd(argc, argv); +} + static int batch(const char *name) { - char *line = NULL; - size_t len = 0; - int ret = 0; + int ret; batch_mode = 1; - if (name && strcmp(name, "-") != 0) { - if (freopen(name, "r", stdin) == NULL) { - fprintf(stderr, - "Cannot open file \"%s\" for reading: %s\n", - name, strerror(errno)); - return -1; - } - } - tc_core_init(); if (rtnl_open(&rth, 0) < 0) { @@ -254,26 +248,8 @@ static int batch(const char *name) return -1; } - cmdlineno = 0; - while (getcmdline(&line, &len, stdin) != -1) { - char *largv[100]; - int largc; - - largc = makeargs(line, largv, 100); - if (largc == 0) - continue; /* blank line */ - - if (do_cmd(largc, largv)) { - fprintf(stderr, "Command failed %s:%d\n", - name, cmdlineno); - ret = 1; - if (!force) - break; - } - fflush(stdout); - } + ret = do_batch(name, force, tc_batch_cmd, NULL); - free(line); rtnl_close(&rth); return ret; } From patchwork Sun Nov 8 21:14:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889863 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 22233C55ABD for ; Sun, 8 Nov 2020 21:14:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5B1DA206E3 for ; Sun, 8 Nov 2020 21:14:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="THiGxhZW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728885AbgKHVOl (ORCPT ); Sun, 8 Nov 2020 16:14:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43812 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727929AbgKHVOl (ORCPT ); Sun, 8 Nov 2020 16:14:41 -0500 Received: from mout-p-201.mailbox.org (mout-p-201.mailbox.org [IPv6:2001:67c:2050::465:201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4B1B4C0613D3 for ; Sun, 8 Nov 2020 13:14:41 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [80.241.60.241]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-201.mailbox.org (Postfix) with ESMTPS id 4CTn276FwLzQlL2; Sun, 8 Nov 2020 22:14:39 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870078; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=reJsB5/K3a/oTlTqeGRODg6xD0dkFikmeb1Md1DF2xI=; b=THiGxhZW+GzTbExGes1cTlygCJYV8qLoHDYjE/lXMlDRJR/VsvRyEnkIeSCJqx0O3P4d+e pT4zsIO0UG4mdhTJYQ7eAjaiJT+yeBS/fwPpu6cker4LiV7GXjakjyz/RqDcnWrCPIpdjx jUOoDpLqOHFpZSJNcMwpWmn/dxd2aI5pHt4IrqQN9Sto6MPqXi1AfvnZ1ygvhwwu35rDrA ysjsmIaH80FZpa+H1Mj4fpLw0Xnz4ckvM1a/Td/QM/6/kF0oMkbmT9IL+Zj9pffNjvd8sN 735Cy0Gyt24W2aM8rgLThjSKb4OkoainANG6cHN01r9TlL+59lXP0LMXyDSGfA== Received: from smtp2.mailbox.org ([80.241.60.241]) by hefe.heinlein-support.de (hefe.heinlein-support.de [91.198.250.172]) (amavisd-new, port 10030) with ESMTP id vTk8kza3um1H; Sun, 8 Nov 2020 22:14:36 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 02/11] lib: Add parse_one_of(), parse_on_off() Date: Sun, 8 Nov 2020 22:14:07 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 1.14 / 15.00 / 15.00 X-Rspamd-Queue-Id: C3148170E X-Rspamd-UID: c18a31 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Take from the macsec code parse_one_of() and adapt so that it passes the primary result as the main return value, and error result through a pointer. That is the simplest way to make the code reusable across data types without introducing extra magic. Also from macsec take the specialization of parse_one_of() for parsing specifically the strings "off" and "on". Convert the macsec code to the new helpers. Signed-off-by: Petr Machata --- Notes: v3: - Have parse_on_off() return a boolean. [David Ahern] include/utils.h | 4 ++++ ip/ipmacsec.c | 52 +++++++++++-------------------------------------- lib/utils.c | 28 ++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/include/utils.h b/include/utils.h index 085b17b1f6e3..d7653273af5f 100644 --- a/include/utils.h +++ b/include/utils.h @@ -325,4 +325,8 @@ char *sprint_time64(__s64 time, char *buf); int do_batch(const char *name, bool force, int (*cmd)(int argc, char *argv[], void *user), void *user); +int parse_one_of(const char *msg, const char *realval, const char * const *list, + size_t len, int *p_err); +bool parse_on_off(const char *msg, const char *realval, int *p_err); + #endif /* __UTILS_H__ */ diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index 18289ecd6d9e..bf48e8b5d0b2 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -23,8 +23,6 @@ #include "ll_map.h" #include "libgenl.h" -static const char * const values_on_off[] = { "off", "on" }; - static const char * const validate_str[] = { [MACSEC_VALIDATE_DISABLED] = "disabled", [MACSEC_VALIDATE_CHECK] = "check", @@ -108,25 +106,6 @@ static void ipmacsec_usage(void) exit(-1); } -static int one_of(const char *msg, const char *realval, const char * const *list, - size_t len, int *index) -{ - int i; - - for (i = 0; i < len; i++) { - if (matches(realval, list[i]) == 0) { - *index = i; - return 0; - } - } - - fprintf(stderr, "Error: argument of \"%s\" must be one of ", msg); - for (i = 0; i < len; i++) - fprintf(stderr, "\"%s\", ", list[i]); - fprintf(stderr, "not \"%s\"\n", realval); - return -1; -} - static int get_an(__u8 *val, const char *arg) { int ret = get_u8(val, arg, 0); @@ -559,8 +538,7 @@ static int do_offload(enum cmd c, int argc, char **argv) if (argc == 0) ipmacsec_usage(); - ret = one_of("offload", *argv, offload_str, ARRAY_SIZE(offload_str), - (int *)&offload); + offload = parse_one_of("offload", *argv, offload_str, ARRAY_SIZE(offload_str), &ret); if (ret) ipmacsec_usage(); @@ -1334,8 +1312,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); int i; - ret = one_of("encrypt", *argv, values_on_off, - ARRAY_SIZE(values_on_off), &i); + i = parse_on_off("encrypt", *argv, &ret); if (ret != 0) return ret; addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_ENCRYPT, i); @@ -1343,8 +1320,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); int i; - ret = one_of("send_sci", *argv, values_on_off, - ARRAY_SIZE(values_on_off), &i); + i = parse_on_off("send_sci", *argv, &ret); if (ret != 0) return ret; send_sci = i; @@ -1354,8 +1330,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); int i; - ret = one_of("end_station", *argv, values_on_off, - ARRAY_SIZE(values_on_off), &i); + i = parse_on_off("end_station", *argv, &ret); if (ret != 0) return ret; es = i; @@ -1364,8 +1339,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); int i; - ret = one_of("scb", *argv, values_on_off, - ARRAY_SIZE(values_on_off), &i); + i = parse_on_off("scb", *argv, &ret); if (ret != 0) return ret; scb = i; @@ -1374,8 +1348,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); int i; - ret = one_of("protect", *argv, values_on_off, - ARRAY_SIZE(values_on_off), &i); + i = parse_on_off("protect", *argv, &ret); if (ret != 0) return ret; addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_PROTECT, i); @@ -1383,8 +1356,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); int i; - ret = one_of("replay", *argv, values_on_off, - ARRAY_SIZE(values_on_off), &i); + i = parse_on_off("replay", *argv, &ret); if (ret != 0) return ret; replay_protect = !!i; @@ -1395,9 +1367,8 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, invarg("expected replay window size", *argv); } else if (strcmp(*argv, "validate") == 0) { NEXT_ARG(); - ret = one_of("validate", *argv, - validate_str, ARRAY_SIZE(validate_str), - (int *)&validate); + validate = parse_one_of("validate", *argv, validate_str, + ARRAY_SIZE(validate_str), &ret); if (ret != 0) return ret; addattr8(n, MACSEC_BUFLEN, @@ -1411,9 +1382,8 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, invarg("expected an { 0..3 }", *argv); } else if (strcmp(*argv, "offload") == 0) { NEXT_ARG(); - ret = one_of("offload", *argv, - offload_str, ARRAY_SIZE(offload_str), - (int *)&offload); + offload = parse_one_of("offload", *argv, offload_str, + ARRAY_SIZE(offload_str), &ret); if (ret != 0) return ret; addattr8(n, MACSEC_BUFLEN, diff --git a/lib/utils.c b/lib/utils.c index 9815e328c9e0..eab0839a13c7 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1735,3 +1735,31 @@ int do_batch(const char *name, bool force, return ret; } + +int parse_one_of(const char *msg, const char *realval, const char * const *list, + size_t len, int *p_err) +{ + int i; + + for (i = 0; i < len; i++) { + if (list[i] && matches(realval, list[i]) == 0) { + *p_err = 0; + return i; + } + } + + fprintf(stderr, "Error: argument of \"%s\" must be one of ", msg); + for (i = 0; i < len; i++) + if (list[i]) + fprintf(stderr, "\"%s\", ", list[i]); + fprintf(stderr, "not \"%s\"\n", realval); + *p_err = -EINVAL; + return 0; +} + +bool parse_on_off(const char *msg, const char *realval, int *p_err) +{ + static const char * const values_on_off[] = { "off", "on" }; + + return parse_one_of(msg, realval, values_on_off, ARRAY_SIZE(values_on_off), p_err); +} From patchwork Sun Nov 8 21:14:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889853 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 008E2C388F9 for ; Sun, 8 Nov 2020 21:14:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BA907221FB for ; Sun, 8 Nov 2020 21:14:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="QzL0XDwO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728901AbgKHVOn (ORCPT ); Sun, 8 Nov 2020 16:14:43 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43818 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727929AbgKHVOm (ORCPT ); Sun, 8 Nov 2020 16:14:42 -0500 Received: from mout-p-201.mailbox.org (mout-p-201.mailbox.org [IPv6:2001:67c:2050::465:201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7ABD0C0613CF for ; Sun, 8 Nov 2020 13:14:42 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [80.241.60.241]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-201.mailbox.org (Postfix) with ESMTPS id 4CTn290jt9zQlWB; Sun, 8 Nov 2020 22:14:41 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870079; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=UQPqtFPni3LKjqH2SE5mPQslRREm+4iBNCJmGmvPc5E=; b=QzL0XDwOAJb8VjDK3KYxUhNaUOgCBnoNHkKzqCGaTQDosQNPw0lvSraFsmYTnLYVHS540p uj23S3Y5E2A/E9259rP4o1b7+kJDdt3bxgA86La5TKxBUrClYOhznrbrTOFPN285hHiQZj xQgezp3HtPvD9NgqZZpBI0l9B18t3K9yPWEKRW2FFgA+fKFFXPi+RZdaJ3ztwPrOS+TPAA kmgkUQkmJHf99mWQZzl0sjJlzbhWxd9Sn+GhLo6fzlBZtNxlov+HL5k89bshdxEmBnlIDl hbEt3/4k2M+CK0l02KvRECYTiwWXbm0SZyiBKqk+IhHXlwegxS8Jg2VvANHYIA== Received: from smtp2.mailbox.org ([80.241.60.241]) by spamfilter03.heinlein-hosting.de (spamfilter03.heinlein-hosting.de [80.241.56.117]) (amavisd-new, port 10030) with ESMTP id rYrXYJ-J5hLz; Sun, 8 Nov 2020 22:14:37 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 03/11] lib: json_print: Add print_on_off() Date: Sun, 8 Nov 2020 22:14:08 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 1.15 / 15.00 / 15.00 X-Rspamd-Queue-Id: 0A6DC171D X-Rspamd-UID: 79b4f3 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The value of a number of booleans is shown as "on" and "off" in the plain output, and as an actual boolean in JSON mode. Add a function that does that. RDMA tool already uses a function named print_on_off(). This function always shows "on" and "off", even in JSON mode. Since there are probably very few if any consumers of this interface at this point, migrate it to the new central print_on_off() as well. Signed-off-by: Petr Machata Reviewed-by: Leon Romanovsky Reviewed-by: Leon Romanovsky --- Notes: v3: - Rename to print_on_off(). [David Ahern] - Move over to json_print.c and make it a variant of print_bool(). Convert RDMA tool over to print_on_off(). [Leon Romanovsky] include/json_print.h | 1 + lib/json_print.c | 34 +++++++++++++++++++++++++++------- rdma/dev.c | 2 +- rdma/rdma.h | 1 - rdma/res-cq.c | 2 +- rdma/utils.c | 5 ----- 6 files changed, 30 insertions(+), 15 deletions(-) diff --git a/include/json_print.h b/include/json_print.h index 50e71de443ab..096a999a4de4 100644 --- a/include/json_print.h +++ b/include/json_print.h @@ -65,6 +65,7 @@ void print_nl(void); _PRINT_FUNC(int, int) _PRINT_FUNC(s64, int64_t) _PRINT_FUNC(bool, bool) +_PRINT_FUNC(on_off, bool) _PRINT_FUNC(null, const char*) _PRINT_FUNC(string, const char*) _PRINT_FUNC(uint, unsigned int) diff --git a/lib/json_print.c b/lib/json_print.c index fe0705bf6965..62eeb1f1fb31 100644 --- a/lib/json_print.c +++ b/lib/json_print.c @@ -191,11 +191,12 @@ int print_color_string(enum output_type type, * a value to it, you will need to use "is_json_context()" to have different * branch for json and regular output. grep -r "print_bool" for example */ -int print_color_bool(enum output_type type, - enum color_attr color, - const char *key, - const char *fmt, - bool value) +static int __print_color_bool(enum output_type type, + enum color_attr color, + const char *key, + const char *fmt, + bool value, + const char *str) { int ret = 0; @@ -205,13 +206,32 @@ int print_color_bool(enum output_type type, else jsonw_bool(_jw, value); } else if (_IS_FP_CONTEXT(type)) { - ret = color_fprintf(stdout, color, fmt, - value ? "true" : "false"); + ret = color_fprintf(stdout, color, fmt, str); } return ret; } +int print_color_bool(enum output_type type, + enum color_attr color, + const char *key, + const char *fmt, + bool value) +{ + return __print_color_bool(type, color, key, fmt, value, + value ? "true" : "false"); +} + +int print_color_on_off(enum output_type type, + enum color_attr color, + const char *key, + const char *fmt, + bool value) +{ + return __print_color_bool(type, color, key, fmt, value, + value ? "on" : "off"); +} + /* * In JSON context uses hardcode %#x format: 42 -> 0x2a */ diff --git a/rdma/dev.c b/rdma/dev.c index a11081b82170..c684dde4a56f 100644 --- a/rdma/dev.c +++ b/rdma/dev.c @@ -159,7 +159,7 @@ static void dev_print_dim_setting(struct rd *rd, struct nlattr **tb) if (dim_setting > 1) return; - print_on_off(rd, "adaptive-moderation", dim_setting); + print_on_off(PRINT_ANY, "adaptive-moderation", "adaptive-moderation %s ", dim_setting); } diff --git a/rdma/rdma.h b/rdma/rdma.h index a6c6bdea5a80..8638b2a39aeb 100644 --- a/rdma/rdma.h +++ b/rdma/rdma.h @@ -138,7 +138,6 @@ void print_driver_table(struct rd *rd, struct nlattr *tb); void print_raw_data(struct rd *rd, struct nlattr **nla_line); void newline(struct rd *rd); void newline_indent(struct rd *rd); -void print_on_off(struct rd *rd, const char *key_str, bool on); void print_raw_data(struct rd *rd, struct nlattr **nla_line); #define MAX_LINE_LENGTH 80 diff --git a/rdma/res-cq.c b/rdma/res-cq.c index 313f929a29b5..9e7c4f512b72 100644 --- a/rdma/res-cq.c +++ b/rdma/res-cq.c @@ -36,7 +36,7 @@ static void print_cq_dim_setting(struct rd *rd, struct nlattr *attr) if (dim_setting > 1) return; - print_on_off(rd, "adaptive-moderation", dim_setting); + print_on_off(PRINT_ANY, "adaptive-moderation", "adaptive-moderation %s ", dim_setting); } static int res_cq_line_raw(struct rd *rd, const char *name, int idx, diff --git a/rdma/utils.c b/rdma/utils.c index 4d3de4fadba2..2a201aa4aeb7 100644 --- a/rdma/utils.c +++ b/rdma/utils.c @@ -781,11 +781,6 @@ static int print_driver_string(struct rd *rd, const char *key_str, return 0; } -void print_on_off(struct rd *rd, const char *key_str, bool on) -{ - print_driver_string(rd, key_str, (on) ? "on":"off"); -} - static int print_driver_s32(struct rd *rd, const char *key_str, int32_t val, enum rdma_nldev_print_type print_type) { From patchwork Sun Nov 8 21:14:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889855 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 2485DC55ABD for ; Sun, 8 Nov 2020 21:14:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DF68C22202 for ; Sun, 8 Nov 2020 21:14:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="ibcu69pk" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728917AbgKHVOp (ORCPT ); Sun, 8 Nov 2020 16:14:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43824 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727929AbgKHVOo (ORCPT ); Sun, 8 Nov 2020 16:14:44 -0500 Received: from mout-p-101.mailbox.org (mout-p-101.mailbox.org [IPv6:2001:67c:2050::465:101]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 279E5C0613CF for ; Sun, 8 Nov 2020 13:14:44 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:105:465:1:2:0]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-101.mailbox.org (Postfix) with ESMTPS id 4CTn2B04cYzQlF0; Sun, 8 Nov 2020 22:14:42 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870080; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Yk9vsKqU6CoSoOgqvkxP3qcJS25ZON71cxiU9k5XwyU=; b=ibcu69pk7fsALb3LEJAvTmFBljOimc3naUQ3lkVQR5ZEJg99/1QZJzLcBElF2FJsJKL5Fx Covcgi/w4o3Ey8HQ5aSipbR7e3fTr1B4juJuCilThX5gWPv24CR/w1jedtVNkcrSdeWKPr P3kBChE7qrJF9N2sWMJUSxOl54C6AXoZzMNTSXI0fqEligblmqbq9L3rhDusrz86NNFJUo 55e/kc1LDcn0YQYumNt55dVLxph/rFDG+yEmPq143Cp91RANR9335LFPDAI1enpSfrU4Rs uqzpatU4t5gAm2fw7Yq5lKUXWoDgIbMkzu6He3gJ5Q7XQvGcNJ2e9SyGPLpTqg== Received: from smtp2.mailbox.org ([80.241.60.241]) by gerste.heinlein-support.de (gerste.heinlein-support.de [91.198.250.173]) (amavisd-new, port 10030) with ESMTP id 8l1Wp9KxOioE; Sun, 8 Nov 2020 22:14:38 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 04/11] lib: Extract from devlink/mnlg a helper, mnlu_socket_open() Date: Sun, 8 Nov 2020 22:14:09 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 1.15 / 15.00 / 15.00 X-Rspamd-Queue-Id: E7D84170E X-Rspamd-UID: 00b840 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This little dance of mnl_socket_open(), option setting, and bind, is the same regardless of tool. Extract into a new module that should hold helpers for working with libmnl, mnl_util.c. Signed-off-by: Petr Machata --- Notes: v2: - Add SPDX-License-Identifier devlink/Makefile | 2 +- devlink/mnlg.c | 19 ++++--------------- include/mnl_utils.h | 7 +++++++ lib/Makefile | 2 +- lib/mnl_utils.c | 30 ++++++++++++++++++++++++++++++ 5 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 include/mnl_utils.h create mode 100644 lib/mnl_utils.c diff --git a/devlink/Makefile b/devlink/Makefile index 7da7d1fa18d5..d540feb3c012 100644 --- a/devlink/Makefile +++ b/devlink/Makefile @@ -12,7 +12,7 @@ endif all: $(TARGETS) $(LIBS) -devlink: $(DEVLINKOBJ) +devlink: $(DEVLINKOBJ) $(LIBNETLINK) $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ install: all diff --git a/devlink/mnlg.c b/devlink/mnlg.c index c7d25e8713a1..9817bbad5e7d 100644 --- a/devlink/mnlg.c +++ b/devlink/mnlg.c @@ -19,6 +19,7 @@ #include #include "libnetlink.h" +#include "mnl_utils.h" #include "utils.h" #include "mnlg.h" @@ -263,7 +264,6 @@ struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version) { struct mnlg_socket *nlg; struct nlmsghdr *nlh; - int one = 1; int err; nlg = malloc(sizeof(*nlg)); @@ -274,19 +274,9 @@ struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version) if (!nlg->buf) goto err_buf_alloc; - nlg->nl = mnl_socket_open(NETLINK_GENERIC); + nlg->nl = mnlu_socket_open(NETLINK_GENERIC); if (!nlg->nl) - goto err_mnl_socket_open; - - /* Older kernels may no support capped/extended ACK reporting */ - mnl_socket_setsockopt(nlg->nl, NETLINK_CAP_ACK, &one, sizeof(one)); - mnl_socket_setsockopt(nlg->nl, NETLINK_EXT_ACK, &one, sizeof(one)); - - err = mnl_socket_bind(nlg->nl, 0, MNL_SOCKET_AUTOPID); - if (err < 0) - goto err_mnl_socket_bind; - - nlg->portid = mnl_socket_get_portid(nlg->nl); + goto err_socket_open; nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY, NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1); @@ -305,9 +295,8 @@ struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version) err_mnlg_socket_recv_run: err_mnlg_socket_send: -err_mnl_socket_bind: mnl_socket_close(nlg->nl); -err_mnl_socket_open: +err_socket_open: free(nlg->buf); err_buf_alloc: free(nlg); diff --git a/include/mnl_utils.h b/include/mnl_utils.h new file mode 100644 index 000000000000..10a064afdfe8 --- /dev/null +++ b/include/mnl_utils.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __MNL_UTILS_H__ +#define __MNL_UTILS_H__ 1 + +struct mnl_socket *mnlu_socket_open(int bus); + +#endif /* __MNL_UTILS_H__ */ diff --git a/lib/Makefile b/lib/Makefile index 7cba1857b7fa..13f4ee15373b 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -7,7 +7,7 @@ UTILOBJ = utils.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \ inet_proto.o namespace.o json_writer.o json_print.o \ names.o color.o bpf.o exec.o fs.o cg_map.o -NLOBJ=libgenl.o libnetlink.o +NLOBJ=libgenl.o libnetlink.o mnl_utils.o all: libnetlink.a libutil.a diff --git a/lib/mnl_utils.c b/lib/mnl_utils.c new file mode 100644 index 000000000000..2426912aa511 --- /dev/null +++ b/lib/mnl_utils.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * mnl_utils.c Helpers for working with libmnl. + */ + +#include + +#include "mnl_utils.h" + +struct mnl_socket *mnlu_socket_open(int bus) +{ + struct mnl_socket *nl; + int one = 1; + + nl = mnl_socket_open(bus); + if (nl == NULL) + return NULL; + + mnl_socket_setsockopt(nl, NETLINK_CAP_ACK, &one, sizeof(one)); + mnl_socket_setsockopt(nl, NETLINK_EXT_ACK, &one, sizeof(one)); + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) + goto err_bind; + + return nl; + +err_bind: + mnl_socket_close(nl); + return NULL; +} From patchwork Sun Nov 8 21:14:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889851 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 CB030C56201 for ; Sun, 8 Nov 2020 21:14:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 92F50206DC for ; Sun, 8 Nov 2020 21:14:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="Ag7FZDiY" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728927AbgKHVOq (ORCPT ); Sun, 8 Nov 2020 16:14:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43826 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728904AbgKHVOo (ORCPT ); Sun, 8 Nov 2020 16:14:44 -0500 Received: from mout-p-103.mailbox.org (mout-p-103.mailbox.org [IPv6:2001:67c:2050::465:103]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 647E8C0613D2 for ; Sun, 8 Nov 2020 13:14:44 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:105:465:1:2:0]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-103.mailbox.org (Postfix) with ESMTPS id 4CTn2B6QlMzQjy2; Sun, 8 Nov 2020 22:14:42 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870080; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HQljg/nd8YNyMVPl1dJEdxLDy2LuGivGEot1LFvtSGU=; b=Ag7FZDiY+qSdOrFKl6pjlw2kqwP8XvJ2sTUdOec4gIAwp0vqUO9F+4l6NNNa0zkBUf8QDK hqsetInpni0D+ch+6tFrzbY9SXCZ2vZjnLJLyYBbfzIdfKrWSB+Uu6Mq4JOIbn/OaIcYUT /ptD2ri/sX+ZXZcEyCWQsrGqhZIDSmF7QGnrowO/eE5woI+tnQ92d33zRLm4XWg6pQhrsh 2QMHdOvyj9T/ObthQeJf9Gf8E+S8v2C/YMgtsLcPIY+ZvKVTNbBOmW8LhlPI30IJ5H/5UH G2dFbRqP6uWB3/pEYSZIZ5/BX9vQSbobKIzzEpPIZjDUvYGK5HrJ3s8W8HWwZQ== Received: from smtp2.mailbox.org ([80.241.60.241]) by spamfilter03.heinlein-hosting.de (spamfilter03.heinlein-hosting.de [80.241.56.117]) (amavisd-new, port 10030) with ESMTP id FoEozGr9Tw-b; Sun, 8 Nov 2020 22:14:39 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 05/11] lib: Extract from devlink/mnlg a helper, mnlu_msg_prepare() Date: Sun, 8 Nov 2020 22:14:10 +0100 Message-Id: <52cc2abecaa94ff64b981309d1d3c7ad2d66cf44.1604869679.git.me@pmachata.org> In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: ** X-Rspamd-Score: 1.57 / 15.00 / 15.00 X-Rspamd-Queue-Id: B85261720 X-Rspamd-UID: 21d68d Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Allocation of a new netlink message with the two usual headers is reusable with other netlink netlink message types. Extract it into a helper, mnlu_msg_prepare(). Take the second header as an argument, instead of passing in parameters to initialize it, and copy it in. Signed-off-by: Petr Machata --- devlink/mnlg.c | 18 ++++++------------ include/mnl_utils.h | 2 ++ lib/mnl_utils.c | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/devlink/mnlg.c b/devlink/mnlg.c index 9817bbad5e7d..4995b7af06a3 100644 --- a/devlink/mnlg.c +++ b/devlink/mnlg.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -36,19 +35,14 @@ static struct nlmsghdr *__mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd, uint16_t flags, uint32_t id, uint8_t version) { + struct genlmsghdr genl = { + .cmd = cmd, + .version = version, + }; struct nlmsghdr *nlh; - struct genlmsghdr *genl; - - nlh = mnl_nlmsg_put_header(nlg->buf); - nlh->nlmsg_type = id; - nlh->nlmsg_flags = flags; - nlg->seq = time(NULL); - nlh->nlmsg_seq = nlg->seq; - - genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr)); - genl->cmd = cmd; - genl->version = version; + nlh = mnlu_msg_prepare(nlg->buf, id, flags, &genl, sizeof(genl)); + nlg->seq = nlh->nlmsg_seq; return nlh; } diff --git a/include/mnl_utils.h b/include/mnl_utils.h index 10a064afdfe8..86ce30f49a94 100644 --- a/include/mnl_utils.h +++ b/include/mnl_utils.h @@ -3,5 +3,7 @@ #define __MNL_UTILS_H__ 1 struct mnl_socket *mnlu_socket_open(int bus); +struct nlmsghdr *mnlu_msg_prepare(void *buf, uint32_t nlmsg_type, uint16_t flags, + void *extra_header, size_t extra_header_size); #endif /* __MNL_UTILS_H__ */ diff --git a/lib/mnl_utils.c b/lib/mnl_utils.c index 2426912aa511..61e8060ecbca 100644 --- a/lib/mnl_utils.c +++ b/lib/mnl_utils.c @@ -3,6 +3,8 @@ * mnl_utils.c Helpers for working with libmnl. */ +#include +#include #include #include "mnl_utils.h" @@ -28,3 +30,20 @@ err_bind: mnl_socket_close(nl); return NULL; } + +struct nlmsghdr *mnlu_msg_prepare(void *buf, uint32_t nlmsg_type, uint16_t flags, + void *extra_header, size_t extra_header_size) +{ + struct nlmsghdr *nlh; + void *eh; + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = nlmsg_type; + nlh->nlmsg_flags = flags; + nlh->nlmsg_seq = time(NULL); + + eh = mnl_nlmsg_put_extra_header(nlh, extra_header_size); + memcpy(eh, extra_header, extra_header_size); + + return nlh; +} From patchwork Sun Nov 8 21:14:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889857 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 45990C61DD8 for ; Sun, 8 Nov 2020 21:14:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 04D92206DC for ; Sun, 8 Nov 2020 21:14:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="bKkJkt17" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728937AbgKHVOr (ORCPT ); Sun, 8 Nov 2020 16:14:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43830 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728914AbgKHVOp (ORCPT ); Sun, 8 Nov 2020 16:14:45 -0500 Received: from mout-p-102.mailbox.org (mout-p-102.mailbox.org [IPv6:2001:67c:2050::465:102]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 218CDC0613CF for ; Sun, 8 Nov 2020 13:14:45 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [80.241.60.241]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4CTn2C5Y8XzQjbV; Sun, 8 Nov 2020 22:14:43 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870081; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6aWX8XASs/6sWnV9mLSOL43vd4+o+FUZfJHei4wY9Vg=; b=bKkJkt17/8IlbIFJaT1KPIbbH3Y7CvImsGNxCwx5D3pgjS/RsW1oItLmoXMINdHsofCeX3 TWI6PdIAo/YFvITDkJG3khQCRWqqW4gjP4yZ6OcJoNuvFQkafK8rWQIt2nOhYExFPpWRvM w16TF3GRwsFdzXS14niTvMQLk7SQkSr/oAD6WKfCigNrZoicLnAAuDuV8A+MP29vcuwjmo JmNaa4d6CiWj4IQ9XzHql3Eo+DRmIDfip68zAMKmeDzruKmKifDW8PMNnuRE9m1EL6mOLY ttQvQu6GCUJ1R+zsPiDC5aTneNy7AshhLNdegS2+F1EznY/G6qZDfxEU7jnQvA== Received: from smtp2.mailbox.org ([80.241.60.241]) by spamfilter05.heinlein-hosting.de (spamfilter05.heinlein-hosting.de [80.241.56.123]) (amavisd-new, port 10030) with ESMTP id szGjoLrR5r3D; Sun, 8 Nov 2020 22:14:40 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 06/11] lib: Extract from devlink/mnlg a helper, mnlu_socket_recv_run() Date: Sun, 8 Nov 2020 22:14:11 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: ** X-Rspamd-Score: 1.56 / 15.00 / 15.00 X-Rspamd-Queue-Id: A62A216FE X-Rspamd-UID: 68749e Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Receiving a message in libmnl is a somewhat involved operation. Devlink's mnlg library has an implementation that is going to be handy for other tools as well. Extract it into a new helper. Signed-off-by: Petr Machata --- devlink/mnlg.c | 56 ++--------------------------------------- include/mnl_utils.h | 2 ++ lib/mnl_utils.c | 61 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 54 deletions(-) diff --git a/devlink/mnlg.c b/devlink/mnlg.c index 4995b7af06a3..21b10c5a5669 100644 --- a/devlink/mnlg.c +++ b/devlink/mnlg.c @@ -28,7 +28,6 @@ struct mnlg_socket { uint32_t id; uint8_t version; unsigned int seq; - unsigned int portid; }; static struct nlmsghdr *__mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd, @@ -57,61 +56,10 @@ int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh) return mnl_socket_sendto(nlg->nl, nlh, nlh->nlmsg_len); } -static int mnlg_cb_noop(const struct nlmsghdr *nlh, void *data) -{ - return MNL_CB_OK; -} - -static int mnlg_cb_error(const struct nlmsghdr *nlh, void *data) -{ - const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); - - /* Netlink subsystems returns the errno value with different signess */ - if (err->error < 0) - errno = -err->error; - else - errno = err->error; - - if (nl_dump_ext_ack(nlh, NULL)) - return MNL_CB_ERROR; - - return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR; -} - -static int mnlg_cb_stop(const struct nlmsghdr *nlh, void *data) -{ - int len = *(int *)NLMSG_DATA(nlh); - - if (len < 0) { - errno = -len; - nl_dump_ext_ack_done(nlh, len); - return MNL_CB_ERROR; - } - return MNL_CB_STOP; -} - -static mnl_cb_t mnlg_cb_array[NLMSG_MIN_TYPE] = { - [NLMSG_NOOP] = mnlg_cb_noop, - [NLMSG_ERROR] = mnlg_cb_error, - [NLMSG_DONE] = mnlg_cb_stop, - [NLMSG_OVERRUN] = mnlg_cb_noop, -}; - int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data) { - int err; - - do { - err = mnl_socket_recvfrom(nlg->nl, nlg->buf, - MNL_SOCKET_BUFFER_SIZE); - if (err <= 0) - break; - err = mnl_cb_run2(nlg->buf, err, nlg->seq, nlg->portid, - data_cb, data, mnlg_cb_array, - ARRAY_SIZE(mnlg_cb_array)); - } while (err > 0); - - return err; + return mnlu_socket_recv_run(nlg->nl, nlg->seq, nlg->buf, MNL_SOCKET_BUFFER_SIZE, + data_cb, data); } struct group_info { diff --git a/include/mnl_utils.h b/include/mnl_utils.h index 86ce30f49a94..fa826ef1f8fe 100644 --- a/include/mnl_utils.h +++ b/include/mnl_utils.h @@ -5,5 +5,7 @@ struct mnl_socket *mnlu_socket_open(int bus); struct nlmsghdr *mnlu_msg_prepare(void *buf, uint32_t nlmsg_type, uint16_t flags, void *extra_header, size_t extra_header_size); +int mnlu_socket_recv_run(struct mnl_socket *nl, unsigned int seq, void *buf, size_t buf_size, + mnl_cb_t cb, void *data); #endif /* __MNL_UTILS_H__ */ diff --git a/lib/mnl_utils.c b/lib/mnl_utils.c index 61e8060ecbca..46384ff81cf1 100644 --- a/lib/mnl_utils.c +++ b/lib/mnl_utils.c @@ -3,11 +3,14 @@ * mnl_utils.c Helpers for working with libmnl. */ +#include #include #include #include +#include "libnetlink.h" #include "mnl_utils.h" +#include "utils.h" struct mnl_socket *mnlu_socket_open(int bus) { @@ -47,3 +50,61 @@ struct nlmsghdr *mnlu_msg_prepare(void *buf, uint32_t nlmsg_type, uint16_t flags return nlh; } + +static int mnlu_cb_noop(const struct nlmsghdr *nlh, void *data) +{ + return MNL_CB_OK; +} + +static int mnlu_cb_error(const struct nlmsghdr *nlh, void *data) +{ + const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); + + /* Netlink subsystems returns the errno value with different signess */ + if (err->error < 0) + errno = -err->error; + else + errno = err->error; + + if (nl_dump_ext_ack(nlh, NULL)) + return MNL_CB_ERROR; + + return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR; +} + +static int mnlu_cb_stop(const struct nlmsghdr *nlh, void *data) +{ + int len = *(int *)NLMSG_DATA(nlh); + + if (len < 0) { + errno = -len; + nl_dump_ext_ack_done(nlh, len); + return MNL_CB_ERROR; + } + return MNL_CB_STOP; +} + +static mnl_cb_t mnlu_cb_array[NLMSG_MIN_TYPE] = { + [NLMSG_NOOP] = mnlu_cb_noop, + [NLMSG_ERROR] = mnlu_cb_error, + [NLMSG_DONE] = mnlu_cb_stop, + [NLMSG_OVERRUN] = mnlu_cb_noop, +}; + +int mnlu_socket_recv_run(struct mnl_socket *nl, unsigned int seq, void *buf, size_t buf_size, + mnl_cb_t cb, void *data) +{ + unsigned int portid = mnl_socket_get_portid(nl); + int err; + + do { + err = mnl_socket_recvfrom(nl, buf, buf_size); + if (err <= 0) + break; + err = mnl_cb_run2(buf, err, seq, portid, + cb, data, mnlu_cb_array, + ARRAY_SIZE(mnlu_cb_array)); + } while (err > 0); + + return err; +} From patchwork Sun Nov 8 21:14:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889859 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 73336C56202 for ; Sun, 8 Nov 2020 21:14:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2106E206DC for ; Sun, 8 Nov 2020 21:14:50 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="aMOP/tp4" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728942AbgKHVOt (ORCPT ); Sun, 8 Nov 2020 16:14:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728924AbgKHVOq (ORCPT ); Sun, 8 Nov 2020 16:14:46 -0500 Received: from mout-p-103.mailbox.org (mout-p-103.mailbox.org [IPv6:2001:67c:2050::465:103]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1B7D4C0613CF for ; Sun, 8 Nov 2020 13:14:46 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [80.241.60.241]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-103.mailbox.org (Postfix) with ESMTPS id 4CTn2D5CYrzQl8l; Sun, 8 Nov 2020 22:14:44 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870082; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CejmdtCpUP4hF0QdUazjGj0eVhhM9Cy+N5Lrnfd7Z4Y=; b=aMOP/tp4s2rQ8iRYVadexFLDZLCAkY33k3m86e/PXkRCdlDSUJeEErWdmBxexkPt7c3ovL aUPIg5R4SGNPz1sEafffaTZoB8TRP+qBNE/NDEQUwR57pGcXk4hnJSoTDgVFx3KJ6aTwtO jIZSvqysXqYjVFsitCksnOUAiceSzAyDvQtwZWUjJUyv6XIbxy/CGkpZGXqj7LpLxnbVJm h0bmwer1W7ftJgwB6+MMwuM7pLeGrSvDjAXqxxR+mPR5+7GFe1JCXetWkvBM6s9QPVigy0 TvdYv//lIlFPNwH9BpcHsV6jIQbfJG3vMlUBuUl5HAFw6jgqzbHZlqgdePCF8w== Received: from smtp2.mailbox.org ([80.241.60.241]) by hefe.heinlein-support.de (hefe.heinlein-support.de [91.198.250.172]) (amavisd-new, port 10030) with ESMTP id E5iW6E3iSyaV; Sun, 8 Nov 2020 22:14:41 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 07/11] lib: Extract from iplink_vlan a helper to parse key:value arrays Date: Sun, 8 Nov 2020 22:14:12 +0100 Message-Id: <03990f6240a8bcf19c620a77f7264923cae066e2.1604869679.git.me@pmachata.org> In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: ** X-Rspamd-Score: 1.56 / 15.00 / 15.00 X-Rspamd-Queue-Id: B13E5170E X-Rspamd-UID: 37b716 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org VLAN netdevices have two similar attributes: ingress-qos-map and egress-qos-map. These attributes can be configured with a series of 802.1-priority-to-skb-priority (and vice versa) mappings. A reusable helper along those lines will be handy for configuration of various priority-to-tc, tc-to-algorithm, and other arrays in DCB. Therefore extract the logic to a function parse_mapping(), move to utils.c, and dispatch to utils.c from iplink_vlan.c. That necessitates extraction of a VLAN-specific parse_qos_mapping(). Do that, and propagate addattr_l() return value up, unlike the original. Signed-off-by: Petr Machata --- Notes: v2: - In parse_qos_mapping(), propagate return value from addattr_l() [Roman Mashak] include/utils.h | 4 ++++ ip/iplink_vlan.c | 36 +++++++++++++++--------------------- lib/utils.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/include/utils.h b/include/utils.h index d7653273af5f..2d1a587cb1ef 100644 --- a/include/utils.h +++ b/include/utils.h @@ -329,4 +329,8 @@ int parse_one_of(const char *msg, const char *realval, const char * const *list, size_t len, int *p_err); bool parse_on_off(const char *msg, const char *realval, int *p_err); +int parse_mapping(int *argcp, char ***argvp, + int (*mapping_cb)(__u32 key, char *value, void *data), + void *mapping_cb_data); + #endif /* __UTILS_H__ */ diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c index 1e6817f5de3d..dadc349db16c 100644 --- a/ip/iplink_vlan.c +++ b/ip/iplink_vlan.c @@ -49,36 +49,30 @@ static int on_off(const char *msg, const char *arg) return -1; } +static int parse_qos_mapping(__u32 key, char *value, void *data) +{ + struct nlmsghdr *n = data; + struct ifla_vlan_qos_mapping m = { + .from = key, + }; + + if (get_u32(&m.to, value, 0)) + return 1; + + return addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m)); +} + static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n, int attrtype) { - int argc = *argcp; - char **argv = *argvp; - struct ifla_vlan_qos_mapping m; struct rtattr *tail; tail = addattr_nest(n, 1024, attrtype); - while (argc > 0) { - char *colon = strchr(*argv, ':'); - - if (!colon) - break; - *colon = '\0'; - - if (get_u32(&m.from, *argv, 0)) - return 1; - if (get_u32(&m.to, colon + 1, 0)) - return 1; - argc--, argv++; - - addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m)); - } + if (parse_mapping(argcp, argvp, &parse_qos_mapping, n)) + return 1; addattr_nest_end(n, tail); - - *argcp = argc; - *argvp = argv; return 0; } diff --git a/lib/utils.c b/lib/utils.c index eab0839a13c7..1dfaaf564915 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1763,3 +1763,31 @@ bool parse_on_off(const char *msg, const char *realval, int *p_err) return parse_one_of(msg, realval, values_on_off, ARRAY_SIZE(values_on_off), p_err); } + +int parse_mapping(int *argcp, char ***argvp, + int (*mapping_cb)(__u32 key, char *value, void *data), + void *mapping_cb_data) +{ + int argc = *argcp; + char **argv = *argvp; + + while (argc > 0) { + char *colon = strchr(*argv, ':'); + __u32 key; + + if (!colon) + break; + *colon = '\0'; + + if (get_u32(&key, *argv, 0)) + return 1; + if (mapping_cb(key, colon + 1, mapping_cb_data)) + return 1; + + argc--, argv++; + } + + *argcp = argc; + *argvp = argv; + return 0; +} From patchwork Sun Nov 8 21:14:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889849 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 4EEC9C5517A for ; Sun, 8 Nov 2020 21:14:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 024AB206E3 for ; Sun, 8 Nov 2020 21:14:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="MdGUtWZ8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728954AbgKHVOu (ORCPT ); Sun, 8 Nov 2020 16:14:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43842 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728939AbgKHVOs (ORCPT ); Sun, 8 Nov 2020 16:14:48 -0500 Received: from mout-p-202.mailbox.org (mout-p-202.mailbox.org [IPv6:2001:67c:2050::465:202]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DBAA2C0613CF for ; Sun, 8 Nov 2020 13:14:47 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:105:465:1:2:0]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-202.mailbox.org (Postfix) with ESMTPS id 4CTn2F5DrLzQkZy; Sun, 8 Nov 2020 22:14:45 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870083; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CFbtoKg0yNPTPNPiJU6eAQZTm+DpY3s42tO2xXgqpCA=; b=MdGUtWZ8Cgmus7B/ZA9s6dEjnlz9/15/ld4GwgAtsh7rg3z8/OKOGz/+79YRvX/JYshbS/ r/ntmK3KgzCmMja849D7aR59jIHt0CWje60DY9+zuvIQd82IphYQ2vLNbaIU11MP6xK7OL GrEmY1NMaffRjcSEkLfU276oTJeE15/d4/Y1HfEH4IdCmL6/iqUt9ec4FqX6TnmgkZYx9T 6XUFNnDdryrqqvzB/iIJAkttctK4u248U5m2S0CUyHLb2TQFavhCmYn6SrMnNLJ1hMrtoG Nzzni/WcHZ2Y08O/qSGCDMEZUvIux+4D+rR2YcGn2i/AlkF1Mrm/CzVME3e8JQ== Received: from smtp2.mailbox.org ([80.241.60.241]) by gerste.heinlein-support.de (gerste.heinlein-support.de [91.198.250.173]) (amavisd-new, port 10030) with ESMTP id pW_USuaWyQCB; Sun, 8 Nov 2020 22:14:42 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 08/11] lib: parse_mapping: Update argc, argv on error Date: Sun, 8 Nov 2020 22:14:13 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 1.24 / 15.00 / 15.00 X-Rspamd-Queue-Id: B4235171D X-Rspamd-UID: 66e810 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Currently argc and argv are not updated unless parsing of all of the mapping was successful. However in that case, "ip link" will point at the wrong argument when complaining: # ip link add name eth0.100 link eth0 type vlan id 100 egress 1:1 2:foo Error: argument "1" is wrong: invalid egress-qos-map Update argc and argv even in the case of parsing error, so that the right element is indicated. Signed-off-by: Petr Machata --- lib/utils.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/utils.c b/lib/utils.c index 1dfaaf564915..67d64df7e3e6 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1770,6 +1770,7 @@ int parse_mapping(int *argcp, char ***argvp, { int argc = *argcp; char **argv = *argvp; + int ret = 0; while (argc > 0) { char *colon = strchr(*argv, ':'); @@ -1779,15 +1780,19 @@ int parse_mapping(int *argcp, char ***argvp, break; *colon = '\0'; - if (get_u32(&key, *argv, 0)) - return 1; - if (mapping_cb(key, colon + 1, mapping_cb_data)) - return 1; + if (get_u32(&key, *argv, 0)) { + ret = 1; + break; + } + if (mapping_cb(key, colon + 1, mapping_cb_data)) { + ret = 1; + break; + } argc--, argv++; } *argcp = argc; *argvp = argv; - return 0; + return ret; } From patchwork Sun Nov 8 21:14:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889869 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 9E833C388F9 for ; Sun, 8 Nov 2020 21:15:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 60AAC206E3 for ; Sun, 8 Nov 2020 21:15:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="ZKL08ti6" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728988AbgKHVPC (ORCPT ); Sun, 8 Nov 2020 16:15:02 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43848 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728941AbgKHVOs (ORCPT ); Sun, 8 Nov 2020 16:14:48 -0500 Received: from mout-p-201.mailbox.org (mout-p-201.mailbox.org [IPv6:2001:67c:2050::465:201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A49C4C0613D3 for ; Sun, 8 Nov 2020 13:14:48 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:105:465:1:2:0]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-201.mailbox.org (Postfix) with ESMTPS id 4CTn2G5yJLzQky8; Sun, 8 Nov 2020 22:14:46 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870084; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=knKqnF1zJmuRCXbT34BozvnJMAmwYT+16StvsvU/LEQ=; b=ZKL08ti6WsIWrQYRU6wJKY+dxVfkqi0FThBgq4ZOyV77DFKz60qbZmwCEF5+d1ySksuQxT m6Ygzc9dE1sV6Xyo4v/Py+Emd+TDrTz7erRZ97QPJ6bLfpM2GxHHgFcCod0G65nuLBsR7H BRfokLELnL0k8vvGpjAqHRXdv6iQowC4/y09Z39uY/0U8/Iimi4uPNLyDjWVLEsJ/cO2j6 y9TW6SjYQjjrk7irjLQNR8mhx+W/fnWgVG0hm28drGIO2a6NsftNG13oeym0BKlYFPTTky lIVbAo8zlo5073DKQ+eW7TuOtW3FTlwJW2Cw+4dK3S5EwF3eMIC1yUsVG40GZQ== Received: from smtp2.mailbox.org ([80.241.60.241]) by spamfilter03.heinlein-hosting.de (spamfilter03.heinlein-hosting.de [80.241.56.117]) (amavisd-new, port 10030) with ESMTP id IVBjKocHU_Vl; Sun, 8 Nov 2020 22:14:43 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 09/11] lib: parse_mapping: Recognize a keyword "all" Date: Sun, 8 Nov 2020 22:14:14 +0100 Message-Id: <7415644e8a733b7984d576a2d3bc2632b79145d0.1604869679.git.me@pmachata.org> In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: ** X-Rspamd-Score: 1.56 / 15.00 / 15.00 X-Rspamd-Queue-Id: CD024271 X-Rspamd-UID: 1e29e7 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The DCB tool will have to provide an interface to a number of fixed-size arrays. Unlike the egress- and ingress-qos-map, it makes good sense to have an interface to set all members to the same value. For example to set strict priority on all TCs besides select few, or to reset allocated bandwidth to all zeroes, again besides several explicitly-given ones. To support this usage, extend the parse_mapping() with a boolean that determines whether this special use is supported. If "all" is given and recognized, mapping_cb is called with the key of -1. Have iplink_vlan pass false for allow_all. Signed-off-by: Petr Machata --- include/utils.h | 2 +- ip/iplink_vlan.c | 2 +- lib/utils.c | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/utils.h b/include/utils.h index 2d1a587cb1ef..588fceb72442 100644 --- a/include/utils.h +++ b/include/utils.h @@ -329,7 +329,7 @@ int parse_one_of(const char *msg, const char *realval, const char * const *list, size_t len, int *p_err); bool parse_on_off(const char *msg, const char *realval, int *p_err); -int parse_mapping(int *argcp, char ***argvp, +int parse_mapping(int *argcp, char ***argvp, bool allow_all, int (*mapping_cb)(__u32 key, char *value, void *data), void *mapping_cb_data); diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c index dadc349db16c..1426f2afca23 100644 --- a/ip/iplink_vlan.c +++ b/ip/iplink_vlan.c @@ -69,7 +69,7 @@ static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n, tail = addattr_nest(n, 1024, attrtype); - if (parse_mapping(argcp, argvp, &parse_qos_mapping, n)) + if (parse_mapping(argcp, argvp, false, &parse_qos_mapping, n)) return 1; addattr_nest_end(n, tail); diff --git a/lib/utils.c b/lib/utils.c index 67d64df7e3e6..a0ba5181160e 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1764,7 +1764,7 @@ bool parse_on_off(const char *msg, const char *realval, int *p_err) return parse_one_of(msg, realval, values_on_off, ARRAY_SIZE(values_on_off), p_err); } -int parse_mapping(int *argcp, char ***argvp, +int parse_mapping(int *argcp, char ***argvp, bool allow_all, int (*mapping_cb)(__u32 key, char *value, void *data), void *mapping_cb_data) { @@ -1780,7 +1780,9 @@ int parse_mapping(int *argcp, char ***argvp, break; *colon = '\0'; - if (get_u32(&key, *argv, 0)) { + if (allow_all && matches(*argv, "all") == 0) { + key = (__u32) -1; + } else if (get_u32(&key, *argv, 0)) { ret = 1; break; } From patchwork Sun Nov 8 21:14:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889865 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 91E46C388F9 for ; Sun, 8 Nov 2020 21:14:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 54BC4206E3 for ; Sun, 8 Nov 2020 21:14:56 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="rbTEMla4" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728971AbgKHVOz (ORCPT ); Sun, 8 Nov 2020 16:14:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43860 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728802AbgKHVOw (ORCPT ); Sun, 8 Nov 2020 16:14:52 -0500 Received: from mout-p-201.mailbox.org (mout-p-201.mailbox.org [IPv6:2001:67c:2050::465:201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CC72BC0613D2 for ; Sun, 8 Nov 2020 13:14:51 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:105:465:1:2:0]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-201.mailbox.org (Postfix) with ESMTPS id 4CTn2L06pjzQlL2; Sun, 8 Nov 2020 22:14:50 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870088; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=j4NDXFGh7Mhg9YWDeCXO7McZjJ9OAwqodUsuLI8/4tI=; b=rbTEMla48QUtAeO4x+pSAUbiztXmZC86Q9NtunSI7jmToCCvY3qyZUUBA4Z89I6si/Oo1+ o466fS+k+kMz/MrZ8kajYNPdYpZ2KIODDBQiTxfIT34VVCSSAzkncQcxcRk+/SX95ji/uW 1M2UtnFfFJm8lYtzmk1bc1Z+d66Gxvb4TuCyqjajuAKjZL5yM+h2HZMmJWyAjiFtylkKgC nWhrqCVMejidbyW75Bl1IDh2eMH11tFClokivDN7Zoez+TxqrjrFEN2M5HXzbvmlWAwwWY LPcbJgax8a+0eVlaZ4mKc/AUoA0mDZbQs6XUQmrFBZpr7xRi16Q+9N7gNi640g== Received: from smtp2.mailbox.org ([80.241.60.241]) by hefe.heinlein-support.de (hefe.heinlein-support.de [91.198.250.172]) (amavisd-new, port 10030) with ESMTP id BrV0Wd6eJK8p; Sun, 8 Nov 2020 22:14:45 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 10/11] Add skeleton of a new tool, dcb Date: Sun, 8 Nov 2020 22:14:15 +0100 Message-Id: <0f83e68eb878bdf5eafa650e22f80cf9549d52c6.1604869679.git.me@pmachata.org> In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 0.10 / 15.00 / 15.00 X-Rspamd-Queue-Id: ECEAC1718 X-Rspamd-UID: b2ca47 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The Linux DCB interface allows configuration of a broad range of hardware-specific attributes, such as TC scheduling, flow control, per-port buffer configuration, TC rate, etc. Add a new tool to show that configuration and tweak it. DCB allows configuration of several objects, and possibly could expand to pre-standard CEE interfaces. Therefore the tool itself is a lean shell that dispatches to subtools each dedicated to one of the objects. Signed-off-by: Petr Machata --- Notes: v4: - Drop all the FILE* arguments that were passed around unnecessarily - Change dcb_parse_mapping() to make it more general - Rename dcb_print_array_num() to dcb_print_array_u8() - Swap around arguments to dcb_print_named_array() so that they are in sync with print_uint(), print_on_off() etc. v3: - Fix help output and man page to show the arguments as they are, so -p and --pretty, not -[p]retty, which is inaccurate. Makefile | 2 +- dcb/Makefile | 24 +++ dcb/dcb.c | 414 +++++++++++++++++++++++++++++++++++++++++++++++++ dcb/dcb.h | 39 +++++ man/man8/dcb.8 | 103 ++++++++++++ 5 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 dcb/Makefile create mode 100644 dcb/dcb.c create mode 100644 dcb/dcb.h create mode 100644 man/man8/dcb.8 diff --git a/Makefile b/Makefile index 5b040415a12b..e64c65992585 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ WFLAGS += -Wmissing-declarations -Wold-style-definition -Wformat=2 CFLAGS := $(WFLAGS) $(CCOPTS) -I../include -I../include/uapi $(DEFINES) $(CFLAGS) YACCFLAGS = -d -t -v -SUBDIRS=lib ip tc bridge misc netem genl tipc devlink rdma man +SUBDIRS=lib ip tc bridge misc netem genl tipc devlink rdma dcb man LIBNETLINK=../lib/libutil.a ../lib/libnetlink.a LDLIBS += $(LIBNETLINK) diff --git a/dcb/Makefile b/dcb/Makefile new file mode 100644 index 000000000000..9966c8f0bfa4 --- /dev/null +++ b/dcb/Makefile @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0 +include ../config.mk + +TARGETS := + +ifeq ($(HAVE_MNL),y) + +DCBOBJ = dcb.o +TARGETS += dcb + +endif + +all: $(TARGETS) $(LIBS) + +dcb: $(DCBOBJ) $(LIBNETLINK) + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ + +install: all + for i in $(TARGETS); \ + do install -m 0755 $$i $(DESTDIR)$(SBINDIR); \ + done + +clean: + rm -f $(DCBOBJ) $(TARGETS) diff --git a/dcb/dcb.c b/dcb/dcb.c new file mode 100644 index 000000000000..5346f0ec4179 --- /dev/null +++ b/dcb/dcb.c @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include + +#include "dcb.h" +#include "mnl_utils.h" +#include "namespace.h" +#include "utils.h" +#include "version.h" + +static int dcb_init(struct dcb *dcb) +{ + dcb->buf = malloc(MNL_SOCKET_BUFFER_SIZE); + if (dcb->buf == NULL) { + perror("Netlink buffer allocation"); + return -1; + } + + dcb->nl = mnlu_socket_open(NETLINK_ROUTE); + if (dcb->nl == NULL) { + perror("Open netlink socket"); + goto err_socket_open; + } + + new_json_obj_plain(dcb->json_output); + return 0; + +err_socket_open: + free(dcb->buf); + return -1; +} + +static void dcb_fini(struct dcb *dcb) +{ + delete_json_obj_plain(); + mnl_socket_close(dcb->nl); +} + +static struct dcb *dcb_alloc(void) +{ + struct dcb *dcb; + + dcb = calloc(1, sizeof(*dcb)); + if (!dcb) + return NULL; + return dcb; +} + +static void dcb_free(struct dcb *dcb) +{ + free(dcb); +} + +struct dcb_get_attribute { + struct dcb *dcb; + int attr; + void *data; + size_t data_len; +}; + +static int dcb_get_attribute_attr_ieee_cb(const struct nlattr *attr, void *data) +{ + struct dcb_get_attribute *ga = data; + uint16_t len; + + if (mnl_attr_get_type(attr) != ga->attr) + return MNL_CB_OK; + + len = mnl_attr_get_payload_len(attr); + if (len != ga->data_len) { + fprintf(stderr, "Wrong len %d, expected %zd\n", len, ga->data_len); + return MNL_CB_ERROR; + } + + memcpy(ga->data, mnl_attr_get_payload(attr), ga->data_len); + return MNL_CB_STOP; +} + +static int dcb_get_attribute_attr_cb(const struct nlattr *attr, void *data) +{ + if (mnl_attr_get_type(attr) != DCB_ATTR_IEEE) + return MNL_CB_OK; + + return mnl_attr_parse_nested(attr, dcb_get_attribute_attr_ieee_cb, data); +} + +static int dcb_get_attribute_cb(const struct nlmsghdr *nlh, void *data) +{ + return mnl_attr_parse(nlh, sizeof(struct dcbmsg), dcb_get_attribute_attr_cb, data); +} + +static int dcb_set_attribute_attr_cb(const struct nlattr *attr, void *data) +{ + uint16_t len; + uint8_t err; + + if (mnl_attr_get_type(attr) != DCB_ATTR_IEEE) + return MNL_CB_OK; + + len = mnl_attr_get_payload_len(attr); + if (len != 1) { + fprintf(stderr, "Response attribute expected to have size 1, not %d\n", len); + return MNL_CB_ERROR; + } + + err = mnl_attr_get_u8(attr); + if (err) { + fprintf(stderr, "Error when attempting to set attribute: %s\n", + strerror(err)); + return MNL_CB_ERROR; + } + + return MNL_CB_STOP; +} + +static int dcb_set_attribute_cb(const struct nlmsghdr *nlh, void *data) +{ + return mnl_attr_parse(nlh, sizeof(struct dcbmsg), dcb_set_attribute_attr_cb, data); +} + +static int dcb_talk(struct dcb *dcb, struct nlmsghdr *nlh, mnl_cb_t cb, void *data) +{ + int ret; + + ret = mnl_socket_sendto(dcb->nl, nlh, nlh->nlmsg_len); + if (ret < 0) { + perror("mnl_socket_sendto"); + return -1; + } + + return mnlu_socket_recv_run(dcb->nl, nlh->nlmsg_seq, dcb->buf, MNL_SOCKET_BUFFER_SIZE, + cb, data); +} + +static struct nlmsghdr *dcb_prepare(struct dcb *dcb, const char *dev, + uint32_t nlmsg_type, uint8_t dcb_cmd) +{ + struct dcbmsg dcbm = { + .cmd = dcb_cmd, + }; + struct nlmsghdr *nlh; + + nlh = mnlu_msg_prepare(dcb->buf, nlmsg_type, NLM_F_REQUEST, &dcbm, sizeof(dcbm)); + mnl_attr_put_strz(nlh, DCB_ATTR_IFNAME, dev); + return nlh; +} + +int dcb_get_attribute(struct dcb *dcb, const char *dev, int attr, void *data, size_t data_len) +{ + struct dcb_get_attribute ga; + struct nlmsghdr *nlh; + int ret; + + nlh = dcb_prepare(dcb, dev, RTM_GETDCB, DCB_CMD_IEEE_GET); + + ga = (struct dcb_get_attribute) { + .dcb = dcb, + .attr = attr, + .data = data, + .data_len = data_len, + }; + ret = dcb_talk(dcb, nlh, dcb_get_attribute_cb, &ga); + if (ret) { + perror("Attribute read"); + return ret; + } + return 0; +} + +int dcb_set_attribute(struct dcb *dcb, const char *dev, int attr, const void *data, size_t data_len) +{ + struct nlmsghdr *nlh; + struct nlattr *nest; + int ret; + + nlh = dcb_prepare(dcb, dev, RTM_GETDCB, DCB_CMD_IEEE_SET); + + nest = mnl_attr_nest_start(nlh, DCB_ATTR_IEEE); + mnl_attr_put(nlh, attr, data_len, data); + mnl_attr_nest_end(nlh, nest); + + ret = dcb_talk(dcb, nlh, dcb_set_attribute_cb, NULL); + if (ret) { + perror("Attribute write"); + return ret; + } + return 0; +} + +void dcb_print_array_u8(const __u8 *array, size_t size) +{ + SPRINT_BUF(b); + size_t i; + + for (i = 0; i < size; i++) { + snprintf(b, sizeof(b), "%zd:%%d ", i); + print_uint(PRINT_ANY, NULL, b, array[i]); + } +} + +void dcb_print_array_kw(const __u8 *array, size_t array_size, + const char *const kw[], size_t kw_size) +{ + SPRINT_BUF(b); + size_t i; + + for (i = 0; i < array_size; i++) { + __u8 emt = array[i]; + + snprintf(b, sizeof(b), "%zd:%%s ", i); + if (emt < kw_size && kw[emt]) + print_string(PRINT_ANY, NULL, b, kw[emt]); + else + print_string(PRINT_ANY, NULL, b, "???"); + } +} + +void dcb_print_named_array(const char *json_name, const char *fp_name, + const __u8 *array, size_t size, + void (*print_array)(const __u8 *, size_t)) +{ + open_json_array(PRINT_JSON, json_name); + print_string(PRINT_FP, NULL, "%s ", fp_name); + print_array(array, size); + close_json_array(PRINT_JSON, json_name); +} + +int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key, + const char *what_value, __u32 value, __u32 max_value, + void (*set_array)(__u32 index, __u32 value, void *data), + void *set_array_data) +{ + bool is_all = key == (__u32) -1; + + if (!is_all && key > max_key) { + fprintf(stderr, "In %s:%s mapping, %s is expected to be 0..%d\n", + what_key, what_value, what_key, max_key); + return -EINVAL; + } + + if (value > max_value) { + fprintf(stderr, "In %s:%s mapping, %s is expected to be 0..%d\n", + what_key, what_value, what_value, max_value); + return -EINVAL; + } + + if (is_all) { + for (key = 0; key < max_key; key++) + set_array(key, value, set_array_data); + } else { + set_array(key, value, set_array_data); + } + + return 0; +} + +void dcb_set_u8(__u32 key, __u32 value, void *data) +{ + __u8 *array = data; + + array[key] = value; +} + +int dcb_cmd_parse_dev(struct dcb *dcb, int argc, char **argv, + int (*and_then)(struct dcb *dcb, const char *dev, + int argc, char **argv), + void (*help)(void)) +{ + const char *dev; + + if (!argc || matches(*argv, "help") == 0) { + help(); + return 0; + } else if (matches(*argv, "dev") == 0) { + NEXT_ARG(); + dev = *argv; + if (check_ifname(dev)) { + invarg("not a valid ifname", *argv); + return -EINVAL; + } + NEXT_ARG_FWD(); + return and_then(dcb, dev, argc, argv); + } else { + fprintf(stderr, "Expected `dev DEV', not `%s'", *argv); + help(); + return -EINVAL; + } +} + +static void dcb_help(void) +{ + fprintf(stderr, + "Usage: dcb [ OPTIONS ] OBJECT { COMMAND | help }\n" + " dcb [ -f | --force ] { -b | --batch } filename [ -N | --Netns ] netnsname\n" + "where OBJECT :=\n" + " OPTIONS := [ -V | --Version | -j | --json | -p | --pretty | -v | --verbose ]\n"); +} + +static int dcb_cmd(struct dcb *dcb, int argc, char **argv) +{ + if (!argc || matches(*argv, "help") == 0) { + dcb_help(); + return 0; + } + + fprintf(stderr, "Object \"%s\" is unknown\n", *argv); + return -ENOENT; +} + +static int dcb_batch_cmd(int argc, char *argv[], void *data) +{ + struct dcb *dcb = data; + + return dcb_cmd(dcb, argc, argv); +} + +static int dcb_batch(struct dcb *dcb, const char *name, bool force) +{ + return do_batch(name, force, dcb_batch_cmd, dcb); +} + +int main(int argc, char **argv) +{ + static const struct option long_options[] = { + { "Version", no_argument, NULL, 'V' }, + { "force", no_argument, NULL, 'f' }, + { "batch", required_argument, NULL, 'b' }, + { "json", no_argument, NULL, 'j' }, + { "pretty", no_argument, NULL, 'p' }, + { "Netns", required_argument, NULL, 'N' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } + }; + const char *batch_file = NULL; + bool force = false; + struct dcb *dcb; + int opt; + int err; + int ret; + + dcb = dcb_alloc(); + if (!dcb) { + fprintf(stderr, "Failed to allocate memory for dcb\n"); + return EXIT_FAILURE; + } + + while ((opt = getopt_long(argc, argv, "b:c::fhjnpvN:V", + long_options, NULL)) >= 0) { + + switch (opt) { + case 'V': + printf("dcb utility, iproute2-%s\n", version); + ret = EXIT_SUCCESS; + goto dcb_free; + case 'f': + force = true; + break; + case 'b': + batch_file = optarg; + break; + case 'j': + dcb->json_output = true; + break; + case 'p': + pretty = true; + break; + case 'N': + if (netns_switch(optarg)) { + ret = EXIT_FAILURE; + goto dcb_free; + } + break; + case 'h': + dcb_help(); + return 0; + default: + fprintf(stderr, "Unknown option.\n"); + dcb_help(); + ret = EXIT_FAILURE; + goto dcb_free; + } + } + + argc -= optind; + argv += optind; + + err = dcb_init(dcb); + if (err) { + ret = EXIT_FAILURE; + goto dcb_free; + } + + if (batch_file) + err = dcb_batch(dcb, batch_file, force); + else + err = dcb_cmd(dcb, argc, argv); + + if (err) { + ret = EXIT_FAILURE; + goto dcb_fini; + } + + ret = EXIT_SUCCESS; + +dcb_fini: + dcb_fini(dcb); +dcb_free: + dcb_free(dcb); + + return ret; +} diff --git a/dcb/dcb.h b/dcb/dcb.h new file mode 100644 index 000000000000..a09d102a7fc6 --- /dev/null +++ b/dcb/dcb.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DCB_H__ +#define __DCB_H__ 1 + +#include +#include + +/* dcb.c */ + +struct dcb { + char *buf; + struct mnl_socket *nl; + bool json_output; +}; + +int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key, + const char *what_value, __u32 value, __u32 max_value, + void (*set_array)(__u32 index, __u32 value, void *data), + void *set_array_data); +int dcb_cmd_parse_dev(struct dcb *dcb, int argc, char **argv, + int (*and_then)(struct dcb *dcb, const char *dev, + int argc, char **argv), + void (*help)(void)); + +void dcb_set_u8(__u32 key, __u32 value, void *data); + +int dcb_get_attribute(struct dcb *dcb, const char *dev, int attr, + void *data, size_t data_len); +int dcb_set_attribute(struct dcb *dcb, const char *dev, int attr, + const void *data, size_t data_len); + +void dcb_print_named_array(const char *json_name, const char *fp_name, + const __u8 *array, size_t size, + void (*print_array)(const __u8 *, size_t)); +void dcb_print_array_u8(const __u8 *array, size_t size); +void dcb_print_array_kw(const __u8 *array, size_t array_size, + const char *const kw[], size_t kw_size); + +#endif /* __DCB_H__ */ diff --git a/man/man8/dcb.8 b/man/man8/dcb.8 new file mode 100644 index 000000000000..19433bfb906d --- /dev/null +++ b/man/man8/dcb.8 @@ -0,0 +1,103 @@ +.TH DCB 8 "19 October 2020" "iproute2" "Linux" +.SH NAME +dcb \- show / manipulate DCB (Data Center Bridging) settings +.SH SYNOPSIS +.sp +.ad l +.in +8 + +.ti -8 +.B dcb +.RB "[ " -force " ] " +.BI "-batch " filename +.sp + +.ti -8 +.B dcb +.RI "[ " OPTIONS " ] " +.B help +.sp + +.SH OPTIONS + +.TP +.BR "\-V" , " --Version" +Print the version of the +.B dcb +utility and exit. + +.TP +.BR "\-b", " --batch " +Read commands from provided file or standard input and invoke them. First +failure will cause termination of dcb. + +.TP +.BR "\-f", " --force" +Don't terminate dcb on errors in batch mode. If there were any errors during +execution of the commands, the application return code will be non zero. + +.TP +.BR "\-j" , " --json" +Generate JSON output. + +.TP +.BR "\-p" , " --pretty" +When combined with -j generate a pretty JSON output. + +.SH OBJECTS + +.SH COMMANDS + +A \fICOMMAND\fR specifies the action to perform on the object. The set of +possible actions depends on the object type. As a rule, it is possible to +.B show +objects and to invoke topical +.B help, +which prints a list of available commands and argument syntax conventions. + +.SH ARRAY PARAMETERS + +Like commands, specification of parameters is in the domain of individual +objects (and their commands) as well. However, much of the DCB interface +revolves around arrays of fixed size that specify one value per some key, such +as per traffic class or per priority. There is therefore a single syntax for +adjusting elements of these arrays. It consists of a series of +\fIKEY\fB:\fIVALUE\fR pairs, where the meaning of the individual keys and values +depends on the parameter. + +The elements are evaluated in order from left to right, and the latter ones +override the earlier ones. The elements that are not specified on the command +line are queried from the kernel and their current value is retained. + +As an example, take a made-up parameter tc-juju, which can be set to charm +traffic in a given TC with either good luck or bad luck. \fIKEY\fR can therefore +be 0..7 (as is usual for TC numbers in DCB), and \fIVALUE\fR either of +\fBnone\fR, \fBgood\fR, and \fBbad\fR. An example of changing a juju value of +TCs 0 and 7, while leaving all other intact, would then be: + +.P +# dcb foo set dev eth0 tc-juju 0:good 7:bad + +A special key, \fBall\fR, is recognized which sets the same value to all array +elements. This can be combined with the usual single-element syntax. E.g. in the +following, the juju of all keys is set to \fBnone\fR, except 0 and 7, which have +other values: + +.P +# dcb foo set dev eth0 tc-juju all:none 0:good 7:bad + +.SH EXIT STATUS +Exit status is 0 if command was successful or a positive integer upon failure. + +.SH SEE ALSO +.BR dcb-ets (8) +.br + +.SH REPORTING BUGS +Report any bugs to the Network Developers mailing list +.B +where the development and maintenance is primarily done. +You do not have to be subscribed to the list to send a message there. + +.SH AUTHOR +Petr Machata From patchwork Sun Nov 8 21:14:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Machata X-Patchwork-Id: 11889867 X-Patchwork-Delegate: stephen@networkplumber.org 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.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS 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 E82A0C55ABD for ; Sun, 8 Nov 2020 21:14:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A8E53206DC for ; Sun, 8 Nov 2020 21:14:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=pmachata.org header.i=@pmachata.org header.b="yF2CX3sL" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728962AbgKHVO4 (ORCPT ); Sun, 8 Nov 2020 16:14:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43872 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728970AbgKHVOx (ORCPT ); Sun, 8 Nov 2020 16:14:53 -0500 Received: from mout-p-102.mailbox.org (mout-p-102.mailbox.org [IPv6:2001:67c:2050::465:102]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5EC08C0613D3 for ; Sun, 8 Nov 2020 13:14:53 -0800 (PST) Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:105:465:1:2:0]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4CTn2M2gwxzQlVP; Sun, 8 Nov 2020 22:14:51 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pmachata.org; s=MBO0001; t=1604870089; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uvIwaDI5Ph6T1ftJEvKGxzPuBsmpps0XmbT/G/vESfw=; b=yF2CX3sLzXRhTcDu7Dv3EAnx8IYOtagv0csIX59Q5393nfYIFoCN+CrsscEqL3qFDZpIzX zh9fc5jyhGIYeOh0UfEvuc/+3CJ/9Bp5adLJ0M0MLOy1fohDALYKw+3kRpAvARrmx6RMCM o60wWy3a2t/YcwHpHXl2OqPdqoLStiQu85ntYVEUQa8MCnuZk8hPLLPEyhiP8HwpmvgsJi tcQgUaK58Y5U4BKKDKKVjkD7GZhTMpkNt+mkRVRmh+cv7JV8ODuJRt2YEKguZa7dtI+Uiu rOEBDC+7da7GSGkx6Agb0DhY8fmSIgx2fsSPeMh67E+gK+lXxh2SKPXr7ZDYQQ== Received: from smtp2.mailbox.org ([80.241.60.241]) by spamfilter03.heinlein-hosting.de (spamfilter03.heinlein-hosting.de [80.241.56.117]) (amavisd-new, port 10030) with ESMTP id MbX3E0Cspmmc; Sun, 8 Nov 2020 22:14:47 +0100 (CET) From: Petr Machata To: netdev@vger.kernel.org, dsahern@gmail.com, stephen@networkplumber.org Cc: john.fastabend@gmail.com, jiri@nvidia.com, idosch@nvidia.com, Jakub Kicinski , Roman Mashak , Leon Romanovsky , Petr Machata Subject: [PATCH iproute2-next v4 11/11] dcb: Add a subtool for the DCB ETS object Date: Sun, 8 Nov 2020 22:14:16 +0100 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 0.10 / 15.00 / 15.00 X-Rspamd-Queue-Id: 574CD108B X-Rspamd-UID: 0e73a0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org ETS, for "Enhanced Transmission Selection", is a set of configurations that permit configuration of mapping of priorities to traffic classes, traffic selection algorithm to use per traffic class, bandwidth allocation, etc. Add a dcb subtool to allow showing and tweaking of individual ETS configuration options. For example: # dcb ets show dev eni1np1 willing on ets_cap 8 cbs off tc-bw 0:0 1:0 2:0 3:0 4:100 5:0 6:0 7:0 pg-bw 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 tc-tsa 0:strict 1:strict 2:strict 3:strict 4:ets 5:strict 6:strict 7:strict prio-tc 0:1 1:3 2:5 3:0 4:0 5:0 6:0 7:0 reco-tc-bw 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 reco-tc-tsa 0:strict 1:strict 2:strict 3:strict 4:strict 5:strict 6:strict 7:strict reco-prio-tc 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 Signed-off-by: Petr Machata --- Notes: v4: - Drop all the FILE* arguments that were passed around unnecessarily - Emit ets-cap in FP as "ets-cap", not "ets_cap" v3: - Formatting tweaks in the man page dcb/Makefile | 2 +- dcb/dcb.c | 4 +- dcb/dcb.h | 4 + dcb/dcb_ets.c | 435 +++++++++++++++++++++++++++++++++++++++++++++ man/man8/dcb-ets.8 | 185 +++++++++++++++++++ man/man8/dcb.8 | 11 ++ 6 files changed, 639 insertions(+), 2 deletions(-) create mode 100644 dcb/dcb_ets.c create mode 100644 man/man8/dcb-ets.8 diff --git a/dcb/Makefile b/dcb/Makefile index 9966c8f0bfa4..895817163562 100644 --- a/dcb/Makefile +++ b/dcb/Makefile @@ -5,7 +5,7 @@ TARGETS := ifeq ($(HAVE_MNL),y) -DCBOBJ = dcb.o +DCBOBJ = dcb.o dcb_ets.o TARGETS += dcb endif diff --git a/dcb/dcb.c b/dcb/dcb.c index 5346f0ec4179..3be4f9fd57f5 100644 --- a/dcb/dcb.c +++ b/dcb/dcb.c @@ -295,7 +295,7 @@ static void dcb_help(void) fprintf(stderr, "Usage: dcb [ OPTIONS ] OBJECT { COMMAND | help }\n" " dcb [ -f | --force ] { -b | --batch } filename [ -N | --Netns ] netnsname\n" - "where OBJECT :=\n" + "where OBJECT := ets\n" " OPTIONS := [ -V | --Version | -j | --json | -p | --pretty | -v | --verbose ]\n"); } @@ -304,6 +304,8 @@ static int dcb_cmd(struct dcb *dcb, int argc, char **argv) if (!argc || matches(*argv, "help") == 0) { dcb_help(); return 0; + } else if (matches(*argv, "ets") == 0) { + return dcb_cmd_ets(dcb, argc - 1, argv + 1); } fprintf(stderr, "Object \"%s\" is unknown\n", *argv); diff --git a/dcb/dcb.h b/dcb/dcb.h index a09d102a7fc6..6f135ed06b08 100644 --- a/dcb/dcb.h +++ b/dcb/dcb.h @@ -36,4 +36,8 @@ void dcb_print_array_u8(const __u8 *array, size_t size); void dcb_print_array_kw(const __u8 *array, size_t array_size, const char *const kw[], size_t kw_size); +/* dcb_ets.c */ + +int dcb_cmd_ets(struct dcb *dcb, int argc, char **argv); + #endif /* __DCB_H__ */ diff --git a/dcb/dcb_ets.c b/dcb/dcb_ets.c new file mode 100644 index 000000000000..1735885aa8ed --- /dev/null +++ b/dcb/dcb_ets.c @@ -0,0 +1,435 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include + +#include "dcb.h" +#include "utils.h" + +static void dcb_ets_help_set(void) +{ + fprintf(stderr, + "Usage: dcb ets set dev STRING\n" + " [ willing { on | off } ]\n" + " [ { tc-tsa | reco-tc-tsa } TSA-MAP ]\n" + " [ { pg-bw | tc-bw | reco-tc-bw } BW-MAP ]\n" + " [ { prio-tc | reco-prio-tc } PRIO-MAP ]\n" + "\n" + " where TSA-MAP := [ TSA-MAP ] TSA-MAPPING\n" + " TSA-MAPPING := { all | TC }:{ strict | cbs | ets | vendor }\n" + " BW-MAP := [ BW-MAP ] BW-MAPPING\n" + " BW-MAPPING := { all | TC }:INTEGER\n" + " PRIO-MAP := [ PRIO-MAP ] PRIO-MAPPING\n" + " PRIO-MAPPING := { all | PRIO }:TC\n" + " TC := { 0 .. 7 }\n" + " PRIO := { 0 .. 7 }\n" + "\n" + ); +} + +static void dcb_ets_help_show(void) +{ + fprintf(stderr, + "Usage: dcb ets show dev STRING\n" + " [ willing | ets-cap | cbs | tc-tsa | reco-tc-tsa |\n" + " pg-bw | tc-bw | reco-tc-bw | prio-tc |\n" + " reco-prio-tc ]\n" + "\n" + ); +} + +static void dcb_ets_help(void) +{ + fprintf(stderr, + "Usage: dcb ets help\n" + "\n" + ); + dcb_ets_help_show(); + dcb_ets_help_set(); +} + +static const char *const tsa_names[] = { + [IEEE_8021QAZ_TSA_STRICT] = "strict", + [IEEE_8021QAZ_TSA_CB_SHAPER] = "cbs", + [IEEE_8021QAZ_TSA_ETS] = "ets", + [IEEE_8021QAZ_TSA_VENDOR] = "vendor", +}; + +static int dcb_ets_parse_mapping_tc_tsa(__u32 key, char *value, void *data) +{ + __u8 tsa; + int ret; + + tsa = parse_one_of("TSA", value, tsa_names, ARRAY_SIZE(tsa_names), &ret); + if (ret) + return ret; + + return dcb_parse_mapping("TC", key, IEEE_8021QAZ_MAX_TCS - 1, + "TSA", tsa, -1U, + dcb_set_u8, data); +} + +static int dcb_ets_parse_mapping_tc_bw(__u32 key, char *value, void *data) +{ + __u8 bw; + + if (get_u8(&bw, value, 0)) + return -EINVAL; + + return dcb_parse_mapping("TC", key, IEEE_8021QAZ_MAX_TCS - 1, + "BW", bw, 100, + dcb_set_u8, data); +} + +static int dcb_ets_parse_mapping_prio_tc(unsigned int key, char *value, void *data) +{ + __u8 tc; + + if (get_u8(&tc, value, 0)) + return -EINVAL; + + return dcb_parse_mapping("PRIO", key, IEEE_8021QAZ_MAX_TCS - 1, + "TC", tc, IEEE_8021QAZ_MAX_TCS - 1, + dcb_set_u8, data); +} + +static void dcb_print_array_tsa(const __u8 *array, size_t size) +{ + dcb_print_array_kw(array, size, tsa_names, ARRAY_SIZE(tsa_names)); +} + +static void dcb_ets_print_willing(const struct ieee_ets *ets) +{ + print_on_off(PRINT_ANY, "willing", "willing %s ", ets->willing); +} + +static void dcb_ets_print_ets_cap(const struct ieee_ets *ets) +{ + print_uint(PRINT_ANY, "ets_cap", "ets-cap %d ", ets->ets_cap); +} + +static void dcb_ets_print_cbs(const struct ieee_ets *ets) +{ + print_on_off(PRINT_ANY, "cbs", "cbs %s ", ets->cbs); +} + +static void dcb_ets_print_tc_bw(const struct ieee_ets *ets) +{ + dcb_print_named_array("tc_bw", "tc-bw", + ets->tc_tx_bw, ARRAY_SIZE(ets->tc_tx_bw), + dcb_print_array_u8); +} + +static void dcb_ets_print_pg_bw(const struct ieee_ets *ets) +{ + dcb_print_named_array("pg_bw", "pg-bw", + ets->tc_rx_bw, ARRAY_SIZE(ets->tc_rx_bw), + dcb_print_array_u8); +} + +static void dcb_ets_print_tc_tsa(const struct ieee_ets *ets) +{ + dcb_print_named_array("tc_tsa", "tc-tsa", + ets->tc_tsa, ARRAY_SIZE(ets->tc_tsa), + dcb_print_array_tsa); +} + +static void dcb_ets_print_prio_tc(const struct ieee_ets *ets) +{ + dcb_print_named_array("prio_tc", "prio-tc", + ets->prio_tc, ARRAY_SIZE(ets->prio_tc), + dcb_print_array_u8); +} + +static void dcb_ets_print_reco_tc_bw(const struct ieee_ets *ets) +{ + dcb_print_named_array("reco_tc_bw", "reco-tc-bw", + ets->tc_reco_bw, ARRAY_SIZE(ets->tc_reco_bw), + dcb_print_array_u8); +} + +static void dcb_ets_print_reco_tc_tsa(const struct ieee_ets *ets) +{ + dcb_print_named_array("reco_tc_tsa", "reco-tc-tsa", + ets->tc_reco_tsa, ARRAY_SIZE(ets->tc_reco_tsa), + dcb_print_array_tsa); +} + +static void dcb_ets_print_reco_prio_tc(const struct ieee_ets *ets) +{ + dcb_print_named_array("reco_prio_tc", "reco-prio-tc", + ets->reco_prio_tc, ARRAY_SIZE(ets->reco_prio_tc), + dcb_print_array_u8); +} + +static void dcb_ets_print(const struct ieee_ets *ets) +{ + dcb_ets_print_willing(ets); + dcb_ets_print_ets_cap(ets); + dcb_ets_print_cbs(ets); + print_nl(); + + dcb_ets_print_tc_bw(ets); + print_nl(); + + dcb_ets_print_pg_bw(ets); + print_nl(); + + dcb_ets_print_tc_tsa(ets); + print_nl(); + + dcb_ets_print_prio_tc(ets); + print_nl(); + + dcb_ets_print_reco_tc_bw(ets); + print_nl(); + + dcb_ets_print_reco_tc_tsa(ets); + print_nl(); + + dcb_ets_print_reco_prio_tc(ets); + print_nl(); +} + +static int dcb_ets_get(struct dcb *dcb, const char *dev, struct ieee_ets *ets) +{ + return dcb_get_attribute(dcb, dev, DCB_ATTR_IEEE_ETS, ets, sizeof(*ets)); +} + +static int dcb_ets_validate_bw(const __u8 bw[], const __u8 tsa[], const char *what) +{ + bool has_ets = false; + unsigned int total = 0; + unsigned int tc; + + for (tc = 0; tc < IEEE_8021QAZ_MAX_TCS; tc++) { + if (tsa[tc] == IEEE_8021QAZ_TSA_ETS) { + has_ets = true; + break; + } + } + + /* TC bandwidth is only intended for ETS, but 802.1Q-2018 only requires + * that the sum be 100, and individual entries 0..100. It explicitly + * notes that non-ETS TCs can have non-0 TC bandwidth during + * reconfiguration. + */ + for (tc = 0; tc < IEEE_8021QAZ_MAX_TCS; tc++) { + if (bw[tc] > 100) { + fprintf(stderr, "%d%% for TC %d of %s is not a valid bandwidth percentage, expected 0..100%%\n", + bw[tc], tc, what); + return -EINVAL; + } + total += bw[tc]; + } + + /* This is what 802.1Q-2018 requires. */ + if (total == 100) + return 0; + + /* But this requirement does not make sense for all-strict + * configurations. Anything else than 0 does not make sense: either BW + * has not been reconfigured for the all-strict allocation yet, at which + * point we expect sum of 100. Or it has already been reconfigured, at + * which point accept 0. + */ + if (!has_ets && total == 0) + return 0; + + fprintf(stderr, "Bandwidth percentages in %s sum to %d%%, expected %d%%\n", + what, total, has_ets ? 100 : 0); + return -EINVAL; +} + +static int dcb_ets_set(struct dcb *dcb, const char *dev, const struct ieee_ets *ets) +{ + /* Do not validate pg-bw, which is not standard and has unclear + * meaning. + */ + if (dcb_ets_validate_bw(ets->tc_tx_bw, ets->tc_tsa, "tc-bw") || + dcb_ets_validate_bw(ets->tc_reco_bw, ets->tc_reco_tsa, "reco-tc-bw")) + return -EINVAL; + + return dcb_set_attribute(dcb, dev, DCB_ATTR_IEEE_ETS, ets, sizeof(*ets)); +} + +static int dcb_cmd_ets_set(struct dcb *dcb, const char *dev, int argc, char **argv) +{ + struct ieee_ets ets; + int ret; + + if (!argc) { + dcb_ets_help_set(); + return 1; + } + + ret = dcb_ets_get(dcb, dev, &ets); + if (ret) + return ret; + + do { + if (matches(*argv, "help") == 0) { + dcb_ets_help_set(); + return 0; + } else if (matches(*argv, "willing") == 0) { + NEXT_ARG(); + ets.willing = parse_on_off("willing", *argv, &ret); + if (ret) + return ret; + } else if (matches(*argv, "tc-tsa") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_tc_tsa, + ets.tc_tsa); + if (ret) { + fprintf(stderr, "Invalid tc-tsa mapping %s\n", *argv); + return ret; + } + continue; + } else if (matches(*argv, "reco-tc-tsa") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_tc_tsa, + ets.tc_reco_tsa); + if (ret) { + fprintf(stderr, "Invalid reco-tc-tsa mapping %s\n", *argv); + return ret; + } + continue; + } else if (matches(*argv, "tc-bw") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_tc_bw, + ets.tc_tx_bw); + if (ret) { + fprintf(stderr, "Invalid tc-bw mapping %s\n", *argv); + return ret; + } + continue; + } else if (matches(*argv, "pg-bw") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_tc_bw, + ets.tc_rx_bw); + if (ret) { + fprintf(stderr, "Invalid pg-bw mapping %s\n", *argv); + return ret; + } + continue; + } else if (matches(*argv, "reco-tc-bw") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_tc_bw, + ets.tc_reco_bw); + if (ret) { + fprintf(stderr, "Invalid reco-tc-bw mapping %s\n", *argv); + return ret; + } + continue; + } else if (matches(*argv, "prio-tc") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_prio_tc, + ets.prio_tc); + if (ret) { + fprintf(stderr, "Invalid prio-tc mapping %s\n", *argv); + return ret; + } + continue; + } else if (matches(*argv, "reco-prio-tc") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_prio_tc, + ets.reco_prio_tc); + if (ret) { + fprintf(stderr, "Invalid reco-prio-tc mapping %s\n", *argv); + return ret; + } + continue; + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_ets_help_set(); + return -EINVAL; + } + + NEXT_ARG_FWD(); + } while (argc > 0); + + return dcb_ets_set(dcb, dev, &ets); +} + +static int dcb_cmd_ets_show(struct dcb *dcb, const char *dev, int argc, char **argv) +{ + struct ieee_ets ets; + int ret; + + ret = dcb_ets_get(dcb, dev, &ets); + if (ret) + return ret; + + open_json_object(NULL); + + if (!argc) { + dcb_ets_print(&ets); + goto out; + } + + do { + if (matches(*argv, "help") == 0) { + dcb_ets_help(); + return 0; + } else if (matches(*argv, "willing") == 0) { + dcb_ets_print_willing(&ets); + print_nl(); + } else if (matches(*argv, "ets-cap") == 0) { + dcb_ets_print_ets_cap(&ets); + print_nl(); + } else if (matches(*argv, "cbs") == 0) { + dcb_ets_print_cbs(&ets); + print_nl(); + } else if (matches(*argv, "tc-tsa") == 0) { + dcb_ets_print_tc_tsa(&ets); + print_nl(); + } else if (matches(*argv, "reco-tc-tsa") == 0) { + dcb_ets_print_reco_tc_tsa(&ets); + print_nl(); + } else if (matches(*argv, "tc-bw") == 0) { + dcb_ets_print_tc_bw(&ets); + print_nl(); + } else if (matches(*argv, "pg-bw") == 0) { + dcb_ets_print_pg_bw(&ets); + print_nl(); + } else if (matches(*argv, "reco-tc-bw") == 0) { + dcb_ets_print_reco_tc_bw(&ets); + print_nl(); + } else if (matches(*argv, "prio-tc") == 0) { + dcb_ets_print_prio_tc(&ets); + print_nl(); + } else if (matches(*argv, "reco-prio-tc") == 0) { + dcb_ets_print_reco_prio_tc(&ets); + print_nl(); + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_ets_help(); + return -EINVAL; + } + + NEXT_ARG_FWD(); + } while (argc > 0); + +out: + close_json_object(); + return 0; +} + +int dcb_cmd_ets(struct dcb *dcb, int argc, char **argv) +{ + if (!argc || matches(*argv, "help") == 0) { + dcb_ets_help(); + return 0; + } else if (matches(*argv, "show") == 0) { + NEXT_ARG_FWD(); + return dcb_cmd_parse_dev(dcb, argc, argv, dcb_cmd_ets_show, dcb_ets_help_show); + } else if (matches(*argv, "set") == 0) { + NEXT_ARG_FWD(); + return dcb_cmd_parse_dev(dcb, argc, argv, dcb_cmd_ets_set, dcb_ets_help_set); + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_ets_help(); + return -EINVAL; + } +} diff --git a/man/man8/dcb-ets.8 b/man/man8/dcb-ets.8 new file mode 100644 index 000000000000..81d8c5bce7e6 --- /dev/null +++ b/man/man8/dcb-ets.8 @@ -0,0 +1,185 @@ +.TH DCB-ETS 8 "19 October 2020" "iproute2" "Linux" +.SH NAME +dcb-ets \- show / manipulate ETS (Enhanced Transmission Selection) settings of +the DCB (Data Center Bridging) subsystem +.SH SYNOPSIS +.sp +.ad l +.in +8 + +.ti -8 +.B dcb +.RI "[ " OPTIONS " ] " +.B ets +.RI "{ " COMMAND " | " help " }" +.sp + +.ti -8 +.B dcb ets show dev +.RI DEV +.RB "[ { " willing " | " ets-cap " | " cbs " | " tc-tsa " | " reco-tc-tsa +.RB " | " pg-bw " | " tc-bw " | " reco-tc-bw " | " prio-tc +.RB " | " reco-prio-tc " } ]" + +.ti -8 +.B dcb ets set dev +.RI DEV +.RB "[ " willing " { " on " | " off " } ]" +.RB "[ { " tc-tsa " | " reco-tc-tsa " } " \fITSA-MAP\fB " ]" +.RB "[ { " pg-bw " | " tc-bw " | " reco-tc-bw " } " \fIBW-MAP\fB " ]" +.RB "[ { " prio-tc " | " reco-prio-tc " } " \fIPRIO-MAP\fB " ]" + +.ti -8 +.IR TSA-MAP " := [ " TSA-MAP " ] " TSA-MAPPING + +.ti -8 +.IR TSA-MAPPING " := { " TC " | " \fBall " }" \fB: "{ " \fBstrict\fR " | " +.IR \fBcbs\fR " | " \fBets\fR " | " \fBvendor\fR " }" + +.ti -8 +.IR BW-MAP " := [ " BW-MAP " ] " BW-MAPPING + +.ti -8 +.IR BW-MAPPING " := { " TC " | " \fBall " }" \fB:\fIINTEGER\fR + +.ti -8 +.IR PRIO-MAP " := [ " PRIO-MAP " ] " PRIO-MAPPING + +.ti -8 +.IR PRIO-MAPPING " := { " PRIO " | " \fBall " }" \fB:\fITC\fR + +.ti -8 +.IR TC " := { " \fB0\fR " .. " \fB7\fR " }" + +.ti -8 +.IR PRIO " := { " \fB0\fR " .. " \fB7\fR " }" + + +.SH DESCRIPTION + +.B dcb ets +is used to configure Enhanced Transmission Selection attributes through Linux +DCB (Data Center Bridging) interface. ETS permits configuration of mapping of +priorities to traffic classes, traffic selection algorithm to use per traffic +class, bandwidth allocation, etc. + +Two DCB TLVs are related to the ETS feature: a configuration and recommendation +values. Recommendation values are named with a prefix +.B reco-, +while the configuration ones have plain names. + +.SH PARAMETERS + +For read-write parameters, the following describes only the write direction, +i.e. as used with the \fBset\fR command. For the \fBshow\fR command, the +parameter name is to be used as a simple keyword without further arguments. This +instructs the tool to show the value of a given parameter. When no parameters +are given, the tool shows the complete ETS configuration. + +.TP +.B ets-cap +A read-only property that shows the number of supported ETS traffic classes. + +.TP +.B cbs +A read-only property that is enabled if the driver and the hardware support the +CBS Transmission Selection Algorithm. + +.TP +.B willing \fR{ \fBon\fR | \fBoff\fR } +Whether local host should accept configuration from peer TLVs. + +.TP +.B prio-tc \fITC-MAP +.TQ +.B reco-prio-tc \fITC-MAP +\fITC-MAP\fR uses the array parameter syntax, see dcb(8) for details. Keys are +priorities, values are traffic classes. For each priority sets a TC where +traffic with that priority is directed to. + +.TP +.B tc-tsa \fITSA-MAP +.TQ +.B reco-tc-tsa \fITSA-MAP +\fITC-MAP\fR uses the array parameter syntax, see dcb(8) for details. Keys are +TCs, values are Transmission Selection Algorithm (TSA) keywords described below. +For each TC sets an algorithm used for deciding how traffic queued up at this TC +is scheduled for transmission. Supported TSAs are: + +.B strict +- for strict priority, where traffic in higher-numbered TCs always takes +precedence over traffic in lower-numbered TCs. +.br +.B ets +- for Enhanced Traffic Selection, where available bandwidth is distributed among +the ETS-enabled TCs according to the weights set by +.B tc-bw +and +.B reco-tc-bw\fR, +respectively. +.br +.B cbs +- for Credit Based Shaper, where traffic is scheduled in a strict manner up to +the limit set by a shaper. +.br +.B vendor +- for vendor-specific traffic selection algorithm. + +.TP +.B tc-bw \fIBW-MAP +.TQ +.B reco-tc-bw \fIBW-MAP +\fIBW-MAP\fR uses the array parameter syntax, see dcb(8) for details. Keys are +TCs, values are integers representing percent of available bandwidth given to +the traffic class in question. The value should be 0 for TCs whose TSA is not +\fBets\fR, and the sum of all values shall be 100. As an exception to the +standard wording, a configuration with no ETS TCs is permitted to sum up to 0 +instead. +.br + +.TP +.B pg-bw \fIBW-MAP +The precise meaning of \fBpg-bw\fR is not standardized, but the assumption seems +to be that the same scheduling process as on the transmit side is applicable on +receive side as well, and configures receive bandwidth allocation for \fBets\fR +ingress traffic classes (priority groups). + +.SH EXAMPLE & USAGE + +Configure ETS priomap in a one-to-one fashion: + +.P +# dcb ets set dev eth0 prio-tc 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 + +Set TSA and transmit bandwidth configuration: + +.P +# dcb ets set dev eth0 tc-tsa all:strict 0:ets 1:ets 2:ets \\ +.br + tc-bw all:0 0:33 1:33 2:34 + +Show what was set: + +.P +# dcb ets show dev eth0 prio-tc tc-tsa tc-bw +.br +prio-tc 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 +.br +tc-tsa 0:ets 1:ets 2:ets 3:strict 4:strict 5:strict 6:strict 7:strict +.br +tc-bw 0:33 1:33 2:34 3:0 4:0 5:0 6:0 7:0 + +.SH EXIT STATUS +Exit status is 0 if command was successful or a positive integer upon failure. + +.SH SEE ALSO +.BR dcb (8) + +.SH REPORTING BUGS +Report any bugs to the Network Developers mailing list +.B +where the development and maintenance is primarily done. +You do not have to be subscribed to the list to send a message there. + +.SH AUTHOR +Petr Machata diff --git a/man/man8/dcb.8 b/man/man8/dcb.8 index 19433bfb906d..f318435caa98 100644 --- a/man/man8/dcb.8 +++ b/man/man8/dcb.8 @@ -6,6 +6,13 @@ dcb \- show / manipulate DCB (Data Center Bridging) settings .ad l .in +8 +.ti -8 +.B dcb +.RI "[ " OPTIONS " ] " +.B ets +.RI "{ " COMMAND " | " help " }" +.sp + .ti -8 .B dcb .RB "[ " -force " ] " @@ -46,6 +53,10 @@ When combined with -j generate a pretty JSON output. .SH OBJECTS +.TP +.B ets +- Configuration of ETS (Enhanced Transmission Selection) + .SH COMMANDS A \fICOMMAND\fR specifies the action to perform on the object. The set of