net: rtnetlink: Add RTM_SETSTATS
authorPetr Machata <petrm@nvidia.com>
Wed, 2 Mar 2022 16:31:22 +0000 (18:31 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 3 Mar 2022 10:37:23 +0000 (10:37 +0000)
The offloaded HW stats are designed to allow per-netdevice enablement and
disablement. These stats are only accessible through RTM_GETSTATS, and
therefore should be toggled by a RTM_SETSTATS message. Add it, and the
necessary skeleton handler.

Signed-off-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/rtnetlink.h
net/core/rtnetlink.c
security/selinux/nlmsgtab.c

index 0970cb4..14462dc 100644 (file)
@@ -146,6 +146,8 @@ enum {
 #define RTM_NEWSTATS RTM_NEWSTATS
        RTM_GETSTATS = 94,
 #define RTM_GETSTATS RTM_GETSTATS
+       RTM_SETSTATS,
+#define RTM_SETSTATS RTM_SETSTATS
 
        RTM_NEWCACHEREPORT = 96,
 #define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT
index 9ce894a..d093545 100644 (file)
@@ -5564,6 +5564,10 @@ rtnl_stats_get_policy[IFLA_STATS_GETSET_MAX + 1] = {
                    NLA_POLICY_NESTED(rtnl_stats_get_policy_filters),
 };
 
+static const struct nla_policy
+ifla_stats_set_policy[IFLA_STATS_GETSET_MAX + 1] = {
+};
+
 static int rtnl_stats_get_parse_filters(struct nlattr *ifla_filters,
                                        struct rtnl_stats_dump_filters *filters,
                                        struct netlink_ext_ack *extack)
@@ -5769,6 +5773,67 @@ out:
        return skb->len;
 }
 
+static int rtnl_stats_set(struct sk_buff *skb, struct nlmsghdr *nlh,
+                         struct netlink_ext_ack *extack)
+{
+       struct rtnl_stats_dump_filters response_filters = {};
+       struct nlattr *tb[IFLA_STATS_GETSET_MAX + 1];
+       struct net *net = sock_net(skb->sk);
+       struct net_device *dev = NULL;
+       int idxattr = 0, prividx = 0;
+       struct if_stats_msg *ifsm;
+       struct sk_buff *nskb;
+       int err;
+
+       err = rtnl_valid_stats_req(nlh, netlink_strict_get_check(skb),
+                                  false, extack);
+       if (err)
+               return err;
+
+       ifsm = nlmsg_data(nlh);
+       if (ifsm->family != AF_UNSPEC) {
+               NL_SET_ERR_MSG(extack, "Address family should be AF_UNSPEC");
+               return -EINVAL;
+       }
+
+       if (ifsm->ifindex > 0)
+               dev = __dev_get_by_index(net, ifsm->ifindex);
+       else
+               return -EINVAL;
+
+       if (!dev)
+               return -ENODEV;
+
+       if (ifsm->filter_mask) {
+               NL_SET_ERR_MSG(extack, "Filter mask must be 0 for stats set");
+               return -EINVAL;
+       }
+
+       err = nlmsg_parse(nlh, sizeof(*ifsm), tb, IFLA_STATS_GETSET_MAX,
+                         ifla_stats_set_policy, extack);
+       if (err < 0)
+               return err;
+
+       nskb = nlmsg_new(if_nlmsg_stats_size(dev, &response_filters),
+                        GFP_KERNEL);
+       if (!nskb)
+               return -ENOBUFS;
+
+       err = rtnl_fill_statsinfo(nskb, dev, RTM_NEWSTATS,
+                                 NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
+                                 0, &response_filters, &idxattr, &prividx,
+                                 extack);
+       if (err < 0) {
+               /* -EMSGSIZE implies BUG in if_nlmsg_stats_size */
+               WARN_ON(err == -EMSGSIZE);
+               kfree_skb(nskb);
+       } else {
+               err = rtnl_unicast(nskb, net, NETLINK_CB(skb).portid);
+       }
+
+       return err;
+}
+
 /* Process one rtnetlink message. */
 
 static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -5994,4 +6059,5 @@ void __init rtnetlink_init(void)
 
        rtnl_register(PF_UNSPEC, RTM_GETSTATS, rtnl_stats_get, rtnl_stats_dump,
                      0);
+       rtnl_register(PF_UNSPEC, RTM_SETSTATS, rtnl_stats_set, NULL, 0);
 }
index 6ad3ee0..d8ceee9 100644 (file)
@@ -76,6 +76,7 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
        { RTM_GETNSID,          NETLINK_ROUTE_SOCKET__NLMSG_READ  },
        { RTM_NEWSTATS,         NETLINK_ROUTE_SOCKET__NLMSG_READ },
        { RTM_GETSTATS,         NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+       { RTM_SETSTATS,         NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
        { RTM_NEWCACHEREPORT,   NETLINK_ROUTE_SOCKET__NLMSG_READ },
        { RTM_NEWCHAIN,         NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
        { RTM_DELCHAIN,         NETLINK_ROUTE_SOCKET__NLMSG_WRITE },