NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
stream_receive_perf_core.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2025 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 <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 #include <unistd.h>
32 
33 #include <doca_argp.h>
34 #include <doca_ctx.h>
35 #include <doca_log.h>
36 #include <utils.h>
37 #include <samples/common.h>
38 
39 DOCA_LOG_REGISTER(STREAM_RECEIVE_PERF_CORE);
40 
42 
43 /*
44  * Handles the completion event for the received stream data.
45  * Invoked when the data is successfully received by the DOCA stream.
46  * It updates statistics such as the number of received packets and bytes, optionally
47  * dumps the received data in a readable format, and logs detailed information about
48  * the completion event. The data is processed buffer-by-buffer and printed (if enabled)
49  *
50  * @event_rx_data [in]: Pointer to the received event data
51  * @event_user_data [in]: User data associated with the event
52  */
53 static void handle_completion(struct doca_rmax_in_stream_event_rx_data *event_rx_data, union doca_data event_user_data);
54 
55 /*
56  * Handles error events during stream data reception.
57  * Captures and logs detailed information about any errors encountered
58  * during stream data handling, including an error code and message. It ensures that
59  * the application is aware of issues and halts the receive loop to prevent further
60  * processing in erroneous scenarios
61  *
62  * @event_rx_data [in]: Pointer to the received event data
63  * @event_user_data [in]: User data associated with the event
64  */
65 static void handle_error(struct doca_rmax_in_stream_event_rx_data *event_rx_data, union doca_data event_user_data);
66 
67 bool init_config(struct app_config *config)
68 {
69  doca_error_t ret;
70 
71  config->list = false;
72  config->dump = false;
75  config->src_ip.s_addr = 0;
76  config->dst_ip.s_addr = 0;
77  config->dev_ip.s_addr = 0;
78  config->dst_port = 0;
79  config->data_size = 1500;
80  config->hdr_size = 0;
81  config->num_elements = 262144;
82  config->sleep_us = 0;
83  config->min_packets = 0;
84  config->max_packets = 0;
85  config->affinity_mask_set = false;
86  ret = doca_rmax_cpu_affinity_create(&config->affinity_mask);
87  if (ret != DOCA_SUCCESS) {
88  DOCA_LOG_ERR("Failed to create affinity mask: %s", doca_error_get_name(ret));
89  return false;
90  }
91  return true;
92 }
93 
94 void destroy_config(struct app_config *config)
95 {
96  doca_error_t ret;
97 
98  ret = doca_rmax_cpu_affinity_destroy(config->affinity_mask);
99  if (ret != DOCA_SUCCESS)
100  DOCA_LOG_ERR("Failed to destroy affinity mask: %s", doca_error_get_name(ret));
101 }
102 
103 /*
104  * Sets the list flag in the application configuration
105  *
106  * @param [in]: Unused parameter
107  *
108  * @opaque [in]: Pointer to the application configuration
109  *
110  * @return: DOCA_SUCCESS on success
111  */
112 static doca_error_t set_list_flag(void *param, void *opaque)
113 {
114  struct app_config *config = (struct app_config *)opaque;
115 
116  (void)param;
117  config->list = true;
118 
119  return DOCA_SUCCESS;
120 }
121 
122 /*
123  * Sets the scatter type parameter in the application configuration
124  *
125  * @param [in]: Pointer to the scatter type string
126  * @opaque [in]: Pointer to the application configuration
127  * @return: DOCA_SUCCESS on success, or an error code if the scatter type is invalid
128  */
129 static doca_error_t set_scatter_type_param(void *param, void *opaque)
130 {
131  struct app_config *config = (struct app_config *)opaque;
132  const char *str = (const char *)param;
133 
134  if (strcasecmp(str, "RAW") == 0)
135  config->scatter_type = SCATTER_TYPE_RAW;
136  else if (strcasecmp(str, "ULP") == 0)
137  config->scatter_type = SCATTER_TYPE_ULP;
138  else {
139  DOCA_LOG_ERR("unknown scatter type '%s' was specified", str);
141  }
142  return DOCA_SUCCESS;
143 }
144 
145 /*
146  * Sets the timestamp format parameter in the application configuration
147  *
148  * @param [in]: Pointer to the timestamp format string
149  * @opaque [in]: Pointer to the application configuration
150  * @return: DOCA_SUCCESS on success, or an error code if the timestamp format is invalid
151  */
152 static doca_error_t set_tstamp_format_param(void *param, void *opaque)
153 {
154  struct app_config *config = (struct app_config *)opaque;
155  const char *str = (const char *)param;
156 
157  if (strcasecmp(str, "raw") == 0)
159  else if (strcasecmp(str, "free-running") == 0)
161  else if (strcasecmp(str, "synced") == 0)
163  else {
164  DOCA_LOG_ERR("unknown timestamp format '%s' was specified", str);
166  }
167  return DOCA_SUCCESS;
168 }
169 
170 /*
171  * Parses and sets an IPv4 address parameter within the application configuration.
172  * Validates the provided IP string format (e.g., `192.168.0.1`).
173  *
174  * @label [in]: Label describing the IP address type
175  * @str [in]: Pointer to the IP address string
176  * @out [out]: Pointer to the in_addr structure to store the parsed IP address
177  * @return: DOCA_SUCCESS on success, or an error code if the IP address format is invalid
178  */
179 static doca_error_t set_ip_param(const char *label, const char *str, struct in_addr *out)
180 {
181  unsigned int ip[4];
182  union {
183  uint8_t octet[4];
184  uint32_t addr;
185  } addr;
186  char dummy;
187 
188  if (sscanf(str, "%u.%u.%u.%u%c", &ip[0], &ip[1], &ip[2], &ip[3], &dummy) == 4 && ip[0] < 256 && ip[1] < 256 &&
189  ip[2] < 256 && ip[3] < 256) {
190  addr.octet[0] = ip[0];
191  addr.octet[1] = ip[1];
192  addr.octet[2] = ip[2];
193  addr.octet[3] = ip[3];
194  out->s_addr = addr.addr;
195  } else {
196  DOCA_LOG_ERR("bad %s IP address format '%s'", label, str);
198  }
199  return DOCA_SUCCESS;
200 }
201 
202 /*
203  * Sets the source IP address parameter in the application configuration
204  *
205  * @param [in]: Pointer to the IP address string
206  * @opaque [in]: Pointer to the application configuration
207  * @return: DOCA_SUCCESS on success, or an error code if the IP address format is invalid
208  */
209 static doca_error_t set_src_ip_param(void *param, void *opaque)
210 {
211  struct app_config *config = (struct app_config *)opaque;
212  const char *str = (const char *)param;
213 
214  return set_ip_param("source", str, &config->src_ip);
215 }
216 
217 /*
218  * Sets the destination IP address parameter in the application configuration
219  *
220  * @param [in]: Pointer to the IP address string
221  * @opaque [in]: Pointer to the application configuration
222  * @return: DOCA_SUCCESS on success, or an error code if the IP address format is invalid
223  */
224 static doca_error_t set_dst_ip_param(void *param, void *opaque)
225 {
226  struct app_config *config = (struct app_config *)opaque;
227  const char *str = (const char *)param;
228 
229  return set_ip_param("destination", str, &config->dst_ip);
230 }
231 
232 /*
233  * Sets the device IP address parameter in the application configuration
234  *
235  * @param [in]: Pointer to the IP address string
236  * @opaque [in]: Pointer to the application configuration
237  * @return: DOCA_SUCCESS on success, or an error code if the IP address format is invalid
238  */
239 static doca_error_t set_dev_ip_param(void *param, void *opaque)
240 {
241  struct app_config *config = (struct app_config *)opaque;
242  const char *str = (const char *)param;
243 
244  return set_ip_param("local interface", str, &config->dev_ip);
245 }
246 
247 /*
248  * Sets the destination port parameter in the application configuration
249  *
250  * @param [in]: Pointer to the port number
251  * @opaque [in]: Pointer to the application configuration
252  * @return: DOCA_SUCCESS on success, or an error code if the port number is invalid
253  */
254 static doca_error_t set_dst_port_param(void *param, void *opaque)
255 {
256  struct app_config *config = (struct app_config *)opaque;
257  const int value = *(const int *)param;
258 
259  if (value > 0 && value <= UINT16_MAX)
260  config->dst_port = (uint16_t)value;
261  else {
262  DOCA_LOG_ERR("bad source port '%d' was specified", value);
264  }
265  return DOCA_SUCCESS;
266 }
267 
268 /*
269  * Sets the data size parameter in the application configuration
270  *
271  * @param [in]: Pointer to the data size
272  * @opaque [in]: Pointer to the application configuration
273  * @return: DOCA_SUCCESS on success, or an error code if the data size is invalid
274  */
275 static doca_error_t set_data_size_param(void *param, void *opaque)
276 {
277  struct app_config *config = (struct app_config *)opaque;
278  const int value = *(const int *)param;
279 
280  if (value >= 0 && value <= UINT16_MAX)
281  config->data_size = (uint16_t)value;
282  else {
283  DOCA_LOG_ERR("bad data size '%d' was specified", value);
285  }
286  return DOCA_SUCCESS;
287 }
288 
289 /*
290  * Sets the header size parameter in the application configuration
291  *
292  * @param [in]: Pointer to the header size
293  * @opaque [in]: Pointer to the application configuration
294  * @return: DOCA_SUCCESS on success, or an error code if the header size is invalid
295  */
296 static doca_error_t set_hdr_size_param(void *param, void *opaque)
297 {
298  struct app_config *config = (struct app_config *)opaque;
299  const int value = *(const int *)param;
300 
301  if (value >= 0 && value <= UINT16_MAX)
302  config->hdr_size = (uint16_t)value;
303  else {
304  DOCA_LOG_ERR("bad header size '%d' was specified", value);
306  }
307  return DOCA_SUCCESS;
308 }
309 
310 /*
311  * Sets the number of elements parameter in the application configuration
312  *
313  * @param [in]: Pointer to the number of elements
314  * @opaque [in]: Pointer to the application configuration
315  * @return: DOCA_SUCCESS on success, or an error code if the number of elements is invalid
316  */
317 static doca_error_t set_num_elements_param(void *param, void *opaque)
318 {
319  struct app_config *config = (struct app_config *)opaque;
320  const int value = *(const int *)param;
321 
322  if (value > 0 && value <= UINT32_MAX)
323  config->num_elements = (uint32_t)value;
324  else {
325  DOCA_LOG_ERR("bad number of elements '%d' was specified", value);
327  }
328  return DOCA_SUCCESS;
329 }
330 
331 /*
332  * Sets the CPU affinity parameter in the application configuration.
333  * Parses a string of CPU core indices (e.g., "0,1,2") to bind the application
334  * to specific cores, optimizing resource usage and performance.
335  *
336  * @param [in]: Pointer to the CPU affinity string
337  * @opaque [in]: Pointer to the application configuration
338  * @return: DOCA_SUCCESS on success, or an error code if the CPU affinity is invalid
339  */
340 static doca_error_t set_cpu_affinity_param(void *param, void *opaque)
341 {
342  struct app_config *config = (struct app_config *)opaque;
343  const char *input = (const char *)param;
344  char *str, *alloc;
346 
347  alloc = str = strdup(input);
348  if (str == NULL) {
349  DOCA_LOG_ERR("unable to allocate memory: %s", strerror(errno));
350  return DOCA_ERROR_NO_MEMORY;
351  }
352 
353  while ((str = strtok(str, ",")) != NULL) {
354  int idx;
355  char dummy;
356 
357  if (sscanf(str, "%d%c", &idx, &dummy) != 1) {
358  DOCA_LOG_ERR("bad CPU index '%s' was specified", str);
360  goto exit;
361  }
362 
363  ret = doca_rmax_cpu_affinity_set(config->affinity_mask, idx);
364  if (ret != DOCA_SUCCESS) {
365  DOCA_LOG_ERR("error setting CPU index '%d' in affinity mask", idx);
366  goto exit;
367  }
368 
369  str = NULL;
370  }
371 
372  config->affinity_mask_set = true;
373 exit:
374  free(alloc);
375 
376  return ret;
377 }
378 
379 /*
380  * Sets the sleep duration parameter in the application configuration
381  *
382  * @param [in]: Pointer to the sleep duration
383  * @opaque [in]: Pointer to the application configuration
384  * @return: DOCA_SUCCESS on success, or an error code if the sleep duration is invalid
385  */
386 static doca_error_t set_sleep_param(void *param, void *opaque)
387 {
388  struct app_config *config = (struct app_config *)opaque;
389  const int value = *(const int *)param;
390 
391  if (value > 0)
392  config->sleep_us = value;
393  else {
394  DOCA_LOG_ERR("bad sleep duration '%d' was specified", value);
396  }
397  return DOCA_SUCCESS;
398 }
399 
400 /*
401  * Sets the minimum packets number parameter in the application configuration
402  *
403  * @param [in]: Pointer to the minimum packets
404  * @opaque [in]: Pointer to the application configuration
405  * @return: DOCA_SUCCESS on success, or an error code if the minimum packets is invalid
406  */
407 static doca_error_t set_min_packets_param(void *param, void *opaque)
408 {
409  struct app_config *config = (struct app_config *)opaque;
410  const int value = *(const int *)param;
411 
412  if (value >= 0 && value <= UINT32_MAX)
413  config->min_packets = (uint32_t)value;
414  else {
415  DOCA_LOG_ERR("bad minimum packets count '%d' was specified", value);
417  }
418  return DOCA_SUCCESS;
419 }
420 
421 /*
422  * Sets the maximum packets number parameter in the application configuration
423  *
424  * @param [in]: Pointer to the maximum packets
425  * @opaque [in]: Pointer to the application configuration
426  * @return: DOCA_SUCCESS on success, or an error code if the maximum packets is invalid
427  */
428 static doca_error_t set_max_packets_param(void *param, void *opaque)
429 {
430  struct app_config *config = (struct app_config *)opaque;
431  const int value = *(const int *)param;
432 
433  if (value > 0 && value <= UINT32_MAX)
434  config->max_packets = (uint32_t)value;
435  else {
436  DOCA_LOG_ERR("bad maximum packets count '%d' was specified", value);
438  }
439  return DOCA_SUCCESS;
440 }
441 
442 /*
443  * Sets the dump flag in the application configuration.
444  * Enables the option to dump packet content for debugging or analysis purposes.
445  * If the flag is set, the application will provide a content dump of all received packets
446  * during runtime.
447  *
448  * @param [in]: Unused parameter
449  * @opaque [in]: Pointer to the application configuration
450  * @return: DOCA_SUCCESS on success
451  */
452 static doca_error_t set_dump_flag(void *param, void *opaque)
453 {
454  struct app_config *config = (struct app_config *)opaque;
455 
456  (void)param;
457  config->dump = true;
458 
459  return DOCA_SUCCESS;
460 }
461 
463 {
464  doca_error_t ret;
465  struct doca_argp_param *list_flag;
466  struct doca_argp_param *scatter_type_param;
467  struct doca_argp_param *tstamp_format_param;
468  struct doca_argp_param *dev_ip_param;
469  struct doca_argp_param *dst_ip_param;
470  struct doca_argp_param *src_ip_param;
471  struct doca_argp_param *dst_port_param;
472  struct doca_argp_param *hdr_size_param;
473  struct doca_argp_param *data_size_param;
474  struct doca_argp_param *num_elements_param;
475  struct doca_argp_param *cpu_affinity_param;
476  struct doca_argp_param *min_packets_param;
477  struct doca_argp_param *max_packets_param;
478  struct doca_argp_param *sleep_param;
479  struct doca_argp_param *dump_flag;
480 
481  /* --list flag */
482  ret = doca_argp_param_create(&list_flag);
483  if (ret != DOCA_SUCCESS) {
484  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
485  return false;
486  }
487  doca_argp_param_set_long_name(list_flag, "list");
488  doca_argp_param_set_description(list_flag, "List available devices");
491  ret = doca_argp_register_param(list_flag);
492  if (ret != DOCA_SUCCESS) {
493  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
494  return false;
495  }
496 
497  /* --scatter-type parameter */
498  ret = doca_argp_param_create(&scatter_type_param);
499  if (ret != DOCA_SUCCESS) {
500  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
501  return false;
502  }
503  doca_argp_param_set_long_name(scatter_type_param, "scatter-type");
504  doca_argp_param_set_description(scatter_type_param, "Scattering type: RAW (default) or ULP");
506  doca_argp_param_set_type(scatter_type_param, DOCA_ARGP_TYPE_STRING);
507  ret = doca_argp_register_param(scatter_type_param);
508  if (ret != DOCA_SUCCESS) {
509  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
510  return false;
511  }
512 
513  /* --tstamp-format parameter */
514  ret = doca_argp_param_create(&tstamp_format_param);
515  if (ret != DOCA_SUCCESS) {
516  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
517  return false;
518  }
519  doca_argp_param_set_long_name(tstamp_format_param, "tstamp-format");
520  doca_argp_param_set_description(tstamp_format_param, "Timestamp format: raw (default), free-running or synced");
522  doca_argp_param_set_type(tstamp_format_param, DOCA_ARGP_TYPE_STRING);
523  ret = doca_argp_register_param(tstamp_format_param);
524  if (ret != DOCA_SUCCESS) {
525  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
526  return false;
527  }
528 
529  /* -s,--src-ip parameter */
530  ret = doca_argp_param_create(&src_ip_param);
531  if (ret != DOCA_SUCCESS) {
532  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
533  return false;
534  }
535  doca_argp_param_set_short_name(src_ip_param, "s");
536  doca_argp_param_set_long_name(src_ip_param, "src-ip");
537  doca_argp_param_set_description(src_ip_param, "Source address to read from");
540  ret = doca_argp_register_param(src_ip_param);
541  if (ret != DOCA_SUCCESS) {
542  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
543  return false;
544  }
545 
546  /* -d,--dst-ip parameter */
547  ret = doca_argp_param_create(&dst_ip_param);
548  if (ret != DOCA_SUCCESS) {
549  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
550  return false;
551  }
552  doca_argp_param_set_short_name(dst_ip_param, "d");
553  doca_argp_param_set_long_name(dst_ip_param, "dst-ip");
554  doca_argp_param_set_description(dst_ip_param, "Destination address to bind to");
557  ret = doca_argp_register_param(dst_ip_param);
558  if (ret != DOCA_SUCCESS) {
559  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
560  return false;
561  }
562 
563  /* -i,--local-ip parameter */
564  ret = doca_argp_param_create(&dev_ip_param);
565  if (ret != DOCA_SUCCESS) {
566  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
567  return false;
568  }
569  doca_argp_param_set_short_name(dev_ip_param, "i");
570  doca_argp_param_set_long_name(dev_ip_param, "local-ip");
571  doca_argp_param_set_description(dev_ip_param, "IP of the local interface to receive data");
574  ret = doca_argp_register_param(dev_ip_param);
575  if (ret != DOCA_SUCCESS) {
576  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
577  return false;
578  }
579 
580  /* -p,--dst-port parameter */
581  ret = doca_argp_param_create(&dst_port_param);
582  if (ret != DOCA_SUCCESS) {
583  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
584  return false;
585  }
586  doca_argp_param_set_short_name(dst_port_param, "p");
587  doca_argp_param_set_long_name(dst_port_param, "dst-port");
588  doca_argp_param_set_description(dst_port_param, "Destination port to read from");
591  ret = doca_argp_register_param(dst_port_param);
592  if (ret != DOCA_SUCCESS) {
593  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
594  return false;
595  }
596 
597  /* -K,--packets parameter */
598  ret = doca_argp_param_create(&num_elements_param);
599  if (ret != DOCA_SUCCESS) {
600  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
601  return false;
602  }
603  doca_argp_param_set_short_name(num_elements_param, "K");
604  doca_argp_param_set_long_name(num_elements_param, "packets");
605  doca_argp_param_set_description(num_elements_param,
606  "Number of packets to allocate memory for (default 262144)");
608  doca_argp_param_set_type(num_elements_param, DOCA_ARGP_TYPE_INT);
609  ret = doca_argp_register_param(num_elements_param);
610  if (ret != DOCA_SUCCESS) {
611  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
612  return false;
613  }
614 
615  /* -y,--payload-size parameter */
616  ret = doca_argp_param_create(&data_size_param);
617  if (ret != DOCA_SUCCESS) {
618  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
619  return false;
620  }
621  doca_argp_param_set_short_name(data_size_param, "y");
622  doca_argp_param_set_long_name(data_size_param, "payload-size");
623  doca_argp_param_set_description(data_size_param, "Packet's payload size (default 1500)");
626  ret = doca_argp_register_param(data_size_param);
627  if (ret != DOCA_SUCCESS) {
628  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
629  return false;
630  }
631 
632  /* -e,--app-hdr-size parameter */
633  ret = doca_argp_param_create(&hdr_size_param);
634  if (ret != DOCA_SUCCESS) {
635  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
636  return false;
637  }
638  doca_argp_param_set_short_name(hdr_size_param, "e");
639  doca_argp_param_set_long_name(hdr_size_param, "app-hdr-size");
640  doca_argp_param_set_description(hdr_size_param, "Packet's application header size (default 0)");
643  ret = doca_argp_register_param(hdr_size_param);
644  if (ret != DOCA_SUCCESS) {
645  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
646  return false;
647  }
648 
649  /* -a,--cpu-affinity parameter */
650  ret = doca_argp_param_create(&cpu_affinity_param);
651  if (ret != DOCA_SUCCESS) {
652  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
653  return false;
654  }
655  doca_argp_param_set_short_name(cpu_affinity_param, "a");
656  doca_argp_param_set_long_name(cpu_affinity_param, "cpu-affinity");
657  doca_argp_param_set_description(cpu_affinity_param,
658  "Comma separated list of CPU affinity cores for the application main thread");
660  doca_argp_param_set_type(cpu_affinity_param, DOCA_ARGP_TYPE_STRING);
661  ret = doca_argp_register_param(cpu_affinity_param);
662  if (ret != DOCA_SUCCESS) {
663  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
664  return false;
665  }
666 
667  /* --sleep parameter */
668  ret = doca_argp_param_create(&sleep_param);
669  if (ret != DOCA_SUCCESS) {
670  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
671  return false;
672  }
673  doca_argp_param_set_long_name(sleep_param, "sleep");
674  doca_argp_param_set_description(sleep_param, "Amount of microseconds to sleep between requests (default 0)");
677  ret = doca_argp_register_param(sleep_param);
678  if (ret != DOCA_SUCCESS) {
679  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
680  return false;
681  }
682 
683  /* --min parameter */
684  ret = doca_argp_param_create(&min_packets_param);
685  if (ret != DOCA_SUCCESS) {
686  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
687  return false;
688  }
689  doca_argp_param_set_long_name(min_packets_param, "min");
690  doca_argp_param_set_description(min_packets_param,
691  "Block until at least this number of packets are received (default 0)");
693  doca_argp_param_set_type(min_packets_param, DOCA_ARGP_TYPE_INT);
694  ret = doca_argp_register_param(min_packets_param);
695  if (ret != DOCA_SUCCESS) {
696  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
697  return false;
698  }
699 
700  /* --max parameter */
701  ret = doca_argp_param_create(&max_packets_param);
702  if (ret != DOCA_SUCCESS) {
703  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
704  return false;
705  }
706  doca_argp_param_set_long_name(max_packets_param, "max");
707  doca_argp_param_set_description(max_packets_param, "Maximum number of packets to return in one completion");
709  doca_argp_param_set_type(max_packets_param, DOCA_ARGP_TYPE_INT);
710  ret = doca_argp_register_param(max_packets_param);
711  if (ret != DOCA_SUCCESS) {
712  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
713  return false;
714  }
715 
716  /* --dump flag */
717  ret = doca_argp_param_create(&dump_flag);
718  if (ret != DOCA_SUCCESS) {
719  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(ret));
720  return false;
721  }
722  doca_argp_param_set_long_name(dump_flag, "dump");
723  doca_argp_param_set_description(dump_flag, "Dump packet content");
726  ret = doca_argp_register_param(dump_flag);
727  if (ret != DOCA_SUCCESS) {
728  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(ret));
729  return false;
730  }
731 
732  /* version callback */
734  if (ret != DOCA_SUCCESS) {
735  DOCA_LOG_ERR("Failed to register version callback: %s", doca_error_get_name(ret));
736  return false;
737  }
738 
739  return true;
740 }
741 
742 bool mandatory_args_set(struct app_config *config)
743 {
744  bool status = true;
745 
746  if (config->dev_ip.s_addr == 0) {
747  DOCA_LOG_ERR("Local interface IP is not set");
748  status = false;
749  }
750  if (config->dst_ip.s_addr == 0) {
751  DOCA_LOG_ERR("Destination multicast IP is not set");
752  status = false;
753  }
754  if (config->src_ip.s_addr == 0) {
755  DOCA_LOG_ERR("Source IP is not set");
756  status = false;
757  }
758  if (config->dst_port == 0) {
759  DOCA_LOG_ERR("Destination port is not set");
760  status = false;
761  }
762  return status;
763 }
764 
765 void list_devices(void)
766 {
767  struct doca_devinfo **devinfo;
768  uint32_t nb_devs;
769  doca_error_t ret;
770 
771  ret = doca_devinfo_create_list(&devinfo, &nb_devs);
772  if (ret != DOCA_SUCCESS) {
773  DOCA_LOG_ERR("Failed to enumerate devices: %s", doca_error_get_name(ret));
774  return;
775  }
776  DOCA_LOG_INFO("Iface\t\tIB dev\t\tBus ID\tIP addr\t\tPTP\n");
777  for (uint32_t i = 0; i < nb_devs; ++i) {
778  char dev_pci_addr[DOCA_DEVINFO_PCI_ADDR_SIZE];
779  char netdev[DOCA_DEVINFO_IFACE_NAME_SIZE];
780  char ibdev[DOCA_DEVINFO_IBDEV_NAME_SIZE];
781  uint8_t addr[4];
782  bool has_ptp = false;
783 
784  /* get network interface name */
785  ret = doca_devinfo_get_iface_name(devinfo[i], netdev, sizeof(netdev));
786  if (ret != DOCA_SUCCESS) {
787  DOCA_LOG_WARN("Failed to get interface name for device %d: %s", i, doca_error_get_name(ret));
788  continue;
789  }
790  /* get Infiniband device name */
791  ret = doca_devinfo_get_ibdev_name(devinfo[i], ibdev, sizeof(ibdev));
792  if (ret != DOCA_SUCCESS) {
793  DOCA_LOG_WARN("Failed to get Infiniband name for device %d: %s", i, doca_error_get_name(ret));
794  continue;
795  }
796  /* get PCI address */
797  ret = doca_devinfo_get_pci_addr_str(devinfo[i], dev_pci_addr);
798  if (ret != DOCA_SUCCESS) {
799  DOCA_LOG_WARN("Failed to get PCI address for device %d: %s", i, doca_error_get_name(ret));
800  continue;
801  }
802  /* get IP address */
803  ret = doca_devinfo_get_ipv4_addr(devinfo[i], (uint8_t *)&addr, sizeof(addr));
804  if (ret == DOCA_SUCCESS) {
805  /* query PTP capability */
806  ret = doca_rmax_get_ptp_clock_supported(devinfo[i]);
807  switch (ret) {
808  case DOCA_SUCCESS:
809  has_ptp = true;
810  break;
812  has_ptp = false;
813  break;
814  default: {
815  DOCA_LOG_WARN("Failed to query PTP capability for device %d: %s",
816  i,
817  doca_error_get_name(ret));
818  continue;
819  }
820  }
821  } else {
822  if (ret != DOCA_ERROR_NOT_FOUND)
823  DOCA_LOG_WARN("Failed to query IP address for device %d: %s",
824  i,
825  doca_error_get_name(ret));
826  }
827 
828  DOCA_LOG_INFO("%-8s\t%-8s\t%-8s\t%03d.%03d.%03d.%03d\t%c\n",
829  netdev,
830  ibdev,
831  dev_pci_addr,
832  addr[0],
833  addr[1],
834  addr[2],
835  addr[3],
836  (has_ptp) ? 'y' : 'n');
837  }
838  ret = doca_devinfo_destroy_list(devinfo);
839  if (ret != DOCA_SUCCESS)
840  DOCA_LOG_ERR("Failed to clean up devices list: %s", doca_error_get_name(ret));
841 }
842 
843 struct doca_dev *open_device(struct in_addr *dev_ip)
844 {
845  struct doca_devinfo **devinfo;
846  struct doca_devinfo *found_devinfo = NULL;
847  uint32_t nb_devs;
848  doca_error_t ret;
849  struct in_addr addr;
850  struct doca_dev *dev = NULL;
851 
852  ret = doca_devinfo_create_list(&devinfo, &nb_devs);
853  if (ret != DOCA_SUCCESS) {
854  DOCA_LOG_ERR("Failed to enumerate devices: %s", doca_error_get_name(ret));
855  return NULL;
856  }
857  for (uint32_t i = 0; i < nb_devs; ++i) {
858  ret = doca_devinfo_get_ipv4_addr(devinfo[i], (uint8_t *)&addr, sizeof(addr));
859  if (ret != DOCA_SUCCESS)
860  continue;
861  if (addr.s_addr != dev_ip->s_addr)
862  continue;
863  found_devinfo = devinfo[i];
864  break;
865  }
866  if (found_devinfo) {
867  ret = doca_dev_open(found_devinfo, &dev);
868  if (ret != DOCA_SUCCESS)
869  DOCA_LOG_WARN("Error opening network device: %s", doca_error_get_name(ret));
870  } else
871  DOCA_LOG_ERR("Device not found");
872 
873  ret = doca_devinfo_destroy_list(devinfo);
874  if (ret != DOCA_SUCCESS)
875  DOCA_LOG_WARN("Failed to clean up devices list: %s", doca_error_get_name(ret));
876 
877  return dev;
878 }
879 
880 /*
881  * Frees allocated memory with the specified callback
882  *
883  * @addr [in]: Pointer to the allocated memory
884  * @len [in]: Length of the allocated memory
885  * @opaque [in]: Unused parameter
886  */
887 static void free_callback(void *addr, size_t len, void *opaque)
888 {
889  (void)len;
890  (void)opaque;
891  free(addr);
892 }
893 
894 doca_error_t init_globals(struct app_config *config, struct doca_dev *dev, struct globals *globals)
895 {
896  doca_error_t ret;
897  size_t num_buffers = (config->hdr_size > 0) ? 2 : 1;
898 
899  /* create memory-related DOCA objects */
900  ret = doca_mmap_create(&globals->mmap);
901  if (ret != DOCA_SUCCESS) {
902  DOCA_LOG_ERR("Error creating mmap: %s", doca_error_get_name(ret));
903  return ret;
904  }
905  ret = doca_mmap_add_dev(globals->mmap, dev);
906  if (ret != DOCA_SUCCESS) {
907  DOCA_LOG_ERR("Error adding device to mmap: %s", doca_error_get_name(ret));
908  return ret;
909  }
910  /* set mmap free callback */
912  if (ret != DOCA_SUCCESS) {
913  DOCA_LOG_ERR("Failed to set mmap free callback: %s", doca_error_get_name(ret));
914  return ret;
915  }
916  ret = doca_buf_inventory_create(num_buffers, &globals->inventory);
917  if (ret != DOCA_SUCCESS) {
918  DOCA_LOG_ERR("Error creating inventory: %s", doca_error_get_name(ret));
919  return ret;
920  }
922  if (ret != DOCA_SUCCESS) {
923  DOCA_LOG_ERR("Error starting inventory: %s", doca_error_get_name(ret));
924  return ret;
925  }
926 
927  ret = doca_pe_create(&globals->pe);
928  if (ret != DOCA_SUCCESS) {
929  DOCA_LOG_ERR("Error creating progress engine: %s", doca_error_get_name(ret));
930  return ret;
931  }
932 
933  return DOCA_SUCCESS;
934 }
935 
936 bool destroy_globals(struct globals *globals, struct doca_dev *dev)
937 {
938  doca_error_t ret;
939  bool is_ok = true;
940 
941  ret = doca_pe_destroy(globals->pe);
942  if (ret != DOCA_SUCCESS) {
943  DOCA_LOG_WARN("Error destroying progress engine: %s", doca_error_get_name(ret));
944  is_ok = false;
945  }
947  if (ret != DOCA_SUCCESS) {
948  DOCA_LOG_WARN("Error stopping inventory: %s", doca_error_get_name(ret));
949  is_ok = false;
950  }
952  if (ret != DOCA_SUCCESS) {
953  DOCA_LOG_WARN("Error destroying inventory: %s", doca_error_get_name(ret));
954  is_ok = false;
955  }
956  /* will also free all allocated memory via callback */
958  if (ret != DOCA_SUCCESS) {
959  DOCA_LOG_WARN("Error destroying mmap: %s", doca_error_get_name(ret));
960  is_ok = false;
961  }
962 
963  return is_ok;
964 }
965 
967  struct doca_dev *dev,
968  struct globals *globals,
969  struct stream_data *data)
970 {
971  static const size_t page_size = 4096;
972  doca_error_t ret;
973  doca_error_t err;
974  size_t num_buffers;
975  size_t size[MAX_BUFFERS];
976  void *ptr[MAX_BUFFERS];
977  union doca_data event_user_data;
978  char *ptr_memory = NULL;
979 
980  memset(&size, 0, sizeof(size));
981 
982  /* create stream object */
983  ret = doca_rmax_in_stream_create(dev, &data->stream);
984  if (ret != DOCA_SUCCESS)
985  return ret;
986 
987  /* Register Rx data event handlers */
988  event_user_data.ptr = (void *)data;
989  ret = doca_rmax_in_stream_event_rx_data_register(data->stream, event_user_data, handle_completion, handle_error);
990  if (ret != DOCA_SUCCESS)
991  goto destroy_stream;
992  /* fill stream parameters */
993  switch (config->scatter_type) {
994  case SCATTER_TYPE_RAW:
995  ret = doca_rmax_in_stream_set_scatter_type_raw(data->stream);
996  break;
997  case SCATTER_TYPE_ULP:
998  ret = doca_rmax_in_stream_set_scatter_type_ulp(data->stream);
999  break;
1000  }
1001  if (ret != DOCA_SUCCESS)
1002  goto destroy_stream;
1003  switch (config->tstamp_format) {
1005  ret = doca_rmax_in_stream_set_timestamp_format_raw_counter(data->stream);
1006  break;
1008  ret = doca_rmax_in_stream_set_timestamp_format_free_running(data->stream);
1009  break;
1011  ret = doca_rmax_in_stream_set_timestamp_format_ptp_synced(data->stream);
1012  break;
1013  }
1014  if (ret != DOCA_SUCCESS)
1015  goto destroy_stream;
1016  ret = doca_rmax_in_stream_set_elements_count(data->stream, config->num_elements);
1017  if (ret != DOCA_SUCCESS)
1018  goto destroy_stream;
1019  ret = doca_rmax_in_stream_set_min_packets(data->stream, config->min_packets);
1020  if (ret != DOCA_SUCCESS)
1021  goto destroy_stream;
1022  if (config->max_packets > 0) {
1023  ret = doca_rmax_in_stream_set_max_packets(data->stream, config->max_packets);
1024  if (ret != DOCA_SUCCESS)
1025  goto destroy_stream;
1026  }
1027 
1028  if (config->hdr_size == 0) {
1029  num_buffers = 1;
1030  data->pkt_size[0] = config->data_size;
1031  } else {
1032  /* Header-Data Split mode */
1033  num_buffers = 2;
1034  data->pkt_size[0] = config->hdr_size;
1035  data->pkt_size[1] = config->data_size;
1036  }
1037 
1038  data->num_buffers = num_buffers;
1039  ret = doca_rmax_in_stream_set_memblks_count(data->stream, num_buffers);
1040  if (ret != DOCA_SUCCESS)
1041  goto destroy_stream;
1042  ret = doca_rmax_in_stream_memblk_desc_set_min_size(data->stream, data->pkt_size);
1043  if (ret != DOCA_SUCCESS)
1044  goto destroy_stream;
1045  ret = doca_rmax_in_stream_memblk_desc_set_max_size(data->stream, data->pkt_size);
1046  if (ret != DOCA_SUCCESS)
1047  goto destroy_stream;
1048 
1049  /* query buffer size */
1050  ret = doca_rmax_in_stream_get_memblk_size(data->stream, size);
1051  if (ret != DOCA_SUCCESS)
1052  goto destroy_stream;
1053  /* query stride size */
1054  ret = doca_rmax_in_stream_get_memblk_stride_size(data->stream, data->stride_size);
1055  if (ret != DOCA_SUCCESS)
1056  goto destroy_stream;
1057 
1058  /* allocate memory */
1059  ptr_memory = aligned_alloc(page_size, size[0] + size[1]);
1060  if (ptr_memory == NULL) {
1061  DOCA_LOG_ERR("Failed to allocate memory size: %zu", size[0] + size[1]);
1062  ret = DOCA_ERROR_NO_MEMORY;
1063  goto destroy_stream;
1064  }
1065 
1066  ret = doca_mmap_set_memrange(globals->mmap, ptr_memory, size[0] + size[1]);
1067  if (ret != DOCA_SUCCESS) {
1068  DOCA_LOG_ERR("Failed to set mmap memory range, %p, size %zu: %s",
1069  ptr_memory,
1070  size[0] + size[1],
1071  doca_error_get_name(ret));
1072  goto free_memory;
1073  }
1074 
1075  /* start mmap */
1076  ret = doca_mmap_start(globals->mmap);
1077  if (ret != DOCA_SUCCESS) {
1078  DOCA_LOG_ERR("Error starting mmap: %s", doca_error_get_name(ret));
1079  goto free_memory;
1080  }
1081 
1082  if (num_buffers == 1) {
1083  ptr[0] = ptr_memory;
1084  } else {
1085  ptr[0] = ptr_memory; /* header */
1086  ptr[1] = ptr_memory + size[0]; /* data */
1087  }
1088 
1089  /* build memory buffer chain */
1090  for (size_t i = 0; i < num_buffers; ++i) {
1091  struct doca_buf *buf;
1092 
1093  if (ptr[i] == NULL) {
1094  ret = DOCA_ERROR_NO_MEMORY;
1095  if (i > 0)
1096  goto destroy_buffers;
1097  goto free_memory;
1098  }
1099  ret = doca_buf_inventory_buf_get_by_addr(globals->inventory, globals->mmap, ptr[i], size[i], &buf);
1100  if (ret != DOCA_SUCCESS) {
1101  if (i > 0)
1102  goto destroy_buffers;
1103  goto free_memory;
1104  }
1105  if (i == 0)
1106  data->buffer = buf;
1107  else {
1108  /* chain buffers */
1109  ret = doca_buf_chain_list(data->buffer, buf);
1110  if (ret != DOCA_SUCCESS)
1111  goto destroy_buffers;
1112  }
1113  }
1114  /* set memory buffer(s) */
1115  ret = doca_rmax_in_stream_set_memblk(data->stream, data->buffer);
1116  if (ret != DOCA_SUCCESS)
1117  goto destroy_buffers;
1118 
1119  /* connect to progress engine */
1120  ret = doca_pe_connect_ctx(globals->pe, doca_rmax_in_stream_as_ctx(data->stream));
1121  if (ret != DOCA_SUCCESS)
1122  goto destroy_buffers;
1123 
1124  /* start stream */
1125  ret = doca_ctx_start(doca_rmax_in_stream_as_ctx(data->stream));
1126  if (ret != DOCA_SUCCESS)
1127  goto destroy_buffers;
1128 
1129  /* attach a flow */
1130  ret = doca_rmax_flow_create(&data->flow);
1131  if (ret != DOCA_SUCCESS)
1132  goto stop_stream;
1133  ret = doca_rmax_flow_set_src_ip(data->flow, &config->src_ip);
1134  if (ret != DOCA_SUCCESS)
1135  goto destroy_flow;
1136  ret = doca_rmax_flow_set_dst_ip(data->flow, &config->dst_ip);
1137  if (ret != DOCA_SUCCESS)
1138  goto destroy_flow;
1139  ret = doca_rmax_flow_set_dst_port(data->flow, config->dst_port);
1140  if (ret != DOCA_SUCCESS)
1141  goto destroy_flow;
1142  ret = doca_rmax_flow_attach(data->flow, data->stream);
1143  if (ret != DOCA_SUCCESS)
1144  goto destroy_flow;
1145 
1146  data->recv_pkts = 0;
1147  data->recv_bytes = 0;
1148  data->dump = config->dump;
1149 
1150  return DOCA_SUCCESS;
1151 destroy_flow:
1152  err = doca_rmax_flow_destroy(data->flow);
1153  if (err != DOCA_SUCCESS)
1154  DOCA_LOG_WARN("Error destroying flow: %s", doca_error_get_name(err));
1155 stop_stream:
1156  err = doca_ctx_stop(doca_rmax_in_stream_as_ctx(data->stream));
1157  if (err != DOCA_SUCCESS)
1158  DOCA_LOG_WARN("Error stopping context: %s", doca_error_get_name(err));
1159 destroy_buffers:
1160  err = doca_buf_dec_refcount(data->buffer, NULL);
1161  if (err != DOCA_SUCCESS)
1162  DOCA_LOG_WARN("Error removing buffers: %s", doca_error_get_name(err));
1163 free_memory:
1164  free(ptr_memory);
1166  err = doca_rmax_in_stream_destroy(data->stream);
1167  if (err != DOCA_SUCCESS)
1168  DOCA_LOG_WARN("Error destroying stream: %s", doca_error_get_name(err));
1169  return ret;
1170 }
1171 
1172 bool destroy_stream(struct doca_dev *dev, struct globals *globals, struct stream_data *data)
1173 {
1174  doca_error_t ret;
1175  bool is_ok = true;
1176 
1177  /* detach flow */
1178  ret = doca_rmax_flow_detach(data->flow, data->stream);
1179  if (ret != DOCA_SUCCESS) {
1180  DOCA_LOG_WARN("Error detaching flow: %s", doca_error_get_name(ret));
1181  is_ok = false;
1182  }
1183  ret = doca_rmax_flow_destroy(data->flow);
1184  if (ret != DOCA_SUCCESS) {
1185  DOCA_LOG_WARN("Error destroying flow: %s", doca_error_get_name(ret));
1186  is_ok = false;
1187  }
1188 
1189  /* stop stream */
1190  ret = doca_ctx_stop(doca_rmax_in_stream_as_ctx(data->stream));
1191  if (ret != DOCA_SUCCESS) {
1192  DOCA_LOG_WARN("Error stopping context: %s", doca_error_get_name(ret));
1193  is_ok = false;
1194  }
1195  /* will destroy all the buffers in the chain */
1196  ret = doca_buf_dec_refcount(data->buffer, NULL);
1197  if (ret != DOCA_SUCCESS) {
1198  DOCA_LOG_WARN("Error removing buffers: %s", doca_error_get_name(ret));
1199  is_ok = false;
1200  }
1201  /* destroy stream */
1202  ret = doca_rmax_in_stream_destroy(data->stream);
1203  if (ret != DOCA_SUCCESS) {
1204  DOCA_LOG_WARN("Error destroying stream: %s", doca_error_get_name(ret));
1205  is_ok = false;
1206  }
1207  return is_ok;
1208 }
1209 
1210 static void handle_completion(struct doca_rmax_in_stream_event_rx_data *event_rx_data, union doca_data event_user_data)
1211 {
1212  struct stream_data *data = event_user_data.ptr;
1213  const struct doca_rmax_in_stream_result *comp = doca_rmax_in_stream_event_rx_data_get_result(event_rx_data);
1214 
1215  if (!comp)
1216  return;
1217  if (comp->elements_count <= 0)
1218  return;
1219 
1220  data->recv_pkts += comp->elements_count;
1221  for (size_t i = 0; i < data->num_buffers; ++i)
1222  data->recv_bytes += comp->elements_count * data->pkt_size[i];
1223 
1224  if (!data->dump)
1225  return;
1226  for (size_t i = 0; i < comp->elements_count; ++i)
1227  for (size_t chunk = 0; chunk < data->num_buffers; ++chunk) {
1228  const uint8_t *ptr = comp->memblk_ptr_arr[chunk] + data->stride_size[chunk] * i;
1229  char *dump_str = hex_dump(ptr, data->pkt_size[chunk]);
1230 
1231  DOCA_LOG_INFO("pkt %zu chunk %zu\n%s", i, chunk, dump_str);
1232  free(dump_str);
1233  }
1234 }
1235 
1236 /*
1237  * Prints the number of received packets and rx bitrate then reset the statistics.
1238  * Prints information with at least 1 second interval
1239  *
1240  * @data [in]: Pointer to the stream data
1241  * @return: true if statistics are printed successfully; false otherwise
1242  */
1243 static bool print_statistics(struct stream_data *data)
1244 {
1245  static const uint64_t us_in_s = 1000000L;
1246  struct timespec now;
1247  int ret;
1248  uint64_t dt;
1249  double mbits_received;
1250 
1251  ret = clock_gettime(CLOCK_MONOTONIC_RAW, &now);
1252  if (ret != 0) {
1253  DOCA_LOG_ERR("error getting time: %s", strerror(errno));
1254  return false;
1255  }
1256 
1257  dt = (now.tv_sec - data->start.tv_sec) * us_in_s;
1258  dt += now.tv_nsec / 1000 - data->start.tv_nsec / 1000;
1259  /* ignore intervals shorter than 1 second */
1260  if (dt < us_in_s)
1261  return true;
1262 
1263  mbits_received = (double)(data->recv_bytes * 8) / dt;
1264  const char *unit = mbits_received > 1e3 ? "Gbps" : "Mbps";
1265  double rate = mbits_received > 1e3 ? mbits_received * 1e-3 : mbits_received;
1266 
1267  DOCA_LOG_INFO("Got %7zu packets | %7.2lf %s during %7.2lf sec\n", data->recv_pkts, rate, unit, dt * 1e-6);
1268 
1269  /* clear stats */
1270  data->start.tv_sec = now.tv_sec;
1271  data->start.tv_nsec = now.tv_nsec;
1272  data->recv_pkts = 0;
1273  data->recv_bytes = 0;
1274 
1275  return true;
1276 }
1277 
1278 static void handle_error(struct doca_rmax_in_stream_event_rx_data *event_rx_data, union doca_data event_user_data)
1279 {
1280  struct stream_data *data = event_user_data.ptr;
1281  const struct doca_rmax_stream_error *err = doca_rmax_in_stream_event_rx_data_get_error(event_rx_data);
1282 
1283  if (err)
1284  DOCA_LOG_ERR("Error: code=%d message=%s", err->code, err->message);
1285  else
1286  DOCA_LOG_ERR("Unknown error");
1287 
1288  data->run_recv_loop = false;
1289 }
1290 
1291 bool run_recv_loop(const struct app_config *config, struct globals *globals, struct stream_data *data)
1292 {
1293  int ret;
1294 
1295  ret = clock_gettime(CLOCK_MONOTONIC_RAW, &data->start);
1296  if (ret != 0) {
1297  DOCA_LOG_ERR("error getting time: %s", strerror(errno));
1298  return false;
1299  }
1300 
1301  data->run_recv_loop = true;
1302 
1303  while (data->run_recv_loop) {
1304  (void)doca_pe_progress(globals->pe);
1305 
1306  if (!print_statistics(data))
1307  return false;
1308  if (config->sleep_us > 0) {
1309  if (usleep(config->sleep_us) != 0) {
1310  if (errno != EINTR)
1311  DOCA_LOG_ERR("usleep error: %s", strerror(errno));
1312  return false;
1313  }
1314  }
1315  }
1316 
1317  return true;
1318 }
#define NULL
Definition: __stddef_null.h:26
uintptr_t addr
uint64_t len
if(bitoffset % 64+bitlength > 64) result|
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 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_BOOLEAN
Definition: doca_argp.h:58
@ DOCA_ARGP_TYPE_INT
Definition: doca_argp.h:57
DOCA_STABLE doca_error_t doca_buf_inventory_destroy(struct doca_buf_inventory *inventory)
Destroy buffer inventory structure.
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...
DOCA_STABLE doca_error_t doca_buf_inventory_start(struct doca_buf_inventory *inventory)
Start element retrieval from inventory.
DOCA_STABLE doca_error_t doca_buf_inventory_create(size_t num_elements, struct doca_buf_inventory **inventory)
Allocates buffer inventory with default/unset attributes.
DOCA_STABLE doca_error_t doca_buf_inventory_stop(struct doca_buf_inventory *inventory)
Stop element retrieval from inventory.
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_chain_list(struct doca_buf *list1, struct doca_buf *list2)
Append list2 to list1.
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_stop(struct doca_ctx *ctx)
Stops the context allowing reconfiguration.
DOCA_STABLE doca_error_t doca_devinfo_create_list(struct doca_devinfo ***dev_list, uint32_t *nb_devs)
Creates list of all available local devices.
DOCA_STABLE doca_error_t doca_devinfo_get_ibdev_name(const struct doca_devinfo *devinfo, char *ibdev_name, uint32_t size)
Get the name of the IB device represented by a DOCA devinfo.
#define DOCA_DEVINFO_IBDEV_NAME_SIZE
Buffer size to hold Infiniband/RoCE device name. Including a null terminator.
Definition: doca_dev.h:309
DOCA_STABLE doca_error_t doca_devinfo_destroy_list(struct doca_devinfo **dev_list)
Destroy list of local device info structures.
DOCA_STABLE doca_error_t doca_dev_open(struct doca_devinfo *devinfo, struct doca_dev **dev)
Initialize local device for use.
#define DOCA_DEVINFO_IFACE_NAME_SIZE
Buffer size to hold network interface name. Including a null terminator.
Definition: doca_dev.h:305
#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 doca_error_t doca_devinfo_get_ipv4_addr(const struct doca_devinfo *devinfo, uint8_t *ipv4_addr, uint32_t size)
Get the IPv4 address of a DOCA devinfo.
DOCA_STABLE doca_error_t doca_devinfo_get_iface_name(const struct doca_devinfo *devinfo, char *iface_name, uint32_t size)
Get the name of the ethernet interface of a DOCA devinfo.
DOCA_STABLE doca_error_t doca_devinfo_get_pci_addr_str(const struct doca_devinfo *devinfo, char *pci_addr_str)
Get the PCI address of a DOCA devinfo.
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_ERROR_NOT_FOUND
Definition: doca_error.h:54
@ DOCA_ERROR_NOT_SUPPORTED
Definition: doca_error.h:42
@ 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_WARN(format,...)
Generates a WARNING application log message.
Definition: doca_log.h:476
#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_destroy(struct doca_mmap *mmap)
Destroy DOCA Memory Map structure.
DOCA_STABLE doca_error_t doca_mmap_create(struct doca_mmap **mmap)
Allocates zero size memory map object with default/unset attributes.
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_add_dev(struct doca_mmap *mmap, struct doca_dev *dev)
Register DOCA memory map on a given device.
DOCA_STABLE doca_error_t doca_pe_destroy(struct doca_pe *pe)
Destroy doca progress engine.
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 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.
type value
void * aligned_alloc(size_t alignment, size_t size)
Definition: os_utils.cpp:126
char * hex_dump(const void *data, size_t size)
rte_ipv6_hdr ip
Definition: psp_gw_flows.cpp:4
bool destroy_stream(struct doca_dev *dev, struct globals *globals, struct stream_data *data)
static void handle_error(struct doca_rmax_in_stream_event_rx_data *event_rx_data, union doca_data event_user_data)
static doca_error_t set_dev_ip_param(void *param, void *opaque)
bool register_argp_params(void)
static doca_error_t set_max_packets_param(void *param, void *opaque)
doca_error_t init_globals(struct app_config *config, struct doca_dev *dev, struct globals *globals)
static doca_error_t set_dst_ip_param(void *param, void *opaque)
static doca_error_t set_tstamp_format_param(void *param, void *opaque)
static doca_error_t set_num_elements_param(void *param, void *opaque)
static doca_error_t set_dst_port_param(void *param, void *opaque)
bool run_recv_loop(const struct app_config *config, struct globals *globals, struct stream_data *data)
static void handle_completion(struct doca_rmax_in_stream_event_rx_data *event_rx_data, union doca_data event_user_data)
struct doca_dev * open_device(struct in_addr *dev_ip)
static doca_error_t set_cpu_affinity_param(void *param, void *opaque)
static doca_error_t set_sleep_param(void *param, void *opaque)
static doca_error_t set_dump_flag(void *param, void *opaque)
DOCA_LOG_REGISTER(STREAM_RECEIVE_PERF_CORE)
bool destroy_globals(struct globals *globals, struct doca_dev *dev)
static bool print_statistics(struct stream_data *data)
static doca_error_t set_scatter_type_param(void *param, void *opaque)
doca_error_t init_stream(struct app_config *config, struct doca_dev *dev, struct globals *globals, struct stream_data *data)
bool mandatory_args_set(struct app_config *config)
void list_devices(void)
static doca_error_t set_ip_param(const char *label, const char *str, struct in_addr *out)
bool init_config(struct app_config *config)
static doca_error_t set_list_flag(void *param, void *opaque)
static doca_error_t set_src_ip_param(void *param, void *opaque)
void destroy_config(struct app_config *config)
static doca_error_t set_min_packets_param(void *param, void *opaque)
static void free_callback(void *addr, size_t len, void *opaque)
static doca_error_t set_data_size_param(void *param, void *opaque)
static doca_error_t set_hdr_size_param(void *param, void *opaque)
@ SCATTER_TYPE_RAW
@ SCATTER_TYPE_ULP
#define MAX_BUFFERS
@ TIMESTAMP_FORMAT_PTP_SYNCED
@ TIMESTAMP_FORMAT_RAW_COUNTER
@ TIMESTAMP_FORMAT_FREE_RUNNING
struct in_addr dev_ip
struct in_addr dst_ip
enum timestamp_format tstamp_format
struct doca_rmax_cpu_affinity * affinity_mask
struct in_addr src_ip
enum scatter_type scatter_type
struct doca_buf_inventory * inventory
struct doca_pe * pe
struct doca_mmap * mmap
uint16_t stride_size[MAX_BUFFERS]
uint16_t pkt_size[MAX_BUFFERS]
struct timespec start
struct doca_buf * buffer
struct doca_rmax_flow * flow
struct doca_rmax_in_stream * stream
Convenience type for representing opaque data.
Definition: doca_types.h:56
void * ptr
Definition: doca_types.h:57
noreturn doca_error_t sdk_version_callback(void *param, void *doca_config)
Definition: utils.c:41