bypass_watchdog_example.c

Reference Documentation

product_line_custom
Napatech SmartNIC
category
Reference Information

Go to the documentation of this file.

1/* 2 * %NT_SOFTWARE_LICENSE% 3 */ 4 5/** 6 * @example bypass/watchdog/bypass_watchdog_example.c 7 * @section bypass_watchdog_example_description Description 8 * 9 * This source file is an example of how to use the @ref ConfigStream 10 * "Configuration stream" interface in NTAPI for setting up and using 11 * the bypass watchdog timer using NTAPI (config stream) 12 * 13 * The following NTAPI functions are used: 14 * - @ref NT_Init() 15 * - @ref NT_InfoOpen() 16 * - @ref NT_InfoRead() 17 * - @ref NT_InfoClose() 18 * - @ref NT_ConfigOpen() 19 * - @ref NT_ConfigWrite() 20 * - @ref NT_ConfigRead() 21 * - @ref NT_ConfigClose() 22 * - @ref NT_Done() 23 * - @ref NT_ExplainError() 24 * 25 * <hr> 26 * @section bypass_watchdog_example_prerequisites Prerequisites 27 * A working system is needed with a Napatech bypass accelerator 28 * 29 * @section bypass_watchdog_example_flow Program flow 30 * @{ 31 * The following is required to perform read and write operations on 32 * the @ref ConfigStream "configuration stream": 33 * 34 * - \#include/nt.h - Applications/Tools only need to include @ref 35 * nt.h to obtain prototypes, macros etc. from NTAPI. 36 * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI 37 * library. @ref NTAPI_VERSION is a define that describes the version 38 * of the API described in the header files included by @ref 39 * nt.h. @ref NT_Init() will ask the NTAPI library to convert return data 40 * to the @ref NTAPI_VERSION if possible. This will ensure that 41 * applications can run on NTAPI libraries of newer versions. 42 * 43 * - @ref NT_InfoOpen() - Open an info stream. 44 * - @ref NT_InfoRead() - Read info stream. 45 * - @ref NT_InfoClose() - Close the stream when terminating. 46 * - @ref NT_ConfigOpen() - Open a configuration stream. 47 * - @ref NT_ConfigRead() - Read configuration. 48 * - @ref NT_ConfigWrite() - Write configuration. 49 * - @ref NT_ConfigClose() - Close the stream when terminating. 50 * - @ref NT_Done() - Close down the NTAPI library. 51 * - @ref NT_ExplainError() - Explain an error code returned by NTAPI functions. 52 * 53 *<hr> 54 * @} 55 */ 56 57 58 59// std includes 60 61#if defined(__linux__) || defined(__FreeBSD__) 62#include <unistd.h> 63#include <signal.h> 64#elif defined(WIN32) || defined (WIN64) 65#include <winsock2.h> // Sleep() 66#endif 67 68#include <stdlib.h> 69#include <stdio.h> 70#include <limits.h> 71#include <errno.h> 72#include <time.h> 73#include <string.h> 74#include <argparse.h> 75 76// NT includes 77#include "nt.h" 78 79// 80// usage() 81// 82static const char *usageText[] = 83{ 84 "USAGE: bypass_watchdog_example [-a <adapter> | -p <port>] -t <watchdogTimeoutMsec> -s <watchdogDelayMsec>\n", 85 NULL 86}; 87 88// 89// Flag to signal that application should stop. 90// 91static volatile bool stopApplication = false; 92 93// 94// The function called when the user presses CTRL-C 95// 96#if defined(WIN32) || defined (WIN64) 97static BOOL WINAPI StopApplication(int sig) 98#else 99static void StopApplication(int sig) 100#endif 101{ 102#ifdef WIN32 103 stopApplication = true; 104 return TRUE; 105#else 106 if (sig == SIGINT) 107 stopApplication = true; 108#endif 109} 110 111static int adapterNo = -1; 112static int portNo = -1; 113static int watchdogTimeoutMsec = -1; 114static int watchdogDelayMsec = -1; 115 116/** 117 * Table of valid options. 118 */ 119struct argparse_option arg_options[] = { 120 OPT_HELP(), 121 OPT_INTEGER('a', NULL, &adapterNo, "Adapter Number", NULL, 0, 0, "adapter number"), 122 OPT_INTEGER('p', NULL, &portNo, "Port Number", NULL, 0, 0, "port number"), 123 OPT_INTEGER('t', NULL, &watchdogTimeoutMsec, "Watchdog Timeout in msec", NULL, 0, 0, "msec"), 124 OPT_INTEGER('s', NULL, &watchdogDelayMsec, "Watchdog Delay in msec", NULL, 0, 0, "msec"), 125 OPT_END(), 126}; 127 128// 129// main() 130// 131int main(int argc, const char *argv[]) 132{ 133 uint32_t status = 0; 134 char errBuf[NT_ERRBUF_SIZE]; 135 // 136 NtInfoStream_t hInfo; 137 NtConfigStream_t hConfig; 138 // 139 NtInfo_t infoSystem; 140 NtInfo_t infoAdapter; 141 NtInfo_t infoPort; 142 // 143 NtConfig_t configBypassState; 144 NtConfig_t saveBypassState; 145 enum NtBypassPortState_e* ep = NULL; 146 // 147 NtConfig_t configBypassWatchdogTimeout; 148 NtConfig_t configBypassWatchdogTimer; 149 // 150 // 151 int port; 152 int portBegin = 0; 153 int portCount = 0; 154 int iterationCount = 0; 155 int bypassFeatureFound = 0; 156 // 157 struct argparse argparse; 158 // 159 // Read command line arguments 160 // 161 argparse_init(&argparse, arg_options, usageText, 0); 162 argparse_parse(&argparse, argc, argv); 163 // Check that command line arguments are provided 164 if ((watchdogTimeoutMsec == -1) || (watchdogDelayMsec == -1) || (adapterNo == -1 && portNo == -1) || (adapterNo != -1 && portNo != -1)) { 165 argparse_usage(&argparse); 166 exit(0); 167 } 168 169// Set up ctrl+c handler 170#if defined(WIN32) || defined (WIN64) 171 SetConsoleCtrlHandler((PHANDLER_ROUTINE)StopApplication, TRUE); 172#else 173 struct sigaction newaction; // Ctrl+c handle 174 memset(&newaction, 0, sizeof(newaction)); 175 newaction.sa_handler = StopApplication; 176 if (sigaction(SIGINT, &newaction, NULL) < 0) { 177 fprintf(stderr, "Failed to register sigaction.\n"); 178 return -1; 179 } 180#endif 181 182 // cleanup structures 183 memset(&configBypassState, 0, sizeof(configBypassState)); 184 memset(&saveBypassState, 0, sizeof(saveBypassState)); 185 memset(&configBypassWatchdogTimeout, 0, sizeof(configBypassWatchdogTimeout)); 186 memset(&configBypassWatchdogTimer, 0, sizeof(configBypassWatchdogTimer)); 187 188 // Initialize NTAPI library 189 if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) { 190 NT_ExplainError(status, errBuf, sizeof(errBuf)); 191 fprintf(stderr, ">>> Error: NT_Init failed. Code 0x%x = %s\n", status, errBuf); 192 return status; 193 } 194 195 // Open the config stream 196 status = NT_ConfigOpen(&hConfig, "bypass_watchdog_example"); 197 if (status != NT_SUCCESS) { 198 NT_ExplainError(status, errBuf, sizeof(errBuf)); 199 fprintf(stderr, ">>> Error: NT_ConfigOpen failed. Code 0x%x = %s\n", status, errBuf); 200 return status; 201 } 202 203 // Open the information stream 204 if ((status = NT_InfoOpen(&hInfo, "bypass_watchdog_example")) != NT_SUCCESS) { 205 NT_ExplainError(status, errBuf, sizeof(errBuf)); 206 fprintf(stderr, ">>> Error: NT_InfoOpen failed. Code 0x%x = %s\n", status, errBuf); 207 return status; 208 } 209 210 // Read system information 211 infoSystem.cmd = NT_INFO_CMD_READ_SYSTEM; 212 if ((status = NT_InfoRead(hInfo, &infoSystem)) != NT_SUCCESS) { 213 NT_ExplainError(status, errBuf, sizeof(errBuf)); 214 fprintf(stderr, ">>> Error: NT_InfoRead failed. Code 0x%x = %s\n", status, errBuf); 215 return status; 216 } 217 218 printf("System: %d.%d.%d.%d\n\n", infoSystem.u.system.data.version.major, 219 infoSystem.u.system.data.version.minor, 220 infoSystem.u.system.data.version.patch, 221 infoSystem.u.system.data.version.tag); 222 printf("Adapters: %u\n", infoSystem.u.system.data.numAdapters); 223 printf("Ports: %u\n", infoSystem.u.system.data.numPorts); 224 printf("\n"); 225 226 if ( adapterNo != -1 && portNo == -1) { 227 printf("Adapter: %d\n", adapterNo); 228 } else { 229 printf("Port: %d\n", portNo); 230 } 231 printf("watchdogTimeoutMsec: %d\n", watchdogTimeoutMsec); 232 printf("watchdogDelayMsec: %d\n", watchdogDelayMsec); 233 printf("\n"); 234 235 // 236 // Check if adapter or port has bypass feature 237 // 238 239 // 240 // Check for bypass adapter/port feature. 241 // 242 if ( adapterNo != -1 && portNo == -1) { 243 infoAdapter.cmd = NT_INFO_CMD_READ_ADAPTER_V6; 244 infoAdapter.u.adapter_v6.adapterNo = (uint8_t)adapterNo; 245 if ((status = NT_InfoRead(hInfo, &infoAdapter)) != NT_SUCCESS) { 246 NT_ExplainError(status, errBuf, sizeof(errBuf)); 247 fprintf(stderr, ">>> Error: NT_InfoRead failed. Code 0x%x = %s\n", status, errBuf); 248 exit(EXIT_FAILURE); 249 } 250 portBegin = infoAdapter.u.adapter_v6.data.portOffset; 251 portCount = infoAdapter.u.adapter_v6.data.numPorts; 252 // Check if adapter itself is product type bypass. 253 if (infoAdapter.u.adapter_v6.data.productType == NT_PRODUCT_TYPE_BYPASS) { 254 printf("Adapter #%d has bypass feature\n", adapterNo); 255 bypassFeatureFound++; 256 } 257 } else { 258 portBegin = portNo; 259 portCount = 1; 260 } 261 262 263 for (port = 0; port < portCount; port++) { 264 infoPort.cmd = NT_INFO_CMD_READ_PORT_V9; 265 infoPort.u.port_v9.portNo = (uint8_t)(portBegin + port); 266 if ((status = NT_InfoRead(hInfo, &infoPort)) != 0) { 267 NT_ExplainError(status, errBuf, sizeof(errBuf)); 268 fprintf(stderr, ">>> Error: NT_InfoRead failed. Code 0x%x = %s\n", status, errBuf); 269 exit(EXIT_FAILURE); 270 } 271 if ( infoPort.u.port_v9.data.capabilities.featureMask & NT_PORT_FEATURE_BYPASS) { 272 printf("Port #%d has bypass feature\n", portBegin + port); 273 bypassFeatureFound++; 274 } 275 } 276 277 printf("\n"); 278 279 // Output result of search for bypass features 280 if ( adapterNo != -1 && portNo == -1) { 281 printf("Adapter #%d: ", adapterNo); 282 } else { 283 printf("Port #%d: ", portNo); 284 } 285 286 if ( bypassFeatureFound != 0) { 287 printf("bypass feature found: OK\n\n"); 288 } else { 289 printf("ERROR: bypass feature NOT found\n\n"); 290 exit(EXIT_FAILURE); 291 } 292 293 // 294 // WDT setup 295 // 296 297 // Read bypass adapter/port state config 298 if ( adapterNo != -1 && portNo == -1) { 299 configBypassState.parm = NT_CONFIG_PARM_BYPASS_ADAPTER; 300 configBypassState.u.bypassConfig.u.adapterNo = (uint8_t)adapterNo; 301 } else { 302 configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT; 303 configBypassState.u.bypassConfig.u.portNo = (uint8_t)portNo; 304 } 305 if ((status = NT_ConfigRead(hConfig, &configBypassState)) != 0) { 306 NT_ExplainError(status, errBuf, sizeof(errBuf)); 307 fprintf(stderr, ">>> Error: NT_ConfigRead failed. Code 0x%08X = %s\n", status, errBuf); 308 return status; 309 } 310 311 // Save initial bypass state 312 saveBypassState = configBypassState; 313 314 // Check saved adapter port state - if NT_BYPASS_PORT_STATE_UNKNOWN then ports can be controlled individually 315 if (saveBypassState.u.bypassConfig.data.currentBypassPortState == NT_BYPASS_PORT_STATE_UNKNOWN) { 316 ep = malloc(sizeof(enum NtBypassPortState_e)*portCount+1); 317 if (ep != NULL) { 318 // Save individual port state 319 for (port = 0; port < portCount; port++) { 320 configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT; 321 configBypassState.u.bypassConfig.u.portNo = (uint8_t)(portBegin + port); 322 if ((status = NT_ConfigRead(hConfig, &configBypassState)) != 0) { 323 NT_ExplainError(status, errBuf, sizeof(errBuf)); 324 fprintf(stderr, ">>> Error: NT_ConfigRead failed. Code 0x%08X = %s\n", status, errBuf); 325 free(ep); 326 return status; 327 } 328 ep[port] = configBypassState.u.bypassConfig.data.currentBypassPortState; 329 } 330 } else { 331 exit(EXIT_FAILURE); 332 } 333 } 334 335 // Prepare: setup bypass port states 336 if ( adapterNo != -1 && portNo == -1) { 337 configBypassState.parm = NT_CONFIG_PARM_BYPASS_ADAPTER; 338 configBypassState.u.bypassConfig.u.adapterNo = (uint8_t)adapterNo; 339 } else { 340 configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT; 341 configBypassState.u.bypassConfig.u.portNo = (uint8_t)portNo; 342 } 343 344 configBypassState.u.bypassConfig.data.currentBypassPortState = NT_BYPASS_PORT_STATE_NORMAL; 345 configBypassState.u.bypassConfig.data.onWatchdogFailBypassPortState = NT_BYPASS_PORT_STATE_BYPASS; 346 347 if ((status = NT_ConfigWrite(hConfig, &configBypassState)) != 0) { 348 NT_ExplainError(status, errBuf, sizeof(errBuf)); 349 fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf); 350 free(ep); 351 return status; 352 } 353 354 // Setup bypass port wdt config settings 355 if ( adapterNo != -1 && portNo == -1) { 356 configBypassWatchdogTimeout.parm = NT_CONFIG_PARM_BYPASS_ADAPTER_WATCHDOG_TIMEOUT; 357 configBypassWatchdogTimeout.u.bypassWatchdogTimeout.u.adapterNo = (uint8_t)adapterNo; 358 } else { 359 configBypassWatchdogTimeout.parm = NT_CONFIG_PARM_BYPASS_PORT_WATCHDOG_TIMEOUT; 360 configBypassWatchdogTimeout.u.bypassWatchdogTimeout.u.portNo = (uint8_t)portNo; 361 } 362 configBypassWatchdogTimeout.u.bypassWatchdogTimeout.data.bypassWatchdogTimeout = watchdogTimeoutMsec; 363 if ((status = NT_ConfigWrite(hConfig, &configBypassWatchdogTimeout)) != 0) { 364 NT_ExplainError(status, errBuf, sizeof(errBuf)); 365 fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf); 366 if (status == NT_ERROR_WATCHDOG_TIMEOUT_OUT_OF_RANGE) { 367 368 // Restore bypass port states to previous state 369 fprintf(stderr, "\nRestoring previous bypass state\n"); 370 configBypassState = saveBypassState; 371 // Check saved adapter port state - if NT_BYPASS_PORT_STATE_UNKNOWN then ports can be controlled individually 372 if (saveBypassState.u.bypassConfig.data.currentBypassPortState != NT_BYPASS_PORT_STATE_UNKNOWN) { 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 if ((status = NT_ConfigWrite(hConfig, &configBypassState)) != 0) { 381 NT_ExplainError(status, errBuf, sizeof(errBuf)); 382 fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf); 383 free(ep); 384 return status; 385 } 386 387 } else { 388 if (ep != NULL) { 389 // Restore individual port state 390 for (port = 0; port < portCount; port++) { 391 configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT; 392 configBypassState.u.bypassConfig.u.portNo = (uint8_t)(portBegin + port); 393 configBypassState.u.bypassConfig.data.currentBypassPortState = ep[port]; 394 if ((status = NT_ConfigWrite(hConfig, &configBypassState)) != 0) { 395 NT_ExplainError(status, errBuf, sizeof(errBuf)); 396 fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf); 397 free(ep); 398 return status; 399 } 400 } 401 } else { 402 exit(EXIT_FAILURE); 403 } 404 } 405 } 406 free(ep); 407 return status; 408 } 409 printf("INFO: bypass setup: watchdog timeout=%u msec\n", configBypassWatchdogTimeout.u.bypassWatchdogTimeout.data.bypassWatchdogTimeout); 410 411 // 412 // WDT heartbeat ping loop... 413 // 414 while(!stopApplication) { 415 struct NtConfigBypassWatchdogTimerData_s* bypassWatchdogTimerData; 416 417 if ( adapterNo != -1 && portNo == -1) { 418 configBypassWatchdogTimer.parm = NT_CONFIG_PARM_BYPASS_ADAPTER_WATCHDOG_TIMER; 419 configBypassWatchdogTimer.u.bypassWatchdogTimer.u.adapterNo = (uint8_t)adapterNo; 420 } else { 421 configBypassWatchdogTimer.parm = NT_CONFIG_PARM_BYPASS_PORT_WATCHDOG_TIMER; 422 configBypassWatchdogTimer.u.bypassWatchdogTimer.u.portNo = (uint8_t)portNo; 423 } 424 configBypassWatchdogTimer.u.bypassWatchdogTimer.data.bypassWatchdogTimeout = 0; 425 configBypassWatchdogTimer.u.bypassWatchdogTimer.data.bypassWatchdogTimeRemaining = 0; 426 if ((status = NT_ConfigWrite(hConfig, &configBypassWatchdogTimer)) != 0) { 427 428 NT_ExplainError(status, errBuf, sizeof(errBuf)); 429 fprintf(stderr, ">>> Error: NT_ConfigRead failed. Code 0x%08X = %s\n", status, errBuf); 430 free(ep); 431 return status; 432 } 433 434 // Process returned WDT timeouts. 435 bypassWatchdogTimerData = &configBypassWatchdogTimer.u.bypassWatchdogTimer.data; 436 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); 437 438 // 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. 439 if (bypassWatchdogTimerData->bypassWatchdogTimeout == 0) { 440 441 fprintf(stderr, "\n"); 442 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); 443 fprintf(stderr, "\n"); 444 break; 445 } 446 iterationCount++; 447 448 // If remaining time is close to run out then skip wait delay. 449 if (bypassWatchdogTimerData->bypassWatchdogTimeRemaining >= 25) { 450 if (watchdogDelayMsec >= 1) { 451 #if defined(__linux__) || defined(__FreeBSD__) 452 usleep(watchdogDelayMsec*1000U); // sleep in microseconds 453 #elif defined(WIN32) || defined (WIN64) 454 Sleep(watchdogDelayMsec); // sleep in milliseconds 455 #endif 456 } 457 } 458 } 459 460 free(ep); 461 462 // Close down the NTAPI library 463 NT_Done(); 464 printf("Done.\n"); 465 466 return 0; 467} 468 469// 470// EOF 471//