2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <svm/svm_fifo_segment.h>
20 #include <vlibmemory/api.h>
21 #include <vpp/api/vpe_msg_enum.h>
22 #include <vnet/session/application_interface.h>
23 #include <vcl/vppcom.h>
24 #include <vcl/vcl_event.h>
25 #include <vlib/unix/unix.h>
26 #include <vppinfra/vec_bootstrap.h>
27 #include <vppinfra/elog.h>
29 #define vl_typedefs /* define message structures */
30 #include <vpp/api/vpe_all_api_h.h>
33 /* declare message handlers for each api */
35 #define vl_endianfun /* define message structures */
36 #include <vpp/api/vpe_all_api_h.h>
39 /* instantiate all the print functions we know about */
40 #define vl_print(handle, ...)
42 #include <vpp/api/vpe_all_api_h.h>
46 /* Set VPPCOM_DEBUG_INIT 2 for connection debug,
47 * 3 for read/write debug output
49 * export VCL_DEBUG=<#> to set dynamically.
51 #define VPPCOM_DEBUG_INIT 1
53 #define VPPCOM_DEBUG_INIT 0
56 #define VPPCOM_DEBUG vcm->debug
59 * VPPCOM Private definitions and functions.
75 STATE_CLOSE_ON_EMPTY = 0x10,
76 STATE_DISCONNECT = 0x20,
80 #define SERVER_STATE_OPEN (STATE_ACCEPT|STATE_CLOSE_ON_EMPTY)
81 #define CLIENT_STATE_OPEN (STATE_CONNECT|STATE_CLOSE_ON_EMPTY)
83 typedef struct epoll_event vppcom_epoll_event_t;
90 vppcom_epoll_event_t ev;
91 #define VEP_DEFAULT_ET_MASK (EPOLLIN|EPOLLOUT)
92 #define VEP_UNSUPPORTED_EVENTS (EPOLLONESHOT|EPOLLEXCLUSIVE)
104 VCL_SESS_ATTR_SERVER,
105 VCL_SESS_ATTR_CUT_THRU,
107 VCL_SESS_ATTR_VEP_SESSION,
108 VCL_SESS_ATTR_LISTEN, // SOL_SOCKET,SO_ACCEPTCONN
109 VCL_SESS_ATTR_NONBLOCK, // fcntl,O_NONBLOCK
110 VCL_SESS_ATTR_REUSEADDR, // SOL_SOCKET,SO_REUSEADDR
111 VCL_SESS_ATTR_REUSEPORT, // SOL_SOCKET,SO_REUSEPORT
112 VCL_SESS_ATTR_BROADCAST, // SOL_SOCKET,SO_BROADCAST
113 VCL_SESS_ATTR_V6ONLY, // SOL_TCP,IPV6_V6ONLY
114 VCL_SESS_ATTR_KEEPALIVE, // SOL_SOCKET,SO_KEEPALIVE
115 VCL_SESS_ATTR_TCP_NODELAY, // SOL_TCP,TCP_NODELAY
116 VCL_SESS_ATTR_TCP_KEEPIDLE, // SOL_TCP,TCP_KEEPIDLE
117 VCL_SESS_ATTR_TCP_KEEPINTVL, // SOL_TCP,TCP_KEEPINTVL
119 } vppcom_session_attr_t;
121 #define VCL_SESS_ATTR_SET(ATTR, VAL) \
123 (ATTR) |= 1 << (VAL); \
126 #define VCL_SESS_ATTR_CLR(ATTR, VAL) \
128 (ATTR) &= ~(1 << (VAL)); \
131 #define VCL_SESS_ATTR_TEST(ATTR, VAL) \
132 ((ATTR) & (1 << (VAL)) ? 1 : 0)
136 volatile session_state_t state;
140 u32 sndbuf_size; // VPP-TBD: Hack until support setsockopt(SO_SNDBUF)
141 u32 rcvbuf_size; // VPP-TBD: Hack until support setsockopt(SO_RCVBUF)
142 u32 user_mss; // VPP-TBD: Hack until support setsockopt(TCP_MAXSEG)
147 svm_queue_t *vpp_event_queue;
149 /* Socket configuration state */
156 vppcom_ip46_t lcl_addr;
157 vppcom_ip46_t peer_addr;
158 u16 lcl_port; // network order
159 u16 peer_port; // network order
161 u64 client_queue_address;
163 elog_track_t elog_track;
164 vce_event_handler_reg_t *poll_reg;
167 typedef struct vppcom_cfg_t_
170 u32 vpp_api_q_length;
173 u32 add_segment_size;
174 u32 preallocated_fifo_pairs;
177 u32 event_queue_size;
178 u32 listen_queue_size;
179 u8 app_proxy_transport_tcp;
180 u8 app_proxy_transport_udp;
184 u64 namespace_secret;
189 char *event_log_path;
190 u8 *vpp_api_filename;
193 /* VPPCOM Event typedefs */
194 typedef enum vcl_event_id_
196 VCL_EVENT_INVALID_EVENT,
197 VCL_EVENT_CONNECT_REQ_ACCEPTED,
198 VCL_EVENT_IOEVENT_RX_FIFO,
199 VCL_EVENT_IOEVENT_TX_FIFO,
204 typedef struct vce_event_connect_request_
206 u32 accepted_session_index;
207 } vce_event_connect_request_t;
209 typedef struct vppcom_session_listener
211 vppcom_session_listener_cb user_cb;
212 vppcom_session_listener_errcb user_errcb;
214 } vppcom_session_listener_t;
216 typedef struct vppcom_session_ioevent_
218 vppcom_session_ioevent_cb user_cb;
220 } vppcom_session_ioevent_t;
222 typedef struct vppcom_session_io_thread_
225 pthread_mutex_t vce_io_lock;
226 pthread_cond_t vce_io_cond;
227 u32 *active_session_indexes; //pool
228 vppcom_session_ioevent_t *ioevents; //pool
229 clib_spinlock_t io_sessions_lockp;
230 } vppcom_session_io_thread_t;
232 typedef struct vppcom_main_t_
238 /* FIFO for accepted connections - used in epoll/select */
239 clib_spinlock_t session_fifo_lockp;
240 u32 *client_session_index_fifo;
242 /* vpp input queue */
243 svm_queue_t *vl_input_queue;
245 /* API client handle */
248 clib_spinlock_t sessions_lockp;
251 /* Hash table for disconnect processing */
252 uword *session_index_by_vpp_handles;
255 clib_bitmap_t *rd_bitmap;
256 clib_bitmap_t *wr_bitmap;
257 clib_bitmap_t *ex_bitmap;
259 /* Our event queue */
260 svm_queue_t *app_event_queue;
262 /* unique segment name counter */
263 u32 unique_segment_index;
265 /* For deadman timers */
266 clib_time_t clib_time;
268 /* State of the connection, shared between msg RX thread and main thread */
269 volatile app_state_t app_state;
274 vce_event_thread_t event_thread;
277 vppcom_session_io_thread_t session_io_thread;
279 /* VPP Event-logger */
280 elog_main_t elog_main;
281 elog_track_t elog_track;
283 /* VNET_API_ERROR_FOO -> "Foo" hash table */
284 uword *error_string_by_error_number;
287 /* NOTE: _vppcom_main is only used until the heap is allocated.
288 * Do not access it directly -- use vcm which will point to
289 * the heap allocated copy after init.
291 static vppcom_main_t _vppcom_main = {
292 .debug = VPPCOM_DEBUG_INIT,
293 .my_client_index = ~0
296 static vppcom_main_t *vcm = &_vppcom_main;
298 #define VCL_LOCK_AND_GET_SESSION(I, S) \
300 clib_spinlock_lock (&vcm->sessions_lockp); \
301 rv = vppcom_session_at_index (I, S); \
302 if (PREDICT_FALSE (rv)) \
304 clib_spinlock_unlock (&vcm->sessions_lockp); \
305 clib_warning ("VCL<%d>: ERROR: Invalid ##I (%u)!", \
312 vppcom_app_state_str (app_state_t state)
318 case STATE_APP_START:
319 st = "STATE_APP_START";
322 case STATE_APP_CONN_VPP:
323 st = "STATE_APP_CONN_VPP";
326 case STATE_APP_ENABLED:
327 st = "STATE_APP_ENABLED";
330 case STATE_APP_ATTACHED:
331 st = "STATE_APP_ATTACHED";
335 st = "UNKNOWN_APP_STATE";
343 vppcom_session_state_str (session_state_t state)
354 st = "STATE_CONNECT";
365 case STATE_CLOSE_ON_EMPTY:
366 st = "STATE_CLOSE_ON_EMPTY";
369 case STATE_DISCONNECT:
370 st = "STATE_DISCONNECT";
378 st = "UNKNOWN_STATE";
387 * VPPCOM Utility Functions
393 vppcom_session_at_index (u32 session_index, session_t * volatile *sess)
395 /* Assumes that caller has acquired spinlock: vcm->sessions_lockp */
396 if (PREDICT_FALSE ((session_index == ~0) ||
397 pool_is_free_index (vcm->sessions, session_index)))
399 clib_warning ("VCL<%d>: invalid session, sid (%u) has been closed!",
400 getpid (), session_index);
401 return VPPCOM_EBADFD;
403 *sess = pool_elt_at_index (vcm->sessions, session_index);
408 vppcom_session_io_thread_fn (void *arg)
410 vppcom_session_io_thread_t *evt = (vppcom_session_io_thread_t *) arg;
411 u32 *session_indexes = 0, *session_index;
418 vec_reset_length (session_indexes);
419 clib_spinlock_lock (&evt->io_sessions_lockp);
420 pool_foreach (session_index, evt->active_session_indexes, (
427 clib_spinlock_unlock (&evt->io_sessions_lockp);
430 for (i = 0; i < vec_len (session_indexes); ++i)
432 VCL_LOCK_AND_GET_SESSION (session_indexes[i], &session);
433 bytes = svm_fifo_max_dequeue (session->rx_fifo);
434 clib_spinlock_unlock (&vcm->sessions_lockp);
438 vppcom_ioevent_t *eio;
442 clib_spinlock_lock (&vcm->event_thread.events_lockp);
444 pool_get (vcm->event_thread.vce_events, ev);
445 ev_idx = (u32) (ev - vcm->event_thread.vce_events);
446 eio = vce_get_event_data (ev, sizeof (*eio));
447 ev->evk.eid = VCL_EVENT_IOEVENT_RX_FIFO;
448 ev->evk.session_index = session_indexes[i];
450 eio->session_index = session_indexes[i];
452 clib_spinlock_unlock (&vcm->event_thread.events_lockp);
454 rv = vce_generate_event (&vcm->event_thread, ev_idx);
460 ts.tv_nsec = 1000000; /* 1 millisecond */
461 nanosleep (&ts, NULL);
464 clib_spinlock_unlock (&vcm->sessions_lockp);
469 vppcom_start_io_event_thread (vppcom_session_io_thread_t * evt,
472 pthread_cond_init (&(evt->vce_io_cond), NULL);
473 pthread_mutex_init (&(evt->vce_io_lock), NULL);
475 clib_spinlock_init (&(evt->io_sessions_lockp));
477 return pthread_create (&(evt->thread), NULL /* attr */ ,
478 vppcom_session_io_thread_fn, evt);
483 vppcom_session_table_add_listener (u64 listener_handle, u32 value)
485 /* Session and listener handles have different formats. The latter has
486 * the thread index in the upper 32 bits while the former has the session
487 * type. Knowing that, for listeners we just flip the MSB to 1 */
488 listener_handle |= 1ULL << 63;
489 hash_set (vcm->session_index_by_vpp_handles, listener_handle, value);
492 static inline session_t *
493 vppcom_session_table_lookup_listener (u64 listener_handle)
496 u64 handle = listener_handle | (1ULL << 63);
499 p = hash_get (vcm->session_index_by_vpp_handles, handle);
502 clib_warning ("VCL<%d>: couldn't find listen session: unknown vpp "
503 "listener handle %llx", getpid (), listener_handle);
506 if (pool_is_free_index (vcm->sessions, p[0]))
508 if (VPPCOM_DEBUG > 1)
509 clib_warning ("VCL<%d>: invalid listen session, sid (%u)",
514 session = pool_elt_at_index (vcm->sessions, p[0]);
515 ASSERT (session->state & STATE_LISTEN);
520 vppcom_session_table_del_listener (u64 listener_handle)
522 listener_handle |= 1ULL << 63;
523 hash_unset (vcm->session_index_by_vpp_handles, listener_handle);
529 elog_main_t *em = &vcm->elog_main;
531 clib_error_t *error = 0;
534 (char *) format (0, "%s/%d-%d-vcl-elog%c", vcm->cfg.event_log_path,
535 vcm->my_client_index, getpid (), 0);
536 error = elog_write_file (em, chroot_file, 1 /* flush ring */ );
539 clib_error_report (error);
541 if (VPPCOM_DEBUG > 0)
542 clib_warning ("[%d] Event Log:'%s' ", getpid (), chroot_file);
547 vppcom_send_accept_session_reply (u64 handle, u32 context, int retval)
549 vl_api_accept_session_reply_t *rmp;
551 rmp = vl_msg_api_alloc (sizeof (*rmp));
552 memset (rmp, 0, sizeof (*rmp));
553 rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY);
554 rmp->retval = htonl (retval);
555 rmp->context = context;
556 rmp->handle = handle;
557 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
561 * VPPCOM Event Functions
565 vce_registered_ioevent_handler_fn (void *arg)
567 vce_event_handler_reg_t *reg = (vce_event_handler_reg_t *) arg;
568 vppcom_ioevent_t *eio;
570 u32 ioevt_ndx = (u64) (reg->handler_fn_args);
571 vppcom_session_ioevent_t *ioevent, ioevent_;
573 clib_spinlock_lock (&(vcm->event_thread.events_lockp));
574 ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx);
575 eio = vce_get_event_data (ev, sizeof (*eio));
576 clib_spinlock_unlock (&(vcm->event_thread.events_lockp));
578 clib_spinlock_lock (&vcm->session_io_thread.io_sessions_lockp);
579 ioevent = pool_elt_at_index (vcm->session_io_thread.ioevents, ioevt_ndx);
581 clib_spinlock_unlock (&vcm->session_io_thread.io_sessions_lockp);
582 (ioevent_.user_cb) (eio, ioevent_.user_cb_data);
583 vce_clear_event (&vcm->event_thread, reg->ev_idx);
586 /*TODO - Unregister check in close for this listener */
591 vce_registered_listener_connect_handler_fn (void *arg)
593 vce_event_handler_reg_t *reg = (vce_event_handler_reg_t *) arg;
594 vce_event_connect_request_t *ecr;
598 session_t *new_session;
601 vppcom_session_listener_t *session_listener =
602 (vppcom_session_listener_t *) reg->handler_fn_args;
604 clib_spinlock_lock (&(vcm->event_thread.events_lockp));
605 ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx);
606 ecr = vce_get_event_data (ev, sizeof (*ecr));
607 clib_spinlock_unlock (&(vcm->event_thread.events_lockp));
608 VCL_LOCK_AND_GET_SESSION (ecr->accepted_session_index, &new_session);
610 ep.is_ip4 = new_session->peer_addr.is_ip4;
611 ep.port = new_session->peer_port;
612 if (new_session->peer_addr.is_ip4)
613 clib_memcpy (&ep.ip, &new_session->peer_addr.ip46.ip4,
614 sizeof (ip4_address_t));
616 clib_memcpy (&ep.ip, &new_session->peer_addr.ip46.ip6,
617 sizeof (ip6_address_t));
619 vppcom_send_accept_session_reply (new_session->vpp_handle,
620 new_session->client_context,
622 clib_spinlock_unlock (&vcm->sessions_lockp);
624 (session_listener->user_cb) (ecr->accepted_session_index, &ep,
625 session_listener->user_cb_data);
627 if (vcm->session_io_thread.io_sessions_lockp)
629 /* Throw this new accepted session index into the rx poll thread pool */
630 clib_spinlock_lock (&vcm->session_io_thread.io_sessions_lockp);
631 u32 *active_session_index;
632 pool_get (vcm->session_io_thread.active_session_indexes,
633 active_session_index);
634 *active_session_index = ecr->accepted_session_index;
635 clib_spinlock_unlock (&vcm->session_io_thread.io_sessions_lockp);
638 /*TODO - Unregister check in close for this listener */
642 ASSERT (0); // If we can't get a lock or accepted session fails, lets blow up.
646 * * @brief vce_connect_request_handler_fn
647 * - used for listener sessions
648 * - when a vl_api_accept_session_t_handler() generates an event
649 * this callback is alerted and sets fields that consumers such as
650 * vppcom_session_accept() expect to see, ie. accepted_client_index
652 * @param arg - void* to be cast to vce_event_handler_reg_t*
655 vce_connect_request_handler_fn (void *arg)
657 vce_event_handler_reg_t *reg = (vce_event_handler_reg_t *) arg;
659 pthread_mutex_lock (®->handler_lock);
660 pthread_cond_signal (®->handler_cond);
661 pthread_mutex_unlock (®->handler_lock);
665 * @brief vce_poll_wait_connect_request_handler_fn
666 * - used by vppcom_epoll_xxxx() for listener sessions
667 * - when a vl_api_accept_session_t_handler() generates an event
668 * this callback is alerted and sets the fields that vppcom_epoll_wait()
671 * @param arg - void* to be cast to vce_event_handler_reg_t*
674 vce_poll_wait_connect_request_handler_fn (void *arg)
676 vce_event_handler_reg_t *reg = (vce_event_handler_reg_t *) arg;
678 /* Retrieve the VCL_EVENT_CONNECT_REQ_ACCEPTED event */
679 ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx);
680 vce_event_connect_request_t *ecr = vce_get_event_data (ev, sizeof (*ecr));
682 /* Add the accepted_session_index to the FIFO */
683 clib_spinlock_lock (&vcm->session_fifo_lockp);
684 clib_fifo_add1 (vcm->client_session_index_fifo,
685 ecr->accepted_session_index);
686 clib_spinlock_unlock (&vcm->session_fifo_lockp);
688 /* Recycling the event. */
689 clib_spinlock_lock (&(vcm->event_thread.events_lockp));
691 clib_fifo_add1 (vcm->event_thread.event_index_fifo, reg->ev_idx);
692 clib_spinlock_unlock (&(vcm->event_thread.events_lockp));
696 vppcom_connect_to_vpp (char *app_name)
698 api_main_t *am = &api_main;
699 vppcom_cfg_t *vcl_cfg = &vcm->cfg;
702 if (!vcl_cfg->vpp_api_filename)
703 vcl_cfg->vpp_api_filename = format (0, "/vpe-api%c", 0);
705 if (VPPCOM_DEBUG > 0)
706 clib_warning ("VCL<%d>: app (%s) connecting to VPP api (%s)...",
707 getpid (), app_name, vcl_cfg->vpp_api_filename);
709 if (vl_client_connect_to_vlib ((char *) vcl_cfg->vpp_api_filename, app_name,
710 vcm->cfg.vpp_api_q_length) < 0)
712 clib_warning ("VCL<%d>: app (%s) connect failed!", getpid (), app_name);
713 rv = VPPCOM_ECONNREFUSED;
717 vcm->vl_input_queue = am->shmem_hdr->vl_input_queue;
718 vcm->my_client_index = (u32) am->my_client_index;
719 vcm->app_state = STATE_APP_CONN_VPP;
721 if (VPPCOM_DEBUG > 0)
722 clib_warning ("VCL<%d>: app (%s) is connected to VPP!",
723 getpid (), app_name);
726 if (VPPCOM_DEBUG > 0)
728 vcm->elog_main.lock =
729 clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
730 vcm->elog_main.lock[0] = 0;
731 vcm->elog_main.event_ring_size = vcm->cfg.event_ring_size;
732 elog_init (&vcm->elog_main, vcm->elog_main.event_ring_size);
733 elog_enable_disable (&vcm->elog_main, 1);
735 vcm->elog_track.name =
736 (char *) format (0, "P:%d:C:%d%c", getpid (),
737 vcm->my_client_index, 0);
738 elog_track_register (&vcm->elog_main, &vcm->elog_track);
741 ELOG_TYPE_DECLARE (e) =
743 .format = "connect_vpp:rv:%d",
750 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
758 format_api_error (u8 * s, va_list * args)
760 i32 error = va_arg (*args, u32);
763 p = hash_get (vcm->error_string_by_error_number, -error);
766 s = format (s, "%s (%d)", p[0], error);
768 s = format (s, "%d", error);
773 vppcom_init_error_string_table (void)
775 vcm->error_string_by_error_number = hash_create (0, sizeof (uword));
777 #define _(n, v, s) hash_set (vcm->error_string_by_error_number, -v, s);
778 foreach_vnet_api_error;
781 hash_set (vcm->error_string_by_error_number, 99, "Misc");
785 vppcom_wait_for_app_state_change (app_state_t app_state)
787 f64 timeout = clib_time_now (&vcm->clib_time) + vcm->cfg.app_timeout;
789 while (clib_time_now (&vcm->clib_time) < timeout)
791 if (vcm->app_state == app_state)
794 if (VPPCOM_DEBUG > 0)
795 clib_warning ("VCL<%d>: timeout waiting for state %s (%d)", getpid (),
796 vppcom_app_state_str (app_state), app_state);
798 if (VPPCOM_DEBUG > 0)
801 ELOG_TYPE_DECLARE (e) =
803 .format = "ERR: timeout state:%d",
811 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
813 ed->data = app_state;
817 return VPPCOM_ETIMEDOUT;
821 vppcom_wait_for_session_state_change (u32 session_index,
822 session_state_t state,
825 f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
826 session_t *volatile session;
831 clib_spinlock_lock (&vcm->sessions_lockp);
832 rv = vppcom_session_at_index (session_index, &session);
833 if (PREDICT_FALSE (rv))
835 clib_spinlock_unlock (&vcm->sessions_lockp);
838 if (session->state & state)
840 clib_spinlock_unlock (&vcm->sessions_lockp);
843 if (session->state & STATE_FAILED)
845 clib_spinlock_unlock (&vcm->sessions_lockp);
846 return VPPCOM_ECONNREFUSED;
849 clib_spinlock_unlock (&vcm->sessions_lockp);
851 while (clib_time_now (&vcm->clib_time) < timeout);
853 if (VPPCOM_DEBUG > 0)
854 clib_warning ("VCL<%d>: timeout waiting for state 0x%x (%s)", getpid (),
855 state, vppcom_session_state_str (state));
857 if (VPPCOM_DEBUG > 0)
860 ELOG_TYPE_DECLARE (e) =
862 .format = "ERR: timeout state:%d",
870 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
876 return VPPCOM_ETIMEDOUT;
880 * VPP-API message functions
883 vppcom_send_session_enable_disable (u8 is_enable)
885 vl_api_session_enable_disable_t *bmp;
886 bmp = vl_msg_api_alloc (sizeof (*bmp));
887 memset (bmp, 0, sizeof (*bmp));
889 bmp->_vl_msg_id = ntohs (VL_API_SESSION_ENABLE_DISABLE);
890 bmp->client_index = vcm->my_client_index;
891 bmp->context = htonl (0xfeedface);
892 bmp->is_enable = is_enable;
893 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
897 vppcom_app_session_enable (void)
901 if (vcm->app_state != STATE_APP_ENABLED)
903 vppcom_send_session_enable_disable (1 /* is_enabled == TRUE */ );
904 rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED);
905 if (PREDICT_FALSE (rv))
907 if (VPPCOM_DEBUG > 0)
908 clib_warning ("VCL<%d>: application session enable timed out! "
910 getpid (), rv, vppcom_retval_str (rv));
918 vl_api_session_enable_disable_reply_t_handler
919 (vl_api_session_enable_disable_reply_t * mp)
923 clib_warning ("VCL<%d>: session_enable_disable failed: %U", getpid (),
924 format_api_error, ntohl (mp->retval));
927 vcm->app_state = STATE_APP_ENABLED;
931 vppcom_app_send_attach (void)
933 vl_api_application_attach_t *bmp;
934 u8 nsid_len = vec_len (vcm->cfg.namespace_id);
935 u8 app_is_proxy = (vcm->cfg.app_proxy_transport_tcp ||
936 vcm->cfg.app_proxy_transport_udp);
938 bmp = vl_msg_api_alloc (sizeof (*bmp));
939 memset (bmp, 0, sizeof (*bmp));
941 bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_ATTACH);
942 bmp->client_index = vcm->my_client_index;
943 bmp->context = htonl (0xfeedface);
944 bmp->options[APP_OPTIONS_FLAGS] =
945 APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT |
946 (vcm->cfg.app_scope_local ? APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE : 0) |
947 (vcm->cfg.app_scope_global ? APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE : 0) |
948 (app_is_proxy ? APP_OPTIONS_FLAGS_IS_PROXY : 0);
949 bmp->options[APP_OPTIONS_PROXY_TRANSPORT] =
950 (u64) ((vcm->cfg.app_proxy_transport_tcp ? 1 << TRANSPORT_PROTO_TCP : 0) |
951 (vcm->cfg.app_proxy_transport_udp ? 1 << TRANSPORT_PROTO_UDP : 0));
952 bmp->options[APP_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size;
953 bmp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size;
954 bmp->options[APP_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size;
955 bmp->options[APP_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size;
956 bmp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
957 vcm->cfg.preallocated_fifo_pairs;
958 bmp->options[APP_OPTIONS_EVT_QUEUE_SIZE] = vcm->cfg.event_queue_size;
961 bmp->namespace_id_len = nsid_len;
962 clib_memcpy (bmp->namespace_id, vcm->cfg.namespace_id, nsid_len);
963 bmp->options[APP_OPTIONS_NAMESPACE_SECRET] = vcm->cfg.namespace_secret;
965 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
969 vppcom_app_attach (void)
973 vppcom_app_send_attach ();
974 rv = vppcom_wait_for_app_state_change (STATE_APP_ATTACHED);
975 if (PREDICT_FALSE (rv))
977 if (VPPCOM_DEBUG > 0)
978 clib_warning ("VCL<%d>: application attach timed out! "
980 getpid (), rv, vppcom_retval_str (rv));
988 vppcom_app_detach (void)
990 vl_api_application_detach_t *bmp;
991 bmp = vl_msg_api_alloc (sizeof (*bmp));
992 memset (bmp, 0, sizeof (*bmp));
994 bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH);
995 bmp->client_index = vcm->my_client_index;
996 bmp->context = htonl (0xfeedface);
997 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
1001 vl_api_application_attach_reply_t_handler (vl_api_application_attach_reply_t *
1004 static svm_fifo_segment_create_args_t _a;
1005 svm_fifo_segment_create_args_t *a = &_a;
1008 memset (a, 0, sizeof (*a));
1011 clib_warning ("VCL<%d>: attach failed: %U", getpid (),
1012 format_api_error, ntohl (mp->retval));
1016 if (mp->segment_name_length == 0)
1018 clib_warning ("VCL<%d>: segment_name_length zero", getpid ());
1022 a->segment_name = (char *) mp->segment_name;
1023 a->segment_size = mp->segment_size;
1025 ASSERT (mp->app_event_queue_address);
1027 /* Attach to the segment vpp created */
1028 rv = svm_fifo_segment_attach (a);
1029 vec_reset_length (a->new_segment_indices);
1030 if (PREDICT_FALSE (rv))
1032 clib_warning ("VCL<%d>: svm_fifo_segment_attach ('%s') failed",
1033 getpid (), mp->segment_name);
1037 vcm->app_event_queue =
1038 uword_to_pointer (mp->app_event_queue_address, svm_queue_t *);
1040 vcm->app_state = STATE_APP_ATTACHED;
1044 vl_api_application_detach_reply_t_handler (vl_api_application_detach_reply_t *
1048 clib_warning ("VCL<%d>: detach failed: %U", getpid (), format_api_error,
1049 ntohl (mp->retval));
1051 vcm->app_state = STATE_APP_ENABLED;
1055 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
1059 clib_warning ("VCL<%d>: vpp handle 0x%llx: disconnect session failed: %U",
1060 getpid (), mp->handle, format_api_error,
1061 ntohl (mp->retval));
1065 vl_api_map_another_segment_t_handler (vl_api_map_another_segment_t * mp)
1067 static svm_fifo_segment_create_args_t _a;
1068 svm_fifo_segment_create_args_t *a = &_a;
1071 memset (a, 0, sizeof (*a));
1072 a->segment_name = (char *) mp->segment_name;
1073 a->segment_size = mp->segment_size;
1074 /* Attach to the segment vpp created */
1075 rv = svm_fifo_segment_attach (a);
1076 vec_reset_length (a->new_segment_indices);
1077 if (PREDICT_FALSE (rv))
1079 clib_warning ("VCL<%d>: svm_fifo_segment_attach ('%s') failed",
1080 getpid (), mp->segment_name);
1083 if (VPPCOM_DEBUG > 1)
1084 clib_warning ("VCL<%d>: mapped new segment '%s' size %d", getpid (),
1085 mp->segment_name, mp->segment_size);
1089 vl_api_unmap_segment_t_handler (vl_api_unmap_segment_t * mp)
1093 * XXX Need segment_name to session_id hash,
1094 * XXX - have sessionID by handle hash currently
1096 if (VPPCOM_DEBUG > 1)
1097 clib_warning ("Unmapped segment '%s'", mp->segment_name);
1101 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
1105 p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
1109 session_t *session = 0;
1110 u32 session_index = p[0];
1112 VCL_LOCK_AND_GET_SESSION (session_index, &session);
1113 session->state = STATE_CLOSE_ON_EMPTY;
1115 if (VPPCOM_DEBUG > 1)
1116 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1117 "setting state to 0x%x (%s)",
1118 getpid (), mp->handle, session_index, session->state,
1119 vppcom_session_state_str (session->state));
1120 clib_spinlock_unlock (&vcm->sessions_lockp);
1124 if (VPPCOM_DEBUG > 1)
1125 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1126 "session lookup failed!",
1127 getpid (), mp->handle, session_index);
1130 clib_warning ("VCL<%d>: vpp handle 0x%llx: session lookup by "
1131 "handle failed!", getpid (), mp->handle);
1135 vl_api_reset_session_t_handler (vl_api_reset_session_t * mp)
1137 session_t *session = 0;
1138 vl_api_reset_session_reply_t *rmp;
1142 p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
1146 clib_spinlock_lock (&vcm->sessions_lockp);
1147 rval = vppcom_session_at_index (p[0], &session);
1148 if (PREDICT_FALSE (rval))
1150 rv = VNET_API_ERROR_INVALID_VALUE_2;
1151 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
1152 "session lookup failed! returning %d %U",
1153 getpid (), mp->handle, p[0],
1154 rv, format_api_error, rv);
1158 /* TBD: should this disconnect immediately and
1161 session->state = STATE_CLOSE_ON_EMPTY;
1163 if (VPPCOM_DEBUG > 1)
1164 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1165 "state set to %d (%s)!", getpid (),
1166 mp->handle, p[0], session->state,
1167 vppcom_session_state_str (session->state));
1169 clib_spinlock_unlock (&vcm->sessions_lockp);
1173 rv = VNET_API_ERROR_INVALID_VALUE;
1174 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx: session lookup "
1175 "failed! returning %d %U",
1176 getpid (), mp->handle, rv, format_api_error, rv);
1179 rmp = vl_msg_api_alloc (sizeof (*rmp));
1180 memset (rmp, 0, sizeof (*rmp));
1181 rmp->_vl_msg_id = ntohs (VL_API_RESET_SESSION_REPLY);
1182 rmp->retval = htonl (rv);
1183 rmp->handle = mp->handle;
1184 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
1188 vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp)
1190 session_t *session = 0;
1192 svm_fifo_t *rx_fifo, *tx_fifo;
1195 session_index = mp->context;
1196 VCL_LOCK_AND_GET_SESSION (session_index, &session);
1200 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
1201 "connect failed! %U",
1202 getpid (), mp->handle, session_index,
1203 format_api_error, ntohl (mp->retval));
1206 session->state = STATE_FAILED;
1207 session->vpp_handle = mp->handle;
1211 clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
1212 "Invalid session index (%u)!",
1213 getpid (), mp->handle, session_index);
1224 if (vcm->session_io_thread.io_sessions_lockp)
1226 // Add this connection to the active io sessions list
1227 clib_spinlock_lock (&vcm->session_io_thread.io_sessions_lockp);
1228 u32 *active_session_index;
1229 pool_get (vcm->session_io_thread.active_session_indexes,
1230 active_session_index);
1231 *active_session_index = session_index;
1232 clib_spinlock_unlock (&vcm->session_io_thread.io_sessions_lockp);
1234 session->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
1237 rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
1238 rx_fifo->client_session_index = session_index;
1239 tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
1240 tx_fifo->client_session_index = session_index;
1242 session->rx_fifo = rx_fifo;
1243 session->tx_fifo = tx_fifo;
1244 session->vpp_handle = mp->handle;
1245 session->lcl_addr.is_ip4 = mp->is_ip4;
1246 clib_memcpy (&session->lcl_addr.ip46, mp->lcl_ip,
1247 sizeof (session->peer_addr.ip46));
1248 session->lcl_port = mp->lcl_port;
1249 session->state = STATE_CONNECT;
1251 /* Add it to lookup table */
1252 hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
1254 if (VPPCOM_DEBUG > 1)
1255 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: connect succeeded!"
1256 " session_rx_fifo %p, refcnt %d,"
1257 " session_tx_fifo %p, refcnt %d",
1258 getpid (), mp->handle, session_index,
1260 session->rx_fifo->refcnt,
1261 session->tx_fifo, session->tx_fifo->refcnt);
1263 clib_spinlock_unlock (&vcm->sessions_lockp);
1267 vppcom_send_connect_sock (session_t * session, u32 session_index)
1269 vl_api_connect_sock_t *cmp;
1271 /* Assumes caller as acquired the spinlock: vcm->sessions_lockp */
1272 cmp = vl_msg_api_alloc (sizeof (*cmp));
1273 memset (cmp, 0, sizeof (*cmp));
1274 cmp->_vl_msg_id = ntohs (VL_API_CONNECT_SOCK);
1275 cmp->client_index = vcm->my_client_index;
1276 cmp->context = session_index;
1278 cmp->is_ip4 = session->peer_addr.is_ip4;
1279 clib_memcpy (cmp->ip, &session->peer_addr.ip46, sizeof (cmp->ip));
1280 cmp->port = session->peer_port;
1281 cmp->proto = session->proto;
1282 clib_memcpy (cmp->options, session->options, sizeof (cmp->options));
1283 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & cmp);
1287 vppcom_send_disconnect_session_reply (u64 vpp_handle, u32 session_index,
1290 vl_api_disconnect_session_reply_t *rmp;
1292 if (VPPCOM_DEBUG > 1)
1293 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1294 "sending disconnect msg",
1295 getpid (), vpp_handle, session_index);
1297 rmp = vl_msg_api_alloc (sizeof (*rmp));
1298 memset (rmp, 0, sizeof (*rmp));
1300 rmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION_REPLY);
1301 rmp->retval = htonl (rv);
1302 rmp->handle = vpp_handle;
1303 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
1307 vppcom_send_disconnect_session (u64 vpp_handle, u32 session_index)
1309 vl_api_disconnect_session_t *dmp;
1311 if (VPPCOM_DEBUG > 1)
1312 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1313 "sending disconnect msg",
1314 getpid (), vpp_handle, session_index);
1316 dmp = vl_msg_api_alloc (sizeof (*dmp));
1317 memset (dmp, 0, sizeof (*dmp));
1318 dmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION);
1319 dmp->client_index = vcm->my_client_index;
1320 dmp->handle = vpp_handle;
1321 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & dmp);
1325 vl_api_bind_sock_reply_t_handler (vl_api_bind_sock_reply_t * mp)
1327 session_t *session = 0;
1328 u32 session_index = mp->context;
1331 VCL_LOCK_AND_GET_SESSION (session_index, &session);
1335 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, "
1336 "sid %u: bind failed: %U",
1337 getpid (), mp->handle, session_index,
1338 format_api_error, ntohl (mp->retval));
1339 rv = vppcom_session_at_index (session_index, &session);
1340 if (rv == VPPCOM_OK)
1342 session->state = STATE_FAILED;
1343 session->vpp_handle = mp->handle;
1347 clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
1348 "Invalid session index (%u)!",
1349 getpid (), mp->handle, session_index);
1354 session->vpp_handle = mp->handle;
1355 session->lcl_addr.is_ip4 = mp->lcl_is_ip4;
1356 session->lcl_addr.ip46 = to_ip46 (!mp->lcl_is_ip4, mp->lcl_ip);
1357 session->lcl_port = mp->lcl_port;
1358 vppcom_session_table_add_listener (mp->handle, session_index);
1359 session->state = STATE_LISTEN;
1361 if (VPPCOM_DEBUG > 1)
1362 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: bind succeeded!",
1363 getpid (), mp->handle, mp->context);
1365 clib_spinlock_unlock (&vcm->sessions_lockp);
1369 vl_api_unbind_sock_reply_t_handler (vl_api_unbind_sock_reply_t * mp)
1372 clib_warning ("VCL<%d>: ERROR: sid %u: unbind failed: %U",
1373 getpid (), mp->context, format_api_error,
1374 ntohl (mp->retval));
1376 else if (VPPCOM_DEBUG > 1)
1377 clib_warning ("VCL<%d>: sid %u: unbind succeeded!",
1378 getpid (), mp->context);
1382 format_ip4_address (u8 * s, va_list * args)
1384 u8 *a = va_arg (*args, u8 *);
1385 return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
1389 format_ip6_address (u8 * s, va_list * args)
1391 ip6_address_t *a = va_arg (*args, ip6_address_t *);
1392 u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
1394 i_max_n_zero = ARRAY_LEN (a->as_u16);
1396 i_first_zero = i_max_n_zero;
1398 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1400 u32 is_zero = a->as_u16[i] == 0;
1401 if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
1407 if ((!is_zero && n_zeros > max_n_zeros)
1408 || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
1410 i_max_n_zero = i_first_zero;
1411 max_n_zeros = n_zeros;
1412 i_first_zero = ARRAY_LEN (a->as_u16);
1417 last_double_colon = 0;
1418 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1420 if (i == i_max_n_zero && max_n_zeros > 1)
1422 s = format (s, "::");
1423 i += max_n_zeros - 1;
1424 last_double_colon = 1;
1428 s = format (s, "%s%x",
1429 (last_double_colon || i == 0) ? "" : ":",
1430 clib_net_to_host_u16 (a->as_u16[i]));
1431 last_double_colon = 0;
1438 /* Format an IP46 address. */
1440 format_ip46_address (u8 * s, va_list * args)
1442 ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
1443 ip46_type_t type = va_arg (*args, ip46_type_t);
1449 is_ip4 = ip46_address_is_ip4 (ip46);
1460 format (s, "%U", format_ip4_address, &ip46->ip4) :
1461 format (s, "%U", format_ip6_address, &ip46->ip6);
1465 vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
1467 svm_fifo_t *rx_fifo, *tx_fifo;
1468 session_t *session, *listen_session;
1470 vce_event_connect_request_t *ecr;
1476 clib_spinlock_lock (&vcm->sessions_lockp);
1478 clib_spinlock_lock (&vcm->session_fifo_lockp);
1479 elts = clib_fifo_free_elts (vcm->client_session_index_fifo);
1480 clib_spinlock_unlock (&vcm->session_fifo_lockp);
1484 clib_warning ("VCL<%d>: client session queue is full!", getpid ());
1485 vppcom_send_accept_session_reply (mp->handle, mp->context,
1486 VNET_API_ERROR_QUEUE_FULL);
1487 clib_spinlock_unlock (&vcm->sessions_lockp);
1491 listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
1492 if (!listen_session)
1494 clib_warning ("VCL<%d>: ERROR: couldn't find listen session: "
1495 "unknown vpp listener handle %llx",
1496 getpid (), mp->listener_handle);
1497 vppcom_send_accept_session_reply (mp->handle, mp->context,
1498 VNET_API_ERROR_INVALID_ARGUMENT);
1499 clib_spinlock_unlock (&vcm->sessions_lockp);
1503 /* TODO check listener depth and update */
1504 /* TODO on "child" fd close, update listener depth */
1506 /* Allocate local session and set it up */
1507 pool_get (vcm->sessions, session);
1508 memset (session, 0, sizeof (*session));
1509 session_index = (u32) (session - vcm->sessions);
1511 rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
1512 rx_fifo->client_session_index = session_index;
1513 tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
1514 tx_fifo->client_session_index = session_index;
1516 session->vpp_handle = mp->handle;
1517 session->client_context = mp->context;
1518 session->rx_fifo = rx_fifo;
1519 session->tx_fifo = tx_fifo;
1520 session->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
1522 session->state = STATE_ACCEPT;
1523 session->peer_port = mp->port;
1524 session->peer_addr.is_ip4 = mp->is_ip4;
1525 session->peer_addr.ip46 = to_ip46 (!mp->is_ip4, mp->ip);
1527 /* Add it to lookup table */
1528 hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
1529 session->lcl_port = listen_session->lcl_port;
1530 session->lcl_addr = listen_session->lcl_addr;
1532 /* Create an event for handlers */
1534 clib_spinlock_lock (&vcm->event_thread.events_lockp);
1536 pool_get (vcm->event_thread.vce_events, ev);
1537 ev_idx = (u32) (ev - vcm->event_thread.vce_events);
1538 ecr = vce_get_event_data (ev, sizeof (*ecr));
1539 ev->evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
1540 listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
1541 ev->evk.session_index = (u32) (listen_session - vcm->sessions);
1542 ecr->accepted_session_index = session_index;
1544 clib_spinlock_unlock (&vcm->event_thread.events_lockp);
1546 rv = vce_generate_event (&vcm->event_thread, ev_idx);
1549 if (VPPCOM_DEBUG > 1)
1550 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: client accept "
1551 "request from %s address %U port %d queue %p!", getpid (),
1552 mp->handle, session_index, mp->is_ip4 ? "IPv4" : "IPv6",
1553 format_ip46_address, &mp->ip,
1554 mp->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
1555 clib_net_to_host_u16 (mp->port), session->vpp_event_queue);
1557 if (VPPCOM_DEBUG > 0)
1559 session->elog_track.name =
1560 (char *) format (0, "C:%d:S:%d%c", vcm->my_client_index,
1562 elog_track_register (&vcm->elog_main, &session->elog_track);
1564 if (session->peer_addr.is_ip4)
1567 ELOG_TYPE_DECLARE (e) =
1570 "client_accept:handle:%x addr:%d.%d.%d.%d:%d",
1571 .format_args = "i8i1i1i1i1i2",
1574 CLIB_PACKED (struct {
1580 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
1582 ed->handle = mp->handle;
1583 ed->addr[0] = session->peer_addr.ip46.ip4.as_u8[0];
1584 ed->addr[1] = session->peer_addr.ip46.ip4.as_u8[1];
1585 ed->addr[2] = session->peer_addr.ip46.ip4.as_u8[2];
1586 ed->addr[3] = session->peer_addr.ip46.ip4.as_u8[3];
1587 ed->port = clib_net_to_host_u16 (session->peer_port);
1592 clib_warning ("ip6");
1596 clib_spinlock_unlock (&vcm->sessions_lockp);
1600 /* VPP combines bind and listen as one operation. VCL manages the separation
1601 * of bind and listen locally via vppcom_session_bind() and
1602 * vppcom_session_listen() */
1604 vppcom_send_bind_sock (session_t * session, u32 session_index)
1606 vl_api_bind_sock_t *bmp;
1608 /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
1609 bmp = vl_msg_api_alloc (sizeof (*bmp));
1610 memset (bmp, 0, sizeof (*bmp));
1612 bmp->_vl_msg_id = ntohs (VL_API_BIND_SOCK);
1613 bmp->client_index = vcm->my_client_index;
1614 bmp->context = session_index;
1615 bmp->is_ip4 = session->lcl_addr.is_ip4;
1616 clib_memcpy (bmp->ip, &session->lcl_addr.ip46, sizeof (bmp->ip));
1617 bmp->port = session->lcl_port;
1618 bmp->proto = session->proto;
1619 clib_memcpy (bmp->options, session->options, sizeof (bmp->options));
1620 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
1624 vppcom_send_unbind_sock (u64 vpp_handle)
1626 vl_api_unbind_sock_t *ump;
1628 ump = vl_msg_api_alloc (sizeof (*ump));
1629 memset (ump, 0, sizeof (*ump));
1631 ump->_vl_msg_id = ntohs (VL_API_UNBIND_SOCK);
1632 ump->client_index = vcm->my_client_index;
1633 ump->handle = vpp_handle;
1634 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & ump);
1638 vppcom_session_unbind (u32 session_index)
1640 session_t *session = 0;
1643 elog_track_t session_elog_track;
1645 VCL_LOCK_AND_GET_SESSION (session_index, &session);
1647 vpp_handle = session->vpp_handle;
1648 vppcom_session_table_del_listener (vpp_handle);
1649 session->vpp_handle = ~0;
1650 session->state = STATE_DISCONNECT;
1651 session_elog_track = session->elog_track;
1653 clib_spinlock_unlock (&vcm->sessions_lockp);
1655 if (VPPCOM_DEBUG > 1)
1656 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1657 "sending unbind msg! new state 0x%x (%s)",
1658 getpid (), vpp_handle, session_index,
1660 vppcom_session_state_str (STATE_DISCONNECT));
1662 if (VPPCOM_DEBUG > 0)
1665 ELOG_TYPE_DECLARE (e) =
1667 .format = "unbind: handle:%x",
1668 .format_args = "i8",
1676 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session_elog_track);
1677 ed->handle = vpp_handle;
1681 vppcom_send_unbind_sock (vpp_handle);
1688 vppcom_session_disconnect (u32 session_index)
1693 session_state_t state;
1695 VCL_LOCK_AND_GET_SESSION (session_index, &session);
1697 vpp_handle = session->vpp_handle;
1698 state = session->state;
1699 clib_spinlock_unlock (&vcm->sessions_lockp);
1701 if (VPPCOM_DEBUG > 1)
1703 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u "
1705 getpid (), vpp_handle, session_index,
1706 state, vppcom_session_state_str (state));
1709 if (PREDICT_FALSE (state & STATE_LISTEN))
1711 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
1712 "Cannot disconnect a listen socket!",
1713 getpid (), vpp_handle, session_index);
1718 /* The peer has already initiated the close,
1719 * so send the disconnect session reply.
1721 if (state & STATE_CLOSE_ON_EMPTY)
1723 //XXX alagalah - Check and drain here?
1724 vppcom_send_disconnect_session_reply (vpp_handle,
1725 session_index, 0 /* rv */ );
1726 if (VPPCOM_DEBUG > 1)
1727 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1728 "sending disconnect REPLY...",
1729 getpid (), vpp_handle, session_index);
1732 /* Otherwise, send a disconnect session msg...
1736 if (VPPCOM_DEBUG > 1)
1737 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
1738 "sending disconnect...",
1739 getpid (), vpp_handle, session_index);
1741 vppcom_send_disconnect_session (vpp_handle, session_index);
1748 #define foreach_sock_msg \
1749 _(SESSION_ENABLE_DISABLE_REPLY, session_enable_disable_reply) \
1750 _(BIND_SOCK_REPLY, bind_sock_reply) \
1751 _(UNBIND_SOCK_REPLY, unbind_sock_reply) \
1752 _(ACCEPT_SESSION, accept_session) \
1753 _(CONNECT_SESSION_REPLY, connect_session_reply) \
1754 _(DISCONNECT_SESSION, disconnect_session) \
1755 _(DISCONNECT_SESSION_REPLY, disconnect_session_reply) \
1756 _(RESET_SESSION, reset_session) \
1757 _(APPLICATION_ATTACH_REPLY, application_attach_reply) \
1758 _(APPLICATION_DETACH_REPLY, application_detach_reply) \
1759 _(MAP_ANOTHER_SEGMENT, map_another_segment) \
1760 _(UNMAP_SEGMENT, unmap_segment)
1763 vppcom_api_hookup (void)
1766 vl_msg_api_set_handlers(VL_API_##N, #n, \
1767 vl_api_##n##_t_handler, \
1769 vl_api_##n##_t_endian, \
1770 vl_api_##n##_t_print, \
1771 sizeof(vl_api_##n##_t), 1);
1777 vppcom_cfg_init (vppcom_cfg_t * vcl_cfg)
1781 vcl_cfg->heapsize = (256ULL << 20);
1782 vcl_cfg->vpp_api_q_length = 1024;
1783 vcl_cfg->segment_baseva = 0x200000000ULL;
1784 vcl_cfg->segment_size = (256 << 20);
1785 vcl_cfg->add_segment_size = (128 << 20);
1786 vcl_cfg->preallocated_fifo_pairs = 8;
1787 vcl_cfg->rx_fifo_size = (1 << 20);
1788 vcl_cfg->tx_fifo_size = (1 << 20);
1789 vcl_cfg->event_queue_size = 2048;
1790 vcl_cfg->listen_queue_size = CLIB_CACHE_LINE_BYTES / sizeof (u32);
1791 vcl_cfg->app_timeout = 10 * 60.0;
1792 vcl_cfg->session_timeout = 10 * 60.0;
1793 vcl_cfg->accept_timeout = 60.0;
1794 vcl_cfg->event_ring_size = (128 << 10);
1795 vcl_cfg->event_log_path = "/dev/shm";
1799 vppcom_cfg_heapsize (char *conf_fname)
1801 vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1814 fp = fopen (conf_fname, "r");
1817 if (VPPCOM_DEBUG > 0)
1818 clib_warning ("VCL<%d>: using default heapsize %lld (0x%llx)",
1819 getpid (), vcl_cfg->heapsize, vcl_cfg->heapsize);
1823 argv = calloc (1, sizeof (char *));
1826 if (VPPCOM_DEBUG > 0)
1827 clib_warning ("VCL<%d>: calloc failed, using default "
1828 "heapsize %lld (0x%llx)",
1829 getpid (), vcl_cfg->heapsize, vcl_cfg->heapsize);
1835 if (fgets (inbuf, 4096, fp) == 0)
1837 p = strtok (inbuf, " \t\n");
1843 char **tmp = realloc (argv, argc * sizeof (char *));
1846 if (VPPCOM_DEBUG > 0)
1847 clib_warning ("VCL<%d>: realloc failed, "
1848 "using default heapsize %lld (0x%llx)",
1849 getpid (), vcl_cfg->heapsize,
1854 arg = strndup (p, 1024);
1857 if (VPPCOM_DEBUG > 0)
1858 clib_warning ("VCL<%d>: strndup failed, "
1859 "using default heapsize %lld (0x%llx)",
1860 getpid (), vcl_cfg->heapsize,
1864 argv[argc - 1] = arg;
1865 p = strtok (NULL, " \t\n");
1872 char **tmp = realloc (argv, (argc + 1) * sizeof (char *));
1875 if (VPPCOM_DEBUG > 0)
1876 clib_warning ("VCL<%d>: realloc failed, "
1877 "using default heapsize %lld (0x%llx)",
1878 getpid (), vcl_cfg->heapsize, vcl_cfg->heapsize);
1885 * Look for and parse the "heapsize" config parameter.
1886 * Manual since none of the clib infra has been bootstrapped yet.
1888 * Format: heapsize <nn>[mM][gG]
1891 for (i = 1; i < (argc - 1); i++)
1893 if (!strncmp (argv[i], "heapsize", 8))
1895 sizep = (u8 *) argv[i + 1];
1897 while (*sizep >= '0' && *sizep <= '9')
1900 size += *sizep++ - '0';
1904 if (VPPCOM_DEBUG > 0)
1905 clib_warning ("VCL<%d>: parse error '%s %s', "
1906 "using default heapsize %lld (0x%llx)",
1907 getpid (), argv[i], argv[i + 1],
1908 vcl_cfg->heapsize, vcl_cfg->heapsize);
1912 if (*sizep == 'g' || *sizep == 'G')
1913 vcl_cfg->heapsize = size << 30;
1914 else if (*sizep == 'm' || *sizep == 'M')
1915 vcl_cfg->heapsize = size << 20;
1918 if (VPPCOM_DEBUG > 0)
1919 clib_warning ("VCL<%d>: parse error '%s %s', "
1920 "using default heapsize %lld (0x%llx)",
1921 getpid (), argv[i], argv[i + 1],
1922 vcl_cfg->heapsize, vcl_cfg->heapsize);
1934 vcl_mem = mmap (0, vcl_cfg->heapsize, PROT_READ | PROT_WRITE,
1935 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
1936 if (vcl_mem == MAP_FAILED)
1938 clib_unix_error ("VCL<%d>: ERROR: mmap(0, %lld == 0x%llx, "
1939 "PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, "
1941 getpid (), vcl_cfg->heapsize, vcl_cfg->heapsize);
1942 ASSERT (vcl_mem != MAP_FAILED);
1945 heap = clib_mem_init (vcl_mem, vcl_cfg->heapsize);
1948 clib_warning ("VCL<%d>: ERROR: clib_mem_init() failed!", getpid ());
1952 vcl_mem = clib_mem_alloc (sizeof (_vppcom_main));
1955 clib_warning ("VCL<%d>: ERROR: clib_mem_alloc() failed!", getpid ());
1960 clib_memcpy (vcl_mem, &_vppcom_main, sizeof (_vppcom_main));
1963 if (VPPCOM_DEBUG > 0)
1964 clib_warning ("VCL<%d>: allocated VCL heap = %p, size %lld (0x%llx)",
1965 getpid (), heap, vcl_cfg->heapsize, vcl_cfg->heapsize);
1969 vppcom_cfg_read (char *conf_fname)
1971 vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1973 unformat_input_t _input, *input = &_input;
1974 unformat_input_t _line_input, *line_input = &_line_input;
1975 u8 vc_cfg_input = 0;
1978 u32 uid, gid, q_len;
1980 fd = open (conf_fname, O_RDONLY);
1983 if (VPPCOM_DEBUG > 0)
1984 clib_warning ("VCL<%d>: using default configuration.",
1985 getpid (), conf_fname);
1989 if (fstat (fd, &s) < 0)
1991 if (VPPCOM_DEBUG > 0)
1992 clib_warning ("VCL<%d>: failed to stat `%s', "
1993 "using default configuration", getpid (), conf_fname);
1997 if (!(S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
1999 if (VPPCOM_DEBUG > 0)
2000 clib_warning ("VCL<%d>: not a regular file `%s', "
2001 "using default configuration", getpid (), conf_fname);
2005 unformat_init_clib_file (input, fd);
2007 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2009 (void) unformat_user (input, unformat_line_input, line_input);
2010 unformat_skip_white_space (line_input);
2012 if (unformat (line_input, "vcl {"))
2020 if (unformat (line_input, "heapsize %s", &chroot_path))
2022 vec_terminate_c_string (chroot_path);
2023 if (VPPCOM_DEBUG > 0)
2024 clib_warning ("VCL<%d>: configured heapsize %s, "
2025 "actual heapsize %lld (0x%llx)",
2026 getpid (), chroot_path, vcl_cfg->heapsize,
2028 vec_free (chroot_path);
2030 else if (unformat (line_input, "api-prefix %s", &chroot_path))
2032 vec_terminate_c_string (chroot_path);
2033 if (vcl_cfg->vpp_api_filename)
2034 vec_free (vcl_cfg->vpp_api_filename);
2035 vcl_cfg->vpp_api_filename = format (0, "/%s-vpe-api%c",
2037 vl_set_memory_root_path ((char *) chroot_path);
2039 if (VPPCOM_DEBUG > 0)
2040 clib_warning ("VCL<%d>: configured api-prefix (%s) and "
2041 "api filename (%s)", getpid (), chroot_path,
2042 vcl_cfg->vpp_api_filename);
2043 chroot_path = 0; /* Don't vec_free() it! */
2045 else if (unformat (line_input, "vpp-api-q-length %d", &q_len))
2047 if (q_len < vcl_cfg->vpp_api_q_length)
2049 clib_warning ("VCL<%d>: ERROR: configured vpp-api-q-length "
2050 "(%u) is too small! Using default: %u ",
2051 getpid (), q_len, vcl_cfg->vpp_api_q_length);
2055 vcl_cfg->vpp_api_q_length = q_len;
2057 if (VPPCOM_DEBUG > 0)
2058 clib_warning ("VCL<%d>: configured vpp-api-q-length %u",
2059 getpid (), vcl_cfg->vpp_api_q_length);
2062 else if (unformat (line_input, "uid %d", &uid))
2064 vl_set_memory_uid (uid);
2065 if (VPPCOM_DEBUG > 0)
2066 clib_warning ("VCL<%d>: configured uid %d", getpid (), uid);
2068 else if (unformat (line_input, "gid %d", &gid))
2070 vl_set_memory_gid (gid);
2071 if (VPPCOM_DEBUG > 0)
2072 clib_warning ("VCL<%d>: configured gid %d", getpid (), gid);
2074 else if (unformat (line_input, "segment-baseva 0x%lx",
2075 &vcl_cfg->segment_baseva))
2077 if (VPPCOM_DEBUG > 0)
2078 clib_warning ("VCL<%d>: configured segment_baseva 0x%lx",
2079 getpid (), vcl_cfg->segment_baseva);
2081 else if (unformat (line_input, "segment-size 0x%lx",
2082 &vcl_cfg->segment_size))
2084 if (VPPCOM_DEBUG > 0)
2085 clib_warning ("VCL<%d>: configured segment_size 0x%lx (%ld)",
2086 getpid (), vcl_cfg->segment_size,
2087 vcl_cfg->segment_size);
2089 else if (unformat (line_input, "segment-size %ld",
2090 &vcl_cfg->segment_size))
2092 if (VPPCOM_DEBUG > 0)
2093 clib_warning ("VCL<%d>: configured segment_size %ld (0x%lx)",
2094 getpid (), vcl_cfg->segment_size,
2095 vcl_cfg->segment_size);
2097 else if (unformat (line_input, "add-segment-size 0x%lx",
2098 &vcl_cfg->add_segment_size))
2100 if (VPPCOM_DEBUG > 0)
2102 ("VCL<%d>: configured add_segment_size 0x%lx (%ld)",
2103 getpid (), vcl_cfg->add_segment_size,
2104 vcl_cfg->add_segment_size);
2106 else if (unformat (line_input, "add-segment-size %ld",
2107 &vcl_cfg->add_segment_size))
2109 if (VPPCOM_DEBUG > 0)
2111 ("VCL<%d>: configured add_segment_size %ld (0x%lx)",
2112 getpid (), vcl_cfg->add_segment_size,
2113 vcl_cfg->add_segment_size);
2115 else if (unformat (line_input, "preallocated-fifo-pairs %d",
2116 &vcl_cfg->preallocated_fifo_pairs))
2118 if (VPPCOM_DEBUG > 0)
2119 clib_warning ("VCL<%d>: configured preallocated_fifo_pairs "
2120 "%d (0x%x)", getpid (),
2121 vcl_cfg->preallocated_fifo_pairs,
2122 vcl_cfg->preallocated_fifo_pairs);
2124 else if (unformat (line_input, "rx-fifo-size 0x%lx",
2125 &vcl_cfg->rx_fifo_size))
2127 if (VPPCOM_DEBUG > 0)
2128 clib_warning ("VCL<%d>: configured rx_fifo_size 0x%lx (%ld)",
2129 getpid (), vcl_cfg->rx_fifo_size,
2130 vcl_cfg->rx_fifo_size);
2132 else if (unformat (line_input, "rx-fifo-size %ld",
2133 &vcl_cfg->rx_fifo_size))
2135 if (VPPCOM_DEBUG > 0)
2136 clib_warning ("VCL<%d>: configured rx_fifo_size %ld (0x%lx)",
2137 getpid (), vcl_cfg->rx_fifo_size,
2138 vcl_cfg->rx_fifo_size);
2140 else if (unformat (line_input, "tx-fifo-size 0x%lx",
2141 &vcl_cfg->tx_fifo_size))
2143 if (VPPCOM_DEBUG > 0)
2144 clib_warning ("VCL<%d>: configured tx_fifo_size 0x%lx (%ld)",
2145 getpid (), vcl_cfg->tx_fifo_size,
2146 vcl_cfg->tx_fifo_size);
2148 else if (unformat (line_input, "tx-fifo-size %ld",
2149 &vcl_cfg->tx_fifo_size))
2151 if (VPPCOM_DEBUG > 0)
2152 clib_warning ("VCL<%d>: configured tx_fifo_size %ld (0x%lx)",
2153 getpid (), vcl_cfg->tx_fifo_size,
2154 vcl_cfg->tx_fifo_size);
2156 else if (unformat (line_input, "event-queue-size 0x%lx",
2157 &vcl_cfg->event_queue_size))
2159 if (VPPCOM_DEBUG > 0)
2160 clib_warning ("VCL<%d>: configured event_queue_size "
2162 getpid (), vcl_cfg->event_queue_size,
2163 vcl_cfg->event_queue_size);
2165 else if (unformat (line_input, "event-queue-size %ld",
2166 &vcl_cfg->event_queue_size))
2168 if (VPPCOM_DEBUG > 0)
2169 clib_warning ("VCL<%d>: configured event_queue_size "
2171 getpid (), vcl_cfg->event_queue_size,
2172 vcl_cfg->event_queue_size);
2174 else if (unformat (line_input, "listen-queue-size 0x%lx",
2175 &vcl_cfg->listen_queue_size))
2177 if (VPPCOM_DEBUG > 0)
2178 clib_warning ("VCL<%d>: configured listen_queue_size "
2180 getpid (), vcl_cfg->listen_queue_size,
2181 vcl_cfg->listen_queue_size);
2183 else if (unformat (line_input, "listen-queue-size %ld",
2184 &vcl_cfg->listen_queue_size))
2186 if (VPPCOM_DEBUG > 0)
2187 clib_warning ("VCL<%d>: configured listen_queue_size "
2189 getpid (), vcl_cfg->listen_queue_size,
2190 vcl_cfg->listen_queue_size);
2192 else if (unformat (line_input, "app-timeout %f",
2193 &vcl_cfg->app_timeout))
2195 if (VPPCOM_DEBUG > 0)
2196 clib_warning ("VCL<%d>: configured app_timeout %f",
2197 getpid (), vcl_cfg->app_timeout);
2199 else if (unformat (line_input, "session-timeout %f",
2200 &vcl_cfg->session_timeout))
2202 if (VPPCOM_DEBUG > 0)
2203 clib_warning ("VCL<%d>: configured session_timeout %f",
2204 getpid (), vcl_cfg->session_timeout);
2206 else if (unformat (line_input, "accept-timeout %f",
2207 &vcl_cfg->accept_timeout))
2209 if (VPPCOM_DEBUG > 0)
2210 clib_warning ("VCL<%d>: configured accept_timeout %f",
2211 getpid (), vcl_cfg->accept_timeout);
2213 else if (unformat (line_input, "app-proxy-transport-tcp"))
2215 vcl_cfg->app_proxy_transport_tcp = 1;
2216 if (VPPCOM_DEBUG > 0)
2217 clib_warning ("VCL<%d>: configured "
2218 "app_proxy_transport_tcp (%d)",
2219 getpid (), vcl_cfg->app_proxy_transport_tcp);
2221 else if (unformat (line_input, "app-proxy-transport-udp"))
2223 vcl_cfg->app_proxy_transport_udp = 1;
2224 if (VPPCOM_DEBUG > 0)
2225 clib_warning ("VCL<%d>: configured "
2226 "app_proxy_transport_udp (%d)",
2227 getpid (), vcl_cfg->app_proxy_transport_udp);
2229 else if (unformat (line_input, "app-scope-local"))
2231 vcl_cfg->app_scope_local = 1;
2232 if (VPPCOM_DEBUG > 0)
2233 clib_warning ("VCL<%d>: configured app_scope_local (%d)",
2234 getpid (), vcl_cfg->app_scope_local);
2236 else if (unformat (line_input, "app-scope-global"))
2238 vcl_cfg->app_scope_global = 1;
2239 if (VPPCOM_DEBUG > 0)
2240 clib_warning ("VCL<%d>: configured app_scope_global (%d)",
2241 getpid (), vcl_cfg->app_scope_global);
2243 else if (unformat (line_input, "namespace-secret %lu",
2244 &vcl_cfg->namespace_secret))
2246 if (VPPCOM_DEBUG > 0)
2248 ("VCL<%d>: configured namespace_secret %lu (0x%lx)",
2249 getpid (), vcl_cfg->namespace_secret,
2250 vcl_cfg->namespace_secret);
2252 else if (unformat (line_input, "namespace-id %v",
2253 &vcl_cfg->namespace_id))
2255 vl_api_application_attach_t *mp;
2256 u32 max_nsid_vec_len = sizeof (mp->namespace_id) - 1;
2257 u32 nsid_vec_len = vec_len (vcl_cfg->namespace_id);
2258 if (nsid_vec_len > max_nsid_vec_len)
2260 _vec_len (vcl_cfg->namespace_id) = max_nsid_vec_len;
2261 if (VPPCOM_DEBUG > 0)
2262 clib_warning ("VCL<%d>: configured namespace_id is "
2263 "too long, truncated to %d characters!",
2264 getpid (), max_nsid_vec_len);
2267 if (VPPCOM_DEBUG > 0)
2268 clib_warning ("VCL<%d>: configured namespace_id %v",
2269 getpid (), vcl_cfg->namespace_id);
2271 else if (unformat (line_input, "}"))
2274 if (VPPCOM_DEBUG > 0)
2275 clib_warning ("VCL<%d>: completed parsing vppcom config!",
2281 if (line_input->buffer[line_input->index] != '#')
2283 clib_warning ("VCL<%d>: Unknown vppcom config option: '%s'",
2285 &line_input->buffer[line_input->index]);
2292 unformat_free (input);
2300 * VPPCOM Public API functions
2303 vppcom_app_create (char *app_name)
2305 vppcom_cfg_t *vcl_cfg = &vcm->cfg;
2316 vppcom_cfg_init (vcl_cfg);
2317 env_var_str = getenv (VPPCOM_ENV_DEBUG);
2321 if (sscanf (env_var_str, "%u", &tmp) != 1)
2322 clib_warning ("VCL<%d>: WARNING: Invalid debug level specified "
2323 "in the environment variable " VPPCOM_ENV_DEBUG
2324 " (%s)!\n", getpid (), env_var_str);
2328 if (VPPCOM_DEBUG > 0)
2329 clib_warning ("VCL<%d>: configured VCL debug level (%u) from "
2330 VPPCOM_ENV_DEBUG "!", getpid (), vcm->debug);
2333 conf_fname = getenv (VPPCOM_ENV_CONF);
2335 conf_fname = VPPCOM_CONF_DEFAULT;
2336 vppcom_cfg_heapsize (conf_fname);
2337 vcl_cfg = &vcm->cfg;
2338 clib_spinlock_init (&vcm->session_fifo_lockp);
2339 clib_fifo_validate (vcm->client_session_index_fifo,
2340 vcm->cfg.listen_queue_size);
2341 vppcom_cfg_read (conf_fname);
2344 env_var_str = getenv (VPPCOM_ENV_API_PREFIX);
2347 if (vcl_cfg->vpp_api_filename)
2348 vec_free (vcl_cfg->vpp_api_filename);
2349 vcl_cfg->vpp_api_filename = format (0, "/%s-vpe-api%c",
2351 vl_set_memory_root_path ((char *) env_var_str);
2353 if (VPPCOM_DEBUG > 0)
2354 clib_warning ("VCL<%d>: configured api prefix (%s) and "
2355 "filename (%s) from " VPPCOM_ENV_API_PREFIX "!",
2356 getpid (), env_var_str, vcl_cfg->vpp_api_filename);
2358 env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_ID);
2361 u32 ns_id_vec_len = strlen (env_var_str);
2363 vec_reset_length (vcm->cfg.namespace_id);
2364 vec_validate (vcm->cfg.namespace_id, ns_id_vec_len - 1);
2365 clib_memcpy (vcm->cfg.namespace_id, env_var_str, ns_id_vec_len);
2367 if (VPPCOM_DEBUG > 0)
2368 clib_warning ("VCL<%d>: configured namespace_id (%v) from "
2369 VPPCOM_ENV_APP_NAMESPACE_ID
2370 "!", getpid (), vcm->cfg.namespace_id);
2372 env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_SECRET);
2376 if (sscanf (env_var_str, "%lu", &tmp) != 1)
2377 clib_warning ("VCL<%d>: WARNING: Invalid namespace secret "
2378 "specified in the environment variable "
2379 VPPCOM_ENV_APP_NAMESPACE_SECRET
2380 " (%s)!\n", getpid (), env_var_str);
2383 vcm->cfg.namespace_secret = tmp;
2384 if (VPPCOM_DEBUG > 0)
2385 clib_warning ("VCL<%d>: configured namespace secret "
2387 VPPCOM_ENV_APP_NAMESPACE_SECRET
2388 "!", getpid (), vcm->cfg.namespace_secret);
2391 if (getenv (VPPCOM_ENV_APP_PROXY_TRANSPORT_TCP))
2393 vcm->cfg.app_proxy_transport_tcp = 1;
2394 if (VPPCOM_DEBUG > 0)
2395 clib_warning ("VCL<%d>: configured app_proxy_transport_tcp "
2397 VPPCOM_ENV_APP_PROXY_TRANSPORT_TCP
2398 "!", getpid (), vcm->cfg.app_proxy_transport_tcp);
2400 if (getenv (VPPCOM_ENV_APP_PROXY_TRANSPORT_UDP))
2402 vcm->cfg.app_proxy_transport_udp = 1;
2403 if (VPPCOM_DEBUG > 0)
2404 clib_warning ("VCL<%d>: configured app_proxy_transport_udp "
2406 VPPCOM_ENV_APP_PROXY_TRANSPORT_UDP
2407 "!", getpid (), vcm->cfg.app_proxy_transport_udp);
2409 if (getenv (VPPCOM_ENV_APP_SCOPE_LOCAL))
2411 vcm->cfg.app_scope_local = 1;
2412 if (VPPCOM_DEBUG > 0)
2413 clib_warning ("VCL<%d>: configured app_scope_local (%u) from "
2414 VPPCOM_ENV_APP_SCOPE_LOCAL
2415 "!", getpid (), vcm->cfg.app_scope_local);
2417 if (getenv (VPPCOM_ENV_APP_SCOPE_GLOBAL))
2419 vcm->cfg.app_scope_global = 1;
2420 if (VPPCOM_DEBUG > 0)
2421 clib_warning ("VCL<%d>: configured app_scope_global (%u) from "
2422 VPPCOM_ENV_APP_SCOPE_GLOBAL
2423 "!", getpid (), vcm->cfg.app_scope_global);
2426 vcm->main_cpu = os_get_thread_index ();
2427 heap = clib_mem_get_per_cpu_heap ();
2428 h = mheap_header (heap);
2430 /* make the main heap thread-safe */
2431 h->flags |= MHEAP_FLAG_THREAD_SAFE;
2433 vcm->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
2435 clib_time_init (&vcm->clib_time);
2436 vppcom_init_error_string_table ();
2437 svm_fifo_segment_main_init (vcl_cfg->segment_baseva,
2438 20 /* timeout in secs */ );
2439 clib_spinlock_init (&vcm->sessions_lockp);
2442 if (vcm->my_client_index == ~0)
2445 /* API hookup and connect to VPP */
2446 vppcom_api_hookup ();
2447 vcm->app_state = STATE_APP_START;
2448 rv = vppcom_connect_to_vpp (app_name);
2451 clib_warning ("VCL<%d>: ERROR: couldn't connect to VPP!",
2456 /* State event handling thread */
2458 rv = vce_start_event_thread (&(vcm->event_thread), 20);
2460 if (VPPCOM_DEBUG > 0)
2461 clib_warning ("VCL<%d>: sending session enable", getpid ());
2463 rv = vppcom_app_session_enable ();
2466 clib_warning ("VCL<%d>: ERROR: vppcom_app_session_enable() "
2467 "failed!", getpid ());
2471 if (VPPCOM_DEBUG > 0)
2472 clib_warning ("VCL<%d>: sending app attach", getpid ());
2474 rv = vppcom_app_attach ();
2477 clib_warning ("VCL<%d>: ERROR: vppcom_app_attach() failed!",
2482 if (VPPCOM_DEBUG > 0)
2483 clib_warning ("VCL<%d>: app_name '%s', my_client_index %d (0x%x)",
2484 getpid (), app_name, vcm->my_client_index,
2485 vcm->my_client_index);
2492 vppcom_app_destroy (void)
2495 f64 orig_app_timeout;
2497 if (vcm->my_client_index == ~0)
2500 if (VPPCOM_DEBUG > 0)
2501 clib_warning ("VCL<%d>: detaching from VPP, my_client_index %d (0x%x)",
2502 getpid (), vcm->my_client_index, vcm->my_client_index);
2504 if (VPPCOM_DEBUG > 0)
2507 ELOG_TYPE_DECLARE (e) =
2509 .format = "app_detach:C:%d",
2510 .format_args = "i4",
2517 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
2518 ed->data = vcm->my_client_index;
2522 vppcom_app_detach ();
2523 orig_app_timeout = vcm->cfg.app_timeout;
2524 vcm->cfg.app_timeout = 2.0;
2525 rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED);
2526 vcm->cfg.app_timeout = orig_app_timeout;
2527 if (PREDICT_FALSE (rv))
2529 if (VPPCOM_DEBUG > 0)
2530 clib_warning ("VCL<%d>: application detach timed out! "
2531 "returning %d (%s)",
2532 getpid (), rv, vppcom_retval_str (rv));
2535 /* Finished with logging before client gets reset to ~0 */
2536 if (VPPCOM_DEBUG > 0)
2539 vl_client_disconnect_from_vlib ();
2540 vcm->my_client_index = ~0;
2541 vcm->app_state = STATE_APP_START;
2545 vppcom_session_create (u8 proto, u8 is_nonblocking)
2549 session_state_t state;
2550 elog_track_t session_elog_track;
2552 clib_spinlock_lock (&vcm->sessions_lockp);
2553 pool_get (vcm->sessions, session);
2554 memset (session, 0, sizeof (*session));
2555 session_index = session - vcm->sessions;
2557 session->proto = proto;
2558 session->state = STATE_START;
2559 state = session->state;
2560 session->vpp_handle = ~0;
2563 VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_NONBLOCK);
2565 VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_NONBLOCK);
2567 if (VPPCOM_DEBUG > 0)
2569 session->elog_track.name =
2570 (char *) format (0, "C:%d:S:%d%c", vcm->my_client_index,
2572 elog_track_register (&vcm->elog_main, &session->elog_track);
2573 session_elog_track = session->elog_track;
2576 clib_spinlock_unlock (&vcm->sessions_lockp);
2578 if (VPPCOM_DEBUG > 0)
2579 clib_warning ("VCL<%d>: sid %u", getpid (), session_index);
2581 if (VPPCOM_DEBUG > 0)
2584 ELOG_TYPE_DECLARE (e) =
2586 .format = "session_create:proto:%d state:%d is_nonblocking:%d",
2587 .format_args = "i4i4i4",
2595 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session_elog_track);
2596 ed->data[0] = proto;
2597 ed->data[1] = state;
2598 ed->data[2] = is_nonblocking;
2602 return (int) session_index;
2606 vppcom_session_close (uint32_t session_index)
2608 session_t *session = 0;
2616 session_state_t state;
2617 elog_track_t session_elog_track;
2619 VCL_LOCK_AND_GET_SESSION (session_index, &session);
2620 is_vep = session->is_vep;
2621 is_vep_session = session->is_vep_session;
2622 next_sid = session->vep.next_sid;
2623 vep_idx = session->vep.vep_idx;
2624 state = session->state;
2625 vpp_handle = session->vpp_handle;
2626 clib_spinlock_unlock (&vcm->sessions_lockp);
2629 * Why two if(VPPCOM_DEBUG) checks?
2631 * Eventually all clib_warnings need their own way of being
2632 * logged and signalled (like severity) where event logging
2633 * is a separate debugging tool. It will make the separation
2634 * easier. ... parting is such sweet sorrow ...
2636 if (VPPCOM_DEBUG > 0)
2638 session_elog_track = session->elog_track;
2641 if (VPPCOM_DEBUG > 0)
2644 clib_warning ("VCL<%d>: vep_idx %u / sid %u: "
2645 "closing epoll session...",
2646 getpid (), session_index, session_index);
2648 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %d: "
2649 "closing session...",
2650 getpid (), vpp_handle, session_index);
2655 while (next_sid != ~0)
2657 rv = vppcom_epoll_ctl (session_index, EPOLL_CTL_DEL, next_sid, 0);
2658 if ((VPPCOM_DEBUG > 0) && PREDICT_FALSE (rv < 0))
2659 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
2660 "EPOLL_CTL_DEL vep_idx %u failed! rv %d (%s)",
2661 getpid (), vpp_handle, next_sid, vep_idx,
2662 rv, vppcom_retval_str (rv));
2664 VCL_LOCK_AND_GET_SESSION (session_index, &session);
2665 next_sid = session->vep.next_sid;
2666 clib_spinlock_unlock (&vcm->sessions_lockp);
2673 rv = vppcom_epoll_ctl (vep_idx, EPOLL_CTL_DEL, session_index, 0);
2674 if ((VPPCOM_DEBUG > 0) && (rv < 0))
2675 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
2676 "EPOLL_CTL_DEL vep_idx %u failed! rv %d (%s)",
2677 getpid (), vpp_handle, session_index,
2678 vep_idx, rv, vppcom_retval_str (rv));
2681 if (state & STATE_LISTEN)
2683 rv = vppcom_session_unbind (session_index);
2684 if (PREDICT_FALSE (rv < 0))
2686 if (VPPCOM_DEBUG > 0)
2687 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
2688 "listener unbind failed! rv %d (%s)",
2689 getpid (), vpp_handle, session_index,
2690 rv, vppcom_retval_str (rv));
2694 else if (state & (CLIENT_STATE_OPEN | SERVER_STATE_OPEN))
2696 rv = vppcom_session_disconnect (session_index);
2697 if (PREDICT_FALSE (rv < 0))
2698 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
2699 "session disconnect failed! rv %d (%s)",
2700 getpid (), vpp_handle, session_index,
2701 rv, vppcom_retval_str (rv));
2705 VCL_LOCK_AND_GET_SESSION (session_index, &session);
2706 vpp_handle = session->vpp_handle;
2707 if (vpp_handle != ~0)
2709 p = hash_get (vcm->session_index_by_vpp_handles, vpp_handle);
2711 hash_unset (vcm->session_index_by_vpp_handles, vpp_handle);
2713 pool_put_index (vcm->sessions, session_index);
2715 clib_spinlock_unlock (&vcm->sessions_lockp);
2717 if (VPPCOM_DEBUG > 0)
2720 clib_warning ("VCL<%d>: vep_idx %u / sid %u: epoll session removed.",
2721 getpid (), session_index, session_index);
2723 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: session removed.",
2724 getpid (), vpp_handle, session_index);
2728 if (VPPCOM_DEBUG > 0)
2731 ELOG_TYPE_DECLARE (e) =
2733 .format = "session_close:rv:%d",
2734 .format_args = "i4",
2742 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session_elog_track);
2751 vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep)
2753 session_t *session = 0;
2757 return VPPCOM_EINVAL;
2759 VCL_LOCK_AND_GET_SESSION (session_index, &session);
2761 if (session->is_vep)
2763 clib_spinlock_unlock (&vcm->sessions_lockp);
2764 clib_warning ("VCL<%d>: ERROR: sid %u: cannot "
2765 "bind to an epoll session!", getpid (), session_index);
2770 session->lcl_addr.is_ip4 = ep->is_ip4;
2771 session->lcl_addr.ip46 = to_ip46 (!ep->is_ip4, ep->ip);
2772 session->lcl_port = ep->port;
2774 if (VPPCOM_DEBUG > 0)
2775 clib_warning ("VCL<%d>: sid %u: binding to local %s address %U "
2776 "port %u, proto %s", getpid (), session_index,
2777 session->lcl_addr.is_ip4 ? "IPv4" : "IPv6",
2778 format_ip46_address, &session->lcl_addr.ip46,
2779 session->lcl_addr.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
2780 clib_net_to_host_u16 (session->lcl_port),
2781 session->proto ? "UDP" : "TCP");
2783 if (VPPCOM_DEBUG > 0)
2785 if (session->lcl_addr.is_ip4)
2788 ELOG_TYPE_DECLARE (e) =
2790 .format = "bind local:%s:%d.%d.%d.%d:%d ",
2791 .format_args = "t1i1i1i1i1i2",
2792 .n_enum_strings = 2,
2793 .enum_strings = {"TCP", "UDP",},
2796 CLIB_PACKED (struct {
2802 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
2803 ed->proto = session->proto;
2804 ed->addr[0] = session->lcl_addr.ip46.ip4.as_u8[0];
2805 ed->addr[1] = session->lcl_addr.ip46.ip4.as_u8[1];
2806 ed->addr[2] = session->lcl_addr.ip46.ip4.as_u8[2];
2807 ed->addr[3] = session->lcl_addr.ip46.ip4.as_u8[3];
2808 ed->port = clib_net_to_host_u16 (session->lcl_port);
2813 clib_spinlock_unlock (&vcm->sessions_lockp);
2819 vppcom_session_listen (uint32_t listen_session_index, uint32_t q_len)
2821 session_t *listen_session = 0;
2822 u64 listen_vpp_handle;
2825 if (q_len == 0 || q_len == ~0)
2826 q_len = vcm->cfg.listen_queue_size;
2828 VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2830 if (listen_session->is_vep)
2832 clib_spinlock_unlock (&vcm->sessions_lockp);
2833 clib_warning ("VCL<%d>: ERROR: sid %u: cannot listen on an "
2834 "epoll session!", getpid (), listen_session_index);
2839 listen_vpp_handle = listen_session->vpp_handle;
2840 if (listen_session->state & STATE_LISTEN)
2842 clib_spinlock_unlock (&vcm->sessions_lockp);
2843 if (VPPCOM_DEBUG > 0)
2844 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
2845 "already in listen state!",
2846 getpid (), listen_vpp_handle, listen_session_index);
2851 if (VPPCOM_DEBUG > 0)
2852 clib_warning ("VCL<%d>: vpp handle 0x%llx, "
2853 "sid %u: sending VPP bind+listen request...",
2854 getpid (), listen_vpp_handle, listen_session_index);
2856 vppcom_send_bind_sock (listen_session, listen_session_index);
2857 clib_spinlock_unlock (&vcm->sessions_lockp);
2859 vppcom_wait_for_session_state_change (listen_session_index, STATE_LISTEN,
2860 vcm->cfg.session_timeout);
2862 VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2863 if (PREDICT_FALSE (retval))
2865 if (VPPCOM_DEBUG > 0)
2867 ("VCL<%d>: vpp handle 0x%llx, sid %u: bind+listen failed! "
2868 "returning %d (%s)", getpid (), listen_session->vpp_handle,
2869 listen_session_index, retval, vppcom_retval_str (retval));
2870 clib_spinlock_unlock (&vcm->sessions_lockp);
2875 clib_spinlock_lock (&vcm->session_fifo_lockp);
2876 clib_fifo_validate (vcm->client_session_index_fifo, q_len);
2877 clib_spinlock_unlock (&vcm->session_fifo_lockp);
2879 clib_spinlock_unlock (&vcm->sessions_lockp);
2886 vppcom_session_register_listener (uint32_t session_index,
2887 vppcom_session_listener_cb cb,
2888 vppcom_session_listener_errcb
2889 errcb, uint8_t flags, int q_len, void *ptr)
2892 vce_event_key_t evk;
2893 vppcom_session_listener_t *listener_args;
2895 if (!vcm->session_io_thread.io_sessions_lockp)
2896 rv = vppcom_start_io_event_thread (&vcm->session_io_thread, 100 /* DAW_TODO: ??? hard-coded value */
2902 rv = vppcom_session_listen (session_index, q_len);
2908 /* Register handler for connect_request event on listen_session_index */
2909 listener_args = clib_mem_alloc (sizeof (vppcom_session_listener_t)); // DAW_TODO: Use a pool instead of thrashing the memory allocator!
2910 listener_args->user_cb = cb;
2911 listener_args->user_cb_data = ptr;
2912 listener_args->user_errcb = errcb;
2914 evk.session_index = session_index;
2915 evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
2916 (void) vce_register_handler (&vcm->event_thread, &evk,
2917 vce_registered_listener_connect_handler_fn,
2925 validate_args_session_accept_ (session_t * listen_session)
2927 u32 listen_session_index = listen_session - vcm->sessions;
2929 /* Input validation - expects spinlock on sessions_lockp */
2930 if (listen_session->is_vep)
2932 clib_warning ("VCL<%d>: ERROR: sid %u: cannot accept on an "
2933 "epoll session!", getpid (), listen_session_index);
2934 return VPPCOM_EBADFD;
2937 if (listen_session->state != STATE_LISTEN)
2939 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
2940 "not in listen state! state 0x%x (%s)", getpid (),
2941 listen_session->vpp_handle, listen_session_index,
2942 listen_session->state,
2943 vppcom_session_state_str (listen_session->state));
2944 return VPPCOM_EBADFD;
2950 vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
2953 session_t *listen_session = 0;
2954 session_t *client_session = 0;
2955 u32 client_session_index = ~0;
2957 u64 listen_vpp_handle;
2958 vce_event_handler_reg_t *reg;
2960 vce_event_connect_request_t *result;
2963 int millisecond_timeout = 1;
2964 int hours_timeout = 20 * 60 * 60;
2966 VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2967 listen_vpp_handle = listen_session->vpp_handle; // For debugging
2969 rv = validate_args_session_accept_ (listen_session);
2972 clib_spinlock_unlock (&vcm->sessions_lockp);
2976 /* Using an aggressive timer of 1ms and a generous timer of
2977 * 20 hours, we can implement a blocking and non-blocking listener
2978 * as both event and time driven */
2979 gettimeofday (&tv, NULL);
2980 ts.tv_nsec = (tv.tv_usec * 1000) + (1000 * millisecond_timeout);
2981 ts.tv_sec = tv.tv_sec;
2983 /* Predict that the Listener is blocking more often than not */
2984 if (PREDICT_TRUE (!VCL_SESS_ATTR_TEST (listen_session->attr,
2985 VCL_SESS_ATTR_NONBLOCK)))
2986 ts.tv_sec += hours_timeout;
2988 clib_spinlock_unlock (&vcm->sessions_lockp);
2990 /* Register handler for connect_request event on listen_session_index */
2991 vce_event_key_t evk;
2992 evk.session_index = listen_session_index;
2993 evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
2994 reg = vce_register_handler (&vcm->event_thread, &evk,
2995 vce_connect_request_handler_fn, 0);
2996 clib_spinlock_lock (&(vcm->event_thread.events_lockp));
2997 ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx);
2998 pthread_mutex_lock (®->handler_lock);
3001 clib_spinlock_unlock (&(vcm->event_thread.events_lockp));
3002 rv = pthread_cond_timedwait (®->handler_cond,
3003 ®->handler_lock, &ts);
3004 if (rv == ETIMEDOUT)
3009 clib_spinlock_lock (&(vcm->event_thread.events_lockp));
3010 ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx);
3012 result = vce_get_event_data (ev, sizeof (*result));
3013 client_session_index = result->accepted_session_index;
3014 clib_spinlock_unlock (&(vcm->event_thread.events_lockp));
3016 /* Remove from the FIFO used to service epoll */
3017 clib_spinlock_lock (&vcm->session_fifo_lockp);
3018 if (clib_fifo_elts (vcm->client_session_index_fifo))
3020 u32 tmp_client_session_index;
3021 clib_fifo_sub1 (vcm->client_session_index_fifo,
3022 tmp_client_session_index);
3023 /* It wasn't ours... put it back ... */
3024 if (tmp_client_session_index != client_session_index)
3025 clib_fifo_add1 (vcm->client_session_index_fifo,
3026 tmp_client_session_index);
3028 clib_spinlock_unlock (&vcm->session_fifo_lockp);
3030 clib_spinlock_lock (&vcm->sessions_lockp);
3032 rv = vppcom_session_at_index (client_session_index, &client_session);
3033 if (PREDICT_FALSE (rv))
3035 rv = VPPCOM_ECONNABORTED;
3036 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: client sid %u "
3037 "lookup failed! returning %d (%s)", getpid (),
3038 listen_vpp_handle, listen_session_index,
3039 client_session_index, rv, vppcom_retval_str (rv));
3043 if (flags & O_NONBLOCK)
3044 VCL_SESS_ATTR_SET (client_session->attr, VCL_SESS_ATTR_NONBLOCK);
3046 VCL_SESS_ATTR_CLR (client_session->attr, VCL_SESS_ATTR_NONBLOCK);
3048 if (VPPCOM_DEBUG > 0)
3049 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: Got a client request! "
3050 "vpp handle 0x%llx, sid %u, flags %d, is_nonblocking %u",
3051 getpid (), listen_vpp_handle, listen_session_index,
3052 client_session->vpp_handle, client_session_index,
3053 flags, VCL_SESS_ATTR_TEST (client_session->attr,
3054 VCL_SESS_ATTR_NONBLOCK));
3058 ep->is_ip4 = client_session->peer_addr.is_ip4;
3059 ep->port = client_session->peer_port;
3060 if (client_session->peer_addr.is_ip4)
3061 clib_memcpy (ep->ip, &client_session->peer_addr.ip46.ip4,
3062 sizeof (ip4_address_t));
3064 clib_memcpy (ep->ip, &client_session->peer_addr.ip46.ip6,
3065 sizeof (ip6_address_t));
3068 vppcom_send_accept_session_reply (client_session->vpp_handle,
3069 client_session->client_context,
3070 0 /* retval OK */ );
3072 if (VPPCOM_DEBUG > 0)
3073 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: accepted vpp handle "
3074 "0x%llx, sid %u connection to local %s address "
3075 "%U port %u", getpid (), listen_vpp_handle,
3076 listen_session_index, client_session->vpp_handle,
3077 client_session_index,
3078 client_session->lcl_addr.is_ip4 ? "IPv4" : "IPv6",
3079 format_ip46_address, &client_session->lcl_addr.ip46,
3080 client_session->lcl_addr.is_ip4 ?
3081 IP46_TYPE_IP4 : IP46_TYPE_IP6,
3082 clib_net_to_host_u16 (client_session->lcl_port));
3084 if (VPPCOM_DEBUG > 0)
3086 client_session->elog_track.name =
3087 (char *) format (0, "C:%d:S:%d%c", vcm->my_client_index,
3088 client_session_index, 0);
3089 elog_track_register (&vcm->elog_main, &client_session->elog_track);
3091 // Two elog entries due to 20-byte per entry constraint.
3093 ELOG_TYPE_DECLARE (e) =
3095 .format = "accept: listen_handle:%x from_handle:%x",
3096 .format_args = "i8i8",
3104 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, client_session->elog_track);
3105 ed->handle[0] = listen_vpp_handle;
3106 ed->handle[1] = client_session->vpp_handle;
3109 if (client_session->lcl_addr.is_ip4)
3112 ELOG_TYPE_DECLARE (e2) =
3114 .format = "accept: S:%d %d.%d.%d.%d:%d ",
3115 .format_args = "i4i1i1i1i1i2",
3118 CLIB_PACKED (struct {
3125 ELOG_TRACK_DATA (&vcm->elog_main, e2, client_session->elog_track);
3126 ed2->session = client_session_index;
3127 ed2->addr[0] = client_session->lcl_addr.ip46.ip4.as_u8[0];
3128 ed2->addr[1] = client_session->lcl_addr.ip46.ip4.as_u8[1];
3129 ed2->addr[2] = client_session->lcl_addr.ip46.ip4.as_u8[2];
3130 ed2->addr[3] = client_session->lcl_addr.ip46.ip4.as_u8[3];
3131 ed2->port = clib_net_to_host_u16 (client_session->lcl_port);
3136 clib_spinlock_unlock (&vcm->sessions_lockp);
3138 rv = (int) client_session_index;
3139 vce_clear_event (&vcm->event_thread, reg->ev_idx);
3140 if (vcm->session_io_thread.io_sessions_lockp)
3142 /* Throw this new accepted session index into the rx poll thread pool */
3143 clib_spinlock_lock (&vcm->session_io_thread.io_sessions_lockp);
3144 u32 *active_session_index;
3145 pool_get (vcm->session_io_thread.active_session_indexes,
3146 active_session_index);
3147 *active_session_index = client_session_index;
3148 clib_spinlock_unlock (&vcm->session_io_thread.io_sessions_lockp);
3151 vce_unregister_handler (&vcm->event_thread, reg);
3152 pthread_mutex_unlock (®->handler_lock);
3159 vppcom_session_connect (uint32_t session_index, vppcom_endpt_t * server_ep)
3161 session_t *session = 0;
3163 int rv, retval = VPPCOM_OK;
3165 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3167 if (PREDICT_FALSE (session->is_vep))
3169 clib_spinlock_unlock (&vcm->sessions_lockp);
3170 clib_warning ("VCL<%d>: ERROR: sid %u: cannot "
3171 "connect on an epoll session!", getpid (), session_index);
3176 if (PREDICT_FALSE (session->state & CLIENT_STATE_OPEN))
3178 if (VPPCOM_DEBUG > 0)
3179 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: session already "
3180 "connected to %s %U port %d proto %s, state 0x%x (%s)",
3181 getpid (), session->vpp_handle, session_index,
3182 session->peer_addr.is_ip4 ? "IPv4" : "IPv6",
3183 format_ip46_address,
3184 &session->peer_addr.ip46, session->peer_addr.is_ip4 ?
3185 IP46_TYPE_IP4 : IP46_TYPE_IP6,
3186 clib_net_to_host_u16 (session->peer_port),
3187 session->proto ? "UDP" : "TCP", session->state,
3188 vppcom_session_state_str (session->state));
3190 clib_spinlock_unlock (&vcm->sessions_lockp);
3194 session->peer_addr.is_ip4 = server_ep->is_ip4;
3195 session->peer_addr.ip46 = to_ip46 (!server_ep->is_ip4, server_ep->ip);
3196 session->peer_port = server_ep->port;
3198 if (VPPCOM_DEBUG > 0)
3199 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: connecting to server "
3200 "%s %U port %d proto %s",
3201 getpid (), session->vpp_handle, session_index,
3202 session->peer_addr.is_ip4 ? "IPv4" : "IPv6",
3203 format_ip46_address,
3204 &session->peer_addr.ip46, session->peer_addr.is_ip4 ?
3205 IP46_TYPE_IP4 : IP46_TYPE_IP6,
3206 clib_net_to_host_u16 (session->peer_port),
3207 session->proto ? "UDP" : "TCP");
3209 vppcom_send_connect_sock (session, session_index);
3210 clib_spinlock_unlock (&vcm->sessions_lockp);
3213 vppcom_wait_for_session_state_change (session_index, STATE_CONNECT,
3214 vcm->cfg.session_timeout);
3216 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3217 vpp_handle = session->vpp_handle;
3218 clib_spinlock_unlock (&vcm->sessions_lockp);
3221 if (PREDICT_FALSE (retval))
3224 if (VPPCOM_DEBUG > 0)
3228 ("VCL<%d>: vpp handle 0x%llx, sid %u: connect failed! "
3229 "returning %d (%s)", getpid (), vpp_handle,
3230 session_index, rv, vppcom_retval_str (rv));
3232 clib_warning ("VCL<%d>: no session for sid %u: connect failed! "
3233 "returning %d (%s)", getpid (),
3234 session_index, rv, vppcom_retval_str (rv));
3237 else if (VPPCOM_DEBUG > 0)
3238 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: connected!",
3239 getpid (), vpp_handle, session_index);
3245 vppcom_session_read_internal (uint32_t session_index, void *buf, int n,
3248 session_t *session = 0;
3249 svm_fifo_t *rx_fifo;
3256 session_state_t state;
3260 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3262 is_nonblocking = VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK);
3263 rx_fifo = session->rx_fifo;
3264 state = session->state;
3265 vpp_handle = session->vpp_handle;
3267 if (PREDICT_FALSE (session->is_vep))
3269 clib_spinlock_unlock (&vcm->sessions_lockp);
3270 clib_warning ("VCL<%d>: ERROR: sid %u: cannot "
3271 "read from an epoll session!", getpid (), session_index);
3276 if (PREDICT_FALSE (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN))))
3278 clib_spinlock_unlock (&vcm->sessions_lockp);
3279 rv = ((state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET : VPPCOM_ENOTCONN);
3281 if (VPPCOM_DEBUG > 0)
3282 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: %s session is "
3283 "not open! state 0x%x (%s), returning %d (%s)",
3284 getpid (), vpp_handle, session_index, state,
3285 vppcom_session_state_str (state),
3286 rv, vppcom_retval_str (rv));
3290 clib_spinlock_unlock (&vcm->sessions_lockp);
3295 n_read = svm_fifo_peek (rx_fifo, 0, n, buf);
3297 n_read = svm_fifo_dequeue_nowait (rx_fifo, n, buf);
3299 while (!is_nonblocking && (n_read <= 0));
3303 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3305 poll_et = (((EPOLLET | EPOLLIN) & session->vep.ev.events) ==
3306 (EPOLLET | EPOLLIN));
3308 session->vep.et_mask |= EPOLLIN;
3310 if (state & STATE_CLOSE_ON_EMPTY)
3312 rv = VPPCOM_ECONNRESET;
3314 if (VPPCOM_DEBUG > 1)
3316 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: Empty fifo "
3317 "with session state 0x%x (%s)!"
3318 " Setting state to 0x%x (%s), returning %d (%s)",
3319 getpid (), session->vpp_handle, session_index,
3320 state, vppcom_session_state_str (state),
3322 vppcom_session_state_str (STATE_DISCONNECT), rv,
3323 vppcom_retval_str (rv));
3326 session->state = STATE_DISCONNECT;
3331 clib_spinlock_unlock (&vcm->sessions_lockp);
3336 if (VPPCOM_DEBUG > 2)
3339 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: read %d bytes "
3340 "from (%p)", getpid (), vpp_handle,
3341 session_index, n_read, rx_fifo);
3343 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: nothing read! "
3344 "returning %d (%s)", getpid (), vpp_handle,
3345 session_index, rv, vppcom_retval_str (rv));
3352 vppcom_session_read (uint32_t session_index, void *buf, size_t n)
3354 return (vppcom_session_read_internal (session_index, buf, n, 0));
3358 vppcom_session_peek (uint32_t session_index, void *buf, int n)
3360 return (vppcom_session_read_internal (session_index, buf, n, 1));
3364 vppcom_session_read_ready (session_t * session, u32 session_index)
3369 session_state_t state = session->state;
3370 u64 vpp_handle = session->vpp_handle;
3372 /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3373 if (PREDICT_FALSE (session->is_vep))
3375 clib_warning ("VCL<%d>: ERROR: sid %u: cannot read from an "
3376 "epoll session!", getpid (), session_index);
3381 if (session->state & STATE_LISTEN)
3383 clib_spinlock_lock (&vcm->session_fifo_lockp);
3384 ready = clib_fifo_elts (vcm->client_session_index_fifo);
3385 clib_spinlock_unlock (&vcm->session_fifo_lockp);
3389 if (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN | STATE_LISTEN)))
3391 rv = ((state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET :
3394 if (VPPCOM_DEBUG > 1)
3395 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: session is "
3396 "not open! state 0x%x (%s), returning %d (%s)",
3397 getpid (), vpp_handle, session_index,
3398 state, vppcom_session_state_str (state),
3399 rv, vppcom_retval_str (rv));
3403 ready = svm_fifo_max_dequeue (session->rx_fifo);
3409 ((EPOLLET | EPOLLIN) & session->vep.ev.events) == (EPOLLET | EPOLLIN);
3411 session->vep.et_mask |= EPOLLIN;
3413 if (state & STATE_CLOSE_ON_EMPTY)
3415 rv = VPPCOM_ECONNRESET;
3417 if (VPPCOM_DEBUG > 1)
3419 clib_warning ("VCL<%d>: vpp handle 0x%llx, "
3420 "sid %u: Empty fifo with"
3421 " session state 0x%x (%s)! Setting state to "
3422 "0x%x (%s), returning %d (%s)",
3423 getpid (), session_index, vpp_handle,
3424 state, vppcom_session_state_str (state),
3426 vppcom_session_state_str (STATE_DISCONNECT), rv,
3427 vppcom_retval_str (rv));
3429 session->state = STATE_DISCONNECT;
3435 if (vcm->app_event_queue->cursize &&
3436 !pthread_mutex_trylock (&vcm->app_event_queue->mutex))
3438 u32 i, n_to_dequeue = vcm->app_event_queue->cursize;
3439 session_fifo_event_t e;
3441 for (i = 0; i < n_to_dequeue; i++)
3442 svm_queue_sub_raw (vcm->app_event_queue, (u8 *) & e);
3444 pthread_mutex_unlock (&vcm->app_event_queue->mutex);
3451 vppcom_session_register_ioevent_cb (uint32_t session_index,
3452 vppcom_session_ioevent_cb cb,
3453 uint8_t rx, void *ptr)
3456 vce_event_key_t evk;
3457 vppcom_session_ioevent_t *ioevent;
3459 if (!vcm->session_io_thread.io_sessions_lockp)
3460 rv = vppcom_start_io_event_thread (&vcm->session_io_thread, 100 /* DAW_TODO: ??? hard-coded value */
3463 if (rv == VPPCOM_OK)
3467 /* Register handler for ioevent on session_index */
3468 clib_spinlock_lock (&vcm->session_io_thread.io_sessions_lockp);
3469 pool_get (vcm->session_io_thread.ioevents, ioevent);
3470 io_evt_ndx = (void *) (ioevent - vcm->session_io_thread.ioevents);
3471 ioevent->user_cb = cb;
3472 ioevent->user_cb_data = ptr;
3473 clib_spinlock_unlock (&vcm->session_io_thread.io_sessions_lockp);
3475 evk.session_index = session_index;
3476 evk.eid = rx ? VCL_EVENT_IOEVENT_RX_FIFO : VCL_EVENT_IOEVENT_TX_FIFO;
3478 (void) vce_register_handler (&vcm->event_thread, &evk,
3479 vce_registered_ioevent_handler_fn,
3486 vppcom_session_write (uint32_t session_index, void *buf, size_t n)
3488 session_t *session = 0;
3489 svm_fifo_t *tx_fifo = 0;
3491 session_fifo_event_t evt;
3492 session_state_t state;
3493 int rv, n_write, is_nonblocking;
3499 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3501 tx_fifo = session->tx_fifo;
3502 is_nonblocking = VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK);
3503 vpp_handle = session->vpp_handle;
3504 state = session->state;
3506 if (PREDICT_FALSE (session->is_vep))
3508 clib_spinlock_unlock (&vcm->sessions_lockp);
3509 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
3510 "cannot write to an epoll session!",
3511 getpid (), vpp_handle, session_index);
3517 if (!(session->state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN)))
3520 ((session->state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET :
3523 clib_spinlock_unlock (&vcm->sessions_lockp);
3524 if (VPPCOM_DEBUG > 1)
3525 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3526 "session is not open! state 0x%x (%s)",
3527 getpid (), vpp_handle, session_index,
3528 state, vppcom_session_state_str (state));
3532 clib_spinlock_unlock (&vcm->sessions_lockp);
3536 n_write = svm_fifo_enqueue_nowait (tx_fifo, n, (void *) buf);
3538 while (!is_nonblocking && (n_write <= 0));
3540 /* If event wasn't set, add one
3542 * To reduce context switching, can check if an
3543 * event is already there for this event_key, but for now
3544 * this will suffice. */
3546 if ((n_write > 0) && svm_fifo_set_event (tx_fifo))
3548 /* Fabricate TX event, send to vpp */
3550 evt.event_type = FIFO_EVENT_APP_TX;
3552 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3553 q = session->vpp_event_queue;
3555 svm_queue_add (q, (u8 *) & evt, 0 /* do wait for mutex */ );
3556 clib_spinlock_unlock (&vcm->sessions_lockp);
3557 if (VPPCOM_DEBUG > 1)
3558 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3559 "added FIFO_EVENT_APP_TX to "
3560 "vpp_event_q %p, n_write %d", getpid (),
3561 vpp_handle, session_index, q, n_write);
3566 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3568 poll_et = (((EPOLLET | EPOLLOUT) & session->vep.ev.events) ==
3569 (EPOLLET | EPOLLOUT));
3571 session->vep.et_mask |= EPOLLOUT;
3573 if (session->state & STATE_CLOSE_ON_EMPTY)
3575 rv = VPPCOM_ECONNRESET;
3577 if (VPPCOM_DEBUG > 1)
3579 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3580 "Empty fifo with session state 0x%x (%s)!"
3581 " Setting state to 0x%x (%s), returning %d (%s)",
3582 getpid (), session->vpp_handle, session_index,
3584 vppcom_session_state_str (session->state),
3586 vppcom_session_state_str (STATE_DISCONNECT), rv,
3587 vppcom_retval_str (rv));
3590 session->state = STATE_DISCONNECT;
3595 clib_spinlock_unlock (&vcm->sessions_lockp);
3600 if (VPPCOM_DEBUG > 2)
3603 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3604 "FIFO-FULL (%p)", getpid (), vpp_handle,
3605 session_index, tx_fifo);
3607 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3608 "wrote %d bytes tx-fifo: (%p)", getpid (),
3609 vpp_handle, session_index, n_write, tx_fifo);
3616 vppcom_session_write_ready (session_t * session, u32 session_index)
3624 /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3625 if (PREDICT_FALSE (session->is_vep))
3627 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
3628 "cannot write to an epoll session!",
3629 getpid (), session->vpp_handle, session_index);
3634 if (PREDICT_FALSE (session->state & STATE_LISTEN))
3636 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
3637 "cannot write to a listen session!",
3638 getpid (), session->vpp_handle, session_index);
3643 if (!(session->state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN)))
3645 session_state_t state = session->state;
3647 rv = ((state & STATE_DISCONNECT) ? VPPCOM_ECONNRESET : VPPCOM_ENOTCONN);
3649 clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
3650 "session is not open! state 0x%x (%s), "
3651 "returning %d (%s)", getpid (), session->vpp_handle,
3653 state, vppcom_session_state_str (state),
3654 rv, vppcom_retval_str (rv));
3658 ready = svm_fifo_max_enqueue (session->tx_fifo);
3660 if (VPPCOM_DEBUG > 3)
3661 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3662 "peek %s (%p), ready = %d", getpid (),
3663 session->vpp_handle, session_index,
3664 session->tx_fifo, ready);
3668 poll_et = (((EPOLLET | EPOLLOUT) & session->vep.ev.events) ==
3669 (EPOLLET | EPOLLOUT));
3671 session->vep.et_mask |= EPOLLOUT;
3673 if (session->state & STATE_CLOSE_ON_EMPTY)
3675 rv = VPPCOM_ECONNRESET;
3677 if (VPPCOM_DEBUG > 1)
3679 clib_warning ("VCL<%d>: vpp handle 0x%llx, sid %u: "
3680 "Empty fifo with session "
3681 "state 0x%x (%s)! Setting state to 0x%x (%s), "
3682 "returning %d (%s)", getpid (),
3683 session->vpp_handle, session_index,
3685 vppcom_session_state_str (session->state),
3687 vppcom_session_state_str (STATE_DISCONNECT), rv,
3688 vppcom_retval_str (rv));
3690 session->state = STATE_DISCONNECT;
3700 vppcom_select (unsigned long n_bits, unsigned long *read_map,
3701 unsigned long *write_map, unsigned long *except_map,
3702 double time_to_wait)
3705 session_t *session = 0;
3706 int rv, bits_set = 0;
3707 f64 timeout = clib_time_now (&vcm->clib_time) + time_to_wait;
3708 u32 minbits = clib_max (n_bits, BITS (uword));
3710 ASSERT (sizeof (clib_bitmap_t) == sizeof (long int));
3712 if (n_bits && read_map)
3714 clib_bitmap_validate (vcm->rd_bitmap, minbits);
3715 clib_memcpy (vcm->rd_bitmap, read_map,
3716 vec_len (vcm->rd_bitmap) * sizeof (clib_bitmap_t));
3717 memset (read_map, 0, vec_len (vcm->rd_bitmap) * sizeof (clib_bitmap_t));
3719 if (n_bits && write_map)
3721 clib_bitmap_validate (vcm->wr_bitmap, minbits);
3722 clib_memcpy (vcm->wr_bitmap, write_map,
3723 vec_len (vcm->wr_bitmap) * sizeof (clib_bitmap_t));
3724 memset (write_map, 0,
3725 vec_len (vcm->wr_bitmap) * sizeof (clib_bitmap_t));
3727 if (n_bits && except_map)
3729 clib_bitmap_validate (vcm->ex_bitmap, minbits);
3730 clib_memcpy (vcm->ex_bitmap, except_map,
3731 vec_len (vcm->ex_bitmap) * sizeof (clib_bitmap_t));
3732 memset (except_map, 0,
3733 vec_len (vcm->ex_bitmap) * sizeof (clib_bitmap_t));
3743 clib_bitmap_foreach (session_index, vcm->rd_bitmap,
3745 clib_spinlock_lock (&vcm->sessions_lockp);
3746 rv = vppcom_session_at_index (session_index, &session);
3749 clib_spinlock_unlock (&vcm->sessions_lockp);
3750 if (VPPCOM_DEBUG > 1)
3751 clib_warning ("VCL<%d>: session %d specified in "
3752 "read_map is closed.", getpid (),
3754 bits_set = VPPCOM_EBADFD;
3757 if (session->state & STATE_LISTEN)
3759 vce_event_handler_reg_t *reg = 0;
3760 vce_event_key_t evk;
3762 /* Check if handler already registered for this
3764 * If not, register handler for connect_request event
3765 * on listen_session_index
3767 evk.session_index = session_index;
3768 evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
3769 reg = vce_get_event_handler (&vcm->event_thread, &evk);
3771 reg = vce_register_handler (&vcm->event_thread, &evk,
3772 vce_poll_wait_connect_request_handler_fn,
3773 0 /* No callback args */);
3774 rv = vppcom_session_read_ready (session, session_index);
3777 vce_unregister_handler (&vcm->event_thread, reg);
3781 rv = vppcom_session_read_ready (session, session_index);
3782 clib_spinlock_unlock (&vcm->sessions_lockp);
3783 if (except_map && vcm->ex_bitmap &&
3784 clib_bitmap_get (vcm->ex_bitmap, session_index) &&
3787 clib_bitmap_set_no_check (except_map, session_index, 1);
3792 clib_bitmap_set_no_check (read_map, session_index, 1);
3800 clib_bitmap_foreach (session_index, vcm->wr_bitmap,
3802 clib_spinlock_lock (&vcm->sessions_lockp);
3803 rv = vppcom_session_at_index (session_index, &session);
3806 clib_spinlock_unlock (&vcm->sessions_lockp);
3807 if (VPPCOM_DEBUG > 0)
3808 clib_warning ("VCL<%d>: session %d specified in "
3809 "write_map is closed.", getpid (),
3811 bits_set = VPPCOM_EBADFD;
3815 rv = vppcom_session_write_ready (session, session_index);
3816 clib_spinlock_unlock (&vcm->sessions_lockp);
3817 if (write_map && (rv > 0))
3819 clib_bitmap_set_no_check (write_map, session_index, 1);
3827 clib_bitmap_foreach (session_index, vcm->ex_bitmap,
3829 clib_spinlock_lock (&vcm->sessions_lockp);
3830 rv = vppcom_session_at_index (session_index, &session);
3833 clib_spinlock_unlock (&vcm->sessions_lockp);
3834 if (VPPCOM_DEBUG > 1)
3835 clib_warning ("VCL<%d>: session %d specified in "
3836 "except_map is closed.", getpid (),
3838 bits_set = VPPCOM_EBADFD;
3842 rv = vppcom_session_read_ready (session, session_index);
3843 clib_spinlock_unlock (&vcm->sessions_lockp);
3846 clib_bitmap_set_no_check (except_map, session_index, 1);
3854 while ((time_to_wait == -1) || (clib_time_now (&vcm->clib_time) < timeout));
3861 vep_verify_epoll_chain (u32 vep_idx)
3864 vppcom_epoll_t *vep;
3868 if (VPPCOM_DEBUG <= 1)
3871 /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3872 rv = vppcom_session_at_index (vep_idx, &session);
3873 if (PREDICT_FALSE (rv))
3875 clib_warning ("VCL<%d>: ERROR: Invalid vep_idx (%u)!",
3876 getpid (), vep_idx);
3879 if (PREDICT_FALSE (!session->is_vep))
3881 clib_warning ("VCL<%d>: ERROR: vep_idx (%u) is not a vep!",
3882 getpid (), vep_idx);
3885 vep = &session->vep;
3886 clib_warning ("VCL<%d>: vep_idx (%u): Dumping epoll chain\n"
3889 " is_vep_session = %u\n"
3890 " next_sid = 0x%x (%u)\n"
3891 " wait_cont_idx = 0x%x (%u)\n"
3892 "}\n", getpid (), vep_idx,
3893 session->is_vep, session->is_vep_session,
3894 vep->next_sid, vep->next_sid,
3895 session->wait_cont_idx, session->wait_cont_idx);
3897 for (sid = vep->next_sid; sid != ~0; sid = vep->next_sid)
3899 rv = vppcom_session_at_index (sid, &session);
3900 if (PREDICT_FALSE (rv))
3902 clib_warning ("VCL<%d>: ERROR: Invalid sid (%u)!", getpid (), sid);
3905 if (PREDICT_FALSE (session->is_vep))
3906 clib_warning ("VCL<%d>: ERROR: sid (%u) is a vep!",
3907 getpid (), vep_idx);
3908 else if (PREDICT_FALSE (!session->is_vep_session))
3910 clib_warning ("VCL<%d>: ERROR: session (%u) "
3911 "is not a vep session!", getpid (), sid);
3914 vep = &session->vep;
3915 if (PREDICT_FALSE (vep->vep_idx != vep_idx))
3916 clib_warning ("VCL<%d>: ERROR: session (%u) vep_idx (%u) != "
3917 "vep_idx (%u)!", getpid (),
3918 sid, session->vep.vep_idx, vep_idx);
3919 if (session->is_vep_session)
3921 clib_warning ("vep_idx[%u]: sid 0x%x (%u)\n"
3923 " next_sid = 0x%x (%u)\n"
3924 " prev_sid = 0x%x (%u)\n"
3925 " vep_idx = 0x%x (%u)\n"
3926 " ev.events = 0x%x\n"
3927 " ev.data.u64 = 0x%llx\n"
3931 vep->next_sid, vep->next_sid,
3932 vep->prev_sid, vep->prev_sid,
3933 vep->vep_idx, vep->vep_idx,
3934 vep->ev.events, vep->ev.data.u64, vep->et_mask);
3939 clib_warning ("VCL<%d>: vep_idx (%u): Dump complete!\n",
3940 getpid (), vep_idx);
3944 vppcom_epoll_create (void)
3946 session_t *vep_session;
3948 elog_track_t vep_elog_track;
3950 clib_spinlock_lock (&vcm->sessions_lockp);
3951 pool_get (vcm->sessions, vep_session);
3952 memset (vep_session, 0, sizeof (*vep_session));
3953 vep_idx = vep_session - vcm->sessions;
3955 vep_session->is_vep = 1;
3956 vep_session->vep.vep_idx = ~0;
3957 vep_session->vep.next_sid = ~0;
3958 vep_session->vep.prev_sid = ~0;
3959 vep_session->wait_cont_idx = ~0;
3960 vep_session->vpp_handle = ~0;
3961 vep_session->poll_reg = 0;
3963 if (VPPCOM_DEBUG > 0)
3965 vep_session->elog_track.name =
3966 (char *) format (0, "C:%d:VEP:%d%c", vcm->my_client_index,
3968 elog_track_register (&vcm->elog_main, &vep_session->elog_track);
3969 vep_elog_track = vep_session->elog_track;
3972 clib_spinlock_unlock (&vcm->sessions_lockp);
3974 if (VPPCOM_DEBUG > 0)
3975 clib_warning ("VCL<%d>: Created vep_idx %u / sid %u!",
3976 getpid (), vep_idx, vep_idx);
3978 if (VPPCOM_DEBUG > 0)
3982 ELOG_TYPE_DECLARE (e) =
3984 .format = "created epoll session:%d",
3985 .format_args = "i4",
3993 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vep_elog_track);
4002 vppcom_epoll_ctl (uint32_t vep_idx, int op, uint32_t session_index,
4003 struct epoll_event *event)
4005 session_t *vep_session;
4009 if (vep_idx == session_index)
4011 clib_warning ("VCL<%d>: ERROR: vep_idx == session_index (%u)!",
4012 getpid (), vep_idx);
4013 return VPPCOM_EINVAL;
4016 clib_spinlock_lock (&vcm->sessions_lockp);
4017 rv = vppcom_session_at_index (vep_idx, &vep_session);
4018 if (PREDICT_FALSE (rv))
4020 clib_warning ("VCL<%d>: ERROR: Invalid vep_idx (%u)!", vep_idx);
4023 if (PREDICT_FALSE (!vep_session->is_vep))
4025 clib_warning ("VCL<%d>: ERROR: vep_idx (%u) is not a vep!",
4026 getpid (), vep_idx);
4031 ASSERT (vep_session->vep.vep_idx == ~0);
4032 ASSERT (vep_session->vep.prev_sid == ~0);
4034 rv = vppcom_session_at_index (session_index, &session);
4035 if (PREDICT_FALSE (rv))
4037 if (VPPCOM_DEBUG > 0)
4038 clib_warning ("VCL<%d>: ERROR: Invalid session_index (%u)!",
4039 getpid (), session_index);
4042 if (PREDICT_FALSE (session->is_vep))
4044 clib_warning ("ERROR: session_index (%u) is a vep!", vep_idx);
4052 if (PREDICT_FALSE (!event))
4054 clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_ADD: NULL pointer to "
4055 "epoll_event structure!", getpid ());
4059 if (vep_session->vep.next_sid != ~0)
4061 session_t *next_session;
4062 rv = vppcom_session_at_index (vep_session->vep.next_sid,
4064 if (PREDICT_FALSE (rv))
4066 clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_ADD: Invalid "
4067 "vep.next_sid (%u) on vep_idx (%u)!",
4068 getpid (), vep_session->vep.next_sid, vep_idx);
4071 ASSERT (next_session->vep.prev_sid == vep_idx);
4072 next_session->vep.prev_sid = session_index;
4074 session->vep.next_sid = vep_session->vep.next_sid;
4075 session->vep.prev_sid = vep_idx;
4076 session->vep.vep_idx = vep_idx;
4077 session->vep.et_mask = VEP_DEFAULT_ET_MASK;
4078 session->vep.ev = *event;
4079 session->is_vep = 0;
4080 session->is_vep_session = 1;
4081 vep_session->vep.next_sid = session_index;
4083 /* VCL Event Register handler */
4084 if (session->state & STATE_LISTEN)
4086 /* Register handler for connect_request event on listen_session_index */
4087 vce_event_key_t evk;
4088 evk.session_index = session_index;
4089 evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
4090 vep_session->poll_reg =
4091 vce_register_handler (&vcm->event_thread, &evk,
4092 vce_poll_wait_connect_request_handler_fn,
4093 0 /* No callback args */ );
4095 if (VPPCOM_DEBUG > 1)
4096 clib_warning ("VCL<%d>: EPOLL_CTL_ADD: vep_idx %u, "
4097 "sid %u, events 0x%x, data 0x%llx!",
4098 getpid (), vep_idx, session_index,
4099 event->events, event->data.u64);
4100 if (VPPCOM_DEBUG > 0)
4103 ELOG_TYPE_DECLARE (e) =
4105 .format = "epoll_ctladd: events:%x data:%x",
4106 .format_args = "i4i4i8",
4114 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4116 ed->events = event->events;
4117 ed->event_data = event->data.u64;
4123 if (PREDICT_FALSE (!event))
4125 clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_MOD: NULL pointer to "
4126 "epoll_event structure!", getpid ());
4130 else if (PREDICT_FALSE (!session->is_vep_session))
4132 clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_MOD: "
4133 "not a vep session!", getpid (), session_index);
4137 else if (PREDICT_FALSE (session->vep.vep_idx != vep_idx))
4139 clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_MOD: "
4140 "vep_idx (%u) != vep_idx (%u)!",
4141 getpid (), session_index,
4142 session->vep.vep_idx, vep_idx);
4146 session->vep.et_mask = VEP_DEFAULT_ET_MASK;
4147 session->vep.ev = *event;
4148 if (VPPCOM_DEBUG > 1)
4150 ("VCL<%d>: EPOLL_CTL_MOD: vep_idx %u, sid %u, events 0x%x,"
4151 " data 0x%llx!", getpid (), vep_idx, session_index, event->events,
4156 if (PREDICT_FALSE (!session->is_vep_session))
4158 clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_DEL: "
4159 "not a vep session!", getpid (), session_index);
4163 else if (PREDICT_FALSE (session->vep.vep_idx != vep_idx))
4165 clib_warning ("VCL<%d>: ERROR: sid %u EPOLL_CTL_DEL: "
4166 "vep_idx (%u) != vep_idx (%u)!",
4167 getpid (), session_index,
4168 session->vep.vep_idx, vep_idx);
4173 /* VCL Event Un-register handler */
4174 if ((session->state & STATE_LISTEN) && vep_session->poll_reg)
4176 (void) vce_unregister_handler (&vcm->event_thread,
4177 vep_session->poll_reg);
4180 vep_session->wait_cont_idx =
4181 (vep_session->wait_cont_idx == session_index) ?
4182 session->vep.next_sid : vep_session->wait_cont_idx;
4184 if (session->vep.prev_sid == vep_idx)
4185 vep_session->vep.next_sid = session->vep.next_sid;
4188 session_t *prev_session;
4189 rv = vppcom_session_at_index (session->vep.prev_sid, &prev_session);
4190 if (PREDICT_FALSE (rv))
4192 clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_DEL: Invalid "
4193 "vep.prev_sid (%u) on sid (%u)!",
4194 getpid (), session->vep.prev_sid, session_index);
4197 ASSERT (prev_session->vep.next_sid == session_index);
4198 prev_session->vep.next_sid = session->vep.next_sid;
4200 if (session->vep.next_sid != ~0)
4202 session_t *next_session;
4203 rv = vppcom_session_at_index (session->vep.next_sid, &next_session);
4204 if (PREDICT_FALSE (rv))
4206 clib_warning ("VCL<%d>: ERROR: EPOLL_CTL_DEL: Invalid "
4207 "vep.next_sid (%u) on sid (%u)!",
4208 getpid (), session->vep.next_sid, session_index);
4211 ASSERT (next_session->vep.prev_sid == session_index);
4212 next_session->vep.prev_sid = session->vep.prev_sid;
4215 memset (&session->vep, 0, sizeof (session->vep));
4216 session->vep.next_sid = ~0;
4217 session->vep.prev_sid = ~0;
4218 session->vep.vep_idx = ~0;
4219 session->is_vep_session = 0;
4220 if (VPPCOM_DEBUG > 1)
4221 clib_warning ("VCL<%d>: EPOLL_CTL_DEL: vep_idx %u, sid %u!",
4222 getpid (), vep_idx, session_index);
4223 if (VPPCOM_DEBUG > 0)
4226 ELOG_TYPE_DECLARE (e) =
4228 .format = "epoll_ctldel: vep:%d",
4229 .format_args = "i4",
4236 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4244 clib_warning ("VCL<%d>: ERROR: Invalid operation (%d)!", getpid (), op);
4248 vep_verify_epoll_chain (vep_idx);
4251 clib_spinlock_unlock (&vcm->sessions_lockp);
4256 vppcom_epoll_wait (uint32_t vep_idx, struct epoll_event *events,
4257 int maxevents, double wait_for_time)
4259 session_t *vep_session;
4260 elog_track_t vep_elog_track;
4262 f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
4263 u32 keep_trying = 1;
4265 u32 vep_next_sid, wait_cont_idx;
4268 if (PREDICT_FALSE (maxevents <= 0))
4270 clib_warning ("VCL<%d>: ERROR: Invalid maxevents (%d)!",
4271 getpid (), maxevents);
4272 return VPPCOM_EINVAL;
4274 memset (events, 0, sizeof (*events) * maxevents);
4276 VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
4277 vep_next_sid = vep_session->vep.next_sid;
4278 is_vep = vep_session->is_vep;
4279 wait_cont_idx = vep_session->wait_cont_idx;
4280 vep_elog_track = vep_session->elog_track;
4281 clib_spinlock_unlock (&vcm->sessions_lockp);
4283 if (PREDICT_FALSE (!is_vep))
4285 clib_warning ("VCL<%d>: ERROR: vep_idx (%u) is not a vep!",
4286 getpid (), vep_idx);
4290 if (PREDICT_FALSE (vep_next_sid == ~0))
4292 if (VPPCOM_DEBUG > 1)
4293 clib_warning ("VCL<%d>: WARNING: vep_idx (%u) is empty!",
4294 getpid (), vep_idx);
4295 if (VPPCOM_DEBUG > 1)
4298 ELOG_TYPE_DECLARE (e) =
4300 .format = "WRN: vep_idx:%d empty",
4301 .format_args = "i4",
4308 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vep_elog_track);
4321 elog_track_t session_elog_track;
4323 for (sid = (wait_cont_idx == ~0) ? vep_next_sid : wait_cont_idx;
4324 sid != ~0; sid = next_sid)
4326 u32 session_events, et_mask, clear_et_mask, session_vep_idx;
4327 u8 add_event, is_vep_session;
4329 u64 session_ev_data;
4331 VCL_LOCK_AND_GET_SESSION (sid, &session);
4332 next_sid = session->vep.next_sid;
4333 session_events = session->vep.ev.events;
4334 et_mask = session->vep.et_mask;
4335 is_vep = session->is_vep;
4336 is_vep_session = session->is_vep_session;
4337 session_vep_idx = session->vep.vep_idx;
4338 session_ev_data = session->vep.ev.data.u64;
4340 if (VPPCOM_DEBUG > 0)
4342 session_elog_track = session->elog_track;
4345 clib_spinlock_unlock (&vcm->sessions_lockp);
4347 if (PREDICT_FALSE (is_vep))
4349 if (VPPCOM_DEBUG > 0)
4350 clib_warning ("VCL<%d>: ERROR: sid (%u) is a vep!",
4351 getpid (), vep_idx);
4352 if (VPPCOM_DEBUG > 0)
4355 ELOG_TYPE_DECLARE (e) =
4357 .format = "ERR:vep_idx:%d is vep",
4358 .format_args = "i4",
4365 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session_elog_track);
4374 if (PREDICT_FALSE (!is_vep_session))
4376 if (VPPCOM_DEBUG > 0)
4377 clib_warning ("VCL<%d>: ERROR: session (%u) is not "
4378 "a vep session!", getpid (), sid);
4379 if (VPPCOM_DEBUG > 0)
4382 ELOG_TYPE_DECLARE (e) =
4384 .format = "ERR:SID:%d not vep",
4385 .format_args = "i4",
4392 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session_elog_track);
4401 if (PREDICT_FALSE (session_vep_idx != vep_idx))
4403 clib_warning ("VCL<%d>: ERROR: session (%u) "
4404 "vep_idx (%u) != vep_idx (%u)!",
4405 getpid (), sid, session_vep_idx, vep_idx);
4410 add_event = clear_et_mask = 0;
4412 if (EPOLLIN & session_events)
4414 VCL_LOCK_AND_GET_SESSION (sid, &session);
4415 ready = vppcom_session_read_ready (session, sid);
4416 clib_spinlock_unlock (&vcm->sessions_lockp);
4417 if ((ready > 0) && (EPOLLIN & et_mask))
4420 events[num_ev].events |= EPOLLIN;
4421 if (((EPOLLET | EPOLLIN) & session_events) ==
4422 (EPOLLET | EPOLLIN))
4423 clear_et_mask |= EPOLLIN;
4430 case VPPCOM_ECONNRESET:
4431 events[num_ev].events |= EPOLLHUP | EPOLLRDHUP;
4435 events[num_ev].events |= EPOLLERR;
4441 if (EPOLLOUT & session_events)
4443 VCL_LOCK_AND_GET_SESSION (sid, &session);
4444 ready = vppcom_session_write_ready (session, sid);
4445 clib_spinlock_unlock (&vcm->sessions_lockp);
4446 if ((ready > 0) && (EPOLLOUT & et_mask))
4449 events[num_ev].events |= EPOLLOUT;
4450 if (((EPOLLET | EPOLLOUT) & session_events) ==
4451 (EPOLLET | EPOLLOUT))
4452 clear_et_mask |= EPOLLOUT;
4459 case VPPCOM_ECONNRESET:
4460 events[num_ev].events |= EPOLLHUP;
4464 events[num_ev].events |= EPOLLERR;
4472 events[num_ev].data.u64 = session_ev_data;
4473 if (EPOLLONESHOT & session_events)
4475 VCL_LOCK_AND_GET_SESSION (sid, &session);
4476 session->vep.ev.events = 0;
4477 clib_spinlock_unlock (&vcm->sessions_lockp);
4480 if (num_ev == maxevents)
4482 VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
4483 vep_session->wait_cont_idx = next_sid;
4484 clib_spinlock_unlock (&vcm->sessions_lockp);
4488 if (wait_cont_idx != ~0)
4491 next_sid = vep_next_sid;
4492 else if (next_sid == wait_cont_idx)
4496 if (wait_for_time != -1)
4497 keep_trying = (clib_time_now (&vcm->clib_time) <= timeout) ? 1 : 0;
4499 while ((num_ev == 0) && keep_trying);
4501 if (wait_cont_idx != ~0)
4503 VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
4504 vep_session->wait_cont_idx = ~0;
4505 clib_spinlock_unlock (&vcm->sessions_lockp);
4508 return (rv != VPPCOM_OK) ? rv : num_ev;
4512 vppcom_session_attr (uint32_t session_index, uint32_t op,
4513 void *buffer, uint32_t * buflen)
4517 u32 *flags = buffer;
4518 vppcom_endpt_t *ep = buffer;
4520 VCL_LOCK_AND_GET_SESSION (session_index, &session);
4526 case VPPCOM_ATTR_GET_NREAD:
4527 rv = vppcom_session_read_ready (session, session_index);
4528 if (VPPCOM_DEBUG > 2)
4529 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_NREAD: sid %u, nread = %d",
4531 if (VPPCOM_DEBUG > 0)
4534 ELOG_TYPE_DECLARE (e) =
4536 .format = "VPPCOM_ATTR_GET_NREAD: nread=%d",
4537 .format_args = "i4",
4544 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4552 case VPPCOM_ATTR_GET_NWRITE:
4553 rv = vppcom_session_write_ready (session, session_index);
4554 if (VPPCOM_DEBUG > 2)
4555 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_NWRITE: sid %u, nwrite = %d",
4556 getpid (), session_index, rv);
4557 if (VPPCOM_DEBUG > 0)
4560 ELOG_TYPE_DECLARE (e) =
4562 .format = "VPPCOM_ATTR_GET_NWRITE: nwrite=%d",
4563 .format_args = "i4",
4570 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4577 case VPPCOM_ATTR_GET_FLAGS:
4578 if (PREDICT_TRUE (buffer && buflen && (*buflen >= sizeof (*flags))))
4580 *flags = O_RDWR | (VCL_SESS_ATTR_TEST (session->attr,
4581 VCL_SESS_ATTR_NONBLOCK));
4582 *buflen = sizeof (*flags);
4583 if (VPPCOM_DEBUG > 2)
4584 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_FLAGS: sid %u, "
4585 "flags = 0x%08x, is_nonblocking = %u", getpid (),
4586 session_index, *flags,
4587 VCL_SESS_ATTR_TEST (session->attr,
4588 VCL_SESS_ATTR_NONBLOCK));
4589 if (VPPCOM_DEBUG > 0)
4592 ELOG_TYPE_DECLARE (e) =
4594 .format = "VPPCOM_ATTR_GET_FLAGS: flags=%x is_nonblk=%d",
4595 .format_args = "i4i4",
4603 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4606 ed->is_nonblk = VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK);
4615 case VPPCOM_ATTR_SET_FLAGS:
4616 if (PREDICT_TRUE (buffer && buflen && (*buflen == sizeof (*flags))))
4618 if (*flags & O_NONBLOCK)
4619 VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_NONBLOCK);
4621 VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_NONBLOCK);
4623 if (VPPCOM_DEBUG > 2)
4624 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_FLAGS: sid %u, "
4625 "flags = 0x%08x, is_nonblocking = %u",
4626 getpid (), session_index, *flags,
4627 VCL_SESS_ATTR_TEST (session->attr,
4628 VCL_SESS_ATTR_NONBLOCK));
4629 if (VPPCOM_DEBUG > 0)
4632 ELOG_TYPE_DECLARE (e) =
4634 .format = "VPPCOM_ATTR_SET_FLAGS: flags=%x is_nonblk=%d",
4635 .format_args = "i4i4",
4643 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4646 ed->is_nonblk = VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_NONBLOCK);
4654 case VPPCOM_ATTR_GET_PEER_ADDR:
4655 if (PREDICT_TRUE (buffer && buflen &&
4656 (*buflen >= sizeof (*ep)) && ep->ip))
4658 ep->is_ip4 = session->peer_addr.is_ip4;
4659 ep->port = session->peer_port;
4660 if (session->peer_addr.is_ip4)
4661 clib_memcpy (ep->ip, &session->peer_addr.ip46.ip4,
4662 sizeof (ip4_address_t));
4664 clib_memcpy (ep->ip, &session->peer_addr.ip46.ip6,
4665 sizeof (ip6_address_t));
4666 *buflen = sizeof (*ep);
4667 if (VPPCOM_DEBUG > 1)
4668 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_PEER_ADDR: sid %u, "
4669 "is_ip4 = %u, addr = %U, port %u", getpid (),
4670 session_index, ep->is_ip4, format_ip46_address,
4671 &session->peer_addr.ip46,
4672 ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
4673 clib_net_to_host_u16 (ep->port));
4674 if (VPPCOM_DEBUG > 0)
4679 ELOG_TYPE_DECLARE (e) =
4681 .format = "VPPCOM_ATTR_GET_PEER_ADDR: addr:%d.%d.%d.%d:%d",
4682 .format_args = "i1i1i1i1i2",
4684 CLIB_PACKED (struct {
4689 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4691 ed->addr[0] = session->peer_addr.ip46.ip4.as_u8[0];
4692 ed->addr[1] = session->peer_addr.ip46.ip4.as_u8[1];
4693 ed->addr[2] = session->peer_addr.ip46.ip4.as_u8[2];
4694 ed->addr[3] = session->peer_addr.ip46.ip4.as_u8[3];
4695 ed->port = clib_net_to_host_u16 (session->peer_port);
4701 ELOG_TYPE_DECLARE (e) =
4703 .format = "VPPCOM_ATTR_GET_PEER_ADDR: addr:IP6:%d",
4704 .format_args = "i2",
4706 CLIB_PACKED (struct {
4710 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4712 ed->port = clib_net_to_host_u16 (session->peer_port);
4721 case VPPCOM_ATTR_GET_LCL_ADDR:
4722 if (PREDICT_TRUE (buffer && buflen &&
4723 (*buflen >= sizeof (*ep)) && ep->ip))
4725 ep->is_ip4 = session->lcl_addr.is_ip4;
4726 ep->port = session->lcl_port;
4727 if (session->lcl_addr.is_ip4)
4728 clib_memcpy (ep->ip, &session->lcl_addr.ip46.ip4,
4729 sizeof (ip4_address_t));
4731 clib_memcpy (ep->ip, &session->lcl_addr.ip46.ip6,
4732 sizeof (ip6_address_t));
4733 *buflen = sizeof (*ep);
4734 if (VPPCOM_DEBUG > 1)
4735 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_LCL_ADDR: sid %u, "
4736 "is_ip4 = %u, addr = %U port %d", getpid (),
4737 session_index, ep->is_ip4, format_ip46_address,
4738 &session->lcl_addr.ip46,
4739 ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
4740 clib_net_to_host_u16 (ep->port));
4741 if (VPPCOM_DEBUG > 0)
4746 ELOG_TYPE_DECLARE (e) =
4748 .format = "VPPCOM_ATTR_GET_LCL_ADDR: addr:%d.%d.%d.%d:%d",
4749 .format_args = "i1i1i1i1i2",
4751 CLIB_PACKED (struct {
4756 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4758 ed->addr[0] = session->lcl_addr.ip46.ip4.as_u8[0];
4759 ed->addr[1] = session->lcl_addr.ip46.ip4.as_u8[1];
4760 ed->addr[2] = session->lcl_addr.ip46.ip4.as_u8[2];
4761 ed->addr[3] = session->lcl_addr.ip46.ip4.as_u8[3];
4762 ed->port = clib_net_to_host_u16 (session->peer_port);
4768 ELOG_TYPE_DECLARE (e) =
4770 .format = "VPPCOM_ATTR_GET_LCL_ADDR: addr:IP6:%d",
4771 .format_args = "i2",
4773 CLIB_PACKED (struct {
4777 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4779 ed->port = clib_net_to_host_u16 (session->peer_port);
4788 case VPPCOM_ATTR_GET_LIBC_EPFD:
4789 rv = session->libc_epfd;
4790 if (VPPCOM_DEBUG > 2)
4791 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_LIBC_EPFD: libc_epfd %d",
4793 if (VPPCOM_DEBUG > 0)
4796 ELOG_TYPE_DECLARE (e) =
4798 .format = "VPPCOM_ATTR_GET_LIBC_EPFD: libc_epfd=%d",
4799 .format_args = "i4",
4801 CLIB_PACKED (struct {
4805 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4806 ed->data = session->libc_epfd;
4812 case VPPCOM_ATTR_SET_LIBC_EPFD:
4813 if (PREDICT_TRUE (buffer && buflen &&
4814 (*buflen == sizeof (session->libc_epfd))))
4816 session->libc_epfd = *(int *) buffer;
4817 *buflen = sizeof (session->libc_epfd);
4819 if (VPPCOM_DEBUG > 2)
4820 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_LIBC_EPFD: libc_epfd %d, "
4821 "buflen %d", getpid (), session->libc_epfd,
4823 if (VPPCOM_DEBUG > 0)
4826 ELOG_TYPE_DECLARE (e) =
4828 .format = "VPPCOM_ATTR_SET_LIBC_EPFD: libc_epfd=%s%d buflen=%d",
4829 .format_args = "t1i4i4",
4830 .n_enum_strings = 2,
4831 .enum_strings = {"", "-",},
4833 CLIB_PACKED (struct {
4838 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4840 ed->sign = (session->libc_epfd < 0);
4841 ed->data[0] = abs(session->libc_epfd);
4842 ed->data[1] = *buflen;
4850 case VPPCOM_ATTR_GET_PROTOCOL:
4851 if (buffer && buflen && (*buflen >= sizeof (int)))
4853 *(int *) buffer = session->proto;
4854 *buflen = sizeof (int);
4856 if (VPPCOM_DEBUG > 2)
4857 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_PROTOCOL: %d (%s), "
4858 "buflen %d", getpid (), *(int *) buffer,
4859 *(int *) buffer ? "UDP" : "TCP", *buflen);
4860 if (VPPCOM_DEBUG > 0)
4863 ELOG_TYPE_DECLARE (e) =
4865 .format = "VPPCOM_ATTR_GET_PROTOCOL: %s buflen=%d",
4866 .format_args = "t1i4",
4867 .n_enum_strings = 2,
4868 .enum_strings = {"TCP", "UDP",},
4871 CLIB_PACKED (struct {
4876 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4877 ed->proto = session->proto;
4878 ed->buflen = *(int *) buffer;
4886 case VPPCOM_ATTR_GET_LISTEN:
4887 if (buffer && buflen && (*buflen >= sizeof (int)))
4889 *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
4890 VCL_SESS_ATTR_LISTEN);
4891 *buflen = sizeof (int);
4893 if (VPPCOM_DEBUG > 2)
4894 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_LISTEN: %d, "
4895 "buflen %d", getpid (), *(int *) buffer, *buflen);
4896 if (VPPCOM_DEBUG > 0)
4899 ELOG_TYPE_DECLARE (e) =
4901 .format = "VPPCOM_ATTR_GET_LISTEN: %d buflen=%d",
4902 .format_args = "i4i4",
4909 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4910 ed->data[0] = *(int *) buffer;
4911 ed->data[1] = *buflen;
4919 case VPPCOM_ATTR_GET_ERROR:
4920 if (buffer && buflen && (*buflen >= sizeof (int)))
4922 *(int *) buffer = 0;
4923 *buflen = sizeof (int);
4925 if (VPPCOM_DEBUG > 2)
4926 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_ERROR: %d, "
4927 "buflen %d, #VPP-TBD#", getpid (),
4928 *(int *) buffer, *buflen);
4929 if (VPPCOM_DEBUG > 0)
4932 ELOG_TYPE_DECLARE (e) =
4934 .format = "VPPCOM_ATTR_GET_ERROR: %d buflen=%d",
4935 .format_args = "i4i4",
4942 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4943 ed->data[0] = *(int *) buffer;
4944 ed->data[1] = *buflen;
4952 case VPPCOM_ATTR_GET_TX_FIFO_LEN:
4953 if (buffer && buflen && (*buflen >= sizeof (u32)))
4957 *(size_t *) buffer = (session->sndbuf_size ? session->sndbuf_size :
4958 session->tx_fifo ? session->tx_fifo->nitems :
4959 vcm->cfg.tx_fifo_size);
4960 *buflen = sizeof (u32);
4962 if (VPPCOM_DEBUG > 2)
4963 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_TX_FIFO_LEN: %u (0x%x), "
4964 "buflen %d, #VPP-TBD#", getpid (),
4965 *(size_t *) buffer, *(size_t *) buffer, *buflen);
4966 if (VPPCOM_DEBUG > 0)
4969 ELOG_TYPE_DECLARE (e) =
4971 .format = "VPPCOM_ATTR_GET_TX_FIFO_LEN: 0x%x buflen=%d",
4972 .format_args = "i4i4",
4979 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
4980 ed->data[0] = *(size_t *) buffer;
4981 ed->data[1] = *buflen;
4989 case VPPCOM_ATTR_SET_TX_FIFO_LEN:
4990 if (buffer && buflen && (*buflen == sizeof (u32)))
4993 session->sndbuf_size = *(u32 *) buffer;
4994 if (VPPCOM_DEBUG > 2)
4995 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_TX_FIFO_LEN: %u (0x%x), "
4996 "buflen %d, #VPP-TBD#", getpid (),
4997 session->sndbuf_size, session->sndbuf_size,
4999 if (VPPCOM_DEBUG > 0)
5002 ELOG_TYPE_DECLARE (e) =
5004 .format = "VPPCOM_ATTR_SET_TX_FIFO_LEN: 0x%x buflen=%d",
5005 .format_args = "i4i4",
5012 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5013 ed->data[0] = session->sndbuf_size;
5014 ed->data[1] = *buflen;
5022 case VPPCOM_ATTR_GET_RX_FIFO_LEN:
5023 if (buffer && buflen && (*buflen >= sizeof (u32)))
5027 *(size_t *) buffer = (session->rcvbuf_size ? session->rcvbuf_size :
5028 session->rx_fifo ? session->rx_fifo->nitems :
5029 vcm->cfg.rx_fifo_size);
5030 *buflen = sizeof (u32);
5032 if (VPPCOM_DEBUG > 2)
5033 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_RX_FIFO_LEN: %u (0x%x), "
5034 "buflen %d, #VPP-TBD#", getpid (),
5035 *(size_t *) buffer, *(size_t *) buffer, *buflen);
5036 if (VPPCOM_DEBUG > 0)
5039 ELOG_TYPE_DECLARE (e) =
5041 .format = "VPPCOM_ATTR_GET_RX_FIFO_LEN: 0x%x buflen=%d",
5042 .format_args = "i4i4",
5049 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5050 ed->data[0] = *(size_t *) buffer;
5051 ed->data[1] = *buflen;
5059 case VPPCOM_ATTR_SET_RX_FIFO_LEN:
5060 if (buffer && buflen && (*buflen == sizeof (u32)))
5063 session->rcvbuf_size = *(u32 *) buffer;
5064 if (VPPCOM_DEBUG > 2)
5065 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_RX_FIFO_LEN: %u (0x%x), "
5066 "buflen %d, #VPP-TBD#", getpid (),
5067 session->sndbuf_size, session->sndbuf_size,
5069 if (VPPCOM_DEBUG > 0)
5072 ELOG_TYPE_DECLARE (e) =
5074 .format = "VPPCOM_ATTR_SET_RX_FIFO_LEN: 0x%x buflen=%d",
5075 .format_args = "i4i4",
5082 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5083 ed->data[0] = session->sndbuf_size;
5084 ed->data[1] = *buflen;
5092 case VPPCOM_ATTR_GET_REUSEADDR:
5093 if (buffer && buflen && (*buflen >= sizeof (int)))
5096 *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5097 VCL_SESS_ATTR_REUSEADDR);
5098 *buflen = sizeof (int);
5100 if (VPPCOM_DEBUG > 2)
5101 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_REUSEADDR: %d, "
5102 "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5104 if (VPPCOM_DEBUG > 0)
5107 ELOG_TYPE_DECLARE (e) =
5109 .format = "VPPCOM_ATTR_GET_REUSEADDR: %d buflen=%d",
5110 .format_args = "i4i4",
5117 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5118 ed->data[0] = *(int *) buffer;
5119 ed->data[1] = *buflen;
5127 case VPPCOM_ATTR_SET_REUSEADDR:
5128 if (buffer && buflen && (*buflen == sizeof (int)) &&
5129 !VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_LISTEN))
5132 if (*(int *) buffer)
5133 VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_REUSEADDR);
5135 VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_REUSEADDR);
5137 if (VPPCOM_DEBUG > 2)
5138 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_REUSEADDR: %d, "
5139 "buflen %d, #VPP-TBD#", getpid (),
5140 VCL_SESS_ATTR_TEST (session->attr,
5141 VCL_SESS_ATTR_REUSEADDR),
5143 if (VPPCOM_DEBUG > 0)
5146 ELOG_TYPE_DECLARE (e) =
5148 .format = "VPPCOM_ATTR_SET_REUSEADDR: %d buflen=%d",
5149 .format_args = "i4i4",
5156 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5157 ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5158 VCL_SESS_ATTR_REUSEADDR);
5159 ed->data[1] = *buflen;
5167 case VPPCOM_ATTR_GET_REUSEPORT:
5168 if (buffer && buflen && (*buflen >= sizeof (int)))
5171 *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5172 VCL_SESS_ATTR_REUSEPORT);
5173 *buflen = sizeof (int);
5175 if (VPPCOM_DEBUG > 2)
5176 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_REUSEPORT: %d, "
5177 "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5179 if (VPPCOM_DEBUG > 0)
5182 ELOG_TYPE_DECLARE (e) =
5184 .format = "VPPCOM_ATTR_GET_REUSEPORT: %d buflen=%d",
5185 .format_args = "i4i4",
5192 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5193 ed->data[0] = *(int *) buffer;
5194 ed->data[1] = *buflen;
5202 case VPPCOM_ATTR_SET_REUSEPORT:
5203 if (buffer && buflen && (*buflen == sizeof (int)) &&
5204 !VCL_SESS_ATTR_TEST (session->attr, VCL_SESS_ATTR_LISTEN))
5207 if (*(int *) buffer)
5208 VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_REUSEPORT);
5210 VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_REUSEPORT);
5212 if (VPPCOM_DEBUG > 2)
5213 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_REUSEPORT: %d, "
5214 "buflen %d, #VPP-TBD#", getpid (),
5215 VCL_SESS_ATTR_TEST (session->attr,
5216 VCL_SESS_ATTR_REUSEPORT),
5218 if (VPPCOM_DEBUG > 0)
5221 ELOG_TYPE_DECLARE (e) =
5223 .format = "VPPCOM_ATTR_SET_REUSEPORT: %d buflen=%d",
5224 .format_args = "i4i4",
5231 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5232 ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5233 VCL_SESS_ATTR_REUSEPORT);
5234 ed->data[1] = *buflen;
5242 case VPPCOM_ATTR_GET_BROADCAST:
5243 if (buffer && buflen && (*buflen >= sizeof (int)))
5246 *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5247 VCL_SESS_ATTR_BROADCAST);
5248 *buflen = sizeof (int);
5250 if (VPPCOM_DEBUG > 2)
5251 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_BROADCAST: %d, "
5252 "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5254 if (VPPCOM_DEBUG > 0)
5257 ELOG_TYPE_DECLARE (e) =
5259 .format = "VPPCOM_ATTR_GET_BROADCAST: %d buflen=%d",
5260 .format_args = "i4i4",
5267 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5268 ed->data[0] = *(int *) buffer;
5269 ed->data[1] = *buflen;
5277 case VPPCOM_ATTR_SET_BROADCAST:
5278 if (buffer && buflen && (*buflen == sizeof (int)))
5281 if (*(int *) buffer)
5282 VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_BROADCAST);
5284 VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_BROADCAST);
5286 if (VPPCOM_DEBUG > 2)
5287 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_BROADCAST: %d, "
5288 "buflen %d, #VPP-TBD#", getpid (),
5289 VCL_SESS_ATTR_TEST (session->attr,
5290 VCL_SESS_ATTR_BROADCAST),
5292 if (VPPCOM_DEBUG > 0)
5295 ELOG_TYPE_DECLARE (e) =
5297 .format = "VPPCOM_ATTR_SET_BROADCAST: %d buflen=%d",
5298 .format_args = "i4i4",
5305 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5306 ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5307 VCL_SESS_ATTR_BROADCAST);
5308 ed->data[1] = *buflen;
5316 case VPPCOM_ATTR_GET_V6ONLY:
5317 if (buffer && buflen && (*buflen >= sizeof (int)))
5320 *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5321 VCL_SESS_ATTR_V6ONLY);
5322 *buflen = sizeof (int);
5324 if (VPPCOM_DEBUG > 2)
5325 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_V6ONLY: %d, "
5326 "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5328 if (VPPCOM_DEBUG > 0)
5331 ELOG_TYPE_DECLARE (e) =
5333 .format = "VPPCOM_ATTR_GET_V6ONLY: %d buflen=%d",
5334 .format_args = "i4i4",
5341 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5342 ed->data[0] = *(int *) buffer;
5343 ed->data[1] = *buflen;
5351 case VPPCOM_ATTR_SET_V6ONLY:
5352 if (buffer && buflen && (*buflen == sizeof (int)))
5355 if (*(int *) buffer)
5356 VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_V6ONLY);
5358 VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_V6ONLY);
5360 if (VPPCOM_DEBUG > 2)
5361 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_V6ONLY: %d, "
5362 "buflen %d, #VPP-TBD#", getpid (),
5363 VCL_SESS_ATTR_TEST (session->attr,
5364 VCL_SESS_ATTR_V6ONLY), *buflen);
5365 if (VPPCOM_DEBUG > 0)
5368 ELOG_TYPE_DECLARE (e) =
5370 .format = "VPPCOM_ATTR_SET_V6ONLY: %d buflen=%d",
5371 .format_args = "i4i4",
5378 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5379 ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5380 VCL_SESS_ATTR_V6ONLY);
5381 ed->data[1] = *buflen;
5389 case VPPCOM_ATTR_GET_KEEPALIVE:
5390 if (buffer && buflen && (*buflen >= sizeof (int)))
5393 *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5394 VCL_SESS_ATTR_KEEPALIVE);
5395 *buflen = sizeof (int);
5397 if (VPPCOM_DEBUG > 2)
5398 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_KEEPALIVE: %d, "
5399 "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5401 if (VPPCOM_DEBUG > 0)
5404 ELOG_TYPE_DECLARE (e) =
5406 .format = "VPPCOM_ATTR_GET_KEEPALIVE: %d buflen=%d",
5407 .format_args = "i4i4",
5414 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5415 ed->data[0] = *(int *) buffer;
5416 ed->data[1] = *buflen;
5424 case VPPCOM_ATTR_SET_KEEPALIVE:
5425 if (buffer && buflen && (*buflen == sizeof (int)))
5428 if (*(int *) buffer)
5429 VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_KEEPALIVE);
5431 VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_KEEPALIVE);
5433 if (VPPCOM_DEBUG > 2)
5434 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_KEEPALIVE: %d, "
5435 "buflen %d, #VPP-TBD#", getpid (),
5436 VCL_SESS_ATTR_TEST (session->attr,
5437 VCL_SESS_ATTR_KEEPALIVE),
5439 if (VPPCOM_DEBUG > 0)
5442 ELOG_TYPE_DECLARE (e) =
5444 .format = "VPPCOM_ATTR_SET_KEEPALIVE: %d buflen=%d",
5445 .format_args = "i4i4",
5452 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5453 ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5454 VCL_SESS_ATTR_KEEPALIVE);
5455 ed->data[1] = *buflen;
5463 case VPPCOM_ATTR_GET_TCP_NODELAY:
5464 if (buffer && buflen && (*buflen >= sizeof (int)))
5467 *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5468 VCL_SESS_ATTR_TCP_NODELAY);
5469 *buflen = sizeof (int);
5471 if (VPPCOM_DEBUG > 2)
5472 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_TCP_NODELAY: %d, "
5473 "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5475 if (VPPCOM_DEBUG > 0)
5478 ELOG_TYPE_DECLARE (e) =
5480 .format = "VPPCOM_ATTR_GET_TCP_NODELAY: %d buflen=%d",
5481 .format_args = "i4i4",
5488 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5489 ed->data[0] = *(int *) buffer;
5490 ed->data[1] = *buflen;
5498 case VPPCOM_ATTR_SET_TCP_NODELAY:
5499 if (buffer && buflen && (*buflen == sizeof (int)))
5502 if (*(int *) buffer)
5503 VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_NODELAY);
5505 VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_NODELAY);
5507 if (VPPCOM_DEBUG > 2)
5508 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_TCP_NODELAY: %d, "
5509 "buflen %d, #VPP-TBD#", getpid (),
5510 VCL_SESS_ATTR_TEST (session->attr,
5511 VCL_SESS_ATTR_TCP_NODELAY),
5513 if (VPPCOM_DEBUG > 0)
5516 ELOG_TYPE_DECLARE (e) =
5518 .format = "VPPCOM_ATTR_SET_TCP_NODELAY: %d buflen=%d",
5519 .format_args = "i4i4",
5526 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5527 ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5528 VCL_SESS_ATTR_TCP_NODELAY);
5529 ed->data[1] = *buflen;
5537 case VPPCOM_ATTR_GET_TCP_KEEPIDLE:
5538 if (buffer && buflen && (*buflen >= sizeof (int)))
5541 *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5542 VCL_SESS_ATTR_TCP_KEEPIDLE);
5543 *buflen = sizeof (int);
5545 if (VPPCOM_DEBUG > 2)
5546 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d, "
5547 "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5549 if (VPPCOM_DEBUG > 0)
5552 ELOG_TYPE_DECLARE (e) =
5554 .format = "VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d buflen=%d",
5555 .format_args = "i4i4",
5562 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5563 ed->data[0] = *(int *) buffer;
5564 ed->data[1] = *buflen;
5572 case VPPCOM_ATTR_SET_TCP_KEEPIDLE:
5573 if (buffer && buflen && (*buflen == sizeof (int)))
5576 if (*(int *) buffer)
5577 VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_KEEPIDLE);
5579 VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_KEEPIDLE);
5581 if (VPPCOM_DEBUG > 2)
5582 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_TCP_KEEPIDLE: %d, "
5583 "buflen %d, #VPP-TBD#", getpid (),
5584 VCL_SESS_ATTR_TEST (session->attr,
5585 VCL_SESS_ATTR_TCP_KEEPIDLE),
5587 if (VPPCOM_DEBUG > 0)
5590 ELOG_TYPE_DECLARE (e) =
5592 .format = "VPPCOM_ATTR_SET_TCP_KEEPIDLE: %d buflen=%d",
5593 .format_args = "i4i4",
5600 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5601 ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5602 VCL_SESS_ATTR_TCP_KEEPIDLE);
5603 ed->data[1] = *buflen;
5611 case VPPCOM_ATTR_GET_TCP_KEEPINTVL:
5612 if (buffer && buflen && (*buflen >= sizeof (int)))
5615 *(int *) buffer = VCL_SESS_ATTR_TEST (session->attr,
5616 VCL_SESS_ATTR_TCP_KEEPINTVL);
5617 *buflen = sizeof (int);
5619 if (VPPCOM_DEBUG > 2)
5620 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_TCP_KEEPINTVL: %d, "
5621 "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5623 if (VPPCOM_DEBUG > 0)
5626 ELOG_TYPE_DECLARE (e) =
5628 .format = "VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d buflen=%d",
5629 .format_args = "i4i4",
5636 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5637 ed->data[0] = *(int *) buffer;
5638 ed->data[1] = *buflen;
5646 case VPPCOM_ATTR_SET_TCP_KEEPINTVL:
5647 if (buffer && buflen && (*buflen == sizeof (int)))
5650 if (*(int *) buffer)
5651 VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_TCP_KEEPINTVL);
5653 VCL_SESS_ATTR_CLR (session->attr, VCL_SESS_ATTR_TCP_KEEPINTVL);
5655 if (VPPCOM_DEBUG > 2)
5656 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_TCP_KEEPINTVL: %d, "
5657 "buflen %d, #VPP-TBD#", getpid (),
5658 VCL_SESS_ATTR_TEST (session->attr,
5659 VCL_SESS_ATTR_TCP_KEEPINTVL),
5661 if (VPPCOM_DEBUG > 0)
5664 ELOG_TYPE_DECLARE (e) =
5666 .format = "VPPCOM_ATTR_SET_TCP_KEEPINTVL: %d buflen=%d",
5667 .format_args = "i4i4",
5674 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5675 ed->data[0] = VCL_SESS_ATTR_TEST (session->attr,
5676 VCL_SESS_ATTR_TCP_KEEPINTVL);
5677 ed->data[1] = *buflen;
5685 case VPPCOM_ATTR_GET_TCP_USER_MSS:
5686 if (buffer && buflen && (*buflen >= sizeof (u32)))
5689 *(u32 *) buffer = session->user_mss;
5690 *buflen = sizeof (int);
5692 if (VPPCOM_DEBUG > 2)
5693 clib_warning ("VCL<%d>: VPPCOM_ATTR_GET_TCP_USER_MSS: %d, "
5694 "buflen %d, #VPP-TBD#", getpid (), *(int *) buffer,
5696 if (VPPCOM_DEBUG > 0)
5699 ELOG_TYPE_DECLARE (e) =
5701 .format = "VPPCOM_ATTR_GET_TCP_USER_MSS: %d buflen=%d",
5702 .format_args = "i4i4",
5709 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5710 ed->data[0] = *(int *) buffer;
5711 ed->data[1] = *buflen;
5719 case VPPCOM_ATTR_SET_TCP_USER_MSS:
5720 if (buffer && buflen && (*buflen == sizeof (u32)))
5723 session->user_mss = *(u32 *) buffer;
5725 if (VPPCOM_DEBUG > 2)
5726 clib_warning ("VCL<%d>: VPPCOM_ATTR_SET_TCP_USER_MSS: %u, "
5727 "buflen %d, #VPP-TBD#", getpid (),
5728 session->user_mss, *buflen);
5729 if (VPPCOM_DEBUG > 0)
5732 ELOG_TYPE_DECLARE (e) =
5734 .format = "VPPCOM_ATTR_SET_TCP_USER_MSS: %d buflen=%d",
5735 .format_args = "i4i4",
5742 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
5743 ed->data[0] = session->user_mss;
5744 ed->data[1] = *buflen;
5758 clib_spinlock_unlock (&vcm->sessions_lockp);
5763 vppcom_session_recvfrom (uint32_t session_index, void *buffer,
5764 uint32_t buflen, int flags, vppcom_endpt_t * ep)
5767 session_t *session = 0;
5771 clib_spinlock_lock (&vcm->sessions_lockp);
5772 rv = vppcom_session_at_index (session_index, &session);
5773 if (PREDICT_FALSE (rv))
5775 clib_spinlock_unlock (&vcm->sessions_lockp);
5776 if (VPPCOM_DEBUG > 0)
5777 clib_warning ("VCL<%d>: invalid session, "
5778 "sid (%u) has been closed!",
5779 getpid (), session_index);
5780 if (VPPCOM_DEBUG > 0)
5783 ELOG_TYPE_DECLARE (e) =
5785 .format = "invalid session: %d closed",
5786 .format_args = "i4",
5793 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
5794 ed->data = session_index;
5798 clib_spinlock_unlock (&vcm->sessions_lockp);
5801 ep->is_ip4 = session->peer_addr.is_ip4;
5802 ep->port = session->peer_port;
5803 if (session->peer_addr.is_ip4)
5804 clib_memcpy (ep->ip, &session->peer_addr.ip46.ip4,
5805 sizeof (ip4_address_t));
5807 clib_memcpy (ep->ip, &session->peer_addr.ip46.ip6,
5808 sizeof (ip6_address_t));
5809 clib_spinlock_unlock (&vcm->sessions_lockp);
5813 rv = vppcom_session_read (session_index, buffer, buflen);
5814 else if (flags & MSG_PEEK)
5815 rv = vppcom_session_peek (session_index, buffer, buflen);
5818 clib_warning ("VCL<%d>: Unsupport flags for recvfrom %d",
5820 rv = VPPCOM_EAFNOSUPPORT;
5828 vppcom_session_sendto (uint32_t session_index, void *buffer,
5829 uint32_t buflen, int flags, vppcom_endpt_t * ep)
5832 return VPPCOM_EINVAL;
5837 return VPPCOM_EINVAL;
5842 // TBD check the flags and do the right thing
5843 if (VPPCOM_DEBUG > 2)
5844 clib_warning ("VCL<%d>: handling flags 0x%u (%d) "
5845 "not implemented yet.", getpid (), flags, flags);
5848 return (vppcom_session_write (session_index, buffer, buflen));
5852 vppcom_poll (vcl_poll_t * vp, uint32_t n_sids, double wait_for_time)
5854 f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
5855 u32 i, keep_trying = 1;
5858 if (VPPCOM_DEBUG > 3)
5859 clib_warning ("VCL<%d>: vp %p, nsids %u, wait_for_time %f",
5860 getpid (), vp, n_sids, wait_for_time);
5863 return VPPCOM_EFAULT;
5869 for (i = 0; i < n_sids; i++)
5871 ASSERT (vp[i].revents);
5873 VCL_LOCK_AND_GET_SESSION (vp[i].sid, &session);
5874 clib_spinlock_unlock (&vcm->sessions_lockp);
5879 if (POLLIN & vp[i].events)
5881 VCL_LOCK_AND_GET_SESSION (vp[i].sid, &session);
5882 rv = vppcom_session_read_ready (session, vp[i].sid);
5883 clib_spinlock_unlock (&vcm->sessions_lockp);
5886 *vp[i].revents |= POLLIN;
5893 case VPPCOM_ECONNRESET:
5894 *vp[i].revents = POLLHUP;
5898 *vp[i].revents = POLLERR;
5905 if (POLLOUT & vp[i].events)
5907 VCL_LOCK_AND_GET_SESSION (vp[i].sid, &session);
5908 rv = vppcom_session_write_ready (session, vp[i].sid);
5909 clib_spinlock_unlock (&vcm->sessions_lockp);
5912 *vp[i].revents |= POLLOUT;
5919 case VPPCOM_ECONNRESET:
5920 *vp[i].revents = POLLHUP;
5924 *vp[i].revents = POLLERR;
5931 if (0) // Note "done:" label used by VCL_LOCK_AND_GET_SESSION()
5934 *vp[i].revents = POLLNVAL;
5938 if (wait_for_time != -1)
5939 keep_trying = (clib_time_now (&vcm->clib_time) <= timeout) ? 1 : 0;
5941 while ((num_ev == 0) && keep_trying);
5943 if (VPPCOM_DEBUG > 3)
5945 clib_warning ("VCL<%d>: returning %d", getpid (), num_ev);
5946 for (i = 0; i < n_sids; i++)
5948 clib_warning ("VCL<%d>: vp[%d].sid %d (0x%x), .events 0x%x, "
5949 ".revents 0x%x", getpid (), i, vp[i].sid, vp[i].sid,
5950 vp[i].events, *vp[i].revents);
5957 * fd.io coding-style-patch-verification: ON
5960 * eval: (c-set-style "gnu")