1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2021 Intel Corporation 3 */ 4 5 #include <stdlib.h> 6 #include <rte_ipsec.h> 7 #include <rte_telemetry.h> 8 #include <rte_malloc.h> 9 #include "sa.h" 10 11 12 struct ipsec_telemetry_entry { 13 LIST_ENTRY(ipsec_telemetry_entry) next; 14 const struct rte_ipsec_sa *sa; 15 }; 16 static LIST_HEAD(ipsec_telemetry_head, ipsec_telemetry_entry) 17 ipsec_telemetry_list = LIST_HEAD_INITIALIZER(); 18 19 static int 20 handle_telemetry_cmd_ipsec_sa_list(const char *cmd __rte_unused, 21 const char *params __rte_unused, 22 struct rte_tel_data *data) 23 { 24 struct ipsec_telemetry_entry *entry; 25 rte_tel_data_start_array(data, RTE_TEL_UINT_VAL); 26 27 LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 28 const struct rte_ipsec_sa *sa = entry->sa; 29 rte_tel_data_add_array_uint(data, rte_be_to_cpu_32(sa->spi)); 30 } 31 32 return 0; 33 } 34 35 /** 36 * Handle IPsec SA statistics telemetry request 37 * 38 * Return dict of SA's with dict of key/value counters 39 * 40 * { 41 * "SA_SPI_XX": {"count": 0, "bytes": 0, "errors": 0}, 42 * "SA_SPI_YY": {"count": 0, "bytes": 0, "errors": 0} 43 * } 44 */ 45 static int 46 handle_telemetry_cmd_ipsec_sa_stats(const char *cmd __rte_unused, 47 const char *params, 48 struct rte_tel_data *data) 49 { 50 struct ipsec_telemetry_entry *entry; 51 const struct rte_ipsec_sa *sa; 52 uint32_t sa_spi = 0; 53 54 if (params) { 55 sa_spi = rte_cpu_to_be_32((uint32_t)strtoul(params, NULL, 0)); 56 if (sa_spi == 0) 57 return -EINVAL; 58 } 59 60 rte_tel_data_start_dict(data); 61 62 LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 63 char sa_name[64]; 64 sa = entry->sa; 65 static const char *name_pkt_cnt = "count"; 66 static const char *name_byte_cnt = "bytes"; 67 static const char *name_error_cnt = "errors"; 68 struct rte_tel_data *sa_data; 69 70 /* If user provided SPI only get telemetry for that SA */ 71 if (sa_spi && (sa_spi != sa->spi)) 72 continue; 73 74 /* allocate telemetry data struct for SA telemetry */ 75 sa_data = rte_tel_data_alloc(); 76 if (!sa_data) 77 return -ENOMEM; 78 79 rte_tel_data_start_dict(sa_data); 80 81 /* add telemetry key/values pairs */ 82 rte_tel_data_add_dict_uint(sa_data, name_pkt_cnt, 83 sa->statistics.count); 84 85 rte_tel_data_add_dict_uint(sa_data, name_byte_cnt, 86 sa->statistics.bytes - 87 (sa->statistics.count * sa->hdr_len)); 88 89 rte_tel_data_add_dict_uint(sa_data, name_error_cnt, 90 sa->statistics.errors.count); 91 92 /* generate telemetry label */ 93 snprintf(sa_name, sizeof(sa_name), "SA_SPI_%i", 94 rte_be_to_cpu_32(sa->spi)); 95 96 /* add SA telemetry to dictionary container */ 97 rte_tel_data_add_dict_container(data, sa_name, sa_data, 0); 98 } 99 100 return 0; 101 } 102 103 static int 104 handle_telemetry_cmd_ipsec_sa_details(const char *cmd __rte_unused, 105 const char *params, 106 struct rte_tel_data *data) 107 { 108 struct ipsec_telemetry_entry *entry; 109 const struct rte_ipsec_sa *sa; 110 uint32_t sa_spi = 0; 111 112 if (params) 113 sa_spi = rte_cpu_to_be_32((uint32_t)strtoul(params, NULL, 0)); 114 /* valid SPI needed */ 115 if (sa_spi == 0) 116 return -EINVAL; 117 118 119 rte_tel_data_start_dict(data); 120 121 LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 122 uint64_t mode; 123 sa = entry->sa; 124 if (sa_spi != sa->spi) 125 continue; 126 127 /* add SA configuration key/values pairs */ 128 rte_tel_data_add_dict_string(data, "Type", 129 (sa->type & RTE_IPSEC_SATP_PROTO_MASK) == 130 RTE_IPSEC_SATP_PROTO_AH ? "AH" : "ESP"); 131 132 rte_tel_data_add_dict_string(data, "Direction", 133 (sa->type & RTE_IPSEC_SATP_DIR_MASK) == 134 RTE_IPSEC_SATP_DIR_IB ? "Inbound" : "Outbound"); 135 136 mode = sa->type & RTE_IPSEC_SATP_MODE_MASK; 137 138 if (mode == RTE_IPSEC_SATP_MODE_TRANS) { 139 rte_tel_data_add_dict_string(data, "Mode", "Transport"); 140 } else { 141 rte_tel_data_add_dict_string(data, "Mode", "Tunnel"); 142 143 if ((sa->type & RTE_IPSEC_SATP_NATT_MASK) == 144 RTE_IPSEC_SATP_NATT_ENABLE) { 145 if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { 146 rte_tel_data_add_dict_string(data, 147 "Tunnel-Type", 148 "IPv4-UDP"); 149 } else if (sa->type & 150 RTE_IPSEC_SATP_MODE_TUNLV6) { 151 rte_tel_data_add_dict_string(data, 152 "Tunnel-Type", 153 "IPv6-UDP"); 154 } 155 } else { 156 if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { 157 rte_tel_data_add_dict_string(data, 158 "Tunnel-Type", 159 "IPv4"); 160 } else if (sa->type & 161 RTE_IPSEC_SATP_MODE_TUNLV6) { 162 rte_tel_data_add_dict_string(data, 163 "Tunnel-Type", 164 "IPv6"); 165 } 166 } 167 } 168 169 rte_tel_data_add_dict_string(data, 170 "extended-sequence-number", 171 (sa->type & RTE_IPSEC_SATP_ESN_MASK) == 172 RTE_IPSEC_SATP_ESN_ENABLE ? 173 "enabled" : "disabled"); 174 175 if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) == 176 RTE_IPSEC_SATP_DIR_IB) 177 178 if (sa->sqn.inb.rsn[sa->sqn.inb.rdidx]) 179 rte_tel_data_add_dict_uint(data, 180 "sequence-number", 181 sa->sqn.inb.rsn[sa->sqn.inb.rdidx]->sqn); 182 else 183 rte_tel_data_add_dict_uint(data, 184 "sequence-number", 185 0); 186 else 187 rte_tel_data_add_dict_uint(data, "sequence-number", 188 sa->sqn.outb); 189 190 rte_tel_data_add_dict_string(data, 191 "explicit-congestion-notification", 192 (sa->type & RTE_IPSEC_SATP_ECN_MASK) == 193 RTE_IPSEC_SATP_ECN_ENABLE ? 194 "enabled" : "disabled"); 195 196 rte_tel_data_add_dict_string(data, 197 "copy-DSCP", 198 (sa->type & RTE_IPSEC_SATP_DSCP_MASK) == 199 RTE_IPSEC_SATP_DSCP_ENABLE ? 200 "enabled" : "disabled"); 201 } 202 203 return 0; 204 } 205 206 207 int 208 rte_ipsec_telemetry_sa_add(const struct rte_ipsec_sa *sa) 209 { 210 struct ipsec_telemetry_entry *entry = rte_zmalloc(NULL, 211 sizeof(struct ipsec_telemetry_entry), 0); 212 if (entry == NULL) 213 return -ENOMEM; 214 entry->sa = sa; 215 LIST_INSERT_HEAD(&ipsec_telemetry_list, entry, next); 216 return 0; 217 } 218 219 void 220 rte_ipsec_telemetry_sa_del(const struct rte_ipsec_sa *sa) 221 { 222 struct ipsec_telemetry_entry *entry; 223 LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 224 if (sa == entry->sa) { 225 LIST_REMOVE(entry, next); 226 rte_free(entry); 227 return; 228 } 229 } 230 } 231 232 233 RTE_INIT(rte_ipsec_telemetry_init) 234 { 235 rte_telemetry_register_cmd("/ipsec/sa/list", 236 handle_telemetry_cmd_ipsec_sa_list, 237 "Return list of IPsec SAs with telemetry enabled."); 238 rte_telemetry_register_cmd("/ipsec/sa/stats", 239 handle_telemetry_cmd_ipsec_sa_stats, 240 "Returns IPsec SA statistics. Parameters: int sa_spi"); 241 rte_telemetry_register_cmd("/ipsec/sa/details", 242 handle_telemetry_cmd_ipsec_sa_details, 243 "Returns IPsec SA configuration. Parameters: int sa_spi"); 244 } 245