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
handle_telemetry_cmd_ipsec_sa_list(const char * cmd __rte_unused,const char * params __rte_unused,struct rte_tel_data * data)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
handle_telemetry_cmd_ipsec_sa_stats(const char * cmd __rte_unused,const char * params,struct rte_tel_data * data)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
handle_telemetry_cmd_ipsec_sa_details(const char * cmd __rte_unused,const char * params,struct rte_tel_data * data)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
rte_ipsec_telemetry_sa_add(const struct rte_ipsec_sa * sa)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
rte_ipsec_telemetry_sa_del(const struct rte_ipsec_sa * sa)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
RTE_INIT(rte_ipsec_telemetry_init)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