checksum_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/checksum/checksum_example.cpp Source File
checksum_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/checksum/checksum_example.cpp
45  * @section checksum_example_description Description
46  *
47  * This example transmits 10 packets where
48  * L3/L4 checksum calculation is controlled
49  * via control bits in the packet descriptor.
50  *
51  * By default this program transmits packets where
52  * the adapter recalculates both L3 and L4 checksum.
53  *
54  * It is controlled by these code lines:
55  *
56  * constexpr ChecksumCmdLayer3 cmd_l3 = CHECKSUM_LAYER3_GOOD;
57  *
58  * constexpr ChecksumCmdLayer4 cmd_l4 = CHECKSUM_LAYER4_GOOD;
59  *
60  * By changing these code lines and recompiling, the
61  * behavior can be changed to perform other action
62  * on the L3 and L4 checksum.
63  *
64  * L3 options:
65  *
66  * CHECKSUM_LAYER3_DO_NOTHING
67  *
68  * CHECKSUM_LAYER3_BAD
69  *
70  * CHECKSUM_LAYER3_GOOD
71  *
72  *
73  * L4 options:
74  *
75  * CHECKSUM_LAYER4_DO_NOTHING
76  *
77  * CHECKSUM_LAYER4_BAD
78  *
79  * CHECKSUM_LAYER4_GOOD
80  *
81  * CHECKSUM_LAYER4_GOOD_TCP_ZERO_UDP
82  *
83  * CHECKSUM_LAYER4_GOOD_TCP_ZERO_UDP_IPV4
84  *
85  * CHECKSUM_LAYER4_GOOD_TCP_UDP_ZERO_UDP_TUNNEL
86  *
87  * CHECKSUM_LAYER4_GOOD_TCP_UDP_ZERO_UDP_IPV4_TUNNEL
88  *
89  *
90  */
91 
92 // Include this in order to access the Napatech API
93 #include <nt.h>
94 
95 #include <cstdint>
96 #include <cstdlib>
97 #include <cstring>
98 #include <iostream>
99 
100 /**
101  * IPv4 UDP packet with IPv4 checksum error and UDP checksum error.
102  * No FCS included. Size: 96 byte.
103  */
104 static constexpr uint8_t Test_packet[] {
105  0x42, 0xb3, 0xbb, 0x9b, 0x7b, 0x6b, 0x02, 0xe1,
106  0x27, 0xc4, 0x33, 0x0f, 0x08, 0x00, 0x45, 0x00,
107  0x00, 0x52, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
108  0x79, 0x2c, 0x73, 0x35, 0xd7, 0xbe, 0x18, 0xdf,
109  0x1a, 0x71, 0x34, 0x8b, 0xcf, 0x5f, 0x00, 0x3e,
110  0xce, 0xe8, 0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70,
111  0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a,
112  0x61, 0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69,
113  0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a, 0x61,
114  0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a,
115  0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70,
116  0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a
117 };
118 
119 /**
120  * An overlay struct for NtDyn3Descr_t making c-style or reinterpret cast possible.
121  * frame_type: Bit position 128. Overlays bit [3:0] in NtDyn3Descr_t.color_hi
122  * checksum_cmd: Bit position 132. Overlays bit [8:4] in NtDyn3Descr_t.color_hi
123  */
125  uint64_t dont_care0;
126  uint64_t dont_care1;
127  uint64_t frame_type:4;
128  uint64_t checksum_cmd:5;
129  uint64_t dont_care2:39;
130 };
131 
132 /**
133  * Valid values for layer 3 checksum command.
134  */
136  CHECKSUM_LAYER3_DO_NOTHING = 0, // Do nothing
137  CHECKSUM_LAYER3_BAD = 2, // Insert BAD checksum in IPv4 header
138  CHECKSUM_LAYER3_GOOD = 3, // Insert GOOD checksum in IPv4 header
139 };
140 
141 /**
142  * Valid values for layer 4 checksum command.
143  */
145  CHECKSUM_LAYER4_DO_NOTHING = 0, // Do nothing
146  CHECKSUM_LAYER4_BAD = 2, // Insert BAD checksum in TCP/UDP header
147  CHECKSUM_LAYER4_GOOD = 3, // Insert GOOD checksum in TCP/UDP header
148  CHECKSUM_LAYER4_GOOD_TCP_ZERO_UDP = 4, // Insert GOOD checksum in TCP header and a value of ZERO in UDP header
149  CHECKSUM_LAYER4_GOOD_TCP_ZERO_UDP_IPV4 = 5, // Insert GOOD checksum in TCP header and a value of ZERO in UDP header when IP is IPv4
150  CHECKSUM_LAYER4_GOOD_TCP_UDP_ZERO_UDP_TUNNEL = 6, // Insert GOOD checksum in TCP/UDP header and a value of ZERO in UDP header when part of a tunnel
151  CHECKSUM_LAYER4_GOOD_TCP_UDP_ZERO_UDP_IPV4_TUNNEL = 7, // Insert GOOD checksum in TCP/UDP header and a value of ZERO in UDP header when IP is IPv4 and part of a tunnel
152 };
153 
154 /**
155  * Valid values for a descriptor frame type.
156  *
157  * Bit [ 0]: Value 0: Not tunneled
158  * Value 1: Tunneled
159  *
160  * Bit [ 1]: Value 0: IPv4 or other
161  * Value 1: IPv6
162  *
163  * Bit [3:2]: Value 0: Other
164  * Value 1: TCP
165  * Value 2: UDP
166  * Value 3: Reserved
167  */
168 enum FrameType {
169  FRAME_TYPE_IPV4_TCP = 0x0 | 0x0 | 0x4,
170  FRAME_TYPE_IPV4_UDP = 0x0 | 0x0 | 0x8,
171  FRAME_TYPE_IPV6_TCP = 0x0 | 0x2 | 0x4,
172  FRAME_TYPE_IPV6_UDP = 0x0 | 0x2 | 0x8,
173  FRAME_TYPE_IPV4_TCP_TUNNELED = 0x1 | 0x0 | 0x4,
174  FRAME_TYPE_IPV4_UDP_TUNNELED = 0x1 | 0x0 | 0x8,
175  FRAME_TYPE_IPV6_TCP_TUNNELED = 0x1 | 0x2 | 0x4,
176  FRAME_TYPE_IPV6_UDP_TUNNELED = 0x1 | 0x2 | 0x8,
177 };
178 
179 /**
180  * Correctly combines layer 3 checksum command and layer 4 checksum command.
181  */
183 {
184  return (((uint64_t)l3 & 0x3) << 3) | ((uint64_t)l4 & 0x7);
185 }
186 
187 /**
188  * Handles and prints NT error messages, and the terminates the program.
189  */
190 static inline void handle_error_status(int status, const char* message)
191 {
192  if (status != NT_SUCCESS) {
193  char error_buffer[NT_ERRBUF_SIZE];
194  NT_ExplainError(status, error_buffer, sizeof(error_buffer));
195  std::cerr << message << ": " << error_buffer << std::endl;
196  std::exit(EXIT_FAILURE);
197  }
198 }
199 
200 int main(int, char**)
201 {
202  constexpr uint64_t fcs_size = 4;
203  constexpr uint64_t num_packets = 10;
204  constexpr uint32_t tx_port = 0;
205 
206  constexpr ChecksumCmdLayer3 cmd_l3 = CHECKSUM_LAYER3_GOOD;
207  constexpr ChecksumCmdLayer4 cmd_l4 = CHECKSUM_LAYER4_GOOD;
208 
209  int status;
210  NtNetBuf_t net_buffer;
211  NtNetStreamTx_t net_tx_stream;
212  NtNetTxAttr_t attr;
213 
214  // Initialize NT API.
215  status = NT_Init(NTAPI_VERSION);
216  handle_error_status(status, "NT_Init() failed");
217 
218  // Initialize TX attributes struct and set up relevant stream related attributes.
219  NT_NetTxOpenAttrInit(&attr);
220  NT_NetTxOpenAttrSetName(&attr, "Checksum example NetTx");
221  NT_NetTxOpenAttrSetPortMask(&attr, 1 << tx_port);
222 
223  // Setting descriptor mode to DYN3 will cause Net Buffers received from NT_NetTxGet
224  // to be initialized with a DYN3 packet descriptor.
226  handle_error_status(status, "NT_NetTxOpenAttrSetDescriptorMode() failed");
227 
228  // To tell the adapter where to look for the frame type and checksum command bits.
229  status = NT_NetTxOpenAttrSetDescriptorPosFrameType(&attr, true, 128); // Bit position of Dyn3_checksum_overlay.frame_type
230  handle_error_status(status, "NT_NetTxOpenAttrSetDescriptorPosFrameType() failed");
231  status = NT_NetTxOpenAttrSetDescriptorPosChecksumCmd(&attr, true, 132); // Bit position of Dyn3_checksum_overlay.checksum_cmd
232  handle_error_status(status, "NT_NetTxOpenAttrSetDescriptorPosChecksumCmd() failed");
233 
234  // Open TX stream with attributes
235  status = NT_NetTxOpen_Attr(&net_tx_stream, &attr);
236  handle_error_status(status, "NT_NetTxOpen() failed");
237 
238  for (uint64_t i = 0; i < num_packets; ++i) {
239  // Use the option NT_NETTX_PACKET_OPTION_DYN to get a net buffer initialized with
240  // the DYN3 packet descriptor that was specified in NT_NetTxOpenAttrSetDescriptorMode.
241  // Note: Since the DYN3 packet descriptor does not contain a wire-length argument
242  // must be the correct size of the packet, not just big enough.
243  status = NT_NetTxGet(net_tx_stream, &net_buffer, tx_port, sizeof(Test_packet) + fcs_size, NT_NETTX_PACKET_OPTION_DYN, 100);
244  handle_error_status(status, "NT_NetTxGet() failed");
245 
246  // Get a pointer to the beginning of the Ethernet frame, and copy Test_packet to that memory.
247  uint8_t* l2_ptr = reinterpret_cast<uint8_t*>(NT_NET_GET_PKT_L2_PTR(net_buffer));
248  std::memcpy(l2_ptr, Test_packet, sizeof(Test_packet));
249 
250  // Get pointer to DYN3 packet descriptor.
251  auto descr_ptr = NT_NET_GET_PKT_DESCR_PTR_DYN3(net_buffer);
252  auto overlay_ptr = reinterpret_cast<Dyn3_checksum_overlay*>(descr_ptr);
253 
254  // Set offset 0 to start of IP header, and offset 1 to start of UDP header.
255  descr_ptr->offset0 = 14; // Point to start of Layer 3, i.e. set to size of Ethernet header
256  descr_ptr->offset1 = 34; // Point to start of Layer 4, i.e. set to size of Ethernet header + IPv4 header with no options
257 
258  // Set color values via the overlay struct.
259  overlay_ptr->frame_type = FRAME_TYPE_IPV4_UDP & 0xF;
260  overlay_ptr->checksum_cmd = checksum_command(cmd_l3, cmd_l4) & 0x1F;
261 
262  // Release / transmit net buffer from NT_NetTxGet
263  status = NT_NetTxRelease(net_tx_stream, net_buffer);
264  handle_error_status(status, "NT_NetTxRelease() failed");
265  }
266 
267  // Close TX stream, and then the NT API.
268  status = NT_NetTxClose(net_tx_stream);
269  handle_error_status(status, "NT_NetTxClose() failed");
270 
271  NT_Done();
272 
273  return 0;
274 }