[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20220620153555.2504178-2-dchumak@nvidia.com>
Date: Mon, 20 Jun 2022 18:35:52 +0300
From: Dima Chumak <dchumak@...dia.com>
To: Stephen Hemminger <stephen@...workplumber.org>,
David Ahern <dsahern@...nel.org>
CC: Jakub Kicinski <kuba@...nel.org>, Jiri Pirko <jiri@...dia.com>,
"David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
"Paolo Abeni" <pabeni@...hat.com>, <netdev@...r.kernel.org>,
Dima Chumak <dchumak@...dia.com>
Subject: [PATCH iproute2-next 2/5] devlink: Add port rate limit_type support
Extend existing `devlink port func rate {set|add}` CLI with a new
parameter 'limit_type'. It specifies differnt kinds of rate limiting
that may be supported by a driver.
The parameter is optional and the only value it can take as of now is
'shaping', which is just a name for the existing rate limiting
mechanism.
It lays a foundation to adding other limit types. Following patches in
the series introduce new limit_type 'police'.
Signed-off-by: Dima Chumak <dchumak@...dia.com>
---
devlink/devlink.c | 121 ++++++++++++++++++++++++++++++++++------
man/man8/devlink-rate.8 | 17 ++++++
2 files changed, 120 insertions(+), 18 deletions(-)
diff --git a/devlink/devlink.c b/devlink/devlink.c
index ddf430bbb02a..9b234f2a6825 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c
@@ -294,6 +294,7 @@ static void ifname_map_free(struct ifname_map *ifname_map)
#define DL_OPT_PORT_FN_RATE_TX_MAX BIT(49)
#define DL_OPT_PORT_FN_RATE_NODE_NAME BIT(50)
#define DL_OPT_PORT_FN_RATE_PARENT BIT(51)
+#define DL_OPT_PORT_FN_RATE_LIMIT_TYPE BIT(52)
struct dl_opts {
uint64_t present; /* flags of present items */
@@ -354,6 +355,7 @@ struct dl_opts {
uint64_t rate_tx_max;
char *rate_node_name;
const char *rate_parent_node;
+ uint16_t rate_limit_type;
};
struct dl {
@@ -1438,6 +1440,17 @@ static int port_fn_rate_type_get(const char *typestr, uint16_t *type)
return 0;
}
+static int port_fn_rate_limit_type_get(const char *ltypestr, uint16_t *ltype)
+{
+ if (!strcmp(ltypestr, "unset"))
+ *ltype = DEVLINK_RATE_LIMIT_TYPE_UNSET;
+ else if (!strcmp(ltypestr, "shaping"))
+ *ltype = DEVLINK_RATE_LIMIT_TYPE_SHAPING;
+ else
+ return -EINVAL;
+ return 0;
+}
+
static int port_fn_rate_value_get(struct dl *dl, uint64_t *rate)
{
const char *ratestr;
@@ -1982,6 +1995,18 @@ static int dl_argv_parse(struct dl *dl, uint64_t o_required,
if (err)
return err;
o_found |= DL_OPT_PORT_FN_RATE_TYPE;
+ } else if (dl_argv_match(dl, "limit_type") &&
+ (o_all & DL_OPT_PORT_FN_RATE_LIMIT_TYPE)) {
+ const char *ltypestr;
+
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, <ypestr);
+ if (err)
+ return err;
+ err = port_fn_rate_limit_type_get(ltypestr, &opts->rate_limit_type);
+ if (err)
+ return err;
+ o_found |= DL_OPT_PORT_FN_RATE_LIMIT_TYPE;
} else if (dl_argv_match(dl, "tx_share") &&
(o_all & DL_OPT_PORT_FN_RATE_TX_SHARE)) {
dl_arg_inc(dl);
@@ -2212,6 +2237,9 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
if (opts->present & DL_OPT_PORT_FN_RATE_TYPE)
mnl_attr_put_u16(nlh, DEVLINK_ATTR_RATE_TYPE,
opts->rate_type);
+ if (opts->present & DL_OPT_PORT_FN_RATE_LIMIT_TYPE)
+ mnl_attr_put_u16(nlh, DEVLINK_ATTR_RATE_LIMIT_TYPE,
+ opts->rate_limit_type);
if (opts->present & DL_OPT_PORT_FN_RATE_TX_SHARE)
mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_SHARE,
opts->rate_tx_share);
@@ -4487,8 +4515,21 @@ static char *port_rate_type_name(uint16_t type)
}
}
+static char *port_rate_limit_type_name(uint16_t ltype)
+{
+ switch (ltype) {
+ case DEVLINK_RATE_LIMIT_TYPE_UNSET:
+ return "unset";
+ case DEVLINK_RATE_LIMIT_TYPE_SHAPING:
+ return "shaping";
+ default:
+ return "<unknown type>";
+ }
+}
+
static void pr_out_port_fn_rate(struct dl *dl, struct nlattr **tb)
{
+ uint16_t ltype = DEVLINK_RATE_LIMIT_TYPE_UNSET;
if (!tb[DEVLINK_ATTR_RATE_NODE_NAME])
pr_out_port_handle_start(dl, tb, false);
@@ -4503,7 +4544,14 @@ static void pr_out_port_fn_rate(struct dl *dl, struct nlattr **tb)
print_string(PRINT_ANY, "type", "type %s",
port_rate_type_name(type));
}
- if (tb[DEVLINK_ATTR_RATE_TX_SHARE]) {
+ if (tb[DEVLINK_ATTR_RATE_LIMIT_TYPE]) {
+ ltype = mnl_attr_get_u16(tb[DEVLINK_ATTR_RATE_LIMIT_TYPE]);
+
+ print_string(PRINT_ANY, "limit_type", " limit_type %s",
+ port_rate_limit_type_name(ltype));
+ }
+ if (tb[DEVLINK_ATTR_RATE_TX_SHARE] &&
+ ltype == DEVLINK_RATE_LIMIT_TYPE_SHAPING) {
uint64_t rate =
mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_SHARE]);
@@ -4550,10 +4598,10 @@ static void cmd_port_fn_rate_help(void)
pr_err("Usage: devlink port function rate help\n");
pr_err(" devlink port function rate show [ DEV/{ PORT_INDEX | NODE_NAME } ]\n");
pr_err(" devlink port function rate add DEV/NODE_NAME\n");
- pr_err(" [ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n");
+ pr_err(" [ limit_type shaping ][ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n");
pr_err(" devlink port function rate del DEV/NODE_NAME\n");
pr_err(" devlink port function rate set DEV/{ PORT_INDEX | NODE_NAME }\n");
- pr_err(" [ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n\n");
+ pr_err(" [ limit_type shaping ][ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n\n");
pr_err(" VAL - float or integer value in units of bits or bytes per second (bit|bps)\n");
pr_err(" and SI (k-, m-, g-, t-) or IEC (ki-, mi-, gi-, ti-) case-insensitive prefix.\n");
pr_err(" Bare number, means bits per second, is possible.\n\n");
@@ -4604,18 +4652,22 @@ static int port_fn_get_and_check_tx_rates(struct dl_opts *reply,
return port_fn_check_tx_rates(min, request->rate_tx_max);
}
-static int cmd_port_fn_rate_add(struct dl *dl)
+static int port_rate_shaping_add(struct dl *dl)
{
struct nlmsghdr *nlh;
int err;
+ if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
+ (dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
+ err = port_fn_check_tx_rates(dl->opts.rate_tx_share,
+ dl->opts.rate_tx_max);
+ if (err)
+ return err;
+ }
+
nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_NEW,
NLM_F_REQUEST | NLM_F_ACK);
- err = dl_argv_parse_put(nlh, dl, DL_OPT_PORT_FN_RATE_NODE_NAME,
- DL_OPT_PORT_FN_RATE_TX_SHARE |
- DL_OPT_PORT_FN_RATE_TX_MAX);
- if (err)
- return err;
+ dl_opts_put(nlh, dl);
if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
(dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
@@ -4628,6 +4680,27 @@ static int cmd_port_fn_rate_add(struct dl *dl)
return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
}
+#define RATE_SHAPING_OPTS (DL_OPT_PORT_FN_RATE_TX_SHARE)
+
+static int cmd_port_fn_rate_add(struct dl *dl)
+{
+ int err;
+
+ err = dl_argv_parse(dl, DL_OPT_PORT_FN_RATE_NODE_NAME,
+ DL_OPT_PORT_FN_RATE_LIMIT_TYPE | DL_OPT_PORT_FN_RATE_TX_MAX |
+ RATE_SHAPING_OPTS);
+ if (err)
+ return err;
+
+ if (!(dl->opts.present & DL_OPT_PORT_FN_RATE_LIMIT_TYPE)) {
+ dl->opts.rate_limit_type = DEVLINK_RATE_LIMIT_TYPE_SHAPING;
+ dl->opts.present |= DL_OPT_PORT_FN_RATE_LIMIT_TYPE;
+ }
+
+
+ return port_rate_shaping_add(dl);
+}
+
static int cmd_port_fn_rate_del(struct dl *dl)
{
struct nlmsghdr *nlh;
@@ -4664,20 +4737,12 @@ static int port_fn_get_rates_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_OK;
}
-static int cmd_port_fn_rate_set(struct dl *dl)
+static int port_rate_shaping_set(struct dl *dl)
{
struct dl_opts tmp_opts = {0};
struct nlmsghdr *nlh;
int err;
- err = dl_argv_parse(dl, DL_OPT_HANDLEP |
- DL_OPT_PORT_FN_RATE_NODE_NAME,
- DL_OPT_PORT_FN_RATE_TX_SHARE |
- DL_OPT_PORT_FN_RATE_TX_MAX |
- DL_OPT_PORT_FN_RATE_PARENT);
- if (err)
- return err;
-
if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
(dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
err = port_fn_check_tx_rates(dl->opts.rate_tx_share,
@@ -4709,6 +4774,26 @@ static int cmd_port_fn_rate_set(struct dl *dl)
return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
}
+static int cmd_port_fn_rate_set(struct dl *dl)
+{
+ int err;
+
+ err = dl_argv_parse(dl, DL_OPT_HANDLEP | DL_OPT_PORT_FN_RATE_NODE_NAME,
+ DL_OPT_PORT_FN_RATE_LIMIT_TYPE | DL_OPT_PORT_FN_RATE_TX_MAX |
+ RATE_SHAPING_OPTS | DL_OPT_PORT_FN_RATE_PARENT);
+ if (err)
+ return err;
+
+ if (!(dl->opts.present & DL_OPT_PORT_FN_RATE_LIMIT_TYPE) &&
+ !(dl->opts.present & DL_OPT_PORT_FN_RATE_PARENT)) {
+ dl->opts.rate_limit_type = DEVLINK_RATE_LIMIT_TYPE_SHAPING;
+ dl->opts.present |= DL_OPT_PORT_FN_RATE_LIMIT_TYPE;
+ }
+
+
+ return port_rate_shaping_set(dl);
+}
+
static int cmd_port_function_rate(struct dl *dl)
{
if (dl_argv_match(dl, "help")) {
diff --git a/man/man8/devlink-rate.8 b/man/man8/devlink-rate.8
index cc2f50c38619..6b7b179a8696 100644
--- a/man/man8/devlink-rate.8
+++ b/man/man8/devlink-rate.8
@@ -24,12 +24,16 @@ devlink-rate \- devlink rate management
.ti -8
.B devlink port function rate set
.RI "{ " DEV/PORT_INDEX " | " DEV/NODE_NAME " } "
+.RB "{"
+.RB [ " limit_type \fIshaping " ]
.RB [ " tx_share \fIVALUE " ]
.RB [ " tx_max \fIVALUE " ]
.RB "[ {" " parent \fINODE_NAME " | " noparent " "} ]"
.ti -8
.BI "devlink port function rate add " DEV/NODE_NAME
+.RB "{"
+.RB [ " limit_type \fIshaping " ]
.RB [ " tx_share \fIVALUE " ]
.RB [ " tx_max \fIVALUE " ]
.RB "[ {" " parent \fINODE_NAME " | " noparent " "} ]"
@@ -76,6 +80,19 @@ the last occurrence is used.
.I DEV/NODE_NAME
- specifies devlink node rate object.
.PP
+.BR limit_type " \fIshaping "
+- specifies a kind of rate limiting. The parameter is optional and, if omitted,
+\fIshaping\fR limit type is assumed by default. Each limit type has its own set
+of supported attributes. Some limit types may not be supported by a particular
+driver's implementation. At a high level, \fBlimit_type\fR definition is:
+.PP
+.I shaping
+- limiting traffic rate by using a back pressure mechanism, that can delay
+traffic until there is a capacity, available at the lower level, to process it.
+This type of rate limiting doesn't require packets to be dropped in order to
+ensure the requested rate, on the other hand it may suffer from excessive delays
+and it cannot be applied to inbound traffic.
+.PP
.BI tx_share " VALUE"
- specifies minimal tx rate value shared among all rate objects. If rate object
is a part of some rate group, then this value shared with rate objects of this
--
2.36.1
Powered by blists - more mailing lists