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]
Message-ID: <20250807180740.GA31890@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net>
Date: Thu, 7 Aug 2025 11:07:40 -0700
From: Erni Sri Satya Vennela <ernis@...ux.microsoft.com>
To: Stephen Hemminger <stephen@...workplumber.org>
Cc: dsahern@...il.com, netdev@...r.kernel.org, haiyangz@...rosoft.com,
	shradhagupta@...ux.microsoft.com, ssengar@...rosoft.com,
	dipayanroy@...rosoft.com, ernis@...rosoft.com
Subject: Re: [PATCH iproute2-next v2] iproute2: Add 'netshaper' command to
 'ip link' for netdev shaping

On Tue, Aug 05, 2025 at 11:03:31AM -0700, Stephen Hemminger wrote:
> On Wed, 30 Jul 2025 02:21:56 -0700
> Erni Sri Satya Vennela <ernis@...ux.microsoft.com> wrote:
> 
> > Add support for the netshaper Generic Netlink
> > family to iproute2. Introduce a new subcommand to `ip link` for
> > configuring netshaper parameters directly from userspace.
> > 
> > This interface allows users to set shaping attributes (such as speed)
> > which are passed to the kernel to perform the corresponding netshaper
> > operation.
> > 
> > Example usage:
> > $ip link netshaper { set | get | delete } dev DEVNAME \
> >                    handle scope SCOPE id ID \
> >                    [ speed SPEED ]
> > 
> > Internally, this triggers a kernel call to apply the shaping
> > configuration to the specified network device.
> > 
> > Currently, the tool supports the following functionalities:
> > - Setting speed in Mbps, enabling bandwidth clamping for
> >   a network device that support netshaper operations.
> > - Deleting the current configuration.
> > - Querying the existing configuration.
> > 
> > Additional netshaper operations will be integrated into the tool
> > as per requirement.
> > 
> > This change enables easy and scriptable configuration of bandwidth
> > shaping for  devices that use the netshaper Netlink family.
> > 
> > Corresponding net-next patches:
> > 1) https://lore.kernel.org/all/cover.1728460186.git.pabeni@redhat.com/
> > 2) https://lore.kernel.org/lkml/1750144656-2021-1-git-send-email-ernis@linux.microsoft.com/
> > 
> > Install pkg-config and libmnl* packages to print any kernel extack
> > errors to stdout.
> > 
> > Signed-off-by: Erni Sri Satya Vennela <ernis@...ux.microsoft.com>
> > ---
> > Please add include/uapi/linux/net_shaper.h from kernel source tree
> > for this patch.
> > ---
> > Changes in v2:
> > * Use color coding for printing device name in stdout.
> > * Use clang-format to format the code inline.
> > * Use __u64 for speed_bps.
> > * Remove include/uapi/linux/netshaper.h file.
> > ---
> >  ip/Makefile           |   2 +-
> >  ip/iplink.c           |  12 +++
> >  ip/iplink_netshaper.c | 190 ++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 203 insertions(+), 1 deletion(-)
> >  create mode 100644 ip/iplink_netshaper.c
> 
> Good start but changes needed.
> 
> > 
> > diff --git a/ip/Makefile b/ip/Makefile
> > index 3535ba78..18218c3b 100644
> > --- a/ip/Makefile
> > +++ b/ip/Makefile
> > @@ -4,7 +4,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
> >      ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o iptoken.o \
> >      ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o iplink_dummy.o \
> >      iplink_ifb.o iplink_nlmon.o iplink_team.o iplink_vcan.o iplink_vxcan.o \
> > -    iplink_vlan.o link_veth.o link_gre.o iplink_can.o iplink_xdp.o \
> > +    iplink_vlan.o iplink_netshaper.o link_veth.o link_gre.o iplink_can.o iplink_xdp.o \
> >      iplink_macvlan.o ipl2tp.o link_vti.o link_vti6.o link_xfrm.o \
> >      iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o \
> >      link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \
> > diff --git a/ip/iplink.c b/ip/iplink.c
> > index 59e8caf4..9da6e304 100644
> > --- a/ip/iplink.c
> > +++ b/ip/iplink.c
> > @@ -1509,6 +1509,15 @@ static void do_help(int argc, char **argv)
> >  		usage();
> >  }
> >  
> > +static int iplink_netshaper(int argc, char **argv)
> > +{
> > +	struct link_util *lu;
> > +
> > +	lu = get_link_kind("netshaper");
> > +
> > +	return lu->parse_opt(lu, argc, argv, NULL);
> > +}
> > +
> >  int do_iplink(int argc, char **argv)
> >  {
> >  	if (argc < 1)
> > @@ -1545,6 +1554,9 @@ int do_iplink(int argc, char **argv)
> >  	if (matches(*argv, "property") == 0)
> >  		return iplink_prop(argc-1, argv+1);
> >  
> > +	if (matches(*argv, "netshaper") == 0)
> > +		return iplink_netshaper(argc-1, argv+1);
> > +
> 
> Matches() can cause issues, prefer strcmp() for new code.

Okay, I'll make this change in the the next version.
> 
> >  	if (matches(*argv, "help") == 0) {
> >  		do_help(argc-1, argv+1);
> >  		return 0;
> > diff --git a/ip/iplink_netshaper.c b/ip/iplink_netshaper.c
> > new file mode 100644
> > index 00000000..af7d5e09
> > --- /dev/null
> > +++ b/ip/iplink_netshaper.c
> > @@ -0,0 +1,190 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * iplink_netshaper.c netshaper H/W shaping support
> > + *
> > + * Authors:        Erni Sri Satya Vennela <ernis@...ux.microsoft.com>
> > + */
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <linux/genetlink.h>
> > +#include <linux/netlink.h>
> > +#include <linux/rtnetlink.h>
> > +#include <uapi/linux/netshaper.h>
> > +#include "utils.h"
> > +#include "ip_common.h"
> > +#include "libgenl.h"
> > +
> > +/* netlink socket */
> > +static struct rtnl_handle gen_rth = { .fd = -1 };
> > +static int genl_family = -1;
> > +
> > +static void usage(void)
> > +{
> > +	fprintf(stderr,
> > +		"Usage:	ip link netshaper set dev DEVNAME handle scope HANDLE_SCOPE id HANDLE_ID speed SPEED\n"
> > +		"	ip link netshaper delete dev DEVNAME handle scope HANDLE_SCOPE id HANDLE_ID\n"
> > +		"	ip link netshaper get dev DEVNAME handle scope HANDLE_SCOPE id HANDLE_ID\n"
> > +		"Where:	DEVNAME		:= STRING\n"
> > +		"	HANDLE_SCOPE	:= { netdev | queue | node }\n"
> > +		"	HANDLE_ID	:= UINT\n"
> > +		"	SPEED		:= UINT (Mega bits per second)\n");
> > +
> > +	exit(-1);
> > +}
> > +
> > +static void print_netshaper_attrs(struct nlmsghdr *answer)
> > +{
> > +	struct genlmsghdr *ghdr = NLMSG_DATA(answer);
> > +	int len = answer->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
> > +	struct rtattr *tb[NET_SHAPER_A_MAX + 1] = {};
> > +	__u32 speed_mbps;
> > +	__u64 speed_bps;
> > +	int ifindex;
> > +
> > +	parse_rtattr(tb, NET_SHAPER_A_MAX,
> > +		     (struct rtattr *)((char *)ghdr + GENL_HDRLEN), len);
> > +
> > +	for (int i = 1; i <= NET_SHAPER_A_MAX; ++i) {
> > +		if (!tb[i])
> > +			continue;
> > +		switch (i) {
> > +		case NET_SHAPER_A_BW_MAX:
> > +			speed_bps = rta_getattr_u64(tb[i]);
> > +			speed_mbps = (speed_bps / 1000000);
> > +			print_uint(PRINT_ANY, "speed", "speed: %u mbps\n",
> > +				   speed_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;
> > +		default:
> > +			break;
> > +		}
> > +	}
> > +}
> > +
> > +static int do_cmd(int argc, char **argv, struct nlmsghdr *n, int cmd)
> > +{
> > +	GENL_REQUEST(req, 1024, genl_family, 0, NET_SHAPER_FAMILY_VERSION, cmd,
> > +		     NLM_F_REQUEST | NLM_F_ACK);
> > +
> > +	struct nlmsghdr *answer;
> > +	__u32 speed_mbps = 0;
> > +	__u64 speed_bps = 0;
> > +	int ifindex = -1;
> > +	int handle_scope = NET_SHAPER_SCOPE_UNSPEC;
> > +	__u32 handle_id = 0;
> > +	bool handle_present = false;
> > +	int err;
> > +
> > +	while (argc > 0) {
> > +		if (matches(*argv, "dev") == 0) {
> > +			NEXT_ARG();
> > +			ifindex = ll_name_to_index(*argv);
> > +		} else if (matches(*argv, "speed") == 0) {
> 
> Iproute2 no longer allows shortcut matches on new commands.
> Shortcuts have lead to lots of confusion where there are multiple matches possible.

Thanks for the clarification. I'll will update my usage accordingly to
avoid ambiguity.
> 
> > +			NEXT_ARG();
> > +			if (get_unsigned(&speed_mbps, *argv, 10)) {
> > +				fprintf(stderr, "Invalid speed value\n");
> > +				return -1;
> > +			}
> 
> Could you change this code to use the get_rate() in lib/utils_math.c
> That routine handles wide variety of suffixes.
> 
> > +			/*Convert Mbps to Bps*/
> 
> Won't need this if you use get_rate() or get_rate64

Okay I'll make the changes accordingly.
> 
> > +			speed_bps = (((__u64)speed_mbps) * 1000000);
> > +		} else if (matches(*argv, "handle") == 0) {
> > +			handle_present = true;
> > +			NEXT_ARG();
> > +			if (matches(*argv, "scope") == 0) {
> > +				NEXT_ARG();
> > +				if (matches(*argv, "netdev") == 0) {
> > +					handle_scope = NET_SHAPER_SCOPE_NETDEV;
> > +				} else if (matches(*argv, "queue") == 0) {
> > +					handle_scope = NET_SHAPER_SCOPE_QUEUE;
> > +				} else if (matches(*argv, "node") == 0) {
> > +					handle_scope = NET_SHAPER_SCOPE_NODE;
> > +				} else {
> > +					fprintf(stderr, "Invalid scope\n");
> > +					return -1;
> > +				}
> > +
> > +				NEXT_ARG();
> > +				if (matches(*argv, "id") == 0) {
> > +					NEXT_ARG();
> > +					if (get_unsigned(&handle_id, *argv, 10)) {
> > +						fprintf(stderr,
> > +							"Invalid handle id\n");
> > +						return -1;
> > +					}
> > +				}
> > +			}
> > +		} else {
> > +			fprintf(stderr, "What is \"%s\"\n", *argv);
> > +			usage();
> > +		}
> > +		argc--;
> > +		argv++;
> > +	}
> > +
> > +	if (ifindex == -1)
> > +		missarg("dev");
> > +
> > +	if (!handle_present)
> > +		missarg("handle");
> > +
> > +	if (cmd == NET_SHAPER_CMD_SET && speed_mbps == 0)
> > +		missarg("speed");
> > +
> > +	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);
> > +	addattr_nest_end(&req.n, handle);
> > +
> > +	if (cmd == NET_SHAPER_CMD_SET)
> > +		addattr64(&req.n, sizeof(req), NET_SHAPER_A_BW_MAX, speed_bps);
> > +
> > +	err = rtnl_talk(&gen_rth, &req.n, &answer);
> > +	if (err < 0) {
> > +		printf("Kernel command failed: %d\n", err);
> > +		return err;
> > +	}
> > +
> > +	if (cmd == NET_SHAPER_CMD_GET)
> > +		print_netshaper_attrs(answer);
> > +
> > +	return err;
> > +}
> > +
> > +static int netshaper_parse_opt(struct link_util *lu, int argc, char **argv,
> > +			       struct nlmsghdr *n)
> > +{
> > +	if (argc < 1)
> > +		usage();
> > +	if (matches(*argv, "help") == 0)
> > +		usage();
> > +
> > +	if (genl_init_handle(&gen_rth, NET_SHAPER_FAMILY_NAME, &genl_family))
> > +		exit(1);
> > +
> > +	if (matches(*argv, "set") == 0)
> > +		return do_cmd(argc - 1, argv + 1, n, NET_SHAPER_CMD_SET);
> > +
> > +	if (matches(*argv, "delete") == 0)
> > +		return do_cmd(argc - 1, argv + 1, n, NET_SHAPER_CMD_DELETE);
> > +
> > +	if (matches(*argv, "get") == 0)
> > +		return do_cmd(argc - 1, argv + 1, n, NET_SHAPER_CMD_GET);
> 
> No matches shortcuts
Okay.
> 
> > +
> > +	fprintf(stderr,
> > +		"Command \"%s\" is unknown, try \"ip link netshaper help\".\n",
> > +		*argv);
> > +	exit(-1);
> > +}
> > +
> > +struct link_util netshaper_link_util = {
> > +	.id = "netshaper",
> > +	.parse_opt = netshaper_parse_opt,
> > +};
> 
> Where is the print function. You should be able to print current shaper
> state?
The current shaper state can be retrieved from the get opearation like:
"ip link netshaper get dev <interface> handle scope <scope> id <id>"


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ