inline_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/inline/inline_example.c Source File
inline_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/inline/inline_example.c
46  * @section inline_example_description Description
47  *
48  * INFO: This is an 3GA and 4GA inline example.
49  * A more advanced 4GA inline example can be found in examples/net/vlandemo/.
50  *
51  * This source file is an example of how to run in an inline
52  * scenario. The example will discard every 2nd packet.
53  *
54  * The following NTAPI functions are used:
55  * - @ref NT_Init()
56  * - @ref NT_InfoOpen()
57  * - @ref NT_InfoRead()
58  * - @ref NT_InfoClose()
59  * - @ref NT_ConfigOpen()
60  * - @ref NT_NetRxOpen()
61  * - @ref NT_NTPL()
62  * - @ref NT_NetRxGet()
63  * - @ref NT_NET_SET_PKT_TXIGNORE()
64  * - @ref NT_NET_GET_PKT_WIRE_LENGTH()
65  * - @ref NT_NET_GET_PKT_TIMESTAMP()
66  * - @ref NT_NetRxRelease()
67  * - @ref NT_NetRxClose()
68  * - @ref NT_ConfigClose()
69  * - @ref NT_ExplainError()
70  *
71  * @section inline_example_prerequisites Prerequisites
72  * An Napatech inline accelerator with at least one RX host buffer per port
73  * defined. Below is an example of a minimum ini-file. It will create
74  * two 32MB RX hostbuffers from NUMA node 0. The source and
75  * destination is determined by the filter. Use a traffic generator to
76  * apply traffic to one of the ports.
77  * @code
78  * [System]
79  * TimestampFormat = NATIVE
80  *
81  * [Adapter0]
82  * AdapterType = NT20E
83  * BusId = 00:0a:00.00
84  * HostBuffersRx = [2,32,0]
85  * @endcode
86  *
87  * @section inline_example_flow Program flow
88  * @{
89  * The following is required to run in an inline scenario:
90  * - \#include/nt.h - Applications/Tools only need to include @ref
91  * nt.h to obtain prototypes, macros etc. from NTAPI.
92  * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI
93  * library. @ref NTAPI_VERSION is a define that describes the version
94  * of the API described in the header files included by @ref
95  * nt.h. NT_Init() will ask the NTAPI library to convert return data
96  * to the @ref NTAPI_VERSION if possible. This will ensure that
97  * applications can run on NTAPI libraries of newer versions.
98  * - @ref NT_InfoOpen() - Detect the adapter generation and if TX is
99  * available.
100  * - @ref NT_ConfigOpen() - Open a config stream in order to setup
101  * filter using the @ref NT_NTPL() command.
102  * - @ref NT_NetRxOpen() - Open a stream. The stream ID must match
103  * the one used when creating the filter using the @ref NT_NTPL()
104  * command. A stream doesn't return data until traffic is assigned
105  * to it by creating a filter. Stream IDs might be shared between
106  * other streams and it is possible to make several filters to one
107  * stream ID. Each filter can have a unique color in the ASSIGN. The
108  * "color" of the ASSIGN can be used to mark packets making it
109  * possible for the stream to determine if the packets it receives
110  * via @ref NT_NetRxGet() as based on its assign or if the packet
111  * belongs to the other streams that also share the hostbuffer.
112  * - @ref NT_NTPL() - Assign traffic to a stream by creating a filter
113  * using a manually chosen stream ID. The stream ID must match the
114  * one used @ref NT_NetRxOpen(). On 4GA adapters and above,
115  * the Setup NTPL statement must be used to forward the packets from
116  * the stream to the output tx port (as opposed to the older form on
117  * 3Garch adapters where this could be done in the Assign statement).
118  * To indicate whether a packet should be dropped, we use the DYN3
119  * descriptors and indicate that the wirelength is used.
120  * - Optional step. Wait until we start seeing packets that are hit by
121  * the NTPL assign command. This is done to avoid getting packets
122  * that are not fully classified by the stream. @ref NT_NetRxGet() is
123  * called with a timeout of 1000ms and will return NT_STATUS_TIMEOUT
124  * in case nothing is received within 1000ms and will return
125  * NT_SUCCESS if something is returned. Return values different from
126  * that is an indication of an error. Packets that are prior to the
127  * expected time are released via @ref NT_NetRxRelease().
128  * - @ref NT_NetRxGet(), discard every 2nd packet and @ref NT_NetRxRelease() -
129  * Receive packets, discard every 2nd and release packets. The @ref
130  * PacketMacros are used to find the packet length ant the timestamp
131  * of the packet:
132  * - @ref NT_NET_GET_PKT_WIRE_LENGTH() - Get length of the packet to store.
133  * - @ref NT_NET_GET_PKT_TIMESTAMP() - The time the packet was delivered.
134  * - @ref NT_NET_SET_PKT_TXIGNORE() - Don't send the current packet (3GArch).
135  * - @ref NT_NET_GET_PKT_DESCR_PTR() - Get the packet descriptor header (4GArch).
136  * In the 4GArch, we set the wire length to 0 in order to discard the packet
137  * as opposed to using the NT_NET_SET_PKT_TXIGNORE().
138  * - @ref NT_NetRxClose() - Close the stream when terminating. This
139  * will close the stream and release the NTPL assignment made on the
140  * hostbuffer.
141  *
142  *<hr>
143  * @section inline_example_code Code
144  * @}
145  */
146 
147 // Include this in order to access the Napatech API
148 #include <nt.h>
149 #if defined(__linux__)
150 #include <signal.h>
151 #include <unistd.h>
152 #endif
153 
154 #if defined(WIN32) || defined (WIN64)
155  #define snprintf(dst, ...) _snprintf_s((dst), _countof(dst), __VA_ARGS__)
156 #endif
157 
158 #define PORT 0
159 
160 static volatile int running = 1;
161 
162 #if defined(__linux__)
163 static void catch_signal(int sig)
164 {
165  (void)sig;
166  running = 0;
167 }
168 #endif
169 
170 int main(void)
171 {
172  int numPackets=0; // The number of packets received
173  int numBytes=0; // The number of bytes received
174  int numPacketsDiscard=0; // The number of packets discarded
175  int numBytesDiscard=0; // The number of bytes discarded
176  char tmpBuffer[20]; // Buffer to build filter string
177  char errorBuffer[NT_ERRBUF_SIZE]; // Error buffer
178  int status; // Status variable
179  int isFpga4Garch=0; // Flag specifying whether this is 4GA adapter.
180  int isTxSupported=0; // Flag specifying whether Tx is supported on this adapter.
181  NtNetStreamRx_t hNetRx; // Handle to the RX stream
182  NtConfigStream_t hCfgStream; // Handle to a config stream
183  NtNtplInfo_t ntplInfo; // Return data structure from the NT_NTPL() call.
184  NtNetBuf_t hNetBuf; // Net buffer container. Packet data is returned in this when calling NT_NetRxGet().
185  NtInfoStream_t hInfo; // Handle to the Info stream for determining adapter type
186  NtInfo_t info; // Return data structure from NT_InfoRead() calls.
187  const char *ntplFilter; // Temporary variable storing the filter.
188  uint8_t adapterNo; // The adapter number for the port defined as PORT.
189 
190 #if defined(__linux__)
191  signal(SIGINT, catch_signal); //<-- Catch keyboard QUIT (CTRL-\)
192 #endif
193 
194  // Initialize the NTAPI library and thereby check if NTAPI_VERSION can be used together with this library
195  if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
196  // Get the status code as text
197  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
198  fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
199  return -1;
200  }
201 
202  if ((status = NT_InfoOpen(&hInfo, "inline_example")) != NT_SUCCESS) {
203  // Get the status code as text
204  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
205  fprintf(stderr, "NT_InfoOpen() failed: %s\n", errorBuffer);
206  return -1;
207  }
208 
209  // Detect adapter version and feature set
211  info.u.port_v9.portNo = PORT;
212  if ((status = NT_InfoRead(hInfo, &info)) != NT_SUCCESS) {
213  NT_InfoClose(hInfo);
214  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
215  fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer);
216  return -1;
217  }
218 
219  adapterNo = info.u.port_v9.data.adapterNo;
221  snprintf(info.u.property.path, sizeof(info.u.property.path), "Adapter%d.FpgaGeneration", adapterNo);
222  if ((status = NT_InfoRead(hInfo, &info)) != NT_SUCCESS) {
223  NT_InfoClose(hInfo);
224  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
225  fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer);
226  return -1;
227  }
228 
229  isFpga4Garch = info.u.property.data.u.i >= 4;
230 
231  if (isFpga4Garch) {
232  memset(&info, 0, sizeof(NtInfo_t));
235  if ((status = NT_InfoRead(hInfo, &info)) != NT_SUCCESS) {
236  NT_InfoClose(hInfo);
237  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
238  fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer); return -1;
239  }
243  // 4GA adapters with ANL9 feature level support native TX with inline capabilities
244  // NOTE: 4GA adapters with ANL9 feature level doesn't support
245  // NT_NET_SET_PKT_DESCR_TYPE_EXT7 descriptor type
246  isTxSupported=1;
247  }
248  } else {
249  isTxSupported=1;
250  }
251 
252  if ((status = NT_InfoClose(hInfo)) != NT_SUCCESS) {
253  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
254  fprintf(stderr, "NT_InfoClose() failed: %s\n", errorBuffer);
255  return -1;
256  }
257 
258  // Bail out early because inline isn't possible without Tx.
259  if (!isTxSupported) {
260  fprintf(stderr, "error: Tx is not supported on this adapter.\n");
261  return -1;
262  }
263 
264  // Open a config stream to assign a filter to a stream ID.
265  if ((status = NT_ConfigOpen(&hCfgStream, "TestStream")) != NT_SUCCESS) {
266  // Get the status code as text
267  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
268  fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
269  return -1;
270  }
271 
272  // Assign traffic to stream ID 1 and mask all traffic matching the assign statement color=7.
273  if (isFpga4Garch) {
274  // Setup traffic to stream ID(=1) and Tx port = 0, and use wire length to discard packets
275  if ((status = NT_NTPL(hCfgStream, "Setup[TxDescriptor=Dyn;TxPorts=0;UseWL=True] = StreamId == 1",
276  &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
277  // Get the status code as text
278  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
279  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
280  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
281  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
282  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
283  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
284  return -1;
285  }
286  ntplFilter = "Assign[streamid=1;color=7;Descriptor=Dyn3] = All";
287  } else { // 3Garch - for older FPGAs and adapters
288  ntplFilter = "Assign[streamid=1;color=7;txport=1] = All";
289  }
290 
291  if ((status = NT_NTPL(hCfgStream, ntplFilter, &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
292  // Get the status code as text
293  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
294  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
295  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
296  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
297  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
298  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
299  return -1;
300  }
301 
302  // Close the config stream
303  if ((status = NT_ConfigClose(hCfgStream)) != NT_SUCCESS) {
304  // Get the status code as text
305  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
306  fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
307  return -1;
308  }
309 
310  // Get a stream handle with the stream ID. NT_NET_INTERFACE_PACKET specify that we will receive data in a packet based matter.
311  if ((status = NT_NetRxOpen(&hNetRx, "TestStream", NT_NET_INTERFACE_PACKET, 1, -1)) != NT_SUCCESS) {
312  // Get the status code as text
313  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
314  fprintf(stderr, "NT_NetRxOpen() failed: %s\n", errorBuffer);
315  return -1;
316  }
317 
318  // Optional step. Wait for the first packet that hit the NTPL assign command
319  printf("Waiting for the first packet\n");
320  while (1) {
321  if ((status = NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
322  if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
323  // Timeouts are ok, we just need to wait a little longer for a packet
324  continue;
325  }
326  // Get the status code as text
327  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
328  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
329  return -1;
330  }
331  // We got a packet. Check if the timestamp is newer than when the NTPL assign command was applied
332  if (NT_NET_GET_PKT_TIMESTAMP(hNetBuf) > ntplInfo.ts) {
333  break; // Break out, we have received a packet that is received after the NTPL assign command was applied
334  }
335  // Release the packet, it is too "old".
336  if ((status = NT_NetRxRelease(hNetRx, hNetBuf)) != NT_SUCCESS) {
337  // Get the status code as text
338  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
339  fprintf(stderr, "NT_NetRxRelease() failed: %s\n", errorBuffer);
340  return -1;
341  }
342  }
343 
344  // Forward all packages and skip every second packet until signal received
345  while (running) {
346  static int disc=0;
347  // Check if the packet should be discarded
348  if (disc) {
349  // Discard the current packet
350  if (isFpga4Garch) {
351  // On 4garch, we use wirelength = 0 to discard packet (see vlandemo for other methods)
352  NtDyn3Descr_t *pDyn3 = (NtDyn3Descr_t *)NT_NET_GET_PKT_DESCR_PTR(hNetBuf);
353  pDyn3->wireLength = 0;
354  } else { // 3Garch
355  NT_NET_SET_PKT_TXIGNORE(hNetBuf, 1);
356  }
357  // Increment the number of packets and bytes discarded.
358  numBytesDiscard+=NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf);
359  numPacketsDiscard++;
360  printf("Discarded: %016llx - %d bytes\n", (unsigned long long)NT_NET_GET_PKT_TIMESTAMP(hNetBuf), NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf));
361  } else {
362  // Increment the number of packets and bytes forwarded.
363  numBytes+=NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf);
364  numPackets++;
365  printf("Forwarded: %016llx - %d bytes\n", (unsigned long long)NT_NET_GET_PKT_TIMESTAMP(hNetBuf), NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf));
366  }
367 
368  // Toggle the discard bit
369  disc ^= 1;
370 
371  // Release the current packet
372  if ((status = NT_NetRxRelease(hNetRx, hNetBuf)) != NT_SUCCESS) {
373  // Get the status code as text
374  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
375  fprintf(stderr, "NT_NetRxRelease() failed: %s\n", errorBuffer);
376  return -1;
377  }
378 
379  // Get the next packet
380  while (running) {
381  if ((status = NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
382  if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
383  // Timeouts are ok, we just need to wait a little longer for a packet
384  continue;
385  }
386  // Get the status code as text
387  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
388  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
389  return -1;
390  }
391  break; // We got a packet
392  }
393  }
394 
395  // Open a config stream to delete a filter.
396  if ((status = NT_ConfigOpen(&hCfgStream, "TestStream")) != NT_SUCCESS) {
397  // Get the status code as text
398  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
399  fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
400  return -1;
401  }
402 
403  // Delete the filter
404  snprintf(tmpBuffer, sizeof(tmpBuffer), "delete=%d", ntplInfo.ntplId);
405  if ((status = NT_NTPL(hCfgStream, tmpBuffer, &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
406  // Get the status code as text
407  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
408  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
409  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
410  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
411  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
412  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
413  return -1;
414  }
415 
416  // Close the config stream
417  if ((status = NT_ConfigClose(hCfgStream)) != NT_SUCCESS) {
418  // Get the status code as text
419  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
420  fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
421  return -1;
422  }
423 
424  // Close the stream and release the hostbuffer. This will also remove the NTPL assignments performed.
425  NT_NetRxClose(hNetRx);
426 
427  printf("Done: Discarded %d packets out of %d, %d bytes out of %d\n",
428  numPacketsDiscard, numPackets+numPacketsDiscard, numBytes, numBytes+numBytesDiscard);
429  return 0;
430 }