bypass/watchdog/bypass_watchdog_example.c

Reference Documentation

product_line_custom
IntelĀ® PAC
Napatech SmartNIC
category
Reference Information
Napatech Software Suite: bypass/watchdog/bypass_watchdog_example.c
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:


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:


/*
*
* Copyright 2020 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()
//
static const char *usageText[] =
{
"USAGE: bypass_watchdog_example [-a <adapter> | -p <port>] -t <watchdogTimeoutMsec> -s <watchdogDelayMsec>\n",
};
//
// 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
return TRUE;
#else
if (sig == SIGINT)
#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_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"),
};
//
// main()
//
int main(int argc, const char *argv[])
{
uint32_t status = 0;
char errBuf[NT_ERRBUF_SIZE];
//
//
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;
//
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
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.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.
printf("Adapter #%d has bypass feature\n", adapterNo);
bypassFeatureFound++;
}
} else {
portBegin = portNo;
portCount = 1;
}
for (port = 0; port < portCount; port++) {
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);
}
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
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;
}
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.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;
}
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 ( 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.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
printf("Done.\n");
return 0;
}
//
// EOF
//