1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2021 Intel Corporation 3 */ 4 5 #include <rte_ipsec.h> 6 #include <rte_telemetry.h> 7 #include <rte_malloc.h> 8 #include "sa.h" 9 10 11 struct ipsec_telemetry_entry { 12 LIST_ENTRY(ipsec_telemetry_entry) next; 13 const struct rte_ipsec_sa *sa; 14 }; 15 static LIST_HEAD(ipsec_telemetry_head, ipsec_telemetry_entry) 16 ipsec_telemetry_list = LIST_HEAD_INITIALIZER(); 17 18 static int 19 handle_telemetry_cmd_ipsec_sa_list(const char *cmd __rte_unused, 20 const char *params __rte_unused, 21 struct rte_tel_data *data) 22 { 23 struct ipsec_telemetry_entry *entry; 24 rte_tel_data_start_array(data, RTE_TEL_U64_VAL); 25 26 LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 27 const struct rte_ipsec_sa *sa = entry->sa; 28 rte_tel_data_add_array_u64(data, rte_be_to_cpu_32(sa->spi)); 29 } 30 31 return 0; 32 } 33 34 /** 35 * Handle IPsec SA statistics telemetry request 36 * 37 * Return dict of SA's with dict of key/value counters 38 * 39 * { 40 * "SA_SPI_XX": {"count": 0, "bytes": 0, "errors": 0}, 41 * "SA_SPI_YY": {"count": 0, "bytes": 0, "errors": 0} 42 * } 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_u64(sa_data, name_pkt_cnt, 83 sa->statistics.count); 84 85 rte_tel_data_add_dict_u64(sa_data, name_byte_cnt, 86 sa->statistics.bytes - 87 (sa->statistics.count * sa->hdr_len)); 88 89 rte_tel_data_add_dict_u64(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_u64(data, 180 "sequence-number", 181 sa->sqn.inb.rsn[sa->sqn.inb.rdidx]->sqn); 182 else 183 rte_tel_data_add_dict_u64(data, 184 "sequence-number", 0); 185 else 186 rte_tel_data_add_dict_u64(data, "sequence-number", 187 sa->sqn.outb); 188 189 rte_tel_data_add_dict_string(data, 190 "explicit-congestion-notification", 191 (sa->type & RTE_IPSEC_SATP_ECN_MASK) == 192 RTE_IPSEC_SATP_ECN_ENABLE ? 193 "enabled" : "disabled"); 194 195 rte_tel_data_add_dict_string(data, 196 "copy-DSCP", 197 (sa->type & RTE_IPSEC_SATP_DSCP_MASK) == 198 RTE_IPSEC_SATP_DSCP_ENABLE ? 199 "enabled" : "disabled"); 200 } 201 202 return 0; 203 } 204 205 206 int 207 rte_ipsec_telemetry_sa_add(const struct rte_ipsec_sa *sa) 208 { 209 struct ipsec_telemetry_entry *entry = rte_zmalloc(NULL, 210 sizeof(struct ipsec_telemetry_entry), 0); 211 if (entry == NULL) 212 return -ENOMEM; 213 entry->sa = sa; 214 LIST_INSERT_HEAD(&ipsec_telemetry_list, entry, next); 215 return 0; 216 } 217 218 void 219 rte_ipsec_telemetry_sa_del(const struct rte_ipsec_sa *sa) 220 { 221 struct ipsec_telemetry_entry *entry; 222 LIST_FOREACH(entry, &ipsec_telemetry_list, next) { 223 if (sa == entry->sa) { 224 LIST_REMOVE(entry, next); 225 rte_free(entry); 226 return; 227 } 228 } 229 } 230 231 232 RTE_INIT(rte_ipsec_telemetry_init) 233 { 234 rte_telemetry_register_cmd("/ipsec/sa/list", 235 handle_telemetry_cmd_ipsec_sa_list, 236 "Return list of IPsec SAs with telemetry enabled."); 237 rte_telemetry_register_cmd("/ipsec/sa/stats", 238 handle_telemetry_cmd_ipsec_sa_stats, 239 "Returns IPsec SA statistics. Parameters: int sa_spi"); 240 rte_telemetry_register_cmd("/ipsec/sa/details", 241 handle_telemetry_cmd_ipsec_sa_details, 242 "Returns IPsec SA configuration. Parameters: int sa_spi"); 243 } 244