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