X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvcl%2Fvppcom.c;h=0060922fea681ccc4f6b1a62c43c2e8399964d60;hb=7cd982d007f9073a301aed5b44d8806bfddd5891;hp=9a351d8aca6f67ed2c0ab03ccaf4c28b6ebbc675;hpb=2d379d8cc7612c2a29670aa66d3d2b0a4007b951;p=vpp.git diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index 9a351d8aca6..0060922fea6 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -312,7 +312,9 @@ vcl_session_accepted_handler (vcl_worker_t * wrk, session_accepted_msg_t * mp, session->transport.lcl_port = listen_session->transport.lcl_port; session->transport.lcl_ip = listen_session->transport.lcl_ip; session->session_type = listen_session->session_type; - session->is_dgram = session->session_type == VPPCOM_PROTO_UDP; + session->is_dgram = vcl_proto_is_dgram (session->session_type); + session->listener_index = listen_session->session_index; + listen_session->n_accepted_sessions++; VDBG (1, "session %u [0x%llx]: client accept request from %s address %U" " port %d queue %p!", session->session_index, mp->handle, @@ -822,13 +824,27 @@ static int vppcom_session_unbind (u32 session_handle) { vcl_worker_t *wrk = vcl_worker_get_current (); + session_accepted_msg_t *accepted_msg; vcl_session_t *session = 0; + vcl_session_msg_t *evt; u64 vpp_handle; session = vcl_session_get_w_handle (wrk, session_handle); if (!session) return VPPCOM_EBADFD; + /* Flush pending accept events, if any */ + while (clib_fifo_elts (session->accept_evts_fifo)) + { + clib_fifo_sub2 (session->accept_evts_fifo, evt); + accepted_msg = &evt->accepted_msg; + vcl_session_table_del_vpp_handle (wrk, accepted_msg->handle); + vcl_send_session_accepted_reply (session->vpp_evt_q, + accepted_msg->context, + session->vpp_handle, -1); + } + clib_fifo_free (session->accept_evts_fifo); + vpp_handle = session->vpp_handle; session->vpp_handle = ~0; session->session_state = STATE_DISCONNECT; @@ -846,7 +862,7 @@ vppcom_session_disconnect (u32 session_handle) { vcl_worker_t *wrk = vcl_worker_get_current (); svm_msg_q_t *vpp_evt_q; - vcl_session_t *session; + vcl_session_t *session, *listen_session; vcl_session_state_t state; u64 vpp_handle; @@ -881,6 +897,12 @@ vppcom_session_disconnect (u32 session_handle) vppcom_send_disconnect_session (vpp_handle); } + if (session->listener_index != VCL_INVALID_SESSION_INDEX) + { + listen_session = vcl_session_get (wrk, session->listener_index); + listen_session->n_accepted_sessions--; + } + return VPPCOM_OK; } @@ -900,7 +922,7 @@ vppcom_app_exit (void) vcl_set_worker_index (~0); vcl_elog_stop (vcm); if (vec_len (vcm->workers) == 1) - vl_client_disconnect_from_vlib (); + vppcom_disconnect_from_vpp (); else vl_client_send_disconnect (1 /* vpp should cleanup */ ); } @@ -1015,7 +1037,7 @@ vppcom_session_create (u8 proto, u8 is_nonblocking) session->session_type = proto; session->session_state = STATE_START; session->vpp_handle = ~0; - session->is_dgram = proto == VPPCOM_PROTO_UDP; + session->is_dgram = vcl_proto_is_dgram (proto); if (is_nonblocking) VCL_SESS_ATTR_SET (session->attr, VCL_SESS_ATTR_NONBLOCK); @@ -1086,7 +1108,8 @@ vcl_session_cleanup (vcl_worker_t * wrk, vcl_session_t * session, vppcom_retval_str (rv)); return rv; } - else if (state & STATE_OPEN) + else if ((state & STATE_OPEN) + || (vcl_session_is_connectable_listener (wrk, session))) { rv = vppcom_session_disconnect (sh); if (PREDICT_FALSE (rv < 0)) @@ -1192,8 +1215,7 @@ vppcom_session_listen (uint32_t listen_sh, uint32_t q_len) return VPPCOM_OK; } - VDBG (0, "session %u [0x%llx]: sending vpp listen request...", - listen_sh, listen_vpp_handle); + VDBG (0, "session %u: sending vpp listen request...", listen_sh); /* * Send listen request to vpp and wait for reply @@ -1274,16 +1296,50 @@ validate_args_session_accept_ (vcl_worker_t * wrk, vcl_session_t * ls) return VPPCOM_EBADFD; } - if (ls->session_state != STATE_LISTEN) + if ((ls->session_state != STATE_LISTEN) + && (!vcl_session_is_connectable_listener (wrk, ls))) { - VDBG (0, "ERROR: session [0x%llx]: not in listen state! state 0x%x" - " (%s)", ls->vpp_handle, ls->session_index, ls->session_state, + VDBG (0, + "ERROR: session [0x%llx]: not in listen state! state 0x%x" + " (%s)", ls->vpp_handle, ls->session_state, vppcom_session_state_str (ls->session_state)); return VPPCOM_EBADFD; } return VPPCOM_OK; } +int +vppcom_unformat_proto (uint8_t * proto, char *proto_str) +{ + if (!strcmp (proto_str, "TCP")) + *proto = VPPCOM_PROTO_TCP; + else if (!strcmp (proto_str, "tcp")) + *proto = VPPCOM_PROTO_TCP; + else if (!strcmp (proto_str, "UDP")) + *proto = VPPCOM_PROTO_UDP; + else if (!strcmp (proto_str, "udp")) + *proto = VPPCOM_PROTO_UDP; + else if (!strcmp (proto_str, "UDPC")) + *proto = VPPCOM_PROTO_UDPC; + else if (!strcmp (proto_str, "udpc")) + *proto = VPPCOM_PROTO_UDPC; + else if (!strcmp (proto_str, "SCTP")) + *proto = VPPCOM_PROTO_SCTP; + else if (!strcmp (proto_str, "sctp")) + *proto = VPPCOM_PROTO_SCTP; + else if (!strcmp (proto_str, "TLS")) + *proto = VPPCOM_PROTO_TLS; + else if (!strcmp (proto_str, "tls")) + *proto = VPPCOM_PROTO_TLS; + else if (!strcmp (proto_str, "QUIC")) + *proto = VPPCOM_PROTO_QUIC; + else if (!strcmp (proto_str, "quic")) + *proto = VPPCOM_PROTO_QUIC; + else + return 1; + return 0; +} + int vppcom_session_accept (uint32_t listen_session_handle, vppcom_endpt_t * ep, uint32_t flags) @@ -1418,8 +1474,7 @@ vppcom_session_connect (uint32_t session_handle, vppcom_endpt_t * server_ep) VDBG (0, "session handle %u [0x%llx]: session already " "connected to %s %U port %d proto %s, state 0x%x (%s)", session_handle, session->vpp_handle, - session->transport.is_ip4 ? "IPv4" : "IPv6", - format_ip46_address, + session->transport.is_ip4 ? "IPv4" : "IPv6", format_ip46_address, &session->transport.rmt_ip, session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (session->transport.rmt_port), @@ -1436,9 +1491,10 @@ vppcom_session_connect (uint32_t session_handle, vppcom_endpt_t * server_ep) clib_memcpy_fast (&session->transport.rmt_ip.ip6, server_ep->ip, sizeof (ip6_address_t)); session->transport.rmt_port = server_ep->port; + session->parent_handle = VCL_INVALID_SESSION_HANDLE; - VDBG (0, "session handle %u [0x%llx]: connecting to server %s %U " - "port %d proto %s", session_handle, session->vpp_handle, + VDBG (0, "session handle %u: connecting to server %s %U " + "port %d proto %s", session_handle, session->transport.is_ip4 ? "IPv4" : "IPv6", format_ip46_address, &session->transport.rmt_ip, session->transport.is_ip4 ? @@ -1460,6 +1516,70 @@ vppcom_session_connect (uint32_t session_handle, vppcom_endpt_t * server_ep) return rv; } +int +vppcom_session_stream_connect (uint32_t session_handle, + uint32_t parent_session_handle) +{ + vcl_worker_t *wrk = vcl_worker_get_current (); + vcl_session_t *session, *parent_session; + u32 session_index, parent_session_index; + int rv; + + session = vcl_session_get_w_handle (wrk, session_handle); + if (!session) + return VPPCOM_EBADFD; + parent_session = vcl_session_get_w_handle (wrk, parent_session_handle); + if (!parent_session) + return VPPCOM_EBADFD; + + session_index = session->session_index; + parent_session_index = parent_session->session_index; + if (PREDICT_FALSE (session->is_vep)) + { + VDBG (0, "ERROR: cannot connect epoll session %u!", + session->session_index); + return VPPCOM_EBADFD; + } + + if (PREDICT_FALSE (session->session_state & CLIENT_STATE_OPEN)) + { + VDBG (0, "session handle %u [0x%llx]: session already " + "connected to session %u [0x%llx] proto %s, state 0x%x (%s)", + session_handle, session->vpp_handle, + parent_session_handle, parent_session->vpp_handle, + vppcom_proto_str (session->session_type), session->session_state, + vppcom_session_state_str (session->session_state)); + return VPPCOM_OK; + } + + /* Connect to quic session specifics */ + session->transport.is_ip4 = parent_session->transport.is_ip4; + session->transport.rmt_ip.ip4.as_u32 = (uint32_t) 1; + session->transport.rmt_port = 0; + session->parent_handle = parent_session->vpp_handle; + + VDBG (0, "session handle %u: connecting to session %u [0x%llx]", + session_handle, parent_session_handle, parent_session->vpp_handle); + + /* + * Send connect request and wait for reply from vpp + */ + vppcom_send_connect_sock (session); + rv = vppcom_wait_for_session_state_change (session_index, STATE_CONNECT, + vcm->cfg.session_timeout); + + session->listener_index = parent_session_index; + parent_session = vcl_session_get_w_handle (wrk, parent_session_handle); + if (parent_session) + parent_session->n_accepted_sessions++; + + session = vcl_session_get (wrk, session_index); + VDBG (0, "session %u [0x%llx]: connect %s!", session->session_index, + session->vpp_handle, rv ? "failed" : "succeeded"); + + return rv; +} + static u8 vcl_is_rx_evt_for_session (session_event_t * e, u32 sid, u8 is_ct) { @@ -2067,75 +2187,75 @@ check_mq: } static inline void -vep_verify_epoll_chain (vcl_worker_t * wrk, u32 vep_idx) +vep_verify_epoll_chain (vcl_worker_t * wrk, u32 vep_handle) { vcl_session_t *session; vppcom_epoll_t *vep; - u32 sid = vep_idx; + u32 sh = vep_handle; if (VPPCOM_DEBUG <= 2) return; - session = vcl_session_get (wrk, vep_idx); + session = vcl_session_get_w_handle (wrk, vep_handle); if (PREDICT_FALSE (!session)) { - VDBG (0, "ERROR: Invalid vep_idx (%u)!", vep_idx); + VDBG (0, "ERROR: Invalid vep_sh (%u)!", vep_handle); goto done; } if (PREDICT_FALSE (!session->is_vep)) { - VDBG (0, "ERROR: vep_idx (%u) is not a vep!", vep_idx); + VDBG (0, "ERROR: vep_sh (%u) is not a vep!", vep_handle); goto done; } vep = &session->vep; - VDBG (0, "vep_idx (%u): Dumping epoll chain\n" + VDBG (0, "vep_sh (%u): Dumping epoll chain\n" "{\n" " is_vep = %u\n" " is_vep_session = %u\n" - " next_sid = 0x%x (%u)\n" - "}\n", vep_idx, session->is_vep, session->is_vep_session, + " next_sh = 0x%x (%u)\n" + "}\n", vep_handle, session->is_vep, session->is_vep_session, vep->next_sh, vep->next_sh); - for (sid = vep->next_sh; sid != ~0; sid = vep->next_sh) + for (sh = vep->next_sh; sh != ~0; sh = vep->next_sh) { - session = vcl_session_get (wrk, sid); + session = vcl_session_get_w_handle (wrk, sh); if (PREDICT_FALSE (!session)) { - VDBG (0, "ERROR: Invalid sid (%u)!", sid); + VDBG (0, "ERROR: Invalid sh (%u)!", sh); goto done; } if (PREDICT_FALSE (session->is_vep)) { - VDBG (0, "ERROR: sid (%u) is a vep!", vep_idx); + VDBG (0, "ERROR: sh (%u) is a vep!", vep_handle); } else if (PREDICT_FALSE (!session->is_vep_session)) { - VDBG (0, "ERROR: session (%u) is not a vep session!", sid); + VDBG (0, "ERROR: sh (%u) is not a vep session handle!", sh); goto done; } vep = &session->vep; - if (PREDICT_FALSE (vep->vep_sh != vep_idx)) - VDBG (0, "ERROR: session (%u) vep_idx (%u) != vep_idx (%u)!", - sid, session->vep.vep_sh, vep_idx); + if (PREDICT_FALSE (vep->vep_sh != vep_handle)) + VDBG (0, "ERROR: session (%u) vep_sh (%u) != vep_sh (%u)!", + sh, session->vep.vep_sh, vep_handle); if (session->is_vep_session) { - VDBG (0, "vep_idx[%u]: sid 0x%x (%u)\n" + VDBG (0, "vep_sh[%u]: sh 0x%x (%u)\n" "{\n" - " next_sid = 0x%x (%u)\n" - " prev_sid = 0x%x (%u)\n" - " vep_idx = 0x%x (%u)\n" + " next_sh = 0x%x (%u)\n" + " prev_sh = 0x%x (%u)\n" + " vep_sh = 0x%x (%u)\n" " ev.events = 0x%x\n" " ev.data.u64 = 0x%llx\n" " et_mask = 0x%x\n" "}\n", - vep_idx, sid, sid, vep->next_sh, vep->next_sh, vep->prev_sh, + vep_handle, sh, sh, vep->next_sh, vep->next_sh, vep->prev_sh, vep->prev_sh, vep->vep_sh, vep->vep_sh, vep->ev.events, vep->ev.data.u64, vep->et_mask); } } done: - VDBG (0, "vep_idx (%u): Dump complete!\n", vep_idx); + VDBG (0, "vep_sh (%u): Dump complete!\n", vep_handle); } int @@ -3343,6 +3463,13 @@ vppcom_worker_register (void) return VPPCOM_OK; } +void +vppcom_worker_unregister (void) +{ + vcl_worker_cleanup (vcl_worker_get_current (), 1 /* notify vpp */ ); + vcl_set_worker_index (~0); +} + int vppcom_worker_index (void) { @@ -3358,6 +3485,43 @@ vppcom_worker_mqs_epfd (void) return wrk->mqs_epfd; } +int +vppcom_session_is_connectable_listener (uint32_t session_handle) +{ + vcl_session_t *session; + vcl_worker_t *wrk = vcl_worker_get_current (); + session = vcl_session_get_w_handle (wrk, session_handle); + if (!session) + return VPPCOM_EBADFD; + return vcl_session_is_connectable_listener (wrk, session); +} + +int +vppcom_session_listener (uint32_t session_handle) +{ + vcl_worker_t *wrk = vcl_worker_get_current (); + vcl_session_t *listen_session, *session; + session = vcl_session_get_w_handle (wrk, session_handle); + if (!session) + return VPPCOM_EBADFD; + if (session->listener_index == VCL_INVALID_SESSION_INDEX) + return VPPCOM_EBADFD; + listen_session = vcl_session_get_w_handle (wrk, session->listener_index); + if (!listen_session) + return VPPCOM_EBADFD; + return vcl_session_handle (listen_session); +} + +int +vppcom_session_n_accepted (uint32_t session_handle) +{ + vcl_worker_t *wrk = vcl_worker_get_current (); + vcl_session_t *session = vcl_session_get_w_handle (wrk, session_handle); + if (!session) + return VPPCOM_EBADFD; + return session->n_accepted_sessions; +} + /* * fd.io coding-style-patch-verification: ON *