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