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