New upstream version 18.02
[deb_dpdk.git] / lib / librte_metrics / rte_metrics.c
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_malloc.h>
10 #include <rte_metrics.h>
11 #include <rte_lcore.h>
12 #include <rte_memzone.h>
13 #include <rte_spinlock.h>
14
15 #define RTE_METRICS_MAX_METRICS 256
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 (rte_eal_process_type() != RTE_PROC_PRIMARY)
64                 return;
65
66         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
67         if (memzone != NULL)
68                 return;
69         memzone = rte_memzone_reserve(RTE_METRICS_MEMZONE_NAME,
70                 sizeof(struct rte_metrics_data_s), socket_id, 0);
71         if (memzone == NULL)
72                 rte_exit(EXIT_FAILURE, "Unable to allocate stats memzone\n");
73         stats = memzone->addr;
74         memset(stats, 0, sizeof(struct rte_metrics_data_s));
75         rte_spinlock_init(&stats->lock);
76 }
77
78 int
79 rte_metrics_reg_name(const char *name)
80 {
81         const char * const list_names[] = {name};
82
83         return rte_metrics_reg_names(list_names, 1);
84 }
85
86 int
87 rte_metrics_reg_names(const char * const *names, uint16_t cnt_names)
88 {
89         struct rte_metrics_meta_s *entry = NULL;
90         struct rte_metrics_data_s *stats;
91         const struct rte_memzone *memzone;
92         uint16_t idx_name;
93         uint16_t idx_base;
94
95         /* Some sanity checks */
96         if (cnt_names < 1 || names == NULL)
97                 return -EINVAL;
98
99         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
100         if (memzone == NULL)
101                 return -EIO;
102         stats = memzone->addr;
103
104         if (stats->cnt_stats + cnt_names >= RTE_METRICS_MAX_METRICS)
105                 return -ENOMEM;
106
107         rte_spinlock_lock(&stats->lock);
108
109         /* Overwritten later if this is actually first set.. */
110         stats->metadata[stats->idx_last_set].idx_next_set = stats->cnt_stats;
111
112         stats->idx_last_set = idx_base = stats->cnt_stats;
113
114         for (idx_name = 0; idx_name < cnt_names; idx_name++) {
115                 entry = &stats->metadata[idx_name + stats->cnt_stats];
116                 strncpy(entry->name, names[idx_name],
117                         RTE_METRICS_MAX_NAME_LEN);
118                 /* Enforce NULL-termination */
119                 entry->name[RTE_METRICS_MAX_NAME_LEN - 1] = '\0';
120                 memset(entry->value, 0, sizeof(entry->value));
121                 entry->idx_next_stat = idx_name + stats->cnt_stats + 1;
122         }
123         entry->idx_next_stat = 0;
124         entry->idx_next_set = 0;
125         stats->cnt_stats += cnt_names;
126
127         rte_spinlock_unlock(&stats->lock);
128
129         return idx_base;
130 }
131
132 int
133 rte_metrics_update_value(int port_id, uint16_t key, const uint64_t value)
134 {
135         return rte_metrics_update_values(port_id, key, &value, 1);
136 }
137
138 int
139 rte_metrics_update_values(int port_id,
140         uint16_t key,
141         const uint64_t *values,
142         uint32_t count)
143 {
144         struct rte_metrics_meta_s *entry;
145         struct rte_metrics_data_s *stats;
146         const struct rte_memzone *memzone;
147         uint16_t idx_metric;
148         uint16_t idx_value;
149         uint16_t cnt_setsize;
150
151         if (port_id != RTE_METRICS_GLOBAL &&
152                         (port_id < 0 || port_id >= RTE_MAX_ETHPORTS))
153                 return -EINVAL;
154
155         if (values == NULL)
156                 return -EINVAL;
157
158         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
159         if (memzone == NULL)
160                 return -EIO;
161         stats = memzone->addr;
162
163         rte_spinlock_lock(&stats->lock);
164         idx_metric = key;
165         cnt_setsize = 1;
166         while (idx_metric < stats->cnt_stats) {
167                 entry = &stats->metadata[idx_metric];
168                 if (entry->idx_next_stat == 0)
169                         break;
170                 cnt_setsize++;
171                 idx_metric++;
172         }
173         /* Check update does not cross set border */
174         if (count > cnt_setsize) {
175                 rte_spinlock_unlock(&stats->lock);
176                 return -ERANGE;
177         }
178
179         if (port_id == RTE_METRICS_GLOBAL)
180                 for (idx_value = 0; idx_value < count; idx_value++) {
181                         idx_metric = key + idx_value;
182                         stats->metadata[idx_metric].global_value =
183                                 values[idx_value];
184                 }
185         else
186                 for (idx_value = 0; idx_value < count; idx_value++) {
187                         idx_metric = key + idx_value;
188                         stats->metadata[idx_metric].value[port_id] =
189                                 values[idx_value];
190                 }
191         rte_spinlock_unlock(&stats->lock);
192         return 0;
193 }
194
195 int
196 rte_metrics_get_names(struct rte_metric_name *names,
197         uint16_t capacity)
198 {
199         struct rte_metrics_data_s *stats;
200         const struct rte_memzone *memzone;
201         uint16_t idx_name;
202         int return_value;
203
204         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
205         /* If not allocated, fail silently */
206         if (memzone == NULL)
207                 return 0;
208
209         stats = memzone->addr;
210         rte_spinlock_lock(&stats->lock);
211         if (names != NULL) {
212                 if (capacity < stats->cnt_stats) {
213                         return_value = stats->cnt_stats;
214                         rte_spinlock_unlock(&stats->lock);
215                         return return_value;
216                 }
217                 for (idx_name = 0; idx_name < stats->cnt_stats; idx_name++)
218                         strncpy(names[idx_name].name,
219                                 stats->metadata[idx_name].name,
220                                 RTE_METRICS_MAX_NAME_LEN);
221         }
222         return_value = stats->cnt_stats;
223         rte_spinlock_unlock(&stats->lock);
224         return return_value;
225 }
226
227 int
228 rte_metrics_get_values(int port_id,
229         struct rte_metric_value *values,
230         uint16_t capacity)
231 {
232         struct rte_metrics_meta_s *entry;
233         struct rte_metrics_data_s *stats;
234         const struct rte_memzone *memzone;
235         uint16_t idx_name;
236         int return_value;
237
238         if (port_id != RTE_METRICS_GLOBAL &&
239                         (port_id < 0 || port_id >= RTE_MAX_ETHPORTS))
240                 return -EINVAL;
241
242         memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
243         /* If not allocated, fail silently */
244         if (memzone == NULL)
245                 return 0;
246         stats = memzone->addr;
247         rte_spinlock_lock(&stats->lock);
248
249         if (values != NULL) {
250                 if (capacity < stats->cnt_stats) {
251                         return_value = stats->cnt_stats;
252                         rte_spinlock_unlock(&stats->lock);
253                         return return_value;
254                 }
255                 if (port_id == RTE_METRICS_GLOBAL)
256                         for (idx_name = 0;
257                                         idx_name < stats->cnt_stats;
258                                         idx_name++) {
259                                 entry = &stats->metadata[idx_name];
260                                 values[idx_name].key = idx_name;
261                                 values[idx_name].value = entry->global_value;
262                         }
263                 else
264                         for (idx_name = 0;
265                                         idx_name < stats->cnt_stats;
266                                         idx_name++) {
267                                 entry = &stats->metadata[idx_name];
268                                 values[idx_name].key = idx_name;
269                                 values[idx_name].value = entry->value[port_id];
270                         }
271         }
272         return_value = stats->cnt_stats;
273         rte_spinlock_unlock(&stats->lock);
274         return return_value;
275 }