Line data Source code
1 : /*
2 : * Copyright (c) 2017-2019 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 <stdio.h>
17 : #include <stdlib.h>
18 : #include <vcl/vppcom.h>
19 : #include <vcl/vcl_debug.h>
20 : #include <vcl/vcl_private.h>
21 : #include <svm/fifo_segment.h>
22 :
23 : __thread uword __vcl_worker_index = ~0;
24 :
25 : static inline int
26 111766 : vcl_mq_dequeue_batch (vcl_worker_t * wrk, svm_msg_q_t * mq, u32 n_max_msg)
27 : {
28 111766 : u32 n_msgs = 0, sz, len;
29 :
30 222332 : while ((sz = svm_msg_q_size (mq)))
31 : {
32 110566 : len = vec_len (wrk->mq_msg_vector);
33 110566 : vec_validate (wrk->mq_msg_vector, len + sz - 1);
34 110566 : svm_msg_q_sub_raw_batch (mq, wrk->mq_msg_vector + len, sz);
35 110566 : n_msgs += sz;
36 : }
37 111766 : return n_msgs;
38 : }
39 :
40 :
41 :
42 : static void
43 6 : vcl_msg_add_ext_config (vcl_session_t *s, uword *offset)
44 : {
45 : svm_fifo_chunk_t *c;
46 :
47 6 : c = vcl_segment_alloc_chunk (vcl_vpp_worker_segment_handle (0),
48 6 : 0 /* one slice only */, s->ext_config->len,
49 : offset);
50 6 : if (c)
51 6 : clib_memcpy_fast (c->data, s->ext_config, s->ext_config->len);
52 6 : }
53 :
54 : void
55 40 : vcl_send_session_listen (vcl_worker_t *wrk, vcl_session_t *s)
56 : {
57 40 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
58 : session_listen_msg_t *mp;
59 : svm_msg_q_t *mq;
60 :
61 40 : mq = vcl_worker_ctrl_mq (wrk);
62 40 : app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_LISTEN);
63 40 : mp = (session_listen_msg_t *) app_evt->evt->data;
64 40 : memset (mp, 0, sizeof (*mp));
65 40 : mp->client_index = wrk->api_client_handle;
66 40 : mp->context = s->session_index;
67 40 : mp->wrk_index = wrk->vpp_wrk_index;
68 40 : mp->is_ip4 = s->transport.is_ip4;
69 40 : clib_memcpy_fast (&mp->ip, &s->transport.lcl_ip, sizeof (mp->ip));
70 40 : mp->port = s->transport.lcl_port;
71 40 : mp->proto = s->session_type;
72 40 : mp->vrf = s->vrf;
73 40 : if (s->flags & VCL_SESSION_F_CONNECTED)
74 0 : mp->flags = TRANSPORT_CFG_F_CONNECTED;
75 40 : if (s->ext_config)
76 3 : vcl_msg_add_ext_config (s, &mp->ext_config);
77 40 : app_send_ctrl_evt_to_vpp (mq, app_evt);
78 40 : if (s->ext_config)
79 : {
80 3 : clib_mem_free (s->ext_config);
81 3 : s->ext_config = 0;
82 : }
83 40 : s->flags |= VCL_SESSION_F_PENDING_LISTEN;
84 40 : }
85 :
86 : static void
87 47 : vcl_send_session_connect (vcl_worker_t * wrk, vcl_session_t * s)
88 : {
89 47 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
90 : session_connect_msg_t *mp;
91 : svm_msg_q_t *mq;
92 :
93 47 : mq = vcl_worker_ctrl_mq (wrk);
94 47 : app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_CONNECT);
95 47 : mp = (session_connect_msg_t *) app_evt->evt->data;
96 47 : memset (mp, 0, sizeof (*mp));
97 47 : mp->client_index = wrk->api_client_handle;
98 47 : mp->context = s->session_index;
99 47 : mp->dscp = s->dscp;
100 47 : mp->wrk_index = wrk->vpp_wrk_index;
101 47 : mp->is_ip4 = s->transport.is_ip4;
102 47 : mp->parent_handle = s->parent_handle;
103 47 : clib_memcpy_fast (&mp->ip, &s->transport.rmt_ip, sizeof (mp->ip));
104 47 : clib_memcpy_fast (&mp->lcl_ip, &s->transport.lcl_ip, sizeof (mp->lcl_ip));
105 47 : mp->port = s->transport.rmt_port;
106 47 : mp->lcl_port = s->transport.lcl_port;
107 47 : mp->proto = s->session_type;
108 47 : mp->vrf = s->vrf;
109 47 : if (s->flags & VCL_SESSION_F_CONNECTED)
110 47 : mp->flags |= TRANSPORT_CFG_F_CONNECTED;
111 47 : if (s->ext_config)
112 3 : vcl_msg_add_ext_config (s, &mp->ext_config);
113 47 : app_send_ctrl_evt_to_vpp (mq, app_evt);
114 :
115 47 : if (s->ext_config)
116 : {
117 3 : clib_mem_free (s->ext_config);
118 3 : s->ext_config = 0;
119 : }
120 47 : }
121 :
122 : void
123 23 : vcl_send_session_unlisten (vcl_worker_t * wrk, vcl_session_t * s)
124 : {
125 23 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
126 : session_unlisten_msg_t *mp;
127 : svm_msg_q_t *mq;
128 :
129 23 : mq = vcl_worker_ctrl_mq (wrk);
130 23 : app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_UNLISTEN);
131 23 : mp = (session_unlisten_msg_t *) app_evt->evt->data;
132 23 : memset (mp, 0, sizeof (*mp));
133 23 : mp->client_index = wrk->api_client_handle;
134 23 : mp->wrk_index = wrk->vpp_wrk_index;
135 23 : mp->handle = s->vpp_handle;
136 23 : mp->context = wrk->wrk_index;
137 23 : app_send_ctrl_evt_to_vpp (mq, app_evt);
138 23 : }
139 :
140 : static void
141 0 : vcl_send_session_shutdown (vcl_worker_t *wrk, vcl_session_t *s)
142 : {
143 0 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
144 : session_shutdown_msg_t *mp;
145 : svm_msg_q_t *mq;
146 :
147 : /* Send to thread that owns the session */
148 0 : mq = s->vpp_evt_q;
149 0 : app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_SHUTDOWN);
150 0 : mp = (session_shutdown_msg_t *) app_evt->evt->data;
151 0 : memset (mp, 0, sizeof (*mp));
152 0 : mp->client_index = wrk->api_client_handle;
153 0 : mp->handle = s->vpp_handle;
154 0 : app_send_ctrl_evt_to_vpp (mq, app_evt);
155 0 : }
156 :
157 : static void
158 56 : vcl_send_session_disconnect (vcl_worker_t * wrk, vcl_session_t * s)
159 : {
160 56 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
161 : session_disconnect_msg_t *mp;
162 : svm_msg_q_t *mq;
163 :
164 : /* Send to thread that owns the session */
165 56 : mq = s->vpp_evt_q;
166 56 : app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_DISCONNECT);
167 56 : mp = (session_disconnect_msg_t *) app_evt->evt->data;
168 56 : memset (mp, 0, sizeof (*mp));
169 56 : mp->client_index = wrk->api_client_handle;
170 56 : mp->handle = s->vpp_handle;
171 56 : app_send_ctrl_evt_to_vpp (mq, app_evt);
172 56 : }
173 :
174 : static void
175 24 : vcl_send_app_detach (vcl_worker_t * wrk)
176 : {
177 24 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
178 : session_app_detach_msg_t *mp;
179 : svm_msg_q_t *mq;
180 :
181 24 : mq = vcl_worker_ctrl_mq (wrk);
182 24 : app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_APP_DETACH);
183 24 : mp = (session_app_detach_msg_t *) app_evt->evt->data;
184 24 : memset (mp, 0, sizeof (*mp));
185 24 : mp->client_index = wrk->api_client_handle;
186 24 : app_send_ctrl_evt_to_vpp (mq, app_evt);
187 24 : }
188 :
189 : static void
190 37 : vcl_send_session_accepted_reply (svm_msg_q_t * mq, u32 context,
191 : session_handle_t handle, int retval)
192 : {
193 37 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
194 : session_accepted_reply_msg_t *rmp;
195 37 : app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_ACCEPTED_REPLY);
196 37 : rmp = (session_accepted_reply_msg_t *) app_evt->evt->data;
197 37 : rmp->handle = handle;
198 37 : rmp->context = context;
199 37 : rmp->retval = retval;
200 37 : app_send_ctrl_evt_to_vpp (mq, app_evt);
201 37 : }
202 :
203 : static void
204 6 : vcl_send_session_disconnected_reply (vcl_worker_t * wrk, vcl_session_t * s,
205 : int retval)
206 : {
207 6 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
208 : session_disconnected_reply_msg_t *rmp;
209 6 : app_alloc_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt,
210 : SESSION_CTRL_EVT_DISCONNECTED_REPLY);
211 6 : rmp = (session_disconnected_reply_msg_t *) app_evt->evt->data;
212 6 : rmp->handle = s->vpp_handle;
213 6 : rmp->context = wrk->api_client_handle;
214 6 : rmp->retval = retval;
215 6 : app_send_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt);
216 6 : }
217 :
218 : static void
219 4 : vcl_send_session_reset_reply (vcl_worker_t * wrk, vcl_session_t * s,
220 : int retval)
221 : {
222 4 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
223 : session_reset_reply_msg_t *rmp;
224 4 : app_alloc_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt,
225 : SESSION_CTRL_EVT_RESET_REPLY);
226 4 : rmp = (session_reset_reply_msg_t *) app_evt->evt->data;
227 4 : rmp->handle = s->vpp_handle;
228 4 : rmp->context = wrk->api_client_handle;
229 4 : rmp->retval = retval;
230 4 : app_send_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt);
231 4 : }
232 :
233 : void
234 0 : vcl_send_session_worker_update (vcl_worker_t * wrk, vcl_session_t * s,
235 : u32 wrk_index)
236 : {
237 0 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
238 : session_worker_update_msg_t *mp;
239 :
240 0 : app_alloc_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt,
241 : SESSION_CTRL_EVT_WORKER_UPDATE);
242 0 : mp = (session_worker_update_msg_t *) app_evt->evt->data;
243 0 : mp->client_index = wrk->api_client_handle;
244 0 : mp->handle = s->vpp_handle;
245 0 : mp->req_wrk_index = wrk->vpp_wrk_index;
246 0 : mp->wrk_index = wrk_index;
247 0 : app_send_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt);
248 0 : }
249 :
250 : int
251 0 : vcl_send_worker_rpc (u32 dst_wrk_index, void *data, u32 data_len)
252 : {
253 0 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
254 : session_app_wrk_rpc_msg_t *mp;
255 : vcl_worker_t *dst_wrk, *wrk;
256 : svm_msg_q_t *mq;
257 0 : int ret = -1;
258 :
259 0 : if (data_len > sizeof (mp->data))
260 0 : goto done;
261 :
262 0 : clib_spinlock_lock (&vcm->workers_lock);
263 :
264 0 : dst_wrk = vcl_worker_get_if_valid (dst_wrk_index);
265 0 : if (!dst_wrk)
266 0 : goto done;
267 :
268 0 : wrk = vcl_worker_get_current ();
269 0 : mq = vcl_worker_ctrl_mq (wrk);
270 0 : app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_APP_WRK_RPC);
271 0 : mp = (session_app_wrk_rpc_msg_t *) app_evt->evt->data;
272 0 : mp->client_index = wrk->api_client_handle;
273 0 : mp->wrk_index = dst_wrk->vpp_wrk_index;
274 0 : clib_memcpy (mp->data, data, data_len);
275 0 : app_send_ctrl_evt_to_vpp (mq, app_evt);
276 0 : ret = 0;
277 :
278 0 : done:
279 0 : clib_spinlock_unlock (&vcm->workers_lock);
280 0 : return ret;
281 : }
282 :
283 : int
284 7 : vcl_session_transport_attr (vcl_worker_t *wrk, vcl_session_t *s, u8 is_get,
285 : transport_endpt_attr_t *attr)
286 : {
287 7 : app_session_evt_t _app_evt, *app_evt = &_app_evt;
288 : session_transport_attr_msg_t *mp;
289 : svm_msg_q_t *mq;
290 : f64 timeout;
291 :
292 7 : ASSERT (!wrk->session_attr_op);
293 7 : mq = s->vpp_evt_q;
294 7 : if (PREDICT_FALSE (!mq))
295 : {
296 : /* FIXME: attribute should be stored and sent once session is
297 : * bound/connected to vpp */
298 2 : return 0;
299 : }
300 :
301 5 : wrk->session_attr_op = 1;
302 5 : wrk->session_attr_op_rv = -1;
303 :
304 5 : app_alloc_ctrl_evt_to_vpp (mq, app_evt, SESSION_CTRL_EVT_TRANSPORT_ATTR);
305 5 : mp = (session_transport_attr_msg_t *) app_evt->evt->data;
306 5 : memset (mp, 0, sizeof (*mp));
307 5 : mp->client_index = wrk->api_client_handle;
308 5 : mp->handle = s->vpp_handle;
309 5 : mp->is_get = is_get;
310 5 : mp->attr = *attr;
311 5 : app_send_ctrl_evt_to_vpp (mq, app_evt);
312 :
313 5 : timeout = clib_time_now (&wrk->clib_time) + 1;
314 :
315 1355 : while (wrk->session_attr_op && clib_time_now (&wrk->clib_time) < timeout)
316 1350 : vcl_flush_mq_events ();
317 :
318 5 : if (!wrk->session_attr_op_rv && is_get)
319 3 : *attr = wrk->session_attr_rv;
320 :
321 5 : wrk->session_attr_op = 0;
322 :
323 5 : return wrk->session_attr_op_rv;
324 : }
325 :
326 : static u32
327 37 : vcl_session_accepted_handler (vcl_worker_t * wrk, session_accepted_msg_t * mp,
328 : u32 ls_index)
329 : {
330 : vcl_session_t *session, *listen_session;
331 : svm_msg_q_t *evt_q;
332 :
333 37 : session = vcl_session_alloc (wrk);
334 :
335 37 : listen_session = vcl_session_get (wrk, ls_index);
336 37 : if (listen_session->vpp_handle != mp->listener_handle)
337 : {
338 0 : VDBG (0, "ERROR: listener handle %lu does not match session %u",
339 : mp->listener_handle, ls_index);
340 0 : goto error;
341 : }
342 :
343 37 : if (vcl_segment_attach_session (
344 : mp->segment_handle, mp->server_rx_fifo, mp->server_tx_fifo,
345 : mp->vpp_event_queue_address, mp->mq_index, 0, session))
346 : {
347 0 : VDBG (0, "session %u [0x%llx]: failed to attach fifos",
348 : session->session_index, mp->handle);
349 0 : goto error;
350 : }
351 :
352 37 : session->vpp_handle = mp->handle;
353 37 : session->session_state = VCL_STATE_READY;
354 37 : session->transport.rmt_port = mp->rmt.port;
355 37 : session->transport.is_ip4 = mp->rmt.is_ip4;
356 37 : clib_memcpy_fast (&session->transport.rmt_ip, &mp->rmt.ip,
357 : sizeof (ip46_address_t));
358 :
359 37 : vcl_session_table_add_vpp_handle (wrk, mp->handle, session->session_index);
360 37 : session->transport.lcl_port = mp->lcl.port;
361 37 : session->transport.lcl_ip = mp->lcl.ip;
362 37 : session->session_type = listen_session->session_type;
363 37 : session->is_dgram = vcl_proto_is_dgram (session->session_type);
364 37 : if (session->is_dgram)
365 1 : session->flags |= (listen_session->flags & VCL_SESSION_F_CONNECTED);
366 37 : session->listener_index = listen_session->session_index;
367 37 : listen_session->n_accepted_sessions++;
368 :
369 : vcl_evt (VCL_EVT_ACCEPT, session, listen_session, session_index);
370 :
371 37 : vcl_send_session_accepted_reply (session->vpp_evt_q, mp->context,
372 : session->vpp_handle, 0);
373 :
374 37 : return session->session_index;
375 :
376 0 : error:
377 0 : vcl_segment_attach_mq (vcl_vpp_worker_segment_handle (0),
378 : mp->vpp_event_queue_address, mp->mq_index, &evt_q);
379 0 : vcl_send_session_accepted_reply (evt_q, mp->context, mp->handle,
380 : VNET_API_ERROR_INVALID_ARGUMENT);
381 0 : vcl_session_free (wrk, session);
382 0 : return VCL_INVALID_SESSION_INDEX;
383 : }
384 :
385 : static u32
386 47 : vcl_session_connected_handler (vcl_worker_t * wrk,
387 : session_connected_msg_t * mp)
388 : {
389 47 : vcl_session_t *session = 0;
390 : u32 session_index;
391 :
392 47 : session_index = mp->context;
393 47 : session = vcl_session_get (wrk, session_index);
394 47 : if (PREDICT_FALSE (!session))
395 : {
396 0 : VERR ("vpp handle 0x%llx has no session index (%u)!", mp->handle,
397 : session_index);
398 : /* Should not happen but if it does, force vpp session cleanup */
399 0 : vcl_session_t tmp_session = {
400 0 : .vpp_handle = mp->handle,
401 : .vpp_evt_q = 0,
402 : };
403 0 : vcl_segment_attach_session (
404 : mp->segment_handle, mp->server_rx_fifo, mp->server_tx_fifo,
405 : mp->vpp_event_queue_address, mp->mq_index, 0, session);
406 0 : if (tmp_session.vpp_evt_q)
407 0 : vcl_send_session_disconnect (wrk, &tmp_session);
408 0 : return VCL_INVALID_SESSION_INDEX;
409 : }
410 :
411 47 : if (mp->retval)
412 : {
413 0 : VDBG (0, "session %u: connect failed! %U", session_index,
414 : format_session_error, mp->retval);
415 0 : session->session_state = VCL_STATE_DETACHED;
416 0 : session->vpp_handle = VCL_INVALID_SESSION_HANDLE;
417 0 : session->vpp_error = mp->retval;
418 0 : return session_index;
419 : }
420 :
421 47 : session->vpp_handle = mp->handle;
422 :
423 : /* Add to lookup table. Even if something fails, session cannot be
424 : * cleaned up prior to notifying vpp and going through the cleanup
425 : * "procedure" see @ref vcl_session_cleanup_handler */
426 47 : vcl_session_table_add_vpp_handle (wrk, mp->handle, session_index);
427 :
428 47 : if (vcl_segment_attach_session (
429 : mp->segment_handle, mp->server_rx_fifo, mp->server_tx_fifo,
430 : mp->vpp_event_queue_address, mp->mq_index, 0, session))
431 : {
432 0 : VDBG (0, "session %u [0x%llx]: failed to attach fifos",
433 : session->session_index, session->vpp_handle);
434 0 : session->session_state = VCL_STATE_UPDATED;
435 0 : vcl_send_session_disconnect (wrk, session);
436 0 : return session_index;
437 : }
438 :
439 47 : if (mp->ct_rx_fifo)
440 : {
441 12 : if (vcl_segment_attach_session (mp->ct_segment_handle, mp->ct_rx_fifo,
442 : mp->ct_tx_fifo, (uword) ~0, ~0, 1,
443 : session))
444 : {
445 0 : VDBG (0, "session %u [0x%llx]: failed to attach ct fifos",
446 : session->session_index, session->vpp_handle);
447 0 : session->session_state = VCL_STATE_UPDATED;
448 0 : vcl_send_session_disconnect (wrk, session);
449 0 : return session_index;
450 : }
451 : }
452 :
453 47 : session->transport.is_ip4 = mp->lcl.is_ip4;
454 47 : clib_memcpy_fast (&session->transport.lcl_ip, &mp->lcl.ip,
455 : sizeof (session->transport.lcl_ip));
456 47 : session->transport.lcl_port = mp->lcl.port;
457 :
458 : /* Application closed session before connect reply */
459 47 : if (vcl_session_has_attr (session, VCL_SESS_ATTR_NONBLOCK)
460 0 : && session->session_state == VCL_STATE_CLOSED)
461 0 : vcl_send_session_disconnect (wrk, session);
462 : else
463 47 : session->session_state = VCL_STATE_READY;
464 :
465 47 : VDBG (0, "session %u [0x%llx] connected local: %U:%u remote %U:%u",
466 : session->session_index, session->vpp_handle, vcl_format_ip46_address,
467 : &session->transport.lcl_ip,
468 : session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
469 : clib_net_to_host_u16 (session->transport.lcl_port),
470 : vcl_format_ip46_address, &session->transport.rmt_ip,
471 : session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
472 : clib_net_to_host_u16 (session->transport.rmt_port));
473 :
474 47 : return session_index;
475 : }
476 :
477 : static int
478 0 : vcl_flag_accepted_session (vcl_session_t * session, u64 handle, u32 flags)
479 : {
480 : vcl_session_msg_t *accepted_msg;
481 : int i;
482 :
483 0 : for (i = 0; i < vec_len (session->accept_evts_fifo); i++)
484 : {
485 0 : accepted_msg = &session->accept_evts_fifo[i];
486 0 : if (accepted_msg->accepted_msg.handle == handle)
487 : {
488 0 : accepted_msg->flags |= flags;
489 0 : return 1;
490 : }
491 : }
492 0 : return 0;
493 : }
494 :
495 : static u32
496 5 : vcl_session_reset_handler (vcl_worker_t * wrk,
497 : session_reset_msg_t * reset_msg)
498 : {
499 : vcl_session_t *session;
500 : u32 sid;
501 :
502 5 : sid = vcl_session_index_from_vpp_handle (wrk, reset_msg->handle);
503 5 : session = vcl_session_get (wrk, sid);
504 5 : if (!session)
505 : {
506 0 : VDBG (0, "request to reset unknown handle 0x%llx", reset_msg->handle);
507 0 : return VCL_INVALID_SESSION_INDEX;
508 : }
509 :
510 : /* Caught a reset before actually accepting the session */
511 5 : if (session->session_state == VCL_STATE_LISTEN)
512 : {
513 :
514 0 : if (!vcl_flag_accepted_session (session, reset_msg->handle,
515 : VCL_ACCEPTED_F_RESET))
516 0 : VDBG (0, "session was not accepted!");
517 0 : return VCL_INVALID_SESSION_INDEX;
518 : }
519 :
520 5 : if (session->session_state != VCL_STATE_CLOSED)
521 4 : session->session_state = VCL_STATE_DISCONNECT;
522 :
523 5 : session->flags |= (VCL_SESSION_F_RD_SHUTDOWN | VCL_SESSION_F_WR_SHUTDOWN);
524 5 : VDBG (0, "session %u [0x%llx]: reset", sid, reset_msg->handle);
525 5 : return sid;
526 : }
527 :
528 : static u32
529 40 : vcl_session_bound_handler (vcl_worker_t * wrk, session_bound_msg_t * mp)
530 : {
531 : vcl_session_t *session;
532 40 : u32 sid = mp->context;
533 :
534 40 : session = vcl_session_get (wrk, sid);
535 40 : if (mp->retval)
536 : {
537 0 : VERR ("session %u [0x%llx]: bind failed: %U", sid, mp->handle,
538 : format_session_error, mp->retval);
539 0 : if (session)
540 : {
541 0 : session->session_state = VCL_STATE_DETACHED;
542 0 : session->vpp_handle = mp->handle;
543 0 : return sid;
544 : }
545 : else
546 : {
547 0 : VDBG (0, "session %u [0x%llx]: Invalid session index!", sid,
548 : mp->handle);
549 0 : return VCL_INVALID_SESSION_INDEX;
550 : }
551 : }
552 :
553 40 : session->vpp_handle = mp->handle;
554 40 : session->transport.is_ip4 = mp->lcl_is_ip4;
555 40 : clib_memcpy_fast (&session->transport.lcl_ip, mp->lcl_ip,
556 : sizeof (ip46_address_t));
557 40 : session->transport.lcl_port = mp->lcl_port;
558 40 : vcl_session_table_add_listener (wrk, mp->handle, sid);
559 40 : session->session_state = VCL_STATE_LISTEN;
560 40 : session->flags &= ~VCL_SESSION_F_PENDING_LISTEN;
561 :
562 40 : if (vcl_session_is_cl (session))
563 : {
564 3 : if (vcl_segment_attach_session (mp->segment_handle, mp->rx_fifo,
565 : mp->tx_fifo, mp->vpp_evt_q, mp->mq_index,
566 : 0, session))
567 : {
568 0 : VDBG (0, "session %u [0x%llx]: failed to attach fifos",
569 : session->session_index, session->vpp_handle);
570 0 : session->session_state = VCL_STATE_DETACHED;
571 0 : return VCL_INVALID_SESSION_INDEX;
572 : }
573 : }
574 :
575 40 : VDBG (0, "session %u [0x%llx]: listen succeeded!", sid, mp->handle);
576 40 : return sid;
577 : }
578 :
579 : static void
580 10 : vcl_session_unlisten_reply_handler (vcl_worker_t * wrk, void *data)
581 : {
582 10 : session_unlisten_reply_msg_t *mp = (session_unlisten_reply_msg_t *) data;
583 : vcl_session_t *s;
584 :
585 10 : s = vcl_session_get_w_vpp_handle (wrk, mp->handle);
586 10 : if (!s)
587 : {
588 0 : VDBG (0, "Unlisten reply with wrong handle %llx", mp->handle);
589 0 : return;
590 : }
591 10 : if (s->session_state != VCL_STATE_DISCONNECT)
592 : {
593 : /* Connected udp listener */
594 2 : if (s->session_type == VPPCOM_PROTO_UDP
595 2 : && s->session_state == VCL_STATE_CLOSED)
596 2 : return;
597 :
598 0 : VDBG (0, "Unlisten session in wrong state %llx", mp->handle);
599 0 : return;
600 : }
601 :
602 8 : if (mp->retval)
603 0 : VDBG (0, "ERROR: session %u [0xllx]: unlisten failed: %U",
604 : s->session_index, mp->handle, format_session_error, mp->retval);
605 :
606 8 : if (mp->context != wrk->wrk_index)
607 0 : VDBG (0, "wrong context");
608 :
609 8 : vcl_session_table_del_vpp_handle (wrk, mp->handle);
610 8 : vcl_session_free (wrk, s);
611 : }
612 :
613 : static void
614 0 : vcl_session_migrated_handler (vcl_worker_t * wrk, void *data)
615 : {
616 0 : session_migrated_msg_t *mp = (session_migrated_msg_t *) data;
617 : vcl_session_t *s;
618 : u32 fs_index;
619 :
620 0 : s = vcl_session_get_w_vpp_handle (wrk, mp->handle);
621 0 : if (!s)
622 : {
623 0 : VDBG (0, "Migrated notification with wrong handle %llx", mp->handle);
624 0 : return;
625 : }
626 :
627 : /* Only validate if a value is provided */
628 0 : if (mp->segment_handle != SESSION_INVALID_HANDLE)
629 : {
630 0 : fs_index = vcl_segment_table_lookup (mp->segment_handle);
631 0 : if (fs_index == VCL_INVALID_SEGMENT_INDEX)
632 : {
633 0 : VDBG (0, "segment %lx for session %u is not mounted!",
634 : mp->segment_handle, s->session_index);
635 0 : s->session_state = VCL_STATE_DETACHED;
636 0 : return;
637 : }
638 : }
639 :
640 0 : s->vpp_handle = mp->new_handle;
641 :
642 0 : vcl_segment_attach_mq (vcl_vpp_worker_segment_handle (0), mp->vpp_evt_q,
643 : mp->vpp_thread_index, &s->vpp_evt_q);
644 :
645 0 : vcl_session_table_del_vpp_handle (wrk, mp->handle);
646 0 : vcl_session_table_add_vpp_handle (wrk, mp->new_handle, s->session_index);
647 :
648 : /* Generate new tx event if we have outstanding data */
649 0 : if (svm_fifo_has_event (s->tx_fifo))
650 0 : app_send_io_evt_to_vpp (s->vpp_evt_q,
651 0 : s->tx_fifo->shr->master_session_index,
652 : SESSION_IO_EVT_TX, SVM_Q_WAIT);
653 :
654 0 : VDBG (0, "Migrated 0x%lx to thread %u 0x%lx", mp->handle,
655 : mp->vpp_thread_index, mp->new_handle);
656 : }
657 :
658 : static vcl_session_t *
659 37 : vcl_session_accepted (vcl_worker_t * wrk, session_accepted_msg_t * msg)
660 : {
661 : vcl_session_msg_t *vcl_msg;
662 : vcl_session_t *session;
663 :
664 37 : session = vcl_session_get_w_vpp_handle (wrk, msg->handle);
665 37 : if (PREDICT_FALSE (session != 0))
666 0 : VWRN ("session overlap handle %lu state %u!", msg->handle,
667 : session->session_state);
668 :
669 37 : session = vcl_session_table_lookup_listener (wrk, msg->listener_handle);
670 37 : if (!session)
671 : {
672 0 : VERR ("couldn't find listen session: listener handle %llx",
673 : msg->listener_handle);
674 0 : return 0;
675 : }
676 :
677 37 : clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
678 37 : vcl_msg->flags = 0;
679 37 : vcl_msg->accepted_msg = *msg;
680 : /* Session handle points to listener until fully accepted by app */
681 37 : vcl_session_table_add_vpp_handle (wrk, msg->handle, session->session_index);
682 :
683 37 : return session;
684 : }
685 :
686 : static vcl_session_t *
687 11 : vcl_session_disconnected_handler (vcl_worker_t * wrk,
688 : session_disconnected_msg_t * msg)
689 : {
690 : vcl_session_t *session;
691 :
692 11 : session = vcl_session_get_w_vpp_handle (wrk, msg->handle);
693 11 : if (!session)
694 : {
695 0 : VWRN ("request to disconnect unknown handle 0x%llx", msg->handle);
696 0 : return 0;
697 : }
698 :
699 : /* Late disconnect notification on a session that has been closed */
700 11 : if (session->session_state == VCL_STATE_CLOSED)
701 5 : return 0;
702 :
703 : /* Caught a disconnect before actually accepting the session */
704 6 : if (session->session_state == VCL_STATE_LISTEN)
705 : {
706 0 : if (!vcl_flag_accepted_session (session, msg->handle,
707 : VCL_ACCEPTED_F_CLOSED))
708 0 : VDBG (0, "session was not accepted!");
709 0 : return 0;
710 : }
711 :
712 : /* If not already reset change state */
713 6 : if (session->session_state != VCL_STATE_DISCONNECT)
714 6 : session->session_state = VCL_STATE_VPP_CLOSING;
715 :
716 6 : return session;
717 : }
718 :
719 : int
720 0 : vppcom_session_shutdown (uint32_t session_handle, int how)
721 : {
722 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
723 : vcl_session_t *session;
724 : vcl_session_state_t state;
725 : u64 vpp_handle;
726 :
727 0 : session = vcl_session_get_w_handle (wrk, session_handle);
728 0 : if (PREDICT_FALSE (!session))
729 0 : return VPPCOM_EBADFD;
730 :
731 0 : vpp_handle = session->vpp_handle;
732 0 : state = session->session_state;
733 :
734 0 : VDBG (1, "session %u [0x%llx] state 0x%x (%s)", session->session_index,
735 : vpp_handle, state, vcl_session_state_str (state));
736 :
737 0 : if (PREDICT_FALSE (state == VCL_STATE_LISTEN))
738 : {
739 0 : VDBG (0, "ERROR: Cannot shutdown a listen socket!");
740 0 : return VPPCOM_EBADFD;
741 : }
742 :
743 0 : if (how == SHUT_RD || how == SHUT_RDWR)
744 : {
745 0 : session->flags |= VCL_SESSION_F_RD_SHUTDOWN;
746 0 : if (how == SHUT_RD)
747 0 : return VPPCOM_OK;
748 : }
749 0 : session->flags |= VCL_SESSION_F_WR_SHUTDOWN;
750 :
751 0 : if (PREDICT_TRUE (state == VCL_STATE_READY))
752 : {
753 0 : VDBG (1, "session %u [0x%llx]: sending shutdown...",
754 : session->session_index, vpp_handle);
755 :
756 0 : vcl_send_session_shutdown (wrk, session);
757 : }
758 :
759 0 : return VPPCOM_OK;
760 : }
761 :
762 : static int
763 62 : vppcom_session_disconnect (u32 session_handle)
764 : {
765 62 : vcl_worker_t *wrk = vcl_worker_get_current ();
766 : vcl_session_t *session, *listen_session;
767 : vcl_session_state_t state;
768 : u64 vpp_handle;
769 :
770 62 : session = vcl_session_get_w_handle (wrk, session_handle);
771 62 : if (!session)
772 0 : return VPPCOM_EBADFD;
773 :
774 62 : vpp_handle = session->vpp_handle;
775 62 : state = session->session_state;
776 :
777 62 : VDBG (1, "session %u [0x%llx]: disconnecting state (%s)",
778 : session->session_index, vpp_handle, vcl_session_state_str (state));
779 :
780 62 : if (PREDICT_FALSE (state == VCL_STATE_LISTEN))
781 : {
782 0 : VDBG (0, "ERROR: Cannot disconnect a listen socket!");
783 0 : return VPPCOM_EBADFD;
784 : }
785 :
786 62 : if (state == VCL_STATE_VPP_CLOSING)
787 : {
788 6 : vcl_send_session_disconnected_reply (wrk, session, 0);
789 6 : VDBG (1, "session %u [0x%llx]: sending disconnect REPLY...",
790 : session->session_index, vpp_handle);
791 : }
792 : else
793 : {
794 : /* Session doesn't have an event queue yet. Probably a non-blocking
795 : * connect. Wait for the reply */
796 56 : if (PREDICT_FALSE (!session->vpp_evt_q))
797 0 : return VPPCOM_OK;
798 :
799 56 : VDBG (1, "session %u [0x%llx]: sending disconnect",
800 : session->session_index, vpp_handle);
801 56 : vcl_send_session_disconnect (wrk, session);
802 : }
803 :
804 62 : if (session->listener_index != VCL_INVALID_SESSION_INDEX)
805 : {
806 36 : listen_session = vcl_session_get (wrk, session->listener_index);
807 36 : if (listen_session)
808 35 : listen_session->n_accepted_sessions--;
809 : }
810 :
811 62 : return VPPCOM_OK;
812 : }
813 :
814 : static void
815 18 : vcl_session_cleanup_handler (vcl_worker_t * wrk, void *data)
816 : {
817 : session_cleanup_msg_t *msg;
818 : vcl_session_t *session;
819 :
820 18 : msg = (session_cleanup_msg_t *) data;
821 18 : session = vcl_session_get_w_vpp_handle (wrk, msg->handle);
822 18 : if (!session)
823 : {
824 0 : VWRN ("disconnect confirmed for unknown handle 0x%llx", msg->handle);
825 0 : return;
826 : }
827 :
828 18 : if (msg->type == SESSION_CLEANUP_TRANSPORT)
829 : {
830 : /* Transport was cleaned up before we confirmed close. Probably the
831 : * app is still waiting for some data that cannot be delivered.
832 : * Confirm close to make sure everything is cleaned up.
833 : * Move to undetermined state to ensure that the session is not
834 : * removed before both vpp and the app cleanup.
835 : * - If the app closes first, the session is moved to CLOSED state
836 : * and the session cleanup notification from vpp removes the
837 : * session.
838 : * - If vpp cleans up the session first, the session is moved to
839 : * DETACHED state lower and subsequently the close from the app
840 : * frees the session
841 : */
842 2 : if (session->session_state == VCL_STATE_VPP_CLOSING)
843 : {
844 0 : vppcom_session_disconnect (vcl_session_handle (session));
845 0 : session->session_state = VCL_STATE_UPDATED;
846 : }
847 2 : else if (session->session_state == VCL_STATE_DISCONNECT)
848 : {
849 0 : vcl_send_session_reset_reply (wrk, session, 0);
850 0 : session->session_state = VCL_STATE_UPDATED;
851 : }
852 2 : return;
853 : }
854 :
855 : /* VPP will reuse the handle so clean it up now */
856 16 : vcl_session_table_del_vpp_handle (wrk, msg->handle);
857 :
858 : /* App did not close the connection yet so don't free it. */
859 16 : if (session->session_state != VCL_STATE_CLOSED)
860 : {
861 0 : VDBG (0, "session %u: app did not close", session->session_index);
862 0 : session->session_state = VCL_STATE_DETACHED;
863 0 : session->vpp_handle = VCL_INVALID_SESSION_HANDLE;
864 0 : return;
865 : }
866 :
867 : /* Session probably tracked with epoll, disconnect not yet handled and
868 : * 1) both transport and session cleanup completed 2) app closed. Wait
869 : * until message is drained to free the session.
870 : * See @ref vcl_handle_mq_event */
871 16 : if (session->flags & VCL_SESSION_F_PENDING_DISCONNECT)
872 : {
873 0 : session->flags |= VCL_SESSION_F_PENDING_FREE;
874 0 : return;
875 : }
876 :
877 16 : vcl_session_free (wrk, session);
878 : }
879 :
880 : static void
881 0 : vcl_session_req_worker_update_handler (vcl_worker_t * wrk, void *data)
882 : {
883 : session_req_worker_update_msg_t *msg;
884 : vcl_session_t *s;
885 :
886 0 : msg = (session_req_worker_update_msg_t *) data;
887 0 : s = vcl_session_get_w_vpp_handle (wrk, msg->session_handle);
888 0 : if (!s)
889 0 : return;
890 :
891 0 : vec_add1 (wrk->pending_session_wrk_updates, s->session_index);
892 : }
893 :
894 : static void
895 0 : vcl_session_worker_update_reply_handler (vcl_worker_t * wrk, void *data)
896 : {
897 : session_worker_update_reply_msg_t *msg;
898 : vcl_session_t *s;
899 :
900 0 : msg = (session_worker_update_reply_msg_t *) data;
901 0 : s = vcl_session_get_w_vpp_handle (wrk, msg->handle);
902 0 : if (!s)
903 : {
904 0 : VDBG (0, "unknown handle 0x%llx", msg->handle);
905 0 : return;
906 : }
907 :
908 0 : if (s->rx_fifo)
909 : {
910 0 : if (vcl_segment_attach_session (msg->segment_handle, msg->rx_fifo,
911 : msg->tx_fifo, (uword) ~0, ~0, 0, s))
912 : {
913 0 : VDBG (0, "failed to attach fifos for %u", s->session_index);
914 0 : return;
915 : }
916 : }
917 0 : s->session_state = VCL_STATE_UPDATED;
918 :
919 0 : VDBG (0, "session %u[0x%llx] moved to worker %u", s->session_index,
920 : s->vpp_handle, wrk->wrk_index);
921 : }
922 :
923 : static int
924 37 : vcl_api_recv_fd (vcl_worker_t * wrk, int *fds, int n_fds)
925 : {
926 :
927 37 : if (vcm->cfg.vpp_app_socket_api)
928 7 : return vcl_sapi_recv_fds (wrk, fds, n_fds);
929 :
930 30 : return vcl_bapi_recv_fds (wrk, fds, n_fds);
931 : }
932 :
933 : static void
934 37 : vcl_session_app_add_segment_handler (vcl_worker_t * wrk, void *data)
935 : {
936 37 : ssvm_segment_type_t seg_type = SSVM_SEGMENT_SHM;
937 : session_app_add_segment_msg_t *msg;
938 : u64 segment_handle;
939 37 : int fd = -1;
940 :
941 37 : msg = (session_app_add_segment_msg_t *) data;
942 :
943 37 : if (msg->fd_flags)
944 : {
945 37 : vcl_api_recv_fd (wrk, &fd, 1);
946 37 : seg_type = SSVM_SEGMENT_MEMFD;
947 : }
948 :
949 37 : segment_handle = msg->segment_handle;
950 37 : if (segment_handle == VCL_INVALID_SEGMENT_HANDLE)
951 : {
952 0 : clib_warning ("invalid segment handle");
953 0 : return;
954 : }
955 :
956 37 : if (vcl_segment_attach (segment_handle, (char *) msg->segment_name,
957 : seg_type, fd))
958 : {
959 0 : VDBG (0, "vcl_segment_attach ('%s') failed", msg->segment_name);
960 0 : return;
961 : }
962 :
963 37 : VDBG (1, "mapped new segment '%s' size %d", msg->segment_name,
964 : msg->segment_size);
965 : }
966 :
967 : static void
968 4 : vcl_session_app_del_segment_handler (vcl_worker_t * wrk, void *data)
969 : {
970 4 : session_app_del_segment_msg_t *msg = (session_app_del_segment_msg_t *) data;
971 4 : vcl_segment_detach (msg->segment_handle);
972 4 : VDBG (1, "Unmapped segment: %lx", msg->segment_handle);
973 4 : }
974 :
975 : static void
976 0 : vcl_worker_rpc_handler (vcl_worker_t * wrk, void *data)
977 : {
978 0 : if (!vcm->wrk_rpc_fn)
979 0 : return;
980 :
981 0 : (vcm->wrk_rpc_fn) (((session_app_wrk_rpc_msg_t *) data)->data);
982 : }
983 :
984 : static void
985 5 : vcl_session_transport_attr_reply_handler (vcl_worker_t *wrk, void *data)
986 : {
987 : session_transport_attr_reply_msg_t *mp;
988 :
989 5 : if (!wrk->session_attr_op)
990 0 : return;
991 :
992 5 : mp = (session_transport_attr_reply_msg_t *) data;
993 :
994 5 : wrk->session_attr_op_rv = mp->retval;
995 5 : wrk->session_attr_op = 0;
996 5 : wrk->session_attr_rv = mp->attr;
997 : }
998 :
999 : static int
1000 223 : vcl_handle_mq_event (vcl_worker_t * wrk, session_event_t * e)
1001 : {
1002 : session_disconnected_msg_t *disconnected_msg;
1003 : session_connected_msg_t *connected_msg;
1004 : session_reset_msg_t *reset_msg;
1005 : session_event_t *ecpy;
1006 : vcl_session_t *s;
1007 : u32 sid;
1008 :
1009 223 : switch (e->event_type)
1010 : {
1011 94 : case SESSION_IO_EVT_RX:
1012 : case SESSION_IO_EVT_TX:
1013 94 : s = vcl_session_get (wrk, e->session_index);
1014 94 : if (!s || !vcl_session_is_open (s))
1015 : break;
1016 88 : vec_add1 (wrk->unhandled_evts_vector, *e);
1017 88 : break;
1018 40 : case SESSION_CTRL_EVT_BOUND:
1019 : /* We can only wait for only one listen so not postponed */
1020 40 : vcl_session_bound_handler (wrk, (session_bound_msg_t *) e->data);
1021 40 : break;
1022 0 : case SESSION_CTRL_EVT_ACCEPTED:
1023 0 : s = vcl_session_accepted (wrk, (session_accepted_msg_t *) e->data);
1024 0 : if (vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK))
1025 : {
1026 0 : vec_add2 (wrk->unhandled_evts_vector, ecpy, 1);
1027 0 : *ecpy = *e;
1028 0 : ecpy->postponed = 1;
1029 0 : ecpy->session_index = s->session_index;
1030 : }
1031 0 : break;
1032 47 : case SESSION_CTRL_EVT_CONNECTED:
1033 47 : connected_msg = (session_connected_msg_t *) e->data;
1034 47 : sid = vcl_session_connected_handler (wrk, connected_msg);
1035 47 : if (!(s = vcl_session_get (wrk, sid)))
1036 0 : break;
1037 47 : if (vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK))
1038 : {
1039 0 : vec_add2 (wrk->unhandled_evts_vector, ecpy, 1);
1040 0 : *ecpy = *e;
1041 0 : ecpy->postponed = 1;
1042 0 : ecpy->session_index = s->session_index;
1043 : }
1044 47 : break;
1045 1 : case SESSION_CTRL_EVT_DISCONNECTED:
1046 1 : disconnected_msg = (session_disconnected_msg_t *) e->data;
1047 1 : if (!(s = vcl_session_get_w_vpp_handle (wrk, disconnected_msg->handle)))
1048 0 : break;
1049 1 : if (s->session_state == VCL_STATE_CLOSED)
1050 0 : break;
1051 1 : if (vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK))
1052 : {
1053 0 : s->session_state = VCL_STATE_VPP_CLOSING;
1054 0 : s->flags |= VCL_SESSION_F_PENDING_DISCONNECT;
1055 0 : vec_add2 (wrk->unhandled_evts_vector, ecpy, 1);
1056 0 : *ecpy = *e;
1057 0 : ecpy->postponed = 1;
1058 0 : ecpy->session_index = s->session_index;
1059 0 : break;
1060 : }
1061 1 : if (!(s = vcl_session_disconnected_handler (wrk, disconnected_msg)))
1062 0 : break;
1063 1 : VDBG (0, "disconnected session %u [0x%llx]", s->session_index,
1064 : s->vpp_handle);
1065 1 : break;
1066 3 : case SESSION_CTRL_EVT_RESET:
1067 3 : reset_msg = (session_reset_msg_t *) e->data;
1068 3 : if (!(s = vcl_session_get_w_vpp_handle (wrk, reset_msg->handle)))
1069 0 : break;
1070 3 : if (s->session_state == VCL_STATE_CLOSED)
1071 0 : break;
1072 3 : if (vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK))
1073 : {
1074 0 : s->flags |= VCL_SESSION_F_PENDING_DISCONNECT;
1075 0 : s->session_state = VCL_STATE_DISCONNECT;
1076 0 : s->flags |= (VCL_SESSION_F_RD_SHUTDOWN | VCL_SESSION_F_WR_SHUTDOWN);
1077 0 : vec_add2 (wrk->unhandled_evts_vector, ecpy, 1);
1078 0 : *ecpy = *e;
1079 0 : ecpy->postponed = 1;
1080 0 : ecpy->session_index = s->session_index;
1081 0 : break;
1082 : }
1083 3 : vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data);
1084 3 : break;
1085 9 : case SESSION_CTRL_EVT_UNLISTEN_REPLY:
1086 9 : vcl_session_unlisten_reply_handler (wrk, e->data);
1087 9 : break;
1088 0 : case SESSION_CTRL_EVT_MIGRATED:
1089 0 : vcl_session_migrated_handler (wrk, e->data);
1090 0 : break;
1091 11 : case SESSION_CTRL_EVT_CLEANUP:
1092 11 : vcl_session_cleanup_handler (wrk, e->data);
1093 11 : break;
1094 0 : case SESSION_CTRL_EVT_REQ_WORKER_UPDATE:
1095 0 : vcl_session_req_worker_update_handler (wrk, e->data);
1096 0 : break;
1097 0 : case SESSION_CTRL_EVT_WORKER_UPDATE_REPLY:
1098 0 : vcl_session_worker_update_reply_handler (wrk, e->data);
1099 0 : break;
1100 11 : case SESSION_CTRL_EVT_APP_ADD_SEGMENT:
1101 11 : vcl_session_app_add_segment_handler (wrk, e->data);
1102 11 : break;
1103 2 : case SESSION_CTRL_EVT_APP_DEL_SEGMENT:
1104 2 : vcl_session_app_del_segment_handler (wrk, e->data);
1105 2 : break;
1106 0 : case SESSION_CTRL_EVT_APP_WRK_RPC:
1107 0 : vcl_worker_rpc_handler (wrk, e->data);
1108 0 : break;
1109 5 : case SESSION_CTRL_EVT_TRANSPORT_ATTR_REPLY:
1110 5 : vcl_session_transport_attr_reply_handler (wrk, e->data);
1111 5 : break;
1112 0 : default:
1113 0 : clib_warning ("unhandled %u", e->event_type);
1114 : }
1115 223 : return VPPCOM_OK;
1116 : }
1117 :
1118 : static int
1119 87 : vppcom_wait_for_session_state_change (u32 session_index,
1120 : vcl_session_state_t state,
1121 : f64 wait_for_time)
1122 : {
1123 87 : vcl_worker_t *wrk = vcl_worker_get_current ();
1124 87 : f64 timeout = clib_time_now (&wrk->clib_time) + wait_for_time;
1125 : vcl_session_t *volatile session;
1126 : svm_msg_q_msg_t msg;
1127 : session_event_t *e;
1128 :
1129 : do
1130 : {
1131 1400 : session = vcl_session_get (wrk, session_index);
1132 1400 : if (PREDICT_FALSE (!session))
1133 : {
1134 0 : return VPPCOM_EBADFD;
1135 : }
1136 1400 : if (session->session_state == state)
1137 : {
1138 87 : return VPPCOM_OK;
1139 : }
1140 1313 : if (session->session_state == VCL_STATE_DETACHED)
1141 : {
1142 0 : return VPPCOM_ECONNREFUSED;
1143 : }
1144 :
1145 1313 : if (svm_msg_q_sub (wrk->app_event_queue, &msg, SVM_Q_NOWAIT, 0))
1146 : {
1147 1194 : usleep (100);
1148 1194 : continue;
1149 : }
1150 119 : e = svm_msg_q_msg_data (wrk->app_event_queue, &msg);
1151 119 : vcl_handle_mq_event (wrk, e);
1152 119 : svm_msg_q_free_msg (wrk->app_event_queue, &msg);
1153 : }
1154 1313 : while (clib_time_now (&wrk->clib_time) < timeout);
1155 :
1156 0 : VDBG (0, "timeout waiting for state 0x%x (%s)", state,
1157 : vcl_session_state_str (state));
1158 : vcl_evt (VCL_EVT_SESSION_TIMEOUT, session, session_state);
1159 :
1160 0 : return VPPCOM_ETIMEDOUT;
1161 : }
1162 :
1163 : static void
1164 111766 : vcl_handle_pending_wrk_updates (vcl_worker_t * wrk)
1165 : {
1166 : vcl_session_state_t state;
1167 : vcl_session_t *s;
1168 : u32 *sip;
1169 :
1170 111766 : if (PREDICT_TRUE (vec_len (wrk->pending_session_wrk_updates) == 0))
1171 111766 : return;
1172 :
1173 0 : vec_foreach (sip, wrk->pending_session_wrk_updates)
1174 : {
1175 0 : s = vcl_session_get (wrk, *sip);
1176 0 : vcl_send_session_worker_update (wrk, s, wrk->wrk_index);
1177 0 : state = s->session_state;
1178 0 : vppcom_wait_for_session_state_change (s->session_index, VCL_STATE_UPDATED,
1179 : 5);
1180 0 : s->session_state = state;
1181 : }
1182 0 : vec_reset_length (wrk->pending_session_wrk_updates);
1183 : }
1184 :
1185 : void
1186 1445 : vcl_worker_flush_mq_events (vcl_worker_t *wrk)
1187 : {
1188 : svm_msg_q_msg_t *msg;
1189 : session_event_t *e;
1190 : svm_msg_q_t *mq;
1191 : int i;
1192 :
1193 1445 : mq = wrk->app_event_queue;
1194 1445 : vcl_mq_dequeue_batch (wrk, mq, ~0);
1195 :
1196 1549 : for (i = 0; i < vec_len (wrk->mq_msg_vector); i++)
1197 : {
1198 104 : msg = vec_elt_at_index (wrk->mq_msg_vector, i);
1199 104 : e = svm_msg_q_msg_data (mq, msg);
1200 104 : vcl_handle_mq_event (wrk, e);
1201 104 : svm_msg_q_free_msg (mq, msg);
1202 : }
1203 1445 : vec_reset_length (wrk->mq_msg_vector);
1204 1445 : vcl_handle_pending_wrk_updates (wrk);
1205 1445 : }
1206 :
1207 : void
1208 1350 : vcl_flush_mq_events (void)
1209 : {
1210 1350 : vcl_worker_flush_mq_events (vcl_worker_get_current ());
1211 1350 : }
1212 :
1213 : static int
1214 21 : vppcom_session_unbind (u32 session_handle)
1215 : {
1216 21 : vcl_worker_t *wrk = vcl_worker_get_current ();
1217 : session_accepted_msg_t *accepted_msg;
1218 21 : vcl_session_t *session = 0;
1219 : vcl_session_msg_t *evt;
1220 :
1221 21 : session = vcl_session_get_w_handle (wrk, session_handle);
1222 21 : if (!session)
1223 0 : return VPPCOM_EBADFD;
1224 :
1225 : /* Flush pending accept events, if any */
1226 21 : while (clib_fifo_elts (session->accept_evts_fifo))
1227 : {
1228 0 : clib_fifo_sub2 (session->accept_evts_fifo, evt);
1229 0 : accepted_msg = &evt->accepted_msg;
1230 0 : vcl_session_table_del_vpp_handle (wrk, accepted_msg->handle);
1231 0 : vcl_send_session_accepted_reply (session->vpp_evt_q,
1232 : accepted_msg->context,
1233 : accepted_msg->handle, -1);
1234 : }
1235 21 : clib_fifo_free (session->accept_evts_fifo);
1236 :
1237 21 : vcl_send_session_unlisten (wrk, session);
1238 :
1239 21 : VDBG (0, "session %u [0x%llx]: sending unbind!", session->session_index,
1240 : session->vpp_handle);
1241 : vcl_evt (VCL_EVT_UNBIND, session);
1242 :
1243 21 : session->vpp_handle = ~0;
1244 21 : session->session_state = VCL_STATE_DISCONNECT;
1245 :
1246 21 : return VPPCOM_OK;
1247 : }
1248 :
1249 : /**
1250 : * Handle app exit
1251 : *
1252 : * Notify vpp of the disconnect and mark the worker as free. If we're the
1253 : * last worker, do a full cleanup otherwise, since we're probably a forked
1254 : * child, avoid syscalls as much as possible. We might've lost privileges.
1255 : */
1256 : void
1257 37 : vppcom_app_exit (void)
1258 : {
1259 37 : if (!pool_elts (vcm->workers))
1260 24 : return;
1261 13 : vcl_worker_cleanup (vcl_worker_get_current (), 1 /* notify vpp */ );
1262 13 : vcl_set_worker_index (~0);
1263 : vcl_elog_stop (vcm);
1264 : }
1265 :
1266 : static int
1267 37 : vcl_api_attach (void)
1268 : {
1269 37 : if (vcm->cfg.vpp_app_socket_api)
1270 8 : return vcl_sapi_attach ();
1271 :
1272 29 : return vcl_bapi_attach ();
1273 : }
1274 :
1275 : int
1276 0 : vcl_is_first_reattach_to_execute ()
1277 : {
1278 0 : if (vcm->reattach_count == 0)
1279 0 : return 1;
1280 :
1281 0 : return 0;
1282 : }
1283 :
1284 : void
1285 0 : vcl_set_reattach_counter ()
1286 : {
1287 0 : ++vcm->reattach_count;
1288 :
1289 0 : if (vcm->reattach_count == vec_len (vcm->workers))
1290 0 : vcm->reattach_count = 0;
1291 0 : }
1292 :
1293 : /**
1294 : * Reattach vcl to vpp after it has previously been disconnected.
1295 : *
1296 : * The logic should be:
1297 : * - first worker to hit `vcl_api_retry_attach` should attach to vpp,
1298 : * to reproduce the `vcl_api_attach` in `vppcom_app_create`.
1299 : * - the rest of the workers should `reproduce vcl_worker_register_with_vpp`
1300 : * from `vppcom_worker_register` since they were already allocated.
1301 : */
1302 :
1303 : static void
1304 0 : vcl_api_retry_attach (vcl_worker_t *wrk)
1305 : {
1306 : vcl_session_t *s;
1307 :
1308 0 : clib_spinlock_lock (&vcm->workers_lock);
1309 0 : if (vcl_is_first_reattach_to_execute ())
1310 : {
1311 0 : if (vcl_api_attach ())
1312 : {
1313 0 : clib_spinlock_unlock (&vcm->workers_lock);
1314 0 : return;
1315 : }
1316 0 : vcl_set_reattach_counter ();
1317 0 : clib_spinlock_unlock (&vcm->workers_lock);
1318 : }
1319 : else
1320 : {
1321 0 : vcl_set_reattach_counter ();
1322 0 : clib_spinlock_unlock (&vcm->workers_lock);
1323 0 : vcl_worker_register_with_vpp ();
1324 : }
1325 :
1326 : /* Treat listeners as configuration that needs to be re-added to vpp */
1327 0 : pool_foreach (s, wrk->sessions)
1328 : {
1329 0 : if (s->flags & VCL_SESSION_F_IS_VEP)
1330 0 : continue;
1331 0 : if (s->session_state == VCL_STATE_LISTEN_NO_MQ)
1332 0 : vppcom_session_listen (vcl_session_handle (s), 10);
1333 : else
1334 0 : VDBG (0, "internal error: unexpected state %d", s->session_state);
1335 : }
1336 : }
1337 :
1338 : static void
1339 0 : vcl_api_handle_disconnect (vcl_worker_t *wrk)
1340 : {
1341 0 : wrk->api_client_handle = ~0;
1342 0 : vcl_worker_detach_sessions (wrk);
1343 0 : }
1344 :
1345 : static void
1346 24 : vcl_api_detach (vcl_worker_t * wrk)
1347 : {
1348 24 : if (wrk->api_client_handle == ~0)
1349 0 : return;
1350 :
1351 24 : vcl_send_app_detach (wrk);
1352 :
1353 24 : if (vcm->cfg.vpp_app_socket_api)
1354 6 : return vcl_sapi_detach (wrk);
1355 :
1356 18 : return vcl_bapi_disconnect_from_vpp ();
1357 : }
1358 :
1359 : /*
1360 : * VPPCOM Public API functions
1361 : */
1362 : int
1363 37 : vppcom_app_create (const char *app_name)
1364 : {
1365 37 : vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1366 : int rv;
1367 :
1368 37 : if (vcm->is_init)
1369 : {
1370 0 : VDBG (1, "already initialized");
1371 0 : return VPPCOM_EEXIST;
1372 : }
1373 :
1374 37 : vcm->is_init = 1;
1375 37 : vppcom_cfg (&vcm->cfg);
1376 37 : vcl_cfg = &vcm->cfg;
1377 :
1378 37 : vcm->main_cpu = pthread_self ();
1379 37 : vcm->main_pid = getpid ();
1380 37 : vcm->app_name = format (0, "%s", app_name);
1381 37 : fifo_segment_main_init (&vcm->segment_main, (uword) ~0,
1382 : 20 /* timeout in secs */);
1383 37 : pool_alloc (vcm->workers, vcl_cfg->max_workers);
1384 37 : clib_spinlock_init (&vcm->workers_lock);
1385 37 : clib_rwlock_init (&vcm->segment_table_lock);
1386 37 : atexit (vppcom_app_exit);
1387 : vcl_elog_init (vcm);
1388 :
1389 : /* Allocate default worker */
1390 37 : vcl_worker_alloc_and_init ();
1391 :
1392 37 : if ((rv = vcl_api_attach ()))
1393 : {
1394 0 : vppcom_app_destroy ();
1395 0 : return rv;
1396 : }
1397 :
1398 37 : VDBG (0, "app_name '%s', my_client_index %d (0x%x)", app_name,
1399 : vcm->workers[0].api_client_handle, vcm->workers[0].api_client_handle);
1400 :
1401 37 : return VPPCOM_OK;
1402 : }
1403 :
1404 : void
1405 24 : vppcom_app_destroy (void)
1406 : {
1407 : vcl_worker_t *wrk, *current_wrk;
1408 : void *heap;
1409 :
1410 24 : if (!pool_elts (vcm->workers))
1411 0 : return;
1412 :
1413 : vcl_evt (VCL_EVT_DETACH, vcm);
1414 :
1415 24 : current_wrk = vcl_worker_get_current ();
1416 :
1417 : /* *INDENT-OFF* */
1418 48 : pool_foreach (wrk, vcm->workers) {
1419 24 : if (current_wrk != wrk)
1420 0 : vcl_worker_cleanup (wrk, 0 /* notify vpp */ );
1421 : }
1422 : /* *INDENT-ON* */
1423 :
1424 24 : vcl_api_detach (current_wrk);
1425 24 : vcl_worker_cleanup (current_wrk, 0 /* notify vpp */ );
1426 24 : vcl_set_worker_index (~0);
1427 :
1428 : vcl_elog_stop (vcm);
1429 :
1430 : /*
1431 : * Free the heap and fix vcm
1432 : */
1433 24 : heap = clib_mem_get_heap ();
1434 24 : munmap (clib_mem_get_heap_base (heap), clib_mem_get_heap_size (heap));
1435 :
1436 24 : vcm = &_vppcom_main;
1437 24 : vcm->is_init = 0;
1438 : }
1439 :
1440 : int
1441 85 : vppcom_session_create (u8 proto, u8 is_nonblocking)
1442 : {
1443 85 : vcl_worker_t *wrk = vcl_worker_get_current ();
1444 : vcl_session_t *session;
1445 :
1446 85 : session = vcl_session_alloc (wrk);
1447 :
1448 85 : session->session_type = proto;
1449 85 : session->session_state = VCL_STATE_CLOSED;
1450 85 : session->vpp_handle = ~0;
1451 85 : session->is_dgram = vcl_proto_is_dgram (proto);
1452 85 : session->vpp_error = SESSION_E_NONE;
1453 :
1454 85 : if (is_nonblocking)
1455 12 : vcl_session_set_attr (session, VCL_SESS_ATTR_NONBLOCK);
1456 :
1457 : vcl_evt (VCL_EVT_CREATE, session, session_type, session->session_state,
1458 : is_nonblocking, session_index);
1459 :
1460 85 : VDBG (0, "created session %u", session->session_index);
1461 :
1462 85 : return vcl_session_handle (session);
1463 : }
1464 :
1465 : static void
1466 0 : vcl_epoll_lt_add (vcl_worker_t *wrk, vcl_session_t *s)
1467 : {
1468 : vcl_session_t *cur, *prev;
1469 :
1470 0 : ASSERT (s->vep.lt_next == VCL_INVALID_SESSION_INDEX);
1471 :
1472 0 : if (wrk->ep_lt_current == VCL_INVALID_SESSION_INDEX)
1473 : {
1474 0 : wrk->ep_lt_current = s->session_index;
1475 0 : s->vep.lt_next = s->session_index;
1476 0 : s->vep.lt_prev = s->session_index;
1477 0 : return;
1478 : }
1479 :
1480 0 : cur = vcl_session_get (wrk, wrk->ep_lt_current);
1481 0 : prev = vcl_session_get (wrk, cur->vep.lt_prev);
1482 :
1483 0 : prev->vep.lt_next = s->session_index;
1484 0 : s->vep.lt_prev = prev->session_index;
1485 :
1486 0 : s->vep.lt_next = cur->session_index;
1487 0 : cur->vep.lt_prev = s->session_index;
1488 : }
1489 :
1490 : static void
1491 0 : vcl_epoll_lt_del (vcl_worker_t *wrk, vcl_session_t *s)
1492 : {
1493 : vcl_session_t *prev, *next;
1494 :
1495 0 : ASSERT (s->vep.lt_next != VCL_INVALID_SESSION_INDEX);
1496 :
1497 0 : if (s->vep.lt_next == s->session_index)
1498 : {
1499 0 : wrk->ep_lt_current = VCL_INVALID_SESSION_INDEX;
1500 0 : s->vep.lt_next = VCL_INVALID_SESSION_INDEX;
1501 0 : s->vep.lt_prev = VCL_INVALID_SESSION_INDEX;
1502 0 : return;
1503 : }
1504 :
1505 0 : prev = vcl_session_get (wrk, s->vep.lt_prev);
1506 0 : next = vcl_session_get (wrk, s->vep.lt_next);
1507 :
1508 0 : prev->vep.lt_next = next->session_index;
1509 0 : next->vep.lt_prev = prev->session_index;
1510 :
1511 0 : if (s->session_index == wrk->ep_lt_current)
1512 0 : wrk->ep_lt_current = s->vep.lt_next;
1513 :
1514 0 : s->vep.lt_next = VCL_INVALID_SESSION_INDEX;
1515 0 : s->vep.lt_prev = VCL_INVALID_SESSION_INDEX;
1516 : }
1517 :
1518 : int
1519 87 : vcl_session_cleanup (vcl_worker_t * wrk, vcl_session_t * s,
1520 : vcl_session_handle_t sh, u8 do_disconnect)
1521 : {
1522 87 : int rv = VPPCOM_OK;
1523 :
1524 87 : VDBG (1, "session %u [0x%llx] closing", s->session_index, s->vpp_handle);
1525 :
1526 87 : if (s->flags & VCL_SESSION_F_IS_VEP)
1527 : {
1528 0 : u32 next_sh = s->vep.next_sh;
1529 0 : while (next_sh != ~0)
1530 : {
1531 0 : rv = vppcom_epoll_ctl (sh, EPOLL_CTL_DEL, next_sh, 0);
1532 0 : if (PREDICT_FALSE (rv < 0))
1533 0 : VDBG (0, "vpp handle 0x%llx, sh %u: EPOLL_CTL_DEL vep_idx %u"
1534 : " failed! rv %d (%s)", s->vpp_handle, next_sh,
1535 : s->vep.vep_sh, rv, vppcom_retval_str (rv));
1536 0 : next_sh = s->vep.next_sh;
1537 : }
1538 0 : goto free_session;
1539 : }
1540 :
1541 87 : if (s->flags & VCL_SESSION_F_IS_VEP_SESSION)
1542 : {
1543 41 : rv = vppcom_epoll_ctl (s->vep.vep_sh, EPOLL_CTL_DEL, sh, 0);
1544 41 : if (rv < 0)
1545 0 : VDBG (0, "session %u [0x%llx]: EPOLL_CTL_DEL vep_idx %u "
1546 : "failed! rv %d (%s)", s->session_index, s->vpp_handle,
1547 : s->vep.vep_sh, rv, vppcom_retval_str (rv));
1548 : }
1549 :
1550 87 : if (!do_disconnect)
1551 : {
1552 0 : VDBG (1, "session %u [0x%llx] disconnect skipped",
1553 : s->session_index, s->vpp_handle);
1554 0 : goto cleanup;
1555 : }
1556 :
1557 87 : if (s->session_state == VCL_STATE_LISTEN)
1558 : {
1559 21 : rv = vppcom_session_unbind (sh);
1560 21 : if (PREDICT_FALSE (rv < 0))
1561 0 : VDBG (0, "session %u [0x%llx]: listener unbind failed! "
1562 : "rv %d (%s)", s->session_index, s->vpp_handle, rv,
1563 : vppcom_retval_str (rv));
1564 21 : return rv;
1565 : }
1566 66 : else if (vcl_session_is_ready (s)
1567 4 : || (vcl_session_is_connectable_listener (wrk, s)))
1568 : {
1569 62 : rv = vppcom_session_disconnect (sh);
1570 62 : if (PREDICT_FALSE (rv < 0))
1571 0 : VDBG (0, "ERROR: session %u [0x%llx]: disconnect failed!"
1572 : " rv %d (%s)", s->session_index, s->vpp_handle,
1573 : rv, vppcom_retval_str (rv));
1574 : }
1575 4 : else if (s->session_state == VCL_STATE_DISCONNECT)
1576 : {
1577 4 : vcl_send_session_reset_reply (wrk, s, 0);
1578 : }
1579 0 : else if (s->session_state == VCL_STATE_DETACHED)
1580 : {
1581 0 : VDBG (0, "vpp freed session %d before close", s->session_index);
1582 :
1583 0 : if (!(s->flags & VCL_SESSION_F_PENDING_DISCONNECT))
1584 0 : goto free_session;
1585 :
1586 : /* Disconnect/reset messages pending but vpp transport and session
1587 : * cleanups already done. Free only after messages drained. */
1588 0 : s->flags |= VCL_SESSION_F_PENDING_FREE;
1589 : }
1590 :
1591 66 : s->session_state = VCL_STATE_CLOSED;
1592 :
1593 : /* Session is removed only after vpp confirms the disconnect */
1594 66 : return rv;
1595 :
1596 0 : cleanup:
1597 0 : vcl_session_table_del_vpp_handle (wrk, s->vpp_handle);
1598 0 : free_session:
1599 0 : vcl_session_free (wrk, s);
1600 : vcl_evt (VCL_EVT_CLOSE, s, rv);
1601 :
1602 0 : return rv;
1603 : }
1604 :
1605 : int
1606 87 : vppcom_session_close (uint32_t session_handle)
1607 : {
1608 87 : vcl_worker_t *wrk = vcl_worker_get_current ();
1609 : vcl_session_t *session;
1610 :
1611 87 : session = vcl_session_get_w_handle (wrk, session_handle);
1612 87 : if (!session)
1613 0 : return VPPCOM_EBADFD;
1614 87 : return vcl_session_cleanup (wrk, session, session_handle,
1615 : 1 /* do_disconnect */ );
1616 : }
1617 :
1618 : int
1619 40 : vppcom_session_bind (uint32_t session_handle, vppcom_endpt_t * ep)
1620 : {
1621 40 : vcl_worker_t *wrk = vcl_worker_get_current ();
1622 40 : vcl_session_t *session = 0;
1623 :
1624 40 : if (!ep || !ep->ip)
1625 0 : return VPPCOM_EINVAL;
1626 :
1627 40 : session = vcl_session_get_w_handle (wrk, session_handle);
1628 40 : if (!session)
1629 0 : return VPPCOM_EBADFD;
1630 :
1631 40 : if (session->flags & VCL_SESSION_F_IS_VEP)
1632 : {
1633 0 : VDBG (0, "ERROR: cannot bind to epoll session %u!",
1634 : session->session_index);
1635 0 : return VPPCOM_EBADFD;
1636 : }
1637 :
1638 40 : session->transport.is_ip4 = ep->is_ip4;
1639 40 : if (ep->is_ip4)
1640 34 : clib_memcpy_fast (&session->transport.lcl_ip.ip4, ep->ip,
1641 : sizeof (ip4_address_t));
1642 : else
1643 6 : clib_memcpy_fast (&session->transport.lcl_ip.ip6, ep->ip,
1644 : sizeof (ip6_address_t));
1645 40 : session->transport.lcl_port = ep->port;
1646 :
1647 40 : VDBG (0,
1648 : "session %u handle %u: binding to local %s address %U port %u, "
1649 : "proto %s",
1650 : session->session_index, session_handle,
1651 : session->transport.is_ip4 ? "IPv4" : "IPv6", vcl_format_ip46_address,
1652 : &session->transport.lcl_ip,
1653 : session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1654 : clib_net_to_host_u16 (session->transport.lcl_port),
1655 : vppcom_proto_str (session->session_type));
1656 : vcl_evt (VCL_EVT_BIND, session);
1657 :
1658 40 : if (session->session_type == VPPCOM_PROTO_UDP)
1659 3 : vppcom_session_listen (session_handle, 10);
1660 :
1661 40 : return VPPCOM_OK;
1662 : }
1663 :
1664 : int
1665 40 : vppcom_session_listen (uint32_t listen_sh, uint32_t q_len)
1666 : {
1667 40 : vcl_worker_t *wrk = vcl_worker_get_current ();
1668 40 : vcl_session_t *listen_session = 0;
1669 : u64 listen_vpp_handle;
1670 : int rv;
1671 :
1672 40 : listen_session = vcl_session_get_w_handle (wrk, listen_sh);
1673 40 : if (!listen_session || (listen_session->flags & VCL_SESSION_F_IS_VEP))
1674 0 : return VPPCOM_EBADFD;
1675 :
1676 40 : listen_vpp_handle = listen_session->vpp_handle;
1677 40 : if (listen_session->session_state == VCL_STATE_LISTEN)
1678 : {
1679 0 : VDBG (0, "session %u [0x%llx]: already in listen state!",
1680 : listen_sh, listen_vpp_handle);
1681 0 : return VPPCOM_OK;
1682 : }
1683 :
1684 40 : VDBG (0, "session %u: sending vpp listen request...", listen_sh);
1685 :
1686 : /*
1687 : * Send listen request to vpp and wait for reply
1688 : */
1689 40 : vcl_send_session_listen (wrk, listen_session);
1690 40 : rv = vppcom_wait_for_session_state_change (listen_session->session_index,
1691 : VCL_STATE_LISTEN,
1692 40 : vcm->cfg.session_timeout);
1693 :
1694 40 : if (PREDICT_FALSE (rv))
1695 : {
1696 0 : listen_session = vcl_session_get_w_handle (wrk, listen_sh);
1697 0 : VDBG (0, "session %u [0x%llx]: listen failed! returning %d (%s)",
1698 : listen_sh, listen_session->vpp_handle, rv,
1699 : vppcom_retval_str (rv));
1700 0 : return rv;
1701 : }
1702 :
1703 40 : return VPPCOM_OK;
1704 : }
1705 :
1706 : int
1707 2 : vppcom_unformat_proto (uint8_t * proto, char *proto_str)
1708 : {
1709 2 : if (!strcmp (proto_str, "TCP"))
1710 0 : *proto = VPPCOM_PROTO_TCP;
1711 2 : else if (!strcmp (proto_str, "tcp"))
1712 0 : *proto = VPPCOM_PROTO_TCP;
1713 2 : else if (!strcmp (proto_str, "UDP"))
1714 0 : *proto = VPPCOM_PROTO_UDP;
1715 2 : else if (!strcmp (proto_str, "udp"))
1716 0 : *proto = VPPCOM_PROTO_UDP;
1717 2 : else if (!strcmp (proto_str, "TLS"))
1718 0 : *proto = VPPCOM_PROTO_TLS;
1719 2 : else if (!strcmp (proto_str, "tls"))
1720 0 : *proto = VPPCOM_PROTO_TLS;
1721 2 : else if (!strcmp (proto_str, "QUIC"))
1722 0 : *proto = VPPCOM_PROTO_QUIC;
1723 2 : else if (!strcmp (proto_str, "quic"))
1724 0 : *proto = VPPCOM_PROTO_QUIC;
1725 2 : else if (!strcmp (proto_str, "DTLS"))
1726 0 : *proto = VPPCOM_PROTO_DTLS;
1727 2 : else if (!strcmp (proto_str, "dtls"))
1728 2 : *proto = VPPCOM_PROTO_DTLS;
1729 0 : else if (!strcmp (proto_str, "SRTP"))
1730 0 : *proto = VPPCOM_PROTO_SRTP;
1731 0 : else if (!strcmp (proto_str, "srtp"))
1732 0 : *proto = VPPCOM_PROTO_SRTP;
1733 : else
1734 0 : return 1;
1735 2 : return 0;
1736 : }
1737 :
1738 : int
1739 37 : vppcom_session_accept (uint32_t ls_handle, vppcom_endpt_t *ep, uint32_t flags)
1740 : {
1741 37 : u32 client_session_index = ~0, ls_index, accept_flags = 0;
1742 37 : vcl_worker_t *wrk = vcl_worker_get_current ();
1743 : session_accepted_msg_t accepted_msg;
1744 37 : vcl_session_t *ls, *client_session = 0;
1745 : vcl_session_msg_t *evt;
1746 : u8 is_nonblocking;
1747 :
1748 37 : again:
1749 :
1750 37 : ls = vcl_session_get_w_handle (wrk, ls_handle);
1751 37 : if (!ls)
1752 0 : return VPPCOM_EBADFD;
1753 :
1754 37 : if ((ls->session_state != VCL_STATE_LISTEN) &&
1755 0 : (ls->session_state != VCL_STATE_LISTEN_NO_MQ) &&
1756 0 : (!vcl_session_is_connectable_listener (wrk, ls)))
1757 : {
1758 0 : VDBG (0, "ERROR: session [0x%llx]: not in listen state! state (%s)",
1759 : ls->vpp_handle, vcl_session_state_str (ls->session_state));
1760 0 : return VPPCOM_EBADFD;
1761 : }
1762 :
1763 37 : ls_index = ls->session_index;
1764 :
1765 37 : if (clib_fifo_elts (ls->accept_evts_fifo))
1766 : {
1767 37 : clib_fifo_sub2 (ls->accept_evts_fifo, evt);
1768 37 : accept_flags = evt->flags;
1769 37 : accepted_msg = evt->accepted_msg;
1770 37 : goto handle;
1771 : }
1772 :
1773 0 : is_nonblocking = vcl_session_has_attr (ls, VCL_SESS_ATTR_NONBLOCK);
1774 : while (1)
1775 : {
1776 0 : if (svm_msg_q_is_empty (wrk->app_event_queue) && is_nonblocking)
1777 0 : return VPPCOM_EAGAIN;
1778 :
1779 0 : svm_msg_q_wait (wrk->app_event_queue, SVM_MQ_WAIT_EMPTY);
1780 0 : vcl_worker_flush_mq_events (wrk);
1781 0 : goto again;
1782 : }
1783 :
1784 37 : handle:
1785 :
1786 : client_session_index =
1787 37 : vcl_session_accepted_handler (wrk, &accepted_msg, ls_index);
1788 37 : if (client_session_index == VCL_INVALID_SESSION_INDEX)
1789 0 : return VPPCOM_ECONNABORTED;
1790 :
1791 37 : ls = vcl_session_get (wrk, ls_index);
1792 37 : client_session = vcl_session_get (wrk, client_session_index);
1793 :
1794 37 : if (flags & O_NONBLOCK)
1795 0 : vcl_session_set_attr (client_session, VCL_SESS_ATTR_NONBLOCK);
1796 :
1797 37 : VDBG (1,
1798 : "listener %u [0x%llx]: Got a connect request! session %u [0x%llx],"
1799 : " flags %d, is_nonblocking %u",
1800 : ls->session_index, ls->vpp_handle, client_session_index,
1801 : client_session->vpp_handle, flags,
1802 : vcl_session_has_attr (client_session, VCL_SESS_ATTR_NONBLOCK));
1803 :
1804 37 : if (ep)
1805 : {
1806 37 : ep->is_ip4 = client_session->transport.is_ip4;
1807 37 : ep->port = client_session->transport.rmt_port;
1808 37 : if (client_session->transport.is_ip4)
1809 33 : clib_memcpy_fast (ep->ip, &client_session->transport.rmt_ip.ip4,
1810 : sizeof (ip4_address_t));
1811 : else
1812 4 : clib_memcpy_fast (ep->ip, &client_session->transport.rmt_ip.ip6,
1813 : sizeof (ip6_address_t));
1814 : }
1815 :
1816 37 : VDBG (0,
1817 : "listener %u [0x%llx] accepted %u [0x%llx] peer: %U:%u "
1818 : "local: %U:%u",
1819 : ls_handle, ls->vpp_handle, client_session_index,
1820 : client_session->vpp_handle, vcl_format_ip46_address,
1821 : &client_session->transport.rmt_ip,
1822 : client_session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1823 : clib_net_to_host_u16 (client_session->transport.rmt_port),
1824 : vcl_format_ip46_address, &client_session->transport.lcl_ip,
1825 : client_session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1826 : clib_net_to_host_u16 (client_session->transport.lcl_port));
1827 : vcl_evt (VCL_EVT_ACCEPT, client_session, ls, client_session_index);
1828 :
1829 : /*
1830 : * Session might have been closed already
1831 : */
1832 37 : if (accept_flags)
1833 : {
1834 0 : if (accept_flags & VCL_ACCEPTED_F_CLOSED)
1835 0 : client_session->session_state = VCL_STATE_VPP_CLOSING;
1836 0 : else if (accept_flags & VCL_ACCEPTED_F_RESET)
1837 0 : client_session->session_state = VCL_STATE_DISCONNECT;
1838 : }
1839 37 : return vcl_session_handle (client_session);
1840 : }
1841 :
1842 : int
1843 47 : vppcom_session_connect (uint32_t session_handle, vppcom_endpt_t * server_ep)
1844 : {
1845 47 : vcl_worker_t *wrk = vcl_worker_get_current ();
1846 47 : vcl_session_t *session = 0;
1847 : u32 session_index;
1848 : int rv;
1849 :
1850 47 : session = vcl_session_get_w_handle (wrk, session_handle);
1851 47 : if (!session)
1852 0 : return VPPCOM_EBADFD;
1853 47 : session_index = session->session_index;
1854 :
1855 47 : if (PREDICT_FALSE (session->flags & VCL_SESSION_F_IS_VEP))
1856 : {
1857 0 : VWRN ("cannot connect epoll session %u!", session->session_index);
1858 0 : return VPPCOM_EBADFD;
1859 : }
1860 :
1861 47 : if (PREDICT_FALSE (vcl_session_is_ready (session)))
1862 : {
1863 0 : VDBG (0,
1864 : "session %u [0x%llx]: already connected to %U:%d proto %s,"
1865 : " state (%s)",
1866 : session->session_index, session->vpp_handle,
1867 : vcl_format_ip46_address, &session->transport.rmt_ip,
1868 : session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1869 : clib_net_to_host_u16 (session->transport.rmt_port),
1870 : vppcom_proto_str (session->session_type),
1871 : vcl_session_state_str (session->session_state));
1872 0 : return VPPCOM_OK;
1873 : }
1874 :
1875 : /* Attempt to connect a connectionless listener */
1876 47 : if (PREDICT_FALSE (session->session_state == VCL_STATE_LISTEN))
1877 : {
1878 2 : if (session->session_type != VPPCOM_PROTO_UDP)
1879 0 : return VPPCOM_EINVAL;
1880 2 : vcl_send_session_unlisten (wrk, session);
1881 2 : session->session_state = VCL_STATE_CLOSED;
1882 : }
1883 :
1884 47 : session->transport.is_ip4 = server_ep->is_ip4;
1885 47 : vcl_ip_copy_from_ep (&session->transport.rmt_ip, server_ep);
1886 47 : session->transport.rmt_port = server_ep->port;
1887 47 : session->parent_handle = VCL_INVALID_SESSION_HANDLE;
1888 47 : session->flags |= VCL_SESSION_F_CONNECTED;
1889 :
1890 47 : VDBG (0, "session %u: connecting to peer %U:%d proto %s",
1891 : session->session_index, vcl_format_ip46_address,
1892 : &session->transport.rmt_ip,
1893 : session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1894 : clib_net_to_host_u16 (session->transport.rmt_port),
1895 : vppcom_proto_str (session->session_type));
1896 :
1897 47 : vcl_send_session_connect (wrk, session);
1898 :
1899 47 : if (vcl_session_has_attr (session, VCL_SESS_ATTR_NONBLOCK))
1900 : {
1901 : /* State set to STATE_UPDATED to ensure the session is not assumed
1902 : * to be ready and to also allow the app to close it prior to vpp's
1903 : * connected reply. */
1904 0 : session->session_state = VCL_STATE_UPDATED;
1905 0 : return VPPCOM_EINPROGRESS;
1906 : }
1907 :
1908 : /*
1909 : * Wait for reply from vpp if blocking
1910 : */
1911 47 : rv = vppcom_wait_for_session_state_change (session_index, VCL_STATE_READY,
1912 47 : vcm->cfg.session_timeout);
1913 :
1914 47 : session = vcl_session_get (wrk, session_index);
1915 47 : VDBG (0, "session %u [0x%llx]: connect %s!", session->session_index,
1916 : session->vpp_handle, rv ? "failed" : "succeeded");
1917 :
1918 47 : return rv;
1919 : }
1920 :
1921 : int
1922 0 : vppcom_session_stream_connect (uint32_t session_handle,
1923 : uint32_t parent_session_handle)
1924 : {
1925 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
1926 : vcl_session_t *session, *parent_session;
1927 : u32 session_index, parent_session_index;
1928 : int rv;
1929 :
1930 0 : session = vcl_session_get_w_handle (wrk, session_handle);
1931 0 : if (!session)
1932 0 : return VPPCOM_EBADFD;
1933 0 : parent_session = vcl_session_get_w_handle (wrk, parent_session_handle);
1934 0 : if (!parent_session)
1935 0 : return VPPCOM_EBADFD;
1936 :
1937 0 : session_index = session->session_index;
1938 0 : parent_session_index = parent_session->session_index;
1939 0 : if (PREDICT_FALSE (session->flags & VCL_SESSION_F_IS_VEP))
1940 : {
1941 0 : VDBG (0, "ERROR: cannot connect epoll session %u!",
1942 : session->session_index);
1943 0 : return VPPCOM_EBADFD;
1944 : }
1945 :
1946 0 : if (PREDICT_FALSE (vcl_session_is_ready (session)))
1947 : {
1948 0 : VDBG (0,
1949 : "session handle %u [0x%llx]: session already "
1950 : "connected to session %u [0x%llx] proto %s, state 0x%x (%s)",
1951 : session_handle, session->vpp_handle, parent_session_handle,
1952 : parent_session->vpp_handle,
1953 : vppcom_proto_str (session->session_type), session->session_state,
1954 : vcl_session_state_str (session->session_state));
1955 0 : return VPPCOM_OK;
1956 : }
1957 :
1958 : /* Connect to quic session specifics */
1959 0 : session->transport.is_ip4 = parent_session->transport.is_ip4;
1960 0 : session->transport.rmt_ip.ip4.as_u32 = (uint32_t) 1;
1961 0 : session->transport.rmt_port = 0;
1962 0 : session->parent_handle = parent_session->vpp_handle;
1963 :
1964 0 : VDBG (0, "session handle %u: connecting to session %u [0x%llx]",
1965 : session_handle, parent_session_handle, parent_session->vpp_handle);
1966 :
1967 : /*
1968 : * Send connect request and wait for reply from vpp
1969 : */
1970 0 : vcl_send_session_connect (wrk, session);
1971 0 : rv = vppcom_wait_for_session_state_change (session_index, VCL_STATE_READY,
1972 0 : vcm->cfg.session_timeout);
1973 :
1974 0 : session->listener_index = parent_session_index;
1975 0 : parent_session = vcl_session_get_w_handle (wrk, parent_session_handle);
1976 0 : if (parent_session)
1977 0 : parent_session->n_accepted_sessions++;
1978 :
1979 0 : session = vcl_session_get (wrk, session_index);
1980 0 : VDBG (0, "session %u [0x%llx]: connect %s!", session->session_index,
1981 : session->vpp_handle, rv ? "failed" : "succeeded");
1982 :
1983 0 : return rv;
1984 : }
1985 :
1986 : static inline int
1987 719687 : vppcom_session_read_internal (uint32_t session_handle, void *buf, int n,
1988 : u8 peek)
1989 : {
1990 719687 : vcl_worker_t *wrk = vcl_worker_get_current ();
1991 719687 : int rv, n_read = 0, is_nonblocking;
1992 719687 : vcl_session_t *s = 0;
1993 : svm_fifo_t *rx_fifo;
1994 : session_event_t *e;
1995 : svm_msg_q_t *mq;
1996 : u8 is_ct;
1997 :
1998 719687 : if (PREDICT_FALSE (!buf))
1999 0 : return VPPCOM_EFAULT;
2000 :
2001 719687 : s = vcl_session_get_w_handle (wrk, session_handle);
2002 719687 : if (PREDICT_FALSE (!s || (s->flags & VCL_SESSION_F_IS_VEP)))
2003 0 : return VPPCOM_EBADFD;
2004 :
2005 719687 : if (PREDICT_FALSE (!vcl_session_is_open (s)))
2006 : {
2007 0 : VDBG (0, "session %u[0x%llx] is not open! state 0x%x (%s)",
2008 : s->session_index, s->vpp_handle, s->session_state,
2009 : vcl_session_state_str (s->session_state));
2010 0 : return vcl_session_closed_error (s);
2011 : }
2012 :
2013 719687 : if (PREDICT_FALSE (s->flags & VCL_SESSION_F_RD_SHUTDOWN))
2014 : {
2015 : /* Vpp would ack the incoming data and enqueue it for reading.
2016 : * So even if SHUT_RD is set, we can still read() the data if
2017 : * the session is ready.
2018 : */
2019 0 : if (!vcl_session_read_ready (s))
2020 : {
2021 0 : return 0;
2022 : }
2023 : }
2024 :
2025 719687 : is_nonblocking = vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK);
2026 719687 : is_ct = vcl_session_is_ct (s);
2027 719687 : mq = wrk->app_event_queue;
2028 719687 : rx_fifo = is_ct ? s->ct_rx_fifo : s->rx_fifo;
2029 719687 : s->flags &= ~VCL_SESSION_F_HAS_RX_EVT;
2030 :
2031 719687 : if (svm_fifo_is_empty_cons (rx_fifo))
2032 : {
2033 261251 : if (is_nonblocking)
2034 : {
2035 261179 : if (vcl_session_is_closing (s))
2036 0 : return vcl_session_closing_error (s);
2037 261179 : if (is_ct)
2038 0 : svm_fifo_unset_event (s->rx_fifo);
2039 261179 : svm_fifo_unset_event (rx_fifo);
2040 261179 : return VPPCOM_EWOULDBLOCK;
2041 : }
2042 167 : while (svm_fifo_is_empty_cons (rx_fifo))
2043 : {
2044 95 : if (vcl_session_is_closing (s))
2045 0 : return vcl_session_closing_error (s);
2046 :
2047 95 : if (is_ct)
2048 22 : svm_fifo_unset_event (s->rx_fifo);
2049 95 : svm_fifo_unset_event (rx_fifo);
2050 :
2051 95 : svm_msg_q_wait (mq, SVM_MQ_WAIT_EMPTY);
2052 95 : vcl_worker_flush_mq_events (wrk);
2053 : }
2054 : }
2055 :
2056 458508 : read_again:
2057 :
2058 766779 : if (s->is_dgram)
2059 1380 : rv = app_recv_dgram_raw (rx_fifo, buf, n, &s->transport, 0, peek);
2060 : else
2061 765399 : rv = app_recv_stream_raw (rx_fifo, buf, n, 0, peek);
2062 :
2063 766779 : ASSERT (rv >= 0);
2064 :
2065 766779 : if (peek)
2066 0 : return rv;
2067 :
2068 766779 : n_read += rv;
2069 :
2070 766779 : if (svm_fifo_is_empty_cons (rx_fifo))
2071 : {
2072 401818 : if (is_ct)
2073 552 : svm_fifo_unset_event (s->rx_fifo);
2074 401818 : svm_fifo_unset_event (rx_fifo);
2075 401818 : if (!svm_fifo_is_empty_cons (rx_fifo)
2076 15426 : && svm_fifo_set_event (rx_fifo) && is_nonblocking)
2077 : {
2078 15398 : vec_add2 (wrk->unhandled_evts_vector, e, 1);
2079 15398 : e->event_type = SESSION_IO_EVT_RX;
2080 15398 : e->session_index = s->session_index;
2081 : }
2082 : }
2083 364961 : else if (PREDICT_FALSE (rv < n && !s->is_dgram))
2084 : {
2085 : /* More data enqueued while reading. Try to drain it
2086 : * or fill the buffer. Avoid doing that for dgrams */
2087 308271 : buf += rv;
2088 308271 : n -= rv;
2089 308271 : goto read_again;
2090 : }
2091 :
2092 458508 : if (PREDICT_FALSE (svm_fifo_needs_deq_ntf (rx_fifo, n_read)))
2093 : {
2094 13 : svm_fifo_clear_deq_ntf (rx_fifo);
2095 13 : app_send_io_evt_to_vpp (s->vpp_evt_q,
2096 13 : s->rx_fifo->shr->master_session_index,
2097 : SESSION_IO_EVT_RX, SVM_Q_WAIT);
2098 : }
2099 :
2100 458508 : VDBG (2, "session %u[0x%llx]: read %d bytes from (%p)", s->session_index,
2101 : s->vpp_handle, n_read, rx_fifo);
2102 :
2103 458508 : return n_read;
2104 : }
2105 :
2106 : int
2107 719687 : vppcom_session_read (uint32_t session_handle, void *buf, size_t n)
2108 : {
2109 719687 : return (vppcom_session_read_internal (session_handle, buf, n, 0));
2110 : }
2111 :
2112 : static int
2113 0 : vppcom_session_peek (uint32_t session_handle, void *buf, int n)
2114 : {
2115 0 : return (vppcom_session_read_internal (session_handle, buf, n, 1));
2116 : }
2117 :
2118 : int
2119 0 : vppcom_session_read_segments (uint32_t session_handle,
2120 : vppcom_data_segment_t * ds, uint32_t n_segments,
2121 : uint32_t max_bytes)
2122 : {
2123 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
2124 0 : int n_read = 0, is_nonblocking;
2125 0 : vcl_session_t *s = 0;
2126 : svm_fifo_t *rx_fifo;
2127 : svm_msg_q_t *mq;
2128 : u8 is_ct;
2129 :
2130 0 : s = vcl_session_get_w_handle (wrk, session_handle);
2131 0 : if (PREDICT_FALSE (!s || (s->flags & VCL_SESSION_F_IS_VEP)))
2132 0 : return VPPCOM_EBADFD;
2133 :
2134 0 : if (PREDICT_FALSE (!vcl_session_is_open (s)))
2135 0 : return vcl_session_closed_error (s);
2136 :
2137 0 : is_nonblocking = vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK);
2138 0 : is_ct = vcl_session_is_ct (s);
2139 0 : mq = wrk->app_event_queue;
2140 0 : rx_fifo = is_ct ? s->ct_rx_fifo : s->rx_fifo;
2141 0 : s->flags &= ~VCL_SESSION_F_HAS_RX_EVT;
2142 :
2143 0 : if (svm_fifo_is_empty_cons (rx_fifo))
2144 : {
2145 0 : if (is_nonblocking)
2146 : {
2147 0 : if (is_ct)
2148 0 : svm_fifo_unset_event (s->rx_fifo);
2149 0 : svm_fifo_unset_event (rx_fifo);
2150 0 : return VPPCOM_EWOULDBLOCK;
2151 : }
2152 0 : while (svm_fifo_is_empty_cons (rx_fifo))
2153 : {
2154 0 : if (vcl_session_is_closing (s))
2155 0 : return vcl_session_closing_error (s);
2156 :
2157 0 : if (is_ct)
2158 0 : svm_fifo_unset_event (s->rx_fifo);
2159 0 : svm_fifo_unset_event (rx_fifo);
2160 :
2161 0 : svm_msg_q_wait (mq, SVM_MQ_WAIT_EMPTY);
2162 0 : vcl_worker_flush_mq_events (wrk);
2163 : }
2164 : }
2165 :
2166 0 : n_read = svm_fifo_segments (rx_fifo, s->rx_bytes_pending,
2167 : (svm_fifo_seg_t *) ds, &n_segments, max_bytes);
2168 0 : if (n_read < 0)
2169 0 : return VPPCOM_EAGAIN;
2170 :
2171 0 : if (svm_fifo_max_dequeue_cons (rx_fifo) == n_read)
2172 : {
2173 0 : if (is_ct)
2174 0 : svm_fifo_unset_event (s->rx_fifo);
2175 0 : svm_fifo_unset_event (rx_fifo);
2176 0 : if (svm_fifo_max_dequeue_cons (rx_fifo) != n_read
2177 0 : && svm_fifo_set_event (rx_fifo)
2178 0 : && vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK))
2179 : {
2180 : session_event_t *e;
2181 0 : vec_add2 (wrk->unhandled_evts_vector, e, 1);
2182 0 : e->event_type = SESSION_IO_EVT_RX;
2183 0 : e->session_index = s->session_index;
2184 : }
2185 : }
2186 :
2187 0 : s->rx_bytes_pending += n_read;
2188 0 : return n_read;
2189 : }
2190 :
2191 : void
2192 0 : vppcom_session_free_segments (uint32_t session_handle, uint32_t n_bytes)
2193 : {
2194 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
2195 : vcl_session_t *s;
2196 : u8 is_ct;
2197 :
2198 0 : s = vcl_session_get_w_handle (wrk, session_handle);
2199 0 : if (PREDICT_FALSE (!s || (s->flags & VCL_SESSION_F_IS_VEP)))
2200 0 : return;
2201 :
2202 0 : is_ct = vcl_session_is_ct (s);
2203 0 : svm_fifo_dequeue_drop (is_ct ? s->ct_rx_fifo : s->rx_fifo, n_bytes);
2204 :
2205 0 : ASSERT (s->rx_bytes_pending >= n_bytes);
2206 0 : s->rx_bytes_pending -= n_bytes;
2207 : }
2208 :
2209 : always_inline u8
2210 846364 : vcl_fifo_is_writeable (svm_fifo_t * f, u32 len, u8 is_dgram)
2211 : {
2212 846364 : u32 max_enq = svm_fifo_max_enqueue_prod (f);
2213 846364 : if (is_dgram)
2214 1380 : return max_enq >= (sizeof (session_dgram_hdr_t) + len);
2215 : else
2216 844984 : return max_enq > 0;
2217 : }
2218 :
2219 : always_inline int
2220 846364 : vppcom_session_write_inline (vcl_worker_t *wrk, vcl_session_t *s, void *buf,
2221 : size_t n, u8 is_flush, u8 is_dgram)
2222 : {
2223 : int n_write, is_nonblocking;
2224 : session_evt_type_t et;
2225 : svm_fifo_t *tx_fifo;
2226 : svm_msg_q_t *mq;
2227 : u8 is_ct;
2228 :
2229 : /* Accept zero length writes but just return */
2230 846364 : if (PREDICT_FALSE (!n))
2231 0 : return VPPCOM_OK;
2232 :
2233 846364 : if (PREDICT_FALSE (!buf))
2234 0 : return VPPCOM_EFAULT;
2235 :
2236 846364 : if (PREDICT_FALSE (s->flags & VCL_SESSION_F_IS_VEP))
2237 : {
2238 0 : VDBG (0, "ERROR: session %u [0x%llx]: cannot write to an epoll"
2239 : " session!", s->session_index, s->vpp_handle);
2240 0 : return VPPCOM_EBADFD;
2241 : }
2242 :
2243 846364 : if (PREDICT_FALSE (!vcl_session_is_open (s)))
2244 : {
2245 0 : VDBG (1, "session %u [0x%llx]: is not open! state 0x%x (%s)",
2246 : s->session_index, s->vpp_handle, s->session_state,
2247 : vcl_session_state_str (s->session_state));
2248 0 : return vcl_session_closed_error (s);;
2249 : }
2250 :
2251 846364 : if (PREDICT_FALSE (s->flags & VCL_SESSION_F_WR_SHUTDOWN))
2252 : {
2253 0 : VDBG (1, "session %u [0x%llx]: is shutdown! state 0x%x (%s)",
2254 : s->session_index, s->vpp_handle, s->session_state,
2255 : vcl_session_state_str (s->session_state));
2256 0 : return VPPCOM_EPIPE;
2257 : }
2258 :
2259 846364 : is_ct = vcl_session_is_ct (s);
2260 846364 : tx_fifo = is_ct ? s->ct_tx_fifo : s->tx_fifo;
2261 846364 : is_nonblocking = vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK);
2262 :
2263 846364 : mq = wrk->app_event_queue;
2264 846364 : if (!vcl_fifo_is_writeable (tx_fifo, n, is_dgram))
2265 : {
2266 682715 : if (is_nonblocking)
2267 : {
2268 682715 : return VPPCOM_EWOULDBLOCK;
2269 : }
2270 0 : while (!vcl_fifo_is_writeable (tx_fifo, n, is_dgram))
2271 : {
2272 0 : svm_fifo_add_want_deq_ntf (tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
2273 0 : if (vcl_session_is_closing (s))
2274 0 : return vcl_session_closing_error (s);
2275 :
2276 0 : svm_msg_q_wait (mq, SVM_MQ_WAIT_EMPTY);
2277 0 : vcl_worker_flush_mq_events (wrk);
2278 : }
2279 : }
2280 :
2281 163649 : et = SESSION_IO_EVT_TX;
2282 163649 : if (is_flush && !is_ct)
2283 27667 : et = SESSION_IO_EVT_TX_FLUSH;
2284 :
2285 163649 : if (is_dgram)
2286 : {
2287 1380 : et = vcl_session_dgram_tx_evt (s, et);
2288 : n_write =
2289 1380 : app_send_dgram_raw_gso (tx_fifo, &s->transport, s->vpp_evt_q, buf, n,
2290 1380 : s->gso_size, et, 0 /* do_evt */, SVM_Q_WAIT);
2291 : }
2292 : else
2293 : {
2294 162269 : n_write = app_send_stream_raw (tx_fifo, s->vpp_evt_q, buf, n, et,
2295 : 0 /* do_evt */, SVM_Q_WAIT);
2296 : }
2297 :
2298 163649 : if (svm_fifo_set_event (s->tx_fifo))
2299 125261 : app_send_io_evt_to_vpp (
2300 125261 : s->vpp_evt_q, s->tx_fifo->shr->master_session_index, et, SVM_Q_WAIT);
2301 :
2302 : /* The underlying fifo segment can run out of memory */
2303 163649 : if (PREDICT_FALSE (n_write < 0))
2304 0 : return VPPCOM_EAGAIN;
2305 :
2306 163649 : VDBG (2, "session %u [0x%llx]: wrote %d bytes", s->session_index,
2307 : s->vpp_handle, n_write);
2308 :
2309 163649 : return n_write;
2310 : }
2311 :
2312 : int
2313 17235 : vppcom_session_write (uint32_t session_handle, void *buf, size_t n)
2314 : {
2315 17235 : vcl_worker_t *wrk = vcl_worker_get_current ();
2316 : vcl_session_t *s;
2317 :
2318 17235 : s = vcl_session_get_w_handle (wrk, session_handle);
2319 17235 : if (PREDICT_FALSE (!s))
2320 0 : return VPPCOM_EBADFD;
2321 :
2322 17235 : return vppcom_session_write_inline (wrk, s, buf, n, 0 /* is_flush */,
2323 17235 : s->is_dgram ? 1 : 0);
2324 : }
2325 :
2326 : int
2327 829129 : vppcom_session_write_msg (uint32_t session_handle, void *buf, size_t n)
2328 : {
2329 829129 : vcl_worker_t *wrk = vcl_worker_get_current ();
2330 : vcl_session_t *s;
2331 :
2332 829129 : s = vcl_session_get_w_handle (wrk, session_handle);
2333 829129 : if (PREDICT_FALSE (!s))
2334 0 : return VPPCOM_EBADFD;
2335 :
2336 829129 : return vppcom_session_write_inline (wrk, s, buf, n, 1 /* is_flush */,
2337 829129 : s->is_dgram ? 1 : 0);
2338 : }
2339 :
2340 : #define vcl_fifo_rx_evt_valid_or_break(_s) \
2341 : if (PREDICT_FALSE (!_s->rx_fifo)) \
2342 : break; \
2343 : if (PREDICT_FALSE (svm_fifo_is_empty (_s->rx_fifo))) \
2344 : { \
2345 : if (!vcl_session_is_ct (_s)) \
2346 : { \
2347 : svm_fifo_unset_event (_s->rx_fifo); \
2348 : if (svm_fifo_is_empty (_s->rx_fifo)) \
2349 : break; \
2350 : } \
2351 : else if (svm_fifo_is_empty (_s->ct_rx_fifo)) \
2352 : { \
2353 : svm_fifo_unset_event (_s->rx_fifo); /* rx evts on actual fifo*/ \
2354 : if (svm_fifo_is_empty (_s->ct_rx_fifo)) \
2355 : break; \
2356 : } \
2357 : } \
2358 :
2359 : static void
2360 121560 : vcl_select_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
2361 : unsigned long n_bits, unsigned long *read_map,
2362 : unsigned long *write_map,
2363 : unsigned long *except_map, u32 * bits_set)
2364 : {
2365 : session_disconnected_msg_t *disconnected_msg;
2366 : session_connected_msg_t *connected_msg;
2367 : vcl_session_t *s;
2368 : u32 sid;
2369 :
2370 121560 : switch (e->event_type)
2371 : {
2372 99273 : case SESSION_IO_EVT_RX:
2373 99273 : sid = e->session_index;
2374 99273 : s = vcl_session_get (wrk, sid);
2375 99273 : if (!s || !vcl_session_is_open (s))
2376 : break;
2377 99273 : vcl_fifo_rx_evt_valid_or_break (s);
2378 39589 : if (sid < n_bits && read_map)
2379 : {
2380 39589 : clib_bitmap_set_no_check ((uword *) read_map, sid, 1);
2381 39589 : *bits_set += 1;
2382 : }
2383 39589 : break;
2384 22269 : case SESSION_IO_EVT_TX:
2385 22269 : sid = e->session_index;
2386 22269 : s = vcl_session_get (wrk, sid);
2387 22269 : if (!s || !vcl_session_is_open (s))
2388 : break;
2389 22269 : if (sid < n_bits && write_map)
2390 : {
2391 22269 : clib_bitmap_set_no_check ((uword *) write_map, sid, 1);
2392 22269 : *bits_set += 1;
2393 : }
2394 22269 : break;
2395 9 : case SESSION_CTRL_EVT_ACCEPTED:
2396 9 : if (!e->postponed)
2397 9 : s = vcl_session_accepted (wrk, (session_accepted_msg_t *) e->data);
2398 : else
2399 0 : s = vcl_session_get (wrk, e->session_index);
2400 9 : if (!s)
2401 0 : break;
2402 9 : sid = s->session_index;
2403 9 : if (sid < n_bits && read_map)
2404 : {
2405 9 : clib_bitmap_set_no_check ((uword *) read_map, sid, 1);
2406 9 : *bits_set += 1;
2407 : }
2408 9 : break;
2409 0 : case SESSION_CTRL_EVT_CONNECTED:
2410 0 : if (!e->postponed)
2411 : {
2412 0 : connected_msg = (session_connected_msg_t *) e->data;
2413 0 : sid = vcl_session_connected_handler (wrk, connected_msg);
2414 : }
2415 : else
2416 0 : sid = e->session_index;
2417 0 : if (sid == VCL_INVALID_SESSION_INDEX)
2418 0 : break;
2419 0 : if (!(sid < n_bits && write_map))
2420 : break;
2421 0 : clib_bitmap_set_no_check ((uword *) write_map, sid, 1);
2422 0 : *bits_set += 1;
2423 0 : s = vcl_session_get (wrk, sid);
2424 : /* We didn't have a fifo when the event was added */
2425 0 : vcl_session_add_want_deq_ntf (s, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL);
2426 0 : break;
2427 0 : case SESSION_CTRL_EVT_DISCONNECTED:
2428 0 : disconnected_msg = (session_disconnected_msg_t *) e->data;
2429 0 : s = vcl_session_disconnected_handler (wrk, disconnected_msg);
2430 0 : if (!s)
2431 0 : break;
2432 0 : sid = s->session_index;
2433 0 : if (sid < n_bits && except_map)
2434 : {
2435 0 : clib_bitmap_set_no_check ((uword *) except_map, sid, 1);
2436 0 : *bits_set += 1;
2437 : }
2438 0 : break;
2439 0 : case SESSION_CTRL_EVT_RESET:
2440 0 : sid = vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data);
2441 0 : if (sid < n_bits && except_map)
2442 : {
2443 0 : clib_bitmap_set_no_check ((uword *) except_map, sid, 1);
2444 0 : *bits_set += 1;
2445 : }
2446 0 : break;
2447 1 : case SESSION_CTRL_EVT_UNLISTEN_REPLY:
2448 1 : vcl_session_unlisten_reply_handler (wrk, e->data);
2449 1 : break;
2450 0 : case SESSION_CTRL_EVT_MIGRATED:
2451 0 : vcl_session_migrated_handler (wrk, e->data);
2452 0 : break;
2453 2 : case SESSION_CTRL_EVT_CLEANUP:
2454 2 : vcl_session_cleanup_handler (wrk, e->data);
2455 2 : break;
2456 0 : case SESSION_CTRL_EVT_WORKER_UPDATE_REPLY:
2457 0 : vcl_session_worker_update_reply_handler (wrk, e->data);
2458 0 : break;
2459 0 : case SESSION_CTRL_EVT_REQ_WORKER_UPDATE:
2460 0 : vcl_session_req_worker_update_handler (wrk, e->data);
2461 0 : break;
2462 6 : case SESSION_CTRL_EVT_APP_ADD_SEGMENT:
2463 6 : vcl_session_app_add_segment_handler (wrk, e->data);
2464 6 : break;
2465 0 : case SESSION_CTRL_EVT_APP_DEL_SEGMENT:
2466 0 : vcl_session_app_del_segment_handler (wrk, e->data);
2467 0 : break;
2468 0 : case SESSION_CTRL_EVT_APP_WRK_RPC:
2469 0 : vcl_worker_rpc_handler (wrk, e->data);
2470 0 : break;
2471 0 : default:
2472 0 : clib_warning ("unhandled: %u", e->event_type);
2473 0 : break;
2474 : }
2475 0 : }
2476 :
2477 : static int
2478 26849800 : vcl_select_handle_mq (vcl_worker_t * wrk, svm_msg_q_t * mq,
2479 : unsigned long n_bits, unsigned long *read_map,
2480 : unsigned long *write_map, unsigned long *except_map,
2481 : double time_to_wait, u32 * bits_set)
2482 : {
2483 : svm_msg_q_msg_t *msg;
2484 : session_event_t *e;
2485 : u32 i;
2486 :
2487 26849800 : if (svm_msg_q_is_empty (mq))
2488 : {
2489 26744400 : if (*bits_set)
2490 443940 : return 0;
2491 :
2492 26300400 : if (!time_to_wait)
2493 26300400 : return 0;
2494 0 : else if (time_to_wait < 0)
2495 0 : svm_msg_q_wait (mq, SVM_MQ_WAIT_EMPTY);
2496 : else
2497 : {
2498 0 : if (svm_msg_q_timedwait (mq, time_to_wait))
2499 0 : return 0;
2500 : }
2501 : }
2502 105461 : vcl_mq_dequeue_batch (wrk, mq, ~0);
2503 :
2504 211564 : for (i = 0; i < vec_len (wrk->mq_msg_vector); i++)
2505 : {
2506 106103 : msg = vec_elt_at_index (wrk->mq_msg_vector, i);
2507 106103 : e = svm_msg_q_msg_data (mq, msg);
2508 106103 : vcl_select_handle_mq_event (wrk, e, n_bits, read_map, write_map,
2509 : except_map, bits_set);
2510 106103 : svm_msg_q_free_msg (mq, msg);
2511 : }
2512 105461 : vec_reset_length (wrk->mq_msg_vector);
2513 105461 : vcl_handle_pending_wrk_updates (wrk);
2514 105461 : return *bits_set;
2515 : }
2516 :
2517 : static int
2518 26849800 : vppcom_select_condvar (vcl_worker_t * wrk, int n_bits,
2519 : vcl_si_set * read_map, vcl_si_set * write_map,
2520 : vcl_si_set * except_map, double time_to_wait,
2521 : u32 * bits_set)
2522 : {
2523 26849800 : double wait = 0, start = 0;
2524 :
2525 26849800 : if (!*bits_set)
2526 : {
2527 26380600 : wait = time_to_wait;
2528 26380600 : start = clib_time_now (&wrk->clib_time);
2529 : }
2530 :
2531 : do
2532 : {
2533 26849800 : vcl_select_handle_mq (wrk, wrk->app_event_queue, n_bits, read_map,
2534 : write_map, except_map, wait, bits_set);
2535 26849800 : if (*bits_set)
2536 492316 : return *bits_set;
2537 26357500 : if (wait == -1)
2538 0 : continue;
2539 :
2540 26357500 : wait = wait - (clib_time_now (&wrk->clib_time) - start);
2541 : }
2542 26357500 : while (wait > 0);
2543 :
2544 26357500 : return 0;
2545 : }
2546 :
2547 : static int
2548 0 : vppcom_select_eventfd (vcl_worker_t * wrk, int n_bits,
2549 : vcl_si_set * read_map, vcl_si_set * write_map,
2550 : vcl_si_set * except_map, double time_to_wait,
2551 : u32 * bits_set)
2552 : {
2553 : vcl_mq_evt_conn_t *mqc;
2554 : int __clib_unused n_read;
2555 : int n_mq_evts, i;
2556 : u64 buf;
2557 :
2558 0 : if (PREDICT_FALSE (wrk->api_client_handle == ~0))
2559 : {
2560 0 : vcl_api_retry_attach (wrk);
2561 0 : return 0;
2562 : }
2563 :
2564 0 : vec_validate (wrk->mq_events, pool_elts (wrk->mq_evt_conns));
2565 0 : n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events,
2566 0 : vec_len (wrk->mq_events), time_to_wait);
2567 0 : for (i = 0; i < n_mq_evts; i++)
2568 : {
2569 0 : if (PREDICT_FALSE (wrk->mq_events[i].data.u32 == ~0))
2570 : {
2571 0 : vcl_api_handle_disconnect (wrk);
2572 0 : continue;
2573 : }
2574 :
2575 0 : mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32);
2576 0 : n_read = read (mqc->mq_fd, &buf, sizeof (buf));
2577 0 : vcl_select_handle_mq (wrk, mqc->mq, n_bits, read_map, write_map,
2578 : except_map, 0, bits_set);
2579 : }
2580 :
2581 0 : return (n_mq_evts > 0 ? (int) *bits_set : 0);
2582 : }
2583 :
2584 : int
2585 26849800 : vppcom_select (int n_bits, vcl_si_set * read_map, vcl_si_set * write_map,
2586 : vcl_si_set * except_map, double time_to_wait)
2587 : {
2588 26849800 : u32 sid, minbits = clib_max (n_bits, BITS (uword)), bits_set = 0;
2589 26849800 : vcl_worker_t *wrk = vcl_worker_get_current ();
2590 26849800 : vcl_session_t *s = 0;
2591 : int i;
2592 :
2593 26849800 : if (n_bits && read_map)
2594 : {
2595 26848800 : clib_bitmap_validate (wrk->rd_bitmap, minbits);
2596 26848800 : clib_memcpy_fast (wrk->rd_bitmap, read_map,
2597 26848800 : vec_len (wrk->rd_bitmap) * sizeof (vcl_si_set));
2598 26848800 : memset (read_map, 0, vec_len (wrk->rd_bitmap) * sizeof (vcl_si_set));
2599 : }
2600 26849800 : if (n_bits && write_map)
2601 : {
2602 26849800 : clib_bitmap_validate (wrk->wr_bitmap, minbits);
2603 26849800 : clib_memcpy_fast (wrk->wr_bitmap, write_map,
2604 26849800 : vec_len (wrk->wr_bitmap) * sizeof (vcl_si_set));
2605 26849800 : memset (write_map, 0, vec_len (wrk->wr_bitmap) * sizeof (vcl_si_set));
2606 : }
2607 26849800 : if (n_bits && except_map)
2608 : {
2609 0 : clib_bitmap_validate (wrk->ex_bitmap, minbits);
2610 0 : clib_memcpy_fast (wrk->ex_bitmap, except_map,
2611 0 : vec_len (wrk->ex_bitmap) * sizeof (vcl_si_set));
2612 0 : memset (except_map, 0, vec_len (wrk->ex_bitmap) * sizeof (vcl_si_set));
2613 : }
2614 :
2615 26849800 : if (!n_bits)
2616 0 : return 0;
2617 :
2618 26849800 : if (!write_map)
2619 6 : goto check_rd;
2620 :
2621 34477000 : clib_bitmap_foreach (sid, wrk->wr_bitmap)
2622 : {
2623 7627220 : if (!(s = vcl_session_get (wrk, sid)))
2624 : {
2625 0 : clib_bitmap_set_no_check ((uword *) write_map, sid, 1);
2626 0 : bits_set++;
2627 0 : continue;
2628 : }
2629 :
2630 7627220 : if (vcl_session_write_ready (s))
2631 : {
2632 113756 : clib_bitmap_set_no_check ((uword *) write_map, sid, 1);
2633 113756 : bits_set++;
2634 : }
2635 : else
2636 : {
2637 7513460 : vcl_session_add_want_deq_ntf (s, SVM_FIFO_WANT_DEQ_NOTIF);
2638 : }
2639 : }
2640 :
2641 26849800 : check_rd:
2642 26849800 : if (!read_map)
2643 1000 : goto check_mq;
2644 :
2645 77187900 : clib_bitmap_foreach (sid, wrk->rd_bitmap)
2646 : {
2647 50339000 : if (!(s = vcl_session_get (wrk, sid)))
2648 : {
2649 0 : clib_bitmap_set_no_check ((uword *) read_map, sid, 1);
2650 0 : bits_set++;
2651 0 : continue;
2652 : }
2653 :
2654 50339000 : if (vcl_session_read_ready (s))
2655 : {
2656 410891 : clib_bitmap_set_no_check ((uword *) read_map, sid, 1);
2657 410891 : bits_set++;
2658 : }
2659 : }
2660 :
2661 26848800 : check_mq:
2662 :
2663 26865300 : for (i = 0; i < vec_len (wrk->unhandled_evts_vector); i++)
2664 : {
2665 15457 : vcl_select_handle_mq_event (wrk, &wrk->unhandled_evts_vector[i], n_bits,
2666 : read_map, write_map, except_map, &bits_set);
2667 : }
2668 26849800 : vec_reset_length (wrk->unhandled_evts_vector);
2669 :
2670 26849800 : if (vcm->cfg.use_mq_eventfd)
2671 0 : vppcom_select_eventfd (wrk, n_bits, read_map, write_map, except_map,
2672 : time_to_wait, &bits_set);
2673 : else
2674 26849800 : vppcom_select_condvar (wrk, n_bits, read_map, write_map, except_map,
2675 : time_to_wait, &bits_set);
2676 :
2677 26849800 : return (bits_set);
2678 : }
2679 :
2680 : static inline void
2681 94 : vep_verify_epoll_chain (vcl_worker_t * wrk, u32 vep_handle)
2682 : {
2683 : vppcom_epoll_t *vep;
2684 94 : u32 sh = vep_handle;
2685 : vcl_session_t *s;
2686 :
2687 94 : if (VPPCOM_DEBUG <= 3)
2688 94 : return;
2689 :
2690 0 : s = vcl_session_get_w_handle (wrk, vep_handle);
2691 0 : if (PREDICT_FALSE (!s))
2692 : {
2693 0 : VDBG (0, "ERROR: Invalid vep_sh (%u)!", vep_handle);
2694 0 : goto done;
2695 : }
2696 0 : if (PREDICT_FALSE (!(s->flags & VCL_SESSION_F_IS_VEP)))
2697 : {
2698 0 : VDBG (0, "ERROR: vep_sh (%u) is not a vep!", vep_handle);
2699 0 : goto done;
2700 : }
2701 0 : vep = &s->vep;
2702 0 : VDBG (0, "vep_sh (%u): Dumping epoll chain\n"
2703 : "{\n"
2704 : " is_vep = %u\n"
2705 : " is_vep_session = %u\n"
2706 : " next_sh = 0x%x (%u)\n"
2707 : "}\n", vep_handle, s->flags & VCL_SESSION_F_IS_VEP,
2708 : s->flags & VCL_SESSION_F_IS_VEP_SESSION, vep->next_sh, vep->next_sh);
2709 :
2710 0 : for (sh = vep->next_sh; sh != ~0; sh = vep->next_sh)
2711 : {
2712 0 : s = vcl_session_get_w_handle (wrk, sh);
2713 0 : if (PREDICT_FALSE (!s))
2714 : {
2715 0 : VDBG (0, "ERROR: Invalid sh (%u)!", sh);
2716 0 : goto done;
2717 : }
2718 0 : if (PREDICT_FALSE (s->flags & VCL_SESSION_F_IS_VEP))
2719 : {
2720 0 : VDBG (0, "ERROR: sh (%u) is a vep!", vep_handle);
2721 : }
2722 0 : else if (PREDICT_FALSE (!(s->flags & VCL_SESSION_F_IS_VEP_SESSION)))
2723 : {
2724 0 : VDBG (0, "ERROR: sh (%u) is not a vep session handle!", sh);
2725 0 : goto done;
2726 : }
2727 0 : vep = &s->vep;
2728 0 : if (PREDICT_FALSE (vep->vep_sh != vep_handle))
2729 0 : VDBG (0, "ERROR: session (%u) vep_sh (%u) != vep_sh (%u)!",
2730 : sh, s->vep.vep_sh, vep_handle);
2731 0 : if (s->flags & VCL_SESSION_F_IS_VEP_SESSION)
2732 : {
2733 0 : VDBG (0, "vep_sh[%u]: sh 0x%x (%u)\n"
2734 : "{\n"
2735 : " next_sh = 0x%x (%u)\n"
2736 : " prev_sh = 0x%x (%u)\n"
2737 : " vep_sh = 0x%x (%u)\n"
2738 : " ev.events = 0x%x\n"
2739 : " ev.data.u64 = 0x%llx\n"
2740 : " et_mask = 0x%x\n"
2741 : "}\n",
2742 : vep_handle, sh, sh, vep->next_sh, vep->next_sh, vep->prev_sh,
2743 : vep->prev_sh, vep->vep_sh, vep->vep_sh, vep->ev.events,
2744 : vep->ev.data.u64, vep->et_mask);
2745 : }
2746 : }
2747 :
2748 0 : done:
2749 0 : VDBG (0, "vep_sh (%u): Dump complete!\n", vep_handle);
2750 : }
2751 :
2752 : int
2753 13 : vppcom_epoll_create (void)
2754 : {
2755 13 : vcl_worker_t *wrk = vcl_worker_get_current ();
2756 : vcl_session_t *vep_session;
2757 :
2758 13 : vep_session = vcl_session_alloc (wrk);
2759 :
2760 13 : vep_session->flags |= VCL_SESSION_F_IS_VEP;
2761 13 : vep_session->vep.vep_sh = ~0;
2762 13 : vep_session->vep.next_sh = ~0;
2763 13 : vep_session->vep.prev_sh = ~0;
2764 13 : vep_session->vpp_handle = ~0;
2765 :
2766 : vcl_evt (VCL_EVT_EPOLL_CREATE, vep_session, vep_session->session_index);
2767 13 : VDBG (0, "Created vep_idx %u", vep_session->session_index);
2768 :
2769 13 : return vcl_session_handle (vep_session);
2770 : }
2771 :
2772 : static void
2773 0 : vcl_epoll_ctl_add_unhandled_event (vcl_worker_t *wrk, vcl_session_t *s,
2774 : u8 is_epollet, session_evt_type_t evt)
2775 : {
2776 0 : if (!is_epollet)
2777 : {
2778 0 : if (s->vep.lt_next == VCL_INVALID_SESSION_INDEX)
2779 0 : vcl_epoll_lt_add (wrk, s);
2780 0 : return;
2781 : }
2782 :
2783 0 : session_event_t e = { 0 };
2784 0 : e.session_index = s->session_index;
2785 0 : e.event_type = evt;
2786 0 : if (evt == SESSION_IO_EVT_RX)
2787 0 : s->flags &= ~VCL_SESSION_F_HAS_RX_EVT;
2788 0 : vec_add1 (wrk->unhandled_evts_vector, e);
2789 : }
2790 :
2791 : int
2792 94 : vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle,
2793 : struct epoll_event *event)
2794 : {
2795 94 : vcl_worker_t *wrk = vcl_worker_get_current ();
2796 94 : int rv = VPPCOM_OK, add_evt = 0;
2797 : vcl_session_t *vep_session;
2798 : vcl_session_t *s;
2799 :
2800 94 : if (vep_handle == session_handle)
2801 : {
2802 0 : VDBG (0, "vep_sh == session handle (%u)!", vep_handle);
2803 0 : return VPPCOM_EINVAL;
2804 : }
2805 :
2806 94 : vep_session = vcl_session_get_w_handle (wrk, vep_handle);
2807 94 : if (PREDICT_FALSE (!vep_session))
2808 : {
2809 0 : VDBG (0, "Invalid vep_sh (%u)!", vep_handle);
2810 0 : return VPPCOM_EBADFD;
2811 : }
2812 94 : if (PREDICT_FALSE (!(vep_session->flags & VCL_SESSION_F_IS_VEP)))
2813 : {
2814 0 : VDBG (0, "vep_sh (%u) is not a vep!", vep_handle);
2815 0 : return VPPCOM_EINVAL;
2816 : }
2817 :
2818 94 : ASSERT (vep_session->vep.vep_sh == ~0);
2819 94 : ASSERT (vep_session->vep.prev_sh == ~0);
2820 :
2821 94 : s = vcl_session_get_w_handle (wrk, session_handle);
2822 94 : if (PREDICT_FALSE (!s))
2823 : {
2824 0 : VDBG (0, "Invalid session_handle (%u)!", session_handle);
2825 0 : return VPPCOM_EBADFD;
2826 : }
2827 94 : if (PREDICT_FALSE (s->flags & VCL_SESSION_F_IS_VEP))
2828 : {
2829 0 : VDBG (0, "session_handle (%u) is a vep!", vep_handle);
2830 0 : return VPPCOM_EINVAL;
2831 : }
2832 :
2833 94 : switch (op)
2834 : {
2835 53 : case EPOLL_CTL_ADD:
2836 53 : if (PREDICT_FALSE (!event))
2837 : {
2838 0 : VDBG (0, "EPOLL_CTL_ADD: NULL pointer to epoll_event structure!");
2839 0 : return VPPCOM_EINVAL;
2840 : }
2841 53 : if (s->flags & VCL_SESSION_F_IS_VEP_SESSION)
2842 : {
2843 0 : VDBG (0, "EPOLL_CTL_ADD: %u already epolled!", s->session_index);
2844 0 : rv = VPPCOM_EEXIST;
2845 0 : goto done;
2846 : }
2847 53 : if (vep_session->vep.next_sh != ~0)
2848 : {
2849 : vcl_session_t *next_session;
2850 40 : next_session = vcl_session_get_w_handle (wrk,
2851 : vep_session->vep.next_sh);
2852 40 : if (PREDICT_FALSE (!next_session))
2853 : {
2854 0 : VDBG (0, "EPOLL_CTL_ADD: Invalid vep.next_sh (%u) on "
2855 : "vep_idx (%u)!", vep_session->vep.next_sh, vep_handle);
2856 0 : return VPPCOM_EBADFD;
2857 : }
2858 40 : ASSERT (next_session->vep.prev_sh == vep_handle);
2859 40 : next_session->vep.prev_sh = session_handle;
2860 : }
2861 53 : s->vep.next_sh = vep_session->vep.next_sh;
2862 53 : s->vep.prev_sh = vep_handle;
2863 53 : s->vep.vep_sh = vep_handle;
2864 53 : s->vep.et_mask = VEP_DEFAULT_ET_MASK;
2865 53 : s->vep.lt_next = VCL_INVALID_SESSION_INDEX;
2866 53 : s->vep.ev = *event;
2867 53 : s->vep.ev.events |= EPOLLHUP | EPOLLERR;
2868 53 : s->flags &= ~VCL_SESSION_F_IS_VEP;
2869 53 : s->flags |= VCL_SESSION_F_IS_VEP_SESSION;
2870 53 : vep_session->vep.next_sh = session_handle;
2871 :
2872 53 : if ((event->events & EPOLLOUT))
2873 : {
2874 0 : int write_ready = vcl_session_write_ready (s);
2875 :
2876 0 : vcl_session_add_want_deq_ntf (s, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL);
2877 0 : if (write_ready > 0)
2878 : {
2879 : /* Generate EPOLLOUT if tx fifo not full */
2880 0 : vcl_epoll_ctl_add_unhandled_event (
2881 : wrk, s, event->events & EPOLLET, SESSION_IO_EVT_TX);
2882 0 : add_evt = 1;
2883 : }
2884 : else
2885 : {
2886 0 : vcl_session_add_want_deq_ntf (s, SVM_FIFO_WANT_DEQ_NOTIF);
2887 : }
2888 : }
2889 : /* Generate EPOLLIN if rx fifo has data */
2890 53 : if ((event->events & EPOLLIN) && (vcl_session_read_ready (s) > 0))
2891 : {
2892 0 : vcl_epoll_ctl_add_unhandled_event (wrk, s, event->events & EPOLLET,
2893 : SESSION_IO_EVT_RX);
2894 0 : add_evt = 1;
2895 : }
2896 53 : if (!add_evt && vcl_session_is_closing (s))
2897 : {
2898 0 : session_event_t e = { 0 };
2899 0 : if (s->session_state == VCL_STATE_VPP_CLOSING)
2900 0 : e.event_type = SESSION_CTRL_EVT_DISCONNECTED;
2901 : else
2902 0 : e.event_type = SESSION_CTRL_EVT_RESET;
2903 0 : e.session_index = s->session_index;
2904 0 : e.postponed = 1;
2905 0 : vec_add1 (wrk->unhandled_evts_vector, e);
2906 : }
2907 53 : VDBG (1, "EPOLL_CTL_ADD: vep_sh %u, sh %u, events 0x%x, data 0x%llx!",
2908 : vep_handle, session_handle, event->events, event->data.u64);
2909 : vcl_evt (VCL_EVT_EPOLL_CTLADD, s, event->events, event->data.u64);
2910 53 : break;
2911 :
2912 0 : case EPOLL_CTL_MOD:
2913 0 : if (PREDICT_FALSE (!event))
2914 : {
2915 0 : VDBG (0, "EPOLL_CTL_MOD: NULL pointer to epoll_event structure!");
2916 0 : rv = VPPCOM_EINVAL;
2917 0 : goto done;
2918 : }
2919 0 : else if (PREDICT_FALSE (!(s->flags & VCL_SESSION_F_IS_VEP_SESSION)))
2920 : {
2921 0 : VDBG (0, "sh %u EPOLL_CTL_MOD: not a vep session!", session_handle);
2922 0 : rv = VPPCOM_ENOENT;
2923 0 : goto done;
2924 : }
2925 0 : else if (PREDICT_FALSE (s->vep.vep_sh != vep_handle))
2926 : {
2927 0 : VDBG (0, "EPOLL_CTL_MOD: sh %u vep_sh (%u) != vep_sh (%u)!",
2928 : session_handle, s->vep.vep_sh, vep_handle);
2929 0 : rv = VPPCOM_EINVAL;
2930 0 : goto done;
2931 : }
2932 :
2933 : /* Generate EPOLLOUT if session write ready and event was not on */
2934 0 : if ((event->events & EPOLLOUT) && !(s->vep.ev.events & EPOLLOUT))
2935 0 : {
2936 : /* Fifo size load acq synchronized with update store rel */
2937 0 : int write_ready = vcl_session_write_ready (s);
2938 :
2939 0 : vcl_session_add_want_deq_ntf (s, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL);
2940 0 : if (write_ready > 0)
2941 0 : vcl_epoll_ctl_add_unhandled_event (wrk, s, event->events & EPOLLET,
2942 : SESSION_IO_EVT_TX);
2943 : else
2944 : /* Request deq ntf in case dequeue happened while updating flag */
2945 0 : vcl_session_add_want_deq_ntf (s, SVM_FIFO_WANT_DEQ_NOTIF);
2946 : }
2947 0 : else if (!(event->events & EPOLLOUT))
2948 0 : vcl_session_del_want_deq_ntf (s, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL);
2949 :
2950 : /* Generate EPOLLIN if session read ready and event was not on */
2951 0 : if ((event->events & EPOLLIN) && !(s->vep.ev.events & EPOLLIN) &&
2952 0 : (vcl_session_read_ready (s) > 0))
2953 : {
2954 0 : vcl_epoll_ctl_add_unhandled_event (wrk, s, event->events & EPOLLET,
2955 : SESSION_IO_EVT_RX);
2956 : }
2957 0 : s->vep.et_mask = VEP_DEFAULT_ET_MASK;
2958 0 : s->vep.ev = *event;
2959 0 : s->vep.ev.events |= EPOLLHUP | EPOLLERR;
2960 :
2961 0 : VDBG (1, "EPOLL_CTL_MOD: vep_sh %u, sh %u, events 0x%x, data 0x%llx!",
2962 : vep_handle, session_handle, event->events, event->data.u64);
2963 0 : break;
2964 :
2965 41 : case EPOLL_CTL_DEL:
2966 41 : if (PREDICT_FALSE (!(s->flags & VCL_SESSION_F_IS_VEP_SESSION)))
2967 : {
2968 0 : VDBG (0, "EPOLL_CTL_DEL: %u not a vep session!", session_handle);
2969 0 : rv = VPPCOM_ENOENT;
2970 0 : goto done;
2971 : }
2972 41 : else if (PREDICT_FALSE (s->vep.vep_sh != vep_handle))
2973 : {
2974 0 : VDBG (0, "EPOLL_CTL_DEL: sh %u vep_sh (%u) != vep_sh (%u)!",
2975 : session_handle, s->vep.vep_sh, vep_handle);
2976 0 : rv = VPPCOM_EINVAL;
2977 0 : goto done;
2978 : }
2979 :
2980 41 : if (s->vep.prev_sh == vep_handle)
2981 34 : vep_session->vep.next_sh = s->vep.next_sh;
2982 : else
2983 : {
2984 : vcl_session_t *prev_session;
2985 7 : prev_session = vcl_session_get_w_handle (wrk, s->vep.prev_sh);
2986 7 : if (PREDICT_FALSE (!prev_session))
2987 : {
2988 0 : VDBG (0, "EPOLL_CTL_DEL: Invalid prev_sh (%u) on sh (%u)!",
2989 : s->vep.prev_sh, session_handle);
2990 0 : return VPPCOM_EBADFD;
2991 : }
2992 7 : ASSERT (prev_session->vep.next_sh == session_handle);
2993 7 : prev_session->vep.next_sh = s->vep.next_sh;
2994 : }
2995 41 : if (s->vep.next_sh != ~0)
2996 : {
2997 : vcl_session_t *next_session;
2998 40 : next_session = vcl_session_get_w_handle (wrk, s->vep.next_sh);
2999 40 : if (PREDICT_FALSE (!next_session))
3000 : {
3001 0 : VDBG (0, "EPOLL_CTL_DEL: Invalid next_sh (%u) on sh (%u)!",
3002 : s->vep.next_sh, session_handle);
3003 0 : return VPPCOM_EBADFD;
3004 : }
3005 40 : ASSERT (next_session->vep.prev_sh == session_handle);
3006 40 : next_session->vep.prev_sh = s->vep.prev_sh;
3007 : }
3008 :
3009 41 : if (s->vep.lt_next != VCL_INVALID_SESSION_INDEX)
3010 0 : vcl_epoll_lt_del (wrk, s);
3011 :
3012 41 : memset (&s->vep, 0, sizeof (s->vep));
3013 41 : s->vep.next_sh = ~0;
3014 41 : s->vep.prev_sh = ~0;
3015 41 : s->vep.vep_sh = ~0;
3016 41 : s->vep.lt_next = VCL_INVALID_SESSION_INDEX;
3017 41 : s->flags &= ~VCL_SESSION_F_IS_VEP_SESSION;
3018 :
3019 41 : if (vcl_session_is_open (s))
3020 27 : vcl_session_del_want_deq_ntf (s, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL);
3021 :
3022 41 : VDBG (1, "EPOLL_CTL_DEL: vep_idx %u, sh %u!", vep_handle,
3023 : session_handle);
3024 : vcl_evt (VCL_EVT_EPOLL_CTLDEL, s, vep_sh);
3025 41 : break;
3026 :
3027 0 : default:
3028 0 : VDBG (0, "Invalid operation (%d)!", op);
3029 0 : rv = VPPCOM_EINVAL;
3030 : }
3031 :
3032 94 : vep_verify_epoll_chain (wrk, vep_handle);
3033 :
3034 94 : done:
3035 94 : return rv;
3036 : }
3037 :
3038 : always_inline u8
3039 5017 : vcl_ep_session_needs_evt (vcl_session_t *s, u32 evt)
3040 : {
3041 : /* No event if not epolled / events reset on hup or level-trigger on */
3042 10034 : return ((s->vep.ev.events & evt) &&
3043 5017 : s->vep.lt_next == VCL_INVALID_SESSION_INDEX);
3044 : }
3045 :
3046 : static inline void
3047 5838 : vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
3048 : struct epoll_event *events, u32 * num_ev)
3049 : {
3050 : session_disconnected_msg_t *disconnected_msg;
3051 : session_connected_msg_t *connected_msg;
3052 5838 : u32 sid = ~0, session_events;
3053 5838 : u64 session_evt_data = ~0;
3054 : vcl_session_t *s;
3055 5838 : u8 add_event = 0;
3056 :
3057 5838 : switch (e->event_type)
3058 : {
3059 5771 : case SESSION_IO_EVT_RX:
3060 5771 : sid = e->session_index;
3061 5771 : s = vcl_session_get (wrk, sid);
3062 5771 : if (vcl_session_is_closed (s))
3063 1 : break;
3064 5770 : vcl_fifo_rx_evt_valid_or_break (s);
3065 4983 : if (!vcl_ep_session_needs_evt (s, EPOLLIN) ||
3066 4983 : (s->flags & VCL_SESSION_F_HAS_RX_EVT))
3067 : break;
3068 4975 : session_events = s->vep.ev.events;
3069 4975 : add_event = 1;
3070 4975 : events[*num_ev].events = EPOLLIN;
3071 4975 : session_evt_data = s->vep.ev.data.u64;
3072 4975 : s->flags |= VCL_SESSION_F_HAS_RX_EVT;
3073 4975 : break;
3074 0 : case SESSION_IO_EVT_TX:
3075 0 : sid = e->session_index;
3076 0 : s = vcl_session_get (wrk, sid);
3077 0 : if (!s || !vcl_session_is_open (s))
3078 : break;
3079 0 : svm_fifo_reset_has_deq_ntf (vcl_session_is_ct (s) ? s->ct_tx_fifo :
3080 : s->tx_fifo);
3081 0 : if (!vcl_ep_session_needs_evt (s, EPOLLOUT))
3082 0 : break;
3083 0 : session_events = s->vep.ev.events;
3084 0 : add_event = 1;
3085 0 : events[*num_ev].events = EPOLLOUT;
3086 0 : session_evt_data = s->vep.ev.data.u64;
3087 0 : break;
3088 28 : case SESSION_CTRL_EVT_ACCEPTED:
3089 28 : if (!e->postponed)
3090 28 : s = vcl_session_accepted (wrk, (session_accepted_msg_t *) e->data);
3091 : else
3092 0 : s = vcl_session_get (wrk, e->session_index);
3093 28 : if (!s || !vcl_ep_session_needs_evt (s, EPOLLIN))
3094 : break;
3095 28 : sid = s->session_index;
3096 28 : session_events = s->vep.ev.events;
3097 28 : add_event = 1;
3098 28 : events[*num_ev].events = EPOLLIN;
3099 28 : session_evt_data = s->vep.ev.data.u64;
3100 28 : break;
3101 0 : case SESSION_CTRL_EVT_CONNECTED:
3102 0 : if (!e->postponed)
3103 : {
3104 0 : connected_msg = (session_connected_msg_t *) e->data;
3105 0 : sid = vcl_session_connected_handler (wrk, connected_msg);
3106 : }
3107 : else
3108 0 : sid = e->session_index;
3109 0 : s = vcl_session_get (wrk, sid);
3110 0 : if (vcl_session_is_closed (s) || !vcl_ep_session_needs_evt (s, EPOLLOUT))
3111 : break;
3112 : /* We didn't have a fifo when the event was added */
3113 0 : vcl_session_add_want_deq_ntf (s, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL);
3114 0 : add_event = 1;
3115 0 : session_events = s->vep.ev.events;
3116 : /* Generate EPOLLOUT because there's no connected event */
3117 0 : events[*num_ev].events = EPOLLOUT;
3118 0 : session_evt_data = s->vep.ev.data.u64;
3119 0 : if (s->session_state == VCL_STATE_DETACHED)
3120 : {
3121 0 : events[*num_ev].events |= EPOLLHUP;
3122 0 : s->vep.ev.events = 0;
3123 : }
3124 0 : break;
3125 10 : case SESSION_CTRL_EVT_DISCONNECTED:
3126 10 : if (!e->postponed)
3127 : {
3128 10 : disconnected_msg = (session_disconnected_msg_t *) e->data;
3129 10 : s = vcl_session_disconnected_handler (wrk, disconnected_msg);
3130 : }
3131 : else
3132 : {
3133 0 : s = vcl_session_get (wrk, e->session_index);
3134 0 : s->flags &= ~VCL_SESSION_F_PENDING_DISCONNECT;
3135 : }
3136 10 : if (vcl_session_is_closed (s) || !vcl_ep_session_needs_evt (s, EPOLLHUP))
3137 : {
3138 5 : if (s && (s->flags & VCL_SESSION_F_PENDING_FREE))
3139 0 : vcl_session_free (wrk, s);
3140 5 : break;
3141 : }
3142 5 : sid = s->session_index;
3143 5 : session_events = s->vep.ev.events;
3144 5 : add_event = 1;
3145 5 : if (EPOLLRDHUP & session_events)
3146 : {
3147 : /* If app can distinguish between RDHUP and HUP,
3148 : * we make finer control */
3149 0 : events[*num_ev].events = EPOLLRDHUP;
3150 0 : if (s->flags & VCL_SESSION_F_WR_SHUTDOWN)
3151 : {
3152 0 : events[*num_ev].events |= EPOLLHUP;
3153 : }
3154 : }
3155 : else
3156 : {
3157 5 : events[*num_ev].events = EPOLLHUP;
3158 : }
3159 5 : session_evt_data = s->vep.ev.data.u64;
3160 5 : s->vep.ev.events = 0;
3161 5 : break;
3162 0 : case SESSION_CTRL_EVT_BOUND:
3163 0 : vcl_session_bound_handler (wrk, (session_bound_msg_t *) e->data);
3164 0 : break;
3165 2 : case SESSION_CTRL_EVT_RESET:
3166 2 : if (!e->postponed)
3167 : {
3168 : sid =
3169 2 : vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data);
3170 2 : s = vcl_session_get (wrk, sid);
3171 : }
3172 : else
3173 : {
3174 0 : sid = e->session_index;
3175 0 : s = vcl_session_get (wrk, sid);
3176 0 : s->flags &= ~VCL_SESSION_F_PENDING_DISCONNECT;
3177 : }
3178 2 : if (vcl_session_is_closed (s) || !vcl_ep_session_needs_evt (s, EPOLLHUP))
3179 : {
3180 1 : if (s && (s->flags & VCL_SESSION_F_PENDING_FREE))
3181 0 : vcl_session_free (wrk, s);
3182 1 : break;
3183 : }
3184 1 : session_events = s->vep.ev.events;
3185 1 : add_event = 1;
3186 1 : events[*num_ev].events = EPOLLERR | EPOLLHUP;
3187 1 : if ((EPOLLRDHUP & session_events) &&
3188 0 : (s->flags & VCL_SESSION_F_RD_SHUTDOWN))
3189 : {
3190 0 : events[*num_ev].events |= EPOLLRDHUP;
3191 : }
3192 1 : if ((EPOLLIN & session_events) && (s->flags & VCL_SESSION_F_RD_SHUTDOWN))
3193 : {
3194 1 : events[*num_ev].events |= EPOLLIN;
3195 : }
3196 1 : session_evt_data = s->vep.ev.data.u64;
3197 1 : s->vep.ev.events = 0;
3198 1 : break;
3199 0 : case SESSION_CTRL_EVT_UNLISTEN_REPLY:
3200 0 : vcl_session_unlisten_reply_handler (wrk, e->data);
3201 0 : break;
3202 0 : case SESSION_CTRL_EVT_MIGRATED:
3203 0 : vcl_session_migrated_handler (wrk, e->data);
3204 0 : break;
3205 5 : case SESSION_CTRL_EVT_CLEANUP:
3206 5 : vcl_session_cleanup_handler (wrk, e->data);
3207 5 : break;
3208 0 : case SESSION_CTRL_EVT_REQ_WORKER_UPDATE:
3209 0 : vcl_session_req_worker_update_handler (wrk, e->data);
3210 0 : break;
3211 0 : case SESSION_CTRL_EVT_WORKER_UPDATE_REPLY:
3212 0 : vcl_session_worker_update_reply_handler (wrk, e->data);
3213 0 : break;
3214 20 : case SESSION_CTRL_EVT_APP_ADD_SEGMENT:
3215 20 : vcl_session_app_add_segment_handler (wrk, e->data);
3216 20 : break;
3217 2 : case SESSION_CTRL_EVT_APP_DEL_SEGMENT:
3218 2 : vcl_session_app_del_segment_handler (wrk, e->data);
3219 2 : break;
3220 0 : case SESSION_CTRL_EVT_APP_WRK_RPC:
3221 0 : vcl_worker_rpc_handler (wrk, e->data);
3222 0 : break;
3223 0 : default:
3224 0 : VDBG (0, "unhandled: %u", e->event_type);
3225 0 : break;
3226 : }
3227 :
3228 5838 : if (add_event)
3229 : {
3230 5009 : ASSERT (s->flags & VCL_SESSION_F_IS_VEP_SESSION);
3231 5009 : events[*num_ev].data.u64 = session_evt_data;
3232 5009 : if (EPOLLONESHOT & session_events)
3233 : {
3234 0 : s = vcl_session_get (wrk, sid);
3235 0 : if (!(events[*num_ev].events & EPOLLHUP))
3236 0 : s->vep.ev.events = EPOLLHUP | EPOLLERR;
3237 : }
3238 5009 : else if (!(EPOLLET & session_events))
3239 : {
3240 0 : s = vcl_session_get (wrk, sid);
3241 0 : if (s->vep.lt_next == VCL_INVALID_SESSION_INDEX)
3242 0 : vcl_epoll_lt_add (wrk, s);
3243 : }
3244 5009 : *num_ev += 1;
3245 : }
3246 5838 : }
3247 :
3248 : static int
3249 122158000 : vcl_epoll_wait_handle_mq (vcl_worker_t * wrk, svm_msg_q_t * mq,
3250 : struct epoll_event *events, u32 maxevents,
3251 : double wait_for_time, u32 * num_ev)
3252 : {
3253 : svm_msg_q_msg_t *msg;
3254 : session_event_t *e;
3255 : int i;
3256 :
3257 122158000 : if (vec_len (wrk->mq_msg_vector) && svm_msg_q_is_empty (mq))
3258 0 : goto handle_dequeued;
3259 :
3260 122158000 : if (svm_msg_q_is_empty (mq))
3261 : {
3262 122153000 : if (!wait_for_time)
3263 122153000 : return 0;
3264 0 : else if (wait_for_time < 0)
3265 0 : svm_msg_q_wait (mq, SVM_MQ_WAIT_EMPTY);
3266 : else
3267 : {
3268 0 : if (svm_msg_q_timedwait (mq, wait_for_time / 1e3))
3269 0 : return 0;
3270 : }
3271 : }
3272 4860 : ASSERT (maxevents > *num_ev);
3273 4860 : vcl_mq_dequeue_batch (wrk, mq, ~0);
3274 :
3275 4860 : handle_dequeued:
3276 10698 : for (i = 0; i < vec_len (wrk->mq_msg_vector); i++)
3277 : {
3278 5838 : msg = vec_elt_at_index (wrk->mq_msg_vector, i);
3279 5838 : e = svm_msg_q_msg_data (mq, msg);
3280 5838 : if (*num_ev < maxevents)
3281 5838 : vcl_epoll_wait_handle_mq_event (wrk, e, events, num_ev);
3282 : else
3283 0 : vcl_handle_mq_event (wrk, e);
3284 5838 : svm_msg_q_free_msg (mq, msg);
3285 : }
3286 4860 : vec_reset_length (wrk->mq_msg_vector);
3287 4860 : vcl_handle_pending_wrk_updates (wrk);
3288 4860 : return *num_ev;
3289 : }
3290 :
3291 : static int
3292 122158000 : vppcom_epoll_wait_condvar (vcl_worker_t *wrk, struct epoll_event *events,
3293 : int maxevents, u32 n_evts, double timeout_ms)
3294 : {
3295 122158000 : double end = -1;
3296 :
3297 122158000 : if (!n_evts)
3298 : {
3299 122158000 : if (timeout_ms > 0)
3300 0 : end = clib_time_now (&wrk->clib_time) + (timeout_ms / 1e3);
3301 : }
3302 :
3303 : do
3304 : {
3305 122158000 : vcl_epoll_wait_handle_mq (wrk, wrk->app_event_queue, events, maxevents,
3306 : timeout_ms, &n_evts);
3307 122158000 : if (n_evts || !timeout_ms)
3308 122158000 : return n_evts;
3309 : }
3310 0 : while (end == -1 || clib_time_now (&wrk->clib_time) < end);
3311 :
3312 0 : return 0;
3313 : }
3314 :
3315 : static int
3316 0 : vppcom_epoll_wait_eventfd (vcl_worker_t *wrk, struct epoll_event *events,
3317 : int maxevents, u32 n_evts, double timeout_ms)
3318 : {
3319 : int __clib_unused n_read;
3320 : vcl_mq_evt_conn_t *mqc;
3321 : int n_mq_evts, i;
3322 0 : double end = -1;
3323 : u64 buf;
3324 :
3325 0 : if (PREDICT_FALSE (wrk->api_client_handle == ~0))
3326 : {
3327 0 : vcl_api_retry_attach (wrk);
3328 0 : return n_evts;
3329 : }
3330 :
3331 0 : vec_validate (wrk->mq_events, pool_elts (wrk->mq_evt_conns));
3332 0 : if (!n_evts)
3333 : {
3334 0 : if (timeout_ms > 0)
3335 0 : end = clib_time_now (&wrk->clib_time) + (timeout_ms / 1e3);
3336 : }
3337 :
3338 : do
3339 : {
3340 0 : n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events,
3341 0 : vec_len (wrk->mq_events), timeout_ms);
3342 0 : if (n_mq_evts < 0)
3343 : {
3344 0 : VDBG (0, "epoll_wait error %u", errno);
3345 0 : return n_evts;
3346 : }
3347 :
3348 0 : for (i = 0; i < n_mq_evts; i++)
3349 : {
3350 0 : if (PREDICT_FALSE (wrk->mq_events[i].data.u32 == ~0))
3351 : {
3352 : /* api socket was closed */
3353 0 : vcl_api_handle_disconnect (wrk);
3354 0 : continue;
3355 : }
3356 :
3357 0 : mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32);
3358 0 : n_read = read (mqc->mq_fd, &buf, sizeof (buf));
3359 0 : vcl_epoll_wait_handle_mq (wrk, mqc->mq, events, maxevents, 0,
3360 : &n_evts);
3361 : }
3362 :
3363 0 : if (n_evts || !timeout_ms)
3364 0 : return n_evts;
3365 : }
3366 0 : while (end == -1 || clib_time_now (&wrk->clib_time) < end);
3367 :
3368 0 : return 0;
3369 : }
3370 :
3371 : static void
3372 0 : vcl_epoll_wait_handle_lt (vcl_worker_t *wrk, struct epoll_event *events,
3373 : int maxevents, u32 *n_evts)
3374 : {
3375 0 : u32 add_event = 0, evt_flags = 0, next, *to_remove = 0, *si;
3376 : vcl_session_t *s;
3377 : u64 evt_data;
3378 : int rv;
3379 :
3380 0 : ASSERT (wrk->ep_lt_current != VCL_INVALID_SESSION_INDEX);
3381 0 : if (*n_evts >= maxevents)
3382 0 : return;
3383 :
3384 0 : next = wrk->ep_lt_current;
3385 : do
3386 : {
3387 0 : s = vcl_session_get (wrk, next);
3388 0 : next = s->vep.lt_next;
3389 :
3390 0 : if (s->vep.ev.events == 0)
3391 : {
3392 0 : vec_add1 (to_remove, s->session_index);
3393 0 : continue;
3394 : }
3395 0 : if ((s->vep.ev.events & EPOLLIN) && (rv = vcl_session_read_ready (s)))
3396 : {
3397 0 : add_event = 1;
3398 0 : evt_flags |= rv > 0 ? EPOLLIN : EPOLLHUP | EPOLLRDHUP;
3399 0 : evt_data = s->vep.ev.data.u64;
3400 : }
3401 0 : if ((s->vep.ev.events & EPOLLOUT) && (rv = vcl_session_write_ready (s)))
3402 : {
3403 0 : add_event = 1;
3404 0 : evt_flags |= rv > 0 ? EPOLLOUT : EPOLLHUP | EPOLLRDHUP;
3405 0 : evt_data = s->vep.ev.data.u64;
3406 : }
3407 0 : if (!add_event && s->session_state > VCL_STATE_READY)
3408 : {
3409 0 : add_event = 1;
3410 0 : evt_flags |= EPOLLHUP | EPOLLRDHUP;
3411 0 : evt_data = s->vep.ev.data.u64;
3412 : }
3413 0 : if (add_event)
3414 : {
3415 0 : events[*n_evts].events = evt_flags;
3416 0 : events[*n_evts].data.u64 = evt_data;
3417 0 : if (EPOLLONESHOT & s->vep.ev.events)
3418 0 : s->vep.ev.events = EPOLLHUP | EPOLLERR;
3419 0 : if (evt_flags & EPOLLHUP)
3420 0 : s->vep.ev.events = 0;
3421 0 : *n_evts += 1;
3422 0 : add_event = 0;
3423 0 : evt_flags = 0;
3424 0 : if (*n_evts == maxevents)
3425 : {
3426 0 : wrk->ep_lt_current = next;
3427 0 : break;
3428 : }
3429 : }
3430 : else
3431 : {
3432 0 : vec_add1 (to_remove, s->session_index);
3433 : }
3434 : }
3435 0 : while (next != wrk->ep_lt_current);
3436 :
3437 0 : vec_foreach (si, to_remove)
3438 : {
3439 0 : s = vcl_session_get (wrk, *si);
3440 0 : vcl_epoll_lt_del (wrk, s);
3441 : }
3442 0 : vec_free (to_remove);
3443 : }
3444 :
3445 : int
3446 122158000 : vppcom_epoll_wait (uint32_t vep_handle, struct epoll_event *events,
3447 : int maxevents, double wait_for_time)
3448 : {
3449 122158000 : vcl_worker_t *wrk = vcl_worker_get_current ();
3450 : vcl_session_t *vep_session;
3451 122158000 : u32 n_evts = 0;
3452 : int i;
3453 :
3454 122158000 : if (PREDICT_FALSE (maxevents <= 0))
3455 : {
3456 0 : VDBG (0, "ERROR: Invalid maxevents (%d)!", maxevents);
3457 0 : return VPPCOM_EINVAL;
3458 : }
3459 :
3460 122158000 : vep_session = vcl_session_get_w_handle (wrk, vep_handle);
3461 122158000 : if (!vep_session)
3462 0 : return VPPCOM_EBADFD;
3463 :
3464 122158000 : if (PREDICT_FALSE (!(vep_session->flags & VCL_SESSION_F_IS_VEP)))
3465 : {
3466 0 : VDBG (0, "ERROR: vep_idx (%u) is not a vep!", vep_handle);
3467 0 : return VPPCOM_EINVAL;
3468 : }
3469 :
3470 122158000 : if (vec_len (wrk->unhandled_evts_vector))
3471 : {
3472 0 : for (i = 0; i < vec_len (wrk->unhandled_evts_vector); i++)
3473 : {
3474 0 : vcl_epoll_wait_handle_mq_event (wrk, &wrk->unhandled_evts_vector[i],
3475 : events, &n_evts);
3476 0 : if (n_evts == maxevents)
3477 : {
3478 0 : vec_delete (wrk->unhandled_evts_vector, i + 1, 0);
3479 0 : return n_evts;
3480 : }
3481 : }
3482 0 : vec_reset_length (wrk->unhandled_evts_vector);
3483 : }
3484 :
3485 122158000 : if (PREDICT_FALSE (wrk->ep_lt_current != VCL_INVALID_SESSION_INDEX))
3486 0 : vcl_epoll_wait_handle_lt (wrk, events, maxevents, &n_evts);
3487 :
3488 : /* Request to only drain unhandled */
3489 122158000 : if ((int) wait_for_time == -2)
3490 0 : return n_evts;
3491 :
3492 :
3493 122158000 : if (vcm->cfg.use_mq_eventfd)
3494 0 : n_evts = vppcom_epoll_wait_eventfd (wrk, events, maxevents, n_evts,
3495 : wait_for_time);
3496 : else
3497 122158000 : n_evts = vppcom_epoll_wait_condvar (wrk, events, maxevents, n_evts,
3498 : wait_for_time);
3499 :
3500 122158000 : return n_evts;
3501 : }
3502 :
3503 : int
3504 6567 : vppcom_session_attr (uint32_t session_handle, uint32_t op,
3505 : void *buffer, uint32_t * buflen)
3506 : {
3507 6567 : vcl_worker_t *wrk = vcl_worker_get_current ();
3508 6567 : u32 *flags = buffer;
3509 6567 : vppcom_endpt_t *ep = buffer;
3510 : transport_endpt_attr_t tea;
3511 : vcl_session_t *session;
3512 6567 : int rv = VPPCOM_OK;
3513 :
3514 6567 : session = vcl_session_get_w_handle (wrk, session_handle);
3515 6567 : if (!session)
3516 0 : return VPPCOM_EBADFD;
3517 :
3518 6567 : switch (op)
3519 : {
3520 6128 : case VPPCOM_ATTR_GET_NREAD:
3521 6128 : rv = vcl_session_read_ready (session);
3522 6128 : VDBG (2, "VPPCOM_ATTR_GET_NREAD: sh %u, nread = %d", session_handle,
3523 : rv);
3524 6128 : break;
3525 :
3526 0 : case VPPCOM_ATTR_GET_NWRITE:
3527 0 : rv = vcl_session_write_ready (session);
3528 0 : VDBG (2, "VPPCOM_ATTR_GET_NWRITE: sh %u, nwrite = %d", session_handle,
3529 : rv);
3530 0 : break;
3531 :
3532 14 : case VPPCOM_ATTR_GET_FLAGS:
3533 14 : if (PREDICT_TRUE (buffer && buflen && (*buflen >= sizeof (*flags))))
3534 : {
3535 14 : *flags =
3536 14 : O_RDWR |
3537 14 : (vcl_session_has_attr (session, VCL_SESS_ATTR_NONBLOCK) ?
3538 : O_NONBLOCK : 0);
3539 14 : *buflen = sizeof (*flags);
3540 14 : VDBG (2, "VPPCOM_ATTR_GET_FLAGS: sh %u, flags = 0x%08x, "
3541 : "is_nonblocking = %u", session_handle, *flags,
3542 : vcl_session_has_attr (session, VCL_SESS_ATTR_NONBLOCK));
3543 : }
3544 : else
3545 0 : rv = VPPCOM_EINVAL;
3546 14 : break;
3547 :
3548 37 : case VPPCOM_ATTR_SET_FLAGS:
3549 37 : if (PREDICT_TRUE (buffer && buflen && (*buflen == sizeof (*flags))))
3550 : {
3551 37 : if (*flags & O_NONBLOCK)
3552 33 : vcl_session_set_attr (session, VCL_SESS_ATTR_NONBLOCK);
3553 : else
3554 4 : vcl_session_clear_attr (session, VCL_SESS_ATTR_NONBLOCK);
3555 :
3556 37 : VDBG (2, "VPPCOM_ATTR_SET_FLAGS: sh %u, flags = 0x%08x,"
3557 : " is_nonblocking = %u", session_handle, *flags,
3558 : vcl_session_has_attr (session, VCL_SESS_ATTR_NONBLOCK));
3559 : }
3560 : else
3561 0 : rv = VPPCOM_EINVAL;
3562 37 : break;
3563 :
3564 17 : case VPPCOM_ATTR_GET_PEER_ADDR:
3565 17 : if (PREDICT_TRUE (buffer && buflen &&
3566 : (*buflen >= sizeof (*ep)) && ep->ip))
3567 : {
3568 17 : ep->is_ip4 = session->transport.is_ip4;
3569 17 : ep->port = session->transport.rmt_port;
3570 17 : if (session->transport.is_ip4)
3571 14 : clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip4,
3572 : sizeof (ip4_address_t));
3573 : else
3574 3 : clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip6,
3575 : sizeof (ip6_address_t));
3576 17 : *buflen = sizeof (*ep);
3577 17 : VDBG (1,
3578 : "VPPCOM_ATTR_GET_PEER_ADDR: sh %u, is_ip4 = %u, "
3579 : "addr = %U, port %u",
3580 : session_handle, ep->is_ip4, vcl_format_ip46_address,
3581 : &session->transport.rmt_ip,
3582 : ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
3583 : clib_net_to_host_u16 (ep->port));
3584 : }
3585 : else
3586 0 : rv = VPPCOM_EINVAL;
3587 17 : break;
3588 :
3589 29 : case VPPCOM_ATTR_GET_LCL_ADDR:
3590 29 : if (PREDICT_TRUE (buffer && buflen &&
3591 : (*buflen >= sizeof (*ep)) && ep->ip))
3592 : {
3593 29 : ep->is_ip4 = session->transport.is_ip4;
3594 29 : ep->port = session->transport.lcl_port;
3595 29 : if (session->transport.is_ip4)
3596 24 : clib_memcpy_fast (ep->ip, &session->transport.lcl_ip.ip4,
3597 : sizeof (ip4_address_t));
3598 : else
3599 5 : clib_memcpy_fast (ep->ip, &session->transport.lcl_ip.ip6,
3600 : sizeof (ip6_address_t));
3601 29 : *buflen = sizeof (*ep);
3602 29 : VDBG (1,
3603 : "VPPCOM_ATTR_GET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U"
3604 : " port %d",
3605 : session_handle, ep->is_ip4, vcl_format_ip46_address,
3606 : &session->transport.lcl_ip,
3607 : ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
3608 : clib_net_to_host_u16 (ep->port));
3609 : }
3610 : else
3611 0 : rv = VPPCOM_EINVAL;
3612 29 : break;
3613 :
3614 0 : case VPPCOM_ATTR_SET_LCL_ADDR:
3615 0 : if (PREDICT_TRUE (buffer && buflen &&
3616 : (*buflen >= sizeof (*ep)) && ep->ip))
3617 : {
3618 0 : session->transport.is_ip4 = ep->is_ip4;
3619 0 : session->transport.lcl_port = ep->port;
3620 0 : vcl_ip_copy_from_ep (&session->transport.lcl_ip, ep);
3621 0 : *buflen = sizeof (*ep);
3622 0 : VDBG (1,
3623 : "VPPCOM_ATTR_SET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U"
3624 : " port %d",
3625 : session_handle, ep->is_ip4, vcl_format_ip46_address,
3626 : &session->transport.lcl_ip,
3627 : ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
3628 : clib_net_to_host_u16 (ep->port));
3629 : }
3630 : else
3631 0 : rv = VPPCOM_EINVAL;
3632 0 : break;
3633 :
3634 287 : case VPPCOM_ATTR_GET_LIBC_EPFD:
3635 287 : rv = session->libc_epfd;
3636 287 : VDBG (2, "VPPCOM_ATTR_GET_LIBC_EPFD: libc_epfd %d", rv);
3637 287 : break;
3638 :
3639 1 : case VPPCOM_ATTR_SET_LIBC_EPFD:
3640 1 : if (PREDICT_TRUE (buffer && buflen &&
3641 : (*buflen == sizeof (session->libc_epfd))))
3642 : {
3643 1 : session->libc_epfd = *(int *) buffer;
3644 1 : *buflen = sizeof (session->libc_epfd);
3645 :
3646 1 : VDBG (2, "VPPCOM_ATTR_SET_LIBC_EPFD: libc_epfd %d, buflen %d",
3647 : session->libc_epfd, *buflen);
3648 : }
3649 : else
3650 0 : rv = VPPCOM_EINVAL;
3651 1 : break;
3652 :
3653 0 : case VPPCOM_ATTR_GET_PROTOCOL:
3654 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3655 : {
3656 0 : *(int *) buffer = session->session_type;
3657 0 : *buflen = sizeof (int);
3658 :
3659 0 : VDBG (2, "VPPCOM_ATTR_GET_PROTOCOL: %d (%s), buflen %d",
3660 : *(int *) buffer, *(int *) buffer ? "UDP" : "TCP", *buflen);
3661 : }
3662 : else
3663 0 : rv = VPPCOM_EINVAL;
3664 0 : break;
3665 :
3666 0 : case VPPCOM_ATTR_GET_LISTEN:
3667 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3668 : {
3669 0 : *(int *) buffer = vcl_session_has_attr (session,
3670 : VCL_SESS_ATTR_LISTEN);
3671 0 : *buflen = sizeof (int);
3672 :
3673 0 : VDBG (2, "VPPCOM_ATTR_GET_LISTEN: %d, buflen %d", *(int *) buffer,
3674 : *buflen);
3675 : }
3676 : else
3677 0 : rv = VPPCOM_EINVAL;
3678 0 : break;
3679 :
3680 0 : case VPPCOM_ATTR_GET_ERROR:
3681 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3682 : {
3683 0 : *(int *) buffer = 0;
3684 0 : *buflen = sizeof (int);
3685 :
3686 0 : VDBG (2, "VPPCOM_ATTR_GET_ERROR: %d, buflen %d, #VPP-TBD#",
3687 : *(int *) buffer, *buflen);
3688 : }
3689 : else
3690 0 : rv = VPPCOM_EINVAL;
3691 0 : break;
3692 :
3693 12 : case VPPCOM_ATTR_GET_TX_FIFO_LEN:
3694 12 : if (buffer && buflen && (*buflen >= sizeof (u32)))
3695 : {
3696 :
3697 : /* VPP-TBD */
3698 24 : *(size_t *) buffer = (session->sndbuf_size ? session->sndbuf_size :
3699 12 : session->tx_fifo ?
3700 4 : svm_fifo_size (session->tx_fifo) :
3701 8 : vcm->cfg.tx_fifo_size);
3702 12 : *buflen = sizeof (u32);
3703 :
3704 12 : VDBG (2, "VPPCOM_ATTR_GET_TX_FIFO_LEN: %u (0x%x), buflen %d,"
3705 : " #VPP-TBD#", *(size_t *) buffer, *(size_t *) buffer,
3706 : *buflen);
3707 : }
3708 : else
3709 0 : rv = VPPCOM_EINVAL;
3710 12 : break;
3711 :
3712 0 : case VPPCOM_ATTR_SET_DSCP:
3713 0 : if (buffer && buflen && (*buflen >= sizeof (u8)))
3714 : {
3715 0 : session->dscp = *(u8 *) buffer;
3716 :
3717 0 : VDBG (2, "VPPCOM_ATTR_SET_DSCP: %u (0x%x), buflen %d,",
3718 : *(u8 *) buffer, *(u8 *) buffer, *buflen);
3719 : }
3720 : else
3721 0 : rv = VPPCOM_EINVAL;
3722 0 : break;
3723 :
3724 0 : case VPPCOM_ATTR_SET_TX_FIFO_LEN:
3725 0 : if (buffer && buflen && (*buflen == sizeof (u32)))
3726 : {
3727 : /* VPP-TBD */
3728 0 : session->sndbuf_size = *(u32 *) buffer;
3729 0 : VDBG (2, "VPPCOM_ATTR_SET_TX_FIFO_LEN: %u (0x%x), buflen %d,"
3730 : " #VPP-TBD#", session->sndbuf_size, session->sndbuf_size,
3731 : *buflen);
3732 : }
3733 : else
3734 0 : rv = VPPCOM_EINVAL;
3735 0 : break;
3736 :
3737 12 : case VPPCOM_ATTR_GET_RX_FIFO_LEN:
3738 12 : if (buffer && buflen && (*buflen >= sizeof (u32)))
3739 : {
3740 :
3741 : /* VPP-TBD */
3742 24 : *(size_t *) buffer = (session->rcvbuf_size ? session->rcvbuf_size :
3743 12 : session->rx_fifo ?
3744 4 : svm_fifo_size (session->rx_fifo) :
3745 8 : vcm->cfg.rx_fifo_size);
3746 12 : *buflen = sizeof (u32);
3747 :
3748 12 : VDBG (2, "VPPCOM_ATTR_GET_RX_FIFO_LEN: %u (0x%x), buflen %d, "
3749 : "#VPP-TBD#", *(size_t *) buffer, *(size_t *) buffer, *buflen);
3750 : }
3751 : else
3752 0 : rv = VPPCOM_EINVAL;
3753 12 : break;
3754 :
3755 0 : case VPPCOM_ATTR_SET_RX_FIFO_LEN:
3756 0 : if (buffer && buflen && (*buflen == sizeof (u32)))
3757 : {
3758 : /* VPP-TBD */
3759 0 : session->rcvbuf_size = *(u32 *) buffer;
3760 0 : VDBG (2, "VPPCOM_ATTR_SET_RX_FIFO_LEN: %u (0x%x), buflen %d,"
3761 : " #VPP-TBD#", session->sndbuf_size, session->sndbuf_size,
3762 : *buflen);
3763 : }
3764 : else
3765 0 : rv = VPPCOM_EINVAL;
3766 0 : break;
3767 :
3768 0 : case VPPCOM_ATTR_GET_REUSEADDR:
3769 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3770 : {
3771 : /* VPP-TBD */
3772 0 : *(int *) buffer = vcl_session_has_attr (session,
3773 : VCL_SESS_ATTR_REUSEADDR);
3774 0 : *buflen = sizeof (int);
3775 :
3776 0 : VDBG (2, "VPPCOM_ATTR_GET_REUSEADDR: %d, buflen %d, #VPP-TBD#",
3777 : *(int *) buffer, *buflen);
3778 : }
3779 : else
3780 0 : rv = VPPCOM_EINVAL;
3781 0 : break;
3782 :
3783 15 : case VPPCOM_ATTR_SET_REUSEADDR:
3784 30 : if (buffer && buflen && (*buflen == sizeof (int)) &&
3785 15 : !vcl_session_has_attr (session, VCL_SESS_ATTR_LISTEN))
3786 : {
3787 : /* VPP-TBD */
3788 15 : if (*(int *) buffer)
3789 15 : vcl_session_set_attr (session, VCL_SESS_ATTR_REUSEADDR);
3790 : else
3791 0 : vcl_session_clear_attr (session, VCL_SESS_ATTR_REUSEADDR);
3792 :
3793 15 : VDBG (2, "VPPCOM_ATTR_SET_REUSEADDR: %d, buflen %d, #VPP-TBD#",
3794 : vcl_session_has_attr (session, VCL_SESS_ATTR_REUSEADDR),
3795 : *buflen);
3796 : }
3797 : else
3798 0 : rv = VPPCOM_EINVAL;
3799 15 : break;
3800 :
3801 0 : case VPPCOM_ATTR_GET_REUSEPORT:
3802 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3803 : {
3804 : /* VPP-TBD */
3805 0 : *(int *) buffer = vcl_session_has_attr (session,
3806 : VCL_SESS_ATTR_REUSEPORT);
3807 0 : *buflen = sizeof (int);
3808 :
3809 0 : VDBG (2, "VPPCOM_ATTR_GET_REUSEPORT: %d, buflen %d, #VPP-TBD#",
3810 : *(int *) buffer, *buflen);
3811 : }
3812 : else
3813 0 : rv = VPPCOM_EINVAL;
3814 0 : break;
3815 :
3816 0 : case VPPCOM_ATTR_SET_REUSEPORT:
3817 0 : if (buffer && buflen && (*buflen == sizeof (int)) &&
3818 0 : !vcl_session_has_attr (session, VCL_SESS_ATTR_LISTEN))
3819 : {
3820 : /* VPP-TBD */
3821 0 : if (*(int *) buffer)
3822 0 : vcl_session_set_attr (session, VCL_SESS_ATTR_REUSEPORT);
3823 : else
3824 0 : vcl_session_clear_attr (session, VCL_SESS_ATTR_REUSEPORT);
3825 :
3826 0 : VDBG (2, "VPPCOM_ATTR_SET_REUSEPORT: %d, buflen %d, #VPP-TBD#",
3827 : vcl_session_has_attr (session, VCL_SESS_ATTR_REUSEPORT),
3828 : *buflen);
3829 : }
3830 : else
3831 0 : rv = VPPCOM_EINVAL;
3832 0 : break;
3833 :
3834 0 : case VPPCOM_ATTR_GET_BROADCAST:
3835 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3836 : {
3837 : /* VPP-TBD */
3838 0 : *(int *) buffer = vcl_session_has_attr (session,
3839 : VCL_SESS_ATTR_BROADCAST);
3840 0 : *buflen = sizeof (int);
3841 :
3842 0 : VDBG (2, "VPPCOM_ATTR_GET_BROADCAST: %d, buflen %d, #VPP-TBD#",
3843 : *(int *) buffer, *buflen);
3844 : }
3845 : else
3846 0 : rv = VPPCOM_EINVAL;
3847 0 : break;
3848 :
3849 0 : case VPPCOM_ATTR_SET_BROADCAST:
3850 0 : if (buffer && buflen && (*buflen == sizeof (int)))
3851 : {
3852 : /* VPP-TBD */
3853 0 : if (*(int *) buffer)
3854 0 : vcl_session_set_attr (session, VCL_SESS_ATTR_BROADCAST);
3855 : else
3856 0 : vcl_session_clear_attr (session, VCL_SESS_ATTR_BROADCAST);
3857 :
3858 0 : VDBG (2, "VPPCOM_ATTR_SET_BROADCAST: %d, buflen %d, #VPP-TBD#",
3859 : vcl_session_has_attr (session, VCL_SESS_ATTR_BROADCAST),
3860 : *buflen);
3861 : }
3862 : else
3863 0 : rv = VPPCOM_EINVAL;
3864 0 : break;
3865 :
3866 0 : case VPPCOM_ATTR_GET_V6ONLY:
3867 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3868 : {
3869 : /* VPP-TBD */
3870 0 : *(int *) buffer = vcl_session_has_attr (session,
3871 : VCL_SESS_ATTR_V6ONLY);
3872 0 : *buflen = sizeof (int);
3873 :
3874 0 : VDBG (2, "VPPCOM_ATTR_GET_V6ONLY: %d, buflen %d, #VPP-TBD#",
3875 : *(int *) buffer, *buflen);
3876 : }
3877 : else
3878 0 : rv = VPPCOM_EINVAL;
3879 0 : break;
3880 :
3881 2 : case VPPCOM_ATTR_SET_V6ONLY:
3882 2 : if (buffer && buflen && (*buflen == sizeof (int)))
3883 : {
3884 : /* VPP-TBD */
3885 2 : if (*(int *) buffer)
3886 2 : vcl_session_set_attr (session, VCL_SESS_ATTR_V6ONLY);
3887 : else
3888 0 : vcl_session_clear_attr (session, VCL_SESS_ATTR_V6ONLY);
3889 :
3890 2 : VDBG (2, "VPPCOM_ATTR_SET_V6ONLY: %d, buflen %d, #VPP-TBD#",
3891 : vcl_session_has_attr (session, VCL_SESS_ATTR_V6ONLY),
3892 : *buflen);
3893 : }
3894 : else
3895 0 : rv = VPPCOM_EINVAL;
3896 2 : break;
3897 :
3898 0 : case VPPCOM_ATTR_GET_KEEPALIVE:
3899 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3900 : {
3901 : /* VPP-TBD */
3902 0 : *(int *) buffer = vcl_session_has_attr (session,
3903 : VCL_SESS_ATTR_KEEPALIVE);
3904 0 : *buflen = sizeof (int);
3905 :
3906 0 : VDBG (2, "VPPCOM_ATTR_GET_KEEPALIVE: %d, buflen %d, #VPP-TBD#",
3907 : *(int *) buffer, *buflen);
3908 : }
3909 : else
3910 0 : rv = VPPCOM_EINVAL;
3911 0 : break;
3912 :
3913 0 : case VPPCOM_ATTR_SET_KEEPALIVE:
3914 0 : if (buffer && buflen && (*buflen == sizeof (int)))
3915 : {
3916 : /* VPP-TBD */
3917 0 : if (*(int *) buffer)
3918 0 : vcl_session_set_attr (session, VCL_SESS_ATTR_KEEPALIVE);
3919 : else
3920 0 : vcl_session_clear_attr (session, VCL_SESS_ATTR_KEEPALIVE);
3921 :
3922 0 : VDBG (2, "VPPCOM_ATTR_SET_KEEPALIVE: %d, buflen %d, #VPP-TBD#",
3923 : vcl_session_has_attr (session, VCL_SESS_ATTR_KEEPALIVE),
3924 : *buflen);
3925 : }
3926 : else
3927 0 : rv = VPPCOM_EINVAL;
3928 0 : break;
3929 :
3930 0 : case VPPCOM_ATTR_GET_TCP_NODELAY:
3931 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3932 : {
3933 : /* VPP-TBD */
3934 0 : *(int *) buffer = vcl_session_has_attr (session,
3935 : VCL_SESS_ATTR_TCP_NODELAY);
3936 0 : *buflen = sizeof (int);
3937 :
3938 0 : VDBG (2, "VPPCOM_ATTR_GET_TCP_NODELAY: %d, buflen %d, #VPP-TBD#",
3939 : *(int *) buffer, *buflen);
3940 : }
3941 : else
3942 0 : rv = VPPCOM_EINVAL;
3943 0 : break;
3944 :
3945 0 : case VPPCOM_ATTR_SET_TCP_NODELAY:
3946 0 : if (buffer && buflen && (*buflen == sizeof (int)))
3947 : {
3948 : /* VPP-TBD */
3949 0 : if (*(int *) buffer)
3950 0 : vcl_session_set_attr (session, VCL_SESS_ATTR_TCP_NODELAY);
3951 : else
3952 0 : vcl_session_clear_attr (session, VCL_SESS_ATTR_TCP_NODELAY);
3953 :
3954 0 : VDBG (2, "VPPCOM_ATTR_SET_TCP_NODELAY: %d, buflen %d, #VPP-TBD#",
3955 : vcl_session_has_attr (session, VCL_SESS_ATTR_TCP_NODELAY),
3956 : *buflen);
3957 : }
3958 : else
3959 0 : rv = VPPCOM_EINVAL;
3960 0 : break;
3961 :
3962 0 : case VPPCOM_ATTR_GET_TCP_KEEPIDLE:
3963 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3964 : {
3965 : /* VPP-TBD */
3966 0 : *(int *) buffer = vcl_session_has_attr (session,
3967 : VCL_SESS_ATTR_TCP_KEEPIDLE);
3968 0 : *buflen = sizeof (int);
3969 :
3970 0 : VDBG (2, "VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d, buflen %d, #VPP-TBD#",
3971 : *(int *) buffer, *buflen);
3972 : }
3973 : else
3974 0 : rv = VPPCOM_EINVAL;
3975 0 : break;
3976 :
3977 0 : case VPPCOM_ATTR_SET_TCP_KEEPIDLE:
3978 0 : if (buffer && buflen && (*buflen == sizeof (int)))
3979 : {
3980 : /* VPP-TBD */
3981 0 : if (*(int *) buffer)
3982 0 : vcl_session_set_attr (session, VCL_SESS_ATTR_TCP_KEEPIDLE);
3983 : else
3984 0 : vcl_session_clear_attr (session, VCL_SESS_ATTR_TCP_KEEPIDLE);
3985 :
3986 0 : VDBG (2, "VPPCOM_ATTR_SET_TCP_KEEPIDLE: %d, buflen %d, #VPP-TBD#",
3987 : vcl_session_has_attr (session,
3988 : VCL_SESS_ATTR_TCP_KEEPIDLE), *buflen);
3989 : }
3990 : else
3991 0 : rv = VPPCOM_EINVAL;
3992 0 : break;
3993 :
3994 0 : case VPPCOM_ATTR_GET_TCP_KEEPINTVL:
3995 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
3996 : {
3997 : /* VPP-TBD */
3998 0 : *(int *) buffer = vcl_session_has_attr (session,
3999 : VCL_SESS_ATTR_TCP_KEEPINTVL);
4000 0 : *buflen = sizeof (int);
4001 :
4002 0 : VDBG (2, "VPPCOM_ATTR_GET_TCP_KEEPINTVL: %d, buflen %d, #VPP-TBD#",
4003 : *(int *) buffer, *buflen);
4004 : }
4005 : else
4006 0 : rv = VPPCOM_EINVAL;
4007 0 : break;
4008 :
4009 0 : case VPPCOM_ATTR_SET_TCP_KEEPINTVL:
4010 0 : if (buffer && buflen && (*buflen == sizeof (int)))
4011 : {
4012 : /* VPP-TBD */
4013 0 : if (*(int *) buffer)
4014 0 : vcl_session_set_attr (session, VCL_SESS_ATTR_TCP_KEEPINTVL);
4015 : else
4016 0 : vcl_session_clear_attr (session, VCL_SESS_ATTR_TCP_KEEPINTVL);
4017 :
4018 0 : VDBG (2, "VPPCOM_ATTR_SET_TCP_KEEPINTVL: %d, buflen %d, #VPP-TBD#",
4019 : vcl_session_has_attr (session,
4020 : VCL_SESS_ATTR_TCP_KEEPINTVL), *buflen);
4021 : }
4022 : else
4023 0 : rv = VPPCOM_EINVAL;
4024 0 : break;
4025 :
4026 5 : case VPPCOM_ATTR_GET_TCP_USER_MSS:
4027 5 : if (!(buffer && buflen && (*buflen >= sizeof (u32))))
4028 : {
4029 0 : rv = VPPCOM_EINVAL;
4030 0 : break;
4031 : }
4032 :
4033 5 : tea.type = TRANSPORT_ENDPT_ATTR_MSS;
4034 5 : tea.mss = *(u32 *) buffer;
4035 5 : if (vcl_session_transport_attr (wrk, session, 1 /* is_get */, &tea))
4036 2 : rv = VPPCOM_ENOPROTOOPT;
4037 :
4038 5 : if (!rv)
4039 : {
4040 3 : *(u32 *) buffer = tea.mss;
4041 3 : *buflen = sizeof (int);
4042 : }
4043 :
4044 5 : VDBG (2, "VPPCOM_ATTR_GET_TCP_USER_MSS: %d, buflen %d", *(int *) buffer,
4045 : *buflen);
4046 5 : break;
4047 2 : case VPPCOM_ATTR_SET_TCP_USER_MSS:
4048 2 : if (!(buffer && buflen && (*buflen == sizeof (u32))))
4049 : {
4050 0 : rv = VPPCOM_EINVAL;
4051 0 : break;
4052 : }
4053 :
4054 2 : tea.type = TRANSPORT_ENDPT_ATTR_MSS;
4055 2 : tea.mss = *(u32 *) buffer;
4056 2 : if (vcl_session_transport_attr (wrk, session, 0 /* is_get */, &tea))
4057 0 : rv = VPPCOM_ENOPROTOOPT;
4058 :
4059 2 : VDBG (2, "VPPCOM_ATTR_SET_TCP_USER_MSS: %u, buflen %d", tea.mss,
4060 : *buflen);
4061 2 : break;
4062 :
4063 0 : case VPPCOM_ATTR_SET_CONNECTED:
4064 0 : session->flags |= VCL_SESSION_F_CONNECTED;
4065 0 : break;
4066 :
4067 6 : case VPPCOM_ATTR_SET_CKPAIR:
4068 12 : if (!(buffer && buflen && (*buflen == sizeof (int))) ||
4069 6 : !vcl_session_has_crypto (session))
4070 : {
4071 0 : rv = VPPCOM_EINVAL;
4072 0 : break;
4073 : }
4074 6 : if (!session->ext_config)
4075 : {
4076 6 : vcl_session_alloc_ext_cfg (session, TRANSPORT_ENDPT_EXT_CFG_CRYPTO,
4077 : sizeof (transport_endpt_ext_cfg_t));
4078 : }
4079 0 : else if (session->ext_config->type != TRANSPORT_ENDPT_EXT_CFG_CRYPTO)
4080 : {
4081 0 : rv = VPPCOM_EINVAL;
4082 0 : break;
4083 : }
4084 :
4085 6 : session->ext_config->crypto.ckpair_index = *(uint32_t *) buffer;
4086 6 : break;
4087 :
4088 0 : case VPPCOM_ATTR_SET_VRF:
4089 0 : if (!(buffer && buflen && (*buflen == sizeof (u32))))
4090 : {
4091 0 : rv = VPPCOM_EINVAL;
4092 0 : break;
4093 : }
4094 0 : session->vrf = *(u32 *) buffer;
4095 0 : break;
4096 :
4097 0 : case VPPCOM_ATTR_GET_VRF:
4098 0 : if (!(buffer && buflen && (*buflen >= sizeof (u32))))
4099 : {
4100 0 : rv = VPPCOM_EINVAL;
4101 0 : break;
4102 : }
4103 0 : *(u32 *) buffer = session->vrf;
4104 0 : *buflen = sizeof (u32);
4105 0 : break;
4106 :
4107 0 : case VPPCOM_ATTR_GET_DOMAIN:
4108 0 : if (!(buffer && buflen && (*buflen >= sizeof (int))))
4109 : {
4110 0 : rv = VPPCOM_EINVAL;
4111 0 : break;
4112 : }
4113 :
4114 0 : if (session->transport.is_ip4)
4115 0 : *(int *) buffer = AF_INET;
4116 : else
4117 0 : *(int *) buffer = AF_INET6;
4118 0 : *buflen = sizeof (int);
4119 :
4120 0 : VDBG (2, "VPPCOM_ATTR_GET_DOMAIN: %d, buflen %u", *(int *) buffer,
4121 : *buflen);
4122 0 : break;
4123 :
4124 0 : case VPPCOM_ATTR_SET_ENDPT_EXT_CFG:
4125 0 : if (!(buffer && buflen && (*buflen > 0)))
4126 : {
4127 0 : rv = VPPCOM_EINVAL;
4128 0 : break;
4129 : }
4130 0 : if (session->ext_config)
4131 : {
4132 0 : rv = VPPCOM_EINVAL;
4133 0 : break;
4134 : }
4135 0 : vcl_session_alloc_ext_cfg (session, TRANSPORT_ENDPT_EXT_CFG_NONE,
4136 0 : *buflen + sizeof (u32));
4137 0 : clib_memcpy (session->ext_config->data, buffer, *buflen);
4138 0 : session->ext_config->len = *buflen;
4139 0 : break;
4140 0 : case VPPCOM_ATTR_SET_IP_PKTINFO:
4141 0 : if (buffer && buflen && (*buflen == sizeof (int)) &&
4142 0 : !vcl_session_has_attr (session, VCL_SESS_ATTR_IP_PKTINFO))
4143 : {
4144 0 : if (*(int *) buffer)
4145 0 : vcl_session_set_attr (session, VCL_SESS_ATTR_IP_PKTINFO);
4146 : else
4147 0 : vcl_session_clear_attr (session, VCL_SESS_ATTR_IP_PKTINFO);
4148 :
4149 0 : VDBG (2, "VCL_SESS_ATTR_IP_PKTINFO: %d, buflen %d",
4150 : vcl_session_has_attr (session, VCL_SESS_ATTR_IP_PKTINFO),
4151 : *buflen);
4152 : }
4153 : else
4154 0 : rv = VPPCOM_EINVAL;
4155 0 : break;
4156 :
4157 0 : case VPPCOM_ATTR_GET_IP_PKTINFO:
4158 0 : if (buffer && buflen && (*buflen >= sizeof (int)))
4159 : {
4160 0 : *(int *) buffer =
4161 0 : vcl_session_has_attr (session, VCL_SESS_ATTR_IP_PKTINFO);
4162 0 : *buflen = sizeof (int);
4163 :
4164 0 : VDBG (2, "VCL_SESS_ATTR_IP_PKTINFO: %d, buflen %d", *(int *) buffer,
4165 : *buflen);
4166 : }
4167 : else
4168 0 : rv = VPPCOM_EINVAL;
4169 0 : break;
4170 :
4171 0 : default:
4172 0 : rv = VPPCOM_EINVAL;
4173 0 : break;
4174 : }
4175 :
4176 6567 : return rv;
4177 : }
4178 :
4179 : int
4180 4 : vppcom_session_recvfrom (uint32_t session_handle, void *buffer,
4181 : uint32_t buflen, int flags, vppcom_endpt_t * ep)
4182 : {
4183 4 : vcl_worker_t *wrk = vcl_worker_get_current ();
4184 : vcl_session_t *session;
4185 4 : int rv = VPPCOM_OK;
4186 :
4187 4 : if (flags == 0)
4188 4 : rv = vppcom_session_read (session_handle, buffer, buflen);
4189 0 : else if (flags & MSG_PEEK)
4190 0 : rv = vppcom_session_peek (session_handle, buffer, buflen);
4191 : else
4192 : {
4193 0 : VDBG (0, "Unsupport flags for recvfrom %d", flags);
4194 0 : return VPPCOM_EAFNOSUPPORT;
4195 : }
4196 :
4197 4 : if (ep && rv > 0)
4198 : {
4199 2 : session = vcl_session_get_w_handle (wrk, session_handle);
4200 2 : if (session->transport.is_ip4)
4201 2 : clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip4,
4202 : sizeof (ip4_address_t));
4203 : else
4204 0 : clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip6,
4205 : sizeof (ip6_address_t));
4206 2 : ep->is_ip4 = session->transport.is_ip4;
4207 2 : ep->port = session->transport.rmt_port;
4208 : }
4209 :
4210 4 : return rv;
4211 : }
4212 :
4213 : static void
4214 0 : vcl_handle_ep_app_tlvs (vcl_session_t *s, vppcom_endpt_t *ep)
4215 : {
4216 0 : vppcom_endpt_tlv_t *tlv = ep->app_tlvs;
4217 :
4218 : do
4219 : {
4220 0 : switch (tlv->data_type)
4221 : {
4222 0 : case VCL_UDP_SEGMENT:
4223 0 : s->gso_size = *(u16 *) tlv->data;
4224 0 : break;
4225 0 : case VCL_IP_PKTINFO:
4226 0 : clib_memcpy_fast (&s->transport.lcl_ip, (ip4_address_t *) tlv->data,
4227 : sizeof (ip4_address_t));
4228 0 : break;
4229 0 : default:
4230 0 : VDBG (0, "Ignorning unsupported app tlv %u", tlv->data_type);
4231 0 : break;
4232 : }
4233 0 : tlv = VCL_EP_NEXT_APP_TLV (ep, tlv);
4234 : }
4235 0 : while (tlv);
4236 0 : }
4237 :
4238 : int
4239 0 : vppcom_session_sendto (uint32_t session_handle, void *buffer,
4240 : uint32_t buflen, int flags, vppcom_endpt_t * ep)
4241 : {
4242 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
4243 : vcl_session_t *s;
4244 :
4245 0 : s = vcl_session_get_w_handle (wrk, session_handle);
4246 0 : if (PREDICT_FALSE (!s))
4247 0 : return VPPCOM_EBADFD;
4248 :
4249 0 : if (ep)
4250 : {
4251 0 : if (!vcl_session_is_cl (s))
4252 0 : return VPPCOM_EINVAL;
4253 :
4254 0 : s->transport.is_ip4 = ep->is_ip4;
4255 0 : s->transport.rmt_port = ep->port;
4256 0 : vcl_ip_copy_from_ep (&s->transport.rmt_ip, ep);
4257 :
4258 0 : if (ep->app_tlvs)
4259 0 : vcl_handle_ep_app_tlvs (s, ep);
4260 :
4261 : /* Session not connected/bound in vpp. Create it by 'connecting' it */
4262 0 : if (PREDICT_FALSE (s->session_state == VCL_STATE_CLOSED))
4263 : {
4264 0 : u32 session_index = s->session_index;
4265 0 : f64 timeout = vcm->cfg.session_timeout;
4266 : int rv;
4267 :
4268 0 : vcl_send_session_connect (wrk, s);
4269 0 : rv = vppcom_wait_for_session_state_change (session_index,
4270 : VCL_STATE_READY,
4271 : timeout);
4272 0 : if (rv < 0)
4273 0 : return rv;
4274 0 : s = vcl_session_get (wrk, session_index);
4275 : }
4276 : }
4277 :
4278 0 : if (flags)
4279 : {
4280 : // TBD check the flags and do the right thing
4281 0 : VDBG (2, "handling flags 0x%u (%d) not implemented yet.", flags, flags);
4282 : }
4283 :
4284 0 : return (vppcom_session_write_inline (wrk, s, buffer, buflen, 1,
4285 0 : s->is_dgram ? 1 : 0));
4286 : }
4287 :
4288 : int
4289 0 : vppcom_poll (vcl_poll_t * vp, uint32_t n_sids, double wait_for_time)
4290 : {
4291 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
4292 0 : f64 timeout = clib_time_now (&wrk->clib_time) + wait_for_time;
4293 0 : u32 i, keep_trying = 1;
4294 : svm_msg_q_msg_t msg;
4295 : session_event_t *e;
4296 0 : int rv, num_ev = 0;
4297 :
4298 0 : VDBG (3, "vp %p, nsids %u, wait_for_time %f", vp, n_sids, wait_for_time);
4299 :
4300 0 : if (!vp)
4301 0 : return VPPCOM_EFAULT;
4302 :
4303 : do
4304 : {
4305 : vcl_session_t *session;
4306 :
4307 : /* Dequeue all events and drop all unhandled io events */
4308 0 : while (svm_msg_q_sub (wrk->app_event_queue, &msg, SVM_Q_NOWAIT, 0) == 0)
4309 : {
4310 0 : e = svm_msg_q_msg_data (wrk->app_event_queue, &msg);
4311 0 : vcl_handle_mq_event (wrk, e);
4312 0 : svm_msg_q_free_msg (wrk->app_event_queue, &msg);
4313 : }
4314 0 : vec_reset_length (wrk->unhandled_evts_vector);
4315 :
4316 0 : for (i = 0; i < n_sids; i++)
4317 : {
4318 0 : session = vcl_session_get (wrk, vp[i].sh);
4319 0 : if (!session)
4320 : {
4321 0 : vp[i].revents = POLLHUP;
4322 0 : num_ev++;
4323 0 : continue;
4324 : }
4325 :
4326 0 : vp[i].revents = 0;
4327 :
4328 0 : if (POLLIN & vp[i].events)
4329 : {
4330 0 : rv = vcl_session_read_ready (session);
4331 0 : if (rv > 0)
4332 : {
4333 0 : vp[i].revents |= POLLIN;
4334 0 : num_ev++;
4335 : }
4336 0 : else if (rv < 0)
4337 : {
4338 0 : switch (rv)
4339 : {
4340 0 : case VPPCOM_ECONNRESET:
4341 0 : vp[i].revents = POLLHUP;
4342 0 : break;
4343 :
4344 0 : default:
4345 0 : vp[i].revents = POLLERR;
4346 0 : break;
4347 : }
4348 0 : num_ev++;
4349 : }
4350 : }
4351 :
4352 0 : if (POLLOUT & vp[i].events)
4353 : {
4354 0 : rv = vcl_session_write_ready (session);
4355 0 : if (rv > 0)
4356 : {
4357 0 : vp[i].revents |= POLLOUT;
4358 0 : num_ev++;
4359 : }
4360 0 : else if (rv < 0)
4361 : {
4362 0 : switch (rv)
4363 : {
4364 0 : case VPPCOM_ECONNRESET:
4365 0 : vp[i].revents = POLLHUP;
4366 0 : break;
4367 :
4368 0 : default:
4369 0 : vp[i].revents = POLLERR;
4370 0 : break;
4371 : }
4372 0 : num_ev++;
4373 : }
4374 : }
4375 :
4376 : if (0) // Note "done:" label used by VCL_SESSION_LOCK_AND_GET()
4377 : {
4378 : vp[i].revents = POLLNVAL;
4379 : num_ev++;
4380 : }
4381 : }
4382 0 : if (wait_for_time != -1)
4383 0 : keep_trying = (clib_time_now (&wrk->clib_time) <= timeout) ? 1 : 0;
4384 : }
4385 0 : while ((num_ev == 0) && keep_trying);
4386 :
4387 0 : return num_ev;
4388 : }
4389 :
4390 : int
4391 0 : vppcom_mq_epoll_fd (void)
4392 : {
4393 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
4394 0 : return wrk->mqs_epfd;
4395 : }
4396 :
4397 : int
4398 1585120 : vppcom_session_index (vcl_session_handle_t session_handle)
4399 : {
4400 1585120 : return session_handle & 0xFFFFFF;
4401 : }
4402 :
4403 : int
4404 47 : vppcom_session_worker (vcl_session_handle_t session_handle)
4405 : {
4406 47 : return session_handle >> 24;
4407 : }
4408 :
4409 : int
4410 0 : vppcom_worker_register (void)
4411 : {
4412 0 : if (!vcl_worker_alloc_and_init ())
4413 0 : return VPPCOM_EEXIST;
4414 :
4415 0 : if (vcl_worker_register_with_vpp ())
4416 0 : return VPPCOM_EEXIST;
4417 :
4418 0 : return VPPCOM_OK;
4419 : }
4420 :
4421 : void
4422 0 : vppcom_worker_unregister (void)
4423 : {
4424 0 : vcl_worker_cleanup (vcl_worker_get_current (), 1 /* notify vpp */ );
4425 0 : vcl_set_worker_index (~0);
4426 0 : }
4427 :
4428 : void
4429 0 : vppcom_worker_index_set (int index)
4430 : {
4431 0 : vcl_set_worker_index (index);
4432 0 : }
4433 :
4434 : int
4435 442235 : vppcom_worker_index (void)
4436 : {
4437 442235 : return vcl_get_worker_index ();
4438 : }
4439 :
4440 : int
4441 0 : vppcom_worker_mqs_epfd (void)
4442 : {
4443 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
4444 0 : if (!vcm->cfg.use_mq_eventfd)
4445 0 : return -1;
4446 0 : return wrk->mqs_epfd;
4447 : }
4448 :
4449 : int
4450 4725 : vppcom_session_is_connectable_listener (uint32_t session_handle)
4451 : {
4452 : vcl_session_t *session;
4453 4725 : vcl_worker_t *wrk = vcl_worker_get_current ();
4454 4725 : session = vcl_session_get_w_handle (wrk, session_handle);
4455 4725 : if (!session)
4456 0 : return VPPCOM_EBADFD;
4457 4725 : return vcl_session_is_connectable_listener (wrk, session);
4458 : }
4459 :
4460 : int
4461 0 : vppcom_session_listener (uint32_t session_handle)
4462 : {
4463 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
4464 : vcl_session_t *listen_session, *session;
4465 0 : session = vcl_session_get_w_handle (wrk, session_handle);
4466 0 : if (!session)
4467 0 : return VPPCOM_EBADFD;
4468 0 : if (session->listener_index == VCL_INVALID_SESSION_INDEX)
4469 0 : return VPPCOM_EBADFD;
4470 0 : listen_session = vcl_session_get_w_handle (wrk, session->listener_index);
4471 0 : if (!listen_session)
4472 0 : return VPPCOM_EBADFD;
4473 0 : return vcl_session_handle (listen_session);
4474 : }
4475 :
4476 : int
4477 0 : vppcom_session_n_accepted (uint32_t session_handle)
4478 : {
4479 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
4480 0 : vcl_session_t *session = vcl_session_get_w_handle (wrk, session_handle);
4481 0 : if (!session)
4482 0 : return VPPCOM_EBADFD;
4483 0 : return session->n_accepted_sessions;
4484 : }
4485 :
4486 : const char *
4487 122 : vppcom_proto_str (vppcom_proto_t proto)
4488 : {
4489 : char const *proto_str;
4490 :
4491 122 : switch (proto)
4492 : {
4493 104 : case VPPCOM_PROTO_TCP:
4494 104 : proto_str = "TCP";
4495 104 : break;
4496 12 : case VPPCOM_PROTO_UDP:
4497 12 : proto_str = "UDP";
4498 12 : break;
4499 4 : case VPPCOM_PROTO_TLS:
4500 4 : proto_str = "TLS";
4501 4 : break;
4502 0 : case VPPCOM_PROTO_QUIC:
4503 0 : proto_str = "QUIC";
4504 0 : break;
4505 2 : case VPPCOM_PROTO_DTLS:
4506 2 : proto_str = "DTLS";
4507 2 : break;
4508 0 : case VPPCOM_PROTO_SRTP:
4509 0 : proto_str = "SRTP";
4510 0 : break;
4511 0 : default:
4512 0 : proto_str = "UNKNOWN";
4513 0 : break;
4514 : }
4515 122 : return proto_str;
4516 : }
4517 :
4518 : const char *
4519 0 : vppcom_retval_str (int retval)
4520 : {
4521 : char const *st;
4522 :
4523 0 : switch (retval)
4524 : {
4525 0 : case VPPCOM_OK:
4526 0 : st = "VPPCOM_OK";
4527 0 : break;
4528 :
4529 0 : case VPPCOM_EAGAIN:
4530 0 : st = "VPPCOM_EAGAIN";
4531 0 : break;
4532 :
4533 0 : case VPPCOM_EFAULT:
4534 0 : st = "VPPCOM_EFAULT";
4535 0 : break;
4536 :
4537 0 : case VPPCOM_ENOMEM:
4538 0 : st = "VPPCOM_ENOMEM";
4539 0 : break;
4540 :
4541 0 : case VPPCOM_EINVAL:
4542 0 : st = "VPPCOM_EINVAL";
4543 0 : break;
4544 :
4545 0 : case VPPCOM_EBADFD:
4546 0 : st = "VPPCOM_EBADFD";
4547 0 : break;
4548 :
4549 0 : case VPPCOM_EAFNOSUPPORT:
4550 0 : st = "VPPCOM_EAFNOSUPPORT";
4551 0 : break;
4552 :
4553 0 : case VPPCOM_ECONNABORTED:
4554 0 : st = "VPPCOM_ECONNABORTED";
4555 0 : break;
4556 :
4557 0 : case VPPCOM_ECONNRESET:
4558 0 : st = "VPPCOM_ECONNRESET";
4559 0 : break;
4560 :
4561 0 : case VPPCOM_ENOTCONN:
4562 0 : st = "VPPCOM_ENOTCONN";
4563 0 : break;
4564 :
4565 0 : case VPPCOM_ECONNREFUSED:
4566 0 : st = "VPPCOM_ECONNREFUSED";
4567 0 : break;
4568 :
4569 0 : case VPPCOM_ETIMEDOUT:
4570 0 : st = "VPPCOM_ETIMEDOUT";
4571 0 : break;
4572 :
4573 0 : case VPPCOM_EADDRINUSE:
4574 0 : st = "VPPCOM_EADDRINUSE";
4575 0 : break;
4576 :
4577 0 : default:
4578 0 : st = "UNKNOWN_STATE";
4579 0 : break;
4580 : }
4581 :
4582 0 : return st;
4583 : }
4584 :
4585 : int
4586 6 : vppcom_add_cert_key_pair (vppcom_cert_key_pair_t *ckpair)
4587 : {
4588 6 : if (vcm->cfg.vpp_app_socket_api)
4589 4 : return vcl_sapi_add_cert_key_pair (ckpair);
4590 : else
4591 2 : return vcl_bapi_add_cert_key_pair (ckpair);
4592 : }
4593 :
4594 : int
4595 0 : vppcom_del_cert_key_pair (uint32_t ckpair_index)
4596 : {
4597 0 : if (vcm->cfg.vpp_app_socket_api)
4598 0 : return vcl_sapi_del_cert_key_pair (ckpair_index);
4599 : else
4600 0 : return vcl_bapi_del_cert_key_pair (ckpair_index);
4601 : }
4602 :
4603 : int
4604 0 : vppcom_session_get_error (uint32_t session_handle)
4605 : {
4606 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
4607 0 : vcl_session_t *session = 0;
4608 :
4609 0 : session = vcl_session_get_w_handle (wrk, session_handle);
4610 0 : if (!session)
4611 0 : return VPPCOM_EBADFD;
4612 :
4613 0 : if (PREDICT_FALSE (session->flags & VCL_SESSION_F_IS_VEP))
4614 : {
4615 0 : VWRN ("epoll session %u! will not have connect", session->session_index);
4616 0 : return VPPCOM_EBADFD;
4617 : }
4618 :
4619 0 : if (session->vpp_error == SESSION_E_PORTINUSE)
4620 0 : return VPPCOM_EADDRINUSE;
4621 0 : else if (session->vpp_error == SESSION_E_REFUSED)
4622 0 : return VPPCOM_ECONNREFUSED;
4623 0 : else if (session->vpp_error != SESSION_E_NONE)
4624 0 : return VPPCOM_EFAULT;
4625 : else
4626 0 : return VPPCOM_OK;
4627 : }
4628 :
4629 : int
4630 0 : vppcom_worker_is_detached (void)
4631 : {
4632 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
4633 :
4634 0 : if (!vcm->cfg.use_mq_eventfd)
4635 0 : return VPPCOM_ENOTSUP;
4636 :
4637 0 : return wrk->api_client_handle == ~0;
4638 : }
4639 :
4640 : /*
4641 : * fd.io coding-style-patch-verification: ON
4642 : *
4643 : * Local Variables:
4644 : * eval: (c-set-style "gnu")
4645 : * End:
4646 : */
|