replay4ga_largefile_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_largefile/replay4ga_largefile_example.c Source File
replay4ga_largefile_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 // Include this in order to access the Napatech API
45 #include <nt.h>
46 
47 #if defined(__linux__) || defined(__FreeBSD__)
48  #include <unistd.h> // sleep()
49 #endif
50 
51 #include <argparse.h>
52 #include <signal.h>
53 
54 #define ONEMBIT (1000000ULL)
55 
56 /**
57  * Print command line info
58  */
59 static const char *usageText[] = {
60  "Syntax:\n"
61  "replay4ga_largefile_example [-h][-p <port no.>][-f <file name>]\n"
62  "Example: replay4ga_largefile_example -p 1 -f mycapture.cap\n",
63  NULL
64 };
65 
66 static int opt_port = 0;
67 static char *opt_filename;
68 
69 static int appRunning = 1;
70 
71 /**
72  * Table of valid options.
73  */
75  OPT_HELP(),
76  OPT_INTEGER('p', "port", &opt_port, "Tx port", NULL, 0, 0, "port number"),
77  OPT_STRING('f', "filename", &opt_filename, "File name\n", NULL, 0, 0, "value"),
78  OPT_END(),
79 };
80 
81 
82 /**
83  * The function called when user is pressing CTRL-C
84  */
85 #if defined(WIN32) || defined (WIN64)
86 static BOOL WINAPI
87 StopApplication(int sig)
88 #else
89 static void
91 #endif
92 {
93 #ifdef WIN32
94  // Force the application to stop.
95  appRunning = 0;
96  return TRUE;
97 #else
98  if (sig == SIGINT)
99  // Force the application to stop.
100  appRunning = 0;
101 #endif
102 }
103 
104 
105 int
106 main(int argc, const char **argv)
107 {
108  char errorBuffer[NT_ERRBUF_SIZE]; // Error buffer
109  int status; // Status variable
110  NtNetStreamFile_t hNetFile; // Handle to the File stream
111  NtNetBuf_t hNetBufFile; // Net buffer container. Used to return segments from the file stream
112  NtNetStreamTx_t hNetTx; // Handle to the TX stream
113  NtNetBuf_t hNetBufTx; // Net buffer container. Used when getting a transmit buffer
114  NtInfoStream_t hInfo; // Handle to a info stream
115  NtInfo_t infoRead; // Buffer to hold data from infostream
116  NtConfigStream_t hConfig; // Handle to a config stream
117  NtConfig_t configRead; // Config stream data container
118  NtConfig_t configWrite; // Config stream data container
119  uint8_t adapterNo; // Adapter no
120  uint64_t firstPacketTS = 0; // Timestamp of first packet
121  uint64_t lastPacketTS = 0; // Timestamp of last packet
122  uint64_t adapterTS = 0; // Timestamp on the adapter
123  uint64_t timeDelta = 0; // Calculated time delta
124  uint64_t timeDeltaAdjust = 0; // Calculated time delta adjust
125  uint64_t speed; // Tx port speed
126  uint64_t tx_time_for_last_pkt; // Calculated transmission time for last packet
127  uint64_t segment_length = 0;
128  uint64_t last_segment_length = 0;
129 
130  struct argparse argparse;
131  int last_pkt_size = 0;
132 
133  // Register ctrl+c handler so we are able to stop again
134 #if defined(WIN32) || defined (WIN64)
135  SetConsoleCtrlHandler((PHANDLER_ROUTINE) StopApplication, TRUE);
136 #else
137  struct sigaction newaction; // Ctrl+c signal handler container
138  memset(&newaction, 0, sizeof(newaction));
139  newaction.sa_handler = StopApplication;
140  if (sigaction(SIGINT, &newaction, NULL) < 0) {
141  fprintf(stderr, "Failed to register SIGINT sigaction.\n");
142  exit(-1);
143  }
144 #endif
145 
146  argparse_init(&argparse, arg_options, usageText, 0);
147  argparse_parse(&argparse, argc, argv);
148 
149  // Initialize the NTAPI library and thereby check if NTAPI_VERSION can be used together with this library
150  if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
151  // Get the status code as text
152  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
153  fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
154  return -1;
155  }
156 
157  // Open the infostream.
158  if ((status = NT_InfoOpen(&hInfo, "replay")) != NT_SUCCESS) {
159  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
160  fprintf(stderr, "NT_InfoOpen() failed: %s\n", errorBuffer);
161  return -1;
162  }
163 
164  // Check whether or not TX is supported on the defined port
165  infoRead.cmd = NT_INFO_CMD_READ_PORT_V9;
166  infoRead.u.port_v9.portNo = (uint8_t)opt_port; // TX port
167  if ((status = NT_InfoRead(hInfo, &infoRead)) != NT_SUCCESS) {
168  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
169  fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer);
170  NT_InfoClose(hInfo);
171  return -1;
172  }
173 
174  // read port speed to use for calculating transmission time for last packet
175  switch (infoRead.u.port_v9.data.speed)
176  {
177 
178  case NT_LINK_SPEED_10M:
179  speed = 10ULL * ONEMBIT;
180  break;
181  case NT_LINK_SPEED_100M:
182  speed = 100ULL * ONEMBIT;
183  break;
184  case NT_LINK_SPEED_1G:
185  speed = 1000ULL * ONEMBIT;
186  break;
187  case NT_LINK_SPEED_10G:
188  speed = 10000ULL * ONEMBIT;
189  break;
190  case NT_LINK_SPEED_40G:
191  speed = 40000ULL * ONEMBIT;
192  break;
193  case NT_LINK_SPEED_100G:
194  speed = 100000ULL * ONEMBIT;
195  break;
196  default:
197  fprintf(stderr, "BUG: Unhandled port speed\n");
198  NT_InfoClose(hInfo);
199  return -1;
200  }
201 
202  if (infoRead.u.port_v9.data.state == NT_LINK_STATE_DOWN) {
203  fprintf(stderr, "Port %d has no link\n", opt_port);
204  NT_InfoClose(hInfo);
205  return -1;
206  }
207 
209  fprintf(stderr, "Transmit is not possible on the selected port %d\n", opt_port);
210  NT_InfoClose(hInfo);
211  return -1;
212  }
213 
214  // save adapter number of the TX port
215  adapterNo = infoRead.u.port_v9.data.adapterNo;
216  NT_InfoClose(hInfo);
217 
218  uint64_t totalSize = 0;
219  uint64_t totalSegments = 0;
220 
221  // Open the capture file to replay - for this purpose, just open it in PACKET mode and read packet by packet.
222  if ((status = NT_NetFileOpen(&hNetFile, "FileStream", NT_NET_INTERFACE_SEGMENT, opt_filename)) != NT_SUCCESS) {
223  // Get the status code as text
224  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
225  fprintf(stderr, "NT_NetFileOpen() failed: %s\n", errorBuffer);
226  return -1;
227  }
228 
229  // Issue get so we can read first packet timstamp
230  if ((status = NT_NetFileGet(hNetFile, &hNetBufFile)) != NT_SUCCESS) {
231  if (status == NT_STATUS_END_OF_FILE) {
232  fprintf(stderr, "The file %s has no data\n", opt_filename);
233  return -1;
234  }
235  }
236 
237  firstPacketTS = NT_NET_GET_PKT_TIMESTAMP(hNetBufFile) * 10;
238  totalSize += NT_NET_GET_SEGMENT_LENGTH(hNetBufFile);
239  totalSegments ++;
240 
241  do {
242  status = NT_NetFileGet(hNetFile, &hNetBufFile);
243  if (status != NT_STATUS_END_OF_FILE) {
244  lastPacketTS = NT_NET_GET_PKT_TIMESTAMP(hNetBufFile) * 10;
245  last_pkt_size = NT_NET_GET_PKT_WIRE_LENGTH(hNetBufFile) + 20;
246  totalSize += NT_NET_GET_SEGMENT_LENGTH(hNetBufFile);
247  totalSegments ++;
248  }
249  }
250  while (status != NT_STATUS_END_OF_FILE);
251 
252  // Close the file again. We will open it again later to actually transmit packets.
253  NT_NetFileClose(hNetFile);
254 
255  // Open the config stream
256  if ((status = NT_ConfigOpen(&hConfig, "replay")) != NT_SUCCESS) {
257  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
258  fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
259  NT_ConfigClose(hConfig);
260  return -1;
261  }
262 
263  // Open the capture file to replay
264  if ((status = NT_NetFileOpen(&hNetFile, "FileStream", NT_NET_INTERFACE_SEGMENT, opt_filename)) != NT_SUCCESS) {
265  // Get the status code as text
266  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
267  fprintf(stderr, "NT_NetFileOpen() failed: %s\n", errorBuffer);
268  return -1;
269  }
270 
271  uint64_t requiredHostbuffer = totalSize / (1024UL * 1024UL);
272  printf("Required host buffer: %lu MiB (Actual size: %lu MiB)\n", totalSegments, requiredHostbuffer);
273  // Open a TX hostbuffer from TX host buffer pool on the NUMA node of the adapter with the defined port
274  //if ((status = NT_NetTxOpen_v3(&hNetTx, "TxStreamPort", (0x1 << opt_port), NT_NETTX_NUMA_ADAPTER_HB, totalSize, NT_PACKET_DESCRIPTOR_TYPE_NT, NT_TIMESTAMP_TYPE_NATIVE_UNIX)) != NT_SUCCESS) {
275  if ((status = NT_NetTxOpen(&hNetTx, "TxStreamPort", 1ULL << opt_port, NT_NETTX_NUMA_ADAPTER_HB, (uint32_t)totalSegments)) != NT_SUCCESS) {
276  // Get the status code as text
277  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
278  fprintf(stderr, "NT_NetTxOpen() failed: %s\n", errorBuffer);
279  return -1;
280  }
281 
282  //Read the adapter time
284  configRead.u.timestampRead.adapter = adapterNo;
285  if ((status = NT_ConfigRead(hConfig, &configRead)) != NT_SUCCESS) {
286  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
287  fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer);
288  NT_ConfigClose(hConfig);
289  return -1;
290  }
291  adapterTS = configRead.u.timestampRead.data.nativeUnixTs * 10; // Convert 10ns ticks to 1ns
292 
293  // last frame time stamp - first frame time stamp + estimated transmission time for last frame
294  tx_time_for_last_pkt = (last_pkt_size * 8 * 100000000ULL) / speed;
295  timeDeltaAdjust = lastPacketTS - firstPacketTS + tx_time_for_last_pkt;
296 
297  // Start transfer 10 seconds from now
298  timeDelta = (adapterTS - firstPacketTS) + 10000000000UL;
299  printf("Transfer starts in 10 seconds from now\n");
300 
301  // Configure transmit on timestamp
303  configWrite.u.transmitOnTimestamp.portNo = (uint8_t) opt_port;
304  configWrite.u.transmitOnTimestamp.data.timeDelta = timeDelta;
305  configWrite.u.transmitOnTimestamp.data.timeDeltaAdjust = timeDeltaAdjust;
306  configWrite.u.transmitOnTimestamp.data.enable = true;
307  configWrite.u.transmitOnTimestamp.data.forceTxOnTs = false;
308  if ((status = NT_ConfigWrite(hConfig, &configWrite)) != NT_SUCCESS) {
309  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
310  fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer);
311  NT_ConfigClose(hConfig);
312  return 0;
313  }
314 
315  printf("Capture file duration: %.01fs\n", (double)timeDeltaAdjust / 1000000000);
316  printf("NOTICE: First repetition may be slower than capture rate!\n");
317 
318  NtNetBuf_t *netBufs = malloc(totalSegments * sizeof(NtNetBuf_t));
319  if (netBufs == NULL) {
320  fprintf(stderr, "Could not allocate tx segment pointer array\n");
321  return -1;
322  }
323 
324  for (uint32_t i = 0; i < totalSegments; i++) {
325  if ((status = NT_NetFileGet(hNetFile, &hNetBufFile)) != NT_SUCCESS) {
326  // Get the status code as text
327  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
328  fprintf(stderr, "NT_NetFileGet() failed: %s\n", errorBuffer);
329  goto ExitError;
330  }
331 
332  if ((status = NT_NetTxGet(hNetTx, &netBufs[i], opt_port, NT_NET_GET_SEGMENT_LENGTH(hNetBufFile), NT_NETTX_SEGMENT_OPTION_RAW, -1))) {
333  // Get the status code as text
334  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
335  fprintf(stderr, "NT_NetTxGet() failed: %s\n", errorBuffer);
336  goto ExitError;
337  }
338 
339  if (i == totalSegments - 1)
340  last_segment_length = NT_NET_GET_SEGMENT_LENGTH(hNetBufFile);
341  else
342  segment_length = NT_NET_GET_SEGMENT_LENGTH(hNetBufFile);
343 
344  memcpy(NT_NET_GET_SEGMENT_PTR(netBufs[i]), NT_NET_GET_SEGMENT_PTR(hNetBufFile), NT_NET_GET_SEGMENT_LENGTH(hNetBufFile));
345 
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  goto ExitError;
351  }
352 
353  // Due to a potential bug, tx segments are released right after filling,
354  // resulting in potentially slower initial transmit
355  if ((status = NT_NetTxRelease(hNetTx, netBufs[i])) != NT_SUCCESS) {
356  // Get the status code as text
357  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
358  fprintf(stderr, "NT_NetTxRelease() failed: %s\n", errorBuffer);
359  goto ExitError;
360  }
361  }
362 
363  // Close the file stream
364  NT_NetFileClose(hNetFile);
365 
366  // // Release the loaded tx segments
367  // for (uint32_t i = 0; i < totalSegments; i++) {
368  // if ((status = NT_NetTxRelease(hNetTx, netBufs[i])) != NT_SUCCESS) {
369  // // Get the status code as text
370  // NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
371  // fprintf(stderr, "NT_NetTxRelease() failed: %s\n", errorBuffer);
372  // return -1;
373  // }
374  // }
375 
376  // Get segments from the file and transmit them to defined port
377  while (appRunning) {
378  for (uint32_t i = 0; i < totalSegments; i++) {
379 
380  // Get a TX buffer for this segment
381  do {
382  uint64_t segmentLen = i + 1 == totalSegments ? last_segment_length : segment_length;
383  status = NT_NetTxGet(hNetTx, &hNetBufTx, opt_port, segmentLen, NT_NETTX_SEGMENT_OPTION_RAW, 100);
384 
385  if ((status != NT_SUCCESS) && (status != NT_STATUS_TIMEOUT)) {
386  // Get the status code as text
387  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
388  fprintf(stderr, "NT_NetFileGet() failed: %s\n", errorBuffer);
389  goto ExitError;
390  }
391  } while (status == NT_STATUS_TIMEOUT);
392 
393  if (i == 0) {
394  NT_NET_SET_PKT_TXSETCLOCK(hNetBufTx, 1);
395  }
396 
397  // Release the TX buffer and the packets within the segment will be transmitted
398  if ((status = NT_NetTxRelease(hNetTx, hNetBufTx)) != NT_SUCCESS) {
399  // Get the status code as text
400  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
401  fprintf(stderr, "NT_NetTxRelease() failed: %s\n", errorBuffer);
402  goto ExitError;
403  }
404  }
405  }
406 
407  // Close the TX stream
408  NT_NetTxClose(hNetTx);
409 
410  // Disable transmit on timestamp
412  configWrite.u.transmitOnTimestamp.portNo = (uint8_t) opt_port;
413  configWrite.u.transmitOnTimestamp.data.timeDelta = 0;
414  configWrite.u.transmitOnTimestamp.data.enable = false;
415  configWrite.u.transmitOnTimestamp.data.forceTxOnTs = false;
416  if ((status = NT_ConfigWrite(hConfig, &configWrite)) != NT_SUCCESS) {
417  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
418  fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer);
419  NT_ConfigClose(hConfig);
420  goto ExitError;
421  }
422 
423  // Close the config stream
424  NT_ConfigClose(hConfig);
425 
426  free(netBufs);
427  return 0;
428 
429 ExitError:
430  if (netBufs) {
431  free(netBufs);
432  }
433  return -1;
434 }