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: 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:
Родитель
9309f97aef
Коммит
0e7788fd76
|
@ -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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
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,
|
||||||
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);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче