diff options
Diffstat (limited to 'src/vcl/vppcom.c')
-rw-r--r-- | src/vcl/vppcom.c | 234 |
1 files changed, 197 insertions, 37 deletions
diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index a557093e897..4568ac618d5 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -351,10 +351,16 @@ vcl_session_accepted_handler (vcl_worker_t * wrk, session_accepted_msg_t * mp, session->vpp_handle = mp->handle; session->session_state = VCL_STATE_READY; - if (mp->rmt.is_ip4) + if (mp->rmt.is_ip4 && mp->original_dst_port) { - session->original_dst_ip4 = mp->original_dst_ip4; - session->original_dst_port = mp->original_dst_port; + transport_endpt_attr_t *tep_attr; + vec_add2 (session->tep_attrs, tep_attr, 1); + /* Expecting to receive this on accepted connections + * and the external transport endpoint received is + * the local one, prior to something like nat */ + tep_attr->type = TRANSPORT_ENDPT_ATTR_EXT_ENDPT; + tep_attr->ext_endpt.port = mp->original_dst_port; + tep_attr->ext_endpt.ip.ip4.as_u32 = mp->original_dst_ip4; } session->transport.rmt_port = mp->rmt.port; session->transport.is_ip4 = mp->rmt.is_ip4; @@ -989,6 +995,24 @@ vcl_worker_rpc_handler (vcl_worker_t * wrk, void *data) } static void +vcl_session_transport_attr_handler (vcl_worker_t *wrk, void *data) +{ + session_transport_attr_msg_t *mp = (session_transport_attr_msg_t *) data; + vcl_session_t *s; + + s = vcl_session_get_w_vpp_handle (wrk, mp->handle); + if (!s) + { + VDBG (0, "session transport attr with wrong handle %llx", mp->handle); + return; + } + + VDBG (0, "session %u [0x%llx]: transport attr %u", s->session_index, + s->vpp_handle, mp->attr.type); + vec_add1 (s->tep_attrs, mp->attr); +} + +static void vcl_session_transport_attr_reply_handler (vcl_worker_t *wrk, void *data) { session_transport_attr_reply_msg_t *mp; @@ -1129,6 +1153,9 @@ vcl_handle_mq_event (vcl_worker_t * wrk, session_event_t * e) case SESSION_CTRL_EVT_APP_WRK_RPC: vcl_worker_rpc_handler (wrk, e->data); break; + case SESSION_CTRL_EVT_TRANSPORT_ATTR: + vcl_session_transport_attr_handler (wrk, e->data); + break; case SESSION_CTRL_EVT_TRANSPORT_ATTR_REPLY: vcl_session_transport_attr_reply_handler (wrk, e->data); break; @@ -1754,6 +1781,10 @@ vppcom_unformat_proto (uint8_t * proto, char *proto_str) *proto = VPPCOM_PROTO_SRTP; else if (!strcmp (proto_str, "srtp")) *proto = VPPCOM_PROTO_SRTP; + else if (!strcmp (proto_str, "HTTP")) + *proto = VPPCOM_PROTO_HTTP; + else if (!strcmp (proto_str, "http")) + *proto = VPPCOM_PROTO_HTTP; else return 1; return 0; @@ -2345,6 +2376,75 @@ vppcom_session_write_inline (vcl_worker_t *wrk, vcl_session_t *s, void *buf, } int +vppcom_session_write_segments (uint32_t session_handle, + vppcom_data_segment_t *ds, uint32_t n_segments) +{ + vcl_worker_t *wrk = vcl_worker_get_current (); + int n_write = 0, n_bytes = 0, is_nonblocking; + vcl_session_t *s = 0; + svm_fifo_t *tx_fifo; + svm_msg_q_t *mq; + u8 is_ct; + u32 i; + + if (PREDICT_FALSE (!ds)) + return VPPCOM_EFAULT; + + /* Accept zero length writes but just return */ + if (PREDICT_FALSE (ds[0].len == 0)) + return VPPCOM_OK; + + s = vcl_session_get_w_handle (wrk, session_handle); + if (PREDICT_FALSE (!s || (s->flags & VCL_SESSION_F_IS_VEP))) + return VPPCOM_EBADFD; + + if (PREDICT_FALSE (!vcl_session_is_open (s))) + return vcl_session_closed_error (s); + + if (PREDICT_FALSE (s->flags & VCL_SESSION_F_WR_SHUTDOWN)) + return VPPCOM_EPIPE; + + is_nonblocking = vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK); + is_ct = vcl_session_is_ct (s); + mq = wrk->app_event_queue; + tx_fifo = is_ct ? s->ct_tx_fifo : s->tx_fifo; + + for (i = 0; i < n_segments; i++) + n_bytes += ds[i].len; + + if (svm_fifo_max_enqueue_prod (tx_fifo) < n_bytes) + { + if (is_nonblocking) + { + return VPPCOM_EWOULDBLOCK; + } + while (svm_fifo_max_enqueue_prod (tx_fifo) < n_bytes) + { + svm_fifo_add_want_deq_ntf (tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF); + if (vcl_session_is_closing (s)) + return vcl_session_closing_error (s); + + svm_msg_q_wait (mq, SVM_MQ_WAIT_EMPTY); + vcl_worker_flush_mq_events (wrk); + } + } + + n_write = svm_fifo_enqueue_segments (tx_fifo, (svm_fifo_seg_t *) ds, + n_segments, 0 /* allow_partial */); + + /* The underlying fifo segment can run out of memory */ + if (PREDICT_FALSE (n_write < 0)) + return VPPCOM_EAGAIN; + + if (svm_fifo_set_event (s->tx_fifo)) + app_send_io_evt_to_vpp (s->vpp_evt_q, + s->tx_fifo->shr->master_session_index, + SESSION_IO_EVT_TX, SVM_Q_WAIT); + + return n_write; +} + +int vppcom_session_write (uint32_t session_handle, void *buf, size_t n) { vcl_worker_t *wrk = vcl_worker_get_current (); @@ -2534,6 +2634,9 @@ vcl_select_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, case SESSION_CTRL_EVT_APP_WRK_RPC: vcl_worker_rpc_handler (wrk, e->data); break; + case SESSION_CTRL_EVT_TRANSPORT_ATTR: + vcl_session_transport_attr_handler (wrk, e->data); + break; default: clib_warning ("unhandled: %u", e->event_type); break; @@ -2619,6 +2722,7 @@ vppcom_select_eventfd (vcl_worker_t * wrk, int n_bits, vcl_mq_evt_conn_t *mqc; int __clib_unused n_read; int n_mq_evts, i; + double end = -1; u64 buf; if (PREDICT_FALSE (wrk->api_client_handle == ~0)) @@ -2628,23 +2732,45 @@ vppcom_select_eventfd (vcl_worker_t * wrk, int n_bits, } vec_validate (wrk->mq_events, pool_elts (wrk->mq_evt_conns)); - n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events, - vec_len (wrk->mq_events), time_to_wait); - for (i = 0; i < n_mq_evts; i++) + if (time_to_wait > 0) + end = clib_time_now (&wrk->clib_time) + (time_to_wait / 1e3); + + do { - if (PREDICT_FALSE (wrk->mq_events[i].data.u32 == ~0)) + n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events, + vec_len (wrk->mq_events), time_to_wait); + if (n_mq_evts < 0) { - vcl_api_handle_disconnect (wrk); - continue; + if (errno == EINTR) + continue; + + VDBG (0, "epoll_wait error %u", errno); + return 0; + } + + if (n_mq_evts == 0) + return 0; + + for (i = 0; i < n_mq_evts; i++) + { + if (PREDICT_FALSE (wrk->mq_events[i].data.u32 == ~0)) + { + 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_select_handle_mq (wrk, mqc->mq, n_bits, read_map, write_map, + except_map, 0, bits_set); } - mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32); - n_read = read (mqc->mq_fd, &buf, sizeof (buf)); - vcl_select_handle_mq (wrk, mqc->mq, n_bits, read_map, write_map, - except_map, 0, bits_set); + if (*bits_set || !time_to_wait) + return (int) *bits_set; } + while (end == -1 || clib_time_now (&wrk->clib_time) < end); - return (n_mq_evts > 0 ? (int) *bits_set : 0); + return 0; } int @@ -3286,6 +3412,9 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, case SESSION_CTRL_EVT_APP_WRK_RPC: vcl_worker_rpc_handler (wrk, e->data); break; + case SESSION_CTRL_EVT_TRANSPORT_ATTR: + vcl_session_transport_attr_handler (wrk, e->data); + break; default: VDBG (0, "unhandled: %u", e->event_type); break; @@ -3407,6 +3536,9 @@ vppcom_epoll_wait_eventfd (vcl_worker_t *wrk, struct epoll_event *events, vec_len (wrk->mq_events), timeout_ms); if (n_mq_evts < 0) { + if (errno == EINTR) + continue; + VDBG (0, "epoll_wait error %u", errno); return n_evts; } @@ -3573,7 +3705,7 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op, vcl_worker_t *wrk = vcl_worker_get_current (); u32 *flags = buffer; vppcom_endpt_t *ep = buffer; - transport_endpt_attr_t tea; + transport_endpt_attr_t tea, *tepap; vcl_session_t *session; int rv = VPPCOM_OK; @@ -3696,24 +3828,49 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op, rv = VPPCOM_EAFNOSUPPORT; break; } - if (PREDICT_TRUE (buffer && buflen && (*buflen >= sizeof (*ep)) && - ep->ip)) + if (PREDICT_FALSE (!buffer || !buflen || (*buflen < sizeof (*ep)) || + !ep->ip)) { - ep->is_ip4 = session->transport.is_ip4; - ep->port = session->original_dst_port; - clib_memcpy_fast (ep->ip, &session->original_dst_ip4, - sizeof (ip4_address_t)); - *buflen = sizeof (*ep); - VDBG (1, - "VPPCOM_ATTR_GET_ORIGINAL_DST: sh %u, is_ip4 = %u, addr = %U" - " port %d", - session_handle, ep->is_ip4, vcl_format_ip4_address, - (ip4_address_t *) (&session->original_dst_ip4), - ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, - clib_net_to_host_u16 (ep->port)); + rv = VPPCOM_EINVAL; + break; } - else - rv = VPPCOM_EINVAL; + + tepap = + vcl_session_tep_attr_get (session, TRANSPORT_ENDPT_ATTR_EXT_ENDPT); + if (!tepap) + { + rv = VPPCOM_EINVAL; + break; + } + vcl_ip_copy_to_ep (&tepap->ext_endpt.ip, ep, tepap->ext_endpt.is_ip4); + ep->port = tepap->ext_endpt.port; + *buflen = sizeof (*ep); + + VDBG (1, + "VPPCOM_ATTR_GET_ORIGINAL_DST: sh %u, is_ip4 = %u, " + "addr = %U port %d", + session_handle, ep->is_ip4, vcl_format_ip4_address, + (ip4_address_t *) ep->ip, + ep->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, + clib_net_to_host_u16 (ep->port)); + break; + + case VPPCOM_ATTR_GET_EXT_ENDPT: + if (PREDICT_FALSE (!buffer || !buflen || (*buflen < sizeof (*ep)) || + !ep->ip)) + { + rv = VPPCOM_EINVAL; + break; + } + tepap = + vcl_session_tep_attr_get (session, TRANSPORT_ENDPT_ATTR_EXT_ENDPT); + if (!tepap) + { + rv = VPPCOM_EINVAL; + break; + } + vcl_ip_copy_to_ep (&tepap->ext_endpt.ip, ep, tepap->ext_endpt.is_ip4); + ep->port = tepap->ext_endpt.port; break; case VPPCOM_ATTR_SET_LCL_ADDR: @@ -3798,12 +3955,11 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op, 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); + *(u32 *) 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," @@ -4238,7 +4394,8 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op, break; } vcl_session_alloc_ext_cfg (session, TRANSPORT_ENDPT_EXT_CFG_NONE, - *buflen + sizeof (u32)); + *buflen + + TRANSPORT_ENDPT_EXT_CFG_HEADER_SIZE); clib_memcpy (session->ext_config->data, buffer, *buflen); session->ext_config->len = *buflen; break; @@ -4613,6 +4770,9 @@ vppcom_proto_str (vppcom_proto_t proto) case VPPCOM_PROTO_SRTP: proto_str = "SRTP"; break; + case VPPCOM_PROTO_HTTP: + proto_str = "HTTP"; + break; default: proto_str = "UNKNOWN"; break; |