xref: /dpdk/lib/metrics/rte_metrics.c (revision 8c76e2f6937730782baa210bf456bd19da2a9600)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4 
5 #include <stdlib.h>
6 #include <string.h>
7 
8 #include <rte_common.h>
9 #include <rte_string_fns.h>
10 #include <rte_metrics.h>
11 #include <rte_memzone.h>
12 #include <rte_spinlock.h>
13 
14 int metrics_initialized;
15 
16 #define RTE_METRICS_MEMZONE_NAME "RTE_METRICS"
17 
18 /**
19  * Internal stats metadata and value entry.
20  *
21  * @internal
22  */
23 struct rte_metrics_meta_s {
24 	/** Name of metric */
25 	char name[RTE_METRICS_MAX_NAME_LEN];
26 	/** Current value for metric */
27 	uint64_t value[RTE_MAX_ETHPORTS];
28 	/** Used for global metrics */
29 	uint64_t global_value;
30 	/** Index of next root element (zero for none) */
31 	uint16_t idx_next_set;
32 	/** Index of next metric in set (zero for none) */
33 	uint16_t idx_next_stat;
34 };
35 
36 /**
37  * Internal stats info structure.
38  *
39  * @internal
40  * Offsets into metadata are used instead of pointers because ASLR
41  * means that having the same physical addresses in different
42  * processes is not guaranteed.
43  */
44 struct rte_metrics_data_s {
45 	/**   Index of last metadata entry with valid data.
46 	 * This value is not valid if cnt_stats is zero.
47 	 */
48 	uint16_t idx_last_set;
49 	/**   Number of metrics. */
50 	uint16_t cnt_stats;
51 	/** Metric data memory block. */
52 	struct rte_metrics_meta_s metadata[RTE_METRICS_MAX_METRICS];
53 	/** Metric data access lock */
54 	rte_spinlock_t lock;
55 };
56 
57 void
58 rte_metrics_init(int socket_id)
59 {
60 	struct rte_metrics_data_s *stats;
61 	const struct rte_memzone *memzone;
62 
63 	if (metrics_initialized)
64 		return;
65 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
66 		return;
67 
68 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
69 	if (memzone != NULL)
70 		return;
71 	memzone = rte_memzone_reserve(RTE_METRICS_MEMZONE_NAME,
72 		sizeof(struct rte_metrics_data_s), socket_id, 0);
73 	if (memzone == NULL)
74 		rte_exit(EXIT_FAILURE, "Unable to allocate stats memzone\n");
75 	stats = memzone->addr;
76 	memset(stats, 0, sizeof(struct rte_metrics_data_s));
77 	rte_spinlock_init(&stats->lock);
78 	metrics_initialized = 1;
79 }
80 
81 int
82 rte_metrics_deinit(void)
83 {
84 	struct rte_metrics_data_s *stats;
85 	const struct rte_memzone *memzone;
86 	int ret;
87 
88 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
89 		return -EINVAL;
90 
91 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
92 	if (memzone == NULL)
93 		return -EIO;
94 
95 	stats = memzone->addr;
96 	memset(stats, 0, sizeof(struct rte_metrics_data_s));
97 
98 	ret = rte_memzone_free(memzone);
99 	if (ret == 0)
100 		metrics_initialized = 0;
101 	return ret;
102 }
103 
104 int
105 rte_metrics_reg_name(const char *name)
106 {
107 	const char * const list_names[] = {name};
108 
109 	return rte_metrics_reg_names(list_names, 1);
110 }
111 
112 int
113 rte_metrics_reg_names(const char * const *names, uint16_t cnt_names)
114 {
115 	struct rte_metrics_meta_s *entry = NULL;
116 	struct rte_metrics_data_s *stats;
117 	const struct rte_memzone *memzone;
118 	uint16_t idx_name;
119 	uint16_t idx_base;
120 
121 	/* Some sanity checks */
122 	if (cnt_names < 1 || names == NULL)
123 		return -EINVAL;
124 	for (idx_name = 0; idx_name < cnt_names; idx_name++)
125 		if (names[idx_name] == NULL)
126 			return -EINVAL;
127 
128 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
129 	if (memzone == NULL)
130 		return -EIO;
131 	stats = memzone->addr;
132 
133 	if (stats->cnt_stats + cnt_names >= RTE_METRICS_MAX_METRICS)
134 		return -ENOMEM;
135 
136 	rte_spinlock_lock(&stats->lock);
137 
138 	/* Overwritten later if this is actually first set.. */
139 	stats->metadata[stats->idx_last_set].idx_next_set = stats->cnt_stats;
140 
141 	stats->idx_last_set = idx_base = stats->cnt_stats;
142 
143 	for (idx_name = 0; idx_name < cnt_names; idx_name++) {
144 		entry = &stats->metadata[idx_name + stats->cnt_stats];
145 		strlcpy(entry->name, names[idx_name], RTE_METRICS_MAX_NAME_LEN);
146 		memset(entry->value, 0, sizeof(entry->value));
147 		entry->idx_next_stat = idx_name + stats->cnt_stats + 1;
148 	}
149 	entry->idx_next_stat = 0;
150 	entry->idx_next_set = 0;
151 	stats->cnt_stats += cnt_names;
152 
153 	rte_spinlock_unlock(&stats->lock);
154 
155 	return idx_base;
156 }
157 
158 int
159 rte_metrics_update_value(int port_id, uint16_t key, const uint64_t value)
160 {
161 	return rte_metrics_update_values(port_id, key, &value, 1);
162 }
163 
164 int
165 rte_metrics_update_values(int port_id,
166 	uint16_t key,
167 	const uint64_t *values,
168 	uint32_t count)
169 {
170 	struct rte_metrics_meta_s *entry;
171 	struct rte_metrics_data_s *stats;
172 	const struct rte_memzone *memzone;
173 	uint16_t idx_metric;
174 	uint16_t idx_value;
175 	uint16_t cnt_setsize;
176 
177 	if (port_id != RTE_METRICS_GLOBAL &&
178 			(port_id < 0 || port_id >= RTE_MAX_ETHPORTS))
179 		return -EINVAL;
180 
181 	if (values == NULL)
182 		return -EINVAL;
183 
184 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
185 	if (memzone == NULL)
186 		return -EIO;
187 	stats = memzone->addr;
188 
189 	rte_spinlock_lock(&stats->lock);
190 
191 	if (key >= stats->cnt_stats) {
192 		rte_spinlock_unlock(&stats->lock);
193 		return -EINVAL;
194 	}
195 	idx_metric = key;
196 	cnt_setsize = 1;
197 	while (idx_metric < stats->cnt_stats) {
198 		entry = &stats->metadata[idx_metric];
199 		if (entry->idx_next_stat == 0)
200 			break;
201 		cnt_setsize++;
202 		idx_metric++;
203 	}
204 	/* Check update does not cross set border */
205 	if (count > cnt_setsize) {
206 		rte_spinlock_unlock(&stats->lock);
207 		return -ERANGE;
208 	}
209 
210 	if (port_id == RTE_METRICS_GLOBAL)
211 		for (idx_value = 0; idx_value < count; idx_value++) {
212 			idx_metric = key + idx_value;
213 			stats->metadata[idx_metric].global_value =
214 				values[idx_value];
215 		}
216 	else
217 		for (idx_value = 0; idx_value < count; idx_value++) {
218 			idx_metric = key + idx_value;
219 			stats->metadata[idx_metric].value[port_id] =
220 				values[idx_value];
221 		}
222 	rte_spinlock_unlock(&stats->lock);
223 	return 0;
224 }
225 
226 int
227 rte_metrics_get_names(struct rte_metric_name *names,
228 	uint16_t capacity)
229 {
230 	struct rte_metrics_data_s *stats;
231 	const struct rte_memzone *memzone;
232 	uint16_t idx_name;
233 	int return_value;
234 
235 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
236 	if (memzone == NULL)
237 		return -EIO;
238 
239 	stats = memzone->addr;
240 	rte_spinlock_lock(&stats->lock);
241 	if (names != NULL) {
242 		if (capacity < stats->cnt_stats) {
243 			return_value = stats->cnt_stats;
244 			rte_spinlock_unlock(&stats->lock);
245 			return return_value;
246 		}
247 		for (idx_name = 0; idx_name < stats->cnt_stats; idx_name++)
248 			strlcpy(names[idx_name].name,
249 				stats->metadata[idx_name].name,
250 				RTE_METRICS_MAX_NAME_LEN);
251 	}
252 	return_value = stats->cnt_stats;
253 	rte_spinlock_unlock(&stats->lock);
254 	return return_value;
255 }
256 
257 int
258 rte_metrics_get_values(int port_id,
259 	struct rte_metric_value *values,
260 	uint16_t capacity)
261 {
262 	struct rte_metrics_meta_s *entry;
263 	struct rte_metrics_data_s *stats;
264 	const struct rte_memzone *memzone;
265 	uint16_t idx_name;
266 	int return_value;
267 
268 	if (port_id != RTE_METRICS_GLOBAL &&
269 			(port_id < 0 || port_id >= RTE_MAX_ETHPORTS))
270 		return -EINVAL;
271 
272 	memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
273 	if (memzone == NULL)
274 		return -EIO;
275 
276 	stats = memzone->addr;
277 	rte_spinlock_lock(&stats->lock);
278 
279 	if (values != NULL) {
280 		if (capacity < stats->cnt_stats) {
281 			return_value = stats->cnt_stats;
282 			rte_spinlock_unlock(&stats->lock);
283 			return return_value;
284 		}
285 		if (port_id == RTE_METRICS_GLOBAL)
286 			for (idx_name = 0;
287 					idx_name < stats->cnt_stats;
288 					idx_name++) {
289 				entry = &stats->metadata[idx_name];
290 				values[idx_name].key = idx_name;
291 				values[idx_name].value = entry->global_value;
292 			}
293 		else
294 			for (idx_name = 0;
295 					idx_name < stats->cnt_stats;
296 					idx_name++) {
297 				entry = &stats->metadata[idx_name];
298 				values[idx_name].key = idx_name;
299 				values[idx_name].value = entry->value[port_id];
300 			}
301 	}
302 	return_value = stats->cnt_stats;
303 	rte_spinlock_unlock(&stats->lock);
304 	return return_value;
305 }
306