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
handle_telemetry_cmd_ipsec_sa_list(const char * cmd __rte_unused,const char * params __rte_unused,struct rte_tel_data * data)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;
252d2c55e4SBruce 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;
29*af0785a2SBruce Richardson rte_tel_data_add_array_uint(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 static int
handle_telemetry_cmd_ipsec_sa_stats(const char * cmd __rte_unused,const char * params,struct rte_tel_data * data)4668977baaSRadu Nicolau handle_telemetry_cmd_ipsec_sa_stats(const char *cmd __rte_unused,
4768977baaSRadu Nicolau const char *params,
4868977baaSRadu Nicolau struct rte_tel_data *data)
4968977baaSRadu Nicolau {
5068977baaSRadu Nicolau struct ipsec_telemetry_entry *entry;
5168977baaSRadu Nicolau const struct rte_ipsec_sa *sa;
5268977baaSRadu Nicolau uint32_t sa_spi = 0;
5368977baaSRadu Nicolau
5468977baaSRadu Nicolau if (params) {
5568977baaSRadu Nicolau sa_spi = rte_cpu_to_be_32((uint32_t)strtoul(params, NULL, 0));
5668977baaSRadu Nicolau if (sa_spi == 0)
5768977baaSRadu Nicolau return -EINVAL;
5868977baaSRadu Nicolau }
5968977baaSRadu Nicolau
6068977baaSRadu Nicolau rte_tel_data_start_dict(data);
6168977baaSRadu Nicolau
6268977baaSRadu Nicolau LIST_FOREACH(entry, &ipsec_telemetry_list, next) {
6368977baaSRadu Nicolau char sa_name[64];
6468977baaSRadu Nicolau sa = entry->sa;
6568977baaSRadu Nicolau static const char *name_pkt_cnt = "count";
6668977baaSRadu Nicolau static const char *name_byte_cnt = "bytes";
6768977baaSRadu Nicolau static const char *name_error_cnt = "errors";
6868977baaSRadu Nicolau struct rte_tel_data *sa_data;
6968977baaSRadu Nicolau
7068977baaSRadu Nicolau /* If user provided SPI only get telemetry for that SA */
7168977baaSRadu Nicolau if (sa_spi && (sa_spi != sa->spi))
7268977baaSRadu Nicolau continue;
7368977baaSRadu Nicolau
7468977baaSRadu Nicolau /* allocate telemetry data struct for SA telemetry */
7568977baaSRadu Nicolau sa_data = rte_tel_data_alloc();
7668977baaSRadu Nicolau if (!sa_data)
7768977baaSRadu Nicolau return -ENOMEM;
7868977baaSRadu Nicolau
7968977baaSRadu Nicolau rte_tel_data_start_dict(sa_data);
8068977baaSRadu Nicolau
8168977baaSRadu Nicolau /* add telemetry key/values pairs */
82*af0785a2SBruce Richardson rte_tel_data_add_dict_uint(sa_data, name_pkt_cnt,
8368977baaSRadu Nicolau sa->statistics.count);
8468977baaSRadu Nicolau
85*af0785a2SBruce Richardson rte_tel_data_add_dict_uint(sa_data, name_byte_cnt,
8668977baaSRadu Nicolau sa->statistics.bytes -
8768977baaSRadu Nicolau (sa->statistics.count * sa->hdr_len));
8868977baaSRadu Nicolau
89*af0785a2SBruce Richardson rte_tel_data_add_dict_uint(sa_data, name_error_cnt,
9068977baaSRadu Nicolau sa->statistics.errors.count);
9168977baaSRadu Nicolau
9268977baaSRadu Nicolau /* generate telemetry label */
9368977baaSRadu Nicolau snprintf(sa_name, sizeof(sa_name), "SA_SPI_%i",
9468977baaSRadu Nicolau rte_be_to_cpu_32(sa->spi));
9568977baaSRadu Nicolau
9668977baaSRadu Nicolau /* add SA telemetry to dictionary container */
9768977baaSRadu Nicolau rte_tel_data_add_dict_container(data, sa_name, sa_data, 0);
9868977baaSRadu Nicolau }
9968977baaSRadu Nicolau
10068977baaSRadu Nicolau return 0;
10168977baaSRadu Nicolau }
10268977baaSRadu Nicolau
10368977baaSRadu Nicolau static int
handle_telemetry_cmd_ipsec_sa_details(const char * cmd __rte_unused,const char * params,struct rte_tel_data * data)10468977baaSRadu Nicolau handle_telemetry_cmd_ipsec_sa_details(const char *cmd __rte_unused,
10568977baaSRadu Nicolau const char *params,
10668977baaSRadu Nicolau struct rte_tel_data *data)
10768977baaSRadu Nicolau {
10868977baaSRadu Nicolau struct ipsec_telemetry_entry *entry;
10968977baaSRadu Nicolau const struct rte_ipsec_sa *sa;
11068977baaSRadu Nicolau uint32_t sa_spi = 0;
11168977baaSRadu Nicolau
11268977baaSRadu Nicolau if (params)
11368977baaSRadu Nicolau sa_spi = rte_cpu_to_be_32((uint32_t)strtoul(params, NULL, 0));
11468977baaSRadu Nicolau /* valid SPI needed */
11568977baaSRadu Nicolau if (sa_spi == 0)
11668977baaSRadu Nicolau return -EINVAL;
11768977baaSRadu Nicolau
11868977baaSRadu Nicolau
11968977baaSRadu Nicolau rte_tel_data_start_dict(data);
12068977baaSRadu Nicolau
12168977baaSRadu Nicolau LIST_FOREACH(entry, &ipsec_telemetry_list, next) {
12268977baaSRadu Nicolau uint64_t mode;
12368977baaSRadu Nicolau sa = entry->sa;
12468977baaSRadu Nicolau if (sa_spi != sa->spi)
12568977baaSRadu Nicolau continue;
12668977baaSRadu Nicolau
12768977baaSRadu Nicolau /* add SA configuration key/values pairs */
12868977baaSRadu Nicolau rte_tel_data_add_dict_string(data, "Type",
12968977baaSRadu Nicolau (sa->type & RTE_IPSEC_SATP_PROTO_MASK) ==
13068977baaSRadu Nicolau RTE_IPSEC_SATP_PROTO_AH ? "AH" : "ESP");
13168977baaSRadu Nicolau
13268977baaSRadu Nicolau rte_tel_data_add_dict_string(data, "Direction",
13368977baaSRadu Nicolau (sa->type & RTE_IPSEC_SATP_DIR_MASK) ==
13468977baaSRadu Nicolau RTE_IPSEC_SATP_DIR_IB ? "Inbound" : "Outbound");
13568977baaSRadu Nicolau
13668977baaSRadu Nicolau mode = sa->type & RTE_IPSEC_SATP_MODE_MASK;
13768977baaSRadu Nicolau
13868977baaSRadu Nicolau if (mode == RTE_IPSEC_SATP_MODE_TRANS) {
13968977baaSRadu Nicolau rte_tel_data_add_dict_string(data, "Mode", "Transport");
14068977baaSRadu Nicolau } else {
14168977baaSRadu Nicolau rte_tel_data_add_dict_string(data, "Mode", "Tunnel");
14268977baaSRadu Nicolau
14368977baaSRadu Nicolau if ((sa->type & RTE_IPSEC_SATP_NATT_MASK) ==
14468977baaSRadu Nicolau RTE_IPSEC_SATP_NATT_ENABLE) {
14568977baaSRadu Nicolau if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) {
14668977baaSRadu Nicolau rte_tel_data_add_dict_string(data,
14768977baaSRadu Nicolau "Tunnel-Type",
14868977baaSRadu Nicolau "IPv4-UDP");
14968977baaSRadu Nicolau } else if (sa->type &
15068977baaSRadu Nicolau RTE_IPSEC_SATP_MODE_TUNLV6) {
15168977baaSRadu Nicolau rte_tel_data_add_dict_string(data,
15268977baaSRadu Nicolau "Tunnel-Type",
15374176aecSRadu Nicolau "IPv6-UDP");
15468977baaSRadu Nicolau }
15568977baaSRadu Nicolau } else {
15668977baaSRadu Nicolau if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) {
15768977baaSRadu Nicolau rte_tel_data_add_dict_string(data,
15868977baaSRadu Nicolau "Tunnel-Type",
15974176aecSRadu Nicolau "IPv4");
16068977baaSRadu Nicolau } else if (sa->type &
16168977baaSRadu Nicolau RTE_IPSEC_SATP_MODE_TUNLV6) {
16268977baaSRadu Nicolau rte_tel_data_add_dict_string(data,
16368977baaSRadu Nicolau "Tunnel-Type",
16474176aecSRadu Nicolau "IPv6");
16568977baaSRadu Nicolau }
16668977baaSRadu Nicolau }
16768977baaSRadu Nicolau }
16868977baaSRadu Nicolau
16968977baaSRadu Nicolau rte_tel_data_add_dict_string(data,
17068977baaSRadu Nicolau "extended-sequence-number",
17168977baaSRadu Nicolau (sa->type & RTE_IPSEC_SATP_ESN_MASK) ==
17268977baaSRadu Nicolau RTE_IPSEC_SATP_ESN_ENABLE ?
17368977baaSRadu Nicolau "enabled" : "disabled");
17468977baaSRadu Nicolau
17568977baaSRadu Nicolau if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) ==
17668977baaSRadu Nicolau RTE_IPSEC_SATP_DIR_IB)
17768977baaSRadu Nicolau
17868977baaSRadu Nicolau if (sa->sqn.inb.rsn[sa->sqn.inb.rdidx])
179*af0785a2SBruce Richardson rte_tel_data_add_dict_uint(data,
18068977baaSRadu Nicolau "sequence-number",
18168977baaSRadu Nicolau sa->sqn.inb.rsn[sa->sqn.inb.rdidx]->sqn);
18268977baaSRadu Nicolau else
183*af0785a2SBruce Richardson rte_tel_data_add_dict_uint(data,
184*af0785a2SBruce Richardson "sequence-number",
185*af0785a2SBruce Richardson 0);
18668977baaSRadu Nicolau else
187*af0785a2SBruce Richardson rte_tel_data_add_dict_uint(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
rte_ipsec_telemetry_sa_add(const struct rte_ipsec_sa * sa)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
rte_ipsec_telemetry_sa_del(const struct rte_ipsec_sa * sa)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
RTE_INIT(rte_ipsec_telemetry_init)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