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