NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
urom_ping_pong_sample.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2023-2024 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 <stdbool.h>
27 #include <stdio.h>
28 #include <string.h>
29 
30 #include <mpi.h>
31 
32 #include <doca_ctx.h>
33 #include <doca_dev.h>
34 #include <doca_error.h>
35 #include <doca_log.h>
36 #include <doca_pe.h>
37 #include <doca_urom.h>
38 
39 #include <worker_sandbox.h>
40 
41 #include "common.h"
42 #include "urom_common.h"
43 
44 DOCA_LOG_REGISTER(UROM_PING_PONG::SAMPLE);
45 
46 /* ping pong result type */
51 };
52 
53 #define PING_TAG 0x1234 /* UCX data for ping tag */
54 #define PONG_TAG 0x5678 /* UCX data for pong tag */
55 #define RECV_MAX_LEN 100 /* Receive message maximum size */
56 #define PING_RECV_CTX 0xdead /* Ping recv context */
57 #define PONG_RECV_CTX 0xbeef /* Pong recv context */
58 
59 /*
60  * PP OOB allgather handler
61  *
62  * @sbuf [in]: local buffer to send to other processes
63  * @rbuf [in]: global buffer to include other processes source buffer
64  * @msglen [in]: source buffer length
65  * @coll_info [in]: collection info
66  * @req [in]: allgather request data
67  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
68  */
69 static doca_error_t oob_allgather(void *sbuf, void *rbuf, size_t msglen, void *coll_info, void **req)
70 {
71  MPI_Request *request;
72  MPI_Comm comm = (MPI_Comm)(uintptr_t)coll_info;
73 
74  request = calloc(1, sizeof(*request));
75  if (request == NULL)
76  return DOCA_ERROR_NO_MEMORY;
77 
78  MPI_Iallgather(sbuf, msglen, MPI_BYTE, rbuf, msglen, MPI_BYTE, comm, request);
79 
80  *req = request;
81  return DOCA_SUCCESS;
82 }
83 
84 /*
85  * PP OOB allgather test
86  *
87  * @req [in]: allgather request data
88  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
89  */
91 {
92  int is_done = 0;
93  MPI_Request *request = (MPI_Request *)req;
94 
95  MPI_Test(request, &is_done, MPI_STATUS_IGNORE);
96 
97  return is_done ? DOCA_SUCCESS : DOCA_ERROR_IN_PROGRESS;
98 }
99 
100 /*
101  * PP OOB allgather free
102  *
103  * @req [in]: allgather request data
104  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
105  */
107 {
108  free(req);
109  return DOCA_SUCCESS;
110 }
111 
115 struct recv_result {
116  enum pp_res_type_t type; /* Result type */
117  uint64_t context; /* Task context */
118  char buffer[RECV_MAX_LEN]; /* Message buffer */
119  uint64_t count; /* Message size */
120  uint64_t sender_tag; /* Sender tag */
121  ucs_status_t status; /* Sandbox recv task status */
122  doca_error_t result; /* Worker task result */
123 };
124 
128 struct send_result {
129  enum pp_res_type_t type; /* Result type */
130  uint64_t context; /* Task context */
131  ucs_status_t status; /* Sandbox send task status */
132  doca_error_t result; /* Worker task result */
133 };
134 
135 /*
136  * Recv task callback
137  *
138  * @result [in]: task result
139  * @cookie [in]: user cookie
140  * @context [in]: user context
141  * @buffer [in]: inline receive data, NULL if RDMA
142  * @buf_len [in]: buffer length
143  * @sender_tag [in]: sender tag
144  * @status [in]: UCX status
145  */
147  union doca_data cookie,
148  union doca_data context,
149  void *buffer,
150  uint64_t buf_len,
151  uint64_t sender_tag,
152  ucs_status_t status)
153 {
154  struct recv_result *res = (struct recv_result *)cookie.ptr;
155 
156  if (res == NULL)
157  return;
158 
159  res->type = PP_RES_TYPE_RECV;
160  res->result = result;
161  res->context = context.u64;
162  if (result != DOCA_SUCCESS)
163  return;
164  res->status = status;
165  snprintf(res->buffer, RECV_MAX_LEN, "%s", (char *)buffer);
166  res->count = buf_len;
167  res->sender_tag = sender_tag;
168 }
169 
170 /*
171  * Send task callback
172  *
173  * @result [in]: task result
174  * @cookie [in]: user cookie
175  * @context [in]: user context
176  * @status [in]: UCX status
177  */
178 static void send_finished_cb(doca_error_t result, union doca_data cookie, union doca_data context, ucs_status_t status)
179 {
180  struct send_result *res = (struct send_result *)cookie.ptr;
181 
182  if (res == NULL)
183  return;
184 
185  res->type = PP_RES_TYPE_SEND;
186  res->context = context.u64;
187  res->result = result;
188  res->status = status;
189 }
190 
191 /*
192  * Do a ping pong between MPI processes, the rank points who is the server or client
193  *
194  * @pe [in]: progress engine context
195  * @worker [in]: UROM worker context
196  * @msg [in]: ping pong message
197  * @my_rank [in]: Current MPI process rank
198  * @size [in]: MPI world size
199  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
200  */
201 doca_error_t ping_pong(struct doca_pe *pe, struct doca_urom_worker *worker, const char *msg, int my_rank, int size)
202 {
203  int ret;
204  bool is_client = false;
206  union doca_data context;
207  union doca_data send_data;
208  union doca_data recv_data;
209  int msg_len = strlen(msg) + 1;
210  int dest = (my_rank + 1) % size;
211  struct send_result *send_res;
212  struct recv_result *recv_res;
213 
214  recv_res = calloc(1, sizeof(*recv_res));
215  if (recv_res == NULL)
216  return DOCA_ERROR_NO_MEMORY;
217 
218  send_res = calloc(1, sizeof(*send_res));
219  if (send_res == NULL) {
220  free(recv_res);
221  return DOCA_ERROR_NO_MEMORY;
222  }
223 
224  recv_data.ptr = recv_res;
225  send_data.ptr = send_res;
226 
227  if (my_rank != 0)
228  is_client = true;
229 
230  if (is_client) {
231  context.u64 = PONG_RECV_CTX;
233  recv_data,
234  context,
235  0,
236  RECV_MAX_LEN,
237  PONG_TAG,
238  0xffff,
239  0,
241  if (result != DOCA_SUCCESS)
242  goto error_exit;
243 
244  DOCA_LOG_INFO("Client posted PING recv");
245  } else {
246  context.u64 = PING_RECV_CTX;
248  recv_data,
249  context,
250  0,
251  RECV_MAX_LEN,
252  PING_TAG,
253  0xffff,
254  0,
256  if (result != DOCA_SUCCESS)
257  goto error_exit;
258 
259  DOCA_LOG_INFO("Server posted PONG recv");
260  }
261 
262  if (is_client) {
263  context.u64 = 0;
265  send_data,
266  context,
267  dest,
268  (uint64_t)msg,
269  msg_len,
270  PING_TAG,
271  0,
273  if (result != DOCA_SUCCESS)
274  goto error_exit;
275 
276  DOCA_LOG_INFO("Client posted PING send");
277 
278  send_res->type = 0;
279  send_res->result = DOCA_SUCCESS;
280  do {
281  ret = doca_pe_progress(pe);
282  } while (ret == 0 || send_res->type == 0);
283 
284  if (send_res->result != DOCA_SUCCESS || send_res->type != PP_RES_TYPE_SEND ||
285  send_res->status != UCS_OK) {
286  DOCA_LOG_ERR("Client ping send failed");
287  result = send_res->result;
288  goto error_exit;
289  }
290  } else {
291  /* Wait to receive ping */
292  recv_res->type = 0;
293  recv_res->result = DOCA_SUCCESS;
294  do {
295  ret = doca_pe_progress(pe);
296  } while (ret == 0 || recv_res->type == 0);
297 
298  if (recv_res->context != PING_RECV_CTX || recv_res->sender_tag != PING_TAG ||
299  recv_res->status != UCS_OK || recv_res->result != DOCA_SUCCESS) {
300  DOCA_LOG_ERR("Server receive ping failed");
301  result = recv_res->result;
302  goto error_exit;
303  }
304 
305  DOCA_LOG_INFO("Server completed PING recv: %s", (char *)recv_res->buffer);
306 
307  /* Do pong */
308  context.u64 = 0;
310  send_data,
311  context,
312  dest,
313  (uint64_t)msg,
314  msg_len,
315  PONG_TAG,
316  0,
318  if (result != DOCA_SUCCESS)
319  goto error_exit;
320 
321  DOCA_LOG_INFO("Server posted PONG send");
322 
323  /* Pop tag send notification */
324  send_res->type = 0;
325  send_res->result = DOCA_SUCCESS;
326  do {
327  ret = doca_pe_progress(pe);
328  } while (ret == 0 || send_res->type == 0);
329 
330  if (send_res->result != DOCA_SUCCESS || send_res->type != PP_RES_TYPE_SEND ||
331  send_res->status != UCS_OK) {
332  DOCA_LOG_ERR("Server ping send failed");
333  result = send_res->result;
334  goto error_exit;
335  }
336  }
337 
338  if (is_client) {
339  /* Wait to receive pong */
340  recv_res->type = 0;
341  recv_res->result = DOCA_SUCCESS;
342  do {
343  ret = doca_pe_progress(pe);
344  } while (ret == 0 || recv_res->type == 0);
345 
346  if (recv_res->context != PONG_RECV_CTX || recv_res->sender_tag != PONG_TAG ||
347  recv_res->status != UCS_OK || recv_res->result != DOCA_SUCCESS) {
348  DOCA_LOG_ERR("Server receive ping failed");
349  result = recv_res->result;
350  goto error_exit;
351  }
352 
353  DOCA_LOG_INFO("Client received PONG recv: %s", (char *)recv_res->buffer);
354  }
355 
356  return DOCA_SUCCESS;
357 
358 error_exit:
359  free(recv_res);
360  free(send_res);
361  return result;
362 }
363 
364 /*
365  * Ping Pong sample based on Sandbox plugin
366  *
367  * @message [in]: ping pong message
368  * @device_name [in]: IB device name to open
369  * @rank [in]: Current MPI process rank
370  * @size [in]: MPI world size
371  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
372  */
373 doca_error_t urom_ping_pong(const char *message, const char *device_name, uint32_t rank, uint32_t size)
374 {
375  int idx;
376  size_t i, plugins_count = 0;
377  char *plugin_name = "worker_sandbox";
378  struct doca_pe *pe;
379  struct doca_dev *dev;
380  doca_cpu_set_t cpuset;
381  enum doca_ctx_states state;
382  doca_error_t tmp_result, result;
383  struct doca_urom_domain *domain;
384  struct doca_urom_worker *worker;
385  struct doca_urom_service *service;
386  uint64_t worker_id = (uint64_t)rank;
387  struct doca_urom_domain_oob_coll oob_coll = {
389  .req_test = oob_allgather_test,
390  .req_free = oob_allgather_free,
391  .coll_info = (void *)(uintptr_t)MPI_COMM_WORLD,
392  .n_oob_indexes = size,
393  .oob_index = rank,
394  };
395  const struct doca_urom_service_plugin_info *plugins, *sandbox_info = NULL;
396 
397  /* Open IB device */
398  result = open_doca_device_with_ibdev_name((uint8_t *)device_name, strlen(device_name), NULL, &dev);
399  if (result != DOCA_SUCCESS)
400  return result;
401 
402  /* Create PE context */
404  if (result != DOCA_SUCCESS)
405  goto close_dev;
406 
407  /* Create and start service context */
408  result = start_urom_service(pe, dev, 32, &service);
409  if (result != DOCA_SUCCESS)
410  goto pe_cleanup;
411 
412  result = doca_urom_service_get_plugins_list(service, &plugins, &plugins_count);
413  if (result != DOCA_SUCCESS || plugins_count == 0)
414  goto service_stop;
415 
416  for (i = 0; i < plugins_count; i++) {
417  if (strcmp(plugin_name, plugins[i].plugin_name) == 0) {
418  sandbox_info = &plugins[i];
419  break;
420  }
421  }
422 
423  if (sandbox_info == NULL) {
424  DOCA_LOG_ERR("Failed to match sandbox plugin");
426  goto service_stop;
427  }
428 
429  result = urom_sandbox_init(sandbox_info->id, sandbox_info->version);
430  if (result != DOCA_SUCCESS)
431  goto service_stop;
432 
433  result = doca_urom_service_get_cpuset(service, &cpuset);
434  if (result != DOCA_SUCCESS)
435  goto service_stop;
436 
437  for (idx = 0; idx < 8; idx++) {
438  if (!doca_cpu_is_set(idx, &cpuset))
439  goto service_stop;
440  }
441 
442  /* Create and start worker context */
443  result = start_urom_worker(pe, service, worker_id, NULL, 16, NULL, NULL, 0, sandbox_info->id, &worker);
444  if (result != DOCA_SUCCESS)
445  goto service_stop;
446 
447  /* Loop till worker state changes to running */
448  do {
451  } while (state == DOCA_CTX_STATE_STARTING && result == DOCA_SUCCESS);
452 
453  /* Create domain context */
454  result = start_urom_domain(pe, &oob_coll, &worker_id, &worker, 1, NULL, 0, &domain);
455  if (result != DOCA_SUCCESS)
456  goto worker_stop;
457 
458  /* Loop till domain state changes to running */
459  do {
462  } while (state == DOCA_CTX_STATE_STARTING && result == DOCA_SUCCESS);
463 
464  /* Run ping pong flow */
465  result = ping_pong(pe, worker, message, rank, size);
466  if (result != DOCA_SUCCESS)
467  MPI_Abort(MPI_COMM_WORLD, 1);
468 
470  if (tmp_result != DOCA_SUCCESS) {
471  DOCA_LOG_ERR("Failed to stop UROM domain");
472  DOCA_ERROR_PROPAGATE(result, tmp_result);
473  }
474 
475  tmp_result = doca_urom_domain_destroy(domain);
476  if (tmp_result != DOCA_SUCCESS) {
477  DOCA_LOG_ERR("Failed to destroy UROM domain");
478  DOCA_ERROR_PROPAGATE(result, tmp_result);
479  }
480 
481 worker_stop:
482  tmp_result = doca_ctx_stop(doca_urom_worker_as_ctx(worker));
483  if (tmp_result != DOCA_SUCCESS && tmp_result != DOCA_ERROR_IN_PROGRESS) {
484  DOCA_LOG_ERR("Failed to request stop UROM worker");
485  DOCA_ERROR_PROPAGATE(result, tmp_result);
486  }
487 
488  do {
491  } while (state != DOCA_CTX_STATE_IDLE);
492 
493  tmp_result = doca_urom_worker_destroy(worker);
494  if (tmp_result != DOCA_SUCCESS) {
495  DOCA_LOG_ERR("Failed to destroy UROM worker");
496  DOCA_ERROR_PROPAGATE(result, tmp_result);
497  }
498 
499 service_stop:
500  tmp_result = doca_ctx_stop(doca_urom_service_as_ctx(service));
501  if (tmp_result != DOCA_SUCCESS) {
502  DOCA_LOG_ERR("Failed to stop UROM service");
503  DOCA_ERROR_PROPAGATE(result, tmp_result);
504  }
505 
506  tmp_result = doca_urom_service_destroy(service);
507  if (tmp_result != DOCA_SUCCESS) {
508  DOCA_LOG_ERR("Failed to destroy UROM service");
509  DOCA_ERROR_PROPAGATE(result, tmp_result);
510  }
511 pe_cleanup:
512  tmp_result = doca_pe_destroy(pe);
513  if (tmp_result != DOCA_SUCCESS) {
514  DOCA_LOG_ERR("Failed to destroy PE");
515  DOCA_ERROR_PROPAGATE(result, tmp_result);
516  }
517 
518 close_dev:
519  tmp_result = doca_dev_close(dev);
520  if (tmp_result != DOCA_SUCCESS) {
521  DOCA_LOG_ERR("Failed to close device");
522  DOCA_ERROR_PROPAGATE(result, tmp_result);
523  }
524  return result;
525 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
doca_error_t open_doca_device_with_ibdev_name(const uint8_t *value, size_t val_size, tasks_check func, struct doca_dev **retval)
Definition: common.c:84
uint64_t cookie
if(bitoffset % 64+bitlength > 64) result|
static enum doca_flow_pipe_domain domain
static struct doca_pe * pe
DOCA_STABLE doca_error_t doca_ctx_get_state(const struct doca_ctx *ctx, enum doca_ctx_states *state)
Get context state.
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_CTX_STATE_STARTING
Definition: doca_ctx.h:93
@ DOCA_CTX_STATE_IDLE
Definition: doca_ctx.h:88
DOCA_STABLE doca_error_t doca_dev_close(struct doca_dev *dev)
Destroy allocated local device instance.
#define DOCA_ERROR_PROPAGATE(r, t)
Save the first encountered doca_error_t.
Definition: doca_error.h:83
enum doca_error doca_error_t
DOCA API return codes.
@ DOCA_ERROR_INVALID_VALUE
Definition: doca_error.h:44
@ DOCA_SUCCESS
Definition: doca_error.h:38
@ DOCA_ERROR_NO_MEMORY
Definition: doca_error.h:45
@ DOCA_ERROR_IN_PROGRESS
Definition: doca_error.h:64
#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 uint8_t doca_pe_progress(struct doca_pe *pe)
Run the progress engine.
DOCA_STABLE doca_error_t doca_pe_create(struct doca_pe **pe)
Creates DOCA progress engine.
DOCA_EXPERIMENTAL struct doca_ctx * doca_urom_domain_as_ctx(struct doca_urom_domain *domain_ctx)
DOCA_EXPERIMENTAL doca_error_t doca_urom_domain_destroy(struct doca_urom_domain *domain_ctx)
ucs_cpu_set_t doca_cpu_set_t
DOCA CPU set structure.
Definition: doca_urom.h:98
DOCA_EXPERIMENTAL doca_error_t doca_urom_service_get_plugins_list(struct doca_urom_service *service_ctx, const struct doca_urom_service_plugin_info **plugins, size_t *plugins_count)
This method gets the list of supported plugins on service's DPU side.
DOCA_EXPERIMENTAL doca_error_t doca_urom_service_get_cpuset(struct doca_urom_service *service_ctx, doca_cpu_set_t *cpuset)
Get the allowed CPU set for the service.
DOCA_EXPERIMENTAL struct doca_ctx * doca_urom_service_as_ctx(struct doca_urom_service *service_ctx)
Convert service_ctx instance into a generalized context for use with DOCA core objects.
DOCA_EXPERIMENTAL doca_error_t doca_urom_service_destroy(struct doca_urom_service *service_ctx)
This method destroys a UROM Service context.
#define doca_cpu_is_set(_cpu, _cpusetp)
Check if specific bit in DOCA CPU is set.
Definition: doca_urom.h:119
DOCA_EXPERIMENTAL doca_error_t doca_urom_worker_destroy(struct doca_urom_worker *worker_ctx)
This method destroys a UROM Worker context.
DOCA_EXPERIMENTAL struct doca_ctx * doca_urom_worker_as_ctx(struct doca_urom_worker *worker_ctx)
__UINTPTR_TYPE__ uintptr_t
Definition: stdint.h:298
Out-of-band communication descriptor for Domain creation.
Definition: doca_urom.h:1058
doca_urom_domain_allgather_cb_t allgather
Definition: doca_urom.h:1060
char plugin_name[DOCA_UROM_PLUGIN_NAME_MAX_LEN]
char buffer[RECV_MAX_LEN]
ucs_status_t status
enum pp_res_type_t type
doca_error_t result
ucs_status_t status
enum pp_res_type_t type
doca_error_t result
Convenience type for representing opaque data.
Definition: doca_types.h:56
void * ptr
Definition: doca_types.h:57
doca_error_t start_urom_service(struct doca_pe *pe, struct doca_dev *dev, uint64_t nb_workers, struct doca_urom_service **service)
Definition: urom_common.c:95
doca_error_t start_urom_worker(struct doca_pe *pe, struct doca_urom_service *service, uint64_t worker_id, uint32_t *gid, uint64_t nb_tasks, doca_cpu_set_t *cpuset, char **env, size_t env_count, uint64_t plugins, struct doca_urom_worker **worker)
Definition: urom_common.c:148
doca_error_t start_urom_domain(struct doca_pe *pe, struct doca_urom_domain_oob_coll *oob, uint64_t *worker_ids, struct doca_urom_worker **workers, size_t nb_workers, struct urom_domain_buffer_attrs *buffers, size_t nb_buffers, struct doca_urom_domain **domain)
Definition: urom_common.c:243
static void recv_finished_cb(doca_error_t result, union doca_data cookie, union doca_data context, void *buffer, uint64_t buf_len, uint64_t sender_tag, ucs_status_t status)
#define RECV_MAX_LEN
doca_error_t urom_ping_pong(const char *message, const char *device_name, uint32_t rank, uint32_t size)
#define PONG_TAG
static void send_finished_cb(doca_error_t result, union doca_data cookie, union doca_data context, ucs_status_t status)
static doca_error_t oob_allgather_free(void *req)
@ PP_RES_TYPE_RECV
@ PP_RES_TYPE_SEND
@ PP_RES_TYPE_UNKNOWN
doca_error_t ping_pong(struct doca_pe *pe, struct doca_urom_worker *worker, const char *msg, int my_rank, int size)
#define PONG_RECV_CTX
static doca_error_t oob_allgather(void *sbuf, void *rbuf, size_t msglen, void *coll_info, void **req)
DOCA_LOG_REGISTER(UROM_PING_PONG::SAMPLE)
#define PING_TAG
static doca_error_t oob_allgather_test(void *req)
#define PING_RECV_CTX
doca_error_t urom_sandbox_tag_task_send(struct doca_urom_worker *worker_ctx, union doca_data cookie, union doca_data context, uint64_t dest, uint64_t buffer, uint64_t count, uint64_t tag, uint64_t memh_id, urom_sandbox_send_finished cb)
doca_error_t urom_sandbox_init(uint64_t plugin_id, uint64_t version)
doca_error_t urom_sandbox_tag_task_recv(struct doca_urom_worker *worker_ctx, union doca_data cookie, union doca_data context, uint64_t buffer, uint64_t count, uint64_t tag, uint64_t tag_mask, uint64_t memh_id, urom_sandbox_recv_finished cb)