segment_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/segment_inline/segment_inline_example.c Source File
segment_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/segment_inline/segment_inline_example.c
46  * @section segment_inline_example_description Description
47  *
48  * This source file is an example of how to do inline with the segment interface.
49  *
50  * The following NTAPI functions are used:
51  * - @ref NT_Init()
52  * - @ref NT_NetRxOpen()
53  * - @ref NT_NTPL()
54  * - @ref NT_NetRxRead()
55  * - @ref NT_NetRxGet()
56  * - @ref NT_NET_GET_SEGMENT_PTR()
57  * - @ref NT_NET_GET_SEGMENT_LENGTH()
58  * - @ref NT_NET_GET_SEGMENT_TIMESTAMP()
59  * - @ref NT_NetRxRelease()
60  * - @ref NT_NetRxClose()
61  * - @ref NT_Done()
62  * - @ref NT_ExplainError()
63  *
64  * @section segment_inline_example_prerequisites Prerequisites
65  * A Napatech capture accelerator is need to run this example. The ntservice.ini
66  * must have at least one HostBuffersRx defined. Below is an example
67  * of a minimum ini-file. It will create a 32MB RX hostbuffer from
68  * NUMA node 0.
69  * @code
70  * [System]
71  * TimestampFormat = NATIVE
72  *
73  * [Adapter0]
74  * AdapterType = NT20E
75  * BusId = 00:0a:00.00
76  * HostBuffersRx = [1,32,0]
77  * @endcode
78  *
79  * @section capture_example_flow Program flow
80  * @{
81  * The following is required to perform capture of segments to disk:
82  * - \#include/nt.h - Applications/Tools only need to include @ref
83  * nt.h to obtain prototypes, macros etc. from NTAPI.
84  * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI
85  * library. @ref NTAPI_VERSION is a define that describes the version
86  * of the API described in the header files included by @ref
87  * nt.h. NT_Init() will ask the NTAPI library to convert return data
88  * to the @ref NTAPI_VERSION if possible. This will ensure that
89  * applications can run on NTAPI libraries of newer versions.
90  * - @ref NT_NetRxOpen() - Open the stream using a stream ID.
91  * The stream ID must match the one used when creating the
92  * filter.
93  * - @ref NT_NTPL() - Setup traffic forwarding from stream, and use the wirelength
94  * to indicate whether the packet should be dropped or not.
95  * Assign traffic to the stream with Dyn3 descriptor.
96  * A stream does not return data until traffic is assigned to it by a filter.
97  * Stream IDs can be shared between other streams.
98  * - Wait until we start seeing segments that are hit
99  * by the NTPL assign command. This is done to avoid getting
100  * segments that are not fully classified by the stream.
101  * NT_NetRxGet() is called with a timeout of 1000ms and will return
102  * NT_STATUS_TIMEOUT in case nothing is received within 1000ms and
103  * will return NT_SUCCESS when a segment is returned. Segments with NT_NET_GET_SEGMENTLENGTH()==0
104  * can be returned so it is needed to check for the segment length before using data within
105  * the segment. The NT_NET_GET_SEGMENT_TIMESTAMP() macro can still be used on the empty segments.
106  * Return values different from that is an indication of an error. Segments that
107  * are prior to the expected time are released via NT_NetRxRelease().
108  * - NT_NetRxGet(), and NT_NetRxRelease() - Receive
109  * segments, drop every other packet and release segments. The @ref
110  * SegmentMacros are used to find the segment and length and
111  * timestamp of the segment:
112  * - @ref NT_NET_GET_SEGMENT_PTR() - Get a pointer to the segment.
113  * - @ref NT_NET_GET_SEGMENT_LENGTH() - Get length of the segment to store.
114  * - @ref NT_NET_GET_SEGMENT_TIMESTAMP() - The time the segment was delivered.
115  * - @ref _nt_net_build_pkt_netbuf() and @ref _nt_net_get_next_packet() are used to traverse
116  * packets inside a segment. This is usefull if inspection is needed before saving the
117  * segment.
118  * - NT_NetRxClose() - Close the stream when terminating.
119  * This will close the stream and release the NTPL assignment made on the hostbuffer.
120  * - Close captured file
121  * - @ref NT_Done() - Close down the NTAPI library.
122  *
123  *<hr>
124  * @section capture_example_code Code
125  * @}
126  */
127 
128 #include <nt.h>
129 #if defined(__linux__)
130 #include <signal.h>
131 #include <unistd.h>
132 #endif
133 
134 #if defined(WIN32) || defined (WIN64)
135  #define snprintf _snprintf
136 #endif
137 
138 static volatile int running = 1;
139 
140 #if defined(__linux__)
141 static void catch_signal(int sig)
142 {
143  (void)sig;
144  running = 0;
145 }
146 #endif
147 
148 int main(void)
149 {
150  int numSegments = 0; // The number of segments received
151  int numPackets = 0; // The number of packets received
152  uint64_t numBytes = 0; // The number of bytes received
153  uint64_t numBytesWire = 0; // The number of bytes received on the wire
154  char tmpBuffer[20]; // Buffer to build filter string
155  char errorBuffer[NT_ERRBUF_SIZE]; // Error buffer
156  int status; // Status variable
157  NtNetStreamRx_t hNetRx; // Handle to the RX stream
158  NtConfigStream_t hCfgStream; // Handle to a config stream
159  NtNtplInfo_t ntplInfo; // Return data structure from the NT_NTPL() call.
160  NtNetBuf_t hNetBuf; // Net buffer container. Segment data is returned in this when calling NT_NetRxGet().
161  struct NtNetBuf_s pktNetBuf; // Packet netbuf structure.
162  int disc = 0; // Counter to toggle discard the packets
163 
164 #if defined(__linux__)
165  signal(SIGINT, catch_signal); //<-- Catch keyboard QUIT (CTRL-\)
166 #endif
167 
168  // Initialize the NTAPI library and thereby check if NTAPI_VERSION can be used together with this library
169  if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
170  // Get the status code as text
171  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
172  fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
173  return -1;
174  }
175 
176  // Open a config stream to assign a filter to a stream ID.
177  if ((status = NT_ConfigOpen(&hCfgStream, "TestStream")) != NT_SUCCESS) {
178  // Get the status code as text
179  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
180  fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
181  return -1;
182  }
183 
184  // Setup traffic to stream ID(=1) and Tx port = 0
185  if ((status = NT_NTPL(hCfgStream, "Setup[TxDescriptor=Dyn;TxPorts=0;UseWL=True] = StreamId == 1", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
186  // Get the status code as text
187  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
188  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
189  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
190  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
191  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
192  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
193  return -1;
194  }
195 
196  // Assign traffic to stream ID 1 and mask all traffic matching the assign statement.
197  if ((status = NT_NTPL(hCfgStream, "Assign[StreamId=1;Descriptor=Dyn3] = Port == 0", &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
198  // Get the status code as text
199  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
200  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
201  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
202  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
203  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
204  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
205  return -1;
206  }
207 
208  // Close the config stream
209  if ((status = NT_ConfigClose(hCfgStream)) != NT_SUCCESS) {
210  // Get the status code as text
211  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
212  fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
213  return -1;
214  }
215 
216  // Open stat stream
217  NtStatStream_t hStat = NULL;
218  if ((status = NT_StatOpen(&hStat, "hStat")) != 0) {
219  fprintf(stderr, "Failed to create statistics stream: 0x%08X\n", status);
220  return -1;
221  }
222 
223  // Reset stats
224  static NtStatistics_t statSet;
226  statSet.u.query_v3.poll = 1;
227  statSet.u.query_v3.clear = 1;
228  if ((status = NT_StatRead(hStat, &statSet))) {
229  fprintf(stderr, "Failed resetting statistics: 0x%08X\n", status);
230  return -1;
231  }
232 
233  // Get a stream handle with stream ID 1. NT_NET_INTERFACE_SEGMENT specify that we will receive data in a segment based matter.
234  if ((status = NT_NetRxOpen(&hNetRx, "TestStream", NT_NET_INTERFACE_SEGMENT, 1, -1)) != NT_SUCCESS) {
235  // Get the status code as text
236  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
237  fprintf(stderr, "NT_NetRxOpen() failed: %s\n", errorBuffer);
238  return -1;
239  }
240 
241  // Optional step. Wait for the first packet that hit the NTPL assign command
242  printf("Waiting for the first segment\n");
243 
244  while (running) {
245  if ((status = NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
246  if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
247  // Timeouts are ok, we just need to wait a little longer for a segment
248  continue;
249  }
250  // Get the status code as text
251  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
252  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
253  return -1;
254  }
255 
256  // We got a segment. Check if the timestamp is newer than when the NTPL assign command was applied
257  if (NT_NET_GET_SEGMENT_TIMESTAMP(hNetBuf) > ntplInfo.ts) {
258  break; // Break out, we have received a segment that is received after the NTPL assign command was applied
259  }
260 
261  // Release the segment as it is too "old".
262  if ((status = NT_NetRxRelease(hNetRx, hNetBuf)) != NT_SUCCESS) {
263  // Get the status code as text
264  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
265  fprintf(stderr, "NT_NetRxRelease() failed: %s\n", errorBuffer);
266  return -1;
267  }
268  }
269 
270  // Process segments
271  while (running) {
272  if (NT_NET_GET_SEGMENT_LENGTH(hNetBuf)) {
273  // Start by building a packet netbuf structure
274  _nt_net_build_pkt_netbuf(hNetBuf, &pktNetBuf);
275  do {
276  // Just count the amount of packets and wire length
277  numPackets++;
278  numBytesWire += NT_NET_GET_PKT_WIRE_LENGTH((&pktNetBuf));
279 
280  // Discard every other packet
281  if (disc) {
282  NtDyn3Descr_t *pDyn3 = (NtDyn3Descr_t *)NT_NET_GET_PKT_DESCR_PTR(&pktNetBuf);
283  pDyn3->wireLength = 0;
284  }
285 
286  // Toggle the discard bit
287  disc ^= 1;
288  } while (_nt_net_get_next_packet(hNetBuf, NT_NET_GET_SEGMENT_LENGTH(hNetBuf), &pktNetBuf)>0);
289 
290  // Increment the number of segments processed.
291  numSegments++;
292 
293  // Increment the bytes received
294  numBytes += NT_NET_GET_SEGMENT_LENGTH(hNetBuf);
295  printf("%016llx - Received segment of %lu bytes.\n",
296  (unsigned long long)NT_NET_GET_SEGMENT_TIMESTAMP(hNetBuf), NT_NET_GET_SEGMENT_LENGTH(hNetBuf));
297  }
298 
299  // Release the current segment
300  if ((status = NT_NetRxRelease(hNetRx, hNetBuf)) != NT_SUCCESS) {
301  // Get the status code as text
302  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
303  fprintf(stderr, "NT_NetRxRelease() failed: %s\n", errorBuffer);
304  return -1;
305  }
306 
307  // Get the next segment
308  while (1) {
309  if ((status = NT_NetRxGet(hNetRx, &hNetBuf, 1000)) != NT_SUCCESS) {
310  if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
311  // Timeouts are ok, we just need to wait a little longer for a segment
312  continue;
313  }
314  // Get the status code as text
315  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
316  fprintf(stderr, "NT_NetRxGet() failed: %s\n", errorBuffer);
317  return -1;
318  }
319  break; // We got a segment
320  }
321  }
322 
323  // Close the stream and release the hostbuffer. This will also remove the NTPL assignments performed.
324  NT_NetRxClose(hNetRx);
325 
326  // Request stats
328  statSet.u.query_v3.poll = 1;
329  statSet.u.query_v3.clear = 0;
330  if ((status = NT_StatRead(hStat, &statSet)) != NT_SUCCESS) {
331  fprintf(stderr, "Failed reading statistics: 0x%08X\n", status);
332  return -1;
333  }
334 
335  // Read drop counters for streamid 1
336  uint64_t totDropsPkts = statSet.u.query_v3.data.stream.streamid[1].drop.pkts;
337  uint64_t totDropsBytes = statSet.u.query_v3.data.stream.streamid[1].drop.octets;
338 
339  // Close stat stream
340  NT_StatClose(hStat);
341 
342  // Open a config stream to delete a filter.
343  if ((status = NT_ConfigOpen(&hCfgStream, "TestStream")) != NT_SUCCESS) {
344  // Get the status code as text
345  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
346  fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
347  return -1;
348  }
349 
350  // Delete the filter
351  snprintf(tmpBuffer, sizeof(tmpBuffer), "delete=%d", ntplInfo.ntplId);
352  if ((status = NT_NTPL(hCfgStream, tmpBuffer, &ntplInfo, NT_NTPL_PARSER_VALIDATE_NORMAL)) != NT_SUCCESS) {
353  // Get the status code as text
354  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
355  fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
356  fprintf(stderr, ">>> NTPL errorcode: %X\n", ntplInfo.u.errorData.errCode);
357  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
358  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
359  fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
360  return -1;
361  }
362 
363  // Close the config stream
364  if ((status = NT_ConfigClose(hCfgStream)) != NT_SUCCESS) {
365  // Get the status code as text
366  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
367  fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
368  return -1;
369  }
370 
371  printf("Drop: %16lu packets, %16lu bytes\n", totDropsPkts, totDropsBytes);
372  printf("Done: %16d segments, %16d packets, %16lu bytes, %16lu bytes on wire\n", numSegments, numPackets, numBytes, numBytesWire);
373 
374  // Close down the NTAPI library
375  NT_Done();
376 
377  return 0;
378 }
379 
380 //
381 // EOF
382 //