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