net/txgbe: add security session create operation
[dpdk.git] / drivers / net / txgbe / txgbe_ipsec.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2015-2020
3  */
4
5 #include <rte_ethdev_pci.h>
6 #include <rte_security_driver.h>
7 #include <rte_cryptodev.h>
8
9 #include "base/txgbe.h"
10 #include "txgbe_ethdev.h"
11 #include "txgbe_ipsec.h"
12
13 #define CMP_IP(a, b) (\
14         (a).ipv6[0] == (b).ipv6[0] && \
15         (a).ipv6[1] == (b).ipv6[1] && \
16         (a).ipv6[2] == (b).ipv6[2] && \
17         (a).ipv6[3] == (b).ipv6[3])
18
19 static int
20 txgbe_crypto_add_sa(struct txgbe_crypto_session *ic_session)
21 {
22         struct rte_eth_dev *dev = ic_session->dev;
23         struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
24         struct txgbe_ipsec *priv = TXGBE_DEV_IPSEC(dev);
25         uint32_t reg_val;
26         int sa_index = -1;
27
28         if (ic_session->op == TXGBE_OP_AUTHENTICATED_DECRYPTION) {
29                 int i, ip_index = -1;
30                 uint8_t *key;
31
32                 /* Find a match in the IP table*/
33                 for (i = 0; i < IPSEC_MAX_RX_IP_COUNT; i++) {
34                         if (CMP_IP(priv->rx_ip_tbl[i].ip,
35                                    ic_session->dst_ip)) {
36                                 ip_index = i;
37                                 break;
38                         }
39                 }
40                 /* If no match, find a free entry in the IP table*/
41                 if (ip_index < 0) {
42                         for (i = 0; i < IPSEC_MAX_RX_IP_COUNT; i++) {
43                                 if (priv->rx_ip_tbl[i].ref_count == 0) {
44                                         ip_index = i;
45                                         break;
46                                 }
47                         }
48                 }
49
50                 /* Fail if no match and no free entries*/
51                 if (ip_index < 0) {
52                         PMD_DRV_LOG(ERR,
53                                     "No free entry left in the Rx IP table\n");
54                         return -1;
55                 }
56
57                 /* Find a free entry in the SA table*/
58                 for (i = 0; i < IPSEC_MAX_SA_COUNT; i++) {
59                         if (priv->rx_sa_tbl[i].used == 0) {
60                                 sa_index = i;
61                                 break;
62                         }
63                 }
64                 /* Fail if no free entries*/
65                 if (sa_index < 0) {
66                         PMD_DRV_LOG(ERR,
67                                     "No free entry left in the Rx SA table\n");
68                         return -1;
69                 }
70
71                 priv->rx_ip_tbl[ip_index].ip.ipv6[0] =
72                                 ic_session->dst_ip.ipv6[0];
73                 priv->rx_ip_tbl[ip_index].ip.ipv6[1] =
74                                 ic_session->dst_ip.ipv6[1];
75                 priv->rx_ip_tbl[ip_index].ip.ipv6[2] =
76                                 ic_session->dst_ip.ipv6[2];
77                 priv->rx_ip_tbl[ip_index].ip.ipv6[3] =
78                                 ic_session->dst_ip.ipv6[3];
79                 priv->rx_ip_tbl[ip_index].ref_count++;
80
81                 priv->rx_sa_tbl[sa_index].spi = ic_session->spi;
82                 priv->rx_sa_tbl[sa_index].ip_index = ip_index;
83                 priv->rx_sa_tbl[sa_index].mode = IPSRXMOD_VALID;
84                 if (ic_session->op == TXGBE_OP_AUTHENTICATED_DECRYPTION)
85                         priv->rx_sa_tbl[sa_index].mode |=
86                                         (IPSRXMOD_PROTO | IPSRXMOD_DECRYPT);
87                 if (ic_session->dst_ip.type == IPv6) {
88                         priv->rx_sa_tbl[sa_index].mode |= IPSRXMOD_IPV6;
89                         priv->rx_ip_tbl[ip_index].ip.type = IPv6;
90                 } else if (ic_session->dst_ip.type == IPv4) {
91                         priv->rx_ip_tbl[ip_index].ip.type = IPv4;
92                 }
93                 priv->rx_sa_tbl[sa_index].used = 1;
94
95                 /* write IP table entry*/
96                 reg_val = TXGBE_IPSRXIDX_ENA | TXGBE_IPSRXIDX_WRITE |
97                                 TXGBE_IPSRXIDX_TB_IP | (ip_index << 3);
98                 if (priv->rx_ip_tbl[ip_index].ip.type == IPv4) {
99                         wr32(hw, TXGBE_IPSRXADDR(0), 0);
100                         wr32(hw, TXGBE_IPSRXADDR(1), 0);
101                         wr32(hw, TXGBE_IPSRXADDR(2), 0);
102                         wr32(hw, TXGBE_IPSRXADDR(3),
103                                         priv->rx_ip_tbl[ip_index].ip.ipv4);
104                 } else {
105                         wr32(hw, TXGBE_IPSRXADDR(0),
106                                         priv->rx_ip_tbl[ip_index].ip.ipv6[0]);
107                         wr32(hw, TXGBE_IPSRXADDR(1),
108                                         priv->rx_ip_tbl[ip_index].ip.ipv6[1]);
109                         wr32(hw, TXGBE_IPSRXADDR(2),
110                                         priv->rx_ip_tbl[ip_index].ip.ipv6[2]);
111                         wr32(hw, TXGBE_IPSRXADDR(3),
112                                         priv->rx_ip_tbl[ip_index].ip.ipv6[3]);
113                 }
114                 wr32w(hw, TXGBE_IPSRXIDX, reg_val, TXGBE_IPSRXIDX_WRITE, 1000);
115
116                 /* write SPI table entry*/
117                 reg_val = TXGBE_IPSRXIDX_ENA | TXGBE_IPSRXIDX_WRITE |
118                                 TXGBE_IPSRXIDX_TB_SPI | (sa_index << 3);
119                 wr32(hw, TXGBE_IPSRXSPI,
120                                 priv->rx_sa_tbl[sa_index].spi);
121                 wr32(hw, TXGBE_IPSRXADDRIDX,
122                                 priv->rx_sa_tbl[sa_index].ip_index);
123                 wr32w(hw, TXGBE_IPSRXIDX, reg_val, TXGBE_IPSRXIDX_WRITE, 1000);
124
125                 /* write Key table entry*/
126                 key = malloc(ic_session->key_len);
127                 if (!key)
128                         return -ENOMEM;
129
130                 memcpy(key, ic_session->key, ic_session->key_len);
131
132                 reg_val = TXGBE_IPSRXIDX_ENA | TXGBE_IPSRXIDX_WRITE |
133                                 TXGBE_IPSRXIDX_TB_KEY | (sa_index << 3);
134                 wr32(hw, TXGBE_IPSRXKEY(0),
135                         rte_cpu_to_be_32(*(uint32_t *)&key[12]));
136                 wr32(hw, TXGBE_IPSRXKEY(1),
137                         rte_cpu_to_be_32(*(uint32_t *)&key[8]));
138                 wr32(hw, TXGBE_IPSRXKEY(2),
139                         rte_cpu_to_be_32(*(uint32_t *)&key[4]));
140                 wr32(hw, TXGBE_IPSRXKEY(3),
141                         rte_cpu_to_be_32(*(uint32_t *)&key[0]));
142                 wr32(hw, TXGBE_IPSRXSALT,
143                                 rte_cpu_to_be_32(ic_session->salt));
144                 wr32(hw, TXGBE_IPSRXMODE,
145                                 priv->rx_sa_tbl[sa_index].mode);
146                 wr32w(hw, TXGBE_IPSRXIDX, reg_val, TXGBE_IPSRXIDX_WRITE, 1000);
147
148                 free(key);
149         } else { /* sess->dir == RTE_CRYPTO_OUTBOUND */
150                 uint8_t *key;
151                 int i;
152
153                 /* Find a free entry in the SA table*/
154                 for (i = 0; i < IPSEC_MAX_SA_COUNT; i++) {
155                         if (priv->tx_sa_tbl[i].used == 0) {
156                                 sa_index = i;
157                                 break;
158                         }
159                 }
160                 /* Fail if no free entries*/
161                 if (sa_index < 0) {
162                         PMD_DRV_LOG(ERR,
163                                     "No free entry left in the Tx SA table\n");
164                         return -1;
165                 }
166
167                 priv->tx_sa_tbl[sa_index].spi =
168                         rte_cpu_to_be_32(ic_session->spi);
169                 priv->tx_sa_tbl[i].used = 1;
170                 ic_session->sa_index = sa_index;
171
172                 key = malloc(ic_session->key_len);
173                 if (!key)
174                         return -ENOMEM;
175
176                 memcpy(key, ic_session->key, ic_session->key_len);
177
178                 /* write Key table entry*/
179                 reg_val = TXGBE_IPSRXIDX_ENA |
180                         TXGBE_IPSRXIDX_WRITE | (sa_index << 3);
181                 wr32(hw, TXGBE_IPSTXKEY(0),
182                         rte_cpu_to_be_32(*(uint32_t *)&key[12]));
183                 wr32(hw, TXGBE_IPSTXKEY(1),
184                         rte_cpu_to_be_32(*(uint32_t *)&key[8]));
185                 wr32(hw, TXGBE_IPSTXKEY(2),
186                         rte_cpu_to_be_32(*(uint32_t *)&key[4]));
187                 wr32(hw, TXGBE_IPSTXKEY(3),
188                         rte_cpu_to_be_32(*(uint32_t *)&key[0]));
189                 wr32(hw, TXGBE_IPSTXSALT,
190                                 rte_cpu_to_be_32(ic_session->salt));
191                 wr32w(hw, TXGBE_IPSTXIDX, reg_val, TXGBE_IPSTXIDX_WRITE, 1000);
192
193                 free(key);
194         }
195
196         return 0;
197 }
198
199 static int
200 txgbe_crypto_create_session(void *device,
201                 struct rte_security_session_conf *conf,
202                 struct rte_security_session *session,
203                 struct rte_mempool *mempool)
204 {
205         struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)device;
206         struct txgbe_crypto_session *ic_session = NULL;
207         struct rte_crypto_aead_xform *aead_xform;
208         struct rte_eth_conf *dev_conf = &eth_dev->data->dev_conf;
209
210         if (rte_mempool_get(mempool, (void **)&ic_session)) {
211                 PMD_DRV_LOG(ERR, "Cannot get object from ic_session mempool");
212                 return -ENOMEM;
213         }
214
215         if (conf->crypto_xform->type != RTE_CRYPTO_SYM_XFORM_AEAD ||
216                         conf->crypto_xform->aead.algo !=
217                                         RTE_CRYPTO_AEAD_AES_GCM) {
218                 PMD_DRV_LOG(ERR, "Unsupported crypto transformation mode\n");
219                 rte_mempool_put(mempool, (void *)ic_session);
220                 return -ENOTSUP;
221         }
222         aead_xform = &conf->crypto_xform->aead;
223
224         if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
225                 if (dev_conf->rxmode.offloads & DEV_RX_OFFLOAD_SECURITY) {
226                         ic_session->op = TXGBE_OP_AUTHENTICATED_DECRYPTION;
227                 } else {
228                         PMD_DRV_LOG(ERR, "IPsec decryption not enabled\n");
229                         rte_mempool_put(mempool, (void *)ic_session);
230                         return -ENOTSUP;
231                 }
232         } else {
233                 if (dev_conf->txmode.offloads & DEV_TX_OFFLOAD_SECURITY) {
234                         ic_session->op = TXGBE_OP_AUTHENTICATED_ENCRYPTION;
235                 } else {
236                         PMD_DRV_LOG(ERR, "IPsec encryption not enabled\n");
237                         rte_mempool_put(mempool, (void *)ic_session);
238                         return -ENOTSUP;
239                 }
240         }
241
242         ic_session->key = aead_xform->key.data;
243         ic_session->key_len = aead_xform->key.length;
244         memcpy(&ic_session->salt,
245                &aead_xform->key.data[aead_xform->key.length], 4);
246         ic_session->spi = conf->ipsec.spi;
247         ic_session->dev = eth_dev;
248
249         set_sec_session_private_data(session, ic_session);
250
251         if (ic_session->op == TXGBE_OP_AUTHENTICATED_ENCRYPTION) {
252                 if (txgbe_crypto_add_sa(ic_session)) {
253                         PMD_DRV_LOG(ERR, "Failed to add SA\n");
254                         rte_mempool_put(mempool, (void *)ic_session);
255                         return -EPERM;
256                 }
257         }
258
259         return 0;
260 }
261
262 static const struct rte_security_capability *
263 txgbe_crypto_capabilities_get(void *device __rte_unused)
264 {
265         static const struct rte_cryptodev_capabilities
266         aes_gcm_gmac_crypto_capabilities[] = {
267                 {       /* AES GMAC (128-bit) */
268                         .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
269                         {.sym = {
270                                 .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
271                                 {.auth = {
272                                         .algo = RTE_CRYPTO_AUTH_AES_GMAC,
273                                         .block_size = 16,
274                                         .key_size = {
275                                                 .min = 16,
276                                                 .max = 16,
277                                                 .increment = 0
278                                         },
279                                         .digest_size = {
280                                                 .min = 16,
281                                                 .max = 16,
282                                                 .increment = 0
283                                         },
284                                         .iv_size = {
285                                                 .min = 12,
286                                                 .max = 12,
287                                                 .increment = 0
288                                         }
289                                 }, }
290                         }, }
291                 },
292                 {       /* AES GCM (128-bit) */
293                         .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
294                         {.sym = {
295                                 .xform_type = RTE_CRYPTO_SYM_XFORM_AEAD,
296                                 {.aead = {
297                                         .algo = RTE_CRYPTO_AEAD_AES_GCM,
298                                         .block_size = 16,
299                                         .key_size = {
300                                                 .min = 16,
301                                                 .max = 16,
302                                                 .increment = 0
303                                         },
304                                         .digest_size = {
305                                                 .min = 16,
306                                                 .max = 16,
307                                                 .increment = 0
308                                         },
309                                         .aad_size = {
310                                                 .min = 0,
311                                                 .max = 65535,
312                                                 .increment = 1
313                                         },
314                                         .iv_size = {
315                                                 .min = 12,
316                                                 .max = 12,
317                                                 .increment = 0
318                                         }
319                                 }, }
320                         }, }
321                 },
322                 {
323                         .op = RTE_CRYPTO_OP_TYPE_UNDEFINED,
324                         {.sym = {
325                                 .xform_type = RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED
326                         }, }
327                 },
328         };
329
330         static const struct rte_security_capability
331         txgbe_security_capabilities[] = {
332                 { /* IPsec Inline Crypto ESP Transport Egress */
333                         .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
334                         .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
335                         {.ipsec = {
336                                 .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
337                                 .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
338                                 .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
339                                 .options = { 0 }
340                         } },
341                         .crypto_capabilities = aes_gcm_gmac_crypto_capabilities,
342                         .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
343                 },
344                 { /* IPsec Inline Crypto ESP Transport Ingress */
345                         .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
346                         .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
347                         {.ipsec = {
348                                 .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
349                                 .mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
350                                 .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
351                                 .options = { 0 }
352                         } },
353                         .crypto_capabilities = aes_gcm_gmac_crypto_capabilities,
354                         .ol_flags = 0
355                 },
356                 { /* IPsec Inline Crypto ESP Tunnel Egress */
357                         .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
358                         .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
359                         {.ipsec = {
360                                 .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
361                                 .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
362                                 .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
363                                 .options = { 0 }
364                         } },
365                         .crypto_capabilities = aes_gcm_gmac_crypto_capabilities,
366                         .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
367                 },
368                 { /* IPsec Inline Crypto ESP Tunnel Ingress */
369                         .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
370                         .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
371                         {.ipsec = {
372                                 .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
373                                 .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
374                                 .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
375                                 .options = { 0 }
376                         } },
377                         .crypto_capabilities = aes_gcm_gmac_crypto_capabilities,
378                         .ol_flags = 0
379                 },
380                 {
381                         .action = RTE_SECURITY_ACTION_TYPE_NONE
382                 }
383         };
384
385         return txgbe_security_capabilities;
386 }
387
388 static struct rte_security_ops txgbe_security_ops = {
389         .session_create = txgbe_crypto_create_session,
390         .capabilities_get = txgbe_crypto_capabilities_get
391 };
392
393 static int
394 txgbe_crypto_capable(struct rte_eth_dev *dev)
395 {
396         struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
397         uint32_t reg_i, reg, capable = 1;
398         /* test if rx crypto can be enabled and then write back initial value*/
399         reg_i = rd32(hw, TXGBE_SECRXCTL);
400         wr32m(hw, TXGBE_SECRXCTL, TXGBE_SECRXCTL_ODSA, 0);
401         reg = rd32m(hw, TXGBE_SECRXCTL, TXGBE_SECRXCTL_ODSA);
402         if (reg != 0)
403                 capable = 0;
404         wr32(hw, TXGBE_SECRXCTL, reg_i);
405         return capable;
406 }
407
408 int
409 txgbe_ipsec_ctx_create(struct rte_eth_dev *dev)
410 {
411         struct rte_security_ctx *ctx = NULL;
412
413         if (txgbe_crypto_capable(dev)) {
414                 ctx = rte_malloc("rte_security_instances_ops",
415                                  sizeof(struct rte_security_ctx), 0);
416                 if (ctx) {
417                         ctx->device = (void *)dev;
418                         ctx->ops = &txgbe_security_ops;
419                         ctx->sess_cnt = 0;
420                         dev->security_ctx = ctx;
421                 } else {
422                         return -ENOMEM;
423                 }
424         }
425         if (rte_security_dynfield_register() < 0)
426                 return -rte_errno;
427         return 0;
428 }