xref: /f-stack/dpdk/drivers/net/ixgbe/ixgbe_ipsec.c (revision 031be553)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <rte_ethdev.h>
35 #include <rte_ethdev_pci.h>
36 #include <rte_ip.h>
37 #include <rte_jhash.h>
38 #include <rte_security_driver.h>
39 #include <rte_cryptodev.h>
40 #include <rte_flow.h>
41 
42 #include "base/ixgbe_type.h"
43 #include "base/ixgbe_api.h"
44 #include "ixgbe_ethdev.h"
45 #include "ixgbe_ipsec.h"
46 
47 #define RTE_IXGBE_REGISTER_POLL_WAIT_5_MS  5
48 
49 #define IXGBE_WAIT_RREAD \
50 	IXGBE_WRITE_REG_THEN_POLL_MASK(hw, IXGBE_IPSRXIDX, reg_val, \
51 	IPSRXIDX_READ, RTE_IXGBE_REGISTER_POLL_WAIT_5_MS)
52 #define IXGBE_WAIT_RWRITE \
53 	IXGBE_WRITE_REG_THEN_POLL_MASK(hw, IXGBE_IPSRXIDX, reg_val, \
54 	IPSRXIDX_WRITE, RTE_IXGBE_REGISTER_POLL_WAIT_5_MS)
55 #define IXGBE_WAIT_TREAD \
56 	IXGBE_WRITE_REG_THEN_POLL_MASK(hw, IXGBE_IPSTXIDX, reg_val, \
57 	IPSRXIDX_READ, RTE_IXGBE_REGISTER_POLL_WAIT_5_MS)
58 #define IXGBE_WAIT_TWRITE \
59 	IXGBE_WRITE_REG_THEN_POLL_MASK(hw, IXGBE_IPSTXIDX, reg_val, \
60 	IPSRXIDX_WRITE, RTE_IXGBE_REGISTER_POLL_WAIT_5_MS)
61 
62 #define CMP_IP(a, b) (\
63 	(a).ipv6[0] == (b).ipv6[0] && \
64 	(a).ipv6[1] == (b).ipv6[1] && \
65 	(a).ipv6[2] == (b).ipv6[2] && \
66 	(a).ipv6[3] == (b).ipv6[3])
67 
68 
69 static void
70 ixgbe_crypto_clear_ipsec_tables(struct rte_eth_dev *dev)
71 {
72 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
73 	int i = 0;
74 
75 	/* clear Rx IP table*/
76 	for (i = 0; i < IPSEC_MAX_RX_IP_COUNT; i++) {
77 		uint16_t index = i << 3;
78 		uint32_t reg_val = IPSRXIDX_WRITE | IPSRXIDX_TABLE_IP | index;
79 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(0), 0);
80 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(1), 0);
81 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(2), 0);
82 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(3), 0);
83 		IXGBE_WAIT_RWRITE;
84 	}
85 
86 	/* clear Rx SPI and Rx/Tx SA tables*/
87 	for (i = 0; i < IPSEC_MAX_SA_COUNT; i++) {
88 		uint32_t index = i << 3;
89 		uint32_t reg_val = IPSRXIDX_WRITE | IPSRXIDX_TABLE_SPI | index;
90 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXSPI, 0);
91 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPIDX, 0);
92 		IXGBE_WAIT_RWRITE;
93 		reg_val = IPSRXIDX_WRITE | IPSRXIDX_TABLE_KEY | index;
94 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(0), 0);
95 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(1), 0);
96 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(2), 0);
97 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(3), 0);
98 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXSALT, 0);
99 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXMOD, 0);
100 		IXGBE_WAIT_RWRITE;
101 		reg_val = IPSRXIDX_WRITE | index;
102 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(0), 0);
103 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(1), 0);
104 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(2), 0);
105 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(3), 0);
106 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXSALT, 0);
107 		IXGBE_WAIT_TWRITE;
108 	}
109 }
110 
111 static int
112 ixgbe_crypto_add_sa(struct ixgbe_crypto_session *ic_session)
113 {
114 	struct rte_eth_dev *dev = ic_session->dev;
115 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
116 	struct ixgbe_ipsec *priv = IXGBE_DEV_PRIVATE_TO_IPSEC(
117 			dev->data->dev_private);
118 	uint32_t reg_val;
119 	int sa_index = -1;
120 
121 	if (ic_session->op == IXGBE_OP_AUTHENTICATED_DECRYPTION) {
122 		int i, ip_index = -1;
123 
124 		/* Find a match in the IP table*/
125 		for (i = 0; i < IPSEC_MAX_RX_IP_COUNT; i++) {
126 			if (CMP_IP(priv->rx_ip_tbl[i].ip,
127 				   ic_session->dst_ip)) {
128 				ip_index = i;
129 				break;
130 			}
131 		}
132 		/* If no match, find a free entry in the IP table*/
133 		if (ip_index < 0) {
134 			for (i = 0; i < IPSEC_MAX_RX_IP_COUNT; i++) {
135 				if (priv->rx_ip_tbl[i].ref_count == 0) {
136 					ip_index = i;
137 					break;
138 				}
139 			}
140 		}
141 
142 		/* Fail if no match and no free entries*/
143 		if (ip_index < 0) {
144 			PMD_DRV_LOG(ERR,
145 				    "No free entry left in the Rx IP table\n");
146 			return -1;
147 		}
148 
149 		/* Find a free entry in the SA table*/
150 		for (i = 0; i < IPSEC_MAX_SA_COUNT; i++) {
151 			if (priv->rx_sa_tbl[i].used == 0) {
152 				sa_index = i;
153 				break;
154 			}
155 		}
156 		/* Fail if no free entries*/
157 		if (sa_index < 0) {
158 			PMD_DRV_LOG(ERR,
159 				    "No free entry left in the Rx SA table\n");
160 			return -1;
161 		}
162 
163 		priv->rx_ip_tbl[ip_index].ip.ipv6[0] =
164 				ic_session->dst_ip.ipv6[0];
165 		priv->rx_ip_tbl[ip_index].ip.ipv6[1] =
166 				ic_session->dst_ip.ipv6[1];
167 		priv->rx_ip_tbl[ip_index].ip.ipv6[2] =
168 				ic_session->dst_ip.ipv6[2];
169 		priv->rx_ip_tbl[ip_index].ip.ipv6[3] =
170 				ic_session->dst_ip.ipv6[3];
171 		priv->rx_ip_tbl[ip_index].ref_count++;
172 
173 		priv->rx_sa_tbl[sa_index].spi =
174 			rte_cpu_to_be_32(ic_session->spi);
175 		priv->rx_sa_tbl[sa_index].ip_index = ip_index;
176 		priv->rx_sa_tbl[sa_index].key[3] =
177 			rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[0]);
178 		priv->rx_sa_tbl[sa_index].key[2] =
179 			rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[4]);
180 		priv->rx_sa_tbl[sa_index].key[1] =
181 			rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[8]);
182 		priv->rx_sa_tbl[sa_index].key[0] =
183 			rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[12]);
184 		priv->rx_sa_tbl[sa_index].salt =
185 			rte_cpu_to_be_32(ic_session->salt);
186 		priv->rx_sa_tbl[sa_index].mode = IPSRXMOD_VALID;
187 		if (ic_session->op == IXGBE_OP_AUTHENTICATED_DECRYPTION)
188 			priv->rx_sa_tbl[sa_index].mode |=
189 					(IPSRXMOD_PROTO | IPSRXMOD_DECRYPT);
190 		if (ic_session->dst_ip.type == IPv6)
191 			priv->rx_sa_tbl[sa_index].mode |= IPSRXMOD_IPV6;
192 		priv->rx_sa_tbl[sa_index].used = 1;
193 
194 		/* write IP table entry*/
195 		reg_val = IPSRXIDX_RX_EN | IPSRXIDX_WRITE |
196 				IPSRXIDX_TABLE_IP | (ip_index << 3);
197 		if (priv->rx_ip_tbl[ip_index].ip.type == IPv4) {
198 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(0), 0);
199 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(1), 0);
200 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(2), 0);
201 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(3),
202 					priv->rx_ip_tbl[ip_index].ip.ipv4);
203 		} else {
204 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(0),
205 					priv->rx_ip_tbl[ip_index].ip.ipv6[0]);
206 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(1),
207 					priv->rx_ip_tbl[ip_index].ip.ipv6[1]);
208 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(2),
209 					priv->rx_ip_tbl[ip_index].ip.ipv6[2]);
210 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(3),
211 					priv->rx_ip_tbl[ip_index].ip.ipv6[3]);
212 		}
213 		IXGBE_WAIT_RWRITE;
214 
215 		/* write SPI table entry*/
216 		reg_val = IPSRXIDX_RX_EN | IPSRXIDX_WRITE |
217 				IPSRXIDX_TABLE_SPI | (sa_index << 3);
218 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXSPI,
219 				priv->rx_sa_tbl[sa_index].spi);
220 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPIDX,
221 				priv->rx_sa_tbl[sa_index].ip_index);
222 		IXGBE_WAIT_RWRITE;
223 
224 		/* write Key table entry*/
225 		reg_val = IPSRXIDX_RX_EN | IPSRXIDX_WRITE |
226 				IPSRXIDX_TABLE_KEY | (sa_index << 3);
227 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(0),
228 				priv->rx_sa_tbl[sa_index].key[0]);
229 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(1),
230 				priv->rx_sa_tbl[sa_index].key[1]);
231 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(2),
232 				priv->rx_sa_tbl[sa_index].key[2]);
233 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(3),
234 				priv->rx_sa_tbl[sa_index].key[3]);
235 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXSALT,
236 				priv->rx_sa_tbl[sa_index].salt);
237 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXMOD,
238 				priv->rx_sa_tbl[sa_index].mode);
239 		IXGBE_WAIT_RWRITE;
240 
241 	} else { /* sess->dir == RTE_CRYPTO_OUTBOUND */
242 		int i;
243 
244 		/* Find a free entry in the SA table*/
245 		for (i = 0; i < IPSEC_MAX_SA_COUNT; i++) {
246 			if (priv->tx_sa_tbl[i].used == 0) {
247 				sa_index = i;
248 				break;
249 			}
250 		}
251 		/* Fail if no free entries*/
252 		if (sa_index < 0) {
253 			PMD_DRV_LOG(ERR,
254 				    "No free entry left in the Tx SA table\n");
255 			return -1;
256 		}
257 
258 		priv->tx_sa_tbl[sa_index].spi =
259 			rte_cpu_to_be_32(ic_session->spi);
260 		priv->tx_sa_tbl[sa_index].key[3] =
261 			rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[0]);
262 		priv->tx_sa_tbl[sa_index].key[2] =
263 			rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[4]);
264 		priv->tx_sa_tbl[sa_index].key[1] =
265 			rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[8]);
266 		priv->tx_sa_tbl[sa_index].key[0] =
267 			rte_cpu_to_be_32(*(uint32_t *)&ic_session->key[12]);
268 		priv->tx_sa_tbl[sa_index].salt =
269 			rte_cpu_to_be_32(ic_session->salt);
270 
271 		reg_val = IPSRXIDX_RX_EN | IPSRXIDX_WRITE | (sa_index << 3);
272 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(0),
273 				priv->tx_sa_tbl[sa_index].key[0]);
274 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(1),
275 				priv->tx_sa_tbl[sa_index].key[1]);
276 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(2),
277 				priv->tx_sa_tbl[sa_index].key[2]);
278 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(3),
279 				priv->tx_sa_tbl[sa_index].key[3]);
280 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXSALT,
281 				priv->tx_sa_tbl[sa_index].salt);
282 		IXGBE_WAIT_TWRITE;
283 
284 		priv->tx_sa_tbl[i].used = 1;
285 		ic_session->sa_index = sa_index;
286 	}
287 
288 	return 0;
289 }
290 
291 static int
292 ixgbe_crypto_remove_sa(struct rte_eth_dev *dev,
293 		       struct ixgbe_crypto_session *ic_session)
294 {
295 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
296 	struct ixgbe_ipsec *priv =
297 			IXGBE_DEV_PRIVATE_TO_IPSEC(dev->data->dev_private);
298 	uint32_t reg_val;
299 	int sa_index = -1;
300 
301 	if (ic_session->op == IXGBE_OP_AUTHENTICATED_DECRYPTION) {
302 		int i, ip_index = -1;
303 
304 		/* Find a match in the IP table*/
305 		for (i = 0; i < IPSEC_MAX_RX_IP_COUNT; i++) {
306 			if (CMP_IP(priv->rx_ip_tbl[i].ip, ic_session->dst_ip)) {
307 				ip_index = i;
308 				break;
309 			}
310 		}
311 
312 		/* Fail if no match*/
313 		if (ip_index < 0) {
314 			PMD_DRV_LOG(ERR,
315 				    "Entry not found in the Rx IP table\n");
316 			return -1;
317 		}
318 
319 		/* Find a free entry in the SA table*/
320 		for (i = 0; i < IPSEC_MAX_SA_COUNT; i++) {
321 			if (priv->rx_sa_tbl[i].spi ==
322 				  rte_cpu_to_be_32(ic_session->spi)) {
323 				sa_index = i;
324 				break;
325 			}
326 		}
327 		/* Fail if no match*/
328 		if (sa_index < 0) {
329 			PMD_DRV_LOG(ERR,
330 				    "Entry not found in the Rx SA table\n");
331 			return -1;
332 		}
333 
334 		/* Disable and clear Rx SPI and key table table entryes*/
335 		reg_val = IPSRXIDX_WRITE | IPSRXIDX_TABLE_SPI | (sa_index << 3);
336 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXSPI, 0);
337 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPIDX, 0);
338 		IXGBE_WAIT_RWRITE;
339 		reg_val = IPSRXIDX_WRITE | IPSRXIDX_TABLE_KEY | (sa_index << 3);
340 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(0), 0);
341 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(1), 0);
342 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(2), 0);
343 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXKEY(3), 0);
344 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXSALT, 0);
345 		IXGBE_WRITE_REG(hw, IXGBE_IPSRXMOD, 0);
346 		IXGBE_WAIT_RWRITE;
347 		priv->rx_sa_tbl[sa_index].used = 0;
348 
349 		/* If last used then clear the IP table entry*/
350 		priv->rx_ip_tbl[ip_index].ref_count--;
351 		if (priv->rx_ip_tbl[ip_index].ref_count == 0) {
352 			reg_val = IPSRXIDX_WRITE | IPSRXIDX_TABLE_IP |
353 					(ip_index << 3);
354 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(0), 0);
355 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(1), 0);
356 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(2), 0);
357 			IXGBE_WRITE_REG(hw, IXGBE_IPSRXIPADDR(3), 0);
358 		}
359 	} else { /* session->dir == RTE_CRYPTO_OUTBOUND */
360 		int i;
361 
362 		/* Find a match in the SA table*/
363 		for (i = 0; i < IPSEC_MAX_SA_COUNT; i++) {
364 			if (priv->tx_sa_tbl[i].spi ==
365 				    rte_cpu_to_be_32(ic_session->spi)) {
366 				sa_index = i;
367 				break;
368 			}
369 		}
370 		/* Fail if no match entries*/
371 		if (sa_index < 0) {
372 			PMD_DRV_LOG(ERR,
373 				    "Entry not found in the Tx SA table\n");
374 			return -1;
375 		}
376 		reg_val = IPSRXIDX_WRITE | (sa_index << 3);
377 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(0), 0);
378 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(1), 0);
379 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(2), 0);
380 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXKEY(3), 0);
381 		IXGBE_WRITE_REG(hw, IXGBE_IPSTXSALT, 0);
382 		IXGBE_WAIT_TWRITE;
383 
384 		priv->tx_sa_tbl[sa_index].used = 0;
385 	}
386 
387 	return 0;
388 }
389 
390 static int
391 ixgbe_crypto_create_session(void *device,
392 		struct rte_security_session_conf *conf,
393 		struct rte_security_session *session,
394 		struct rte_mempool *mempool)
395 {
396 	struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)device;
397 	struct ixgbe_crypto_session *ic_session = NULL;
398 	struct rte_crypto_aead_xform *aead_xform;
399 	struct rte_eth_conf *dev_conf = &eth_dev->data->dev_conf;
400 
401 	if (rte_mempool_get(mempool, (void **)&ic_session)) {
402 		PMD_DRV_LOG(ERR, "Cannot get object from ic_session mempool");
403 		return -ENOMEM;
404 	}
405 
406 	if (conf->crypto_xform->type != RTE_CRYPTO_SYM_XFORM_AEAD ||
407 			conf->crypto_xform->aead.algo !=
408 					RTE_CRYPTO_AEAD_AES_GCM) {
409 		PMD_DRV_LOG(ERR, "Unsupported crypto transformation mode\n");
410 		return -ENOTSUP;
411 	}
412 	aead_xform = &conf->crypto_xform->aead;
413 
414 	if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
415 		if (dev_conf->rxmode.offloads & DEV_RX_OFFLOAD_SECURITY) {
416 			ic_session->op = IXGBE_OP_AUTHENTICATED_DECRYPTION;
417 		} else {
418 			PMD_DRV_LOG(ERR, "IPsec decryption not enabled\n");
419 			return -ENOTSUP;
420 		}
421 	} else {
422 		if (dev_conf->txmode.offloads & DEV_TX_OFFLOAD_SECURITY) {
423 			ic_session->op = IXGBE_OP_AUTHENTICATED_ENCRYPTION;
424 		} else {
425 			PMD_DRV_LOG(ERR, "IPsec encryption not enabled\n");
426 			return -ENOTSUP;
427 		}
428 	}
429 
430 	ic_session->key = aead_xform->key.data;
431 	memcpy(&ic_session->salt,
432 	       &aead_xform->key.data[aead_xform->key.length], 4);
433 	ic_session->spi = conf->ipsec.spi;
434 	ic_session->dev = eth_dev;
435 
436 	set_sec_session_private_data(session, ic_session);
437 
438 	if (ic_session->op == IXGBE_OP_AUTHENTICATED_ENCRYPTION) {
439 		if (ixgbe_crypto_add_sa(ic_session)) {
440 			PMD_DRV_LOG(ERR, "Failed to add SA\n");
441 			return -EPERM;
442 		}
443 	}
444 
445 	return 0;
446 }
447 
448 static int
449 ixgbe_crypto_remove_session(void *device,
450 		struct rte_security_session *session)
451 {
452 	struct rte_eth_dev *eth_dev = device;
453 	struct ixgbe_crypto_session *ic_session =
454 		(struct ixgbe_crypto_session *)
455 		get_sec_session_private_data(session);
456 	struct rte_mempool *mempool = rte_mempool_from_obj(ic_session);
457 
458 	if (eth_dev != ic_session->dev) {
459 		PMD_DRV_LOG(ERR, "Session not bound to this device\n");
460 		return -ENODEV;
461 	}
462 
463 	if (ixgbe_crypto_remove_sa(eth_dev, ic_session)) {
464 		PMD_DRV_LOG(ERR, "Failed to remove session\n");
465 		return -EFAULT;
466 	}
467 
468 	rte_mempool_put(mempool, (void *)ic_session);
469 
470 	return 0;
471 }
472 
473 static inline uint8_t
474 ixgbe_crypto_compute_pad_len(struct rte_mbuf *m)
475 {
476 	if (m->nb_segs == 1) {
477 		/* 16 bytes ICV + 2 bytes ESP trailer + payload padding size
478 		 * payload padding size is stored at <pkt_len - 18>
479 		 */
480 		uint8_t *esp_pad_len = rte_pktmbuf_mtod_offset(m, uint8_t *,
481 					rte_pktmbuf_pkt_len(m) -
482 					(ESP_TRAILER_SIZE + ESP_ICV_SIZE));
483 		return *esp_pad_len + ESP_TRAILER_SIZE + ESP_ICV_SIZE;
484 	}
485 	return 0;
486 }
487 
488 static int
489 ixgbe_crypto_update_mb(void *device __rte_unused,
490 		struct rte_security_session *session,
491 		       struct rte_mbuf *m, void *params __rte_unused)
492 {
493 	struct ixgbe_crypto_session *ic_session =
494 			get_sec_session_private_data(session);
495 	if (ic_session->op == IXGBE_OP_AUTHENTICATED_ENCRYPTION) {
496 		union ixgbe_crypto_tx_desc_md *mdata =
497 			(union ixgbe_crypto_tx_desc_md *)&m->udata64;
498 		mdata->enc = 1;
499 		mdata->sa_idx = ic_session->sa_index;
500 		mdata->pad_len = ixgbe_crypto_compute_pad_len(m);
501 	}
502 	return 0;
503 }
504 
505 
506 static const struct rte_security_capability *
507 ixgbe_crypto_capabilities_get(void *device __rte_unused)
508 {
509 	static const struct rte_cryptodev_capabilities
510 	aes_gcm_gmac_crypto_capabilities[] = {
511 		{	/* AES GMAC (128-bit) */
512 			.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
513 			{.sym = {
514 				.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
515 				{.auth = {
516 					.algo = RTE_CRYPTO_AUTH_AES_GMAC,
517 					.block_size = 16,
518 					.key_size = {
519 						.min = 16,
520 						.max = 16,
521 						.increment = 0
522 					},
523 					.digest_size = {
524 						.min = 16,
525 						.max = 16,
526 						.increment = 0
527 					},
528 					.iv_size = {
529 						.min = 12,
530 						.max = 12,
531 						.increment = 0
532 					}
533 				}, }
534 			}, }
535 		},
536 		{	/* AES GCM (128-bit) */
537 			.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
538 			{.sym = {
539 				.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
540 				{.aead = {
541 					.algo = RTE_CRYPTO_AEAD_AES_GCM,
542 					.block_size = 16,
543 					.key_size = {
544 						.min = 16,
545 						.max = 16,
546 						.increment = 0
547 					},
548 					.digest_size = {
549 						.min = 16,
550 						.max = 16,
551 						.increment = 0
552 					},
553 					.aad_size = {
554 						.min = 0,
555 						.max = 65535,
556 						.increment = 1
557 					},
558 					.iv_size = {
559 						.min = 12,
560 						.max = 12,
561 						.increment = 0
562 					}
563 				}, }
564 			}, }
565 		},
566 		{
567 			.op = RTE_CRYPTO_OP_TYPE_UNDEFINED,
568 			{.sym = {
569 				.xform_type = RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED
570 			}, }
571 		},
572 	};
573 
574 	static const struct rte_security_capability
575 	ixgbe_security_capabilities[] = {
576 		{ /* IPsec Inline Crypto ESP Transport Egress */
577 			.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
578 			.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
579 			{.ipsec = {
580 				.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
581 				.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
582 				.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
583 				.options = { 0 }
584 			} },
585 			.crypto_capabilities = aes_gcm_gmac_crypto_capabilities,
586 			.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
587 		},
588 		{ /* IPsec Inline Crypto ESP Transport Ingress */
589 			.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
590 			.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
591 			{.ipsec = {
592 				.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
593 				.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
594 				.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
595 				.options = { 0 }
596 			} },
597 			.crypto_capabilities = aes_gcm_gmac_crypto_capabilities,
598 			.ol_flags = 0
599 		},
600 		{ /* IPsec Inline Crypto ESP Tunnel Egress */
601 			.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
602 			.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
603 			{.ipsec = {
604 				.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
605 				.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
606 				.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
607 				.options = { 0 }
608 			} },
609 			.crypto_capabilities = aes_gcm_gmac_crypto_capabilities,
610 			.ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
611 		},
612 		{ /* IPsec Inline Crypto ESP Tunnel Ingress */
613 			.action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
614 			.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
615 			{.ipsec = {
616 				.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
617 				.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
618 				.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
619 				.options = { 0 }
620 			} },
621 			.crypto_capabilities = aes_gcm_gmac_crypto_capabilities,
622 			.ol_flags = 0
623 		},
624 		{
625 			.action = RTE_SECURITY_ACTION_TYPE_NONE
626 		}
627 	};
628 
629 	return ixgbe_security_capabilities;
630 }
631 
632 
633 int
634 ixgbe_crypto_enable_ipsec(struct rte_eth_dev *dev)
635 {
636 	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
637 	uint32_t reg;
638 
639 	/* sanity checks */
640 	if (dev->data->dev_conf.rxmode.enable_lro) {
641 		PMD_DRV_LOG(ERR, "RSC and IPsec not supported");
642 		return -1;
643 	}
644 	if (!dev->data->dev_conf.rxmode.hw_strip_crc) {
645 		PMD_DRV_LOG(ERR, "HW CRC strip needs to be enabled for IPsec");
646 		return -1;
647 	}
648 
649 
650 	/* Set IXGBE_SECTXBUFFAF to 0x15 as required in the datasheet*/
651 	IXGBE_WRITE_REG(hw, IXGBE_SECTXBUFFAF, 0x15);
652 
653 	/* IFG needs to be set to 3 when we are using security. Otherwise a Tx
654 	 * hang will occur with heavy traffic.
655 	 */
656 	reg = IXGBE_READ_REG(hw, IXGBE_SECTXMINIFG);
657 	reg = (reg & 0xFFFFFFF0) | 0x3;
658 	IXGBE_WRITE_REG(hw, IXGBE_SECTXMINIFG, reg);
659 
660 	reg  = IXGBE_READ_REG(hw, IXGBE_HLREG0);
661 	reg |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_RXCRCSTRP;
662 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg);
663 
664 	if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_SECURITY) {
665 		IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, 0);
666 		reg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
667 		if (reg != 0) {
668 			PMD_DRV_LOG(ERR, "Error enabling Rx Crypto");
669 			return -1;
670 		}
671 	}
672 	if (dev->data->dev_conf.txmode.offloads & DEV_TX_OFFLOAD_SECURITY) {
673 		IXGBE_WRITE_REG(hw, IXGBE_SECTXCTRL,
674 				IXGBE_SECTXCTRL_STORE_FORWARD);
675 		reg = IXGBE_READ_REG(hw, IXGBE_SECTXCTRL);
676 		if (reg != IXGBE_SECTXCTRL_STORE_FORWARD) {
677 			PMD_DRV_LOG(ERR, "Error enabling Rx Crypto");
678 			return -1;
679 		}
680 	}
681 
682 	ixgbe_crypto_clear_ipsec_tables(dev);
683 
684 	return 0;
685 }
686 
687 int
688 ixgbe_crypto_add_ingress_sa_from_flow(const void *sess,
689 				      const void *ip_spec,
690 				      uint8_t is_ipv6)
691 {
692 	struct ixgbe_crypto_session *ic_session
693 		= get_sec_session_private_data(sess);
694 
695 	if (ic_session->op == IXGBE_OP_AUTHENTICATED_DECRYPTION) {
696 		if (is_ipv6) {
697 			const struct rte_flow_item_ipv6 *ipv6 = ip_spec;
698 			ic_session->src_ip.type = IPv6;
699 			ic_session->dst_ip.type = IPv6;
700 			rte_memcpy(ic_session->src_ip.ipv6,
701 				   ipv6->hdr.src_addr, 16);
702 			rte_memcpy(ic_session->dst_ip.ipv6,
703 				   ipv6->hdr.dst_addr, 16);
704 		} else {
705 			const struct rte_flow_item_ipv4 *ipv4 = ip_spec;
706 			ic_session->src_ip.type = IPv4;
707 			ic_session->dst_ip.type = IPv4;
708 			ic_session->src_ip.ipv4 = ipv4->hdr.src_addr;
709 			ic_session->dst_ip.ipv4 = ipv4->hdr.dst_addr;
710 		}
711 		return ixgbe_crypto_add_sa(ic_session);
712 	}
713 
714 	return 0;
715 }
716 
717 static struct rte_security_ops ixgbe_security_ops = {
718 	.session_create = ixgbe_crypto_create_session,
719 	.session_update = NULL,
720 	.session_stats_get = NULL,
721 	.session_destroy = ixgbe_crypto_remove_session,
722 	.set_pkt_metadata = ixgbe_crypto_update_mb,
723 	.capabilities_get = ixgbe_crypto_capabilities_get
724 };
725 
726 struct rte_security_ctx *
727 ixgbe_ipsec_ctx_create(struct rte_eth_dev *dev)
728 {
729 	struct rte_security_ctx *ctx = rte_malloc("rte_security_instances_ops",
730 					sizeof(struct rte_security_ctx), 0);
731 	if (ctx) {
732 		ctx->device = (void *)dev;
733 		ctx->ops = &ixgbe_security_ops;
734 		ctx->sess_cnt = 0;
735 	}
736 	return ctx;
737 }
738