NVIDIA DOCA SDK Data Center on a Chip Framework Documentation
telemetry_diag_main.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 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 <errno.h>
27 #include <stdbool.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <json-c/json.h>
32 
33 #include <doca_argp.h>
34 #include <doca_dev.h>
35 #include <doca_error.h>
36 #include <doca_log.h>
37 #include <doca_telemetry_diag.h>
38 #include "telemetry_diag_sample.h"
39 
40 DOCA_LOG_REGISTER(TELEMETRY_DIAG::MAIN);
41 
42 #define MAX_DESCRIPTION_LEN 256
43 #define DATA_ID_STRING_MAX_LEN 20
44 
45 #define DEFAULT_SAMPLE_PERIOD_NS 100000 /* 100 usec */
46 #define DEFAULT_LOG_MAX_NUM_SAMPLES 10
47 #define DEFAULT_MAX_NUM_SAMPLES_PER_READ 128
48 #define DEFAULT_SAMPLE_MODE DOCA_TELEMETRY_DIAG_SAMPLE_MODE_REPETITIVE
49 #define DEFAULT_OUTPUT_FORMAT DOCA_TELEMETRY_DIAG_OUTPUT_FORMAT_1
50 #define DEFAULT_TOTAL_RUN_TIME_SECS 1
51 #define DEFAULT_OUTPUT_PATH "/tmp/out.csv"
52 #define DEFAULT_FORCE_OWNERSHIP 0
53 #define DEFAULT_DATA_IDS_PATH "/0"
54 #define DEFAULT_EXAMPLE_JSON_PATH "/0"
55 
56 #define JSON_NAME_KEY "name"
57 #define JSON_DATA_ID_KEY "data_id"
58 
59 #define DATA_ID_PORT_0_RX_BYTES 0x1020000100000000
60 #define DATA_ID_PORT_0_TX_BYTES 0x1140000100000000
61 #define DATA_ID_PORT_0_RX_PACKETS 0x1020000300000000
62 #define DATA_ID_PORT_0_TX_PACKETS 0x1140000300000000
63 
64 /*
65  * ARGP Callback - Handle PCI device address parameter
66  *
67  * @param [in]: Input parameter
68  * @config [in/out]: Program configuration context
69  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
70  */
71 static doca_error_t pci_address_callback(void *param, void *config)
72 {
74  char *pci_address = (char *)param;
75  int len;
76 
77  len = strnlen(pci_address, DOCA_DEVINFO_PCI_ADDR_SIZE);
79  DOCA_LOG_ERR("Entered device PCI address exceeding the maximum size of %d",
82  }
83  strncpy(telemetry_diag_sample_cfg->pci_addr, pci_address, len + 1);
85  return DOCA_SUCCESS;
86 }
87 
88 /*
89  * ARGP Callback - Handle data ids file parameter
90  *
91  * @param [in]: Input parameter
92  * @config [in/out]: Program configuration context
93  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
94  */
95 static doca_error_t data_ids_callback(void *param, void *config)
96 {
98  char *json_path = (char *)param;
99  int len;
100 
101  len = strnlen(json_path, TELEMETRY_DIAG_SAMPLE_MAX_FILE_NAME);
103  DOCA_LOG_ERR("Invalid path: data-ids file name length exceeds the maximum of %d characters",
106  }
107  if (access(json_path, F_OK) == -1) {
108  DOCA_LOG_ERR("JSON file was not found %s", json_path);
109  return DOCA_ERROR_NOT_FOUND;
110  }
113  return DOCA_SUCCESS;
114 }
115 
116 /*
117  * ARGP Callback - Handle output file parameter
118  *
119  * @param [in]: Input parameter
120  * @config [in/out]: Program configuration context
121  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
122  */
123 static doca_error_t output_callback(void *param, void *config)
124 {
126  char *file = (char *)param;
127  int len;
128 
129  len = strnlen(file, TELEMETRY_DIAG_SAMPLE_MAX_FILE_NAME);
131  DOCA_LOG_ERR("Invalid path: output file name length exceeds the maximum of %d characters",
134  }
136  return DOCA_SUCCESS;
137 }
138 
139 /*
140  * ARGP Callback - Handle sample time parameter
141  *
142  * @param [in]: Input parameter
143  * @config [in/out]: Program configuration context
144  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
145  */
146 static doca_error_t run_time_callback(void *param, void *config)
147 {
149  uint32_t *run_time = (uint32_t *)param;
150 
152  return DOCA_SUCCESS;
153 }
154 
155 /*
156  * ARGP Callback - Handle sample_period parameter
157  *
158  * @param [in]: Input parameter
159  * @config [in/out]: Program configuration context
160  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
161  */
162 static doca_error_t sample_period_callback(void *param, void *config)
163 {
165  uint32_t *sample_period = (uint32_t *)param;
166 
168  return DOCA_SUCCESS;
169 }
170 
171 /*
172  * ARGP Callback - Handle log_max_num_samples parameter
173  *
174  * @param [in]: Input parameter
175  * @config [in/out]: Program configuration context
176  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
177  */
178 static doca_error_t log_max_num_samples_callback(void *param, void *config)
179 {
181  uint32_t *log_max_num_samples = (uint32_t *)param;
182 
183  if (*log_max_num_samples > __UINT8_MAX__) {
184  DOCA_LOG_ERR("Parameter log_max_num_samples larger than uint8. log_max_num_samples=%d",
187  }
189  return DOCA_SUCCESS;
190 }
191 
192 /*
193  * ARGP Callback - Handle max_num_samples_per_read parameter
194  *
195  * @param [in]: Input parameter
196  * @config [in/out]: Program configuration context
197  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
198  */
199 static doca_error_t max_num_samples_per_read_callback(void *param, void *config)
200 {
202  uint32_t *max_num_samples_per_read = (uint32_t *)param;
203 
204  if (*max_num_samples_per_read > __UINT8_MAX__) {
205  DOCA_LOG_ERR("Parameter max_num_samples_per_read larger than uint8. max_num_samples_per_read=%d",
208  }
210 
211  return DOCA_SUCCESS;
212 }
213 
214 /*
215  * ARGP Callback - Handle sample_mode parameter
216  *
217  * @param [in]: Input parameter
218  * @config [in/out]: Program configuration context
219  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
220  */
221 static doca_error_t sample_mode_callback(void *param, void *config)
222 {
225 
227  return DOCA_SUCCESS;
228 }
229 
230 /*
231  * ARGP Callback - Handle output_format parameter
232  *
233  * @param [in]: Input parameter
234  * @config [in/out]: Program configuration context
235  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
236  */
237 static doca_error_t output_format_callback(void *param, void *config)
238 {
241 
243  return DOCA_SUCCESS;
244 }
245 
246 /*
247  * ARGP Callback - Handle force_ownership parameter
248  *
249  * @param [in]: Input parameter
250  * @config [in/out]: Program configuration context
251  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
252  */
253 static doca_error_t force_ownership_callback(void *param, void *config)
254 {
256  bool force_ownership = *(bool *)param;
257 
259  return DOCA_SUCCESS;
260 }
261 
262 /*
263  * ARGP Callback - example json file parameter
264  * If set, create a new file in the location given and fill with the example data_ids json
265  *
266  * @param [in]: Input parameter
267  * @config [in/out]: Program configuration context
268  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
269  */
270 static doca_error_t example_json_file_callback(void *param, void *config)
271 {
273  char *file = (char *)param;
274  int len;
275 
276  len = strnlen(file, TELEMETRY_DIAG_SAMPLE_MAX_FILE_NAME);
278  DOCA_LOG_ERR("Invalid path: output file name length exceeds the maximum of %d characters",
281  }
284  return DOCA_SUCCESS;
285 }
286 
287 /*
288  * Register the command line parameters for the sample.
289  *
290  * @return: DOCA_SUCCESS on success and DOCA_ERROR otherwise
291  */
293 {
295  struct doca_argp_param *pci_param, *data_ids_param, *run_time_param, *sample_period_param,
296  *log_max_num_samples_param, *max_num_samples_per_read_param, *sample_mode_param, *output_format_param,
297  *output_param, *force_ownership_param, *generate_example_json;
298 
299  result = doca_argp_param_create(&pci_param);
300  if (result != DOCA_SUCCESS) {
301  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(result));
302  return result;
303  }
304  doca_argp_param_set_short_name(pci_param, "p");
305  doca_argp_param_set_long_name(pci_param, "pci-addr");
306  doca_argp_param_set_description(pci_param, "DOCA device PCI device address");
309  result = doca_argp_register_param(pci_param);
310  if (result != DOCA_SUCCESS) {
311  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(result));
312  return result;
313  }
314 
315  result = doca_argp_param_create(&data_ids_param);
316  if (result != DOCA_SUCCESS) {
317  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(result));
318  return result;
319  }
320  doca_argp_param_set_short_name(data_ids_param, "di");
321  doca_argp_param_set_long_name(data_ids_param, "data-ids");
322  doca_argp_param_set_description(data_ids_param, "Path to data ids JSON file");
325  result = doca_argp_register_param(data_ids_param);
326  if (result != DOCA_SUCCESS) {
327  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(result));
328  return result;
329  }
330 
331  result = doca_argp_param_create(&output_param);
332  if (result != DOCA_SUCCESS) {
333  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
334  return result;
335  }
336  doca_argp_param_set_short_name(output_param, "o");
337  doca_argp_param_set_long_name(output_param, "output");
338  doca_argp_param_set_description(output_param, "Output CSV file - default: \"" DEFAULT_OUTPUT_PATH "\"");
341  result = doca_argp_register_param(output_param);
342  if (result != DOCA_SUCCESS) {
343  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
344  return result;
345  }
346 
347  result = doca_argp_param_create(&run_time_param);
348  if (result != DOCA_SUCCESS) {
349  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(result));
350  return result;
351  }
352  doca_argp_param_set_short_name(run_time_param, "rt");
353  doca_argp_param_set_long_name(run_time_param, "sample-run-time");
354  doca_argp_param_set_description(run_time_param, "Total sample run time, in seconds");
357  result = doca_argp_register_param(run_time_param);
358  if (result != DOCA_SUCCESS) {
359  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(result));
360  return result;
361  }
362 
363  result = doca_argp_param_create(&sample_period_param);
364  if (result != DOCA_SUCCESS) {
365  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(result));
366  return result;
367  }
368  doca_argp_param_set_short_name(sample_period_param, "sp");
369  doca_argp_param_set_long_name(sample_period_param, "sample-period");
370  doca_argp_param_set_description(sample_period_param, "Sample period, in nanoseconds");
372  doca_argp_param_set_type(sample_period_param, DOCA_ARGP_TYPE_INT);
373  result = doca_argp_register_param(sample_period_param);
374  if (result != DOCA_SUCCESS) {
375  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(result));
376  return result;
377  }
378 
379  result = doca_argp_param_create(&log_max_num_samples_param);
380  if (result != DOCA_SUCCESS) {
381  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(result));
382  return result;
383  }
384  doca_argp_param_set_short_name(log_max_num_samples_param, "ns");
385  doca_argp_param_set_long_name(log_max_num_samples_param, "log-num-samples");
386  doca_argp_param_set_description(log_max_num_samples_param, "Log max number of samples");
388  doca_argp_param_set_type(log_max_num_samples_param, DOCA_ARGP_TYPE_INT);
389  result = doca_argp_register_param(log_max_num_samples_param);
390  if (result != DOCA_SUCCESS) {
391  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(result));
392  return result;
393  }
394 
395  result = doca_argp_param_create(&max_num_samples_per_read_param);
396  if (result != DOCA_SUCCESS) {
397  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(result));
398  return result;
399  }
400  doca_argp_param_set_short_name(max_num_samples_per_read_param, "sr");
401  doca_argp_param_set_long_name(max_num_samples_per_read_param, "max-samples-per-read");
402  doca_argp_param_set_description(max_num_samples_per_read_param, "Max num samples per read");
403  doca_argp_param_set_callback(max_num_samples_per_read_param, max_num_samples_per_read_callback);
404  doca_argp_param_set_type(max_num_samples_per_read_param, DOCA_ARGP_TYPE_INT);
405  result = doca_argp_register_param(max_num_samples_per_read_param);
406  if (result != DOCA_SUCCESS) {
407  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(result));
408  return result;
409  }
410 
411  result = doca_argp_param_create(&sample_mode_param);
412  if (result != DOCA_SUCCESS) {
413  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(result));
414  return result;
415  }
416  doca_argp_param_set_short_name(sample_mode_param, "sm");
417  doca_argp_param_set_long_name(sample_mode_param, "sample-mode");
418  doca_argp_param_set_description(sample_mode_param, "sample mode (0 - single, 1 - repetitive, 2 - on demand)");
420  doca_argp_param_set_type(sample_mode_param, DOCA_ARGP_TYPE_INT);
421  result = doca_argp_register_param(sample_mode_param);
422  if (result != DOCA_SUCCESS) {
423  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(result));
424  return result;
425  }
426 
427  result = doca_argp_param_create(&output_format_param);
428  if (result != DOCA_SUCCESS) {
429  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(result));
430  return result;
431  }
432  doca_argp_param_set_short_name(output_format_param, "of");
433  doca_argp_param_set_long_name(output_format_param, "output-format");
434  doca_argp_param_set_description(output_format_param, "output format");
436  doca_argp_param_set_type(output_format_param, DOCA_ARGP_TYPE_INT);
437  result = doca_argp_register_param(output_format_param);
438  if (result != DOCA_SUCCESS) {
439  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(result));
440  return result;
441  }
442 
443  result = doca_argp_param_create(&force_ownership_param);
444  if (result != DOCA_SUCCESS) {
445  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_name(result));
446  return result;
447  }
448  doca_argp_param_set_short_name(force_ownership_param, "f");
449  doca_argp_param_set_long_name(force_ownership_param, "force-ownership");
450  doca_argp_param_set_description(force_ownership_param, "Force ownership when creating context");
452  doca_argp_param_set_type(force_ownership_param, DOCA_ARGP_TYPE_BOOLEAN);
453  result = doca_argp_register_param(force_ownership_param);
454  if (result != DOCA_SUCCESS) {
455  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_name(result));
456  return result;
457  }
458 
460  if (result != DOCA_SUCCESS) {
461  DOCA_LOG_ERR("Failed to create ARGP param: %s", doca_error_get_descr(result));
462  return result;
463  }
467  "Generate an example json file with the default data_ids to the given path \
468 and exit immediately. This file can be used as input later on. \
469 All other flags are ignored");
473  if (result != DOCA_SUCCESS) {
474  DOCA_LOG_ERR("Failed to register program param: %s", doca_error_get_descr(result));
475  return result;
476  }
477 
478  return DOCA_SUCCESS;
479 }
480 
481 /*
482  * Parses the "data-ids" array from a JSON object and stores the results
483  * in the globally allocated data_ids_struct.
484  *
485  * @cfg [in]: the sample configuration
486  * @json_data_ids [in]: JSON object containing the "data-ids" array.
487  * @array_len [in]: The length of the "data-ids" array in json_data_ids.
488  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise.
489  */
491  struct json_object *json_data_ids,
492  int array_len)
493 {
494  struct json_object *json_entry, *json_data_id, *json_name;
495  const char *data_id_str;
496 
497  // Loop through each element in the "data-ids" array
498  for (int i = 0; i < array_len; i++) {
499  json_entry = json_object_array_get_idx(json_data_ids, i); // Get JSON object for the
500  // current entry.
501 
502  // Extract "data_id" field, handle error if it's missing or invalid
503  if (!json_object_object_get_ex(json_entry, JSON_DATA_ID_KEY, &json_data_id)) {
504  DOCA_LOG_ERR("Missing or invalid \"%s\" field in data_ids JSON entry %d", JSON_DATA_ID_KEY, i);
506  }
507 
508  // Extract "name" field, handle error if it's missing or invalid
509  if (!json_object_object_get_ex(json_entry, JSON_NAME_KEY, &json_name)) {
510  DOCA_LOG_ERR("Missing or invalid \"%s\" field in data_ids JSON entry %d", JSON_NAME_KEY, i);
512  }
513 
514  // Parse the "data_id" field as a hexadecimal string and convert it to uint64_t
515  data_id_str = json_object_get_string(json_data_id);
516  if (sscanf(data_id_str, "%lx", &cfg->data_ids_struct[i].data_id) != 1) {
517  DOCA_LOG_ERR("Failed to parse data_id (expected hexadecimal number): '%s'", data_id_str);
519  }
520 
521  strncpy(cfg->data_ids_struct[i].name, json_object_get_string(json_name), MAX_NAME_SIZE - 1);
522  cfg->data_ids_struct[i].name[MAX_NAME_SIZE - 1] = '\0';
523  }
524 
525  // Store the total number of parsed data-ids
526  cfg->num_data_ids = array_len;
527 
528  return DOCA_SUCCESS;
529 }
530 
531 /*
532  * Sets default data IDs and their corresponding names.
533  *
534  * @cfg [in]: the sample configuration
535  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise.
536  */
538 {
539  cfg->num_data_ids = 4;
540 
541  cfg->data_ids_struct = calloc(cfg->num_data_ids, sizeof(struct data_id_entry));
542  if (!cfg->data_ids_struct) {
543  DOCA_LOG_ERR("Failed to allocate memory for data_ids_struct");
544  return DOCA_ERROR_NO_MEMORY;
545  }
546 
547  cfg->data_ids_struct[0].data_id = DATA_ID_PORT_0_RX_BYTES;
548  strncpy(cfg->data_ids_struct[0].name, "port_0_rx_bytes", MAX_NAME_SIZE - 1);
549 
550  cfg->data_ids_struct[1].data_id = DATA_ID_PORT_0_TX_BYTES;
551  strncpy(cfg->data_ids_struct[1].name, "port_0_tx_bytes", MAX_NAME_SIZE - 1);
552 
553  cfg->data_ids_struct[2].data_id = DATA_ID_PORT_0_RX_PACKETS;
554  strncpy(cfg->data_ids_struct[2].name, "port_0_rx_packets", MAX_NAME_SIZE - 1);
555 
556  cfg->data_ids_struct[3].data_id = DATA_ID_PORT_0_TX_PACKETS;
557  strncpy(cfg->data_ids_struct[3].name, "port_0_tx_packets", MAX_NAME_SIZE - 1);
558 
559  return DOCA_SUCCESS;
560 }
561 
562 /*
563  * Reads and parses a JSON file containing "data-ids" entries or sets default data IDs if specified.
564  * The function checks if the user wants to use default data IDs, handles file I/O (if a JSON file is specified),
565  * and calls parse_json_data_ids to handle parsing of the relevant data.
566  *
567  * @cfg [in]: the sample configuration
568  * @return: DOCA_SUCCESS on success, DOCA_ERROR otherwise.
569  */
570 
572 {
573  // Check if the user wants to use default data IDs.
574  if (!cfg->import_json) {
575  return set_default_data_ids(cfg);
576  }
577 
578  FILE *json_fp;
579  long temp_length;
580  size_t file_length;
581  char *json_data = NULL;
582  struct json_object *parsed_json, *json_data_ids;
583  int array_len = 0;
585 
586  json_fp = fopen(cfg->data_ids_input_path, "r");
587  if (json_fp == NULL) {
588  DOCA_LOG_ERR("JSON file open failed");
589  return DOCA_ERROR_IO_FAILED;
590  }
591 
592  // Get the size of the file by seeking to the end and then rewinding
593  if (fseek(json_fp, 0, SEEK_END) != 0) {
594  DOCA_LOG_ERR("Failed to seek to end of JSON file");
596  goto close_file;
597  }
598 
599  temp_length = ftell(json_fp);
600  if (temp_length < 0) {
601  DOCA_LOG_ERR("Failed to get file length using ftell");
603  goto close_file;
604  }
605  file_length = (size_t)temp_length;
606  rewind(json_fp);
607 
608  // Allocate memory to store the file content
609  json_data = malloc(file_length + 1);
610  if (json_data == NULL) {
611  DOCA_LOG_ERR("Failed to allocate data buffer for the json file");
613  goto close_file;
614  }
615 
616  // Read the entire file into the buffer
617  if (fread(json_data, 1, file_length, json_fp) < file_length)
618  DOCA_LOG_DBG("EOF reached");
619 
620  json_data[file_length] = '\0';
621 
622  parsed_json = json_tokener_parse(json_data);
623 
624  // Check for the presence of the "data-ids" array in the JSON object
625  if (!json_object_object_get_ex(parsed_json, "data-ids", &json_data_ids)) {
626  DOCA_LOG_ERR("Missing \"data-ids\" parameter in the data ids JSON file");
628  goto json_release;
629  }
630 
631  array_len = json_object_array_length(json_data_ids); // Get the length of the "data-ids" array
632  if (array_len == 0) {
633  DOCA_LOG_ERR("The \"data-ids\" array in the JSON file is empty");
635  goto json_release;
636  }
637 
638  cfg->data_ids_struct = malloc(sizeof(struct data_id_entry) * array_len); // Allocate memory for data_id_entry
639  // structures.
640 
641  // Check if memory allocation was successful
642  if (!cfg->data_ids_struct) {
644  DOCA_LOG_ERR("Failed to allocate memory for data_ids_struct");
645  goto json_release;
646  }
647 
648  result = parse_json_data_ids(cfg, json_data_ids, array_len);
649  if (result != DOCA_SUCCESS) {
650  DOCA_LOG_ERR("Failed to parse data-ids");
651  free(cfg->data_ids_struct);
652  goto json_release;
653  }
654 
655 json_release:
656  json_object_put(parsed_json);
657  free(json_data);
658 close_file:
659  fclose(json_fp);
660  return result;
661 }
662 
663 /*
664  * create pair of name/data_id to be in the data_ids json
665  *
666  * @name [in]: data_id name
667  * @data_id_string [in]: data_id value
668  *
669  * @return: a json object with the new pair
670  */
671 static json_object *create_data_id_pair(char *name, char *data_id_string)
672 {
673  json_object *data_id, *pair, *name_obj;
674 
675  pair = json_object_new_object();
676  if (pair == NULL) {
677  DOCA_LOG_ERR("Failed to create pair json object");
678  return NULL;
679  }
680 
681  name_obj = json_object_new_string(name);
682  if (name_obj == NULL) {
683  DOCA_LOG_ERR("Failed to create new name json object");
684  goto put_pair;
685  }
686 
687  if (json_object_object_add(pair, JSON_NAME_KEY, name_obj)) {
688  DOCA_LOG_ERR("Failed to add name to default data_ids json");
689  json_object_put(name_obj);
690  goto put_pair;
691  }
692 
693  data_id = json_object_new_string(data_id_string);
694  if (data_id == NULL) {
695  DOCA_LOG_ERR("Failed to create new data_id json object");
696  goto put_pair;
697  }
698 
699  if (json_object_object_add(pair, JSON_DATA_ID_KEY, data_id)) {
700  DOCA_LOG_ERR("Failed to add data_id to default data_ids json");
701  json_object_put(data_id);
702  goto put_pair;
703  }
704 
705  return pair;
706 
707 put_pair:
708  json_object_put(pair);
709  return NULL;
710 }
711 
712 /*
713  * create an example json object that contains the default data_ids.
714  *
715  * @cfg [in]: the sample configuration
716  * @example_json [out]: new json object
717  */
718 static doca_error_t create_default_json(struct telemetry_diag_sample_cfg *cfg, struct json_object *example_json)
719 {
720  json_object *data_id_array = json_object_new_array();
721  json_object *pair;
722  char data_id_string[DATA_ID_STRING_MAX_LEN] = {0};
723 
724  if (data_id_array == NULL) {
725  DOCA_LOG_ERR("Failed to create data_id_array json object");
726  return DOCA_ERROR_NO_MEMORY;
727  }
728 
729  for (uint32_t i = 0; i < cfg->num_data_ids; i++) {
730  if (snprintf(data_id_string, sizeof(data_id_string), "0x%lx", cfg->data_ids_struct[i].data_id) < 0) {
731  DOCA_LOG_ERR("Failed to create data_id_string");
732  goto put_data_id_array;
733  }
734  pair = create_data_id_pair(cfg->data_ids_struct[i].name, data_id_string);
735  if (pair == NULL) {
736  DOCA_LOG_ERR("Failed to create data_id pair");
737  goto put_data_id_array;
738  }
739  if (json_object_array_add(data_id_array, pair)) {
740  DOCA_LOG_ERR("Failed to add data_id to array");
741  goto put_pair;
742  }
743  }
744 
745  if (json_object_object_add(example_json, "data-ids", data_id_array)) {
746  DOCA_LOG_ERR("Failed to add data_id_array to example json");
747  goto put_data_id_array;
748  }
749  return DOCA_SUCCESS;
750 
751 put_pair:
752  json_object_put(pair);
753 put_data_id_array:
754  json_object_put(data_id_array);
755  return DOCA_ERROR_NO_MEMORY;
756 }
757 
758 /*
759  * dump the default data_ids into an example json file
760  *
761  * @cfg [in]: the sample configuration
762  */
764 {
765  json_object *example_json;
766  FILE *json_file;
768  const char *exported_json;
769 
771  if (result != DOCA_SUCCESS) {
772  DOCA_LOG_ERR("Failed to create default data_ids struct with error=%s", doca_error_get_name(result));
773  return result;
774  }
775 
776  json_file = fopen(cfg->data_ids_example_export_path, "w");
777  if (json_file == NULL) {
778  DOCA_LOG_ERR("Failed to open output file \"%s\" with errno=%s (%d)",
779  cfg->data_ids_example_export_path,
780  strerror(errno),
781  errno);
783  goto free_data_ids;
784  }
785  example_json = json_object_new_object();
786  if (example_json == NULL) {
787  DOCA_LOG_ERR("Failed to create example json");
789  goto close_file;
790  }
791 
792  result = create_default_json(cfg, example_json);
793  if (result != DOCA_SUCCESS) {
794  DOCA_LOG_ERR("Failed to create example json");
795  goto put_json_object;
796  }
797 
798  exported_json = json_object_to_json_string_ext(example_json, JSON_C_TO_STRING_PRETTY);
799  if (fwrite(exported_json, sizeof(char), strlen(exported_json), json_file) == 0) {
800  DOCA_LOG_ERR("Failed to write json to file");
802  goto put_json_object;
803  }
804 
806 
807 put_json_object:
808  json_object_put(example_json);
809 close_file:
810  fclose(json_file);
811 free_data_ids:
812  free(cfg->data_ids_struct);
813  return result;
814 }
815 
816 /*
817  * Set the default parameters to be used in the sample.
818  *
819  * @cfg [in]: the sample configuration
820  */
822 {
823  cfg->sample_period = DEFAULT_SAMPLE_PERIOD_NS;
824  cfg->log_max_num_samples = DEFAULT_LOG_MAX_NUM_SAMPLES;
825  cfg->max_num_samples_per_read = DEFAULT_MAX_NUM_SAMPLES_PER_READ;
826  cfg->run_time = DEFAULT_TOTAL_RUN_TIME_SECS;
827  cfg->force_ownership = DEFAULT_FORCE_OWNERSHIP;
828  cfg->sample_mode = DEFAULT_SAMPLE_MODE;
829  cfg->output_format = DEFAULT_OUTPUT_FORMAT;
830  cfg->pci_set = false;
831  cfg->import_json = false;
832  cfg->export_json = false;
833  strncpy(cfg->output_path, DEFAULT_OUTPUT_PATH, TELEMETRY_DIAG_SAMPLE_MAX_FILE_NAME - 1);
834  strncpy(cfg->data_ids_input_path, DEFAULT_DATA_IDS_PATH, TELEMETRY_DIAG_SAMPLE_MAX_FILE_NAME - 1);
835  strncpy(cfg->data_ids_example_export_path, DEFAULT_EXAMPLE_JSON_PATH, TELEMETRY_DIAG_SAMPLE_MAX_FILE_NAME - 1);
836 }
837 
838 /*
839  * Sample main function
840  *
841  * @argc [in]: command line arguments size
842  * @argv [in]: array of command line arguments
843  * @return: EXIT_SUCCESS on success and EXIT_FAILURE otherwise
844  */
845 int main(int argc, char **argv)
846 {
848  int exit_status = EXIT_FAILURE;
849  struct telemetry_diag_sample_cfg sample_cfg = {};
850  struct doca_log_backend *sdk_log;
851 
852  /* Register a logger backend */
854  if (result != DOCA_SUCCESS)
855  goto sample_exit;
856 
857  /* Register a logger backend for internal SDK errors and warnings */
858  result = doca_log_backend_create_with_file_sdk(stderr, &sdk_log);
859  if (result != DOCA_SUCCESS)
860  goto sample_exit;
862  if (result != DOCA_SUCCESS)
863  goto sample_exit;
864 
865  set_default_params(&sample_cfg);
866 
867  DOCA_LOG_INFO("Starting the sample");
868 
869  result = doca_argp_init(NULL, &sample_cfg);
870  if (result != DOCA_SUCCESS) {
871  DOCA_LOG_ERR("Failed to init ARGP resources: %s", doca_error_get_name(result));
872  goto sample_exit;
873  }
874 
876  if (result != DOCA_SUCCESS) {
877  DOCA_LOG_ERR("Failed to register ARGP params: %s", doca_error_get_name(result));
878  goto argp_cleanup;
879  }
880 
881  result = doca_argp_start(argc, argv);
882  if (result != DOCA_SUCCESS) {
883  DOCA_LOG_ERR("Failed to parse sample input: %s", doca_error_get_name(result));
884  goto argp_cleanup;
885  }
886 
887  if (sample_cfg.export_json) {
888  result = generate_example_json(&sample_cfg);
889  if (result == DOCA_SUCCESS) {
890  DOCA_LOG_INFO("Example data_ids json exported successfully, exiting");
891  exit_status = EXIT_SUCCESS;
892  } else {
893  DOCA_LOG_INFO("Example data_ids json export failed");
894  }
895  goto argp_cleanup;
896  }
897 
898  if (!sample_cfg.pci_set) {
899  DOCA_LOG_ERR("PCI address must be provided");
900  goto argp_cleanup;
901  }
902 
904  if (result != DOCA_SUCCESS) {
905  DOCA_LOG_ERR("Failed to list the data ids with error=%s", doca_error_get_name(result));
906  goto argp_cleanup;
907  }
908 
909  result = telemetry_diag_sample_run(&sample_cfg);
910  if (result != DOCA_SUCCESS) {
911  DOCA_LOG_ERR("telemetry_diag_sample_run() encountered an error: %s", doca_error_get_name(result));
912  goto free_data_ids;
913  }
914 
915  exit_status = EXIT_SUCCESS;
916 
917 free_data_ids:
918  free(sample_cfg.data_ids_struct);
919 
920 argp_cleanup:
922 sample_exit:
923  if (exit_status == EXIT_SUCCESS)
924  DOCA_LOG_INFO("Sample finished successfully");
925  else
926  DOCA_LOG_INFO("Sample finished with errors");
927  return exit_status;
928 }
#define NULL
Definition: __stddef_null.h:26
__SIZE_TYPE__ size_t
int32_t result
uint64_t len
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 doca_error_t doca_argp_start(int argc, char **argv)
Parse incoming arguments (cmd line/json).
DOCA_EXPERIMENTAL doca_error_t doca_argp_init(const char *program_name, void *program_config)
Initialize the parser interface.
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 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_destroy(void)
ARG Parser destroy.
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
#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
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_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_IO_FAILED
Definition: doca_error.h:55
@ DOCA_SUCCESS
Definition: doca_error.h:38
@ DOCA_ERROR_NO_MEMORY
Definition: doca_error.h:45
DOCA_EXPERIMENTAL doca_error_t doca_log_backend_create_standard(void)
Create default, non configurable backend for application messages.
#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_EXPERIMENTAL doca_error_t doca_log_backend_create_with_file_sdk(FILE *fptr, struct doca_log_backend **backend)
Create a logging backend with a FILE* stream for SDK messages.
#define DOCA_LOG_DBG(format,...)
Generates a DEBUG application log message.
Definition: doca_log.h:496
DOCA_EXPERIMENTAL doca_error_t doca_log_backend_set_sdk_level(struct doca_log_backend *backend, uint32_t level)
Set the log level limit for SDK logging backends.
@ DOCA_LOG_LEVEL_WARNING
Definition: doca_log.h:47
doca_telemetry_diag_sample_mode
description of data sampling mode
doca_telemetry_diag_output_format
Defines the layout of the diagnostic data output:
const struct ip_frag_config * cfg
Definition: ip_frag_dp.c:0
char data_ids_input_path[TELEMETRY_DIAG_SAMPLE_MAX_FILE_NAME]
enum doca_telemetry_diag_output_format output_format
struct data_id_entry * data_ids_struct
char data_ids_example_export_path[TELEMETRY_DIAG_SAMPLE_MAX_FILE_NAME]
char output_path[TELEMETRY_DIAG_SAMPLE_MAX_FILE_NAME]
enum doca_telemetry_diag_sample_mode sample_mode
char pci_addr[DOCA_DEVINFO_PCI_ADDR_SIZE]
#define DEFAULT_SAMPLE_MODE
static doca_error_t register_telemetry_diag_params(void)
static doca_error_t data_ids_callback(void *param, void *config)
#define DEFAULT_MAX_NUM_SAMPLES_PER_READ
#define DEFAULT_SAMPLE_PERIOD_NS
static doca_error_t generate_example_json(struct telemetry_diag_sample_cfg *cfg)
DOCA_LOG_REGISTER(TELEMETRY_DIAG::MAIN)
int main(int argc, char **argv)
#define DATA_ID_PORT_0_RX_PACKETS
static doca_error_t pci_address_callback(void *param, void *config)
static doca_error_t parse_and_read_data_ids_json_file(struct telemetry_diag_sample_cfg *cfg)
static doca_error_t log_max_num_samples_callback(void *param, void *config)
#define DEFAULT_LOG_MAX_NUM_SAMPLES
#define DATA_ID_PORT_0_TX_BYTES
#define DEFAULT_FORCE_OWNERSHIP
static json_object * create_data_id_pair(char *name, char *data_id_string)
static void set_default_params(struct telemetry_diag_sample_cfg *cfg)
static doca_error_t sample_mode_callback(void *param, void *config)
#define DATA_ID_PORT_0_RX_BYTES
static doca_error_t create_default_json(struct telemetry_diag_sample_cfg *cfg, struct json_object *example_json)
static doca_error_t example_json_file_callback(void *param, void *config)
static doca_error_t parse_json_data_ids(struct telemetry_diag_sample_cfg *cfg, struct json_object *json_data_ids, int array_len)
#define DEFAULT_TOTAL_RUN_TIME_SECS
#define JSON_NAME_KEY
static doca_error_t sample_period_callback(void *param, void *config)
#define DEFAULT_OUTPUT_FORMAT
static doca_error_t output_callback(void *param, void *config)
static doca_error_t run_time_callback(void *param, void *config)
#define DEFAULT_EXAMPLE_JSON_PATH
#define JSON_DATA_ID_KEY
#define DATA_ID_STRING_MAX_LEN
#define DEFAULT_OUTPUT_PATH
static doca_error_t max_num_samples_per_read_callback(void *param, void *config)
static doca_error_t output_format_callback(void *param, void *config)
static doca_error_t set_default_data_ids(struct telemetry_diag_sample_cfg *cfg)
static doca_error_t force_ownership_callback(void *param, void *config)
#define DATA_ID_PORT_0_TX_PACKETS
#define DEFAULT_DATA_IDS_PATH
doca_error_t telemetry_diag_sample_run(const struct telemetry_diag_sample_cfg *cfg)
#define MAX_NAME_SIZE
#define TELEMETRY_DIAG_SAMPLE_MAX_FILE_NAME