replay4ga_example.c Source File

Reference Documentation

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