vpp_echo_common.h revision ff5a9b6e
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#ifndef __included_vpp_echo_common_h__
17#define __included_vpp_echo_common_h__
18
19#include <vnet/session/application_interface.h>
20#include <vpp/api/vpe_msg_enum.h>
21
22#define vl_typedefs		/* define message structures */
23#include <vpp/api/vpe_all_api_h.h>
24#undef vl_typedefs
25
26/* declare message handlers for each api */
27
28#define vl_endianfun		/* define message structures */
29#include <vpp/api/vpe_all_api_h.h>
30#undef vl_endianfun
31
32/* instantiate all the print functions we know about */
33#define vl_print(handle, ...)
34#define vl_printfun
35#include <vpp/api/vpe_all_api_h.h>
36#undef vl_printfun
37
38#define TIMEOUT 10.0
39
40#define foreach_echo_fail_code                                          \
41  _(ECHO_FAIL_NONE, "ECHO_FAIL_NONE")                                   \
42  _(ECHO_FAIL_USAGE, "ECHO_FAIL_USAGE")                                 \
43  _(ECHO_FAIL_SEND_IO_EVT, "ECHO_FAIL_SEND_IO_EVT")                     \
44  _(ECHO_FAIL_SOCKET_CONNECT, "ECHO_FAIL_SOCKET_CONNECT")               \
45  _(ECHO_FAIL_INIT_SHM_API, "ECHO_FAIL_INIT_SHM_API")                   \
46  _(ECHO_FAIL_SHMEM_CONNECT, "ECHO_FAIL_SHMEM_CONNECT")                 \
47  _(ECHO_FAIL_TEST_BYTES_ERR, "ECHO_FAIL_TEST_BYTES_ERR")               \
48  _(ECHO_FAIL_BIND, "ECHO_FAIL_BIND")                                   \
49  _(ECHO_FAIL_SESSION_ACCEPTED_BAD_LISTENER,                            \
50    "ECHO_FAIL_SESSION_ACCEPTED_BAD_LISTENER")                          \
51  _(ECHO_FAIL_ACCEPTED_WAIT_FOR_SEG_ALLOC,                              \
52    "ECHO_FAIL_ACCEPTED_WAIT_FOR_SEG_ALLOC")                            \
53  _(ECHO_FAIL_SESSION_CONNECT, "ECHO_FAIL_SESSION_CONNECT")             \
54  _(ECHO_FAIL_CONNECTED_WAIT_FOR_SEG_ALLOC,                             \
55    "ECHO_FAIL_CONNECTED_WAIT_FOR_SEG_ALLOC")                           \
56  _(ECHO_FAIL_APP_ATTACH, "ECHO_FAIL_APP_ATTACH")                       \
57  _(ECHO_FAIL_SERVER_DISCONNECT_TIMEOUT,                                \
58    "ECHO_FAIL_SERVER_DISCONNECT_TIMEOUT")                              \
59  _(ECHO_FAIL_INVALID_URI, "ECHO_FAIL_INVALID_URI")                     \
60  _(ECHO_FAIL_PROTOCOL_NOT_SUPPORTED,                                   \
61    "ECHO_FAIL_PROTOCOL_NOT_SUPPORTED")                                 \
62  _(ECHO_FAIL_CONNECT_TO_VPP, "ECHO_FAIL_CONNECT_TO_VPP")               \
63  _(ECHO_FAIL_ATTACH_TO_VPP, "ECHO_FAIL_ATTACH_TO_VPP")                 \
64  _(ECHO_FAIL_1ST_PTHREAD_CREATE, "ECHO_FAIL_1ST_PTHREAD_CREATE")       \
65  _(ECHO_FAIL_PTHREAD_CREATE, "ECHO_FAIL_PTHREAD_CREATE")               \
66  _(ECHO_FAIL_DETACH, "ECHO_FAIL_DETACH")                               \
67  _(ECHO_FAIL_MQ_PTHREAD, "ECHO_FAIL_MQ_PTHREAD")                       \
68  _(ECHO_FAIL_VL_API_APP_ATTACH, "ECHO_FAIL_VL_API_APP_ATTACH")         \
69  _(ECHO_FAIL_VL_API_MISSING_SEGMENT_NAME,                              \
70    "ECHO_FAIL_VL_API_MISSING_SEGMENT_NAME")                            \
71  _(ECHO_FAIL_VL_API_NULL_APP_MQ, "ECHO_FAIL_VL_API_NULL_APP_MQ")       \
72  _(ECHO_FAIL_VL_API_RECV_FD_MSG, "ECHO_FAIL_VL_API_RECV_FD_MSG")       \
73  _(ECHO_FAIL_VL_API_SVM_FIFO_SEG_ATTACH,                               \
74    "ECHO_FAIL_VL_API_SVM_FIFO_SEG_ATTACH")                             \
75  _(ECHO_FAIL_VL_API_FIFO_SEG_ATTACH,                                   \
76    "ECHO_FAIL_VL_API_FIFO_SEG_ATTACH")                                 \
77  _(ECHO_FAIL_VL_API_DETACH_REPLY, "ECHO_FAIL_VL_API_DETACH_REPLY")     \
78  _(ECHO_FAIL_VL_API_BIND_URI_REPLY, "ECHO_FAIL_VL_API_BIND_URI_REPLY") \
79  _(ECHO_FAIL_VL_API_UNBIND_REPLY, "ECHO_FAIL_VL_API_UNBIND_REPLY")     \
80  _(ECHO_FAIL_SESSION_DISCONNECT, "ECHO_FAIL_SESSION_DISCONNECT")       \
81  _(ECHO_FAIL_SESSION_RESET, "ECHO_FAIL_SESSION_RESET")                 \
82  _(ECHO_FAIL_VL_API_TLS_CERT_ADD_REPLY,                                \
83    "ECHO_FAIL_VL_API_TLS_CERT_ADD_REPLY")                              \
84  _(ECHO_FAIL_VL_API_TLS_KEY_ADD_REPLY,                                 \
85    "ECHO_FAIL_VL_API_TLS_KEY_ADD_REPLY")                               \
86  _(ECHO_FAIL_GET_SESSION_FROM_HANDLE,                                  \
87    "ECHO_FAIL_GET_SESSION_FROM_HANDLE")                                \
88  _(ECHO_FAIL_QUIC_WRONG_CONNECT, "ECHO_FAIL_QUIC_WRONG_CONNECT")       \
89  _(ECHO_FAIL_QUIC_WRONG_ACCEPT, "ECHO_FAIL_QUIC_WRONG_ACCEPT")         \
90  _(ECHO_FAIL_TCP_BAPI_CONNECT, "ECHO_FAIL_TCP_BAPI_CONNECT")           \
91  _(ECHO_FAIL_UDP_BAPI_CONNECT, "ECHO_FAIL_UDP_BAPI_CONNECT")           \
92  _(ECHO_FAIL_MISSING_START_EVENT, "ECHO_FAIL_MISSING_START_EVENT")     \
93  _(ECHO_FAIL_MISSING_END_EVENT, "ECHO_FAIL_MISSING_END_EVENT")         \
94  _(ECHO_FAIL_TEST_ASSERT_RX_TOTAL, "ECHO_FAIL_TEST_ASSERT_RX_TOTAL")   \
95  _(ECHO_FAIL_TEST_ASSERT_TX_TOTAL, "ECHO_FAIL_TEST_ASSERT_TX_TOTAL")   \
96  _(ECHO_FAIL_TEST_ASSERT_ALL_SESSIONS_CLOSED,                          \
97    "ECHO_FAIL_TEST_ASSERT_ALL_SESSIONS_CLOSED")
98
99typedef enum
100{
101#define _(sym, str) sym,
102  foreach_echo_fail_code
103#undef _
104} echo_fail_t;
105
106extern char *echo_fail_code_str[];
107
108#define CHECK_SAME(fail, expected, result, _fmt, _args...)      \
109do {                                                            \
110  if ((expected) != (result))                                   \
111    ECHO_FAIL ((fail), "expected same (%d, got %d) : "_fmt,     \
112               (expected), (result), ##_args);                  \
113} while (0)
114
115#define CHECK_DIFF(fail, expected, result, _fmt, _args...)      \
116do {                                                            \
117  if ((expected) == (result))                                   \
118    ECHO_FAIL ((fail), "expected different (both %d) : "_fmt,   \
119               (expected), ##_args);                            \
120} while (0)
121
122#define ECHO_FAIL(fail, _fmt, _args...)                                 \
123do {                                                                    \
124    echo_main_t *em = &echo_main;                                       \
125    em->has_failed = (fail);                                            \
126    if (vec_len(em->fail_descr))                                        \
127      em->fail_descr = format(em->fail_descr, " | %s (%d): "_fmt,       \
128                              echo_fail_code_str[fail], fail, ##_args); \
129    else                                                                \
130      em->fail_descr = format(0, "%s (%d): "_fmt,                       \
131                              echo_fail_code_str[fail], fail, ##_args); \
132    em->time_to_stop = 1;                                               \
133    if (em->log_lvl > 0)                                                \
134      clib_warning ("%v", em->fail_descr);                              \
135} while (0)
136
137#define ECHO_LOG(lvl, _fmt,_args...)    \
138  {                                     \
139    echo_main_t *em = &echo_main;       \
140    if (em->log_lvl > lvl)              \
141         clib_warning (_fmt, ##_args);  \
142  }
143
144#define ECHO_REGISTER_PROTO(proto, vft)         \
145  static void __clib_constructor                \
146  vpp_echo_init_##proto ()                      \
147  {                                             \
148    echo_main_t *em = &echo_main;               \
149    em->available_proto_cb_vft[proto] = &vft;   \
150  }
151
152typedef struct
153{
154  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
155#define _(type, name) type name;
156  foreach_app_session_field
157#undef _
158  u64 vpp_session_handle;
159  u64 bytes_sent;
160  u64 bytes_to_send;
161  volatile u64 bytes_received;
162  volatile u64 bytes_to_receive;
163  f64 start;
164  u32 listener_index;		/* listener index in echo session pool */
165  u32 idle_cycles;		/* consecutive enq/deq with no data */
166  volatile u64 accepted_session_count;	/* sessions we accepted (as a listener) */
167} echo_session_t;
168
169typedef enum
170{
171  ECHO_NO_DATA_SOURCE,
172  ECHO_TEST_DATA_SOURCE,
173  ECHO_RX_DATA_SOURCE,
174  ECHO_INVALID_DATA_SOURCE
175} data_source_t;
176
177enum echo_close_f_t
178{
179  ECHO_CLOSE_F_INVALID = 0,
180  ECHO_CLOSE_F_PASSIVE,		/* wait for close msg */
181  ECHO_CLOSE_F_ACTIVE,		/* send close msg */
182  ECHO_CLOSE_F_NONE,		/* don't bother sending close msg */
183};
184
185enum quic_session_type_t
186{
187  ECHO_SESSION_TYPE_QUIC,
188  ECHO_SESSION_TYPE_STREAM,
189  ECHO_SESSION_TYPE_LISTEN,
190};
191
192enum quic_session_state_t
193{
194  ECHO_SESSION_STATE_INITIAL,
195  ECHO_SESSION_STATE_READY,
196  ECHO_SESSION_STATE_AWAIT_CLOSING,	/* Data transfer is done, wait for close evt */
197  ECHO_SESSION_STATE_AWAIT_DATA,	/* Peer closed, wait for outstanding data */
198  ECHO_SESSION_STATE_CLOSING,	/* told vpp to close */
199  ECHO_SESSION_STATE_CLOSED,	/* closed in vpp */
200};
201
202typedef enum
203{
204  STATE_START,
205  STATE_ATTACHED_NO_CERT,
206  STATE_ATTACHED_ONE_CERT,
207  STATE_ATTACHED,
208  STATE_LISTEN,
209  STATE_READY,
210  STATE_DATA_DONE,
211  STATE_DISCONNECTED,
212  STATE_DETACHED
213} connection_state_t;
214
215typedef enum echo_test_evt_
216{
217  ECHO_EVT_START = 1,		/* app starts */
218  ECHO_EVT_FIRST_QCONNECT = (1 << 1),	/* First connect Quic session sent */
219  ECHO_EVT_LAST_QCONNECTED = (1 << 2),	/* All Quic session are connected */
220  ECHO_EVT_FIRST_SCONNECT = (1 << 3),	/* First connect Stream session sent */
221  ECHO_EVT_LAST_SCONNECTED = (1 << 4),	/* All Stream session are connected */
222  ECHO_EVT_LAST_BYTE = (1 << 5),	/* Last byte received */
223  ECHO_EVT_EXIT = (1 << 6),	/* app exits */
224} echo_test_evt_t;
225
226typedef union session_connected_bundled_msg_
227{
228  session_connected_msg_t *mp;
229  vl_api_connect_uri_reply_t *bmp;
230} session_connected_bundled_msg_t;
231
232typedef struct echo_proto_cb_vft_
233{
234  void (*connected_cb) (session_connected_bundled_msg_t * mp, u32 session_index, u8 is_failed);	/* Session is connected */
235  void (*accepted_cb) (session_accepted_msg_t * mp, echo_session_t * session);	/* Session got accepted */
236  void (*bound_uri_cb) (session_bound_msg_t * mp, echo_session_t * session);	/* Session got bound */
237  void (*reset_cb) (session_reset_msg_t * mp, echo_session_t * s);	/* Received RESET on session */
238  void (*disconnected_cb) (session_disconnected_msg_t * mp, echo_session_t * s);	/* Received DISCONNECT on session */
239  void (*sent_disconnect_cb) (echo_session_t * s);	/* ACK disconnect we sent to vpp */
240  void (*cleanup_cb) (echo_session_t * s, u8 parent_died);	/* Session should be cleaned up (parent listener may be dead) */
241  /* Add CLI options */
242  int (*process_opts_cb) (unformat_input_t * a);
243  void (*set_defaults_before_opts_cb) (void);
244  void (*set_defaults_after_opts_cb) (void);
245  void (*print_usage_cb) (void);
246} echo_proto_cb_vft_t;
247
248typedef enum
249{
250  RETURN_PACKETS_NOTEST,
251  RETURN_PACKETS_LOG_WRONG,
252  RETURN_PACKETS_ASSERT,
253} test_return_packets_t;
254
255typedef struct teardown_stat_
256{
257  u32 q;			/* quic sessions */
258  u32 s;			/* stream sessions */
259} teardown_stat_t;
260
261typedef struct
262{
263  svm_queue_t *vl_input_queue;	/* vpe input queue */
264  u32 my_client_index;		/* API client handle */
265  u8 *uri;			/* The URI we're playing with */
266  echo_session_t *sessions;	/* Session pool */
267  svm_msg_q_t *app_mq;		/* Our receiveing event queue */
268  svm_msg_q_t *ctrl_mq;		/* Our control queue (towards vpp) */
269  clib_time_t clib_time;	/* For deadman timers */
270  u8 *socket_name;
271  int i_am_master;
272  u32 listen_session_index;	/* Index of vpp listener session */
273
274  uword *session_index_by_vpp_handles;	/* Hash table : quic_echo s_id -> vpp s_handle */
275  clib_spinlock_t sid_vpp_handles_lock;	/* Hash table lock */
276
277  uword *shared_segment_handles;	/* Hash table : segment_names -> 1 */
278  clib_spinlock_t segment_handles_lock;	/* Hash table lock */
279  echo_proto_cb_vft_t *proto_cb_vft;
280  svm_msg_q_t *rpc_msq_queue;	/* MQ between quic_echo threads */
281  fifo_segment_main_t segment_main;
282
283  /* State of the connection, shared between msg RX thread and main thread */
284  volatile connection_state_t state;
285  volatile u8 time_to_stop;	/* Signal variables */
286  u8 rx_results_diff;		/* Rx results will be different than cfg */
287  u8 tx_results_diff;		/* Tx results will be different than cfg */
288  u8 has_failed;		/* stores the exit code */
289  u8 *fail_descr;		/* vector containing fail description */
290
291  /** Flag that decides if socket, instead of svm, api is used to connect to
292   * vpp. If sock api is used, shm binary api is subsequently bootstrapped
293   * and all other messages are exchanged using shm IPC. */
294  u8 use_sock_api;
295
296  u8 *connect_test_data;
297  u8 test_return_packets;
298  u64 bytes_to_send;		/* target per stream */
299  u64 bytes_to_receive;		/* target per stream */
300  u32 fifo_size;
301  u32 prealloc_fifo_pairs;
302  u32 rx_buf_size;
303  u32 tx_buf_size;
304  data_source_t data_source;	/* Use no/dummy/mirrored data */
305  u8 send_stream_disconnects;	/* actively send disconnect */
306  u8 output_json;		/* Output stats as JSON */
307  u8 log_lvl;			/* Verbosity of the logging */
308  int max_test_msg;		/* Limit the number of incorrect data messages */
309  u32 evt_q_size;		/* Size of the vpp MQ (app<->vpp events) */
310  u32 crypto_ctx_engine;	/* crypto engine used */
311
312  u8 *appns_id;
313  u64 appns_flags;
314  u64 appns_secret;
315
316  pthread_t *data_thread_handles;	/* vec of data thread handles */
317  pthread_t mq_thread_handle;	/* Message queue thread handle */
318  u32 *volatile data_thread_args;
319
320  u32 n_connects;		/* Target number of connects to send */
321  u32 n_sessions;		/* Number of sessions to prealloc */
322  u32 n_clients;		/* Target number of clients doing RX/TX */
323  u32 n_rx_threads;		/* Number of data threads */
324
325  volatile u32 n_clients_connected;	/* Number of STREAM sessions connected */
326  volatile u32 nxt_available_sidx;	/* next unused prealloced session_index */
327
328  /* VNET_API_ERROR_FOO -> "Foo" hash table */
329  uword *error_string_by_error_number;
330  echo_proto_cb_vft_t *available_proto_cb_vft[TRANSPORT_N_PROTO];
331
332  struct
333  {
334    u64 tx_total;
335    u64 rx_total;
336    teardown_stat_t reset_count;	/* received reset from vpp */
337    teardown_stat_t close_count;	/* received close from vpp */
338    teardown_stat_t active_count;	/* sent close to vpp */
339    teardown_stat_t clean_count;	/* cleaned up stale session */
340  } stats;
341
342  struct			/* Event based timing : start & end depend on CLI specified events */
343  {
344    f64 start_time;
345    f64 end_time;
346    u8 events_sent;
347    u8 start_event;
348    u8 end_event;
349  } timing;
350
351  struct
352  {
353    u32 transport_proto;
354    ip46_address_t ip;
355    u32 port;
356    u8 is_ip4;
357  } uri_elts;
358} echo_main_t;
359
360extern echo_main_t echo_main;
361
362typedef void (*echo_rpc_t) (void *arg, u32 opaque);
363
364typedef struct
365{
366  void *fp;
367  void *arg;
368  u32 opaque;
369} echo_rpc_msg_t;
370
371u8 *format_ip4_address (u8 * s, va_list * args);
372u8 *format_ip6_address (u8 * s, va_list * args);
373u8 *format_ip46_address (u8 * s, va_list * args);
374uword unformat_data (unformat_input_t * input, va_list * args);
375u8 *format_api_error (u8 * s, va_list * args);
376void init_error_string_table ();
377u8 *echo_format_session (u8 * s, va_list * args);
378u8 *echo_format_session_type (u8 * s, va_list * args);
379u8 *echo_format_session_state (u8 * s, va_list * args);
380u8 *echo_format_app_state (u8 * s, va_list * args);
381uword echo_unformat_close (unformat_input_t * input, va_list * args);
382uword echo_unformat_timing_event (unformat_input_t * input, va_list * args);
383u8 *echo_format_timing_event (u8 * s, va_list * args);
384uword unformat_transport_proto (unformat_input_t * input, va_list * args);
385u8 *format_transport_proto (u8 * s, va_list * args);
386uword unformat_ip4_address (unformat_input_t * input, va_list * args);
387uword unformat_ip6_address (unformat_input_t * input, va_list * args);
388
389void echo_session_handle_add_del (echo_main_t * em, u64 handle, u32 sid);
390echo_session_t *echo_session_new (echo_main_t * em);
391int echo_send_rpc (echo_main_t * em, void *fp, void *arg, u32 opaque);
392echo_session_t *echo_get_session_from_handle (echo_main_t * em, u64 handle);
393int wait_for_segment_allocation (u64 segment_handle);
394int wait_for_state_change (echo_main_t * em, connection_state_t state,
395			   f64 timeout);
396void echo_notify_event (echo_main_t * em, echo_test_evt_t e);
397void echo_session_print_stats (echo_main_t * em, echo_session_t * session);
398u8 *echo_format_crypto_engine (u8 * s, va_list * args);
399uword echo_unformat_crypto_engine (unformat_input_t * input, va_list * args);
400
401/* Binary API */
402
403void echo_send_attach (echo_main_t * em);
404void echo_send_detach (echo_main_t * em);
405void echo_send_listen (echo_main_t * em);
406void echo_send_unbind (echo_main_t * em, echo_session_t * s);
407void echo_send_connect (u64 vpp_session_handle, u32 opaque);
408void echo_send_disconnect_session (u64 handle, u32 opaque);
409void echo_api_hookup (echo_main_t * em);
410void echo_send_add_crypto_ctx (echo_main_t * em);
411
412#endif /* __included_vpp_echo_common_h__ */
413
414/*
415 * fd.io coding-style-patch-verification: ON
416 *
417 * Local Variables:
418 * eval: (c-set-style "gnu")
419 * End:
420 */
421