VCL: Update lcl addr/port from connect session reply msg.
[vpp.git] / src / vcl / vppcom.c
index 09ebe26..2e867c7 100644 (file)
@@ -306,6 +306,46 @@ vppcom_session_at_index (u32 session_index, session_t * volatile *sess)
   return VPPCOM_OK;
 }
 
+static inline void
+vppcom_session_table_add_listener (u64 listener_handle, u32 value)
+{
+  /* Session and listener handles have different formats. The latter has
+   * the thread index in the upper 32 bits while the former has the session
+   * type. Knowing that, for listeners we just flip the MSB to 1 */
+  listener_handle |= 1ULL << 63;
+  hash_set (vcm->session_index_by_vpp_handles, listener_handle, value);
+}
+
+static inline session_t *
+vppcom_session_table_lookup_listener (u64 listener_handle)
+{
+  uword *p;
+  u64 handle = listener_handle | (1ULL << 63);
+  p = hash_get (vcm->session_index_by_vpp_handles, handle);
+  if (!p)
+    {
+      clib_warning ("[%d] couldn't find listen session: unknown vpp "
+                   "listener handle %llx", getpid (), listener_handle);
+      return 0;
+    }
+  if (pool_is_free_index (vcm->sessions, p[0]))
+    {
+      if (VPPCOM_DEBUG > 1)
+       clib_warning ("[%d] invalid listen session, sid (%u)", getpid (),
+                     p[0]);
+      return 0;
+    }
+
+  return pool_elt_at_index (vcm->sessions, p[0]);
+}
+
+static inline void
+vppcom_session_table_del_listener (u64 listener_handle)
+{
+  listener_handle |= 1ULL << 63;
+  hash_unset (vcm->session_index_by_vpp_handles, listener_handle);
+}
+
 static int
 vppcom_connect_to_vpp (char *app_name)
 {
@@ -670,12 +710,26 @@ vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
   session_t *session = 0;
   vl_api_disconnect_session_reply_t *rmp;
   uword *p;
-  int rv = 0;
+  int rv = 0, rval;
 
   p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
+  if (VPPCOM_DEBUG > 0)
+    {
+      if (!p)
+       {
+         clib_warning ("[%d] request to disconnect invalid handle (%u)!",
+                       getpid (), mp->handle);
+         rv = -11;
+         goto done;
+       }
+      clib_warning ("[%d] disconnecting handle %u sid (%u)!", getpid (),
+                   mp->handle, p[0]);
+    }
+
+  goto done;
+
   if (p)
     {
-      int rval;
       clib_spinlock_lock (&vcm->sessions_lockp);
       rval = vppcom_session_at_index (p[0], &session);
       if (PREDICT_FALSE (rval))
@@ -691,11 +745,12 @@ vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
     }
   else
     {
-      clib_warning ("[%d] couldn't find session: unknonwn vpp handle 0x%llx",
+      clib_warning ("[%d] couldn't find session: unknown vpp handle 0x%llx",
                    getpid (), mp->handle);
       rv = -11;
     }
 
+done:
   rmp = vl_msg_api_alloc (sizeof (*rmp));
   memset (rmp, 0, sizeof (*rmp));
 
@@ -816,6 +871,10 @@ vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp)
   session->server_rx_fifo = rx_fifo;
   session->server_tx_fifo = tx_fifo;
   session->vpp_handle = mp->handle;
+  session->lcl_addr.is_ip4 = mp->is_ip4;
+  clib_memcpy (&session->lcl_addr.ip46, mp->lcl_ip,
+              sizeof (session->peer_addr.ip46));
+  session->lcl_port = mp->lcl_port;
   session->state = STATE_CONNECT;
 
   /* Add it to lookup table */
@@ -890,8 +949,11 @@ vl_api_bind_sock_reply_t_handler (vl_api_bind_sock_reply_t * mp)
   if (rv == VPPCOM_OK)
     {
       session->vpp_handle = mp->handle;
-      hash_set (vcm->session_index_by_vpp_handles, mp->handle,
-               vcm->bind_session_index);
+      session->lcl_addr.is_ip4 = mp->lcl_is_ip4;
+      clib_memcpy (&session->lcl_addr.ip46, mp->lcl_ip,
+                  sizeof (session->peer_addr.ip46));
+      session->lcl_port = mp->lcl_port;
+      vppcom_session_table_add_listener (mp->handle, vcm->bind_session_index);
       session->state = mp->retval ? STATE_FAILED : STATE_LISTEN;
       vcm->bind_session_index = ~0;
     }
@@ -902,16 +964,17 @@ static void
 vl_api_unbind_sock_reply_t_handler (vl_api_unbind_sock_reply_t * mp)
 {
   session_t *session = 0;
-  int rv;
 
   clib_spinlock_lock (&vcm->sessions_lockp);
-  rv = vppcom_session_at_index (vcm->bind_session_index, &session);
-  if (rv == VPPCOM_OK)
+  session = vppcom_session_table_lookup_listener (vcm->bind_session_index);
+
+  if (session)
     {
       if ((VPPCOM_DEBUG > 1) && (mp->retval))
        clib_warning ("[%d] unbind failed: %U", getpid (), format_api_error,
                      ntohl (mp->retval));
 
+      vppcom_session_table_del_listener (vcm->bind_session_index);
       vcm->bind_session_index = ~0;
       session->state = STATE_START;
     }
@@ -1018,15 +1081,24 @@ static void
 vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
 {
   svm_fifo_t *rx_fifo, *tx_fifo;
-  session_t *session;
+  session_t *session, *listen_session;
   u32 session_index;
 
   clib_spinlock_lock (&vcm->sessions_lockp);
   if (!clib_fifo_free_elts (vcm->client_session_index_fifo))
     {
       clib_warning ("[%d] client session queue is full!", getpid ());
-      vppcom_send_accept_session_reply (VNET_API_ERROR_QUEUE_FULL,
-                                       mp->handle);
+      vppcom_send_accept_session_reply (mp->handle,
+                                       VNET_API_ERROR_QUEUE_FULL);
+      clib_spinlock_unlock (&vcm->sessions_lockp);
+      return;
+    }
+
+  listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
+  if (!listen_session)
+    {
+      clib_warning ("[%d] ERROR: couldn't find listen session: unknown vpp "
+                   "listener handle %llx", getpid (), mp->listener_handle);
       clib_spinlock_unlock (&vcm->sessions_lockp);
       return;
     }
@@ -1056,8 +1128,12 @@ vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
 
   /* Add it to lookup table */
   hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
+  session->lcl_port = listen_session->lcl_port;
+  session->lcl_addr = listen_session->lcl_addr;
 
+  /* TBD: move client_session_index_fifo into listener session */
   clib_fifo_add1 (vcm->client_session_index_fifo, session_index);
+
   clib_spinlock_unlock (&vcm->sessions_lockp);
 
   if (VPPCOM_DEBUG > 1)
@@ -1071,8 +1147,7 @@ vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
 }
 
 static void
-vppcom_send_connect_session_reply (session_t * session, u32 context,
-                                  int retval, int handle)
+vppcom_send_connect_session_reply (session_t * session, int retval)
 {
   vl_api_connect_session_reply_t *rmp;
   u32 len;
@@ -1082,26 +1157,20 @@ vppcom_send_connect_session_reply (session_t * session, u32 context,
   memset (rmp, 0, sizeof (*rmp));
 
   rmp->_vl_msg_id = ntohs (VL_API_CONNECT_SESSION_REPLY);
-  rmp->context = session ? session->client_context : context;
+  rmp->context = session->client_context;
   rmp->retval = htonl (retval);
-  rmp->handle = session ? session->vpp_handle : handle;
-
-  if (session)
-    {
-      rmp->server_rx_fifo = pointer_to_uword (session->server_rx_fifo);
-      rmp->server_tx_fifo = pointer_to_uword (session->server_tx_fifo);
-      rmp->vpp_event_queue_address =
-       pointer_to_uword (session->vpp_event_queue);
-      rmp->segment_size = vcm->cfg.segment_size;
-      len = vec_len (session->segment_name);
-      rmp->segment_name_length = clib_min (len, sizeof (rmp->segment_name));
-      clib_memcpy (rmp->segment_name, session->segment_name,
-                  rmp->segment_name_length - 1);
-      clib_memcpy (rmp->lcl_ip, session->lcl_addr.ip46.as_u8,
-                  sizeof (rmp->lcl_ip));
-      rmp->is_ip4 = session->lcl_addr.is_ip4;
-    }
-
+  rmp->handle = session->vpp_handle;
+  rmp->server_rx_fifo = pointer_to_uword (session->server_rx_fifo);
+  rmp->server_tx_fifo = pointer_to_uword (session->server_tx_fifo);
+  rmp->vpp_event_queue_address = pointer_to_uword (session->vpp_event_queue);
+  rmp->segment_size = vcm->cfg.segment_size;
+  len = vec_len (session->segment_name);
+  rmp->segment_name_length = clib_min (len, sizeof (rmp->segment_name));
+  clib_memcpy (rmp->segment_name, session->segment_name,
+              rmp->segment_name_length - 1);
+  clib_memcpy (rmp->lcl_ip, session->lcl_addr.ip46.as_u8,
+              sizeof (rmp->lcl_ip));
+  rmp->is_ip4 = session->lcl_addr.is_ip4;
   client_q = uword_to_pointer (session->client_queue_address,
                               unix_shared_memory_queue_t *);
   ASSERT (client_q);
@@ -1123,7 +1192,8 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
       if (VPPCOM_DEBUG > 1)
        clib_warning ("[%d] client session queue is full!", getpid ());
       clib_spinlock_unlock (&vcm->sessions_lockp);
-      vppcom_send_accept_session_reply (VNET_API_ERROR_QUEUE_FULL, 0);
+      /* TBD: fix handle */
+      vppcom_send_accept_session_reply (0, VNET_API_ERROR_QUEUE_FULL);
       return;
     }
 
@@ -1242,6 +1312,9 @@ vppcom_session_unbind (u32 session_index)
     }
   clib_spinlock_unlock (&vcm->sessions_lockp);
 
+  if (vcm->bind_session_index != session_index)
+    clib_warning ("[%d] ERROR: unbinding a not bound listener %u (%u)",
+                 session_index, vcm->bind_session_index);
   vcm->bind_session_index = session_index;
   vppcom_send_unbind_sock (session_index);
   rv = vppcom_wait_for_session_state_change (session_index, STATE_START,
@@ -1276,17 +1349,26 @@ vppcom_session_disconnect (u32 session_index)
 
   if (!session->is_cut_thru)
     {
+      if (VPPCOM_DEBUG > 1)
+       clib_warning ("[%d] disconnecting sid (%u)", getpid (),
+                     session_index);
       vppcom_send_disconnect (session);
       clib_spinlock_unlock (&vcm->sessions_lockp);
 
       rv = vppcom_wait_for_session_state_change (session_index,
                                                 STATE_DISCONNECT, 1.0);
+      /* TBD: Force clean up on error/timeout since there is no other
+       *      way to recover from a failed disconnect.
+       */
       if ((VPPCOM_DEBUG > 0) && (rv < 0))
        clib_warning ("[%d] disconnect (session %d) failed, rv = %s (%d)",
                      getpid (), session_index, vppcom_retval_str (rv), rv);
     }
   else
-    clib_spinlock_unlock (&vcm->sessions_lockp);
+    {
+      /* TBD: Handle cut-thru disconnect */
+      clib_spinlock_unlock (&vcm->sessions_lockp);
+    }
 
   return VPPCOM_OK;
 }
@@ -2212,11 +2294,11 @@ vppcom_session_listen (uint32_t listen_session_index, uint32_t q_len)
 
 int
 vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
-                      double wait_for_time)
+                      uint32_t flags, double wait_for_time)
 {
   session_t *listen_session = 0;
   session_t *client_session = 0;
-  u32 client_session_index;
+  u32 client_session_index = ~0;
   int rv;
   f64 wait_for;
   char *cut_thru_str;
@@ -2283,9 +2365,11 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
   ASSERT (client_session->peer_addr.is_ip4 ==
          listen_session->lcl_addr.is_ip4);
 
+  client_session->is_nonblocking = (flags & O_NONBLOCK) ? 1 : 0;
   if (VPPCOM_DEBUG > 0)
-    clib_warning ("[%d] Got a request: client sid %d", getpid (),
-                 client_session_index);
+    clib_warning ("[%d] Got a request: client sid %d, flags %d, "
+                 " is_nonblocking %u", getpid (), client_session_index,
+                 flags, client_session->is_nonblocking);
 
   ep->vrf = client_session->vrf;
   ep->is_cut_thru = client_session->is_cut_thru;
@@ -2324,7 +2408,7 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
                          getpid (), a->segment_name);
          vec_reset_length (a->new_segment_indices);
          rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
-         vppcom_send_connect_session_reply (client_session, 0, rv, 0);
+         vppcom_send_connect_session_reply (client_session, rv);
          clib_spinlock_unlock (&vcm->sessions_lockp);
          return VPPCOM_ENOMEM;
        }
@@ -2344,7 +2428,7 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
                        getpid (), vcm->cfg.rx_fifo_size,
                        vcm->cfg.rx_fifo_size);
          rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
-         vppcom_send_connect_session_reply (client_session, 0, rv, 0);
+         vppcom_send_connect_session_reply (client_session, rv);
          clib_spinlock_unlock (&vcm->sessions_lockp);
          return VPPCOM_ENOMEM;
        }
@@ -2362,7 +2446,7 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
                          getpid (), vcm->cfg.tx_fifo_size,
                          vcm->cfg.tx_fifo_size);
          rv = VNET_API_ERROR_URI_FIFO_CREATE_FAILED;
-         vppcom_send_connect_session_reply (client_session, 0, rv, 0);
+         vppcom_send_connect_session_reply (client_session, rv);
          clib_spinlock_unlock (&vcm->sessions_lockp);
          return VPPCOM_ENOMEM;
        }
@@ -2390,12 +2474,12 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
        ssvm_unlock_non_recursive (sh);
       }
 #endif
-      vppcom_send_connect_session_reply (client_session, 0, 0, 0);
+      vppcom_send_connect_session_reply (client_session, 0);
     }
   else
     {
       cut_thru_str = " ";
-      vppcom_send_accept_session_reply (0, client_session->vpp_handle);
+      vppcom_send_accept_session_reply (client_session->vpp_handle, 0);
     }
 
   if (VPPCOM_DEBUG > 0)
@@ -3419,14 +3503,18 @@ vppcom_session_attr (uint32_t session_index, uint32_t op,
     {
     case VPPCOM_ATTR_GET_NREAD:
       rv = vppcom_session_read_ready (session, session_index);
-      if (VPPCOM_DEBUG > 1)
-       clib_warning ("[%d] VPPCOM_ATTR_GET_NREAD: nread = %d",
+      if (VPPCOM_DEBUG > 2)
+       clib_warning ("[%d] VPPCOM_ATTR_GET_NREAD: sid %u, nread = %d",
                      getpid (), rv);
 
       break;
 
-    case VPPCOM_ATTR_PEEK_NREAD:
-      /* TBD */
+    case VPPCOM_ATTR_GET_NWRITE:
+      rv = vppcom_session_write_ready (session, session_index);
+      if (VPPCOM_DEBUG > 2)
+       clib_warning ("[%d] VPPCOM_ATTR_GET_NWRITE: sid %u, nwrite = %d",
+                     getpid (), session_index, rv);
+
       break;
 
     case VPPCOM_ATTR_GET_FLAGS:
@@ -3434,10 +3522,10 @@ vppcom_session_attr (uint32_t session_index, uint32_t op,
        {
          *flags = O_RDWR | ((session->is_nonblocking) ? O_NONBLOCK : 0);
          *buflen = sizeof (*flags);
-         if (VPPCOM_DEBUG > 1)
-           clib_warning ("[%d] VPPCOM_ATTR_GET_FLAGS: flags = 0x%08x, "
-                         "is_nonblocking = %u", getpid (), *flags,
-                         session->is_nonblocking);
+         if (VPPCOM_DEBUG > 2)
+           clib_warning ("[%d] VPPCOM_ATTR_GET_FLAGS: sid %u, "
+                         "flags = 0x%08x, is_nonblocking = %u", getpid (),
+                         session_index, *flags, session->is_nonblocking);
        }
       else
        rv = VPPCOM_EINVAL;
@@ -3447,10 +3535,10 @@ vppcom_session_attr (uint32_t session_index, uint32_t op,
       if (buffer && buflen && (*buflen >= sizeof (*flags)))
        {
          session->is_nonblocking = (*flags & O_NONBLOCK) ? 1 : 0;
-         if (VPPCOM_DEBUG > 1)
-           clib_warning ("[%d] VPPCOM_ATTR_SET_FLAGS: flags = 0x%08x, "
-                         "is_nonblocking = %u", getpid (), *flags,
-                         session->is_nonblocking);
+         if (VPPCOM_DEBUG > 2)
+           clib_warning ("[%d] VPPCOM_ATTR_SET_FLAGS: sid %u, "
+                         "flags = 0x%08x, is_nonblocking = %u",
+                         getpid (), *flags, session->is_nonblocking);
        }
       else
        rv = VPPCOM_EINVAL;
@@ -3470,7 +3558,7 @@ vppcom_session_attr (uint32_t session_index, uint32_t op,
                         sizeof (ip6_address_t));
          *buflen = sizeof (*ep);
          if (VPPCOM_DEBUG > 1)
-           clib_warning ("[%d] VPPCOM_ATTR_GET_PEER_ADDR: sid %u is_ip4 = "
+           clib_warning ("[%d] VPPCOM_ATTR_GET_PEER_ADDR: sid %u, is_ip4 = "
                          "%u, addr = %U, port %u", getpid (),
                          session_index, ep->is_ip4, format_ip46_address,
                          &session->peer_addr.ip46, ep->is_ip4,
@@ -3494,7 +3582,7 @@ vppcom_session_attr (uint32_t session_index, uint32_t op,
                         sizeof (ip6_address_t));
          *buflen = sizeof (*ep);
          if (VPPCOM_DEBUG > 1)
-           clib_warning ("[%d] VPPCOM_ATTR_GET_LCL_ADDR: sid %u is_ip4 = "
+           clib_warning ("[%d] VPPCOM_ATTR_GET_LCL_ADDR: sid %u, is_ip4 = "
                          "%u, addr = %U port %d", getpid (),
                          session_index, ep->is_ip4, format_ip46_address,
                          &session->lcl_addr.ip46, ep->is_ip4,