lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
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, &ltypestr);
+			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

Powered by Openwall GNU/*/Linux Powered by OpenVZ