bypass_watchdog_example.c Source File

Reference Documentation

Platform
Intel® PAC
Napatech SmartNIC
Content Type
Reference Information
Capture Software Version
Link™ Capture Software 12.10
Napatech Software Suite: examples/bypass/watchdog/bypass_watchdog_example.c Source File
bypass_watchdog_example.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2023 Napatech A/S. All Rights Reserved.
4  *
5  * 1. Copying, modification, and distribution of this file, or executable
6  * versions of this file, is governed by the terms of the Napatech Software
7  * license agreement under which this file was made available. If you do not
8  * agree to the terms of the license do not install, copy, access or
9  * otherwise use this file.
10  *
11  * 2. Under the Napatech Software license agreement you are granted a
12  * limited, non-exclusive, non-assignable, copyright license to copy, modify
13  * and distribute this file in conjunction with Napatech SmartNIC's and
14  * similar hardware manufactured or supplied by Napatech A/S.
15  *
16  * 3. The full Napatech Software license agreement is included in this
17  * distribution, please see "NP-0405 Napatech Software license
18  * agreement.pdf"
19  *
20  * 4. Redistributions of source code must retain this copyright notice,
21  * list of conditions and the following disclaimer.
22  *
23  * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, EXPRESS OR
24  * IMPLIED, AND NAPATECH DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING ANY
25  * IMPLIED WARRANTY OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, OR OF
26  * FITNESS FOR A PARTICULAR PURPOSE. TO THE EXTENT NOT PROHIBITED BY
27  * APPLICABLE LAW, IN NO EVENT SHALL NAPATECH BE LIABLE FOR PERSONAL INJURY,
28  * OR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER,
29  * INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, CORRUPTION OR
30  * LOSS OF DATA, FAILURE TO TRANSMIT OR RECEIVE ANY DATA OR INFORMATION,
31  * BUSINESS INTERRUPTION OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING
32  * OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE NAPATECH SOFTWARE OR
33  * SERVICES OR ANY THIRD PARTY SOFTWARE OR APPLICATIONS IN CONJUNCTION WITH
34  * THE NAPATECH SOFTWARE OR SERVICES, HOWEVER CAUSED, REGARDLESS OF THE THEORY
35  * OF LIABILITY (CONTRACT, TORT OR OTHERWISE) AND EVEN IF NAPATECH HAS BEEN
36  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW
37  * THE EXCLUSION OR LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF
38  * INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU.
39  *
40  *
41 
42  */
43 
44 /**
45  * @example bypass/watchdog/bypass_watchdog_example.c
46  * @section bypass_watchdog_example_description Description
47  *
48  * This source file is an example of how to use the @ref ConfigStream
49  * "Configuration stream" interface in NTAPI for setting up and using
50  * the bypass watchdog timer using NTAPI (config stream)
51  *
52  * The following NTAPI functions are used:
53  * - @ref NT_Init()
54  * - @ref NT_InfoOpen()
55  * - @ref NT_InfoRead()
56  * - @ref NT_InfoClose()
57  * - @ref NT_ConfigOpen()
58  * - @ref NT_ConfigWrite()
59  * - @ref NT_ConfigRead()
60  * - @ref NT_ConfigClose()
61  * - @ref NT_Done()
62  * - @ref NT_ExplainError()
63  *
64  * <hr>
65  * @section bypass_watchdog_example_prerequisites Prerequisites
66  * A working system is needed with a Napatech bypass accelerator
67  *
68  * @section bypass_watchdog_example_flow Program flow
69  * @{
70  * The following is required to perform read and write operations on
71  * the @ref ConfigStream "configuration stream":
72  *
73  * - \#include/nt.h - Applications/Tools only need to include @ref
74  * nt.h to obtain prototypes, macros etc. from NTAPI.
75  * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI
76  * library. @ref NTAPI_VERSION is a define that describes the version
77  * of the API described in the header files included by @ref
78  * nt.h. @ref NT_Init() will ask the NTAPI library to convert return data
79  * to the @ref NTAPI_VERSION if possible. This will ensure that
80  * applications can run on NTAPI libraries of newer versions.
81  *
82  * - @ref NT_InfoOpen() - Open an info stream.
83  * - @ref NT_InfoRead() - Read info stream.
84  * - @ref NT_InfoClose() - Close the stream when terminating.
85  * - @ref NT_ConfigOpen() - Open a configuration stream.
86  * - @ref NT_ConfigRead() - Read configuration.
87  * - @ref NT_ConfigWrite() - Write configuration.
88  * - @ref NT_ConfigClose() - Close the stream when terminating.
89  * - @ref NT_Done() - Close down the NTAPI library.
90  * - @ref NT_ExplainError() - Explain an error code returned by NTAPI functions.
91  *
92  *<hr>
93  * @}
94  */
95 
96 // Include this in order to access the Napatech API
97 #include <nt.h>
98 
99 #if defined(__linux__) || defined(__FreeBSD__)
100  #include <unistd.h> // sleep()
101  #include <signal.h>
102 #elif defined(WIN32) || defined (WIN64)
103  #include <winsock2.h> // Sleep()
104 #endif
105 
106 #include <stdlib.h>
107 #include <stdio.h>
108 #include <limits.h>
109 #include <errno.h>
110 #include <time.h>
111 #include <string.h>
112 
113 #include <argparse.h>
114 
115 
116 //
117 // usage()
118 //
119 static const char *usageText[] =
120 {
121  "USAGE: bypass_watchdog_example [-a <adapter> | -p <port>] -t <watchdogTimeoutMsec> -s <watchdogDelayMsec>\n",
122  NULL
123 };
124 
125 //
126 // Flag to signal that application should stop.
127 //
128 static volatile bool stopApplication = false;
129 
130 //
131 // The function called when the user presses CTRL-C
132 //
133 #if defined(WIN32) || defined (WIN64)
134 static BOOL WINAPI StopApplication(int sig)
135 #else
136 static void StopApplication(int sig)
137 #endif
138 {
139 #ifdef WIN32
140  stopApplication = true;
141  return TRUE;
142 #else
143  if (sig == SIGINT)
144  stopApplication = true;
145 #endif
146 }
147 
148 static int adapterNo = -1;
149 static int portNo = -1;
150 static int watchdogTimeoutMsec = -1;
151 static int watchdogDelayMsec = -1;
152 
153 /**
154  * Table of valid options.
155  */
157  OPT_HELP(),
158  OPT_INTEGER('a', NULL, &adapterNo, "Adapter Number", NULL, 0, 0, "adapter number"),
159  OPT_INTEGER('p', NULL, &portNo, "Port Number", NULL, 0, 0, "port number"),
160  OPT_INTEGER('t', NULL, &watchdogTimeoutMsec, "Watchdog Timeout in msec", NULL, 0, 0, "msec"),
161  OPT_INTEGER('s', NULL, &watchdogDelayMsec, "Watchdog Delay in msec", NULL, 0, 0, "msec"),
162  OPT_END(),
163 };
164 
165 //
166 // main()
167 //
168 int main(int argc, const char *argv[])
169 {
170  uint32_t status = 0;
171  char errBuf[NT_ERRBUF_SIZE];
172  //
173  NtInfoStream_t hInfo;
174  NtConfigStream_t hConfig;
175  //
176  NtInfo_t infoSystem;
177  NtInfo_t infoAdapter;
178  NtInfo_t infoPort;
179  //
180  NtConfig_t configBypassState;
181  NtConfig_t saveBypassState;
182  enum NtBypassPortState_e* ep = NULL;
183  //
184  NtConfig_t configBypassWatchdogTimeout;
185  NtConfig_t configBypassWatchdogTimer;
186  //
187  //
188  int port;
189  int portBegin = 0;
190  int portCount = 0;
191  int iterationCount = 0;
192  int bypassFeatureFound = 0;
193  //
194  struct argparse argparse;
195  //
196  // Read command line arguments
197  //
198  argparse_init(&argparse, arg_options, usageText, 0);
199  argparse_parse(&argparse, argc, argv);
200  // Check that command line arguments are provided
201  if ((watchdogTimeoutMsec == -1) || (watchdogDelayMsec == -1) || (adapterNo == -1 && portNo == -1) || (adapterNo != -1 && portNo != -1)) {
202  argparse_usage(&argparse);
203  exit(0);
204  }
205 
206 // Set up ctrl+c handler
207 #if defined(WIN32) || defined (WIN64)
208  SetConsoleCtrlHandler((PHANDLER_ROUTINE)StopApplication, TRUE);
209 #else
210  struct sigaction newaction; // Ctrl+c handle
211  memset(&newaction, 0, sizeof(newaction));
212  newaction.sa_handler = StopApplication;
213  if (sigaction(SIGINT, &newaction, NULL) < 0) {
214  fprintf(stderr, "Failed to register sigaction.\n");
215  return -1;
216  }
217 #endif
218 
219  // cleanup structures
220  memset(&configBypassState, 0, sizeof(configBypassState));
221  memset(&saveBypassState, 0, sizeof(saveBypassState));
222  memset(&configBypassWatchdogTimeout, 0, sizeof(configBypassWatchdogTimeout));
223  memset(&configBypassWatchdogTimer, 0, sizeof(configBypassWatchdogTimer));
224 
225  // Initialize NTAPI library
226  if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
227  NT_ExplainError(status, errBuf, sizeof(errBuf));
228  fprintf(stderr, ">>> Error: NT_Init failed. Code 0x%x = %s\n", status, errBuf);
229  return status;
230  }
231 
232  // Open the config stream
233  status = NT_ConfigOpen(&hConfig, "bypass_watchdog_example");
234  if (status != NT_SUCCESS) {
235  NT_ExplainError(status, errBuf, sizeof(errBuf));
236  fprintf(stderr, ">>> Error: NT_ConfigOpen failed. Code 0x%x = %s\n", status, errBuf);
237  return status;
238  }
239 
240  // Open the information stream
241  if ((status = NT_InfoOpen(&hInfo, "bypass_watchdog_example")) != NT_SUCCESS) {
242  NT_ExplainError(status, errBuf, sizeof(errBuf));
243  fprintf(stderr, ">>> Error: NT_InfoOpen failed. Code 0x%x = %s\n", status, errBuf);
244  return status;
245  }
246 
247  // Read system information
248  infoSystem.cmd = NT_INFO_CMD_READ_SYSTEM;
249  if ((status = NT_InfoRead(hInfo, &infoSystem)) != NT_SUCCESS) {
250  NT_ExplainError(status, errBuf, sizeof(errBuf));
251  fprintf(stderr, ">>> Error: NT_InfoRead failed. Code 0x%x = %s\n", status, errBuf);
252  return status;
253  }
254 
255  printf("System: %d.%d.%d.%d\n\n", infoSystem.u.system.data.version.major,
256  infoSystem.u.system.data.version.minor,
257  infoSystem.u.system.data.version.patch,
258  infoSystem.u.system.data.version.tag);
259  printf("Adapters: %u\n", infoSystem.u.system.data.numAdapters);
260  printf("Ports: %u\n", infoSystem.u.system.data.numPorts);
261  printf("\n");
262 
263  if ( adapterNo != -1 && portNo == -1) {
264  printf("Adapter: %d\n", adapterNo);
265  } else {
266  printf("Port: %d\n", portNo);
267  }
268  printf("watchdogTimeoutMsec: %d\n", watchdogTimeoutMsec);
269  printf("watchdogDelayMsec: %d\n", watchdogDelayMsec);
270  printf("\n");
271 
272  //
273  // Check if adapter or port has bypass feature
274  //
275 
276  //
277  // Check for bypass adapter/port feature.
278  //
279  if ( adapterNo != -1 && portNo == -1) {
280  infoAdapter.cmd = NT_INFO_CMD_READ_ADAPTER_V6;
281  infoAdapter.u.adapter_v6.adapterNo = (uint8_t)adapterNo;
282  if ((status = NT_InfoRead(hInfo, &infoAdapter)) != NT_SUCCESS) {
283  NT_ExplainError(status, errBuf, sizeof(errBuf));
284  fprintf(stderr, ">>> Error: NT_InfoRead failed. Code 0x%x = %s\n", status, errBuf);
285  exit(EXIT_FAILURE);
286  }
287  portBegin = infoAdapter.u.adapter_v6.data.portOffset;
288  portCount = infoAdapter.u.adapter_v6.data.numPorts;
289  // Check if adapter itself is product type bypass.
290  if (infoAdapter.u.adapter_v6.data.productType == NT_PRODUCT_TYPE_BYPASS) {
291  printf("Adapter #%d has bypass feature\n", adapterNo);
292  bypassFeatureFound++;
293  }
294  } else {
295  portBegin = portNo;
296  portCount = 1;
297  }
298 
299 
300  for (port = 0; port < portCount; port++) {
301  infoPort.cmd = NT_INFO_CMD_READ_PORT_V9;
302  infoPort.u.port_v9.portNo = (uint8_t)(portBegin + port);
303  if ((status = NT_InfoRead(hInfo, &infoPort)) != 0) {
304  NT_ExplainError(status, errBuf, sizeof(errBuf));
305  fprintf(stderr, ">>> Error: NT_InfoRead failed. Code 0x%x = %s\n", status, errBuf);
306  exit(EXIT_FAILURE);
307  }
309  printf("Port #%d has bypass feature\n", portBegin + port);
310  bypassFeatureFound++;
311  }
312  }
313 
314  printf("\n");
315 
316  // Output result of search for bypass features
317  if ( adapterNo != -1 && portNo == -1) {
318  printf("Adapter #%d: ", adapterNo);
319  } else {
320  printf("Port #%d: ", portNo);
321  }
322 
323  if ( bypassFeatureFound != 0) {
324  printf("bypass feature found: OK\n\n");
325  } else {
326  printf("ERROR: bypass feature NOT found\n\n");
327  exit(EXIT_FAILURE);
328  }
329 
330  //
331  // WDT setup
332  //
333 
334  // Read bypass adapter/port state config
335  if ( adapterNo != -1 && portNo == -1) {
336  configBypassState.parm = NT_CONFIG_PARM_BYPASS_ADAPTER;
337  configBypassState.u.bypassConfig.u.adapterNo = (uint8_t)adapterNo;
338  } else {
339  configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT;
340  configBypassState.u.bypassConfig.u.portNo = (uint8_t)portNo;
341  }
342  if ((status = NT_ConfigRead(hConfig, &configBypassState)) != 0) {
343  NT_ExplainError(status, errBuf, sizeof(errBuf));
344  fprintf(stderr, ">>> Error: NT_ConfigRead failed. Code 0x%08X = %s\n", status, errBuf);
345  return status;
346  }
347 
348  // Save initial bypass state
349  saveBypassState = configBypassState;
350 
351  // Check saved adapter port state - if NT_BYPASS_PORT_STATE_UNKNOWN then ports can be controlled individually
353  ep = malloc(sizeof(enum NtBypassPortState_e)*portCount+1);
354  if (ep != NULL) {
355  // Save individual port state
356  for (port = 0; port < portCount; port++) {
357  configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT;
358  configBypassState.u.bypassConfig.u.portNo = (uint8_t)(portBegin + port);
359  if ((status = NT_ConfigRead(hConfig, &configBypassState)) != 0) {
360  NT_ExplainError(status, errBuf, sizeof(errBuf));
361  fprintf(stderr, ">>> Error: NT_ConfigRead failed. Code 0x%08X = %s\n", status, errBuf);
362  free(ep);
363  return status;
364  }
365  ep[port] = configBypassState.u.bypassConfig.data.currentBypassPortState;
366  }
367  } else {
368  exit(EXIT_FAILURE);
369  }
370  }
371 
372  // Prepare: setup bypass port states
373  if ( adapterNo != -1 && portNo == -1) {
374  configBypassState.parm = NT_CONFIG_PARM_BYPASS_ADAPTER;
375  configBypassState.u.bypassConfig.u.adapterNo = (uint8_t)adapterNo;
376  } else {
377  configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT;
378  configBypassState.u.bypassConfig.u.portNo = (uint8_t)portNo;
379  }
380 
383 
384  if ((status = NT_ConfigWrite(hConfig, &configBypassState)) != 0) {
385  NT_ExplainError(status, errBuf, sizeof(errBuf));
386  fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf);
387  free(ep);
388  return status;
389  }
390 
391  // Setup bypass port wdt config settings
392  if ( adapterNo != -1 && portNo == -1) {
393  configBypassWatchdogTimeout.parm = NT_CONFIG_PARM_BYPASS_ADAPTER_WATCHDOG_TIMEOUT;
394  configBypassWatchdogTimeout.u.bypassWatchdogTimeout.u.adapterNo = (uint8_t)adapterNo;
395  } else {
396  configBypassWatchdogTimeout.parm = NT_CONFIG_PARM_BYPASS_PORT_WATCHDOG_TIMEOUT;
397  configBypassWatchdogTimeout.u.bypassWatchdogTimeout.u.portNo = (uint8_t)portNo;
398  }
399  configBypassWatchdogTimeout.u.bypassWatchdogTimeout.data.bypassWatchdogTimeout = (uint32_t)watchdogTimeoutMsec;
400  if ((status = NT_ConfigWrite(hConfig, &configBypassWatchdogTimeout)) != 0) {
401  NT_ExplainError(status, errBuf, sizeof(errBuf));
402  fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf);
403  if (status == NT_ERROR_WATCHDOG_TIMEOUT_OUT_OF_RANGE) {
404 
405  // Restore bypass port states to previous state
406  fprintf(stderr, "\nRestoring previous bypass state\n");
407  configBypassState = saveBypassState;
408  // Check saved adapter port state - if NT_BYPASS_PORT_STATE_UNKNOWN then ports can be controlled individually
410  if ( adapterNo != -1 && portNo == -1) {
411  configBypassState.parm = NT_CONFIG_PARM_BYPASS_ADAPTER;
412  configBypassState.u.bypassConfig.u.adapterNo = (uint8_t)adapterNo;
413  } else {
414  configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT;
415  configBypassState.u.bypassConfig.u.portNo = (uint8_t)portNo;
416  }
417  if ((status = NT_ConfigWrite(hConfig, &configBypassState)) != 0) {
418  NT_ExplainError(status, errBuf, sizeof(errBuf));
419  fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf);
420  free(ep);
421  return status;
422  }
423 
424  } else {
425  if (ep != NULL) {
426  // Restore individual port state
427  for (port = 0; port < portCount; port++) {
428  configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT;
429  configBypassState.u.bypassConfig.u.portNo = (uint8_t)(portBegin + port);
430  configBypassState.u.bypassConfig.data.currentBypassPortState = ep[port];
431  if ((status = NT_ConfigWrite(hConfig, &configBypassState)) != 0) {
432  NT_ExplainError(status, errBuf, sizeof(errBuf));
433  fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf);
434  free(ep);
435  return status;
436  }
437  }
438  } else {
439  exit(EXIT_FAILURE);
440  }
441  }
442  }
443  free(ep);
444  return status;
445  }
446  printf("INFO: bypass setup: watchdog timeout=%u msec\n", configBypassWatchdogTimeout.u.bypassWatchdogTimeout.data.bypassWatchdogTimeout);
447 
448  //
449  // WDT heartbeat ping loop...
450  //
451  while (!stopApplication) {
452  struct NtConfigBypassWatchdogTimerData_s* bypassWatchdogTimerData;
453 
454  if ( adapterNo != -1 && portNo == -1) {
455  configBypassWatchdogTimer.parm = NT_CONFIG_PARM_BYPASS_ADAPTER_WATCHDOG_TIMER;
456  configBypassWatchdogTimer.u.bypassWatchdogTimer.u.adapterNo = (uint8_t)adapterNo;
457  } else {
458  configBypassWatchdogTimer.parm = NT_CONFIG_PARM_BYPASS_PORT_WATCHDOG_TIMER;
459  configBypassWatchdogTimer.u.bypassWatchdogTimer.u.portNo = (uint8_t)portNo;
460  }
461  configBypassWatchdogTimer.u.bypassWatchdogTimer.data.bypassWatchdogTimeout = 0;
462  configBypassWatchdogTimer.u.bypassWatchdogTimer.data.bypassWatchdogTimeRemaining = 0;
463  if ((status = NT_ConfigWrite(hConfig, &configBypassWatchdogTimer)) != 0) {
464 
465  NT_ExplainError(status, errBuf, sizeof(errBuf));
466  fprintf(stderr, ">>> Error: NT_ConfigRead failed. Code 0x%08X = %s\n", status, errBuf);
467  free(ep);
468  return status;
469  }
470 
471  // Process returned WDT timeouts.
472  bypassWatchdogTimerData = &configBypassWatchdogTimer.u.bypassWatchdogTimer.data;
473  printf("INFO: watchdog ping response : %s=%d wdt_timeout=%u msec wdt_remaining=%u msec iteration=%u\n", (portNo!=-1?"port":"adapter"), (portNo!=-1?portNo:adapterNo), bypassWatchdogTimerData->bypassWatchdogTimeout, bypassWatchdogTimerData->bypassWatchdogTimeRemaining, iterationCount);
474 
475  // Returned WDT timeout (not the remaining time) of value zero indicates that we have failed to deliver heartbeat ping within the proper (configured) WDT timeframe.
476  if (bypassWatchdogTimerData->bypassWatchdogTimeout == 0) {
477 
478  fprintf(stderr, "\n");
479  fprintf(stderr, "STOP: watchdog ping response : %s=%d wdt_timeout=%u msec wdt_remaining=%u msec iteration=%u\n", (portNo!=-1?"port":"adapter"), (portNo!=-1?portNo:adapterNo), bypassWatchdogTimerData->bypassWatchdogTimeout, bypassWatchdogTimerData->bypassWatchdogTimeRemaining, iterationCount);
480  fprintf(stderr, "\n");
481  break;
482  }
483  iterationCount++;
484 
485  // If remaining time is close to run out then skip wait delay.
486  if (bypassWatchdogTimerData->bypassWatchdogTimeRemaining >= 25) {
487  if (watchdogDelayMsec >= 1) {
488  #if defined(__linux__) || defined(__FreeBSD__)
489  usleep(watchdogDelayMsec*1000U); // sleep in microseconds
490  #elif defined(WIN32) || defined (WIN64)
491  Sleep(watchdogDelayMsec); // sleep in milliseconds
492  #endif
493  }
494  }
495  }
496 
497  free(ep);
498 
499  // Close down the NTAPI library
500  NT_Done();
501  printf("Done.\n");
502 
503  return 0;
504 }
505 
506 //
507 // EOF
508 //