168977baaSRadu Nicolau /* SPDX-License-Identifier: BSD-3-Clause 268977baaSRadu Nicolau * Copyright(c) 2021 Intel Corporation 368977baaSRadu Nicolau */ 468977baaSRadu Nicolau 572b452c5SDmitry Kozlyuk #include <stdlib.h> 668977baaSRadu Nicolau #include <rte_ipsec.h> 768977baaSRadu Nicolau #include <rte_telemetry.h> 868977baaSRadu Nicolau #include <rte_malloc.h> 968977baaSRadu Nicolau #include "sa.h" 1068977baaSRadu Nicolau 1168977baaSRadu Nicolau 1268977baaSRadu Nicolau struct ipsec_telemetry_entry { 1368977baaSRadu Nicolau LIST_ENTRY(ipsec_telemetry_entry) next; 1468977baaSRadu Nicolau const struct rte_ipsec_sa *sa; 1568977baaSRadu Nicolau }; 1668977baaSRadu Nicolau static LIST_HEAD(ipsec_telemetry_head, ipsec_telemetry_entry) 1768977baaSRadu Nicolau ipsec_telemetry_list = LIST_HEAD_INITIALIZER(); 1868977baaSRadu Nicolau 1968977baaSRadu Nicolau static int 2068977baaSRadu Nicolau handle_telemetry_cmd_ipsec_sa_list(const char *cmd __rte_unused, 2168977baaSRadu Nicolau const char *params __rte_unused, 2268977baaSRadu Nicolau struct rte_tel_data *data) 2368977baaSRadu Nicolau { 2468977baaSRadu Nicolau struct ipsec_telemetry_entry *entry; 25*2d2c55e4SBruce Richardson rte_tel_data_start_array(data, RTE_TEL_UINT_VAL); 2668977baaSRadu Nicolau 2768977baaSRadu Nicolau LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 2868977baaSRadu Nicolau const struct rte_ipsec_sa *sa = entry->sa; 2968977baaSRadu Nicolau rte_tel_data_add_array_u64(data, rte_be_to_cpu_32(sa->spi)); 3068977baaSRadu Nicolau } 3168977baaSRadu Nicolau 3268977baaSRadu Nicolau return 0; 3368977baaSRadu Nicolau } 3468977baaSRadu Nicolau 3568977baaSRadu Nicolau /** 3668977baaSRadu Nicolau * Handle IPsec SA statistics telemetry request 3768977baaSRadu Nicolau * 3868977baaSRadu Nicolau * Return dict of SA's with dict of key/value counters 3968977baaSRadu Nicolau * 4068977baaSRadu Nicolau * { 4168977baaSRadu Nicolau * "SA_SPI_XX": {"count": 0, "bytes": 0, "errors": 0}, 4268977baaSRadu Nicolau * "SA_SPI_YY": {"count": 0, "bytes": 0, "errors": 0} 4368977baaSRadu Nicolau * } 4468977baaSRadu Nicolau * 4568977baaSRadu Nicolau */ 4668977baaSRadu Nicolau static int 4768977baaSRadu Nicolau handle_telemetry_cmd_ipsec_sa_stats(const char *cmd __rte_unused, 4868977baaSRadu Nicolau const char *params, 4968977baaSRadu Nicolau struct rte_tel_data *data) 5068977baaSRadu Nicolau { 5168977baaSRadu Nicolau struct ipsec_telemetry_entry *entry; 5268977baaSRadu Nicolau const struct rte_ipsec_sa *sa; 5368977baaSRadu Nicolau uint32_t sa_spi = 0; 5468977baaSRadu Nicolau 5568977baaSRadu Nicolau if (params) { 5668977baaSRadu Nicolau sa_spi = rte_cpu_to_be_32((uint32_t)strtoul(params, NULL, 0)); 5768977baaSRadu Nicolau if (sa_spi == 0) 5868977baaSRadu Nicolau return -EINVAL; 5968977baaSRadu Nicolau } 6068977baaSRadu Nicolau 6168977baaSRadu Nicolau rte_tel_data_start_dict(data); 6268977baaSRadu Nicolau 6368977baaSRadu Nicolau LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 6468977baaSRadu Nicolau char sa_name[64]; 6568977baaSRadu Nicolau sa = entry->sa; 6668977baaSRadu Nicolau static const char *name_pkt_cnt = "count"; 6768977baaSRadu Nicolau static const char *name_byte_cnt = "bytes"; 6868977baaSRadu Nicolau static const char *name_error_cnt = "errors"; 6968977baaSRadu Nicolau struct rte_tel_data *sa_data; 7068977baaSRadu Nicolau 7168977baaSRadu Nicolau /* If user provided SPI only get telemetry for that SA */ 7268977baaSRadu Nicolau if (sa_spi && (sa_spi != sa->spi)) 7368977baaSRadu Nicolau continue; 7468977baaSRadu Nicolau 7568977baaSRadu Nicolau /* allocate telemetry data struct for SA telemetry */ 7668977baaSRadu Nicolau sa_data = rte_tel_data_alloc(); 7768977baaSRadu Nicolau if (!sa_data) 7868977baaSRadu Nicolau return -ENOMEM; 7968977baaSRadu Nicolau 8068977baaSRadu Nicolau rte_tel_data_start_dict(sa_data); 8168977baaSRadu Nicolau 8268977baaSRadu Nicolau /* add telemetry key/values pairs */ 8368977baaSRadu Nicolau rte_tel_data_add_dict_u64(sa_data, name_pkt_cnt, 8468977baaSRadu Nicolau sa->statistics.count); 8568977baaSRadu Nicolau 8668977baaSRadu Nicolau rte_tel_data_add_dict_u64(sa_data, name_byte_cnt, 8768977baaSRadu Nicolau sa->statistics.bytes - 8868977baaSRadu Nicolau (sa->statistics.count * sa->hdr_len)); 8968977baaSRadu Nicolau 9068977baaSRadu Nicolau rte_tel_data_add_dict_u64(sa_data, name_error_cnt, 9168977baaSRadu Nicolau sa->statistics.errors.count); 9268977baaSRadu Nicolau 9368977baaSRadu Nicolau /* generate telemetry label */ 9468977baaSRadu Nicolau snprintf(sa_name, sizeof(sa_name), "SA_SPI_%i", 9568977baaSRadu Nicolau rte_be_to_cpu_32(sa->spi)); 9668977baaSRadu Nicolau 9768977baaSRadu Nicolau /* add SA telemetry to dictionary container */ 9868977baaSRadu Nicolau rte_tel_data_add_dict_container(data, sa_name, sa_data, 0); 9968977baaSRadu Nicolau } 10068977baaSRadu Nicolau 10168977baaSRadu Nicolau return 0; 10268977baaSRadu Nicolau } 10368977baaSRadu Nicolau 10468977baaSRadu Nicolau static int 10568977baaSRadu Nicolau handle_telemetry_cmd_ipsec_sa_details(const char *cmd __rte_unused, 10668977baaSRadu Nicolau const char *params, 10768977baaSRadu Nicolau struct rte_tel_data *data) 10868977baaSRadu Nicolau { 10968977baaSRadu Nicolau struct ipsec_telemetry_entry *entry; 11068977baaSRadu Nicolau const struct rte_ipsec_sa *sa; 11168977baaSRadu Nicolau uint32_t sa_spi = 0; 11268977baaSRadu Nicolau 11368977baaSRadu Nicolau if (params) 11468977baaSRadu Nicolau sa_spi = rte_cpu_to_be_32((uint32_t)strtoul(params, NULL, 0)); 11568977baaSRadu Nicolau /* valid SPI needed */ 11668977baaSRadu Nicolau if (sa_spi == 0) 11768977baaSRadu Nicolau return -EINVAL; 11868977baaSRadu Nicolau 11968977baaSRadu Nicolau 12068977baaSRadu Nicolau rte_tel_data_start_dict(data); 12168977baaSRadu Nicolau 12268977baaSRadu Nicolau LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 12368977baaSRadu Nicolau uint64_t mode; 12468977baaSRadu Nicolau sa = entry->sa; 12568977baaSRadu Nicolau if (sa_spi != sa->spi) 12668977baaSRadu Nicolau continue; 12768977baaSRadu Nicolau 12868977baaSRadu Nicolau /* add SA configuration key/values pairs */ 12968977baaSRadu Nicolau rte_tel_data_add_dict_string(data, "Type", 13068977baaSRadu Nicolau (sa->type & RTE_IPSEC_SATP_PROTO_MASK) == 13168977baaSRadu Nicolau RTE_IPSEC_SATP_PROTO_AH ? "AH" : "ESP"); 13268977baaSRadu Nicolau 13368977baaSRadu Nicolau rte_tel_data_add_dict_string(data, "Direction", 13468977baaSRadu Nicolau (sa->type & RTE_IPSEC_SATP_DIR_MASK) == 13568977baaSRadu Nicolau RTE_IPSEC_SATP_DIR_IB ? "Inbound" : "Outbound"); 13668977baaSRadu Nicolau 13768977baaSRadu Nicolau mode = sa->type & RTE_IPSEC_SATP_MODE_MASK; 13868977baaSRadu Nicolau 13968977baaSRadu Nicolau if (mode == RTE_IPSEC_SATP_MODE_TRANS) { 14068977baaSRadu Nicolau rte_tel_data_add_dict_string(data, "Mode", "Transport"); 14168977baaSRadu Nicolau } else { 14268977baaSRadu Nicolau rte_tel_data_add_dict_string(data, "Mode", "Tunnel"); 14368977baaSRadu Nicolau 14468977baaSRadu Nicolau if ((sa->type & RTE_IPSEC_SATP_NATT_MASK) == 14568977baaSRadu Nicolau RTE_IPSEC_SATP_NATT_ENABLE) { 14668977baaSRadu Nicolau if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { 14768977baaSRadu Nicolau rte_tel_data_add_dict_string(data, 14868977baaSRadu Nicolau "Tunnel-Type", 14968977baaSRadu Nicolau "IPv4-UDP"); 15068977baaSRadu Nicolau } else if (sa->type & 15168977baaSRadu Nicolau RTE_IPSEC_SATP_MODE_TUNLV6) { 15268977baaSRadu Nicolau rte_tel_data_add_dict_string(data, 15368977baaSRadu Nicolau "Tunnel-Type", 15474176aecSRadu Nicolau "IPv6-UDP"); 15568977baaSRadu Nicolau } 15668977baaSRadu Nicolau } else { 15768977baaSRadu Nicolau if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { 15868977baaSRadu Nicolau rte_tel_data_add_dict_string(data, 15968977baaSRadu Nicolau "Tunnel-Type", 16074176aecSRadu Nicolau "IPv4"); 16168977baaSRadu Nicolau } else if (sa->type & 16268977baaSRadu Nicolau RTE_IPSEC_SATP_MODE_TUNLV6) { 16368977baaSRadu Nicolau rte_tel_data_add_dict_string(data, 16468977baaSRadu Nicolau "Tunnel-Type", 16574176aecSRadu Nicolau "IPv6"); 16668977baaSRadu Nicolau } 16768977baaSRadu Nicolau } 16868977baaSRadu Nicolau } 16968977baaSRadu Nicolau 17068977baaSRadu Nicolau rte_tel_data_add_dict_string(data, 17168977baaSRadu Nicolau "extended-sequence-number", 17268977baaSRadu Nicolau (sa->type & RTE_IPSEC_SATP_ESN_MASK) == 17368977baaSRadu Nicolau RTE_IPSEC_SATP_ESN_ENABLE ? 17468977baaSRadu Nicolau "enabled" : "disabled"); 17568977baaSRadu Nicolau 17668977baaSRadu Nicolau if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) == 17768977baaSRadu Nicolau RTE_IPSEC_SATP_DIR_IB) 17868977baaSRadu Nicolau 17968977baaSRadu Nicolau if (sa->sqn.inb.rsn[sa->sqn.inb.rdidx]) 18068977baaSRadu Nicolau rte_tel_data_add_dict_u64(data, 18168977baaSRadu Nicolau "sequence-number", 18268977baaSRadu Nicolau sa->sqn.inb.rsn[sa->sqn.inb.rdidx]->sqn); 18368977baaSRadu Nicolau else 18468977baaSRadu Nicolau rte_tel_data_add_dict_u64(data, 18568977baaSRadu Nicolau "sequence-number", 0); 18668977baaSRadu Nicolau else 18768977baaSRadu Nicolau rte_tel_data_add_dict_u64(data, "sequence-number", 18868977baaSRadu Nicolau sa->sqn.outb); 18968977baaSRadu Nicolau 19068977baaSRadu Nicolau rte_tel_data_add_dict_string(data, 19168977baaSRadu Nicolau "explicit-congestion-notification", 19268977baaSRadu Nicolau (sa->type & RTE_IPSEC_SATP_ECN_MASK) == 19368977baaSRadu Nicolau RTE_IPSEC_SATP_ECN_ENABLE ? 19468977baaSRadu Nicolau "enabled" : "disabled"); 19568977baaSRadu Nicolau 19668977baaSRadu Nicolau rte_tel_data_add_dict_string(data, 19768977baaSRadu Nicolau "copy-DSCP", 19868977baaSRadu Nicolau (sa->type & RTE_IPSEC_SATP_DSCP_MASK) == 19968977baaSRadu Nicolau RTE_IPSEC_SATP_DSCP_ENABLE ? 20068977baaSRadu Nicolau "enabled" : "disabled"); 20168977baaSRadu Nicolau } 20268977baaSRadu Nicolau 20368977baaSRadu Nicolau return 0; 20468977baaSRadu Nicolau } 20568977baaSRadu Nicolau 20668977baaSRadu Nicolau 20768977baaSRadu Nicolau int 20868977baaSRadu Nicolau rte_ipsec_telemetry_sa_add(const struct rte_ipsec_sa *sa) 20968977baaSRadu Nicolau { 21068977baaSRadu Nicolau struct ipsec_telemetry_entry *entry = rte_zmalloc(NULL, 21168977baaSRadu Nicolau sizeof(struct ipsec_telemetry_entry), 0); 21268977baaSRadu Nicolau if (entry == NULL) 21368977baaSRadu Nicolau return -ENOMEM; 21468977baaSRadu Nicolau entry->sa = sa; 21568977baaSRadu Nicolau LIST_INSERT_HEAD(&ipsec_telemetry_list, entry, next); 21668977baaSRadu Nicolau return 0; 21768977baaSRadu Nicolau } 21868977baaSRadu Nicolau 21968977baaSRadu Nicolau void 22068977baaSRadu Nicolau rte_ipsec_telemetry_sa_del(const struct rte_ipsec_sa *sa) 22168977baaSRadu Nicolau { 22268977baaSRadu Nicolau struct ipsec_telemetry_entry *entry; 22368977baaSRadu Nicolau LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 22468977baaSRadu Nicolau if (sa == entry->sa) { 22568977baaSRadu Nicolau LIST_REMOVE(entry, next); 22668977baaSRadu Nicolau rte_free(entry); 22768977baaSRadu Nicolau return; 22868977baaSRadu Nicolau } 22968977baaSRadu Nicolau } 23068977baaSRadu Nicolau } 23168977baaSRadu Nicolau 23268977baaSRadu Nicolau 23368977baaSRadu Nicolau RTE_INIT(rte_ipsec_telemetry_init) 23468977baaSRadu Nicolau { 23568977baaSRadu Nicolau rte_telemetry_register_cmd("/ipsec/sa/list", 23668977baaSRadu Nicolau handle_telemetry_cmd_ipsec_sa_list, 23768977baaSRadu Nicolau "Return list of IPsec SAs with telemetry enabled."); 23868977baaSRadu Nicolau rte_telemetry_register_cmd("/ipsec/sa/stats", 23968977baaSRadu Nicolau handle_telemetry_cmd_ipsec_sa_stats, 2407be78d02SJosh Soref "Returns IPsec SA statistics. Parameters: int sa_spi"); 24168977baaSRadu Nicolau rte_telemetry_register_cmd("/ipsec/sa/details", 24268977baaSRadu Nicolau handle_telemetry_cmd_ipsec_sa_details, 24368977baaSRadu Nicolau "Returns IPsec SA configuration. Parameters: int sa_spi"); 24468977baaSRadu Nicolau } 245