NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
file_integrity_core.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2022-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 <arpa/inet.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30 #include <sys/mman.h>
31 #include <time.h>
32 #include <unistd.h>
33 
34 #include <doca_argp.h>
35 #include <doca_log.h>
36 #include <doca_mmap.h>
37 #include <doca_pe.h>
38 
39 #include <utils.h>
40 
41 #include "file_integrity_core.h"
42 
43 #define SLEEP_IN_NANOS (10 * 1000) /* Sample the task every 10 microseconds */
44 #define DEFAULT_TIMEOUT (10) /* default timeout for receiving messages */
45 #define SHA_ALGORITHM (DOCA_SHA_ALGORITHM_SHA256) /* doca_sha_algorithm for the sample */
46 #define LOG_NUM_SHA_TASKS (0) /* Log of SHA tasks number */
47 
48 DOCA_LOG_REGISTER(FILE_INTEGRITY::Core);
49 
50 /*
51  * Free callback - free doca_buf allocated pointer
52  *
53  * @addr [in]: Memory range pointer
54  * @len [in]: Memory range length
55  * @opaque [in]: An opaque pointer passed to iterator
56  */
57 static void free_cb(void *addr, size_t len, void *opaque)
58 {
59  (void)len;
60  (void)opaque;
61 
62  if (addr != NULL)
63  free(addr);
64 }
65 
66 /*
67  * Unmap callback - free doca_buf allocated pointer
68  *
69  * @addr [in]: Memory range pointer
70  * @len [in]: Memory range length
71  * @opaque [in]: An opaque pointer passed to iterator
72  */
73 static void unmap_cb(void *addr, size_t len, void *opaque)
74 {
75  (void)opaque;
76 
77  if (addr != NULL)
78  munmap(addr, len);
79 }
80 
81 /*
82  * Populate destination doca buffer for SHA tasks
83  *
84  * @state [in]: application configuration struct
85  * @dst_doca_buf [out]: created doca buffer
86  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
87  */
88 static doca_error_t populate_dst_buf(struct program_core_objects *state, struct doca_buf **dst_doca_buf)
89 {
90  char *dst_buffer = NULL;
91  uint32_t min_dst_sha_buffer_size;
93 
96  &min_dst_sha_buffer_size);
97  if (result != DOCA_SUCCESS) {
98  DOCA_LOG_ERR("Failed to get minimum destination buffer size for DOCA SHA: %s",
100  return result;
101  }
102 
103  dst_buffer = calloc(1, min_dst_sha_buffer_size);
104  if (dst_buffer == NULL) {
105  DOCA_LOG_ERR("Failed to allocate memory");
106  return DOCA_ERROR_NO_MEMORY;
107  }
108 
109  result = doca_mmap_set_memrange(state->dst_mmap, dst_buffer, min_dst_sha_buffer_size);
110  if (result != DOCA_SUCCESS) {
111  DOCA_LOG_ERR("Unable to set memory range destination memory map: %s", doca_error_get_descr(result));
112  free(dst_buffer);
113  return result;
114  }
116  if (result != DOCA_SUCCESS) {
117  DOCA_LOG_ERR("Unable to set free callback of destination memory map: %s", doca_error_get_descr(result));
118  free(dst_buffer);
119  return result;
120  }
121  result = doca_mmap_start(state->dst_mmap);
122  if (result != DOCA_SUCCESS) {
123  DOCA_LOG_ERR("Unable to start destination memory map: %s", doca_error_get_descr(result));
124  free(dst_buffer);
125  return result;
126  }
127 
129  state->dst_mmap,
130  dst_buffer,
131  min_dst_sha_buffer_size,
132  dst_doca_buf);
133  if (result != DOCA_SUCCESS) {
134  DOCA_LOG_ERR("Unable to acquire DOCA buffer representing destination buffer: %s",
136  return result;
137  }
138  return result;
139 }
140 
141 /*
142  * Construct DOCA SHA task, submit it and print the result
143  *
144  * @state [in]: application configuration struct
145  * @sha_ctx [in]: context of SHA library
146  * @dst_doca_buf [in]: destination doca buffer
147  * @file_data [in]: file data to the source buffer
148  * @file_size [in]: file size
149  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
150  */
152  struct doca_sha *sha_ctx,
153  struct doca_buf **dst_doca_buf,
154  char *file_data,
155  size_t file_size)
156 {
157  struct doca_buf *src_doca_buf;
158  struct doca_sha_task_hash *sha_hash_task = NULL;
159  struct doca_task *task = NULL;
160  size_t num_remaining_tasks = 0;
161  union doca_data ctx_user_data = {0};
162  union doca_data task_user_data = {0};
163  doca_error_t result, task_result;
164  struct timespec ts = {
165  .tv_sec = 0,
166  .tv_nsec = SLEEP_IN_NANOS,
167  };
168 
169  result = doca_mmap_set_memrange(state->src_mmap, file_data, file_size);
170  if (result != DOCA_SUCCESS) {
171  DOCA_LOG_ERR("Unable to set memory range of source memory map: %s", doca_error_get_descr(result));
172  munmap(file_data, file_size);
173  return result;
174  }
176  if (result != DOCA_SUCCESS) {
177  DOCA_LOG_ERR("Unable to set free callback of source memory map: %s", doca_error_get_descr(result));
178  munmap(file_data, file_size);
179  return result;
180  }
181  result = doca_mmap_start(state->src_mmap);
182  if (result != DOCA_SUCCESS) {
183  DOCA_LOG_ERR("Unable to start source memory map: %s", doca_error_get_descr(result));
184  munmap(file_data, file_size);
185  return result;
186  }
187 
188  result =
189  doca_buf_inventory_buf_get_by_addr(state->buf_inv, state->src_mmap, file_data, file_size, &src_doca_buf);
190  if (result != DOCA_SUCCESS) {
191  DOCA_LOG_ERR("Unable to acquire DOCA buffer representing source buffer: %s",
193  return result;
194  }
195 
196  result = doca_buf_set_data(src_doca_buf, file_data, file_size);
197  if (result != DOCA_SUCCESS) {
198  DOCA_LOG_ERR("doca_buf_set_data() for request doca_buf failure");
199  doca_buf_dec_refcount(src_doca_buf, NULL);
200  return result;
201  }
202 
203  result = populate_dst_buf(state, dst_doca_buf);
204  if (result != DOCA_SUCCESS) {
205  doca_buf_dec_refcount(src_doca_buf, NULL);
206  return result;
207  }
208 
209  /* Include tasks counter in user data of context to be decremented in callbacks */
210  ctx_user_data.ptr = &num_remaining_tasks;
211  result = doca_ctx_set_user_data(state->ctx, ctx_user_data);
212  if (result != DOCA_SUCCESS) {
213  doca_buf_dec_refcount(src_doca_buf, NULL);
214  return result;
215  }
216 
217  result = doca_ctx_start(state->ctx);
218  if (result != DOCA_SUCCESS) {
219  doca_buf_dec_refcount(src_doca_buf, NULL);
220  return result;
221  }
222 
223  /* Include result in user data of task to be used in the callbacks */
224  task_user_data.ptr = &task_result;
225  /* Allocate and construct SHA hash task */
228  src_doca_buf,
229  *dst_doca_buf,
230  task_user_data,
231  &sha_hash_task);
232  if (result != DOCA_SUCCESS) {
233  DOCA_LOG_ERR("Failed to allocate SHA hash task: %s", doca_error_get_descr(result));
234  doca_buf_dec_refcount(src_doca_buf, NULL);
235  return result;
236  }
237 
238  task = doca_sha_task_hash_as_task(sha_hash_task);
239 
240  /* Submit SHA hash task */
241  num_remaining_tasks++;
242  result = doca_task_submit(task);
243  if (result != DOCA_SUCCESS) {
244  DOCA_LOG_ERR("Failed to submit SHA hash task: %s", doca_error_get_descr(result));
245  doca_task_free(task);
246  doca_buf_dec_refcount(src_doca_buf, NULL);
247  return result;
248  }
249 
250  /* Wait for all tasks to be completed */
251  while (num_remaining_tasks > 0) {
252  if (doca_pe_progress(state->pe) == 0)
253  nanosleep(&ts, &ts);
254  }
255 
256  result = task_result;
257 
258  /* Check result of task according to the result we update in the callbacks */
259  if (task_result != DOCA_SUCCESS)
260  DOCA_LOG_ERR("SHA hash task failed: %s", doca_error_get_descr(task_result));
261 
262  doca_task_free(task);
263  doca_buf_dec_refcount(src_doca_buf, NULL);
264 
265  return result;
266 }
267 
268 /*
269  * Send the input file over comch to the server in segments of that can be handled by SHA
270  *
271  * @comch_cfg [in]: comch configuration object to send file across
272  * @app_cfg [in]: app configuration
273  * @file_data [in]: file data to the source buffer
274  * @file_size [in]: file size
275  * @file_sha [in]: SHA of the file to send
276  * @sha_len [in]: length of the sha array
277  * @min_partial_block_size [in]: minimum size of a SHA partial block
278  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
279  */
282  char *file_data,
283  size_t file_size,
284  uint8_t *file_sha,
285  size_t sha_len,
286  uint32_t min_partial_block_size)
287 {
288  struct file_integrity_metadata_msg *meta_msg;
289  size_t meta_msg_len;
290  uint32_t total_msgs;
291  uint32_t max_comch_msg;
292  size_t msg_len;
293  uint32_t i, partial_block_size;
295  struct timespec ts = {
296  .tv_nsec = SLEEP_IN_NANOS,
297  };
298 
299  meta_msg_len = sizeof(struct file_integrity_metadata_msg) + sha_len;
300  meta_msg = (struct file_integrity_metadata_msg *)malloc(meta_msg_len);
301  if (meta_msg == NULL) {
302  DOCA_LOG_ERR("Failed allocate memory for file metadata message");
303  return DOCA_ERROR_NO_MEMORY;
304  }
305 
307  if (max_comch_msg == 0 || min_partial_block_size > max_comch_msg) {
308  DOCA_LOG_ERR("Comch message size too small for minimum SHA block. Comch size: %u, partial SHA min: %u",
309  max_comch_msg,
310  min_partial_block_size);
311  free(meta_msg);
313  }
314 
315  /*
316  * Calculate the biggest partial block size that is smaller than the max_comch_msg
317  * A valid partial block size must be a multiple of min_partial_block_size
318  */
319  partial_block_size = max_comch_msg - (max_comch_msg % min_partial_block_size);
320 
321  /*
322  * Send to the server the number of messages needed for receiving the file
323  * The number of messages is equal to the size of the file divided by the size of the partial block size
324  * of the partial hash task, and rounding up
325  */
326  total_msgs = 1 + ((file_size - 1) / partial_block_size);
327  meta_msg->total_file_chunks = htonl(total_msgs);
328 
329  memcpy(&meta_msg->sha_data[0], file_sha, sha_len);
330 
331  /* This is the first message so assume there's room to send it */
332  result = comch_utils_send(comch_util_get_connection(comch_cfg), meta_msg, meta_msg_len);
333  if (result != DOCA_SUCCESS) {
334  DOCA_LOG_ERR("Failed to send file meta message: %s", doca_error_get_descr(result));
335  free(meta_msg);
336  return result;
337  }
338 
339  free(meta_msg);
340 
341  /* Send file to the server */
342  for (i = 0; i < total_msgs; i++) {
343  msg_len = MIN(file_size, partial_block_size);
344 
345  /* Verify that the other side has not signalled it is done */
346  if (app_cfg->state == TRANSFER_COMPLETE)
347  break;
348 
350  while (result == DOCA_ERROR_AGAIN) {
351  nanosleep(&ts, &ts);
353  if (result != DOCA_SUCCESS)
354  break;
356  }
357 
358  if (result != DOCA_SUCCESS) {
359  DOCA_LOG_ERR("File data was not sent: %s", doca_error_get_descr(result));
360  return result;
361  }
362  file_data += msg_len;
363  file_size -= msg_len;
364  }
365  return DOCA_SUCCESS;
366 }
367 
368 void client_recv_event_cb(struct doca_comch_event_msg_recv *event,
369  uint8_t *recv_buffer,
370  uint32_t msg_len,
371  struct doca_comch_connection *comch_connection)
372 {
373  struct file_integrity_config *cfg = comch_utils_get_user_data(comch_connection);
374 
375  /* A message is only expected from the server when it has finished processing the file */
376  (void)event;
377 
378  /* Print the completion message sent from the server */
379  recv_buffer[msg_len] = '\0';
380  DOCA_LOG_INFO("Received message: %s", recv_buffer);
381  cfg->state = TRANSFER_COMPLETE;
382 }
383 
386  struct program_core_objects *state,
387  struct doca_sha *sha_ctx)
388 {
389  struct doca_buf *dst_doca_buf;
390  struct timespec ts = {
391  .tv_nsec = SLEEP_IN_NANOS,
392  };
393  char *file_data, *sha_output;
394  uint8_t *sha_msg;
395  size_t hash_length, i;
396  struct stat statbuf;
397  int fd;
398  uint64_t max_source_buffer_size;
399  uint32_t min_partial_block_size;
401 
402  fd = open(app_cfg->file_path, O_RDWR);
403  if (fd < 0) {
404  DOCA_LOG_ERR("Failed to open %s", app_cfg->file_path);
405  return DOCA_ERROR_IO_FAILED;
406  }
407 
408  if (fstat(fd, &statbuf) < 0) {
409  DOCA_LOG_ERR("Failed to get file information");
410  close(fd);
411  return DOCA_ERROR_IO_FAILED;
412  }
413 
414  /* Get the partial block size */
417  &min_partial_block_size);
418  if (result != DOCA_SUCCESS) {
419  DOCA_LOG_ERR("Failed to get the partial hash block size for DOCA SHA: %s",
421  close(fd);
422  return result;
423  }
424 
425  result = doca_sha_cap_get_max_src_buf_size(doca_dev_as_devinfo(state->dev), &max_source_buffer_size);
426  if (result != DOCA_SUCCESS) {
427  DOCA_LOG_ERR("Failed to get maximum source buffer size for DOCA SHA: %s", doca_error_get_descr(result));
428  close(fd);
429  return result;
430  }
431 
432  if (statbuf.st_size <= 0 || (uint64_t)statbuf.st_size > max_source_buffer_size) {
433  DOCA_LOG_ERR("Invalid file size. Should be greater then zero and smaller than %lu",
434  max_source_buffer_size);
435  close(fd);
437  }
438 
439  file_data = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
440  if (file_data == MAP_FAILED) {
441  DOCA_LOG_ERR("Unable to map file content: %s", strerror(errno));
442  close(fd);
443  return DOCA_ERROR_NO_MEMORY;
444  }
445 
446  /* Calculate SHA */
447  result = calculate_sha(state, sha_ctx, &dst_doca_buf, file_data, statbuf.st_size);
448  if (result != DOCA_SUCCESS) {
449  close(fd);
450  return result;
451  }
452 
453  result = doca_buf_get_data_len(dst_doca_buf, &hash_length);
454  if (result != DOCA_SUCCESS) {
455  DOCA_LOG_ERR("Failed to get the data length of DOCA buffer: %s", doca_error_get_descr(result));
456  doca_buf_dec_refcount(dst_doca_buf, NULL);
457  close(fd);
458  return result;
459  }
460  result = doca_buf_get_data(dst_doca_buf, (void **)&sha_msg);
461  if (result != DOCA_SUCCESS) {
462  DOCA_LOG_ERR("Failed to get the data of DOCA buffer: %s", doca_error_get_descr(result));
463  doca_buf_dec_refcount(dst_doca_buf, NULL);
464  close(fd);
465  return result;
466  }
467 
468  /* Engine outputs hex format. For char format output, we need double the length */
469  sha_output = calloc(1, (hash_length * 2) + 1);
470  if (sha_output == NULL) {
471  DOCA_LOG_ERR("Failed to allocate memory");
472  doca_buf_dec_refcount(dst_doca_buf, NULL);
473  close(fd);
474  return DOCA_ERROR_NO_MEMORY;
475  }
476 
477  for (i = 0; i < hash_length; i++)
478  snprintf(sha_output + (2 * i), 3, "%02x", sha_msg[i]);
479  DOCA_LOG_INFO("SHA256 output is: %s", sha_output);
480 
481  free(sha_output);
482 
483  /* Send the file content to the server */
484  result =
485  send_file(comch_cfg, app_cfg, file_data, statbuf.st_size, sha_msg, hash_length, min_partial_block_size);
486  if (result != DOCA_SUCCESS) {
487  doca_buf_dec_refcount(dst_doca_buf, NULL);
488  close(fd);
489  return result;
490  }
491 
492  doca_buf_dec_refcount(dst_doca_buf, NULL);
493  close(fd);
494 
495  /* Receive finish message when file was completely read by the server */
496  while (app_cfg->state != TRANSFER_COMPLETE) {
497  nanosleep(&ts, &ts);
499  if (result != DOCA_SUCCESS) {
500  DOCA_LOG_ERR("Comch connection unexpectedly dropped: %s", doca_error_get_descr(result));
501  return result;
502  }
503  }
504 
505  return result;
506 }
507 
508 void server_recv_event_cb(struct doca_comch_event_msg_recv *event,
509  uint8_t *recv_buffer,
510  uint32_t msg_len,
511  struct doca_comch_connection *comch_connection)
512 {
513  struct file_integrity_config *cfg = comch_utils_get_user_data(comch_connection);
514  struct server_runtime_data *server_data;
515  union doca_data task_user_data = {0};
516  struct doca_task *task;
517  doca_error_t result, task_result;
518  struct timespec ts = {
519  .tv_nsec = SLEEP_IN_NANOS,
520  };
521 
522  (void)event;
523 
524  if (cfg == NULL) {
525  DOCA_LOG_ERR("Cannot get configuration information");
526  return;
527  }
528 
529  /* Ignore any events occurring after transfer is complete */
530  if (cfg->state == TRANSFER_COMPLETE || cfg->state == TRANSFER_ERROR)
531  return;
532 
533  server_data = &cfg->server_data;
534 
535  /* First received message should contain file metadata */
536  if (server_data->expected_file_chunks == 0) {
537  struct file_integrity_metadata_msg *file_meta = (struct file_integrity_metadata_msg *)recv_buffer;
538 
539  if (msg_len < sizeof(struct file_integrity_metadata_msg)) {
540  DOCA_LOG_ERR("Unexpected file metadata message received. Size %u, min expected size %lu",
541  msg_len,
542  sizeof(struct file_integrity_metadata_msg));
543  cfg->state = TRANSFER_ERROR;
544  return;
545  }
546 
547  server_data->expected_file_chunks = ntohl(file_meta->total_file_chunks);
548  server_data->expected_sha_len = msg_len - (sizeof(struct file_integrity_metadata_msg));
549  memcpy(server_data->expected_sha, file_meta->sha_data, server_data->expected_sha_len);
550 
551  cfg->state = TRANSFER_IN_PROGRESS;
552  return;
553  }
554 
555  /* At this point all messages must be file data */
556 
557  /* Put the new message into the buffer data */
558  memcpy(server_data->sha_src_data, recv_buffer, msg_len);
559 
560  /* Set data address and length in the doca_buf */
561  result = doca_buf_set_data(server_data->sha_src_buf, server_data->sha_src_data, msg_len);
562  if (result != DOCA_SUCCESS) {
563  DOCA_LOG_ERR("doca_buf_set_data() for request doca_buf failure: %s", doca_error_get_descr(result));
564  cfg->state = TRANSFER_ERROR;
565  return;
566  }
567 
568  /* If there is only one chunk then send it as a complete SHA request */
569  if (server_data->expected_file_chunks == 1) {
570  result = doca_sha_task_hash_set_src(server_data->sha_hash_task, server_data->sha_src_buf);
571  if (result != DOCA_SUCCESS) {
572  DOCA_LOG_ERR("Failed to set source for SHA hash task: %s", doca_error_get_descr(result));
573  cfg->state = TRANSFER_ERROR;
574  return;
575  }
576 
577  task = doca_sha_task_hash_as_task(server_data->sha_hash_task);
578  } else {
579  /* If multiple file chunks, send as partial SHA */
580 
582  server_data->sha_src_buf);
583  if (result != DOCA_SUCCESS) {
584  DOCA_LOG_ERR("Failed to set source for SHA partial hash task: %s",
586  cfg->state = TRANSFER_ERROR;
587  return;
588  }
589 
590  /* If it is the last chunk then mark it as the final buffer */
591  if (server_data->received_file_chunks == server_data->expected_file_chunks - 1) {
593  if (result != DOCA_SUCCESS) {
594  DOCA_LOG_ERR("Failed to set final buffer for SHA partial hash task: %s",
596  cfg->state = TRANSFER_ERROR;
597  return;
598  }
599  }
600 
602  }
603 
604  task_user_data.ptr = &task_result;
605  doca_task_set_user_data(task, task_user_data);
606 
607  (server_data->active_sha_tasks)++;
608  result = doca_task_submit(task);
609  if (result != DOCA_SUCCESS) {
610  DOCA_LOG_ERR("Failed to submit SHA partial hash task: %s", doca_error_get_descr(result));
611  cfg->state = TRANSFER_ERROR;
612  return;
613  }
614 
615  /* Wait for the task to be completed */
616  while (server_data->active_sha_tasks > 0) {
617  if (doca_pe_progress(server_data->sha_state->pe) == 0)
618  nanosleep(&ts, &ts);
619  }
620 
621  /* Check result of task according to the result we update in the callbacks */
622  if (task_result != DOCA_SUCCESS) {
623  DOCA_LOG_ERR("SHA partial hash task failed: %s", doca_error_get_descr(task_result));
624  cfg->state = TRANSFER_ERROR;
625  return;
626  }
627 
628  /* Write the received chunk to file */
629  if ((size_t)write(server_data->fd, recv_buffer, msg_len) != msg_len) {
630  DOCA_LOG_ERR("Failed to write the received message into the input file");
631  cfg->state = TRANSFER_ERROR;
632  return;
633  }
634 
635  server_data->received_file_chunks += 1;
636  server_data->received_file_length += msg_len;
637 
638  if (server_data->received_file_chunks == server_data->expected_file_chunks)
639  cfg->state = TRANSFER_COMPLETE;
640 }
641 
642 /*
643  * Initiate SHA specific data in the app config
644  *
645  * This data can be accessed by comch callbacks to send data directly to the SHA engine.
646  *
647  * @sha_ctx [in]: doca context to use for SHA offload
648  * @state [in]: core objects configured for SHA offload
649  * @server_data [in]: app global information that can be shared in callbacks
650  * @dst_doca_buf [in]: preallocated buffer to receive SHA output
651  * @max_comch_msg [in]: maximum size message across comch
652  * @fd [in]: file descriptor to write data to
653  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
654  */
655 static doca_error_t init_async_sha_recv_data(struct doca_sha *sha_ctx,
656  struct program_core_objects *state,
657  struct server_runtime_data *server_data,
658  struct doca_buf *dst_doca_buf,
659  uint32_t max_comch_msg,
660  int fd)
661 {
662  union doca_data task_user_data = {0};
663  union doca_data ctx_user_data = {0};
664  uint32_t received_sha_msg_size;
666 
667  /* Get size of SHA output */
670  &received_sha_msg_size);
671  if (result != DOCA_SUCCESS) {
672  DOCA_LOG_ERR("Failed to get minimum destination buffer size for DOCA SHA: %s",
674  return result;
675  }
676 
677  /* Allocate a buffer to copy the expect SHA to */
678  server_data->expected_sha = calloc(1, received_sha_msg_size);
679  if (server_data->expected_sha == NULL) {
680  DOCA_LOG_ERR("Failed to allocate memory for received sha");
681  return DOCA_ERROR_NO_MEMORY;
682  }
683 
684  /* Allocate buffer to register for SHA and handle incoming messages */
685  server_data->sha_src_data = calloc(1, max_comch_msg);
686  if (server_data->sha_src_data == NULL) {
687  DOCA_LOG_ERR("Failed to allocate memory for SHA data buffer");
689  goto free_expected_sha;
690  }
691 
692  /* Include the allocated data buffer in the source mmap */
693  result = doca_mmap_set_memrange(state->src_mmap, server_data->sha_src_data, max_comch_msg);
694  if (result != DOCA_SUCCESS) {
695  DOCA_LOG_ERR("Unable to set memory range of source memory map: %s", doca_error_get_descr(result));
696  goto free_sha_src_buf;
697  }
698 
699  result = doca_mmap_start(state->src_mmap);
700  if (result != DOCA_SUCCESS) {
701  DOCA_LOG_ERR("Unable to start source memory map: %s", doca_error_get_descr(result));
702  goto free_sha_src_buf;
703  }
704 
705  /* Get a doca_buf associated with the data buffer for sending to the SHA engine */
707  state->src_mmap,
708  server_data->sha_src_data,
709  max_comch_msg,
710  &server_data->sha_src_buf);
711  if (result != DOCA_SUCCESS) {
712  DOCA_LOG_ERR("Unable to acquire DOCA buffer representing source buffer: %s",
714  goto stop_mmap;
715  }
716 
717  /* Set the user data of the context to the number of active tasks variable - task completion decrements
718  * this */
719  server_data->active_sha_tasks = 0;
720  ctx_user_data.ptr = &server_data->active_sha_tasks;
721  result = doca_ctx_set_user_data(state->ctx, ctx_user_data);
722  if (result != DOCA_SUCCESS) {
723  DOCA_LOG_ERR("Failed to set DOCA context user data: %s", doca_error_get_descr(result));
724  goto free_doca_buf;
725  }
726 
727  result = doca_ctx_start(state->ctx);
728  if (result != DOCA_SUCCESS) {
729  DOCA_LOG_ERR("Failed to start DOCA context: %s", doca_error_get_descr(result));
730  goto free_doca_buf;
731  }
732 
733  /* Allocate a single task for a full SHA offload */
736  server_data->sha_src_buf,
737  dst_doca_buf,
738  task_user_data,
739  &server_data->sha_hash_task);
740  if (result != DOCA_SUCCESS) {
741  DOCA_LOG_ERR("Failed to allocate SHA hash task: %s", doca_error_get_descr(result));
742  goto stop_ctx;
743  }
744 
745  /* Allocate a single task for use in partial SHA */
748  server_data->sha_src_buf,
749  dst_doca_buf,
750  task_user_data,
751  &server_data->sha_partial_hash_task);
752  if (result != DOCA_SUCCESS) {
753  DOCA_LOG_ERR("Failed to allocate SHA partial hash task: %s", doca_error_get_descr(result));
754  goto free_sha_task;
755  }
756 
757  server_data->sha_state = state;
758  server_data->fd = fd;
759 
760  return DOCA_SUCCESS;
761 
762 free_sha_task:
764 stop_ctx:
765  doca_ctx_stop(state->ctx);
766 free_doca_buf:
767  doca_buf_dec_refcount(server_data->sha_src_buf, NULL);
768 stop_mmap:
769  doca_mmap_stop(state->src_mmap);
770 free_sha_src_buf:
771  free(server_data->sha_src_data);
772 free_expected_sha:
773  free(server_data->expected_sha);
774 
775  return result;
776 }
777 
778 /*
779  * Undo the allocations made in init_async_sha_recv_data()
780  *
781  * @server_data [in]: app global information that can be shared in callbacks
782  */
783 static void uninit_async_sha_recv_data(struct server_runtime_data *server_data)
784 {
785  /* Note, the SHA context will be stopped in file_integrity_cleanup() */
788  doca_buf_dec_refcount(server_data->sha_src_buf, NULL);
789  doca_mmap_stop(server_data->sha_state->src_mmap);
790  free(server_data->sha_src_data);
791  server_data->sha_src_data = NULL;
792  free(server_data->expected_sha);
793  server_data->expected_sha = NULL;
794 
795  server_data->sha_state = NULL;
796  server_data->fd = 0;
797 }
798 
801  struct program_core_objects *state,
802  struct doca_sha *sha_ctx)
803 {
804  struct doca_buf *dst_doca_buf = NULL;
805  uint32_t i, max_comch_msg;
806  size_t hash_length;
807  char *sha_output;
808  int fd;
809  uint8_t *file_sha;
810  char finish_msg[] = "Server was done receiving messages";
811  int counter = 0;
812  int num_of_iterations = (app_cfg->timeout * 1000 * 1000) / (SLEEP_IN_NANOS / 1000);
813  struct timespec ts = {
814  .tv_nsec = SLEEP_IN_NANOS,
815  };
817 
818  result = populate_dst_buf(state, &dst_doca_buf);
819  if (result != DOCA_SUCCESS)
820  goto finish_msg;
821 
822  fd = open(app_cfg->file_path, O_CREAT | O_WRONLY, S_IRUSR | S_IRGRP);
823  if (fd < 0) {
824  DOCA_LOG_ERR("Failed to open %s", app_cfg->file_path);
826  goto free_dst_buf;
827  }
828 
830  result = init_async_sha_recv_data(sha_ctx, state, &app_cfg->server_data, dst_doca_buf, max_comch_msg, fd);
831  if (result != DOCA_SUCCESS) {
832  DOCA_LOG_ERR("Failed to init async data: %s", doca_error_get_descr(result));
833  goto close_fd;
834  }
835 
836  /* Wait on comch to complete client to server transactions */
837  while (app_cfg->state != TRANSFER_COMPLETE && app_cfg->state != TRANSFER_ERROR) {
838  nanosleep(&ts, &ts);
840  if (result != DOCA_SUCCESS) {
841  DOCA_LOG_ERR("Comch connection unexpectedly dropped: %s", doca_error_get_descr(result));
842  goto uninit_async;
843  }
844 
845  if (app_cfg->state == TRANSFER_IDLE)
846  continue;
847 
848  counter++;
849  if (counter == num_of_iterations) {
850  DOCA_LOG_ERR("Message was not received at the given timeout");
852  goto uninit_async;
853  }
854  }
855 
856  if (app_cfg->state == TRANSFER_ERROR) {
857  DOCA_LOG_ERR("Error detected during comch exchange");
859  goto uninit_async;
860  }
861 
862  /* compare received SHA with calculated SHA */
863  result = doca_buf_get_data_len(dst_doca_buf, &hash_length);
864  if (result != DOCA_SUCCESS) {
865  DOCA_LOG_ERR("Failed to get the data length of DOCA buffer: %s", doca_error_get_descr(result));
866  goto uninit_async;
867  }
868 
869  if (hash_length == 0) {
870  DOCA_LOG_ERR("Error in calculating SHA - output length is 0");
872  goto uninit_async;
873  }
874 
875  result = doca_buf_get_data(dst_doca_buf, (void **)&file_sha);
876  if (result != DOCA_SUCCESS) {
877  DOCA_LOG_ERR("Failed to get the data of DOCA buffer: %s", doca_error_get_descr(result));
878  goto uninit_async;
879  }
880 
881  /* Engine outputs hex format. For char format output, we need double the length */
882  sha_output = calloc(1, (hash_length * 2) + 1);
883  if (sha_output == NULL) {
884  DOCA_LOG_ERR("Failed to allocate memory to display SHA");
886  goto uninit_async;
887  }
888 
889  for (i = 0; i < hash_length; i++)
890  snprintf(sha_output + (2 * i), 3, "%02x", file_sha[i]);
891  DOCA_LOG_INFO("SHA256 output is: %s", sha_output);
892 
893  free(sha_output);
894 
895  if (memcmp(file_sha, app_cfg->server_data.expected_sha, hash_length) == 0)
896  DOCA_LOG_INFO("SUCCESS: file SHA is identical to received SHA");
897  else {
898  DOCA_LOG_ERR("ERROR: SHA is not identical, file was compromised");
899  if (remove(app_cfg->file_path) < 0)
900  DOCA_LOG_ERR("Failed to remove %s", app_cfg->file_path);
901  }
902 
903 uninit_async:
904  uninit_async_sha_recv_data(&app_cfg->server_data);
905 close_fd:
906  close(fd);
907 free_dst_buf:
908  doca_buf_dec_refcount(dst_doca_buf, NULL);
909 finish_msg:
910  if (comch_utils_send(comch_util_get_connection(comch_cfg), finish_msg, sizeof(finish_msg)) != DOCA_SUCCESS)
911  DOCA_LOG_ERR("Failed to send finish message: %s", doca_error_get_descr(result));
912 
913  return result;
914 }
915 
916 /*
917  * SHA hash task completed callback
918  *
919  * @sha_hash_task [in]: Completed task
920  * @task_user_data [in]: doca_data from the task
921  * @ctx_user_data [in]: doca_data from the context
922  */
923 static void sha_hash_completed_callback(struct doca_sha_task_hash *sha_hash_task,
924  union doca_data task_user_data,
925  union doca_data ctx_user_data)
926 {
927  size_t *num_remaining_tasks = (size_t *)ctx_user_data.ptr;
928  doca_error_t *result = (doca_error_t *)task_user_data.ptr;
929 
930  (void)sha_hash_task;
931 
932  /* Decrement number of remaining tasks */
933  --*num_remaining_tasks;
934  /* Assign success to the result */
935  *result = DOCA_SUCCESS;
936 }
937 
938 /*
939  * SHA hash task error callback
940  *
941  * @sha_hash_task [in]: Failed task
942  * @task_user_data [in]: doca_data from the task
943  * @ctx_user_data [in]: doca_data from the context
944  */
945 static void sha_hash_error_callback(struct doca_sha_task_hash *sha_hash_task,
946  union doca_data task_user_data,
947  union doca_data ctx_user_data)
948 {
949  size_t *num_remaining_tasks = (size_t *)ctx_user_data.ptr;
950  struct doca_task *task = doca_sha_task_hash_as_task(sha_hash_task);
951  doca_error_t *result = (doca_error_t *)task_user_data.ptr;
952 
953  /* Decrement number of remaining tasks */
954  --*num_remaining_tasks;
955  /* Get the result of the task */
956  *result = doca_task_get_status(task);
957 }
958 
959 /*
960  * SHA partial hash task completed callback
961  *
962  * @sha_partial_hash_task [in]: Completed task
963  * @task_user_data [in]: doca_data from the task
964  * @ctx_user_data [in]: doca_data from the context
965  */
966 static void sha_partial_hash_completed_callback(struct doca_sha_task_partial_hash *sha_partial_hash_task,
967  union doca_data task_user_data,
968  union doca_data ctx_user_data)
969 {
970  size_t *num_remaining_tasks = (size_t *)ctx_user_data.ptr;
971  doca_error_t *result = (doca_error_t *)task_user_data.ptr;
972 
973  (void)sha_partial_hash_task;
974 
975  /* Decrement number of remaining tasks */
976  --*num_remaining_tasks;
977  /* Assign success to the result */
978  *result = DOCA_SUCCESS;
979 }
980 
981 /*
982  * SHA partial hash task error callback
983  *
984  * @sha_partial_hash_task [in]: Failed task
985  * @task_user_data [in]: doca_data from the task
986  * @ctx_user_data [in]: doca_data from the context
987  */
988 static void sha_partial_hash_error_callback(struct doca_sha_task_partial_hash *sha_partial_hash_task,
989  union doca_data task_user_data,
990  union doca_data ctx_user_data)
991 {
992  size_t *num_remaining_tasks = (size_t *)ctx_user_data.ptr;
993  struct doca_task *task = doca_sha_task_partial_hash_as_task(sha_partial_hash_task);
994  doca_error_t *result = (doca_error_t *)task_user_data.ptr;
995 
996  /* Decrement number of remaining tasks */
997  --*num_remaining_tasks;
998  /* Get the result of the task */
999  *result = doca_task_get_status(task);
1000 }
1001 
1002 /*
1003  * Check if given device is capable of executing a SHA partial hash task.
1004  *
1005  * @devinfo [in]: The DOCA device information
1006  * @return: DOCA_SUCCESS if the device supports SHA hash task and DOCA_ERROR otherwise.
1007  */
1008 static doca_error_t sha_partial_hash_is_supported(struct doca_devinfo *devinfo)
1009 {
1011 }
1012 
1014  struct program_core_objects *state,
1015  struct doca_sha **sha_ctx)
1016 {
1017  uint32_t max_bufs = 2; /* The app will use 2 doca buffers */
1019 
1020  /* set default timeout */
1021  if (app_cfg->timeout == 0)
1022  app_cfg->timeout = DEFAULT_TIMEOUT;
1023 
1024  /* Open device for partial SHA tasks */
1026  if (result != DOCA_SUCCESS) {
1027  DOCA_LOG_ERR("Failed to init DOCA device with SHA capabilities: %s", doca_error_get_descr(result));
1028  return result;
1029  }
1030 
1031  result = doca_sha_create(state->dev, sha_ctx);
1032  if (result != DOCA_SUCCESS) {
1033  DOCA_LOG_ERR("Failed to init sha library: %s", doca_error_get_descr(result));
1034  /* Destroying core objects closes state->dev, ignoring objects not yet created */
1035  goto destroy_core_objs;
1036  }
1037 
1038  state->ctx = doca_sha_as_ctx(*sha_ctx);
1039 
1040  result = create_core_objects(state, max_bufs);
1041  if (result != DOCA_SUCCESS) {
1042  DOCA_LOG_ERR("Failed to init DOCA core objects: %s", doca_error_get_descr(result));
1043  goto destroy_sha;
1044  }
1045 
1046  /* Connect context to progress engine */
1047  result = doca_pe_connect_ctx(state->pe, state->ctx);
1048  if (result != DOCA_SUCCESS) {
1049  DOCA_LOG_ERR("Failed to connect progress engine to context: %s", doca_error_get_descr(result));
1050  goto destroy_sha;
1051  }
1052 
1053  if (app_cfg->mode == CLIENT) {
1054  /* Set SHA hash task configuration for the client */
1059  if (result != DOCA_SUCCESS) {
1060  DOCA_LOG_ERR("Failed to set configuration for SHA hash task: %s", doca_error_get_descr(result));
1061  goto destroy_sha;
1062  }
1063 
1064  } else {
1069  if (result != DOCA_SUCCESS) {
1070  DOCA_LOG_ERR("Failed to set configuration for SHA hash task: %s", doca_error_get_descr(result));
1071  goto destroy_sha;
1072  }
1073 
1074  /* Set SHA partial hash task configuration for the client */
1079  if (result != DOCA_SUCCESS) {
1080  DOCA_LOG_ERR("Failed to set configuration for SHA partial hash task: %s",
1082  goto destroy_sha;
1083  }
1084  }
1085 
1086  return DOCA_SUCCESS;
1087 
1088 destroy_sha:
1089  (void)doca_sha_destroy(*sha_ctx);
1090  state->ctx = NULL;
1091 destroy_core_objs:
1092  destroy_core_objects(state);
1093 
1094  return result;
1095 }
1096 
1097 void file_integrity_cleanup(struct program_core_objects *state, struct doca_sha *sha_ctx)
1098 {
1100 
1101  if (state->pe != NULL && state->ctx != NULL) {
1102  result = request_stop_ctx(state->pe, state->ctx);
1103  if (result != DOCA_SUCCESS)
1104  DOCA_LOG_ERR("Failed to destroy DOCA SHA: %s", doca_error_get_descr(result));
1105  state->ctx = NULL;
1106  }
1107 
1108  if (sha_ctx != NULL) {
1109  result = doca_sha_destroy(sha_ctx);
1110  if (result != DOCA_SUCCESS)
1111  DOCA_LOG_ERR("Failed to destroy DOCA SHA: %s", doca_error_get_descr(result));
1112  }
1113 
1114  result = destroy_core_objects(state);
1115  if (result != DOCA_SUCCESS)
1116  DOCA_LOG_ERR("Failed to destroy core objects: %s", doca_error_get_descr(result));
1117 }
1118 
1119 /*
1120  * ARGP Callback - Handle file parameter
1121  *
1122  * @param [in]: Input parameter
1123  * @config [in/out]: Program configuration context
1124  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
1125  */
1126 static doca_error_t file_callback(void *param, void *config)
1127 {
1128  struct file_integrity_config *app_cfg = (struct file_integrity_config *)config;
1129  char *file_path = (char *)param;
1130 
1131  if (strnlen(file_path, MAX_FILE_NAME) == MAX_FILE_NAME) {
1132  DOCA_LOG_ERR("File name is too long - MAX=%d", MAX_FILE_NAME - 1);
1133  return DOCA_ERROR_INVALID_VALUE;
1134  }
1135  strlcpy(app_cfg->file_path, file_path, MAX_FILE_NAME);
1136  return DOCA_SUCCESS;
1137 }
1138 
1139 /*
1140  * ARGP Callback - Handle Comch DOCA device PCI address parameter
1141  *
1142  * @param [in]: Input parameter
1143  * @config [in/out]: Program configuration context
1144  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
1145  */
1146 static doca_error_t dev_pci_addr_callback(void *param, void *config)
1147 {
1148  struct file_integrity_config *app_cfg = (struct file_integrity_config *)config;
1149  char *dev_pci_addr = (char *)param;
1150 
1151  if (strnlen(dev_pci_addr, DOCA_DEVINFO_PCI_ADDR_SIZE) == DOCA_DEVINFO_PCI_ADDR_SIZE) {
1152  DOCA_LOG_ERR("Entered device PCI address exceeding the maximum size of %d",
1154  return DOCA_ERROR_INVALID_VALUE;
1155  }
1156  strlcpy(app_cfg->cc_dev_pci_addr, dev_pci_addr, DOCA_DEVINFO_PCI_ADDR_SIZE);
1157  return DOCA_SUCCESS;
1158 }
1159 
1160 /*
1161  * ARGP Callback - Handle Comch DOCA device representor PCI address parameter
1162  *
1163  * @param [in]: Input parameter
1164  * @config [in/out]: Program configuration context
1165  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
1166  */
1167 static doca_error_t rep_pci_addr_callback(void *param, void *config)
1168 {
1169  struct file_integrity_config *app_cfg = (struct file_integrity_config *)config;
1170  const char *rep_pci_addr = (char *)param;
1171 
1172  if (app_cfg->mode == SERVER) {
1173  if (strnlen(rep_pci_addr, DOCA_DEVINFO_REP_PCI_ADDR_SIZE) == DOCA_DEVINFO_REP_PCI_ADDR_SIZE) {
1174  DOCA_LOG_ERR("Entered device representor PCI address exceeding the maximum size of %d",
1176  return DOCA_ERROR_INVALID_VALUE;
1177  }
1178 
1179  strlcpy(app_cfg->cc_dev_rep_pci_addr, rep_pci_addr, DOCA_DEVINFO_REP_PCI_ADDR_SIZE);
1180  }
1181 
1182  return DOCA_SUCCESS;
1183 }
1184 
1185 /*
1186  * ARGP Callback - Handle timeout parameter
1187  *
1188  * @param [in]: Input parameter
1189  * @config [in/out]: Program configuration context
1190  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
1191  */
1192 static doca_error_t timeout_callback(void *param, void *config)
1193 {
1194  struct file_integrity_config *app_cfg = (struct file_integrity_config *)config;
1195  int *timeout = (int *)param;
1196 
1197  if (*timeout <= 0) {
1198  DOCA_LOG_ERR("Timeout parameter must be positive value");
1199  return DOCA_ERROR_INVALID_VALUE;
1200  }
1201  app_cfg->timeout = *timeout;
1202  return DOCA_SUCCESS;
1203 }
1204 
1205 /*
1206  * ARGP validation Callback - check if the running mode is valid and that the input file exists in client mode
1207  *
1208  * @cfg [in]: Program configuration context
1209  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
1210  */
1212 {
1214 
1215  if (app_cfg->mode == CLIENT && (access(app_cfg->file_path, F_OK) == -1)) {
1216  DOCA_LOG_ERR("File was not found %s", app_cfg->file_path);
1217  return DOCA_ERROR_NOT_FOUND;
1218  } else if (app_cfg->mode == SERVER && strlen(app_cfg->cc_dev_rep_pci_addr) == 0) {
1219  DOCA_LOG_ERR("Missing PCI address for server");
1220  return DOCA_ERROR_NOT_FOUND;
1221  }
1222  return DOCA_SUCCESS;
1223 }
1224 
1226 {
1228 
1229  struct doca_argp_param *dev_pci_addr_param, *rep_pci_addr_param, *file_param, *timeout_param;
1230 
1231  /* Create and register DOCA Comch device PCI address */
1232  result = doca_argp_param_create(&dev_pci_addr_param);
1233  if (result != DOCA_SUCCESS) {
1234  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
1235  return result;
1236  }
1237  doca_argp_param_set_short_name(dev_pci_addr_param, "p");
1238  doca_argp_param_set_long_name(dev_pci_addr_param, "pci-addr");
1239  doca_argp_param_set_description(dev_pci_addr_param, "DOCA Comch device PCI address");
1241  doca_argp_param_set_type(dev_pci_addr_param, DOCA_ARGP_TYPE_STRING);
1242  doca_argp_param_set_mandatory(dev_pci_addr_param);
1243  result = doca_argp_register_param(dev_pci_addr_param);
1244  if (result != DOCA_SUCCESS) {
1245  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
1246  return result;
1247  }
1248 
1249  /* Create and register DOCA Comch device representor PCI address */
1250  result = doca_argp_param_create(&rep_pci_addr_param);
1251  if (result != DOCA_SUCCESS) {
1252  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
1253  return result;
1254  }
1255  doca_argp_param_set_short_name(rep_pci_addr_param, "r");
1256  doca_argp_param_set_long_name(rep_pci_addr_param, "rep-pci");
1257  doca_argp_param_set_description(rep_pci_addr_param, "DOCA Comch device representor PCI address");
1259  doca_argp_param_set_type(rep_pci_addr_param, DOCA_ARGP_TYPE_STRING);
1260  result = doca_argp_register_param(rep_pci_addr_param);
1261  if (result != DOCA_SUCCESS) {
1262  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
1263  return result;
1264  }
1265 
1266  /* Create and register message to send param */
1267  result = doca_argp_param_create(&file_param);
1268  if (result != DOCA_SUCCESS) {
1269  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
1270  return result;
1271  }
1272  doca_argp_param_set_short_name(file_param, "f");
1273  doca_argp_param_set_long_name(file_param, "file");
1274  doca_argp_param_set_description(file_param, "File to send by the client / File to write by the server");
1277  doca_argp_param_set_mandatory(file_param);
1278  result = doca_argp_register_param(file_param);
1279  if (result != DOCA_SUCCESS) {
1280  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
1281  return result;
1282  }
1283 
1284  /* Create and register timeout */
1285  result = doca_argp_param_create(&timeout_param);
1286  if (result != DOCA_SUCCESS) {
1287  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
1288  return result;
1289  }
1290  doca_argp_param_set_short_name(timeout_param, "t");
1291  doca_argp_param_set_long_name(timeout_param, "timeout");
1292  doca_argp_param_set_description(timeout_param,
1293  "Application timeout for receiving file content messages, default is 5 sec");
1296  result = doca_argp_register_param(timeout_param);
1297  if (result != DOCA_SUCCESS) {
1298  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
1299  return result;
1300  }
1301 
1302  /* Register version callback for DOCA SDK & RUNTIME */
1304  if (result != DOCA_SUCCESS) {
1305  DOCA_LOG_ERR("Failed to register version callback: %s", doca_error_get_descr(result));
1306  return result;
1307  }
1308 
1309  /* Register application callback */
1311  if (result != DOCA_SUCCESS) {
1312  DOCA_LOG_ERR("Failed to register program validation callback: %s", doca_error_get_descr(result));
1313  return result;
1314  }
1315 
1316  return result;
1317 }
#define NULL
Definition: __stddef_null.h:26
int32_t result
void * comch_utils_get_user_data(struct doca_comch_connection *connection)
Definition: comch_utils.c:254
doca_error_t comch_utils_progress_connection(struct doca_comch_connection *connection)
Definition: comch_utils.c:264
struct doca_comch_connection * comch_util_get_connection(struct comch_cfg *comch_cfg)
Definition: comch_utils.c:276
doca_error_t comch_utils_send(struct doca_comch_connection *connection, const void *msg, uint32_t len)
Definition: comch_utils.c:212
uint32_t comch_utils_get_max_buffer_size(struct comch_cfg *comch_cfg)
Definition: comch_utils.c:286
doca_error_t request_stop_ctx(struct doca_pe *pe, struct doca_ctx *ctx)
Definition: common.c:367
doca_error_t destroy_core_objects(struct program_core_objects *state)
Definition: common.c:392
doca_error_t create_core_objects(struct program_core_objects *state, uint32_t max_bufs)
Definition: common.c:302
doca_error_t open_doca_device_with_capabilities(tasks_check func, struct doca_dev **retval)
Definition: common.c:188
#define MIN(X, Y)
Definition: utils.h:30
uintptr_t addr
doca_dpa_dev_mmap_t mmap
uint64_t len
@ TRANSFER_ERROR
@ TRANSFER_COMPLETE
@ TRANSFER_IN_PROGRESS
@ TRANSFER_IDLE
DOCA_LOG_REGISTER(FILE_INTEGRITY::Core)
doca_error_t register_file_integrity_params(void)
static void uninit_async_sha_recv_data(struct server_runtime_data *server_data)
doca_error_t file_integrity_server(struct comch_cfg *comch_cfg, struct file_integrity_config *app_cfg, struct program_core_objects *state, struct doca_sha *sha_ctx)
static doca_error_t send_file(struct comch_cfg *comch_cfg, struct file_integrity_config *app_cfg, char *file_data, size_t file_size, uint8_t *file_sha, size_t sha_len, uint32_t min_partial_block_size)
void file_integrity_cleanup(struct program_core_objects *state, struct doca_sha *sha_ctx)
static void free_cb(void *addr, size_t len, void *opaque)
static doca_error_t calculate_sha(struct program_core_objects *state, struct doca_sha *sha_ctx, struct doca_buf **dst_doca_buf, char *file_data, size_t file_size)
static void sha_partial_hash_error_callback(struct doca_sha_task_partial_hash *sha_partial_hash_task, union doca_data task_user_data, union doca_data ctx_user_data)
static doca_error_t init_async_sha_recv_data(struct doca_sha *sha_ctx, struct program_core_objects *state, struct server_runtime_data *server_data, struct doca_buf *dst_doca_buf, uint32_t max_comch_msg, int fd)
static doca_error_t rep_pci_addr_callback(void *param, void *config)
static void sha_hash_completed_callback(struct doca_sha_task_hash *sha_hash_task, union doca_data task_user_data, union doca_data ctx_user_data)
doca_error_t file_integrity_init(struct file_integrity_config *app_cfg, struct program_core_objects *state, struct doca_sha **sha_ctx)
static void sha_partial_hash_completed_callback(struct doca_sha_task_partial_hash *sha_partial_hash_task, union doca_data task_user_data, union doca_data ctx_user_data)
doca_error_t file_integrity_client(struct comch_cfg *comch_cfg, struct file_integrity_config *app_cfg, struct program_core_objects *state, struct doca_sha *sha_ctx)
static doca_error_t timeout_callback(void *param, void *config)
#define DEFAULT_TIMEOUT
#define LOG_NUM_SHA_TASKS
static doca_error_t sha_partial_hash_is_supported(struct doca_devinfo *devinfo)
void server_recv_event_cb(struct doca_comch_event_msg_recv *event, uint8_t *recv_buffer, uint32_t msg_len, struct doca_comch_connection *comch_connection)
void client_recv_event_cb(struct doca_comch_event_msg_recv *event, uint8_t *recv_buffer, uint32_t msg_len, struct doca_comch_connection *comch_connection)
static void unmap_cb(void *addr, size_t len, void *opaque)
static doca_error_t args_validation_callback(void *cfg)
static void sha_hash_error_callback(struct doca_sha_task_hash *sha_hash_task, union doca_data task_user_data, union doca_data ctx_user_data)
#define SHA_ALGORITHM
static doca_error_t dev_pci_addr_callback(void *param, void *config)
static doca_error_t populate_dst_buf(struct program_core_objects *state, struct doca_buf **dst_doca_buf)
#define SLEEP_IN_NANOS
static doca_error_t file_callback(void *param, void *config)
#define MAX_FILE_NAME
static struct app_gpu_cfg app_cfg
DOCA_EXPERIMENTAL doca_error_t doca_argp_register_validation_callback(doca_argp_validation_cb_t callback)
Register program validation callback function.
DOCA_EXPERIMENTAL void doca_argp_param_set_description(struct doca_argp_param *param, const char *description)
Set the description of the program param, used during program usage.
DOCA_EXPERIMENTAL void doca_argp_param_set_long_name(struct doca_argp_param *param, const char *name)
Set the long name of the program param.
DOCA_EXPERIMENTAL void doca_argp_param_set_callback(struct doca_argp_param *param, doca_argp_param_cb_t callback)
Set the callback function of the program param.
DOCA_EXPERIMENTAL void doca_argp_param_set_mandatory(struct doca_argp_param *param)
Mark the program param as mandatory.
DOCA_EXPERIMENTAL doca_error_t doca_argp_param_create(struct doca_argp_param **param)
Create new program param.
DOCA_EXPERIMENTAL void doca_argp_param_set_type(struct doca_argp_param *param, enum doca_argp_type type)
Set the type of the param arguments.
DOCA_EXPERIMENTAL doca_error_t doca_argp_register_version_callback(doca_argp_param_cb_t callback)
Register an alternative version callback.
DOCA_EXPERIMENTAL void doca_argp_param_set_short_name(struct doca_argp_param *param, const char *name)
Set the short name of the program param.
DOCA_EXPERIMENTAL doca_error_t doca_argp_register_param(struct doca_argp_param *input_param)
Register a program flag.
@ DOCA_ARGP_TYPE_STRING
Definition: doca_argp.h:56
@ DOCA_ARGP_TYPE_INT
Definition: doca_argp.h:57
static doca_error_t doca_buf_inventory_buf_get_by_addr(struct doca_buf_inventory *inventory, struct doca_mmap *mmap, void *addr, size_t len, struct doca_buf **buf)
Allocate single element from buffer inventory and point it to the buffer defined by addr & len argume...
static doca_error_t doca_buf_inventory_buf_get_by_data(struct doca_buf_inventory *inventory, struct doca_mmap *mmap, void *data, size_t data_len, struct doca_buf **buf)
Allocate single element from buffer inventory and point it to the buffer defined by data & data_len a...
DOCA_STABLE doca_error_t doca_buf_dec_refcount(struct doca_buf *buf, uint16_t *refcount)
Decrease the object reference count by 1, if 0 reached, return the element back to the inventory.
DOCA_STABLE doca_error_t doca_buf_get_data(const struct doca_buf *buf, void **data)
Get the buffer's data.
DOCA_STABLE doca_error_t doca_buf_get_data_len(const struct doca_buf *buf, size_t *data_len)
Get buffer's data length.
DOCA_STABLE doca_error_t doca_buf_set_data(struct doca_buf *buf, void *data, size_t data_len)
DOCA_STABLE doca_error_t doca_ctx_start(struct doca_ctx *ctx)
Finalizes all configurations, and starts the DOCA CTX.
DOCA_STABLE doca_error_t doca_ctx_set_user_data(struct doca_ctx *ctx, union doca_data user_data)
set user data to context
DOCA_STABLE doca_error_t doca_ctx_stop(struct doca_ctx *ctx)
Stops the context allowing reconfiguration.
#define DOCA_DEVINFO_REP_PCI_ADDR_SIZE
Buffer size to hold PCI BDF format: "XXXX:XX:XX.X". Including a null terminator.
Definition: doca_dev.h:665
#define DOCA_DEVINFO_PCI_ADDR_SIZE
Buffer size to hold PCI BDF format: "XXXX:XX:XX.X". Including a null terminator.
Definition: doca_dev.h:313
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...
enum doca_error doca_error_t
DOCA API return codes.
DOCA_STABLE const char * doca_error_get_descr(doca_error_t error)
Returns the description string of an error code.
@ DOCA_ERROR_INVALID_VALUE
Definition: doca_error.h:44
@ DOCA_ERROR_NOT_FOUND
Definition: doca_error.h:54
@ DOCA_ERROR_BAD_STATE
Definition: doca_error.h:56
@ DOCA_ERROR_IO_FAILED
Definition: doca_error.h:55
@ DOCA_ERROR_AGAIN
Definition: doca_error.h:43
@ DOCA_SUCCESS
Definition: doca_error.h:38
@ DOCA_ERROR_NO_MEMORY
Definition: doca_error.h:45
#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_mmap_set_memrange(struct doca_mmap *mmap, void *addr, size_t len)
Set the memory range of DOCA memory map.
DOCA_STABLE doca_error_t doca_mmap_start(struct doca_mmap *mmap)
Start DOCA Memory Map.
DOCA_STABLE doca_error_t doca_mmap_set_free_cb(struct doca_mmap *mmap, doca_mmap_memrange_free_cb_t *free_cb, void *opaque)
Set callback that will free the memory range when destroying DOCA memory map.
DOCA_STABLE doca_error_t doca_mmap_stop(struct doca_mmap *mmap)
Stop DOCA Memory Map.
DOCA_STABLE doca_error_t doca_task_get_status(const struct doca_task *task)
Get task status.
DOCA_STABLE doca_error_t doca_pe_connect_ctx(struct doca_pe *pe, struct doca_ctx *ctx)
This method connects a context to a progress engine.
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.
DOCA_EXPERIMENTAL doca_error_t doca_sha_cap_get_partial_hash_block_size(struct doca_devinfo const *devinfo, enum doca_sha_algorithm algorithm, uint32_t *partial_block_size)
DOCA_EXPERIMENTAL struct doca_task * doca_sha_task_partial_hash_as_task(struct doca_sha_task_partial_hash *task)
DOCA_EXPERIMENTAL doca_error_t doca_sha_create(struct doca_dev *dev, struct doca_sha **sha)
DOCA_EXPERIMENTAL doca_error_t doca_sha_cap_get_min_dst_buf_size(struct doca_devinfo const *devinfo, enum doca_sha_algorithm algorithm, uint32_t *min_dst_buf_size)
DOCA_EXPERIMENTAL struct doca_task * doca_sha_task_hash_as_task(struct doca_sha_task_hash *task)
DOCA_EXPERIMENTAL doca_error_t doca_sha_task_partial_hash_set_is_final_buf(struct doca_sha_task_partial_hash *task)
DOCA_EXPERIMENTAL doca_error_t doca_sha_task_partial_hash_alloc_init(struct doca_sha *sha, enum doca_sha_algorithm algorithm, struct doca_buf const *src_buf, struct doca_buf *dst_buf, union doca_data user_data, struct doca_sha_task_partial_hash **task)
DOCA_EXPERIMENTAL doca_error_t doca_sha_cap_task_partial_hash_get_supported(struct doca_devinfo const *devinfo, enum doca_sha_algorithm algorithm)
DOCA_EXPERIMENTAL doca_error_t doca_sha_task_partial_hash_set_conf(struct doca_sha *sha, doca_sha_task_partial_hash_completion_cb_t task_completion_cb, doca_sha_task_partial_hash_completion_cb_t task_error_cb, uint8_t log_num_tasks)
This method sets the doca_sha partial hash task pool configuration.
DOCA_EXPERIMENTAL doca_error_t doca_sha_task_partial_hash_set_src(struct doca_sha_task_partial_hash *task, struct doca_buf const *src_buf)
DOCA_EXPERIMENTAL doca_error_t doca_sha_task_hash_set_conf(struct doca_sha *sha, doca_sha_task_hash_completion_cb_t task_completion_cb, doca_sha_task_hash_completion_cb_t task_error_cb, uint8_t log_num_tasks)
This method sets the doca_sha hash task pool configuration.
DOCA_EXPERIMENTAL doca_error_t doca_sha_destroy(struct doca_sha *sha)
DOCA_EXPERIMENTAL doca_error_t doca_sha_task_hash_alloc_init(struct doca_sha *sha, enum doca_sha_algorithm algorithm, struct doca_buf const *src_buf, struct doca_buf *dst_buf, union doca_data user_data, struct doca_sha_task_hash **task)
DOCA_EXPERIMENTAL doca_error_t doca_sha_task_hash_set_src(struct doca_sha_task_hash *task, struct doca_buf const *src_buf)
DOCA_EXPERIMENTAL doca_error_t doca_sha_cap_get_max_src_buf_size(struct doca_devinfo const *devinfo, uint64_t *max_src_buf_size)
DOCA_EXPERIMENTAL struct doca_ctx * doca_sha_as_ctx(struct doca_sha *sha)
const struct ip_frag_config * cfg
Definition: ip_frag_dp.c:0
enum transfer_state state
char file_path[MAX_FILE_NAME]
struct doca_pe * pe
Definition: common.h:51
struct doca_mmap * src_mmap
Definition: common.h:47
struct doca_buf_inventory * buf_inv
Definition: common.h:49
struct doca_dev * dev
Definition: common.h:46
struct doca_mmap * dst_mmap
Definition: common.h:48
struct doca_ctx * ctx
Definition: common.h:50
struct doca_sha_task_partial_hash * sha_partial_hash_task
struct doca_buf * sha_src_buf
struct doca_sha_task_hash * sha_hash_task
struct program_core_objects * sha_state
Convenience type for representing opaque data.
Definition: doca_types.h:56
void * ptr
Definition: doca_types.h:57
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: utils.c:123
noreturn doca_error_t sdk_version_callback(void *param, void *doca_config)
Definition: utils.c:41