b7a1ef908e6a1839df8b9e0ba7fe889f3a3899da
[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_event_eth_tx_adapter.h>
6
7 #include "event_helper.h"
8 #include "ipsec.h"
9 #include "ipsec-secgw.h"
10
11 static inline void
12 ipsec_event_pre_forward(struct rte_mbuf *m, unsigned int port_id)
13 {
14         /* Save the destination port in the mbuf */
15         m->port = port_id;
16
17         /* Save eth queue for Tx */
18         rte_event_eth_tx_adapter_txq_set(m, 0);
19 }
20
21 static inline void
22 prepare_out_sessions_tbl(struct sa_ctx *sa_out,
23                 struct rte_security_session **sess_tbl, uint16_t size)
24 {
25         struct rte_ipsec_session *pri_sess;
26         struct ipsec_sa *sa;
27         uint32_t i;
28
29         if (!sa_out)
30                 return;
31
32         for (i = 0; i < sa_out->nb_sa; i++) {
33
34                 sa = &sa_out->sa[i];
35                 if (!sa)
36                         continue;
37
38                 pri_sess = ipsec_get_primary_session(sa);
39                 if (!pri_sess)
40                         continue;
41
42                 if (pri_sess->type !=
43                         RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
44
45                         RTE_LOG(ERR, IPSEC, "Invalid session type %d\n",
46                                 pri_sess->type);
47                         continue;
48                 }
49
50                 if (sa->portid >= size) {
51                         RTE_LOG(ERR, IPSEC,
52                                 "Port id >= than table size %d, %d\n",
53                                 sa->portid, size);
54                         continue;
55                 }
56
57                 /* Use only first inline session found for a given port */
58                 if (sess_tbl[sa->portid])
59                         continue;
60                 sess_tbl[sa->portid] = pri_sess->security.ses;
61         }
62 }
63
64 /*
65  * Event mode exposes various operating modes depending on the
66  * capabilities of the event device and the operating mode
67  * selected.
68  */
69
70 /* Workers registered */
71 #define IPSEC_EVENTMODE_WORKERS         1
72
73 /*
74  * Event mode worker
75  * Operating parameters : non-burst - Tx internal port - driver mode
76  */
77 static void
78 ipsec_wrkr_non_burst_int_port_drv_mode(struct eh_event_link_info *links,
79                 uint8_t nb_links)
80 {
81         struct rte_security_session *sess_tbl[RTE_MAX_ETHPORTS] = { NULL };
82         unsigned int nb_rx = 0;
83         struct rte_mbuf *pkt;
84         struct rte_event ev;
85         uint32_t lcore_id;
86         int32_t socket_id;
87         int16_t port_id;
88
89         /* Check if we have links registered for this lcore */
90         if (nb_links == 0) {
91                 /* No links registered - exit */
92                 return;
93         }
94
95         /* Get core ID */
96         lcore_id = rte_lcore_id();
97
98         /* Get socket ID */
99         socket_id = rte_lcore_to_socket_id(lcore_id);
100
101         /*
102          * Prepare security sessions table. In outbound driver mode
103          * we always use first session configured for a given port
104          */
105         prepare_out_sessions_tbl(socket_ctx[socket_id].sa_out, sess_tbl,
106                         RTE_MAX_ETHPORTS);
107
108         RTE_LOG(INFO, IPSEC,
109                 "Launching event mode worker (non-burst - Tx internal port - "
110                 "driver mode) on lcore %d\n", lcore_id);
111
112         /* We have valid links */
113
114         /* Check if it's single link */
115         if (nb_links != 1) {
116                 RTE_LOG(INFO, IPSEC,
117                         "Multiple links not supported. Using first link\n");
118         }
119
120         RTE_LOG(INFO, IPSEC, " -- lcoreid=%u event_port_id=%u\n", lcore_id,
121                         links[0].event_port_id);
122         while (!force_quit) {
123                 /* Read packet from event queues */
124                 nb_rx = rte_event_dequeue_burst(links[0].eventdev_id,
125                                 links[0].event_port_id,
126                                 &ev,    /* events */
127                                 1,      /* nb_events */
128                                 0       /* timeout_ticks */);
129
130                 if (nb_rx == 0)
131                         continue;
132
133                 pkt = ev.mbuf;
134                 port_id = pkt->port;
135
136                 rte_prefetch0(rte_pktmbuf_mtod(pkt, void *));
137
138                 /* Process packet */
139                 ipsec_event_pre_forward(pkt, port_id);
140
141                 if (!is_unprotected_port(port_id)) {
142
143                         if (unlikely(!sess_tbl[port_id])) {
144                                 rte_pktmbuf_free(pkt);
145                                 continue;
146                         }
147
148                         /* Save security session */
149                         pkt->udata64 = (uint64_t) sess_tbl[port_id];
150
151                         /* Mark the packet for Tx security offload */
152                         pkt->ol_flags |= PKT_TX_SEC_OFFLOAD;
153                 }
154
155                 /*
156                  * Since tx internal port is available, events can be
157                  * directly enqueued to the adapter and it would be
158                  * internally submitted to the eth device.
159                  */
160                 rte_event_eth_tx_adapter_enqueue(links[0].eventdev_id,
161                                 links[0].event_port_id,
162                                 &ev,    /* events */
163                                 1,      /* nb_events */
164                                 0       /* flags */);
165         }
166 }
167
168 static uint8_t
169 ipsec_eventmode_populate_wrkr_params(struct eh_app_worker_params *wrkrs)
170 {
171         struct eh_app_worker_params *wrkr;
172         uint8_t nb_wrkr_param = 0;
173
174         /* Save workers */
175         wrkr = wrkrs;
176
177         /* Non-burst - Tx internal port - driver mode */
178         wrkr->cap.burst = EH_RX_TYPE_NON_BURST;
179         wrkr->cap.tx_internal_port = EH_TX_TYPE_INTERNAL_PORT;
180         wrkr->cap.ipsec_mode = EH_IPSEC_MODE_TYPE_DRIVER;
181         wrkr->worker_thread = ipsec_wrkr_non_burst_int_port_drv_mode;
182         wrkr++;
183
184         return nb_wrkr_param;
185 }
186
187 static void
188 ipsec_eventmode_worker(struct eh_conf *conf)
189 {
190         struct eh_app_worker_params ipsec_wrkr[IPSEC_EVENTMODE_WORKERS] = {
191                                         {{{0} }, NULL } };
192         uint8_t nb_wrkr_param;
193
194         /* Populate l2fwd_wrkr params */
195         nb_wrkr_param = ipsec_eventmode_populate_wrkr_params(ipsec_wrkr);
196
197         /*
198          * Launch correct worker after checking
199          * the event device's capabilities.
200          */
201         eh_launch_worker(conf, ipsec_wrkr, nb_wrkr_param);
202 }
203
204 int ipsec_launch_one_lcore(void *args)
205 {
206         struct eh_conf *conf;
207
208         conf = (struct eh_conf *)args;
209
210         if (conf->mode == EH_PKT_TRANSFER_MODE_POLL) {
211                 /* Run in poll mode */
212                 ipsec_poll_mode_worker();
213         } else if (conf->mode == EH_PKT_TRANSFER_MODE_EVENT) {
214                 /* Run in event mode */
215                 ipsec_eventmode_worker(conf);
216         }
217         return 0;
218 }