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