1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2017 Intel Corporation 3 */ 4 5 #include <string.h> 6 7 #include <rte_common.h> 8 #include <rte_string_fns.h> 9 #include <rte_metrics.h> 10 #include <rte_memzone.h> 11 #include <rte_spinlock.h> 12 13 int metrics_initialized; 14 15 #define RTE_METRICS_MEMZONE_NAME "RTE_METRICS" 16 17 /** 18 * Internal stats metadata and value entry. 19 * 20 * @internal 21 */ 22 struct rte_metrics_meta_s { 23 /** Name of metric */ 24 char name[RTE_METRICS_MAX_NAME_LEN]; 25 /** Current value for metric */ 26 uint64_t value[RTE_MAX_ETHPORTS]; 27 /** Used for global metrics */ 28 uint64_t global_value; 29 /** Index of next root element (zero for none) */ 30 uint16_t idx_next_set; 31 /** Index of next metric in set (zero for none) */ 32 uint16_t idx_next_stat; 33 }; 34 35 /** 36 * Internal stats info structure. 37 * 38 * @internal 39 * Offsets into metadata are used instead of pointers because ASLR 40 * means that having the same physical addresses in different 41 * processes is not guaranteed. 42 */ 43 struct rte_metrics_data_s { 44 /** Index of last metadata entry with valid data. 45 * This value is not valid if cnt_stats is zero. 46 */ 47 uint16_t idx_last_set; 48 /** Number of metrics. */ 49 uint16_t cnt_stats; 50 /** Metric data memory block. */ 51 struct rte_metrics_meta_s metadata[RTE_METRICS_MAX_METRICS]; 52 /** Metric data access lock */ 53 rte_spinlock_t lock; 54 }; 55 56 void 57 rte_metrics_init(int socket_id) 58 { 59 struct rte_metrics_data_s *stats; 60 const struct rte_memzone *memzone; 61 62 if (metrics_initialized) 63 return; 64 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 65 return; 66 67 memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 68 if (memzone != NULL) 69 return; 70 memzone = rte_memzone_reserve(RTE_METRICS_MEMZONE_NAME, 71 sizeof(struct rte_metrics_data_s), socket_id, 0); 72 if (memzone == NULL) 73 rte_exit(EXIT_FAILURE, "Unable to allocate stats memzone\n"); 74 stats = memzone->addr; 75 memset(stats, 0, sizeof(struct rte_metrics_data_s)); 76 rte_spinlock_init(&stats->lock); 77 metrics_initialized = 1; 78 } 79 80 int 81 rte_metrics_deinit(void) 82 { 83 struct rte_metrics_data_s *stats; 84 const struct rte_memzone *memzone; 85 int ret; 86 87 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 88 return -EINVAL; 89 90 memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 91 if (memzone == NULL) 92 return -EIO; 93 94 stats = memzone->addr; 95 memset(stats, 0, sizeof(struct rte_metrics_data_s)); 96 97 ret = rte_memzone_free(memzone); 98 if (ret == 0) 99 metrics_initialized = 0; 100 return ret; 101 } 102 103 int 104 rte_metrics_reg_name(const char *name) 105 { 106 const char * const list_names[] = {name}; 107 108 return rte_metrics_reg_names(list_names, 1); 109 } 110 111 int 112 rte_metrics_reg_names(const char * const *names, uint16_t cnt_names) 113 { 114 struct rte_metrics_meta_s *entry = NULL; 115 struct rte_metrics_data_s *stats; 116 const struct rte_memzone *memzone; 117 uint16_t idx_name; 118 uint16_t idx_base; 119 120 /* Some sanity checks */ 121 if (cnt_names < 1 || names == NULL) 122 return -EINVAL; 123 for (idx_name = 0; idx_name < cnt_names; idx_name++) 124 if (names[idx_name] == NULL) 125 return -EINVAL; 126 127 memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 128 if (memzone == NULL) 129 return -EIO; 130 stats = memzone->addr; 131 132 if (stats->cnt_stats + cnt_names >= RTE_METRICS_MAX_METRICS) 133 return -ENOMEM; 134 135 rte_spinlock_lock(&stats->lock); 136 137 /* Overwritten later if this is actually first set.. */ 138 stats->metadata[stats->idx_last_set].idx_next_set = stats->cnt_stats; 139 140 stats->idx_last_set = idx_base = stats->cnt_stats; 141 142 for (idx_name = 0; idx_name < cnt_names; idx_name++) { 143 entry = &stats->metadata[idx_name + stats->cnt_stats]; 144 strlcpy(entry->name, names[idx_name], RTE_METRICS_MAX_NAME_LEN); 145 memset(entry->value, 0, sizeof(entry->value)); 146 entry->idx_next_stat = idx_name + stats->cnt_stats + 1; 147 } 148 entry->idx_next_stat = 0; 149 entry->idx_next_set = 0; 150 stats->cnt_stats += cnt_names; 151 152 rte_spinlock_unlock(&stats->lock); 153 154 return idx_base; 155 } 156 157 int 158 rte_metrics_update_value(int port_id, uint16_t key, const uint64_t value) 159 { 160 return rte_metrics_update_values(port_id, key, &value, 1); 161 } 162 163 int 164 rte_metrics_update_values(int port_id, 165 uint16_t key, 166 const uint64_t *values, 167 uint32_t count) 168 { 169 struct rte_metrics_meta_s *entry; 170 struct rte_metrics_data_s *stats; 171 const struct rte_memzone *memzone; 172 uint16_t idx_metric; 173 uint16_t idx_value; 174 uint16_t cnt_setsize; 175 176 if (port_id != RTE_METRICS_GLOBAL && 177 (port_id < 0 || port_id >= RTE_MAX_ETHPORTS)) 178 return -EINVAL; 179 180 if (values == NULL) 181 return -EINVAL; 182 183 memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 184 if (memzone == NULL) 185 return -EIO; 186 stats = memzone->addr; 187 188 rte_spinlock_lock(&stats->lock); 189 190 if (key >= stats->cnt_stats) { 191 rte_spinlock_unlock(&stats->lock); 192 return -EINVAL; 193 } 194 idx_metric = key; 195 cnt_setsize = 1; 196 while (idx_metric < stats->cnt_stats) { 197 entry = &stats->metadata[idx_metric]; 198 if (entry->idx_next_stat == 0) 199 break; 200 cnt_setsize++; 201 idx_metric++; 202 } 203 /* Check update does not cross set border */ 204 if (count > cnt_setsize) { 205 rte_spinlock_unlock(&stats->lock); 206 return -ERANGE; 207 } 208 209 if (port_id == RTE_METRICS_GLOBAL) 210 for (idx_value = 0; idx_value < count; idx_value++) { 211 idx_metric = key + idx_value; 212 stats->metadata[idx_metric].global_value = 213 values[idx_value]; 214 } 215 else 216 for (idx_value = 0; idx_value < count; idx_value++) { 217 idx_metric = key + idx_value; 218 stats->metadata[idx_metric].value[port_id] = 219 values[idx_value]; 220 } 221 rte_spinlock_unlock(&stats->lock); 222 return 0; 223 } 224 225 int 226 rte_metrics_get_names(struct rte_metric_name *names, 227 uint16_t capacity) 228 { 229 struct rte_metrics_data_s *stats; 230 const struct rte_memzone *memzone; 231 uint16_t idx_name; 232 int return_value; 233 234 memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 235 if (memzone == NULL) 236 return -EIO; 237 238 stats = memzone->addr; 239 rte_spinlock_lock(&stats->lock); 240 if (names != NULL) { 241 if (capacity < stats->cnt_stats) { 242 return_value = stats->cnt_stats; 243 rte_spinlock_unlock(&stats->lock); 244 return return_value; 245 } 246 for (idx_name = 0; idx_name < stats->cnt_stats; idx_name++) 247 strlcpy(names[idx_name].name, 248 stats->metadata[idx_name].name, 249 RTE_METRICS_MAX_NAME_LEN); 250 } 251 return_value = stats->cnt_stats; 252 rte_spinlock_unlock(&stats->lock); 253 return return_value; 254 } 255 256 int 257 rte_metrics_get_values(int port_id, 258 struct rte_metric_value *values, 259 uint16_t capacity) 260 { 261 struct rte_metrics_meta_s *entry; 262 struct rte_metrics_data_s *stats; 263 const struct rte_memzone *memzone; 264 uint16_t idx_name; 265 int return_value; 266 267 if (port_id != RTE_METRICS_GLOBAL && 268 (port_id < 0 || port_id >= RTE_MAX_ETHPORTS)) 269 return -EINVAL; 270 271 memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); 272 if (memzone == NULL) 273 return -EIO; 274 275 stats = memzone->addr; 276 rte_spinlock_lock(&stats->lock); 277 278 if (values != NULL) { 279 if (capacity < stats->cnt_stats) { 280 return_value = stats->cnt_stats; 281 rte_spinlock_unlock(&stats->lock); 282 return return_value; 283 } 284 if (port_id == RTE_METRICS_GLOBAL) 285 for (idx_name = 0; 286 idx_name < stats->cnt_stats; 287 idx_name++) { 288 entry = &stats->metadata[idx_name]; 289 values[idx_name].key = idx_name; 290 values[idx_name].value = entry->global_value; 291 } 292 else 293 for (idx_name = 0; 294 idx_name < stats->cnt_stats; 295 idx_name++) { 296 entry = &stats->metadata[idx_name]; 297 values[idx_name].key = idx_name; 298 values[idx_name].value = entry->value[port_id]; 299 } 300 } 301 return_value = stats->cnt_stats; 302 rte_spinlock_unlock(&stats->lock); 303 return return_value; 304 } 305