X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvcl%2Fvppcom.c;h=0b4d75765ea44520a2aca126156a6a68a331ff5c;hb=refs%2Fchanges%2F43%2F38843%2F3;hp=3b265d29ab85e54845ff9e449af9c2341f91b0ed;hpb=1d84abc93ed0f41ee7ced184e57ab9b6241c6eba;p=vpp.git diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index 3b265d29ab8..0b4d75765ea 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -51,8 +51,8 @@ vcl_msg_add_ext_config (vcl_session_t *s, uword *offset) clib_memcpy_fast (c->data, s->ext_config, s->ext_config->len); } -static void -vcl_send_session_listen (vcl_worker_t * wrk, vcl_session_t * s) +void +vcl_send_session_listen (vcl_worker_t *wrk, vcl_session_t *s) { app_session_evt_t _app_evt, *app_evt = &_app_evt; session_listen_msg_t *mp; @@ -80,6 +80,7 @@ vcl_send_session_listen (vcl_worker_t * wrk, vcl_session_t * s) clib_mem_free (s->ext_config); s->ext_config = 0; } + s->flags |= VCL_SESSION_F_PENDING_LISTEN; } static void @@ -360,6 +361,8 @@ vcl_session_accepted_handler (vcl_worker_t * wrk, session_accepted_msg_t * mp, session->transport.lcl_ip = mp->lcl.ip; session->session_type = listen_session->session_type; session->is_dgram = vcl_proto_is_dgram (session->session_type); + if (session->is_dgram) + session->flags |= (listen_session->flags & VCL_SESSION_F_CONNECTED); session->listener_index = listen_session->session_index; listen_session->n_accepted_sessions++; @@ -554,6 +557,7 @@ vcl_session_bound_handler (vcl_worker_t * wrk, session_bound_msg_t * mp) session->transport.lcl_port = mp->lcl_port; vcl_session_table_add_listener (wrk, mp->handle, sid); session->session_state = VCL_STATE_LISTEN; + session->flags &= ~VCL_SESSION_F_PENDING_LISTEN; if (vcl_session_is_cl (session)) { @@ -1232,7 +1236,7 @@ vppcom_session_unbind (u32 session_handle) vcl_send_session_unlisten (wrk, session); - VDBG (1, "session %u [0x%llx]: sending unbind!", session->session_index, + VDBG (0, "session %u [0x%llx]: sending unbind!", session->session_index, session->vpp_handle); vcl_evt (VCL_EVT_UNBIND, session); @@ -1463,6 +1467,8 @@ vcl_epoll_lt_add (vcl_worker_t *wrk, vcl_session_t *s) { vcl_session_t *cur, *prev; + ASSERT (s->vep.lt_next == VCL_INVALID_SESSION_INDEX); + if (wrk->ep_lt_current == VCL_INVALID_SESSION_INDEX) { wrk->ep_lt_current = s->session_index; @@ -1486,10 +1492,13 @@ vcl_epoll_lt_del (vcl_worker_t *wrk, vcl_session_t *s) { vcl_session_t *prev, *next; + ASSERT (s->vep.lt_next != VCL_INVALID_SESSION_INDEX); + if (s->vep.lt_next == s->session_index) { wrk->ep_lt_current = VCL_INVALID_SESSION_INDEX; s->vep.lt_next = VCL_INVALID_SESSION_INDEX; + s->vep.lt_prev = VCL_INVALID_SESSION_INDEX; return; } @@ -1503,6 +1512,7 @@ vcl_epoll_lt_del (vcl_worker_t *wrk, vcl_session_t *s) wrk->ep_lt_current = s->vep.lt_next; s->vep.lt_next = VCL_INVALID_SESSION_INDEX; + s->vep.lt_prev = VCL_INVALID_SESSION_INDEX; } int @@ -1693,29 +1703,6 @@ vppcom_session_listen (uint32_t listen_sh, uint32_t q_len) return VPPCOM_OK; } -static int -validate_args_session_accept_ (vcl_worker_t * wrk, vcl_session_t * ls) -{ - if (ls->flags & VCL_SESSION_F_IS_VEP) - { - VDBG (0, "ERROR: cannot accept on epoll session %u!", - ls->session_index); - return VPPCOM_EBADFD; - } - - if ((ls->session_state != VCL_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_state, - vcl_session_state_str (ls->session_state)); - return VPPCOM_EBADFD; - } - return VPPCOM_OK; -} - int vppcom_unformat_proto (uint8_t * proto, char *proto_str) { @@ -1749,38 +1736,41 @@ vppcom_unformat_proto (uint8_t * proto, char *proto_str) } int -vppcom_session_accept (uint32_t listen_session_handle, vppcom_endpt_t * ep, - uint32_t flags) +vppcom_session_accept (uint32_t ls_handle, vppcom_endpt_t *ep, uint32_t flags) { - u32 client_session_index = ~0, listen_session_index, accept_flags = 0; + u32 client_session_index = ~0, ls_index, accept_flags = 0; vcl_worker_t *wrk = vcl_worker_get_current (); session_accepted_msg_t accepted_msg; - vcl_session_t *listen_session = 0; - vcl_session_t *client_session = 0; + vcl_session_t *ls, *client_session = 0; vcl_session_msg_t *evt; u8 is_nonblocking; - int rv; again: - listen_session = vcl_session_get_w_handle (wrk, listen_session_handle); - if (!listen_session) + ls = vcl_session_get_w_handle (wrk, ls_handle); + if (!ls) return VPPCOM_EBADFD; - listen_session_index = listen_session->session_index; - if ((rv = validate_args_session_accept_ (wrk, listen_session))) - return rv; + if ((ls->session_state != VCL_STATE_LISTEN) && + (ls->session_state != VCL_STATE_LISTEN_NO_MQ) && + (!vcl_session_is_connectable_listener (wrk, ls))) + { + VDBG (0, "ERROR: session [0x%llx]: not in listen state! state (%s)", + ls->vpp_handle, vcl_session_state_str (ls->session_state)); + return VPPCOM_EBADFD; + } - if (clib_fifo_elts (listen_session->accept_evts_fifo)) + ls_index = ls->session_index; + + if (clib_fifo_elts (ls->accept_evts_fifo)) { - clib_fifo_sub2 (listen_session->accept_evts_fifo, evt); + clib_fifo_sub2 (ls->accept_evts_fifo, evt); accept_flags = evt->flags; accepted_msg = evt->accepted_msg; goto handle; } - is_nonblocking = vcl_session_has_attr (listen_session, - VCL_SESS_ATTR_NONBLOCK); + is_nonblocking = vcl_session_has_attr (ls, VCL_SESS_ATTR_NONBLOCK); while (1) { if (svm_msg_q_is_empty (wrk->app_event_queue) && is_nonblocking) @@ -1793,20 +1783,21 @@ again: handle: - client_session_index = vcl_session_accepted_handler (wrk, &accepted_msg, - listen_session_index); + client_session_index = + vcl_session_accepted_handler (wrk, &accepted_msg, ls_index); if (client_session_index == VCL_INVALID_SESSION_INDEX) return VPPCOM_ECONNABORTED; - listen_session = vcl_session_get (wrk, listen_session_index); + ls = vcl_session_get (wrk, ls_index); client_session = vcl_session_get (wrk, client_session_index); if (flags & O_NONBLOCK) vcl_session_set_attr (client_session, VCL_SESS_ATTR_NONBLOCK); - VDBG (1, "listener %u [0x%llx]: Got a connect request! session %u [0x%llx]," - " flags %d, is_nonblocking %u", listen_session->session_index, - listen_session->vpp_handle, client_session_index, + VDBG (1, + "listener %u [0x%llx]: Got a connect request! session %u [0x%llx]," + " flags %d, is_nonblocking %u", + ls->session_index, ls->vpp_handle, client_session_index, client_session->vpp_handle, flags, vcl_session_has_attr (client_session, VCL_SESS_ATTR_NONBLOCK)); @@ -1825,16 +1816,15 @@ handle: VDBG (0, "listener %u [0x%llx] accepted %u [0x%llx] peer: %U:%u " "local: %U:%u", - listen_session_handle, listen_session->vpp_handle, - client_session_index, client_session->vpp_handle, - vcl_format_ip46_address, &client_session->transport.rmt_ip, + ls_handle, ls->vpp_handle, client_session_index, + client_session->vpp_handle, vcl_format_ip46_address, + &client_session->transport.rmt_ip, client_session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (client_session->transport.rmt_port), vcl_format_ip46_address, &client_session->transport.lcl_ip, client_session->transport.is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6, clib_net_to_host_u16 (client_session->transport.lcl_port)); - vcl_evt (VCL_EVT_ACCEPT, client_session, listen_session, - client_session_index); + vcl_evt (VCL_EVT_ACCEPT, client_session, ls, client_session_index); /* * Session might have been closed already @@ -2228,7 +2218,7 @@ vcl_fifo_is_writeable (svm_fifo_t * f, u32 len, u8 is_dgram) always_inline int vppcom_session_write_inline (vcl_worker_t *wrk, vcl_session_t *s, void *buf, - size_t n, u16 gso_size, u8 is_flush, u8 is_dgram) + size_t n, u8 is_flush, u8 is_dgram) { int n_write, is_nonblocking; session_evt_type_t et; @@ -2293,12 +2283,17 @@ vppcom_session_write_inline (vcl_worker_t *wrk, vcl_session_t *s, void *buf, et = SESSION_IO_EVT_TX_FLUSH; if (is_dgram) - n_write = - app_send_dgram_raw_gso (tx_fifo, &s->transport, s->vpp_evt_q, buf, n, - gso_size, et, 0 /* do_evt */, SVM_Q_WAIT); + { + et = vcl_session_dgram_tx_evt (s, et); + n_write = + app_send_dgram_raw_gso (tx_fifo, &s->transport, s->vpp_evt_q, buf, n, + s->gso_size, et, 0 /* do_evt */, SVM_Q_WAIT); + } else - n_write = app_send_stream_raw (tx_fifo, s->vpp_evt_q, buf, n, et, - 0 /* do_evt */ , SVM_Q_WAIT); + { + n_write = app_send_stream_raw (tx_fifo, s->vpp_evt_q, buf, n, et, + 0 /* do_evt */, SVM_Q_WAIT); + } if (svm_fifo_set_event (s->tx_fifo)) app_send_io_evt_to_vpp ( @@ -2324,7 +2319,7 @@ vppcom_session_write (uint32_t session_handle, void *buf, size_t n) if (PREDICT_FALSE (!s)) return VPPCOM_EBADFD; - return vppcom_session_write_inline (wrk, s, buf, n, 0, 0 /* is_flush */, + return vppcom_session_write_inline (wrk, s, buf, n, 0 /* is_flush */, s->is_dgram ? 1 : 0); } @@ -2338,7 +2333,7 @@ vppcom_session_write_msg (uint32_t session_handle, void *buf, size_t n) if (PREDICT_FALSE (!s)) return VPPCOM_EBADFD; - return vppcom_session_write_inline (wrk, s, buf, n, 0, 1 /* is_flush */, + return vppcom_session_write_inline (wrk, s, buf, n, 1 /* is_flush */, s->is_dgram ? 1 : 0); } @@ -2421,11 +2416,17 @@ vcl_select_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, sid = e->session_index; if (sid == VCL_INVALID_SESSION_INDEX) break; - if (sid < n_bits && write_map) - { - clib_bitmap_set_no_check ((uword *) write_map, sid, 1); - *bits_set += 1; - } + if (!(sid < n_bits && write_map)) + break; + clib_bitmap_set_no_check ((uword *) write_map, sid, 1); + *bits_set += 1; + s = vcl_session_get (wrk, sid); + if (!s->tx_fifo) + break; + /* We didn't have a fifo when the event was added */ + svm_fifo_add_want_deq_ntf ( + (vcl_session_is_ct (s) ? s->ct_tx_fifo : s->tx_fifo), + SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL); break; case SESSION_CTRL_EVT_DISCONNECTED: disconnected_msg = (session_disconnected_msg_t *) e->data; @@ -2635,7 +2636,7 @@ vppcom_select (int n_bits, vcl_si_set * read_map, vcl_si_set * write_map, clib_bitmap_set_no_check ((uword *) write_map, sid, 1); bits_set++; } - else + else if (s->tx_fifo) { svm_fifo_t *txf = vcl_session_is_ct (s) ? s->ct_tx_fifo : s->tx_fifo; svm_fifo_add_want_deq_ntf (txf, SVM_FIFO_WANT_DEQ_NOTIF); @@ -2688,7 +2689,7 @@ vep_verify_epoll_chain (vcl_worker_t * wrk, u32 vep_handle) u32 sh = vep_handle; vcl_session_t *s; - if (VPPCOM_DEBUG <= 2) + if (VPPCOM_DEBUG <= 3) return; s = vcl_session_get_w_handle (wrk, vep_handle); @@ -2773,6 +2774,25 @@ vppcom_epoll_create (void) return vcl_session_handle (vep_session); } +static void +vcl_epoll_ctl_add_unhandled_event (vcl_worker_t *wrk, vcl_session_t *s, + u8 is_epollet, session_evt_type_t evt) +{ + if (!is_epollet) + { + if (s->vep.lt_next == VCL_INVALID_SESSION_INDEX) + vcl_epoll_lt_add (wrk, s); + return; + } + + session_event_t e = { 0 }; + e.session_index = s->session_index; + e.event_type = evt; + if (evt == SESSION_IO_EVT_RX) + s->flags &= ~VCL_SESSION_F_HAS_RX_EVT; + vec_add1 (wrk->unhandled_evts_vector, e); +} + int vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle, struct epoll_event *event) @@ -2861,20 +2881,15 @@ vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle, /* Generate EPOLLOUT if tx fifo not full */ if ((event->events & EPOLLOUT) && (vcl_session_write_ready (s) > 0)) { - session_event_t e = { 0 }; - e.event_type = SESSION_IO_EVT_TX; - e.session_index = s->session_index; - vec_add1 (wrk->unhandled_evts_vector, e); + vcl_epoll_ctl_add_unhandled_event (wrk, s, event->events & EPOLLET, + SESSION_IO_EVT_TX); add_evt = 1; } /* Generate EPOLLIN if rx fifo has data */ if ((event->events & EPOLLIN) && (vcl_session_read_ready (s) > 0)) { - session_event_t e = { 0 }; - e.event_type = SESSION_IO_EVT_RX; - e.session_index = s->session_index; - vec_add1 (wrk->unhandled_evts_vector, e); - s->flags &= ~VCL_SESSION_F_HAS_RX_EVT; + vcl_epoll_ctl_add_unhandled_event (wrk, s, event->events & EPOLLET, + SESSION_IO_EVT_RX); add_evt = 1; } if (!add_evt && vcl_session_is_closing (s)) @@ -2914,35 +2929,32 @@ vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle, goto done; } + txf = vcl_session_is_ct (s) ? s->ct_tx_fifo : s->tx_fifo; + if (txf) + { + if (event->events & EPOLLOUT) + svm_fifo_add_want_deq_ntf (txf, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL); + else + svm_fifo_del_want_deq_ntf (txf, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL); + } + /* Generate EPOLLOUT if session write ready nd event was not on */ if ((event->events & EPOLLOUT) && !(s->vep.ev.events & EPOLLOUT) && (vcl_session_write_ready (s) > 0)) { - session_event_t e = { 0 }; - e.event_type = SESSION_IO_EVT_TX; - e.session_index = s->session_index; - vec_add1 (wrk->unhandled_evts_vector, e); + vcl_epoll_ctl_add_unhandled_event (wrk, s, event->events & EPOLLET, + SESSION_IO_EVT_TX); } /* Generate EPOLLIN if session read ready and event was not on */ if ((event->events & EPOLLIN) && !(s->vep.ev.events & EPOLLIN) && (vcl_session_read_ready (s) > 0)) { - session_event_t e = { 0 }; - e.event_type = SESSION_IO_EVT_RX; - e.session_index = s->session_index; - vec_add1 (wrk->unhandled_evts_vector, e); - s->flags &= ~VCL_SESSION_F_HAS_RX_EVT; + vcl_epoll_ctl_add_unhandled_event (wrk, s, event->events & EPOLLET, + SESSION_IO_EVT_RX); } s->vep.et_mask = VEP_DEFAULT_ET_MASK; s->vep.ev = *event; - txf = vcl_session_is_ct (s) ? s->ct_tx_fifo : s->tx_fifo; - if (txf) - { - if (event->events & EPOLLOUT) - svm_fifo_add_want_deq_ntf (txf, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL); - else - svm_fifo_del_want_deq_ntf (txf, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL); - } + VDBG (1, "EPOLL_CTL_MOD: vep_sh %u, sh %u, events 0x%x, data 0x%llx!", vep_handle, session_handle, event->events, event->data.u64); break; @@ -3058,14 +3070,14 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, s = vcl_session_get (wrk, sid); if (!s || !vcl_session_is_open (s)) break; + svm_fifo_reset_has_deq_ntf (vcl_session_is_ct (s) ? s->ct_tx_fifo : + s->tx_fifo); session_events = s->vep.ev.events; if (!(EPOLLOUT & session_events)) break; add_event = 1; events[*num_ev].events = EPOLLOUT; session_evt_data = s->vep.ev.data.u64; - svm_fifo_reset_has_deq_ntf (vcl_session_is_ct (s) ? - s->ct_tx_fifo : s->tx_fifo); break; case SESSION_CTRL_EVT_ACCEPTED: if (!e->postponed) @@ -3096,7 +3108,7 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, break; session_events = s->vep.ev.events; /* Generate EPOLLOUT because there's no connected event */ - if (!(EPOLLOUT & session_events)) + if (!(EPOLLOUT & session_events) || !s->tx_fifo) break; /* We didn't have a fifo when the event was added */ svm_fifo_add_want_deq_ntf ( @@ -3145,6 +3157,9 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e, } session_evt_data = s->vep.ev.data.u64; + 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) @@ -3354,7 +3369,7 @@ static void vcl_epoll_wait_handle_lt (vcl_worker_t *wrk, struct epoll_event *events, int maxevents, u32 *n_evts) { - u32 add_event = 0, next; + u32 add_event = 0, next, *to_remove = 0, *si; vcl_session_t *s; u64 evt_data; int rv; @@ -3402,12 +3417,17 @@ vcl_epoll_wait_handle_lt (vcl_worker_t *wrk, struct epoll_event *events, } else { - vcl_epoll_lt_del (wrk, s); - if (wrk->ep_lt_current == VCL_INVALID_SESSION_INDEX) - break; + 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 @@ -4105,6 +4125,36 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op, 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; @@ -4148,13 +4198,37 @@ vppcom_session_recvfrom (uint32_t session_handle, void *buffer, 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; - u16 gso_size = 0; s = vcl_session_get_w_handle (wrk, session_handle); if (PREDICT_FALSE (!s)) @@ -4169,12 +4243,9 @@ vppcom_session_sendto (uint32_t session_handle, void *buffer, s->transport.rmt_port = ep->port; vcl_ip_copy_from_ep (&s->transport.rmt_ip, ep); - vppcom_endpt_tlv_t *p_app_data = &ep->app_data; + if (ep->app_tlvs) + vcl_handle_ep_app_tlvs (s, ep); - if (p_app_data && (p_app_data->data_type == VCL_UDP_SEGMENT)) - { - gso_size = p_app_data->value; - } /* Session not connected/bound in vpp. Create it by 'connecting' it */ if (PREDICT_FALSE (s->session_state == VCL_STATE_CLOSED)) { @@ -4198,7 +4269,7 @@ vppcom_session_sendto (uint32_t session_handle, void *buffer, VDBG (2, "handling flags 0x%u (%d) not implemented yet.", flags, flags); } - return (vppcom_session_write_inline (wrk, s, buffer, buflen, gso_size, 1, + return (vppcom_session_write_inline (wrk, s, buffer, buflen, 1, s->is_dgram ? 1 : 0)); }