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