net: rtnetlink: Add RTM_SETSTATS
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>
This commit is contained in:
parent
0e7788fd76
commit
03ba356670
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 },
|
||||
|
|
Loading…
Reference in New Issue