transmit_segment_dyn_descr_example.cpp Source File

Reference Documentation

Platform
Napatech SmartNIC
Content Type
Reference Information
Capture Software Version
Link™ Capture Software 12.15
Napatech Software Suite: examples/net/transmit_segment_dyn_descr/transmit_segment_dyn_descr_example.cpp Source File
transmit_segment_dyn_descr_example.cpp
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/transmit_segment_dyn_descr/transmit_segment_dyn_descr_example.cpp
45  * @section transmit_segment_dyn_descr_example_description Description
46  *
47  * This example transmits 100 packets with DYN3 descriptors
48  * using a network TX stream in segment interface mode.
49  * The packets are transmitted on port 0.
50  *
51  * The example also shows how the tx_ignore command bit is used.
52  *
53  * While this example use DYN3 descriptors, the same functionality is possible
54  * with DYN1, DYN2, DYN4, or any future dynamic descriptors with a color field.
55  *
56  */
57 
58 // Include this in order to access the Napatech API
59 #include <nt.h>
60 
61 #include <cstdint>
62 #include <cstdlib>
63 #include <cstring>
64 #include <iostream>
65 
66 /**
67  * IPv4 UDP packet. No FCS included. Size: 96 byte.
68  */
69 static constexpr uint8_t Test_packet[] {
70  0xb7, 0x27, 0x53, 0x03, 0xe5, 0x8a, 0x6e, 0x97,
71  0xba, 0x83, 0xa4, 0xc4, 0x08, 0x00, 0x45, 0x00,
72  0x00, 0x52, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
73  0x26, 0x57, 0xfb, 0x83, 0x89, 0xd7, 0xd9, 0x4c,
74  0xf5, 0x9b, 0x06, 0x09, 0xfa, 0xaa, 0x00, 0x3e,
75  0xce, 0xa5, 0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70,
76  0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a,
77  0x61, 0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69,
78  0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a, 0x61,
79  0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a,
80  0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70,
81  0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a
82 };
83 
84 /**
85  * An overlay struct for NtDyn3Descr_t making c-style or reinterpret cast possible.
86  * tx_ignore: Bit position 28. Overlays bit [13] in NtDyn3Descr_t.color_lo
87  */
88 struct Dyn3_checksum_overlay {
89  uint64_t dont_care0:28;
90  uint64_t tx_ignore:1;
91  uint64_t dont_care1:35;
92  uint64_t dont_care2;
93  uint64_t dont_care3:48;
94 };
95 
96 /**
97  * Handles and prints NT error messages, and the terminates the program.
98  */
99 static void handle_error_status(int status, const char* message)
100 {
101  if (status != NT_SUCCESS) {
102  char error_buffer[NT_ERRBUF_SIZE];
103  NT_ExplainError(status, error_buffer, sizeof(error_buffer));
104  std::cerr << message << ": " << error_buffer << std::endl;
105  std::exit(EXIT_FAILURE);
106  }
107 }
108 
109 /**
110  * Calculate the size of a segment padding packet, and add it to the net buffer.
111  * Returns the size of the padding packet added (incl. descriptor size).
112  */
113 static uint64_t create_padding_packet_dyn3(struct NtNetBuf_s& buffer,
114  uint64_t max_packet_size, uint64_t remaining_segment_space)
115 {
116  constexpr uint64_t min_packet_size = 64;
117  constexpr uint64_t min_padding_size = NT_DESCR_DYN3_LENGTH + min_packet_size;
118 
119  uint64_t max_padding_size = NT_DESCR_DYN3_LENGTH + max_packet_size;
120  uint16_t padding_size = 0;
121 
122  if (remaining_segment_space >= min_padding_size + max_padding_size) {
123  // More than one padding packet is needed.
124  // So add a padding packet with maximum size
125  padding_size = static_cast<uint16_t>(max_packet_size);
126  }
127  else if (remaining_segment_space <= max_padding_size) {
128  // One padding packet is enough.
129  // So add a padding packet that will fill the rest of the segment
130  padding_size = static_cast<uint16_t>(remaining_segment_space - NT_DESCR_DYN3_LENGTH);
131  }
132  else {
133  // Exactly two packets are needed.
134  // So add a padding packet so that the remaining space in segment matches a minimum packet
135  padding_size = static_cast<uint16_t>(remaining_segment_space - (NT_DESCR_DYN3_LENGTH + min_padding_size));
136  }
137 
138  // Setup DYN3 descriptor.
141  NT_NET_SET_PKT_CAP_LENGTH_NOALIGN(&buffer, padding_size);
142  NT_NET_UPDATE_PKT_L2_PTR(&buffer);
143 
144  // Set the TX ignore bit to 1, such that the padding packet will not be transmitted.
145  auto packet_ptr = NT_NET_GET_PKT_DESCR_PTR_DYN3(&buffer);
146  reinterpret_cast<Dyn3_checksum_overlay*>(packet_ptr)->tx_ignore = 1;
147 
148  return NT_DESCR_DYN3_LENGTH + padding_size;
149 }
150 
151 /**
152  * Use the NT info stream to get the maximum size of a TX packet.
153  */
154 static uint64_t get_max_packet_size(uint8_t port)
155 {
156  int status;
157  NtInfoStream_t info_stream;
158  NtInfo_t info;
159 
160  // Open info stream.
161  status = NT_InfoOpen(&info_stream, "transmit_segment_dyn_descr_example_info");
162  handle_error_status(status, "NT_InfoOpen() failed");
163 
164  // Read NT info for a specific port.
166  info.u.port_v10.portNo = port;
167  status = NT_InfoRead(info_stream, &info);
168  handle_error_status(status, "NT_InfoRead() failed");
169 
170  // Close info steam.
171  status = NT_InfoClose(info_stream);
172  handle_error_status(status, "NT_InfoClose() failed");
173 
175 }
176 
177 int main(int, char**)
178 {
179  // Note: Segments can be much larger than 8192 bytes, but this value gives
180  // some nice printable results.
181  constexpr uint64_t fcs_size = 4;
182  constexpr uint64_t min_packet_size = 64;
183  constexpr uint64_t segment_size = 8192;
184  constexpr uint64_t total_packets = 100;
185  constexpr uint8_t tx_port = 0;
186 
187  int status;
188  NtNetBuf_t net_buffer_segment;
189  NtNetStreamTx_t net_tx_stream;
190  NtNetTxAttr_t attr;
191 
192  // Initialize NT API.
193  status = NT_Init(NTAPI_VERSION);
194  handle_error_status(status, "NT_Init() failed");
195 
196  // Get maximum size of a TX packet for a specific port.
197  uint64_t max_packet_size = get_max_packet_size(tx_port);
198 
199  // Initialize TX attributes struct and set up relevant stream related attributes.
200  NT_NetTxOpenAttrInit(&attr);
201  NT_NetTxOpenAttrSetName(&attr, "Checksum example NetTx");
202  NT_NetTxOpenAttrSetPortMask(&attr, 1 << tx_port);
203 
204  // Set the TX packet descriptor to DYN3.
206  handle_error_status(status, "NT_NetTxOpenAttrSetDescriptorMode() failed");
207 
208  // To tell the adapter where to look for the TX ignore bit.
209  // 28 is the bit position of Dyn3_checksum_overlay.tx_ignore.
210  status = NT_NetTxOpenAttrSetDescriptorPosIgnoreBit(&attr, true, 28);
211  handle_error_status(status, "NT_NetTxOpenAttrSetDescriptorPosFrameType() failed");
212 
213  // While this example uses DYN3 descriptors, it does not use the "wireLength"
214  // field to tell the FPGA the size of the packet, as is the default behavior,
215  // but rather the "capLength" field.
216  status = NT_NetTxOpenAttrSetDescriptorUseWireLength(&attr, false);
217  handle_error_status(status, "NT_NetTxOpenAttrSetDescriptorUseWireLength() failed");
218 
219  // Open TX stream with attributes
220  status = NT_NetTxOpen_Attr(&net_tx_stream, &attr);
221  handle_error_status(status, "NT_NetTxOpen() failed");
222 
223  for (uint64_t packet_count = 0; packet_count < total_packets;) {
224  // Use the option NT_NETTX_SEGMENT_OPTION_RAW to get a net buffer segment.
225  status = NT_NetTxGet(net_tx_stream, &net_buffer_segment, tx_port, segment_size, NT_NETTX_SEGMENT_OPTION_RAW, 100);
226  handle_error_status(status, "NT_NetTxGet() failed");
227 
228  // Create a new net buffer to use as a window into the segment net buffer.
229  struct NtNetBuf_s net_buffer_packet;
230  _nt_net_build_pkt_netbuf(net_buffer_segment, &net_buffer_packet);
231  uint64_t remaining_segment_space = NT_NET_GET_SEGMENT_LENGTH(net_buffer_segment);
232 
233  // Fill the segment.
234  while (remaining_segment_space > 0) {
235  // Since segments has to be completely filled with packets, a check is needed
236  // to prevent a case where the remaining segment space is too small to
237  // contain a padding packet.
238  uint64_t min_required_segment_space = NT_DESCR_DYN3_LENGTH + sizeof(Test_packet) + fcs_size +
239  NT_DESCR_DYN3_LENGTH + min_packet_size;
240 
241  if (packet_count < total_packets && remaining_segment_space >= min_required_segment_space) {
242  // Setup packet with a DYN3 descriptor.
243  // Note: This also sets the tx_ignore to 0.
244  NT_NET_SET_PKT_CLEAR_DESCR_DYN3(&net_buffer_packet);
245  NT_NET_SET_PKT_DESCR_TYPE_DYN3(&net_buffer_packet);
246  NT_NET_SET_PKT_CAP_LENGTH_NOALIGN(&net_buffer_packet, sizeof(Test_packet) + fcs_size);
247  NT_NET_UPDATE_PKT_L2_PTR(&net_buffer_packet);
248 
249  // Copy packet data into TX net buffer.
250  uint8_t* l2_ptr = reinterpret_cast<uint8_t*>(NT_NET_GET_PKT_L2_PTR(&net_buffer_packet));
251  std::memcpy(l2_ptr, Test_packet, sizeof(Test_packet));
252 
253  packet_count += 1;
254 
255  std::cout << "Adding packet number: " << packet_count << std::endl;
256  }
257  else {
258  // Copy a padding packet into net buffer.
259  uint64_t padding_size = create_padding_packet_dyn3(net_buffer_packet,
260  max_packet_size,
261  remaining_segment_space);
262 
263 
264  std::cout << "Adding padding packet with size: " << padding_size << std::endl;
265  }
266 
267  // Get the next packet of the segment.
268  remaining_segment_space = _nt_net_get_next_packet(net_buffer_segment,
269  NT_NET_GET_SEGMENT_LENGTH(net_buffer_segment),
270  &net_buffer_packet);
271  }
272 
273  // Release / transmit net buffer segment from NT_NetTxGet
274  status = NT_NetTxRelease(net_tx_stream, net_buffer_segment);
275  handle_error_status(status, "NT_NetTxRelease() failed");
276  }
277 
278  // Close TX stream, and then the NT API.
279  status = NT_NetTxClose(net_tx_stream);
280  handle_error_status(status, "NT_NetTxClose() failed");
281 
282  NT_Done();
283 
284  return 0;
285 }