xref: /dpdk/lib/ipsec/ipsec_telemetry.c (revision b4f0a9bb5807a4f0a4904595bb85a9a386696311)
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