xref: /linux/tools/net/ynl/samples/page-pool.c (revision ea518afc992032f7570c0a89ac9240b387dc0faf)
1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 
4 #include <stdio.h>
5 #include <string.h>
6 
7 #include <ynl.h>
8 
9 #include <net/if.h>
10 
11 #include "netdev-user.h"
12 
13 struct stat {
14 	unsigned int ifc;
15 
16 	struct {
17 		unsigned int cnt;
18 		size_t refs, bytes;
19 	} live[2];
20 
21 	size_t alloc_slow, alloc_fast, recycle_ring, recycle_cache;
22 };
23 
24 struct stats_array {
25 	unsigned int i, max;
26 	struct stat *s;
27 };
28 
29 static struct stat *find_ifc(struct stats_array *a, unsigned int ifindex)
30 {
31 	unsigned int i;
32 
33 	for (i = 0; i < a->i; i++) {
34 		if (a->s[i].ifc == ifindex)
35 			return &a->s[i];
36 	}
37 
38 	a->i++;
39 	if (a->i == a->max) {
40 		a->max *= 2;
41 		a->s = reallocarray(a->s, a->max, sizeof(*a->s));
42 	}
43 	a->s[i].ifc = ifindex;
44 	return &a->s[i];
45 }
46 
47 static void count(struct stat *s, unsigned int l,
48 		  struct netdev_page_pool_get_rsp *pp)
49 {
50 	s->live[l].cnt++;
51 	if (pp->_present.inflight)
52 		s->live[l].refs += pp->inflight;
53 	if (pp->_present.inflight_mem)
54 		s->live[l].bytes += pp->inflight_mem;
55 }
56 
57 int main(int argc, char **argv)
58 {
59 	struct netdev_page_pool_stats_get_list *pp_stats;
60 	struct netdev_page_pool_get_list *pools;
61 	struct stats_array a = {};
62 	struct ynl_error yerr;
63 	struct ynl_sock *ys;
64 
65 	ys = ynl_sock_create(&ynl_netdev_family, &yerr);
66 	if (!ys) {
67 		fprintf(stderr, "YNL: %s\n", yerr.msg);
68 		return 1;
69 	}
70 
71 	a.max = 128;
72 	a.s = calloc(a.max, sizeof(*a.s));
73 	if (!a.s)
74 		goto err_close;
75 
76 	pools = netdev_page_pool_get_dump(ys);
77 	if (!pools)
78 		goto err_free;
79 
80 	ynl_dump_foreach(pools, pp) {
81 		struct stat *s = find_ifc(&a, pp->ifindex);
82 
83 		count(s, 1, pp);
84 		if (pp->_present.detach_time)
85 			count(s, 0, pp);
86 	}
87 	netdev_page_pool_get_list_free(pools);
88 
89 	pp_stats = netdev_page_pool_stats_get_dump(ys);
90 	if (!pp_stats)
91 		goto err_free;
92 
93 	ynl_dump_foreach(pp_stats, pp) {
94 		struct stat *s = find_ifc(&a, pp->info.ifindex);
95 
96 		if (pp->_present.alloc_fast)
97 			s->alloc_fast += pp->alloc_fast;
98 		if (pp->_present.alloc_slow)
99 			s->alloc_slow += pp->alloc_slow;
100 		if (pp->_present.recycle_ring)
101 			s->recycle_ring += pp->recycle_ring;
102 		if (pp->_present.recycle_cached)
103 			s->recycle_cache += pp->recycle_cached;
104 	}
105 	netdev_page_pool_stats_get_list_free(pp_stats);
106 
107 	for (unsigned int i = 0; i < a.i; i++) {
108 		char ifname[IF_NAMESIZE];
109 		struct stat *s = &a.s[i];
110 		const char *name;
111 		double recycle;
112 
113 		if (!s->ifc) {
114 			name = "<orphan>\t";
115 		} else {
116 			name = if_indextoname(s->ifc, ifname);
117 			if (name)
118 				printf("%8s", name);
119 			printf("[%d]\t", s->ifc);
120 		}
121 
122 		printf("page pools: %u (zombies: %u)\n",
123 		       s->live[1].cnt, s->live[0].cnt);
124 		printf("\t\trefs: %zu bytes: %zu (refs: %zu bytes: %zu)\n",
125 		       s->live[1].refs, s->live[1].bytes,
126 		       s->live[0].refs, s->live[0].bytes);
127 
128 		/* We don't know how many pages are sitting in cache and ring
129 		 * so we will under-count the recycling rate a bit.
130 		 */
131 		recycle = (double)(s->recycle_ring + s->recycle_cache) /
132 			(s->alloc_fast + s->alloc_slow) * 100;
133 		printf("\t\trecycling: %.1lf%% (alloc: %zu:%zu recycle: %zu:%zu)\n",
134 		       recycle, s->alloc_slow, s->alloc_fast,
135 		       s->recycle_ring, s->recycle_cache);
136 	}
137 
138 	ynl_sock_destroy(ys);
139 	return 0;
140 
141 err_free:
142 	free(a.s);
143 err_close:
144 	fprintf(stderr, "YNL: %s\n", ys->err.msg);
145 	ynl_sock_destroy(ys);
146 	return 2;
147 }
148