bypass_watchdog_example.c Source File

Reference Documentation

Platform
Napatech SmartNIC
Content Type
Reference Information
Capture Software Version
Link™ Capture Software 12.15
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 2025 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 "NA-0009 Software License Agreement.pdf"
18  *
19  * 4. Redistributions of source code must retain this copyright notice,
20  * list of conditions and the following disclaimer.
21  *
22  * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, EXPRESS OR
23  * IMPLIED, AND NAPATECH DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING ANY
24  * IMPLIED WARRANTY OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, OR OF
25  * FITNESS FOR A PARTICULAR PURPOSE. TO THE EXTENT NOT PROHIBITED BY
26  * APPLICABLE LAW, IN NO EVENT SHALL NAPATECH BE LIABLE FOR PERSONAL INJURY,
27  * OR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER,
28  * INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, CORRUPTION OR
29  * LOSS OF DATA, FAILURE TO TRANSMIT OR RECEIVE ANY DATA OR INFORMATION,
30  * BUSINESS INTERRUPTION OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING
31  * OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE NAPATECH SOFTWARE OR
32  * SERVICES OR ANY THIRD PARTY SOFTWARE OR APPLICATIONS IN CONJUNCTION WITH
33  * THE NAPATECH SOFTWARE OR SERVICES, HOWEVER CAUSED, REGARDLESS OF THE THEORY
34  * OF LIABILITY (CONTRACT, TORT OR OTHERWISE) AND EVEN IF NAPATECH HAS BEEN
35  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW
36  * THE EXCLUSION OR LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF
37  * INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU.
38  *
39  *
40 
41  */
42 
43 /**
44  * @example bypass/watchdog/bypass_watchdog_example.c
45  * @section bypass_watchdog_example_description Description
46  *
47  * This source file is an example of how to use the @ref ConfigStream
48  * "Configuration stream" interface in NTAPI for setting up and using
49  * the bypass watchdog timer using NTAPI (config stream)
50  *
51  * The following NTAPI functions are used:
52  * - @ref NT_Init()
53  * - @ref NT_InfoOpen()
54  * - @ref NT_InfoRead()
55  * - @ref NT_InfoClose()
56  * - @ref NT_ConfigOpen()
57  * - @ref NT_ConfigWrite()
58  * - @ref NT_ConfigRead()
59  * - @ref NT_ConfigClose()
60  * - @ref NT_Done()
61  * - @ref NT_ExplainError()
62  *
63  * <hr>
64  * @section bypass_watchdog_example_prerequisites Prerequisites
65  * A working system is needed with a Napatech bypass accelerator
66  *
67  * @section bypass_watchdog_example_flow Program flow
68  * @{
69  * The following is required to perform read and write operations on
70  * the @ref ConfigStream "configuration stream":
71  *
72  * - \#include/nt.h - Applications/Tools only need to include @ref
73  * nt.h to obtain prototypes, macros etc. from NTAPI.
74  * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI
75  * library. @ref NTAPI_VERSION is a define that describes the version
76  * of the API described in the header files included by @ref
77  * nt.h. @ref NT_Init() will ask the NTAPI library to convert return data
78  * to the @ref NTAPI_VERSION if possible. This will ensure that
79  * applications can run on NTAPI libraries of newer versions.
80  *
81  * - @ref NT_InfoOpen() - Open an info stream.
82  * - @ref NT_InfoRead() - Read info stream.
83  * - @ref NT_InfoClose() - Close the stream when terminating.
84  * - @ref NT_ConfigOpen() - Open a configuration stream.
85  * - @ref NT_ConfigRead() - Read configuration.
86  * - @ref NT_ConfigWrite() - Write configuration.
87  * - @ref NT_ConfigClose() - Close the stream when terminating.
88  * - @ref NT_Done() - Close down the NTAPI library.
89  * - @ref NT_ExplainError() - Explain an error code returned by NTAPI functions.
90  *
91  *<hr>
92  * @}
93  */
94 
95 // Include this in order to access the Napatech API
96 #include <nt.h>
97 
98 #if defined(WIN32) || defined (WIN64)
99  #include <winsock2.h> // Sleep()
100 #else
101  #include <unistd.h> // sleep()
102  #include <signal.h>
103  #include <stdatomic.h>
104 #endif
105 
106 #include <stdlib.h>
107 #include <stdio.h>
108 #include <limits.h>
109 #include <time.h>
110 #include <string.h>
111 
112 #include <argparse.h>
113 
114 
115 //
116 // usage()
117 //
118 static const char *usageText[] =
119 {
120  "USAGE: bypass_watchdog_example [-a <adapter> | -p <port>] -t <watchdogTimeoutMsec> -s <watchdogDelayMsec>\n",
121  NULL
122 };
123 
124 #if defined(WIN32) || defined (WIN64)
125 static volatile int appRunning = 1; // The application will run as long as appRunning == 1
126 #else
127 static atomic_int appRunning = 1; // The application will run as long as appRunning == 1
128 #endif
129 
130 static int adapterNo = -1;
131 static int portNo = -1;
132 static int watchdogTimeoutMsec = -1;
133 static int watchdogDelayMsec = -1;
134 
135 /**
136  * Table of valid options.
137  */
139  OPT_HELP(),
140  OPT_INTEGER('a', NULL, &adapterNo, "Adapter Number", NULL, 0, 0, "adapter number"),
141  OPT_INTEGER('p', NULL, &portNo, "Port Number", NULL, 0, 0, "port number"),
142  OPT_INTEGER('t', NULL, &watchdogTimeoutMsec, "Watchdog Timeout in msec", NULL, 0, 0, "msec"),
143  OPT_INTEGER('s', NULL, &watchdogDelayMsec, "Watchdog Delay in msec", NULL, 0, 0, "msec"),
144  OPT_END(),
145 };
146 
147 //
148 // The function called when the user presses CTRL-C
149 //
150 #if defined(WIN32) || defined (WIN64)
151 static BOOL WINAPI StopApplication(int sig)
152 {
153  (void) sig;
154  appRunning = 0;
155  return TRUE;
156 }
157 #else
158 static void StopApplication(int sig)
159 {
160  if (sig == SIGINT)
161  appRunning = 0;
162 }
163 #endif
164 
165 //
166 // main()
167 //
168 int main(int argc, const char *argv[])
169 {
170  int 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  unsigned int port;
189  unsigned int portBegin = 0;
190  unsigned 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  // Register ctrl+c handler so we are able to stop again
207 #if defined(WIN32) || defined (WIN64)
208  SetConsoleCtrlHandler((PHANDLER_ROUTINE)StopApplication, TRUE);
209 #else
210  struct sigaction newaction; // Ctrl+c signal handler container
211  memset(&newaction, 0, sizeof(newaction));
212  newaction.sa_handler = StopApplication;
213  if (sigaction(SIGINT, &newaction, NULL) < 0) {
214  fprintf(stderr, "Failed to register SIGINT sigaction.\n");
215  exit(EXIT_FAILURE);
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_V7;
281  infoAdapter.u.adapter_v7.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_v7.data.portOffset;
288  portCount = infoAdapter.u.adapter_v7.data.numPorts;
289  // Check if adapter itself is product type bypass.
290  if (infoAdapter.u.adapter_v7.data.productType == NT_PRODUCT_TYPE_BYPASS) {
291  printf("Adapter #%d has bypass feature\n", adapterNo);
292  bypassFeatureFound++;
293  }
294  } else {
295  portBegin = (unsigned)portNo;
296  portCount = 1;
297  }
298 
299 
300  for (port = 0; port < portCount; port++) {
301  infoPort.cmd = NT_INFO_CMD_READ_PORT_V10;
302  infoPort.u.port_v10.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 (appRunning == 1) {
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(WIN32) || defined (WIN64)
489  Sleep(watchdogDelayMsec); // sleep in milliseconds
490  #else
491  usleep((useconds_t)watchdogDelayMsec*1000U); // sleep in microseconds
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 //