199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2017 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
572b452c5SDmitry Kozlyuk #include <stdlib.h>
699a2dd95SBruce Richardson #include <string.h>
799a2dd95SBruce Richardson
8*6d03ef60SBruce Richardson #include <rte_errno.h>
999a2dd95SBruce Richardson #include <rte_common.h>
1099a2dd95SBruce Richardson #include <rte_string_fns.h>
1199a2dd95SBruce Richardson #include <rte_metrics.h>
1299a2dd95SBruce Richardson #include <rte_memzone.h>
1399a2dd95SBruce Richardson #include <rte_spinlock.h>
1499a2dd95SBruce Richardson
1599a2dd95SBruce Richardson int metrics_initialized;
1699a2dd95SBruce Richardson
1799a2dd95SBruce Richardson #define RTE_METRICS_MEMZONE_NAME "RTE_METRICS"
1899a2dd95SBruce Richardson
1999a2dd95SBruce Richardson /**
2099a2dd95SBruce Richardson * Internal stats metadata and value entry.
2199a2dd95SBruce Richardson *
2299a2dd95SBruce Richardson * @internal
2399a2dd95SBruce Richardson */
2499a2dd95SBruce Richardson struct rte_metrics_meta_s {
2599a2dd95SBruce Richardson /** Name of metric */
2699a2dd95SBruce Richardson char name[RTE_METRICS_MAX_NAME_LEN];
2799a2dd95SBruce Richardson /** Current value for metric */
2899a2dd95SBruce Richardson uint64_t value[RTE_MAX_ETHPORTS];
2999a2dd95SBruce Richardson /** Used for global metrics */
3099a2dd95SBruce Richardson uint64_t global_value;
3199a2dd95SBruce Richardson /** Index of next root element (zero for none) */
3299a2dd95SBruce Richardson uint16_t idx_next_set;
3399a2dd95SBruce Richardson /** Index of next metric in set (zero for none) */
3499a2dd95SBruce Richardson uint16_t idx_next_stat;
3599a2dd95SBruce Richardson };
3699a2dd95SBruce Richardson
3799a2dd95SBruce Richardson /**
3899a2dd95SBruce Richardson * Internal stats info structure.
3999a2dd95SBruce Richardson *
4099a2dd95SBruce Richardson * @internal
4199a2dd95SBruce Richardson * Offsets into metadata are used instead of pointers because ASLR
4299a2dd95SBruce Richardson * means that having the same physical addresses in different
4399a2dd95SBruce Richardson * processes is not guaranteed.
4499a2dd95SBruce Richardson */
4599a2dd95SBruce Richardson struct rte_metrics_data_s {
4699a2dd95SBruce Richardson /** Index of last metadata entry with valid data.
4799a2dd95SBruce Richardson * This value is not valid if cnt_stats is zero.
4899a2dd95SBruce Richardson */
4999a2dd95SBruce Richardson uint16_t idx_last_set;
5099a2dd95SBruce Richardson /** Number of metrics. */
5199a2dd95SBruce Richardson uint16_t cnt_stats;
5299a2dd95SBruce Richardson /** Metric data memory block. */
5399a2dd95SBruce Richardson struct rte_metrics_meta_s metadata[RTE_METRICS_MAX_METRICS];
5499a2dd95SBruce Richardson /** Metric data access lock */
5599a2dd95SBruce Richardson rte_spinlock_t lock;
5699a2dd95SBruce Richardson };
5799a2dd95SBruce Richardson
58*6d03ef60SBruce Richardson int
rte_metrics_init(int socket_id)5999a2dd95SBruce Richardson rte_metrics_init(int socket_id)
6099a2dd95SBruce Richardson {
6199a2dd95SBruce Richardson struct rte_metrics_data_s *stats;
6299a2dd95SBruce Richardson const struct rte_memzone *memzone;
6399a2dd95SBruce Richardson
6499a2dd95SBruce Richardson if (metrics_initialized)
65*6d03ef60SBruce Richardson return 0;
6699a2dd95SBruce Richardson if (rte_eal_process_type() != RTE_PROC_PRIMARY)
67*6d03ef60SBruce Richardson return -E_RTE_SECONDARY;
6899a2dd95SBruce Richardson
6999a2dd95SBruce Richardson memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
7099a2dd95SBruce Richardson if (memzone != NULL)
71*6d03ef60SBruce Richardson return -EEXIST;
7299a2dd95SBruce Richardson memzone = rte_memzone_reserve(RTE_METRICS_MEMZONE_NAME,
7399a2dd95SBruce Richardson sizeof(struct rte_metrics_data_s), socket_id, 0);
7499a2dd95SBruce Richardson if (memzone == NULL)
75*6d03ef60SBruce Richardson return -ENOMEM;
7699a2dd95SBruce Richardson stats = memzone->addr;
7799a2dd95SBruce Richardson memset(stats, 0, sizeof(struct rte_metrics_data_s));
7899a2dd95SBruce Richardson rte_spinlock_init(&stats->lock);
7999a2dd95SBruce Richardson metrics_initialized = 1;
80*6d03ef60SBruce Richardson return 0;
8199a2dd95SBruce Richardson }
8299a2dd95SBruce Richardson
8399a2dd95SBruce Richardson int
rte_metrics_deinit(void)8499a2dd95SBruce Richardson rte_metrics_deinit(void)
8599a2dd95SBruce Richardson {
8699a2dd95SBruce Richardson struct rte_metrics_data_s *stats;
8799a2dd95SBruce Richardson const struct rte_memzone *memzone;
8899a2dd95SBruce Richardson int ret;
8999a2dd95SBruce Richardson
9099a2dd95SBruce Richardson if (rte_eal_process_type() != RTE_PROC_PRIMARY)
9199a2dd95SBruce Richardson return -EINVAL;
9299a2dd95SBruce Richardson
9399a2dd95SBruce Richardson memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
9499a2dd95SBruce Richardson if (memzone == NULL)
9599a2dd95SBruce Richardson return -EIO;
9699a2dd95SBruce Richardson
9799a2dd95SBruce Richardson stats = memzone->addr;
9899a2dd95SBruce Richardson memset(stats, 0, sizeof(struct rte_metrics_data_s));
9999a2dd95SBruce Richardson
10099a2dd95SBruce Richardson ret = rte_memzone_free(memzone);
10199a2dd95SBruce Richardson if (ret == 0)
10299a2dd95SBruce Richardson metrics_initialized = 0;
10399a2dd95SBruce Richardson return ret;
10499a2dd95SBruce Richardson }
10599a2dd95SBruce Richardson
10699a2dd95SBruce Richardson int
rte_metrics_reg_name(const char * name)10799a2dd95SBruce Richardson rte_metrics_reg_name(const char *name)
10899a2dd95SBruce Richardson {
10999a2dd95SBruce Richardson const char * const list_names[] = {name};
11099a2dd95SBruce Richardson
11199a2dd95SBruce Richardson return rte_metrics_reg_names(list_names, 1);
11299a2dd95SBruce Richardson }
11399a2dd95SBruce Richardson
11499a2dd95SBruce Richardson int
rte_metrics_reg_names(const char * const * names,uint16_t cnt_names)11599a2dd95SBruce Richardson rte_metrics_reg_names(const char * const *names, uint16_t cnt_names)
11699a2dd95SBruce Richardson {
11799a2dd95SBruce Richardson struct rte_metrics_meta_s *entry = NULL;
11899a2dd95SBruce Richardson struct rte_metrics_data_s *stats;
11999a2dd95SBruce Richardson const struct rte_memzone *memzone;
12099a2dd95SBruce Richardson uint16_t idx_name;
12199a2dd95SBruce Richardson uint16_t idx_base;
12299a2dd95SBruce Richardson
12399a2dd95SBruce Richardson /* Some sanity checks */
12499a2dd95SBruce Richardson if (cnt_names < 1 || names == NULL)
12599a2dd95SBruce Richardson return -EINVAL;
12699a2dd95SBruce Richardson for (idx_name = 0; idx_name < cnt_names; idx_name++)
12799a2dd95SBruce Richardson if (names[idx_name] == NULL)
12899a2dd95SBruce Richardson return -EINVAL;
12999a2dd95SBruce Richardson
13099a2dd95SBruce Richardson memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
13199a2dd95SBruce Richardson if (memzone == NULL)
13299a2dd95SBruce Richardson return -EIO;
13399a2dd95SBruce Richardson stats = memzone->addr;
13499a2dd95SBruce Richardson
13599a2dd95SBruce Richardson if (stats->cnt_stats + cnt_names >= RTE_METRICS_MAX_METRICS)
13699a2dd95SBruce Richardson return -ENOMEM;
13799a2dd95SBruce Richardson
13899a2dd95SBruce Richardson rte_spinlock_lock(&stats->lock);
13999a2dd95SBruce Richardson
14099a2dd95SBruce Richardson /* Overwritten later if this is actually first set.. */
14199a2dd95SBruce Richardson stats->metadata[stats->idx_last_set].idx_next_set = stats->cnt_stats;
14299a2dd95SBruce Richardson
14399a2dd95SBruce Richardson stats->idx_last_set = idx_base = stats->cnt_stats;
14499a2dd95SBruce Richardson
14599a2dd95SBruce Richardson for (idx_name = 0; idx_name < cnt_names; idx_name++) {
14699a2dd95SBruce Richardson entry = &stats->metadata[idx_name + stats->cnt_stats];
14799a2dd95SBruce Richardson strlcpy(entry->name, names[idx_name], RTE_METRICS_MAX_NAME_LEN);
14899a2dd95SBruce Richardson memset(entry->value, 0, sizeof(entry->value));
14999a2dd95SBruce Richardson entry->idx_next_stat = idx_name + stats->cnt_stats + 1;
15099a2dd95SBruce Richardson }
15199a2dd95SBruce Richardson entry->idx_next_stat = 0;
15299a2dd95SBruce Richardson entry->idx_next_set = 0;
15399a2dd95SBruce Richardson stats->cnt_stats += cnt_names;
15499a2dd95SBruce Richardson
15599a2dd95SBruce Richardson rte_spinlock_unlock(&stats->lock);
15699a2dd95SBruce Richardson
15799a2dd95SBruce Richardson return idx_base;
15899a2dd95SBruce Richardson }
15999a2dd95SBruce Richardson
16099a2dd95SBruce Richardson int
rte_metrics_update_value(int port_id,uint16_t key,const uint64_t value)16199a2dd95SBruce Richardson rte_metrics_update_value(int port_id, uint16_t key, const uint64_t value)
16299a2dd95SBruce Richardson {
16399a2dd95SBruce Richardson return rte_metrics_update_values(port_id, key, &value, 1);
16499a2dd95SBruce Richardson }
16599a2dd95SBruce Richardson
16699a2dd95SBruce Richardson int
rte_metrics_update_values(int port_id,uint16_t key,const uint64_t * values,uint32_t count)16799a2dd95SBruce Richardson rte_metrics_update_values(int port_id,
16899a2dd95SBruce Richardson uint16_t key,
16999a2dd95SBruce Richardson const uint64_t *values,
17099a2dd95SBruce Richardson uint32_t count)
17199a2dd95SBruce Richardson {
17299a2dd95SBruce Richardson struct rte_metrics_meta_s *entry;
17399a2dd95SBruce Richardson struct rte_metrics_data_s *stats;
17499a2dd95SBruce Richardson const struct rte_memzone *memzone;
17599a2dd95SBruce Richardson uint16_t idx_metric;
17699a2dd95SBruce Richardson uint16_t idx_value;
17799a2dd95SBruce Richardson uint16_t cnt_setsize;
17899a2dd95SBruce Richardson
17999a2dd95SBruce Richardson if (port_id != RTE_METRICS_GLOBAL &&
18099a2dd95SBruce Richardson (port_id < 0 || port_id >= RTE_MAX_ETHPORTS))
18199a2dd95SBruce Richardson return -EINVAL;
18299a2dd95SBruce Richardson
18399a2dd95SBruce Richardson if (values == NULL)
18499a2dd95SBruce Richardson return -EINVAL;
18599a2dd95SBruce Richardson
18699a2dd95SBruce Richardson memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
18799a2dd95SBruce Richardson if (memzone == NULL)
18899a2dd95SBruce Richardson return -EIO;
18999a2dd95SBruce Richardson stats = memzone->addr;
19099a2dd95SBruce Richardson
19199a2dd95SBruce Richardson rte_spinlock_lock(&stats->lock);
19299a2dd95SBruce Richardson
19399a2dd95SBruce Richardson if (key >= stats->cnt_stats) {
19499a2dd95SBruce Richardson rte_spinlock_unlock(&stats->lock);
19599a2dd95SBruce Richardson return -EINVAL;
19699a2dd95SBruce Richardson }
19799a2dd95SBruce Richardson idx_metric = key;
19899a2dd95SBruce Richardson cnt_setsize = 1;
19999a2dd95SBruce Richardson while (idx_metric < stats->cnt_stats) {
20099a2dd95SBruce Richardson entry = &stats->metadata[idx_metric];
20199a2dd95SBruce Richardson if (entry->idx_next_stat == 0)
20299a2dd95SBruce Richardson break;
20399a2dd95SBruce Richardson cnt_setsize++;
20499a2dd95SBruce Richardson idx_metric++;
20599a2dd95SBruce Richardson }
20699a2dd95SBruce Richardson /* Check update does not cross set border */
20799a2dd95SBruce Richardson if (count > cnt_setsize) {
20899a2dd95SBruce Richardson rte_spinlock_unlock(&stats->lock);
20999a2dd95SBruce Richardson return -ERANGE;
21099a2dd95SBruce Richardson }
21199a2dd95SBruce Richardson
21299a2dd95SBruce Richardson if (port_id == RTE_METRICS_GLOBAL)
21399a2dd95SBruce Richardson for (idx_value = 0; idx_value < count; idx_value++) {
21499a2dd95SBruce Richardson idx_metric = key + idx_value;
21599a2dd95SBruce Richardson stats->metadata[idx_metric].global_value =
21699a2dd95SBruce Richardson values[idx_value];
21799a2dd95SBruce Richardson }
21899a2dd95SBruce Richardson else
21999a2dd95SBruce Richardson for (idx_value = 0; idx_value < count; idx_value++) {
22099a2dd95SBruce Richardson idx_metric = key + idx_value;
22199a2dd95SBruce Richardson stats->metadata[idx_metric].value[port_id] =
22299a2dd95SBruce Richardson values[idx_value];
22399a2dd95SBruce Richardson }
22499a2dd95SBruce Richardson rte_spinlock_unlock(&stats->lock);
22599a2dd95SBruce Richardson return 0;
22699a2dd95SBruce Richardson }
22799a2dd95SBruce Richardson
22899a2dd95SBruce Richardson int
rte_metrics_get_names(struct rte_metric_name * names,uint16_t capacity)22999a2dd95SBruce Richardson rte_metrics_get_names(struct rte_metric_name *names,
23099a2dd95SBruce Richardson uint16_t capacity)
23199a2dd95SBruce Richardson {
23299a2dd95SBruce Richardson struct rte_metrics_data_s *stats;
23399a2dd95SBruce Richardson const struct rte_memzone *memzone;
23499a2dd95SBruce Richardson uint16_t idx_name;
23599a2dd95SBruce Richardson int return_value;
23699a2dd95SBruce Richardson
23799a2dd95SBruce Richardson memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
23899a2dd95SBruce Richardson if (memzone == NULL)
23999a2dd95SBruce Richardson return -EIO;
24099a2dd95SBruce Richardson
24199a2dd95SBruce Richardson stats = memzone->addr;
24299a2dd95SBruce Richardson rte_spinlock_lock(&stats->lock);
24399a2dd95SBruce Richardson if (names != NULL) {
24499a2dd95SBruce Richardson if (capacity < stats->cnt_stats) {
24599a2dd95SBruce Richardson return_value = stats->cnt_stats;
24699a2dd95SBruce Richardson rte_spinlock_unlock(&stats->lock);
24799a2dd95SBruce Richardson return return_value;
24899a2dd95SBruce Richardson }
24999a2dd95SBruce Richardson for (idx_name = 0; idx_name < stats->cnt_stats; idx_name++)
25099a2dd95SBruce Richardson strlcpy(names[idx_name].name,
25199a2dd95SBruce Richardson stats->metadata[idx_name].name,
25299a2dd95SBruce Richardson RTE_METRICS_MAX_NAME_LEN);
25399a2dd95SBruce Richardson }
25499a2dd95SBruce Richardson return_value = stats->cnt_stats;
25599a2dd95SBruce Richardson rte_spinlock_unlock(&stats->lock);
25699a2dd95SBruce Richardson return return_value;
25799a2dd95SBruce Richardson }
25899a2dd95SBruce Richardson
25999a2dd95SBruce Richardson int
rte_metrics_get_values(int port_id,struct rte_metric_value * values,uint16_t capacity)26099a2dd95SBruce Richardson rte_metrics_get_values(int port_id,
26199a2dd95SBruce Richardson struct rte_metric_value *values,
26299a2dd95SBruce Richardson uint16_t capacity)
26399a2dd95SBruce Richardson {
26499a2dd95SBruce Richardson struct rte_metrics_meta_s *entry;
26599a2dd95SBruce Richardson struct rte_metrics_data_s *stats;
26699a2dd95SBruce Richardson const struct rte_memzone *memzone;
26799a2dd95SBruce Richardson uint16_t idx_name;
26899a2dd95SBruce Richardson int return_value;
26999a2dd95SBruce Richardson
27099a2dd95SBruce Richardson if (port_id != RTE_METRICS_GLOBAL &&
27199a2dd95SBruce Richardson (port_id < 0 || port_id >= RTE_MAX_ETHPORTS))
27299a2dd95SBruce Richardson return -EINVAL;
27399a2dd95SBruce Richardson
27499a2dd95SBruce Richardson memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME);
27599a2dd95SBruce Richardson if (memzone == NULL)
27699a2dd95SBruce Richardson return -EIO;
27799a2dd95SBruce Richardson
27899a2dd95SBruce Richardson stats = memzone->addr;
27999a2dd95SBruce Richardson rte_spinlock_lock(&stats->lock);
28099a2dd95SBruce Richardson
28199a2dd95SBruce Richardson if (values != NULL) {
28299a2dd95SBruce Richardson if (capacity < stats->cnt_stats) {
28399a2dd95SBruce Richardson return_value = stats->cnt_stats;
28499a2dd95SBruce Richardson rte_spinlock_unlock(&stats->lock);
28599a2dd95SBruce Richardson return return_value;
28699a2dd95SBruce Richardson }
28799a2dd95SBruce Richardson if (port_id == RTE_METRICS_GLOBAL)
28899a2dd95SBruce Richardson for (idx_name = 0;
28999a2dd95SBruce Richardson idx_name < stats->cnt_stats;
29099a2dd95SBruce Richardson idx_name++) {
29199a2dd95SBruce Richardson entry = &stats->metadata[idx_name];
29299a2dd95SBruce Richardson values[idx_name].key = idx_name;
29399a2dd95SBruce Richardson values[idx_name].value = entry->global_value;
29499a2dd95SBruce Richardson }
29599a2dd95SBruce Richardson else
29699a2dd95SBruce Richardson for (idx_name = 0;
29799a2dd95SBruce Richardson idx_name < stats->cnt_stats;
29899a2dd95SBruce Richardson idx_name++) {
29999a2dd95SBruce Richardson entry = &stats->metadata[idx_name];
30099a2dd95SBruce Richardson values[idx_name].key = idx_name;
30199a2dd95SBruce Richardson values[idx_name].value = entry->value[port_id];
30299a2dd95SBruce Richardson }
30399a2dd95SBruce Richardson }
30499a2dd95SBruce Richardson return_value = stats->cnt_stats;
30599a2dd95SBruce Richardson rte_spinlock_unlock(&stats->lock);
30699a2dd95SBruce Richardson return return_value;
30799a2dd95SBruce Richardson }
308