+static const char *
+vcl_bapi_app_state_str (vcl_bapi_app_state_t state)
+{
+ char *st;
+
+ switch (state)
+ {
+ case STATE_APP_START:
+ st = "STATE_APP_START";
+ break;
+
+ case STATE_APP_CONN_VPP:
+ st = "STATE_APP_CONN_VPP";
+ break;
+
+ case STATE_APP_ENABLED:
+ st = "STATE_APP_ENABLED";
+ break;
+
+ case STATE_APP_ATTACHED:
+ st = "STATE_APP_ATTACHED";
+ break;
+
+ default:
+ st = "UNKNOWN_APP_STATE";
+ break;
+ }
+
+ return st;
+}
+
+static int
+vcl_bapi_wait_for_wrk_state_change (vcl_bapi_app_state_t app_state)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+ f64 timeout = clib_time_now (&wrk->clib_time) + vcm->cfg.app_timeout;
+
+ while (clib_time_now (&wrk->clib_time) < timeout)
+ {
+ if (wrk->bapi_app_state == app_state)
+ return VPPCOM_OK;
+ if (wrk->bapi_app_state == STATE_APP_FAILED)
+ return VPPCOM_ECONNABORTED;
+ }
+ VDBG (0, "timeout waiting for state %s (%d)",
+ vcl_bapi_app_state_str (app_state), app_state);
+ vcl_evt (VCL_EVT_SESSION_TIMEOUT, vcm, bapi_app_state);
+
+ return VPPCOM_ETIMEDOUT;
+}
+
+static int
+vcl_bapi_session_enable (void)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+ int rv;
+
+ if (wrk->bapi_app_state != STATE_APP_ENABLED)
+ {
+ vcl_bapi_send_session_enable_disable (1 /* is_enabled == TRUE */ );
+ rv = vcl_bapi_wait_for_wrk_state_change (STATE_APP_ENABLED);
+ if (PREDICT_FALSE (rv))
+ {
+ VDBG (0, "application session enable timed out! returning %d (%s)",
+ rv, vppcom_retval_str (rv));
+ return rv;
+ }
+ }
+ return VPPCOM_OK;
+}
+
+static int
+vcl_bapi_init (void)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+ int rv;
+
+ wrk->bapi_app_state = STATE_APP_START;
+ vcl_bapi_init_error_string_table ();
+ rv = vcl_bapi_connect_to_vpp ();
+ if (rv)
+ {
+ VERR ("couldn't connect to VPP!");
+ return rv;
+ }
+ VDBG (0, "sending session enable");
+ rv = vcl_bapi_session_enable ();
+ if (rv)
+ {
+ VERR ("vppcom_app_session_enable() failed!");
+ return rv;
+ }
+
+ return 0;
+}
+
+int
+vcl_bapi_attach (void)
+{
+ int rv;
+
+ /* API hookup and connect to VPP */
+ if ((rv = vcl_bapi_init ()))
+ return rv;
+
+ vcl_bapi_send_attach ();
+ rv = vcl_bapi_wait_for_wrk_state_change (STATE_APP_ATTACHED);
+ if (PREDICT_FALSE (rv))
+ {
+ VDBG (0, "application attach timed out! returning %d (%s)", rv,
+ vppcom_retval_str (rv));
+ return rv;
+ }
+
+ return 0;
+}
+
+int
+vcl_bapi_app_worker_add (void)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+
+ if (vcl_bapi_connect_to_vpp ())
+ return -1;
+
+ wrk->bapi_app_state = STATE_APP_ADDING_WORKER;
+ vcl_bapi_send_app_worker_add_del (1 /* is_add */ );
+ if (vcl_bapi_wait_for_wrk_state_change (STATE_APP_READY))
+ return -1;
+ return 0;
+}
+
+void
+vcl_bapi_app_worker_del (vcl_worker_t * wrk)
+{
+ /* Notify vpp that the worker is going away */
+ if (wrk->wrk_index == vcl_get_worker_index ())
+ vcl_bapi_send_app_worker_add_del (0 /* is_add */ );
+ else
+ vcl_bapi_send_child_worker_del (wrk);
+
+ /* Disconnect the binary api */
+ if (vec_len (vcm->workers) == 1)
+ vcl_bapi_disconnect_from_vpp ();
+ else
+ vl_client_send_disconnect (1 /* vpp should cleanup */ );
+}
+
+int
+vcl_bapi_recv_fds (vcl_worker_t * wrk, int *fds, int n_fds)
+{
+ clib_error_t *err;
+
+ if ((err = vl_socket_client_recv_fd_msg2 (&wrk->bapi_sock_ctx, fds, n_fds,
+ 5)))
+ {
+ clib_error_report (err);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+vcl_bapi_add_cert_key_pair (vppcom_cert_key_pair_t *ckpair)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+
+ if (ckpair->key_len == 0 || ckpair->key_len == ~0)
+ return VPPCOM_EINVAL;
+
+ vcl_bapi_send_app_add_cert_key_pair (ckpair);
+ wrk->bapi_app_state = STATE_APP_ADDING_TLS_DATA;
+ vcl_bapi_wait_for_wrk_state_change (STATE_APP_READY);
+ if (wrk->bapi_app_state == STATE_APP_READY)
+ return wrk->bapi_return;
+ return VPPCOM_EFAULT;
+}
+
+int
+vcl_bapi_del_cert_key_pair (u32 ckpair_index)
+{
+ /* Don't wait for reply */
+ vcl_bapi_send_app_del_cert_key_pair (ckpair_index);
+ return 0;
+}
+
+int
+vcl_bapi_worker_set (void)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+ int i;
+
+ /* Find the first worker with the same pid */
+ for (i = 0; i < vec_len (vcm->workers); i++)
+ {
+ if (i == wrk->wrk_index)
+ continue;
+ if (vcm->workers[i].current_pid == wrk->current_pid)
+ {
+ wrk->vl_input_queue = vcm->workers[i].vl_input_queue;
+ wrk->api_client_handle = vcm->workers[i].api_client_handle;
+ return 0;
+ }
+ }
+ return -1;
+}
+