* Add siphash file for calculating the sequence number.
[tldk.git] / lib / libtle_l4p / ctx.c
1 /*
2  * Copyright (c) 2016  Intel Corporation.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <string.h>
17 #include <rte_malloc.h>
18 #include <rte_errno.h>
19 #include <rte_ethdev.h>
20 #include <rte_ip.h>
21
22 #include "stream.h"
23 #include "misc.h"
24 #include <halfsiphash.h>
25
26 #define LPORT_START     0x8000
27 #define LPORT_END       MAX_PORT_NUM
28
29 #define LPORT_START_BLK PORT_BLK(LPORT_START)
30 #define LPORT_END_BLK   PORT_BLK(LPORT_END)
31
32 const struct in6_addr tle_ipv6_any = IN6ADDR_ANY_INIT;
33 const struct in6_addr tle_ipv6_none = {
34         {
35                 .__u6_addr32 = {
36                         UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX
37                 },
38         },
39 };
40
41 struct stream_ops tle_stream_ops[TLE_PROTO_NUM] = {};
42
43 static int
44 check_dev_prm(const struct tle_dev_param *dev_prm)
45 {
46         /* no valid IPv4/IPv6 addresses provided. */
47         if (dev_prm->local_addr4.s_addr == INADDR_ANY &&
48                         memcmp(&dev_prm->local_addr6, &tle_ipv6_any,
49                         sizeof(tle_ipv6_any)) == 0)
50                 return -EINVAL;
51
52         if (dev_prm->bl4.nb_port > UINT16_MAX ||
53                         (dev_prm->bl4.nb_port != 0 &&
54                         dev_prm->bl4.port == NULL))
55                 return -EINVAL;
56
57         if (dev_prm->bl6.nb_port > UINT16_MAX ||
58                         (dev_prm->bl6.nb_port != 0 &&
59                         dev_prm->bl6.port == NULL))
60                 return -EINVAL;
61
62         return 0;
63 }
64
65 static int
66 check_ctx_prm(const struct tle_ctx_param *prm)
67 {
68         if (prm->proto >= TLE_PROTO_NUM)
69                 return -EINVAL;
70         if (prm->hash_alg >= TLE_HASH_NUM)
71                 return -EINVAL;
72         return 0;
73 }
74
75 struct tle_ctx *
76 tle_ctx_create(const struct tle_ctx_param *ctx_prm)
77 {
78         struct tle_ctx *ctx;
79         size_t sz;
80         uint32_t i;
81         int32_t rc;
82
83         if (ctx_prm == NULL || check_ctx_prm(ctx_prm) != 0) {
84                 rte_errno = EINVAL;
85                 return NULL;
86         }
87
88         sz = sizeof(*ctx);
89         ctx = rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE,
90                 ctx_prm->socket_id);
91         if (ctx == NULL) {
92                 UDP_LOG(ERR, "allocation of %zu bytes for new ctx "
93                         "on socket %d failed\n",
94                         sz, ctx_prm->socket_id);
95                 return NULL;
96         }
97
98         ctx->prm = *ctx_prm;
99
100         rc = tle_stream_ops[ctx_prm->proto].init_streams(ctx);
101         if (rc != 0) {
102                 UDP_LOG(ERR, "init_streams(ctx=%p, proto=%u) failed "
103                         "with error code: %d;\n",
104                         ctx, ctx_prm->proto, rc);
105                 tle_ctx_destroy(ctx);
106                 rte_errno = -rc;
107                 return NULL;
108         }
109
110         for (i = 0; i != RTE_DIM(ctx->use); i++)
111                 tle_pbm_init(ctx->use + i, LPORT_START_BLK);
112
113         ctx->streams.nb_free = ctx->prm.max_streams;
114
115         /* Initialization of siphash state is done here to speed up the
116          * fastpath processing.
117          */
118         if (ctx->prm.hash_alg == TLE_SIPHASH)
119                 siphash_initialization(&ctx->prm.secret_key,
120                                         &ctx->prm.secret_key);
121         return ctx;
122 }
123
124 void
125 tle_ctx_destroy(struct tle_ctx *ctx)
126 {
127         uint32_t i;
128
129         if (ctx == NULL) {
130                 rte_errno = EINVAL;
131                 return;
132         }
133
134         for (i = 0; i != RTE_DIM(ctx->dev); i++)
135                 tle_del_dev(ctx->dev + i);
136
137         tle_stream_ops[ctx->prm.proto].fini_streams(ctx);
138         rte_free(ctx);
139 }
140
141 void
142 tle_ctx_invalidate(struct tle_ctx *ctx)
143 {
144         RTE_SET_USED(ctx);
145 }
146
147 static void
148 fill_pbm(struct tle_pbm *pbm, const struct tle_bl_port *blp)
149 {
150         uint32_t i;
151
152         for (i = 0; i != blp->nb_port; i++)
153                 tle_pbm_set(pbm, blp->port[i]);
154 }
155
156 static int
157 init_dev_proto(struct tle_dev *dev, uint32_t idx, int32_t socket_id,
158         const struct tle_bl_port *blp)
159 {
160         size_t sz;
161
162         sz = sizeof(*dev->dp[idx]);
163         dev->dp[idx] = rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE,
164                 socket_id);
165
166         if (dev->dp[idx] == NULL) {
167                 UDP_LOG(ERR, "allocation of %zu bytes on "
168                         "socket %d for %u-th device failed\n",
169                         sz, socket_id, idx);
170                 return ENOMEM;
171         }
172
173         tle_pbm_init(&dev->dp[idx]->use, LPORT_START_BLK);
174         fill_pbm(&dev->dp[idx]->use, blp);
175         return 0;
176 }
177
178 static struct tle_dev *
179 find_free_dev(struct tle_ctx *ctx)
180 {
181         uint32_t i;
182
183         if (ctx->nb_dev < RTE_DIM(ctx->dev)) {
184                 for (i = 0; i != RTE_DIM(ctx->dev); i++) {
185                         if (ctx->dev[i].ctx != ctx)
186                                 return ctx->dev + i;
187                 }
188         }
189
190         rte_errno = ENODEV;
191         return NULL;
192 }
193
194 struct tle_dev *
195 tle_add_dev(struct tle_ctx *ctx, const struct tle_dev_param *dev_prm)
196 {
197         int32_t rc;
198         struct tle_dev *dev;
199
200         if (ctx == NULL || dev_prm == NULL || check_dev_prm(dev_prm) != 0) {
201                 rte_errno = EINVAL;
202                 return NULL;
203         }
204
205         dev = find_free_dev(ctx);
206         if (dev == NULL)
207                 return NULL;
208         rc = 0;
209
210         /* device can handle IPv4 traffic */
211         if (dev_prm->local_addr4.s_addr != INADDR_ANY) {
212                 rc = init_dev_proto(dev, TLE_V4, ctx->prm.socket_id,
213                         &dev_prm->bl4);
214                 if (rc == 0)
215                         fill_pbm(&ctx->use[TLE_V4], &dev_prm->bl4);
216         }
217
218         /* device can handle IPv6 traffic */
219         if (rc == 0 && memcmp(&dev_prm->local_addr6, &tle_ipv6_any,
220                         sizeof(tle_ipv6_any)) != 0) {
221                 rc = init_dev_proto(dev, TLE_V6, ctx->prm.socket_id,
222                         &dev_prm->bl6);
223                 if (rc == 0)
224                         fill_pbm(&ctx->use[TLE_V6], &dev_prm->bl6);
225         }
226
227         if (rc != 0) {
228                 /* cleanup and return an error. */
229                 rte_free(dev->dp[TLE_V4]);
230                 rte_free(dev->dp[TLE_V6]);
231                 rte_errno = rc;
232                 return NULL;
233         }
234
235         /* setup RX data. */
236         if (dev_prm->local_addr4.s_addr != INADDR_ANY &&
237                         (dev_prm->rx_offload & DEV_RX_OFFLOAD_IPV4_CKSUM) == 0)
238                 dev->rx.ol_flags[TLE_V4] |= PKT_RX_IP_CKSUM_BAD;
239
240         if (((dev_prm->rx_offload & DEV_RX_OFFLOAD_UDP_CKSUM) == 0 &&
241                         ctx->prm.proto == TLE_PROTO_UDP) ||
242                         ((dev_prm->rx_offload &
243                         DEV_RX_OFFLOAD_TCP_CKSUM) == 0 &&
244                         ctx->prm.proto == TLE_PROTO_TCP)) {
245                 dev->rx.ol_flags[TLE_V4] |= PKT_RX_L4_CKSUM_BAD;
246                 dev->rx.ol_flags[TLE_V6] |= PKT_RX_L4_CKSUM_BAD;
247         }
248
249         /* setup TX data. */
250         tle_dring_reset(&dev->tx.dr);
251
252         if ((dev_prm->tx_offload & DEV_TX_OFFLOAD_UDP_CKSUM) != 0 &&
253                         ctx->prm.proto == TLE_PROTO_UDP) {
254                 dev->tx.ol_flags[TLE_V4] |= PKT_TX_IPV4 | PKT_TX_UDP_CKSUM;
255                 dev->tx.ol_flags[TLE_V6] |= PKT_TX_IPV6 | PKT_TX_UDP_CKSUM;
256         } else if ((dev_prm->tx_offload & DEV_TX_OFFLOAD_TCP_CKSUM) != 0 &&
257                         ctx->prm.proto == TLE_PROTO_TCP) {
258                 dev->tx.ol_flags[TLE_V4] |= PKT_TX_IPV4 | PKT_TX_TCP_CKSUM;
259                 dev->tx.ol_flags[TLE_V6] |= PKT_TX_IPV6 | PKT_TX_TCP_CKSUM;
260         }
261
262         if ((dev_prm->tx_offload & DEV_TX_OFFLOAD_IPV4_CKSUM) != 0)
263                 dev->tx.ol_flags[TLE_V4] |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM;
264
265         dev->prm = *dev_prm;
266         dev->ctx = ctx;
267         ctx->nb_dev++;
268
269         return dev;
270 }
271
272 static void
273 empty_dring(struct tle_dring *dr, uint32_t proto)
274 {
275         uint32_t i, k, n;
276         struct tle_stream *s;
277         struct rte_mbuf *pkt[MAX_PKT_BURST];
278         struct tle_drb *drb[MAX_PKT_BURST];
279
280         do {
281                 k = RTE_DIM(drb);
282                 n = tle_dring_sc_dequeue(dr, (const void **)(uintptr_t)pkt,
283                         RTE_DIM(pkt), drb, &k);
284
285                 /* free mbufs */
286                 for (i = 0; i != n; i++)
287                         rte_pktmbuf_free(pkt[i]);
288                 /* free drbs */
289                 for (i = 0; i != k; i++) {
290                         s = drb[i]->udata;
291                         tle_stream_ops[proto].free_drbs(s, drb + i, 1);
292                 }
293         } while (n != 0);
294 }
295
296 int
297 tle_del_dev(struct tle_dev *dev)
298 {
299         uint32_t p;
300         struct tle_ctx *ctx;
301
302         if (dev == NULL || dev->ctx == NULL)
303                 return -EINVAL;
304
305         ctx = dev->ctx;
306         p = dev - ctx->dev;
307
308         if (p >= RTE_DIM(ctx->dev) ||
309                         (dev->dp[TLE_V4] == NULL &&
310                         dev->dp[TLE_V6] == NULL))
311                 return -EINVAL;
312
313         /* emtpy TX queues. */
314         empty_dring(&dev->tx.dr, ctx->prm.proto);
315
316         rte_free(dev->dp[TLE_V4]);
317         rte_free(dev->dp[TLE_V6]);
318         memset(dev, 0, sizeof(*dev));
319         ctx->nb_dev--;
320         return 0;
321 }
322
323 static struct tle_dev *
324 find_ipv4_dev(struct tle_ctx *ctx, const struct in_addr *addr)
325 {
326         uint32_t i;
327
328         for (i = 0; i != RTE_DIM(ctx->dev); i++) {
329                 if (ctx->dev[i].prm.local_addr4.s_addr == addr->s_addr &&
330                                 ctx->dev[i].dp[TLE_V4] != NULL)
331                         return ctx->dev + i;
332         }
333
334         return NULL;
335 }
336
337 static struct tle_dev *
338 find_ipv6_dev(struct tle_ctx *ctx, const struct in6_addr *addr)
339 {
340         uint32_t i;
341
342         for (i = 0; i != RTE_DIM(ctx->dev); i++) {
343                 if (memcmp(&ctx->dev[i].prm.local_addr6, addr,
344                                 sizeof(*addr)) == 0 &&
345                                 ctx->dev[i].dp[TLE_V6] != NULL)
346                         return ctx->dev + i;
347         }
348
349         return NULL;
350 }
351
352 static int
353 stream_fill_dev(struct tle_ctx *ctx, struct tle_stream *s,
354         const struct sockaddr *addr)
355 {
356         struct tle_dev *dev;
357         struct tle_pbm *pbm;
358         const struct sockaddr_in *lin4;
359         const struct sockaddr_in6 *lin6;
360         uint32_t i, p, sp, t;
361
362         if (addr->sa_family == AF_INET) {
363                 lin4 = (const struct sockaddr_in *)addr;
364                 t = TLE_V4;
365                 p = lin4->sin_port;
366         } else if (addr->sa_family == AF_INET6) {
367                 lin6 = (const struct sockaddr_in6 *)addr;
368                 t = TLE_V6;
369                 p = lin6->sin6_port;
370         } else
371                 return EINVAL;
372
373         p = ntohs(p);
374
375         /* if local address is not wildcard, find device it belongs to. */
376         if (t == TLE_V4 && lin4->sin_addr.s_addr != INADDR_ANY) {
377                 dev = find_ipv4_dev(ctx, &lin4->sin_addr);
378                 if (dev == NULL)
379                         return ENODEV;
380         } else if (t == TLE_V6 && memcmp(&tle_ipv6_any, &lin6->sin6_addr,
381                         sizeof(tle_ipv6_any)) != 0) {
382                 dev = find_ipv6_dev(ctx, &lin6->sin6_addr);
383                 if (dev == NULL)
384                         return ENODEV;
385         } else
386                 dev = NULL;
387
388         if (dev != NULL)
389                 pbm = &dev->dp[t]->use;
390         else
391                 pbm = &ctx->use[t];
392
393         /* try to acquire local port number. */
394         if (p == 0) {
395                 p = tle_pbm_find_range(pbm, pbm->blk, LPORT_END_BLK);
396                 if (p == 0 && pbm->blk > LPORT_START_BLK)
397                         p = tle_pbm_find_range(pbm, LPORT_START_BLK, pbm->blk);
398         } else if (tle_pbm_check(pbm, p) != 0)
399                 return EEXIST;
400
401         if (p == 0)
402                 return ENFILE;
403
404         /* fill socket's dst port and type */
405
406         sp = htons(p);
407         s->type = t;
408         s->port.dst = sp;
409
410         /* mark port as in-use */
411
412         tle_pbm_set(&ctx->use[t], p);
413         if (dev != NULL) {
414                 tle_pbm_set(pbm, p);
415                 dev->dp[t]->streams[sp] = s;
416         } else {
417                 for (i = 0; i != RTE_DIM(ctx->dev); i++) {
418                         if (ctx->dev[i].dp[t] != NULL) {
419                                 tle_pbm_set(&ctx->dev[i].dp[t]->use, p);
420                                 ctx->dev[i].dp[t]->streams[sp] = s;
421                         }
422                 }
423         }
424
425         return 0;
426 }
427
428 static int
429 stream_clear_dev(struct tle_ctx *ctx, const struct tle_stream *s)
430 {
431         struct tle_dev *dev;
432         uint32_t i, p, sp, t;
433
434         t = s->type;
435         sp = s->port.dst;
436         p = ntohs(sp);
437
438         /* if local address is not wildcard, find device it belongs to. */
439         if (t == TLE_V4 && s->ipv4.addr.dst != INADDR_ANY) {
440                 dev = find_ipv4_dev(ctx,
441                         (const struct in_addr *)&s->ipv4.addr.dst);
442                 if (dev == NULL)
443                         return ENODEV;
444         } else if (t == TLE_V6 && memcmp(&tle_ipv6_any, &s->ipv6.addr.dst,
445                         sizeof(tle_ipv6_any)) != 0) {
446                 dev = find_ipv6_dev(ctx,
447                         (const struct in6_addr *)&s->ipv6.addr.dst);
448                 if (dev == NULL)
449                         return ENODEV;
450         } else
451                 dev = NULL;
452
453         tle_pbm_clear(&ctx->use[t], p);
454         if (dev != NULL) {
455                 if (dev->dp[t]->streams[sp] == s) {
456                         tle_pbm_clear(&dev->dp[t]->use, p);
457                         dev->dp[t]->streams[sp] = NULL;
458                 }
459         } else {
460                 for (i = 0; i != RTE_DIM(ctx->dev); i++) {
461                         if (ctx->dev[i].dp[t] != NULL &&
462                                         ctx->dev[i].dp[t]->streams[sp] == s) {
463                                 tle_pbm_clear(&ctx->dev[i].dp[t]->use, p);
464                                 ctx->dev[i].dp[t]->streams[sp] = NULL;
465                         }
466                 }
467         }
468
469         return 0;
470 }
471
472 static void
473 fill_ipv4_am(const struct sockaddr_in *in, uint32_t *addr, uint32_t *mask)
474 {
475         *addr = in->sin_addr.s_addr;
476         *mask = (*addr == INADDR_ANY) ? INADDR_ANY : INADDR_NONE;
477 }
478
479 static void
480 fill_ipv6_am(const struct sockaddr_in6 *in, rte_xmm_t *addr, rte_xmm_t *mask)
481 {
482         const struct in6_addr *pm;
483
484         memcpy(addr, &in->sin6_addr, sizeof(*addr));
485         if (memcmp(&tle_ipv6_any, addr, sizeof(*addr)) == 0)
486                 pm = &tle_ipv6_any;
487         else
488                 pm = &tle_ipv6_none;
489
490         memcpy(mask, pm, sizeof(*mask));
491 }
492
493 int
494 stream_fill_ctx(struct tle_ctx *ctx, struct tle_stream *s,
495         const struct sockaddr *laddr, const struct sockaddr *raddr)
496 {
497         const struct sockaddr_in *rin;
498         int32_t rc;
499
500         /* setup ports and port mask fields (except dst port). */
501         rin = (const struct sockaddr_in *)raddr;
502         s->port.src = rin->sin_port;
503         s->pmsk.src = (s->port.src == 0) ? 0 : UINT16_MAX;
504         s->pmsk.dst = UINT16_MAX;
505
506         /* setup src and dst addresses. */
507         if (laddr->sa_family == AF_INET) {
508                 fill_ipv4_am((const struct sockaddr_in *)laddr,
509                         &s->ipv4.addr.dst, &s->ipv4.mask.dst);
510                 fill_ipv4_am((const struct sockaddr_in *)raddr,
511                         &s->ipv4.addr.src, &s->ipv4.mask.src);
512         } else if (laddr->sa_family == AF_INET6) {
513                 fill_ipv6_am((const struct sockaddr_in6 *)laddr,
514                         &s->ipv6.addr.dst, &s->ipv6.mask.dst);
515                 fill_ipv6_am((const struct sockaddr_in6 *)raddr,
516                         &s->ipv6.addr.src, &s->ipv6.mask.src);
517         }
518
519         rte_spinlock_lock(&ctx->dev_lock);
520         rc = stream_fill_dev(ctx, s, laddr);
521         rte_spinlock_unlock(&ctx->dev_lock);
522
523         return rc;
524 }
525
526 /* free stream's destination port */
527 int
528 stream_clear_ctx(struct tle_ctx *ctx, struct tle_stream *s)
529 {
530         int32_t rc;
531
532         rte_spinlock_lock(&ctx->dev_lock);
533         rc = stream_clear_dev(ctx, s);
534         rte_spinlock_unlock(&ctx->dev_lock);
535
536         return rc;
537 }