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