From 0a1e183e5aa45fb0050eb03e1c8ebdb9f426a374 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Sun, 29 Mar 2020 18:54:04 +0000 Subject: session udp: support connect on listeners Type: feature Signed-off-by: Florin Coras Change-Id: I6aaaec20a2b6d4c6ddfbe659d9402acc1be2f7e2 --- src/plugins/quic/quic.c | 2 +- src/vcl/vcl_private.c | 20 ++++++++++++++++++- src/vcl/vcl_private.h | 6 ++++++ src/vcl/vppcom.c | 33 ++++++++++++++++++++++++++++---- src/vnet/session/application_interface.h | 4 +++- src/vnet/session/session_node.c | 1 + src/vnet/session/session_types.h | 2 +- 7 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/plugins/quic/quic.c b/src/plugins/quic/quic.c index eeea8ab6f5c..8689583c27f 100644 --- a/src/plugins/quic/quic.c +++ b/src/plugins/quic/quic.c @@ -1320,7 +1320,7 @@ quic_connect_connection (session_endpoint_cfg_t * sep) app = application_get (app_wrk->app_index); ctx->parent_app_id = app_wrk->app_index; cargs->sep_ext.ns_index = app->ns_index; - cargs->sep_ext.flags = TRANSPORT_CFG_F_CONNECTED; + cargs->sep_ext.transport_flags = TRANSPORT_CFG_F_CONNECTED; ctx->crypto_engine = sep->crypto_engine; ctx->ckpair_index = sep->ckpair_index; diff --git a/src/vcl/vcl_private.c b/src/vcl/vcl_private.c index 3cb76c6bb7d..14582ce025d 100644 --- a/src/vcl/vcl_private.c +++ b/src/vcl/vcl_private.c @@ -308,6 +308,8 @@ vcl_cleanup_bapi (void) int vcl_session_read_ready (vcl_session_t * session) { + u32 max_deq; + /* Assumes caller has acquired spinlock: vcm->sessions_lockp */ if (PREDICT_FALSE (session->is_vep)) { @@ -335,7 +337,23 @@ vcl_session_read_ready (vcl_session_t * session) if (vcl_session_is_ct (session)) return svm_fifo_max_dequeue_cons (session->ct_rx_fifo); - return svm_fifo_max_dequeue_cons (session->rx_fifo); + max_deq = svm_fifo_max_dequeue_cons (session->rx_fifo); + + if (session->is_dgram) + { + session_dgram_pre_hdr_t ph; + + if (max_deq <= SESSION_CONN_HDR_LEN) + return 0; + if (svm_fifo_peek (session->rx_fifo, 0, sizeof (ph), (u8 *) & ph) < 0) + return 0; + if (ph.data_length + SESSION_CONN_HDR_LEN > max_deq) + return 0; + + return ph.data_length; + } + + return max_deq; } int diff --git a/src/vcl/vcl_private.h b/src/vcl/vcl_private.h index 650d254afc7..433e08e2b46 100644 --- a/src/vcl/vcl_private.h +++ b/src/vcl/vcl_private.h @@ -149,6 +149,11 @@ do { \ #define VCL_SESS_ATTR_TEST(ATTR, VAL) \ ((ATTR) & (1 << (VAL)) ? 1 : 0) +typedef enum vcl_session_flags_ +{ + VCL_SESSION_F_CONNECTED, +} __clib_packed vcl_session_flags_t; + typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); @@ -167,6 +172,7 @@ typedef struct /* Socket configuration state */ u8 is_vep; u8 is_vep_session; + vcl_session_flags_t flags; /* VCL session index of the listening session (if any) */ u32 listener_index; /* Accepted sessions on this listener */ diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index 03bd32c5446..ba1f1166556 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -231,7 +231,10 @@ vcl_send_session_connect (vcl_worker_t * wrk, vcl_session_t * s) clib_memcpy_fast (&mp->ip, &s->transport.rmt_ip, sizeof (mp->ip)); clib_memcpy_fast (&mp->lcl_ip, &s->transport.lcl_ip, sizeof (mp->lcl_ip)); mp->port = s->transport.rmt_port; + mp->lcl_port = s->transport.lcl_port; mp->proto = s->session_type; + if (s->flags & VCL_SESSION_F_CONNECTED) + mp->flags |= TRANSPORT_CFG_F_CONNECTED; app_send_ctrl_evt_to_vpp (mq, app_evt); } @@ -612,11 +615,21 @@ vcl_session_unlisten_reply_handler (vcl_worker_t * wrk, void *data) vcl_session_t *s; s = vcl_session_get_w_vpp_handle (wrk, mp->handle); - if (!s || s->session_state != STATE_DISCONNECT) + if (!s) { VDBG (0, "Unlisten reply with wrong handle %llx", mp->handle); return; } + if (s->session_state != STATE_DISCONNECT) + { + /* Connected udp listener */ + if (s->session_type == VPPCOM_PROTO_UDP + && s->session_state == STATE_CLOSED) + return; + + VDBG (0, "Unlisten session in wrong state %llx", mp->handle); + return; + } if (mp->retval) VDBG (0, "ERROR: session %u [0xllx]: unlisten failed: %U", @@ -1686,13 +1699,24 @@ vppcom_session_connect (uint32_t session_handle, vppcom_endpt_t * server_ep) return VPPCOM_OK; } + /* Attempt to connect a connectionless listener */ + if (PREDICT_FALSE (session->session_state & STATE_LISTEN)) + { + if (session->session_type != VPPCOM_PROTO_UDP) + return VPPCOM_EINVAL; + vcl_send_session_unlisten (wrk, session); + session->session_state = STATE_CLOSED; + } + session->transport.is_ip4 = server_ep->is_ip4; vcl_ip_copy_from_ep (&session->transport.rmt_ip, server_ep); session->transport.rmt_port = server_ep->port; session->parent_handle = VCL_INVALID_SESSION_HANDLE; + session->flags |= VCL_SESSION_F_CONNECTED; - VDBG (0, "session handle %u: connecting to server %s %U " + VDBG (0, "session handle %u (%s): connecting to peer %s %U " "port %d proto %s", session_handle, + vppcom_session_state_str (session->session_state), session->transport.is_ip4 ? "IPv4" : "IPv6", format_ip46_address, &session->transport.rmt_ip, session->transport.is_ip4 ? @@ -3562,7 +3586,7 @@ vppcom_session_recvfrom (uint32_t session_handle, void *buffer, return VPPCOM_EAFNOSUPPORT; } - if (ep && !rv) + if (ep && rv > 0) { session = vcl_session_get_w_handle (wrk, session_handle); if (session->transport.is_ip4) @@ -3594,7 +3618,8 @@ vppcom_session_sendto (uint32_t session_handle, void *buffer, if (!s) return VPPCOM_EBADFD; - if (s->session_type != VPPCOM_PROTO_UDP) + if (s->session_type != VPPCOM_PROTO_UDP + || (s->flags & VCL_SESSION_F_CONNECTED)) return VPPCOM_EINVAL; /* Session not connected/bound in vpp. Create it by 'connecting' it */ diff --git a/src/vnet/session/application_interface.h b/src/vnet/session/application_interface.h index bf946769028..b1ab847073a 100644 --- a/src/vnet/session/application_interface.h +++ b/src/vnet/session/application_interface.h @@ -387,6 +387,7 @@ typedef struct session_connect_msg_ u32 wrk_index; u32 vrf; u16 port; + u16 lcl_port; u8 proto; u8 is_ip4; ip46_address_t ip; @@ -681,7 +682,7 @@ app_recv_dgram_raw (svm_fifo_t * f, u8 * buf, u32 len, int rv; max_deq = svm_fifo_max_dequeue_cons (f); - if (max_deq < sizeof (session_dgram_hdr_t)) + if (max_deq <= sizeof (session_dgram_hdr_t)) { if (clear_evt) svm_fifo_unset_event (f); @@ -699,6 +700,7 @@ app_recv_dgram_raw (svm_fifo_t * f, u8 * buf, u32 len, rv = svm_fifo_peek (f, ph.data_offset + SESSION_CONN_HDR_LEN, len, buf); if (peek) return rv; + ASSERT (rv > 0); ph.data_offset += rv; if (ph.data_offset == ph.data_length) svm_fifo_dequeue_drop (f, ph.data_length + SESSION_CONN_HDR_LEN); diff --git a/src/vnet/session/session_node.c b/src/vnet/session/session_node.c index 2a4bb6b9425..66300bc6024 100644 --- a/src/vnet/session/session_node.c +++ b/src/vnet/session/session_node.c @@ -113,6 +113,7 @@ session_mq_connect_handler (void *data) a->sep.transport_proto = mp->proto; a->sep.peer.fib_index = mp->vrf; clib_memcpy_fast (&a->sep.peer.ip, &mp->lcl_ip, sizeof (mp->lcl_ip)); + a->sep.peer.port = mp->lcl_port; a->sep.peer.sw_if_index = ENDPOINT_INVALID_INDEX; a->sep_ext.parent_handle = mp->parent_handle; a->sep_ext.ckpair_index = mp->ckpair_index; diff --git a/src/vnet/session/session_types.h b/src/vnet/session/session_types.h index aa0e8650747..a0360136b1d 100644 --- a/src/vnet/session/session_types.h +++ b/src/vnet/session/session_types.h @@ -21,7 +21,7 @@ #define SESSION_INVALID_INDEX ((u32)~0) #define SESSION_INVALID_HANDLE ((u64)~0) -#define SESSION_CTRL_MSG_MAX_SIZE 84 +#define SESSION_CTRL_MSG_MAX_SIZE 86 #define foreach_session_endpoint_fields \ foreach_transport_endpoint_cfg_fields \ -- cgit 1.2.3-korg