forked from mirrors/linux
		
	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:
		
							parent
							
								
									9309f97aef
								
							
						
					
					
						commit
						0e7788fd76
					
				
					 2 changed files with 181 additions and 0 deletions
				
			
		| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue