Line data Source code
1 : /*
2 : * Copyright (c) 2018-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 <vcl/vcl_private.h>
17 :
18 : static pthread_key_t vcl_worker_stop_key;
19 :
20 : vcl_mq_evt_conn_t *
21 0 : vcl_mq_evt_conn_alloc (vcl_worker_t * wrk)
22 : {
23 : vcl_mq_evt_conn_t *mqc;
24 0 : pool_get (wrk->mq_evt_conns, mqc);
25 0 : memset (mqc, 0, sizeof (*mqc));
26 0 : return mqc;
27 : }
28 :
29 : u32
30 0 : vcl_mq_evt_conn_index (vcl_worker_t * wrk, vcl_mq_evt_conn_t * mqc)
31 : {
32 0 : return (mqc - wrk->mq_evt_conns);
33 : }
34 :
35 : vcl_mq_evt_conn_t *
36 0 : vcl_mq_evt_conn_get (vcl_worker_t * wrk, u32 mq_conn_idx)
37 : {
38 0 : return pool_elt_at_index (wrk->mq_evt_conns, mq_conn_idx);
39 : }
40 :
41 : /* Add unix socket to epoll.
42 : * Used only to get a notification on socket close
43 : * We can't use eventfd because we don't get notifications on that fds
44 : */
45 : static int
46 0 : vcl_mq_epoll_add_api_sock (vcl_worker_t *wrk)
47 : {
48 0 : clib_socket_t *cs = &wrk->app_api_sock;
49 0 : struct epoll_event e = { 0 };
50 : int rv;
51 :
52 0 : e.data.u32 = ~0;
53 0 : rv = epoll_ctl (wrk->mqs_epfd, EPOLL_CTL_ADD, cs->fd, &e);
54 0 : if (rv != EEXIST && rv < 0)
55 0 : return -1;
56 :
57 0 : return 0;
58 : }
59 :
60 : int
61 0 : vcl_mq_epoll_add_evfd (vcl_worker_t * wrk, svm_msg_q_t * mq)
62 : {
63 0 : struct epoll_event e = { 0 };
64 : vcl_mq_evt_conn_t *mqc;
65 : u32 mqc_index;
66 : int mq_fd;
67 :
68 0 : mq_fd = svm_msg_q_get_eventfd (mq);
69 :
70 0 : if (wrk->mqs_epfd < 0 || mq_fd == -1)
71 0 : return -1;
72 :
73 0 : mqc = vcl_mq_evt_conn_alloc (wrk);
74 0 : mqc_index = vcl_mq_evt_conn_index (wrk, mqc);
75 0 : mqc->mq_fd = mq_fd;
76 0 : mqc->mq = mq;
77 :
78 0 : e.events = EPOLLIN;
79 0 : e.data.u32 = mqc_index;
80 0 : if (epoll_ctl (wrk->mqs_epfd, EPOLL_CTL_ADD, mq_fd, &e) < 0)
81 : {
82 0 : VDBG (0, "failed to add mq eventfd to mq epoll fd");
83 0 : return -1;
84 : }
85 :
86 0 : if (vcl_mq_epoll_add_api_sock (wrk))
87 : {
88 0 : VDBG (0, "failed to add mq socket to mq epoll fd");
89 0 : return -1;
90 : }
91 :
92 0 : return mqc_index;
93 : }
94 :
95 : int
96 0 : vcl_mq_epoll_del_evfd (vcl_worker_t * wrk, u32 mqc_index)
97 : {
98 : vcl_mq_evt_conn_t *mqc;
99 :
100 0 : if (wrk->mqs_epfd || mqc_index == ~0)
101 0 : return -1;
102 :
103 0 : mqc = vcl_mq_evt_conn_get (wrk, mqc_index);
104 0 : if (epoll_ctl (wrk->mqs_epfd, EPOLL_CTL_DEL, mqc->mq_fd, 0) < 0)
105 : {
106 0 : VDBG (0, "failed to del mq eventfd to mq epoll fd");
107 0 : return -1;
108 : }
109 0 : return 0;
110 : }
111 :
112 : static vcl_worker_t *
113 37 : vcl_worker_alloc (void)
114 : {
115 : vcl_worker_t *wrk;
116 37 : pool_get (vcm->workers, wrk);
117 37 : memset (wrk, 0, sizeof (*wrk));
118 37 : wrk->wrk_index = wrk - vcm->workers;
119 37 : wrk->forked_child = ~0;
120 37 : return wrk;
121 : }
122 :
123 : static void
124 37 : vcl_worker_free (vcl_worker_t * wrk)
125 : {
126 37 : pool_put (vcm->workers, wrk);
127 37 : }
128 :
129 : int
130 0 : vcl_api_app_worker_add (void)
131 : {
132 0 : if (vcm->cfg.vpp_app_socket_api)
133 0 : return vcl_sapi_app_worker_add ();
134 :
135 0 : return vcl_bapi_app_worker_add ();
136 : }
137 :
138 : void
139 13 : vcl_api_app_worker_del (vcl_worker_t * wrk)
140 : {
141 13 : if (wrk->api_client_handle == ~0)
142 0 : return;
143 :
144 13 : if (vcm->cfg.vpp_app_socket_api)
145 2 : return vcl_sapi_app_worker_del (wrk);
146 :
147 11 : vcl_bapi_app_worker_del (wrk);
148 : }
149 :
150 : void
151 37 : vcl_worker_cleanup (vcl_worker_t * wrk, u8 notify_vpp)
152 : {
153 37 : clib_spinlock_lock (&vcm->workers_lock);
154 37 : if (notify_vpp)
155 13 : vcl_api_app_worker_del (wrk);
156 :
157 37 : if (wrk->mqs_epfd > 0)
158 0 : close (wrk->mqs_epfd);
159 37 : pool_free (wrk->sessions);
160 37 : pool_free (wrk->mq_evt_conns);
161 37 : hash_free (wrk->session_index_by_vpp_handles);
162 37 : vec_free (wrk->mq_events);
163 37 : vec_free (wrk->mq_msg_vector);
164 37 : vec_free (wrk->unhandled_evts_vector);
165 37 : vec_free (wrk->pending_session_wrk_updates);
166 37 : clib_bitmap_free (wrk->rd_bitmap);
167 37 : clib_bitmap_free (wrk->wr_bitmap);
168 37 : clib_bitmap_free (wrk->ex_bitmap);
169 37 : vcl_worker_free (wrk);
170 37 : clib_spinlock_unlock (&vcm->workers_lock);
171 37 : }
172 :
173 : static void
174 0 : vcl_worker_cleanup_cb (void *arg)
175 : {
176 : vcl_worker_t *wrk;
177 : u32 wrk_index;
178 :
179 0 : wrk_index = vcl_get_worker_index ();
180 0 : wrk = vcl_worker_get_if_valid (wrk_index);
181 0 : if (!wrk)
182 0 : return;
183 :
184 0 : vcl_worker_cleanup (wrk, 1 /* notify vpp */ );
185 0 : vcl_set_worker_index (~0);
186 0 : VDBG (0, "cleaned up worker %u", wrk_index);
187 : }
188 :
189 : void
190 0 : vcl_worker_detach_sessions (vcl_worker_t *wrk)
191 : {
192 : session_event_t *e;
193 : vcl_session_t *s;
194 0 : uword *seg_indices_map = 0;
195 0 : u32 seg_index, val, *seg_indices = 0;
196 :
197 0 : close (wrk->app_api_sock.fd);
198 0 : pool_foreach (s, wrk->sessions)
199 : {
200 0 : if (s->session_state == VCL_STATE_LISTEN)
201 : {
202 0 : s->session_state = VCL_STATE_LISTEN_NO_MQ;
203 0 : continue;
204 : }
205 0 : if ((s->flags & VCL_SESSION_F_IS_VEP) ||
206 0 : s->session_state == VCL_STATE_LISTEN_NO_MQ ||
207 0 : s->session_state == VCL_STATE_CLOSED)
208 0 : continue;
209 :
210 0 : hash_set (seg_indices_map, s->tx_fifo->segment_index, 1);
211 :
212 0 : s->session_state = VCL_STATE_DETACHED;
213 0 : vec_add2 (wrk->unhandled_evts_vector, e, 1);
214 0 : e->event_type = SESSION_CTRL_EVT_DISCONNECTED;
215 0 : e->session_index = s->session_index;
216 0 : e->postponed = 1;
217 : }
218 :
219 0 : hash_foreach (seg_index, val, seg_indices_map,
220 : ({ vec_add1 (seg_indices, seg_index); }));
221 :
222 0 : vcl_segment_detach_segments (seg_indices);
223 :
224 : /* Detach worker's mqs segment */
225 0 : vcl_segment_detach (vcl_vpp_worker_segment_handle (wrk->wrk_index));
226 :
227 0 : vec_free (seg_indices);
228 0 : hash_free (seg_indices_map);
229 0 : }
230 :
231 : vcl_worker_t *
232 37 : vcl_worker_alloc_and_init ()
233 : {
234 : vcl_worker_t *wrk;
235 :
236 : /* This was initialized already */
237 37 : if (vcl_get_worker_index () != ~0)
238 0 : return 0;
239 :
240 : /* Grab lock before selecting mem thread index */
241 37 : clib_spinlock_lock (&vcm->workers_lock);
242 :
243 : /* Use separate heap map entry for worker */
244 37 : clib_mem_set_thread_index ();
245 :
246 37 : if (pool_elts (vcm->workers) == vcm->cfg.max_workers)
247 : {
248 0 : VDBG (0, "max-workers %u limit reached", vcm->cfg.max_workers);
249 0 : wrk = 0;
250 0 : goto done;
251 : }
252 :
253 37 : wrk = vcl_worker_alloc ();
254 37 : vcl_set_worker_index (wrk->wrk_index);
255 37 : wrk->api_client_handle = ~0;
256 37 : wrk->thread_id = pthread_self ();
257 37 : wrk->current_pid = getpid ();
258 :
259 37 : wrk->mqs_epfd = -1;
260 37 : if (vcm->cfg.use_mq_eventfd)
261 : {
262 0 : wrk->vcl_needs_real_epoll = 1;
263 0 : wrk->mqs_epfd = epoll_create (1);
264 0 : wrk->vcl_needs_real_epoll = 0;
265 0 : if (wrk->mqs_epfd < 0)
266 : {
267 0 : clib_unix_warning ("epoll_create() returned");
268 0 : goto done;
269 : }
270 : }
271 :
272 37 : wrk->ep_lt_current = VCL_INVALID_SESSION_INDEX;
273 37 : wrk->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
274 37 : clib_time_init (&wrk->clib_time);
275 37 : vec_validate (wrk->mq_events, 64);
276 37 : vec_validate (wrk->mq_msg_vector, 128);
277 37 : vec_reset_length (wrk->mq_msg_vector);
278 37 : vec_validate (wrk->unhandled_evts_vector, 128);
279 37 : vec_reset_length (wrk->unhandled_evts_vector);
280 :
281 0 : done:
282 37 : clib_spinlock_unlock (&vcm->workers_lock);
283 37 : return wrk;
284 : }
285 :
286 : int
287 0 : vcl_worker_register_with_vpp (void)
288 : {
289 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
290 :
291 0 : clib_spinlock_lock (&vcm->workers_lock);
292 :
293 0 : if (vcl_api_app_worker_add ())
294 : {
295 0 : VDBG (0, "failed to add worker to vpp");
296 0 : clib_spinlock_unlock (&vcm->workers_lock);
297 0 : return -1;
298 : }
299 0 : if (pthread_key_create (&vcl_worker_stop_key, vcl_worker_cleanup_cb))
300 0 : VDBG (0, "failed to add pthread cleanup function");
301 0 : if (pthread_setspecific (vcl_worker_stop_key, &wrk->thread_id))
302 0 : VDBG (0, "failed to setup key value");
303 :
304 0 : clib_spinlock_unlock (&vcm->workers_lock);
305 :
306 0 : VDBG (0, "added worker %u", wrk->wrk_index);
307 0 : return 0;
308 : }
309 :
310 : svm_msg_q_t *
311 134 : vcl_worker_ctrl_mq (vcl_worker_t * wrk)
312 : {
313 134 : return wrk->ctrl_mq;
314 : }
315 :
316 : int
317 50345200 : vcl_session_read_ready (vcl_session_t * s)
318 : {
319 50345200 : if (PREDICT_FALSE (s->flags & VCL_SESSION_F_IS_VEP))
320 : {
321 0 : VDBG (0, "ERROR: session %u: cannot read from an epoll session!",
322 : s->session_index);
323 0 : return VPPCOM_EBADFD;
324 : }
325 :
326 50345200 : if (vcl_session_is_open (s))
327 : {
328 36132900 : if (vcl_session_is_ct (s))
329 17694 : return svm_fifo_max_dequeue_cons (s->ct_rx_fifo);
330 :
331 36115200 : if (s->is_dgram)
332 : {
333 : session_dgram_pre_hdr_t ph;
334 : u32 max_deq;
335 :
336 6974220 : max_deq = svm_fifo_max_dequeue_cons (s->rx_fifo);
337 6974220 : if (max_deq <= SESSION_CONN_HDR_LEN)
338 6972930 : return 0;
339 1292 : if (svm_fifo_peek (s->rx_fifo, 0, sizeof (ph), (u8 *) & ph) < 0)
340 0 : return 0;
341 1292 : if (ph.data_length + SESSION_CONN_HDR_LEN > max_deq)
342 0 : return 0;
343 :
344 1292 : return ph.data_length;
345 : }
346 :
347 29140900 : return svm_fifo_max_dequeue_cons (s->rx_fifo);
348 : }
349 14212400 : else if (s->session_state == VCL_STATE_LISTEN)
350 : {
351 14212400 : return clib_fifo_elts (s->accept_evts_fifo);
352 : }
353 : else
354 : {
355 0 : return (s->session_state == VCL_STATE_DISCONNECT) ?
356 0 : VPPCOM_ECONNRESET : VPPCOM_ENOTCONN;
357 : }
358 : }
359 :
360 : int
361 7627220 : vcl_session_write_ready (vcl_session_t * s)
362 : {
363 7627220 : if (PREDICT_FALSE (s->flags & VCL_SESSION_F_IS_VEP))
364 : {
365 0 : VDBG (0, "session %u [0x%llx]: cannot write to an epoll session!",
366 : s->session_index, s->vpp_handle);
367 0 : return VPPCOM_EBADFD;
368 : }
369 :
370 7627220 : if (vcl_session_is_open (s))
371 : {
372 7627210 : if (vcl_session_is_ct (s))
373 17689 : return svm_fifo_max_enqueue_prod (s->ct_tx_fifo);
374 :
375 7609520 : if (s->is_dgram)
376 : {
377 1416 : u32 max_enq = svm_fifo_max_enqueue_prod (s->tx_fifo);
378 :
379 1416 : if (max_enq <= sizeof (session_dgram_hdr_t))
380 0 : return 0;
381 1416 : return max_enq - sizeof (session_dgram_hdr_t);
382 : }
383 :
384 7608110 : return svm_fifo_max_enqueue_prod (s->tx_fifo);
385 : }
386 3 : else if (s->session_state == VCL_STATE_LISTEN)
387 : {
388 0 : if (s->tx_fifo)
389 0 : return svm_fifo_max_enqueue_prod (s->tx_fifo);
390 : else
391 0 : return VPPCOM_EBADFD;
392 : }
393 3 : else if (s->session_state == VCL_STATE_UPDATED)
394 : {
395 0 : return 0;
396 : }
397 : else
398 : {
399 3 : return (s->session_state == VCL_STATE_DISCONNECT) ?
400 3 : VPPCOM_ECONNRESET : VPPCOM_ENOTCONN;
401 : }
402 : }
403 :
404 : int
405 6 : vcl_session_alloc_ext_cfg (vcl_session_t *s,
406 : transport_endpt_ext_cfg_type_t type, u32 len)
407 : {
408 6 : if (s->ext_config)
409 0 : return -1;
410 :
411 6 : s->ext_config = clib_mem_alloc (len);
412 6 : clib_memset (s->ext_config, 0, len);
413 6 : s->ext_config->len = len;
414 6 : s->ext_config->type = type;
415 :
416 6 : return 0;
417 : }
418 :
419 : int
420 111 : vcl_segment_attach (u64 segment_handle, char *name, ssvm_segment_type_t type,
421 : int fd)
422 : {
423 111 : fifo_segment_create_args_t _a, *a = &_a;
424 : int rv;
425 :
426 111 : memset (a, 0, sizeof (*a));
427 111 : a->segment_name = name;
428 111 : a->segment_type = type;
429 :
430 111 : if (type == SSVM_SEGMENT_MEMFD)
431 111 : a->memfd_fd = fd;
432 :
433 111 : clib_rwlock_writer_lock (&vcm->segment_table_lock);
434 :
435 111 : if ((rv = fifo_segment_attach (&vcm->segment_main, a)))
436 : {
437 0 : clib_warning ("svm_fifo_segment_attach ('%s') failed", name);
438 0 : clib_rwlock_writer_unlock (&vcm->segment_table_lock);
439 0 : return rv;
440 : }
441 111 : hash_set (vcm->segment_table, segment_handle, a->new_segment_indices[0]);
442 :
443 111 : clib_rwlock_writer_unlock (&vcm->segment_table_lock);
444 :
445 111 : vec_free (a->new_segment_indices);
446 111 : return 0;
447 : }
448 :
449 : u32
450 307 : vcl_segment_table_lookup (u64 segment_handle)
451 : {
452 : uword *seg_indexp;
453 :
454 307 : clib_rwlock_reader_lock (&vcm->segment_table_lock);
455 307 : seg_indexp = hash_get (vcm->segment_table, segment_handle);
456 307 : clib_rwlock_reader_unlock (&vcm->segment_table_lock);
457 :
458 307 : if (!seg_indexp)
459 0 : return VCL_INVALID_SEGMENT_INDEX;
460 307 : return ((u32) * seg_indexp);
461 : }
462 :
463 : void
464 4 : vcl_segment_detach (u64 segment_handle)
465 : {
466 4 : fifo_segment_main_t *sm = &vcm->segment_main;
467 : fifo_segment_t *segment;
468 : u32 segment_index;
469 :
470 4 : segment_index = vcl_segment_table_lookup (segment_handle);
471 4 : if (segment_index == (u32) ~ 0)
472 0 : return;
473 :
474 4 : clib_rwlock_writer_lock (&vcm->segment_table_lock);
475 :
476 4 : segment = fifo_segment_get_segment (sm, segment_index);
477 4 : fifo_segment_delete (sm, segment);
478 4 : hash_unset (vcm->segment_table, segment_handle);
479 :
480 4 : clib_rwlock_writer_unlock (&vcm->segment_table_lock);
481 :
482 4 : VDBG (0, "detached segment %u handle %lx", segment_index, segment_handle);
483 : }
484 :
485 : void
486 0 : vcl_segment_detach_segments (u32 *seg_indices)
487 : {
488 0 : u64 *seg_handles = 0, *seg_handle, key;
489 : u32 *seg_index;
490 : u32 val;
491 :
492 0 : clib_rwlock_reader_lock (&vcm->segment_table_lock);
493 :
494 0 : vec_foreach (seg_index, seg_indices)
495 : {
496 : /* clang-format off */
497 0 : hash_foreach (key, val, vcm->segment_table, ({
498 : if (val == *seg_index)
499 : {
500 : vec_add1 (seg_handles, key);
501 : break;
502 : }
503 : }));
504 : /* clang-format on */
505 : }
506 :
507 0 : clib_rwlock_reader_unlock (&vcm->segment_table_lock);
508 :
509 0 : vec_foreach (seg_handle, seg_handles)
510 0 : vcl_segment_detach (seg_handle[0]);
511 :
512 0 : vec_free (seg_handles);
513 0 : }
514 :
515 : int
516 99 : vcl_segment_attach_session (uword segment_handle, uword rxf_offset,
517 : uword txf_offset, uword mq_offset, u32 mq_index,
518 : u8 is_ct, vcl_session_t *s)
519 : {
520 : u32 fs_index, eqs_index;
521 : svm_fifo_t *rxf, *txf;
522 : fifo_segment_t *fs;
523 : u64 eqs_handle;
524 :
525 99 : fs_index = vcl_segment_table_lookup (segment_handle);
526 99 : if (fs_index == VCL_INVALID_SEGMENT_INDEX)
527 : {
528 0 : VDBG (0, "ERROR: segment for session %u is not mounted!",
529 : s->session_index);
530 0 : return -1;
531 : }
532 :
533 99 : if (!is_ct && mq_offset != (uword) ~0)
534 : {
535 87 : eqs_handle = vcl_vpp_worker_segment_handle (0);
536 87 : eqs_index = vcl_segment_table_lookup (eqs_handle);
537 87 : ASSERT (eqs_index != VCL_INVALID_SEGMENT_INDEX);
538 : }
539 :
540 99 : clib_rwlock_reader_lock (&vcm->segment_table_lock);
541 :
542 99 : fs = fifo_segment_get_segment (&vcm->segment_main, fs_index);
543 99 : rxf = fifo_segment_alloc_fifo_w_offset (fs, rxf_offset);
544 99 : txf = fifo_segment_alloc_fifo_w_offset (fs, txf_offset);
545 99 : rxf->segment_index = fs_index;
546 99 : txf->segment_index = fs_index;
547 :
548 99 : if (!is_ct && mq_offset != (uword) ~0)
549 : {
550 87 : fs = fifo_segment_get_segment (&vcm->segment_main, eqs_index);
551 87 : s->vpp_evt_q = fifo_segment_msg_q_attach (fs, mq_offset, mq_index);
552 : }
553 :
554 99 : clib_rwlock_reader_unlock (&vcm->segment_table_lock);
555 :
556 99 : if (!is_ct)
557 : {
558 87 : rxf->shr->client_session_index = s->session_index;
559 87 : txf->shr->client_session_index = s->session_index;
560 87 : rxf->client_thread_index = vcl_get_worker_index ();
561 87 : txf->client_thread_index = vcl_get_worker_index ();
562 87 : s->rx_fifo = rxf;
563 87 : s->tx_fifo = txf;
564 : }
565 : else
566 : {
567 12 : s->ct_rx_fifo = rxf;
568 12 : s->ct_tx_fifo = txf;
569 : }
570 :
571 99 : return 0;
572 : }
573 :
574 : void
575 24 : vcl_session_detach_fifos (vcl_session_t *s)
576 : {
577 : fifo_segment_t *fs;
578 :
579 24 : if (!s->rx_fifo)
580 7 : return;
581 :
582 17 : clib_rwlock_reader_lock (&vcm->segment_table_lock);
583 :
584 17 : fs = fifo_segment_get_segment_if_valid (&vcm->segment_main,
585 17 : s->rx_fifo->segment_index);
586 17 : if (!fs)
587 0 : goto done;
588 :
589 17 : fifo_segment_free_client_fifo (fs, s->rx_fifo);
590 17 : fifo_segment_free_client_fifo (fs, s->tx_fifo);
591 17 : if (s->ct_rx_fifo)
592 : {
593 4 : fs = fifo_segment_get_segment_if_valid (&vcm->segment_main,
594 4 : s->ct_rx_fifo->segment_index);
595 4 : if (!fs)
596 0 : goto done;
597 :
598 4 : fifo_segment_free_client_fifo (fs, s->ct_rx_fifo);
599 4 : fifo_segment_free_client_fifo (fs, s->ct_tx_fifo);
600 : }
601 :
602 13 : done:
603 17 : clib_rwlock_reader_unlock (&vcm->segment_table_lock);
604 : }
605 :
606 : int
607 74 : vcl_segment_attach_mq (uword segment_handle, uword mq_offset, u32 mq_index,
608 : svm_msg_q_t **mq)
609 : {
610 : fifo_segment_t *fs;
611 : u32 fs_index;
612 :
613 74 : fs_index = vcl_segment_table_lookup (segment_handle);
614 74 : if (fs_index == VCL_INVALID_SEGMENT_INDEX)
615 : {
616 0 : VDBG (0, "ERROR: mq segment %lx for is not attached!", segment_handle);
617 0 : return -1;
618 : }
619 :
620 74 : clib_rwlock_reader_lock (&vcm->segment_table_lock);
621 :
622 74 : fs = fifo_segment_get_segment (&vcm->segment_main, fs_index);
623 74 : *mq = fifo_segment_msg_q_attach (fs, mq_offset, mq_index);
624 :
625 74 : clib_rwlock_reader_unlock (&vcm->segment_table_lock);
626 :
627 74 : return 0;
628 : }
629 :
630 : int
631 37 : vcl_segment_discover_mqs (uword segment_handle, int *fds, u32 n_fds)
632 : {
633 : fifo_segment_t *fs;
634 : u32 fs_index;
635 :
636 37 : fs_index = vcl_segment_table_lookup (segment_handle);
637 37 : if (fs_index == VCL_INVALID_SEGMENT_INDEX)
638 : {
639 0 : VDBG (0, "ERROR: mq segment %lx for is not attached!", segment_handle);
640 0 : return -1;
641 : }
642 :
643 37 : clib_rwlock_reader_lock (&vcm->segment_table_lock);
644 :
645 37 : fs = fifo_segment_get_segment (&vcm->segment_main, fs_index);
646 37 : fifo_segment_msg_qs_discover (fs, fds, n_fds);
647 :
648 37 : clib_rwlock_reader_unlock (&vcm->segment_table_lock);
649 :
650 37 : return 0;
651 : }
652 :
653 : svm_fifo_chunk_t *
654 6 : vcl_segment_alloc_chunk (uword segment_handle, u32 slice_index, u32 size,
655 : uword *offset)
656 : {
657 : svm_fifo_chunk_t *c;
658 : fifo_segment_t *fs;
659 : u32 fs_index;
660 :
661 6 : fs_index = vcl_segment_table_lookup (segment_handle);
662 6 : if (fs_index == VCL_INVALID_SEGMENT_INDEX)
663 : {
664 0 : VDBG (0, "ERROR: mq segment %lx for is not attached!", segment_handle);
665 0 : return 0;
666 : }
667 :
668 6 : clib_rwlock_reader_lock (&vcm->segment_table_lock);
669 :
670 6 : fs = fifo_segment_get_segment (&vcm->segment_main, fs_index);
671 6 : c = fifo_segment_alloc_chunk_w_slice (fs, slice_index, size);
672 6 : *offset = fifo_segment_chunk_offset (fs, c);
673 :
674 6 : clib_rwlock_reader_unlock (&vcm->segment_table_lock);
675 :
676 6 : return c;
677 : }
678 :
679 : int
680 0 : vcl_session_share_fifos (vcl_session_t *s, svm_fifo_t *rxf, svm_fifo_t *txf)
681 : {
682 0 : vcl_worker_t *wrk = vcl_worker_get_current ();
683 : fifo_segment_t *fs;
684 :
685 0 : clib_rwlock_reader_lock (&vcm->segment_table_lock);
686 :
687 0 : fs = fifo_segment_get_segment (&vcm->segment_main, rxf->segment_index);
688 0 : s->rx_fifo = fifo_segment_duplicate_fifo (fs, rxf);
689 0 : s->tx_fifo = fifo_segment_duplicate_fifo (fs, txf);
690 :
691 0 : clib_rwlock_reader_unlock (&vcm->segment_table_lock);
692 :
693 0 : svm_fifo_add_subscriber (s->rx_fifo, wrk->vpp_wrk_index);
694 0 : svm_fifo_add_subscriber (s->tx_fifo, wrk->vpp_wrk_index);
695 :
696 0 : return 0;
697 : }
698 :
699 : const char *
700 0 : vcl_session_state_str (vcl_session_state_t state)
701 : {
702 : char *st;
703 :
704 0 : switch (state)
705 : {
706 0 : case VCL_STATE_CLOSED:
707 0 : st = "STATE_CLOSED";
708 0 : break;
709 0 : case VCL_STATE_LISTEN:
710 0 : st = "STATE_LISTEN";
711 0 : break;
712 0 : case VCL_STATE_READY:
713 0 : st = "STATE_READY";
714 0 : break;
715 0 : case VCL_STATE_VPP_CLOSING:
716 0 : st = "STATE_VPP_CLOSING";
717 0 : break;
718 0 : case VCL_STATE_DISCONNECT:
719 0 : st = "STATE_DISCONNECT";
720 0 : break;
721 0 : case VCL_STATE_DETACHED:
722 0 : st = "STATE_DETACHED";
723 0 : break;
724 0 : case VCL_STATE_UPDATED:
725 0 : st = "STATE_UPDATED";
726 0 : break;
727 0 : case VCL_STATE_LISTEN_NO_MQ:
728 0 : st = "STATE_LISTEN_NO_MQ";
729 0 : break;
730 0 : default:
731 0 : st = "UNKNOWN_STATE";
732 0 : break;
733 : }
734 :
735 0 : return st;
736 : }
737 :
738 : u8 *
739 229 : vcl_format_ip4_address (u8 *s, va_list *args)
740 : {
741 229 : u8 *a = va_arg (*args, u8 *);
742 229 : return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
743 : }
744 :
745 : u8 *
746 26 : vcl_format_ip6_address (u8 *s, va_list *args)
747 : {
748 26 : ip6_address_t *a = va_arg (*args, ip6_address_t *);
749 : u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
750 :
751 26 : i_max_n_zero = ARRAY_LEN (a->as_u16);
752 26 : max_n_zeros = 0;
753 26 : i_first_zero = i_max_n_zero;
754 26 : n_zeros = 0;
755 234 : for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
756 : {
757 208 : u32 is_zero = a->as_u16[i] == 0;
758 208 : if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
759 : {
760 26 : i_first_zero = i;
761 26 : n_zeros = 0;
762 : }
763 208 : n_zeros += is_zero;
764 208 : if ((!is_zero && n_zeros > max_n_zeros) ||
765 197 : (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
766 : {
767 26 : i_max_n_zero = i_first_zero;
768 26 : max_n_zeros = n_zeros;
769 26 : i_first_zero = ARRAY_LEN (a->as_u16);
770 26 : n_zeros = 0;
771 : }
772 : }
773 :
774 26 : last_double_colon = 0;
775 73 : for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
776 : {
777 47 : if (i == i_max_n_zero && max_n_zeros > 1)
778 : {
779 26 : s = format (s, "::");
780 26 : i += max_n_zeros - 1;
781 26 : last_double_colon = 1;
782 : }
783 : else
784 : {
785 21 : s = format (s, "%s%x", (last_double_colon || i == 0) ? "" : ":",
786 21 : clib_net_to_host_u16 (a->as_u16[i]));
787 21 : last_double_colon = 0;
788 : }
789 : }
790 :
791 26 : return s;
792 : }
793 :
794 : /* Format an IP46 address. */
795 : u8 *
796 255 : vcl_format_ip46_address (u8 *s, va_list *args)
797 : {
798 255 : ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
799 255 : ip46_type_t type = va_arg (*args, ip46_type_t);
800 255 : int is_ip4 = 1;
801 :
802 255 : switch (type)
803 : {
804 0 : case IP46_TYPE_ANY:
805 0 : is_ip4 = ip46_address_is_ip4 (ip46);
806 0 : break;
807 229 : case IP46_TYPE_IP4:
808 229 : is_ip4 = 1;
809 229 : break;
810 26 : case IP46_TYPE_IP6:
811 26 : is_ip4 = 0;
812 26 : break;
813 : }
814 :
815 281 : return is_ip4 ? format (s, "%U", vcl_format_ip4_address, &ip46->ip4) :
816 26 : format (s, "%U", vcl_format_ip6_address, &ip46->ip6);
817 : }
818 :
819 : /*
820 : * fd.io coding-style-patch-verification: ON
821 : *
822 : * Local Variables:
823 : * eval: (c-set-style "gnu")
824 : * End:
825 : */
|