Commit 0e7788fd authored by Petr Machata's avatar Petr Machata Committed by David S. Miller

net: rtnetlink: Add UAPI for obtaining L3 offload xstats

Add a new IFLA_STATS_LINK_OFFLOAD_XSTATS child attribute,
IFLA_OFFLOAD_XSTATS_L3_STATS, to carry statistics for traffic that takes
place in a HW router.

The offloaded HW stats are designed to allow per-netdevice enablement and
disablement. Additionally, as a netdevice is configured, it may become or
cease being suitable for binding of a HW counter. Both of these aspects
need to be communicated to the userspace. To that end, add another child
attribute, IFLA_OFFLOAD_XSTATS_HW_S_INFO:

    - attr nest IFLA_OFFLOAD_XSTATS_HW_S_INFO
	- attr nest IFLA_OFFLOAD_XSTATS_L3_STATS
 	    - attr IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST
	      - {0,1} as u8
 	    - attr IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED
	      - {0,1} as u8

Thus this one attribute is a nest that can be used to carry information
about various types of HW statistics, and indexing is very simply done by
wrapping the information for a given statistics suite into the attribute
that carries the suite is the RTM_GETSTATS query. At the same time, because
_HW_S_INFO is nested directly below IFLA_STATS_LINK_OFFLOAD_XSTATS, it is
possible through filtering to request only the metadata about individual
statistics suites, without having to hit the HW to get the actual counters.
Signed-off-by: default avatarPetr Machata <petrm@nvidia.com>
Signed-off-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9309f97a
...@@ -1249,10 +1249,21 @@ enum { ...@@ -1249,10 +1249,21 @@ enum {
enum { enum {
IFLA_OFFLOAD_XSTATS_UNSPEC, IFLA_OFFLOAD_XSTATS_UNSPEC,
IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */ IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */
IFLA_OFFLOAD_XSTATS_HW_S_INFO, /* HW stats info. A nest */
IFLA_OFFLOAD_XSTATS_L3_STATS, /* struct rtnl_hw_stats64 */
__IFLA_OFFLOAD_XSTATS_MAX __IFLA_OFFLOAD_XSTATS_MAX
}; };
#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1) #define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1)
enum {
IFLA_OFFLOAD_XSTATS_HW_S_INFO_UNSPEC,
IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST, /* u8 */
IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED, /* u8 */
__IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX,
};
#define IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX \
(__IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX - 1)
/* XDP section */ /* XDP section */
#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0) #define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0)
......
...@@ -5091,10 +5091,110 @@ rtnl_offload_xstats_fill_ndo(struct net_device *dev, int attr_id, ...@@ -5091,10 +5091,110 @@ rtnl_offload_xstats_fill_ndo(struct net_device *dev, int attr_id,
return 0; return 0;
} }
static unsigned int
rtnl_offload_xstats_get_size_stats(const struct net_device *dev,
enum netdev_offload_xstats_type type)
{
bool enabled = netdev_offload_xstats_enabled(dev, type);
return enabled ? sizeof(struct rtnl_hw_stats64) : 0;
}
struct rtnl_offload_xstats_request_used {
bool request;
bool used;
};
static int
rtnl_offload_xstats_get_stats(struct net_device *dev,
enum netdev_offload_xstats_type type,
struct rtnl_offload_xstats_request_used *ru,
struct rtnl_hw_stats64 *stats,
struct netlink_ext_ack *extack)
{
bool request;
bool used;
int err;
request = netdev_offload_xstats_enabled(dev, type);
if (!request) {
used = false;
goto out;
}
err = netdev_offload_xstats_get(dev, type, stats, &used, extack);
if (err)
return err;
out:
if (ru) {
ru->request = request;
ru->used = used;
}
return 0;
}
static int
rtnl_offload_xstats_fill_hw_s_info_one(struct sk_buff *skb, int attr_id,
struct rtnl_offload_xstats_request_used *ru)
{
struct nlattr *nest;
nest = nla_nest_start(skb, attr_id);
if (!nest)
return -EMSGSIZE;
if (nla_put_u8(skb, IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST, ru->request))
goto nla_put_failure;
if (nla_put_u8(skb, IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED, ru->used))
goto nla_put_failure;
nla_nest_end(skb, nest);
return 0;
nla_put_failure:
nla_nest_cancel(skb, nest);
return -EMSGSIZE;
}
static int
rtnl_offload_xstats_fill_hw_s_info(struct sk_buff *skb, struct net_device *dev,
struct netlink_ext_ack *extack)
{
enum netdev_offload_xstats_type t_l3 = NETDEV_OFFLOAD_XSTATS_TYPE_L3;
struct rtnl_offload_xstats_request_used ru_l3;
struct nlattr *nest;
int err;
err = rtnl_offload_xstats_get_stats(dev, t_l3, &ru_l3, NULL, extack);
if (err)
return err;
nest = nla_nest_start(skb, IFLA_OFFLOAD_XSTATS_HW_S_INFO);
if (!nest)
return -EMSGSIZE;
if (rtnl_offload_xstats_fill_hw_s_info_one(skb,
IFLA_OFFLOAD_XSTATS_L3_STATS,
&ru_l3))
goto nla_put_failure;
nla_nest_end(skb, nest);
return 0;
nla_put_failure:
nla_nest_cancel(skb, nest);
return -EMSGSIZE;
}
static int rtnl_offload_xstats_fill(struct sk_buff *skb, struct net_device *dev, static int rtnl_offload_xstats_fill(struct sk_buff *skb, struct net_device *dev,
int *prividx, u32 off_filter_mask, int *prividx, u32 off_filter_mask,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
enum netdev_offload_xstats_type t_l3 = NETDEV_OFFLOAD_XSTATS_TYPE_L3;
int attr_id_hw_s_info = IFLA_OFFLOAD_XSTATS_HW_S_INFO;
int attr_id_l3_stats = IFLA_OFFLOAD_XSTATS_L3_STATS;
int attr_id_cpu_hit = IFLA_OFFLOAD_XSTATS_CPU_HIT; int attr_id_cpu_hit = IFLA_OFFLOAD_XSTATS_CPU_HIT;
bool have_data = false; bool have_data = false;
int err; int err;
...@@ -5111,6 +5211,40 @@ static int rtnl_offload_xstats_fill(struct sk_buff *skb, struct net_device *dev, ...@@ -5111,6 +5211,40 @@ static int rtnl_offload_xstats_fill(struct sk_buff *skb, struct net_device *dev,
} }
} }
if (*prividx <= attr_id_hw_s_info &&
(off_filter_mask & IFLA_STATS_FILTER_BIT(attr_id_hw_s_info))) {
*prividx = attr_id_hw_s_info;
err = rtnl_offload_xstats_fill_hw_s_info(skb, dev, extack);
if (err)
return err;
have_data = true;
*prividx = 0;
}
if (*prividx <= attr_id_l3_stats &&
(off_filter_mask & IFLA_STATS_FILTER_BIT(attr_id_l3_stats))) {
unsigned int size_l3;
struct nlattr *attr;
*prividx = attr_id_l3_stats;
size_l3 = rtnl_offload_xstats_get_size_stats(dev, t_l3);
attr = nla_reserve_64bit(skb, attr_id_l3_stats, size_l3,
IFLA_OFFLOAD_XSTATS_UNSPEC);
if (!attr)
return -EMSGSIZE;
err = rtnl_offload_xstats_get_stats(dev, t_l3, NULL,
nla_data(attr), extack);
if (err)
return err;
have_data = true;
*prividx = 0;
}
if (!have_data) if (!have_data)
return -ENODATA; return -ENODATA;
...@@ -5118,9 +5252,35 @@ static int rtnl_offload_xstats_fill(struct sk_buff *skb, struct net_device *dev, ...@@ -5118,9 +5252,35 @@ static int rtnl_offload_xstats_fill(struct sk_buff *skb, struct net_device *dev,
return 0; return 0;
} }
static unsigned int
rtnl_offload_xstats_get_size_hw_s_info_one(const struct net_device *dev,
enum netdev_offload_xstats_type type)
{
bool enabled = netdev_offload_xstats_enabled(dev, type);
return nla_total_size(0) +
/* IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST */
nla_total_size(sizeof(u8)) +
/* IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED */
(enabled ? nla_total_size(sizeof(u8)) : 0) +
0;
}
static unsigned int
rtnl_offload_xstats_get_size_hw_s_info(const struct net_device *dev)
{
enum netdev_offload_xstats_type t_l3 = NETDEV_OFFLOAD_XSTATS_TYPE_L3;
return nla_total_size(0) +
/* IFLA_OFFLOAD_XSTATS_L3_STATS */
rtnl_offload_xstats_get_size_hw_s_info_one(dev, t_l3) +
0;
}
static int rtnl_offload_xstats_get_size(const struct net_device *dev, static int rtnl_offload_xstats_get_size(const struct net_device *dev,
u32 off_filter_mask) u32 off_filter_mask)
{ {
enum netdev_offload_xstats_type t_l3 = NETDEV_OFFLOAD_XSTATS_TYPE_L3;
int attr_id_cpu_hit = IFLA_OFFLOAD_XSTATS_CPU_HIT; int attr_id_cpu_hit = IFLA_OFFLOAD_XSTATS_CPU_HIT;
int nla_size = 0; int nla_size = 0;
int size; int size;
...@@ -5131,6 +5291,16 @@ static int rtnl_offload_xstats_get_size(const struct net_device *dev, ...@@ -5131,6 +5291,16 @@ static int rtnl_offload_xstats_get_size(const struct net_device *dev,
nla_size += nla_total_size_64bit(size); nla_size += nla_total_size_64bit(size);
} }
if (off_filter_mask &
IFLA_STATS_FILTER_BIT(IFLA_OFFLOAD_XSTATS_HW_S_INFO))
nla_size += rtnl_offload_xstats_get_size_hw_s_info(dev);
if (off_filter_mask &
IFLA_STATS_FILTER_BIT(IFLA_OFFLOAD_XSTATS_L3_STATS)) {
size = rtnl_offload_xstats_get_size_stats(dev, t_l3);
nla_size += nla_total_size_64bit(size);
}
if (nla_size != 0) if (nla_size != 0)
nla_size += nla_total_size(0); nla_size += nla_total_size(0);
......
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