xref: /dpdk/lib/ipsec/ipsec_telemetry.c (revision 09442498ef736d0a96632cf8b8c15d8ca78a6468)
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  */
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_uint(sa_data, name_pkt_cnt,
84 					   sa->statistics.count);
85 
86 		rte_tel_data_add_dict_uint(sa_data, name_byte_cnt,
87 					   sa->statistics.bytes -
88 					   (sa->statistics.count * sa->hdr_len));
89 
90 		rte_tel_data_add_dict_uint(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_uint(data,
181 							   "sequence-number",
182 							   sa->sqn.inb.rsn[sa->sqn.inb.rdidx]->sqn);
183 			else
184 				rte_tel_data_add_dict_uint(data,
185 							   "sequence-number",
186 							   0);
187 		else
188 			rte_tel_data_add_dict_uint(data, "sequence-number",
189 						   sa->sqn.outb);
190 
191 		rte_tel_data_add_dict_string(data,
192 				"explicit-congestion-notification",
193 				(sa->type & RTE_IPSEC_SATP_ECN_MASK) ==
194 				RTE_IPSEC_SATP_ECN_ENABLE ?
195 				"enabled" : "disabled");
196 
197 		rte_tel_data_add_dict_string(data,
198 				"copy-DSCP",
199 				(sa->type & RTE_IPSEC_SATP_DSCP_MASK) ==
200 				RTE_IPSEC_SATP_DSCP_ENABLE ?
201 				"enabled" : "disabled");
202 	}
203 
204 	return 0;
205 }
206 
207 
208 int
209 rte_ipsec_telemetry_sa_add(const struct rte_ipsec_sa *sa)
210 {
211 	struct ipsec_telemetry_entry *entry = rte_zmalloc(NULL,
212 			sizeof(struct ipsec_telemetry_entry), 0);
213 	if (entry == NULL)
214 		return -ENOMEM;
215 	entry->sa = sa;
216 	LIST_INSERT_HEAD(&ipsec_telemetry_list, entry, next);
217 	return 0;
218 }
219 
220 void
221 rte_ipsec_telemetry_sa_del(const struct rte_ipsec_sa *sa)
222 {
223 	struct ipsec_telemetry_entry *entry;
224 	LIST_FOREACH(entry, &ipsec_telemetry_list, next) {
225 		if (sa == entry->sa) {
226 			LIST_REMOVE(entry, next);
227 			rte_free(entry);
228 			return;
229 		}
230 	}
231 }
232 
233 
234 RTE_INIT(rte_ipsec_telemetry_init)
235 {
236 	rte_telemetry_register_cmd("/ipsec/sa/list",
237 		handle_telemetry_cmd_ipsec_sa_list,
238 		"Return list of IPsec SAs with telemetry enabled.");
239 	rte_telemetry_register_cmd("/ipsec/sa/stats",
240 		handle_telemetry_cmd_ipsec_sa_stats,
241 		"Returns IPsec SA statistics. Parameters: int sa_spi");
242 	rte_telemetry_register_cmd("/ipsec/sa/details",
243 		handle_telemetry_cmd_ipsec_sa_details,
244 		"Returns IPsec SA configuration. Parameters: int sa_spi");
245 }
246