1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2022 Marvell. 3 */ 4 5 #include <ctype.h> 6 7 #include <rte_telemetry.h> 8 9 #include <roc_api.h> 10 11 #include "cnxk_ethdev.h" 12 13 #define STR_MAXLEN 20 14 #define W0_MAXLEN 21 15 16 static int 17 copy_outb_sa_9k(struct rte_tel_data *d, uint32_t i, void *sa) 18 { 19 union { 20 struct roc_ie_on_sa_ctl ctl; 21 uint64_t u64; 22 } w0; 23 struct roc_ie_on_outb_sa *out_sa; 24 char strw0[W0_MAXLEN]; 25 char str[STR_MAXLEN]; 26 27 out_sa = (struct roc_ie_on_outb_sa *)sa; 28 w0.ctl = out_sa->common_sa.ctl; 29 30 snprintf(str, sizeof(str), "outsa_w0_%u", i); 31 snprintf(strw0, sizeof(strw0), "%" PRIu64, w0.u64); 32 rte_tel_data_add_dict_string(d, str, strw0); 33 34 return 0; 35 } 36 37 static int 38 copy_inb_sa_9k(struct rte_tel_data *d, uint32_t i, void *sa) 39 { 40 union { 41 struct roc_ie_on_sa_ctl ctl; 42 uint64_t u64; 43 } w0; 44 struct roc_ie_on_inb_sa *in_sa; 45 char strw0[W0_MAXLEN]; 46 char str[STR_MAXLEN]; 47 48 in_sa = (struct roc_ie_on_inb_sa *)sa; 49 w0.ctl = in_sa->common_sa.ctl; 50 51 snprintf(str, sizeof(str), "insa_w0_%u", i); 52 snprintf(strw0, sizeof(strw0), "%" PRIu64, w0.u64); 53 rte_tel_data_add_dict_string(d, str, strw0); 54 55 snprintf(str, sizeof(str), "insa_esnh_%u", i); 56 rte_tel_data_add_dict_uint(d, str, in_sa->common_sa.seq_t.th); 57 58 snprintf(str, sizeof(str), "insa_esnl_%u", i); 59 rte_tel_data_add_dict_uint(d, str, in_sa->common_sa.seq_t.tl); 60 61 return 0; 62 } 63 64 static int 65 copy_outb_sa_10k(struct rte_tel_data *d, uint32_t i, void *sa) 66 { 67 struct roc_ot_ipsec_outb_sa *out_sa; 68 struct rte_tel_data *outer_hdr; 69 char str[STR_MAXLEN]; 70 char s64[W0_MAXLEN]; 71 uint32_t j; 72 73 out_sa = (struct roc_ot_ipsec_outb_sa *)sa; 74 75 snprintf(str, sizeof(str), "outsa_w0_%u", i); 76 snprintf(s64, sizeof(s64), "%" PRIu64, out_sa->w0.u64); 77 rte_tel_data_add_dict_string(d, str, s64); 78 79 snprintf(str, sizeof(str), "outsa_w1_%u", i); 80 snprintf(s64, sizeof(s64), "%" PRIu64, out_sa->w1.u64); 81 rte_tel_data_add_dict_string(d, str, s64); 82 83 snprintf(str, sizeof(str), "outsa_w2_%u", i); 84 snprintf(s64, sizeof(s64), "%" PRIu64, out_sa->w2.u64); 85 rte_tel_data_add_dict_string(d, str, s64); 86 87 snprintf(str, sizeof(str), "outsa_w10_%u", i); 88 snprintf(s64, sizeof(s64), "%" PRIu64, out_sa->w10.u64); 89 rte_tel_data_add_dict_string(d, str, s64); 90 91 outer_hdr = rte_tel_data_alloc(); 92 if (!outer_hdr) { 93 plt_err("Could not allocate space for outer header"); 94 return -ENOMEM; 95 } 96 97 rte_tel_data_start_array(outer_hdr, RTE_TEL_UINT_VAL); 98 99 for (j = 0; j < RTE_DIM(out_sa->outer_hdr.ipv6.src_addr); j++) 100 rte_tel_data_add_array_uint(outer_hdr, 101 out_sa->outer_hdr.ipv6.src_addr[j]); 102 103 for (j = 0; j < RTE_DIM(out_sa->outer_hdr.ipv6.dst_addr); j++) 104 rte_tel_data_add_array_uint(outer_hdr, 105 out_sa->outer_hdr.ipv6.dst_addr[j]); 106 107 snprintf(str, sizeof(str), "outsa_outer_hdr_%u", i); 108 rte_tel_data_add_dict_container(d, str, outer_hdr, 0); 109 110 snprintf(str, sizeof(str), "outsa_errctl_%u", i); 111 snprintf(s64, sizeof(s64), "%" PRIu64, out_sa->ctx.err_ctl.u64); 112 rte_tel_data_add_dict_string(d, str, s64); 113 114 snprintf(str, sizeof(str), "outsa_esnval_%u", i); 115 snprintf(s64, sizeof(s64), "%" PRIu64, out_sa->ctx.esn_val); 116 rte_tel_data_add_dict_string(d, str, s64); 117 118 snprintf(str, sizeof(str), "outsa_hl_%u", i); 119 snprintf(s64, sizeof(s64), "%" PRIu64, out_sa->ctx.hard_life); 120 rte_tel_data_add_dict_string(d, str, s64); 121 122 snprintf(str, sizeof(str), "outsa_sl_%u", i); 123 snprintf(s64, sizeof(s64), "%" PRIu64, out_sa->ctx.soft_life); 124 rte_tel_data_add_dict_string(d, str, s64); 125 126 snprintf(str, sizeof(str), "outsa_octs_%u", i); 127 snprintf(s64, sizeof(s64), "%" PRIu64, out_sa->ctx.mib_octs); 128 rte_tel_data_add_dict_string(d, str, s64); 129 130 snprintf(str, sizeof(str), "outsa_pkts_%u", i); 131 snprintf(s64, sizeof(s64), "%" PRIu64, out_sa->ctx.mib_pkts); 132 rte_tel_data_add_dict_string(d, str, s64); 133 134 return 0; 135 } 136 137 static int 138 copy_inb_sa_10k(struct rte_tel_data *d, uint32_t i, void *sa) 139 { 140 struct roc_ot_ipsec_inb_sa *in_sa; 141 struct rte_tel_data *outer_hdr; 142 char str[STR_MAXLEN]; 143 char s64[W0_MAXLEN]; 144 uint32_t j; 145 146 in_sa = (struct roc_ot_ipsec_inb_sa *)sa; 147 148 snprintf(str, sizeof(str), "insa_w0_%u", i); 149 snprintf(s64, sizeof(s64), "%" PRIu64, in_sa->w0.u64); 150 rte_tel_data_add_dict_string(d, str, s64); 151 152 snprintf(str, sizeof(str), "insa_w1_%u", i); 153 snprintf(s64, sizeof(s64), "%" PRIu64, in_sa->w1.u64); 154 rte_tel_data_add_dict_string(d, str, s64); 155 156 snprintf(str, sizeof(str), "insa_w2_%u", i); 157 snprintf(s64, sizeof(s64), "%" PRIu64, in_sa->w2.u64); 158 rte_tel_data_add_dict_string(d, str, s64); 159 160 snprintf(str, sizeof(str), "insa_w10_%u", i); 161 snprintf(s64, sizeof(s64), "%" PRIu64, in_sa->w10.u64); 162 rte_tel_data_add_dict_string(d, str, s64); 163 164 outer_hdr = rte_tel_data_alloc(); 165 if (!outer_hdr) { 166 plt_err("Could not allocate space for outer header"); 167 return -ENOMEM; 168 } 169 170 rte_tel_data_start_array(outer_hdr, RTE_TEL_UINT_VAL); 171 172 for (j = 0; j < RTE_DIM(in_sa->outer_hdr.ipv6.src_addr); j++) 173 rte_tel_data_add_array_uint(outer_hdr, 174 in_sa->outer_hdr.ipv6.src_addr[j]); 175 176 for (j = 0; j < RTE_DIM(in_sa->outer_hdr.ipv6.dst_addr); j++) 177 rte_tel_data_add_array_uint(outer_hdr, 178 in_sa->outer_hdr.ipv6.dst_addr[j]); 179 180 snprintf(str, sizeof(str), "insa_outer_hdr_%u", i); 181 rte_tel_data_add_dict_container(d, str, outer_hdr, 0); 182 183 snprintf(str, sizeof(str), "insa_arbase_%u", i); 184 snprintf(s64, sizeof(s64), "%" PRIu64, in_sa->ctx.ar_base); 185 rte_tel_data_add_dict_string(d, str, s64); 186 187 snprintf(str, sizeof(str), "insa_ar_validm_%u", i); 188 snprintf(s64, sizeof(s64), "%" PRIu64, in_sa->ctx.ar_valid_mask); 189 rte_tel_data_add_dict_string(d, str, s64); 190 191 snprintf(str, sizeof(str), "insa_hl_%u", i); 192 snprintf(s64, sizeof(s64), "%" PRIu64, in_sa->ctx.hard_life); 193 rte_tel_data_add_dict_string(d, str, s64); 194 195 snprintf(str, sizeof(str), "insa_sl_%u", i); 196 snprintf(s64, sizeof(s64), "%" PRIu64, in_sa->ctx.soft_life); 197 rte_tel_data_add_dict_string(d, str, s64); 198 199 snprintf(str, sizeof(str), "insa_octs_%u", i); 200 snprintf(s64, sizeof(s64), "%" PRIu64, in_sa->ctx.mib_octs); 201 rte_tel_data_add_dict_string(d, str, s64); 202 203 snprintf(str, sizeof(str), "insa_pkts_%u", i); 204 snprintf(s64, sizeof(s64), "%" PRIu64, in_sa->ctx.mib_pkts); 205 rte_tel_data_add_dict_string(d, str, s64); 206 207 return 0; 208 } 209 210 /* n_vals is the number of params to be parsed. */ 211 static int 212 parse_params(const char *params, uint32_t *vals, size_t n_vals) 213 { 214 char dlim[2] = ","; 215 char *params_args; 216 size_t count = 0; 217 char *token; 218 219 if (vals == NULL || params == NULL || strlen(params) == 0) 220 return -1; 221 222 /* strtok expects char * and param is const char *. Hence on using 223 * params as "const char *" compiler throws warning. 224 */ 225 params_args = strdup(params); 226 if (params_args == NULL) 227 return -1; 228 229 token = strtok(params_args, dlim); 230 while (token && isdigit(*token) && count < n_vals) { 231 vals[count++] = strtoul(token, NULL, 10); 232 token = strtok(NULL, dlim); 233 } 234 235 free(params_args); 236 237 if (count < n_vals) 238 return -1; 239 240 return 0; 241 } 242 243 static int 244 ethdev_sec_tel_handle_sa_info(const char *cmd __rte_unused, const char *params, 245 struct rte_tel_data *d) 246 { 247 struct cnxk_eth_sec_sess *eth_sec, *tvar; 248 struct rte_eth_dev *eth_dev; 249 struct cnxk_eth_dev *dev; 250 uint32_t port_id, sa_idx; 251 uint32_t vals[2] = {0}; 252 uint32_t i; 253 int ret; 254 255 if (params == NULL || strlen(params) == 0 || !isdigit(*params)) 256 return -EINVAL; 257 258 if (parse_params(params, vals, RTE_DIM(vals)) < 0) 259 return -EINVAL; 260 261 port_id = vals[0]; 262 sa_idx = vals[1]; 263 264 if (!rte_eth_dev_is_valid_port(port_id)) { 265 plt_err("Invalid port id %u", port_id); 266 return -EINVAL; 267 } 268 269 eth_dev = &rte_eth_devices[port_id]; 270 if (!eth_dev) { 271 plt_err("Ethdev not available"); 272 return -EINVAL; 273 } 274 dev = cnxk_eth_pmd_priv(eth_dev); 275 276 rte_tel_data_start_dict(d); 277 278 i = 0; 279 if (dev->tx_offloads & RTE_ETH_TX_OFFLOAD_SECURITY) { 280 tvar = NULL; 281 RTE_TAILQ_FOREACH_SAFE(eth_sec, &dev->outb.list, entry, tvar) { 282 if (eth_sec->sa_idx == sa_idx) { 283 rte_tel_data_add_dict_int(d, "outb_sa", 1); 284 if (roc_model_is_cn10k()) 285 ret = copy_outb_sa_10k(d, i, eth_sec->sa); 286 else 287 ret = copy_outb_sa_9k(d, i, eth_sec->sa); 288 if (ret < 0) 289 return ret; 290 break; 291 } 292 } 293 } 294 295 i = 0; 296 if (dev->rx_offloads & RTE_ETH_RX_OFFLOAD_SECURITY) { 297 tvar = NULL; 298 RTE_TAILQ_FOREACH_SAFE(eth_sec, &dev->inb.list, entry, tvar) { 299 if (eth_sec->sa_idx == sa_idx) { 300 rte_tel_data_add_dict_int(d, "inb_sa", 1); 301 if (roc_model_is_cn10k()) 302 ret = copy_inb_sa_10k(d, i, eth_sec->sa); 303 else 304 ret = copy_inb_sa_9k(d, i, eth_sec->sa); 305 if (ret < 0) 306 return ret; 307 break; 308 } 309 } 310 } 311 return 0; 312 } 313 314 static int 315 ethdev_sec_tel_handle_info(const char *cmd __rte_unused, const char *params, 316 struct rte_tel_data *d) 317 { 318 uint32_t min_outb_sa = UINT32_MAX, max_outb_sa = 0; 319 uint32_t min_inb_sa = UINT32_MAX, max_inb_sa = 0; 320 struct cnxk_eth_sec_sess *eth_sec, *tvar; 321 struct rte_eth_dev *eth_dev; 322 struct cnxk_eth_dev *dev; 323 uint16_t port_id; 324 char *end_p; 325 326 if (params == NULL || strlen(params) == 0 || !isdigit(*params)) 327 return -EINVAL; 328 329 port_id = strtoul(params, &end_p, 0); 330 if (errno != 0) 331 return -EINVAL; 332 333 if (*end_p != '\0') 334 plt_err("Extra parameters passed to telemetry, ignoring it"); 335 336 if (!rte_eth_dev_is_valid_port(port_id)) { 337 plt_err("Invalid port id %u", port_id); 338 return -EINVAL; 339 } 340 341 eth_dev = &rte_eth_devices[port_id]; 342 if (!eth_dev) { 343 plt_err("Ethdev not available"); 344 return -EINVAL; 345 } 346 347 dev = cnxk_eth_pmd_priv(eth_dev); 348 349 rte_tel_data_start_dict(d); 350 351 rte_tel_data_add_dict_int(d, "nb_outb_sa", dev->outb.nb_sess); 352 353 if (!dev->outb.nb_sess) 354 min_outb_sa = 0; 355 356 if (dev->tx_offloads & RTE_ETH_TX_OFFLOAD_SECURITY) { 357 tvar = NULL; 358 RTE_TAILQ_FOREACH_SAFE(eth_sec, &dev->outb.list, entry, tvar) { 359 if (eth_sec->sa_idx < min_outb_sa) 360 min_outb_sa = eth_sec->sa_idx; 361 if (eth_sec->sa_idx > max_outb_sa) 362 max_outb_sa = eth_sec->sa_idx; 363 } 364 rte_tel_data_add_dict_int(d, "min_outb_sa", min_outb_sa); 365 rte_tel_data_add_dict_int(d, "max_outb_sa", max_outb_sa); 366 } 367 368 rte_tel_data_add_dict_int(d, "nb_inb_sa", dev->inb.nb_sess); 369 370 if (!dev->inb.nb_sess) 371 min_inb_sa = 0; 372 373 if (dev->rx_offloads & RTE_ETH_RX_OFFLOAD_SECURITY) { 374 tvar = NULL; 375 RTE_TAILQ_FOREACH_SAFE(eth_sec, &dev->inb.list, entry, tvar) { 376 if (eth_sec->sa_idx < min_inb_sa) 377 min_inb_sa = eth_sec->sa_idx; 378 if (eth_sec->sa_idx > max_inb_sa) 379 max_inb_sa = eth_sec->sa_idx; 380 } 381 rte_tel_data_add_dict_int(d, "min_inb_sa", min_inb_sa); 382 rte_tel_data_add_dict_int(d, "max_inb_sa", max_inb_sa); 383 } 384 385 return 0; 386 } 387 388 RTE_INIT(cnxk_ipsec_init_telemetry) 389 { 390 rte_telemetry_register_cmd("/cnxk/ipsec/info", 391 ethdev_sec_tel_handle_info, 392 "Returns number of SA's and Max and Min SA. Parameters: port id"); 393 rte_telemetry_register_cmd("/cnxk/ipsec/sa_info", 394 ethdev_sec_tel_handle_sa_info, 395 "Returns ipsec info. Parameters: port id & sa_idx"); 396 } 397