NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
comch_data_path_high_speed_client_sample.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2023 NVIDIA CORPORATION AND AFFILIATES. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are permitted
5  * provided that the following conditions are met:
6  * * Redistributions of source code must retain the above copyright notice, this list of
7  * conditions and the following disclaimer.
8  * * Redistributions in binary form must reproduce the above copyright notice, this list of
9  * conditions and the following disclaimer in the documentation and/or other materials
10  * provided with the distribution.
11  * * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
12  * to endorse or promote products derived from this software without specific prior written
13  * permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
21  * STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  */
25 
26 #include <signal.h>
27 #include <stdbool.h>
28 #include <string.h>
29 #include <time.h>
30 #include <unistd.h>
31 
32 #include <doca_buf.h>
33 #include <doca_buf_inventory.h>
34 #include <doca_comch.h>
35 #include <doca_comch_consumer.h>
36 #include <doca_comch_producer.h>
37 #include <doca_ctx.h>
38 #include <doca_dev.h>
39 #include <doca_error.h>
40 #include <doca_log.h>
41 #include <doca_mmap.h>
42 #include <doca_pe.h>
43 
44 #include "comch_ctrl_path_common.h"
46 #include "common.h"
47 
48 DOCA_LOG_REGISTER(COMCH_DATA_PATH_HIGH_SPEED_CLIENT);
49 
50 /* Sample's objects */
52  struct doca_dev *hw_dev; /* Device used in the sample */
53  struct doca_pe *pe; /* PE object used in the sample */
54  struct doca_comch_client *client; /* Client object used in the sample */
55  struct doca_comch_connection *connection; /* CC connection object used in the sample */
56  doca_error_t client_result; /* Holds result will be updated in client callbacks */
57  bool client_finish; /* Controls whether client progress loop should be run */
58  bool data_path_test_started; /* Indicate whether we can start data_path test */
59  bool data_path_test_stopped; /* Indicate whether we can stop data_path test */
60  struct comch_data_path_objects *data_path; /* Data path objects */
61 };
62 
70 static void client_send_task_completion_callback(struct doca_comch_task_send *task,
71  union doca_data task_user_data,
72  union doca_data ctx_user_data)
73 {
74  struct comch_data_path_client_objects *sample_objects;
75 
76  (void)task_user_data;
77 
78  sample_objects = (struct comch_data_path_client_objects *)(ctx_user_data.ptr);
79  sample_objects->client_result = DOCA_SUCCESS;
80  DOCA_LOG_INFO("Client task sent successfully");
82 }
83 
91 static void client_send_task_completion_err_callback(struct doca_comch_task_send *task,
92  union doca_data task_user_data,
93  union doca_data ctx_user_data)
94 {
95  struct comch_data_path_client_objects *sample_objects;
96 
97  (void)task_user_data;
98 
99  sample_objects = (struct comch_data_path_client_objects *)(ctx_user_data.ptr);
101  DOCA_LOG_ERR("Message failed to send with error = %s", doca_error_get_name(sample_objects->client_result));
103  (void)doca_ctx_stop(doca_comch_client_as_ctx(sample_objects->client));
104 }
105 
114 static void client_message_recv_callback(struct doca_comch_event_msg_recv *event,
115  uint8_t *recv_buffer,
116  uint32_t msg_len,
117  struct doca_comch_connection *comch_connection)
118 {
119  union doca_data user_data;
120  struct doca_comch_client *comch_client;
121  struct comch_data_path_client_objects *sample_objects;
123 
124  (void)event;
125 
126  DOCA_LOG_INFO("Message received: '%.*s'", (int)msg_len, recv_buffer);
127 
128  comch_client = doca_comch_client_get_client_ctx(comch_connection);
129 
130  result = doca_ctx_get_user_data(doca_comch_client_as_ctx(comch_client), &user_data);
131  if (result != DOCA_SUCCESS) {
132  DOCA_LOG_ERR("Failed to get user data from ctx with error = %s", doca_error_get_name(result));
133  return;
134  }
135 
136  sample_objects = (struct comch_data_path_client_objects *)(user_data.ptr);
137 
138  if ((msg_len == strlen(STR_START_DATA_PATH_TEST)) &&
139  (strncmp(STR_START_DATA_PATH_TEST, (char *)recv_buffer, msg_len) == 0))
140  sample_objects->data_path_test_started = true;
141  else if ((msg_len == strlen(STR_STOP_DATA_PATH_TEST)) &&
142  (strncmp(STR_STOP_DATA_PATH_TEST, (char *)recv_buffer, msg_len) == 0)) {
143  sample_objects->data_path_test_stopped = true;
145  (void)doca_ctx_stop(doca_comch_client_as_ctx(sample_objects->client));
146  }
147 }
148 
157 static doca_error_t client_send_msg(struct comch_data_path_client_objects *sample_objects, const char *msg, size_t len)
158 {
160  struct doca_comch_task_send *task;
161 
163  sample_objects->connection,
164  (void *)msg,
165  len,
166  &task);
167  if (result != DOCA_SUCCESS) {
168  DOCA_LOG_ERR("Failed to allocate client task with error = %s", doca_error_get_name(result));
169  return result;
170  }
171 
173  if (result != DOCA_SUCCESS) {
174  DOCA_LOG_ERR("Failed to send client task with error = %s", doca_error_get_name(result));
176  return result;
177  }
178 
179  return DOCA_SUCCESS;
180 }
181 
190 static void client_state_changed_callback(const union doca_data user_data,
191  struct doca_ctx *ctx,
192  enum doca_ctx_states prev_state,
193  enum doca_ctx_states next_state)
194 {
195  (void)ctx;
196  (void)prev_state;
197 
198  struct comch_data_path_client_objects *sample_objects = (struct comch_data_path_client_objects *)user_data.ptr;
199 
200  switch (next_state) {
201  case DOCA_CTX_STATE_IDLE:
202  DOCA_LOG_INFO("CC client context has been stopped");
203  /* We can stop progressing the PE */
204  sample_objects->client_finish = true;
205  break;
210  DOCA_LOG_INFO("CC client context entered into starting state. Waiting for connection establishment");
211  break;
213  /* Get a connection channel */
214  if (sample_objects->connection == NULL) {
215  sample_objects->client_result =
216  doca_comch_client_get_connection(sample_objects->client, &sample_objects->connection);
217  if (sample_objects->client_result != DOCA_SUCCESS) {
218  DOCA_LOG_ERR("Failed to get connection from cc client with error = %s",
219  doca_error_get_name(sample_objects->client_result));
220  (void)doca_ctx_stop(doca_comch_client_as_ctx(sample_objects->client));
221  }
222  DOCA_LOG_INFO("CC client context is running. Get a connection from server");
223  }
224  break;
230  DOCA_LOG_INFO("CC client context entered into stopping state. Waiting for connection termination");
231  break;
232  default:
233  break;
234  }
235 }
236 
244 static void new_consumer_callback(struct doca_comch_event_consumer *event,
245  struct doca_comch_connection *comch_connection,
246  uint32_t id)
247 {
248  union doca_data user_data;
249  struct doca_comch_client *comch_client;
250  struct comch_data_path_client_objects *sample_objects;
252 
253  (void)event;
254 
255  comch_client = doca_comch_client_get_client_ctx(comch_connection);
256 
257  result = doca_ctx_get_user_data(doca_comch_client_as_ctx(comch_client), &user_data);
258  if (result != DOCA_SUCCESS) {
259  DOCA_LOG_ERR("Failed to get user data from ctx with error = %s", doca_error_get_name(result));
260  return;
261  }
262 
263  sample_objects = (struct comch_data_path_client_objects *)(user_data.ptr);
264  sample_objects->data_path->remote_consumer_id = id;
265 
266  DOCA_LOG_INFO("Got a new remote consumer with ID = [%d]", id);
267 }
268 
276 void expired_consumer_callback(struct doca_comch_event_consumer *event,
277  struct doca_comch_connection *comch_connection,
278  uint32_t id)
279 {
280  /* These arguments are not in use */
281  (void)event;
282  (void)comch_connection;
283  (void)id;
284 }
285 
292 {
294  struct timespec ts = {
295  .tv_sec = 0,
296  .tv_nsec = SLEEP_IN_NANOS,
297  };
298 
299  if (sample_objects == NULL)
300  return;
301 
302  /* Verify client is not already stopped due to a server error */
303  if (sample_objects->client_finish == false) {
304  /* Exchange message with server to make connection is reliable */
305  sample_objects->client_result =
307  if (sample_objects->client_result != DOCA_SUCCESS) {
308  DOCA_LOG_ERR("Failed to submit send task with error = %s",
309  doca_error_get_name(sample_objects->client_result));
310  (void)doca_ctx_stop(doca_comch_client_as_ctx(sample_objects->client));
311  }
312  while (sample_objects->data_path_test_stopped == false) {
313  if (doca_pe_progress(sample_objects->pe) == 0)
314  nanosleep(&ts, &ts);
315  }
316  while (sample_objects->client_finish == false) {
317  if (doca_pe_progress(sample_objects->pe) == 0)
318  nanosleep(&ts, &ts);
319  }
320  }
321 
322  clean_comch_ctrl_path_client(sample_objects->client, sample_objects->pe);
323  sample_objects->client = NULL;
324  sample_objects->pe = NULL;
325 
326  if (sample_objects->hw_dev != NULL) {
327  result = doca_dev_close(sample_objects->hw_dev);
328  if (result != DOCA_SUCCESS)
329  DOCA_LOG_ERR("Failed to close hw device properly with error = %s", doca_error_get_name(result));
330 
331  sample_objects->hw_dev = NULL;
332  }
333 }
334 
344 static doca_error_t init_comch_data_path_client_objects(const char *server_name,
345  const char *dev_pci_addr,
346  const char *text,
347  struct comch_data_path_client_objects *sample_objects)
348 {
350  struct comch_ctrl_path_client_cb_config client_cb_cfg = {
352  .send_task_comp_err_cb = client_send_task_completion_err_callback,
353  .msg_recv_cb = client_message_recv_callback,
354  .data_path_mode = true,
355  .new_consumer_cb = new_consumer_callback,
356  .expired_consumer_cb = expired_consumer_callback,
357  .ctx_user_data = sample_objects,
358  .ctx_state_changed_cb = client_state_changed_callback};
359  struct timespec ts = {
360  .tv_sec = 0,
361  .tv_nsec = SLEEP_IN_NANOS,
362  };
363 
364  sample_objects->data_path->text = text;
365 
366  /* Open DOCA device according to the given PCI address */
367  result = open_doca_device_with_pci(dev_pci_addr, NULL, &(sample_objects->hw_dev));
368  if (result != DOCA_SUCCESS) {
369  DOCA_LOG_ERR("Failed to open Comm Channel DOCA device based on PCI address");
370  return result;
371  }
372  sample_objects->data_path->hw_dev = sample_objects->hw_dev;
373 
374  /* Init CC client */
375  result = init_comch_ctrl_path_client(server_name,
376  sample_objects->hw_dev,
377  &client_cb_cfg,
378  &(sample_objects->client),
379  &(sample_objects->pe));
380  if (result != DOCA_SUCCESS) {
381  DOCA_LOG_ERR("Failed to init cc client with error = %s", doca_error_get_name(result));
382  goto close_hw_dev;
383  }
384  sample_objects->data_path->pe = sample_objects->pe;
385 
386  /* Wait connection establishment */
387  while (sample_objects->connection == NULL && sample_objects->client_finish == false) {
388  if (doca_pe_progress(sample_objects->pe) == 0)
389  nanosleep(&ts, &ts);
390  }
391 
392  if (sample_objects->client_finish == true) {
393  clean_comch_data_path_client_objects(sample_objects);
395  }
396 
397  sample_objects->data_path->connection = sample_objects->connection;
398 
399  /* Exchange message with server, to make connection is reliable */
400  sample_objects->client_result =
402  if (sample_objects->client_result != DOCA_SUCCESS) {
403  DOCA_LOG_ERR("Failed to submit send task with error = %s",
404  doca_error_get_name(sample_objects->client_result));
405  (void)doca_ctx_stop(doca_comch_client_as_ctx(sample_objects->client));
406  goto destroy_client;
407  }
408  while (sample_objects->data_path_test_started == false) {
409  if (doca_pe_progress(sample_objects->pe) == 0)
410  nanosleep(&ts, &ts);
411  }
412 
413  return DOCA_SUCCESS;
414 
415 destroy_client:
416  clean_comch_ctrl_path_client(sample_objects->client, sample_objects->pe);
417 close_hw_dev:
418  (void)doca_dev_close(sample_objects->hw_dev);
419  return result;
420 }
421 
430 doca_error_t start_comch_data_path_client_sample(const char *server_name, const char *dev_pci_addr, const char *text)
431 {
433  struct comch_data_path_client_objects sample_objects = {0};
434  struct comch_data_path_objects data_path = {0};
435 
436  sample_objects.data_path = &data_path;
437 
438  result = init_comch_data_path_client_objects(server_name, dev_pci_addr, text, &sample_objects);
439  if (result != DOCA_SUCCESS) {
440  DOCA_LOG_ERR("Failed to initialize sample with error = %s", doca_error_get_name(result));
441  return result;
442  }
443 
444  result = comch_data_path_send_msg(&data_path);
445  if (result != DOCA_SUCCESS)
446  goto exit;
447 
448  result = comch_data_path_recv_msg(&data_path);
449  if (result != DOCA_SUCCESS)
450  goto exit;
451 
452 exit:
453  clean_comch_data_path_client_objects(&sample_objects);
454 
455  return result != DOCA_SUCCESS ? result : sample_objects.client_result;
456 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
doca_error_t init_comch_ctrl_path_client(const char *server_name, struct doca_dev *hw_dev, struct comch_ctrl_path_client_cb_config *cb_cfg, struct doca_comch_client **client, struct doca_pe **pe)
void clean_comch_ctrl_path_client(struct doca_comch_client *client, struct doca_pe *pe)
DOCA_LOG_REGISTER(COMCH_DATA_PATH_HIGH_SPEED_CLIENT)
static void client_state_changed_callback(const union doca_data user_data, struct doca_ctx *ctx, enum doca_ctx_states prev_state, enum doca_ctx_states next_state)
static void new_consumer_callback(struct doca_comch_event_consumer *event, struct doca_comch_connection *comch_connection, uint32_t id)
void expired_consumer_callback(struct doca_comch_event_consumer *event, struct doca_comch_connection *comch_connection, uint32_t id)
static void client_send_task_completion_err_callback(struct doca_comch_task_send *task, union doca_data task_user_data, union doca_data ctx_user_data)
static void clean_comch_data_path_client_objects(struct comch_data_path_client_objects *sample_objects)
static doca_error_t client_send_msg(struct comch_data_path_client_objects *sample_objects, const char *msg, size_t len)
static void client_message_recv_callback(struct doca_comch_event_msg_recv *event, uint8_t *recv_buffer, uint32_t msg_len, struct doca_comch_connection *comch_connection)
static void client_send_task_completion_callback(struct doca_comch_task_send *task, union doca_data task_user_data, union doca_data ctx_user_data)
doca_error_t start_comch_data_path_client_sample(const char *server_name, const char *dev_pci_addr, const char *text)
static doca_error_t init_comch_data_path_client_objects(const char *server_name, const char *dev_pci_addr, const char *text, struct comch_data_path_client_objects *sample_objects)
doca_error_t comch_data_path_send_msg(struct comch_data_path_objects *data_path)
doca_error_t comch_data_path_recv_msg(struct comch_data_path_objects *data_path)
#define STR_STOP_DATA_PATH_TEST
#define INVALID_CONSUMER_ID
#define STR_START_DATA_PATH_TEST
#define SLEEP_IN_NANOS
Definition: comch_utils.c:40
static doca_error_t open_doca_device_with_pci(const char *pcie_value, struct doca_dev **retval)
Definition: device.c:43
uint64_t len
DOCA_STABLE doca_error_t doca_comch_client_get_connection(const struct doca_comch_client *comch_client, struct doca_comch_connection **connection)
DOCA_STABLE struct doca_ctx * doca_comch_client_as_ctx(struct doca_comch_client *comch_client)
DOCA_STABLE doca_error_t doca_comch_client_task_send_alloc_init(struct doca_comch_client *comch_client, struct doca_comch_connection *peer, const void *msg, uint32_t len, struct doca_comch_task_send **task)
DOCA_STABLE struct doca_task * doca_comch_task_send_as_task(struct doca_comch_task_send *task)
DOCA_STABLE struct doca_comch_client * doca_comch_client_get_client_ctx(const struct doca_comch_connection *connection)
DOCA_STABLE doca_error_t doca_ctx_stop(struct doca_ctx *ctx)
Stops the context allowing reconfiguration.
doca_ctx_states
This enum defines the states of a context.
Definition: doca_ctx.h:83
DOCA_STABLE doca_error_t doca_ctx_get_user_data(const struct doca_ctx *ctx, union doca_data *user_data)
get user data from context
@ DOCA_CTX_STATE_STARTING
Definition: doca_ctx.h:93
@ DOCA_CTX_STATE_STOPPING
Definition: doca_ctx.h:106
@ DOCA_CTX_STATE_IDLE
Definition: doca_ctx.h:88
@ DOCA_CTX_STATE_RUNNING
Definition: doca_ctx.h:98
DOCA_STABLE doca_error_t doca_dev_close(struct doca_dev *dev)
Destroy allocated local device instance.
enum doca_error doca_error_t
DOCA API return codes.
DOCA_STABLE const char * doca_error_get_name(doca_error_t error)
Returns the string representation of an error code name.
@ DOCA_ERROR_INITIALIZATION
Definition: doca_error.h:46
@ DOCA_SUCCESS
Definition: doca_error.h:38
#define DOCA_LOG_ERR(format,...)
Generates an ERROR application log message.
Definition: doca_log.h:466
#define DOCA_LOG_INFO(format,...)
Generates an INFO application log message.
Definition: doca_log.h:486
DOCA_STABLE doca_error_t doca_task_get_status(const struct doca_task *task)
Get task status.
DOCA_STABLE doca_error_t doca_task_submit(struct doca_task *task)
Submit a task to a progress engine.
DOCA_STABLE uint8_t doca_pe_progress(struct doca_pe *pe)
Run the progress engine.
DOCA_STABLE void doca_task_free(struct doca_task *task)
Free a task back to where it was allocated from.
doca_comch_task_send_completion_cb_t send_task_comp_cb
struct doca_comch_connection * connection
Convenience type for representing opaque data.
Definition: doca_types.h:56
void * ptr
Definition: doca_types.h:57
struct upf_accel_ctx * ctx