net/transmit_on_timestamp_setclock/transmit_on_timestamp_setclock_example.c

Reference Documentation

product_line_custom
Napatech SmartNIC
category
Reference Information

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.

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_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() * - @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 * [System] * TimestampFormat = NATIVE * * [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_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_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_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_setclock_example_code Code * @} */ #include <nt.h> #include <unistd.h> #define PACKETS 100L // How many packets to send #define PACKET_SIZE 296L // Packet size to transmit (incl crc.) #define PACKET_GAP 500000L // Distance between packet headers #define REPLAYS 1000L // How many times we will repeat the packets #define PORT 0 #define ADAPTER 0 // Time it will take to transmit the packets in a single replay session #define REPLAY_TRANSMIT_TIME (PACKET_GAP * PACKETS) // Time it will take to complete all replay sessions #define TOTAL_TRANSMIT_TIME (REPLAY_TRANSMIT_TIME * REPLAYS) // 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. // // 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. config.parm = NT_CONFIG_PARM_PORT_TRANSMIT_ON_TIMESTAMP; config.u.transmitOnTimestamp.portNo = (uint8_t)PORT; config.u.transmitOnTimestamp.data.timeDelta = adapterTS + 1000000000 - REPLAY_TRANSMIT_TIME; config.u.transmitOnTimestamp.data.timeDeltaAdjust = REPLAY_TRANSMIT_TIME; 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 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; } 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); } // Set the timestamp of the packet, and increment the timestamp for the // next packet. NT_NET_SET_PKT_TIMESTAMP(hNetBufTx, timestamp); timestamp += PACKET_GAP; // 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 + TOTAL_TRANSMIT_TIME)); // // 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", totalPackets); // Close the TX stream NT_NetTxClose(hNetTx); // Close the API NT_Done(); return 0; }