transmit_on_timestamp_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/transmit_on_timestamp/transmit_on_timestamp_example.c Source File
transmit_on_timestamp_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/transmit_on_timestamp/transmit_on_timestamp_example.c
45  * @section transmit_on_timestamp_example_description Description
46  *
47  * This source file is an example of how to transmit packets on timestamp
48  * using the packet interface in NTAPI. The example will transmit 100000
49  * packets with a size of 296 bytes from port 0 at a rate of approximately
50  * 5 Mb/s. The packet contains an incrementing 32bit pattern.
51  *
52  * The transmit on timestamp functionality is also available in segment mode.
53  * See the @ref net/transmit_segment/transmit_segment_example.c example code
54  * to see how to use the segment interface.
55  *
56  * The following NTAPI functions are used:
57  * - @ref NT_Init()
58  * - @ref NT_ConfigOpen()
59  * - @ref NT_ConfigRead()
60  * - @ref NT_ConfigWrite()
61  * - @ref NT_ConfigClose()
62  * - @ref NT_NetTxOpen()
63  * - @ref NT_NetTxGet()
64  * - @ref NT_NET_SET_PKT_TIMESTAMP()
65  * - @ref NT_NET_GET_PKT_L2_PTR()
66  * - @ref NT_NetTxRelease()
67  * - @ref NT_NetTxClose()
68  * - @ref NT_Done()
69  * - @ref NT_ExplainError()
70  *
71  * @section transmit_on_timestamp_example_prerequisites Prerequisites
72  * - This example is only compatible with adapters supporting 4GA transmit on
73  * timestamp.
74  * - The ntservice.ini must have at least one HostBuffersTx defined. Below is
75  * an example of a minimum ini-file. It will create a 4MB TX hostbuffer from
76  * NUMA node 0.
77  *
78  * @code
79  * [System]
80  * TimestampFormat = NATIVE
81  *
82  * [Adapter0]
83  * AdapterType = NT20E2
84  * BusId = 00:0a:00.00
85  * HostBuffersTx = [1,4,0]
86  * @endcode
87  *
88  * @section transmit_on_timestamp_example_flow Program flow
89  * @{
90  * The following is required to transmit packets:
91  * - \#include/nt.h - Applications/Tools only need to include @ref
92  * nt.h to obtain prototypes, macros etc. from NTAPI.
93  * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI
94  * library. @ref NTAPI_VERSION is a define that describes the version
95  * of the API described in the header files included by @ref
96  * nt.h. NT_Init() will ask the NTAPI library to convert return data
97  * to the @ref NTAPI_VERSION if possible. This will ensure that
98  * applications can run on NTAPI libraries of newer versions.
99  * - @ref NT_ConfigOpen() - Open the config stream.
100  * - @ref NT_ConfigRead() - Use the config stream to read the current adapter
101  * time.
102  * - @ref NT_ConfigWrite() - Use the config stream to configure transmit on
103  * timestamp, using the retrieved adapter time.
104  * - @ref NT_NetTxOpen() - Open a hostbuffer than can transmit packets to port 0.
105  * - @ref NT_NetTxGet() - Get an empty tx buffer. This will get a 296 byte
106  * wire length packet buffer that will be sent onto port 0 when the packet
107  * buffer is released, and the timestamp has been reached on the adapter.
108  * - @ref NT_NET_GET_PKT_L2_PTR() is used to get the L2 pointer to the tx
109  * buffer, this is where the payload is placed.
110  * - @ref NT_NET_SET_PKT_TIMESTAMP() is used to set the packet timestamp.
111  * - @ref NT_NetTxRelease() - Release the tx packet buffer. Once a tx
112  * buffer is released it will be transmitted
113  * - @ref NT_ConfigRead() - Read the adapter timestamp to check if the last
114  * packet should have been transmitted. We need to do this in order to avoid
115  * disabling transmit on timestamp too early.
116  * - @ref NT_ConfigWrite() - Disable transmit on timestamp.
117  * - @ref NT_NetTxClose() - Close the TX stream.
118  * - @ref NT_Done() - Close down the NTAPI library.
119  *
120  *<hr>
121  * @section transmit_on_timestamp_example_code Code
122  * @}
123  */
124 
125 // Include this in order to access the Napatech API
126 #include <nt.h>
127 
128 #if defined(__linux__) || defined(__FreeBSD__)
129  #include <unistd.h> // sleep()
130 #elif defined(WIN32) || defined (WIN64)
131  #include <winsock2.h>
132 #endif
133 
134 // default TX packet test setup
135 #define PACKETS 100000
136 #define PACKET_SIZE 296 // Packet size to transmit (incl crc.)
137 #define PORT 0
138 #define ADAPTER 0
139 
140 // printError is a simple convenience function for printing an NTAPI error
141 // message to stderr.
142 static void printError(const char *prefix, int errorCode) {
143  char errorBuffer[NT_ERRBUF_SIZE];
144  NT_ExplainError(errorCode, errorBuffer, sizeof errorBuffer);
145  fprintf(stderr, "%s: %s\n", prefix, errorBuffer);
146 }
147 
148 int main(void)
149 {
150  //
151  // Initialize the API. This also checks if we are compatible with the
152  // installed library version.
153  //
154  int status;
155 
156  if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
157  printError("NT_Init() failed", status);
158  return -1;
159  }
160 
161  //
162  // Open the config stream, in order to retrieve the adapter timestamp and
163  // to configure the transmit on timestamp functionality. We configure
164  // transmit on timestamp in such a way that a packet with timestamp 0 will
165  // transmit in approximately one second from this point.
166  //
167  NtConfigStream_t hConfig;
168  NtConfig_t config;
169 
170  if ((status = NT_ConfigOpen(&hConfig, "replay")) != NT_SUCCESS) {
171  printError("NT_ConfigOpen() failed", status);
172  return -1;
173  }
174 
176  config.u.timestampRead.adapter = ADAPTER;
177 
178  if ((status = NT_ConfigRead(hConfig, &config)) != NT_SUCCESS) {
179  printError("NT_ConfigRead() failed", status);
180  return -1;
181  }
182 
183  // Store adapter timestamp, converted from 10ns ticks to 1ns
184  uint64_t adapterTS = config.u.timestampRead.data.nativeUnixTs * 10;
185 
186  // Configure transmit on timestamp. In scenarios where a packet descriptor
187  // that does not contain a TXNOW bit is used, such as when transmitting PCAP,
188  // forceTxOnTs must be set to true. However, this example uses NT
189  // descriptors, and can thus use the TXNOW bit.
191  config.u.transmitOnTimestamp.portNo = (uint8_t)PORT;
192  config.u.transmitOnTimestamp.data.timeDelta = adapterTS + 1000000000;
194  config.u.transmitOnTimestamp.data.enable = true;
195  config.u.transmitOnTimestamp.data.forceTxOnTs = false;
196 
197  if ((status = NT_ConfigWrite(hConfig, &config)) != NT_SUCCESS) {
198  printError("NT_ConfigWrite() failed", status);
199  return -1;
200  }
201 
202  //
203  // Open a TX stream
204  //
205  NtNetStreamTx_t hNetTx;
206 
207  status = NT_NetTxOpen(&hNetTx, "transmit_on_timestamp_example_txstream",
208  1ULL << PORT, NT_NETTX_NUMA_ANY_HB, 0);
209  if (status != NT_SUCCESS) {
210  printError("NT_NetTxOpen() failed", status);
211  return -1;
212  }
213 
214  //
215  // Retrieve a packet buffer, fill it, and repeat until we have transmitted
216  // the requested amount of packets. The timestamp will be set so that the
217  // adapter will transmit at approximately 5 Mb/s.
218  //
219  printf("Commencing transmission\n");
220 
221  NtNetBuf_t hNetBufTx;
222  uint64_t timestamp = 0;
223  int numPackets = 0;
224 
225  for (numPackets = 0; numPackets < PACKETS; numPackets++) {
226 
227  // Get a packet TX buffer for this tx stream and port, without timeout
228  if ((status = NT_NetTxGet(hNetTx, &hNetBufTx, PORT, PACKET_SIZE,
229  NT_NETTX_PACKET_OPTION_DEFAULT, -1)) != NT_SUCCESS) {
230  printError("NT_NetTxGet() failed", status);
231  return -1;
232  }
233 
234  // Set the timestamp. Note that for the NT descriptor, this is in 10ns
235  // ticks. The descriptor has been cleared, so TXNOW is set to 0. If one
236  // wishes to send a packet as soon as possible while transmit on timestamp
237  // is enabled, use NT_NET_SET_PKT_TXNOW to set TXNOW to 1.
238  NT_NET_SET_PKT_TIMESTAMP(hNetBufTx, timestamp);
239  timestamp += 50000;
240 
241  // Fill the packet with an incrementing payload. Note that this will result
242  // in a garbage ethernet frame.
243  uint32_t *ptr = (uint32_t*)NT_NET_GET_PKT_L2_PTR(hNetBufTx);
244  for (uint32_t i = 0; i < PACKET_SIZE/4; i++) {
245  *(ptr+i) = i;
246  }
247 
248  // Release the TX buffer to commit the packet. It will transmit once the
249  // timestamp is reached, or when transmit on timestamp is disabled.
250  if ((status = NT_NetTxRelease(hNetTx, hNetBufTx)) != NT_SUCCESS) {
251  printError("NT_NetTxRelease() failed", status);
252  return -1;
253  }
254  }
255 
256  //
257  // Wait for all packets to be transmitted. There are multiple ways to do
258  // this, but in this example, we read the adapter timestamp in a loop, and
259  // compare it to the value of our timestamp variable from the loop above.
260  //
261  printf("Waiting for transmission to end\n");
262 
264  config.u.timestampRead.adapter = ADAPTER;
265 
266  uint64_t newAdapterTS;
267  do {
268 #if defined(__linux__) || defined(__FreeBSD__)
269  sleep(1);
270 #elif defined(WIN32) || defined (WIN64)
271  Sleep(1000); // sleep 1000 milliseconds = 1 second
272 #endif
273  if ((status = NT_ConfigRead(hConfig, &config)) != NT_SUCCESS) {
274  printError("NT_ConfigRead() failed", status);
275  return -1;
276  }
277 
278  newAdapterTS = config.u.timestampRead.data.nativeUnixTs * 10;
279  } while (newAdapterTS <= (adapterTS + timestamp));
280 
281  //
282  // Disable transmit on timestamp. If any packets are left in the buffera this
283  // point, they will transmit unhindered at line rate.
284  //
286  config.u.transmitOnTimestamp.portNo = (uint8_t)PORT;
287  config.u.transmitOnTimestamp.data.timeDelta = 0;
289  config.u.transmitOnTimestamp.data.enable = false;
291 
292  if ((status = NT_ConfigWrite(hConfig, &config)) != NT_SUCCESS) {
293  printError("NT_ConfigWrite() failed", status);
294  return -1;
295  }
296 
297  //
298  // Terminate
299  //
300  printf("Done: %d packets sent\n", numPackets);
301 
302  // Close the TX stream
303  NT_NetTxClose(hNetTx);
304 
305  // Close the API
306  NT_Done();
307 
308  return 0;
309 }