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