NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
comch_ctrl_path_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_comch.h>
33 #include <doca_ctx.h>
34 #include <doca_dev.h>
35 #include <doca_error.h>
36 #include <doca_log.h>
37 #include <doca_pe.h>
38 
39 #include "comch_ctrl_path_common.h"
40 #include "common.h"
41 
42 DOCA_LOG_REGISTER(COMCH_CTRL_PATH_SERVER);
43 
44 /* Sample's objects */
46  struct doca_dev *hw_dev; /* Device used in the sample */
47  struct doca_dev_rep *rep_dev; /* Device representor used in the sample */
48  struct doca_pe *pe; /* PE object used in the sample */
49  struct doca_comch_server *server; /* Server object used in the sample */
50  struct doca_comch_connection *connection; /* Connection object used in the sample */
51  uint32_t num_connected_clients; /* Number of currently connected clients */
52  const char *text; /* Message to be sent to client */
53  uint32_t text_len; /* Length of message to be sent */
54  doca_error_t result; /* Holds result will be updated in callbacks */
55  bool finish; /* Controls whether progress loop should be run */
56 };
57 
65 static void send_task_completion_callback(struct doca_comch_task_send *task,
66  union doca_data task_user_data,
67  union doca_data ctx_user_data)
68 {
69  struct comch_ctrl_path_server_objects *sample_objects =
70  (struct comch_ctrl_path_server_objects *)ctx_user_data.ptr;
71 
72  /* This argument is not in use */
73  (void)task_user_data;
74 
75  sample_objects->result = DOCA_SUCCESS;
76  DOCA_LOG_INFO("Task sent successfully");
77 
79  (void)doca_ctx_stop(doca_comch_server_as_ctx(sample_objects->server));
80 }
81 
89 static void send_task_completion_err_callback(struct doca_comch_task_send *task,
90  union doca_data task_user_data,
91  union doca_data ctx_user_data)
92 {
93  struct comch_ctrl_path_server_objects *sample_objects =
94  (struct comch_ctrl_path_server_objects *)ctx_user_data.ptr;
95 
96  /* This argument is not in use */
97  (void)task_user_data;
98 
100  DOCA_LOG_ERR("Message failed to send with error = %s", doca_error_get_name(sample_objects->result));
101 
103  (void)doca_ctx_stop(doca_comch_server_as_ctx(sample_objects->server));
104 }
105 
113 static void server_connection_event_callback(struct doca_comch_event_connection_status_changed *event,
114  struct doca_comch_connection *comch_conn,
115  uint8_t change_success)
116 {
117  union doca_data user_data;
118  struct doca_comch_server *comch_server;
119  struct comch_ctrl_path_server_objects *sample_objects;
121 
122  /* This argument is not in use */
123  (void)event;
124 
125  comch_server = doca_comch_server_get_server_ctx(comch_conn);
126 
127  result = doca_ctx_get_user_data(doca_comch_server_as_ctx(comch_server), &user_data);
128  if (result != DOCA_SUCCESS) {
129  DOCA_LOG_ERR("Failed to get user data from ctx with error = %s", doca_error_get_name(result));
130  return;
131  }
132 
133  /* Update number of connected clients in case of successful connection */
134  sample_objects = (struct comch_ctrl_path_server_objects *)user_data.ptr;
135  if (!change_success) {
136  DOCA_LOG_ERR("Failed connection received");
137  return;
138  }
139 
140  sample_objects->num_connected_clients++;
141  DOCA_LOG_INFO("New client connected to server");
142 }
143 
151 static void server_disconnection_event_callback(struct doca_comch_event_connection_status_changed *event,
152  struct doca_comch_connection *comch_conn,
153  uint8_t change_success)
154 {
155  union doca_data user_data;
156  struct doca_comch_server *comch_server;
157  struct comch_ctrl_path_server_objects *sample_objects;
159 
160  /* These arguments are not in use */
161  (void)event;
162  (void)change_success;
163 
164  comch_server = doca_comch_server_get_server_ctx(comch_conn);
165 
166  result = doca_ctx_get_user_data(doca_comch_server_as_ctx(comch_server), &user_data);
167  if (result != DOCA_SUCCESS) {
168  DOCA_LOG_ERR("Failed to get user data from ctx with error = %s", doca_error_get_name(result));
169  return;
170  }
171 
172  /* Update number of connected clients in case of disconnection, Currently disconnection only happens if server
173  * sent a message to a client which already stopped.
174  */
175  sample_objects = (struct comch_ctrl_path_server_objects *)user_data.ptr;
176  sample_objects->num_connected_clients--;
177  DOCA_LOG_INFO("A client was disconnected from server");
178 }
179 
189 {
190  struct doca_comch_task_send *task;
191  struct doca_task *task_obj;
192  union doca_data user_data;
194  const char *text = sample_objects->text;
195  size_t msg_len = sample_objects->text_len;
196 
197  /* This function will only be called after a message was received, so connection should be available */
198  if (sample_objects->connection == NULL) {
199  DOCA_LOG_ERR("Failed to send response: no connection available");
201  }
202 
204  sample_objects->connection,
205  text,
206  msg_len,
207  &task);
208  if (result != DOCA_SUCCESS) {
209  DOCA_LOG_ERR("Failed to allocate task in server with error = %s", doca_error_get_name(result));
210  return result;
211  }
212 
213  task_obj = doca_comch_task_send_as_task(task);
214 
215  user_data.ptr = (void *)sample_objects;
216  doca_task_set_user_data(task_obj, user_data);
217 
218  result = doca_task_submit(task_obj);
219  if (result != DOCA_SUCCESS) {
220  DOCA_LOG_ERR("Failed submitting send task with error = %s", doca_error_get_name(result));
221  doca_task_free(task_obj);
222  return result;
223  }
224 
225  return DOCA_SUCCESS;
226 }
227 
236 static void message_recv_callback(struct doca_comch_event_msg_recv *event,
237  uint8_t *recv_buffer,
238  uint32_t msg_len,
239  struct doca_comch_connection *comch_connection)
240 {
241  union doca_data user_data;
242  struct doca_comch_server *comch_server;
243  struct comch_ctrl_path_server_objects *sample_objects;
245 
246  /* This argument is not in use */
247  (void)event;
248 
249  comch_server = doca_comch_server_get_server_ctx(comch_connection);
250 
251  result = doca_ctx_get_user_data(doca_comch_server_as_ctx(comch_server), &user_data);
252  if (result != DOCA_SUCCESS) {
253  DOCA_LOG_ERR("Failed to get user data from ctx with error = %s", doca_error_get_name(result));
254  return;
255  }
256 
257  /* Save the connection that the ping was sent over for sending the response */
258  sample_objects = (struct comch_ctrl_path_server_objects *)user_data.ptr;
259  sample_objects->connection = comch_connection;
260 
261  DOCA_LOG_INFO("Message received: '%.*s'", (int)msg_len, recv_buffer);
262  sample_objects->result = server_send_pong(sample_objects);
263  if (sample_objects->result != DOCA_SUCCESS) {
264  DOCA_LOG_ERR("Failed to submit send task with error = %s", doca_error_get_name(sample_objects->result));
265  (void)doca_ctx_stop(doca_comch_server_as_ctx(comch_server));
266  }
267 }
268 
275 {
277 
278  if (sample_objects->server != NULL) {
279  result = doca_comch_server_destroy(sample_objects->server);
280  if (result != DOCA_SUCCESS)
281  DOCA_LOG_ERR("Failed to destroy server properly with error = %s", doca_error_get_name(result));
282 
283  sample_objects->server = NULL;
284  }
285 
286  if (sample_objects->pe != NULL) {
287  result = doca_pe_destroy(sample_objects->pe);
288  if (result != DOCA_SUCCESS)
289  DOCA_LOG_ERR("Failed to destroy pe properly with error = %s", doca_error_get_name(result));
290 
291  sample_objects->pe = NULL;
292  }
293 
294  if (sample_objects->rep_dev != NULL) {
295  result = doca_dev_rep_close(sample_objects->rep_dev);
296  if (result != DOCA_SUCCESS)
297  DOCA_LOG_ERR("Failed to close rep device properly with error = %s",
299 
300  sample_objects->rep_dev = NULL;
301  }
302 
303  if (sample_objects->hw_dev != NULL) {
304  result = doca_dev_close(sample_objects->hw_dev);
305  if (result != DOCA_SUCCESS)
306  DOCA_LOG_ERR("Failed to close hw device properly with error = %s", doca_error_get_name(result));
307 
308  sample_objects->hw_dev = NULL;
309  }
310 }
311 
320 static void comch_server_state_changed_callback(const union doca_data user_data,
321  struct doca_ctx *ctx,
322  enum doca_ctx_states prev_state,
323  enum doca_ctx_states next_state)
324 {
325  (void)ctx;
326  (void)prev_state;
327 
328  struct comch_ctrl_path_server_objects *sample_objects = (struct comch_ctrl_path_server_objects *)user_data.ptr;
329 
330  switch (next_state) {
331  case DOCA_CTX_STATE_IDLE:
332  DOCA_LOG_INFO("CC server context has been stopped");
333  /* We can stop progressing the PE */
334  sample_objects->finish = true;
335  break;
340  DOCA_LOG_ERR("CC server context entered into starting state. Unexpected transition");
341  break;
343  DOCA_LOG_INFO("CC server context is running. Waiting for clients to connect");
344  break;
350  DOCA_LOG_INFO("CC server context entered into stopping state. Terminating connections with clients");
351  break;
352  default:
353  break;
354  }
355 }
356 
366 static doca_error_t init_comch_ctrl_path_server_objects(const char *server_name,
367  const char *dev_pci_addr,
368  const char *dev_rep_pci_addr,
369  struct comch_ctrl_path_server_objects *sample_objects)
370 {
372 
374  .send_task_comp_err_cb = send_task_completion_err_callback,
375  .msg_recv_cb = message_recv_callback,
376  .server_connection_event_cb = server_connection_event_callback,
377  .server_disconnection_event_cb =
379  .data_path_mode = false,
380  .new_consumer_cb = NULL,
381  .expired_consumer_cb = NULL,
382  .ctx_user_data = sample_objects,
383  .ctx_state_changed_cb = comch_server_state_changed_callback};
384 
385  /* Open DOCA device according to the given PCI address */
386  result = open_doca_device_with_pci(dev_pci_addr, NULL, &(sample_objects->hw_dev));
387  if (result != DOCA_SUCCESS) {
388  DOCA_LOG_ERR("Failed to open DOCA device based on PCI address");
389  return result;
390  }
391 
392  /* Open DOCA device representor according to the given PCI address */
393  result = open_doca_device_rep_with_pci(sample_objects->hw_dev,
395  dev_rep_pci_addr,
396  &(sample_objects->rep_dev));
397  if (result != DOCA_SUCCESS) {
398  DOCA_LOG_ERR("Failed to open DOCA device representor based on PCI address");
399  clean_comch_sample_objects(sample_objects);
400  return result;
401  }
402 
403  result = init_comch_ctrl_path_server(server_name,
404  sample_objects->hw_dev,
405  sample_objects->rep_dev,
406  &cfg,
407  &(sample_objects->server),
408  &(sample_objects->pe));
409  if (result != DOCA_SUCCESS) {
410  DOCA_LOG_ERR("Fail init cc server with error = %s", doca_error_get_name(result));
411  clean_comch_sample_objects(sample_objects);
412  return result;
413  }
414 
415  return DOCA_SUCCESS;
416 }
417 
429  const char *dev_pci_addr,
430  const char *rep_pci_addr,
431  const char *text,
432  const uint32_t text_len)
433 {
435  struct comch_ctrl_path_server_objects sample_objects = {0};
436  uint32_t max_msg_size;
437 
438  struct timespec ts = {
439  .tv_sec = 0,
440  .tv_nsec = SLEEP_IN_NANOS,
441  };
442 
443  sample_objects.text = text;
444  sample_objects.finish = false;
445 
446  result = init_comch_ctrl_path_server_objects(server_name, dev_pci_addr, rep_pci_addr, &sample_objects);
447  if (result != DOCA_SUCCESS) {
448  DOCA_LOG_ERR("Failed to initialize sample with error = %s", doca_error_get_name(result));
449  return result;
450  }
451 
452  result = doca_comch_cap_get_max_msg_size(doca_dev_as_devinfo(sample_objects.hw_dev), &max_msg_size);
453  if (result != DOCA_SUCCESS) {
454  DOCA_LOG_ERR("Failed to get max supported message size with error = %s", doca_error_get_name(result));
455  clean_comch_sample_objects(&sample_objects);
456  return result;
457  }
458 
459  if (text_len > max_msg_size) {
460  DOCA_LOG_ERR(
461  "Failed to run sample, text size is larger than supported message size. text_len = %u, supported message size = %u",
462  text_len,
463  max_msg_size);
464  clean_comch_sample_objects(&sample_objects);
466  }
467  sample_objects.text_len = text_len;
468 
469  /* Waiting to receive a message from the client */
470  while (!sample_objects.finish) {
471  if (doca_pe_progress(sample_objects.pe) == 0)
472  nanosleep(&ts, &ts);
473  }
474 
475  clean_comch_sample_objects(&sample_objects);
476  return sample_objects.result;
477 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
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)
static void comch_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 void 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_connection_event_callback(struct doca_comch_event_connection_status_changed *event, struct doca_comch_connection *comch_conn, uint8_t change_success)
static void send_task_completion_err_callback(struct doca_comch_task_send *task, union doca_data task_user_data, union doca_data ctx_user_data)
doca_error_t start_comch_ctrl_path_server_sample(const char *server_name, const char *dev_pci_addr, const char *rep_pci_addr, const char *text, const uint32_t text_len)
DOCA_LOG_REGISTER(COMCH_CTRL_PATH_SERVER)
static void clean_comch_sample_objects(struct comch_ctrl_path_server_objects *sample_objects)
static doca_error_t init_comch_ctrl_path_server_objects(const char *server_name, const char *dev_pci_addr, const char *dev_rep_pci_addr, struct comch_ctrl_path_server_objects *sample_objects)
static void server_disconnection_event_callback(struct doca_comch_event_connection_status_changed *event, struct doca_comch_connection *comch_conn, uint8_t change_success)
static void 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 doca_error_t server_send_pong(struct comch_ctrl_path_server_objects *sample_objects)
#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
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 doca_error_t doca_comch_cap_get_max_msg_size(const struct doca_devinfo *devinfo, uint32_t *size)
DOCA_STABLE doca_error_t doca_comch_server_destroy(struct doca_comch_server *comch_server)
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 struct doca_devinfo * doca_dev_as_devinfo(const struct doca_dev *dev)
Get local device info from device. This should be useful when wanting to query information about devi...
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_ERROR_INVALID_VALUE
Definition: doca_error.h:44
@ DOCA_SUCCESS
Definition: doca_error.h:38
@ DOCA_ERROR_NOT_CONNECTED
Definition: doca_error.h:52
#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_pe_destroy(struct doca_pe *pe)
Destroy doca progress engine.
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_set_user_data(struct doca_task *task, union doca_data user_data)
Set user data to a task.
DOCA_STABLE void doca_task_free(struct doca_task *task)
Free a task back to where it was allocated from.
const struct ip_frag_config * cfg
Definition: ip_frag_dp.c:0
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