replay4ga_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/replay4GA/replay4ga_example.c 7 * @section replay4ga_example_description Description 8 * 9 * This source file is an example of how to replay a capture file onto 10 * a port using NTAPI when using a 4GA transmit on timestamp adapter. 11 * 12 * The following NTAPI functions are used: 13 * - @ref NT_Init() 14 * - @ref NT_ConfigOpen() 15 * - @ref NT_ConfigRead() 16 * - @ref NT_ConfigWrite() 17 * - @ref NT_ConfigClose() 18 * - @ref NT_InfoOpen() 19 * - @ref NT_InfoRead() 20 * - @ref NT_InfoClose() 21 * - @ref NT_NetFileOpen() 22 * - @ref NT_NetTxOpen() 23 * - @ref NT_NTPL() 24 * - @ref NT_NetFileGet() 25 * - @ref NT_NetTxGet() 26 * - @ref NT_NET_GET_SEGMENT_PTR() 27 * - @ref NT_NET_GET_SEGMENT_LENGTH() 28 * - @ref NT_NetTxRelease() 29 * - @ref NT_NetFileRelease() 30 * - @ref NT_NetFileClose() 31 * - @ref NT_NetTxClose() 32 * - @ref NT_ExplainError() 33 * 34 * @section replay4ga_example_prerequisites Prerequisites 35 * - Capture file, capfile.ntcap, that has been captured with the @ref 36 * net/capture/capture_example.c "net/capture/capture_example.c" example. 37 * - A fourth generation adapter supporting transmit on timestamp. 38 * - The ntservice.ini must have at least one HostBuffersTx 39 * defined. Below is an example of a minimum ini-file. It will 40 * create a 32MB TX hostbuffer from NUMA node 0. 41 * @code 42 * [System] 43 * TimestampFormat = NATIVE 44 * 45 * [Adapter0] 46 * AdapterType = NT20E2 47 * BusId = 00:0a:00.00 48 * HostBuffersTx = [1,32,0] 49 * @endcode 50 * 51 * @section replay4ga_example_flow Program flow 52 * @{ 53 * The following is required to perform replay of a captured file: 54 * - \#include/nt.h - Applications/Tools only need to include @ref 55 * nt.h to obtain prototypes, macros etc. from NTAPI. 56 * - \#include/unistd.h - sleep() 57 * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI 58 * library. @ref NTAPI_VERSION is a define that describes the version 59 * of the API described in the header files included by @ref 60 * nt.h. NT_Init() will ask the NTAPI library to convert return data 61 * to the @ref NTAPI_VERSION if possible. This will ensure that 62 * applications can run on NTAPI libraries of newer versions. 63 * - @ref NT_ConfigOpen() - Open the configuration stream. 64 * - @ref NT_ConfigRead() - Read from the configuration stream to fetch the 65 * adapter timestamp. 66 * - @ref NT_ConfigWrite() - Write to the configuration stream to set transmit 67 * on timestamp configuration. 68 * - @ref NT_ConfigClose() - Close the configuration stream. 69 * - @ref NT_InfoOpen() - Open the information stream. 70 * - @ref NT_InfoRead() - Read the adapter information to check whether or not 71 * we are using absolut TX timing. The @ref NtTxTimingMethod_e "txTiming" 72 * tells whether relative or absolut TX timing is enabled. 73 * - @ref NT_InfoClose() - Close the information stream. 74 * - @ref NT_NetFileOpen() - Open the captured file and assign it to a stream. 75 * - @ref NT_NetTxOpen() - Open a hostbuffer than can transmit packets to port 0. 76 * - @ref NT_NetFileGet() - Get a segment from the file. This call will 77 * return @ref NT_SUCCESS upon return of a segment and 78 * @ref NT_STATUS_END_OF_FILE when there is no more segments 79 * avaialble. The latter will cause the example to exit. 80 * - @ref NT_NetTxGet() - Get an empty tx buffer. This will get a segment of the 81 * requested length from the hostbuffer that will be sent 82 * onto port 0 when the buffer is released. 83 * - @ref NT_NET_GET_SEGMENT_PTR() and @ref NT_NET_GET_SEGMENT_LENGTH() are used 84 * to tell where the segment data is located and how much there is. 85 * _nt_net_build_pkt_netbuf() and _nt_net_get_next_packet() are used to traverse 86 * packets inside a segment. This is usefull if ie. the timing of the packet 87 * transmit rate needs to be changed. 88 * - @ref NT_NetTxRelease() - Release the segment buffer. Once a tx 89 * buffer is released it will be transmitted according to the 90 * timestamps of the packets in the segment. 91 * - @ref NT_NetFileRelease() - Release the segment from the file stream. 92 * - @ref NT_NetFileClose() - Close the file stream when no more segments can be found. 93 * - @ref NT_NetTxClose() - Close the TX stream. 94 * 95 *<hr> 96 * @section replay4ga_example_code Code 97 * @} 98 */ 99#include <nt.h> 100#include <unistd.h> 101 102#if defined(__linux__) || defined(__FreeBSD__) 103 #include <string.h> // memcpy 104#endif 105 106// default setup 107#define PORT 0 108 109int main(void) 110{ 111 int numPackets=0; // The number of packets replayed 112 int numBytes=0; // The number of bytes replayed 113 char errorBuffer[NT_ERRBUF_SIZE]; // Error buffer 114 int status; // Status variable 115 NtNetStreamFile_t hNetFile; // Handle to the File stream 116 NtNetBuf_t hNetBufFile; // Net buffer container. Used to return segments from the file stream 117 NtNetStreamTx_t hNetTx; // Handle to the TX stream 118 NtNetBuf_t hNetBufTx; // Net buffer container. Used when getting a transmit buffer 119 NtInfoStream_t hInfo; // Handle to a info stream 120 NtInfo_t infoRead; // Buffer to hold data from infostream 121 NtConfigStream_t hConfig; // Handle to a config stream 122 NtConfig_t configRead; // Config stream data container 123 NtConfig_t configWrite; // Config stream data container 124 struct NtNetBuf_s pktNetBuf; // Packet netbuf structure. 125 uint8_t adapterNo ; // Adapter no 126 uint64_t firstPacketTS=0; // Timestamp of first packet 127 uint64_t lastPacketTS=0; // Timestamp of last packet 128 uint64_t adapterTS=0; // Timestamp on the adapter 129 uint64_t timeDelta=0; // Calculated time delta 130 131 // Initialize the NTAPI library and thereby check if NTAPI_VERSION can be used together with this library 132 if((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) { 133 // Get the status code as text 134 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 135 fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer); 136 return -1; 137 } 138 139 // Open the infostream. 140 if((status = NT_InfoOpen(&hInfo, "replay")) != NT_SUCCESS) { 141 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 142 fprintf(stderr, "NT_InfoOpen() failed: %s\n", errorBuffer); 143 return -1; 144 } 145 146 // Check whether or not TX is supported on the defined port 147 infoRead.cmd = NT_INFO_CMD_READ_PORT_V9; 148 infoRead.u.port_v9.portNo=PORT; // TX port is hardcoded to defined PORT 149 if((status = NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) { 150 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 151 fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer); 152 NT_InfoClose(hInfo); 153 return -1; 154 } 155 156 // save adapter number of the TX port 157 adapterNo = infoRead.u.port_v9.data.adapterNo ; 158 159 if(infoRead.u.port_v9.data.capabilities.featureMask&NT_PORT_FEATURE_RX_ONLY) { 160 fprintf(stderr, "Transmit is not possible on the selected port %d\n",PORT); 161 NT_InfoClose(hInfo); 162 return -1; 163 } 164 165 // Check whether or not absolut TX timing is supported 166 adapterNo = infoRead.u.port_v9.data.adapterNo ; 167 infoRead.cmd = NT_INFO_CMD_READ_ADAPTER_V6; 168 infoRead.u.adapter_v6.adapterNo=adapterNo; // Adapter is derived from PORT of adapter 169 if((status = NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) { 170 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 171 fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer); 172 NT_InfoClose(hInfo); 173 return -1; 174 } 175 176 NT_InfoClose(hInfo); 177 178 // Open the capture file to replay (captured with the capture example) 179 if((status = NT_NetFileOpen(&hNetFile, "FileStream", NT_NET_INTERFACE_SEGMENT, "capfile.ntcap")) != NT_SUCCESS) { 180 // Get the status code as text 181 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 182 fprintf(stderr, "NT_NetFileOpen() failed: %s\n", errorBuffer); 183 return -1; 184 } 185 186 // Read one segment from the file to get the first packet timestamp 187 if ((status = NT_NetFileGet(hNetFile, &hNetBufFile)) != NT_SUCCESS) { 188 if (status == NT_STATUS_END_OF_FILE) { 189 fprintf(stderr, "The file %s has no data\n", "capfile.ntpcap"); 190 return -1; 191 } 192 } 193 _nt_net_build_pkt_netbuf(hNetBufFile, &pktNetBuf); 194 firstPacketTS = NT_NET_GET_PKT_TIMESTAMP(&pktNetBuf) * 10; // Convert 10ns ticks to 1ns 195 196 // Close the file again. We will open it again later to actually transmit packets. 197 NT_NetFileClose(hNetFile); 198 199 // Open the config stream 200 if ((status = NT_ConfigOpen(&hConfig, "replay")) != NT_SUCCESS) { 201 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 202 fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer); 203 NT_ConfigClose(hConfig); 204 return 0; 205 } 206 207 // Read the adapter time 208 configRead.parm = NT_CONFIG_PARM_ADAPTER_TIMESTAMP; 209 configRead.u.timestampRead.adapter = PORT; 210 if ((status = NT_ConfigRead(hConfig, &configRead)) != NT_SUCCESS) { 211 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 212 fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer); 213 NT_ConfigClose(hConfig); 214 return 0; 215 } 216 adapterTS = configRead.u.timestampRead.data.nativeUnixTs * 10; // Convert 10ns ticks to 1ns 217 218 // Calculate time delta - we add 1 second to give ourselves some headroom 219 timeDelta = (adapterTS - firstPacketTS) + 1000000000; 220 221 // Configure transmit on timestamp 222 configWrite.parm = NT_CONFIG_PARM_PORT_TRANSMIT_ON_TIMESTAMP; 223 configWrite.u.transmitOnTimestamp.portNo = (uint8_t) PORT; 224 configWrite.u.transmitOnTimestamp.data.timeDelta = timeDelta; 225 configWrite.u.transmitOnTimestamp.data.enable = true; 226 configWrite.u.transmitOnTimestamp.data.forceTxOnTs = true; 227 if ((status = NT_ConfigWrite(hConfig, &configWrite)) != NT_SUCCESS) { 228 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 229 fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer); 230 NT_ConfigClose(hConfig); 231 return 0; 232 } 233 234 // Open the capture file to replay (captured with the capture example) 235 if((status = NT_NetFileOpen(&hNetFile, "FileStream", NT_NET_INTERFACE_SEGMENT, "capfile.ntcap")) != NT_SUCCESS) { 236 // Get the status code as text 237 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 238 fprintf(stderr, "NT_NetFileOpen() failed: %s\n", errorBuffer); 239 return -1; 240 } 241 242 // Open a TX hostbuffer from TX host buffer pool on the NUMA node of the adapter with the defined PORT 243 if((status = NT_NetTxOpen(&hNetTx, "TxStreamPort", (0x1<<PORT), NT_NETTX_NUMA_ADAPTER_HB, 0)) != NT_SUCCESS) { 244 // Get the status code as text 245 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 246 fprintf(stderr, "NT_NetTxOpen() failed: %s\n", errorBuffer); 247 return -1; 248 } 249 250 // Get segments from the file and transmit them to defined PORT 251 while(1) { 252 printf("Getting segment.\n"); 253 // Get the packet 254 if((status = NT_NetFileGet(hNetFile, &hNetBufFile)) != NT_SUCCESS) { 255 if(status == NT_STATUS_END_OF_FILE) { 256 // The file has no more data 257 break; 258 } 259 // Get the status code as text 260 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 261 fprintf(stderr, "NT_NetFileGet() failed: %s\n", errorBuffer); 262 return -1; 263 } 264 265 NtNetFileRead_t fileRead; 266 fileRead.cmd = NT_NETFILE_READ_INFO_CMD_V1; 267 if ((status = NT_NetFileRead(hNetFile, &fileRead)) != NT_SUCCESS) { 268 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 269 fprintf(stderr, "NT_NetfileRead() failed: %s\n", errorBuffer); 270 return -1; 271 } 272 lastPacketTS = fileRead.u.info_v1.lastTimestamp * 10; 273 274 // Get a TX buffer for this segment 275 if((status = NT_NetTxGet(hNetTx, &hNetBufTx, PORT, NT_NET_GET_SEGMENT_LENGTH(hNetBufFile), NT_NETTX_SEGMENT_OPTION_RAW, -1 /* wait forever */)) != NT_SUCCESS) { 276 // Get the status code as text 277 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 278 fprintf(stderr, "NT_NetFileGet() failed: %s\n", errorBuffer); 279 return -1; 280 } 281 // Copy the segment into the TX buffer 282 memcpy(NT_NET_GET_SEGMENT_PTR(hNetBufTx), NT_NET_GET_SEGMENT_PTR(hNetBufFile), NT_NET_GET_SEGMENT_LENGTH(hNetBufFile)); 283 284 // Build a packet netbuf structure 285 _nt_net_build_pkt_netbuf(hNetBufTx, &pktNetBuf); 286 287 // Optional step. Here all packets are inspected before sent 288 if(NT_NET_GET_SEGMENT_LENGTH(hNetBufTx)) { 289 do { 290 // Just count the amount of packets and wire length 291 numPackets++; 292 numBytes+=NT_NET_GET_PKT_WIRE_LENGTH((&pktNetBuf)); 293 } while(_nt_net_get_next_packet(hNetBufTx, 294 NT_NET_GET_SEGMENT_LENGTH(hNetBufTx), 295 &pktNetBuf)>0); 296 } 297 // Release the TX buffer and the packets within the segment will be transmitted 298 if((status = NT_NetTxRelease(hNetTx, hNetBufTx)) != NT_SUCCESS) { 299 // Get the status code as text 300 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 301 fprintf(stderr, "NT_NetTxRelease() failed: %s\n", errorBuffer); 302 return -1; 303 } 304 // Release the file packet 305 if((status = NT_NetFileRelease(hNetFile, hNetBufFile)) != NT_SUCCESS) { 306 // Get the status code as text 307 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 308 fprintf(stderr, "NT_NetFileRelease() failed: %s\n", errorBuffer); 309 return -1; 310 } 311 } 312 313 // Wait until all packets should have been sent 314 while(1) { 315 // Read the adapter time 316 configRead.parm = NT_CONFIG_PARM_ADAPTER_TIMESTAMP; 317 configRead.u.timestampRead.adapter = PORT; 318 if ((status = NT_ConfigRead(hConfig, &configRead)) != NT_SUCCESS) { 319 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 320 fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer); 321 NT_ConfigClose(hConfig); 322 return 0; 323 } 324 325 adapterTS = configRead.u.timestampRead.data.nativeUnixTs * 10; // Convert 10ns ticks to 1ns 326 327 if (adapterTS > (lastPacketTS + timeDelta)) { 328 // The last packet should be sending now 329 break; 330 } 331 332 sleep(1); 333 } 334 335 // Close the file stream 336 NT_NetFileClose(hNetFile); 337 338 // Close the TX stream 339 NT_NetTxClose(hNetTx); 340 341 342 // Disable transmit on timestamp 343 configWrite.parm = NT_CONFIG_PARM_PORT_TRANSMIT_ON_TIMESTAMP; 344 configWrite.u.transmitOnTimestamp.portNo = (uint8_t) PORT; 345 configWrite.u.transmitOnTimestamp.data.timeDelta = 0; 346 configWrite.u.transmitOnTimestamp.data.enable = false; 347 configWrite.u.transmitOnTimestamp.data.forceTxOnTs = false; 348 if ((status = NT_ConfigWrite(hConfig, &configWrite)) != NT_SUCCESS) { 349 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)-1); 350 fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer); 351 NT_ConfigClose(hConfig); 352 return 0; 353 } 354 355 // Close the config stream 356 NT_ConfigClose(hConfig); 357 358 printf("Done: %d packets %d bytes has been replayed\n", numPackets, numBytes); 359 return 0; 360}