aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/rdma/rdma.h
blob: a8ab07012eedfd7143f34d1c61f506cf1b0c8cea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
/*
 *------------------------------------------------------------------
 * Copyright (c) 2018 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *------------------------------------------------------------------
 */

#ifndef _RDMA_H_
#define _RDMA_H_

#include <infiniband/verbs.h>
#include <vlib/log.h>
#include <vlib/pci/pci.h>
#include <vnet/interface.h>
#include <vnet/ethernet/mac_address.h>
#include <rdma/rdma_mlx5dv.h>

#define foreach_rdma_device_flags \
  _(0, ERROR, "error") \
  _(1, ADMIN_UP, "admin-up") \
  _(2, LINK_UP, "link-up") \
  _(3, PROMISC, "promiscuous") \
  _(4, MLX5DV, "mlx5dv") \
  _(5, STRIDING_RQ, "striding-rq")

enum
{
#define _(a, b, c) RDMA_DEVICE_F_##b = (1 << a),
  foreach_rdma_device_flags
#undef _
};

#ifndef MLX5_ETH_L2_INLINE_HEADER_SIZE
#define MLX5_ETH_L2_INLINE_HEADER_SIZE  18
#endif

typedef struct
{
  CLIB_ALIGN_MARK (align0, MLX5_SEND_WQE_BB);
  union
  {
    struct mlx5_wqe_ctrl_seg ctrl;
    struct
    {
      u8 opc_mod;
      u8 wqe_index_hi;
      u8 wqe_index_lo;
      u8 opcode;
    };
  };
  struct mlx5_wqe_eth_seg eseg;
  struct mlx5_wqe_data_seg dseg;
} rdma_mlx5_wqe_t;
#define RDMA_MLX5_WQE_SZ        sizeof(rdma_mlx5_wqe_t)
#define RDMA_MLX5_WQE_DS        (RDMA_MLX5_WQE_SZ/sizeof(struct mlx5_wqe_data_seg))
STATIC_ASSERT (RDMA_MLX5_WQE_SZ == MLX5_SEND_WQE_BB &&
	       RDMA_MLX5_WQE_SZ % sizeof (struct mlx5_wqe_data_seg) == 0,
	       "bad size");

typedef struct
{
  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
  struct ibv_cq *cq;
  struct ibv_wq *wq;
  u32 *bufs;
  u32 size;
  u32 head;
  u32 tail;
  u32 cq_ci;
  u16 log2_cq_size;
  u16 n_mini_cqes;
  u16 n_mini_cqes_left;
  u16 last_cqe_flags;
  mlx5dv_cqe_t *cqes;
  mlx5dv_wqe_ds_t *wqes;
    CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
  volatile u32 *wq_db;
  volatile u32 *cq_db;
  u32 cqn;
  u32 wqe_cnt;
  u32 wq_stride;
  u32 buf_sz;
  u32 queue_index;
  union
  {
    struct
    {
      u32 striding_wqe_tail;	/* Striding RQ: number of released whole WQE */
      u8 log_stride_per_wqe;	/* Striding RQ: number of strides in a single WQE */
    };

    struct
    {
      u8 *n_used_per_chain;	/* Legacy RQ: for each buffer chain, how many additional segments are needed */

      u32 *second_bufs;		/* Legacy RQ: ring of second buffers of each chain */
      u32 incomplete_tail;	/* Legacy RQ: tail index in bufs,
				   corresponds to buffer chains with recycled valid head buffer,
				   but whose other buffers are not yet recycled (due to pool exhaustion). */
      u16 n_total_additional_segs;
      u8 n_ds_per_wqe;		/* Legacy RQ: number of nonnull data segs per WQE */
    };
  };
  u8 log_wqe_sz;		/* log-size of a single WQE (in data segments) */
} rdma_rxq_t;

typedef struct
{
  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);

  /* following fields are accessed in datapath */
  clib_spinlock_t lock;

  union
  {
    struct
    {
      /* ibverb datapath. Cache of cq, sq below */
      struct ibv_cq *ibv_cq;
      struct ibv_qp *ibv_qp;
    };
    struct
    {
      /* direct verbs datapath */
      rdma_mlx5_wqe_t *dv_sq_wqes;
      volatile u32 *dv_sq_dbrec;
      volatile u64 *dv_sq_db;
      struct mlx5_cqe64 *dv_cq_cqes;
      volatile u32 *dv_cq_dbrec;
    };
  };

  u32 *bufs;			/* vlib_buffer ring buffer */
  u16 head;
  u16 tail;
  u16 dv_cq_idx;		/* monotonic CQE index (valid only for direct verbs) */
  u8 bufs_log2sz;		/* log2 vlib_buffer entries */
  u8 dv_sq_log2sz:4;		/* log2 SQ WQE entries (valid only for direct verbs) */
  u8 dv_cq_log2sz:4;		/* log2 CQ CQE entries (valid only for direct verbs) */
    STRUCT_MARK (cacheline1);

  /* WQE template (valid only for direct verbs) */
  u8 dv_wqe_tmpl[64];

  /* end of 2nd 64-bytes cacheline (or 1st 128-bytes cacheline) */
    STRUCT_MARK (cacheline2);

  /* fields below are not accessed in datapath */
  struct ibv_cq *cq;
  struct ibv_qp *qp;

} rdma_txq_t;
STATIC_ASSERT_OFFSET_OF (rdma_txq_t, cacheline1, 64);
STATIC_ASSERT_OFFSET_OF (rdma_txq_t, cacheline2, 128);

#define RDMA_TXQ_DV_INVALID_ID  0xffffffff

#define RDMA_TXQ_BUF_SZ(txq)    (1U << (txq)->bufs_log2sz)
#define RDMA_TXQ_DV_SQ_SZ(txq)  (1U << (txq)->dv_sq_log2sz)
#define RDMA_TXQ_DV_CQ_SZ(txq)  (1U << (txq)->dv_cq_log2sz)

#define RDMA_TXQ_USED_SZ(head, tail)            ((u16)((u16)(tail) - (u16)(head)))
#define RDMA_TXQ_AVAIL_SZ(txq, head, tail)      ((u16)(RDMA_TXQ_BUF_SZ (txq) - RDMA_TXQ_USED_SZ (head, tail)))
#define RDMA_RXQ_MAX_CHAIN_LOG_SZ 3	/* This should NOT be lower than 3! */
#define RDMA_RXQ_MAX_CHAIN_SZ (1U << RDMA_RXQ_MAX_CHAIN_LOG_SZ)
#define RDMA_RXQ_LEGACY_MODE_MAX_CHAIN_SZ 5
typedef struct
{
  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);

  /* following fields are accessed in datapath */
  rdma_rxq_t *rxqs;
  rdma_txq_t *txqs;
  u32 flags;
  u32 per_interface_next_index;
  u32 sw_if_index;
  u32 hw_if_index;
  u32 lkey;			/* cache of mr->lkey */
  u8 pool;			/* buffer pool index */

  /* fields below are not accessed in datapath */
  vlib_pci_device_info_t *pci;
  u8 *name;
  u8 *linux_ifname;
  mac_address_t hwaddr;
  u32 async_event_clib_file_index;
  u32 dev_instance;

  struct ibv_context *ctx;
  struct ibv_pd *pd;
  struct ibv_mr *mr;
  struct ibv_qp *rx_qp4;
  struct ibv_qp *rx_qp6;
  struct ibv_rwq_ind_table *rx_rwq_ind_tbl;
  struct ibv_flow *flow_ucast4;
  struct ibv_flow *flow_mcast4;
  struct ibv_flow *flow_ucast6;
  struct ibv_flow *flow_mcast6;

  clib_error_t *error;
} rdma_device_t;

typedef struct
{
  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
  union
  {
    u16 cqe_flags[VLIB_FRAME_SIZE];
    u16x8 cqe_flags8[VLIB_FRAME_SIZE / 8];
    u16x16 cqe_flags16[VLIB_FRAME_SIZE / 16];
  };
  union
  {
    struct
    {
      u32 current_segs[VLIB_FRAME_SIZE];
      u32 to_free_buffers[VLIB_FRAME_SIZE];
    };				/* Specific to STRIDING RQ mode */
    struct
    {
      u32 tmp_bi[VLIB_FRAME_SIZE];
      vlib_buffer_t *tmp_bufs[VLIB_FRAME_SIZE];
    };				/* Specific to LEGACY RQ mode */
  };

  vlib_buffer_t buffer_template;
} rdma_per_thread_data_t;

typedef struct
{
  rdma_per_thread_data_t *per_thread_data;
  rdma_device_t *devices;
  vlib_log_class_t log_class;
  u16 msg_id_base;
} rdma_main_t;

extern rdma_main_t rdma_main;

typedef enum
{
  RDMA_MODE_AUTO = 0,
  RDMA_MODE_IBV,
  RDMA_MODE_DV,
} rdma_mode_t;

typedef struct
{
  u8 *ifname;
  u8 *name;
  u32 rxq_size;
  u32 txq_size;
  u32 rxq_num;
  rdma_mode_t mode;
  u8 no_multi_seg;
  u8 disable_striding_rq;
  u16 max_pktlen;

  /* return */
  int rv;
  u32 sw_if_index;
  clib_error_t *error;
} rdma_create_if_args_t;

void rdma_create_if (vlib_main_t * vm, rdma_create_if_args_t * args);
void rdma_delete_if (vlib_main_t * vm, rdma_device_t * rd);

extern vlib_node_registration_t rdma_input_node;
extern vnet_device_class_t rdma_device_class;

format_function_t format_rdma_device;
format_function_t format_rdma_device_name;
format_function_t format_rdma_input_trace;
format_function_t format_rdma_rxq;
unformat_function_t unformat_rdma_create_if_args;

typedef struct
{
  u32 next_index;
  u32 hw_if_index;
  u16 cqe_flags;
} rdma_input_trace_t;

#define foreach_rdma_tx_func_error \
_(SEGMENT_SIZE_EXCEEDED, "segment size exceeded") \
_(NO_FREE_SLOTS, "no free tx slots") \
_(SUBMISSION, "tx submission errors") \
_(COMPLETION, "tx completion errors")

typedef enum
{
#define _(f,s) RDMA_TX_ERROR_##f,
  foreach_rdma_tx_func_error
#undef _
    RDMA_TX_N_ERROR,
} rdma_tx_func_error_t;

#endif /* _RDMA_H_ */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */
nt_name_length; u64 server_event_queue_address; u64 handle; } vnet_listen_args_t; typedef struct _vnet_unlisten_args_t { union { char *uri; u64 handle; /**< Session handle */ }; u32 app_index; /**< Owning application index */ u32 wrk_map_index; /**< App's local pool worker index */ } vnet_unlisten_args_t; typedef struct _vnet_connect_args { union { session_endpoint_cfg_t sep_ext; session_endpoint_t sep; char *uri; }; u32 app_index; u32 wrk_map_index; u32 api_context; session_handle_t session_handle; } vnet_connect_args_t; typedef struct _vnet_disconnect_args_t { session_handle_t handle; u32 app_index; } vnet_disconnect_args_t; typedef struct _vnet_application_add_tls_cert_args_t { u32 app_index; u8 *cert; } vnet_app_add_tls_cert_args_t; typedef struct _vnet_application_add_tls_key_args_t { u32 app_index; u8 *key; } vnet_app_add_tls_key_args_t; typedef enum crypto_engine_type_ { CRYPTO_ENGINE_NONE, CRYPTO_ENGINE_OPENSSL, CRYPTO_ENGINE_MBEDTLS, CRYPTO_ENGINE_VPP, CRYPTO_ENGINE_PICOTLS, CRYPTO_ENGINE_LAST = CRYPTO_ENGINE_PICOTLS, } crypto_engine_type_t; typedef struct _vnet_app_add_cert_key_pair_args_ { u8 *cert; u8 *key; u32 index; } vnet_app_add_cert_key_pair_args_t; typedef struct crypto_ctx_ { u32 ctx_index; /**< index in crypto context pool */ u32 n_subscribers; /**< refcount of sessions using said context */ u32 ckpair_index; /**< certificate & key */ u8 crypto_engine; void *data; /**< protocol specific data */ } crypto_context_t; /* Application attach options */ typedef enum { APP_OPTIONS_FLAGS, APP_OPTIONS_EVT_QUEUE_SIZE, APP_OPTIONS_SEGMENT_SIZE, APP_OPTIONS_ADD_SEGMENT_SIZE, APP_OPTIONS_PRIVATE_SEGMENT_COUNT, APP_OPTIONS_RX_FIFO_SIZE, APP_OPTIONS_TX_FIFO_SIZE, APP_OPTIONS_PREALLOC_FIFO_PAIRS, APP_OPTIONS_PREALLOC_FIFO_HDRS, APP_OPTIONS_NAMESPACE, APP_OPTIONS_NAMESPACE_SECRET, APP_OPTIONS_PROXY_TRANSPORT, APP_OPTIONS_ACCEPT_COOKIE, APP_OPTIONS_TLS_ENGINE, APP_OPTIONS_MAX_FIFO_SIZE, APP_OPTIONS_HIGH_WATERMARK, APP_OPTIONS_LOW_WATERMARK, APP_OPTIONS_PCT_FIRST_ALLOC, APP_OPTIONS_N_OPTIONS } app_attach_options_index_t; #define foreach_app_options_flags \ _(ACCEPT_REDIRECT, "Use FIFO with redirects") \ _(ADD_SEGMENT, "Add segment and signal app if needed") \ _(IS_BUILTIN, "Application is builtin") \ _(IS_TRANSPORT_APP, "Application is a transport proto") \ _(IS_PROXY, "Application is proxying") \ _(USE_GLOBAL_SCOPE, "App can use global session scope") \ _(USE_LOCAL_SCOPE, "App can use local session scope") \ _(EVT_MQ_USE_EVENTFD, "Use eventfds for signaling") \ typedef enum _app_options { #define _(sym, str) APP_OPTIONS_##sym, foreach_app_options_flags #undef _ } app_options_t; typedef enum _app_options_flags { #define _(sym, str) APP_OPTIONS_FLAGS_##sym = 1 << APP_OPTIONS_##sym, foreach_app_options_flags #undef _ } app_options_flags_t; #define foreach_fd_type \ _(VPP_MQ_SEGMENT, "Fd for vpp's event mq segment") \ _(MEMFD_SEGMENT, "Fd for memfd segment") \ _(MQ_EVENTFD, "Event fd used by message queue") \ _(VPP_MQ_EVENTFD, "Event fd used by vpp's message queue") \ typedef enum session_fd_type_ { #define _(sym, str) SESSION_FD_##sym, foreach_fd_type #undef _ SESSION_N_FD_TYPE } session_fd_type_t; typedef enum session_fd_flag_ { #define _(sym, str) SESSION_FD_F_##sym = 1 << SESSION_FD_##sym, foreach_fd_type #undef _ } session_fd_flag_t; int parse_uri (char *uri, session_endpoint_cfg_t * sep); int vnet_bind_uri (vnet_listen_args_t *); int vnet_unbind_uri (vnet_unlisten_args_t * a); int vnet_connect_uri (vnet_connect_args_t * a); int vnet_application_attach (vnet_app_attach_args_t * a); int vnet_application_detach (vnet_app_detach_args_t * a); int vnet_listen (vnet_listen_args_t * a); int vnet_connect (vnet_connect_args_t * a); int vnet_unlisten (vnet_unlisten_args_t * a); int vnet_disconnect_session (vnet_disconnect_args_t * a); clib_error_t *vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a); clib_error_t *vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a); int vnet_app_add_cert_key_pair (vnet_app_add_cert_key_pair_args_t * a); int vnet_app_del_cert_key_pair (u32 index); /** Ask for app cb on pair deletion */ int vnet_app_add_cert_key_interest (u32 index, u32 app_index); typedef struct app_session_transport_ { ip46_address_t rmt_ip; /**< remote ip */ ip46_address_t lcl_ip; /**< local ip */ u16 rmt_port; /**< remote port (network order) */ u16 lcl_port; /**< local port (network order) */ u8 is_ip4; /**< set if uses ip4 networking */ } app_session_transport_t; #define foreach_app_session_field \ _(svm_fifo_t, *rx_fifo) /**< rx fifo */ \ _(svm_fifo_t, *tx_fifo) /**< tx fifo */ \ _(session_type_t, session_type) /**< session type */ \ _(volatile u8, session_state) /**< session state */ \ _(u32, session_index) /**< index in owning pool */ \ _(app_session_transport_t, transport) /**< transport info */ \ _(svm_msg_q_t, *vpp_evt_q) /**< vpp event queue */ \ _(u8, is_dgram) /**< flag for dgram mode */ \ typedef struct { #define _(type, name) type name; foreach_app_session_field #undef _ } app_session_t; typedef struct session_listen_msg_ { u32 client_index; u32 context; /* Not needed but keeping it for compatibility with bapi */ u32 wrk_index; u32 vrf; u16 port; u8 proto; u8 is_ip4; ip46_address_t ip; u32 ckpair_index; u8 crypto_engine; u8 flags; } __clib_packed session_listen_msg_t; STATIC_ASSERT (sizeof (session_listen_msg_t) <= SESSION_CTRL_MSG_MAX_SIZE, "msg too large"); typedef struct session_listen_uri_msg_ { u32 client_index; u32 context; u8 uri[56]; } __clib_packed session_listen_uri_msg_t; STATIC_ASSERT (sizeof (session_listen_uri_msg_t) <= SESSION_CTRL_MSG_MAX_SIZE, "msg too large"); typedef struct session_bound_msg_ { u32 context; u64 handle; i32 retval; u8 lcl_is_ip4; u8 lcl_ip[16]; u16 lcl_port; uword rx_fifo; uword tx_fifo; uword vpp_evt_q; u32 segment_size; u8 segment_name_length; u8 segment_name[128]; } __clib_packed session_bound_msg_t; typedef struct session_unlisten_msg_ { u32 client_index; u32 context; u32 wrk_index; session_handle_t handle; } __clib_packed session_unlisten_msg_t; typedef struct session_unlisten_reply_msg_ { u32 context; u64 handle; i32 retval; } __clib_packed session_unlisten_reply_msg_t; typedef struct session_accepted_msg_ { u32 context; u64 listener_handle; u64 handle; uword server_rx_fifo; uword server_tx_fifo; u64 segment_handle; uword vpp_event_queue_address; transport_endpoint_t rmt; u8 flags; } __clib_packed session_accepted_msg_t; typedef struct session_accepted_reply_msg_ { u32 context; i32 retval; u64 handle; } __clib_packed session_accepted_reply_msg_t; typedef struct session_connect_msg_ { u32 client_index; u32 context; u32 wrk_index; u32 vrf; u16 port; u16 lcl_port; u8 proto; u8 is_ip4; ip46_address_t ip; ip46_address_t lcl_ip; u8 hostname_len; u8 hostname[16]; u64 parent_handle; u32 ckpair_index; u8 crypto_engine; u8 flags; } __clib_packed session_connect_msg_t; STATIC_ASSERT (sizeof (session_connect_msg_t) <= SESSION_CTRL_MSG_MAX_SIZE, "msg too large"); typedef struct session_connect_uri_msg_ { u32 client_index; u32 context; u8 uri[56]; } __clib_packed session_connect_uri_msg_t; STATIC_ASSERT (sizeof (session_connect_uri_msg_t) <= SESSION_CTRL_MSG_MAX_SIZE, "msg too large"); typedef struct session_connected_msg_ { u32 context; i32 retval; u64 handle; uword server_rx_fifo; uword server_tx_fifo; u64 segment_handle; uword ct_rx_fifo; uword ct_tx_fifo; u64 ct_segment_handle; uword vpp_event_queue_address; u32 segment_size; u8 segment_name_length; u8 segment_name[64]; transport_endpoint_t lcl; } __clib_packed session_connected_msg_t; typedef struct session_disconnect_msg_ { u32 client_index; u32 context; session_handle_t handle; } __clib_packed session_disconnect_msg_t; typedef struct session_disconnected_msg_ { u32 client_index; u32 context; u64 handle; } __clib_packed session_disconnected_msg_t; typedef struct session_disconnected_reply_msg_ { u32 context; i32 retval; u64 handle; } __clib_packed session_disconnected_reply_msg_t; typedef struct session_reset_msg_ { u32 client_index; u32 context; u64 handle; } __clib_packed session_reset_msg_t; typedef struct session_reset_reply_msg_ { u32 context; i32 retval; u64 handle; } __clib_packed session_reset_reply_msg_t; typedef struct session_req_worker_update_msg_ { u64 session_handle; } __clib_packed session_req_worker_update_msg_t; /* NOTE: using u16 for wrk indices because message needs to fit in 18B */ typedef struct session_worker_update_msg_ { u32 client_index; u16 wrk_index; u16 req_wrk_index; u64 handle; } __clib_packed session_worker_update_msg_t; typedef struct session_worker_update_reply_msg_ { u64 handle; uword rx_fifo; uword tx_fifo; u64 segment_handle; } __clib_packed session_worker_update_reply_msg_t; typedef struct session_app_detach_msg_ { u32 client_index; u32 context; } session_app_detach_msg_t; typedef struct app_map_another_segment_msg_ { u32 client_index; u32 context; u8 fd_flags; u32 segment_size; u8 segment_name[128]; u64 segment_handle; } session_app_add_segment_msg_t; typedef struct app_unmap_segment_msg_ { u32 client_index; u32 context; u64 segment_handle; } session_app_del_segment_msg_t; typedef struct session_migrate_msg_ { uword vpp_evt_q; session_handle_t handle; session_handle_t new_handle; u32 vpp_thread_index; } __clib_packed session_migrated_msg_t; typedef struct session_cleanup_msg_ { session_handle_t handle; u8 type; } __clib_packed session_cleanup_msg_t; typedef struct app_session_event_ { svm_msg_q_msg_t msg; session_event_t *evt; } __clib_packed app_session_evt_t; static inline void app_alloc_ctrl_evt_to_vpp (svm_msg_q_t * mq, app_session_evt_t * app_evt, u8 evt_type) { svm_msg_q_lock_and_alloc_msg_w_ring (mq, SESSION_MQ_CTRL_EVT_RING, SVM_Q_WAIT, &app_evt->msg); app_evt->evt = svm_msg_q_msg_data (mq, &app_evt->msg); clib_memset (app_evt->evt, 0, sizeof (*app_evt->evt)); app_evt->evt->event_type = evt_type; } static inline void app_send_ctrl_evt_to_vpp (svm_msg_q_t * mq, app_session_evt_t * app_evt) { svm_msg_q_add_and_unlock (mq, &app_evt->msg); } /** * Send fifo io event to vpp worker thread * * Because there may be multiple writers to one of vpp's queues, this * protects message allocation and enqueueing. * * @param mq vpp message queue * @param f fifo for which the event is sent * @param evt_type type of event * @param noblock flag to indicate is request is blocking or not * @return 0 if success, negative integer otherwise */ static inline int app_send_io_evt_to_vpp (svm_msg_q_t * mq, u32 session_index, u8 evt_type, u8 noblock) { session_event_t *evt; svm_msg_q_msg_t msg; if (noblock) { if (svm_msg_q_try_lock (mq)) return -1; if (PREDICT_FALSE (svm_msg_q_ring_is_full (mq, SESSION_MQ_IO_EVT_RING))) { svm_msg_q_unlock (mq); return -2; } msg = svm_msg_q_alloc_msg_w_ring (mq, SESSION_MQ_IO_EVT_RING); evt = (session_event_t *) svm_msg_q_msg_data (mq, &msg); evt->session_index = session_index; evt->event_type = evt_type; svm_msg_q_add_and_unlock (mq, &msg); return 0; } else { svm_msg_q_lock (mq); while (svm_msg_q_ring_is_full (mq, SESSION_MQ_IO_EVT_RING) || svm_msg_q_is_full (mq)) svm_msg_q_wait (mq); msg = svm_msg_q_alloc_msg_w_ring (mq, SESSION_MQ_IO_EVT_RING); evt = (session_event_t *) svm_msg_q_msg_data (mq, &msg); evt->session_index = session_index; evt->event_type = evt_type; svm_msg_q_add_and_unlock (mq, &msg); return 0; } } always_inline int app_send_dgram_raw (svm_fifo_t * f, app_session_transport_t * at, svm_msg_q_t * vpp_evt_q, u8 * data, u32 len, u8 evt_type, u8 do_evt, u8 noblock) { u32 max_enqueue, actual_write; session_dgram_hdr_t hdr; int rv; max_enqueue = svm_fifo_max_enqueue_prod (f); if (max_enqueue < (sizeof (session_dgram_hdr_t) + len)) return 0; max_enqueue -= sizeof (session_dgram_hdr_t); actual_write = clib_min (len, max_enqueue); hdr.data_length = actual_write; hdr.data_offset = 0; clib_memcpy_fast (&hdr.rmt_ip, &at->rmt_ip, sizeof (ip46_address_t)); hdr.is_ip4 = at->is_ip4; hdr.rmt_port = at->rmt_port; clib_memcpy_fast (&hdr.lcl_ip, &at->lcl_ip, sizeof (ip46_address_t)); hdr.lcl_port = at->lcl_port; rv = svm_fifo_enqueue (f, sizeof (hdr), (u8 *) & hdr); ASSERT (rv == sizeof (hdr)); rv = svm_fifo_enqueue (f, actual_write, data); if (do_evt) { if (rv > 0 && svm_fifo_set_event (f)) app_send_io_evt_to_vpp (vpp_evt_q, f->master_session_index, evt_type, noblock); } ASSERT (rv); return rv; } always_inline int app_send_dgram (app_session_t * s, u8 * data, u32 len, u8 noblock) { return app_send_dgram_raw (s->tx_fifo, &s->transport, s->vpp_evt_q, data, len, SESSION_IO_EVT_TX, 1 /* do_evt */ , noblock); } always_inline int app_send_stream_raw (svm_fifo_t * f, svm_msg_q_t * vpp_evt_q, u8 * data, u32 len, u8 evt_type, u8 do_evt, u8 noblock) { int rv; rv = svm_fifo_enqueue (f, len, data); if (do_evt) { if (rv > 0 && svm_fifo_set_event (f)) app_send_io_evt_to_vpp (vpp_evt_q, f->master_session_index, evt_type, noblock); } return rv; } always_inline int app_send_stream (app_session_t * s, u8 * data, u32 len, u8 noblock) { return app_send_stream_raw (s->tx_fifo, s->vpp_evt_q, data, len, SESSION_IO_EVT_TX, 1 /* do_evt */ , noblock); } always_inline int app_send (app_session_t * s, u8 * data, u32 len, u8 noblock) { if (s->is_dgram) return app_send_dgram (s, data, len, noblock); return app_send_stream (s, data, len, noblock); } always_inline int app_recv_dgram_raw (svm_fifo_t * f, u8 * buf, u32 len, app_session_transport_t * at, u8 clear_evt, u8 peek) { session_dgram_pre_hdr_t ph; u32 max_deq; int rv; max_deq = svm_fifo_max_dequeue_cons (f); if (max_deq <= sizeof (session_dgram_hdr_t)) { if (clear_evt) svm_fifo_unset_event (f); return 0; } if (clear_evt) svm_fifo_unset_event (f); svm_fifo_peek (f, 0, sizeof (ph), (u8 *) & ph); ASSERT (ph.data_length >= ph.data_offset); /* Check if we have the full dgram */ if (max_deq < (ph.data_length + SESSION_CONN_HDR_LEN) && len >= ph.data_length) return 0; svm_fifo_peek (f, sizeof (ph), sizeof (*at), (u8 *) at); len = clib_min (len, ph.data_length - ph.data_offset); rv = svm_fifo_peek (f, ph.data_offset + SESSION_CONN_HDR_LEN, len, buf); if (peek) return rv; /* Discards data that did not fit in buffer */ svm_fifo_dequeue_drop (f, ph.data_length + SESSION_CONN_HDR_LEN); return rv; } always_inline int app_recv_dgram (app_session_t * s, u8 * buf, u32 len) { return app_recv_dgram_raw (s->rx_fifo, buf, len, &s->transport, 1, 0); } always_inline int app_recv_stream_raw (svm_fifo_t * f, u8 * buf, u32 len, u8 clear_evt, u8 peek) { if (clear_evt) svm_fifo_unset_event (f); if (peek) return svm_fifo_peek (f, 0, len, buf); return svm_fifo_dequeue (f, len, buf); } always_inline int app_recv_stream (app_session_t * s, u8 * buf, u32 len) { return app_recv_stream_raw (s->rx_fifo, buf, len, 1, 0); } always_inline int app_recv (app_session_t * s, u8 * data, u32 len) { if (s->is_dgram) return app_recv_dgram (s, data, len); return app_recv_stream (s, data, len); } /* *INDENT-OFF* */ static char *session_error_str[] = { #define _(sym, str) str, foreach_session_error #undef _ }; /* *INDENT-ON* */ static inline u8 * format_session_error (u8 * s, va_list * args) { session_error_t error = va_arg (*args, session_error_t); if (-error >= 0 && -error < SESSION_N_ERRORS) s = format (s, "%s", session_error_str[-error]); else s = format (s, "invalid session err %u", -error); return s; } #endif /* __included_uri_h__ */ /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */