Branch data Line data Source code
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 : 3 : rte_metrics_init(int socket_id) 60 : : { 61 : : struct rte_metrics_data_s *stats; 62 : : const struct rte_memzone *memzone; 63 : : 64 [ + - ]: 3 : if (metrics_initialized) 65 : : return 0; 66 [ + - ]: 3 : if (rte_eal_process_type() != RTE_PROC_PRIMARY) 67 : : return -E_RTE_SECONDARY; 68 : : 69 : 3 : memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 70 [ + - ]: 3 : if (memzone != NULL) 71 : : return -EEXIST; 72 : 3 : memzone = rte_memzone_reserve(RTE_METRICS_MEMZONE_NAME, 73 : : sizeof(struct rte_metrics_data_s), socket_id, 0); 74 [ + - ]: 3 : if (memzone == NULL) 75 : : return -ENOMEM; 76 : 3 : stats = memzone->addr; 77 : : memset(stats, 0, sizeof(struct rte_metrics_data_s)); 78 : : rte_spinlock_init(&stats->lock); 79 : 3 : metrics_initialized = 1; 80 : 3 : return 0; 81 : : } 82 : : 83 : : int 84 : 3 : rte_metrics_deinit(void) 85 : : { 86 : : struct rte_metrics_data_s *stats; 87 : : const struct rte_memzone *memzone; 88 : : int ret; 89 : : 90 [ + - ]: 3 : if (rte_eal_process_type() != RTE_PROC_PRIMARY) 91 : : return -EINVAL; 92 : : 93 : 3 : memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 94 [ + - ]: 3 : if (memzone == NULL) 95 : : return -EIO; 96 : : 97 : 3 : stats = memzone->addr; 98 : : memset(stats, 0, sizeof(struct rte_metrics_data_s)); 99 : : 100 : 3 : ret = rte_memzone_free(memzone); 101 [ + - ]: 3 : if (ret == 0) 102 : 3 : metrics_initialized = 0; 103 : : return ret; 104 : : } 105 : : 106 : : int 107 : 4 : rte_metrics_reg_name(const char *name) 108 : : { 109 : 4 : const char * const list_names[] = {name}; 110 : : 111 : 4 : return rte_metrics_reg_names(list_names, 1); 112 : : } 113 : : 114 : : int 115 : 9 : 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 [ + - ]: 9 : if (cnt_names < 1 || names == NULL) 125 : : return -EINVAL; 126 [ + + ]: 33 : for (idx_name = 0; idx_name < cnt_names; idx_name++) 127 [ + + ]: 25 : if (names[idx_name] == NULL) 128 : : return -EINVAL; 129 : : 130 : 8 : memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 131 [ + + ]: 8 : if (memzone == NULL) 132 : : return -EIO; 133 : 5 : stats = memzone->addr; 134 : : 135 [ + - ]: 5 : if (stats->cnt_stats + cnt_names >= RTE_METRICS_MAX_METRICS) 136 : : return -ENOMEM; 137 : : 138 : 5 : rte_spinlock_lock(&stats->lock); 139 : : 140 : : /* Overwritten later if this is actually first set.. */ 141 : 5 : stats->metadata[stats->idx_last_set].idx_next_set = stats->cnt_stats; 142 : : 143 : 5 : stats->idx_last_set = idx_base = stats->cnt_stats; 144 : : 145 [ + + ]: 21 : for (idx_name = 0; idx_name < cnt_names; idx_name++) { 146 : 16 : entry = &stats->metadata[idx_name + stats->cnt_stats]; 147 : 16 : strlcpy(entry->name, names[idx_name], RTE_METRICS_MAX_NAME_LEN); 148 : 16 : memset(entry->value, 0, sizeof(entry->value)); 149 : 16 : entry->idx_next_stat = idx_name + stats->cnt_stats + 1; 150 : : } 151 : 5 : entry->idx_next_stat = 0; 152 : 5 : entry->idx_next_set = 0; 153 : 5 : stats->cnt_stats += cnt_names; 154 : : 155 : : rte_spinlock_unlock(&stats->lock); 156 : : 157 : 5 : return idx_base; 158 : : } 159 : : 160 : : int 161 : 6 : rte_metrics_update_value(int port_id, uint16_t key, const uint64_t value) 162 : : { 163 : 6 : return rte_metrics_update_values(port_id, key, &value, 1); 164 : : } 165 : : 166 : : int 167 : 16 : 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 [ + + ]: 16 : if (port_id != RTE_METRICS_GLOBAL && 180 : : (port_id < 0 || port_id >= RTE_MAX_ETHPORTS)) 181 : : return -EINVAL; 182 : : 183 [ + + ]: 12 : if (values == NULL) 184 : : return -EINVAL; 185 : : 186 : 11 : memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 187 [ + + ]: 11 : if (memzone == NULL) 188 : : return -EIO; 189 : 9 : stats = memzone->addr; 190 : : 191 : 9 : rte_spinlock_lock(&stats->lock); 192 : : 193 [ + + ]: 9 : if (key >= stats->cnt_stats) { 194 : : rte_spinlock_unlock(&stats->lock); 195 : 1 : return -EINVAL; 196 : : } 197 : : idx_metric = key; 198 : : cnt_setsize = 1; 199 [ + - ]: 19 : while (idx_metric < stats->cnt_stats) { 200 : 19 : entry = &stats->metadata[idx_metric]; 201 [ + + ]: 19 : if (entry->idx_next_stat == 0) 202 : : break; 203 : 11 : cnt_setsize++; 204 : 11 : idx_metric++; 205 : : } 206 : : /* Check update does not cross set border */ 207 [ + + ]: 8 : if (count > cnt_setsize) { 208 : : rte_spinlock_unlock(&stats->lock); 209 : 1 : return -ERANGE; 210 : : } 211 : : 212 [ + + ]: 7 : if (port_id == RTE_METRICS_GLOBAL) 213 [ + + ]: 16 : for (idx_value = 0; idx_value < count; idx_value++) { 214 : 11 : idx_metric = key + idx_value; 215 : 11 : stats->metadata[idx_metric].global_value = 216 : 11 : values[idx_value]; 217 : : } 218 : : else 219 [ + + ]: 9 : for (idx_value = 0; idx_value < count; idx_value++) { 220 : 7 : idx_metric = key + idx_value; 221 : 7 : stats->metadata[idx_metric].value[port_id] = 222 : 7 : values[idx_value]; 223 : : } 224 : : rte_spinlock_unlock(&stats->lock); 225 : 7 : return 0; 226 : : } 227 : : 228 : : int 229 : 5 : 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 : 5 : memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 238 [ + + ]: 5 : if (memzone == NULL) 239 : : return -EIO; 240 : : 241 : 4 : stats = memzone->addr; 242 : 4 : rte_spinlock_lock(&stats->lock); 243 [ + + ]: 4 : if (names != NULL) { 244 [ + + ]: 3 : if (capacity < stats->cnt_stats) { 245 : 1 : return_value = stats->cnt_stats; 246 : : rte_spinlock_unlock(&stats->lock); 247 : 1 : return return_value; 248 : : } 249 [ + + ]: 14 : for (idx_name = 0; idx_name < stats->cnt_stats; idx_name++) 250 : 12 : strlcpy(names[idx_name].name, 251 : : stats->metadata[idx_name].name, 252 : : RTE_METRICS_MAX_NAME_LEN); 253 : : } 254 : 3 : return_value = stats->cnt_stats; 255 : : rte_spinlock_unlock(&stats->lock); 256 : 3 : return return_value; 257 : : } 258 : : 259 : : int 260 : 7 : 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 [ + + ]: 7 : if (port_id != RTE_METRICS_GLOBAL && 271 : : (port_id < 0 || port_id >= RTE_MAX_ETHPORTS)) 272 : : return -EINVAL; 273 : : 274 : 5 : memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 275 [ + + ]: 5 : if (memzone == NULL) 276 : : return -EIO; 277 : : 278 : 4 : stats = memzone->addr; 279 : 4 : rte_spinlock_lock(&stats->lock); 280 : : 281 [ + + ]: 4 : if (values != NULL) { 282 [ + + ]: 3 : if (capacity < stats->cnt_stats) { 283 : 1 : return_value = stats->cnt_stats; 284 : : rte_spinlock_unlock(&stats->lock); 285 : 1 : return return_value; 286 : : } 287 [ + - ]: 2 : if (port_id == RTE_METRICS_GLOBAL) 288 : : for (idx_name = 0; 289 [ + + ]: 14 : idx_name < stats->cnt_stats; 290 : 12 : idx_name++) { 291 : 12 : entry = &stats->metadata[idx_name]; 292 : 12 : values[idx_name].key = idx_name; 293 : 12 : values[idx_name].value = entry->global_value; 294 : : } 295 : : else 296 : : for (idx_name = 0; 297 [ # # ]: 0 : idx_name < stats->cnt_stats; 298 : 0 : idx_name++) { 299 : 0 : entry = &stats->metadata[idx_name]; 300 : 0 : values[idx_name].key = idx_name; 301 : 0 : values[idx_name].value = entry->value[port_id]; 302 : : } 303 : : } 304 : 3 : return_value = stats->cnt_stats; 305 : : rte_spinlock_unlock(&stats->lock); 306 : 3 : return return_value; 307 : : }