examples/ipsec-secgw: avoid logs in data path
[dpdk.git] / examples / ipsec-secgw / ipsec_worker.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2016 Intel Corporation
3  * Copyright (C) 2020 Marvell International Ltd.
4  */
5 #include <rte_acl.h>
6 #include <rte_event_eth_tx_adapter.h>
7 #include <rte_lpm.h>
8 #include <rte_lpm6.h>
9
10 #include "event_helper.h"
11 #include "ipsec.h"
12 #include "ipsec-secgw.h"
13 #include "ipsec_worker.h"
14
15 struct port_drv_mode_data {
16         struct rte_security_session *sess;
17         struct rte_security_ctx *ctx;
18 };
19
20 static inline enum pkt_type
21 process_ipsec_get_pkt_type(struct rte_mbuf *pkt, uint8_t **nlp)
22 {
23         struct rte_ether_hdr *eth;
24         uint32_t ptype = pkt->packet_type;
25
26         eth = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
27         rte_prefetch0(eth);
28
29         if (RTE_ETH_IS_IPV4_HDR(ptype)) {
30                 *nlp = RTE_PTR_ADD(eth, RTE_ETHER_HDR_LEN +
31                                 offsetof(struct ip, ip_p));
32                 if ((ptype & RTE_PTYPE_TUNNEL_MASK) == RTE_PTYPE_TUNNEL_ESP)
33                         return PKT_TYPE_IPSEC_IPV4;
34                 else
35                         return PKT_TYPE_PLAIN_IPV4;
36         } else if (RTE_ETH_IS_IPV6_HDR(ptype)) {
37                 *nlp = RTE_PTR_ADD(eth, RTE_ETHER_HDR_LEN +
38                                 offsetof(struct ip6_hdr, ip6_nxt));
39                 if ((ptype & RTE_PTYPE_TUNNEL_MASK) == RTE_PTYPE_TUNNEL_ESP)
40                         return PKT_TYPE_IPSEC_IPV6;
41                 else
42                         return PKT_TYPE_PLAIN_IPV6;
43         }
44
45         /* Unknown/Unsupported type */
46         return PKT_TYPE_INVALID;
47 }
48
49 static inline void
50 update_mac_addrs(struct rte_mbuf *pkt, uint16_t portid)
51 {
52         struct rte_ether_hdr *ethhdr;
53
54         ethhdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
55         memcpy(&ethhdr->src_addr, &ethaddr_tbl[portid].src, RTE_ETHER_ADDR_LEN);
56         memcpy(&ethhdr->dst_addr, &ethaddr_tbl[portid].dst, RTE_ETHER_ADDR_LEN);
57 }
58
59 static inline void
60 ipsec_event_pre_forward(struct rte_mbuf *m, unsigned int port_id)
61 {
62         /* Save the destination port in the mbuf */
63         m->port = port_id;
64
65         /* Save eth queue for Tx */
66         rte_event_eth_tx_adapter_txq_set(m, 0);
67 }
68
69 static inline void
70 ev_vector_attr_init(struct rte_event_vector *vec)
71 {
72         vec->attr_valid = 1;
73         vec->port = 0xFFFF;
74         vec->queue = 0;
75 }
76
77 static inline void
78 ev_vector_attr_update(struct rte_event_vector *vec, struct rte_mbuf *pkt)
79 {
80         if (vec->port == 0xFFFF) {
81                 vec->port = pkt->port;
82                 return;
83         }
84         if (vec->attr_valid && (vec->port != pkt->port))
85                 vec->attr_valid = 0;
86 }
87
88 static inline void
89 prepare_out_sessions_tbl(struct sa_ctx *sa_out,
90                          struct port_drv_mode_data *data,
91                          uint16_t size)
92 {
93         struct rte_ipsec_session *pri_sess;
94         struct ipsec_sa *sa;
95         uint32_t i;
96
97         if (!sa_out)
98                 return;
99
100         for (i = 0; i < sa_out->nb_sa; i++) {
101
102                 sa = &sa_out->sa[i];
103                 if (!sa)
104                         continue;
105
106                 pri_sess = ipsec_get_primary_session(sa);
107                 if (!pri_sess)
108                         continue;
109
110                 if (pri_sess->type !=
111                         RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
112
113                         RTE_LOG(ERR, IPSEC, "Invalid session type %d\n",
114                                 pri_sess->type);
115                         continue;
116                 }
117
118                 if (sa->portid >= size) {
119                         RTE_LOG(ERR, IPSEC,
120                                 "Port id >= than table size %d, %d\n",
121                                 sa->portid, size);
122                         continue;
123                 }
124
125                 /* Use only first inline session found for a given port */
126                 if (data[sa->portid].sess)
127                         continue;
128                 data[sa->portid].sess = pri_sess->security.ses;
129                 data[sa->portid].ctx = pri_sess->security.ctx;
130         }
131 }
132
133 static inline int
134 check_sp(struct sp_ctx *sp, const uint8_t *nlp, uint32_t *sa_idx)
135 {
136         uint32_t res;
137
138         if (unlikely(sp == NULL))
139                 return 0;
140
141         rte_acl_classify((struct rte_acl_ctx *)sp, &nlp, &res, 1,
142                         DEFAULT_MAX_CATEGORIES);
143
144         if (unlikely(res == DISCARD))
145                 return 0;
146         else if (res == BYPASS) {
147                 *sa_idx = -1;
148                 return 1;
149         }
150
151         *sa_idx = res - 1;
152         return 1;
153 }
154
155 static inline void
156 check_sp_bulk(struct sp_ctx *sp, struct traffic_type *ip,
157               struct traffic_type *ipsec)
158 {
159         uint32_t i, j, res;
160         struct rte_mbuf *m;
161
162         if (unlikely(sp == NULL || ip->num == 0))
163                 return;
164
165         rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res, ip->num,
166                          DEFAULT_MAX_CATEGORIES);
167
168         j = 0;
169         for (i = 0; i < ip->num; i++) {
170                 m = ip->pkts[i];
171                 res = ip->res[i];
172                 if (unlikely(res == DISCARD))
173                         free_pkts(&m, 1);
174                 else if (res == BYPASS)
175                         ip->pkts[j++] = m;
176                 else {
177                         ipsec->res[ipsec->num] = res - 1;
178                         ipsec->pkts[ipsec->num++] = m;
179                 }
180         }
181         ip->num = j;
182 }
183
184 static inline void
185 check_sp_sa_bulk(struct sp_ctx *sp, struct sa_ctx *sa_ctx,
186                  struct traffic_type *ip)
187 {
188         struct ipsec_sa *sa;
189         uint32_t i, j, res;
190         struct rte_mbuf *m;
191
192         if (unlikely(sp == NULL || ip->num == 0))
193                 return;
194
195         rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res, ip->num,
196                          DEFAULT_MAX_CATEGORIES);
197
198         j = 0;
199         for (i = 0; i < ip->num; i++) {
200                 m = ip->pkts[i];
201                 res = ip->res[i];
202                 if (unlikely(res == DISCARD))
203                         free_pkts(&m, 1);
204                 else if (res == BYPASS)
205                         ip->pkts[j++] = m;
206                 else {
207                         sa = *(struct ipsec_sa **)rte_security_dynfield(m);
208                         if (sa == NULL)
209                                 free_pkts(&m, 1);
210
211                         /* SPI on the packet should match with the one in SA */
212                         if (unlikely(sa->spi != sa_ctx->sa[res - 1].spi))
213                                 free_pkts(&m, 1);
214
215                         ip->pkts[j++] = m;
216                 }
217         }
218         ip->num = j;
219 }
220
221 static inline uint16_t
222 route4_pkt(struct rte_mbuf *pkt, struct rt_ctx *rt_ctx)
223 {
224         uint32_t dst_ip;
225         uint16_t offset;
226         uint32_t hop;
227         int ret;
228
229         offset = RTE_ETHER_HDR_LEN + offsetof(struct ip, ip_dst);
230         dst_ip = *rte_pktmbuf_mtod_offset(pkt, uint32_t *, offset);
231         dst_ip = rte_be_to_cpu_32(dst_ip);
232
233         ret = rte_lpm_lookup((struct rte_lpm *)rt_ctx, dst_ip, &hop);
234
235         if (ret == 0) {
236                 /* We have a hit */
237                 return hop;
238         }
239
240         /* else */
241         return RTE_MAX_ETHPORTS;
242 }
243
244 /* TODO: To be tested */
245 static inline uint16_t
246 route6_pkt(struct rte_mbuf *pkt, struct rt_ctx *rt_ctx)
247 {
248         uint8_t dst_ip[16];
249         uint8_t *ip6_dst;
250         uint16_t offset;
251         uint32_t hop;
252         int ret;
253
254         offset = RTE_ETHER_HDR_LEN + offsetof(struct ip6_hdr, ip6_dst);
255         ip6_dst = rte_pktmbuf_mtod_offset(pkt, uint8_t *, offset);
256         memcpy(&dst_ip[0], ip6_dst, 16);
257
258         ret = rte_lpm6_lookup((struct rte_lpm6 *)rt_ctx, dst_ip, &hop);
259
260         if (ret == 0) {
261                 /* We have a hit */
262                 return hop;
263         }
264
265         /* else */
266         return RTE_MAX_ETHPORTS;
267 }
268
269 static inline uint16_t
270 get_route(struct rte_mbuf *pkt, struct route_table *rt, enum pkt_type type)
271 {
272         if (type == PKT_TYPE_PLAIN_IPV4 || type == PKT_TYPE_IPSEC_IPV4)
273                 return route4_pkt(pkt, rt->rt4_ctx);
274         else if (type == PKT_TYPE_PLAIN_IPV6 || type == PKT_TYPE_IPSEC_IPV6)
275                 return route6_pkt(pkt, rt->rt6_ctx);
276
277         return RTE_MAX_ETHPORTS;
278 }
279
280 static inline int
281 process_ipsec_ev_inbound(struct ipsec_ctx *ctx, struct route_table *rt,
282                 struct rte_event *ev)
283 {
284         struct ipsec_sa *sa = NULL;
285         struct rte_mbuf *pkt;
286         uint16_t port_id = 0;
287         enum pkt_type type;
288         uint32_t sa_idx;
289         uint8_t *nlp;
290
291         /* Get pkt from event */
292         pkt = ev->mbuf;
293
294         /* Check the packet type */
295         type = process_ipsec_get_pkt_type(pkt, &nlp);
296
297         switch (type) {
298         case PKT_TYPE_PLAIN_IPV4:
299                 if (pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) {
300                         if (unlikely(pkt->ol_flags &
301                                      RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) {
302                                 RTE_LOG(ERR, IPSEC,
303                                         "Inbound security offload failed\n");
304                                 goto drop_pkt_and_exit;
305                         }
306                         sa = *(struct ipsec_sa **)rte_security_dynfield(pkt);
307                 }
308
309                 /* Check if we have a match */
310                 if (check_sp(ctx->sp4_ctx, nlp, &sa_idx) == 0) {
311                         /* No valid match */
312                         goto drop_pkt_and_exit;
313                 }
314                 break;
315
316         case PKT_TYPE_PLAIN_IPV6:
317                 if (pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) {
318                         if (unlikely(pkt->ol_flags &
319                                      RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) {
320                                 RTE_LOG(ERR, IPSEC,
321                                         "Inbound security offload failed\n");
322                                 goto drop_pkt_and_exit;
323                         }
324                         sa = *(struct ipsec_sa **)rte_security_dynfield(pkt);
325                 }
326
327                 /* Check if we have a match */
328                 if (check_sp(ctx->sp6_ctx, nlp, &sa_idx) == 0) {
329                         /* No valid match */
330                         goto drop_pkt_and_exit;
331                 }
332                 break;
333
334         default:
335                 RTE_LOG_DP(DEBUG, IPSEC_ESP, "Unsupported packet type = %d\n",
336                            type);
337                 goto drop_pkt_and_exit;
338         }
339
340         /* Check if the packet has to be bypassed */
341         if (sa_idx == BYPASS)
342                 goto route_and_send_pkt;
343
344         /* Validate sa_idx */
345         if (sa_idx >= ctx->sa_ctx->nb_sa)
346                 goto drop_pkt_and_exit;
347
348         /* Else the packet has to be protected with SA */
349
350         /* If the packet was IPsec processed, then SA pointer should be set */
351         if (sa == NULL)
352                 goto drop_pkt_and_exit;
353
354         /* SPI on the packet should match with the one in SA */
355         if (unlikely(sa->spi != ctx->sa_ctx->sa[sa_idx].spi))
356                 goto drop_pkt_and_exit;
357
358 route_and_send_pkt:
359         port_id = get_route(pkt, rt, type);
360         if (unlikely(port_id == RTE_MAX_ETHPORTS)) {
361                 /* no match */
362                 goto drop_pkt_and_exit;
363         }
364         /* else, we have a matching route */
365
366         /* Update mac addresses */
367         update_mac_addrs(pkt, port_id);
368
369         /* Update the event with the dest port */
370         ipsec_event_pre_forward(pkt, port_id);
371         return PKT_FORWARDED;
372
373 drop_pkt_and_exit:
374         RTE_LOG(ERR, IPSEC, "Inbound packet dropped\n");
375         rte_pktmbuf_free(pkt);
376         ev->mbuf = NULL;
377         return PKT_DROPPED;
378 }
379
380 static inline int
381 process_ipsec_ev_outbound(struct ipsec_ctx *ctx, struct route_table *rt,
382                 struct rte_event *ev)
383 {
384         struct rte_ipsec_session *sess;
385         struct sa_ctx *sa_ctx;
386         struct rte_mbuf *pkt;
387         uint16_t port_id = 0;
388         struct ipsec_sa *sa;
389         enum pkt_type type;
390         uint32_t sa_idx;
391         uint8_t *nlp;
392
393         /* Get pkt from event */
394         pkt = ev->mbuf;
395
396         /* Check the packet type */
397         type = process_ipsec_get_pkt_type(pkt, &nlp);
398
399         switch (type) {
400         case PKT_TYPE_PLAIN_IPV4:
401                 /* Check if we have a match */
402                 if (check_sp(ctx->sp4_ctx, nlp, &sa_idx) == 0) {
403                         /* No valid match */
404                         goto drop_pkt_and_exit;
405                 }
406                 break;
407         case PKT_TYPE_PLAIN_IPV6:
408                 /* Check if we have a match */
409                 if (check_sp(ctx->sp6_ctx, nlp, &sa_idx) == 0) {
410                         /* No valid match */
411                         goto drop_pkt_and_exit;
412                 }
413                 break;
414         default:
415                 /*
416                  * Only plain IPv4 & IPv6 packets are allowed
417                  * on protected port. Drop the rest.
418                  */
419                 RTE_LOG(ERR, IPSEC, "Unsupported packet type = %d\n", type);
420                 goto drop_pkt_and_exit;
421         }
422
423         /* Check if the packet has to be bypassed */
424         if (sa_idx == BYPASS) {
425                 port_id = get_route(pkt, rt, type);
426                 if (unlikely(port_id == RTE_MAX_ETHPORTS)) {
427                         /* no match */
428                         goto drop_pkt_and_exit;
429                 }
430                 /* else, we have a matching route */
431                 goto send_pkt;
432         }
433
434         /* Validate sa_idx */
435         if (unlikely(sa_idx >= ctx->sa_ctx->nb_sa))
436                 goto drop_pkt_and_exit;
437
438         /* Else the packet has to be protected */
439
440         /* Get SA ctx*/
441         sa_ctx = ctx->sa_ctx;
442
443         /* Get SA */
444         sa = &(sa_ctx->sa[sa_idx]);
445
446         /* Get IPsec session */
447         sess = ipsec_get_primary_session(sa);
448
449         /* Allow only inline protocol for now */
450         if (unlikely(sess->type != RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL)) {
451                 RTE_LOG(ERR, IPSEC, "SA type not supported\n");
452                 goto drop_pkt_and_exit;
453         }
454
455         rte_security_set_pkt_metadata(sess->security.ctx,
456                                       sess->security.ses, pkt, NULL);
457
458         /* Mark the packet for Tx security offload */
459         pkt->ol_flags |= RTE_MBUF_F_TX_SEC_OFFLOAD;
460
461         /* Get the port to which this pkt need to be submitted */
462         port_id = sa->portid;
463
464 send_pkt:
465         /* Provide L2 len for Outbound processing */
466         pkt->l2_len = RTE_ETHER_HDR_LEN;
467
468         /* Update mac addresses */
469         update_mac_addrs(pkt, port_id);
470
471         /* Update the event with the dest port */
472         ipsec_event_pre_forward(pkt, port_id);
473         return PKT_FORWARDED;
474
475 drop_pkt_and_exit:
476         RTE_LOG(ERR, IPSEC, "Outbound packet dropped\n");
477         rte_pktmbuf_free(pkt);
478         ev->mbuf = NULL;
479         return PKT_DROPPED;
480 }
481
482 static inline int
483 ipsec_ev_route_pkts(struct rte_event_vector *vec, struct route_table *rt,
484                     struct ipsec_traffic *t, struct sa_ctx *sa_ctx)
485 {
486         struct rte_ipsec_session *sess;
487         uint32_t sa_idx, i, j = 0;
488         uint16_t port_id = 0;
489         struct rte_mbuf *pkt;
490         struct ipsec_sa *sa;
491
492         /* Route IPv4 packets */
493         for (i = 0; i < t->ip4.num; i++) {
494                 pkt = t->ip4.pkts[i];
495                 port_id = route4_pkt(pkt, rt->rt4_ctx);
496                 if (port_id != RTE_MAX_ETHPORTS) {
497                         /* Update mac addresses */
498                         update_mac_addrs(pkt, port_id);
499                         /* Update the event with the dest port */
500                         ipsec_event_pre_forward(pkt, port_id);
501                         ev_vector_attr_update(vec, pkt);
502                         vec->mbufs[j++] = pkt;
503                 } else
504                         free_pkts(&pkt, 1);
505         }
506
507         /* Route IPv6 packets */
508         for (i = 0; i < t->ip6.num; i++) {
509                 pkt = t->ip6.pkts[i];
510                 port_id = route6_pkt(pkt, rt->rt6_ctx);
511                 if (port_id != RTE_MAX_ETHPORTS) {
512                         /* Update mac addresses */
513                         update_mac_addrs(pkt, port_id);
514                         /* Update the event with the dest port */
515                         ipsec_event_pre_forward(pkt, port_id);
516                         ev_vector_attr_update(vec, pkt);
517                         vec->mbufs[j++] = pkt;
518                 } else
519                         free_pkts(&pkt, 1);
520         }
521
522         /* Route ESP packets */
523         for (i = 0; i < t->ipsec.num; i++) {
524                 /* Validate sa_idx */
525                 sa_idx = t->ipsec.res[i];
526                 pkt = t->ipsec.pkts[i];
527                 if (unlikely(sa_idx >= sa_ctx->nb_sa))
528                         free_pkts(&pkt, 1);
529                 else {
530                         /* Else the packet has to be protected */
531                         sa = &(sa_ctx->sa[sa_idx]);
532                         /* Get IPsec session */
533                         sess = ipsec_get_primary_session(sa);
534                         /* Allow only inline protocol for now */
535                         if (unlikely(sess->type !=
536                                 RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL)) {
537                                 RTE_LOG(ERR, IPSEC, "SA type not supported\n");
538                                 free_pkts(&pkt, 1);
539                         }
540                         rte_security_set_pkt_metadata(sess->security.ctx,
541                                                 sess->security.ses, pkt, NULL);
542
543                         pkt->ol_flags |= RTE_MBUF_F_TX_SEC_OFFLOAD;
544                         port_id = sa->portid;
545                         update_mac_addrs(pkt, port_id);
546                         ipsec_event_pre_forward(pkt, port_id);
547                         ev_vector_attr_update(vec, pkt);
548                         vec->mbufs[j++] = pkt;
549                 }
550         }
551
552         return j;
553 }
554
555 static inline void
556 classify_pkt(struct rte_mbuf *pkt, struct ipsec_traffic *t)
557 {
558         enum pkt_type type;
559         uint8_t *nlp;
560
561         /* Check the packet type */
562         type = process_ipsec_get_pkt_type(pkt, &nlp);
563
564         switch (type) {
565         case PKT_TYPE_PLAIN_IPV4:
566                 t->ip4.data[t->ip4.num] = nlp;
567                 t->ip4.pkts[(t->ip4.num)++] = pkt;
568                 break;
569         case PKT_TYPE_PLAIN_IPV6:
570                 t->ip6.data[t->ip6.num] = nlp;
571                 t->ip6.pkts[(t->ip6.num)++] = pkt;
572                 break;
573         default:
574                 RTE_LOG_DP(DEBUG, IPSEC_ESP, "Unsupported packet type = %d\n",
575                            type);
576                 free_pkts(&pkt, 1);
577                 break;
578         }
579 }
580
581 static inline int
582 process_ipsec_ev_inbound_vector(struct ipsec_ctx *ctx, struct route_table *rt,
583                                 struct rte_event_vector *vec)
584 {
585         struct ipsec_traffic t;
586         struct rte_mbuf *pkt;
587         int i;
588
589         t.ip4.num = 0;
590         t.ip6.num = 0;
591         t.ipsec.num = 0;
592
593         for (i = 0; i < vec->nb_elem; i++) {
594                 /* Get pkt from event */
595                 pkt = vec->mbufs[i];
596
597                 if (pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) {
598                         if (unlikely(pkt->ol_flags &
599                                      RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) {
600                                 RTE_LOG(ERR, IPSEC,
601                                         "Inbound security offload failed\n");
602                                 free_pkts(&pkt, 1);
603                                 continue;
604                         }
605                 }
606
607                 classify_pkt(pkt, &t);
608         }
609
610         check_sp_sa_bulk(ctx->sp4_ctx, ctx->sa_ctx, &t.ip4);
611         check_sp_sa_bulk(ctx->sp6_ctx, ctx->sa_ctx, &t.ip6);
612
613         return ipsec_ev_route_pkts(vec, rt, &t, ctx->sa_ctx);
614 }
615
616 static inline int
617 process_ipsec_ev_outbound_vector(struct ipsec_ctx *ctx, struct route_table *rt,
618                                  struct rte_event_vector *vec)
619 {
620         struct ipsec_traffic t;
621         struct rte_mbuf *pkt;
622         uint32_t i;
623
624         t.ip4.num = 0;
625         t.ip6.num = 0;
626         t.ipsec.num = 0;
627
628         for (i = 0; i < vec->nb_elem; i++) {
629                 /* Get pkt from event */
630                 pkt = vec->mbufs[i];
631
632                 classify_pkt(pkt, &t);
633
634                 /* Provide L2 len for Outbound processing */
635                 pkt->l2_len = RTE_ETHER_HDR_LEN;
636         }
637
638         check_sp_bulk(ctx->sp4_ctx, &t.ip4, &t.ipsec);
639         check_sp_bulk(ctx->sp6_ctx, &t.ip6, &t.ipsec);
640
641         return ipsec_ev_route_pkts(vec, rt, &t, ctx->sa_ctx);
642 }
643
644 static inline int
645 process_ipsec_ev_drv_mode_outbound_vector(struct rte_event_vector *vec,
646                                           struct port_drv_mode_data *data)
647 {
648         struct rte_mbuf *pkt;
649         int16_t port_id;
650         uint32_t i;
651         int j = 0;
652
653         for (i = 0; i < vec->nb_elem; i++) {
654                 pkt = vec->mbufs[i];
655                 port_id = pkt->port;
656
657                 if (unlikely(!data[port_id].sess)) {
658                         free_pkts(&pkt, 1);
659                         continue;
660                 }
661                 ipsec_event_pre_forward(pkt, port_id);
662                 /* Save security session */
663                 rte_security_set_pkt_metadata(data[port_id].ctx,
664                                               data[port_id].sess, pkt,
665                                               NULL);
666
667                 /* Mark the packet for Tx security offload */
668                 pkt->ol_flags |= RTE_MBUF_F_TX_SEC_OFFLOAD;
669
670                 /* Provide L2 len for Outbound processing */
671                 pkt->l2_len = RTE_ETHER_HDR_LEN;
672
673                 vec->mbufs[j++] = pkt;
674         }
675
676         return j;
677 }
678
679 static inline void
680 ipsec_ev_vector_process(struct lcore_conf_ev_tx_int_port_wrkr *lconf,
681                         struct eh_event_link_info *links,
682                         struct rte_event *ev)
683 {
684         struct rte_event_vector *vec = ev->vec;
685         struct rte_mbuf *pkt;
686         int ret;
687
688         pkt = vec->mbufs[0];
689
690         ev_vector_attr_init(vec);
691         if (is_unprotected_port(pkt->port))
692                 ret = process_ipsec_ev_inbound_vector(&lconf->inbound,
693                                                       &lconf->rt, vec);
694         else
695                 ret = process_ipsec_ev_outbound_vector(&lconf->outbound,
696                                                        &lconf->rt, vec);
697
698         if (ret > 0) {
699                 vec->nb_elem = ret;
700                 rte_event_eth_tx_adapter_enqueue(links[0].eventdev_id,
701                                                  links[0].event_port_id,
702                                                  ev, 1, 0);
703         }
704 }
705
706 static inline void
707 ipsec_ev_vector_drv_mode_process(struct eh_event_link_info *links,
708                                  struct rte_event *ev,
709                                  struct port_drv_mode_data *data)
710 {
711         struct rte_event_vector *vec = ev->vec;
712         struct rte_mbuf *pkt;
713
714         pkt = vec->mbufs[0];
715
716         if (!is_unprotected_port(pkt->port))
717                 vec->nb_elem = process_ipsec_ev_drv_mode_outbound_vector(vec,
718                                                                          data);
719         if (vec->nb_elem > 0)
720                 rte_event_eth_tx_adapter_enqueue(links[0].eventdev_id,
721                                                  links[0].event_port_id,
722                                                  ev, 1, 0);
723 }
724
725 /*
726  * Event mode exposes various operating modes depending on the
727  * capabilities of the event device and the operating mode
728  * selected.
729  */
730
731 /* Workers registered */
732 #define IPSEC_EVENTMODE_WORKERS         2
733
734 /*
735  * Event mode worker
736  * Operating parameters : non-burst - Tx internal port - driver mode
737  */
738 static void
739 ipsec_wrkr_non_burst_int_port_drv_mode(struct eh_event_link_info *links,
740                 uint8_t nb_links)
741 {
742         struct port_drv_mode_data data[RTE_MAX_ETHPORTS];
743         unsigned int nb_rx = 0;
744         struct rte_mbuf *pkt;
745         struct rte_event ev;
746         uint32_t lcore_id;
747         int32_t socket_id;
748         int16_t port_id;
749
750         /* Check if we have links registered for this lcore */
751         if (nb_links == 0) {
752                 /* No links registered - exit */
753                 return;
754         }
755
756         memset(&data, 0, sizeof(struct port_drv_mode_data));
757
758         /* Get core ID */
759         lcore_id = rte_lcore_id();
760
761         /* Get socket ID */
762         socket_id = rte_lcore_to_socket_id(lcore_id);
763
764         /*
765          * Prepare security sessions table. In outbound driver mode
766          * we always use first session configured for a given port
767          */
768         prepare_out_sessions_tbl(socket_ctx[socket_id].sa_out, data,
769                                  RTE_MAX_ETHPORTS);
770
771         RTE_LOG(INFO, IPSEC,
772                 "Launching event mode worker (non-burst - Tx internal port - "
773                 "driver mode) on lcore %d\n", lcore_id);
774
775         /* We have valid links */
776
777         /* Check if it's single link */
778         if (nb_links != 1) {
779                 RTE_LOG(INFO, IPSEC,
780                         "Multiple links not supported. Using first link\n");
781         }
782
783         RTE_LOG(INFO, IPSEC, " -- lcoreid=%u event_port_id=%u\n", lcore_id,
784                         links[0].event_port_id);
785         while (!force_quit) {
786                 /* Read packet from event queues */
787                 nb_rx = rte_event_dequeue_burst(links[0].eventdev_id,
788                                 links[0].event_port_id,
789                                 &ev,    /* events */
790                                 1,      /* nb_events */
791                                 0       /* timeout_ticks */);
792
793                 if (nb_rx == 0)
794                         continue;
795
796                 switch (ev.event_type) {
797                 case RTE_EVENT_TYPE_ETH_RX_ADAPTER_VECTOR:
798                 case RTE_EVENT_TYPE_ETHDEV_VECTOR:
799                         ipsec_ev_vector_drv_mode_process(links, &ev, data);
800                         continue;
801                 case RTE_EVENT_TYPE_ETHDEV:
802                         break;
803                 default:
804                         RTE_LOG(ERR, IPSEC, "Invalid event type %u",
805                                 ev.event_type);
806                         continue;
807                 }
808
809                 pkt = ev.mbuf;
810                 port_id = pkt->port;
811
812                 rte_prefetch0(rte_pktmbuf_mtod(pkt, void *));
813
814                 /* Process packet */
815                 ipsec_event_pre_forward(pkt, port_id);
816
817                 if (!is_unprotected_port(port_id)) {
818
819                         if (unlikely(!data[port_id].sess)) {
820                                 rte_pktmbuf_free(pkt);
821                                 continue;
822                         }
823
824                         /* Save security session */
825                         rte_security_set_pkt_metadata(data[port_id].ctx,
826                                                       data[port_id].sess, pkt,
827                                                       NULL);
828
829                         /* Mark the packet for Tx security offload */
830                         pkt->ol_flags |= RTE_MBUF_F_TX_SEC_OFFLOAD;
831
832                         /* Provide L2 len for Outbound processing */
833                         pkt->l2_len = RTE_ETHER_HDR_LEN;
834                 }
835
836                 /*
837                  * Since tx internal port is available, events can be
838                  * directly enqueued to the adapter and it would be
839                  * internally submitted to the eth device.
840                  */
841                 rte_event_eth_tx_adapter_enqueue(links[0].eventdev_id,
842                                 links[0].event_port_id,
843                                 &ev,    /* events */
844                                 1,      /* nb_events */
845                                 0       /* flags */);
846         }
847 }
848
849 /*
850  * Event mode worker
851  * Operating parameters : non-burst - Tx internal port - app mode
852  */
853 static void
854 ipsec_wrkr_non_burst_int_port_app_mode(struct eh_event_link_info *links,
855                 uint8_t nb_links)
856 {
857         struct lcore_conf_ev_tx_int_port_wrkr lconf;
858         unsigned int nb_rx = 0;
859         struct rte_event ev;
860         uint32_t lcore_id;
861         int32_t socket_id;
862         int ret;
863
864         /* Check if we have links registered for this lcore */
865         if (nb_links == 0) {
866                 /* No links registered - exit */
867                 return;
868         }
869
870         /* We have valid links */
871
872         /* Get core ID */
873         lcore_id = rte_lcore_id();
874
875         /* Get socket ID */
876         socket_id = rte_lcore_to_socket_id(lcore_id);
877
878         /* Save routing table */
879         lconf.rt.rt4_ctx = socket_ctx[socket_id].rt_ip4;
880         lconf.rt.rt6_ctx = socket_ctx[socket_id].rt_ip6;
881         lconf.inbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_in;
882         lconf.inbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_in;
883         lconf.inbound.sa_ctx = socket_ctx[socket_id].sa_in;
884         lconf.inbound.session_pool = socket_ctx[socket_id].session_pool;
885         lconf.inbound.session_priv_pool =
886                         socket_ctx[socket_id].session_priv_pool;
887         lconf.outbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_out;
888         lconf.outbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_out;
889         lconf.outbound.sa_ctx = socket_ctx[socket_id].sa_out;
890         lconf.outbound.session_pool = socket_ctx[socket_id].session_pool;
891         lconf.outbound.session_priv_pool =
892                         socket_ctx[socket_id].session_priv_pool;
893
894         RTE_LOG(INFO, IPSEC,
895                 "Launching event mode worker (non-burst - Tx internal port - "
896                 "app mode) on lcore %d\n", lcore_id);
897
898         /* Check if it's single link */
899         if (nb_links != 1) {
900                 RTE_LOG(INFO, IPSEC,
901                         "Multiple links not supported. Using first link\n");
902         }
903
904         RTE_LOG(INFO, IPSEC, " -- lcoreid=%u event_port_id=%u\n", lcore_id,
905                 links[0].event_port_id);
906
907         while (!force_quit) {
908                 /* Read packet from event queues */
909                 nb_rx = rte_event_dequeue_burst(links[0].eventdev_id,
910                                 links[0].event_port_id,
911                                 &ev,     /* events */
912                                 1,       /* nb_events */
913                                 0        /* timeout_ticks */);
914
915                 if (nb_rx == 0)
916                         continue;
917
918                 switch (ev.event_type) {
919                 case RTE_EVENT_TYPE_ETH_RX_ADAPTER_VECTOR:
920                 case RTE_EVENT_TYPE_ETHDEV_VECTOR:
921                         ipsec_ev_vector_process(&lconf, links, &ev);
922                         continue;
923                 case RTE_EVENT_TYPE_ETHDEV:
924                         break;
925                 default:
926                         RTE_LOG(ERR, IPSEC, "Invalid event type %u",
927                                 ev.event_type);
928                         continue;
929                 }
930
931                 if (is_unprotected_port(ev.mbuf->port))
932                         ret = process_ipsec_ev_inbound(&lconf.inbound,
933                                                         &lconf.rt, &ev);
934                 else
935                         ret = process_ipsec_ev_outbound(&lconf.outbound,
936                                                         &lconf.rt, &ev);
937                 if (ret != 1)
938                         /* The pkt has been dropped */
939                         continue;
940
941                 /*
942                  * Since tx internal port is available, events can be
943                  * directly enqueued to the adapter and it would be
944                  * internally submitted to the eth device.
945                  */
946                 rte_event_eth_tx_adapter_enqueue(links[0].eventdev_id,
947                                 links[0].event_port_id,
948                                 &ev,    /* events */
949                                 1,      /* nb_events */
950                                 0       /* flags */);
951         }
952 }
953
954 static uint8_t
955 ipsec_eventmode_populate_wrkr_params(struct eh_app_worker_params *wrkrs)
956 {
957         struct eh_app_worker_params *wrkr;
958         uint8_t nb_wrkr_param = 0;
959
960         /* Save workers */
961         wrkr = wrkrs;
962
963         /* Non-burst - Tx internal port - driver mode */
964         wrkr->cap.burst = EH_RX_TYPE_NON_BURST;
965         wrkr->cap.tx_internal_port = EH_TX_TYPE_INTERNAL_PORT;
966         wrkr->cap.ipsec_mode = EH_IPSEC_MODE_TYPE_DRIVER;
967         wrkr->worker_thread = ipsec_wrkr_non_burst_int_port_drv_mode;
968         wrkr++;
969         nb_wrkr_param++;
970
971         /* Non-burst - Tx internal port - app mode */
972         wrkr->cap.burst = EH_RX_TYPE_NON_BURST;
973         wrkr->cap.tx_internal_port = EH_TX_TYPE_INTERNAL_PORT;
974         wrkr->cap.ipsec_mode = EH_IPSEC_MODE_TYPE_APP;
975         wrkr->worker_thread = ipsec_wrkr_non_burst_int_port_app_mode;
976         nb_wrkr_param++;
977
978         return nb_wrkr_param;
979 }
980
981 static void
982 ipsec_eventmode_worker(struct eh_conf *conf)
983 {
984         struct eh_app_worker_params ipsec_wrkr[IPSEC_EVENTMODE_WORKERS] = {
985                                         {{{0} }, NULL } };
986         uint8_t nb_wrkr_param;
987
988         /* Populate l2fwd_wrkr params */
989         nb_wrkr_param = ipsec_eventmode_populate_wrkr_params(ipsec_wrkr);
990
991         /*
992          * Launch correct worker after checking
993          * the event device's capabilities.
994          */
995         eh_launch_worker(conf, ipsec_wrkr, nb_wrkr_param);
996 }
997
998 int ipsec_launch_one_lcore(void *args)
999 {
1000         struct eh_conf *conf;
1001
1002         conf = (struct eh_conf *)args;
1003
1004         if (conf->mode == EH_PKT_TRANSFER_MODE_POLL) {
1005                 /* Run in poll mode */
1006                 ipsec_poll_mode_worker();
1007         } else if (conf->mode == EH_PKT_TRANSFER_MODE_EVENT) {
1008                 /* Run in event mode */
1009                 ipsec_eventmode_worker(conf);
1010         }
1011         return 0;
1012 }