net/transmit_on_timestamp_setclock/transmit_on_timestamp_setclock_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/transmit_on_timestamp_setclock/transmit_on_timestamp_setclock_example.c
net/transmit_on_timestamp_setclock/transmit_on_timestamp_setclock_example.c

Description

This source file is an example of how to transmit a sequence of packets on timestamp multiple times, but instead of manually reconfiguring the delta for each iteration, TXSETCLOCK is used to advance the delta with the duration of a single replay iteration. An example application of this functionality would be where one wishes to replay a single capture file multiple times.

This example will transmit 100000 packets of 296 bytes from port 0 at a rate of approximately 5 Mb/s. The packet contains an incrementing 32bit pattern.

The transmit on timestamp functionality is also available in segment mode. See the net/transmit_segment/transmit_segment_example.c example code to see how to use the segment interface.

The following NTAPI functions are used:

Prerequisites

  • This example is only compatible with adapters supporting 4GA transmit on timestamp.
  • The ntservice.ini must have at least one HostBuffersTx defined. Below is an example of a minimum ini-file. It will create a 4MB TX hostbuffer from NUMA node 0.
[Adapter0]
AdapterType = NT20E2
BusId = 00:0a:00.00
HostBuffersTx = [1,4,0]

Program flow

The following is required to transmit packages:

  • #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_ConfigOpen() - Open the config stream.
  • NT_ConfigRead() - Use the config stream to read the current adapter time.
  • NT_ConfigWrite() - Use the config stream to configure transmit on timestamp, using the retrieved adapter time.
  • NT_NetTxOpen() - Open a hostbuffer than can transmit packets to port 0.
  • NT_NetTxOpen_v2() - Open a hostbuffer than can transmit packets to port 0.
  • NT_NetTxGet() - Get an empty tx buffer. This will get a 296 byte wire length packet buffer that will be sent onto port 0 when the packet buffer is released, and the timestamp has been reached on the adapter.
    • NT_NET_GET_PKT_L2_PTR() is used to get the L2 pointer to the tx buffer, this is where the payload is placed.
    • NT_NET_SET_PKT_TXSETCLOCK() is used to enable txsetclock on the first packet in the replay sequence.
    • NT_NET_SET_PKT_TIMESTAMP() is used to set the timestamp of the packet
  • NT_NetTxRelease() - Release the tx packet buffer. Once a tx buffer is released it will be transmitted
  • NT_ConfigRead() - Read the adapter timestamp to check if the last packet should have been transmitted. We need to do this in order to avoid disabling transmit on timestamp too early.
  • NT_ConfigWrite() - Disable transmit on timestamp.
  • NT_ConfigClose() - Close the configuration stream.
  • NT_NetTxClose() - Close the TX stream.
  • NT_Done() - Close down the NTAPI library.

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/transmit_on_timestamp_setclock/transmit_on_timestamp_setclock_example.c
* @section transmit_on_timestamp_setclock_example_description Description
*
* This source file is an example of how to transmit a sequence of packets
* on timestamp multiple times, but instead of manually reconfiguring the
* delta for each iteration, TXSETCLOCK is used to advance the delta with
* the duration of a single replay iteration. An example application of this
* functionality would be where one wishes to replay a single capture file
* multiple times.
*
* This example will transmit 100000 packets of 296 bytes from port 0 at a rate
* of approximately 5 Mb/s. The packet contains an incrementing 32bit pattern.
*
* The transmit on timestamp functionality is also available in segment mode.
* See the @ref net/transmit_segment/transmit_segment_example.c example code
* to see how to use the segment interface.
*
* The following NTAPI functions are used:
* - @ref NT_Init()
* - @ref NT_ConfigOpen()
* - @ref NT_ConfigRead()
* - @ref NT_ConfigWrite()
* - @ref NT_ConfigClose()
* - @ref NT_NetTxOpen_v2()
* - @ref NT_NetTxGet()
* - @ref NT_NET_SET_PKT_TIMESTAMP()
* - @ref NT_NET_SET_PKT_TXSETCLOCK()
* - @ref NT_NET_GET_PKT_L2_PTR()
* - @ref NT_NetTxRelease()
* - @ref NT_NetTxClose()
* - @ref NT_Done()
* - @ref NT_ExplainError()
*
* @section transmit_on_timestamp_setclock_example_prerequisites Prerequisites
* - This example is only compatible with adapters supporting 4GA transmit on
* timestamp.
* - The ntservice.ini must have at least one HostBuffersTx defined. Below is
* an example of a minimum ini-file. It will create a 4MB TX hostbuffer from
* NUMA node 0.
*
* @code
* [Adapter0]
* AdapterType = NT20E2
* BusId = 00:0a:00.00
* HostBuffersTx = [1,4,0]
* @endcode
*
* @section transmit_on_timestamp_setclock_example_flow Program flow
* @{
* The following is required to transmit packages:
* - \#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.
* - @ref NT_ConfigOpen() - Open the config stream.
* - @ref NT_ConfigRead() - Use the config stream to read the current adapter
* time.
* - @ref NT_ConfigWrite() - Use the config stream to configure transmit on
* timestamp, using the retrieved adapter time.
* - @ref NT_NetTxOpen() - Open a hostbuffer than can transmit packets to port 0.
* - @ref NT_NetTxOpen_v2() - Open a hostbuffer than can transmit packets to port 0.
* - @ref NT_NetTxGet() - Get an empty tx buffer. This will get a 296 byte
* wire length packet buffer that will be sent onto port 0 when the packet
* buffer is released, and the timestamp has been reached on the adapter.
* - @ref NT_NET_GET_PKT_L2_PTR() is used to get the L2 pointer to the tx
* buffer, this is where the payload is placed.
* - @ref NT_NET_SET_PKT_TXSETCLOCK() is used to enable txsetclock on the
* first packet in the replay sequence.
* - @ref NT_NET_SET_PKT_TIMESTAMP() is used to set the timestamp of the
* packet
* - @ref NT_NetTxRelease() - Release the tx packet buffer. Once a tx
* buffer is released it will be transmitted
* - @ref NT_ConfigRead() - Read the adapter timestamp to check if the last
* packet should have been transmitted. We need to do this in order to avoid
* disabling transmit on timestamp too early.
* - @ref NT_ConfigWrite() - Disable transmit on timestamp.
* - @ref NT_ConfigClose() - Close the configuration stream.
* - @ref NT_NetTxClose() - Close the TX stream.
* - @ref NT_Done() - Close down the NTAPI library.
*
*<hr>
* @section transmit_on_timestamp_setclock_example_code Code
* @}
*/
// Include this in order to access the Napatech API
#include <nt.h>
#if defined(__linux__) || defined(__FreeBSD__) || (__MINGW32__)
#include <unistd.h> // sleep()
#endif
#if defined(_MSC_VER)
#include <timesupport.h>
#endif
#include <assert.h>
#define PACKETS 100L // How many packets to send
#define PACKET_SIZE 296L // Packet size to transmit (incl crc.)
#define PACKET_GAP 500000L // Distance in 1ns between packets
#define REPLAYS 1000L // How many times we will repeat the packets
#define TX_DELAY 1000000000 // Initial transmission delay (one second)
#define PORT 0
#define ADAPTER 0
// This program, by default, uses the NT descriptor type to transmit packets.
// To use a PCAP descriptor, set the boolean variable pcapPackets to true.
bool pcapPackets = false; // Set to true to enable PCAP descriptor type.
// Time in nanoseconds to transmit one replay session
#define REPLAY_TRANSMIT_TIME (PACKET_GAP * PACKETS)
// Time in nanoseconds to transmit all replay sessions
#define TOTAL_TRANSMIT_TIME (REPLAY_TRANSMIT_TIME * REPLAYS)
// Struct pcap_timespec_s is the time specification for PCAP. For PCAP_NANO,
// the ts_usec field is in nanoseconds instead of microseconds.
uint32_t ts_sec;
uint32_t ts_usec;
};
// Standard PCAP record header.
struct pcap_record_s {
struct pcap_timespec_s time;
uint32_t incl_len;
uint32_t orig_len;
};
// printError is a simple convenience function for printing an NTAPI error
// message to stderr.
static void printError(const char *prefix, int errorCode) {
NT_ExplainError(errorCode, errorBuffer, sizeof errorBuffer);
fprintf(stderr, "%s: %s\n", prefix, errorBuffer);
}
static uint64_t
convertToUnixNsTs(const struct NtConfigTimestampReadData_s *data)
{
const struct pcap_timespec_s *pcap_ts = (const struct pcap_timespec_s *)&data->ts;
switch (data->tsType) {
return pcap_ts->ts_sec * 1000000000ULL + pcap_ts->ts_usec;
return data->ts;
default:
// default to nativeUnixTs when nanosecond resolution unavailable
// this is Unix Time with 10ns resolution.
return data->nativeUnixTs * 10;
}
}
int main(void)
{
//
// Initialize the API. This also checks if we are compatible with the
// installed library version.
//
int status;
if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
printError("NT_Init() failed", status);
return -1;
}
//
// Open the config stream, in order to retrieve the adapter timestamp and
// to configure the transmit on timestamp functionality. We configure
// transmit on timestamp in such a way that a packet with timestamp 0 will
// transmit in approximately one second from this point.
//
NtConfig_t config;
if ((status = NT_ConfigOpen(&hConfig, "replay")) != NT_SUCCESS) {
printError("NT_ConfigOpen() failed", status);
return -1;
}
if ((status = NT_ConfigRead(hConfig, &config)) != NT_SUCCESS) {
printError("NT_ConfigRead() failed", status);
return -1;
}
// Store the adapter timestamp and convert it to unix nanoseconds.
// Nanosecond precision is only available if TimestampFormat = UNIX_NS or
// TimestampFormat = PCAP_NS as defined in ntservice.ini.
// If TimestampFormat is set to anything else, it will derive the
// nanosecond timestamp from the NATIVE timestamp, which is measured
// in 10-ns ticks, and hence lose a small amount of precision.
uint64_t adapterTS = convertToUnixNsTs(&config.u.timestampRead.data);
// Configure transmit on timestamp. In scenarios where a packet descriptor
// that does not contain a TXNOW bit is used, such as when transmitting PCAP,
// forceTxOnTs must be set to true. However, this example uses NT
// descriptors, and can thus use the TXNOW bit.
//
// timeDeltaAdjust is set to the time it takes to complete a single replay
// session, so that the TXSETCLOCK bit will cause timeDelta to be prepared
// for the next replay run. Note that since we set TXSETCLOCK on the first
// packet of every iteration, including the first one, that the value of
// timeDeltaAdjust need to be subtracted from timeDelta to avoid accidentally
// delaying the initial transmission.
// There must be "room" for one replay session within the delay window.
const uint64_t txBeginTS = adapterTS + TX_DELAY;
config.u.transmitOnTimestamp.portNo = (uint8_t)PORT;
assert(txBeginTS >= REPLAY_TRANSMIT_TIME);
if (pcapPackets) {
// PCAP descriptor
} else {
// NT descriptor
}
if ((status = NT_ConfigWrite(hConfig, &config)) != NT_SUCCESS) {
printError("NT_ConfigWrite() failed", status);
return -1;
}
//
// Open a TX stream
//
if ((status = NT_NetTxOpen_v2(
&hNetTx, "transmit_on_timestamp_example_txstream", 1ULL << PORT,
printError("NT_NetTxOpen_v2() failed", status);
return -1;
}
//
// Retrieve a packet buffer, fill it, and repeat until we have transmitted
// the requested amount of packets. The timestamp will be set so that the
// adapter will transmit at approximately 5 Mb/s.
//
printf("Commencing transmission of %ld packets %ld times\n", PACKETS, REPLAYS);
NtNetBuf_t hNetBufTx;
int totalPackets = 0;
for (int replays = 0; replays < REPLAYS; replays++) {
uint64_t timestamp = 0;
for (int pkts = 0; pkts < PACKETS; pkts++, totalPackets++) {
// Get a packet TX buffer for this tx stream and port, without timeout
if ((status = NT_NetTxGet(hNetTx, &hNetBufTx, PORT, PACKET_SIZE,
NT_NETTX_PACKET_OPTION_DEFAULT, -1)) != NT_SUCCESS) {
printError("NT_NetTxGet() failed", status);
return -1;
}
// Set the packet timestamp
if (pcapPackets) {
// PCAP descriptor
struct pcap_record_s *hdr =
(struct pcap_record_s *)NT_NET_GET_PKT_DESCR_PTR(hNetBufTx);
hdr->time.ts_sec = (uint32_t)(timestamp / 1000000000U);
hdr->time.ts_usec = (uint32_t)(timestamp % 1000000000U);
} else {
// NT descriptor
NT_NET_SET_PKT_TIMESTAMP(hNetBufTx, timestamp);
}
timestamp += PACKET_GAP; // increment the timestamp for the next packet
if (pkts == 0) {
// We set TXSETCLOCK on the first packet. This results in the adapter
// adding timeDeltaAdjust to timeDelta before transmitting this packet.
NT_NET_SET_PKT_TXSETCLOCK(hNetBufTx, 1);
}
// Fill the packet with an incrementing payload. Note that this will result
// in a garbage ethernet frame.
uint32_t *ptr = (uint32_t*)NT_NET_GET_PKT_L2_PTR(hNetBufTx);
for (uint32_t i = 0; i < PACKET_SIZE/4; i++) {
*(ptr+i) = i;
}
// Release the TX buffer to commit the packet. It will transmit once the
// timestamp is reached, or when transmit on timestamp is disabled.
if ((status = NT_NetTxRelease(hNetTx, hNetBufTx)) != NT_SUCCESS) {
printError("NT_NetTxRelease() failed", status);
return -1;
}
}
}
//
// Wait for all packets to be transmitted. There are multiple ways to do
// this, but in this example, we read the adapter timestamp in a loop, and
// compare it to the value of our timestamp variable from the loop above.
//
printf("Waiting for transmission to end\n");
const uint64_t txStopTS = txBeginTS + TOTAL_TRANSMIT_TIME;
uint64_t newAdapterTS;
do {
sleep(1);
if ((status = NT_ConfigRead(hConfig, &config)) != NT_SUCCESS) {
printError("NT_ConfigRead() failed", status);
return -1;
}
newAdapterTS = convertToUnixNsTs(&config.u.timestampRead.data);
} while (newAdapterTS < txStopTS);
//
// Disable transmit on timestamp. If any packets are left in the buffera this
// point, they will transmit unhindered at line rate.
//
config.u.transmitOnTimestamp.portNo = (uint8_t)PORT;
config.u.transmitOnTimestamp.data.enable = false;
if ((status = NT_ConfigWrite(hConfig, &config)) != NT_SUCCESS) {
printError("NT_ConfigWrite() failed", status);
return -1;
}
//
// Terminate
//
printf("Done: %d packets sent\n", totalPackets);
//Close the Config stream
NT_ConfigClose(hConfig);
// Close the TX stream
NT_NetTxClose(hNetTx);
// Close the API
return 0;
}