]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2017 Intel Corporation | |
3 | */ | |
4 | ||
5 | #include <string.h> | |
6 | #include <sys/queue.h> | |
7 | ||
8 | #include <rte_common.h> | |
9 | #include <rte_string_fns.h> | |
10 | #include <rte_malloc.h> | |
11 | #include <rte_metrics.h> | |
12 | #include <rte_lcore.h> | |
13 | #include <rte_memzone.h> | |
14 | #include <rte_spinlock.h> | |
15 | ||
f67539c2 TL |
16 | int metrics_initialized; |
17 | ||
11fdf7f2 TL |
18 | #define RTE_METRICS_MEMZONE_NAME "RTE_METRICS" |
19 | ||
20 | /** | |
21 | * Internal stats metadata and value entry. | |
22 | * | |
23 | * @internal | |
24 | */ | |
25 | struct rte_metrics_meta_s { | |
26 | /** Name of metric */ | |
27 | char name[RTE_METRICS_MAX_NAME_LEN]; | |
28 | /** Current value for metric */ | |
29 | uint64_t value[RTE_MAX_ETHPORTS]; | |
30 | /** Used for global metrics */ | |
31 | uint64_t global_value; | |
32 | /** Index of next root element (zero for none) */ | |
33 | uint16_t idx_next_set; | |
34 | /** Index of next metric in set (zero for none) */ | |
35 | uint16_t idx_next_stat; | |
36 | }; | |
37 | ||
38 | /** | |
39 | * Internal stats info structure. | |
40 | * | |
41 | * @internal | |
42 | * Offsets into metadata are used instead of pointers because ASLR | |
43 | * means that having the same physical addresses in different | |
44 | * processes is not guaranteed. | |
45 | */ | |
46 | struct rte_metrics_data_s { | |
47 | /** Index of last metadata entry with valid data. | |
48 | * This value is not valid if cnt_stats is zero. | |
49 | */ | |
50 | uint16_t idx_last_set; | |
51 | /** Number of metrics. */ | |
52 | uint16_t cnt_stats; | |
53 | /** Metric data memory block. */ | |
54 | struct rte_metrics_meta_s metadata[RTE_METRICS_MAX_METRICS]; | |
55 | /** Metric data access lock */ | |
56 | rte_spinlock_t lock; | |
57 | }; | |
58 | ||
59 | void | |
60 | rte_metrics_init(int socket_id) | |
61 | { | |
62 | struct rte_metrics_data_s *stats; | |
63 | const struct rte_memzone *memzone; | |
64 | ||
f67539c2 TL |
65 | if (metrics_initialized) |
66 | return; | |
11fdf7f2 TL |
67 | if (rte_eal_process_type() != RTE_PROC_PRIMARY) |
68 | return; | |
69 | ||
70 | memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); | |
71 | if (memzone != NULL) | |
72 | return; | |
73 | memzone = rte_memzone_reserve(RTE_METRICS_MEMZONE_NAME, | |
74 | sizeof(struct rte_metrics_data_s), socket_id, 0); | |
75 | if (memzone == NULL) | |
76 | rte_exit(EXIT_FAILURE, "Unable to allocate stats memzone\n"); | |
77 | stats = memzone->addr; | |
78 | memset(stats, 0, sizeof(struct rte_metrics_data_s)); | |
79 | rte_spinlock_init(&stats->lock); | |
f67539c2 TL |
80 | metrics_initialized = 1; |
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; | |
11fdf7f2 TL |
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 | } |