LCOV - code coverage report
Current view: top level - plugins/hs_apps/sapi - vpp_echo.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 592 852 69.5 %
Date: 2023-07-05 22:20:52 Functions: 41 47 87.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2019 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <stdio.h>
      17             : #include <signal.h>
      18             : 
      19             : #include <vlibmemory/api.h>
      20             : #include <svm/fifo_segment.h>
      21             : 
      22             : #include <hs_apps/sapi/vpp_echo_common.h>
      23             : 
      24             : echo_main_t echo_main;
      25             : 
      26             : static void
      27           4 : echo_session_prealloc (echo_main_t * em)
      28             : {
      29             :   /* We need to prealloc to avoid vec resize in threads */
      30             :   echo_session_t *session;
      31             :   int i;
      32          16 :   for (i = 0; i < em->n_sessions; i++)
      33             :     {
      34          12 :       pool_get (em->sessions, session);
      35          12 :       clib_memset (session, 0, sizeof (*session));
      36          12 :       session->session_index = session - em->sessions;
      37          12 :       session->listener_index = SESSION_INVALID_INDEX;
      38          12 :       session->session_state = ECHO_SESSION_STATE_INITIAL;
      39             :     }
      40           4 : }
      41             : 
      42             : static void
      43           4 : echo_assert_test_suceeded (echo_main_t * em)
      44             : {
      45           4 :   if (em->rx_results_diff)
      46           0 :     CHECK_DIFF (ECHO_FAIL_TEST_ASSERT_RX_TOTAL, em->stats.rx_expected,
      47             :                 em->stats.rx_total, "Invalid amount of data received");
      48             :   else
      49           4 :     CHECK_SAME (ECHO_FAIL_TEST_ASSERT_RX_TOTAL, em->stats.rx_expected,
      50             :                 em->stats.rx_total, "Invalid amount of data received");
      51             : 
      52           4 :   if (em->tx_results_diff)
      53           0 :     CHECK_DIFF (ECHO_FAIL_TEST_ASSERT_TX_TOTAL, em->stats.tx_expected,
      54             :                 em->stats.tx_total, "Invalid amount of data sent");
      55             :   else
      56           4 :     CHECK_SAME (ECHO_FAIL_TEST_ASSERT_TX_TOTAL, em->stats.tx_expected,
      57             :                 em->stats.tx_total, "Invalid amount of data sent");
      58             : 
      59           4 :   clib_spinlock_lock (&em->sid_vpp_handles_lock);
      60           4 :   CHECK_SAME (ECHO_FAIL_TEST_ASSERT_ALL_SESSIONS_CLOSED,
      61             :               0, hash_elts (em->session_index_by_vpp_handles),
      62             :               "Some sessions are still open");
      63           4 :   clib_spinlock_unlock (&em->sid_vpp_handles_lock);
      64           4 : }
      65             : 
      66             : always_inline void
      67        1714 : echo_session_dequeue_notify (echo_session_t * s)
      68             : {
      69             :   int rv;
      70        1714 :   if (!svm_fifo_set_event (s->rx_fifo))
      71        1135 :     return;
      72         579 :   if ((rv = app_send_io_evt_to_vpp (s->vpp_evt_q,
      73         579 :                                     s->rx_fifo->shr->master_session_index,
      74             :                                     SESSION_IO_EVT_RX, SVM_Q_WAIT)))
      75           0 :     ECHO_FAIL (ECHO_FAIL_SEND_IO_EVT, "app_send_io_evt_to_vpp errored %d",
      76             :                rv);
      77         579 :   svm_fifo_clear_deq_ntf (s->rx_fifo);
      78             : }
      79             : 
      80             : static void
      81           0 : stop_signal (int signum)
      82             : {
      83           0 :   echo_main_t *em = &echo_main;
      84           0 :   em->time_to_stop = 1;
      85           0 : }
      86             : 
      87             : static int
      88           4 : connect_to_vpp (echo_main_t *em)
      89             : {
      90           4 :   api_main_t *am = vlibapi_get_main ();
      91             : 
      92           4 :   if (em->use_app_socket_api)
      93           4 :     return echo_api_connect_app_socket (em);
      94             : 
      95           0 :   if (em->use_sock_api)
      96             :     {
      97           0 :       if (vl_socket_client_connect ((char *) em->socket_name,
      98           0 :                                     (char *) em->app_name,
      99             :                                     0 /* default rx, tx buffer */))
     100             :         {
     101           0 :           ECHO_FAIL (ECHO_FAIL_SOCKET_CONNECT, "socket connect failed");
     102           0 :           return -1;
     103             :         }
     104             : 
     105           0 :       if (vl_socket_client_init_shm (0, 1 /* want_pthread */ ))
     106             :         {
     107           0 :           ECHO_FAIL (ECHO_FAIL_INIT_SHM_API, "init shm api failed");
     108           0 :           return -1;
     109             :         }
     110             :     }
     111             :   else
     112             :     {
     113           0 :       if (vl_client_connect_to_vlib ("/vpe-api", (char *) em->app_name, 32) <
     114             :           0)
     115             :         {
     116           0 :           ECHO_FAIL (ECHO_FAIL_SHMEM_CONNECT, "shmem connect failed");
     117           0 :           return -1;
     118             :         }
     119             :     }
     120           0 :   em->vl_input_queue = am->shmem_hdr->vl_input_queue;
     121           0 :   em->my_client_index = am->my_client_index;
     122           0 :   return 0;
     123             : }
     124             : 
     125             : static void
     126           4 : print_global_json_stats (echo_main_t * em)
     127             : {
     128           4 :   u8 *start_evt =
     129           4 :     format (0, "%U", echo_format_timing_event, em->timing.start_event);
     130           4 :   u8 *end_evt =
     131           4 :     format (0, "%U", echo_format_timing_event, em->timing.end_event);
     132           4 :   u8 start_evt_missing = !(em->timing.events_sent & em->timing.start_event);
     133           8 :   u8 end_evt_missing = (em->rx_results_diff || em->tx_results_diff) ? 0 :
     134           4 :     !(em->timing.events_sent & em->timing.end_event);
     135           4 :   f64 deltat = start_evt_missing || end_evt_missing ? 0 :
     136           4 :     em->timing.end_time - em->timing.start_time;
     137             : 
     138           4 :   if (start_evt_missing)
     139           0 :     ECHO_FAIL (ECHO_FAIL_MISSING_START_EVENT,
     140             :                "Expected event %v to happen, but it did not!", start_evt);
     141             : 
     142           4 :   if (end_evt_missing)
     143           0 :     ECHO_FAIL (ECHO_FAIL_MISSING_END_EVENT,
     144             :                "Expected event %v to happen, but it did not!", end_evt);
     145             : 
     146           4 :   fformat (stdout, "vpp_echo JSON stats:\n{\n");
     147           4 :   fformat (stdout, "  \"role\": \"%s\",\n",
     148           4 :            em->i_am_master ? "server" : "client");
     149           4 :   fformat (stdout, "  \"time\": \"%.9f\",\n", deltat);
     150           4 :   fformat (stdout, "  \"start_evt\": \"%v\",\n", start_evt);
     151           4 :   fformat (stdout, "  \"start_evt_missing\": \"%s\",\n",
     152             :            start_evt_missing ? "True" : "False");
     153           4 :   fformat (stdout, "  \"end_evt\": \"%v\",\n", end_evt);
     154           4 :   fformat (stdout, "  \"end_evt_missing\": \"%s\",\n",
     155             :            end_evt_missing ? "True" : "False");
     156           4 :   fformat (stdout, "  \"rx_data\": %lld,\n", em->stats.rx_total);
     157           4 :   fformat (stdout, "  \"tx_data\": %lld,\n", em->stats.tx_total);
     158           4 :   fformat (stdout, "  \"rx_bits_per_second\": %.1f,\n",
     159           4 :            em->stats.rx_total * 8 / deltat);
     160           4 :   fformat (stdout, "  \"tx_bits_per_second\": %.1f,\n",
     161           4 :            em->stats.tx_total * 8 / deltat);
     162           4 :   fformat (stdout, "  \"closing\": {\n");
     163           4 :   fformat (stdout, "    \"reset\": { \"q\": %d, \"s\": %d },\n",
     164             :            em->stats.reset_count.q, em->stats.reset_count.s);
     165           4 :   fformat (stdout, "    \"recv evt\": { \"q\": %d, \"s\": %d },\n",
     166             :            em->stats.close_count.q, em->stats.close_count.s);
     167           4 :   fformat (stdout, "    \"send evt\": { \"q\": %d, \"s\": %d },\n",
     168             :            em->stats.active_count.q, em->stats.active_count.s);
     169           4 :   fformat (stdout, "    \"clean\": { \"q\": %d, \"s\": %d },\n",
     170             :            em->stats.clean_count.q, em->stats.clean_count.s);
     171           4 :   fformat (stdout, "    \"accepted\": { \"q\": %d, \"s\": %d },\n",
     172             :            em->stats.accepted_count.q, em->stats.accepted_count.s);
     173           4 :   fformat (stdout, "    \"connected\": { \"q\": %d, \"s\": %d }\n",
     174             :            em->stats.connected_count.q, em->stats.connected_count.s);
     175           4 :   fformat (stdout, "  },\n");
     176           4 :   fformat (stdout, "  \"results\": {\n");
     177           4 :   fformat (stdout, "    \"has_failed\": \"%d\",\n", em->has_failed);
     178           4 :   fformat (stdout, "    \"fail_descr\": \"%v\"\n", em->fail_descr);
     179           4 :   fformat (stdout, "  }\n");
     180           4 :   fformat (stdout, "}\n");
     181           4 :   fflush (stdout);
     182           4 :   vec_free (start_evt);
     183           4 :   vec_free (end_evt);
     184           4 : }
     185             : 
     186             : static void
     187           0 : print_global_stats (echo_main_t * em)
     188             : {
     189           0 :   u8 *start_evt =
     190           0 :     format (0, "%U", echo_format_timing_event, em->timing.start_event);
     191           0 :   u8 *end_evt =
     192           0 :     format (0, "%U", echo_format_timing_event, em->timing.end_event);
     193           0 :   u8 start_evt_missing = !(em->timing.events_sent & em->timing.start_event);
     194           0 :   u8 end_evt_missing = (em->rx_results_diff || em->tx_results_diff) ? 0 :
     195           0 :     !(em->timing.events_sent & em->timing.end_event);
     196           0 :   f64 deltat = start_evt_missing || end_evt_missing ? 0 :
     197           0 :     em->timing.end_time - em->timing.start_time;
     198             : 
     199           0 :   if (start_evt_missing)
     200           0 :     ECHO_FAIL (ECHO_FAIL_MISSING_START_EVENT,
     201             :                "Expected event %v to happen, but it did not!", start_evt);
     202             : 
     203           0 :   if (end_evt_missing)
     204           0 :     ECHO_FAIL (ECHO_FAIL_MISSING_END_EVENT,
     205             :                "Expected event %v to happen, but it did not!", end_evt);
     206             : 
     207           0 :   fformat (stdout, "Timing %v:%v\n", start_evt, end_evt);
     208           0 :   if (start_evt_missing)
     209           0 :     fformat (stdout, "Missing Start Timing Event (%v)!\n", start_evt);
     210           0 :   if (end_evt_missing)
     211           0 :     fformat (stdout, "Missing End Timing Event (%v)!\n", end_evt);
     212           0 :   fformat (stdout, "-------- TX --------\n");
     213           0 :   fformat (stdout, "%lld bytes (%lld mbytes, %lld gbytes) in %.6f seconds\n",
     214           0 :            em->stats.tx_total, em->stats.tx_total / (1ULL << 20),
     215           0 :            em->stats.tx_total / (1ULL << 30), deltat);
     216           0 :   if (deltat)
     217           0 :     fformat (stdout, "%.4f Gbit/second\n",
     218           0 :              (em->stats.tx_total * 8.0) / deltat / 1e9);
     219           0 :   fformat (stdout, "-------- RX --------\n");
     220           0 :   fformat (stdout, "%lld bytes (%lld mbytes, %lld gbytes) in %.6f seconds\n",
     221           0 :            em->stats.rx_total, em->stats.rx_total / (1ULL << 20),
     222           0 :            em->stats.rx_total / (1ULL << 30), deltat);
     223           0 :   if (deltat)
     224           0 :     fformat (stdout, "%.4f Gbit/second\n",
     225           0 :              (em->stats.rx_total * 8.0) / deltat / 1e9);
     226           0 :   fformat (stdout, "--------------------\n");
     227           0 :   fformat (stdout, "Received close on %d streams (and %d Quic conn)\n",
     228             :            em->stats.close_count.s, em->stats.close_count.q);
     229           0 :   fformat (stdout, "Received reset on %d streams (and %d Quic conn)\n",
     230             :            em->stats.reset_count.s, em->stats.reset_count.q);
     231           0 :   fformat (stdout, "Sent close on     %d streams (and %d Quic conn)\n",
     232             :            em->stats.active_count.s, em->stats.active_count.q);
     233           0 :   fformat (stdout, "Discarded         %d streams (and %d Quic conn)\n",
     234             :            em->stats.clean_count.s, em->stats.clean_count.q);
     235           0 :   fformat (stdout, "--------------------\n");
     236           0 :   fformat (stdout, "Got accept on     %d streams (and %d Quic conn)\n",
     237             :            em->stats.accepted_count.s, em->stats.accepted_count.q);
     238           0 :   fformat (stdout, "Got connected on  %d streams (and %d Quic conn)\n",
     239             :            em->stats.connected_count.s, em->stats.connected_count.q);
     240           0 :   if (em->has_failed)
     241           0 :     fformat (stdout, "\nFailure Return Status: %d\n%v", em->has_failed,
     242             :              em->fail_descr);
     243           0 :   vec_free (start_evt);
     244           0 :   vec_free (end_evt);
     245           0 : }
     246             : 
     247             : void
     248           4 : echo_update_count_on_session_close (echo_main_t * em, echo_session_t * s)
     249             : {
     250             : 
     251           4 :   ECHO_LOG (2, "[%lu/%lu] -> %U -> [%lu/%lu]",
     252             :             s->bytes_received, s->bytes_received + s->bytes_to_receive,
     253             :             echo_format_session, s, s->bytes_sent,
     254             :             s->bytes_sent + s->bytes_to_send);
     255             : 
     256           4 :   if (PREDICT_FALSE
     257             :       ((em->stats.rx_total == em->stats.rx_expected)
     258             :        && (em->stats.tx_total == em->stats.tx_expected)))
     259           4 :     echo_notify_event (em, ECHO_EVT_LAST_BYTE);
     260           4 : }
     261             : 
     262             : static void
     263          10 : echo_session_detach_fifos (echo_session_t *s)
     264             : {
     265          10 :   echo_main_t *em = &echo_main;
     266             :   fifo_segment_t *fs;
     267             : 
     268          10 :   if (!s->rx_fifo)
     269           2 :     return;
     270             : 
     271           8 :   clib_spinlock_lock (&em->segment_handles_lock);
     272             : 
     273           8 :   fs = fifo_segment_get_segment_if_valid (&em->segment_main,
     274           8 :                                           s->rx_fifo->segment_index);
     275             : 
     276           8 :   if (!fs)
     277           0 :     goto done;
     278             : 
     279           8 :   fifo_segment_free_client_fifo (fs, s->rx_fifo);
     280           8 :   fifo_segment_free_client_fifo (fs, s->tx_fifo);
     281             : 
     282           8 : done:
     283           8 :   clib_spinlock_unlock (&em->segment_handles_lock);
     284             : }
     285             : 
     286             : static void
     287           4 : echo_free_sessions (echo_main_t * em)
     288             : {
     289             :   /* Free marked sessions */
     290             :   echo_session_t *s;
     291           4 :   u32 *session_indexes = 0, *session_index;
     292             : 
     293             :   /* *INDENT-OFF* */
     294          16 :   pool_foreach (s, em->sessions)
     295             :    {
     296          12 :     if (s->session_state == ECHO_SESSION_STATE_CLOSED)
     297          10 :       vec_add1 (session_indexes, s->session_index);
     298             :    }
     299             :   /* *INDENT-ON* */
     300          14 :   vec_foreach (session_index, session_indexes)
     301             :   {
     302             :     /* Free session */
     303          10 :     s = pool_elt_at_index (em->sessions, *session_index);
     304          10 :     echo_session_detach_fifos (s);
     305          10 :     echo_session_handle_add_del (em, s->vpp_session_handle,
     306             :                                  SESSION_INVALID_INDEX);
     307          10 :     clib_memset (s, 0xfe, sizeof (*s));
     308          10 :     pool_put (em->sessions, s);
     309             :   }
     310           4 : }
     311             : 
     312             : static void
     313        2976 : test_recv_bytes (echo_main_t * em, echo_session_t * s, u8 * rx_buf,
     314             :                  u32 n_read)
     315             : {
     316             :   u32 i;
     317             :   u8 expected;
     318    10619800 :   for (i = 0; i < n_read; i++)
     319             :     {
     320    10616800 :       expected = (s->bytes_received + i) & 0xff;
     321    10616800 :       if (rx_buf[i] == expected || em->max_test_msg > 0)
     322    10616800 :         continue;
     323           0 :       ECHO_LOG (1, "Session 0x%lx byte %lld was 0x%x expected 0x%x",
     324             :                 s->vpp_session_handle, s->bytes_received + i, rx_buf[i],
     325             :                 expected);
     326           0 :       em->max_test_msg--;
     327           0 :       if (em->max_test_msg == 0)
     328           0 :         ECHO_LOG (1, "Too many errors, hiding next ones");
     329           0 :       if (em->test_return_packets == RETURN_PACKETS_ASSERT)
     330           0 :         ECHO_FAIL (ECHO_FAIL_TEST_BYTES_ERR, "test-bytes errored");
     331             :     }
     332        2976 : }
     333             : 
     334             : static int
     335     7294670 : recv_data_chunk (echo_main_t * em, echo_session_t * s, u8 * rx_buf)
     336             : {
     337             :   int n_read;
     338     7294670 :   n_read = app_recv ((app_session_t *) s, rx_buf, vec_len (rx_buf));
     339     7294670 :   if (n_read <= 0)
     340     7291700 :     return 0;
     341        2976 :   if (svm_fifo_needs_deq_ntf (s->rx_fifo, n_read))
     342        1714 :     echo_session_dequeue_notify (s);
     343             : 
     344        2976 :   if (em->test_return_packets)
     345        2976 :     test_recv_bytes (em, s, rx_buf, n_read);
     346             : 
     347        2976 :   s->bytes_received += n_read;
     348        2976 :   s->bytes_to_receive -= n_read;
     349        2976 :   clib_atomic_fetch_add (&em->stats.rx_total, n_read);
     350        2976 :   return n_read;
     351             : }
     352             : 
     353             : static int
     354     2873560 : send_data_chunk (echo_session_t * s, u8 * tx_buf, int offset, int len)
     355             : {
     356             :   int n_sent;
     357     2873560 :   int bytes_this_chunk = clib_min (s->bytes_to_send, len - offset);
     358     2873560 :   echo_main_t *em = &echo_main;
     359             : 
     360     2873560 :   if (!bytes_this_chunk)
     361           0 :     return 0;
     362     2873560 :   n_sent = app_send ((app_session_t *) s, tx_buf + offset,
     363             :                      bytes_this_chunk, SVM_Q_WAIT);
     364     2873560 :   if (n_sent < 0)
     365     2872940 :     return 0;
     366         620 :   s->bytes_to_send -= n_sent;
     367         620 :   s->bytes_sent += n_sent;
     368         620 :   clib_atomic_fetch_add (&em->stats.tx_total, n_sent);
     369         620 :   return n_sent;
     370             : }
     371             : 
     372             : static int
     373       32842 : mirror_data_chunk (echo_main_t * em, echo_session_t * s, u8 * tx_buf, u64 len)
     374             : {
     375       32842 :   u64 n_sent = 0;
     376       32860 :   while (n_sent < len && !em->time_to_stop)
     377          18 :     n_sent += send_data_chunk (s, tx_buf, n_sent, len);
     378       32842 :   return n_sent;
     379             : }
     380             : 
     381             : static inline void
     382     8123000 : echo_check_closed_listener (echo_main_t * em, echo_session_t * s)
     383             : {
     384             :   echo_session_t *ls;
     385             :   /* if parent has died, terminate gracefully */
     386     8123000 :   if (s->listener_index == SESSION_INVALID_INDEX)
     387             :     {
     388           0 :       ECHO_LOG (3, "%U: listener_index == SESSION_INVALID_INDEX",
     389             :                 echo_format_session, s);
     390           0 :       return;
     391             :     }
     392     8123000 :   ls = pool_elt_at_index (em->sessions, s->listener_index);
     393     8123000 :   if (ls->session_state < ECHO_SESSION_STATE_CLOSING)
     394             :     {
     395     8123000 :       ECHO_LOG (3, "%U: ls->session_state (%d) < "
     396             :                 "ECHO_SESSION_STATE_CLOSING (%d)",
     397             :                 echo_format_session, ls, ls->session_state,
     398             :                 ECHO_SESSION_STATE_CLOSING);
     399     8123000 :       return;
     400             :     }
     401             : 
     402           2 :   ECHO_LOG (3, "%U died, close child %U", echo_format_session, ls,
     403             :             echo_format_session, s);
     404           2 :   echo_update_count_on_session_close (em, s);
     405           2 :   em->proto_cb_vft->cleanup_cb (s, 1 /* parent_died */ );
     406             : }
     407             : 
     408             : /*
     409             :  * Rx/Tx polling thread per connection
     410             :  */
     411             : static void
     412     7294670 : echo_handle_data (echo_main_t * em, echo_session_t * s, u8 * rx_buf)
     413             : {
     414     7294670 :   int n_read, n_sent = 0;
     415             : 
     416     7294670 :   n_read = recv_data_chunk (em, s, rx_buf);
     417     7294670 :   if ((em->data_source == ECHO_TEST_DATA_SOURCE) && s->bytes_to_send)
     418     2873540 :     n_sent = send_data_chunk (s, em->connect_test_data,
     419     2873540 :                               s->bytes_sent % em->tx_buf_size,
     420     2873540 :                               em->tx_buf_size);
     421     4421130 :   else if (em->data_source == ECHO_RX_DATA_SOURCE)
     422       32842 :     n_sent = mirror_data_chunk (em, s, rx_buf, n_read);
     423     7294670 :   if (!s->bytes_to_send && !s->bytes_to_receive)
     424             :     {
     425             :       /* Session is done, need to close */
     426           4 :       if (s->session_state == ECHO_SESSION_STATE_AWAIT_DATA)
     427           0 :         s->session_state = ECHO_SESSION_STATE_CLOSING;
     428             :       else
     429             :         {
     430           4 :           s->session_state = ECHO_SESSION_STATE_AWAIT_CLOSING;
     431           4 :           if (em->send_stream_disconnects == ECHO_CLOSE_F_ACTIVE)
     432             :             {
     433           2 :               echo_send_rpc (em, echo_send_disconnect_session,
     434           2 :                              (echo_rpc_args_t *) & s->vpp_session_handle);
     435           2 :               clib_atomic_fetch_add (&em->stats.active_count.s, 1);
     436             :             }
     437           2 :           else if (em->send_stream_disconnects == ECHO_CLOSE_F_NONE)
     438             :             {
     439           0 :               s->session_state = ECHO_SESSION_STATE_CLOSING;
     440           0 :               clib_atomic_fetch_add (&em->stats.clean_count.s, 1);
     441             :             }
     442             :         }
     443           4 :       ECHO_LOG (3, "%U: %U", echo_format_session, s,
     444             :                 echo_format_session_state, s->session_state);
     445           4 :       return;
     446             :     }
     447             : 
     448             :   /* Check for idle clients */
     449     7294670 :   if (em->log_lvl > 1)
     450             :     {
     451           0 :       if (n_sent || n_read)
     452           0 :         s->idle_cycles = 0;
     453           0 :       else if (s->idle_cycles++ == LOG_EVERY_N_IDLE_CYCLES)
     454             :         {
     455           0 :           s->idle_cycles = 0;
     456           0 :           ECHO_LOG (2, "Idle client TX:%dB RX:%dB", s->bytes_to_send,
     457             :                     s->bytes_to_receive);
     458           0 :           ECHO_LOG (2, "Idle FIFOs TX:%dB RX:%dB",
     459             :                     svm_fifo_max_dequeue (s->tx_fifo),
     460             :                     svm_fifo_max_dequeue (s->rx_fifo));
     461           0 :           ECHO_LOG (2, "Session 0x%lx state %U", s->vpp_session_handle,
     462             :                     echo_format_session_state, s->session_state);
     463             :         }
     464             :     }
     465             : }
     466             : 
     467             : static void *
     468           4 : echo_data_thread_fn (void *arg)
     469             : {
     470           4 :   clib_mem_set_thread_index (); /* First thing to do in client thread */
     471           4 :   echo_main_t *em = &echo_main;
     472           4 :   u32 N = em->n_clients;
     473           4 :   u32 n = (N + em->n_rx_threads - 1) / em->n_rx_threads;
     474           4 :   u32 idx = (u64) arg;
     475           4 :   if (n * idx >= N)
     476             :     {
     477           0 :       ECHO_LOG (2, "Thread %u exiting, no sessions to care for", idx);
     478           0 :       pthread_exit (0);
     479             :     }
     480           4 :   u32 thread_n_sessions = clib_min (n, N - n * idx);
     481             : 
     482           4 :   u32 i = 0;
     483           4 :   u32 n_closed_sessions = 0;
     484             :   u32 session_index;
     485           4 :   u8 *rx_buf = 0;
     486             :   echo_session_t *s;
     487           4 :   vec_validate (rx_buf, em->rx_buf_size);
     488             : 
     489   217242000 :   for (i = 0; !em->time_to_stop; i = (i + 1) % thread_n_sessions)
     490             :     {
     491   217242000 :       n_closed_sessions = i == 0 ? 0 : n_closed_sessions;
     492   217242000 :       session_index = em->data_thread_args[n * idx + i];
     493   217242000 :       if (session_index == SESSION_INVALID_INDEX)
     494   209119000 :         continue;
     495     8123000 :       s = pool_elt_at_index (em->sessions, session_index);
     496     8123000 :       switch (s->session_state)
     497             :         {
     498     7294670 :         case ECHO_SESSION_STATE_READY:
     499             :         case ECHO_SESSION_STATE_AWAIT_DATA:
     500     7294670 :           echo_handle_data (em, s, rx_buf);
     501     7294670 :           echo_check_closed_listener (em, s);
     502     7294670 :           break;
     503      828326 :         case ECHO_SESSION_STATE_AWAIT_CLOSING:
     504      828326 :           ECHO_LOG (3, "%U: %U", echo_format_session, s,
     505             :                     echo_format_session_state, s->session_state);
     506      828326 :           echo_check_closed_listener (em, s);
     507      828326 :           break;
     508           2 :         case ECHO_SESSION_STATE_CLOSING:
     509           2 :           ECHO_LOG (3, "%U: %U", echo_format_session, s,
     510             :                     echo_format_session_state, s->session_state);
     511           2 :           echo_update_count_on_session_close (em, s);
     512           2 :           em->proto_cb_vft->cleanup_cb (s, 0 /* parent_died */ );
     513           2 :           break;
     514           4 :         case ECHO_SESSION_STATE_CLOSED:
     515           4 :           ECHO_LOG (3, "%U: %U", echo_format_session, s,
     516             :                     echo_format_session_state, s->session_state);
     517           4 :           n_closed_sessions++;
     518           4 :           break;
     519             :         }
     520     8123000 :       if (n_closed_sessions == thread_n_sessions)
     521           4 :         break;
     522             :     }
     523           4 :   ECHO_LOG (2, "Mission accomplished!");
     524           4 :   pthread_exit (0);
     525             : }
     526             : 
     527             : static void
     528           2 : session_unlisten_handler (session_unlisten_reply_msg_t * mp)
     529             : {
     530             :   echo_session_t *ls;
     531           2 :   echo_main_t *em = &echo_main;
     532             : 
     533           2 :   ls = echo_get_session_from_handle (em, mp->handle);
     534           2 :   if (!ls)
     535           0 :     return;
     536           2 :   em->proto_cb_vft->cleanup_cb (ls, 0 /* parent_died */ );
     537           2 :   ls->session_state = ECHO_SESSION_STATE_CLOSED;
     538           2 :   if (--em->listen_session_cnt == 0)
     539           2 :     em->state = STATE_DISCONNECTED;
     540             : }
     541             : 
     542             : static void
     543           2 : session_bound_handler (session_bound_msg_t * mp)
     544             : {
     545           2 :   echo_main_t *em = &echo_main;
     546             :   echo_session_t *listen_session;
     547           2 :   if (mp->retval)
     548             :     {
     549           0 :       ECHO_FAIL (ECHO_FAIL_BIND, "bind failed: %U", format_api_error,
     550             :                  clib_net_to_host_u32 (mp->retval));
     551           0 :       return;
     552             :     }
     553           2 :   ECHO_LOG (1, "listening on %U:%u", format_ip46_address, mp->lcl_ip,
     554             :             mp->lcl_is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
     555             :             clib_net_to_host_u16 (mp->lcl_port));
     556             : 
     557             :   /* Allocate local session and set it up */
     558           2 :   listen_session = echo_session_new (em);
     559           2 :   listen_session->session_type = ECHO_SESSION_TYPE_LISTEN;
     560           2 :   listen_session->vpp_session_handle = mp->handle;
     561           2 :   echo_session_handle_add_del (em, mp->handle, listen_session->session_index);
     562           2 :   vec_add1 (em->listen_session_indexes, listen_session->session_index);
     563           2 :   if (++em->listen_session_cnt == em->n_uris)
     564           2 :     em->state = STATE_LISTEN;
     565           2 :   if (em->proto_cb_vft->bound_uri_cb)
     566           0 :     em->proto_cb_vft->bound_uri_cb (mp, listen_session);
     567             : }
     568             : 
     569             : static void
     570           4 : session_accepted_handler (session_accepted_msg_t * mp)
     571             : {
     572           4 :   app_session_evt_t _app_evt, *app_evt = &_app_evt;
     573             :   session_accepted_reply_msg_t *rmp;
     574           4 :   echo_main_t *em = &echo_main;
     575             :   echo_session_t *session, *ls;
     576             : 
     577           4 :   if (!(ls = echo_get_session_from_handle (em, mp->listener_handle)))
     578             :     {
     579           0 :       ECHO_FAIL (ECHO_FAIL_SESSION_ACCEPTED_BAD_LISTENER,
     580             :                  "Unknown listener handle 0x%lx", mp->listener_handle);
     581           0 :       return;
     582             :     }
     583             : 
     584             :   /* Allocate local session and set it up */
     585           4 :   session = echo_session_new (em);
     586             : 
     587           4 :   if (echo_attach_session (mp->segment_handle, mp->server_rx_fifo,
     588             :                            mp->server_tx_fifo, mp->vpp_event_queue_address,
     589             :                            session))
     590             :     {
     591           0 :       ECHO_FAIL (ECHO_FAIL_ACCEPTED_WAIT_FOR_SEG_ALLOC,
     592             :                  "accepted wait_for_segment_allocation errored");
     593           0 :       return;
     594             :     }
     595             : 
     596           4 :   session->vpp_session_handle = mp->handle;
     597             : 
     598             :   /* session->transport needed by app_send_dgram */
     599           4 :   clib_memcpy_fast (&session->transport.rmt_ip, &mp->rmt.ip,
     600             :                     sizeof (ip46_address_t));
     601           4 :   session->transport.is_ip4 = mp->rmt.is_ip4;
     602           4 :   session->transport.rmt_port = mp->rmt.port;
     603           4 :   clib_memcpy_fast (&session->transport.lcl_ip, &em->uri_elts.ip,
     604             :                     sizeof (ip46_address_t));
     605           4 :   session->transport.lcl_port = em->uri_elts.port;
     606             : 
     607           4 :   session->vpp_session_handle = mp->handle;
     608           4 :   session->listener_index = ls->session_index;
     609           4 :   session->start = clib_time_now (&em->clib_time);
     610             : 
     611             :   /* Add it to lookup table */
     612           4 :   ECHO_LOG (2, "Accepted session 0x%lx S[%u] -> 0x%lx S[%u]",
     613             :             mp->handle, session->session_index,
     614             :             mp->listener_handle, session->listener_index);
     615           4 :   echo_session_handle_add_del (em, mp->handle, session->session_index);
     616             : 
     617           4 :   app_alloc_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt,
     618             :                              SESSION_CTRL_EVT_ACCEPTED_REPLY);
     619           4 :   rmp = (session_accepted_reply_msg_t *) app_evt->evt->data;
     620           4 :   rmp->handle = mp->handle;
     621           4 :   rmp->context = mp->context;
     622           4 :   app_send_ctrl_evt_to_vpp (session->vpp_evt_q, app_evt);
     623           4 :   em->proto_cb_vft->accepted_cb (mp, session);
     624             : }
     625             : 
     626             : static void
     627           4 : session_connected_handler (session_connected_msg_t * mp)
     628             : {
     629           4 :   echo_main_t *em = &echo_main;
     630             :   echo_session_t *session;
     631           4 :   u32 listener_index = htonl (mp->context);
     632             : 
     633           4 :   clib_atomic_add_fetch (&em->max_sim_connects, 1);
     634             : 
     635           4 :   if (mp->retval)
     636             :     {
     637           0 :       if (em->proto_cb_vft->connected_cb)
     638           0 :         em->
     639           0 :           proto_cb_vft->connected_cb ((session_connected_bundled_msg_t *) mp,
     640             :                                       listener_index, 1 /* is_failed */ );
     641           0 :       return;
     642             :     }
     643             : 
     644           4 :   session = echo_session_new (em);
     645             : 
     646           4 :   if (echo_attach_session (mp->segment_handle, mp->server_rx_fifo,
     647             :                            mp->server_tx_fifo, mp->vpp_event_queue_address,
     648             :                            session))
     649             :     {
     650           0 :       ECHO_FAIL (ECHO_FAIL_CONNECTED_WAIT_FOR_SEG_ALLOC,
     651             :                  "connected wait_for_segment_allocation errored");
     652           0 :       return;
     653             :     }
     654             : 
     655           4 :   session->vpp_session_handle = mp->handle;
     656           4 :   session->start = clib_time_now (&em->clib_time);
     657           4 :   session->listener_index = listener_index;
     658             :   /* session->transport needed by app_send_dgram */
     659           4 :   clib_memcpy_fast (&session->transport.lcl_ip, &mp->lcl.ip,
     660             :                     sizeof (ip46_address_t));
     661           4 :   session->transport.is_ip4 = mp->lcl.is_ip4;
     662           4 :   session->transport.lcl_port = mp->lcl.port;
     663           4 :   clib_memcpy_fast (&session->transport.rmt_ip, &em->uri_elts.ip,
     664             :                     sizeof (ip46_address_t));
     665           4 :   session->transport.rmt_port = em->uri_elts.port;
     666             : 
     667           4 :   echo_session_handle_add_del (em, mp->handle, session->session_index);
     668           4 :   em->proto_cb_vft->connected_cb ((session_connected_bundled_msg_t *) mp,
     669             :                                   session->session_index, 0 /* is_failed */ );
     670             : }
     671             : 
     672             : /*
     673             :  *
     674             :  *  End of ECHO callback definitions
     675             :  *
     676             :  */
     677             : 
     678             : static void
     679           2 : session_disconnected_handler (session_disconnected_msg_t * mp)
     680             : {
     681           2 :   app_session_evt_t _app_evt, *app_evt = &_app_evt;
     682             :   session_disconnected_reply_msg_t *rmp;
     683           2 :   echo_main_t *em = &echo_main;
     684             :   echo_session_t *s;
     685           2 :   if (!(s = echo_get_session_from_handle (em, mp->handle)))
     686             :     {
     687           0 :       ECHO_LOG (1, "Invalid vpp_session_handle: 0x%lx", mp->handle);
     688           0 :       return;
     689             :     }
     690           2 :   if (s->session_state == ECHO_SESSION_STATE_CLOSED)
     691             :     {
     692           0 :       ECHO_LOG (2, "%U: already in ECHO_SESSION_STATE_CLOSED",
     693             :                 echo_format_session, s);
     694             :     }
     695             :   else
     696             :     {
     697           2 :       ECHO_LOG (2, "%U: passive close", echo_format_session, s);
     698           2 :       em->proto_cb_vft->disconnected_cb (mp, s);
     699             :     }
     700           2 :   app_alloc_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt,
     701             :                              SESSION_CTRL_EVT_DISCONNECTED_REPLY);
     702           2 :   rmp = (session_disconnected_reply_msg_t *) app_evt->evt->data;
     703           2 :   rmp->retval = 0;
     704           2 :   rmp->handle = mp->handle;
     705           2 :   rmp->context = mp->context;
     706           2 :   app_send_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt);
     707             : }
     708             : 
     709             : static void
     710           0 : session_reset_handler (session_reset_msg_t * mp)
     711             : {
     712           0 :   app_session_evt_t _app_evt, *app_evt = &_app_evt;
     713           0 :   echo_main_t *em = &echo_main;
     714             :   session_reset_reply_msg_t *rmp;
     715           0 :   echo_session_t *s = 0;
     716           0 :   if (!(s = echo_get_session_from_handle (em, mp->handle)))
     717             :     {
     718           0 :       ECHO_LOG (1, "Invalid vpp_session_handle: 0x%lx", mp->handle);
     719           0 :       return;
     720             :     }
     721           0 :   ECHO_LOG (2, "%U: session reset", echo_format_session, s);
     722           0 :   em->proto_cb_vft->reset_cb (mp, s);
     723             : 
     724           0 :   app_alloc_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt,
     725             :                              SESSION_CTRL_EVT_RESET_REPLY);
     726           0 :   rmp = (session_reset_reply_msg_t *) app_evt->evt->data;
     727           0 :   rmp->retval = 0;
     728           0 :   rmp->handle = mp->handle;
     729           0 :   app_send_ctrl_evt_to_vpp (s->vpp_evt_q, app_evt);
     730             : }
     731             : 
     732             : static int
     733           2 : echo_recv_fd (echo_main_t *em, int *fds, int n_fds)
     734             : {
     735           2 :   if (em->use_app_socket_api)
     736           2 :     return echo_sapi_recv_fd (em, fds, n_fds);
     737           0 :   return echo_bapi_recv_fd (em, fds, n_fds);
     738             : }
     739             : 
     740             : static void
     741           2 : add_segment_handler (session_app_add_segment_msg_t * mp)
     742             : {
     743           2 :   echo_main_t *em = &echo_main;
     744           2 :   fifo_segment_main_t *sm = &echo_main.segment_main;
     745           2 :   fifo_segment_create_args_t _a, *a = &_a;
     746           2 :   int *fds = 0, i;
     747           2 :   char *seg_name = (char *) mp->segment_name;
     748           2 :   u64 segment_handle = mp->segment_handle;
     749             : 
     750           2 :   if (mp->fd_flags & SESSION_FD_F_MEMFD_SEGMENT)
     751             :     {
     752           2 :       vec_validate (fds, 1);
     753           2 :       if (echo_recv_fd (em, fds, 1))
     754             :         {
     755           0 :           ECHO_LOG (0, "echo_recv_fd failed");
     756           0 :           em->time_to_stop = 1;
     757           0 :           goto failed;
     758             :         }
     759             : 
     760           2 :       if (echo_segment_attach (segment_handle, seg_name, SSVM_SEGMENT_MEMFD,
     761             :                                fds[0]))
     762             :         {
     763           0 :           ECHO_FAIL (ECHO_FAIL_VL_API_SVM_FIFO_SEG_ATTACH,
     764             :                      "svm_fifo_segment_attach ('%s') "
     765             :                      "failed on SSVM_SEGMENT_MEMFD", seg_name);
     766           0 :           goto failed;
     767             :         }
     768           2 :       vec_free (fds);
     769             :     }
     770             :   else
     771             :     {
     772           0 :       clib_memset (a, 0, sizeof (*a));
     773           0 :       a->segment_name = seg_name;
     774           0 :       a->segment_size = mp->segment_size;
     775             :       /* Attach to the segment vpp created */
     776           0 :       if (fifo_segment_attach (sm, a))
     777             :         {
     778           0 :           ECHO_FAIL (ECHO_FAIL_VL_API_FIFO_SEG_ATTACH,
     779             :                      "fifo_segment_attach ('%s') failed", seg_name);
     780           0 :           goto failed;
     781             :         }
     782             :     }
     783           2 :   ECHO_LOG (2, "Mapped segment 0x%lx", segment_handle);
     784           2 :   return;
     785             : 
     786           0 : failed:
     787           0 :   for (i = 0; i < vec_len (fds); i++)
     788           0 :     close (fds[i]);
     789           0 :   vec_free (fds);
     790             : }
     791             : 
     792             : static void
     793           0 : del_segment_handler (session_app_del_segment_msg_t * mp)
     794             : {
     795           0 :   echo_segment_detach (mp->segment_handle);
     796           0 :   ECHO_LOG (2, "Unmaped segment 0x%lx", mp->segment_handle);
     797           0 : }
     798             : 
     799             : static void
     800           4 : cleanup_handler (session_cleanup_msg_t * mp)
     801             : {
     802           4 :   ECHO_LOG (1, "Cleanup confirmed for 0x%lx", mp->handle);
     803           4 : }
     804             : 
     805             : static void
     806        2248 : handle_mq_event (session_event_t * e)
     807             : {
     808        2248 :   switch (e->event_type)
     809             :     {
     810           2 :     case SESSION_CTRL_EVT_BOUND:
     811           2 :       return session_bound_handler ((session_bound_msg_t *) e->data);
     812           4 :     case SESSION_CTRL_EVT_ACCEPTED:
     813           4 :       return session_accepted_handler ((session_accepted_msg_t *) e->data);
     814           4 :     case SESSION_CTRL_EVT_CONNECTED:
     815           4 :       return session_connected_handler ((session_connected_msg_t *) e->data);
     816           2 :     case SESSION_CTRL_EVT_DISCONNECTED:
     817           2 :       return session_disconnected_handler ((session_disconnected_msg_t *)
     818           2 :                                            e->data);
     819           0 :     case SESSION_CTRL_EVT_RESET:
     820           0 :       return session_reset_handler ((session_reset_msg_t *) e->data);
     821           2 :     case SESSION_CTRL_EVT_UNLISTEN_REPLY:
     822           2 :       return session_unlisten_handler ((session_unlisten_reply_msg_t *)
     823           2 :                                        e->data);
     824           2 :     case SESSION_CTRL_EVT_APP_ADD_SEGMENT:
     825           2 :       add_segment_handler ((session_app_add_segment_msg_t *) e->data);
     826           2 :       break;
     827           0 :     case SESSION_CTRL_EVT_APP_DEL_SEGMENT:
     828           0 :       del_segment_handler ((session_app_del_segment_msg_t *) e->data);
     829           0 :       break;
     830           4 :     case SESSION_CTRL_EVT_CLEANUP:
     831           4 :       cleanup_handler ((session_cleanup_msg_t *) e->data);
     832           4 :       break;
     833        2228 :     case SESSION_IO_EVT_RX:
     834        2228 :       break;
     835           0 :     default:
     836           0 :       ECHO_LOG (1, "unhandled event %u", e->event_type);
     837             :     }
     838             : }
     839             : 
     840             : static void
     841           4 : echo_process_rpcs (echo_main_t * em)
     842             : {
     843             :   echo_rpc_msg_t *rpc;
     844             :   svm_msg_q_msg_t msg;
     845           4 :   svm_msg_q_t *mq = &em->rpc_msq_queue;
     846             : 
     847          12 :   while (em->state < STATE_DATA_DONE && !em->time_to_stop)
     848             :     {
     849           8 :       if (svm_msg_q_is_empty (mq) && svm_msg_q_timedwait (mq, 1))
     850             :         {
     851           2 :           continue;
     852             :         }
     853           6 :       svm_msg_q_sub_raw (mq, &msg);
     854           6 :       rpc = svm_msg_q_msg_data (mq, &msg);
     855           6 :       ((echo_rpc_t) rpc->fp) (em, &rpc->args);
     856           6 :       svm_msg_q_free_msg (mq, &msg);
     857             :     }
     858           4 : }
     859             : 
     860             : static inline void
     861           0 : echo_print_periodic_stats (echo_main_t * em)
     862             : {
     863           0 :   f64 delta, now = clib_time_now (&em->clib_time);
     864           0 :   echo_stats_t _st, *st = &_st;
     865           0 :   echo_stats_t *lst = &em->last_stat_sampling;
     866           0 :   delta = now - em->last_stat_sampling_ts;
     867           0 :   if (delta < em->periodic_stats_delta)
     868           0 :     return;
     869             : 
     870           0 :   clib_memcpy_fast (st, &em->stats, sizeof (*st));
     871           0 :   if (st->rx_total - lst->rx_total)
     872           0 :     clib_warning ("RX: %U", echo_format_bytes_per_sec,
     873             :                   (st->rx_total - lst->rx_total) / delta);
     874           0 :   if (st->tx_total - lst->tx_total)
     875           0 :     clib_warning ("TX: %U", echo_format_bytes_per_sec,
     876             :                   (st->tx_total - lst->tx_total) / delta);
     877           0 :   if (st->connected_count.q - lst->connected_count.q)
     878           0 :     clib_warning ("conn: %d/s",
     879             :                   st->connected_count.q - lst->connected_count.q);
     880           0 :   if (st->accepted_count.q - lst->accepted_count.q)
     881           0 :     clib_warning ("accept: %d/s",
     882             :                   st->accepted_count.q - lst->accepted_count.q);
     883             : 
     884           0 :   clib_memcpy_fast (lst, st, sizeof (*st));
     885           0 :   em->last_stat_sampling_ts = now;
     886             : }
     887             : 
     888             : static void *
     889           4 : echo_mq_thread_fn (void *arg)
     890             : {
     891           4 :   clib_mem_set_thread_index (); /* First thing to do in client thread */
     892           4 :   svm_msg_q_msg_t *msg_vec = 0;
     893           4 :   echo_main_t *em = &echo_main;
     894             :   session_event_t *e;
     895             :   svm_msg_q_msg_t *msg;
     896             :   svm_msg_q_t *mq;
     897             :   int i;
     898             : 
     899           4 :   vec_validate (msg_vec, em->evt_q_size);
     900           4 :   vec_reset_length (msg_vec);
     901           4 :   wait_for_state_change (em, STATE_ATTACHED, 0);
     902           4 :   mq = em->app_mq;
     903           4 :   if (em->state < STATE_ATTACHED || !mq)
     904             :     {
     905           0 :       ECHO_FAIL (ECHO_FAIL_APP_ATTACH, "Application failed to attach");
     906           0 :       pthread_exit (0);
     907             :     }
     908             : 
     909        1825 :   while (em->state < STATE_DETACHED && !em->time_to_stop)
     910             :     {
     911        1821 :       if (em->periodic_stats_delta)
     912           0 :         echo_print_periodic_stats (em);
     913             : 
     914        1821 :       if (svm_msg_q_is_empty (mq) && svm_msg_q_timedwait (mq, 1))
     915             :         {
     916           8 :           continue;
     917             :         }
     918        4061 :       for (i = 0; i < svm_msg_q_size (mq); i++)
     919             :         {
     920        2248 :           vec_add2 (msg_vec, msg, 1);
     921        2248 :           svm_msg_q_sub_raw (mq, msg);
     922             :         }
     923             : 
     924        4061 :       for (i = 0; i < vec_len (msg_vec); i++)
     925             :         {
     926        2248 :           msg = vec_elt_at_index (msg_vec, i);
     927        2248 :           e = svm_msg_q_msg_data (mq, msg);
     928        2248 :           handle_mq_event (e);
     929        2248 :           svm_msg_q_free_msg (mq, msg); /* No lock, single thread dequeuing */
     930             :         }
     931        1813 :       vec_reset_length (msg_vec);
     932             :     }
     933           4 :   vec_free (msg_vec);
     934           4 :   pthread_exit (0);
     935             : }
     936             : 
     937             : static inline void
     938           4 : echo_cycle_ip (echo_main_t * em, ip46_address_t * ip, ip46_address_t * src_ip,
     939             :                u32 i)
     940             : {
     941             :   u8 *ipu8;
     942             :   u8 l;
     943           4 :   if (i % em->n_uris == 0)
     944             :     {
     945           4 :       clib_memcpy_fast (ip, src_ip, sizeof (*ip));
     946           4 :       return;
     947             :     }
     948           0 :   l = em->uri_elts.is_ip4 ? 3 : 15;
     949           0 :   ipu8 = em->uri_elts.is_ip4 ? ip->ip4.as_u8 : ip->ip6.as_u8;
     950           0 :   while (ipu8[l] == 0xf)
     951           0 :     ipu8[l--] = 0;
     952           0 :   if (l)
     953           0 :     ipu8[l]++;
     954             : }
     955             : 
     956             : static void
     957           2 : clients_run (echo_main_t * em)
     958             : {
     959           2 :   echo_connect_args_t _a, *a = &_a;
     960             :   u64 i;
     961             : 
     962           2 :   a->context = SESSION_INVALID_INDEX;
     963           2 :   a->parent_session_handle = SESSION_INVALID_HANDLE;
     964           2 :   clib_memset (&a->lcl_ip, 0, sizeof (a->lcl_ip));
     965             : 
     966           2 :   echo_notify_event (em, ECHO_EVT_FIRST_QCONNECT);
     967           4 :   for (i = 0; i < em->n_connects; i++)
     968             :     {
     969           2 :       echo_cycle_ip (em, &a->ip, &em->uri_elts.ip, i);
     970           2 :       if (em->lcl_ip_set)
     971           0 :         echo_cycle_ip (em, &a->lcl_ip, &em->lcl_ip, i);
     972           2 :       echo_send_connect (em, a);
     973             :     }
     974           2 :   wait_for_state_change (em, STATE_READY, 0);
     975           2 :   ECHO_LOG (2, "App is ready");
     976           2 :   echo_process_rpcs (em);
     977           2 : }
     978             : 
     979             : static void
     980           2 : server_run (echo_main_t * em)
     981             : {
     982             :   echo_session_t *ls;
     983           2 :   ip46_address_t _ip, *ip = &_ip;
     984             :   u32 *listen_session_index;
     985             :   u32 i;
     986             : 
     987           4 :   for (i = 0; i < em->n_uris; i++)
     988             :     {
     989           2 :       echo_cycle_ip (em, ip, &em->uri_elts.ip, i);
     990           2 :       echo_send_listen (em, ip);
     991             :     }
     992           2 :   wait_for_state_change (em, STATE_READY, 0);
     993           2 :   ECHO_LOG (2, "App is ready");
     994           2 :   echo_process_rpcs (em);
     995             :   /* Cleanup */
     996           4 :   vec_foreach (listen_session_index, em->listen_session_indexes)
     997             :   {
     998           2 :     ECHO_LOG (2, "Unbind listen port %d", em->listen_session_cnt);
     999           2 :     ls = pool_elt_at_index (em->sessions, *listen_session_index);
    1000           2 :     echo_send_unbind (em, ls);
    1001             :   }
    1002           2 :   if (wait_for_state_change (em, STATE_DISCONNECTED, TIMEOUT))
    1003             :     {
    1004           0 :       ECHO_FAIL (ECHO_FAIL_SERVER_DISCONNECT_TIMEOUT,
    1005             :                  "Timeout waiting for state disconnected");
    1006           0 :       return;
    1007             :     }
    1008             : }
    1009             : 
    1010             : static void
    1011           0 : print_usage_and_exit (void)
    1012             : {
    1013           0 :   echo_main_t *em = &echo_main;
    1014             :   int i;
    1015           0 :   fprintf (stderr,
    1016             :            "Usage: vpp_echo [socket-name SOCKET] [client|server] [uri URI] [OPTIONS]\n"
    1017             :            "Generates traffic and assert correct teardown of the hoststack\n"
    1018             :            "\n"
    1019             :            "  socket-name PATH    Specify the binary socket path to connect to VPP\n"
    1020             :            "  use-svm-api         Use SVM API to connect to VPP\n"
    1021             :            "  test-bytes[:assert] Check data correctness when receiving (assert fails on first error)\n"
    1022             :            "  fifo-size N[K|M|G]  Use N[K|M|G] fifos\n"
    1023             :            "  mq-size N           Use mq with N slots for [vpp_echo->vpp] communication\n"
    1024             :            "  max-sim-connects N  Do not allow more than N mq events inflight\n"
    1025             :            "  rx-buf N[K|M|G]     Use N[Kb|Mb|GB] RX buffer\n"
    1026             :            "  tx-buf N[K|M|G]     Use N[Kb|Mb|GB] TX test buffer\n"
    1027             :            "  appns NAMESPACE     Use the namespace NAMESPACE\n"
    1028             :            "  all-scope           all-scope option\n"
    1029             :            "  local-scope         local-scope option\n"
    1030             :            "  global-scope        global-scope option\n"
    1031             :            "  secret SECRET       set namespace secret\n"
    1032             :            "  chroot prefix PATH  Use PATH as memory root path\n"
    1033             :            "  sclose=[Y|N|W]      When stream is done, send[Y]|nop[N]|wait[W] for close\n"
    1034             :            "  nuris N             Cycle through N consecutive (src&dst) ips when creating connections\n"
    1035             :            "  lcl IP              Set the local ip to use as a client (use with nuris to set first src ip)\n"
    1036             :            "\n"
    1037             :            "  time START:END      Time between evts START & END, events being :\n"
    1038             :            "                       start - Start of the app\n"
    1039             :            "                       qconnect    - first Connection connect sent\n"
    1040             :            "                       qconnected  - last Connection connected\n"
    1041             :            "                       sconnect    - first Stream connect sent\n"
    1042             :            "                       sconnected  - last Stream got connected\n"
    1043             :            "                       lastbyte    - Last expected byte received\n"
    1044             :            "                       exit        - Exiting of the app\n"
    1045             :            "  rx-results-diff     Rx results different to pass test\n"
    1046             :            "  tx-results-diff     Tx results different to pass test\n"
    1047             :            "  json                Output global stats in json\n"
    1048             :            "  stats N             Output stats evry N secs\n"
    1049             :            "  log=N               Set the log level to [0: no output, 1:errors, 2:log]\n"
    1050             :            "  crypto [engine]     Set the crypto engine [openssl, vpp, picotls, mbedtls]\n"
    1051             :            "\n"
    1052             :            "  nclients N          Open N clients sending data\n"
    1053             :            "  nthreads N          Use N busy loop threads for data [in addition to main & msg queue]\n"
    1054             :            "  TX=1337[K|M|G]|RX   Send 1337 [K|M|G]bytes, use TX=RX to reflect the data\n"
    1055             :            "  RX=1337[K|M|G]      Expect 1337 [K|M|G]bytes\n" "\n");
    1056           0 :   for (i = 0; i < vec_len (em->available_proto_cb_vft); i++)
    1057             :     {
    1058           0 :       echo_proto_cb_vft_t *vft = em->available_proto_cb_vft[i];
    1059           0 :       if (vft && vft->print_usage_cb)
    1060           0 :         vft->print_usage_cb ();
    1061             :     }
    1062           0 :   fprintf (stderr, "\nDefault configuration is :\n"
    1063             :            " server nclients 1 [quic-streams 1] RX=64Kb TX=RX\n"
    1064             :            " client nclients 1 [quic-streams 1] RX=64Kb TX=64Kb\n");
    1065           0 :   exit (ECHO_FAIL_USAGE);
    1066             : }
    1067             : 
    1068             : static int
    1069          48 : echo_process_each_proto_opts (unformat_input_t * a)
    1070             : {
    1071          48 :   echo_main_t *em = &echo_main;
    1072             :   int i, rv;
    1073         284 :   for (i = 0; i < vec_len (em->available_proto_cb_vft); i++)
    1074             :     {
    1075         240 :       echo_proto_cb_vft_t *vft = em->available_proto_cb_vft[i];
    1076         240 :       if (vft && vft->process_opts_cb)
    1077          48 :         if ((rv = vft->process_opts_cb (a)))
    1078           4 :           return rv;
    1079             :     }
    1080          44 :   return 0;
    1081             : }
    1082             : 
    1083             : static void
    1084           4 : echo_set_each_proto_defaults_before_opts (echo_main_t * em)
    1085             : {
    1086             :   int i;
    1087          24 :   for (i = 0; i < vec_len (em->available_proto_cb_vft); i++)
    1088             :     {
    1089          20 :       echo_proto_cb_vft_t *vft = em->available_proto_cb_vft[i];
    1090          20 :       if (vft && vft->set_defaults_before_opts_cb)
    1091           4 :         vft->set_defaults_before_opts_cb ();
    1092             :     }
    1093           4 : }
    1094             : 
    1095             : void
    1096           4 : echo_process_opts (int argc, char **argv)
    1097             : {
    1098           4 :   echo_main_t *em = &echo_main;
    1099           4 :   unformat_input_t _argv, *a = &_argv;
    1100             :   u8 *chroot_prefix;
    1101           4 :   u8 *uri = 0;
    1102             :   u8 default_f_active;
    1103             :   uword tmp;
    1104             : 
    1105           4 :   unformat_init_command_line (a, argv);
    1106          52 :   while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
    1107             :     {
    1108          48 :       if (echo_process_each_proto_opts (a))
    1109             :         ;
    1110          44 :       else if (unformat (a, "chroot prefix %s", &chroot_prefix))
    1111           0 :         vl_set_memory_root_path ((char *) chroot_prefix);
    1112          44 :       else if (unformat (a, "uri %s", &uri))
    1113           4 :         em->uri = format (0, "%s%c", uri, 0);
    1114          40 :       else if (unformat (a, "lcl %U", unformat_ip46_address, &em->lcl_ip))
    1115           0 :         em->lcl_ip_set = 1;
    1116          40 :       else if (unformat (a, "nuris %u", &em->n_uris))
    1117           0 :         em->n_sessions = em->n_clients + em->n_uris;
    1118          40 :       else if (unformat (a, "server"))
    1119           2 :         em->i_am_master = 1;
    1120          38 :       else if (unformat (a, "client"))
    1121           2 :         em->i_am_master = 0;
    1122          36 :       else if (unformat (a, "test-bytes:assert"))
    1123           4 :         em->test_return_packets = RETURN_PACKETS_ASSERT;
    1124          32 :       else if (unformat (a, "test-bytes"))
    1125           0 :         em->test_return_packets = RETURN_PACKETS_LOG_WRONG;
    1126          32 :       else if (unformat (a, "socket-name %s", &em->socket_name))
    1127             :         ;
    1128          28 :       else if (unformat (a, "use-app-socket-api"))
    1129           4 :         em->use_app_socket_api = 1;
    1130          24 :       else if (unformat (a, "use-svm-api"))
    1131           0 :         em->use_sock_api = 0;
    1132          24 :       else if (unformat (a, "fifo-size %U", unformat_memory_size, &tmp))
    1133             :         {
    1134           4 :           if (tmp >= 0x100000000ULL)
    1135             :             {
    1136           0 :               fprintf (stderr,
    1137             :                        "ERROR: fifo-size %ld (0x%lx) too large\n", tmp, tmp);
    1138           0 :               print_usage_and_exit ();
    1139             :             }
    1140           4 :           em->fifo_size = tmp;
    1141             :         }
    1142          20 :       else if (unformat (a, "prealloc-fifos %u", &em->prealloc_fifo_pairs))
    1143             :         ;
    1144             :       else
    1145          20 :         if (unformat (a, "rx-buf %U", unformat_data_size, &em->rx_buf_size))
    1146             :         ;
    1147             :       else
    1148          20 :         if (unformat (a, "tx-buf %U", unformat_data_size, &em->tx_buf_size))
    1149             :         ;
    1150          20 :       else if (unformat (a, "mq-size %d", &em->evt_q_size))
    1151             :         ;
    1152          16 :       else if (unformat (a, "nclients %d", &em->n_clients))
    1153             :         {
    1154           0 :           em->n_sessions = em->n_clients + em->n_uris;
    1155           0 :           em->n_connects = em->n_clients;
    1156             :         }
    1157          16 :       else if (unformat (a, "nthreads %d", &em->n_rx_threads))
    1158             :         ;
    1159          12 :       else if (unformat (a, "crypto %U", echo_unformat_crypto_engine, &tmp))
    1160           0 :         em->crypto_engine = tmp;
    1161          12 :       else if (unformat (a, "appns %_%v%_", &em->appns_id))
    1162             :         ;
    1163           8 :       else if (unformat (a, "all-scope"))
    1164           0 :         em->appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
    1165             :                             | APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
    1166           8 :       else if (unformat (a, "local-scope"))
    1167           0 :         em->appns_flags = APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
    1168           8 :       else if (unformat (a, "global-scope"))
    1169           0 :         em->appns_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
    1170           8 :       else if (unformat (a, "secret %lu", &em->appns_secret))
    1171             :         ;
    1172           8 :       else if (unformat (a, "TX=RX"))
    1173           0 :         em->data_source = ECHO_RX_DATA_SOURCE;
    1174           8 :       else if (unformat (a, "TX=%U", unformat_data_size, &em->bytes_to_send))
    1175             :         ;
    1176           6 :       else if (unformat (a, "RX=%U", unformat_data_size,
    1177             :                          &em->bytes_to_receive))
    1178             :         ;
    1179           4 :       else if (unformat (a, "rx-results-diff"))
    1180           0 :         em->rx_results_diff = 1;
    1181           4 :       else if (unformat (a, "tx-results-diff"))
    1182           0 :         em->tx_results_diff = 1;
    1183           4 :       else if (unformat (a, "json"))
    1184           4 :         em->output_json = 1;
    1185           0 :       else if (unformat (a, "stats %d", &em->periodic_stats_delta))
    1186             :         ;
    1187           0 :       else if (unformat (a, "wait-for-gdb"))
    1188           0 :         em->wait_for_gdb = 1;
    1189           0 :       else if (unformat (a, "log=%d", &em->log_lvl))
    1190             :         ;
    1191           0 :       else if (unformat (a, "sclose=%U",
    1192             :                          echo_unformat_close, &em->send_stream_disconnects))
    1193             :         ;
    1194           0 :       else if (unformat (a, "time %U:%U",
    1195             :                          echo_unformat_timing_event, &em->timing.start_event,
    1196             :                          echo_unformat_timing_event, &em->timing.end_event))
    1197             :         ;
    1198           0 :       else if (unformat (a, "max-sim-connects %d", &em->max_sim_connects))
    1199             :         ;
    1200             :       else
    1201           0 :         print_usage_and_exit ();
    1202             :     }
    1203             : 
    1204             :   /* setting default for unset values
    1205             :    *
    1206             :    * bytes_to_send / bytes_to_receive & data_source  */
    1207           4 :   if (em->bytes_to_receive == (u64) ~ 0)
    1208           2 :     em->bytes_to_receive = 64 << 10;   /* default */
    1209           4 :   if (em->bytes_to_send == (u64) ~ 0)
    1210           2 :     em->bytes_to_send = 64 << 10;      /* default */
    1211           2 :   else if (em->bytes_to_send == 0)
    1212           1 :     em->data_source = ECHO_NO_DATA_SOURCE;
    1213             :   else
    1214           1 :     em->data_source = ECHO_TEST_DATA_SOURCE;
    1215             : 
    1216           4 :   if (em->data_source == ECHO_INVALID_DATA_SOURCE)
    1217           2 :     em->data_source =
    1218           2 :       em->i_am_master ? ECHO_RX_DATA_SOURCE : ECHO_TEST_DATA_SOURCE;
    1219           4 :   if (em->data_source == ECHO_RX_DATA_SOURCE)
    1220           1 :     em->bytes_to_send = em->bytes_to_receive;
    1221             : 
    1222             :   /* disconnect flags  */
    1223           4 :   if (em->i_am_master)
    1224           2 :     default_f_active =
    1225           2 :       em->bytes_to_send == 0 ? ECHO_CLOSE_F_ACTIVE : ECHO_CLOSE_F_PASSIVE;
    1226             :   else
    1227           2 :     default_f_active =
    1228           2 :       em->bytes_to_receive == 0 ? ECHO_CLOSE_F_PASSIVE : ECHO_CLOSE_F_ACTIVE;
    1229           4 :   if (em->send_stream_disconnects == ECHO_CLOSE_F_INVALID)
    1230           4 :     em->send_stream_disconnects = default_f_active;
    1231             : 
    1232           4 :   if (em->max_sim_connects == 0)
    1233           4 :     em->max_sim_connects = em->evt_q_size >> 1;
    1234             : 
    1235           4 :   if (em->wait_for_gdb)
    1236             :     {
    1237           0 :       volatile u64 nop = 0;
    1238             : 
    1239           0 :       clib_warning ("Waiting for gdb...");
    1240           0 :       while (em->wait_for_gdb)
    1241           0 :         nop++;
    1242           0 :       clib_warning ("Resuming execution (%llu)!", nop);
    1243             :     }
    1244           4 : }
    1245             : 
    1246             : static int
    1247           8 : echo_needs_crypto (echo_main_t *em)
    1248             : {
    1249           8 :   u8 tr = em->uri_elts.transport_proto;
    1250           8 :   if (tr == TRANSPORT_PROTO_QUIC || tr == TRANSPORT_PROTO_TLS)
    1251           8 :     return 1;
    1252           0 :   return 0;
    1253             : }
    1254             : 
    1255             : void
    1256           4 : echo_process_uri (echo_main_t * em)
    1257             : {
    1258           4 :   unformat_input_t _input, *input = &_input;
    1259             :   u32 port;
    1260           4 :   unformat_init_string (input, (char *) em->uri, strlen ((char *) em->uri));
    1261           4 :   if (unformat
    1262             :       (input, "%U://%U/%d", unformat_transport_proto,
    1263             :        &em->uri_elts.transport_proto, unformat_ip4_address,
    1264             :        &em->uri_elts.ip.ip4, &port))
    1265           4 :     em->uri_elts.is_ip4 = 1;
    1266             :   else
    1267           0 :     if (unformat
    1268             :         (input, "%U://%U/%d", unformat_transport_proto,
    1269             :          &em->uri_elts.transport_proto, unformat_ip6_address,
    1270             :          &em->uri_elts.ip.ip6, &port))
    1271           0 :     em->uri_elts.is_ip4 = 0;
    1272             :   else
    1273           0 :     ECHO_FAIL (ECHO_FAIL_INVALID_URI, "Unable to process uri");
    1274           4 :   em->uri_elts.port = clib_host_to_net_u16 (port);
    1275           4 :   unformat_free (input);
    1276           4 : }
    1277             : 
    1278             : static void __clib_constructor
    1279           4 : vpp_echo_init ()
    1280             : {
    1281             :   /* init memory before proto register themselves */
    1282           4 :   echo_main_t *em = &echo_main;
    1283           4 :   clib_mem_init_thread_safe (0, 256 << 20);
    1284           4 :   clib_memset (em, 0, sizeof (*em));
    1285           4 : }
    1286             : 
    1287             : static int
    1288           4 : echo_detach (echo_main_t *em)
    1289             : {
    1290           4 :   if (em->use_app_socket_api)
    1291           4 :     return echo_sapi_detach (em);
    1292             : 
    1293           0 :   echo_send_detach (em);
    1294           0 :   if (wait_for_state_change (em, STATE_DETACHED, TIMEOUT))
    1295             :     {
    1296           0 :       ECHO_FAIL (ECHO_FAIL_DETACH, "Couldn't detach from vpp");
    1297           0 :       return -1;
    1298             :     }
    1299           0 :   return 0;
    1300             : }
    1301             : 
    1302             : static void
    1303           4 : echo_add_cert_key (echo_main_t *em)
    1304             : {
    1305           4 :   if (em->use_app_socket_api)
    1306           4 :     echo_sapi_add_cert_key (em);
    1307             :   else
    1308             :     {
    1309           0 :       echo_send_add_cert_key (em);
    1310           0 :       if (wait_for_state_change (em, STATE_ATTACHED, TIMEOUT))
    1311             :         {
    1312           0 :           ECHO_FAIL (ECHO_FAIL_APP_ATTACH,
    1313             :                      "Couldn't add crypto context to vpp\n");
    1314           0 :           exit (1);
    1315             :         }
    1316             :     }
    1317           4 : }
    1318             : 
    1319             : static int
    1320           4 : echo_del_cert_key (echo_main_t *em)
    1321             : {
    1322           4 :   if (em->use_app_socket_api)
    1323           4 :     return echo_sapi_del_cert_key (em);
    1324             : 
    1325           0 :   echo_send_del_cert_key (em);
    1326           0 :   if (wait_for_state_change (em, STATE_CLEANED_CERT_KEY, TIMEOUT))
    1327             :     {
    1328           0 :       ECHO_FAIL (ECHO_FAIL_DEL_CERT_KEY, "Couldn't cleanup cert and key");
    1329           0 :       return -1;
    1330             :     }
    1331           0 :   return 0;
    1332             : }
    1333             : 
    1334             : static void
    1335           4 : echo_disconnect (echo_main_t *em)
    1336             : {
    1337           4 :   if (em->use_app_socket_api)
    1338           4 :     return;
    1339             : 
    1340           0 :   if (em->use_sock_api)
    1341           0 :     vl_socket_client_disconnect ();
    1342             :   else
    1343           0 :     vl_client_disconnect_from_vlib ();
    1344             : }
    1345             : 
    1346             : static int
    1347           4 : echo_attach (echo_main_t *em)
    1348             : {
    1349           4 :   if (em->use_app_socket_api)
    1350           4 :     return echo_sapi_attach (em);
    1351             :   else
    1352             :     {
    1353           0 :       echo_api_hookup (em);
    1354           0 :       echo_send_attach (em);
    1355           0 :       if (wait_for_state_change (em, STATE_ATTACHED_NO_CERT, TIMEOUT))
    1356             :         {
    1357           0 :           ECHO_FAIL (ECHO_FAIL_ATTACH_TO_VPP,
    1358             :                      "Couldn't attach to vpp, did you run <session enable> ?");
    1359           0 :           return -1;
    1360             :         }
    1361             :     }
    1362           0 :   return 0;
    1363             : }
    1364             : 
    1365             : int
    1366           4 : main (int argc, char **argv)
    1367             : {
    1368           4 :   echo_main_t *em = &echo_main;
    1369           4 :   fifo_segment_main_t *sm = &em->segment_main;
    1370             :   u64 i;
    1371             :   int *rv;
    1372           4 :   svm_msg_q_cfg_t _cfg, *cfg = &_cfg;
    1373           4 :   u32 rpc_queue_size = 256 << 10;
    1374             : 
    1375           4 :   em->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
    1376           4 :   clib_spinlock_init (&em->sid_vpp_handles_lock);
    1377           4 :   em->shared_segment_handles = hash_create (0, sizeof (uword));
    1378           4 :   clib_spinlock_init (&em->segment_handles_lock);
    1379           4 :   em->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
    1380           4 :   em->use_sock_api = 1;
    1381           4 :   em->fifo_size = 64 << 10;
    1382           4 :   em->prealloc_fifo_pairs = 16;
    1383           4 :   em->n_clients = 1;
    1384           4 :   em->n_connects = 1;
    1385           4 :   em->n_sessions = 2;
    1386           4 :   em->max_test_msg = 50;
    1387           4 :   em->time_to_stop = 0;
    1388           4 :   em->i_am_master = 1;
    1389           4 :   em->n_rx_threads = 4;
    1390           4 :   em->evt_q_size = 256;
    1391           4 :   em->lcl_ip_set = 0;
    1392           4 :   clib_memset (&em->lcl_ip, 0, sizeof (em->lcl_ip));
    1393           4 :   em->test_return_packets = RETURN_PACKETS_NOTEST;
    1394           4 :   em->timing.start_event = ECHO_EVT_FIRST_QCONNECT;
    1395           4 :   em->timing.end_event = ECHO_EVT_LAST_BYTE;
    1396           4 :   em->bytes_to_receive = ~0; /* defaulted when we know if server/client */
    1397           4 :   em->bytes_to_send = ~0;    /* defaulted when we know if server/client */
    1398           4 :   em->rx_buf_size = 1 << 20;
    1399           4 :   em->tx_buf_size = 1 << 20;
    1400           4 :   em->data_source = ECHO_INVALID_DATA_SOURCE;
    1401           4 :   em->uri = format (0, "%s%c", "tcp://0.0.0.0/1234", 0);
    1402           4 :   em->n_uris = 1;
    1403           4 :   em->max_sim_connects = 0;
    1404           4 :   em->listen_session_cnt = 0;
    1405           4 :   em->crypto_engine = CRYPTO_ENGINE_NONE;
    1406           4 :   echo_set_each_proto_defaults_before_opts (em);
    1407           4 :   echo_process_opts (argc, argv);
    1408           4 :   echo_process_uri (em);
    1409           4 :   em->proto_cb_vft = em->available_proto_cb_vft[em->uri_elts.transport_proto];
    1410           4 :   if (!em->proto_cb_vft)
    1411             :     {
    1412           0 :       ECHO_FAIL (ECHO_FAIL_PROTOCOL_NOT_SUPPORTED,
    1413             :                  "Protocol %U is not supported",
    1414             :                  format_transport_proto, em->uri_elts.transport_proto);
    1415           0 :       goto exit_on_error;
    1416             :     }
    1417           4 :   if (em->proto_cb_vft->set_defaults_after_opts_cb)
    1418           4 :     em->proto_cb_vft->set_defaults_after_opts_cb ();
    1419             : 
    1420           4 :   em->stats.rx_expected = em->bytes_to_receive * em->n_clients;
    1421           4 :   em->stats.tx_expected = em->bytes_to_send * em->n_clients;
    1422             : 
    1423           4 :   vec_validate (em->data_thread_handles, em->n_rx_threads);
    1424           4 :   vec_validate (em->data_thread_args, em->n_clients);
    1425           8 :   for (i = 0; i < em->n_clients; i++)
    1426           4 :     em->data_thread_args[i] = SESSION_INVALID_INDEX;
    1427           4 :   clib_time_init (&em->clib_time);
    1428           4 :   init_error_string_table ();
    1429           4 :   fifo_segment_main_init (sm, HIGH_SEGMENT_BASEVA, 20);
    1430           4 :   vec_validate (em->connect_test_data, em->tx_buf_size);
    1431     4194310 :   for (i = 0; i < em->tx_buf_size; i++)
    1432     4194300 :     em->connect_test_data[i] = i & 0xff;
    1433             : 
    1434             :   /* *INDENT-OFF* */
    1435           4 :   svm_msg_q_ring_cfg_t rc[1] = {
    1436             :     {rpc_queue_size, sizeof (echo_rpc_msg_t), 0},
    1437             :   };
    1438             :   /* *INDENT-ON* */
    1439           4 :   cfg->consumer_pid = getpid ();
    1440           4 :   cfg->n_rings = 1;
    1441           4 :   cfg->q_nitems = rpc_queue_size;
    1442           4 :   cfg->ring_cfgs = rc;
    1443           4 :   svm_msg_q_attach (&em->rpc_msq_queue, svm_msg_q_alloc (cfg));
    1444             : 
    1445           4 :   signal (SIGINT, stop_signal);
    1446           4 :   signal (SIGQUIT, stop_signal);
    1447           4 :   signal (SIGTERM, stop_signal);
    1448             : 
    1449           4 :   em->app_name =
    1450           4 :     format (0, "%s%c", em->i_am_master ? "echo_server" : "echo_client", 0);
    1451             : 
    1452           4 :   if (connect_to_vpp (em))
    1453             :     {
    1454           0 :       svm_region_exit ();
    1455           0 :       ECHO_FAIL (ECHO_FAIL_CONNECT_TO_VPP, "Couldn't connect to vpp");
    1456           0 :       goto exit_on_error;
    1457             :     }
    1458             : 
    1459           4 :   echo_session_prealloc (em);
    1460           4 :   echo_notify_event (em, ECHO_EVT_START);
    1461             : 
    1462           4 :   if (echo_attach (em))
    1463           0 :     goto exit_on_error;
    1464             : 
    1465           4 :   if (echo_needs_crypto (em))
    1466             :     {
    1467           4 :       ECHO_LOG (2, "Adding crypto context %U", echo_format_crypto_engine,
    1468             :                 em->crypto_engine);
    1469           4 :       echo_add_cert_key (em);
    1470             :     }
    1471             :   else
    1472             :     {
    1473           0 :       em->state = STATE_ATTACHED;
    1474             :     }
    1475             : 
    1476           4 :   if (pthread_create (&em->mq_thread_handle, NULL /*attr */, echo_mq_thread_fn,
    1477             :                       0))
    1478             :     {
    1479           0 :       ECHO_FAIL (ECHO_FAIL_PTHREAD_CREATE, "pthread create errored");
    1480           0 :       goto exit_on_error;
    1481             :     }
    1482             : 
    1483           8 :   for (i = 0; i < em->n_rx_threads; i++)
    1484           4 :     if (pthread_create (&em->data_thread_handles[i],
    1485             :                         NULL /*attr */ , echo_data_thread_fn, (void *) i))
    1486             :       {
    1487           0 :         ECHO_FAIL (ECHO_FAIL_PTHREAD_CREATE,
    1488             :                    "pthread create errored (index %d)", i);
    1489           0 :         goto exit_on_error;
    1490             :       }
    1491           4 :   if (em->i_am_master)
    1492           2 :     server_run (em);
    1493             :   else
    1494           2 :     clients_run (em);
    1495           4 :   echo_notify_event (em, ECHO_EVT_EXIT);
    1496           4 :   echo_free_sessions (em);
    1497           4 :   if (echo_needs_crypto (em))
    1498             :     {
    1499           4 :       if (echo_del_cert_key (em))
    1500           0 :         goto exit_on_error;
    1501             :     }
    1502             : 
    1503           4 :   if (echo_detach (em))
    1504           0 :     goto exit_on_error;
    1505             : 
    1506           4 :   pthread_join (em->mq_thread_handle, (void **) &rv);
    1507           4 :   if (rv)
    1508             :     {
    1509           0 :       ECHO_FAIL (ECHO_FAIL_MQ_PTHREAD, "mq pthread errored %d", rv);
    1510           0 :       goto exit_on_error;
    1511             :     }
    1512           4 :   echo_disconnect (em);
    1513           4 :   echo_assert_test_suceeded (em);
    1514           4 : exit_on_error:
    1515           4 :   ECHO_LOG (1, "Test complete !\n");
    1516           4 :   if (em->output_json)
    1517           4 :     print_global_json_stats (em);
    1518             :   else
    1519           0 :     print_global_stats (em);
    1520           4 :   vec_free (em->fail_descr);
    1521           4 :   vec_free (em->available_proto_cb_vft);
    1522           4 :   exit (em->has_failed);
    1523             : }
    1524             : 
    1525             : /*
    1526             :  * fd.io coding-style-patch-verification: ON
    1527             :  *
    1528             :  * Local Variables:
    1529             :  * eval: (c-set-style "gnu")
    1530             :  * End:
    1531             :  */

Generated by: LCOV version 1.14