aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Machata <petrm@nvidia.com>2022-04-22 10:30:53 +0200
committerDavid Ahern <dsahern@kernel.org>2022-04-27 20:12:42 -0600
commit82f6444f83c76e01870ca9f7779a43cfd81d38d9 (patch)
tree9bdc90650ca3a56d46a8623ec7372a6a3ff274a9
parent54d82b0699a07b1af32a46e229ed37331e38d3a2 (diff)
downloadiproute2-82f6444f83c76e01870ca9f7779a43cfd81d38d9.tar.gz
ipstats: Add a "set" command
Add a command to allow toggling HW stats. An example usage: # ip stats set dev swp1 l3_stats on Signed-off-by: Petr Machata <petrm@nvidia.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: David Ahern <dsahern@kernel.org>
-rw-r--r--ip/ipstats.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/ip/ipstats.c b/ip/ipstats.c
index 099e18a21..1f5b3f774 100644
--- a/ip/ipstats.c
+++ b/ip/ipstats.c
@@ -1,4 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
+#include <errno.h>
+
#include "utils.h"
#include "ip_common.h"
@@ -6,11 +8,85 @@ static int do_help(void)
{
fprintf(stderr,
"Usage: ip stats help\n"
+ " ip stats set dev DEV l3_stats { on | off }\n"
);
return 0;
}
+static int ipstats_set_do(int ifindex, int at, bool enable)
+{
+ struct ipstats_req req = {
+ .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct if_stats_msg)),
+ .nlh.nlmsg_flags = NLM_F_REQUEST,
+ .nlh.nlmsg_type = RTM_SETSTATS,
+ .ifsm.family = PF_UNSPEC,
+ .ifsm.ifindex = ifindex,
+ };
+
+ addattr8(&req.nlh, sizeof(req), at, enable);
+
+ if (rtnl_talk(&rth, &req.nlh, NULL) < 0)
+ return -2;
+ return 0;
+}
+
+static int ipstats_set(int argc, char **argv)
+{
+ const char *dev = NULL;
+ bool enable = false;
+ int ifindex;
+ int at = 0;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ if (dev)
+ duparg2("dev", *argv);
+ if (check_ifname(*argv))
+ invarg("\"dev\" not a valid ifname", *argv);
+ dev = *argv;
+ } else if (strcmp(*argv, "l3_stats") == 0) {
+ int err;
+
+ NEXT_ARG();
+ if (at) {
+ fprintf(stderr, "A statistics suite to toggle was already given.\n");
+ return -EINVAL;
+ }
+ at = IFLA_STATS_SET_OFFLOAD_XSTATS_L3_STATS;
+ enable = parse_on_off("l3_stats", *argv, &err);
+ if (err)
+ return err;
+ } else if (strcmp(*argv, "help") == 0) {
+ do_help();
+ return 0;
+ } else {
+ fprintf(stderr, "What is \"%s\"?\n", *argv);
+ do_help();
+ return -EINVAL;
+ }
+
+ NEXT_ARG_FWD();
+ }
+
+ if (!dev) {
+ fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
+ exit(-1);
+ }
+
+ if (!at) {
+ fprintf(stderr, "Not enough information: stat type to toggle is required.\n");
+ exit(-1);
+ }
+
+ ifindex = ll_name_to_index(dev);
+ if (!ifindex)
+ return nodev(dev);
+
+ return ipstats_set_do(ifindex, at, enable);
+}
+
int do_ipstats(int argc, char **argv)
{
int rc;
@@ -21,6 +97,8 @@ int do_ipstats(int argc, char **argv)
} else if (strcmp(*argv, "help") == 0) {
do_help();
rc = 0;
+ } else if (strcmp(*argv, "set") == 0) {
+ rc = ipstats_set(argc-1, argv+1);
} else {
fprintf(stderr, "Command \"%s\" is unknown, try \"ip stats help\".\n",
*argv);