net/transmit_segment_dyn_descr/transmit_segment_dyn_descr_example.cpp

Reference Documentation

product_line_custom
IntelĀ® PAC
Napatech SmartNIC
category
Reference Information
Napatech Software Suite: net/transmit_segment_dyn_descr/transmit_segment_dyn_descr_example.cpp
net/transmit_segment_dyn_descr/transmit_segment_dyn_descr_example.cpp

Description

This example transmits 100 packets with DYN3 descriptors using a network TX stream in segment interface mode. The packets are transmitted on port 0.

The example also shows how the tx_ignore command bit is used.

While this example use DYN3 descriptors, the same functionality is possible with DYN1, DYN2, DYN4, or any future dynamic descriptors with a color field.

/*
*
* Copyright 2020 Napatech A/S. All Rights Reserved.
*
* 1. Copying, modification, and distribution of this file, or executable
* versions of this file, is governed by the terms of the Napatech Software
* license agreement under which this file was made available. If you do not
* agree to the terms of the license do not install, copy, access or
* otherwise use this file.
*
* 2. Under the Napatech Software license agreement you are granted a
* limited, non-exclusive, non-assignable, copyright license to copy, modify
* and distribute this file in conjunction with Napatech SmartNIC's and
* similar hardware manufactured or supplied by Napatech A/S.
*
* 3. The full Napatech Software license agreement is included in this
* distribution, please see "NP-0405 Napatech Software license
* agreement.pdf"
*
* 4. Redistributions of source code must retain this copyright notice,
* list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, EXPRESS OR
* IMPLIED, AND NAPATECH DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING ANY
* IMPLIED WARRANTY OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, OR OF
* FITNESS FOR A PARTICULAR PURPOSE. TO THE EXTENT NOT PROHIBITED BY
* APPLICABLE LAW, IN NO EVENT SHALL NAPATECH BE LIABLE FOR PERSONAL INJURY,
* OR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER,
* INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, CORRUPTION OR
* LOSS OF DATA, FAILURE TO TRANSMIT OR RECEIVE ANY DATA OR INFORMATION,
* BUSINESS INTERRUPTION OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING
* OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE NAPATECH SOFTWARE OR
* SERVICES OR ANY THIRD PARTY SOFTWARE OR APPLICATIONS IN CONJUNCTION WITH
* THE NAPATECH SOFTWARE OR SERVICES, HOWEVER CAUSED, REGARDLESS OF THE THEORY
* OF LIABILITY (CONTRACT, TORT OR OTHERWISE) AND EVEN IF NAPATECH HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW
* THE EXCLUSION OR LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF
* INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU.
*
*
*/
/**
* @example net/transmit_segment_dyn_descr/transmit_segment_dyn_descr_example.cpp
* @section transmit_segment_dyn_descr_example_description Description
*
* This example transmits 100 packets with DYN3 descriptors
* using a network TX stream in segment interface mode.
* The packets are transmitted on port 0.
*
* The example also shows how the tx_ignore command bit is used.
*
* While this example use DYN3 descriptors, the same functionality is possible
* with DYN1, DYN2, DYN4, or any future dynamic descriptors with a color field.
*
*/
#include <nt.h>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iostream>
/**
* IPv4 UDP packet. No FCS included. Size: 96 byte.
*/
static constexpr uint8_t Test_packet[] {
0xb7, 0x27, 0x53, 0x03, 0xe5, 0x8a, 0x6e, 0x97,
0xba, 0x83, 0xa4, 0xc4, 0x08, 0x00, 0x45, 0x00,
0x00, 0x52, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
0x26, 0x57, 0xfb, 0x83, 0x89, 0xd7, 0xd9, 0x4c,
0xf5, 0x9b, 0x06, 0x09, 0xfa, 0xaa, 0x00, 0x3e,
0xce, 0xa5, 0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70,
0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a,
0x61, 0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69,
0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a, 0x61,
0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a,
0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a, 0x61, 0x70,
0x69, 0x7a, 0x7a, 0x61, 0x70, 0x69, 0x7a, 0x7a
};
/**
* An overlay struct for NtDyn3Descr_t making c-style or reinterpret cast possible.
* tx_ignore: Bit position 28. Overlays bit [13] in NtDyn3Descr_t.color_lo
*/
uint64_t dont_care0:28;
uint64_t tx_ignore:1;
uint64_t dont_care1:35;
uint64_t dont_care2;
uint64_t dont_care3:48;
};
/**
* Handles and prints NT error messages, and the terminates the program.
*/
static void handle_error_status(int status, const char* message)
{
if(status != NT_SUCCESS) {
char error_buffer[NT_ERRBUF_SIZE];
NT_ExplainError(status, error_buffer, sizeof(error_buffer));
std::cerr << message << ": " << error_buffer << std::endl;
std::exit(EXIT_FAILURE);
}
}
/**
* Calculate the size of a segment padding packet, and add it to the net buffer.
* Returns the size of the padding packet added (incl. descriptor size).
*/
static uint64_t create_padding_packet_dyn3(struct NtNetBuf_s& buffer,
uint64_t max_packet_size, uint64_t remaining_segment_space)
{
constexpr uint64_t min_packet_size = 64;
constexpr uint64_t min_padding_size = NT_DESCR_DYN3_LENGTH + min_packet_size;
uint64_t max_padding_size = NT_DESCR_DYN3_LENGTH + max_packet_size;
uint16_t padding_size = 0;
if(remaining_segment_space >= min_padding_size + max_padding_size) {
// More than one padding packet is needed.
// So add a padding packet with maximum size
padding_size = static_cast<uint16_t>(max_packet_size);
}
else if(remaining_segment_space <= max_padding_size) {
// One padding packet is enough.
// So add a padding packet that will fill the rest of the segment
padding_size = static_cast<uint16_t>(remaining_segment_space - NT_DESCR_DYN3_LENGTH);
}
else {
// Exactly two packets are needed.
// So add a padding packet so that the remaining space in segment matches a minimum packet
padding_size = static_cast<uint16_t>(remaining_segment_space - (NT_DESCR_DYN3_LENGTH + min_padding_size));
}
// Setup DYN3 descriptor.
NT_NET_SET_PKT_CAP_LENGTH_NOALIGN(&buffer, padding_size);
// Set the TX ignore bit to 1, such that the padding packet will not be transmitted.
auto packet_ptr = NT_NET_GET_PKT_DESCR_PTR_DYN3(&buffer);
reinterpret_cast<Dyn3_checksum_overlay*>(packet_ptr)->tx_ignore = 1;
return NT_DESCR_DYN3_LENGTH + padding_size;
}
/**
* Use the NT info stream to get the maximum size of a TX packet.
*/
static uint64_t get_max_packet_size(uint8_t port)
{
int status;
NtInfoStream_t info_stream;
NtInfo_t info;
// Open info stream.
status = NT_InfoOpen(&info_stream, "transmit_segment_dyn_descr_example_info");
handle_error_status(status, "NT_InfoOpen() failed");
// Read NT info for a specific port.
info.u.port_v9.portNo = port;
status = NT_InfoRead(info_stream, &info);
handle_error_status(status, "NT_InfoRead() failed");
// Close info steam.
status = NT_InfoClose(info_stream);
handle_error_status(status, "NT_InfoClose() failed");
}
int main(int, char**)
{
// Note: Segments can be much larger than 8192 bytes, but this value gives
// some nice printable results.
constexpr uint64_t fcs_size = 4;
constexpr uint64_t min_packet_size = 64;
constexpr uint64_t segment_size = 8192;
constexpr uint64_t total_packets = 100;
constexpr uint8_t tx_port = 0;
int status;
NtNetBuf_t net_buffer_segment;
NtNetStreamTx_t net_tx_stream;
// Initialize NT API.
handle_error_status(status, "NT_Init() failed");
// Get maximum size of a TX packet for a specific port.
uint64_t max_packet_size = get_max_packet_size(tx_port);
// Initialize TX attributes struct and set up relevant stream related attributes.
NT_NetTxOpenAttrSetName(&attr, "Checksum example NetTx");
NT_NetTxOpenAttrSetPortMask(&attr, 1 << tx_port);
// Set the TX packet descriptor to DYN3.
handle_error_status(status, "NT_NetTxOpenAttrSetDescriptorMode() failed");
// To tell the adapter where to look for the TX ignore bit.
// 28 is the bit position of Dyn3_checksum_overlay.tx_ignore.
status = NT_NetTxOpenAttrSetDescriptorPosIgnoreBit(&attr, true, 28);
handle_error_status(status, "NT_NetTxOpenAttrSetDescriptorPosFrameType() failed");
// Open TX stream with attributes
status = NT_NetTxOpen_Attr(&net_tx_stream, &attr);
handle_error_status(status, "NT_NetTxOpen() failed");
for(uint64_t packet_count = 0; packet_count < total_packets;) {
// Use the option NT_NETTX_SEGMENT_OPTION_RAW to get a net buffer segment.
status = NT_NetTxGet(net_tx_stream, &net_buffer_segment, tx_port, segment_size, NT_NETTX_SEGMENT_OPTION_RAW, 100);
handle_error_status(status, "NT_NetTxGet() failed");
// Create a new net buffer to use as a window into the segment net buffer.
struct NtNetBuf_s net_buffer_packet;
_nt_net_build_pkt_netbuf(net_buffer_segment, &net_buffer_packet);
uint64_t remaining_segment_space = NT_NET_GET_SEGMENT_LENGTH(net_buffer_segment);
// Fill the segment.
while(remaining_segment_space > 0) {
// Since segments has to be completely filled with packets, a check is needed
// to prevent a case where the remaining segment space is too small to
// contain a padding packet.
uint64_t min_required_segment_space = NT_DESCR_DYN3_LENGTH + sizeof(Test_packet) + fcs_size +
NT_DESCR_DYN3_LENGTH + min_packet_size;
if(packet_count < total_packets && remaining_segment_space >= min_required_segment_space) {
// Setup packet with a DYN3 descriptor.
// Note: This also sets the tx_ignore to 0.
NT_NET_SET_PKT_CLEAR_DESCR_DYN3(&net_buffer_packet);
NT_NET_SET_PKT_DESCR_TYPE_DYN3(&net_buffer_packet);
NT_NET_SET_PKT_CAP_LENGTH_NOALIGN(&net_buffer_packet, sizeof(Test_packet) + fcs_size);
NT_NET_UPDATE_PKT_L2_PTR(&net_buffer_packet);
// Copy packet data into TX net buffer.
uint8_t* l2_ptr = reinterpret_cast<uint8_t*>(NT_NET_GET_PKT_L2_PTR(&net_buffer_packet));
std::memcpy(l2_ptr, Test_packet, sizeof(Test_packet));
packet_count += 1;
std::cout << "Adding packet number: " << packet_count << std::endl;
}
else {
// Copy a padding packet into net buffer.
uint64_t padding_size = create_padding_packet_dyn3(net_buffer_packet,
max_packet_size,
remaining_segment_space);
std::cout << "Adding padding packet with size: " << padding_size << std::endl;
}
// Get the next packet of the segment.
remaining_segment_space = _nt_net_get_next_packet(net_buffer_segment,
NT_NET_GET_SEGMENT_LENGTH(net_buffer_segment),
&net_buffer_packet);
}
// Release / transmit net buffer segment from NT_NetTxGet
status = NT_NetTxRelease(net_tx_stream, net_buffer_segment);
handle_error_status(status, "NT_NetTxRelease() failed");
}
// Close TX stream, and then the NT API.
status = NT_NetTxClose(net_tx_stream);
handle_error_status(status, "NT_NetTxClose() failed");
return 0;
}