transmit_on_timestamp_setclock_example.c

Reference Documentation

product_line_custom
Napatech SmartNIC
category
Reference Information

Go to the documentation of this file.

1/* 2 * %NT_SOFTWARE_LICENSE% 3 */ 4 5/** 6 * @example net/transmit_on_timestamp_setclock/transmit_on_timestamp_setclock_example.c 7 * @section transmit_on_timestamp_setclock_example_description Description 8 * 9 * This source file is an example of how to transmit a sequence of packets 10 * on timestamp multiple times, but instead of manually reconfiguring the 11 * delta for each iteration, TXSETCLOCK is used to advance the delta with 12 * the duration of a single replay iteration. An example application of this 13 * functionality would be where one wishes to replay a single capture file 14 * multiple times. 15 * 16 * This example will transmit 100000 packets of 296 bytes from port 0 at a rate 17 * of approximately 5 Mb/s. The packet contains an incrementing 32bit pattern. 18 * 19 * The transmit on timestamp functionality is also available in segment mode. 20 * See the @ref net/transmit_segment/transmit_segment_example.c example code 21 * to see how to use the segment interface. 22 * 23 * The following NTAPI functions are used: 24 * - @ref NT_Init() 25 * - @ref NT_ConfigOpen() 26 * - @ref NT_ConfigRead() 27 * - @ref NT_ConfigWrite() 28 * - @ref NT_ConfigClose() 29 * - @ref NT_NetTxOpen() 30 * - @ref NT_NetTxGet() 31 * - @ref NT_NET_SET_PKT_TIMESTAMP() 32 * - @ref NT_NET_SET_PKT_TXSETCLOCK() 33 * - @ref NT_NET_GET_PKT_L2_PTR() 34 * - @ref NT_NetTxRelease() 35 * - @ref NT_NetTxClose() 36 * - @ref NT_Done() 37 * - @ref NT_ExplainError() 38 * 39 * @section transmit_on_timestamp_setclock_example_prerequisites Prerequisites 40 * - This example is only compatible with adapters supporting 4GA transmit on 41 * timestamp. 42 * - The ntservice.ini must have at least one HostBuffersTx defined. Below is 43 * an example of a minimum ini-file. It will create a 4MB TX hostbuffer from 44 * NUMA node 0. 45 * 46 * @code 47 * [System] 48 * TimestampFormat = NATIVE 49 * 50 * [Adapter0] 51 * AdapterType = NT20E2 52 * BusId = 00:0a:00.00 53 * HostBuffersTx = [1,4,0] 54 * @endcode 55 * 56 * @section transmit_on_timestamp_setclock_example_flow Program flow 57 * @{ 58 * The following is required to transmit packages: 59 * - \#include/nt.h - Applications/Tools only need to include @ref 60 * nt.h to obtain prototypes, macros etc. from NTAPI. 61 * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI 62 * library. @ref NTAPI_VERSION is a define that describes the version 63 * of the API described in the header files included by @ref 64 * nt.h. NT_Init() will ask the NTAPI library to convert return data 65 * to the @ref NTAPI_VERSION if possible. This will ensure that 66 * applications can run on NTAPI libraries of newer versions. 67 * - @ref NT_NetConfigOpen() - Open the config stream. 68 * - @ref NT_ConfigRead() - Use the config stream to read the current adapter 69 * time. 70 * - @ref NT_ConfigWrite() - Use the config stream to configure transmit on 71 * timestamp, using the retrieved adapter time. 72 * - @ref NT_NetTxOpen() - Open a hostbuffer than can transmit packets to port 0. 73 * - @ref NT_NetTxGet() - Get an empty tx buffer. This will get a 296 byte 74 * wire length packet buffer that will be sent onto port 0 when the packet 75 * buffer is released, and the timestamp has been reached on the adapter. 76 * - @ref NT_NET_GET_PKT_L2_PTR() is used to get the L2 pointer to the tx 77 * buffer, this is where the payload is placed. 78 * - @ref NT_NET_SET_PKT_TXSETCLOCK() is used to enable txsetclock on the 79 * first packet in the replay sequence. 80 * - @ref NT_NET_SET_PKT_TIMESTAMP() is used to set the timestamp of the 81 * packet 82 * - @ref NT_NetTxRelease() - Release the tx packet buffer. Once a tx 83 * buffer is released it will be transmitted 84 * - @ref NT_NetConfigRead() - Read the adapter timestamp to check if the last 85 * packet should have been transmitted. We need to do this in order to avoid 86 * disabling transmit on timestamp too early. 87 * - @ref NT_NetConfigWrite() - Disable transmit on timestamp. 88 * - @ref NT_NetTxClose() - Close the TX stream. 89 * - @ref NT_Done() - Close down the NTAPI library. 90 * 91 *<hr> 92 * @section transmit_on_timestamp_setclock_example_code Code 93 * @} 94 */ 95 96#include <nt.h> 97#include <unistd.h> 98 99#define PACKETS 100L // How many packets to send 100#define PACKET_SIZE 296L // Packet size to transmit (incl crc.) 101#define PACKET_GAP 500000L // Distance between packet headers 102#define REPLAYS 1000L // How many times we will repeat the packets 103#define PORT 0 104#define ADAPTER 0 105 106// Time it will take to transmit the packets in a single replay session 107#define REPLAY_TRANSMIT_TIME (PACKET_GAP * PACKETS) 108 109// Time it will take to complete all replay sessions 110#define TOTAL_TRANSMIT_TIME (REPLAY_TRANSMIT_TIME * REPLAYS) 111 112// printError is a simple convenience function for printing an NTAPI error 113// message to stderr. 114static void printError(const char *prefix, int errorCode) { 115 char errorBuffer[NT_ERRBUF_SIZE]; 116 NT_ExplainError(errorCode, errorBuffer, sizeof errorBuffer); 117 fprintf(stderr, "%s: %s\n", prefix, errorBuffer); 118} 119 120int main(void) 121{ 122 // 123 // Initialize the API. This also checks if we are compatible with the 124 // installed library version. 125 // 126 int status; 127 128 if((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) { 129 printError("NT_Init() failed", status); 130 return -1; 131 } 132 133 // 134 // Open the config stream, in order to retrieve the adapter timestamp and 135 // to configure the transmit on timestamp functionality. We configure 136 // transmit on timestamp in such a way that a packet with timestamp 0 will 137 // transmit in approximately one second from this point. 138 // 139 NtConfigStream_t hConfig; 140 NtConfig_t config; 141 142 if ((status = NT_ConfigOpen(&hConfig, "replay")) != NT_SUCCESS) { 143 printError("NT_ConfigOpen() failed", status); 144 return -1; 145 } 146 147 config.parm = NT_CONFIG_PARM_ADAPTER_TIMESTAMP; 148 config.u.timestampRead.adapter = ADAPTER; 149 150 if ((status = NT_ConfigRead(hConfig, &config)) != NT_SUCCESS) { 151 printError("NT_ConfigRead() failed", status); 152 return -1; 153 } 154 155 // Store adapter timestamp, converted from 10ns ticks to 1ns 156 uint64_t adapterTS = config.u.timestampRead.data.nativeUnixTs * 10; 157 158 // Configure transmit on timestamp. In scenarios where a packet descriptor 159 // that does not contain a TXNOW bit is used, such as when transmitting PCAP, 160 // forceTxOnTs must be set to true. However, this example uses NT 161 // descriptors, and can thus use the TXNOW bit. 162 // 163 // timeDeltaAdjust is set to the time it takes to complete a single replay 164 // session, so that the TXSETCLOCK bit will cause timeDelta to be prepared 165 // for the next replay run. Note that since we set TXSETCLOCK on the first 166 // packet of every iteration, including the first one, that the value of 167 // timeDeltaAdjust need to be subtracted from timeDelta to avoid accidentally 168 // delaying the initial transmission. 169 config.parm = NT_CONFIG_PARM_PORT_TRANSMIT_ON_TIMESTAMP; 170 config.u.transmitOnTimestamp.portNo = (uint8_t)PORT; 171 config.u.transmitOnTimestamp.data.timeDelta = adapterTS + 1000000000 - REPLAY_TRANSMIT_TIME; 172 config.u.transmitOnTimestamp.data.timeDeltaAdjust = REPLAY_TRANSMIT_TIME; 173 config.u.transmitOnTimestamp.data.enable = true; 174 config.u.transmitOnTimestamp.data.forceTxOnTs = false; 175 176 if ((status = NT_ConfigWrite(hConfig, &config)) != NT_SUCCESS) { 177 printError("NT_ConfigWrite() failed", status); 178 return -1; 179 } 180 181 // 182 // Open a TX stream 183 // 184 NtNetStreamTx_t hNetTx; 185 186 if ((status = NT_NetTxOpen(&hNetTx, "transmit_on_timestamp_example_txstream", 187 (1<<PORT), NT_NETTX_NUMA_ANY_HB, 0)) != NT_SUCCESS) { 188 printError("NT_NetTxOpen() failed", status); 189 return -1; 190 } 191 192 // 193 // Retrieve a packet buffer, fill it, and repeat until we have transmitted 194 // the requested amount of packets. The timestamp will be set so that the 195 // adapter will transmit at approximately 5 Mb/s. 196 // 197 printf("Commencing transmission of %ld packets %ld times\n", PACKETS, REPLAYS); 198 199 NtNetBuf_t hNetBufTx; 200 int totalPackets = 0; 201 202 for (int replays = 0; replays < REPLAYS; replays++) { 203 204 uint64_t timestamp = 0; 205 for (int pkts = 0; pkts < PACKETS; pkts++, totalPackets++) { 206 207 // Get a packet TX buffer for this tx stream and port, without timeout 208 if ((status = NT_NetTxGet(hNetTx, &hNetBufTx, PORT, PACKET_SIZE, 209 NT_NETTX_PACKET_OPTION_DEFAULT, -1)) != NT_SUCCESS) { 210 printError("NT_NetTxGet() failed", status); 211 return -1; 212 } 213 214 if (pkts == 0) { 215 // We set TXSETCLOCK on the first packet. This results in the adapter 216 // adding timeDeltaAdjust to timeDelta before transmitting this packet. 217 NT_NET_SET_PKT_TXSETCLOCK(hNetBufTx, 1); 218 } 219 220 // Set the timestamp of the packet, and increment the timestamp for the 221 // next packet. 222 NT_NET_SET_PKT_TIMESTAMP(hNetBufTx, timestamp); 223 timestamp += PACKET_GAP; 224 225 // Fill the packet with an incrementing payload. Note that this will result 226 // in a garbage ethernet frame. 227 uint32_t *ptr = (uint32_t*)NT_NET_GET_PKT_L2_PTR(hNetBufTx); 228 for (int i = 0; i < PACKET_SIZE/4; i++) { 229 *(ptr+i) = i; 230 } 231 232 // Release the TX buffer to commit the packet. It will transmit once the 233 // timestamp is reached, or when transmit on timestamp is disabled. 234 if ((status = NT_NetTxRelease(hNetTx, hNetBufTx)) != NT_SUCCESS) { 235 printError("NT_NetTxRelease() failed", status); 236 return -1; 237 } 238 } 239 } 240 241 // 242 // Wait for all packets to be transmitted. There are multiple ways to do 243 // this, but in this example, we read the adapter timestamp in a loop, and 244 // compare it to the value of our timestamp variable from the loop above. 245 // 246 printf("Waiting for transmission to end\n"); 247 248 config.parm = NT_CONFIG_PARM_ADAPTER_TIMESTAMP; 249 config.u.timestampRead.adapter = ADAPTER; 250 251 uint64_t newAdapterTS = adapterTS; 252 do { 253 sleep(1); 254 if ((status = NT_ConfigRead(hConfig, &config)) != NT_SUCCESS) { 255 printError("NT_ConfigRead() failed", status); 256 return -1; 257 } 258 259 newAdapterTS = config.u.timestampRead.data.nativeUnixTs * 10; 260 } while (newAdapterTS <= (adapterTS + TOTAL_TRANSMIT_TIME)); 261 262 // 263 // Disable transmit on timestamp. If any packets are left in the buffera this 264 // point, they will transmit unhindered at line rate. 265 // 266 config.parm = NT_CONFIG_PARM_PORT_TRANSMIT_ON_TIMESTAMP; 267 config.u.transmitOnTimestamp.portNo = (uint8_t)PORT; 268 config.u.transmitOnTimestamp.data.timeDelta = 0; 269 config.u.transmitOnTimestamp.data.timeDeltaAdjust = 0; 270 config.u.transmitOnTimestamp.data.enable = false; 271 config.u.transmitOnTimestamp.data.forceTxOnTs = 0; 272 273 if ((status = NT_ConfigWrite(hConfig, &config)) != NT_SUCCESS) { 274 printError("NT_ConfigWrite() failed", status); 275 return -1; 276 } 277 278 // 279 // Terminate 280 // 281 printf("Done: %d packets sent\n", totalPackets); 282 283 // Close the TX stream 284 NT_NetTxClose(hNetTx); 285 286 // Close the API 287 NT_Done(); 288 289 return 0; 290}