Description
INFO:
- This is an 4GA inline example, which depends on the 4GA inline NTPL features.
- The 3GA inline example can be found in examples/net/inline/.
This source file is an example of how to implement a simple vlan tagging, using the 4GA Napatech inline application capabilities. The example will add a vlan tag to every received packet before forwarding. The example demonstrates how to utilize following features:
RX:
- a) set descriptor type = Dyn3
- b) set descriptor length
TX:
- c) set descriptor type = Dyn
- d) set TxPorts = fixed or dynamic range
- e) discard RxCRC
- f) set TxPortPos for dynamic range (within same adapter)
The following NTAPI functions are used:
Prerequisites
Any 4GA Napatech accelerator with 4GA FPGA inline support which was introduced with the HB2 release, FPGA-images: 200-95xx-08-xx, supporting minimum the NT_FEATURE_LEVEL_N_ANL9 feature set.
Below is an example of an ini-file with the default setting for NT40E3_4_PTP (adapter 0). The default setting supports the 4GA TX inline feature.
Establish optical cable loop from port 0 to port 1.
Use the following NT tools and sequence to demo this vlan example:
- 1) start ntservice: /opt/napatech3/bin/ntstart.sh
- 2) start monitoring: /opt/napatech3/bin/monitoring
- 3) start pktgen: /opt/napatech3/bin/pktgen -p 1 -s 1024 -n 0
- 4) check on monitoring:
- 10G TX traffic on port 1
- 10G RX traffic on port 0
- 5) start vlandemo: /opt/napatech3/examples/net/vlandemo/vlandemo_example
- 6) check on monitoring:
- 10G TX traffic on port 1 and port 0 (inline)
- 10G RX traffic on port 0 and port 1 (inline)
[System]
HostBufferRefreshIntervalAll = default #
LinkPropagationPortPairs = # [portA, portB], ...
NumWorkerThreads = 3 # 1 .. 100
SDRAMFillLevelWarning = 0 # X1, X2, X3, X4
TimestampFormat = NATIVE_UNIX # NATIVE_UNIX* - PCAP - PCAP_NS
TimestampMethod = EOF # UNKNOWN - EOF*
TimeSyncOsTimeReference = None # None* - adapter-0 - adapter-1 - adapter-2 - adapter-3 - adapter-4 - adapter-5 - adapter-6 - adapter-7
[Logging]
LogBufferWrap = wrap # wrap* - nowrap
LogFileName = /tmp/Log3G_%s.log # String
LogMask = 7 # See ini-file help for information about possible values
LogToFile = false # true/false
LogToSystem = true # true/false
[Adapter0]
AdapterType = NT40E3_4_PTP # ...
BusId = 0000:08:00.0 # NNNN:NN:NN.N
DiscardSize = 16 # 16 .. 63
HighFrequencySampling = DISABLE # DISABLE* - ENABLE
HostBufferHandlerAffinity = -2 # -2 .. 39
HostBufferPollInterval = default # default* - 100 - 250 - 500 - 1000 - 10000 - 25000 - 50000 - 100000
HostBufferRefreshIntervalRx = default # default* - 1 - 5 - 10 - 50 - 100 - 250 - 500
HostBufferRefreshIntervalTx = default # default* - 1 - 5 - 10 - 50 - 100 - 250 - 500
HostBufferSegmentAlignmentRx = default # default* - none - 0 - 512 - 1024 - 2048 - 4096
HostBufferSegmentSizeRx = default # default* - dynamic - 0 - 1 - 2 - 4
HostBufferSegmentTimeOut = default # default* - 100 - 250 - 500 - 1000 - 10000 - 25000 - 50000 - 100000
HostBuffersRx = [4,16,-1] # [x1, x2, x3], ...
HostBuffersTx = [4,16,-1] # [x1, x2, x3], ...
IfgMode = NS # NS* - BYTE
KmTcamConfig = [2,4,0],[4,1,0] # [cnt, len, dualLookup], ...
MaxFrameSize = 9018 # 1518 .. 10000
NumaNode = -1 # -1 .. 16
OnBoardMemorySplit = Even # Dynamic - Even* - Proportional
PacketDescriptor = NT # PCAP - NT* - Ext9
PortDisableMask = 0 # See ini-file help for information about possible values
PortSpeedMultiRate = 10G, 10G, 10G, 10G # 1G - 10G*
Profile = None # None* - Capture
PtpDhcp = ENABLE # DISABLE - ENABLE*
PtpMasterModeAllowed = DISABLE # DISABLE* - ENABLE
PtpProfile = Default # Default* - Telecom - Power
PtpUserDescription = Napatech adapter # String
SofLinkSpeed = 10G # 100M - 1G - 10G
TimeSyncConnectorExt1 = PpsIn # None - NttsIn* - PpsIn - NttsOut - PpsOut - RepeatInt1 - RepeatInt2
TimeSyncConnectorInt1 = None # None* - NttsIn - PpsIn - NttsOut - PpsOut - RepeatExt1 - RepeatInt2
TimeSyncConnectorInt2 = None # None* - NttsIn - PpsIn - NttsOut - PpsOut - RepeatExt1 - RepeatInt1
TimeSyncHardReset = ENABLE # DISABLE - ENABLE*
TimeSyncNTTSInSyncLimit = 5000 # 1 .. 4294967295
TimeSyncOSInSyncLimit = 50000 # 1 .. 4294967295
TimeSyncPPSInSyncLimit = 5000 # 1 .. 4294967295
TimeSyncPTPInSyncLimit = 5000 # 1 .. 4294967295
TimeSyncReferencePriority = Ext1, FreeRun # FreeRun* - PTP - Int1 - Int2 - Ext1 - OSTime
TimeSyncTimeOffset = 0 # 0 .. 1000000
TxTiming = RELATIVE # ABSOLUTE - RELATIVE*
VXLANAltDestinationPorts = 4789,4789 # X1, X2
Program flow
The following is required to run in an inline scenario:
- #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.
- To verify that the 4GA inline feature is supported, the Is4GATxSupported() local function open a info stream with NT_InfoOpen() - to inquire the actual feature level with NT_InfoRead() and check if we have minimum the ANL9. Next,
- NT_ConfigOpen() - Open a config stream in order to setup filter using the NT_NTPL() command. Some conditional compile flags control various options:
- ENABLE_DYNAMIC_TX_PORT - setup NTPL "TxPortPos=112" Dyn-desc
- ENABLE_VLAN_TAGGING - enable VLAN tagging or packet forward
- DISCARD_EVERY_SECOND_PACKET - discard every second packet
- DISCARD_BY_WIRELEN - discard setting wirelen=0 or TXIGNORE=1
- ENABLE_DYN_USER_DATA - extend Dyn3 descriptor for user data
- NT_NetRxOpen() - Open a stream. The stream ID(=1) must match the one used when creating the filter using the NT_NTPL() command.
- Having setup the TX inline NTPL configuration for stream ID(=1) and opened the RX stream ID(=1), the packet processing and forwarding loop is entered. Wait until we receive packets with NT_NetRxGet(), which is called with a timeout of 1000ms and will return NT_STATUS_TIMEOUT in case nothing is received within 1000ms and will return NT_SUCCESS if something is returned. Return values different from that is an indication of an error. Packets are received with the Dyn3-descriptor as configured with NTPL. If ENABLE_VLAN_TAGGING is true, the required VLAN-tag space(=4 bytes) is allocated from the Dyn3-descriptor by subtracting 4 bytes from from the descriptor-length and adding 4-bytes to the wire-length along with the MAC-header move and VLAN-tag payload prepending. If DISCARD_EVERY_SECOND_PACKET is enabled, every second packet is discarded either by setting wirelen = 0 if DISCARD_BY_WIRELEN is enabled or by setting the TX IGNORE-bit to 1 with TxIgnorePos=42 . Next, the actual packet is forwarded with the NT_NetRxRelease().
- At program termination, the config stream is opened to clear the NTPL filter serup witth the "Delete=All" before the RX stream(=1) is closed the NT_NetRxClose().
Code
#if defined(__linux__)
#include <signal.h>
#endif
#ifdef _WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
#if defined(WIN32) || defined (WIN64)
#define snprintf(a, b, c, d) _snprintf_s((a), _countof(a), (b), (c), (d))
#endif
#define ENABLE_VLAN_TAGGING 1 // enable VLAN tagging of packets
#define DISCARD_BY_WIRELEN 1 // enable this to use wirelen=0 discard option (recommended)
#if defined(__linux__)
static void catch_signal(int sig)
{
(void)sig;
}
#endif
{
if ((status =
NT_InfoOpen(&hInfo,
"Info")) != NT_SUCCESS) {
fprintf(stderr, "NT_InfoOpen failed: %s", errorBuffer);
return 0;
}
(void)memset(&infoRead, 0,
sizeof(
NtInfo_t));
if ((status =
NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) {
fprintf(stderr, "NT_InfoRead failed: %s", errorBuffer);
return 0;
}
(void)memset(&infoRead, 0,
sizeof(
NtInfo_t));
if ((status =
NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) {
fprintf(stderr, "NT_InfoRead failed: %s", errorBuffer);
return 0;
}
return 1;
}
return 0;
}
{
#if ENABLE_VLAN_TAGGING
uint8_t* pb;
struct __vlan_tag {
uint16_t tpid;
uint16_t tci;
} vlan_tag = {htons(0x8100),htons(0x0001)};
#endif
#if DISCARD_EVERY_SECOND_PACKET
int discard = 0;
#endif
#if ENABLE_DYNAMIC_TX_PORT
int dynamicTxPort = 0;
#endif
#if defined(__linux__)
signal(SIGINT, catch_signal);
#endif
fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
return -1;
}
printf("ERROR: 4GA TX inline is NOT supported !\n");
return -1;
}
if ((status =
NT_ConfigOpen(&hCfgStream,
"TestStream")) != NT_SUCCESS) {
fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
return -1;
}
#if DISCARD_EVERY_SECOND_PACKET
#if DISCARD_BY_WIRELEN
#else
#endif
#else
#if ENABLE_DYNAMIC_TX_PORT
if ((status =
NT_NTPL(hCfgStream,
"Setup[TxDescriptor=Dyn;TxPorts=(0..1);RxCRC=False;TxPortPos=112;UseWL=True] = StreamId == 1", &ntplInfo,
NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
#else
#endif
#endif
fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
return -1;
}
#if ENABLE_DYN_USER_DATA
#else
#endif
fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
return -1;
}
fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
return -1;
}
fprintf(stderr, "Failed to create statistics stream: 0x%08X\n", status);
return -1;
}
fprintf(stderr, "Failed resetting statistics: 0x%08X\n", status);
return -1;
}
fprintf(stderr, "NT_NetRxOpen() failed: %s\n", errorBuffer);
return -1;
}
if ((status =
NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
continue;
}
fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
return -1;
}
break;
}
fprintf(stderr, "NT_NetRxRelease() failed: %s\n", errorBuffer);
return -1;
}
}
uint64_t totPkts = 0;
uint64_t totBytes = 0;
#if ENABLE_VLAN_TAGGING
pb = (uint8_t*)pDyn3;
#endif
#if ENABLE_DYNAMIC_TX_PORT
NT_NET_SET_PKT_TXPORT(hNetBuf, dynamicTxPort);
if (dynamicTxPort == 0) {
dynamicTxPort = 1;
}
else {
dynamicTxPort = 0;
}
#endif
#if DISCARD_EVERY_SECOND_PACKET
if (discard) {
#if DISCARD_BY_WIRELEN
#else
#endif
discard = 0;
}
else {
#if DISCARD_BY_WIRELEN
#else
#endif
discard = 1;
}
#endif
fprintf(stderr, "NT_NetRxRelease() failed: %s\n", errorBuffer);
return -1;
}
if ((status =
NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
continue;
}
fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
return -1;
}
totPkts++;
totBytes += NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf);
break;
}
}
if ((status =
NT_StatRead(hStat, &statSet)) != NT_SUCCESS) {
fprintf(stderr, "Failed reading statistics: 0x%08X\n", status);
return -1;
}
if ((status =
NT_ConfigOpen(&hCfgStream,
"TestStream")) != NT_SUCCESS) {
fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
return -1;
}
snprintf(tmpBuffer,
sizeof(tmpBuffer),
"Delete=All");
fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
return -1;
}
fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
return -1;
}
printf("Drop: %lu packets, %lu bytes\n", totDropsPkts, totDropsBytes);
printf("Done: %lu packets, %lu bytes\n", totPkts, totBytes);
return 0;
}