Skip to content

Commit 0e7788f

Browse files
pmachatadavem330
authored andcommitted
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>
1 parent 9309f97 commit 0e7788f

File tree

2 files changed

+181
-0
lines changed

2 files changed

+181
-0
lines changed

include/uapi/linux/if_link.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,10 +1249,21 @@ enum {
12491249
enum {
12501250
IFLA_OFFLOAD_XSTATS_UNSPEC,
12511251
IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */
1252+
IFLA_OFFLOAD_XSTATS_HW_S_INFO, /* HW stats info. A nest */
1253+
IFLA_OFFLOAD_XSTATS_L3_STATS, /* struct rtnl_hw_stats64 */
12521254
__IFLA_OFFLOAD_XSTATS_MAX
12531255
};
12541256
#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1)
12551257

1258+
enum {
1259+
IFLA_OFFLOAD_XSTATS_HW_S_INFO_UNSPEC,
1260+
IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST, /* u8 */
1261+
IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED, /* u8 */
1262+
__IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX,
1263+
};
1264+
#define IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX \
1265+
(__IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX - 1)
1266+
12561267
/* XDP section */
12571268

12581269
#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0)

net/core/rtnetlink.c

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5091,10 +5091,110 @@ rtnl_offload_xstats_fill_ndo(struct net_device *dev, int attr_id,
50915091
return 0;
50925092
}
50935093

5094+
static unsigned int
5095+
rtnl_offload_xstats_get_size_stats(const struct net_device *dev,
5096+
enum netdev_offload_xstats_type type)
5097+
{
5098+
bool enabled = netdev_offload_xstats_enabled(dev, type);
5099+
5100+
return enabled ? sizeof(struct rtnl_hw_stats64) : 0;
5101+
}
5102+
5103+
struct rtnl_offload_xstats_request_used {
5104+
bool request;
5105+
bool used;
5106+
};
5107+
5108+
static int
5109+
rtnl_offload_xstats_get_stats(struct net_device *dev,
5110+
enum netdev_offload_xstats_type type,
5111+
struct rtnl_offload_xstats_request_used *ru,
5112+
struct rtnl_hw_stats64 *stats,
5113+
struct netlink_ext_ack *extack)
5114+
{
5115+
bool request;
5116+
bool used;
5117+
int err;
5118+
5119+
request = netdev_offload_xstats_enabled(dev, type);
5120+
if (!request) {
5121+
used = false;
5122+
goto out;
5123+
}
5124+
5125+
err = netdev_offload_xstats_get(dev, type, stats, &used, extack);
5126+
if (err)
5127+
return err;
5128+
5129+
out:
5130+
if (ru) {
5131+
ru->request = request;
5132+
ru->used = used;
5133+
}
5134+
return 0;
5135+
}
5136+
5137+
static int
5138+
rtnl_offload_xstats_fill_hw_s_info_one(struct sk_buff *skb, int attr_id,
5139+
struct rtnl_offload_xstats_request_used *ru)
5140+
{
5141+
struct nlattr *nest;
5142+
5143+
nest = nla_nest_start(skb, attr_id);
5144+
if (!nest)
5145+
return -EMSGSIZE;
5146+
5147+
if (nla_put_u8(skb, IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST, ru->request))
5148+
goto nla_put_failure;
5149+
5150+
if (nla_put_u8(skb, IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED, ru->used))
5151+
goto nla_put_failure;
5152+
5153+
nla_nest_end(skb, nest);
5154+
return 0;
5155+
5156+
nla_put_failure:
5157+
nla_nest_cancel(skb, nest);
5158+
return -EMSGSIZE;
5159+
}
5160+
5161+
static int
5162+
rtnl_offload_xstats_fill_hw_s_info(struct sk_buff *skb, struct net_device *dev,
5163+
struct netlink_ext_ack *extack)
5164+
{
5165+
enum netdev_offload_xstats_type t_l3 = NETDEV_OFFLOAD_XSTATS_TYPE_L3;
5166+
struct rtnl_offload_xstats_request_used ru_l3;
5167+
struct nlattr *nest;
5168+
int err;
5169+
5170+
err = rtnl_offload_xstats_get_stats(dev, t_l3, &ru_l3, NULL, extack);
5171+
if (err)
5172+
return err;
5173+
5174+
nest = nla_nest_start(skb, IFLA_OFFLOAD_XSTATS_HW_S_INFO);
5175+
if (!nest)
5176+
return -EMSGSIZE;
5177+
5178+
if (rtnl_offload_xstats_fill_hw_s_info_one(skb,
5179+
IFLA_OFFLOAD_XSTATS_L3_STATS,
5180+
&ru_l3))
5181+
goto nla_put_failure;
5182+
5183+
nla_nest_end(skb, nest);
5184+
return 0;
5185+
5186+
nla_put_failure:
5187+
nla_nest_cancel(skb, nest);
5188+
return -EMSGSIZE;
5189+
}
5190+
50945191
static int rtnl_offload_xstats_fill(struct sk_buff *skb, struct net_device *dev,
50955192
int *prividx, u32 off_filter_mask,
50965193
struct netlink_ext_ack *extack)
50975194
{
5195+
enum netdev_offload_xstats_type t_l3 = NETDEV_OFFLOAD_XSTATS_TYPE_L3;
5196+
int attr_id_hw_s_info = IFLA_OFFLOAD_XSTATS_HW_S_INFO;
5197+
int attr_id_l3_stats = IFLA_OFFLOAD_XSTATS_L3_STATS;
50985198
int attr_id_cpu_hit = IFLA_OFFLOAD_XSTATS_CPU_HIT;
50995199
bool have_data = false;
51005200
int err;
@@ -5111,16 +5211,76 @@ static int rtnl_offload_xstats_fill(struct sk_buff *skb, struct net_device *dev,
51115211
}
51125212
}
51135213

5214+
if (*prividx <= attr_id_hw_s_info &&
5215+
(off_filter_mask & IFLA_STATS_FILTER_BIT(attr_id_hw_s_info))) {
5216+
*prividx = attr_id_hw_s_info;
5217+
5218+
err = rtnl_offload_xstats_fill_hw_s_info(skb, dev, extack);
5219+
if (err)
5220+
return err;
5221+
5222+
have_data = true;
5223+
*prividx = 0;
5224+
}
5225+
5226+
if (*prividx <= attr_id_l3_stats &&
5227+
(off_filter_mask & IFLA_STATS_FILTER_BIT(attr_id_l3_stats))) {
5228+
unsigned int size_l3;
5229+
struct nlattr *attr;
5230+
5231+
*prividx = attr_id_l3_stats;
5232+
5233+
size_l3 = rtnl_offload_xstats_get_size_stats(dev, t_l3);
5234+
attr = nla_reserve_64bit(skb, attr_id_l3_stats, size_l3,
5235+
IFLA_OFFLOAD_XSTATS_UNSPEC);
5236+
if (!attr)
5237+
return -EMSGSIZE;
5238+
5239+
err = rtnl_offload_xstats_get_stats(dev, t_l3, NULL,
5240+
nla_data(attr), extack);
5241+
if (err)
5242+
return err;
5243+
5244+
have_data = true;
5245+
*prividx = 0;
5246+
}
5247+
51145248
if (!have_data)
51155249
return -ENODATA;
51165250

51175251
*prividx = 0;
51185252
return 0;
51195253
}
51205254

5255+
static unsigned int
5256+
rtnl_offload_xstats_get_size_hw_s_info_one(const struct net_device *dev,
5257+
enum netdev_offload_xstats_type type)
5258+
{
5259+
bool enabled = netdev_offload_xstats_enabled(dev, type);
5260+
5261+
return nla_total_size(0) +
5262+
/* IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST */
5263+
nla_total_size(sizeof(u8)) +
5264+
/* IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED */
5265+
(enabled ? nla_total_size(sizeof(u8)) : 0) +
5266+
0;
5267+
}
5268+
5269+
static unsigned int
5270+
rtnl_offload_xstats_get_size_hw_s_info(const struct net_device *dev)
5271+
{
5272+
enum netdev_offload_xstats_type t_l3 = NETDEV_OFFLOAD_XSTATS_TYPE_L3;
5273+
5274+
return nla_total_size(0) +
5275+
/* IFLA_OFFLOAD_XSTATS_L3_STATS */
5276+
rtnl_offload_xstats_get_size_hw_s_info_one(dev, t_l3) +
5277+
0;
5278+
}
5279+
51215280
static int rtnl_offload_xstats_get_size(const struct net_device *dev,
51225281
u32 off_filter_mask)
51235282
{
5283+
enum netdev_offload_xstats_type t_l3 = NETDEV_OFFLOAD_XSTATS_TYPE_L3;
51245284
int attr_id_cpu_hit = IFLA_OFFLOAD_XSTATS_CPU_HIT;
51255285
int nla_size = 0;
51265286
int size;
@@ -5131,6 +5291,16 @@ static int rtnl_offload_xstats_get_size(const struct net_device *dev,
51315291
nla_size += nla_total_size_64bit(size);
51325292
}
51335293

5294+
if (off_filter_mask &
5295+
IFLA_STATS_FILTER_BIT(IFLA_OFFLOAD_XSTATS_HW_S_INFO))
5296+
nla_size += rtnl_offload_xstats_get_size_hw_s_info(dev);
5297+
5298+
if (off_filter_mask &
5299+
IFLA_STATS_FILTER_BIT(IFLA_OFFLOAD_XSTATS_L3_STATS)) {
5300+
size = rtnl_offload_xstats_get_size_stats(dev, t_l3);
5301+
nla_size += nla_total_size_64bit(size);
5302+
}
5303+
51345304
if (nla_size != 0)
51355305
nla_size += nla_total_size(0);
51365306

0 commit comments

Comments
 (0)