replay4ga_example.c Source File

Reference Documentation

Platform
Napatech SmartNIC
Content Type
Reference Information
Capture Software Version
Link™ Capture Software 12.15
Napatech Software Suite: examples/net/replay4GA/replay4ga_example.c Source File
replay4ga_example.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2025 Napatech A/S. All Rights Reserved.
4  *
5  * 1. Copying, modification, and distribution of this file, or executable
6  * versions of this file, is governed by the terms of the Napatech Software
7  * license agreement under which this file was made available. If you do not
8  * agree to the terms of the license do not install, copy, access or
9  * otherwise use this file.
10  *
11  * 2. Under the Napatech Software license agreement you are granted a
12  * limited, non-exclusive, non-assignable, copyright license to copy, modify
13  * and distribute this file in conjunction with Napatech SmartNIC's and
14  * similar hardware manufactured or supplied by Napatech A/S.
15  *
16  * 3. The full Napatech Software License Agreement is included in this
17  * distribution, please see "NA-0009 Software License Agreement.pdf"
18  *
19  * 4. Redistributions of source code must retain this copyright notice,
20  * list of conditions and the following disclaimer.
21  *
22  * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, EXPRESS OR
23  * IMPLIED, AND NAPATECH DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING ANY
24  * IMPLIED WARRANTY OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, OR OF
25  * FITNESS FOR A PARTICULAR PURPOSE. TO THE EXTENT NOT PROHIBITED BY
26  * APPLICABLE LAW, IN NO EVENT SHALL NAPATECH BE LIABLE FOR PERSONAL INJURY,
27  * OR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER,
28  * INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, CORRUPTION OR
29  * LOSS OF DATA, FAILURE TO TRANSMIT OR RECEIVE ANY DATA OR INFORMATION,
30  * BUSINESS INTERRUPTION OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING
31  * OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE NAPATECH SOFTWARE OR
32  * SERVICES OR ANY THIRD PARTY SOFTWARE OR APPLICATIONS IN CONJUNCTION WITH
33  * THE NAPATECH SOFTWARE OR SERVICES, HOWEVER CAUSED, REGARDLESS OF THE THEORY
34  * OF LIABILITY (CONTRACT, TORT OR OTHERWISE) AND EVEN IF NAPATECH HAS BEEN
35  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW
36  * THE EXCLUSION OR LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF
37  * INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU.
38  *
39  *
40 
41  */
42 
43 /**
44  * @example net/replay4GA/replay4ga_example.c
45  * @section replay4ga_example_description Description
46  *
47  * This source file is an example of how to replay a capture file onto
48  * a port using NTAPI when using a 4GA transmit on timestamp adapter.
49  *
50  * The following NTAPI functions are used:
51  * - @ref NT_Init()
52  * - @ref NT_ConfigOpen()
53  * - @ref NT_ConfigRead()
54  * - @ref NT_ConfigWrite()
55  * - @ref NT_ConfigClose()
56  * - @ref NT_InfoOpen()
57  * - @ref NT_InfoRead()
58  * - @ref NT_InfoClose()
59  * - @ref NT_NetFileOpen()
60  * - @ref NT_NetTxOpen()
61  * - @ref NT_NTPL()
62  * - @ref NT_NetFileGet()
63  * - @ref NT_NetTxGet()
64  * - @ref NT_NET_GET_SEGMENT_PTR()
65  * - @ref NT_NET_GET_SEGMENT_LENGTH()
66  * - @ref NT_NetTxRelease()
67  * - @ref NT_NetFileRelease()
68  * - @ref NT_NetFileClose()
69  * - @ref NT_NetTxClose()
70  * - @ref NT_ExplainError()
71  *
72  * @section replay4ga_example_prerequisites Prerequisites
73  * - Capture file, capfile.ntcap, that has been captured with the @ref
74  * net/capture/capture_example.c "net/capture/capture_example.c" example.
75  * - A fourth generation adapter supporting transmit on timestamp.
76  * - The ntservice.ini must have at least one HostBuffersTx
77  * defined. Below is an example of a minimum ini-file. It will
78  * create a 32MB TX hostbuffer from NUMA node 0.
79  * @code
80  * [System]
81  * TimestampFormat = NATIVE
82  *
83  * [Adapter0]
84  * AdapterType = NT20E2
85  * BusId = 00:0a:00.00
86  * HostBuffersTx = [1,32,0]
87  * @endcode
88  *
89  * @section replay4ga_example_flow Program flow
90  * @{
91  * The following is required to perform replay of a captured file:
92  * - \#include/nt.h - Applications/Tools only need to include @ref
93  * nt.h to obtain prototypes, macros etc. from NTAPI.
94  * - \#include/unistd.h - sleep()
95  * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI
96  * library. @ref NTAPI_VERSION is a define that describes the version
97  * of the API described in the header files included by @ref
98  * nt.h. NT_Init() will ask the NTAPI library to convert return data
99  * to the @ref NTAPI_VERSION if possible. This will ensure that
100  * applications can run on NTAPI libraries of newer versions.
101  * - @ref NT_ConfigOpen() - Open the configuration stream.
102  * - @ref NT_ConfigRead() - Read from the configuration stream to fetch the
103  * adapter timestamp.
104  * - @ref NT_ConfigWrite() - Write to the configuration stream to set transmit
105  * on timestamp configuration.
106  * - @ref NT_ConfigClose() - Close the configuration stream.
107  * - @ref NT_InfoOpen() - Open the information stream.
108  * - @ref NT_InfoRead() - Read the adapter information to check whether or not
109  * we are using absolut TX timing. The @ref NtTxTimingMethod_e "txTiming"
110  * tells whether relative or absolut TX timing is enabled.
111  * - @ref NT_InfoClose() - Close the information stream.
112  * - @ref NT_NetFileOpen() - Open the captured file and assign it to a stream.
113  * - @ref NT_NetTxOpen() - Open a hostbuffer than can transmit packets to port 0.
114  * - @ref NT_NetFileGet() - Get a segment from the file. This call will
115  * return @ref NT_SUCCESS upon return of a segment and
116  * @ref NT_STATUS_END_OF_FILE when there is no more segments
117  * avaialble. The latter will cause the example to exit.
118  * - @ref NT_NetTxGet() - Get an empty tx buffer. This will get a segment of the
119  * requested length from the hostbuffer that will be sent
120  * onto port 0 when the buffer is released.
121  * - @ref NT_NET_GET_SEGMENT_PTR() and @ref NT_NET_GET_SEGMENT_LENGTH() are used
122  * to tell where the segment data is located and how much there is.
123  * _nt_net_build_pkt_netbuf() and _nt_net_get_next_packet() are used to traverse
124  * packets inside a segment. This is usefull if ie. the timing of the packet
125  * transmit rate needs to be changed.
126  * - @ref NT_NetTxRelease() - Release the segment buffer. Once a tx
127  * buffer is released it will be transmitted according to the
128  * timestamps of the packets in the segment.
129  * - @ref NT_NetFileRelease() - Release the segment from the file stream.
130  * - @ref NT_NetFileClose() - Close the file stream when no more segments can be found.
131  * - @ref NT_NetTxClose() - Close the TX stream.
132  *
133  *<hr>
134  * @section replay4ga_example_code Code
135  * @}
136  */
137 
138 // Include this in order to access the Napatech API
139 #include <nt.h>
140 
141 #if defined(__linux__) || defined(__FreeBSD__) || (__MINGW32__)
142  #include <unistd.h> // sleep()
143  #include <string.h> // memcpy
144 #endif
145 
146 #if defined(_MSC_VER)
147  #include <timesupport.h>
148 #endif
149 
150 // default setup
151 #define PORT 0
152 
153 int main(void)
154 {
155  int numPackets=0; // The number of packets replayed
156  int numBytes=0; // The number of bytes replayed
157  char errorBuffer[NT_ERRBUF_SIZE]; // Error buffer
158  int status; // Status variable
159  NtNetStreamFile_t hNetFile; // Handle to the File stream
160  NtNetBuf_t hNetBufFile; // Net buffer container. Used to return segments from the file stream
161  NtNetStreamTx_t hNetTx; // Handle to the TX stream
162  NtNetBuf_t hNetBufTx; // Net buffer container. Used when getting a transmit buffer
163  NtInfoStream_t hInfo; // Handle to a info stream
164  NtInfo_t infoRead; // Buffer to hold data from infostream
165  NtConfigStream_t hConfig; // Handle to a config stream
166  NtConfig_t configRead; // Config stream data container
167  NtConfig_t configWrite; // Config stream data container
168  struct NtNetBuf_s pktNetBuf; // Packet netbuf structure.
169  uint8_t adapterNo; // Adapter no
170  uint64_t firstPacketTS=0; // Timestamp of first packet
171  uint64_t lastPacketTS=0; // Timestamp of last packet
172  uint64_t adapterTS=0; // Timestamp on the adapter
173  uint64_t timeDelta=0; // Calculated time delta
174 
175  // Initialize the NTAPI library and thereby check if NTAPI_VERSION can be used together with this library
176  if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
177  // Get the status code as text
178  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
179  fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
180  return -1;
181  }
182 
183  // Open the infostream.
184  if ((status = NT_InfoOpen(&hInfo, "replay")) != NT_SUCCESS) {
185  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
186  fprintf(stderr, "NT_InfoOpen() failed: %s\n", errorBuffer);
187  return -1;
188  }
189 
190  // Check whether or not TX is supported on the defined port
191  infoRead.cmd = NT_INFO_CMD_READ_PORT_V10;
192  infoRead.u.port_v10.portNo=PORT; // TX port is hardcoded to defined PORT
193  if ((status = NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) {
194  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
195  fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer);
196  NT_InfoClose(hInfo);
197  return -1;
198  }
199 
201  fprintf(stderr, "Transmit is not possible on the selected port %d\n",PORT);
202  NT_InfoClose(hInfo);
203  return -1;
204  }
205 
206  // Check whether or not absolut TX timing is supported
207  adapterNo = infoRead.u.port_v10.data.adapterNo;
208  infoRead.cmd = NT_INFO_CMD_READ_ADAPTER_V7;
209  infoRead.u.adapter_v7.adapterNo=adapterNo; // Adapter is derived from PORT of adapter
210  if ((status = NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) {
211  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
212  fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer);
213  NT_InfoClose(hInfo);
214  return -1;
215  }
216 
217  NT_InfoClose(hInfo);
218 
219  // Open the capture file to replay (captured with the capture example)
220  if ((status = NT_NetFileOpen(&hNetFile, "FileStream", NT_NET_INTERFACE_SEGMENT, "capfile.ntcap")) != NT_SUCCESS) {
221  // Get the status code as text
222  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
223  fprintf(stderr, "NT_NetFileOpen() failed: %s\n", errorBuffer);
224  return -1;
225  }
226 
227  // Read one segment from the file to get the first packet timestamp
228  if ((status = NT_NetFileGet(hNetFile, &hNetBufFile)) != NT_SUCCESS) {
229  if (status == NT_STATUS_END_OF_FILE) {
230  fprintf(stderr, "The file %s has no data\n", "capfile.ntpcap");
231  return -1;
232  }
233  }
234  _nt_net_build_pkt_netbuf(hNetBufFile, &pktNetBuf);
235  firstPacketTS = NT_NET_GET_PKT_TIMESTAMP(&pktNetBuf) * 10; // Convert 10ns ticks to 1ns
236 
237  // Close the file again. We will open it again later to actually transmit packets.
238  NT_NetFileClose(hNetFile);
239 
240  // Open the config stream
241  if ((status = NT_ConfigOpen(&hConfig, "replay")) != NT_SUCCESS) {
242  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
243  fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
244  NT_ConfigClose(hConfig);
245  return 0;
246  }
247 
248  // Read the adapter time
250  configRead.u.timestampRead.adapter = PORT;
251  if ((status = NT_ConfigRead(hConfig, &configRead)) != NT_SUCCESS) {
252  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
253  fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer);
254  NT_ConfigClose(hConfig);
255  return 0;
256  }
257  adapterTS = configRead.u.timestampRead.data.nativeUnixTs * 10; // Convert 10ns ticks to 1ns
258 
259  // Calculate time delta - we add 1 second to give ourselves some headroom
260  timeDelta = (adapterTS - firstPacketTS) + 1000000000;
261 
262  // Configure transmit on timestamp
264  configWrite.u.transmitOnTimestamp.portNo = (uint8_t) PORT;
265  configWrite.u.transmitOnTimestamp.data.timeDelta = timeDelta;
266  configWrite.u.transmitOnTimestamp.data.enable = true;
267  configWrite.u.transmitOnTimestamp.data.forceTxOnTs = true;
268  if ((status = NT_ConfigWrite(hConfig, &configWrite)) != NT_SUCCESS) {
269  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
270  fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer);
271  NT_ConfigClose(hConfig);
272  return 0;
273  }
274 
275  // Open the capture file to replay (captured with the capture example)
276  if ((status = NT_NetFileOpen(&hNetFile, "FileStream", NT_NET_INTERFACE_SEGMENT, "capfile.ntcap")) != NT_SUCCESS) {
277  // Get the status code as text
278  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
279  fprintf(stderr, "NT_NetFileOpen() failed: %s\n", errorBuffer);
280  return -1;
281  }
282 
283  // Open a TX hostbuffer from TX host buffer pool on the NUMA node of the adapter with the defined PORT
284  if ((status = NT_NetTxOpen(&hNetTx, "TxStreamPort", 1ULL << PORT, NT_NETTX_NUMA_ADAPTER_HB, 0)) != NT_SUCCESS) {
285  // Get the status code as text
286  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
287  fprintf(stderr, "NT_NetTxOpen() failed: %s\n", errorBuffer);
288  return -1;
289  }
290 
291  // Get segments from the file and transmit them to defined PORT
292  while (1) {
293  printf("Getting segment.\n");
294  // Get the packet
295  if ((status = NT_NetFileGet(hNetFile, &hNetBufFile)) != NT_SUCCESS) {
296  if (status == NT_STATUS_END_OF_FILE) {
297  // The file has no more data
298  break;
299  }
300  // Get the status code as text
301  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
302  fprintf(stderr, "NT_NetFileGet() failed: %s\n", errorBuffer);
303  return -1;
304  }
305 
306  NtNetFileRead_t fileRead;
307  fileRead.cmd = NT_NETFILE_READ_INFO_CMD_V1;
308  if ((status = NT_NetFileRead(hNetFile, &fileRead)) != NT_SUCCESS) {
309  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
310  fprintf(stderr, "NT_NetfileRead() failed: %s\n", errorBuffer);
311  return -1;
312  }
313  lastPacketTS = fileRead.u.info_v1.lastTimestamp * 10;
314 
315  // Get a TX buffer for this segment
316  if ((status = NT_NetTxGet(hNetTx, &hNetBufTx, PORT, NT_NET_GET_SEGMENT_LENGTH(hNetBufFile), NT_NETTX_SEGMENT_OPTION_RAW, -1 /* wait forever */)) != NT_SUCCESS) {
317  // Get the status code as text
318  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
319  fprintf(stderr, "NT_NetFileGet() failed: %s\n", errorBuffer);
320  return -1;
321  }
322  // Copy the segment into the TX buffer
323  memcpy(NT_NET_GET_SEGMENT_PTR(hNetBufTx), NT_NET_GET_SEGMENT_PTR(hNetBufFile), NT_NET_GET_SEGMENT_LENGTH(hNetBufFile));
324 
325  // Build a packet netbuf structure
326  _nt_net_build_pkt_netbuf(hNetBufTx, &pktNetBuf);
327 
328  // Optional step. Here all packets are inspected before sent
329  if (NT_NET_GET_SEGMENT_LENGTH(hNetBufTx)) {
330  do {
331  // Just count the amount of packets and wire length
332  numPackets++;
333  numBytes+=NT_NET_GET_PKT_WIRE_LENGTH((&pktNetBuf));
334  } while (_nt_net_get_next_packet(hNetBufTx,
335  NT_NET_GET_SEGMENT_LENGTH(hNetBufTx),
336  &pktNetBuf)>0);
337  }
338  // Release the TX buffer and the packets within the segment will be transmitted
339  if ((status = NT_NetTxRelease(hNetTx, hNetBufTx)) != NT_SUCCESS) {
340  // Get the status code as text
341  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
342  fprintf(stderr, "NT_NetTxRelease() failed: %s\n", errorBuffer);
343  return -1;
344  }
345  // Release the file packet
346  if ((status = NT_NetFileRelease(hNetFile, hNetBufFile)) != NT_SUCCESS) {
347  // Get the status code as text
348  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
349  fprintf(stderr, "NT_NetFileRelease() failed: %s\n", errorBuffer);
350  return -1;
351  }
352  }
353 
354  // Wait until all packets should have been sent
355  while (1) {
356  // Read the adapter time
358  configRead.u.timestampRead.adapter = PORT;
359  if ((status = NT_ConfigRead(hConfig, &configRead)) != NT_SUCCESS) {
360  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
361  fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer);
362  NT_ConfigClose(hConfig);
363  return 0;
364  }
365 
366  adapterTS = configRead.u.timestampRead.data.nativeUnixTs * 10; // Convert 10ns ticks to 1ns
367 
368  if (adapterTS > (lastPacketTS + timeDelta)) {
369  // The last packet should be sending now
370  break;
371  }
372 
373  sleep(1);
374  }
375 
376  // Close the file stream
377  NT_NetFileClose(hNetFile);
378 
379  // Close the TX stream
380  NT_NetTxClose(hNetTx);
381 
382 
383  // Disable transmit on timestamp
385  configWrite.u.transmitOnTimestamp.portNo = (uint8_t) PORT;
386  configWrite.u.transmitOnTimestamp.data.timeDelta = 0;
387  configWrite.u.transmitOnTimestamp.data.enable = false;
388  configWrite.u.transmitOnTimestamp.data.forceTxOnTs = false;
389  if ((status = NT_ConfigWrite(hConfig, &configWrite)) != NT_SUCCESS) {
390  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
391  fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer);
392  NT_ConfigClose(hConfig);
393  return 0;
394  }
395 
396  // Close the config stream
397  NT_ConfigClose(hConfig);
398 
399  printf("Done: %d packets %d bytes has been replayed\n", numPackets, numBytes);
400  return 0;
401 }