+ }
+ else
+ {
+ events[*num_ev].events = EPOLLHUP;
+ }
+ session_evt_data = s->vep.ev.data.u64;
+ s->vep.ev.events = 0;
+ break;
+ case SESSION_CTRL_EVT_BOUND:
+ vcl_session_bound_handler (wrk, (session_bound_msg_t *) e->data);
+ break;
+ case SESSION_CTRL_EVT_RESET:
+ if (!e->postponed)
+ {
+ sid =
+ vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data);
+ s = vcl_session_get (wrk, sid);
+ }
+ else
+ {
+ sid = e->session_index;
+ s = vcl_session_get (wrk, sid);
+ s->flags &= ~VCL_SESSION_F_PENDING_DISCONNECT;
+ }
+ if (vcl_session_is_closed (s) || !vcl_ep_session_needs_evt (s, EPOLLHUP))
+ {
+ if (s && (s->flags & VCL_SESSION_F_PENDING_FREE))
+ vcl_session_free (wrk, s);
+ break;
+ }
+ session_events = s->vep.ev.events;
+ add_event = 1;
+ events[*num_ev].events = EPOLLERR | EPOLLHUP;
+ if ((EPOLLRDHUP & session_events) &&
+ (s->flags & VCL_SESSION_F_RD_SHUTDOWN))
+ {
+ events[*num_ev].events |= EPOLLRDHUP;
+ }
+ if ((EPOLLIN & session_events) && (s->flags & VCL_SESSION_F_RD_SHUTDOWN))
+ {
+ events[*num_ev].events |= EPOLLIN;
+ }
+ session_evt_data = s->vep.ev.data.u64;
+ s->vep.ev.events = 0;
+ break;
+ case SESSION_CTRL_EVT_UNLISTEN_REPLY:
+ vcl_session_unlisten_reply_handler (wrk, e->data);
+ break;
+ case SESSION_CTRL_EVT_MIGRATED:
+ vcl_session_migrated_handler (wrk, e->data);
+ break;
+ case SESSION_CTRL_EVT_CLEANUP:
+ vcl_session_cleanup_handler (wrk, e->data);
+ break;
+ case SESSION_CTRL_EVT_REQ_WORKER_UPDATE:
+ vcl_session_req_worker_update_handler (wrk, e->data);
+ break;
+ case SESSION_CTRL_EVT_WORKER_UPDATE_REPLY:
+ vcl_session_worker_update_reply_handler (wrk, e->data);
+ break;
+ case SESSION_CTRL_EVT_APP_ADD_SEGMENT:
+ vcl_session_app_add_segment_handler (wrk, e->data);
+ break;
+ case SESSION_CTRL_EVT_APP_DEL_SEGMENT:
+ vcl_session_app_del_segment_handler (wrk, e->data);
+ break;
+ case SESSION_CTRL_EVT_APP_WRK_RPC:
+ vcl_worker_rpc_handler (wrk, e->data);
+ break;
+ default:
+ VDBG (0, "unhandled: %u", e->event_type);
+ break;
+ }
+
+ if (add_event)
+ {
+ ASSERT (s->flags & VCL_SESSION_F_IS_VEP_SESSION);
+ events[*num_ev].data.u64 = session_evt_data;
+ if (EPOLLONESHOT & session_events)
+ {
+ s = vcl_session_get (wrk, sid);
+ if (!(events[*num_ev].events & EPOLLHUP))
+ s->vep.ev.events = EPOLLHUP | EPOLLERR;
+ }
+ else if (!(EPOLLET & session_events))
+ {
+ s = vcl_session_get (wrk, sid);
+ if (s->vep.lt_next == VCL_INVALID_SESSION_INDEX)
+ vcl_epoll_lt_add (wrk, s);
+ }
+ *num_ev += 1;
+ }
+}
+
+static int
+vcl_epoll_wait_handle_mq (vcl_worker_t * wrk, svm_msg_q_t * mq,
+ struct epoll_event *events, u32 maxevents,
+ double wait_for_time, u32 * num_ev)
+{
+ svm_msg_q_msg_t *msg;
+ session_event_t *e;
+ int i;
+
+ if (vec_len (wrk->mq_msg_vector) && svm_msg_q_is_empty (mq))
+ goto handle_dequeued;
+
+ if (svm_msg_q_is_empty (mq))
+ {
+ if (!wait_for_time)
+ return 0;
+ else if (wait_for_time < 0)
+ svm_msg_q_wait (mq, SVM_MQ_WAIT_EMPTY);
+ else
+ {
+ if (svm_msg_q_timedwait (mq, wait_for_time / 1e3))
+ return 0;
+ }
+ }
+ ASSERT (maxevents > *num_ev);
+ vcl_mq_dequeue_batch (wrk, mq, ~0);
+
+handle_dequeued:
+ for (i = 0; i < vec_len (wrk->mq_msg_vector); i++)
+ {
+ msg = vec_elt_at_index (wrk->mq_msg_vector, i);
+ e = svm_msg_q_msg_data (mq, msg);
+ if (*num_ev < maxevents)
+ vcl_epoll_wait_handle_mq_event (wrk, e, events, num_ev);
+ else
+ vcl_handle_mq_event (wrk, e);
+ svm_msg_q_free_msg (mq, msg);
+ }
+ vec_reset_length (wrk->mq_msg_vector);
+ vcl_handle_pending_wrk_updates (wrk);
+ return *num_ev;
+}
+
+static int
+vppcom_epoll_wait_condvar (vcl_worker_t *wrk, struct epoll_event *events,
+ int maxevents, u32 n_evts, double timeout_ms)
+{
+ double end = -1;
+
+ if (!n_evts)
+ {
+ if (timeout_ms > 0)
+ end = clib_time_now (&wrk->clib_time) + (timeout_ms / 1e3);
+ }
+
+ do
+ {
+ vcl_epoll_wait_handle_mq (wrk, wrk->app_event_queue, events, maxevents,
+ timeout_ms, &n_evts);
+ if (n_evts || !timeout_ms)
+ return n_evts;
+ }
+ while (end == -1 || clib_time_now (&wrk->clib_time) < end);
+
+ return 0;
+}
+
+static int
+vppcom_epoll_wait_eventfd (vcl_worker_t *wrk, struct epoll_event *events,
+ int maxevents, u32 n_evts, double timeout_ms)
+{
+ int __clib_unused n_read;
+ vcl_mq_evt_conn_t *mqc;
+ int n_mq_evts, i;
+ double end = -1;
+ u64 buf;
+
+ if (PREDICT_FALSE (wrk->api_client_handle == ~0))
+ {
+ vcl_api_retry_attach (wrk);
+ return n_evts;
+ }
+
+ vec_validate (wrk->mq_events, pool_elts (wrk->mq_evt_conns));
+ if (!n_evts)
+ {
+ if (timeout_ms > 0)
+ end = clib_time_now (&wrk->clib_time) + (timeout_ms / 1e3);
+ }
+
+ do
+ {
+ n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events,
+ vec_len (wrk->mq_events), timeout_ms);
+ if (n_mq_evts < 0)
+ {
+ VDBG (0, "epoll_wait error %u", errno);
+ return n_evts;
+ }
+
+ for (i = 0; i < n_mq_evts; i++)
+ {
+ if (PREDICT_FALSE (wrk->mq_events[i].data.u32 == ~0))
+ {
+ /* api socket was closed */
+ vcl_api_handle_disconnect (wrk);
+ continue;
+ }
+
+ mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32);
+ n_read = read (mqc->mq_fd, &buf, sizeof (buf));
+ vcl_epoll_wait_handle_mq (wrk, mqc->mq, events, maxevents, 0,
+ &n_evts);
+ }
+
+ if (n_evts || !timeout_ms)
+ return n_evts;
+ }
+ while (end == -1 || clib_time_now (&wrk->clib_time) < end);
+
+ return 0;
+}
+
+static void
+vcl_epoll_wait_handle_lt (vcl_worker_t *wrk, struct epoll_event *events,
+ int maxevents, u32 *n_evts)
+{
+ u32 add_event = 0, evt_flags = 0, next, *to_remove = 0, *si;
+ vcl_session_t *s;
+ u64 evt_data;
+ int rv;
+
+ ASSERT (wrk->ep_lt_current != VCL_INVALID_SESSION_INDEX);
+ if (*n_evts >= maxevents)
+ return;
+
+ next = wrk->ep_lt_current;
+ do
+ {
+ s = vcl_session_get (wrk, next);
+ next = s->vep.lt_next;
+
+ if (s->vep.ev.events == 0)
+ {
+ vec_add1 (to_remove, s->session_index);
+ continue;
+ }
+ if ((s->vep.ev.events & EPOLLIN) && (rv = vcl_session_read_ready (s)))
+ {
+ add_event = 1;
+ evt_flags |= rv > 0 ? EPOLLIN : EPOLLHUP | EPOLLRDHUP;
+ evt_data = s->vep.ev.data.u64;
+ }
+ if ((s->vep.ev.events & EPOLLOUT) && (rv = vcl_session_write_ready (s)))
+ {
+ add_event = 1;
+ evt_flags |= rv > 0 ? EPOLLOUT : EPOLLHUP | EPOLLRDHUP;
+ evt_data = s->vep.ev.data.u64;
+ }
+ if (!add_event && s->session_state > VCL_STATE_READY)
+ {
+ add_event = 1;
+ evt_flags |= EPOLLHUP | EPOLLRDHUP;
+ evt_data = s->vep.ev.data.u64;
+ }
+ if (add_event)
+ {
+ events[*n_evts].events = evt_flags;
+ events[*n_evts].data.u64 = evt_data;
+ *n_evts += 1;
+ add_event = 0;
+ evt_flags = 0;
+ if (EPOLLONESHOT & s->vep.ev.events)
+ s->vep.ev.events = EPOLLHUP | EPOLLERR;
+ if (evt_flags & EPOLLHUP)
+ s->vep.ev.events = 0;
+ if (*n_evts == maxevents)
+ {
+ wrk->ep_lt_current = next;
+ break;
+ }
+ }
+ else
+ {
+ vec_add1 (to_remove, s->session_index);
+ }
+ }
+ while (next != wrk->ep_lt_current);
+
+ vec_foreach (si, to_remove)
+ {
+ s = vcl_session_get (wrk, *si);
+ vcl_epoll_lt_del (wrk, s);
+ }
+ vec_free (to_remove);
+}
+
+int
+vppcom_epoll_wait (uint32_t vep_handle, struct epoll_event *events,
+ int maxevents, double wait_for_time)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+ vcl_session_t *vep_session;
+ u32 n_evts = 0;
+ int i;
+
+ if (PREDICT_FALSE (maxevents <= 0))
+ {
+ VDBG (0, "ERROR: Invalid maxevents (%d)!", maxevents);
+ return VPPCOM_EINVAL;
+ }
+
+ vep_session = vcl_session_get_w_handle (wrk, vep_handle);
+ if (!vep_session)
+ return VPPCOM_EBADFD;
+
+ if (PREDICT_FALSE (!(vep_session->flags & VCL_SESSION_F_IS_VEP)))
+ {
+ VDBG (0, "ERROR: vep_idx (%u) is not a vep!", vep_handle);
+ return VPPCOM_EINVAL;
+ }
+
+ if (vec_len (wrk->unhandled_evts_vector))
+ {
+ for (i = 0; i < vec_len (wrk->unhandled_evts_vector); i++)
+ {
+ vcl_epoll_wait_handle_mq_event (wrk, &wrk->unhandled_evts_vector[i],
+ events, &n_evts);
+ if (n_evts == maxevents)
+ {
+ vec_delete (wrk->unhandled_evts_vector, i + 1, 0);
+ return n_evts;
+ }
+ }
+ vec_reset_length (wrk->unhandled_evts_vector);
+ }
+
+ if (PREDICT_FALSE (wrk->ep_lt_current != VCL_INVALID_SESSION_INDEX))
+ vcl_epoll_wait_handle_lt (wrk, events, maxevents, &n_evts);
+
+ /* Request to only drain unhandled */
+ if ((int) wait_for_time == -2)
+ return n_evts;
+
+
+ if (vcm->cfg.use_mq_eventfd)
+ n_evts = vppcom_epoll_wait_eventfd (wrk, events, maxevents, n_evts,
+ wait_for_time);
+ else
+ n_evts = vppcom_epoll_wait_condvar (wrk, events, maxevents, n_evts,
+ wait_for_time);
+
+ return n_evts;
+}
+
+int
+vppcom_session_attr (uint32_t session_handle, uint32_t op,
+ void *buffer, uint32_t * buflen)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+ u32 *flags = buffer;
+ vppcom_endpt_t *ep = buffer;
+ transport_endpt_attr_t tea;
+ vcl_session_t *session;
+ int rv = VPPCOM_OK;
+
+ session = vcl_session_get_w_handle (wrk, session_handle);
+ if (!session)
+ return VPPCOM_EBADFD;
+
+ switch (op)
+ {
+ case VPPCOM_ATTR_GET_NREAD:
+ rv = vcl_session_read_ready (session);
+ VDBG (2, "VPPCOM_ATTR_GET_NREAD: sh %u, nread = %d", session_handle,
+ rv);
+ break;
+
+ case VPPCOM_ATTR_GET_NWRITE:
+ rv = vcl_session_write_ready (session);
+ VDBG (2, "VPPCOM_ATTR_GET_NWRITE: sh %u, nwrite = %d", session_handle,
+ rv);
+ break;
+
+ case VPPCOM_ATTR_GET_FLAGS:
+ if (PREDICT_TRUE (buffer && buflen && (*buflen >= sizeof (*flags))))
+ {
+ *flags =
+ O_RDWR |
+ (vcl_session_has_attr (session, VCL_SESS_ATTR_NONBLOCK) ?
+ O_NONBLOCK : 0);
+ *buflen = sizeof (*flags);
+ VDBG (2, "VPPCOM_ATTR_GET_FLAGS: sh %u, flags = 0x%08x, "
+ "is_nonblocking = %u", session_handle, *flags,
+ vcl_session_has_attr (session, VCL_SESS_ATTR_NONBLOCK));
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_FLAGS:
+ if (PREDICT_TRUE (buffer && buflen && (*buflen == sizeof (*flags))))
+ {
+ if (*flags & O_NONBLOCK)
+ vcl_session_set_attr (session, VCL_SESS_ATTR_NONBLOCK);
+ else
+ vcl_session_clear_attr (session, VCL_SESS_ATTR_NONBLOCK);
+
+ VDBG (2, "VPPCOM_ATTR_SET_FLAGS: sh %u, flags = 0x%08x,"
+ " is_nonblocking = %u", session_handle, *flags,
+ vcl_session_has_attr (session, VCL_SESS_ATTR_NONBLOCK));
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_PEER_ADDR:
+ if (PREDICT_TRUE (buffer && buflen &&
+ (*buflen >= sizeof (*ep)) && ep->ip))
+ {
+ ep->is_ip4 = session->transport.is_ip4;
+ ep->port = session->transport.rmt_port;
+ if (session->transport.is_ip4)
+ clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip4,
+ sizeof (ip4_address_t));
+ else
+ clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip6,
+ sizeof (ip6_address_t));
+ *buflen = sizeof (*ep);
+ VDBG (1,
+ "VPPCOM_ATTR_GET_PEER_ADDR: sh %u, is_ip4 = %u, "
+ "addr = %U, port %u",
+ session_handle, ep->is_ip4, vcl_format_ip46_address,
+ &session->transport.rmt_ip,
+ ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
+ clib_net_to_host_u16 (ep->port));
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_LCL_ADDR:
+ if (PREDICT_TRUE (buffer && buflen &&
+ (*buflen >= sizeof (*ep)) && ep->ip))
+ {
+ ep->is_ip4 = session->transport.is_ip4;
+ ep->port = session->transport.lcl_port;
+ if (session->transport.is_ip4)
+ clib_memcpy_fast (ep->ip, &session->transport.lcl_ip.ip4,
+ sizeof (ip4_address_t));
+ else
+ clib_memcpy_fast (ep->ip, &session->transport.lcl_ip.ip6,
+ sizeof (ip6_address_t));
+ *buflen = sizeof (*ep);
+ VDBG (1,
+ "VPPCOM_ATTR_GET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U"
+ " port %d",
+ session_handle, ep->is_ip4, vcl_format_ip46_address,
+ &session->transport.lcl_ip,
+ ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
+ clib_net_to_host_u16 (ep->port));
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_LCL_ADDR:
+ if (PREDICT_TRUE (buffer && buflen &&
+ (*buflen >= sizeof (*ep)) && ep->ip))
+ {
+ session->transport.is_ip4 = ep->is_ip4;
+ session->transport.lcl_port = ep->port;
+ vcl_ip_copy_from_ep (&session->transport.lcl_ip, ep);
+ *buflen = sizeof (*ep);
+ VDBG (1,
+ "VPPCOM_ATTR_SET_LCL_ADDR: sh %u, is_ip4 = %u, addr = %U"
+ " port %d",
+ session_handle, ep->is_ip4, vcl_format_ip46_address,
+ &session->transport.lcl_ip,
+ ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
+ clib_net_to_host_u16 (ep->port));
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_LIBC_EPFD:
+ rv = session->libc_epfd;
+ VDBG (2, "VPPCOM_ATTR_GET_LIBC_EPFD: libc_epfd %d", rv);
+ break;
+
+ case VPPCOM_ATTR_SET_LIBC_EPFD:
+ if (PREDICT_TRUE (buffer && buflen &&
+ (*buflen == sizeof (session->libc_epfd))))
+ {
+ session->libc_epfd = *(int *) buffer;
+ *buflen = sizeof (session->libc_epfd);
+
+ VDBG (2, "VPPCOM_ATTR_SET_LIBC_EPFD: libc_epfd %d, buflen %d",
+ session->libc_epfd, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_PROTOCOL:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ *(int *) buffer = session->session_type;
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_PROTOCOL: %d (%s), buflen %d",
+ *(int *) buffer, *(int *) buffer ? "UDP" : "TCP", *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_LISTEN:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ *(int *) buffer = vcl_session_has_attr (session,
+ VCL_SESS_ATTR_LISTEN);
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_LISTEN: %d, buflen %d", *(int *) buffer,
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_ERROR:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ *(int *) buffer = 0;
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_ERROR: %d, buflen %d, #VPP-TBD#",
+ *(int *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_TX_FIFO_LEN:
+ if (buffer && buflen && (*buflen >= sizeof (u32)))
+ {
+
+ /* VPP-TBD */
+ *(size_t *) buffer = (session->sndbuf_size ? session->sndbuf_size :
+ session->tx_fifo ?
+ svm_fifo_size (session->tx_fifo) :
+ vcm->cfg.tx_fifo_size);
+ *buflen = sizeof (u32);
+
+ VDBG (2, "VPPCOM_ATTR_GET_TX_FIFO_LEN: %u (0x%x), buflen %d,"
+ " #VPP-TBD#", *(size_t *) buffer, *(size_t *) buffer,
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_DSCP:
+ if (buffer && buflen && (*buflen >= sizeof (u8)))
+ {
+ session->dscp = *(u8 *) buffer;
+
+ VDBG (2, "VPPCOM_ATTR_SET_DSCP: %u (0x%x), buflen %d,",
+ *(u8 *) buffer, *(u8 *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_TX_FIFO_LEN:
+ if (buffer && buflen && (*buflen == sizeof (u32)))
+ {
+ /* VPP-TBD */
+ session->sndbuf_size = *(u32 *) buffer;
+ VDBG (2, "VPPCOM_ATTR_SET_TX_FIFO_LEN: %u (0x%x), buflen %d,"
+ " #VPP-TBD#", session->sndbuf_size, session->sndbuf_size,
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_RX_FIFO_LEN:
+ if (buffer && buflen && (*buflen >= sizeof (u32)))
+ {
+
+ /* VPP-TBD */
+ *(size_t *) buffer = (session->rcvbuf_size ? session->rcvbuf_size :
+ session->rx_fifo ?
+ svm_fifo_size (session->rx_fifo) :
+ vcm->cfg.rx_fifo_size);
+ *buflen = sizeof (u32);
+
+ VDBG (2, "VPPCOM_ATTR_GET_RX_FIFO_LEN: %u (0x%x), buflen %d, "
+ "#VPP-TBD#", *(size_t *) buffer, *(size_t *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_RX_FIFO_LEN:
+ if (buffer && buflen && (*buflen == sizeof (u32)))
+ {
+ /* VPP-TBD */
+ session->rcvbuf_size = *(u32 *) buffer;
+ VDBG (2, "VPPCOM_ATTR_SET_RX_FIFO_LEN: %u (0x%x), buflen %d,"
+ " #VPP-TBD#", session->sndbuf_size, session->sndbuf_size,
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_REUSEADDR:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ /* VPP-TBD */
+ *(int *) buffer = vcl_session_has_attr (session,
+ VCL_SESS_ATTR_REUSEADDR);
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_REUSEADDR: %d, buflen %d, #VPP-TBD#",
+ *(int *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_REUSEADDR:
+ if (buffer && buflen && (*buflen == sizeof (int)) &&
+ !vcl_session_has_attr (session, VCL_SESS_ATTR_LISTEN))
+ {
+ /* VPP-TBD */
+ if (*(int *) buffer)
+ vcl_session_set_attr (session, VCL_SESS_ATTR_REUSEADDR);
+ else
+ vcl_session_clear_attr (session, VCL_SESS_ATTR_REUSEADDR);
+
+ VDBG (2, "VPPCOM_ATTR_SET_REUSEADDR: %d, buflen %d, #VPP-TBD#",
+ vcl_session_has_attr (session, VCL_SESS_ATTR_REUSEADDR),
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_REUSEPORT:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ /* VPP-TBD */
+ *(int *) buffer = vcl_session_has_attr (session,
+ VCL_SESS_ATTR_REUSEPORT);
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_REUSEPORT: %d, buflen %d, #VPP-TBD#",
+ *(int *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_REUSEPORT:
+ if (buffer && buflen && (*buflen == sizeof (int)) &&
+ !vcl_session_has_attr (session, VCL_SESS_ATTR_LISTEN))
+ {
+ /* VPP-TBD */
+ if (*(int *) buffer)
+ vcl_session_set_attr (session, VCL_SESS_ATTR_REUSEPORT);
+ else
+ vcl_session_clear_attr (session, VCL_SESS_ATTR_REUSEPORT);
+
+ VDBG (2, "VPPCOM_ATTR_SET_REUSEPORT: %d, buflen %d, #VPP-TBD#",
+ vcl_session_has_attr (session, VCL_SESS_ATTR_REUSEPORT),
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_BROADCAST:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ /* VPP-TBD */
+ *(int *) buffer = vcl_session_has_attr (session,
+ VCL_SESS_ATTR_BROADCAST);
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_BROADCAST: %d, buflen %d, #VPP-TBD#",
+ *(int *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_BROADCAST:
+ if (buffer && buflen && (*buflen == sizeof (int)))
+ {
+ /* VPP-TBD */
+ if (*(int *) buffer)
+ vcl_session_set_attr (session, VCL_SESS_ATTR_BROADCAST);
+ else
+ vcl_session_clear_attr (session, VCL_SESS_ATTR_BROADCAST);
+
+ VDBG (2, "VPPCOM_ATTR_SET_BROADCAST: %d, buflen %d, #VPP-TBD#",
+ vcl_session_has_attr (session, VCL_SESS_ATTR_BROADCAST),
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_V6ONLY:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ /* VPP-TBD */
+ *(int *) buffer = vcl_session_has_attr (session,
+ VCL_SESS_ATTR_V6ONLY);
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_V6ONLY: %d, buflen %d, #VPP-TBD#",
+ *(int *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_V6ONLY:
+ if (buffer && buflen && (*buflen == sizeof (int)))
+ {
+ /* VPP-TBD */
+ if (*(int *) buffer)
+ vcl_session_set_attr (session, VCL_SESS_ATTR_V6ONLY);
+ else
+ vcl_session_clear_attr (session, VCL_SESS_ATTR_V6ONLY);
+
+ VDBG (2, "VPPCOM_ATTR_SET_V6ONLY: %d, buflen %d, #VPP-TBD#",
+ vcl_session_has_attr (session, VCL_SESS_ATTR_V6ONLY),
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_KEEPALIVE:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ /* VPP-TBD */
+ *(int *) buffer = vcl_session_has_attr (session,
+ VCL_SESS_ATTR_KEEPALIVE);
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_KEEPALIVE: %d, buflen %d, #VPP-TBD#",
+ *(int *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_KEEPALIVE:
+ if (buffer && buflen && (*buflen == sizeof (int)))
+ {
+ /* VPP-TBD */
+ if (*(int *) buffer)
+ vcl_session_set_attr (session, VCL_SESS_ATTR_KEEPALIVE);
+ else
+ vcl_session_clear_attr (session, VCL_SESS_ATTR_KEEPALIVE);
+
+ VDBG (2, "VPPCOM_ATTR_SET_KEEPALIVE: %d, buflen %d, #VPP-TBD#",
+ vcl_session_has_attr (session, VCL_SESS_ATTR_KEEPALIVE),
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_TCP_NODELAY:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ /* VPP-TBD */
+ *(int *) buffer = vcl_session_has_attr (session,
+ VCL_SESS_ATTR_TCP_NODELAY);
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_TCP_NODELAY: %d, buflen %d, #VPP-TBD#",
+ *(int *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_TCP_NODELAY:
+ if (buffer && buflen && (*buflen == sizeof (int)))
+ {
+ /* VPP-TBD */
+ if (*(int *) buffer)
+ vcl_session_set_attr (session, VCL_SESS_ATTR_TCP_NODELAY);
+ else
+ vcl_session_clear_attr (session, VCL_SESS_ATTR_TCP_NODELAY);
+
+ VDBG (2, "VPPCOM_ATTR_SET_TCP_NODELAY: %d, buflen %d, #VPP-TBD#",
+ vcl_session_has_attr (session, VCL_SESS_ATTR_TCP_NODELAY),
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_TCP_KEEPIDLE:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ /* VPP-TBD */
+ *(int *) buffer = vcl_session_has_attr (session,
+ VCL_SESS_ATTR_TCP_KEEPIDLE);
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_TCP_KEEPIDLE: %d, buflen %d, #VPP-TBD#",
+ *(int *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_TCP_KEEPIDLE:
+ if (buffer && buflen && (*buflen == sizeof (int)))
+ {
+ /* VPP-TBD */
+ if (*(int *) buffer)
+ vcl_session_set_attr (session, VCL_SESS_ATTR_TCP_KEEPIDLE);
+ else
+ vcl_session_clear_attr (session, VCL_SESS_ATTR_TCP_KEEPIDLE);
+
+ VDBG (2, "VPPCOM_ATTR_SET_TCP_KEEPIDLE: %d, buflen %d, #VPP-TBD#",
+ vcl_session_has_attr (session,
+ VCL_SESS_ATTR_TCP_KEEPIDLE), *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_TCP_KEEPINTVL:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ /* VPP-TBD */
+ *(int *) buffer = vcl_session_has_attr (session,
+ VCL_SESS_ATTR_TCP_KEEPINTVL);
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_TCP_KEEPINTVL: %d, buflen %d, #VPP-TBD#",
+ *(int *) buffer, *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_SET_TCP_KEEPINTVL:
+ if (buffer && buflen && (*buflen == sizeof (int)))
+ {
+ /* VPP-TBD */
+ if (*(int *) buffer)
+ vcl_session_set_attr (session, VCL_SESS_ATTR_TCP_KEEPINTVL);
+ else
+ vcl_session_clear_attr (session, VCL_SESS_ATTR_TCP_KEEPINTVL);
+
+ VDBG (2, "VPPCOM_ATTR_SET_TCP_KEEPINTVL: %d, buflen %d, #VPP-TBD#",
+ vcl_session_has_attr (session,
+ VCL_SESS_ATTR_TCP_KEEPINTVL), *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_TCP_USER_MSS:
+ if (!(buffer && buflen && (*buflen >= sizeof (u32))))
+ {
+ rv = VPPCOM_EINVAL;
+ break;
+ }
+
+ tea.type = TRANSPORT_ENDPT_ATTR_MSS;
+ tea.mss = *(u32 *) buffer;
+ if (vcl_session_transport_attr (wrk, session, 1 /* is_get */, &tea))
+ rv = VPPCOM_ENOPROTOOPT;
+
+ if (!rv)
+ {
+ *(u32 *) buffer = tea.mss;
+ *buflen = sizeof (int);
+ }
+
+ VDBG (2, "VPPCOM_ATTR_GET_TCP_USER_MSS: %d, buflen %d", *(int *) buffer,
+ *buflen);
+ break;
+ case VPPCOM_ATTR_SET_TCP_USER_MSS:
+ if (!(buffer && buflen && (*buflen == sizeof (u32))))
+ {
+ rv = VPPCOM_EINVAL;
+ break;
+ }
+
+ tea.type = TRANSPORT_ENDPT_ATTR_MSS;
+ tea.mss = *(u32 *) buffer;
+ if (vcl_session_transport_attr (wrk, session, 0 /* is_get */, &tea))
+ rv = VPPCOM_ENOPROTOOPT;
+
+ VDBG (2, "VPPCOM_ATTR_SET_TCP_USER_MSS: %u, buflen %d", tea.mss,
+ *buflen);
+ break;
+
+ case VPPCOM_ATTR_SET_CONNECTED:
+ session->flags |= VCL_SESSION_F_CONNECTED;
+ break;
+
+ case VPPCOM_ATTR_SET_CKPAIR:
+ if (!(buffer && buflen && (*buflen == sizeof (int))) ||
+ !vcl_session_has_crypto (session))
+ {
+ rv = VPPCOM_EINVAL;
+ break;
+ }
+ if (!session->ext_config)
+ {
+ vcl_session_alloc_ext_cfg (session, TRANSPORT_ENDPT_EXT_CFG_CRYPTO,
+ sizeof (transport_endpt_ext_cfg_t));
+ }
+ else if (session->ext_config->type != TRANSPORT_ENDPT_EXT_CFG_CRYPTO)
+ {
+ rv = VPPCOM_EINVAL;
+ break;
+ }
+
+ session->ext_config->crypto.ckpair_index = *(uint32_t *) buffer;
+ break;
+
+ case VPPCOM_ATTR_SET_VRF:
+ if (!(buffer && buflen && (*buflen == sizeof (u32))))
+ {
+ rv = VPPCOM_EINVAL;
+ break;
+ }
+ session->vrf = *(u32 *) buffer;
+ break;
+
+ case VPPCOM_ATTR_GET_VRF:
+ if (!(buffer && buflen && (*buflen >= sizeof (u32))))
+ {
+ rv = VPPCOM_EINVAL;
+ break;
+ }
+ *(u32 *) buffer = session->vrf;
+ *buflen = sizeof (u32);
+ break;
+
+ case VPPCOM_ATTR_GET_DOMAIN:
+ if (!(buffer && buflen && (*buflen >= sizeof (int))))
+ {
+ rv = VPPCOM_EINVAL;
+ break;
+ }
+
+ if (session->transport.is_ip4)
+ *(int *) buffer = AF_INET;
+ else
+ *(int *) buffer = AF_INET6;
+ *buflen = sizeof (int);
+
+ VDBG (2, "VPPCOM_ATTR_GET_DOMAIN: %d, buflen %u", *(int *) buffer,
+ *buflen);
+ break;
+
+ case VPPCOM_ATTR_SET_ENDPT_EXT_CFG:
+ if (!(buffer && buflen && (*buflen > 0)))
+ {
+ rv = VPPCOM_EINVAL;
+ break;
+ }
+ if (session->ext_config)
+ {
+ rv = VPPCOM_EINVAL;
+ break;
+ }
+ vcl_session_alloc_ext_cfg (session, TRANSPORT_ENDPT_EXT_CFG_NONE,
+ *buflen + sizeof (u32));
+ clib_memcpy (session->ext_config->data, buffer, *buflen);
+ session->ext_config->len = *buflen;
+ break;
+ case VPPCOM_ATTR_SET_IP_PKTINFO:
+ if (buffer && buflen && (*buflen == sizeof (int)) &&
+ !vcl_session_has_attr (session, VCL_SESS_ATTR_IP_PKTINFO))
+ {
+ if (*(int *) buffer)
+ vcl_session_set_attr (session, VCL_SESS_ATTR_IP_PKTINFO);
+ else
+ vcl_session_clear_attr (session, VCL_SESS_ATTR_IP_PKTINFO);
+
+ VDBG (2, "VCL_SESS_ATTR_IP_PKTINFO: %d, buflen %d",
+ vcl_session_has_attr (session, VCL_SESS_ATTR_IP_PKTINFO),
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ case VPPCOM_ATTR_GET_IP_PKTINFO:
+ if (buffer && buflen && (*buflen >= sizeof (int)))
+ {
+ *(int *) buffer =
+ vcl_session_has_attr (session, VCL_SESS_ATTR_IP_PKTINFO);
+ *buflen = sizeof (int);
+
+ VDBG (2, "VCL_SESS_ATTR_IP_PKTINFO: %d, buflen %d", *(int *) buffer,
+ *buflen);
+ }
+ else
+ rv = VPPCOM_EINVAL;
+ break;
+
+ default:
+ rv = VPPCOM_EINVAL;
+ break;
+ }
+
+ return rv;
+}
+
+int
+vppcom_session_recvfrom (uint32_t session_handle, void *buffer,
+ uint32_t buflen, int flags, vppcom_endpt_t * ep)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+ vcl_session_t *session;
+ int rv = VPPCOM_OK;
+
+ if (flags == 0)
+ rv = vppcom_session_read (session_handle, buffer, buflen);
+ else if (flags & MSG_PEEK)
+ rv = vppcom_session_peek (session_handle, buffer, buflen);
+ else
+ {
+ VDBG (0, "Unsupport flags for recvfrom %d", flags);
+ return VPPCOM_EAFNOSUPPORT;
+ }
+
+ if (ep && rv > 0)
+ {
+ session = vcl_session_get_w_handle (wrk, session_handle);
+ if (session->transport.is_ip4)
+ clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip4,
+ sizeof (ip4_address_t));
+ else
+ clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip6,
+ sizeof (ip6_address_t));
+ ep->is_ip4 = session->transport.is_ip4;
+ ep->port = session->transport.rmt_port;
+ }
+
+ return rv;
+}
+
+static void
+vcl_handle_ep_app_tlvs (vcl_session_t *s, vppcom_endpt_t *ep)
+{
+ vppcom_endpt_tlv_t *tlv = ep->app_tlvs;
+
+ do
+ {
+ switch (tlv->data_type)
+ {
+ case VCL_UDP_SEGMENT:
+ s->gso_size = *(u16 *) tlv->data;
+ break;
+ case VCL_IP_PKTINFO:
+ clib_memcpy_fast (&s->transport.lcl_ip, (ip4_address_t *) tlv->data,
+ sizeof (ip4_address_t));
+ break;
+ default:
+ VDBG (0, "Ignorning unsupported app tlv %u", tlv->data_type);
+ break;
+ }
+ tlv = VCL_EP_NEXT_APP_TLV (ep, tlv);
+ }
+ while (tlv);
+}
+
+int
+vppcom_session_sendto (uint32_t session_handle, void *buffer,
+ uint32_t buflen, int flags, vppcom_endpt_t * ep)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+ vcl_session_t *s;
+
+ s = vcl_session_get_w_handle (wrk, session_handle);
+ if (PREDICT_FALSE (!s))
+ return VPPCOM_EBADFD;
+
+ if (ep)
+ {
+ if (!vcl_session_is_cl (s))
+ return VPPCOM_EINVAL;
+
+ s->transport.is_ip4 = ep->is_ip4;
+ s->transport.rmt_port = ep->port;
+ vcl_ip_copy_from_ep (&s->transport.rmt_ip, ep);
+
+ if (ep->app_tlvs)
+ vcl_handle_ep_app_tlvs (s, ep);
+
+ /* Session not connected/bound in vpp. Create it by 'connecting' it */
+ if (PREDICT_FALSE (s->session_state == VCL_STATE_CLOSED))
+ {
+ u32 session_index = s->session_index;
+ f64 timeout = vcm->cfg.session_timeout;
+ int rv;
+
+ vcl_send_session_connect (wrk, s);
+ rv = vppcom_wait_for_session_state_change (session_index,
+ VCL_STATE_READY,
+ timeout);
+ if (rv < 0)
+ return rv;
+ s = vcl_session_get (wrk, session_index);
+ }
+ }
+
+ if (flags)
+ {
+ // TBD check the flags and do the right thing
+ VDBG (2, "handling flags 0x%u (%d) not implemented yet.", flags, flags);
+ }
+
+ return (vppcom_session_write_inline (wrk, s, buffer, buflen, 1,
+ s->is_dgram ? 1 : 0));
+}
+
+int
+vppcom_poll (vcl_poll_t * vp, uint32_t n_sids, double wait_for_time)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+ f64 timeout = clib_time_now (&wrk->clib_time) + wait_for_time;
+ u32 i, keep_trying = 1;
+ svm_msg_q_msg_t msg;
+ session_event_t *e;
+ int rv, num_ev = 0;
+
+ VDBG (3, "vp %p, nsids %u, wait_for_time %f", vp, n_sids, wait_for_time);
+
+ if (!vp)
+ return VPPCOM_EFAULT;
+
+ do
+ {
+ vcl_session_t *session;
+
+ /* Dequeue all events and drop all unhandled io events */
+ while (svm_msg_q_sub (wrk->app_event_queue, &msg, SVM_Q_NOWAIT, 0) == 0)
+ {
+ e = svm_msg_q_msg_data (wrk->app_event_queue, &msg);
+ vcl_handle_mq_event (wrk, e);
+ svm_msg_q_free_msg (wrk->app_event_queue, &msg);
+ }
+ vec_reset_length (wrk->unhandled_evts_vector);
+
+ for (i = 0; i < n_sids; i++)
+ {
+ session = vcl_session_get (wrk, vp[i].sh);
+ if (!session)