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_U64_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_u64(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 */ 46 static int 47 handle_telemetry_cmd_ipsec_sa_stats(const char *cmd __rte_unused, 48 const char *params, 49 struct rte_tel_data *data) 50 { 51 struct ipsec_telemetry_entry *entry; 52 const struct rte_ipsec_sa *sa; 53 uint32_t sa_spi = 0; 54 55 if (params) { 56 sa_spi = rte_cpu_to_be_32((uint32_t)strtoul(params, NULL, 0)); 57 if (sa_spi == 0) 58 return -EINVAL; 59 } 60 61 rte_tel_data_start_dict(data); 62 63 LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 64 char sa_name[64]; 65 sa = entry->sa; 66 static const char *name_pkt_cnt = "count"; 67 static const char *name_byte_cnt = "bytes"; 68 static const char *name_error_cnt = "errors"; 69 struct rte_tel_data *sa_data; 70 71 /* If user provided SPI only get telemetry for that SA */ 72 if (sa_spi && (sa_spi != sa->spi)) 73 continue; 74 75 /* allocate telemetry data struct for SA telemetry */ 76 sa_data = rte_tel_data_alloc(); 77 if (!sa_data) 78 return -ENOMEM; 79 80 rte_tel_data_start_dict(sa_data); 81 82 /* add telemetry key/values pairs */ 83 rte_tel_data_add_dict_u64(sa_data, name_pkt_cnt, 84 sa->statistics.count); 85 86 rte_tel_data_add_dict_u64(sa_data, name_byte_cnt, 87 sa->statistics.bytes - 88 (sa->statistics.count * sa->hdr_len)); 89 90 rte_tel_data_add_dict_u64(sa_data, name_error_cnt, 91 sa->statistics.errors.count); 92 93 /* generate telemetry label */ 94 snprintf(sa_name, sizeof(sa_name), "SA_SPI_%i", 95 rte_be_to_cpu_32(sa->spi)); 96 97 /* add SA telemetry to dictionary container */ 98 rte_tel_data_add_dict_container(data, sa_name, sa_data, 0); 99 } 100 101 return 0; 102 } 103 104 static int 105 handle_telemetry_cmd_ipsec_sa_details(const char *cmd __rte_unused, 106 const char *params, 107 struct rte_tel_data *data) 108 { 109 struct ipsec_telemetry_entry *entry; 110 const struct rte_ipsec_sa *sa; 111 uint32_t sa_spi = 0; 112 113 if (params) 114 sa_spi = rte_cpu_to_be_32((uint32_t)strtoul(params, NULL, 0)); 115 /* valid SPI needed */ 116 if (sa_spi == 0) 117 return -EINVAL; 118 119 120 rte_tel_data_start_dict(data); 121 122 LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 123 uint64_t mode; 124 sa = entry->sa; 125 if (sa_spi != sa->spi) 126 continue; 127 128 /* add SA configuration key/values pairs */ 129 rte_tel_data_add_dict_string(data, "Type", 130 (sa->type & RTE_IPSEC_SATP_PROTO_MASK) == 131 RTE_IPSEC_SATP_PROTO_AH ? "AH" : "ESP"); 132 133 rte_tel_data_add_dict_string(data, "Direction", 134 (sa->type & RTE_IPSEC_SATP_DIR_MASK) == 135 RTE_IPSEC_SATP_DIR_IB ? "Inbound" : "Outbound"); 136 137 mode = sa->type & RTE_IPSEC_SATP_MODE_MASK; 138 139 if (mode == RTE_IPSEC_SATP_MODE_TRANS) { 140 rte_tel_data_add_dict_string(data, "Mode", "Transport"); 141 } else { 142 rte_tel_data_add_dict_string(data, "Mode", "Tunnel"); 143 144 if ((sa->type & RTE_IPSEC_SATP_NATT_MASK) == 145 RTE_IPSEC_SATP_NATT_ENABLE) { 146 if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { 147 rte_tel_data_add_dict_string(data, 148 "Tunnel-Type", 149 "IPv4-UDP"); 150 } else if (sa->type & 151 RTE_IPSEC_SATP_MODE_TUNLV6) { 152 rte_tel_data_add_dict_string(data, 153 "Tunnel-Type", 154 "IPv6-UDP"); 155 } 156 } else { 157 if (sa->type & RTE_IPSEC_SATP_MODE_TUNLV4) { 158 rte_tel_data_add_dict_string(data, 159 "Tunnel-Type", 160 "IPv4"); 161 } else if (sa->type & 162 RTE_IPSEC_SATP_MODE_TUNLV6) { 163 rte_tel_data_add_dict_string(data, 164 "Tunnel-Type", 165 "IPv6"); 166 } 167 } 168 } 169 170 rte_tel_data_add_dict_string(data, 171 "extended-sequence-number", 172 (sa->type & RTE_IPSEC_SATP_ESN_MASK) == 173 RTE_IPSEC_SATP_ESN_ENABLE ? 174 "enabled" : "disabled"); 175 176 if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) == 177 RTE_IPSEC_SATP_DIR_IB) 178 179 if (sa->sqn.inb.rsn[sa->sqn.inb.rdidx]) 180 rte_tel_data_add_dict_u64(data, 181 "sequence-number", 182 sa->sqn.inb.rsn[sa->sqn.inb.rdidx]->sqn); 183 else 184 rte_tel_data_add_dict_u64(data, 185 "sequence-number", 0); 186 else 187 rte_tel_data_add_dict_u64(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