streamidstatistics_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/streamidstatistics/streamidstatistics_example.c Source File
streamidstatistics_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/streamidstatistics/streamidstatistics_example.c
45  * @section streamidstatistics_example_description Description
46  *
47  * This source file show the procedure needed to get stream-id statistics that can be correlated with what the application receive.
48  *
49  * The following NTAPI functions are used:
50  * - @ref NT_Init()
51  * - @ref NT_StatOpen()
52  * - @ref NT_ConfigOpen()
53  * - @ref NT_ConfigWrite()
54  * - @ref NT_StatRead()
55  * - @ref NT_NetRxOpen()
56  * - @ref NT_NTPL()
57  * - @ref NT_NetRxGet()
58  * - @ref NT_NET_GET_PKT_DESCRIPTOR_TYPE()
59  * - @ref NT_NET_GET_PKT_TIMESTAMP()
60  * - @ref NT_NET_GET_PKT_WIRE_LENGTH()
61  * - @ref NT_NET_GET_PKT_L2_PTR()
62  * - @ref NT_NetRxRelease()
63  * - @ref NT_NetRxClose()
64  * - @ref NT_ConfigClose()
65  * - @ref NT_StatClose()
66  * - @ref NT_Done()
67  * - @ref NT_ExplainError()
68  *
69  * @note
70  * This example does not work with the NT4E-STD accelerator
71  *
72  * <hr>
73  * @section streamidstatistics_example_prerequisites Prerequisites
74  * A Napatech capture accelerator is needed to run this example. The ntservice.ini must
75  * have at least one HostBuffersRx defined. Below is an example of a
76  * minimum ini-file. It will create a 32MB RX hostbuffer from NUMA
77  * node 0.
78  * @code
79  * [System]
80  * TimestampFormat = NATIVE
81  *
82  * [Adapter0]
83  * AdapterType = NT20E
84  * BusId = 00:0a:00.00
85  * HostBuffersRx = [1,32,0]
86  * @endcode
87  *
88  * @section streamidstatistics_example_flow Program flow
89  * @{
90  * The following is required to perform real-time analysis on 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. @ref 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 a config stream in order to setup
100  * filter using the @ref NT_NTPL() command and stream-id configuration.
101  * - @ref NT_StatOpen() - Open a statistics stream which will be used
102  * to get stream-id statistics.
103  * - @ref NT_NTPL() to inactivate the stream-id to ensure that no
104  * packets are forwarded to the stream-id until we are ready to handle
105  * them. A time stamp of when the stream-id is in-activated is returned. This
106  * time stamp is important because it tells us when to stop discarding packets.
107  * - @ref NT_StatRead() is called asking for a statistics reset when the next
108  * statistics update is performed.
109  * - @ref NT_NetRxOpen() - Open a stream. The stream ID must match the
110  * one used when creating the filter using the @ref NT_NTPL()
111  * command. A stream doesn't return data until traffic is assigned
112  * to it by creating a filter. Stream IDs might be shared between
113  * other streams and it is possible to make several filters to one
114  * stream ID. Each filter can have a unique color in the ASSIGN. The
115  * "color" of the ASSIGN can be used to mark packets making it
116  * possible for the stream to determine if the packets it receives
117  * via @ref NT_NetRxGet() as based on its assign or if the packet belongs
118  * to the other streams that also share the hostbuffer.
119  * - @ref NT_NTPL() - Assign traffic to a stream by creating a filter
120  * using a manually chosen stream ID. The stream ID must match the
121  * one used @ref NT_NetRxOpen().
122  * - @ref NT_NTPL() to activate the stream-id because we are now
123  * ready to handle the traffic. It is important that wait with this
124  * step until all @ref NT_NTPL() has been issued.
125  * - @ref NT_NetRxGet() and @ref NT_NetRxRelease() - Receive and release packets. Packets received
126  * with a @ref NT_NET_GET_PKT_TIMESTAMP() older than the time stamp returned in the "in-activation"
127  * ste are discarded newer packets are counted.
128  * - When 10 packets has been received the stream-id is inactivated via @ref NT_ConfigWrite() and
129  * the application will continue @ref NT_NetRxGet() and @ref NT_NetRxRelease() until @ref NT_STATUS_TIMEOUT
130  * is returned.
131  * - Delete the stream-id assignments via @ref NT_NTPL().
132  * - @ref NT_NetRxClose() - Close the network stream.
133  * - Get stream-id statistics via @ref NT_StatRead() and check that the amount of packets
134  * counted by the application and statistics stream match.
135  * - Close all other streams, @ref NT_StatClose(), @ref NT_ConfigClose().
136  * - @ref NT_Done() - Close down the NTAPI library.
137  * - @ref NT_ExplainError() - Explain an error code returned by NTAPI functions.
138  *
139  *<hr>
140  * @section streamidstatistics_example_code Code
141  * @}
142  */
143 
144 // Include this in order to access the Napatech API
145 #include <nt.h>
146 
147 #include <inttypes.h>
148 
149 #if defined(WIN32) || defined(WIN64)
150  #define snprintf(dst, ...) _snprintf_s((dst), _countof(dst), __VA_ARGS__)
151 #endif
152 
153 int main(void)
154 {
155  int numPackets=0; // The number of packets received
156  int numBytes=0; // The number of bytes received (wire length)
157  char tmpBuffer[20]; // Buffer to build filter string
158  char errorBuffer[NT_ERRBUF_SIZE]; // Error buffer
159  int status; // Status variable
160  NtNetStreamRx_t hNetRx; // Handle to the RX stream
161  NtConfigStream_t hCfgStream; // Handle to a config stream
162  NtStatStream_t hStatStream; // Handle to a statistics stream
163  NtStatistics_t stat; // Statistics data
164  NtNtplInfo_t ntplInfo; // Return data structure from the NT_NTPL() call.
165  NtNetBuf_t hNetBuf; // Net buffer container. Packet data is returned in this when calling NT_NetRxGet().
166  uint64_t inactiveTime=0; // Time when the stream-id was in-activated
167  uint32_t ntplid=0; // The NT_NTPL ntplid returned from the Assign[]
168 
169  // Initialize the NTAPI library and thereby check if NTAPI_VERSION can be used together with this library
170  if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
171  // Get the status code as text
172  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
173  fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
174  return -1;
175  }
176 
177  // Open a config stream to assign a filter to a stream ID.
178  if ((status = NT_ConfigOpen(&hCfgStream, "TestStream")) != NT_SUCCESS) {
179  // Get the status code as text
180  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
181  fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
182  return -1;
183  }
184 
185  if ((status = NT_StatOpen(&hStatStream, "Stat")) != NT_SUCCESS) {
186  // Get the status code as text
187  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
188  fprintf(stderr, "NT_StatOpen() failed: %s\n", errorBuffer);
189  return -1;
190  }
191 
192  // Inactivate the streamid 1 to ensure that no packets are forwarded to it
193  if ((status = NT_NTPL(hCfgStream, "Setup[State=Inactive]=StreamId==1", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
194  // Get the status code as text
195  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
196  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
197  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
198  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
199  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
200  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
201  return -1;
202  }
203  // Save the inactive time so we can discard packets older than this time because
204  // they are of no interest.
205  inactiveTime = ntplInfo.ts;
206 
207  // Reset statistics
209  stat.u.query_v4.poll=0; // Wait for a new set
210  stat.u.query_v4.clear=1; // Clear statistics
211  if ((status = NT_StatRead(hStatStream, &stat)) != NT_SUCCESS) {
212  // Get the status code as text
213  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
214  fprintf(stderr, "NT_StatRead() failed: %s\n", errorBuffer);
215  return -1;
216  }
217 
218  // Get a stream handle with the hostBuffer mapped to it. NT_NET_INTERFACE_PACKET specify that we will receive data packet-by-packet
219  if ((status = NT_NetRxOpen(&hNetRx, "TestStream", NT_NET_INTERFACE_PACKET, 1, -1)) != NT_SUCCESS) {
220  // Get the status code as text
221  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
222  fprintf(stderr, "NT_NetRxOpen() failed: %s\n", errorBuffer);
223  return -1;
224  }
225 
226  // Assign traffic to stream ID 1 and mask all traffic matching the assign statement color=7.
227  if ((status = NT_NTPL(hCfgStream, "Assign[streamid=1;color=7] = All", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
228  // Get the status code as text
229  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
230  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
231  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
232  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
233  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
234  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
235  return -1;
236  }
237  // Store the ntplid so we can delete the Assign as part of the cleanup process
238  ntplid=ntplInfo.ntplId;
239 
240  // Activate the stream-id
241  printf("Activating the stream-id\n");
242  if ((status = NT_NTPL(hCfgStream, "Setup[State=Active]=StreamId==1", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
243  // Get the status code as text
244  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
245  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
246  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
247  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
248  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
249  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
250  return -1;
251  }
252 
253  printf("Waiting to get packets\n");
254  // Dump packet info. Stop when 10 packets has been received
255  while (numPackets < 10) {
256  if ((status = NT_NetRxGet(hNetRx, &hNetBuf, 100000)) != NT_SUCCESS) {
257  if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
258  // Timeouts are ok, we just need to wait a little longer for a packet
259  continue;
260  }
261  // Get the status code as text
262  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
263  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
264  return -1;
265  }
266  // We got a packet. Check if the timestamp is newer than when the NTPL assign command was applied
267  if (NT_NET_GET_PKT_TIMESTAMP(hNetBuf) >= inactiveTime) {
268  // Increment the number of packets processed.
269  numPackets++;
270  // Increment the bytes received
271  numBytes+=NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf);
272  printf("Got %d packets so far\r", numPackets);
273  }
274  // Release the current packet
275  if ((status = NT_NetRxRelease(hNetRx, hNetBuf)) != NT_SUCCESS) {
276  // Get the status code as text
277  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
278  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
279  return -1;
280  }
281  }
282 
283  // Deactivate the stream-id
284  printf("\nDeactivating the stream-id\n");
285  if ((status = NT_NTPL(hCfgStream, "Setup[State=Inactive]=StreamId==1", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
286  // Get the status code as text
287  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
288  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
289  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
290  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
291  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
292  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
293  return -1;
294  }
295 
296  printf("Continue to get packets until NT_STATUS_TIMEOUT... This will take a while.\n");
297  while (1) {
298  if ((status = NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
299  if (status == NT_STATUS_TIMEOUT) {
300  break;
301  }
302  // Get the status code as text
303  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
304  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
305  return -1;
306  }
307  // We got a packet. Check if the timestamp is newer than when the NTPL assign command was applied
308  if (NT_NET_GET_PKT_TIMESTAMP(hNetBuf) >= inactiveTime) {
309  // Increment the number of packets processed.
310  numPackets++;
311  // Increment the bytes received
312  numBytes+=NT_NET_GET_PKT_WIRE_LENGTH(hNetBuf);
313  if ((numPackets%10) == 0) {
314  printf("Got %d packets so far\r", numPackets);
315  }
316  }
317  // Release the current packet
318  if ((status = NT_NetRxRelease(hNetRx, hNetBuf)) != NT_SUCCESS) {
319  // Get the status code as text
320  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
321  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
322  return -1;
323  }
324  }
325  printf("Got %d packets so far\n", numPackets);
326 
327  // Delete the filter
328  snprintf(tmpBuffer, 20, "delete=%d", ntplid);
329  if ((status = NT_NTPL(hCfgStream, tmpBuffer, &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
330  // Get the status code as text
331  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
332  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
333  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
334  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
335  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
336  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
337  return -1;
338  }
339 
340  // Close the stream and release the hostbuffer.
341  NT_NetRxClose(hNetRx);
342 
343  printf("Getting stream-id statistics\n");
345  stat.u.query_v4.poll=0; // Wait for a new set
346  stat.u.query_v4.clear=0; // Don't clear statistics
347  if ((status = NT_StatRead(hStatStream, &stat)) != NT_SUCCESS) {
348  // Get the status code as text
349  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
350  fprintf(stderr, "NT_StatRead() failed: %s\n", errorBuffer);
351  return -1;
352  }
353 
354  // Close the config stream
355  if ((status = NT_ConfigClose(hCfgStream)) != NT_SUCCESS) {
356  // Get the status code as text
357  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
358  fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
359  return -1;
360  }
361 
362  // Close the statistics stream
363  if ((status = NT_StatClose(hStatStream)) != NT_SUCCESS) {
364  // Get the status code as text
365  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
366  fprintf(stderr, "NT_StatClose() failed: %s\n", errorBuffer);
367  return -1;
368  }
369 
370  printf("Done\n");
371  printf("APP received : %d packets, %d bytes. \n", numPackets, numBytes);
372  printf("Stream-id received: %" PRIu64 " packets, %" PRIu64" bytes. \n", stat.u.query_v4.data.stream.streamid[1].forward.pkts, stat.u.query_v4.data.stream.streamid[1].forward.octets);
373  printf("Stream-id dropped : %" PRIu64 " packets, %" PRIu64" bytes. \n", stat.u.query_v4.data.stream.streamid[1].drop.pkts, stat.u.query_v4.data.stream.streamid[1].drop.octets);
374 
375  // Close down the NTAPI library
376  NT_Done();
377 
378  return 0;
379 }