bypass/watchdog/bypass_watchdog_example.c

Reference Documentation

product_line_custom
Napatech SmartNIC
category
Reference Information

Description

This source file is an example of how to use the Configuration stream interface in NTAPI for setting up and using the bypass watchdog timer using NTAPI (config stream)

Prerequisites

A working system is needed with a Napatech bypass accelerator

Program flow

The following is required to perform read and write operations on the configuration stream:

/* * %NT_SOFTWARE_LICENSE% */ /** * @example bypass/watchdog/bypass_watchdog_example.c * @section bypass_watchdog_example_description Description * * This source file is an example of how to use the @ref ConfigStream * "Configuration stream" interface in NTAPI for setting up and using * the bypass watchdog timer using NTAPI (config stream) * * The following NTAPI functions are used: * - @ref NT_Init() * - @ref NT_InfoOpen() * - @ref NT_InfoRead() * - @ref NT_InfoClose() * - @ref NT_ConfigOpen() * - @ref NT_ConfigWrite() * - @ref NT_ConfigRead() * - @ref NT_ConfigClose() * - @ref NT_Done() * - @ref NT_ExplainError() * * <hr> * @section bypass_watchdog_example_prerequisites Prerequisites * A working system is needed with a Napatech bypass accelerator * * @section bypass_watchdog_example_flow Program flow * @{ * The following is required to perform read and write operations on * the @ref ConfigStream "configuration stream": * * - \#include/nt.h - Applications/Tools only need to include @ref * nt.h to obtain prototypes, macros etc. from NTAPI. * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI * library. @ref NTAPI_VERSION is a define that describes the version * of the API described in the header files included by @ref * nt.h. @ref NT_Init() will ask the NTAPI library to convert return data * to the @ref NTAPI_VERSION if possible. This will ensure that * applications can run on NTAPI libraries of newer versions. * * - @ref NT_InfoOpen() - Open an info stream. * - @ref NT_InfoRead() - Read info stream. * - @ref NT_InfoClose() - Close the stream when terminating. * - @ref NT_ConfigOpen() - Open a configuration stream. * - @ref NT_ConfigRead() - Read configuration. * - @ref NT_ConfigWrite() - Write configuration. * - @ref NT_ConfigClose() - Close the stream when terminating. * - @ref NT_Done() - Close down the NTAPI library. * - @ref NT_ExplainError() - Explain an error code returned by NTAPI functions. * *<hr> * @} */ // std includes #if defined(__linux__) || defined(__FreeBSD__) #include <unistd.h> #include <signal.h> #elif defined(WIN32) || defined (WIN64) #include <winsock2.h> // Sleep() #endif #include <stdlib.h> #include <stdio.h> #include <limits.h> #include <errno.h> #include <time.h> #include <string.h> #include <argparse.h> // NT includes #include "nt.h" // // usage() // static const char *usageText[] = { "USAGE: bypass_watchdog_example [-a <adapter> | -p <port>] -t <watchdogTimeoutMsec> -s <watchdogDelayMsec>\n", NULL }; // // Flag to signal that application should stop. // static volatile bool stopApplication = false; // // The function called when the user presses CTRL-C // #if defined(WIN32) || defined (WIN64) static BOOL WINAPI StopApplication(int sig) #else static void StopApplication(int sig) #endif { #ifdef WIN32 stopApplication = true; return TRUE; #else if (sig == SIGINT) stopApplication = true; #endif } static int adapterNo = -1; static int portNo = -1; static int watchdogTimeoutMsec = -1; static int watchdogDelayMsec = -1; /** * Table of valid options. */ struct argparse_option arg_options[] = { OPT_HELP(), OPT_INTEGER('a', NULL, &adapterNo, "Adapter Number", NULL, 0, 0, "adapter number"), OPT_INTEGER('p', NULL, &portNo, "Port Number", NULL, 0, 0, "port number"), OPT_INTEGER('t', NULL, &watchdogTimeoutMsec, "Watchdog Timeout in msec", NULL, 0, 0, "msec"), OPT_INTEGER('s', NULL, &watchdogDelayMsec, "Watchdog Delay in msec", NULL, 0, 0, "msec"), OPT_END(), }; // // main() // int main(int argc, const char *argv[]) { uint32_t status = 0; char errBuf[NT_ERRBUF_SIZE]; // NtInfoStream_t hInfo; NtConfigStream_t hConfig; // NtInfo_t infoSystem; NtInfo_t infoAdapter; NtInfo_t infoPort; // NtConfig_t configBypassState; NtConfig_t saveBypassState; enum NtBypassPortState_e* ep = NULL; // NtConfig_t configBypassWatchdogTimeout; NtConfig_t configBypassWatchdogTimer; // // int port; int portBegin = 0; int portCount = 0; int iterationCount = 0; int bypassFeatureFound = 0; // struct argparse argparse; // // Read command line arguments // argparse_init(&argparse, arg_options, usageText, 0); argparse_parse(&argparse, argc, argv); // Check that command line arguments are provided if ((watchdogTimeoutMsec == -1) || (watchdogDelayMsec == -1) || (adapterNo == -1 && portNo == -1) || (adapterNo != -1 && portNo != -1)) { argparse_usage(&argparse); exit(0); } // Set up ctrl+c handler #if defined(WIN32) || defined (WIN64) SetConsoleCtrlHandler((PHANDLER_ROUTINE)StopApplication, TRUE); #else struct sigaction newaction; // Ctrl+c handle memset(&newaction, 0, sizeof(newaction)); newaction.sa_handler = StopApplication; if (sigaction(SIGINT, &newaction, NULL) < 0) { fprintf(stderr, "Failed to register sigaction.\n"); return -1; } #endif // cleanup structures memset(&configBypassState, 0, sizeof(configBypassState)); memset(&saveBypassState, 0, sizeof(saveBypassState)); memset(&configBypassWatchdogTimeout, 0, sizeof(configBypassWatchdogTimeout)); memset(&configBypassWatchdogTimer, 0, sizeof(configBypassWatchdogTimer)); // Initialize NTAPI library if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_Init failed. Code 0x%x = %s\n", status, errBuf); return status; } // Open the config stream status = NT_ConfigOpen(&hConfig, "bypass_watchdog_example"); if (status != NT_SUCCESS) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_ConfigOpen failed. Code 0x%x = %s\n", status, errBuf); return status; } // Open the information stream if ((status = NT_InfoOpen(&hInfo, "bypass_watchdog_example")) != NT_SUCCESS) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_InfoOpen failed. Code 0x%x = %s\n", status, errBuf); return status; } // Read system information infoSystem.cmd = NT_INFO_CMD_READ_SYSTEM; if ((status = NT_InfoRead(hInfo, &infoSystem)) != NT_SUCCESS) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_InfoRead failed. Code 0x%x = %s\n", status, errBuf); return status; } printf("System: %d.%d.%d.%d\n\n", infoSystem.u.system.data.version.major, infoSystem.u.system.data.version.minor, infoSystem.u.system.data.version.patch, infoSystem.u.system.data.version.tag); printf("Adapters: %u\n", infoSystem.u.system.data.numAdapters); printf("Ports: %u\n", infoSystem.u.system.data.numPorts); printf("\n"); if ( adapterNo != -1 && portNo == -1) { printf("Adapter: %d\n", adapterNo); } else { printf("Port: %d\n", portNo); } printf("watchdogTimeoutMsec: %d\n", watchdogTimeoutMsec); printf("watchdogDelayMsec: %d\n", watchdogDelayMsec); printf("\n"); // // Check if adapter or port has bypass feature // // // Check for bypass adapter/port feature. // if ( adapterNo != -1 && portNo == -1) { infoAdapter.cmd = NT_INFO_CMD_READ_ADAPTER_V6; infoAdapter.u.adapter_v6.adapterNo = (uint8_t)adapterNo; if ((status = NT_InfoRead(hInfo, &infoAdapter)) != NT_SUCCESS) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_InfoRead failed. Code 0x%x = %s\n", status, errBuf); exit(EXIT_FAILURE); } portBegin = infoAdapter.u.adapter_v6.data.portOffset; portCount = infoAdapter.u.adapter_v6.data.numPorts; // Check if adapter itself is product type bypass. if (infoAdapter.u.adapter_v6.data.productType == NT_PRODUCT_TYPE_BYPASS) { printf("Adapter #%d has bypass feature\n", adapterNo); bypassFeatureFound++; } } else { portBegin = portNo; portCount = 1; } for (port = 0; port < portCount; port++) { infoPort.cmd = NT_INFO_CMD_READ_PORT_V9; infoPort.u.port_v9.portNo = (uint8_t)(portBegin + port); if ((status = NT_InfoRead(hInfo, &infoPort)) != 0) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_InfoRead failed. Code 0x%x = %s\n", status, errBuf); exit(EXIT_FAILURE); } if ( infoPort.u.port_v9.data.capabilities.featureMask & NT_PORT_FEATURE_BYPASS) { printf("Port #%d has bypass feature\n", portBegin + port); bypassFeatureFound++; } } printf("\n"); // Output result of search for bypass features if ( adapterNo != -1 && portNo == -1) { printf("Adapter #%d: ", adapterNo); } else { printf("Port #%d: ", portNo); } if ( bypassFeatureFound != 0) { printf("bypass feature found: OK\n\n"); } else { printf("ERROR: bypass feature NOT found\n\n"); exit(EXIT_FAILURE); } // // WDT setup // // Read bypass adapter/port state config if ( adapterNo != -1 && portNo == -1) { configBypassState.parm = NT_CONFIG_PARM_BYPASS_ADAPTER; configBypassState.u.bypassConfig.u.adapterNo = (uint8_t)adapterNo; } else { configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT; configBypassState.u.bypassConfig.u.portNo = (uint8_t)portNo; } if ((status = NT_ConfigRead(hConfig, &configBypassState)) != 0) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_ConfigRead failed. Code 0x%08X = %s\n", status, errBuf); return status; } // Save initial bypass state saveBypassState = configBypassState; // Check saved adapter port state - if NT_BYPASS_PORT_STATE_UNKNOWN then ports can be controlled individually if (saveBypassState.u.bypassConfig.data.currentBypassPortState == NT_BYPASS_PORT_STATE_UNKNOWN) { ep = malloc(sizeof(enum NtBypassPortState_e)*portCount+1); if (ep != NULL) { // Save individual port state for (port = 0; port < portCount; port++) { configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT; configBypassState.u.bypassConfig.u.portNo = (uint8_t)(portBegin + port); if ((status = NT_ConfigRead(hConfig, &configBypassState)) != 0) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_ConfigRead failed. Code 0x%08X = %s\n", status, errBuf); free(ep); return status; } ep[port] = configBypassState.u.bypassConfig.data.currentBypassPortState; } } else { exit(EXIT_FAILURE); } } // Prepare: setup bypass port states if ( adapterNo != -1 && portNo == -1) { configBypassState.parm = NT_CONFIG_PARM_BYPASS_ADAPTER; configBypassState.u.bypassConfig.u.adapterNo = (uint8_t)adapterNo; } else { configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT; configBypassState.u.bypassConfig.u.portNo = (uint8_t)portNo; } configBypassState.u.bypassConfig.data.currentBypassPortState = NT_BYPASS_PORT_STATE_NORMAL; configBypassState.u.bypassConfig.data.onWatchdogFailBypassPortState = NT_BYPASS_PORT_STATE_BYPASS; if ((status = NT_ConfigWrite(hConfig, &configBypassState)) != 0) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf); free(ep); return status; } // Setup bypass port wdt config settings if ( adapterNo != -1 && portNo == -1) { configBypassWatchdogTimeout.parm = NT_CONFIG_PARM_BYPASS_ADAPTER_WATCHDOG_TIMEOUT; configBypassWatchdogTimeout.u.bypassWatchdogTimeout.u.adapterNo = (uint8_t)adapterNo; } else { configBypassWatchdogTimeout.parm = NT_CONFIG_PARM_BYPASS_PORT_WATCHDOG_TIMEOUT; configBypassWatchdogTimeout.u.bypassWatchdogTimeout.u.portNo = (uint8_t)portNo; } configBypassWatchdogTimeout.u.bypassWatchdogTimeout.data.bypassWatchdogTimeout = watchdogTimeoutMsec; if ((status = NT_ConfigWrite(hConfig, &configBypassWatchdogTimeout)) != 0) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf); if (status == NT_ERROR_WATCHDOG_TIMEOUT_OUT_OF_RANGE) { // Restore bypass port states to previous state fprintf(stderr, "\nRestoring previous bypass state\n"); configBypassState = saveBypassState; // Check saved adapter port state - if NT_BYPASS_PORT_STATE_UNKNOWN then ports can be controlled individually if (saveBypassState.u.bypassConfig.data.currentBypassPortState != NT_BYPASS_PORT_STATE_UNKNOWN) { if ( adapterNo != -1 && portNo == -1) { configBypassState.parm = NT_CONFIG_PARM_BYPASS_ADAPTER; configBypassState.u.bypassConfig.u.adapterNo = (uint8_t)adapterNo; } else { configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT; configBypassState.u.bypassConfig.u.portNo = (uint8_t)portNo; } if ((status = NT_ConfigWrite(hConfig, &configBypassState)) != 0) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf); free(ep); return status; } } else { if (ep != NULL) { // Restore individual port state for (port = 0; port < portCount; port++) { configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT; configBypassState.u.bypassConfig.u.portNo = (uint8_t)(portBegin + port); configBypassState.u.bypassConfig.data.currentBypassPortState = ep[port]; if ((status = NT_ConfigWrite(hConfig, &configBypassState)) != 0) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_ConfigWrite failed. Code 0x%08X = %s\n", status, errBuf); free(ep); return status; } } } else { exit(EXIT_FAILURE); } } } free(ep); return status; } printf("INFO: bypass setup: watchdog timeout=%u msec\n", configBypassWatchdogTimeout.u.bypassWatchdogTimeout.data.bypassWatchdogTimeout); // // WDT heartbeat ping loop... // while(!stopApplication) { struct NtConfigBypassWatchdogTimerData_s* bypassWatchdogTimerData; if ( adapterNo != -1 && portNo == -1) { configBypassWatchdogTimer.parm = NT_CONFIG_PARM_BYPASS_ADAPTER_WATCHDOG_TIMER; configBypassWatchdogTimer.u.bypassWatchdogTimer.u.adapterNo = (uint8_t)adapterNo; } else { configBypassWatchdogTimer.parm = NT_CONFIG_PARM_BYPASS_PORT_WATCHDOG_TIMER; configBypassWatchdogTimer.u.bypassWatchdogTimer.u.portNo = (uint8_t)portNo; } configBypassWatchdogTimer.u.bypassWatchdogTimer.data.bypassWatchdogTimeout = 0; configBypassWatchdogTimer.u.bypassWatchdogTimer.data.bypassWatchdogTimeRemaining = 0; if ((status = NT_ConfigWrite(hConfig, &configBypassWatchdogTimer)) != 0) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_ConfigRead failed. Code 0x%08X = %s\n", status, errBuf); free(ep); return status; } // Process returned WDT timeouts. bypassWatchdogTimerData = &configBypassWatchdogTimer.u.bypassWatchdogTimer.data; 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); // 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. if (bypassWatchdogTimerData->bypassWatchdogTimeout == 0) { fprintf(stderr, "\n"); 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); fprintf(stderr, "\n"); break; } iterationCount++; // If remaining time is close to run out then skip wait delay. if (bypassWatchdogTimerData->bypassWatchdogTimeRemaining >= 25) { if (watchdogDelayMsec >= 1) { #if defined(__linux__) || defined(__FreeBSD__) usleep(watchdogDelayMsec*1000U); // sleep in microseconds #elif defined(WIN32) || defined (WIN64) Sleep(watchdogDelayMsec); // sleep in milliseconds #endif } } } free(ep); // Close down the NTAPI library NT_Done(); printf("Done.\n"); return 0; } // // EOF //