84d56af576b6313ab97af11fde0533959e630f0e
[vpp.git] / src / vcl / vcl_sapi.c
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this
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 <vcl/vcl_private.h>
17
18 static int
19 vcl_api_connect_app_socket (vcl_worker_t * wrk)
20 {
21   clib_socket_t *cs = &wrk->app_api_sock;
22   clib_error_t *err;
23   int rv = 0;
24
25   cs->config = (char *) vcm->cfg.vpp_app_socket_api;
26   cs->flags =
27     CLIB_SOCKET_F_IS_CLIENT | CLIB_SOCKET_F_SEQPACKET | CLIB_SOCKET_F_BLOCKING;
28
29   wrk->vcl_needs_real_epoll = 1;
30
31   if ((err = clib_socket_init (cs)))
32     {
33       clib_error_report (err);
34       rv = -1;
35       goto done;
36     }
37
38 done:
39
40   wrk->vcl_needs_real_epoll = 0;
41
42   return rv;
43 }
44
45 static int
46 vcl_api_attach_reply_handler (app_sapi_attach_reply_msg_t * mp, int *fds)
47 {
48   vcl_worker_t *wrk = vcl_worker_get_current ();
49   int i, rv, n_fds_used = 0;
50   u64 segment_handle;
51   u8 *segment_name;
52
53   if (mp->retval)
54     {
55       VERR ("attach failed: %U", format_session_error, mp->retval);
56       goto failed;
57     }
58
59   wrk->api_client_handle = mp->api_client_handle;
60   segment_handle = mp->segment_handle;
61   if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
62     {
63       VERR ("invalid segment handle");
64       goto failed;
65     }
66
67   if (!mp->n_fds)
68     goto failed;
69
70   if (mp->fd_flags & SESSION_FD_F_VPP_MQ_SEGMENT)
71     if (vcl_segment_attach (vcl_vpp_worker_segment_handle (0), "vpp-mq-seg",
72                             SSVM_SEGMENT_MEMFD, fds[n_fds_used++]))
73       goto failed;
74
75   if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
76     {
77       segment_name = format (0, "memfd-%ld%c", segment_handle, 0);
78       rv = vcl_segment_attach (segment_handle, (char *) segment_name,
79                                SSVM_SEGMENT_MEMFD, fds[n_fds_used++]);
80       vec_free (segment_name);
81       if (rv != 0)
82         goto failed;
83     }
84
85   vcl_segment_attach_mq (segment_handle, mp->app_mq, 0, &wrk->app_event_queue);
86
87   if (mp->fd_flags & SESSION_FD_F_MQ_EVENTFD)
88     {
89       svm_msg_q_set_eventfd (wrk->app_event_queue, fds[n_fds_used++]);
90       vcl_mq_epoll_add_evfd (wrk, wrk->app_event_queue);
91     }
92
93   vcl_segment_discover_mqs (vcl_vpp_worker_segment_handle (0),
94                             fds + n_fds_used, mp->n_fds - n_fds_used);
95   vcl_segment_attach_mq (vcl_vpp_worker_segment_handle (0), mp->vpp_ctrl_mq,
96                          mp->vpp_ctrl_mq_thread, &wrk->ctrl_mq);
97   vcm->ctrl_mq = wrk->ctrl_mq;
98   vcm->app_index = mp->app_index;
99
100   return 0;
101
102 failed:
103
104   for (i = clib_max (n_fds_used - 1, 0); i < mp->n_fds; i++)
105     close (fds[i]);
106
107   return -1;
108 }
109
110 static int
111 vcl_api_send_attach (clib_socket_t * cs)
112 {
113   app_sapi_msg_t msg = { 0 };
114   app_sapi_attach_msg_t *mp = &msg.attach;
115   u8 app_is_proxy, tls_engine;
116   clib_error_t *err;
117
118   app_is_proxy = (vcm->cfg.app_proxy_transport_tcp ||
119                   vcm->cfg.app_proxy_transport_udp);
120   tls_engine = CRYPTO_ENGINE_OPENSSL;
121
122   clib_memcpy (&mp->name, vcm->app_name, vec_len (vcm->app_name));
123   mp->options[APP_OPTIONS_FLAGS] =
124     APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT |
125     (vcm->cfg.app_scope_local ? APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE : 0) |
126     (vcm->cfg.app_scope_global ? APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE : 0) |
127     (app_is_proxy ? APP_OPTIONS_FLAGS_IS_PROXY : 0) |
128     (vcm->cfg.use_mq_eventfd ? APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD : 0);
129   mp->options[APP_OPTIONS_PROXY_TRANSPORT] =
130     (u64) ((vcm->cfg.app_proxy_transport_tcp ? 1 << TRANSPORT_PROTO_TCP : 0) |
131            (vcm->cfg.app_proxy_transport_udp ? 1 << TRANSPORT_PROTO_UDP : 0));
132   mp->options[APP_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size;
133   mp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size;
134   mp->options[APP_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size;
135   mp->options[APP_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size;
136   mp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
137     vcm->cfg.preallocated_fifo_pairs;
138   mp->options[APP_OPTIONS_EVT_QUEUE_SIZE] = vcm->cfg.event_queue_size;
139   mp->options[APP_OPTIONS_TLS_ENGINE] = tls_engine;
140
141   msg.type = APP_SAPI_MSG_TYPE_ATTACH;
142   err = clib_socket_sendmsg (cs, &msg, sizeof (msg), 0, 0);
143   if (err)
144     {
145       clib_error_report (err);
146       return -1;
147     }
148
149   return 0;
150 }
151
152 int
153 vcl_sapi_attach (void)
154 {
155   vcl_worker_t *wrk = vcl_worker_get_current ();
156   app_sapi_msg_t _rmp, *rmp = &_rmp;
157   clib_error_t *err;
158   clib_socket_t *cs;
159   int fds[32];
160
161   /*
162    * Init client socket and send attach
163    */
164   if (vcl_api_connect_app_socket (wrk))
165     return -1;
166
167   cs = &wrk->app_api_sock;
168   if (vcl_api_send_attach (cs))
169     return -1;
170
171   /*
172    * Wait for attach reply
173    */
174   err = clib_socket_recvmsg (cs, rmp, sizeof (*rmp), fds, ARRAY_LEN (fds));
175   if (err)
176     {
177       clib_error_report (err);
178       return -1;
179     }
180
181   if (rmp->type != APP_SAPI_MSG_TYPE_ATTACH_REPLY)
182     return -1;
183
184   return vcl_api_attach_reply_handler (&rmp->attach_reply, fds);
185 }
186
187 static int
188 vcl_api_add_del_worker_reply_handler (app_sapi_worker_add_del_reply_msg_t *
189                                       mp, int *fds)
190 {
191   int n_fds = 0, i, rv;
192   u64 segment_handle;
193   vcl_worker_t *wrk;
194
195   if (mp->retval)
196     {
197       VDBG (0, "add/del worker failed: %U", format_session_error, mp->retval);
198       goto failed;
199     }
200
201   if (!mp->is_add)
202     goto failed;
203
204   wrk = vcl_worker_get_current ();
205   wrk->api_client_handle = mp->api_client_handle;
206   wrk->vpp_wrk_index = mp->wrk_index;
207   wrk->ctrl_mq = vcm->ctrl_mq;
208
209   segment_handle = mp->segment_handle;
210   if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
211     {
212       clib_warning ("invalid segment handle");
213       goto failed;
214     }
215
216   if (!mp->n_fds)
217     goto failed;
218
219   if (mp->fd_flags & SESSION_FD_F_VPP_MQ_SEGMENT)
220     if (vcl_segment_attach (vcl_vpp_worker_segment_handle (wrk->wrk_index),
221                             "vpp-worker-seg", SSVM_SEGMENT_MEMFD,
222                             fds[n_fds++]))
223       goto failed;
224
225   if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
226     {
227       u8 *segment_name = format (0, "memfd-%ld%c", segment_handle, 0);
228       rv = vcl_segment_attach (segment_handle, (char *) segment_name,
229                                SSVM_SEGMENT_MEMFD, fds[n_fds++]);
230       vec_free (segment_name);
231       if (rv != 0)
232         goto failed;
233     }
234
235   vcl_segment_attach_mq (segment_handle, mp->app_event_queue_address, 0,
236                          &wrk->app_event_queue);
237
238   if (mp->fd_flags & SESSION_FD_F_MQ_EVENTFD)
239     {
240       svm_msg_q_set_eventfd (wrk->app_event_queue, fds[n_fds]);
241       vcl_mq_epoll_add_evfd (wrk, wrk->app_event_queue);
242       n_fds++;
243     }
244
245   VDBG (0, "worker %u vpp-worker %u added", wrk->wrk_index,
246         wrk->vpp_wrk_index);
247
248   return 0;
249
250 failed:
251   for (i = clib_max (n_fds - 1, 0); i < mp->n_fds; i++)
252     close (fds[i]);
253
254   return -1;
255 }
256
257 int
258 vcl_sapi_app_worker_add (void)
259 {
260   vcl_worker_t *wrk = vcl_worker_get_current ();
261   app_sapi_worker_add_del_msg_t *mp;
262   app_sapi_msg_t _rmp, *rmp = &_rmp;
263   app_sapi_msg_t msg = { 0 };
264   int fds[SESSION_N_FD_TYPE];
265   clib_error_t *err;
266   clib_socket_t *cs;
267
268   /* Connect to socket api */
269   if (vcl_api_connect_app_socket (wrk))
270     return -1;
271
272   /*
273    * Send add worker
274    */
275   cs = &wrk->app_api_sock;
276
277   msg.type = APP_SAPI_MSG_TYPE_ADD_DEL_WORKER;
278   mp = &msg.worker_add_del;
279   mp->app_index = vcm->app_index;
280   mp->is_add = 1;
281
282   err = clib_socket_sendmsg (cs, &msg, sizeof (msg), 0, 0);
283   if (err)
284     {
285       clib_error_report (err);
286       return -1;
287     }
288
289   /*
290    * Wait for reply and process it
291    */
292   err = clib_socket_recvmsg (cs, rmp, sizeof (*rmp), fds, ARRAY_LEN (fds));
293   if (err)
294     {
295       clib_error_report (err);
296       return -1;
297     }
298
299   if (rmp->type != APP_SAPI_MSG_TYPE_ADD_DEL_WORKER_REPLY)
300     {
301       clib_warning ("unexpected reply type %u", rmp->type);
302       return -1;
303     }
304
305   return vcl_api_add_del_worker_reply_handler (&rmp->worker_add_del_reply,
306                                                fds);
307 }
308
309 void
310 vcl_sapi_app_worker_del (vcl_worker_t * wrk)
311 {
312   app_sapi_worker_add_del_msg_t *mp;
313   app_sapi_msg_t msg = { 0 };
314   clib_error_t *err;
315   clib_socket_t *cs;
316
317   cs = &wrk->app_api_sock;
318
319   msg.type = APP_SAPI_MSG_TYPE_ADD_DEL_WORKER;
320   mp = &msg.worker_add_del;
321   mp->app_index = vcm->app_index;
322   mp->wrk_index = wrk->vpp_wrk_index;
323   mp->is_add = 0;
324
325   err = clib_socket_sendmsg (cs, &msg, sizeof (msg), 0, 0);
326   if (err)
327     clib_error_report (err);
328   clib_socket_close (cs);
329 }
330
331 void
332 vcl_sapi_detach (vcl_worker_t * wrk)
333 {
334   clib_socket_t *cs = &wrk->app_api_sock;
335   clib_socket_close (cs);
336 }
337
338 int
339 vcl_sapi_recv_fds (vcl_worker_t * wrk, int *fds, int n_fds)
340 {
341   app_sapi_msg_t _msg, *msg = &_msg;
342   clib_socket_t *cs;
343   clib_error_t *err;
344
345   cs = &wrk->app_api_sock;
346
347   err = clib_socket_recvmsg (cs, msg, sizeof (*msg), fds, n_fds);
348   if (err)
349     {
350       clib_error_report (err);
351       return -1;
352     }
353   if (msg->type != APP_SAPI_MSG_TYPE_SEND_FDS)
354     return -1;
355
356   return 0;
357 }
358
359 /*
360  * fd.io coding-style-patch-verification: ON
361  *
362  * Local Variables:
363  * eval: (c-set-style "gnu")
364  * End:
365  */