7d677e9dc1a5e4a28df4f1e79f44bc42280fbfe4
[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       /* don't report the error to avoid flood of error messages during
34        * reconnect */
35       clib_error_free (err);
36       rv = -1;
37       goto done;
38     }
39
40 done:
41
42   wrk->vcl_needs_real_epoll = 0;
43
44   return rv;
45 }
46
47 static int
48 vcl_api_attach_reply_handler (app_sapi_attach_reply_msg_t * mp, int *fds)
49 {
50   vcl_worker_t *wrk = vcl_worker_get_current ();
51   int i, rv, n_fds_used = 0;
52   u64 segment_handle;
53   u8 *segment_name;
54
55   if (mp->retval)
56     {
57       VERR ("attach failed: %U", format_session_error, mp->retval);
58       goto failed;
59     }
60
61   wrk->api_client_handle = mp->api_client_handle;
62   segment_handle = mp->segment_handle;
63   if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
64     {
65       VERR ("invalid segment handle");
66       goto failed;
67     }
68
69   if (!mp->n_fds)
70     goto failed;
71
72   if (mp->fd_flags & SESSION_FD_F_VPP_MQ_SEGMENT)
73     if (vcl_segment_attach (vcl_vpp_worker_segment_handle (0), "vpp-mq-seg",
74                             SSVM_SEGMENT_MEMFD, fds[n_fds_used++]))
75       goto failed;
76
77   if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
78     {
79       segment_name = format (0, "memfd-%ld%c", segment_handle, 0);
80       rv = vcl_segment_attach (segment_handle, (char *) segment_name,
81                                SSVM_SEGMENT_MEMFD, fds[n_fds_used++]);
82       vec_free (segment_name);
83       if (rv != 0)
84         goto failed;
85     }
86
87   vcl_segment_attach_mq (segment_handle, mp->app_mq, 0, &wrk->app_event_queue);
88
89   if (mp->fd_flags & SESSION_FD_F_MQ_EVENTFD)
90     {
91       svm_msg_q_set_eventfd (wrk->app_event_queue, fds[n_fds_used++]);
92       vcl_mq_epoll_add_evfd (wrk, wrk->app_event_queue);
93     }
94
95   vcl_segment_discover_mqs (vcl_vpp_worker_segment_handle (0),
96                             fds + n_fds_used, mp->n_fds - n_fds_used);
97   vcl_segment_attach_mq (vcl_vpp_worker_segment_handle (0), mp->vpp_ctrl_mq,
98                          mp->vpp_ctrl_mq_thread, &wrk->ctrl_mq);
99   vcm->ctrl_mq = wrk->ctrl_mq;
100   vcm->app_index = mp->app_index;
101
102   return 0;
103
104 failed:
105
106   for (i = clib_max (n_fds_used - 1, 0); i < mp->n_fds; i++)
107     close (fds[i]);
108
109   return -1;
110 }
111
112 static int
113 vcl_api_send_attach (clib_socket_t * cs)
114 {
115   app_sapi_msg_t msg = { 0 };
116   app_sapi_attach_msg_t *mp = &msg.attach;
117   u8 app_is_proxy, tls_engine;
118   clib_error_t *err;
119
120   app_is_proxy = (vcm->cfg.app_proxy_transport_tcp ||
121                   vcm->cfg.app_proxy_transport_udp);
122   tls_engine = CRYPTO_ENGINE_OPENSSL;
123
124   clib_memcpy (&mp->name, vcm->app_name, vec_len (vcm->app_name));
125   mp->options[APP_OPTIONS_FLAGS] =
126     APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT |
127     (vcm->cfg.app_scope_local ? APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE : 0) |
128     (vcm->cfg.app_scope_global ? APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE : 0) |
129     (app_is_proxy ? APP_OPTIONS_FLAGS_IS_PROXY : 0) |
130     (vcm->cfg.use_mq_eventfd ? APP_OPTIONS_FLAGS_EVT_MQ_USE_EVENTFD : 0) |
131     (vcm->cfg.huge_page ? APP_OPTIONS_FLAGS_USE_HUGE_PAGE : 0);
132   mp->options[APP_OPTIONS_PROXY_TRANSPORT] =
133     (u64) ((vcm->cfg.app_proxy_transport_tcp ? 1 << TRANSPORT_PROTO_TCP : 0) |
134            (vcm->cfg.app_proxy_transport_udp ? 1 << TRANSPORT_PROTO_UDP : 0));
135   mp->options[APP_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size;
136   mp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size;
137   mp->options[APP_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size;
138   mp->options[APP_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size;
139   mp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
140     vcm->cfg.preallocated_fifo_pairs;
141   mp->options[APP_OPTIONS_EVT_QUEUE_SIZE] = vcm->cfg.event_queue_size;
142   mp->options[APP_OPTIONS_TLS_ENGINE] = tls_engine;
143
144   msg.type = APP_SAPI_MSG_TYPE_ATTACH;
145   err = clib_socket_sendmsg (cs, &msg, sizeof (msg), 0, 0);
146   if (err)
147     {
148       clib_error_report (err);
149       return -1;
150     }
151
152   return 0;
153 }
154
155 int
156 vcl_sapi_attach (void)
157 {
158   vcl_worker_t *wrk = vcl_worker_get_current ();
159   app_sapi_msg_t _rmp, *rmp = &_rmp;
160   clib_error_t *err;
161   clib_socket_t *cs;
162   int fds[32];
163
164   /*
165    * Init client socket and send attach
166    */
167   if (vcl_api_connect_app_socket (wrk))
168     return -1;
169
170   cs = &wrk->app_api_sock;
171   if (vcl_api_send_attach (cs))
172     return -1;
173
174   /*
175    * Wait for attach reply
176    */
177   err = clib_socket_recvmsg (cs, rmp, sizeof (*rmp), fds, ARRAY_LEN (fds));
178   if (err)
179     {
180       clib_error_report (err);
181       return -1;
182     }
183
184   if (rmp->type != APP_SAPI_MSG_TYPE_ATTACH_REPLY)
185     return -1;
186
187   return vcl_api_attach_reply_handler (&rmp->attach_reply, fds);
188 }
189
190 static int
191 vcl_api_add_del_worker_reply_handler (app_sapi_worker_add_del_reply_msg_t *
192                                       mp, int *fds)
193 {
194   int n_fds = 0, i, rv;
195   u64 segment_handle;
196   vcl_worker_t *wrk;
197
198   if (mp->retval)
199     {
200       VDBG (0, "add/del worker failed: %U", format_session_error, mp->retval);
201       goto failed;
202     }
203
204   if (!mp->is_add)
205     goto failed;
206
207   wrk = vcl_worker_get_current ();
208   wrk->api_client_handle = mp->api_client_handle;
209   wrk->vpp_wrk_index = mp->wrk_index;
210   wrk->ctrl_mq = vcm->ctrl_mq;
211
212   segment_handle = mp->segment_handle;
213   if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
214     {
215       clib_warning ("invalid segment handle");
216       goto failed;
217     }
218
219   if (!mp->n_fds)
220     goto failed;
221
222   if (mp->fd_flags & SESSION_FD_F_VPP_MQ_SEGMENT)
223     if (vcl_segment_attach (vcl_vpp_worker_segment_handle (wrk->wrk_index),
224                             "vpp-worker-seg", SSVM_SEGMENT_MEMFD,
225                             fds[n_fds++]))
226       goto failed;
227
228   if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
229     {
230       u8 *segment_name = format (0, "memfd-%ld%c", segment_handle, 0);
231       rv = vcl_segment_attach (segment_handle, (char *) segment_name,
232                                SSVM_SEGMENT_MEMFD, fds[n_fds++]);
233       vec_free (segment_name);
234       if (rv != 0)
235         goto failed;
236     }
237
238   vcl_segment_attach_mq (segment_handle, mp->app_event_queue_address, 0,
239                          &wrk->app_event_queue);
240
241   if (mp->fd_flags & SESSION_FD_F_MQ_EVENTFD)
242     {
243       svm_msg_q_set_eventfd (wrk->app_event_queue, fds[n_fds]);
244       vcl_mq_epoll_add_evfd (wrk, wrk->app_event_queue);
245       n_fds++;
246     }
247
248   VDBG (0, "worker %u vpp-worker %u added", wrk->wrk_index,
249         wrk->vpp_wrk_index);
250
251   return 0;
252
253 failed:
254   for (i = clib_max (n_fds - 1, 0); i < mp->n_fds; i++)
255     close (fds[i]);
256
257   return -1;
258 }
259
260 int
261 vcl_sapi_app_worker_add (void)
262 {
263   vcl_worker_t *wrk = vcl_worker_get_current ();
264   app_sapi_worker_add_del_msg_t *mp;
265   app_sapi_msg_t _rmp, *rmp = &_rmp;
266   app_sapi_msg_t msg = { 0 };
267   int fds[SESSION_N_FD_TYPE];
268   clib_error_t *err;
269   clib_socket_t *cs;
270
271   /* Connect to socket api */
272   if (vcl_api_connect_app_socket (wrk))
273     return -1;
274
275   /*
276    * Send add worker
277    */
278   cs = &wrk->app_api_sock;
279
280   msg.type = APP_SAPI_MSG_TYPE_ADD_DEL_WORKER;
281   mp = &msg.worker_add_del;
282   mp->app_index = vcm->app_index;
283   mp->is_add = 1;
284
285   err = clib_socket_sendmsg (cs, &msg, sizeof (msg), 0, 0);
286   if (err)
287     {
288       clib_error_report (err);
289       return -1;
290     }
291
292   /*
293    * Wait for reply and process it
294    */
295   err = clib_socket_recvmsg (cs, rmp, sizeof (*rmp), fds, ARRAY_LEN (fds));
296   if (err)
297     {
298       clib_error_report (err);
299       return -1;
300     }
301
302   if (rmp->type != APP_SAPI_MSG_TYPE_ADD_DEL_WORKER_REPLY)
303     {
304       clib_warning ("unexpected reply type %u", rmp->type);
305       return -1;
306     }
307
308   return vcl_api_add_del_worker_reply_handler (&rmp->worker_add_del_reply,
309                                                fds);
310 }
311
312 void
313 vcl_sapi_app_worker_del (vcl_worker_t * wrk)
314 {
315   app_sapi_worker_add_del_msg_t *mp;
316   app_sapi_msg_t msg = { 0 };
317   clib_error_t *err;
318   clib_socket_t *cs;
319
320   cs = &wrk->app_api_sock;
321
322   msg.type = APP_SAPI_MSG_TYPE_ADD_DEL_WORKER;
323   mp = &msg.worker_add_del;
324   mp->app_index = vcm->app_index;
325   mp->wrk_index = wrk->vpp_wrk_index;
326   mp->is_add = 0;
327
328   err = clib_socket_sendmsg (cs, &msg, sizeof (msg), 0, 0);
329   if (err)
330     clib_error_report (err);
331   clib_socket_close (cs);
332 }
333
334 void
335 vcl_sapi_detach (vcl_worker_t * wrk)
336 {
337   clib_socket_t *cs = &wrk->app_api_sock;
338   clib_socket_close (cs);
339 }
340
341 int
342 vcl_sapi_recv_fds (vcl_worker_t * wrk, int *fds, int n_fds)
343 {
344   app_sapi_msg_t _msg, *msg = &_msg;
345   clib_socket_t *cs;
346   clib_error_t *err;
347
348   cs = &wrk->app_api_sock;
349
350   err = clib_socket_recvmsg (cs, msg, sizeof (*msg), fds, n_fds);
351   if (err)
352     {
353       clib_error_report (err);
354       return -1;
355     }
356   if (msg->type != APP_SAPI_MSG_TYPE_SEND_FDS)
357     return -1;
358
359   return 0;
360 }
361
362 int
363 vcl_sapi_add_cert_key_pair (vppcom_cert_key_pair_t *ckpair)
364 {
365   u32 cert_len = ckpair->cert_len, key_len = ckpair->key_len, certkey_len;
366   vcl_worker_t *wrk = vcl_worker_get_current ();
367   app_sapi_msg_t _msg = { 0 }, *msg = &_msg;
368   app_sapi_cert_key_add_del_msg_t *mp;
369   app_sapi_msg_t _rmp, *rmp = &_rmp;
370   clib_error_t *err;
371   clib_socket_t *cs;
372   u8 *certkey = 0;
373   int rv = -1;
374
375   msg->type = APP_SAPI_MSG_TYPE_ADD_DEL_CERT_KEY;
376   mp = &msg->cert_key_add_del;
377   mp->context = wrk->wrk_index;
378   mp->cert_len = cert_len;
379   mp->certkey_len = cert_len + key_len;
380   mp->is_add = 1;
381
382   certkey_len = cert_len + key_len;
383   vec_validate (certkey, certkey_len - 1);
384   clib_memcpy_fast (certkey, ckpair->cert, cert_len);
385   clib_memcpy_fast (certkey + cert_len, ckpair->key, key_len);
386
387   cs = &wrk->app_api_sock;
388   err = clib_socket_sendmsg (cs, msg, sizeof (*msg), 0, 0);
389   if (err)
390     {
391       clib_error_report (err);
392       goto done;
393     }
394
395   err = clib_socket_sendmsg (cs, certkey, certkey_len, 0, 0);
396   if (err)
397     {
398       clib_error_report (err);
399       goto done;
400     }
401
402   /*
403    * Wait for reply and process it
404    */
405   err = clib_socket_recvmsg (cs, rmp, sizeof (*rmp), 0, 0);
406   if (err)
407     {
408       clib_error_report (err);
409       goto done;
410     }
411
412   if (rmp->type != APP_SAPI_MSG_TYPE_ADD_DEL_CERT_KEY_REPLY)
413     {
414       clib_warning ("unexpected reply type %u", rmp->type);
415       goto done;
416     }
417
418   if (!rmp->cert_key_add_del_reply.retval)
419     rv = rmp->cert_key_add_del_reply.index;
420
421 done:
422
423   return rv;
424 }
425
426 int
427 vcl_sapi_del_cert_key_pair (u32 ckpair_index)
428 {
429   vcl_worker_t *wrk = vcl_worker_get_current ();
430   app_sapi_msg_t _msg = { 0 }, *msg = &_msg;
431   app_sapi_cert_key_add_del_msg_t *mp;
432   app_sapi_msg_t _rmp, *rmp = &_rmp;
433   clib_error_t *err;
434   clib_socket_t *cs;
435
436   msg->type = APP_SAPI_MSG_TYPE_ADD_DEL_CERT_KEY;
437   mp = &msg->cert_key_add_del;
438   mp->context = wrk->wrk_index;
439   mp->index = ckpair_index;
440
441   cs = &wrk->app_api_sock;
442   err = clib_socket_sendmsg (cs, msg, sizeof (*msg), 0, 0);
443   if (err)
444     {
445       clib_error_report (err);
446       return -1;
447     }
448
449   /*
450    * Wait for reply and process it
451    */
452   err = clib_socket_recvmsg (cs, rmp, sizeof (*rmp), 0, 0);
453   if (err)
454     {
455       clib_error_report (err);
456       return -1;
457     }
458
459   if (rmp->type != APP_SAPI_MSG_TYPE_ADD_DEL_CERT_KEY_REPLY)
460     {
461       clib_warning ("unexpected reply type %u", rmp->type);
462       return -1;
463     }
464
465   if (rmp->cert_key_add_del_reply.retval)
466     return -1;
467
468   return 0;
469 }
470
471 /*
472  * fd.io coding-style-patch-verification: ON
473  *
474  * Local Variables:
475  * eval: (c-set-style "gnu")
476  * End:
477  */