analysis_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/analysis/analysis_example.c Source File
analysis_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/analysis/analysis_example.c
45  * @section analysis_example_description Description
46  *
47  * This source file is an example of how to do realtime analysis of packets
48  * using NTAPI.
49  *
50  * The following NTAPI functions are used:
51  * - @ref NT_Init()
52  * - @ref NT_ConfigOpen()
53  * - @ref NT_NetRxOpen()
54  * - @ref NT_NTPL()
55  * - @ref NT_NetRxGet()
56  * - @ref NT_NET_GET_PKT_DESCRIPTOR_TYPE()
57  * - @ref NT_NET_GET_PKT_TIMESTAMP()
58  * - @ref NT_NET_GET_PKT_WIRE_LENGTH()
59  * - @ref NT_NET_GET_PKT_L2_PTR()
60  * - @ref NT_NetRxRelease()
61  * - @ref NT_NetRxClose()
62  * - @ref NT_ConfigClose()
63  * - @ref NT_ExplainError()
64  *
65  * @note
66  * This example does not work with the NT4E-STD accelerator
67  *
68  * <hr>
69  * @section analysis_example_prerequisites Prerequisites
70  * A Napatech capture accelerator is needed to run this example. The ntservice.ini must
71  * have at least one HostBuffersRx defined. Below is an example of a
72  * minimum ini-file. It will create a 32MB RX hostbuffer from NUMA
73  * node 0.
74  * @code
75  * [System]
76  * TimestampFormat = NATIVE
77  *
78  * [Adapter0]
79  * AdapterType = NT20E
80  * BusId = 00:0a:00.00
81  * HostBuffersRx = [1,32,0]
82  * @endcode
83  *
84  * @section analysis_example_flow Program flow
85  * @{
86  * The following is required to perform real-time analysis on packets:
87  * - \#include/nt.h - Applications/Tools only need to include @ref
88  * nt.h to obtain prototypes, macros etc. from NTAPI.
89  * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI
90  * library. @ref NTAPI_VERSION is a define that describes the version
91  * of the API described in the header files included by @ref
92  * nt.h. NT_Init() will ask the NTAPI library to convert return data
93  * to the @ref NTAPI_VERSION if possible. This will ensure that
94  * applications can run on NTAPI libraries of newer versions.
95  * - @ref NT_ConfigOpen() - Open a config stream in order to setup
96  * filter using the @ref NT_NTPL() command.
97  * - @ref NT_NetRxOpen() - Open a stream. The stream ID must match the
98  * one used when creating the filter using the @ref NT_NTPL()
99  * command. A stream does not return data until traffic is assigned
100  * to it by creating a filter. Stream IDs might be shared between
101  * other streams and it is possible to make several filters to one
102  * stream ID. Each filter can have a unique color in the ASSIGN. The
103  * "color" of the ASSIGN can be used to mark packets making it
104  * possible for the stream to determine if the packets it receives
105  * via @ref NT_NetRxGet() as based on its assign or if the packet belongs
106  * to the other streams that also share the hostbuffer.
107  * - @ref NT_NTPL() - Assign traffic to a stream by creating a filter
108  * using a manually chosen stream ID. The stream ID must match the
109  * one used @ref NT_NetRxOpen().
110  * - Optional step. Wait until we start seeing packets that are hit by
111  * the NTPL assign command. This is done to avoid getting packets
112  * that are not fully classified by the stream. NT_NetRxGet() is
113  * called with a timeout of 1000ms and will return NT_STATUS_TIMEOUT
114  * in case nothing is received within 1000ms and will return
115  * NT_SUCCESS if something is returned. Return values different from
116  * that is an indication of an error. Packets that are prior to the
117  * expected time are released via NT_NetRxRelease().
118  * - NT_NetRxGet() and NT_NetRxRelease() - Receive and release packets. Each received packet is printed with help of the @ref PacketMacros
119  * - @ref NT_NET_GET_PKT_DESCRIPTOR_TYPE() - Get the descriptor type (@ref NT_PACKET_DESCRIPTOR_TYPE_PCAP, @ref NT_PACKET_DESCRIPTOR_TYPE_NT, @ref NT_PACKET_DESCRIPTOR_TYPE_NT_EXTENDED).
120  * - @ref NT_NET_GET_PKT_TIMESTAMP() - Get the timestamp of the packet.
121  * - @ref NT_NET_GET_PKT_WIRE_LENGTH() - Get the wire length of the packet.
122  * - @ref NT_NET_GET_PKT_L2_PTR() - Get a pointer to the L2 part of the packet, which is where SW decoding would start.
123  * - NT_NetRxClose() - Close the stream when terminating. This will
124  * close the stream and release the NTPL assignment made on the
125  * hostbuffer.
126  *
127  *<hr>
128  * @section analysis_example_code Code
129  * @}
130  */
131 
132 // Include this in order to access the Napatech API
133 #include <nt.h>
134 
135 #if defined(WIN32) || defined (WIN64)
136  #define snprintf(dst, ...) _snprintf_s((dst), _countof(dst), __VA_ARGS__)
137 #endif
138 
139 int main(void)
140 {
141  int numPackets = 0; // The number of packets received
142  int numBytes = 0; // The number of bytes received (wire length)
143  char tmpBuffer[20]; // Buffer to build filter string
144  char errorBuffer[NT_ERRBUF_SIZE]; // Error buffer
145  int status; // Status variable
146  NtNetStreamRx_t hNetRx; // Handle to the RX stream
147  NtConfigStream_t hCfgStream; // Handle to a config stream
148  NtNtplInfo_t ntplInfo; // Return data structure from the NT_NTPL() call.
149  NtNetBuf_t hNetBuf; // Net buffer container. Packet data is returned in this when calling NT_NetRxGet().
150 
151  // Initialize the NTAPI library and thereby check if NTAPI_VERSION can be used together with this library
152  if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
153  // Get the status code as text
154  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
155  fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
156  return -1;
157  }
158 
159  // Open a config stream to assign a filter to a stream ID.
160  if ((status = NT_ConfigOpen(&hCfgStream, "TestStream")) != NT_SUCCESS) {
161  // Get the status code as text
162  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
163  fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
164  return -1;
165  }
166 
167  // Assign traffic to stream ID 1 and mask all traffic matching the assign statement color=7.
168  if ((status = NT_NTPL(hCfgStream, "Assign[streamid=1;color=7] = All", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
169  // Get the status code as text
170  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
171  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
172  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
173  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
174  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
175  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
176  return -1;
177  }
178 
179  // Open stat stream
180  NtStatStream_t hStat = NULL;
181  if ((status = NT_StatOpen(&hStat, "hStat")) != 0) {
182  fprintf(stderr, "Failed to create statistics stream: 0x%08X\n", status);
183  return -1;
184  }
185 
186  // Reset stats
187  static NtStatistics_t statSet;
189  statSet.u.query_v4.poll = 1;
190  statSet.u.query_v4.clear = 1;
191  if ((status = NT_StatRead(hStat, &statSet))) {
192  fprintf(stderr, "Failed resetting statistics: 0x%08X\n", status);
193  return -1;
194  }
195 
196  // Get a stream handle with the hostBuffer mapped to it. NT_NET_INTERFACE_PACKET specify that we will receive data packet-by-packet
197  if ((status = NT_NetRxOpen(&hNetRx, "TestStream", NT_NET_INTERFACE_PACKET, 1, -1)) != NT_SUCCESS) {
198  // Get the status code as text
199  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
200  fprintf(stderr, "NT_NetRxOpen() failed: %s\n", errorBuffer);
201  return -1;
202  }
203 
204  // Optional step. Wait for the first packet that hit the NTPL assign command
205  printf("Waiting for the first packet\n");
206  while (1) {
207  if ((status = NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
208  if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
209  // Timeouts are ok, we just need to wait a little longer for a packet
210  continue;
211  }
212  // Get the status code as text
213  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
214  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
215  return -1;
216  }
217  // We got a packet. Check if the timestamp is newer than when the NTPL assign command was applied
218  if (NT_NET_GET_PKT_TIMESTAMP(hNetBuf) > ntplInfo.ts) {
219  break; // Break out, we have received a packet that is received after the NTPL assign command was applied
220  }
221  // Release the packet, it is too "old".
222  if ((status = NT_NetRxRelease(hNetRx, hNetBuf)) != NT_SUCCESS) {
223  // Get the status code as text
224  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
225  fprintf(stderr, "NT_NetRxRelease() failed: %s\n", errorBuffer);
226  return -1;
227  }
228  }
229 
230  // Dump packet info. Stop when 100 packets has been received
231  while (1) {
232  struct _mac {
233  uint8_t dst[6];
234  uint8_t src[6];
235  uint16_t typelen;
236  } *mac = (struct _mac*) NT_NET_GET_PKT_L2_PTR(hNetBuf);
237  printf("#%03d: %6s %016llX - %04d - %02X:%02X:%02X:%02X:%02X:%02X %02X:%02X:%02X:%02X:%02X:%02X %04x\n",
238  numPackets+1,
239  (NT_NET_GET_PKT_DESCRIPTOR_TYPE(hNetBuf)==NT_PACKET_DESCRIPTOR_TYPE_PCAP?"PCAP":
240  NT_NET_GET_PKT_DESCRIPTOR_TYPE(hNetBuf)==NT_PACKET_DESCRIPTOR_TYPE_NT?"NT":
241  NT_NET_GET_PKT_DESCRIPTOR_TYPE(hNetBuf)==NT_PACKET_DESCRIPTOR_TYPE_NT_EXTENDED?"NT_EXT":"Unknown"),
242  (unsigned long long)NT_NET_GET_PKT_TIMESTAMP(hNetBuf),
243  NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf),
244  mac->dst[0], mac->dst[1], mac->dst[2], mac->dst[3], mac->dst[4], mac->dst[5],
245  mac->src[0], mac->src[1], mac->src[2], mac->src[3], mac->src[4], mac->src[5],
246  mac->typelen);
247  // Increment the number of packets processed.
248  numPackets++;
249  // Increment the bytes received
250  numBytes += NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf);
251 
252  // Release the current packet
253  if ((status = NT_NetRxRelease(hNetRx, hNetBuf)) != NT_SUCCESS) {
254  // Get the status code as text
255  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
256  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
257  return -1;
258  }
259 
260  if (numPackets == 100) {
261  break;
262  }
263 
264  // Get the next packet
265  while (1) {
266  if ((status = NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
267  if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
268  // Timeouts are ok, we just need to wait a little longer for a packet
269  continue;
270  }
271  // Get the status code as text
272  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
273  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
274  return -1;
275  }
276  break; // We got a packet
277  }
278  }
279 
280  // Close the stream and release the hostbuffer
281  NT_NetRxClose(hNetRx);
282 
283  // Request stats
285  statSet.u.query_v4.poll = 1;
286  statSet.u.query_v4.clear = 0;
287  if ((status = NT_StatRead(hStat, &statSet)) != NT_SUCCESS) {
288  fprintf(stderr, "Failed reading statistics: 0x%08X\n", status);
289  return -1;
290  }
291 
292  // Read drop counters for streamid 1
293  uint64_t totDropsPkts = statSet.u.query_v4.data.stream.streamid[1].drop.pkts;
294  uint64_t totDropsBytes = statSet.u.query_v4.data.stream.streamid[1].drop.octets;
295 
296  // Close stat stream
297  NT_StatClose(hStat);
298 
299  // Delete the filter
300  snprintf(tmpBuffer, sizeof(tmpBuffer), "delete=%d", ntplInfo.ntplId);
301  if ((status = NT_NTPL(hCfgStream, tmpBuffer, &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
302  // Get the status code as text
303  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
304  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
305  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
306  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
307  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
308  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
309  return -1;
310  }
311 
312  // Close the config stream
313  if ((status = NT_ConfigClose(hCfgStream)) != NT_SUCCESS) {
314  // Get the status code as text
315  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
316  fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
317  return -1;
318  }
319 
320  // Output totals
321  printf("Drop: %lu packets, %lu bytes\n", totDropsPkts, totDropsBytes);
322  printf("Done: %d packets, %d bytes\n", numPackets, numBytes);
323 
324  // Close down the NTAPI library
325  NT_Done();
326 
327  return 0;
328 }
329 
330 //
331 // EOF
332 //