NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
comch_data_path_high_speed_server_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_SERVER);
49 
50 /* Sample's objects */
52  struct doca_dev *hw_dev; /* Device used in the sample */
53  struct doca_dev_rep *rep_dev; /* Device representor used in the sample */
54  struct doca_pe *pe; /* PE object used in the sample */
55  struct doca_comch_server *server; /* Server object used in the sample*/
56  struct doca_comch_connection *connection; /* Connection object used in the sample*/
57  doca_error_t server_result; /* Holds result will be updated in server callbacks */
58  bool server_finish; /* Controls whether server progress loop should be run */
59  bool data_path_test_started; /* Indicate whether we can start data_path test */
60  bool data_path_test_stopped; /* Indicate whether we can stop data_path test */
61  struct comch_data_path_objects *data_path; /* Data path objects */
62 };
63 
71 static void server_send_task_completion_callback(struct doca_comch_task_send *task,
72  union doca_data task_user_data,
73  union doca_data ctx_user_data)
74 {
75  struct comch_data_path_server_objects *sample_objects;
76 
77  (void)task_user_data;
78 
79  sample_objects = (struct comch_data_path_server_objects *)ctx_user_data.ptr;
80  sample_objects->server_result = DOCA_SUCCESS;
81  DOCA_LOG_INFO("Server task sent successfully");
83 }
84 
92 static void server_send_task_completion_err_callback(struct doca_comch_task_send *task,
93  union doca_data task_user_data,
94  union doca_data ctx_user_data)
95 {
96  struct comch_data_path_server_objects *sample_objects;
97 
98  (void)task_user_data;
99 
100  sample_objects = (struct comch_data_path_server_objects *)ctx_user_data.ptr;
102  DOCA_LOG_ERR("Message failed to send with error = %s", doca_error_get_name(sample_objects->server_result));
104  (void)doca_ctx_stop(doca_comch_server_as_ctx(sample_objects->server));
105 }
106 
115 static doca_error_t server_send_msg(struct comch_data_path_server_objects *sample_objects, const char *msg, size_t len)
116 {
118  struct doca_comch_task_send *task;
119 
121  sample_objects->connection,
122  (void *)msg,
123  len,
124  &task);
125  if (result != DOCA_SUCCESS) {
126  DOCA_LOG_ERR("Failed to allocate server task with error = %s", doca_error_get_name(result));
127  return result;
128  }
129 
131  if (result != DOCA_SUCCESS) {
132  DOCA_LOG_ERR("Failed to send server task with error = %s", doca_error_get_name(result));
134  return result;
135  }
136 
137  return DOCA_SUCCESS;
138 }
139 
148 static void server_message_recv_callback(struct doca_comch_event_msg_recv *event,
149  uint8_t *recv_buffer,
150  uint32_t msg_len,
151  struct doca_comch_connection *comch_connection)
152 {
153  union doca_data user_data;
154  struct doca_comch_server *comch_server;
155  struct comch_data_path_server_objects *sample_objects;
157 
158  (void)event;
159 
160  DOCA_LOG_INFO("Message received: '%.*s'", (int)msg_len, recv_buffer);
161 
162  comch_server = doca_comch_server_get_server_ctx(comch_connection);
163 
164  result = doca_ctx_get_user_data(doca_comch_server_as_ctx(comch_server), &user_data);
165  if (result != DOCA_SUCCESS) {
166  DOCA_LOG_ERR("Failed to get user data from ctx with error = %s", doca_error_get_name(result));
167  return;
168  }
169 
170  sample_objects = (struct comch_data_path_server_objects *)user_data.ptr;
171  sample_objects->connection = comch_connection;
172 
173  if ((msg_len == strlen(STR_START_DATA_PATH_TEST)) &&
174  (strncmp(STR_START_DATA_PATH_TEST, (char *)recv_buffer, msg_len) == 0)) {
176  if (result != DOCA_SUCCESS) {
177  DOCA_LOG_ERR("Failed to submit send task with error = %s", doca_error_get_name(result));
178  (void)doca_ctx_stop(doca_comch_server_as_ctx(sample_objects->server));
179  return;
180  }
181  sample_objects->data_path_test_started = true;
182  } else if ((msg_len == strlen(STR_STOP_DATA_PATH_TEST)) &&
183  (strncmp(STR_STOP_DATA_PATH_TEST, (char *)recv_buffer, msg_len) == 0)) {
185  if (result != DOCA_SUCCESS) {
186  DOCA_LOG_ERR("Failed to submit send task with error = %s", doca_error_get_name(result));
187  (void)doca_ctx_stop(doca_comch_server_as_ctx(sample_objects->server));
188  return;
189  }
190  sample_objects->data_path_test_stopped = true;
192  (void)doca_ctx_stop(doca_comch_server_as_ctx(sample_objects->server));
193  }
194 }
195 
203 static void server_connection_event_callback(struct doca_comch_event_connection_status_changed *event,
204  struct doca_comch_connection *comch_connection,
205  uint8_t change_success)
206 {
207  union doca_data user_data;
208  struct doca_comch_server *comch_server;
209  struct comch_data_path_server_objects *sample_objects;
211 
212  if (change_success == 0) {
213  DOCA_LOG_ERR("Failed connection received");
214  return;
215  }
216 
217  (void)event;
218 
219  comch_server = doca_comch_server_get_server_ctx(comch_connection);
220 
221  result = doca_ctx_get_user_data(doca_comch_server_as_ctx(comch_server), &user_data);
222  if (result != DOCA_SUCCESS) {
223  DOCA_LOG_ERR("Failed to get user data from ctx with error = %s", doca_error_get_name(result));
224  return;
225  }
226 
227  sample_objects = (struct comch_data_path_server_objects *)user_data.ptr;
228  sample_objects->connection = comch_connection;
229 }
230 
238 static void server_disconnection_event_callback(struct doca_comch_event_connection_status_changed *event,
239  struct doca_comch_connection *comch_connection,
240  uint8_t change_success)
241 {
242  (void)event;
243  (void)comch_connection;
244 
245  if (change_success == 0)
246  DOCA_LOG_ERR("Failed disconnection received");
247 }
248 
257 static void server_state_changed_callback(const union doca_data user_data,
258  struct doca_ctx *ctx,
259  enum doca_ctx_states prev_state,
260  enum doca_ctx_states next_state)
261 {
262  (void)ctx;
263  (void)prev_state;
264 
265  struct comch_data_path_server_objects *sample_objects = (struct comch_data_path_server_objects *)user_data.ptr;
266 
267  switch (next_state) {
268  case DOCA_CTX_STATE_IDLE:
269  DOCA_LOG_INFO("CC server context has been stopped");
270  /* We can stop progressing the PE */
271  sample_objects->server_finish = true;
272  break;
277  DOCA_LOG_ERR("CC server context entered into starting state. Unexpected transition");
278  break;
280  DOCA_LOG_INFO("CC server context is running. Waiting for clients to connect");
281  break;
287  DOCA_LOG_INFO("CC server context entered into stopping state. Terminating connections with clients");
288  break;
289  default:
290  break;
291  }
292 }
293 
301 static void new_consumer_callback(struct doca_comch_event_consumer *event,
302  struct doca_comch_connection *comch_connection,
303  uint32_t id)
304 {
305  union doca_data user_data;
306  struct doca_comch_server *comch_server;
307  struct comch_data_path_server_objects *sample_objects;
309 
310  /* This argument is not in use */
311  (void)event;
312 
313  comch_server = doca_comch_server_get_server_ctx(comch_connection);
314 
315  result = doca_ctx_get_user_data(doca_comch_server_as_ctx(comch_server), &user_data);
316  if (result != DOCA_SUCCESS) {
317  DOCA_LOG_ERR("Failed to get user data from ctx with error = %s", doca_error_get_name(result));
318  return;
319  }
320 
321  sample_objects = (struct comch_data_path_server_objects *)(user_data.ptr);
322  sample_objects->data_path->remote_consumer_id = id;
323 
324  DOCA_LOG_INFO("Got a new remote consumer with ID = [%d]", id);
325 }
326 
334 void expired_consumer_callback(struct doca_comch_event_consumer *event,
335  struct doca_comch_connection *comch_connection,
336  uint32_t id)
337 {
338  /* These arguments are not in use */
339  (void)event;
340  (void)comch_connection;
341  (void)id;
342 }
343 
350 {
352  struct timespec ts = {
353  .tv_sec = 0,
354  .tv_nsec = SLEEP_IN_NANOS,
355  };
356 
357  if (sample_objects == NULL)
358  return;
359 
360  /* Exchange message with server to make connection is reliable */
361  while (sample_objects->data_path_test_stopped == false) {
362  if (doca_pe_progress(sample_objects->pe) == 0)
363  nanosleep(&ts, &ts);
364  }
365  while (sample_objects->server_finish == false) {
366  if (doca_pe_progress(sample_objects->pe) == 0)
367  nanosleep(&ts, &ts);
368  }
369 
370  clean_comch_ctrl_path_server(sample_objects->server, sample_objects->pe);
371  sample_objects->server = NULL;
372  sample_objects->pe = NULL;
373 
374  if (sample_objects->rep_dev != NULL) {
375  result = doca_dev_rep_close(sample_objects->rep_dev);
376  if (result != DOCA_SUCCESS)
377  DOCA_LOG_ERR("Failed to close rep device properly with error = %s",
379 
380  sample_objects->rep_dev = NULL;
381  }
382 
383  if (sample_objects->hw_dev != NULL) {
384  result = doca_dev_close(sample_objects->hw_dev);
385  if (result != DOCA_SUCCESS)
386  DOCA_LOG_ERR("Failed to close hw device properly with error = %s", doca_error_get_name(result));
387 
388  sample_objects->hw_dev = NULL;
389  }
390 }
391 
402 static doca_error_t init_comch_data_path_server_objects(const char *server_name,
403  const char *dev_pci_addr,
404  const char *dev_rep_pci_addr,
405  const char *text,
406  struct comch_data_path_server_objects *sample_objects)
407 {
409  struct comch_ctrl_path_server_cb_config server_cb_cfg = {
411  .send_task_comp_err_cb = server_send_task_completion_err_callback,
412  .msg_recv_cb = server_message_recv_callback,
413  .server_connection_event_cb = server_connection_event_callback,
414  .server_disconnection_event_cb = server_disconnection_event_callback,
415  .data_path_mode = true,
416  .new_consumer_cb = new_consumer_callback,
417  .expired_consumer_cb = expired_consumer_callback,
418  .ctx_user_data = sample_objects,
419  .ctx_state_changed_cb = server_state_changed_callback};
420  struct timespec ts = {
421  .tv_sec = 0,
422  .tv_nsec = SLEEP_IN_NANOS,
423  };
424 
425  sample_objects->data_path->text = text;
426 
427  /* Open DOCA device according to the given PCI address */
428  result = open_doca_device_with_pci(dev_pci_addr, NULL, &(sample_objects->hw_dev));
429  if (result != DOCA_SUCCESS) {
430  DOCA_LOG_ERR("Failed to open DOCA device based on PCI address");
431  return result;
432  }
433  sample_objects->data_path->hw_dev = sample_objects->hw_dev;
434 
435  /* Open DOCA device representor according to the given PCI address */
436  result = open_doca_device_rep_with_pci(sample_objects->hw_dev,
438  dev_rep_pci_addr,
439  &(sample_objects->rep_dev));
440  if (result != DOCA_SUCCESS) {
441  DOCA_LOG_ERR("Failed to open DOCA device representor based on PCI address");
442  goto close_hw_dev;
443  }
444 
445  /* Init CC server */
446  result = init_comch_ctrl_path_server(server_name,
447  sample_objects->hw_dev,
448  sample_objects->rep_dev,
449  &server_cb_cfg,
450  &(sample_objects->server),
451  &(sample_objects->pe));
452  if (result != DOCA_SUCCESS) {
453  DOCA_LOG_ERR("Fail init cc server with error = %s", doca_error_get_name(result));
454  goto close_rep_dev;
455  }
456  sample_objects->data_path->pe = sample_objects->pe;
457 
458  /* Wait start_data_path_test msg from client, so that server can get the connection information */
459  while (sample_objects->connection == NULL) {
460  if (doca_pe_progress(sample_objects->pe) == 0)
461  nanosleep(&ts, &ts);
462  }
463  sample_objects->data_path->connection = sample_objects->connection;
464 
465  /* Exchange message with client to make connection is reliable */
466  while (sample_objects->data_path_test_started == false) {
467  if (doca_pe_progress(sample_objects->pe) == 0)
468  nanosleep(&ts, &ts);
469  }
470 
471  return DOCA_SUCCESS;
472 
473 close_rep_dev:
474  (void)doca_dev_rep_close(sample_objects->rep_dev);
475 close_hw_dev:
476  (void)doca_dev_close(sample_objects->hw_dev);
477  return result;
478 }
479 
480 /*
481  * Stop server and relay instruction to client
482  *
483  * @sample_objects [in]: data path configuration for server
484  */
485 static void handle_error_state(struct comch_data_path_server_objects *sample_objects)
486 {
488 
490  if (result != DOCA_SUCCESS)
491  DOCA_LOG_ERR("Failed to submit send task with error = %s", doca_error_get_name(result));
492 
493  sample_objects->data_path_test_stopped = true;
494  (void)doca_ctx_stop(doca_comch_server_as_ctx(sample_objects->server));
495 }
496 
507  const char *dev_pci_addr,
508  const char *rep_pci_addr,
509  const char *text)
510 {
512  struct comch_data_path_server_objects sample_objects = {0};
513  struct comch_data_path_objects data_path = {0};
514 
515  sample_objects.data_path = &data_path;
516 
517  result = init_comch_data_path_server_objects(server_name, dev_pci_addr, rep_pci_addr, text, &sample_objects);
518  if (result != DOCA_SUCCESS) {
519  DOCA_LOG_ERR("Failed to initialize sample with error = %s", doca_error_get_name(result));
520  return result;
521  }
522 
523  result = comch_data_path_recv_msg(&data_path);
524  if (result != DOCA_SUCCESS) {
525  /* Client handles tear down - in case of server error it must be started from server */
526  handle_error_state(&sample_objects);
527  goto exit;
528  }
529 
530  result = comch_data_path_send_msg(&data_path);
531  if (result != DOCA_SUCCESS) {
532  handle_error_state(&sample_objects);
533  goto exit;
534  }
535 
536 exit:
537  clean_comch_data_path_server_objects(&sample_objects);
538 
539  return result != DOCA_SUCCESS ? result : sample_objects.server_result;
540 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
void clean_comch_ctrl_path_server(struct doca_comch_server *server, struct doca_pe *pe)
doca_error_t init_comch_ctrl_path_server(const char *server_name, struct doca_dev *hw_dev, struct doca_dev_rep *rep_dev, struct comch_ctrl_path_server_cb_config *cb_cfg, struct doca_comch_server **server, struct doca_pe **pe)
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
static void server_send_task_completion_callback(struct doca_comch_task_send *task, union doca_data task_user_data, union doca_data ctx_user_data)
static void server_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 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)
DOCA_LOG_REGISTER(COMCH_DATA_PATH_HIGH_SPEED_SERVER)
static void handle_error_state(struct comch_data_path_server_objects *sample_objects)
static void server_connection_event_callback(struct doca_comch_event_connection_status_changed *event, struct doca_comch_connection *comch_connection, uint8_t change_success)
static void clean_comch_data_path_server_objects(struct comch_data_path_server_objects *sample_objects)
static void server_message_recv_callback(struct doca_comch_event_msg_recv *event, uint8_t *recv_buffer, uint32_t msg_len, struct doca_comch_connection *comch_connection)
doca_error_t start_comch_data_path_server_sample(const char *server_name, const char *dev_pci_addr, const char *rep_pci_addr, const char *text)
static void server_disconnection_event_callback(struct doca_comch_event_connection_status_changed *event, struct doca_comch_connection *comch_connection, uint8_t change_success)
static doca_error_t init_comch_data_path_server_objects(const char *server_name, const char *dev_pci_addr, const char *dev_rep_pci_addr, const char *text, struct comch_data_path_server_objects *sample_objects)
static void server_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 doca_error_t server_send_msg(struct comch_data_path_server_objects *sample_objects, const char *msg, size_t len)
#define SLEEP_IN_NANOS
Definition: comch_utils.c:40
doca_error_t open_doca_device_rep_with_pci(struct doca_dev *local, enum doca_devinfo_rep_filter filter, const char *pci_addr, struct doca_dev_rep **retval)
Definition: common.c:267
static doca_error_t open_doca_device_with_pci(const char *pcie_value, struct doca_dev **retval)
Definition: device.c:43
uint64_t len
if(bitoffset % 64+bitlength > 64) result|
DOCA_STABLE struct doca_comch_server * doca_comch_server_get_server_ctx(const struct doca_comch_connection *connection)
DOCA_STABLE struct doca_task * doca_comch_task_send_as_task(struct doca_comch_task_send *task)
DOCA_STABLE doca_error_t doca_comch_server_task_send_alloc_init(struct doca_comch_server *comch_server, struct doca_comch_connection *peer, const void *msg, uint32_t len, struct doca_comch_task_send **task)
DOCA_STABLE struct doca_ctx * doca_comch_server_as_ctx(struct doca_comch_server *comch_server)
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_rep_close(struct doca_dev_rep *dev)
Destroy allocated representor device instance.
DOCA_STABLE doca_error_t doca_dev_close(struct doca_dev *dev)
Destroy allocated local device instance.
@ DOCA_DEVINFO_REP_FILTER_NET
Definition: doca_dev.h:67
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_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