bypass/watchdog/bypass_watchdog_example.c
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)
The following NTAPI functions are used:
- NT_Init()
- NT_InfoOpen()
- NT_InfoRead()
- NT_InfoClose()
- NT_ConfigOpen()
- NT_ConfigWrite()
- NT_ConfigRead()
- NT_ConfigClose()
- NT_Done()
- NT_ExplainError()
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:
- #include/nt.h - Applications/Tools only need to include nt.h to obtain prototypes, macros etc. from NTAPI.
- NT_Init(NTAPI_VERSION) - Initialize the NTAPI library. NTAPI_VERSION is a define that describes the version of the API described in the header files included by nt.h. NT_Init() will ask the NTAPI library to convert return data to the NTAPI_VERSION if possible. This will ensure that applications can run on NTAPI libraries of newer versions.
- NT_InfoOpen() - Open an info stream.
- NT_InfoRead() - Read info stream.
- NT_InfoClose() - Close the stream when terminating.
- NT_ConfigOpen() - Open a configuration stream.
- NT_ConfigRead() - Read configuration.
- NT_ConfigWrite() - Write configuration.
- NT_ConfigClose() - Close the stream when terminating.
- NT_Done() - Close down the NTAPI library.
- NT_ExplainError() - Explain an error code returned by NTAPI functions.
/*
*
* Copyright 2021 Napatech A/S. All Rights Reserved.
*
* 1. Copying, modification, and distribution of this file, or executable
* versions of this file, is governed by the terms of the Napatech Software
* license agreement under which this file was made available. If you do not
* agree to the terms of the license do not install, copy, access or
* otherwise use this file.
*
* 2. Under the Napatech Software license agreement you are granted a
* limited, non-exclusive, non-assignable, copyright license to copy, modify
* and distribute this file in conjunction with Napatech SmartNIC's and
* similar hardware manufactured or supplied by Napatech A/S.
*
* 3. The full Napatech Software license agreement is included in this
* distribution, please see "NP-0405 Napatech Software license
* agreement.pdf"
*
* 4. Redistributions of source code must retain this copyright notice,
* list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, EXPRESS OR
* IMPLIED, AND NAPATECH DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING ANY
* IMPLIED WARRANTY OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, OR OF
* FITNESS FOR A PARTICULAR PURPOSE. TO THE EXTENT NOT PROHIBITED BY
* APPLICABLE LAW, IN NO EVENT SHALL NAPATECH BE LIABLE FOR PERSONAL INJURY,
* OR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER,
* INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, CORRUPTION OR
* LOSS OF DATA, FAILURE TO TRANSMIT OR RECEIVE ANY DATA OR INFORMATION,
* BUSINESS INTERRUPTION OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING
* OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE NAPATECH SOFTWARE OR
* SERVICES OR ANY THIRD PARTY SOFTWARE OR APPLICATIONS IN CONJUNCTION WITH
* THE NAPATECH SOFTWARE OR SERVICES, HOWEVER CAUSED, REGARDLESS OF THE THEORY
* OF LIABILITY (CONTRACT, TORT OR OTHERWISE) AND EVEN IF NAPATECH HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW
* THE EXCLUSION OR LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF
* INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU.
*
*
*/
/**
* @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()
//
{
"USAGE: bypass_watchdog_example [-a <adapter> | -p <port>] -t <watchdogTimeoutMsec> -s <watchdogDelayMsec>\n",
};
//
// Flag to signal that application should stop.
//
//
// The function called when the user presses CTRL-C
//
#if defined(WIN32) || defined (WIN64)
#else
#endif
{
#ifdef WIN32
stopApplication = true;
return TRUE;
#else
if (sig == SIGINT)
stopApplication = true;
#endif
}
/**
* Table of valid options.
*/
OPT_HELP(),
OPT_END(),
};
//
// main()
//
{
uint32_t status = 0;
//
NtInfoStream_t hInfo;
NtConfigStream_t hConfig;
//
NtInfo_t infoSystem;
NtInfo_t infoAdapter;
NtInfo_t infoPort;
//
NtConfig_t configBypassState;
NtConfig_t saveBypassState;
//
NtConfig_t configBypassWatchdogTimeout;
NtConfig_t configBypassWatchdogTimer;
//
//
int port;
int portBegin = 0;
int portCount = 0;
int iterationCount = 0;
int bypassFeatureFound = 0;
//
//
// Read command line arguments
//
// 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
fprintf(stderr, ">>> Error: NT_Init failed. Code 0x%x = %s\n", status, errBuf);
return status;
}
// Open the config stream
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
NT_ExplainError(status, errBuf, sizeof(errBuf));
fprintf(stderr, ">>> Error: NT_InfoOpen failed. Code 0x%x = %s\n", status, errBuf);
return status;
}
// Read system information
NT_ExplainError(status, errBuf, sizeof(errBuf));
fprintf(stderr, ">>> Error: NT_InfoRead failed. Code 0x%x = %s\n", status, errBuf);
return status;
}
printf("\n");
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 ((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);
}
// Check if adapter itself is product type bypass.
printf("Adapter #%d has bypass feature\n", adapterNo);
bypassFeatureFound++;
}
} else {
portBegin = portNo;
portCount = 1;
}
for (port = 0; port < portCount; 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);
}
printf("Port #%d has bypass feature\n", portBegin + port);
bypassFeatureFound++;
}
}
printf("\n");
// Output result of search for bypass features
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
} else {
}
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 (ep != NULL) {
// Save individual port state
for (port = 0; port < portCount; port++) {
configBypassState.parm = NT_CONFIG_PARM_BYPASS_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;
}
}
} else {
exit(EXIT_FAILURE);
}
}
// Prepare: setup bypass port states
configBypassState.parm = NT_CONFIG_PARM_BYPASS_ADAPTER;
} else {
configBypassState.parm = NT_CONFIG_PARM_BYPASS_PORT;
}
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
} else {
}
configBypassWatchdogTimeout.u.bypassWatchdogTimeout.data.bypassWatchdogTimeout = (uint32_t)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
configBypassState.parm = NT_CONFIG_PARM_BYPASS_ADAPTER;
} else {
configBypassState.parm = NT_CONFIG_PARM_BYPASS_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 {
if (ep != NULL) {
// Restore individual port state
for (port = 0; port < portCount; port++) {
configBypassState.parm = NT_CONFIG_PARM_BYPASS_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) {
} else {
}
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.
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
//