Netdev List
 help / color / mirror / Atom feed
* [PATCH iproute2-next v3 0/6] netshaper: Extend netshaper support
@ 2026-05-11 18:39 Mohsin Bashir
  2026-05-11 18:39 ` [PATCH iproute2-next v3 1/6] netshaper: Extract parse_scope() and parse_rate() helpers Mohsin Bashir
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Mohsin Bashir @ 2026-05-11 18:39 UTC (permalink / raw)
  To: netdev; +Cc: dsahern, stephen, pabeni, kuba, ernis, mohsin.bashr,
	alexanderduyck

From: Mohsin Bashir <hmohsin@meta.com>

Changelog:
  Patch 5:
  - Fix JSON output corruption by replacing printf() with fprintf()

V2: https://lore.kernel.org/netdev/20260509022353.3470738-1-mohsin.bashr@gmail.com/ 
V1: https://lore.kernel.org/netdev/20260501011611.3533573-1-mohsin.bashr@gmail.com/

Mohsin Bashir (6):
  netshaper: Extract parse_scope() and parse_rate() helpers
  netshaper: Add bw-min and weight parameter support
  netshaper: Extend show output with parent, bw-min and weight
  netshaper: Extract struct shaper_args and parse_shaper_arg() helper
  netshaper: Add group command for creating scheduling hierarchies
  netshaper: Update man page for new parameters and group command

 include/utils.h       |   1 +
 man/man8/netshaper.8  | 140 ++++++++++--
 netshaper/netshaper.c | 487 ++++++++++++++++++++++++++++++++++--------
 3 files changed, 523 insertions(+), 105 deletions(-)

-- 
2.53.0-Meta


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH iproute2-next v3 1/6] netshaper: Extract parse_scope() and parse_rate() helpers
  2026-05-11 18:39 [PATCH iproute2-next v3 0/6] netshaper: Extend netshaper support Mohsin Bashir
@ 2026-05-11 18:39 ` Mohsin Bashir
  2026-05-11 18:39 ` [PATCH iproute2-next v3 2/6] netshaper: Add bw-min and weight parameter support Mohsin Bashir
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Mohsin Bashir @ 2026-05-11 18:39 UTC (permalink / raw)
  To: netdev
  Cc: dsahern, stephen, pabeni, kuba, ernis, mohsin.bashr,
	alexanderduyck, Claude Assistant

From: Mohsin Bashir <hmohsin@meta.com>

Add parse_scope() and parse_rate() helpers in preparation for
adding the group command which will need scope and rate parsing
at various places in the code. This patch will help to avoid
code duplication.

Verify that the tool works as before:
./netshaper set dev eth2 handle scope queue id 0 bw-max 100kbit
./netshaper delete dev eth2 handle scope queue id 0 bw-max 100kbit

Reviewed-by: Claude Assistant <noreply@anthropic.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Mohsin Bashir <hmohsin@meta.com>
---
 include/utils.h       |  1 +
 netshaper/netshaper.c | 63 ++++++++++++++++++++++---------------------
 2 files changed, 34 insertions(+), 30 deletions(-)

diff --git a/include/utils.h b/include/utils.h
index e4e318e2..f0d45bad 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -260,6 +260,7 @@ unsigned int print_name_and_link(const char *fmt,
 	__attribute__((format(printf, 1, 0)));
 
 
+#define BITS_PER_BYTE           8
 #define BIT(nr)                 (UINT64_C(1) << (nr))
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
diff --git a/netshaper/netshaper.c b/netshaper/netshaper.c
index 47fb805e..f90ceb11 100644
--- a/netshaper/netshaper.c
+++ b/netshaper/netshaper.c
@@ -47,6 +47,26 @@ static const char *net_shaper_scope_names[NET_SHAPER_SCOPE_MAX + 1] = {
 	"node"
 };
 
+static int parse_scope(const char *str)
+{
+	for (int i = 1; i <= NET_SHAPER_SCOPE_MAX; i++) {
+		if (strcmp(str, net_shaper_scope_names[i]) == 0)
+			return i;
+	}
+	return -1;
+}
+
+static int parse_rate(const char *str, __u64 *rate_bps)
+{
+	if (get_rate64(rate_bps, str)) {
+		fprintf(stderr, "Invalid rate value \"%s\"\n", str);
+		return -1;
+	}
+	/* get_rate64 returns bytes/sec, convert to bits/sec */
+	*rate_bps *= BITS_PER_BYTE;
+	return 0;
+}
+
 static void print_netshaper_attrs(struct nlmsghdr *answer)
 {
 	struct genlmsghdr *ghdr = NLMSG_DATA(answer);
@@ -117,12 +137,8 @@ static int do_cmd(int argc, char **argv, int cmd)
 			ifindex = ll_name_to_index(*argv);
 		} else if (strcmp(*argv, "bw-max") == 0) {
 			NEXT_ARG();
-			if (get_rate64(&bw_max_bps, *argv)) {
-				fprintf(stderr, "Invalid bw-max value\n");
+			if (parse_rate(*argv, &bw_max_bps))
 				return -1;
-			}
-			/* Convert Bps to bps */
-			bw_max_bps *= 8;
 		} else if (strcmp(*argv, "handle") == 0) {
 			handle_present = true;
 			NEXT_ARG();
@@ -134,34 +150,24 @@ static int do_cmd(int argc, char **argv, int cmd)
 			}
 			NEXT_ARG();
 
-			if (strcmp(*argv, "netdev") == 0) {
-				handle_scope = NET_SHAPER_SCOPE_NETDEV;
-				/* For netdev scope, id is optional - check if next arg is "id" */
+			handle_scope = parse_scope(*argv);
+			if (handle_scope < 0) {
+				fprintf(stderr, "Invalid scope \"%s\"\n", *argv);
+				return -1;
+			}
+
+			if (handle_scope == NET_SHAPER_SCOPE_NETDEV) {
+				/* For netdev scope, id is optional */
 				if (argc > 1 && strcmp(argv[1], "id") == 0) {
-					NEXT_ARG(); /* move to "id" */
-					NEXT_ARG(); /* move to id value */
+					NEXT_ARG();
+					NEXT_ARG();
 					if (get_unsigned(&handle_id, *argv, 10)) {
 						fprintf(stderr, "Invalid handle id\n");
 						return -1;
 					}
 				}
-			} else if (strcmp(*argv, "queue") == 0) {
-				handle_scope = NET_SHAPER_SCOPE_QUEUE;
-				/* For queue scope, id is required */
-				NEXT_ARG();
-				if (strcmp(*argv, "id") != 0) {
-					fprintf(stderr, "What is \"%s\"\n", *argv);
-					usage();
-					return -1;
-				}
-				NEXT_ARG();
-				if (get_unsigned(&handle_id, *argv, 10)) {
-					fprintf(stderr, "Invalid handle id\n");
-					return -1;
-				}
-			} else if (strcmp(*argv, "node") == 0) {
-				handle_scope = NET_SHAPER_SCOPE_NODE;
-				/* For node scope, id is required */
+			} else {
+				/* For queue/node scope, id is required */
 				NEXT_ARG();
 				if (strcmp(*argv, "id") != 0) {
 					fprintf(stderr, "What is \"%s\"\n", *argv);
@@ -173,9 +179,6 @@ static int do_cmd(int argc, char **argv, int cmd)
 					fprintf(stderr, "Invalid handle id\n");
 					return -1;
 				}
-			} else {
-				fprintf(stderr, "Invalid scope\n");
-				return -1;
 			}
 		} else {
 			fprintf(stderr, "What is \"%s\"\n", *argv);
-- 
2.53.0-Meta


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH iproute2-next v3 2/6] netshaper: Add bw-min and weight parameter support
  2026-05-11 18:39 [PATCH iproute2-next v3 0/6] netshaper: Extend netshaper support Mohsin Bashir
  2026-05-11 18:39 ` [PATCH iproute2-next v3 1/6] netshaper: Extract parse_scope() and parse_rate() helpers Mohsin Bashir
@ 2026-05-11 18:39 ` Mohsin Bashir
  2026-05-11 18:39 ` [PATCH iproute2-next v3 3/6] netshaper: Extend show output with parent, bw-min and weight Mohsin Bashir
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Mohsin Bashir @ 2026-05-11 18:39 UTC (permalink / raw)
  To: netdev
  Cc: dsahern, stephen, pabeni, kuba, ernis, mohsin.bashr,
	alexanderduyck, Claude Assistant

From: Mohsin Bashir <hmohsin@meta.com>

Add bw-min and weight parameters to the set command. Previously
only bw-max was supported. Use boolean flags (has_bw_min,
has_bw_max, has_weight) to track which parameters were provided,
so that zero-valued attrs like bw-max 0 are correctly sent.
Only emit rate and weight attrs for the set command. Add device
name validation and only send handle id when explicitly provided.
Update usage text to reflect the new parameters.

Reviewed-by: Claude Assistant <noreply@anthropic.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Mohsin Bashir <hmohsin@meta.com>
---
 netshaper/netshaper.c | 59 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 47 insertions(+), 12 deletions(-)

diff --git a/netshaper/netshaper.c b/netshaper/netshaper.c
index f90ceb11..186076a1 100644
--- a/netshaper/netshaper.c
+++ b/netshaper/netshaper.c
@@ -33,11 +33,13 @@ static void usage(void)
 		"OPTIONS := { -V[ersion] | -c[olor] | -help }\n"
 		"COMMAND := { set | get | delete } dev DEVNAME\n"
 		"	    handle scope HANDLE_SCOPE [id HANDLE_ID]\n"
-		"	    [bw-max BW_MAX]\n"
+		"	    [bw-min BW_MIN] [bw-max BW_MAX] [weight WEIGHT]\n"
+		"\n"
 		"Where: DEVNAME         := STRING\n"
 		"       HANDLE_SCOPE    := { netdev | queue | node }\n"
 		"       HANDLE_ID       := UINT (required for queue/node, optional for netdev)\n"
-		"       BW_MAX          := UINT{ kbit | mbit | gbit }\n");
+		"       BW_MAX/BW_MIN   := UINT{ kbit | mbit | gbit }\n"
+		"       WEIGHT          := UINT\n");
 }
 
 static const char *net_shaper_scope_names[NET_SHAPER_SCOPE_MAX + 1] = {
@@ -123,22 +125,40 @@ static int do_cmd(int argc, char **argv, int cmd)
 	GENL_REQUEST(req, 1024, genl_family, 0, NET_SHAPER_FAMILY_VERSION, cmd,
 		     NLM_F_REQUEST | NLM_F_ACK);
 
-	struct nlmsghdr *answer;
-	__u64 bw_max_bps = 0;
-	int ifindex = -1;
+	bool has_bw_min = false, has_bw_max = false, has_weight = false;
 	int handle_scope = NET_SHAPER_SCOPE_UNSPEC;
-	__u32 handle_id = 0;
+	__u64 bw_min_bps = 0, bw_max_bps = 0;
+	__u32 handle_id = 0, weight = 0;
 	bool handle_present = false;
-	int err;
+	bool has_handle_id = false;
+	struct nlmsghdr *answer;
+	int err, ifindex = -1;
 
 	while (argc > 0) {
 		if (strcmp(*argv, "dev") == 0) {
 			NEXT_ARG();
 			ifindex = ll_name_to_index(*argv);
+			if (ifindex == 0) {
+				fprintf(stderr, "Device \"%s\" not found\n", *argv);
+				return -1;
+			}
+		} else if (strcmp(*argv, "bw-min") == 0) {
+			NEXT_ARG();
+			if (parse_rate(*argv, &bw_min_bps))
+				return -1;
+			has_bw_min = true;
 		} else if (strcmp(*argv, "bw-max") == 0) {
 			NEXT_ARG();
 			if (parse_rate(*argv, &bw_max_bps))
 				return -1;
+			has_bw_max = true;
+		} else if (strcmp(*argv, "weight") == 0) {
+			NEXT_ARG();
+			if (get_unsigned(&weight, *argv, 10)) {
+				fprintf(stderr, "Invalid weight value\n");
+				return -1;
+			}
+			has_weight = true;
 		} else if (strcmp(*argv, "handle") == 0) {
 			handle_present = true;
 			NEXT_ARG();
@@ -165,6 +185,7 @@ static int do_cmd(int argc, char **argv, int cmd)
 						fprintf(stderr, "Invalid handle id\n");
 						return -1;
 					}
+					has_handle_id = true;
 				}
 			} else {
 				/* For queue/node scope, id is required */
@@ -179,6 +200,7 @@ static int do_cmd(int argc, char **argv, int cmd)
 					fprintf(stderr, "Invalid handle id\n");
 					return -1;
 				}
+				has_handle_id = true;
 			}
 		} else {
 			fprintf(stderr, "What is \"%s\"\n", *argv);
@@ -195,19 +217,32 @@ static int do_cmd(int argc, char **argv, int cmd)
 	if (!handle_present)
 		missarg("handle");
 
-	if (cmd == NET_SHAPER_CMD_SET && bw_max_bps == 0)
-		missarg("bw-max");
+	if (cmd == NET_SHAPER_CMD_SET && !has_bw_min && !has_bw_max && !has_weight)
+		missarg("bw-min, bw-max, or weight");
 
 	addattr32(&req.n, sizeof(req), NET_SHAPER_A_IFINDEX, ifindex);
 
 	struct rtattr *handle = addattr_nest(&req.n, sizeof(req),
 					     NET_SHAPER_A_HANDLE | NLA_F_NESTED);
 	addattr32(&req.n, sizeof(req), NET_SHAPER_A_HANDLE_SCOPE, handle_scope);
-	addattr32(&req.n, sizeof(req), NET_SHAPER_A_HANDLE_ID, handle_id);
+	if (has_handle_id)
+		addattr32(&req.n, sizeof(req), NET_SHAPER_A_HANDLE_ID, handle_id);
 	addattr_nest_end(&req.n, handle);
 
-	if (cmd == NET_SHAPER_CMD_SET)
-		addattr64(&req.n, sizeof(req), NET_SHAPER_A_BW_MAX, bw_max_bps);
+	if (cmd == NET_SHAPER_CMD_SET) {
+		if (has_bw_min)
+			addattr64(&req.n, sizeof(req), NET_SHAPER_A_BW_MIN,
+				  bw_min_bps);
+		if (has_bw_max)
+			addattr64(&req.n, sizeof(req), NET_SHAPER_A_BW_MAX,
+				  bw_max_bps);
+		if (has_weight)
+			addattr32(&req.n, sizeof(req), NET_SHAPER_A_WEIGHT,
+				  weight);
+		if (has_bw_min || has_bw_max)
+			addattr32(&req.n, sizeof(req), NET_SHAPER_A_METRIC,
+				  NET_SHAPER_METRIC_BPS);
+	}
 
 	err = rtnl_talk(&gen_rth, &req.n, &answer);
 	if (err < 0) {
-- 
2.53.0-Meta


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH iproute2-next v3 3/6] netshaper: Extend show output with parent, bw-min and weight
  2026-05-11 18:39 [PATCH iproute2-next v3 0/6] netshaper: Extend netshaper support Mohsin Bashir
  2026-05-11 18:39 ` [PATCH iproute2-next v3 1/6] netshaper: Extract parse_scope() and parse_rate() helpers Mohsin Bashir
  2026-05-11 18:39 ` [PATCH iproute2-next v3 2/6] netshaper: Add bw-min and weight parameter support Mohsin Bashir
@ 2026-05-11 18:39 ` Mohsin Bashir
  2026-05-11 18:39 ` [PATCH iproute2-next v3 4/6] netshaper: Extract struct shaper_args and parse_shaper_arg() helper Mohsin Bashir
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Mohsin Bashir @ 2026-05-11 18:39 UTC (permalink / raw)
  To: netdev
  Cc: dsahern, stephen, pabeni, kuba, ernis, mohsin.bashr,
	alexanderduyck, Claude Assistant

From: Mohsin Bashir <hmohsin@meta.com>

Extend print_netshaper_attrs() to display parent scope/id, bw-min,
and weight fields in the show output. Replace the switch-based
iteration with direct attribute checks for cleaner output formatting.
Use print_rate() for bandwidth display so that sub-Mbps rates
like 100kbit render correctly instead of truncating to 0 mbps.

Reviewed-by: Claude Assistant <noreply@anthropic.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Mohsin Bashir <hmohsin@meta.com>
---
 netshaper/netshaper.c | 100 +++++++++++++++++++++++++++---------------
 1 file changed, 65 insertions(+), 35 deletions(-)

diff --git a/netshaper/netshaper.c b/netshaper/netshaper.c
index 186076a1..83bfd2f6 100644
--- a/netshaper/netshaper.c
+++ b/netshaper/netshaper.c
@@ -71,53 +71,83 @@ static int parse_rate(const char *str, __u64 *rate_bps)
 
 static void print_netshaper_attrs(struct nlmsghdr *answer)
 {
-	struct genlmsghdr *ghdr = NLMSG_DATA(answer);
+	struct rtattr *handle_tb[NET_SHAPER_A_HANDLE_MAX + 1] = {};
+	struct rtattr *parent_tb[NET_SHAPER_A_HANDLE_MAX + 1] = {};
 	int len = answer->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
+	struct genlmsghdr *ghdr = NLMSG_DATA(answer);
 	struct rtattr *tb[NET_SHAPER_A_MAX + 1] = {};
-	struct rtattr *handle_tb[NET_SHAPER_A_HANDLE_MAX + 1] = {};
-	__u32 bw_max_mbps, scope, id;
-	__u64 bw_max_bps;
+	__u32 scope, id;
 	int ifindex;
 
 	parse_rtattr_flags(tb, NET_SHAPER_A_MAX,
 			   (struct rtattr *)((char *)ghdr + GENL_HDRLEN),
 			   len, NLA_F_NESTED);
 
-	for (int i = 1; i <= NET_SHAPER_A_MAX; ++i) {
-		if (!tb[i])
-			continue;
-		switch (i) {
-		case NET_SHAPER_A_BW_MAX:
-			bw_max_bps = rta_getattr_uint(tb[i]);
-			bw_max_mbps = (bw_max_bps / 1000000);
+	if (tb[NET_SHAPER_A_IFINDEX]) {
+		ifindex = rta_getattr_u32(tb[NET_SHAPER_A_IFINDEX]);
+		print_color_string(PRINT_ANY, COLOR_IFNAME, "dev",
+				   "dev: %s ", ll_index_to_name(ifindex));
+	}
 
-			print_uint(PRINT_ANY, "bw-max", "bw-max: %u mbps\n",
-				   bw_max_mbps);
-			break;
-		case NET_SHAPER_A_IFINDEX:
-			ifindex = rta_getattr_u32(tb[i]);
-			print_color_string(PRINT_ANY, COLOR_IFNAME, "dev",
-					   "dev: %s\n",
-					   ll_index_to_name(ifindex));
-			break;
-		case NET_SHAPER_A_HANDLE:
-			parse_rtattr_nested(handle_tb, NET_SHAPER_A_HANDLE_MAX,
-					    tb[NET_SHAPER_A_HANDLE]);
-			if (handle_tb[NET_SHAPER_A_HANDLE_SCOPE]) {
-				scope = rta_getattr_u32(handle_tb[NET_SHAPER_A_HANDLE_SCOPE]);
-				print_string(PRINT_ANY, "scope",
-					     "scope: %s\n",
+	if (tb[NET_SHAPER_A_HANDLE]) {
+		parse_rtattr_nested(handle_tb, NET_SHAPER_A_HANDLE_MAX,
+				    tb[NET_SHAPER_A_HANDLE]);
+		if (handle_tb[NET_SHAPER_A_HANDLE_SCOPE]) {
+			scope = rta_getattr_u32(handle_tb[NET_SHAPER_A_HANDLE_SCOPE]);
+			if (scope <= NET_SHAPER_SCOPE_MAX)
+				print_string(PRINT_ANY, "scope", "scope %s ",
 					     net_shaper_scope_names[scope]);
-			}
-			if (handle_tb[NET_SHAPER_A_HANDLE_ID]) {
-				id = rta_getattr_u32(handle_tb[NET_SHAPER_A_HANDLE_ID]);
-				print_uint(PRINT_ANY, "id", "id: %u\n", id);
-			}
-			break;
-		default:
-			break;
+			else
+				print_uint(PRINT_ANY, "scope", "scope %u ", scope);
+		}
+		if (handle_tb[NET_SHAPER_A_HANDLE_ID]) {
+			id = rta_getattr_u32(handle_tb[NET_SHAPER_A_HANDLE_ID]);
+			print_uint(PRINT_ANY, "id", "id %u ", id);
 		}
 	}
+
+	if (tb[NET_SHAPER_A_PARENT]) {
+		parse_rtattr_nested(parent_tb, NET_SHAPER_A_HANDLE_MAX,
+				    tb[NET_SHAPER_A_PARENT]);
+		if (parent_tb[NET_SHAPER_A_HANDLE_SCOPE]) {
+			scope = rta_getattr_u32(parent_tb[NET_SHAPER_A_HANDLE_SCOPE]);
+			if (scope <= NET_SHAPER_SCOPE_MAX)
+				print_string(PRINT_ANY, "parent-scope",
+					     "parent scope %s ",
+					     net_shaper_scope_names[scope]);
+			else
+				print_uint(PRINT_ANY, "parent-scope",
+					   "parent scope %u ", scope);
+		}
+		if (parent_tb[NET_SHAPER_A_HANDLE_ID]) {
+			id = rta_getattr_u32(parent_tb[NET_SHAPER_A_HANDLE_ID]);
+			print_uint(PRINT_ANY, "parent-id", "id %u ", id);
+		}
+	}
+
+	if (tb[NET_SHAPER_A_BW_MAX]) {
+		__u64 bw = rta_getattr_uint(tb[NET_SHAPER_A_BW_MAX]);
+
+		print_string(PRINT_FP, NULL, "bw-max ", NULL);
+		print_rate(false, PRINT_ANY, "bw-max", "%s ",
+			   bw / BITS_PER_BYTE);
+	}
+
+	if (tb[NET_SHAPER_A_BW_MIN]) {
+		__u64 bw = rta_getattr_uint(tb[NET_SHAPER_A_BW_MIN]);
+
+		print_string(PRINT_FP, NULL, "bw-min ", NULL);
+		print_rate(false, PRINT_ANY, "bw-min", "%s ",
+			   bw / BITS_PER_BYTE);
+	}
+
+	if (tb[NET_SHAPER_A_WEIGHT]) {
+		__u32 weight = rta_getattr_u32(tb[NET_SHAPER_A_WEIGHT]);
+
+		print_uint(PRINT_ANY, "weight", "weight %u ", weight);
+	}
+
+	print_nl();
 }
 
 static int do_cmd(int argc, char **argv, int cmd)
-- 
2.53.0-Meta


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH iproute2-next v3 4/6] netshaper: Extract struct shaper_args and parse_shaper_arg() helper
  2026-05-11 18:39 [PATCH iproute2-next v3 0/6] netshaper: Extend netshaper support Mohsin Bashir
                   ` (2 preceding siblings ...)
  2026-05-11 18:39 ` [PATCH iproute2-next v3 3/6] netshaper: Extend show output with parent, bw-min and weight Mohsin Bashir
@ 2026-05-11 18:39 ` Mohsin Bashir
  2026-05-11 18:39 ` [PATCH iproute2-next v3 5/6] netshaper: Add group command for creating scheduling hierarchies Mohsin Bashir
  2026-05-11 18:39 ` [PATCH iproute2-next v3 6/6] netshaper: Update man page for new parameters and group command Mohsin Bashir
  5 siblings, 0 replies; 7+ messages in thread
From: Mohsin Bashir @ 2026-05-11 18:39 UTC (permalink / raw)
  To: netdev
  Cc: dsahern, stephen, pabeni, kuba, ernis, mohsin.bashr,
	alexanderduyck, Claude Assistant

From: Mohsin Bashir <hmohsin@meta.com>

Extract common shaper parameters (dev, bw-min, bw-max, weight) into
struct shaper_args and add parse_shaper_arg() to parse them. This
avoids duplicating argument parsing when the group command is added
in the next patch.

Reviewed-by: Claude Assistant <noreply@anthropic.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Mohsin Bashir <hmohsin@meta.com>
---
 netshaper/netshaper.c | 111 +++++++++++++++++++++++++++---------------
 1 file changed, 72 insertions(+), 39 deletions(-)

diff --git a/netshaper/netshaper.c b/netshaper/netshaper.c
index 83bfd2f6..9ccd09f4 100644
--- a/netshaper/netshaper.c
+++ b/netshaper/netshaper.c
@@ -69,6 +69,54 @@ static int parse_rate(const char *str, __u64 *rate_bps)
 	return 0;
 }
 
+struct shaper_args {
+	__u64 bw_min_bps, bw_max_bps;
+	__u32 weight;
+	bool has_bw_min, has_bw_max, has_weight;
+	int ifindex;
+};
+
+#define SHAPER_ARGS_INIT { .ifindex = -1 }
+
+static int parse_shaper_arg(const char *key, int *argcp, char ***argvp,
+			    struct shaper_args *args)
+{
+	int argc = *argcp;
+	char **argv = *argvp;
+
+	if (strcmp(key, "dev") == 0) {
+		NEXT_ARG();
+		args->ifindex = ll_name_to_index(*argv);
+		if (args->ifindex == 0) {
+			fprintf(stderr, "Device \"%s\" not found\n", *argv);
+			return -1;
+		}
+	} else if (strcmp(key, "bw-min") == 0) {
+		NEXT_ARG();
+		if (parse_rate(*argv, &args->bw_min_bps))
+			return -1;
+		args->has_bw_min = true;
+	} else if (strcmp(key, "bw-max") == 0) {
+		NEXT_ARG();
+		if (parse_rate(*argv, &args->bw_max_bps))
+			return -1;
+		args->has_bw_max = true;
+	} else if (strcmp(key, "weight") == 0) {
+		NEXT_ARG();
+		if (get_unsigned(&args->weight, *argv, 10)) {
+			fprintf(stderr, "Invalid weight value\n");
+			return -1;
+		}
+		args->has_weight = true;
+	} else {
+		return 0;
+	}
+
+	*argcp = argc;
+	*argvp = argv;
+	return 1;
+}
+
 static void print_netshaper_attrs(struct nlmsghdr *answer)
 {
 	struct rtattr *handle_tb[NET_SHAPER_A_HANDLE_MAX + 1] = {};
@@ -155,41 +203,25 @@ static int do_cmd(int argc, char **argv, int cmd)
 	GENL_REQUEST(req, 1024, genl_family, 0, NET_SHAPER_FAMILY_VERSION, cmd,
 		     NLM_F_REQUEST | NLM_F_ACK);
 
-	bool has_bw_min = false, has_bw_max = false, has_weight = false;
+	struct shaper_args args = SHAPER_ARGS_INIT;
 	int handle_scope = NET_SHAPER_SCOPE_UNSPEC;
-	__u64 bw_min_bps = 0, bw_max_bps = 0;
-	__u32 handle_id = 0, weight = 0;
 	bool handle_present = false;
 	bool has_handle_id = false;
 	struct nlmsghdr *answer;
-	int err, ifindex = -1;
+	__u32 handle_id = 0;
+	int err, ret;
 
 	while (argc > 0) {
-		if (strcmp(*argv, "dev") == 0) {
-			NEXT_ARG();
-			ifindex = ll_name_to_index(*argv);
-			if (ifindex == 0) {
-				fprintf(stderr, "Device \"%s\" not found\n", *argv);
-				return -1;
-			}
-		} else if (strcmp(*argv, "bw-min") == 0) {
-			NEXT_ARG();
-			if (parse_rate(*argv, &bw_min_bps))
-				return -1;
-			has_bw_min = true;
-		} else if (strcmp(*argv, "bw-max") == 0) {
-			NEXT_ARG();
-			if (parse_rate(*argv, &bw_max_bps))
-				return -1;
-			has_bw_max = true;
-		} else if (strcmp(*argv, "weight") == 0) {
-			NEXT_ARG();
-			if (get_unsigned(&weight, *argv, 10)) {
-				fprintf(stderr, "Invalid weight value\n");
-				return -1;
-			}
-			has_weight = true;
-		} else if (strcmp(*argv, "handle") == 0) {
+		ret = parse_shaper_arg(*argv, &argc, &argv, &args);
+		if (ret < 0)
+			return -1;
+		if (ret > 0) {
+			argc--;
+			argv++;
+			continue;
+		}
+
+		if (strcmp(*argv, "handle") == 0) {
 			handle_present = true;
 			NEXT_ARG();
 
@@ -241,16 +273,17 @@ static int do_cmd(int argc, char **argv, int cmd)
 		argv++;
 	}
 
-	if (ifindex == -1)
+	if (args.ifindex == -1)
 		missarg("dev");
 
 	if (!handle_present)
 		missarg("handle");
 
-	if (cmd == NET_SHAPER_CMD_SET && !has_bw_min && !has_bw_max && !has_weight)
+	if (cmd == NET_SHAPER_CMD_SET &&
+	    !args.has_bw_min && !args.has_bw_max && !args.has_weight)
 		missarg("bw-min, bw-max, or weight");
 
-	addattr32(&req.n, sizeof(req), NET_SHAPER_A_IFINDEX, ifindex);
+	addattr32(&req.n, sizeof(req), NET_SHAPER_A_IFINDEX, args.ifindex);
 
 	struct rtattr *handle = addattr_nest(&req.n, sizeof(req),
 					     NET_SHAPER_A_HANDLE | NLA_F_NESTED);
@@ -260,16 +293,16 @@ static int do_cmd(int argc, char **argv, int cmd)
 	addattr_nest_end(&req.n, handle);
 
 	if (cmd == NET_SHAPER_CMD_SET) {
-		if (has_bw_min)
+		if (args.has_bw_min)
 			addattr64(&req.n, sizeof(req), NET_SHAPER_A_BW_MIN,
-				  bw_min_bps);
-		if (has_bw_max)
+				  args.bw_min_bps);
+		if (args.has_bw_max)
 			addattr64(&req.n, sizeof(req), NET_SHAPER_A_BW_MAX,
-				  bw_max_bps);
-		if (has_weight)
+				  args.bw_max_bps);
+		if (args.has_weight)
 			addattr32(&req.n, sizeof(req), NET_SHAPER_A_WEIGHT,
-				  weight);
-		if (has_bw_min || has_bw_max)
+				  args.weight);
+		if (args.has_bw_min || args.has_bw_max)
 			addattr32(&req.n, sizeof(req), NET_SHAPER_A_METRIC,
 				  NET_SHAPER_METRIC_BPS);
 	}
-- 
2.53.0-Meta


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH iproute2-next v3 5/6] netshaper: Add group command for creating scheduling hierarchies
  2026-05-11 18:39 [PATCH iproute2-next v3 0/6] netshaper: Extend netshaper support Mohsin Bashir
                   ` (3 preceding siblings ...)
  2026-05-11 18:39 ` [PATCH iproute2-next v3 4/6] netshaper: Extract struct shaper_args and parse_shaper_arg() helper Mohsin Bashir
@ 2026-05-11 18:39 ` Mohsin Bashir
  2026-05-11 18:39 ` [PATCH iproute2-next v3 6/6] netshaper: Update man page for new parameters and group command Mohsin Bashir
  5 siblings, 0 replies; 7+ messages in thread
From: Mohsin Bashir @ 2026-05-11 18:39 UTC (permalink / raw)
  To: netdev
  Cc: dsahern, stephen, pabeni, kuba, ernis, mohsin.bashr,
	alexanderduyck, Claude Assistant

From: Mohsin Bashir <hmohsin@meta.com>

Add the group command to create and update scheduling groups via the
NET_SHAPER_CMD_GROUP netlink operation. This enables building shaper
hierarchies by specifying a node handle, parent scope, rate parameters,
and a set of queue leaf shapers to attach.

The group command allows the node handle id to be omitted, letting
the kernel auto-assign one for new nodes. Only queue scope is
accepted for leaf shapers. Group handle and parent scopes are
validated to accept only node or netdev. Parent node scope
requires an explicit id since it must reference an existing node.

Common argument parsing (dev, bw-min, bw-max, weight) reuses the
parse_shaper_arg() helper introduced in the previous patch.

Example usage:
  netshaper group dev foo handle scope node parent scope netdev \
      bw-max 1gbit leaves scope queue id 0 scope queue id 1

Reviewed-by: Claude Assistant <noreply@anthropic.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Mohsin Bashir <hmohsin@meta.com>
---
 netshaper/netshaper.c | 220 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 219 insertions(+), 1 deletion(-)

diff --git a/netshaper/netshaper.c b/netshaper/netshaper.c
index 9ccd09f4..4519eb5d 100644
--- a/netshaper/netshaper.c
+++ b/netshaper/netshaper.c
@@ -31,10 +31,15 @@ static void usage(void)
 	fprintf(stderr,
 		"Usage: netshaper [ OPTIONS ] { COMMAND | help }\n"
 		"OPTIONS := { -V[ersion] | -c[olor] | -help }\n"
-		"COMMAND := { set | get | delete } dev DEVNAME\n"
+		"COMMAND := { set | get | delete | group } dev DEVNAME\n"
 		"	    handle scope HANDLE_SCOPE [id HANDLE_ID]\n"
 		"	    [bw-min BW_MIN] [bw-max BW_MAX] [weight WEIGHT]\n"
 		"\n"
+		"netshaper group dev DEVNAME handle scope SCOPE [ id ID ]\n"
+		"          parent scope SCOPE [ id ID ]\n"
+		"          [ bw-min BW ] [ bw-max BW ] [ weight WEIGHT ]\n"
+		"          leaves { scope SCOPE id ID } [ ... ]\n"
+		"\n"
 		"Where: DEVNAME         := STRING\n"
 		"       HANDLE_SCOPE    := { netdev | queue | node }\n"
 		"       HANDLE_ID       := UINT (required for queue/node, optional for netdev)\n"
@@ -319,6 +324,217 @@ static int do_cmd(int argc, char **argv, int cmd)
 	return err;
 }
 
+#define NET_SHAPER_MAX_LEAVES	256
+
+static int do_group(int argc, char **argv)
+{
+	GENL_REQUEST(req, 4096, genl_family, 0, NET_SHAPER_FAMILY_VERSION,
+		     NET_SHAPER_CMD_GROUP, NLM_F_REQUEST | NLM_F_ACK);
+
+	struct shaper_args args = SHAPER_ARGS_INIT;
+	bool parsing_leaves = false, has_handle_id = false, has_parent_id = false;
+	int parent_scope = -1, num_leaves = 0;
+	int err, ret, handle_scope = NET_SHAPER_SCOPE_UNSPEC;
+	__u32 handle_id = 0, parent_id = 0;
+	struct nlmsghdr *answer;
+
+	struct {
+		int scope;
+		__u32 id;
+	} leaves[NET_SHAPER_MAX_LEAVES];
+
+	while (argc > 0) {
+		if (parsing_leaves) {
+			if (strcmp(*argv, "scope") == 0) {
+				int lscope;
+
+				NEXT_ARG();
+				lscope = parse_scope(*argv);
+				if (lscope < 0) {
+					fprintf(stderr, "Invalid leaf scope \"%s\"\n",
+						*argv);
+					return -1;
+				}
+				NEXT_ARG();
+				if (strcmp(*argv, "id") != 0) {
+					fprintf(stderr, "Expected \"id\" after leaf scope\n");
+					return -1;
+				}
+
+				NEXT_ARG();
+				if (num_leaves >= ARRAY_SIZE(leaves)) {
+					fprintf(stderr, "Too many leaves\n");
+					return -1;
+				}
+				leaves[num_leaves].scope = lscope;
+				if (get_unsigned(&leaves[num_leaves].id, *argv, 10)) {
+					fprintf(stderr, "Invalid leaf id\n");
+					return -1;
+				}
+				num_leaves++;
+				argc--;
+				argv++;
+				continue;
+			}
+			parsing_leaves = false;
+		}
+
+		ret = parse_shaper_arg(*argv, &argc, &argv, &args);
+		if (ret < 0)
+			return -1;
+		if (ret > 0) {
+			argc--;
+			argv++;
+			continue;
+		}
+
+		if (strcmp(*argv, "handle") == 0) {
+			NEXT_ARG();
+			if (strcmp(*argv, "scope") != 0) {
+				fprintf(stderr, "Expected \"scope\" after \"handle\"\n");
+				return -1;
+			}
+			NEXT_ARG();
+			handle_scope = parse_scope(*argv);
+			if (handle_scope < 0) {
+				fprintf(stderr, "Invalid handle scope \"%s\"\n",
+					*argv);
+				return -1;
+			}
+			if (handle_scope != NET_SHAPER_SCOPE_NODE &&
+			    handle_scope != NET_SHAPER_SCOPE_NETDEV) {
+				fprintf(stderr, "Group handle scope must be \"node\" or \"netdev\"\n");
+				return -1;
+			}
+
+			if (argc > 1 && strcmp(argv[1], "id") == 0) {
+				NEXT_ARG();
+				NEXT_ARG();
+				if (get_unsigned(&handle_id, *argv, 10)) {
+					fprintf(stderr, "Invalid handle id\n");
+					return -1;
+				}
+				has_handle_id = true;
+			}
+		} else if (strcmp(*argv, "parent") == 0) {
+			NEXT_ARG();
+			if (strcmp(*argv, "scope") != 0) {
+				fprintf(stderr, "Expected \"scope\" after \"parent\"\n");
+				return -1;
+			}
+			NEXT_ARG();
+			parent_scope = parse_scope(*argv);
+			if (parent_scope < 0) {
+				fprintf(stderr, "Invalid parent scope \"%s\"\n",
+					*argv);
+				return -1;
+			}
+			if (parent_scope != NET_SHAPER_SCOPE_NODE &&
+			    parent_scope != NET_SHAPER_SCOPE_NETDEV) {
+				fprintf(stderr, "Parent scope must be \"node\" or \"netdev\"\n");
+				return -1;
+			}
+
+			if (parent_scope == NET_SHAPER_SCOPE_NODE) {
+				NEXT_ARG();
+				if (strcmp(*argv, "id") != 0) {
+					fprintf(stderr, "What is \"%s\"\n", *argv);
+					usage();
+					return -1;
+				}
+				NEXT_ARG();
+				if (get_unsigned(&parent_id, *argv, 10)) {
+					fprintf(stderr, "Invalid parent id\n");
+					return -1;
+				}
+				has_parent_id = true;
+			} else if (argc > 1 && strcmp(argv[1], "id") == 0) {
+				NEXT_ARG();
+				NEXT_ARG();
+				if (get_unsigned(&parent_id, *argv, 10)) {
+					fprintf(stderr, "Invalid parent id\n");
+					return -1;
+				}
+				has_parent_id = true;
+			}
+		} else if (strcmp(*argv, "leaves") == 0) {
+			parsing_leaves = true;
+			argc--;
+			argv++;
+			continue;
+		} else {
+			fprintf(stderr, "What is \"%s\"\n", *argv);
+			usage();
+			return -1;
+		}
+		argc--;
+		argv++;
+	}
+
+	if (args.ifindex == -1)
+		missarg("dev");
+	if (handle_scope == NET_SHAPER_SCOPE_UNSPEC)
+		missarg("handle");
+	if (parent_scope < 0)
+		missarg("parent");
+	if (num_leaves == 0)
+		missarg("leaves");
+
+	addattr32(&req.n, sizeof(req), NET_SHAPER_A_IFINDEX, args.ifindex);
+
+	struct rtattr *parent = addattr_nest(&req.n, sizeof(req),
+					     NET_SHAPER_A_PARENT | NLA_F_NESTED);
+	addattr32(&req.n, sizeof(req), NET_SHAPER_A_HANDLE_SCOPE, parent_scope);
+	if (has_parent_id)
+		addattr32(&req.n, sizeof(req), NET_SHAPER_A_HANDLE_ID, parent_id);
+	addattr_nest_end(&req.n, parent);
+
+	struct rtattr *handle = addattr_nest(&req.n, sizeof(req),
+					     NET_SHAPER_A_HANDLE | NLA_F_NESTED);
+	addattr32(&req.n, sizeof(req), NET_SHAPER_A_HANDLE_SCOPE, handle_scope);
+	if (has_handle_id)
+		addattr32(&req.n, sizeof(req), NET_SHAPER_A_HANDLE_ID, handle_id);
+	addattr_nest_end(&req.n, handle);
+
+	if (args.has_bw_min)
+		addattr64(&req.n, sizeof(req), NET_SHAPER_A_BW_MIN,
+			  args.bw_min_bps);
+	if (args.has_bw_max)
+		addattr64(&req.n, sizeof(req), NET_SHAPER_A_BW_MAX,
+			  args.bw_max_bps);
+	if (args.has_weight)
+		addattr32(&req.n, sizeof(req), NET_SHAPER_A_WEIGHT, args.weight);
+
+	if (args.has_bw_min || args.has_bw_max)
+		addattr32(&req.n, sizeof(req), NET_SHAPER_A_METRIC,
+			  NET_SHAPER_METRIC_BPS);
+
+	for (int i = 0; i < num_leaves; i++) {
+		struct rtattr *leaf, *leaf_handle;
+
+		leaf = addattr_nest(&req.n, sizeof(req),
+				    NET_SHAPER_A_LEAVES | NLA_F_NESTED);
+		leaf_handle = addattr_nest(&req.n, sizeof(req),
+					   NET_SHAPER_A_HANDLE | NLA_F_NESTED);
+		addattr32(&req.n, sizeof(req), NET_SHAPER_A_HANDLE_SCOPE,
+			  leaves[i].scope);
+		addattr32(&req.n, sizeof(req), NET_SHAPER_A_HANDLE_ID,
+			  leaves[i].id);
+		addattr_nest_end(&req.n, leaf_handle);
+		addattr_nest_end(&req.n, leaf);
+	}
+
+	err = rtnl_talk(&gen_rth, &req.n, &answer);
+	if (err < 0) {
+		fprintf(stderr, "Kernel command failed: %d\n", err);
+		return err;
+	}
+
+	print_netshaper_attrs(answer);
+	free(answer);
+	return 0;
+}
+
 int main(int argc, char **argv)
 {
 	int color = default_color_opt();
@@ -363,6 +579,8 @@ int main(int argc, char **argv)
 			return do_cmd(argc - 1, argv + 1, NET_SHAPER_CMD_DELETE);
 		if (strcmp(*argv, "show") == 0)
 			return do_cmd(argc - 1, argv + 1, NET_SHAPER_CMD_GET);
+		if (strcmp(*argv, "group") == 0)
+			return do_group(argc - 1, argv + 1);
 		if (strcmp(*argv, "help") == 0) {
 			usage();
 			return 0;
-- 
2.53.0-Meta


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH iproute2-next v3 6/6] netshaper: Update man page for new parameters and group command
  2026-05-11 18:39 [PATCH iproute2-next v3 0/6] netshaper: Extend netshaper support Mohsin Bashir
                   ` (4 preceding siblings ...)
  2026-05-11 18:39 ` [PATCH iproute2-next v3 5/6] netshaper: Add group command for creating scheduling hierarchies Mohsin Bashir
@ 2026-05-11 18:39 ` Mohsin Bashir
  5 siblings, 0 replies; 7+ messages in thread
From: Mohsin Bashir @ 2026-05-11 18:39 UTC (permalink / raw)
  To: netdev
  Cc: dsahern, stephen, pabeni, kuba, ernis, mohsin.bashr,
	alexanderduyck, Claude Assistant

From: Mohsin Bashir <hmohsin@meta.com>

Document bw-min, weight, and the group command in the netshaper
man page. Node id is required for set/show/delete but optional
for the group command. Leaves are documented as queue-only.

Reviewed-by: Claude Assistant <noreply@anthropic.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Mohsin Bashir <hmohsin@meta.com>
---
 man/man8/netshaper.8 | 140 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 119 insertions(+), 21 deletions(-)

diff --git a/man/man8/netshaper.8 b/man/man8/netshaper.8
index f5fe36cc..ed4f77fc 100644
--- a/man/man8/netshaper.8
+++ b/man/man8/netshaper.8
@@ -25,8 +25,12 @@ netshaper \- show / manipulate network device hardware shaping configuration
 .IR HANDLE_SCOPE
 .RI "[ " id
 .IR HANDLE_ID " ]"
-.B bw-max
-.IR BW_MAX
+.RI "[ " bw-min
+.IR BW_MIN " ]"
+.RI "[ " bw-max
+.IR BW_MAX " ]"
+.RI "[ " weight
+.IR WEIGHT " ]"
 
 .ti -8
 .B "netshaper" " { " show " | " delete " }"
@@ -37,6 +41,27 @@ netshaper \- show / manipulate network device hardware shaping configuration
 .RI "[ " id
 .IR HANDLE_ID " ]"
 
+.ti -8
+.B "netshaper group"
+.B dev
+.IR DEV
+.B handle scope
+.IR HANDLE_SCOPE
+.RI "[ " id
+.IR HANDLE_ID " ]"
+.B parent scope
+.IR PARENT_SCOPE
+.RI "[ " id
+.IR PARENT_ID " ]"
+.RI "[ " bw-min
+.IR BW_MIN " ]"
+.RI "[ " bw-max
+.IR BW_MAX " ]"
+.RI "[ " weight
+.IR WEIGHT " ]"
+.B leaves
+.BI "{ scope " SCOPE " id " ID " } [ ... ]"
+
 .SH DESCRIPTION
 .B netshaper
 allows configuration and management of hardware rate limiting (shaping) capabilities
@@ -69,7 +94,11 @@ parameter is required and specifies the queue number.
 Shapers representing scheduling groups that can be placed at arbitrary
 locations in the scheduling tree. The
 .I id
-parameter is required.
+parameter is required for
+.BR set ", " show ", and " delete
+commands. For the
+.B group
+command it is optional; if omitted, the kernel auto-assigns one.
 
 .SH COMMANDS
 
@@ -77,16 +106,18 @@ parameter is required.
 .B netshaper set
 - Create or update a shaper configuration
 
-Creates or updates a shaper with the specified parameters. The
+Creates or updates a shaper with the specified parameters. At least one of
+.BR bw-min ", " bw-max ", or " weight
+must be provided. The
 .I id
-parameter is optional for netdev scope but required for all other scopes.
+parameter is required for queue and node scopes and optional for netdev scope.
 
 .SS
 .B netshaper show
 - Display shaper information
 
 Shows the current configuration of the specified shaper, including bandwidth
-limits and device information.
+limits, weight, and parent information.
 
 .SS
 .B netshaper delete
@@ -94,6 +125,15 @@ limits and device information.
 
 Removes the specified shaper configuration from the device.
 
+.SS
+.B netshaper group
+- Create a scheduling hierarchy
+
+Creates a scheduling group by binding one or more leaf shapers to a parent
+node in a single operation. The command specifies the group node's handle,
+its parent, optional bandwidth and weight parameters, and the set of leaf
+shapers to attach.
+
 .SH PARAMETERS
 
 .TP
@@ -115,21 +155,51 @@ or
 
 .TP
 .BI id " HANDLE_ID"
-Numeric identifier for the shaper. Optional for
-.B netdev
-scope (defaults to 0), required for
+Numeric identifier for the shaper. Required for
 .B queue
 and
 .B node
-scopes.
+scopes. Optional for
+.B netdev
+scope (defaults to 0). For the
+.B group
+command, node
+.I id
+may be omitted to let the kernel auto-assign one.
 .RE
 
 .TP
-.BI bw-max " BW_MAX"
-Maximum bandwidth limit for the shaper. Accepts values with suffixes:
+.BI bw-min " BW_MIN"
+Minimum guaranteed bandwidth for the shaper. Accepts values with suffixes:
 .BR kbit ", " mbit ", " gbit
 for kilobits, megabits, and gigabits per second respectively.
 
+.TP
+.BI bw-max " BW_MAX"
+Maximum bandwidth limit for the shaper. Accepts the same suffixes as
+.BR bw-min .
+
+.TP
+.BI weight " WEIGHT"
+Scheduling weight for the shaper, used for weighted fair sharing among
+siblings under the same parent node. Value is an unsigned integer.
+
+.TP
+.B parent
+Defines the parent node for the
+.B group
+command. Uses the same
+.BI scope " / " id
+syntax as
+.BR handle .
+
+.TP
+.B leaves
+Specifies one or more leaf shapers to attach to the group. Each leaf
+is given as
+.BI "scope " SCOPE " id " ID\fR.
+Multiple leaves can be specified in sequence.
+
 .SH OPTIONS
 
 .TP
@@ -156,17 +226,27 @@ Display usage information and exit.
 .SH EXAMPLES
 
 .TP
-.B Example 1: Create a device-level shaper (ID optional)
+.B Example 1: Create a device-level shaper
 .nf
 # netshaper set dev foo handle scope netdev bw-max 10gbit
 .fi
 .RS
-Creates a netdev-scoped shaper with default id 0 and sets the maximum
-bandwidth to 10 gigabits per second.
+Creates a netdev-scoped shaper with maximum bandwidth of 10 Gbit/s.
 .RE
 
 .TP
-.B Example 2: Show shaper configuration
+.B Example 2: Set bandwidth and weight on a queue shaper
+.nf
+# netshaper set dev foo handle scope queue id 0 \e
+    bw-min 1gbit bw-max 5gbit weight 10
+.fi
+.RS
+Creates a queue-scoped shaper on queue 0 with minimum/maximum bandwidth
+limits and a scheduling weight.
+.RE
+
+.TP
+.B Example 3: Show shaper configuration
 .nf
 # netshaper show dev foo handle scope netdev
 .fi
@@ -175,9 +255,20 @@ Displays the current shaper configuration for the specified device and handle.
 .RE
 
 .TP
-.B Example 3: Delete shaper configuration
+.B Example 4: Create a scheduling hierarchy with group
 .nf
-# netshaper delete dev eth0 handle scope netdev
+# netshaper group dev foo handle scope node parent scope netdev \e
+    bw-max 10gbit leaves scope queue id 0 scope queue id 1
+.fi
+.RS
+Creates a node shaper under the netdev parent with a 10 Gbit/s cap,
+grouping queues 0 and 1 as leaves.
+.RE
+
+.TP
+.B Example 5: Delete shaper configuration
+.nf
+# netshaper delete dev foo handle scope netdev
 .fi
 .RS
 Removes the specified shaper configuration.
@@ -197,15 +288,20 @@ and
 .B node
 scopes, the
 .I id
-parameter is required.
+parameter is required. For the
+.B group
+command, node
+.I id
+may be omitted to let the kernel auto-assign one.
 .IP \(bu
 Bandwidth values support standard suffixes:
 .BR kbit " (kilobits per second), "
 .BR mbit " (megabits per second), "
 .BR gbit " (gigabits per second)."
 .IP \(bu
-This command currently supports basic shaper operations. Additional
-functionality will be added as requirements are identified.
+The
+.B group
+command creates a node and attaches leaves in a single atomic operation.
 
 .SH SEE ALSO
 .BR ip (8),
@@ -214,3 +310,5 @@ functionality will be added as requirements are identified.
 
 .SH AUTHOR
 Erni Sri Satya Vennela <ernis@linux.microsoft.com>
+.br
+Mohsin Bashir <hmohsin@meta.com>
-- 
2.53.0-Meta


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-05-11 18:39 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-11 18:39 [PATCH iproute2-next v3 0/6] netshaper: Extend netshaper support Mohsin Bashir
2026-05-11 18:39 ` [PATCH iproute2-next v3 1/6] netshaper: Extract parse_scope() and parse_rate() helpers Mohsin Bashir
2026-05-11 18:39 ` [PATCH iproute2-next v3 2/6] netshaper: Add bw-min and weight parameter support Mohsin Bashir
2026-05-11 18:39 ` [PATCH iproute2-next v3 3/6] netshaper: Extend show output with parent, bw-min and weight Mohsin Bashir
2026-05-11 18:39 ` [PATCH iproute2-next v3 4/6] netshaper: Extract struct shaper_args and parse_shaper_arg() helper Mohsin Bashir
2026-05-11 18:39 ` [PATCH iproute2-next v3 5/6] netshaper: Add group command for creating scheduling hierarchies Mohsin Bashir
2026-05-11 18:39 ` [PATCH iproute2-next v3 6/6] netshaper: Update man page for new parameters and group command Mohsin Bashir

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox