net/transmit_on_timestamp/transmit_on_timestamp_example.c

Reference Documentation

product_line_custom
Napatech SmartNIC
category
Reference Information

Description

This source file is an example of how to transmit packets on timestamp using the packet interface in NTAPI. The example will transmit 100000 packets with a size 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.

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.

[System] TimestampFormat = NATIVE [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_NetConfigOpen() - 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_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_NetTxRelease() - Release the tx packet buffer. Once a tx buffer is released it will be transmitted

  • NT_NetConfigRead() - 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_NetConfigWrite() - Disable transmit on timestamp.

  • NT_NetTxClose() - Close the TX stream.

  • NT_Done() - Close down the NTAPI library.

Code

/* * %NT_SOFTWARE_LICENSE% */ /** * @example net/transmit_on_timestamp/transmit_on_timestamp_example.c * @section transmit_on_timestamp_example_description Description * * This source file is an example of how to transmit packets on timestamp * using the packet interface in NTAPI. The example will transmit 100000 * packets with a size 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() * - @ref NT_NetTxGet() * - @ref NT_NET_SET_PKT_TIMESTAMP() * - @ref NT_NET_GET_PKT_L2_PTR() * - @ref NT_NetTxRelease() * - @ref NT_NetTxClose() * - @ref NT_Done() * - @ref NT_ExplainError() * * @section transmit_on_timestamp_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 * [System] * TimestampFormat = NATIVE * * [Adapter0] * AdapterType = NT20E2 * BusId = 00:0a:00.00 * HostBuffersTx = [1,4,0] * @endcode * * @section transmit_on_timestamp_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_NetConfigOpen() - 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_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_TIMESTAMP() is used to set the packet timestamp. * - @ref NT_NetTxRelease() - Release the tx packet buffer. Once a tx * buffer is released it will be transmitted * - @ref NT_NetConfigRead() - 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_NetConfigWrite() - Disable transmit on timestamp. * - @ref NT_NetTxClose() - Close the TX stream. * - @ref NT_Done() - Close down the NTAPI library. * *<hr> * @section transmit_on_timestamp_example_code Code * @} */ #include <nt.h> #include <unistd.h> // default TX packet test setup #define PACKETS 100000 #define PACKET_SIZE 296 // Packet size to transmit (incl crc.) #define PORT 0 #define ADAPTER 0 // printError is a simple convenience function for printing an NTAPI error // message to stderr. static void printError(const char *prefix, int errorCode) { char errorBuffer[NT_ERRBUF_SIZE]; NT_ExplainError(errorCode, errorBuffer, sizeof errorBuffer); fprintf(stderr, "%s: %s\n", prefix, errorBuffer); } 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. // NtConfigStream_t hConfig; NtConfig_t config; if ((status = NT_ConfigOpen(&hConfig, "replay")) != NT_SUCCESS) { printError("NT_ConfigOpen() failed", status); return -1; } config.parm = NT_CONFIG_PARM_ADAPTER_TIMESTAMP; config.u.timestampRead.adapter = ADAPTER; if ((status = NT_ConfigRead(hConfig, &config)) != NT_SUCCESS) { printError("NT_ConfigRead() failed", status); return -1; } // Store adapter timestamp, converted from 10ns ticks to 1ns uint64_t adapterTS = config.u.timestampRead.data.nativeUnixTs * 10; // 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. config.parm = NT_CONFIG_PARM_PORT_TRANSMIT_ON_TIMESTAMP; config.u.transmitOnTimestamp.portNo = (uint8_t)PORT; config.u.transmitOnTimestamp.data.timeDelta = adapterTS + 1000000000; config.u.transmitOnTimestamp.data.timeDeltaAdjust = 0; config.u.transmitOnTimestamp.data.enable = true; config.u.transmitOnTimestamp.data.forceTxOnTs = false; if ((status = NT_ConfigWrite(hConfig, &config)) != NT_SUCCESS) { printError("NT_ConfigWrite() failed", status); return -1; } // // Open a TX stream // NtNetStreamTx_t hNetTx; if ((status = NT_NetTxOpen(&hNetTx, "transmit_on_timestamp_example_txstream", (1<<PORT), NT_NETTX_NUMA_ANY_HB, 0)) != NT_SUCCESS) { printError("NT_NetTxOpen() 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\n"); NtNetBuf_t hNetBufTx; uint64_t timestamp = 0; int numPackets = 0; for (numPackets = 0; numPackets < PACKETS; numPackets++) { // 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 timestamp. Note that for the NT descriptor, this is in 10ns // ticks. The descriptor has been cleared, so TXNOW is set to 0. If one // wishes to send a packet as soon as possible while transmit on timestamp // is enabled, use NT_NET_SET_PKT_TXNOW to set TXNOW to 1. NT_NET_SET_PKT_TIMESTAMP(hNetBufTx, timestamp); timestamp += 50000; // 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 (int 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"); config.parm = NT_CONFIG_PARM_ADAPTER_TIMESTAMP; config.u.timestampRead.adapter = ADAPTER; uint64_t newAdapterTS = adapterTS; do { sleep(1); if ((status = NT_ConfigRead(hConfig, &config)) != NT_SUCCESS) { printError("NT_ConfigRead() failed", status); return -1; } newAdapterTS = config.u.timestampRead.data.nativeUnixTs * 10; } while (newAdapterTS <= (adapterTS + timestamp)); // // Disable transmit on timestamp. If any packets are left in the buffera this // point, they will transmit unhindered at line rate. // config.parm = NT_CONFIG_PARM_PORT_TRANSMIT_ON_TIMESTAMP; config.u.transmitOnTimestamp.portNo = (uint8_t)PORT; config.u.transmitOnTimestamp.data.timeDelta = 0; config.u.transmitOnTimestamp.data.timeDeltaAdjust = 0; config.u.transmitOnTimestamp.data.enable = false; config.u.transmitOnTimestamp.data.forceTxOnTs = 0; if ((status = NT_ConfigWrite(hConfig, &config)) != NT_SUCCESS) { printError("NT_ConfigWrite() failed", status); return -1; } // // Terminate // printf("Done: %d packets sent\n", numPackets); // Close the TX stream NT_NetTxClose(hNetTx); // Close the API NT_Done(); return 0; }