Commit e8872a25 authored by Nikolay Aleksandrov's avatar Nikolay Aleksandrov Committed by David S. Miller

net: rtnetlink: allow rtnl_fill_statsinfo to save private state counter

The new prividx argument allows the current dumping device to save a
private state counter which would enable it to continue dumping from
where it left off. And the idxattr is used to save the current idx user
so multiple prividx using attributes can be requested at the same time
as suggested by Roopa Prabhu.
Signed-off-by: default avatarNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d1ac3b16
......@@ -3444,13 +3444,21 @@ static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)
return err;
}
static bool stats_attr_valid(unsigned int mask, int attrid, int idxattr)
{
return (mask & IFLA_STATS_FILTER_BIT(attrid)) &&
(!idxattr || idxattr == attrid);
}
static int rtnl_fill_statsinfo(struct sk_buff *skb, struct net_device *dev,
int type, u32 pid, u32 seq, u32 change,
unsigned int flags, unsigned int filter_mask)
unsigned int flags, unsigned int filter_mask,
int *idxattr, int *prividx)
{
struct if_stats_msg *ifsm;
struct nlmsghdr *nlh;
struct nlattr *attr;
int s_prividx = *prividx;
ASSERT_RTNL();
......@@ -3462,7 +3470,7 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, struct net_device *dev,
ifsm->ifindex = dev->ifindex;
ifsm->filter_mask = filter_mask;
if (filter_mask & IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_64)) {
if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_64, *idxattr)) {
struct rtnl_link_stats64 *sp;
attr = nla_reserve_64bit(skb, IFLA_STATS_LINK_64,
......@@ -3480,7 +3488,11 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, struct net_device *dev,
return 0;
nla_put_failure:
nlmsg_cancel(skb, nlh);
/* not a multi message or no progress mean a real error */
if (!(flags & NLM_F_MULTI) || s_prividx == *prividx)
nlmsg_cancel(skb, nlh);
else
nlmsg_end(skb, nlh);
return -EMSGSIZE;
}
......@@ -3494,7 +3506,7 @@ static size_t if_nlmsg_stats_size(const struct net_device *dev,
{
size_t size = 0;
if (filter_mask & IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_64))
if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_64, 0))
size += nla_total_size_64bit(sizeof(struct rtnl_link_stats64));
return size;
......@@ -3503,8 +3515,9 @@ static size_t if_nlmsg_stats_size(const struct net_device *dev,
static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct if_stats_msg *ifsm;
struct net_device *dev = NULL;
int idxattr = 0, prividx = 0;
struct if_stats_msg *ifsm;
struct sk_buff *nskb;
u32 filter_mask;
int err;
......@@ -3528,7 +3541,7 @@ static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh)
err = rtnl_fill_statsinfo(nskb, dev, RTM_NEWSTATS,
NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0,
0, filter_mask);
0, filter_mask, &idxattr, &prividx);
if (err < 0) {
/* -EMSGSIZE implies BUG in if_nlmsg_stats_size */
WARN_ON(err == -EMSGSIZE);
......@@ -3542,18 +3555,19 @@ static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh)
static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
int h, s_h, err, s_idx, s_idxattr, s_prividx;
struct net *net = sock_net(skb->sk);
unsigned int flags = NLM_F_MULTI;
struct if_stats_msg *ifsm;
int h, s_h;
int idx = 0, s_idx;
struct net_device *dev;
struct hlist_head *head;
unsigned int flags = NLM_F_MULTI;
struct net_device *dev;
u32 filter_mask = 0;
int err;
int idx = 0;
s_h = cb->args[0];
s_idx = cb->args[1];
s_idxattr = cb->args[2];
s_prividx = cb->args[3];
cb->seq = net->dev_base_seq;
......@@ -3571,7 +3585,8 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb)
err = rtnl_fill_statsinfo(skb, dev, RTM_NEWSTATS,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, 0,
flags, filter_mask);
flags, filter_mask,
&s_idxattr, &s_prividx);
/* If we ran out of room on the first message,
* we're in trouble
*/
......@@ -3579,13 +3594,16 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb)
if (err < 0)
goto out;
s_prividx = 0;
s_idxattr = 0;
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
cont:
idx++;
}
}
out:
cb->args[3] = s_prividx;
cb->args[2] = s_idxattr;
cb->args[1] = idx;
cb->args[0] = h;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment