]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
ipstats: Add a "set" command
authorPetr Machata <petrm@nvidia.com>
Fri, 22 Apr 2022 08:30:53 +0000 (10:30 +0200)
committerDavid Ahern <dsahern@kernel.org>
Thu, 28 Apr 2022 02:12:42 +0000 (20:12 -0600)
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>
ip/ipstats.c

index 099e18a210e30821a9f76f5ef2bc047da0abca1c..1f5b3f774e6997c965f39d8c8bf46d763b026684 100644 (file)
@@ -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);