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 <vlib/unix/unix.h>
25 #include <vppinfra/vec_bootstrap.h>
26 #include <vppinfra/elog.h>
28 #define vl_typedefs /* define message structures */
29 #include <vpp/api/vpe_all_api_h.h>
32 /* declare message handlers for each api */
34 #define vl_endianfun /* define message structures */
35 #include <vpp/api/vpe_all_api_h.h>
38 /* instantiate all the print functions we know about */
39 #define vl_print(handle, ...)
41 #include <vpp/api/vpe_all_api_h.h>
45 /* Set VPPCOM_DEBUG_INIT 2 for connection debug,
46 * 3 for read/write debug output
48 * export VCL_DEBUG=<#> to set dynamically.
50 #define VPPCOM_DEBUG_INIT 1
52 #define VPPCOM_DEBUG_INIT 0
55 #define VPPCOM_DEBUG vcm->debug
58 * VPPCOM Private definitions and functions.
74 STATE_CLOSE_ON_EMPTY = 0x10,
75 STATE_DISCONNECT = 0x20,
79 #define SERVER_STATE_OPEN (STATE_ACCEPT|STATE_CLOSE_ON_EMPTY)
80 #define CLIENT_STATE_OPEN (STATE_CONNECT|STATE_CLOSE_ON_EMPTY)
82 typedef struct epoll_event vppcom_epoll_event_t;
89 vppcom_epoll_event_t ev;
90 #define VEP_DEFAULT_ET_MASK (EPOLLIN|EPOLLOUT)
91 #define VEP_UNSUPPORTED_EVENTS (EPOLLONESHOT|EPOLLEXCLUSIVE)
103 volatile session_state_t state;
105 svm_fifo_t *server_rx_fifo;
106 svm_fifo_t *server_tx_fifo;
111 svm_queue_t *vpp_event_queue;
113 /* Socket configuration state */
114 /* TBD: covert 'is_*' vars to bit in u8 flags; */
124 vppcom_ip46_t lcl_addr;
125 vppcom_ip46_t peer_addr;
126 u16 lcl_port; // network order
127 u16 peer_port; // network order
129 u64 client_queue_address;
131 elog_track_t elog_track;
134 typedef struct vppcom_cfg_t_
137 u32 vpp_api_q_length;
140 u32 add_segment_size;
141 u32 preallocated_fifo_pairs;
144 u32 event_queue_size;
145 u32 listen_queue_size;
146 u8 app_proxy_transport_tcp;
147 u8 app_proxy_transport_udp;
151 u64 namespace_secret;
156 char *event_log_path;
159 typedef struct vppcom_main_t_
163 u32 *client_session_index_fifo;
166 /* vpe input queue */
167 svm_queue_t *vl_input_queue;
169 /* API client handle */
173 clib_spinlock_t sessions_lockp;
176 /* Hash table for disconnect processing */
177 uword *session_index_by_vpp_handles;
180 clib_bitmap_t *rd_bitmap;
181 clib_bitmap_t *wr_bitmap;
182 clib_bitmap_t *ex_bitmap;
184 /* Our event queue */
185 svm_queue_t *app_event_queue;
187 /* unique segment name counter */
188 u32 unique_segment_index;
190 /* For deadman timers */
191 clib_time_t clib_time;
193 /* State of the connection, shared between msg RX thread and main thread */
194 volatile app_state_t app_state;
199 elog_main_t elog_main;
200 elog_track_t elog_track;
202 /* VNET_API_ERROR_FOO -> "Foo" hash table */
203 uword *error_string_by_error_number;
206 /* NOTE: _vppcom_main is only used until the heap is allocated.
207 * Do not access it directly -- use vcm which will point to
208 * the heap allocated copy after init.
210 static vppcom_main_t _vppcom_main = {
211 .debug = VPPCOM_DEBUG_INIT,
212 .my_client_index = ~0
215 static vppcom_main_t *vcm = &_vppcom_main;
217 #define VCL_LOCK_AND_GET_SESSION(I, S) \
219 clib_spinlock_lock (&vcm->sessions_lockp); \
220 rv = vppcom_session_at_index (I, S); \
221 if (PREDICT_FALSE (rv)) \
223 clib_spinlock_unlock (&vcm->sessions_lockp); \
224 clib_warning ("[%s] ERROR: Invalid ##I (%u)!", \
231 vppcom_app_state_str (app_state_t state)
237 case STATE_APP_START:
238 st = "STATE_APP_START";
241 case STATE_APP_CONN_VPP:
242 st = "STATE_APP_CONN_VPP";
245 case STATE_APP_ENABLED:
246 st = "STATE_APP_ENABLED";
249 case STATE_APP_ATTACHED:
250 st = "STATE_APP_ATTACHED";
254 st = "UNKNOWN_APP_STATE";
262 vppcom_session_state_str (session_state_t state)
273 st = "STATE_CONNECT";
284 case STATE_CLOSE_ON_EMPTY:
285 st = "STATE_CLOSE_ON_EMPTY";
288 case STATE_DISCONNECT:
289 st = "STATE_DISCONNECT";
297 st = "UNKNOWN_STATE";
305 * VPPCOM Utility Functions
308 vppcom_session_at_index (u32 session_index, session_t * volatile *sess)
310 /* Assumes that caller has acquired spinlock: vcm->sessions_lockp */
311 if (PREDICT_FALSE ((session_index == ~0) ||
312 pool_is_free_index (vcm->sessions, session_index)))
314 clib_warning ("[%d] invalid session, sid (%u) has been closed!",
315 getpid (), session_index);
316 return VPPCOM_EBADFD;
318 *sess = pool_elt_at_index (vcm->sessions, session_index);
323 vppcom_session_table_add_listener (u64 listener_handle, u32 value)
325 /* Session and listener handles have different formats. The latter has
326 * the thread index in the upper 32 bits while the former has the session
327 * type. Knowing that, for listeners we just flip the MSB to 1 */
328 listener_handle |= 1ULL << 63;
329 hash_set (vcm->session_index_by_vpp_handles, listener_handle, value);
332 static inline session_t *
333 vppcom_session_table_lookup_listener (u64 listener_handle)
336 u64 handle = listener_handle | (1ULL << 63);
339 p = hash_get (vcm->session_index_by_vpp_handles, handle);
342 clib_warning ("[%d] couldn't find listen session: unknown vpp "
343 "listener handle %llx", getpid (), listener_handle);
346 if (pool_is_free_index (vcm->sessions, p[0]))
348 if (VPPCOM_DEBUG > 1)
349 clib_warning ("[%d] invalid listen session, sid (%u)", getpid (),
354 session = pool_elt_at_index (vcm->sessions, p[0]);
355 ASSERT (session->is_listen);
360 vppcom_session_table_del_listener (u64 listener_handle)
362 listener_handle |= 1ULL << 63;
363 hash_unset (vcm->session_index_by_vpp_handles, listener_handle);
369 elog_main_t *em = &vcm->elog_main;
371 clib_error_t *error = 0;
374 (char *) format (0, "%s/%d-%d-vcl-elog%c", vcm->cfg.event_log_path,
375 vcm->my_client_index, getpid (), 0);
376 error = elog_write_file (em, chroot_file, 1 /* flush ring */ );
379 clib_error_report (error);
381 if (VPPCOM_DEBUG > 0)
382 clib_warning ("[%d] Event Log:'%s' ", getpid (), chroot_file);
387 vppcom_connect_to_vpp (char *app_name)
389 api_main_t *am = &api_main;
392 if (VPPCOM_DEBUG > 0)
393 printf ("\nConnecting to VPP api...");
394 if (vl_client_connect_to_vlib ("/vpe-api", app_name,
395 vcm->cfg.vpp_api_q_length) < 0)
397 clib_warning ("[%d] connect to vpp (%s) failed!", getpid (), app_name);
398 rv = VPPCOM_ECONNREFUSED;
403 vcm->vl_input_queue = am->shmem_hdr->vl_input_queue;
404 vcm->my_client_index = am->my_client_index;
405 vcm->app_state = STATE_APP_CONN_VPP;
407 if (VPPCOM_DEBUG > 0)
408 printf (" connected!\n");
411 if (VPPCOM_DEBUG > 0)
413 vcm->elog_main.lock =
414 clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
415 vcm->elog_main.lock[0] = 0;
416 vcm->elog_main.event_ring_size = vcm->cfg.event_ring_size;
417 elog_init (&vcm->elog_main, vcm->elog_main.event_ring_size);
418 elog_enable_disable (&vcm->elog_main, 1);
420 vcm->elog_track.name =
421 (char *) format (0, "P:%d:C:%d%c", getpid (),
422 vcm->my_client_index, 0);
423 elog_track_register (&vcm->elog_main, &vcm->elog_track);
426 ELOG_TYPE_DECLARE (e) =
428 .format = "connect_vpp:rv:%d",
435 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
444 format_api_error (u8 * s, va_list * args)
446 i32 error = va_arg (*args, u32);
449 p = hash_get (vcm->error_string_by_error_number, -error);
452 s = format (s, "%s (%d)", p[0], error);
454 s = format (s, "%d", error);
459 vppcom_init_error_string_table (void)
461 vcm->error_string_by_error_number = hash_create (0, sizeof (uword));
463 #define _(n,v,s) hash_set (vcm->error_string_by_error_number, -v, s);
464 foreach_vnet_api_error;
467 hash_set (vcm->error_string_by_error_number, 99, "Misc");
471 vppcom_wait_for_app_state_change (app_state_t app_state)
473 f64 timeout = clib_time_now (&vcm->clib_time) + vcm->cfg.app_timeout;
475 while (clib_time_now (&vcm->clib_time) < timeout)
477 if (vcm->app_state == app_state)
480 if (VPPCOM_DEBUG > 0)
481 clib_warning ("[%d] timeout waiting for state %s (%d)", getpid (),
482 vppcom_app_state_str (app_state), app_state);
484 if (VPPCOM_DEBUG > 0)
487 ELOG_TYPE_DECLARE (e) =
489 .format = "ERR: timeout state:%d",
497 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
499 ed->data = app_state;
503 return VPPCOM_ETIMEDOUT;
507 vppcom_wait_for_session_state_change (u32 session_index,
508 session_state_t state,
511 f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
512 session_t *volatile session;
517 clib_spinlock_lock (&vcm->sessions_lockp);
518 rv = vppcom_session_at_index (session_index, &session);
519 if (PREDICT_FALSE (rv))
521 clib_spinlock_unlock (&vcm->sessions_lockp);
524 if (session->state == state)
526 clib_spinlock_unlock (&vcm->sessions_lockp);
529 if (session->state == STATE_FAILED)
531 clib_spinlock_unlock (&vcm->sessions_lockp);
532 return VPPCOM_ECONNREFUSED;
535 clib_spinlock_unlock (&vcm->sessions_lockp);
537 while (clib_time_now (&vcm->clib_time) < timeout);
539 if (VPPCOM_DEBUG > 0)
540 clib_warning ("[%d] timeout waiting for state 0x%x (%s)", getpid (),
541 state, vppcom_session_state_str (state));
543 if (VPPCOM_DEBUG > 0)
546 ELOG_TYPE_DECLARE (e) =
548 .format = "ERR: timeout state:%d",
556 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
562 return VPPCOM_ETIMEDOUT;
566 vppcom_wait_for_client_session_index (f64 wait_for_time)
568 f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
572 if (clib_fifo_elts (vcm->client_session_index_fifo))
575 while (clib_time_now (&vcm->clib_time) < timeout);
577 if (wait_for_time == 0)
578 return VPPCOM_EAGAIN;
580 if (VPPCOM_DEBUG > 0)
581 clib_warning ("[%d] timeout waiting for client_session_index", getpid ());
583 if (VPPCOM_DEBUG > 0)
586 ELOG_TYPE_DECLARE (e) =
588 .format = "ERR: timeout waiting for session index :%d",
596 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
602 return VPPCOM_ETIMEDOUT;
606 * VPP-API message functions
609 vppcom_send_session_enable_disable (u8 is_enable)
611 vl_api_session_enable_disable_t *bmp;
612 bmp = vl_msg_api_alloc (sizeof (*bmp));
613 memset (bmp, 0, sizeof (*bmp));
615 bmp->_vl_msg_id = ntohs (VL_API_SESSION_ENABLE_DISABLE);
616 bmp->client_index = vcm->my_client_index;
617 bmp->context = htonl (0xfeedface);
618 bmp->is_enable = is_enable;
619 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
623 vppcom_app_session_enable (void)
627 if (vcm->app_state != STATE_APP_ENABLED)
629 vppcom_send_session_enable_disable (1 /* is_enabled == TRUE */ );
630 rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED);
631 if (PREDICT_FALSE (rv))
633 if (VPPCOM_DEBUG > 0)
634 clib_warning ("[%d] application session enable timed out! "
636 getpid (), rv, vppcom_retval_str (rv));
644 vl_api_session_enable_disable_reply_t_handler
645 (vl_api_session_enable_disable_reply_t * mp)
649 clib_warning ("[%d] session_enable_disable failed: %U", getpid (),
650 format_api_error, ntohl (mp->retval));
653 vcm->app_state = STATE_APP_ENABLED;
657 vppcom_app_send_attach (void)
659 vl_api_application_attach_t *bmp;
660 u8 nsid_len = vec_len (vcm->cfg.namespace_id);
661 u8 app_is_proxy = (vcm->cfg.app_proxy_transport_tcp ||
662 vcm->cfg.app_proxy_transport_udp);
664 bmp = vl_msg_api_alloc (sizeof (*bmp));
665 memset (bmp, 0, sizeof (*bmp));
667 bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_ATTACH);
668 bmp->client_index = vcm->my_client_index;
669 bmp->context = htonl (0xfeedface);
670 bmp->options[APP_OPTIONS_FLAGS] =
671 APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT |
672 (vcm->cfg.app_scope_local ? APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE : 0) |
673 (vcm->cfg.app_scope_global ? APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE : 0) |
674 (app_is_proxy ? APP_OPTIONS_FLAGS_IS_PROXY : 0);
675 bmp->options[APP_OPTIONS_PROXY_TRANSPORT] =
676 (vcm->cfg.app_proxy_transport_tcp ? 1 << TRANSPORT_PROTO_TCP : 0) |
677 (vcm->cfg.app_proxy_transport_udp ? 1 << TRANSPORT_PROTO_UDP : 0);
678 bmp->options[APP_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size;
679 bmp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size;
680 bmp->options[APP_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size;
681 bmp->options[APP_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size;
682 bmp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
683 vcm->cfg.preallocated_fifo_pairs;
684 bmp->options[APP_OPTIONS_EVT_QUEUE_SIZE] = vcm->cfg.event_queue_size;
687 bmp->namespace_id_len = nsid_len;
688 clib_memcpy (bmp->namespace_id, vcm->cfg.namespace_id, nsid_len);
689 bmp->options[APP_OPTIONS_NAMESPACE_SECRET] = vcm->cfg.namespace_secret;
691 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
695 vppcom_app_attach (void)
699 vppcom_app_send_attach ();
700 rv = vppcom_wait_for_app_state_change (STATE_APP_ATTACHED);
701 if (PREDICT_FALSE (rv))
703 if (VPPCOM_DEBUG > 0)
704 clib_warning ("[%d] application attach timed out! returning %d (%s)",
705 getpid (), rv, vppcom_retval_str (rv));
712 vppcom_app_detach (void)
714 vl_api_application_detach_t *bmp;
715 bmp = vl_msg_api_alloc (sizeof (*bmp));
716 memset (bmp, 0, sizeof (*bmp));
718 bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH);
719 bmp->client_index = vcm->my_client_index;
720 bmp->context = htonl (0xfeedface);
721 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
725 vl_api_application_attach_reply_t_handler (vl_api_application_attach_reply_t *
728 static svm_fifo_segment_create_args_t _a;
729 svm_fifo_segment_create_args_t *a = &_a;
732 memset (a, 0, sizeof (*a));
735 clib_warning ("[%d] attach failed: %U", getpid (),
736 format_api_error, ntohl (mp->retval));
740 if (mp->segment_name_length == 0)
742 clib_warning ("[%d] segment_name_length zero", getpid ());
746 a->segment_name = (char *) mp->segment_name;
747 a->segment_size = mp->segment_size;
749 ASSERT (mp->app_event_queue_address);
751 /* Attach to the segment vpp created */
752 rv = svm_fifo_segment_attach (a);
753 vec_reset_length (a->new_segment_indices);
754 if (PREDICT_FALSE (rv))
756 clib_warning ("[%d] svm_fifo_segment_attach ('%s') failed", getpid (),
761 vcm->app_event_queue =
762 uword_to_pointer (mp->app_event_queue_address, svm_queue_t *);
764 vcm->app_state = STATE_APP_ATTACHED;
768 vl_api_application_detach_reply_t_handler (vl_api_application_detach_reply_t *
772 clib_warning ("[%d] detach failed: %U", getpid (), format_api_error,
775 vcm->app_state = STATE_APP_ENABLED;
779 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
783 clib_warning ("[%d] vpp handle 0x%llx: disconnect session failed: %U",
784 getpid (), mp->handle, format_api_error,
789 vl_api_map_another_segment_t_handler (vl_api_map_another_segment_t * mp)
791 static svm_fifo_segment_create_args_t _a;
792 svm_fifo_segment_create_args_t *a = &_a;
795 memset (a, 0, sizeof (*a));
796 a->segment_name = (char *) mp->segment_name;
797 a->segment_size = mp->segment_size;
798 /* Attach to the segment vpp created */
799 rv = svm_fifo_segment_attach (a);
800 vec_reset_length (a->new_segment_indices);
801 if (PREDICT_FALSE (rv))
803 clib_warning ("[%d] svm_fifo_segment_attach ('%s') failed",
804 getpid (), mp->segment_name);
807 if (VPPCOM_DEBUG > 1)
808 clib_warning ("[%d] mapped new segment '%s' size %d", getpid (),
809 mp->segment_name, mp->segment_size);
813 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
817 p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
821 session_t *session = 0;
822 u32 session_index = p[0];
824 VCL_LOCK_AND_GET_SESSION (session_index, &session);
825 session->state = STATE_CLOSE_ON_EMPTY;
827 if (VPPCOM_DEBUG > 1)
828 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
829 "setting state to 0x%x (%s)",
830 getpid (), mp->handle, session_index, session->state,
831 vppcom_session_state_str (session->state));
832 clib_spinlock_unlock (&vcm->sessions_lockp);
836 if (VPPCOM_DEBUG > 1)
837 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
838 "session lookup failed!",
839 getpid (), mp->handle, session_index);
842 clib_warning ("[%d] vpp handle 0x%llx: session lookup by "
843 "handle failed!", getpid (), mp->handle);
847 vl_api_reset_session_t_handler (vl_api_reset_session_t * mp)
849 session_t *session = 0;
850 vl_api_reset_session_reply_t *rmp;
854 p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
858 clib_spinlock_lock (&vcm->sessions_lockp);
859 rval = vppcom_session_at_index (p[0], &session);
860 if (PREDICT_FALSE (rval))
862 rv = VNET_API_ERROR_INVALID_VALUE_2;
863 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
864 "session lookup failed! returning %d %U",
865 getpid (), mp->handle, p[0],
866 rv, format_api_error, rv);
870 /* TBD: should this disconnect immediately and
873 session->state = STATE_CLOSE_ON_EMPTY;
875 if (VPPCOM_DEBUG > 1)
876 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
877 "state set to %d (%s)!", getpid (),
878 mp->handle, p[0], session->state,
879 vppcom_session_state_str (session->state));
881 clib_spinlock_unlock (&vcm->sessions_lockp);
885 rv = VNET_API_ERROR_INVALID_VALUE;
886 clib_warning ("[%d] ERROR: vpp handle 0x%llx: session lookup "
887 "failed! returning %d %U",
888 getpid (), mp->handle, rv, format_api_error, rv);
891 rmp = vl_msg_api_alloc (sizeof (*rmp));
892 memset (rmp, 0, sizeof (*rmp));
893 rmp->_vl_msg_id = ntohs (VL_API_RESET_SESSION_REPLY);
894 rmp->retval = htonl (rv);
895 rmp->handle = mp->handle;
896 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
900 vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp)
902 session_t *session = 0;
904 svm_fifo_t *rx_fifo, *tx_fifo;
908 session_index = mp->context;
909 VCL_LOCK_AND_GET_SESSION (session_index, &session);
913 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
914 "connect failed! %U",
915 getpid (), mp->handle, session_index,
916 format_api_error, ntohl (mp->retval));
919 session->state = STATE_FAILED;
920 session->vpp_handle = mp->handle;
924 clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
925 "Invalid session index (%u)!",
926 getpid (), mp->handle, session_index);
934 /* We've been redirected */
935 if (mp->segment_name_length > 0)
937 static svm_fifo_segment_create_args_t _a;
938 svm_fifo_segment_create_args_t *a = &_a;
941 memset (a, 0, sizeof (*a));
942 a->segment_name = (char *) mp->segment_name;
943 if (VPPCOM_DEBUG > 1)
944 clib_warning ("[%d] cut-thru segment: %s\n",
945 getpid (), a->segment_name);
947 rv = svm_fifo_segment_attach (a);
948 vec_reset_length (a->new_segment_indices);
949 if (PREDICT_FALSE (rv))
951 clib_warning ("[%d] sm_fifo_segment_attach ('%s') failed",
952 getpid (), a->segment_name);
960 session->is_cut_thru = is_cut_thru;
961 session->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
964 rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
965 rx_fifo->client_session_index = session_index;
966 tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
967 tx_fifo->client_session_index = session_index;
969 session->server_rx_fifo = rx_fifo;
970 session->server_tx_fifo = tx_fifo;
971 session->vpp_handle = mp->handle;
972 session->lcl_addr.is_ip4 = mp->is_ip4;
973 clib_memcpy (&session->lcl_addr.ip46, mp->lcl_ip,
974 sizeof (session->peer_addr.ip46));
975 session->lcl_port = mp->lcl_port;
976 session->state = STATE_CONNECT;
978 /* Add it to lookup table */
979 hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
981 if (VPPCOM_DEBUG > 1)
982 clib_warning ("[%d] vpp handle 0x%llx, sid %u: connect succeeded!"
983 " session_rx_fifo %p, refcnt %d,"
984 " session_tx_fifo %p, refcnt %d",
985 getpid (), mp->handle, session_index,
986 session->server_rx_fifo,
987 session->server_rx_fifo->refcnt,
988 session->server_tx_fifo, session->server_tx_fifo->refcnt);
990 clib_spinlock_unlock (&vcm->sessions_lockp);
994 vppcom_send_connect_sock (session_t * session, u32 session_index)
996 vl_api_connect_sock_t *cmp;
998 /* Assumes caller as acquired the spinlock: vcm->sessions_lockp */
999 session->is_server = 0;
1000 cmp = vl_msg_api_alloc (sizeof (*cmp));
1001 memset (cmp, 0, sizeof (*cmp));
1002 cmp->_vl_msg_id = ntohs (VL_API_CONNECT_SOCK);
1003 cmp->client_index = vcm->my_client_index;
1004 cmp->context = session_index;
1006 cmp->vrf = session->vrf;
1007 cmp->is_ip4 = session->peer_addr.is_ip4;
1008 clib_memcpy (cmp->ip, &session->peer_addr.ip46, sizeof (cmp->ip));
1009 cmp->port = session->peer_port;
1010 cmp->proto = session->proto;
1011 clib_memcpy (cmp->options, session->options, sizeof (cmp->options));
1012 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & cmp);
1016 vppcom_send_disconnect_session_reply (u64 vpp_handle, u32 session_index,
1019 vl_api_disconnect_session_reply_t *rmp;
1021 if (VPPCOM_DEBUG > 1)
1022 clib_warning ("[%d] vpp handle 0x%llx, sid %u: sending disconnect msg",
1023 getpid (), vpp_handle, session_index);
1025 rmp = vl_msg_api_alloc (sizeof (*rmp));
1026 memset (rmp, 0, sizeof (*rmp));
1028 rmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION_REPLY);
1029 rmp->retval = htonl (rv);
1030 rmp->handle = vpp_handle;
1031 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
1035 vppcom_send_disconnect_session (u64 vpp_handle, u32 session_index)
1037 vl_api_disconnect_session_t *dmp;
1039 if (VPPCOM_DEBUG > 1)
1040 clib_warning ("[%d] vpp handle 0x%llx, sid %u: sending disconnect msg",
1041 getpid (), vpp_handle, session_index);
1043 dmp = vl_msg_api_alloc (sizeof (*dmp));
1044 memset (dmp, 0, sizeof (*dmp));
1045 dmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION);
1046 dmp->client_index = vcm->my_client_index;
1047 dmp->handle = vpp_handle;
1048 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & dmp);
1052 vl_api_bind_sock_reply_t_handler (vl_api_bind_sock_reply_t * mp)
1054 session_t *session = 0;
1055 u32 session_index = mp->context;
1058 VCL_LOCK_AND_GET_SESSION (session_index, &session);
1062 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: bind failed: %U",
1063 getpid (), mp->handle, session_index, format_api_error,
1064 ntohl (mp->retval));
1065 rv = vppcom_session_at_index (session_index, &session);
1066 if (rv == VPPCOM_OK)
1068 session->state = STATE_FAILED;
1069 session->vpp_handle = mp->handle;
1073 clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
1074 "Invalid session index (%u)!",
1075 getpid (), mp->handle, session_index);
1080 session->vpp_handle = mp->handle;
1081 session->lcl_addr.is_ip4 = mp->lcl_is_ip4;
1082 clib_memcpy (&session->lcl_addr.ip46, mp->lcl_ip,
1083 sizeof (session->peer_addr.ip46));
1084 session->lcl_port = mp->lcl_port;
1085 vppcom_session_table_add_listener (mp->handle, session_index);
1086 session->is_listen = 1;
1087 session->state = STATE_LISTEN;
1089 if (VPPCOM_DEBUG > 1)
1090 clib_warning ("[%d] vpp handle 0x%llx, sid %u: bind succeeded!",
1091 getpid (), mp->handle, mp->context);
1093 clib_spinlock_unlock (&vcm->sessions_lockp);
1097 vl_api_unbind_sock_reply_t_handler (vl_api_unbind_sock_reply_t * mp)
1100 clib_warning ("[%d] ERROR: sid %u: unbind failed: %U",
1101 getpid (), mp->context, format_api_error,
1102 ntohl (mp->retval));
1104 else if (VPPCOM_DEBUG > 1)
1105 clib_warning ("[%d] sid %u: unbind succeeded!", getpid (), mp->context);
1109 format_ip4_address (u8 * s, va_list * args)
1111 u8 *a = va_arg (*args, u8 *);
1112 return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
1116 format_ip6_address (u8 * s, va_list * args)
1118 ip6_address_t *a = va_arg (*args, ip6_address_t *);
1119 u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon;
1121 i_max_n_zero = ARRAY_LEN (a->as_u16);
1123 i_first_zero = i_max_n_zero;
1125 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1127 u32 is_zero = a->as_u16[i] == 0;
1128 if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16))
1134 if ((!is_zero && n_zeros > max_n_zeros)
1135 || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros))
1137 i_max_n_zero = i_first_zero;
1138 max_n_zeros = n_zeros;
1139 i_first_zero = ARRAY_LEN (a->as_u16);
1144 last_double_colon = 0;
1145 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1147 if (i == i_max_n_zero && max_n_zeros > 1)
1149 s = format (s, "::");
1150 i += max_n_zeros - 1;
1151 last_double_colon = 1;
1155 s = format (s, "%s%x",
1156 (last_double_colon || i == 0) ? "" : ":",
1157 clib_net_to_host_u16 (a->as_u16[i]));
1158 last_double_colon = 0;
1165 /* Format an IP46 address. */
1167 format_ip46_address (u8 * s, va_list * args)
1169 ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
1170 ip46_type_t type = va_arg (*args, ip46_type_t);
1176 is_ip4 = ip46_address_is_ip4 (ip46);
1187 format (s, "%U", format_ip4_address, &ip46->ip4) :
1188 format (s, "%U", format_ip6_address, &ip46->ip6);
1192 vppcom_send_accept_session_reply (u64 handle, u32 context, int retval)
1194 vl_api_accept_session_reply_t *rmp;
1196 rmp = vl_msg_api_alloc (sizeof (*rmp));
1197 memset (rmp, 0, sizeof (*rmp));
1198 rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY);
1199 rmp->retval = htonl (retval);
1200 rmp->context = context;
1201 rmp->handle = handle;
1202 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
1206 vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
1208 svm_fifo_t *rx_fifo, *tx_fifo;
1209 session_t *session, *listen_session;
1212 clib_spinlock_lock (&vcm->sessions_lockp);
1213 if (!clib_fifo_free_elts (vcm->client_session_index_fifo))
1215 clib_warning ("[%d] client session queue is full!", getpid ());
1216 vppcom_send_accept_session_reply (mp->handle, mp->context,
1217 VNET_API_ERROR_QUEUE_FULL);
1218 clib_spinlock_unlock (&vcm->sessions_lockp);
1222 listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
1223 if (!listen_session)
1225 clib_warning ("[%d] ERROR: couldn't find listen session: unknown vpp "
1226 "listener handle %llx", getpid (), mp->listener_handle);
1227 clib_spinlock_unlock (&vcm->sessions_lockp);
1231 /* Allocate local session and set it up */
1232 pool_get (vcm->sessions, session);
1233 memset (session, 0, sizeof (*session));
1234 session_index = session - vcm->sessions;
1236 rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
1237 rx_fifo->client_session_index = session_index;
1238 tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
1239 tx_fifo->client_session_index = session_index;
1241 session->vpp_handle = mp->handle;
1242 session->client_context = mp->context;
1243 session->server_rx_fifo = rx_fifo;
1244 session->server_tx_fifo = tx_fifo;
1245 session->vpp_event_queue = uword_to_pointer (mp->vpp_event_queue_address,
1247 session->state = STATE_ACCEPT;
1248 session->is_cut_thru = 0;
1249 session->is_server = 1;
1250 session->peer_port = mp->port;
1251 session->peer_addr.is_ip4 = mp->is_ip4;
1252 clib_memcpy (&session->peer_addr.ip46, mp->ip,
1253 sizeof (session->peer_addr.ip46));
1255 /* Add it to lookup table */
1256 hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
1257 session->lcl_port = listen_session->lcl_port;
1258 session->lcl_addr = listen_session->lcl_addr;
1260 /* TBD: move client_session_index_fifo into listener session */
1261 clib_fifo_add1 (vcm->client_session_index_fifo, session_index);
1263 clib_spinlock_unlock (&vcm->sessions_lockp);
1265 if (VPPCOM_DEBUG > 1)
1266 clib_warning ("[%d] vpp handle 0x%llx, sid %u: client accept "
1267 "request from %s address %U port %d queue %p!", getpid (),
1268 mp->handle, session_index, mp->is_ip4 ? "IPv4" : "IPv6",
1269 format_ip46_address, &mp->ip, mp->is_ip4,
1270 clib_net_to_host_u16 (mp->port), session->vpp_event_queue);
1272 if (VPPCOM_DEBUG > 0)
1274 session->elog_track.name =
1275 (char *) format (0, "C:%d:S:%d%c", vcm->my_client_index,
1277 elog_track_register (&vcm->elog_main, &session->elog_track);
1279 if (session->peer_addr.is_ip4)
1282 ELOG_TYPE_DECLARE (e) =
1285 "client_accept:handle:%x addr:%d.%d.%d.%d:%d",
1286 .format_args = "i8i1i1i1i1i2",
1289 CLIB_PACKED (struct {
1295 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
1297 ed->handle = mp->handle;
1298 ed->addr[0] = session->peer_addr.ip46.ip4.as_u8[0];
1299 ed->addr[1] = session->peer_addr.ip46.ip4.as_u8[1];
1300 ed->addr[2] = session->peer_addr.ip46.ip4.as_u8[2];
1301 ed->addr[3] = session->peer_addr.ip46.ip4.as_u8[3];
1302 ed->port = session->peer_port;
1307 clib_warning ("ip6");
1314 vppcom_send_connect_session_reply (session_t * session, u32 session_index,
1315 u64 vpp_handle, u32 context, int retval)
1317 vl_api_connect_session_reply_t *rmp;
1319 svm_queue_t *client_q;
1321 rmp = vl_msg_api_alloc (sizeof (*rmp));
1322 memset (rmp, 0, sizeof (*rmp));
1323 rmp->_vl_msg_id = ntohs (VL_API_CONNECT_SESSION_REPLY);
1327 rmp->context = context;
1328 rmp->handle = vpp_handle;
1329 rmp->retval = htonl (retval);
1330 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
1334 rmp->context = session->client_context;
1335 rmp->retval = htonl (retval);
1336 rmp->handle = session->vpp_handle;
1337 rmp->server_rx_fifo = pointer_to_uword (session->server_rx_fifo);
1338 rmp->server_tx_fifo = pointer_to_uword (session->server_tx_fifo);
1339 rmp->vpp_event_queue_address = pointer_to_uword (session->vpp_event_queue);
1340 rmp->segment_size = vcm->cfg.segment_size;
1341 len = vec_len (session->segment_name);
1342 rmp->segment_name_length = clib_min (len, sizeof (rmp->segment_name));
1343 clib_memcpy (rmp->segment_name, session->segment_name,
1344 rmp->segment_name_length - 1);
1345 clib_memcpy (rmp->lcl_ip, session->peer_addr.ip46.as_u8,
1346 sizeof (rmp->lcl_ip));
1347 rmp->is_ip4 = session->peer_addr.is_ip4;
1348 rmp->lcl_port = session->peer_port;
1349 client_q = uword_to_pointer (session->client_queue_address, svm_queue_t *);
1351 vl_msg_api_send_shmem (client_q, (u8 *) & rmp);
1355 * Acting as server for redirected connect requests
1358 vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
1361 session_t *session = 0;
1363 clib_spinlock_lock (&vcm->sessions_lockp);
1364 if (!clib_fifo_free_elts (vcm->client_session_index_fifo))
1366 clib_spinlock_unlock (&vcm->sessions_lockp);
1368 if (VPPCOM_DEBUG > 1)
1369 clib_warning ("[%d] client session queue is full!", getpid ());
1371 /* TBD: Fix api to include vpp handle */
1372 vppcom_send_connect_session_reply (0 /* session */ , 0 /* sid */ ,
1373 0 /* handle */ , mp->context,
1374 VNET_API_ERROR_QUEUE_FULL);
1378 pool_get (vcm->sessions, session);
1379 memset (session, 0, sizeof (*session));
1380 session_index = session - vcm->sessions;
1382 session->client_context = mp->context;
1383 session->vpp_handle = session_index;
1384 session->client_queue_address = mp->client_queue_address;
1385 session->is_cut_thru = 1;
1386 session->is_server = 1;
1387 session->lcl_port = mp->port;
1388 session->lcl_addr.is_ip4 = mp->is_ip4;
1389 clib_memcpy (&session->lcl_addr.ip46, mp->ip,
1390 sizeof (session->lcl_addr.ip46));
1392 /* TBD: missing peer info in api msg.
1394 session->peer_addr.is_ip4 = mp->is_ip4;
1395 ASSERT (session->lcl_addr.is_ip4 == session->peer_addr.is_ip4);
1397 session->state = STATE_ACCEPT;
1398 clib_fifo_add1 (vcm->client_session_index_fifo, session_index);
1399 if (VPPCOM_DEBUG > 1)
1400 clib_warning ("[%d] sid %u: Got a cut-thru connect request! "
1401 "clib_fifo_elts %u!\n", getpid (), session_index,
1402 clib_fifo_elts (vcm->client_session_index_fifo));
1404 if (VPPCOM_DEBUG > 0)
1406 session->elog_track.name =
1407 (char *) format (0, "C:%d:S:%d%c", vcm->my_client_index,
1409 elog_track_register (&vcm->elog_main, &session->elog_track);
1412 ELOG_TYPE_DECLARE (e) =
1414 .format = "cut-thru-connect:S:%d clib_fifo_elts:%d",
1415 .format_args = "i4i4",
1423 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
1425 ed->data[0] = session_index;
1426 ed->data[1] = clib_fifo_elts (vcm->client_session_index_fifo);
1430 clib_spinlock_unlock (&vcm->sessions_lockp);
1434 vppcom_send_bind_sock (session_t * session, u32 session_index)
1436 vl_api_bind_sock_t *bmp;
1438 /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
1439 session->is_server = 1;
1440 bmp = vl_msg_api_alloc (sizeof (*bmp));
1441 memset (bmp, 0, sizeof (*bmp));
1443 bmp->_vl_msg_id = ntohs (VL_API_BIND_SOCK);
1444 bmp->client_index = vcm->my_client_index;
1445 bmp->context = session_index;
1446 bmp->vrf = session->vrf;
1447 bmp->is_ip4 = session->lcl_addr.is_ip4;
1448 clib_memcpy (bmp->ip, &session->lcl_addr.ip46, sizeof (bmp->ip));
1449 bmp->port = session->lcl_port;
1450 bmp->proto = session->proto;
1451 clib_memcpy (bmp->options, session->options, sizeof (bmp->options));
1452 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
1456 vppcom_send_unbind_sock (u64 vpp_handle)
1458 vl_api_unbind_sock_t *ump;
1460 ump = vl_msg_api_alloc (sizeof (*ump));
1461 memset (ump, 0, sizeof (*ump));
1463 ump->_vl_msg_id = ntohs (VL_API_UNBIND_SOCK);
1464 ump->client_index = vcm->my_client_index;
1465 ump->handle = vpp_handle;
1466 vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & ump);
1470 vppcom_session_unbind (u32 session_index)
1472 session_t *session = 0;
1476 VCL_LOCK_AND_GET_SESSION (session_index, &session);
1478 vpp_handle = session->vpp_handle;
1479 vppcom_session_table_del_listener (vpp_handle);
1480 session->vpp_handle = ~0;
1481 session->state = STATE_DISCONNECT;
1483 clib_spinlock_unlock (&vcm->sessions_lockp);
1485 if (VPPCOM_DEBUG > 1)
1486 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
1487 "sending unbind msg! new state 0x%x (%s)",
1488 getpid (), vpp_handle, session_index,
1489 session->state, vppcom_session_state_str (session->state));
1491 if (VPPCOM_DEBUG > 0)
1494 ELOG_TYPE_DECLARE (e) =
1496 .format = "unbind: handle:%x",
1497 .format_args = "i8",
1505 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
1506 ed->handle = vpp_handle;
1509 vppcom_send_unbind_sock (vpp_handle);
1516 vppcom_session_disconnect (u32 session_index)
1520 u8 is_cut_thru, is_listen, is_server;
1522 session_state_t state;
1524 VCL_LOCK_AND_GET_SESSION (session_index, &session);
1526 vpp_handle = session->vpp_handle;
1527 is_server = session->is_server;
1528 is_listen = session->is_listen;
1529 is_cut_thru = session->is_cut_thru;
1530 state = session->state;
1531 clib_spinlock_unlock (&vcm->sessions_lockp);
1533 if (VPPCOM_DEBUG > 1)
1535 clib_warning ("[%d] vpp handle 0x%llx, sid %u: %s state 0x%x (%s), "
1536 "is_cut_thru %d, is_listen %d",
1537 getpid (), vpp_handle, session_index,
1538 is_server ? "server" : "client",
1539 state, vppcom_session_state_str (state),
1540 is_cut_thru, is_listen);
1543 if (PREDICT_FALSE (is_listen))
1545 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
1546 "Cannot disconnect a listen socket!",
1547 getpid (), vpp_handle, session_index);
1552 /* Through the VPP host stack...
1554 else if (!is_cut_thru)
1556 /* The peer has already initiated the close,
1557 * so send the disconnect session reply.
1559 if (state & STATE_CLOSE_ON_EMPTY)
1561 vppcom_send_disconnect_session_reply (vpp_handle,
1562 session_index, 0 /* rv */ );
1563 if (VPPCOM_DEBUG > 1)
1564 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
1565 "sending disconnect REPLY...",
1566 getpid (), vpp_handle, session_index);
1569 /* Otherwise, send a disconnect session msg...
1573 if (VPPCOM_DEBUG > 1)
1574 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
1575 "sending disconnect...",
1576 getpid (), vpp_handle, session_index);
1578 vppcom_send_disconnect_session (vpp_handle, session_index);
1582 /* Cut-thru connections...
1584 * server: free fifos and segment allocated during connect/redirect
1585 * client: no cleanup required
1591 svm_fifo_segment_main_t *sm = &svm_fifo_segment_main;
1592 svm_fifo_segment_private_t *seg;
1594 VCL_LOCK_AND_GET_SESSION (session_index, &session);
1596 if (VPPCOM_DEBUG > 1)
1597 clib_warning ("[%d] sid %d: freeing cut-thru fifos in "
1599 " server_rx_fifo %p, refcnt = %d"
1600 " server_tx_fifo %p, refcnt = %d",
1601 getpid (), session_index, session->sm_seg_index,
1602 session->server_rx_fifo,
1603 session->server_rx_fifo->refcnt,
1604 session->server_tx_fifo,
1605 session->server_tx_fifo->refcnt);
1607 seg = vec_elt_at_index (sm->segments, session->sm_seg_index);
1608 svm_fifo_segment_free_fifo (seg, session->server_rx_fifo,
1609 FIFO_SEGMENT_RX_FREELIST);
1610 svm_fifo_segment_free_fifo (seg, session->server_tx_fifo,
1611 FIFO_SEGMENT_TX_FREELIST);
1612 svm_fifo_segment_delete (seg);
1614 /* TBD: Send cut-thru disconnect event to client */
1616 clib_spinlock_unlock (&vcm->sessions_lockp);
1620 /* TBD: Send cut-thru disconnect event to server */
1628 #define foreach_sock_msg \
1629 _(SESSION_ENABLE_DISABLE_REPLY, session_enable_disable_reply) \
1630 _(BIND_SOCK_REPLY, bind_sock_reply) \
1631 _(UNBIND_SOCK_REPLY, unbind_sock_reply) \
1632 _(ACCEPT_SESSION, accept_session) \
1633 _(CONNECT_SOCK, connect_sock) \
1634 _(CONNECT_SESSION_REPLY, connect_session_reply) \
1635 _(DISCONNECT_SESSION, disconnect_session) \
1636 _(DISCONNECT_SESSION_REPLY, disconnect_session_reply) \
1637 _(RESET_SESSION, reset_session) \
1638 _(APPLICATION_ATTACH_REPLY, application_attach_reply) \
1639 _(APPLICATION_DETACH_REPLY, application_detach_reply) \
1640 _(MAP_ANOTHER_SEGMENT, map_another_segment)
1643 vppcom_api_hookup (void)
1646 vl_msg_api_set_handlers(VL_API_##N, #n, \
1647 vl_api_##n##_t_handler, \
1649 vl_api_##n##_t_endian, \
1650 vl_api_##n##_t_print, \
1651 sizeof(vl_api_##n##_t), 1);
1657 vppcom_cfg_init (vppcom_cfg_t * vcl_cfg)
1661 vcl_cfg->heapsize = (256ULL << 20);
1662 vcl_cfg->vpp_api_q_length = 1024;
1663 vcl_cfg->segment_baseva = 0x200000000ULL;
1664 vcl_cfg->segment_size = (256 << 20);
1665 vcl_cfg->add_segment_size = (128 << 20);
1666 vcl_cfg->preallocated_fifo_pairs = 8;
1667 vcl_cfg->rx_fifo_size = (1 << 20);
1668 vcl_cfg->tx_fifo_size = (1 << 20);
1669 vcl_cfg->event_queue_size = 2048;
1670 vcl_cfg->listen_queue_size = CLIB_CACHE_LINE_BYTES / sizeof (u32);
1671 vcl_cfg->app_timeout = 10 * 60.0;
1672 vcl_cfg->session_timeout = 10 * 60.0;
1673 vcl_cfg->accept_timeout = 60.0;
1674 vcl_cfg->event_ring_size = (128 << 10);
1675 vcl_cfg->event_log_path = "/dev/shm";
1679 vppcom_cfg_heapsize (char *conf_fname)
1681 vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1694 fp = fopen (conf_fname, "r");
1697 if (VPPCOM_DEBUG > 0)
1698 fprintf (stderr, "open configuration file '%s' failed\n", conf_fname);
1701 argv = calloc (1, sizeof (char *));
1707 if (fgets (inbuf, 4096, fp) == 0)
1709 p = strtok (inbuf, " \t\n");
1715 char **tmp = realloc (argv, argc * sizeof (char *));
1719 arg = strndup (p, 1024);
1722 argv[argc - 1] = arg;
1723 p = strtok (NULL, " \t\n");
1730 char **tmp = realloc (argv, (argc + 1) * sizeof (char *));
1737 * Look for and parse the "heapsize" config parameter.
1738 * Manual since none of the clib infra has been bootstrapped yet.
1740 * Format: heapsize <nn>[mM][gG]
1743 for (i = 1; i < (argc - 1); i++)
1745 if (!strncmp (argv[i], "heapsize", 8))
1747 sizep = (u8 *) argv[i + 1];
1749 while (*sizep >= '0' && *sizep <= '9')
1752 size += *sizep++ - '0';
1756 if (VPPCOM_DEBUG > 0)
1757 clib_warning ("[%d] parse error '%s %s', "
1758 "using default heapsize %lld (0x%llx)",
1759 getpid (), argv[i], argv[i + 1],
1760 vcl_cfg->heapsize, vcl_cfg->heapsize);
1764 if (*sizep == 'g' || *sizep == 'G')
1765 vcl_cfg->heapsize = size << 30;
1766 else if (*sizep == 'm' || *sizep == 'M')
1767 vcl_cfg->heapsize = size << 20;
1770 if (VPPCOM_DEBUG > 0)
1771 clib_warning ("[%d] parse error '%s %s', "
1772 "using default heapsize %lld (0x%llx)",
1773 getpid (), argv[i], argv[i + 1],
1774 vcl_cfg->heapsize, vcl_cfg->heapsize);
1786 vcl_mem = mmap (0, vcl_cfg->heapsize, PROT_READ | PROT_WRITE,
1787 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
1788 if (vcl_mem == MAP_FAILED)
1790 clib_unix_error ("[%d] ERROR: mmap(0, %lld == 0x%llx, "
1791 "PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, "
1793 getpid (), vcl_cfg->heapsize, vcl_cfg->heapsize);
1796 heap = clib_mem_init (vcl_mem, vcl_cfg->heapsize);
1799 clib_warning ("[%d] ERROR: clib_mem_init() failed!", getpid ());
1802 vcl_mem = clib_mem_alloc (sizeof (_vppcom_main));
1805 clib_warning ("[%d] ERROR: clib_mem_alloc() failed!", getpid ());
1809 clib_memcpy (vcl_mem, &_vppcom_main, sizeof (_vppcom_main));
1812 if (VPPCOM_DEBUG > 0)
1813 clib_warning ("[%d] allocated VCL heap = %p, size %lld (0x%llx)",
1814 getpid (), heap, vcl_cfg->heapsize, vcl_cfg->heapsize);
1818 vppcom_cfg_read (char *conf_fname)
1820 vppcom_cfg_t *vcl_cfg = &vcm->cfg;
1822 unformat_input_t _input, *input = &_input;
1823 unformat_input_t _line_input, *line_input = &_line_input;
1824 u8 vc_cfg_input = 0;
1827 u32 uid, gid, q_len;
1829 fd = open (conf_fname, O_RDONLY);
1832 if (VPPCOM_DEBUG > 0)
1833 clib_warning ("[%d] open configuration file '%s' failed!",
1834 getpid (), conf_fname);
1838 if (fstat (fd, &s) < 0)
1840 if (VPPCOM_DEBUG > 0)
1841 clib_warning ("[%d] failed to stat `%s'", getpid (), conf_fname);
1845 if (!(S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
1847 if (VPPCOM_DEBUG > 0)
1848 clib_warning ("[%d] not a regular file `%s'", getpid (), conf_fname);
1852 unformat_init_clib_file (input, fd);
1854 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1856 (void) unformat_user (input, unformat_line_input, line_input);
1857 unformat_skip_white_space (line_input);
1859 if (unformat (line_input, "vcl {"))
1867 if (unformat (line_input, "heapsize %s", &chroot_path))
1869 vec_terminate_c_string (chroot_path);
1870 if (VPPCOM_DEBUG > 0)
1871 clib_warning ("[%d] configured heapsize %s, "
1872 "actual heapsize %lld (0x%llx)",
1873 getpid (), chroot_path, vcl_cfg->heapsize,
1875 vec_free (chroot_path);
1877 else if (unformat (line_input, "api-prefix %s", &chroot_path))
1879 vec_terminate_c_string (chroot_path);
1880 vl_set_memory_root_path ((char *) chroot_path);
1881 if (VPPCOM_DEBUG > 0)
1882 clib_warning ("[%d] configured api-prefix %s",
1883 getpid (), chroot_path);
1884 chroot_path = 0; /* Don't vec_free() it! */
1886 else if (unformat (line_input, "vpp-api-q-length %d", &q_len))
1888 if (q_len < vcl_cfg->vpp_api_q_length)
1890 clib_warning ("[%d] ERROR: configured vpp-api-q-length "
1891 "(%u) is too small! Using default: %u ",
1892 getpid (), q_len, vcl_cfg->vpp_api_q_length);
1896 vcl_cfg->vpp_api_q_length = q_len;
1898 if (VPPCOM_DEBUG > 0)
1899 clib_warning ("[%d] configured vpp-api-q-length %u",
1900 getpid (), vcl_cfg->vpp_api_q_length);
1903 else if (unformat (line_input, "uid %d", &uid))
1905 vl_set_memory_uid (uid);
1906 if (VPPCOM_DEBUG > 0)
1907 clib_warning ("[%d] configured uid %d", getpid (), uid);
1909 else if (unformat (line_input, "gid %d", &gid))
1911 vl_set_memory_gid (gid);
1912 if (VPPCOM_DEBUG > 0)
1913 clib_warning ("[%d] configured gid %d", getpid (), gid);
1915 else if (unformat (line_input, "segment-baseva 0x%lx",
1916 &vcl_cfg->segment_baseva))
1918 if (VPPCOM_DEBUG > 0)
1919 clib_warning ("[%d] configured segment_baseva 0x%lx",
1920 getpid (), vcl_cfg->segment_baseva);
1922 else if (unformat (line_input, "segment-size 0x%lx",
1923 &vcl_cfg->segment_size))
1925 if (VPPCOM_DEBUG > 0)
1926 clib_warning ("[%d] configured segment_size 0x%lx (%ld)",
1927 getpid (), vcl_cfg->segment_size,
1928 vcl_cfg->segment_size);
1930 else if (unformat (line_input, "segment-size %ld",
1931 &vcl_cfg->segment_size))
1933 if (VPPCOM_DEBUG > 0)
1934 clib_warning ("[%d] configured segment_size %ld (0x%lx)",
1935 getpid (), vcl_cfg->segment_size,
1936 vcl_cfg->segment_size);
1938 else if (unformat (line_input, "add-segment-size 0x%lx",
1939 &vcl_cfg->add_segment_size))
1941 if (VPPCOM_DEBUG > 0)
1943 ("[%d] configured add_segment_size 0x%lx (%ld)",
1944 getpid (), vcl_cfg->add_segment_size,
1945 vcl_cfg->add_segment_size);
1947 else if (unformat (line_input, "add-segment-size %ld",
1948 &vcl_cfg->add_segment_size))
1950 if (VPPCOM_DEBUG > 0)
1952 ("[%d] configured add_segment_size %ld (0x%lx)",
1953 getpid (), vcl_cfg->add_segment_size,
1954 vcl_cfg->add_segment_size);
1956 else if (unformat (line_input, "preallocated-fifo-pairs %d",
1957 &vcl_cfg->preallocated_fifo_pairs))
1959 if (VPPCOM_DEBUG > 0)
1960 clib_warning ("[%d] configured preallocated_fifo_pairs "
1961 "%d (0x%x)", getpid (),
1962 vcl_cfg->preallocated_fifo_pairs,
1963 vcl_cfg->preallocated_fifo_pairs);
1965 else if (unformat (line_input, "rx-fifo-size 0x%lx",
1966 &vcl_cfg->rx_fifo_size))
1968 if (VPPCOM_DEBUG > 0)
1969 clib_warning ("[%d] configured rx_fifo_size 0x%lx (%ld)",
1970 getpid (), vcl_cfg->rx_fifo_size,
1971 vcl_cfg->rx_fifo_size);
1973 else if (unformat (line_input, "rx-fifo-size %ld",
1974 &vcl_cfg->rx_fifo_size))
1976 if (VPPCOM_DEBUG > 0)
1977 clib_warning ("[%d] configured rx_fifo_size %ld (0x%lx)",
1978 getpid (), vcl_cfg->rx_fifo_size,
1979 vcl_cfg->rx_fifo_size);
1981 else if (unformat (line_input, "tx-fifo-size 0x%lx",
1982 &vcl_cfg->tx_fifo_size))
1984 if (VPPCOM_DEBUG > 0)
1985 clib_warning ("[%d] configured tx_fifo_size 0x%lx (%ld)",
1986 getpid (), vcl_cfg->tx_fifo_size,
1987 vcl_cfg->tx_fifo_size);
1989 else if (unformat (line_input, "tx-fifo-size %ld",
1990 &vcl_cfg->tx_fifo_size))
1992 if (VPPCOM_DEBUG > 0)
1993 clib_warning ("[%d] configured tx_fifo_size %ld (0x%lx)",
1994 getpid (), vcl_cfg->tx_fifo_size,
1995 vcl_cfg->tx_fifo_size);
1997 else if (unformat (line_input, "event-queue-size 0x%lx",
1998 &vcl_cfg->event_queue_size))
2000 if (VPPCOM_DEBUG > 0)
2001 clib_warning ("[%d] configured event_queue_size 0x%lx (%ld)",
2002 getpid (), vcl_cfg->event_queue_size,
2003 vcl_cfg->event_queue_size);
2005 else if (unformat (line_input, "event-queue-size %ld",
2006 &vcl_cfg->event_queue_size))
2008 if (VPPCOM_DEBUG > 0)
2009 clib_warning ("[%d] configured event_queue_size %ld (0x%lx)",
2010 getpid (), vcl_cfg->event_queue_size,
2011 vcl_cfg->event_queue_size);
2013 else if (unformat (line_input, "listen-queue-size 0x%lx",
2014 &vcl_cfg->listen_queue_size))
2016 if (VPPCOM_DEBUG > 0)
2017 clib_warning ("[%d] configured listen_queue_size 0x%lx (%ld)",
2018 getpid (), vcl_cfg->listen_queue_size,
2019 vcl_cfg->listen_queue_size);
2021 else if (unformat (line_input, "listen-queue-size %ld",
2022 &vcl_cfg->listen_queue_size))
2024 if (VPPCOM_DEBUG > 0)
2025 clib_warning ("[%d] configured listen_queue_size %ld (0x%lx)",
2026 getpid (), vcl_cfg->listen_queue_size,
2027 vcl_cfg->listen_queue_size);
2029 else if (unformat (line_input, "app-timeout %f",
2030 &vcl_cfg->app_timeout))
2032 if (VPPCOM_DEBUG > 0)
2033 clib_warning ("[%d] configured app_timeout %f",
2034 getpid (), vcl_cfg->app_timeout);
2036 else if (unformat (line_input, "session-timeout %f",
2037 &vcl_cfg->session_timeout))
2039 if (VPPCOM_DEBUG > 0)
2040 clib_warning ("[%d] configured session_timeout %f",
2041 getpid (), vcl_cfg->session_timeout);
2043 else if (unformat (line_input, "accept-timeout %f",
2044 &vcl_cfg->accept_timeout))
2046 if (VPPCOM_DEBUG > 0)
2047 clib_warning ("[%d] configured accept_timeout %f",
2048 getpid (), vcl_cfg->accept_timeout);
2050 else if (unformat (line_input, "app-proxy-transport-tcp"))
2052 vcl_cfg->app_proxy_transport_tcp = 1;
2053 if (VPPCOM_DEBUG > 0)
2054 clib_warning ("[%d] configured app_proxy_transport_tcp (%d)",
2055 getpid (), vcl_cfg->app_proxy_transport_tcp);
2057 else if (unformat (line_input, "app-proxy-transport-udp"))
2059 vcl_cfg->app_proxy_transport_udp = 1;
2060 if (VPPCOM_DEBUG > 0)
2061 clib_warning ("[%d] configured app_proxy_transport_udp (%d)",
2062 getpid (), vcl_cfg->app_proxy_transport_udp);
2064 else if (unformat (line_input, "app-scope-local"))
2066 vcl_cfg->app_scope_local = 1;
2067 if (VPPCOM_DEBUG > 0)
2068 clib_warning ("[%d] configured app_scope_local (%d)",
2069 getpid (), vcl_cfg->app_scope_local);
2071 else if (unformat (line_input, "app-scope-global"))
2073 vcl_cfg->app_scope_global = 1;
2074 if (VPPCOM_DEBUG > 0)
2075 clib_warning ("[%d] configured app_scope_global (%d)",
2076 getpid (), vcl_cfg->app_scope_global);
2078 else if (unformat (line_input, "namespace-secret %lu",
2079 &vcl_cfg->namespace_secret))
2081 if (VPPCOM_DEBUG > 0)
2083 ("[%d] configured namespace_secret %lu (0x%lx)",
2084 getpid (), vcl_cfg->namespace_secret,
2085 vcl_cfg->namespace_secret);
2087 else if (unformat (line_input, "namespace-id %v",
2088 &vcl_cfg->namespace_id))
2090 vl_api_application_attach_t *mp;
2091 u32 max_nsid_vec_len = sizeof (mp->namespace_id) - 1;
2092 u32 nsid_vec_len = vec_len (vcl_cfg->namespace_id);
2093 if (nsid_vec_len > max_nsid_vec_len)
2095 _vec_len (vcl_cfg->namespace_id) = max_nsid_vec_len;
2096 if (VPPCOM_DEBUG > 0)
2097 clib_warning ("[%d] configured namespace_id is too long,"
2098 " truncated to %d characters!", getpid (),
2102 if (VPPCOM_DEBUG > 0)
2103 clib_warning ("[%d] configured namespace_id %v",
2104 getpid (), vcl_cfg->namespace_id);
2106 else if (unformat (line_input, "}"))
2109 if (VPPCOM_DEBUG > 0)
2110 clib_warning ("[%d] completed parsing vppcom config!",
2116 if (line_input->buffer[line_input->index] != '#')
2118 clib_warning ("[%d] Unknown vppcom config option: '%s'",
2120 &line_input->buffer[line_input->index]);
2127 unformat_free (input);
2135 * VPPCOM Public API functions
2138 vppcom_app_create (char *app_name)
2140 vppcom_cfg_t *vcl_cfg = &vcm->cfg;
2151 vppcom_cfg_init (vcl_cfg);
2152 env_var_str = getenv (VPPCOM_ENV_DEBUG);
2156 if (sscanf (env_var_str, "%u", &tmp) != 1)
2157 clib_warning ("[%d] Invalid debug level specified in "
2158 "the environment variable "
2160 " (%s)!\n", getpid (), env_var_str);
2164 clib_warning ("[%d] configured debug level (%u) from "
2165 VPPCOM_ENV_DEBUG "!", getpid (), vcm->debug);
2168 conf_fname = getenv (VPPCOM_ENV_CONF);
2171 conf_fname = VPPCOM_CONF_DEFAULT;
2172 if (VPPCOM_DEBUG > 0)
2173 clib_warning ("[%d] getenv '%s' failed!", getpid (),
2176 vppcom_cfg_heapsize (conf_fname);
2177 clib_fifo_validate (vcm->client_session_index_fifo,
2178 vcm->cfg.listen_queue_size);
2179 vppcom_cfg_read (conf_fname);
2180 env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_ID);
2183 u32 ns_id_vec_len = strlen (env_var_str);
2185 vec_reset_length (vcm->cfg.namespace_id);
2186 vec_validate (vcm->cfg.namespace_id, ns_id_vec_len - 1);
2187 clib_memcpy (vcm->cfg.namespace_id, env_var_str, ns_id_vec_len);
2189 if (VPPCOM_DEBUG > 0)
2190 clib_warning ("[%d] configured namespace_id (%v) from "
2191 VPPCOM_ENV_APP_NAMESPACE_ID "!", getpid (),
2192 vcm->cfg.namespace_id);
2194 env_var_str = getenv (VPPCOM_ENV_APP_NAMESPACE_SECRET);
2198 if (sscanf (env_var_str, "%lu", &tmp) != 1)
2199 clib_warning ("[%d] Invalid namespace secret specified in "
2200 "the environment variable "
2201 VPPCOM_ENV_APP_NAMESPACE_SECRET
2202 " (%s)!\n", getpid (), env_var_str);
2205 vcm->cfg.namespace_secret = tmp;
2206 if (VPPCOM_DEBUG > 0)
2207 clib_warning ("[%d] configured namespace secret (%lu) from "
2208 VPPCOM_ENV_APP_NAMESPACE_ID "!", getpid (),
2209 vcm->cfg.namespace_secret);
2212 if (getenv (VPPCOM_ENV_APP_PROXY_TRANSPORT_TCP))
2214 vcm->cfg.app_proxy_transport_tcp = 1;
2215 if (VPPCOM_DEBUG > 0)
2216 clib_warning ("[%d] configured app_proxy_transport_tcp (%u) from "
2217 VPPCOM_ENV_APP_PROXY_TRANSPORT_TCP "!", getpid (),
2218 vcm->cfg.app_proxy_transport_tcp);
2220 if (getenv (VPPCOM_ENV_APP_PROXY_TRANSPORT_UDP))
2222 vcm->cfg.app_proxy_transport_udp = 1;
2223 if (VPPCOM_DEBUG > 0)
2224 clib_warning ("[%d] configured app_proxy_transport_udp (%u) from "
2225 VPPCOM_ENV_APP_PROXY_TRANSPORT_UDP "!", getpid (),
2226 vcm->cfg.app_proxy_transport_udp);
2228 if (getenv (VPPCOM_ENV_APP_SCOPE_LOCAL))
2230 vcm->cfg.app_scope_local = 1;
2231 if (VPPCOM_DEBUG > 0)
2232 clib_warning ("[%d] configured app_scope_local (%u) from "
2233 VPPCOM_ENV_APP_SCOPE_LOCAL "!", getpid (),
2234 vcm->cfg.app_scope_local);
2236 if (getenv (VPPCOM_ENV_APP_SCOPE_GLOBAL))
2238 vcm->cfg.app_scope_global = 1;
2239 if (VPPCOM_DEBUG > 0)
2240 clib_warning ("[%d] configured app_scope_global (%u) from "
2241 VPPCOM_ENV_APP_SCOPE_GLOBAL "!", getpid (),
2242 vcm->cfg.app_scope_global);
2245 vcm->main_cpu = os_get_thread_index ();
2246 heap = clib_mem_get_per_cpu_heap ();
2247 h = mheap_header (heap);
2249 /* make the main heap thread-safe */
2250 h->flags |= MHEAP_FLAG_THREAD_SAFE;
2252 vcm->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
2254 clib_time_init (&vcm->clib_time);
2255 vppcom_init_error_string_table ();
2256 svm_fifo_segment_init (vcl_cfg->segment_baseva,
2257 20 /* timeout in secs */ );
2258 clib_spinlock_init (&vcm->sessions_lockp);
2259 vppcom_api_hookup ();
2262 if (vcm->my_client_index == ~0)
2264 vcm->app_state = STATE_APP_START;
2265 rv = vppcom_connect_to_vpp (app_name);
2268 clib_warning ("[%d] ERROR: couldn't connect to VPP!", getpid ());
2272 if (VPPCOM_DEBUG > 0)
2273 clib_warning ("[%d] sending session enable", getpid ());
2275 rv = vppcom_app_session_enable ();
2278 clib_warning ("[%d] ERROR: vppcom_app_session_enable() failed!",
2283 if (VPPCOM_DEBUG > 0)
2284 clib_warning ("[%d] sending app attach", getpid ());
2286 rv = vppcom_app_attach ();
2289 clib_warning ("[%d] ERROR: vppcom_app_attach() failed!", getpid ());
2293 if (VPPCOM_DEBUG > 0)
2294 clib_warning ("[%d] app_name '%s', my_client_index %d (0x%x)",
2295 getpid (), app_name, vcm->my_client_index,
2296 vcm->my_client_index);
2303 vppcom_app_destroy (void)
2307 if (vcm->my_client_index == ~0)
2310 if (VPPCOM_DEBUG > 0)
2311 clib_warning ("[%d] detaching from VPP, my_client_index %d (0x%x)",
2312 getpid (), vcm->my_client_index, vcm->my_client_index);
2314 if (VPPCOM_DEBUG > 0)
2317 ELOG_TYPE_DECLARE (e) =
2319 .format = "app_detach:C:%d",
2320 .format_args = "i4",
2327 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vcm->elog_track);
2328 ed->data = vcm->my_client_index;
2332 vppcom_app_detach ();
2333 rv = vppcom_wait_for_app_state_change (STATE_APP_ENABLED);
2334 if (PREDICT_FALSE (rv))
2336 if (VPPCOM_DEBUG > 0)
2337 clib_warning ("[%d] application detach timed out! returning %d (%s)",
2338 getpid (), rv, vppcom_retval_str (rv));
2341 /* Finished with logging before client gets reset to ~0 */
2342 if (VPPCOM_DEBUG > 0)
2345 vl_client_disconnect_from_vlib ();
2346 vcm->my_client_index = ~0;
2347 vcm->app_state = STATE_APP_START;
2351 vppcom_session_create (u32 vrf, u8 proto, u8 is_nonblocking)
2356 clib_spinlock_lock (&vcm->sessions_lockp);
2357 pool_get (vcm->sessions, session);
2358 memset (session, 0, sizeof (*session));
2359 session_index = session - vcm->sessions;
2362 session->proto = proto;
2363 session->state = STATE_START;
2364 session->is_nonblocking = is_nonblocking ? 1 : 0;
2365 session->vpp_handle = ~0;
2366 clib_spinlock_unlock (&vcm->sessions_lockp);
2368 if (VPPCOM_DEBUG > 0)
2369 clib_warning ("[%d] sid %u", getpid (), session_index);
2371 if (VPPCOM_DEBUG > 0)
2373 session->elog_track.name =
2374 (char *) format (0, "C:%d:S:%d%c", vcm->my_client_index,
2376 elog_track_register (&vcm->elog_main, &session->elog_track);
2379 ELOG_TYPE_DECLARE (e) =
2381 .format = "session_create:vrf:%d proto:%d state:%d is_nonblocking:%d",
2382 .format_args = "i4i4i4i4",
2390 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
2391 ed->data[0] = session->vrf;
2392 ed->data[1] = session->proto;
2393 ed->data[2] = session->state;
2394 ed->data[3] = session->is_nonblocking;
2398 return (int) session_index;
2402 vppcom_session_close (uint32_t session_index)
2404 session_t *session = 0;
2413 session_state_t state;
2415 VCL_LOCK_AND_GET_SESSION (session_index, &session);
2416 is_listen = session->is_listen;
2417 is_vep = session->is_vep;
2418 is_vep_session = session->is_vep_session;
2419 next_sid = session->vep.next_sid;
2420 vep_idx = session->vep.vep_idx;
2421 state = session->state;
2422 vpp_handle = session->vpp_handle;
2423 clib_spinlock_unlock (&vcm->sessions_lockp);
2425 if (VPPCOM_DEBUG > 0)
2428 clib_warning ("[%d] vep_idx %u / sid %u: closing epoll session...",
2429 getpid (), session_index, session_index);
2431 clib_warning ("[%d] vpp handle 0x%llx, sid %d: closing session...",
2432 getpid (), vpp_handle, session_index);
2437 while (next_sid != ~0)
2439 rv = vppcom_epoll_ctl (session_index, EPOLL_CTL_DEL, next_sid, 0);
2440 if ((VPPCOM_DEBUG > 0) && PREDICT_FALSE (rv < 0))
2441 clib_warning ("[%d] vpp handle 0x%llx, sid %u: EPOLL_CTL_DEL "
2442 "vep_idx %u failed! rv %d (%s)", getpid (),
2443 vpp_handle, next_sid, vep_idx,
2444 rv, vppcom_retval_str (rv));
2446 VCL_LOCK_AND_GET_SESSION (session_index, &session);
2447 next_sid = session->vep.next_sid;
2448 clib_spinlock_unlock (&vcm->sessions_lockp);
2455 rv = vppcom_epoll_ctl (vep_idx, EPOLL_CTL_DEL, session_index, 0);
2456 if ((VPPCOM_DEBUG > 0) && (rv < 0))
2457 clib_warning ("[%d] vpp handle 0x%llx, sid %u: EPOLL_CTL_DEL "
2458 "vep_idx %u failed! rv %d (%s)",
2459 getpid (), vpp_handle, session_index,
2460 vep_idx, rv, vppcom_retval_str (rv));
2465 if (state == STATE_LISTEN)
2467 rv = vppcom_session_unbind (session_index);
2468 if (PREDICT_FALSE (rv < 0))
2470 if (VPPCOM_DEBUG > 0)
2471 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
2472 "listener unbind failed! rv %d (%s)",
2473 getpid (), vpp_handle, session_index,
2474 rv, vppcom_retval_str (rv));
2479 else if (state & (CLIENT_STATE_OPEN | SERVER_STATE_OPEN))
2481 rv = vppcom_session_disconnect (session_index);
2482 if (PREDICT_FALSE (rv < 0))
2483 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2484 "session disconnect failed! rv %d (%s)",
2485 getpid (), vpp_handle, session_index,
2486 rv, vppcom_retval_str (rv));
2490 VCL_LOCK_AND_GET_SESSION (session_index, &session);
2491 vpp_handle = session->vpp_handle;
2492 if (vpp_handle != ~0)
2494 p = hash_get (vcm->session_index_by_vpp_handles, vpp_handle);
2496 hash_unset (vcm->session_index_by_vpp_handles, vpp_handle);
2498 pool_put_index (vcm->sessions, session_index);
2499 clib_spinlock_unlock (&vcm->sessions_lockp);
2501 if (VPPCOM_DEBUG > 0)
2504 clib_warning ("[%d] vep_idx %u / sid %u: epoll session removed.",
2505 getpid (), session_index, session_index);
2507 clib_warning ("[%d] vpp handle 0x%llx, sid %u: session removed.",
2508 getpid (), vpp_handle, session_index);
2512 if (VPPCOM_DEBUG > 0)
2515 ELOG_TYPE_DECLARE (e) =
2517 .format = "session_close:rv:%d",
2518 .format_args = "i4",
2526 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
2535 vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep)
2537 session_t *session = 0;
2541 return VPPCOM_EINVAL;
2543 VCL_LOCK_AND_GET_SESSION (session_index, &session);
2545 if (session->is_vep)
2547 clib_spinlock_unlock (&vcm->sessions_lockp);
2548 clib_warning ("[%d] ERROR: sid %u: cannot bind to an epoll session!",
2549 getpid (), session_index);
2554 session->vrf = ep->vrf;
2555 session->lcl_addr.is_ip4 = ep->is_ip4;
2556 session->lcl_addr.ip46 = to_ip46 (!ep->is_ip4, ep->ip);
2557 session->lcl_port = ep->port;
2559 if (VPPCOM_DEBUG > 0)
2560 clib_warning ("[%d] sid %u: binding to local %s address %U "
2561 "port %u, proto %s", getpid (), session_index,
2562 session->lcl_addr.is_ip4 ? "IPv4" : "IPv6",
2563 format_ip46_address, &session->lcl_addr.ip46,
2564 session->lcl_addr.is_ip4,
2565 clib_net_to_host_u16 (session->lcl_port),
2566 session->proto ? "UDP" : "TCP");
2568 if (VPPCOM_DEBUG > 0)
2570 if (session->lcl_addr.is_ip4)
2573 ELOG_TYPE_DECLARE (e) =
2575 .format = "bind local:%s:%d.%d.%d.%d:%d ",
2576 .format_args = "t1i1i1i1i1i2",
2577 .n_enum_strings = 2,
2578 .enum_strings = {"TCP", "UDP",},
2581 CLIB_PACKED (struct {
2587 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, session->elog_track);
2588 ed->proto = session->proto;
2589 ed->addr[0] = session->lcl_addr.ip46.ip4.as_u8[0];
2590 ed->addr[1] = session->lcl_addr.ip46.ip4.as_u8[1];
2591 ed->addr[2] = session->lcl_addr.ip46.ip4.as_u8[2];
2592 ed->addr[3] = session->lcl_addr.ip46.ip4.as_u8[3];
2593 ed->port = clib_net_to_host_u16 (session->lcl_port);
2598 clib_spinlock_unlock (&vcm->sessions_lockp);
2604 vppcom_session_listen (uint32_t listen_session_index, uint32_t q_len)
2606 session_t *listen_session = 0;
2607 u64 listen_vpp_handle;
2610 VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2612 if (listen_session->is_vep)
2614 clib_spinlock_unlock (&vcm->sessions_lockp);
2615 clib_warning ("[%d] ERROR: sid %u: cannot listen on an "
2616 "epoll session!", getpid (), listen_session_index);
2621 listen_vpp_handle = listen_session->vpp_handle;
2622 if (listen_session->is_listen)
2624 clib_spinlock_unlock (&vcm->sessions_lockp);
2625 if (VPPCOM_DEBUG > 0)
2626 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
2627 "already in listen state!",
2628 getpid (), listen_vpp_handle, listen_session_index);
2633 if (VPPCOM_DEBUG > 0)
2634 clib_warning ("[%d] vpp handle 0x%llx, sid %u: sending bind request...",
2635 getpid (), listen_vpp_handle, listen_session_index);
2637 vppcom_send_bind_sock (listen_session, listen_session_index);
2638 clib_spinlock_unlock (&vcm->sessions_lockp);
2640 vppcom_wait_for_session_state_change (listen_session_index, STATE_LISTEN,
2641 vcm->cfg.session_timeout);
2643 VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2644 if (PREDICT_FALSE (retval))
2646 if (VPPCOM_DEBUG > 0)
2647 clib_warning ("[%d] vpp handle 0x%llx, sid %u: bind failed! "
2648 "returning %d (%s)", getpid (),
2649 listen_session->vpp_handle, listen_session_index,
2650 retval, vppcom_retval_str (retval));
2651 clib_spinlock_unlock (&vcm->sessions_lockp);
2656 clib_fifo_validate (vcm->client_session_index_fifo, q_len);
2657 clib_spinlock_unlock (&vcm->sessions_lockp);
2663 vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
2664 uint32_t flags, double wait_for_time)
2666 session_t *listen_session = 0;
2667 session_t *client_session = 0;
2668 u32 client_session_index = ~0;
2672 u64 listen_vpp_handle;
2674 VCL_LOCK_AND_GET_SESSION (listen_session_index, &listen_session);
2676 if (listen_session->is_vep)
2678 clib_spinlock_unlock (&vcm->sessions_lockp);
2679 clib_warning ("[%d] ERROR: sid %u: cannot accept on an "
2680 "epoll session!", getpid (), listen_session_index);
2685 listen_vpp_handle = listen_session->vpp_handle;
2686 if (listen_session->state != STATE_LISTEN)
2688 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2689 "not in listen state! state 0x%x (%s)", getpid (),
2690 listen_vpp_handle, listen_session_index,
2691 listen_session->state,
2692 vppcom_session_state_str (listen_session->state));
2693 clib_spinlock_unlock (&vcm->sessions_lockp);
2697 wait_for = ((listen_session->is_nonblocking) ? 0 :
2698 (wait_for_time < 0) ? vcm->cfg.accept_timeout : wait_for_time);
2700 clib_spinlock_unlock (&vcm->sessions_lockp);
2704 rv = vppcom_wait_for_client_session_index (wait_for);
2707 if ((VPPCOM_DEBUG > 0))
2708 clib_warning ("[%d] vpp handle 0x%llx, sid %u: accept failed! "
2709 "returning %d (%s)", getpid (),
2710 listen_vpp_handle, listen_session_index,
2711 rv, vppcom_retval_str (rv));
2712 if ((wait_for == 0) || (wait_for_time > 0))
2719 clib_spinlock_lock (&vcm->sessions_lockp);
2720 clib_fifo_sub1 (vcm->client_session_index_fifo, client_session_index);
2721 rv = vppcom_session_at_index (client_session_index, &client_session);
2722 if (PREDICT_FALSE (rv))
2724 rv = VPPCOM_ECONNABORTED;
2725 clib_warning ("[%d] vpp handle 0x%llx, sid %u: client sid %u "
2726 "lookup failed! returning %d (%s)", getpid (),
2727 listen_vpp_handle, listen_session_index,
2728 client_session_index, rv, vppcom_retval_str (rv));
2732 client_session->is_nonblocking = (flags & O_NONBLOCK) ? 1 : 0;
2733 if (VPPCOM_DEBUG > 0)
2734 clib_warning ("[%d] vpp handle 0x%llx, sid %u: Got a client request! "
2735 "vpp handle 0x%llx, sid %u, flags %d, is_nonblocking %u",
2736 getpid (), listen_vpp_handle, listen_session_index,
2737 client_session->vpp_handle, client_session_index,
2738 flags, client_session->is_nonblocking);
2740 ep->vrf = client_session->vrf;
2741 ep->is_cut_thru = client_session->is_cut_thru;
2742 ep->is_ip4 = client_session->peer_addr.is_ip4;
2743 ep->port = client_session->peer_port;
2744 if (client_session->peer_addr.is_ip4)
2745 clib_memcpy (ep->ip, &client_session->peer_addr.ip46.ip4,
2746 sizeof (ip4_address_t));
2748 clib_memcpy (ep->ip, &client_session->peer_addr.ip46.ip6,
2749 sizeof (ip6_address_t));
2751 if (client_session->is_server && client_session->is_cut_thru)
2753 static svm_fifo_segment_create_args_t _a;
2754 svm_fifo_segment_create_args_t *a = &_a;
2755 svm_fifo_segment_private_t *seg;
2757 cut_thru_str = " cut-thru ";
2759 /* Create the segment */
2760 memset (a, 0, sizeof (*a));
2761 a->segment_name = (char *)
2762 format ((u8 *) a->segment_name, "%d:segment%d%c",
2763 getpid (), vcm->unique_segment_index++, 0);
2764 a->segment_size = vcm->cfg.segment_size;
2765 a->preallocated_fifo_pairs = vcm->cfg.preallocated_fifo_pairs;
2766 a->rx_fifo_size = vcm->cfg.rx_fifo_size;
2767 a->tx_fifo_size = vcm->cfg.tx_fifo_size;
2769 rv = svm_fifo_segment_create (a);
2770 if (PREDICT_FALSE (rv))
2772 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2773 "client sid %u svm_fifo_segment_create ('%s') "
2774 "failed! rv %d", getpid (), listen_vpp_handle,
2775 listen_session_index, client_session_index,
2776 a->segment_name, rv);
2777 vec_reset_length (a->new_segment_indices);
2778 rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
2779 vppcom_send_connect_session_reply (client_session,
2780 client_session_index,
2781 client_session->vpp_handle,
2782 client_session->client_context,
2784 clib_spinlock_unlock (&vcm->sessions_lockp);
2789 client_session->segment_name = vec_dup ((u8 *) a->segment_name);
2790 client_session->sm_seg_index = a->new_segment_indices[0];
2791 vec_free (a->new_segment_indices);
2793 seg = svm_fifo_segment_get_segment (client_session->sm_seg_index);
2794 client_session->server_rx_fifo =
2795 svm_fifo_segment_alloc_fifo (seg, vcm->cfg.rx_fifo_size,
2796 FIFO_SEGMENT_RX_FREELIST);
2797 if (PREDICT_FALSE (!client_session->server_rx_fifo))
2799 svm_fifo_segment_delete (seg);
2800 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2801 "client sid %u rx fifo alloc failed! "
2802 "size %ld (0x%lx)", getpid (), listen_vpp_handle,
2803 listen_session_index, client_session_index,
2804 vcm->cfg.rx_fifo_size, vcm->cfg.rx_fifo_size);
2805 rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
2806 vppcom_send_connect_session_reply (client_session,
2807 client_session_index,
2808 client_session->vpp_handle,
2809 client_session->client_context,
2811 clib_spinlock_unlock (&vcm->sessions_lockp);
2815 client_session->server_rx_fifo->master_session_index =
2816 client_session_index;
2818 client_session->server_tx_fifo =
2819 svm_fifo_segment_alloc_fifo (seg, vcm->cfg.tx_fifo_size,
2820 FIFO_SEGMENT_TX_FREELIST);
2821 if (PREDICT_FALSE (!client_session->server_tx_fifo))
2823 svm_fifo_segment_delete (seg);
2824 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
2825 "client sid %u tx fifo alloc failed! "
2826 "size %ld (0x%lx)", getpid (), listen_vpp_handle,
2827 listen_session_index, client_session_index,
2828 vcm->cfg.tx_fifo_size, vcm->cfg.tx_fifo_size);
2829 rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
2830 vppcom_send_connect_session_reply (client_session,
2831 client_session_index,
2832 client_session->vpp_handle,
2833 client_session->client_context,
2835 clib_spinlock_unlock (&vcm->sessions_lockp);
2839 client_session->server_tx_fifo->master_session_index =
2840 client_session_index;
2842 if (VPPCOM_DEBUG > 1)
2843 clib_warning ("[%d] vpp handle 0x%llx, sid %u: client sid %u "
2844 "created segment '%s', rx_fifo %p, tx_fifo %p",
2845 getpid (), listen_vpp_handle, listen_session_index,
2846 client_session_index, client_session->segment_name,
2847 client_session->server_rx_fifo,
2848 client_session->server_tx_fifo);
2850 #ifdef CUT_THRU_EVENT_QUEUE /* TBD */
2853 ssvm_shared_header_t *sh = seg->ssvm.sh;
2855 ssvm_lock_non_recursive (sh, 1);
2856 oldheap = ssvm_push_heap (sh);
2857 event_q = client_session->vpp_event_queue =
2858 svm_queue_init (vcm->cfg.event_queue_size,
2859 sizeof (session_fifo_event_t),
2860 getpid (), 0 /* signal not sent */ );
2861 ssvm_pop_heap (oldheap);
2862 ssvm_unlock_non_recursive (sh);
2865 vppcom_send_connect_session_reply (client_session,
2866 client_session_index,
2867 client_session->vpp_handle,
2868 client_session->client_context,
2869 0 /* retval OK */ );
2874 vppcom_send_accept_session_reply (client_session->vpp_handle,
2875 client_session->client_context,
2876 0 /* retval OK */ );
2879 if (VPPCOM_DEBUG > 0)
2880 clib_warning ("[%d] vpp handle 0x%llx, sid %u: accepted vpp handle "
2881 "0x%llx, sid %u%sconnection to local %s address "
2882 "%U port %u", getpid (), listen_vpp_handle,
2883 listen_session_index, client_session->vpp_handle,
2884 client_session_index, cut_thru_str,
2885 client_session->lcl_addr.is_ip4 ? "IPv4" : "IPv6",
2886 format_ip46_address, &client_session->lcl_addr.ip46,
2887 client_session->lcl_addr.is_ip4,
2888 clib_net_to_host_u16 (client_session->lcl_port));
2890 if (VPPCOM_DEBUG > 0)
2892 client_session->elog_track.name =
2893 (char *) format (0, "C:%d:S:%d%c", vcm->my_client_index,
2894 client_session_index, 0);
2895 elog_track_register (&vcm->elog_main, &client_session->elog_track);
2898 ELOG_TYPE_DECLARE (e) =
2900 .format = "accept cut-thru: listen_handle:%x from_handle:%x",
2901 .format_args = "i8i8",
2909 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, client_session->elog_track);
2910 ed->handle[0] = listen_vpp_handle;
2911 ed->handle[1] = client_session->vpp_handle;
2914 if (client_session->lcl_addr.is_ip4)
2917 ELOG_TYPE_DECLARE (e2) =
2919 .format = "accept cut-thru: S:%d %d.%d.%d.%d:%d ",
2920 .format_args = "i4i1i1i1i1i2",
2923 CLIB_PACKED (struct {
2930 ELOG_TRACK_DATA (&vcm->elog_main, e2, client_session->elog_track);
2931 ed2->session = client_session_index;
2932 ed2->addr[0] = client_session->lcl_addr.ip46.ip4.as_u8[0];
2933 ed2->addr[1] = client_session->lcl_addr.ip46.ip4.as_u8[1];
2934 ed2->addr[2] = client_session->lcl_addr.ip46.ip4.as_u8[2];
2935 ed2->addr[3] = client_session->lcl_addr.ip46.ip4.as_u8[3];
2936 ed2->port = clib_net_to_host_u16 (client_session->lcl_port);
2941 clib_spinlock_unlock (&vcm->sessions_lockp);
2942 rv = (int) client_session_index;
2948 vppcom_session_connect (uint32_t session_index, vppcom_endpt_t * server_ep)
2950 session_t *session = 0;
2951 int rv, retval = VPPCOM_OK;
2952 u64 vpp_handle = ~0;
2954 VCL_LOCK_AND_GET_SESSION (session_index, &session);
2956 if (PREDICT_FALSE (session->is_vep))
2958 clib_spinlock_unlock (&vcm->sessions_lockp);
2959 clib_warning ("[%d] ERROR: sid %u: cannot connect on an epoll session!",
2960 getpid (), session_index);
2965 vpp_handle = session->vpp_handle;
2966 if (PREDICT_FALSE (session->is_server))
2968 clib_spinlock_unlock (&vcm->sessions_lockp);
2969 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: is in use "
2970 "as a server session!", getpid (), vpp_handle,
2976 if (PREDICT_FALSE (session->state & CLIENT_STATE_OPEN))
2978 if (VPPCOM_DEBUG > 0)
2979 clib_warning ("[%d] vpp handle 0x%llx, sid %u: session already "
2980 "connected to %s %U port %d proto %s, state 0x%x (%s)",
2981 getpid (), vpp_handle, session_index,
2982 session->peer_addr.is_ip4 ? "IPv4" : "IPv6",
2983 format_ip46_address,
2984 &session->peer_addr.ip46, session->peer_addr.is_ip4,
2985 clib_net_to_host_u16 (session->peer_port),
2986 session->proto ? "UDP" : "TCP", session->state,
2987 vppcom_session_state_str (session->state));
2989 clib_spinlock_unlock (&vcm->sessions_lockp);
2993 session->vrf = server_ep->vrf;
2994 session->peer_addr.is_ip4 = server_ep->is_ip4;
2995 session->peer_addr.ip46 = to_ip46 (!server_ep->is_ip4, server_ep->ip);
2996 session->peer_port = server_ep->port;
2998 if (VPPCOM_DEBUG > 0)
2999 clib_warning ("[%d] vpp handle 0x%llx, sid %u: connecting to server "
3000 "%s %U port %d proto %s",
3001 getpid (), vpp_handle, session_index,
3002 session->peer_addr.is_ip4 ? "IPv4" : "IPv6",
3003 format_ip46_address,
3004 &session->peer_addr.ip46, session->peer_addr.is_ip4,
3005 clib_net_to_host_u16 (session->peer_port),
3006 session->proto ? "UDP" : "TCP");
3008 vppcom_send_connect_sock (session, session_index);
3009 clib_spinlock_unlock (&vcm->sessions_lockp);
3012 vppcom_wait_for_session_state_change (session_index, STATE_CONNECT,
3013 vcm->cfg.session_timeout);
3015 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3016 vpp_handle = session->vpp_handle;
3017 clib_spinlock_unlock (&vcm->sessions_lockp);
3020 if (PREDICT_FALSE (retval))
3023 if (VPPCOM_DEBUG > 0)
3024 clib_warning ("[%d] vpp handle 0x%llx, sid %u: connect failed! "
3025 "returning %d (%s)", getpid (), vpp_handle,
3026 session_index, rv, vppcom_retval_str (rv));
3028 else if (VPPCOM_DEBUG > 0)
3029 clib_warning ("[%d] vpp handle 0x%llx, sid %u: connected!",
3030 getpid (), vpp_handle, session_index);
3036 vppcom_session_read_internal (uint32_t session_index, void *buf, int n,
3039 session_t *session = 0;
3040 svm_fifo_t *rx_fifo;
3045 session_state_t state;
3052 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3054 if (PREDICT_FALSE (session->is_vep))
3056 clib_spinlock_unlock (&vcm->sessions_lockp);
3057 clib_warning ("[%d] ERROR: sid %u: cannot read from an epoll session!",
3058 getpid (), session_index);
3063 vpp_handle = session->vpp_handle;
3064 is_server = session->is_server;
3065 is_nonblocking = session->is_nonblocking;
3066 state = session->state;
3067 if (PREDICT_FALSE (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN))))
3069 clib_spinlock_unlock (&vcm->sessions_lockp);
3070 rv = ((state == STATE_DISCONNECT) ?
3071 VPPCOM_ECONNRESET : VPPCOM_ENOTCONN);
3073 if (VPPCOM_DEBUG > 0)
3074 clib_warning ("[%d] vpp handle 0x%llx, sid %u: %s session is "
3075 "not open! state 0x%x (%s), returning %d (%s)",
3076 getpid (), vpp_handle, session_index,
3077 is_server ? "server" : "client", state,
3078 vppcom_session_state_str (state),
3079 rv, vppcom_retval_str (rv));
3083 rx_fifo = ((!session->is_cut_thru || is_server) ?
3084 session->server_rx_fifo : session->server_tx_fifo);
3085 fifo_str = ((!session->is_cut_thru || is_server) ?
3086 "server_rx_fifo" : "server_tx_fifo");
3087 clib_spinlock_unlock (&vcm->sessions_lockp);
3092 n_read = svm_fifo_peek (rx_fifo, 0, n, buf);
3094 n_read = svm_fifo_dequeue_nowait (rx_fifo, n, buf);
3096 while (!is_nonblocking && (n_read <= 0));
3100 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3102 poll_et = (((EPOLLET | EPOLLIN) & session->vep.ev.events) ==
3103 (EPOLLET | EPOLLIN));
3105 session->vep.et_mask |= EPOLLIN;
3107 if (state == STATE_CLOSE_ON_EMPTY)
3109 session_state_t new_state = STATE_DISCONNECT;
3110 rv = VPPCOM_ECONNRESET;
3112 if (VPPCOM_DEBUG > 1)
3114 clib_warning ("[%d] vpp handle 0x%llx, sid %u: Empty fifo "
3115 "with %s session state 0x%x (%s)!"
3116 " Setting state to 0x%x (%s), returning %d (%s)",
3117 getpid (), vpp_handle, session_index,
3118 is_server ? "server" : "client",
3119 state, vppcom_session_state_str (state),
3120 new_state, vppcom_session_state_str (new_state),
3121 rv, vppcom_retval_str (rv));
3124 session->state = new_state;
3129 clib_spinlock_unlock (&vcm->sessions_lockp);
3134 if (VPPCOM_DEBUG > 2)
3137 clib_warning ("[%d] vpp handle 0x%llx, sid %u: read %d bytes "
3138 "from %s (%p)", getpid (), vpp_handle,
3139 session_index, n_read, fifo_str, rx_fifo);
3141 clib_warning ("[%d] vpp handle 0x%llx, sid %u: nothing read! "
3142 "returning %d (%s)", getpid (), vpp_handle,
3143 session_index, rv, vppcom_retval_str (rv));
3150 vppcom_session_read (uint32_t session_index, void *buf, int n)
3152 return (vppcom_session_read_internal (session_index, buf, n, 0));
3156 vppcom_session_peek (uint32_t session_index, void *buf, int n)
3158 return (vppcom_session_read_internal (session_index, buf, n, 1));
3162 vppcom_session_read_ready (session_t * session, u32 session_index)
3164 svm_fifo_t *rx_fifo = 0;
3168 u8 is_server = session->is_server;
3169 session_state_t state = session->state;
3170 u64 vpp_handle = session->vpp_handle;
3172 /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3173 if (PREDICT_FALSE (session->is_vep))
3175 clib_warning ("[%d] ERROR: sid %u: cannot read from an "
3176 "epoll session!", getpid (), session_index);
3181 if (session->is_listen)
3182 ready = clib_fifo_elts (vcm->client_session_index_fifo);
3185 if (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN | STATE_LISTEN)))
3187 rv = ((state == STATE_DISCONNECT) ? VPPCOM_ECONNRESET :
3190 if (VPPCOM_DEBUG > 1)
3191 clib_warning ("[%d] vpp handle 0x%llx, sid %u: %s session is "
3192 "not open! state 0x%x (%s), returning %d (%s)",
3193 getpid (), vpp_handle, session_index,
3194 is_server ? "server" : "client",
3195 state, vppcom_session_state_str (state),
3196 rv, vppcom_retval_str (rv));
3200 rx_fifo = ((!session->is_cut_thru || is_server) ?
3201 session->server_rx_fifo : session->server_tx_fifo);
3203 ready = svm_fifo_max_dequeue (rx_fifo);
3209 ((EPOLLET | EPOLLIN) & session->vep.ev.events) == (EPOLLET | EPOLLIN);
3211 session->vep.et_mask |= EPOLLIN;
3213 if (state == STATE_CLOSE_ON_EMPTY)
3215 rv = VPPCOM_ECONNRESET;
3216 session_state_t new_state = STATE_DISCONNECT;
3218 if (VPPCOM_DEBUG > 1)
3220 clib_warning ("[%d] vpp handle 0x%llx, sid %u: Empty fifo with"
3221 " %s session state 0x%x (%s)! Setting state to "
3222 "0x%x (%s), returning %d (%s)",
3223 getpid (), session_index, vpp_handle,
3224 is_server ? "server" : "client",
3225 state, vppcom_session_state_str (state),
3226 new_state, vppcom_session_state_str (new_state),
3227 rv, vppcom_retval_str (rv));
3229 session->state = new_state;
3235 if (vcm->app_event_queue->cursize &&
3236 !pthread_mutex_trylock (&vcm->app_event_queue->mutex))
3238 u32 i, n_to_dequeue = vcm->app_event_queue->cursize;
3239 session_fifo_event_t e;
3241 for (i = 0; i < n_to_dequeue; i++)
3242 svm_queue_sub_raw (vcm->app_event_queue, (u8 *) & e);
3244 pthread_mutex_unlock (&vcm->app_event_queue->mutex);
3252 vppcom_session_write (uint32_t session_index, void *buf, int n)
3254 session_t *session = 0;
3255 svm_fifo_t *tx_fifo;
3257 session_fifo_event_t evt;
3263 session_state_t state;
3268 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3270 if (PREDICT_FALSE (session->is_vep))
3272 clib_spinlock_unlock (&vcm->sessions_lockp);
3273 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
3274 "cannot write to an epoll session!",
3275 getpid (), session->vpp_handle, session_index);
3281 is_server = session->is_server;
3282 is_nonblocking = session->is_nonblocking;
3283 vpp_handle = session->vpp_handle;
3284 state = session->state;
3285 if (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN)))
3287 rv = ((state == STATE_DISCONNECT) ? VPPCOM_ECONNRESET :
3290 clib_spinlock_unlock (&vcm->sessions_lockp);
3291 if (VPPCOM_DEBUG > 1)
3292 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3293 "%s session is not open! state 0x%x (%s)",
3294 getpid (), vpp_handle, session_index,
3295 is_server ? "server" : "client", state,
3296 vppcom_session_state_str (state));
3300 tx_fifo = ((!session->is_cut_thru || is_server) ?
3301 session->server_tx_fifo : session->server_rx_fifo);
3302 fifo_str = ((!session->is_cut_thru || is_server) ?
3303 "server_tx_fifo" : "server_rx_fifo");
3304 clib_spinlock_unlock (&vcm->sessions_lockp);
3308 n_write = svm_fifo_enqueue_nowait (tx_fifo, n, buf);
3310 while (!is_nonblocking && (n_write <= 0));
3312 /* If event wasn't set, add one */
3313 if (!session->is_cut_thru && (n_write > 0) && svm_fifo_set_event (tx_fifo))
3315 /* Fabricate TX event, send to vpp */
3317 evt.event_type = FIFO_EVENT_APP_TX;
3319 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3320 q = session->vpp_event_queue;
3322 svm_queue_add (q, (u8 *) & evt, 0 /* do wait for mutex */ );
3323 clib_spinlock_unlock (&vcm->sessions_lockp);
3324 if (VPPCOM_DEBUG > 1)
3325 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3326 "added FIFO_EVENT_APP_TX to "
3327 "vpp_event_q %p, n_write %d", getpid (),
3328 vpp_handle, session_index, q, n_write);
3333 VCL_LOCK_AND_GET_SESSION (session_index, &session);
3335 poll_et = (((EPOLLET | EPOLLOUT) & session->vep.ev.events) ==
3336 (EPOLLET | EPOLLOUT));
3338 session->vep.et_mask |= EPOLLOUT;
3340 if (state == STATE_CLOSE_ON_EMPTY)
3342 session_state_t new_state = STATE_DISCONNECT;
3343 rv = VPPCOM_ECONNRESET;
3345 if (VPPCOM_DEBUG > 1)
3347 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3348 "Empty fifo with %s session state 0x%x (%s)!"
3349 " Setting state to 0x%x (%s), returning %d (%s)",
3350 getpid (), vpp_handle, session_index,
3351 is_server ? "server" : "client",
3352 state, vppcom_session_state_str (state),
3353 new_state, vppcom_session_state_str (new_state),
3354 rv, vppcom_retval_str (rv));
3357 session->state = new_state;
3362 clib_spinlock_unlock (&vcm->sessions_lockp);
3367 if (VPPCOM_DEBUG > 2)
3370 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3371 "FIFO-FULL %s (%p)", getpid (), vpp_handle,
3372 session_index, fifo_str, tx_fifo);
3374 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3375 "wrote %d bytes to %s (%p)", getpid (), vpp_handle,
3376 session_index, n_write, fifo_str, tx_fifo);
3383 vppcom_session_write_ready (session_t * session, u32 session_index)
3385 svm_fifo_t *tx_fifo;
3390 u8 is_server = session->is_server;
3391 session_state_t state = session->state;
3393 /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3394 if (PREDICT_FALSE (session->is_vep))
3396 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
3397 "cannot write to an epoll session!",
3398 getpid (), session->vpp_handle, session_index);
3403 if (PREDICT_FALSE (session->is_listen))
3405 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
3406 "cannot write to a listen session!",
3407 getpid (), session->vpp_handle, session_index);
3412 if (!(state & (SERVER_STATE_OPEN | CLIENT_STATE_OPEN)))
3414 session_state_t state = session->state;
3416 rv = ((state == STATE_DISCONNECT) ? VPPCOM_ECONNRESET :
3419 clib_warning ("[%d] ERROR: vpp handle 0x%llx, sid %u: "
3420 "%s session is not open! state 0x%x (%s), "
3421 "returning %d (%s)", getpid (), session->vpp_handle,
3422 session_index, is_server ? "server" : "client",
3423 state, vppcom_session_state_str (state),
3424 rv, vppcom_retval_str (rv));
3428 tx_fifo = ((!session->is_cut_thru || session->is_server) ?
3429 session->server_tx_fifo : session->server_rx_fifo);
3430 fifo_str = ((!session->is_cut_thru || session->is_server) ?
3431 "server_tx_fifo" : "server_rx_fifo");
3433 ready = svm_fifo_max_enqueue (tx_fifo);
3435 if (VPPCOM_DEBUG > 3)
3436 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3437 "peek %s (%p), ready = %d", getpid (),
3438 session->vpp_handle, session_index,
3439 fifo_str, tx_fifo, ready);
3443 poll_et = (((EPOLLET | EPOLLOUT) & session->vep.ev.events) ==
3444 (EPOLLET | EPOLLOUT));
3446 session->vep.et_mask |= EPOLLOUT;
3448 if (state == STATE_CLOSE_ON_EMPTY)
3450 rv = VPPCOM_ECONNRESET;
3451 session_state_t new_state = STATE_DISCONNECT;
3453 if (VPPCOM_DEBUG > 1)
3455 clib_warning ("[%d] vpp handle 0x%llx, sid %u: "
3456 "Empty fifo with %s session "
3457 "state 0x%x (%s)! Setting state to 0x%x (%s), "
3458 "returning %d (%s)", getpid (),
3459 session->vpp_handle, session_index,
3460 is_server ? "server" : "client",
3461 state, vppcom_session_state_str (state),
3462 new_state, vppcom_session_state_str (new_state),
3463 rv, vppcom_retval_str (rv));
3465 session->state = new_state;
3475 vppcom_select (unsigned long n_bits, unsigned long *read_map,
3476 unsigned long *write_map, unsigned long *except_map,
3477 double time_to_wait)
3480 session_t *session = 0;
3481 int rv, bits_set = 0;
3482 f64 timeout = clib_time_now (&vcm->clib_time) + time_to_wait;
3483 u32 minbits = clib_max (n_bits, BITS (uword));
3485 ASSERT (sizeof (clib_bitmap_t) == sizeof (long int));
3487 if (n_bits && read_map)
3489 clib_bitmap_validate (vcm->rd_bitmap, minbits);
3490 clib_memcpy (vcm->rd_bitmap, read_map, vec_len (vcm->rd_bitmap));
3491 memset (read_map, 0, vec_len (vcm->rd_bitmap));
3493 if (n_bits && write_map)
3495 clib_bitmap_validate (vcm->wr_bitmap, minbits);
3496 clib_memcpy (vcm->wr_bitmap, write_map, vec_len (vcm->wr_bitmap));
3497 memset (write_map, 0, vec_len (vcm->wr_bitmap));
3499 if (n_bits && except_map)
3501 clib_bitmap_validate (vcm->ex_bitmap, minbits);
3502 clib_memcpy (vcm->ex_bitmap, except_map, vec_len (vcm->ex_bitmap));
3503 memset (except_map, 0, vec_len (vcm->ex_bitmap));
3513 clib_bitmap_foreach (session_index, vcm->rd_bitmap,
3515 clib_spinlock_lock (&vcm->sessions_lockp);
3516 rv = vppcom_session_at_index (session_index, &session);
3519 clib_spinlock_unlock (&vcm->sessions_lockp);
3520 if (VPPCOM_DEBUG > 1)
3521 clib_warning ("[%d] session %d specified in "
3522 "read_map is closed.", getpid (),
3524 bits_set = VPPCOM_EBADFD;
3528 rv = vppcom_session_read_ready (session, session_index);
3529 clib_spinlock_unlock (&vcm->sessions_lockp);
3530 if (except_map && vcm->ex_bitmap &&
3531 clib_bitmap_get (vcm->ex_bitmap, session_index) &&
3534 // TBD: clib_warning
3535 clib_bitmap_set_no_check (except_map, session_index, 1);
3540 // TBD: clib_warning
3541 clib_bitmap_set_no_check (read_map, session_index, 1);
3549 clib_bitmap_foreach (session_index, vcm->wr_bitmap,
3551 clib_spinlock_lock (&vcm->sessions_lockp);
3552 rv = vppcom_session_at_index (session_index, &session);
3555 clib_spinlock_unlock (&vcm->sessions_lockp);
3556 if (VPPCOM_DEBUG > 0)
3557 clib_warning ("[%d] session %d specified in "
3558 "write_map is closed.", getpid (),
3560 bits_set = VPPCOM_EBADFD;
3564 rv = vppcom_session_write_ready (session, session_index);
3565 clib_spinlock_unlock (&vcm->sessions_lockp);
3566 if (write_map && (rv > 0))
3568 // TBD: clib_warning
3569 clib_bitmap_set_no_check (write_map, session_index, 1);
3577 clib_bitmap_foreach (session_index, vcm->ex_bitmap,
3579 clib_spinlock_lock (&vcm->sessions_lockp);
3580 rv = vppcom_session_at_index (session_index, &session);
3583 clib_spinlock_unlock (&vcm->sessions_lockp);
3584 if (VPPCOM_DEBUG > 1)
3585 clib_warning ("[%d] session %d specified in "
3586 "except_map is closed.", getpid (),
3588 bits_set = VPPCOM_EBADFD;
3592 rv = vppcom_session_read_ready (session, session_index);
3593 clib_spinlock_unlock (&vcm->sessions_lockp);
3596 // TBD: clib_warning
3597 clib_bitmap_set_no_check (except_map, session_index, 1);
3605 while (clib_time_now (&vcm->clib_time) < timeout);
3612 vep_verify_epoll_chain (u32 vep_idx)
3615 vppcom_epoll_t *vep;
3619 if (VPPCOM_DEBUG <= 1)
3622 /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
3623 rv = vppcom_session_at_index (vep_idx, &session);
3624 if (PREDICT_FALSE (rv))
3626 clib_warning ("[%d] ERROR: Invalid vep_idx (%u)!", getpid (), vep_idx);
3629 if (PREDICT_FALSE (!session->is_vep))
3631 clib_warning ("[%d] ERROR: vep_idx (%u) is not a vep!", getpid (),
3635 vep = &session->vep;
3636 clib_warning ("[%d] vep_idx (%u): Dumping epoll chain\n"
3639 " is_vep_session = %u\n"
3640 " next_sid = 0x%x (%u)\n"
3641 " wait_cont_idx = 0x%x (%u)\n"
3642 "}\n", getpid (), vep_idx,
3643 session->is_vep, session->is_vep_session,
3644 vep->next_sid, vep->next_sid,
3645 session->wait_cont_idx, session->wait_cont_idx);
3647 for (sid = vep->next_sid; sid != ~0; sid = vep->next_sid)
3649 rv = vppcom_session_at_index (sid, &session);
3650 if (PREDICT_FALSE (rv))
3652 clib_warning ("[%d] ERROR: Invalid sid (%u)!", getpid (), sid);
3655 if (PREDICT_FALSE (session->is_vep))
3656 clib_warning ("[%d] ERROR: sid (%u) is a vep!", getpid (), vep_idx);
3657 else if (PREDICT_FALSE (!session->is_vep_session))
3659 clib_warning ("[%d] ERROR: session (%u) is not a vep session!",
3663 vep = &session->vep;
3664 if (PREDICT_FALSE (vep->vep_idx != vep_idx))
3665 clib_warning ("[%d] ERROR: session (%u) vep_idx (%u) != "
3666 "vep_idx (%u)!", getpid (),
3667 sid, session->vep.vep_idx, vep_idx);
3668 if (session->is_vep_session)
3670 clib_warning ("vep_idx[%u]: sid 0x%x (%u)\n"
3672 " next_sid = 0x%x (%u)\n"
3673 " prev_sid = 0x%x (%u)\n"
3674 " vep_idx = 0x%x (%u)\n"
3675 " ev.events = 0x%x\n"
3676 " ev.data.u64 = 0x%llx\n"
3680 vep->next_sid, vep->next_sid,
3681 vep->prev_sid, vep->prev_sid,
3682 vep->vep_idx, vep->vep_idx,
3683 vep->ev.events, vep->ev.data.u64, vep->et_mask);
3688 clib_warning ("[%d] vep_idx (%u): Dump complete!\n", getpid (), vep_idx);
3692 vppcom_epoll_create (void)
3694 session_t *vep_session;
3697 clib_spinlock_lock (&vcm->sessions_lockp);
3698 pool_get (vcm->sessions, vep_session);
3699 memset (vep_session, 0, sizeof (*vep_session));
3700 vep_idx = vep_session - vcm->sessions;
3702 vep_session->is_vep = 1;
3703 vep_session->vep.vep_idx = ~0;
3704 vep_session->vep.next_sid = ~0;
3705 vep_session->vep.prev_sid = ~0;
3706 vep_session->wait_cont_idx = ~0;
3707 vep_session->vpp_handle = ~0;
3708 clib_spinlock_unlock (&vcm->sessions_lockp);
3710 if (VPPCOM_DEBUG > 0)
3711 clib_warning ("[%d] Created vep_idx %u / sid %u!",
3712 getpid (), vep_idx, vep_idx);
3714 if (VPPCOM_DEBUG > 0)
3716 vep_session->elog_track.name =
3717 (char *) format (0, "C:%d:VEP:%d%c", vcm->my_client_index,
3719 elog_track_register (&vcm->elog_main, &vep_session->elog_track);
3722 ELOG_TYPE_DECLARE (e) =
3724 .format = "created epoll session:%d",
3725 .format_args = "i4",
3733 ed = ELOG_TRACK_DATA (&vcm->elog_main, e, vep_session->elog_track);
3742 vppcom_epoll_ctl (uint32_t vep_idx, int op, uint32_t session_index,
3743 struct epoll_event *event)
3745 session_t *vep_session;
3749 if (vep_idx == session_index)
3751 clib_warning ("[%d] ERROR: vep_idx == session_index (%u)!",
3752 getpid (), vep_idx);
3753 return VPPCOM_EINVAL;
3756 clib_spinlock_lock (&vcm->sessions_lockp);
3757 rv = vppcom_session_at_index (vep_idx, &vep_session);
3758 if (PREDICT_FALSE (rv))
3760 clib_warning ("[%d] ERROR: Invalid vep_idx (%u)!", vep_idx);
3763 if (PREDICT_FALSE (!vep_session->is_vep))
3765 clib_warning ("[%d] ERROR: vep_idx (%u) is not a vep!",
3766 getpid (), vep_idx);
3771 ASSERT (vep_session->vep.vep_idx == ~0);
3772 ASSERT (vep_session->vep.prev_sid == ~0);
3774 rv = vppcom_session_at_index (session_index, &session);
3775 if (PREDICT_FALSE (rv))
3777 if (VPPCOM_DEBUG > 0)
3778 clib_warning ("[%d] ERROR: Invalid session_index (%u)!",
3779 getpid (), session_index);
3782 if (PREDICT_FALSE (session->is_vep))
3784 clib_warning ("ERROR: session_index (%u) is a vep!", vep_idx);
3792 if (PREDICT_FALSE (!event))
3794 clib_warning ("[%d] ERROR: EPOLL_CTL_ADD: NULL pointer to "
3795 "epoll_event structure!", getpid ());
3799 if (vep_session->vep.next_sid != ~0)
3801 session_t *next_session;
3802 rv = vppcom_session_at_index (vep_session->vep.next_sid,
3804 if (PREDICT_FALSE (rv))
3806 clib_warning ("[%d] ERROR: EPOLL_CTL_ADD: Invalid "
3807 "vep.next_sid (%u) on vep_idx (%u)!",
3808 getpid (), vep_session->vep.next_sid, vep_idx);
3811 ASSERT (next_session->vep.prev_sid == vep_idx);
3812 next_session->vep.prev_sid = session_index;
3814 session->vep.next_sid = vep_session->vep.next_sid;
3815 session->vep.prev_sid = vep_idx;
3816 session->vep.vep_idx = vep_idx;
3817 session->vep.et_mask = VEP_DEFAULT_ET_MASK;
3818 session->vep.ev = *event;
3819 session->is_vep = 0;
3820 session->is_vep_session = 1;
3821 vep_session->vep.next_sid = session_index;
3822 if (VPPCOM_DEBUG > 1)
3823 clib_warning ("[%d] EPOLL_CTL_ADD: vep_idx %u, sid %u, events 0x%x,"
3824 " data 0x%llx!", getpid (), vep_idx, session_index,
3825 event->events, event->data.u64);
3829 if (PREDICT_FALSE (!event))
3831 clib_warning ("[%d] ERROR: EPOLL_CTL_MOD: NULL pointer to "
3832 "epoll_event structure!", getpid ());
3836 else if (PREDICT_FALSE (!session->is_vep_session))
3838 clib_warning ("[%d] ERROR: sid %u EPOLL_CTL_MOD: "
3839 "not a vep session!", getpid (), session_index);
3843 else if (PREDICT_FALSE (session->vep.vep_idx != vep_idx))
3845 clib_warning ("[%d] ERROR: sid %u EPOLL_CTL_MOD: "
3846 "vep_idx (%u) != vep_idx (%u)!",
3847 getpid (), session_index,
3848 session->vep.vep_idx, vep_idx);
3852 session->vep.et_mask = VEP_DEFAULT_ET_MASK;
3853 session->vep.ev = *event;
3854 if (VPPCOM_DEBUG > 1)
3855 clib_warning ("[%d] EPOLL_CTL_MOD: vep_idx %u, sid %u, events 0x%x,"
3856 " data 0x%llx!", getpid (), vep_idx, session_index,
3857 event->events, event->data.u64);
3861 if (PREDICT_FALSE (!session->is_vep_session))
3863 clib_warning ("[%d] ERROR: sid %u EPOLL_CTL_DEL: "
3864 "not a vep session!", getpid (), session_index);
3868 else if (PREDICT_FALSE (session->vep.vep_idx != vep_idx))
3870 clib_warning ("[%d] ERROR: sid %u EPOLL_CTL_DEL: "
3871 "vep_idx (%u) != vep_idx (%u)!",
3872 getpid (), session_index,
3873 session->vep.vep_idx, vep_idx);
3878 vep_session->wait_cont_idx =
3879 (vep_session->wait_cont_idx == session_index) ?
3880 session->vep.next_sid : vep_session->wait_cont_idx;
3882 if (session->vep.prev_sid == vep_idx)
3883 vep_session->vep.next_sid = session->vep.next_sid;
3886 session_t *prev_session;
3887 rv = vppcom_session_at_index (session->vep.prev_sid, &prev_session);
3888 if (PREDICT_FALSE (rv))
3890 clib_warning ("[%d] ERROR: EPOLL_CTL_DEL: Invalid "
3891 "vep.prev_sid (%u) on sid (%u)!",
3892 getpid (), session->vep.prev_sid, session_index);
3895 ASSERT (prev_session->vep.next_sid == session_index);
3896 prev_session->vep.next_sid = session->vep.next_sid;
3898 if (session->vep.next_sid != ~0)
3900 session_t *next_session;
3901 rv = vppcom_session_at_index (session->vep.next_sid, &next_session);
3902 if (PREDICT_FALSE (rv))
3904 clib_warning ("[%d] ERROR: EPOLL_CTL_DEL: Invalid "
3905 "vep.next_sid (%u) on sid (%u)!",
3906 getpid (), session->vep.next_sid, session_index);
3909 ASSERT (next_session->vep.prev_sid == session_index);
3910 next_session->vep.prev_sid = session->vep.prev_sid;
3913 memset (&session->vep, 0, sizeof (session->vep));
3914 session->vep.next_sid = ~0;
3915 session->vep.prev_sid = ~0;
3916 session->vep.vep_idx = ~0;
3917 session->is_vep_session = 0;
3918 if (VPPCOM_DEBUG > 1)
3919 clib_warning ("[%d] EPOLL_CTL_DEL: vep_idx %u, sid %u!",
3920 getpid (), vep_idx, session_index);
3924 clib_warning ("[%d] ERROR: Invalid operation (%d)!", getpid (), op);
3928 vep_verify_epoll_chain (vep_idx);
3931 clib_spinlock_unlock (&vcm->sessions_lockp);
3936 vppcom_epoll_wait (uint32_t vep_idx, struct epoll_event *events,
3937 int maxevents, double wait_for_time)
3939 session_t *vep_session;
3941 f64 timeout = clib_time_now (&vcm->clib_time) + wait_for_time;
3942 u32 keep_trying = 1;
3944 u32 vep_next_sid, wait_cont_idx;
3947 if (PREDICT_FALSE (maxevents <= 0))
3949 clib_warning ("[%d] ERROR: Invalid maxevents (%d)!",
3950 getpid (), maxevents);
3951 return VPPCOM_EINVAL;
3953 memset (events, 0, sizeof (*events) * maxevents);
3955 VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
3956 vep_next_sid = vep_session->vep.next_sid;
3957 is_vep = vep_session->is_vep;
3958 wait_cont_idx = vep_session->wait_cont_idx;
3959 clib_spinlock_unlock (&vcm->sessions_lockp);
3961 if (PREDICT_FALSE (!is_vep))
3963 clib_warning ("[%d] ERROR: vep_idx (%u) is not a vep!",
3964 getpid (), vep_idx);
3968 if (PREDICT_FALSE (vep_next_sid == ~0))
3970 if (VPPCOM_DEBUG > 0)
3971 clib_warning ("[%d] WARNING: vep_idx (%u) is empty!",
3972 getpid (), vep_idx);
3982 for (sid = (wait_cont_idx == ~0) ? vep_next_sid : wait_cont_idx;
3983 sid != ~0; sid = next_sid)
3985 u32 session_events, et_mask, clear_et_mask, session_vep_idx;
3986 u8 add_event, is_vep_session;
3988 u64 session_ev_data;
3990 VCL_LOCK_AND_GET_SESSION (sid, &session);
3991 next_sid = session->vep.next_sid;
3992 session_events = session->vep.ev.events;
3993 et_mask = session->vep.et_mask;
3994 is_vep = session->is_vep;
3995 is_vep_session = session->is_vep_session;
3996 session_vep_idx = session->vep.vep_idx;
3997 session_ev_data = session->vep.ev.data.u64;
3998 clib_spinlock_unlock (&vcm->sessions_lockp);
4000 if (PREDICT_FALSE (is_vep))
4002 if (VPPCOM_DEBUG > 0)
4003 clib_warning ("[%d] ERROR: sid (%u) is a vep!",
4004 getpid (), vep_idx);
4008 if (PREDICT_FALSE (!is_vep_session))
4010 if (VPPCOM_DEBUG > 0)
4011 clib_warning ("[%d] ERROR: session (%u) is not "
4012 "a vep session!", getpid (), sid);
4016 if (PREDICT_FALSE (session_vep_idx != vep_idx))
4018 clib_warning ("[%d] ERROR: session (%u) "
4019 "vep_idx (%u) != vep_idx (%u)!",
4020 getpid (), sid, session->vep.vep_idx, vep_idx);
4025 add_event = clear_et_mask = 0;
4027 if (EPOLLIN & session_events)
4029 VCL_LOCK_AND_GET_SESSION (sid, &session);
4030 ready = vppcom_session_read_ready (session, sid);
4031 clib_spinlock_unlock (&vcm->sessions_lockp);
4032 if ((ready > 0) && (EPOLLIN & et_mask))
4035 events[num_ev].events |= EPOLLIN;
4036 if (((EPOLLET | EPOLLIN) & session_events) ==
4037 (EPOLLET | EPOLLIN))
4038 clear_et_mask |= EPOLLIN;
4045 case VPPCOM_ECONNRESET:
4046 events[num_ev].events |= EPOLLHUP | EPOLLRDHUP;
4050 events[num_ev].events |= EPOLLERR;
4056 if (EPOLLOUT & session_events)
4058 VCL_LOCK_AND_GET_SESSION (sid, &session);
4059 ready = vppcom_session_write_ready (session, sid);
4060 clib_spinlock_unlock (&vcm->sessions_lockp);
4061 if ((ready > 0) && (EPOLLOUT & et_mask))
4064 events[num_ev].events |= EPOLLOUT;
4065 if (((EPOLLET | EPOLLOUT) & session_events) ==
4066 (EPOLLET | EPOLLOUT))
4067 clear_et_mask |= EPOLLOUT;
4074 case VPPCOM_ECONNRESET:
4075 events[num_ev].events |= EPOLLHUP;
4079 events[num_ev].events |= EPOLLERR;
4087 events[num_ev].data.u64 = session_ev_data;
4088 if (EPOLLONESHOT & session_events)
4090 VCL_LOCK_AND_GET_SESSION (sid, &session);
4091 session->vep.ev.events = 0;
4092 clib_spinlock_unlock (&vcm->sessions_lockp);
4095 if (num_ev == maxevents)
4097 VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
4098 vep_session->wait_cont_idx = next_sid;
4099 clib_spinlock_unlock (&vcm->sessions_lockp);
4103 if (wait_cont_idx != ~0)
4106 next_sid = vep_next_sid;
4107 else if (next_sid == wait_cont_idx)
4111 if (wait_for_time != -1)
4112 keep_trying = (clib_time_now (&vcm->clib_time) <= timeout) ? 1 : 0;
4114 while ((num_ev == 0) && keep_trying);
4116 if (wait_cont_idx != ~0)
4118 VCL_LOCK_AND_GET_SESSION (vep_idx, &vep_session);
4119 vep_session->wait_cont_idx = ~0;
4120 clib_spinlock_unlock (&vcm->sessions_lockp);
4123 return (rv != VPPCOM_OK) ? rv : num_ev;
4127 vppcom_session_attr (uint32_t session_index, uint32_t op,
4128 void *buffer, uint32_t * buflen)
4132 u32 *flags = buffer;
4133 vppcom_endpt_t *ep = buffer;
4135 VCL_LOCK_AND_GET_SESSION (session_index, &session);
4138 case VPPCOM_ATTR_GET_NREAD:
4139 rv = vppcom_session_read_ready (session, session_index);
4140 if (VPPCOM_DEBUG > 2)
4141 clib_warning ("[%d] VPPCOM_ATTR_GET_NREAD: sid %u, nread = %d",
4145 case VPPCOM_ATTR_GET_NWRITE:
4146 rv = vppcom_session_write_ready (session, session_index);
4147 if (VPPCOM_DEBUG > 2)
4148 clib_warning ("[%d] VPPCOM_ATTR_GET_NWRITE: sid %u, nwrite = %d",
4149 getpid (), session_index, rv);
4152 case VPPCOM_ATTR_GET_FLAGS:
4153 if (buffer && buflen && (*buflen >= sizeof (*flags)))
4155 *flags = O_RDWR | ((session->is_nonblocking) ? O_NONBLOCK : 0);
4156 *buflen = sizeof (*flags);
4157 if (VPPCOM_DEBUG > 2)
4158 clib_warning ("[%d] VPPCOM_ATTR_GET_FLAGS: sid %u, "
4159 "flags = 0x%08x, is_nonblocking = %u", getpid (),
4160 session_index, *flags, session->is_nonblocking);
4166 case VPPCOM_ATTR_SET_FLAGS:
4167 if (buffer && buflen && (*buflen >= sizeof (*flags)))
4169 session->is_nonblocking = (*flags & O_NONBLOCK) ? 1 : 0;
4170 if (VPPCOM_DEBUG > 2)
4171 clib_warning ("[%d] VPPCOM_ATTR_SET_FLAGS: sid %u, "
4172 "flags = 0x%08x, is_nonblocking = %u",
4173 getpid (), session_index, *flags,
4174 session->is_nonblocking);
4180 case VPPCOM_ATTR_GET_PEER_ADDR:
4181 if (buffer && buflen && (*buflen >= sizeof (*ep)) && ep->ip)
4183 ep->vrf = session->vrf;
4184 ep->is_ip4 = session->peer_addr.is_ip4;
4185 ep->port = session->peer_port;
4186 if (session->peer_addr.is_ip4)
4187 clib_memcpy (ep->ip, &session->peer_addr.ip46.ip4,
4188 sizeof (ip4_address_t));
4190 clib_memcpy (ep->ip, &session->peer_addr.ip46.ip6,
4191 sizeof (ip6_address_t));
4192 *buflen = sizeof (*ep);
4193 if (VPPCOM_DEBUG > 1)
4194 clib_warning ("[%d] VPPCOM_ATTR_GET_PEER_ADDR: sid %u, is_ip4 = "
4195 "%u, addr = %U, port %u", getpid (),
4196 session_index, ep->is_ip4, format_ip46_address,
4197 &session->peer_addr.ip46, ep->is_ip4,
4198 clib_net_to_host_u16 (ep->port));
4204 case VPPCOM_ATTR_GET_LCL_ADDR:
4205 if (buffer && buflen && (*buflen >= sizeof (*ep)) && ep->ip)
4207 ep->vrf = session->vrf;
4208 ep->is_ip4 = session->lcl_addr.is_ip4;
4209 ep->port = session->lcl_port;
4210 if (session->lcl_addr.is_ip4)
4211 clib_memcpy (ep->ip, &session->lcl_addr.ip46.ip4,
4212 sizeof (ip4_address_t));
4214 clib_memcpy (ep->ip, &session->lcl_addr.ip46.ip6,
4215 sizeof (ip6_address_t));
4216 *buflen = sizeof (*ep);
4217 if (VPPCOM_DEBUG > 1)
4218 clib_warning ("[%d] VPPCOM_ATTR_GET_LCL_ADDR: sid %u, is_ip4 = "
4219 "%u, addr = %U port %d", getpid (),
4220 session_index, ep->is_ip4, format_ip46_address,
4221 &session->lcl_addr.ip46, ep->is_ip4,
4222 clib_net_to_host_u16 (ep->port));
4228 case VPPCOM_ATTR_SET_REUSEADDR:
4231 case VPPCOM_ATTR_SET_BROADCAST:
4234 case VPPCOM_ATTR_SET_V6ONLY:
4237 case VPPCOM_ATTR_SET_KEEPALIVE:
4240 case VPPCOM_ATTR_SET_TCP_KEEPIDLE:
4243 case VPPCOM_ATTR_SET_TCP_KEEPINTVL:
4252 clib_spinlock_unlock (&vcm->sessions_lockp);
4257 vppcom_session_recvfrom (uint32_t session_index, void *buffer,
4258 uint32_t buflen, int flags, vppcom_endpt_t * ep)
4261 session_t *session = 0;
4265 clib_spinlock_lock (&vcm->sessions_lockp);
4266 rv = vppcom_session_at_index (session_index, &session);
4267 if (PREDICT_FALSE (rv))
4269 clib_spinlock_unlock (&vcm->sessions_lockp);
4270 if (VPPCOM_DEBUG > 0)
4271 clib_warning ("[%d] invalid session, sid (%u) has been closed!",
4272 getpid (), session_index);
4274 clib_spinlock_unlock (&vcm->sessions_lockp);
4277 ep->vrf = session->vrf;
4278 ep->is_ip4 = session->peer_addr.is_ip4;
4279 ep->port = session->peer_port;
4280 if (session->peer_addr.is_ip4)
4281 clib_memcpy (ep->ip, &session->peer_addr.ip46.ip4,
4282 sizeof (ip4_address_t));
4284 clib_memcpy (ep->ip, &session->peer_addr.ip46.ip6,
4285 sizeof (ip6_address_t));
4286 clib_spinlock_unlock (&vcm->sessions_lockp);
4290 rv = vppcom_session_read (session_index, buffer, buflen);
4291 else if (flags & MSG_PEEK)
4292 rv = vppcom_session_peek (session_index, buffer, buflen);
4295 clib_warning ("[%d] Unsupport flags for recvfrom %d", getpid (), flags);
4296 rv = VPPCOM_EAFNOSUPPORT;
4304 vppcom_session_sendto (uint32_t session_index, void *buffer,
4305 uint32_t buflen, int flags, vppcom_endpt_t * ep)
4308 return VPPCOM_EINVAL;
4313 return VPPCOM_EINVAL;
4318 // TBD check the flags and do the right thing
4319 if (VPPCOM_DEBUG > 2)
4320 clib_warning ("[%d] handling flags 0x%u (%d) not implemented yet.",
4321 getpid (), flags, flags);
4324 return (vppcom_session_write (session_index, buffer, buflen));
4328 * fd.io coding-style-patch-verification: ON
4331 * eval: (c-set-style "gnu")