net/vlandemo/vlandemo_example.c

Reference Documentation

Platform
Intel® PAC
Napatech SmartNIC
Content Type
Reference Information
Capture Software Version
Link™ Capture Software 12.10
Napatech Software Suite: net/vlandemo/vlandemo_example.c
net/vlandemo/vlandemo_example.c

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

/*
*
* Copyright 2023 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 net/vlandemo/vlandemo_example.c
* @section vlandemo_example_description 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:
* - @ref NT_Init()
* - @ref NT_ConfigOpen()
* - @ref NT_InfoOpen()
* - @ref NT_NetRxOpen()
* - @ref NT_InfoRead()
* - @ref NT_NTPL()
* - @ref NT_NetRxGet()
* - @ref NT_NET_GET_PKT_CAP_LENGTH()
* - @ref NT_NET_GET_PKT_DESCR_LENGTH()
* - @ref NT_NET_GET_PKT_WIRE_LENGTH()
* - @ref NT_NET_GET_PKT_TIMESTAMP()
* - @ref NT_NET_GET_PKT_DESCR_PTR()
* - @ref NT_NET_SET_PKT_TXPORT()
* - @ref NT_NetRxRelease()
* - @ref NT_NetRxClose()
* - @ref NT_ConfigClose()
* - @ref NT_InfoClose()
* - @ref NT_ExplainError()
*
* @section vlandemo_example_prerequisites 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)
*
* @code
* [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
*
* @endcode
*
* @section vlandemo_example_flow Program flow
* @{
* The following is required to run in an inline scenario:
* - \#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. 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.
* - To verify that the 4GA inline feature is supported, the
* Is4GATxSupported() local function open a info stream with
* @ref NT_InfoOpen() - to inquire the actual feature level with
* @ref NT_InfoRead() and check if we have minimum the ANL9. Next,
* - @ref NT_ConfigOpen() - Open a config stream in order to setup
* filter using the @ref 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
* - @ref NT_NetRxOpen() - Open a stream. The stream ID(=1) must match
* the one used when creating the filter using the @ref 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 @ref 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 @ref 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 @ref NT_NetRxClose().
*
*<hr>
* @section vlandemo_example_code Code
* @}
*
*/
// Include this in order to access the Napatech API
#include <nt.h>
#if defined(__linux__)
#include <signal.h>
#endif
#ifdef _WIN32
#include <winsock2.h> /* htonl, htons */
#else
#include <arpa/inet.h> /* htonl, htons */
#endif
#if defined(WIN32) || defined(WIN64)
#define snprintf(dst, ...) _snprintf_s((dst), _countof(dst), __VA_ARGS__)
#endif
//#define ENABLE_DYNAMIC_TX_PORT 1 // enable dynamic TX port
#define ENABLE_VLAN_TAGGING 1 // enable VLAN tagging of packets
//#define DISCARD_EVERY_SECOND_PACKET 1 // enable this to discard every second packet
#define DISCARD_BY_WIRELEN 1 // enable this to use wirelen=0 discard option (recommended)
//#define ENABLE_DYN_USER_DATA 1 // enable user data field along with Dyn3
static int running = 1;
#if defined(__linux__)
static void catch_signal(int sig)
{
(void)sig;
running = 0;
}
#endif
static int Is4GATxSupported(uint8_t portNo)
{
int status; // Status variable
uint8_t adapterNo;
NtInfoStream_t hInfo; // Handle to a info stream
NtInfo_t infoRead;
char errorBuffer[NT_ERRBUF_SIZE]; // Error buffer
if ((status = NT_InfoOpen(&hInfo, "Info")) != NT_SUCCESS) {
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_InfoOpen failed: %s", errorBuffer);
return 0;
}
// Get adapterNo of this TX port
(void)memset(&infoRead, 0, sizeof(NtInfo_t));
infoRead.u.port_v9.portNo=portNo;
if ((status = NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) {
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_InfoRead failed: %s", errorBuffer);
return 0;
}
// Save adapter number of the TX port
adapterNo = infoRead.u.port_v9.data.adapterNo;
// Get feature level of this adapter
(void)memset(&infoRead, 0, sizeof(NtInfo_t));
if ((status = NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) {
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_InfoRead failed: %s", errorBuffer);
return 0;
}
NT_InfoClose(hInfo);
// 4GA adapters with ANL9 feature level support native TX with inline capabilities
// NOTE: 4GA adapters with ANL9 feature level doesn't support
// NT_NET_SET_PKT_DESCR_TYPE_EXT7 descriptor type
return 1;
}
printf("Adapter=%d, Port=%d, FeatureLevel=0x%x\n", adapterNo, portNo, infoRead.u.adapter_v6.data.featureLevel );
return 0;
}
int main(void)
{
int status; // Status variable
char tmpBuffer[20]; // Buffer to build filter string
char errorBuffer[NT_ERRBUF_SIZE]; // Error buffer
NtNetStreamRx_t hNetRx; // Handle to the RX stream
NtConfigStream_t hCfgStream; // Handle to a config stream
NtNtplInfo_t ntplInfo; // Return data structure from the NT_NTPL() call.
NtNetBuf_t hNetBuf; // Net buffer container. Packet data is returned in this when calling NT_NetRxGet().
#if ENABLE_VLAN_TAGGING
NtDyn3Descr_t *pDyn3; // dyn3 descriptor ref
uint8_t* pb;
struct {
uint16_t tpid;
uint16_t tci;
} vlan_tag = {htons(0x8100),htons(0x0001)}; // VLAN tag to prepend
#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); //<-- Catch keyboard QUIT (CTRL-\)
#endif
// Initialize the NTAPI library and thereby check if NTAPI_VERSION can be used together with this library
if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
return -1;
}
// Check if 4GA TX including inline capability is supported
if (!Is4GATxSupported(0)) {
printf("ERROR: 4GA TX inline is NOT supported !\n");
return -1;
}
// Open a config stream to assign a filter to a stream ID.
if ((status = NT_ConfigOpen(&hCfgStream, "TestStream")) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
return -1;
}
#if DISCARD_EVERY_SECOND_PACKET
#if DISCARD_BY_WIRELEN
// Setup traffic to stream ID(=1) and Tx port = 0
if ((status = NT_NTPL(hCfgStream, "Setup[TxDescriptor=Dyn;TxPorts=0;UseWL=True] = StreamId == 1", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
#else
// Setup traffic to stream ID(=1) and Tx port = 0, TX Ignore bit position = 42 (located in the rxPort field, which is not used by TX)
if ((status = NT_NTPL(hCfgStream, "Setup[TxDescriptor=Dyn;TxPorts=0;TxIgnorePos=42;UseWL=True] = StreamId == 1", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
#endif
#else
#if ENABLE_DYNAMIC_TX_PORT
// Setup traffic to stream ID(=1), Tx port = 0..1 (within same adapter), RxCRC = false, TxPortPos=112 (to utilize macro)
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
// Setup traffic to stream ID(=1) and Tx port = 0
if ((status = NT_NTPL(hCfgStream, "Setup[TxDescriptor=Dyn;TxPorts=0;UseWL=True] = StreamId == 1", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
#endif
#endif
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
return -1;
}
// Assign all traffic from port 0 to stream ID(=1)
#if ENABLE_DYN_USER_DATA
// Set descriptor length = 62 bytes to add user data field of 40 bytes
if ((status = NT_NTPL(hCfgStream, "Assign[StreamId=1;Descriptor=Dyn3,length=62] = Port == 0", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
#else
// Keep default Dyn3 descriptor length = 22 bytes
if ((status = NT_NTPL(hCfgStream, "Assign[StreamId=1;Descriptor=Dyn3] = Port == 0", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
#endif
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
return -1;
}
// Close the config stream
if ((status = NT_ConfigClose(hCfgStream)) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
return -1;
}
// Open stat stream
NtStatStream_t hStat = NULL;
if ((status = NT_StatOpen(&hStat, "hStat")) != 0) {
fprintf(stderr, "Failed to create statistics stream: 0x%08X\n", status);
return -1;
}
// Reset stats
static NtStatistics_t statSet;
statSet.u.query_v3.poll = 1;
statSet.u.query_v3.clear = 1;
if ((status = NT_StatRead(hStat, &statSet))) {
fprintf(stderr, "Failed resetting statistics: 0x%08X\n", status);
return -1;
}
// Get a stream handle with the stream ID(=1). NT_NET_INTERFACE_PACKET specify that we will receive data in a packet based matter.
if ((status = NT_NetRxOpen(&hNetRx, "TestStream", NT_NET_INTERFACE_PACKET, 1, -1)) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_NetRxOpen() failed: %s\n", errorBuffer);
return -1;
}
// Optional step. Wait for the first packet that hit the NTPL assign command
while (running) {
if ((status = NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
// Timeouts are ok, we just need to wait a little longer for a packet
continue;
}
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
return -1;
}
// We got a packet. Check if the timestamp is newer than when the NTPL assign command was applied
if (NT_NET_GET_PKT_TIMESTAMP(hNetBuf) > ntplInfo.ts) {
printf("First packet received: Capture length=%d, Descriptor length=%d, Wire length=%d\n", NT_NET_GET_PKT_CAP_LENGTH(hNetBuf), NT_NET_GET_PKT_DESCR_LENGTH(hNetBuf), NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf) );
break; // Break out, we have received a packet that is received after the NTPL assign command was applied
}
// Release the packet, it is too "old".
if ((status = NT_NetRxRelease(hNetRx, hNetBuf)) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_NetRxRelease() failed: %s\n", errorBuffer);
return -1;
}
}
// Add VLAN tag and forward packet
uint64_t totPkts = 0;
uint64_t totBytes = 0;
while (running) { // start of packet processing loop
#if ENABLE_VLAN_TAGGING
// 1: Add VLAN tag
pDyn3 = (NtDyn3Descr_t*)NT_NET_GET_PKT_DESCR_PTR(hNetBuf);
pb = (uint8_t*)pDyn3;
const size_t descrLen = pDyn3->descrLength - 4U;
pDyn3->descrLength = descrLen & 0x3fU; // create space in actual packet to prepend 4-byte VLAN-tag,
memmove(pb + descrLen, pb + descrLen + 4U, 12U); // move actual MAC-header to new start of packet payload
memcpy(pb + descrLen + 12U, &vlan_tag, 4U); // insert VLAN tag after MAC-header
pDyn3->wireLength = (pDyn3->wireLength + 4U) & 0x3fffU; // set new wire length to inlude the 4-byte VLAN-tag
#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) {
// discard packet
#if DISCARD_BY_WIRELEN
// force wirelength = 0
pDyn3->wireLength = 0;
#else
pDyn3->rxPort = 1; // INFO: Ensure ignore-bit is TRUE. Requires NTPL-Setup: TxIgnorePos=42
#endif
discard = 0;
}
else {
// don't discard
#if DISCARD_BY_WIRELEN
// keep wirelength untouched
#else
pDyn3->rxPort = 0; // INFO: Ensure ignore-bit is FALSE. Requires NTPL-Setup: TxIgnorePos=42
#endif
discard = 1;
}
#endif
// 2: Forward the VLAN-tagged packet
if ((status = NT_NetRxRelease(hNetRx, hNetBuf)) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_NetRxRelease() failed: %s\n", errorBuffer);
return -1;
}
// 3: Get the next packet
while (running) {
if ((status = NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
// Timeouts are ok, we just need to wait a little longer for a packet
continue;
}
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
return -1;
}
totPkts++;
totBytes += NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf);
break; // We got a packet
}
} // end of packet processing loop
// Close the stream and release the hostbuffer
NT_NetRxClose(hNetRx);
// Request stats
statSet.u.query_v3.poll = 1;
statSet.u.query_v3.clear = 0;
if ((status = NT_StatRead(hStat, &statSet)) != NT_SUCCESS) {
fprintf(stderr, "Failed reading statistics: 0x%08X\n", status);
return -1;
}
// Read drop counters for streamid 1
uint64_t totDropsPkts = statSet.u.query_v3.data.stream.streamid[1].drop.pkts;
uint64_t totDropsBytes = statSet.u.query_v3.data.stream.streamid[1].drop.octets;
// Close stat stream
NT_StatClose(hStat);
// Open a config stream to delete a filter.
if ((status = NT_ConfigOpen(&hCfgStream, "TestStream")) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
return -1;
}
// Clear filter setup
snprintf(tmpBuffer, sizeof(tmpBuffer), "Delete=All");
if ((status = NT_NTPL(hCfgStream, tmpBuffer, &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
return -1;
}
// Close the config stream
if ((status = NT_ConfigClose(hCfgStream)) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
return -1;
}
// Output totals
printf("Drop: %lu packets, %lu bytes\n", totDropsPkts, totDropsBytes);
printf("Done: %lu packets, %lu bytes\n", totPkts, totBytes);
// Close down the NTAPI library
return 0;
}
//
// EOF
//