net/replay/replay_example.c

Reference Documentation

product_line_custom
Napatech SmartNIC
category
Reference Information

Prerequisites

  • Capture file, capfile.ntcap, that has been captured with the net/capture/capture_example.c example.

  • The ntservice.ini must have at least one HostBuffersTx defined. Below is an example of a minimum ini-file. It will create a 32MB TX hostbuffer from NUMA node 0. [System] TimestampFormat = NATIVE [Adapter0] AdapterType = NT20E2 BusId = 00:0a:00.00 HostBuffersTx = [1,32,0]

Program flow

The following is required to perform replay of a captured file:
  • #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_InfoOpen() - Open the information stream.

  • NT_InfoRead() - Read the adapter information to check whether or not we are using absolut TX timing. The txTiming tells whether relative or absolut TX timing is enabled.

  • NT_InfoClose() - Close the information stream.

  • NT_NetFileOpen() - Open the captured file and assign it to a stream.

  • NT_NetTxOpen() - Open a hostbuffer than can transmit packets to port 0.

  • NT_NetFileGet() - Get a segment from the file. This call will return NT_SUCCESS upon return of a segment and NT_STATUS_END_OF_FILE when there is no more segments avaialble. The latter will cause the example to exit.

  • NT_NetTxGet() - Get an empty tx buffer. This will get a segment of the requested length from the hostbuffer that will be sent onto port 0 when the buffer is released.
    • NT_NET_GET_SEGMENT_PTR() and NT_NET_GET_SEGMENT_LENGTH() are used to tell where the segment data is located and how much there is. _nt_net_build_pkt_netbuf() and _nt_net_get_next_packet() are used to traverse packets inside a segment. This is usefull if ie. the timing of the packet transmit rate needs to be changed.

  • NT_NetTxRelease() - Release the segment buffer. Once a tx buffer is released it will be transmitted according to the timestamps of the packets in the segment.

  • NT_NetFileRelease() - Release the segment from the file stream.

  • NT_NetFileClose() - Close the file stream when no more segments can be found.

  • NT_NetTxClose() - Close the TX stream.

Code

/* * %NT_SOFTWARE_LICENSE% */ /** * @example net/replay/replay_example.c * @section replay_example_description Description * * This source file is an example of how to replay a capture file onto * a port using NTAPI. * * The following NTAPI functions are used: * - @ref NT_Init() * - @ref NT_InfoOpen * - @ref NT_InfoRead * - @ref NT_InfoClose * - @ref NT_NetFileOpen() * - @ref NT_NetTxOpen() * - @ref NT_NTPL() * - @ref NT_NetFileGet() * - @ref NT_NetTxGet() * - @ref NT_NET_GET_SEGMENT_PTR() * - @ref NT_NET_GET_SEGMENT_LENGTH() * - @ref NT_NetTxRelease() * - @ref NT_NetFileRelease() * - @ref NT_NetFileClose() * - @ref NT_NetTxClose() * - @ref NT_ExplainError() * * @section replay_example_prerequisites Prerequisites * - Capture file, capfile.ntcap, that has been captured with the @ref * net/capture/capture_example.c "net/capture/capture_example.c" example. * - The ntservice.ini must have at least one HostBuffersTx * defined. Below is an example of a minimum ini-file. It will * create a 32MB TX hostbuffer from NUMA node 0. * @code * [System] * TimestampFormat = NATIVE * * [Adapter0] * AdapterType = NT20E2 * BusId = 00:0a:00.00 * HostBuffersTx = [1,32,0] * @endcode * * @section replay_example_flow Program flow * @{ * The following is required to perform replay of a captured file: * - \#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_InfoOpen() - Open the information stream. * - @ref NT_InfoRead() - Read the adapter information to check whether or not * we are using absolut TX timing. The @ref NtTxTimingMethod_e "txTiming" * tells whether relative or absolut TX timing is enabled. * - @ref NT_InfoClose() - Close the information stream. * - @ref NT_NetFileOpen() - Open the captured file and assign it to a stream. * - @ref NT_NetTxOpen() - Open a hostbuffer than can transmit packets to port 0. * - @ref NT_NetFileGet() - Get a segment from the file. This call will * return @ref NT_SUCCESS upon return of a segment and * @ref NT_STATUS_END_OF_FILE when there is no more segments * avaialble. The latter will cause the example to exit. * - @ref NT_NetTxGet() - Get an empty tx buffer. This will get a segment of the * requested length from the hostbuffer that will be sent * onto port 0 when the buffer is released. * - @ref NT_NET_GET_SEGMENT_PTR() and @ref NT_NET_GET_SEGMENT_LENGTH() are used * to tell where the segment data is located and how much there is. * _nt_net_build_pkt_netbuf() and _nt_net_get_next_packet() are used to traverse * packets inside a segment. This is usefull if ie. the timing of the packet * transmit rate needs to be changed. * - @ref NT_NetTxRelease() - Release the segment buffer. Once a tx * buffer is released it will be transmitted according to the * timestamps of the packets in the segment. * - @ref NT_NetFileRelease() - Release the segment from the file stream. * - @ref NT_NetFileClose() - Close the file stream when no more segments can be found. * - @ref NT_NetTxClose() - Close the TX stream. * *<hr> * @section replay_example_code Code * @} */ #include <nt.h> #if defined(__linux__) || defined(__FreeBSD__) #include <string.h> // memcpy #endif // default setup #define PORT 0 int main(void) { int numPackets=0; // The number of packets replayed int numBytes=0; // The number of bytes replayed int firstPacket=1; // First packet to transmit char errorBuffer[NT_ERRBUF_SIZE]; // Error buffer int status; // Status variable NtNetStreamFile_t hNetFile; // Handle to the File stream NtNetBuf_t hNetBufFile; // Net buffer container. Used to return segments from the file stream NtNetStreamTx_t hNetTx; // Handle to the TX stream NtNetBuf_t hNetBufTx; // Net buffer container. Used when getting a transmit buffer NtInfoStream_t hInfo; // Handle to a info stream NtInfo_t infoRead; // Buffer to hold data from infostream struct NtNetBuf_s pktNetBuf; // Packet netbuf structure. enum NtTxTimingMethod_e txTiming; // TX mode - Do we use absolut or relative mode uint8_t adapterNo ; // Adapter no // 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; } // Open the infostream. if((status = NT_InfoOpen(&hInfo, "replay")) != NT_SUCCESS) { NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_InfoOpen() failed: %s\n", errorBuffer); return -1; } // Check whether or not TX is supported on the defined port infoRead.cmd = NT_INFO_CMD_READ_PORT_V9; infoRead.u.port_v9.portNo=PORT; // TX port is hardcoded to defined PORT if((status = NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) { NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer); NT_InfoClose(hInfo); return -1; } // save adapter number of the TX port adapterNo = infoRead.u.port_v9.data.adapterNo ; if(infoRead.u.port_v9.data.capabilities.featureMask&NT_PORT_FEATURE_RX_ONLY) { fprintf(stderr, "Transmit is not possible on the selected port %d\n",PORT); NT_InfoClose(hInfo); return -1; } // Check whether or not absolut TX timing is supported adapterNo = infoRead.u.port_v9.data.adapterNo ; infoRead.cmd = NT_INFO_CMD_READ_ADAPTER_V6; infoRead.u.adapter_v6.adapterNo=adapterNo; // Adapter is derived from PORT of adapter if((status = NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) { NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer); NT_InfoClose(hInfo); return -1; } // Get the TX mode txTiming = infoRead.u.adapter_v6.data.txTiming; NT_InfoClose(hInfo); // Open the capture file to replay (captured with the capture example) if((status = NT_NetFileOpen(&hNetFile, "FileStream", NT_NET_INTERFACE_SEGMENT, "capfile.ntcap")) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_NetFileOpen() failed: %s\n", errorBuffer); return -1; } // Open a TX hostbuffer from TX host buffer pool on the NUMA node of the adapter with the defined PORT if((status = NT_NetTxOpen(&hNetTx, "TxStreamPort", (0x1<<PORT), NT_NETTX_NUMA_ADAPTER_HB, 0)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_NetTxOpen() failed: %s\n", errorBuffer); return -1; } // Get segments from the file and transmit them to defined PORT while(1) { printf("Getting segment.\n"); // Get the packet if((status = NT_NetFileGet(hNetFile, &hNetBufFile)) != NT_SUCCESS) { if(status == NT_STATUS_END_OF_FILE) { // The file has no more data break; } // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_NetFileGet() failed: %s\n", errorBuffer); return -1; } // Get a TX buffer for this segment if((status = NT_NetTxGet(hNetTx, &hNetBufTx, PORT, NT_NET_GET_SEGMENT_LENGTH(hNetBufFile), NT_NETTX_SEGMENT_OPTION_RAW, -1 /* wait forever */)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_NetFileGet() failed: %s\n", errorBuffer); return -1; } // Copy the segment into the TX buffer memcpy(NT_NET_GET_SEGMENT_PTR(hNetBufTx), NT_NET_GET_SEGMENT_PTR(hNetBufFile), NT_NET_GET_SEGMENT_LENGTH(hNetBufFile)); // Build a packet netbuf structure _nt_net_build_pkt_netbuf(hNetBufTx, &pktNetBuf); if(firstPacket == 1) { if(txTiming == NT_TX_TIMING_ABSOLUTE) { // Absolute TX mode is supported. // If transmit tx relative is disabled i.e. we are using absolut transmit and // the txclock must be synched to the timestamp in the first packet. NT_NET_SET_PKT_TXNOW((&pktNetBuf), 0); // Wait for tx delay before the packet is sent NT_NET_SET_PKT_TXSETCLOCK((&pktNetBuf), 1); // Synchronize tx clock to timestamp in first packet. } else { // Legacy mode/Relative tx timing. // First packet must be sent with txnow=1 NT_NET_SET_PKT_TXNOW((&pktNetBuf), 1); // Send the first packet now } firstPacket = 0; } // Optional step. Here all packets are inspected before sent if(NT_NET_GET_SEGMENT_LENGTH(hNetBufTx)) { do { // Just count the amount of packets and wire length numPackets++; numBytes+=NT_NET_GET_PKT_WIRE_LENGTH((&pktNetBuf)); } while(_nt_net_get_next_packet(hNetBufTx, NT_NET_GET_SEGMENT_LENGTH(hNetBufTx), &pktNetBuf)>0); } // Release the TX buffer and the packets within the segment will be transmitted if((status = NT_NetTxRelease(hNetTx, hNetBufTx)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_NetTxRelease() failed: %s\n", errorBuffer); return -1; } // Release the file packet if((status = NT_NetFileRelease(hNetFile, hNetBufFile)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_NetFileRelease() failed: %s\n", errorBuffer); return -1; } } // Close the file stream NT_NetFileClose(hNetFile); // Close the TX stream NT_NetTxClose(hNetTx); printf("Done: %d packets %d bytes has been replayed\n", numPackets, numBytes); return 0; }