mpmd: Enable force_mtu device argument

This device argument can be used where the automatic MTU discovery fails,
e.g., because of a particularly restrictive network configuration. Note
that it should be used with care, because UHD will use this value for
Ethernet frame sizes, even if the underlying network connection does not
support them.

Also, for 1 GbE connections, the default MTU is always 1500 bytes,
regardless of the detected maximum MTU. This means that when attempting
to increase the MTU over a 1 GbE link, the recv_frame_size stream (or
device) argument also needs to be provided.

See the corresponding x300 commit for additional for information. This
enables the same feature for all MPM devices (X4xx, E3xx, N3xx).
Manual pages were also updated in this commit.
This commit is contained in:
Martin Braun 2025-11-26 12:22:04 +01:00 committed by Jörg Hofrichter
parent d8c8e7f6a1
commit 90b213f2fa
5 changed files with 58 additions and 15 deletions

View File

@ -569,6 +569,7 @@ For a list of which arguments can be passed into make(), see Section
discovery_port | Override default value for MPM discovery port. | discovery_port=49700
rpc_port | Override default value for MPM RPC port. | rpc_port=49701
enable_gps | Enable/disable power to the integrated GPSDO (E320 only). | enable_gps=0
force_mtu | Skips MTU detection and manually sets a network MTU. | force_mtu=8000
\subsection e3xx_usage_sensors The sensor API

View File

@ -488,6 +488,7 @@ For a list of which arguments can be passed into make(), see Section
rx_gain_profile | Initialize device with a specific RX gain profile. | N310 | rx_gain_profile=manual
tx_band_map | Semicolon-separated list of TX band edges. | N310 | tx_band_map=0.0;723.18e6;1623.18e6;3323.18e6
rx_band_map | Semicolon-separated list of RX band edges. | N310 | rx_band_map=0.0;431e6;601e6;1051e6;1601e6;2101e6;2701e6
force_mtu | Skips MTU detection and manually sets a network MTU. | All N3xx | force_mtu=8000
\subsection n3xx_usage_init Device Initialization

View File

@ -1409,6 +1409,7 @@ For a list of which arguments can be passed into make(), see Section
cal_ch_list | Selects the channels to be calibrated. | cal_ch_list=1;2;3
skip_adc_selfcal | Skips the ADC self-cal on clock-reconfig. | skip_adc_selfcal=true
skip_mpm_reboot | Skips MPM rebooting during session initialization on clock-reconfig. X440 only. | skip_mpm_reboot=1
force_mtu | Skips MTU detection and manually sets a network MTU. | force_mtu=8000
\subsection x4xx_usage_mcrs Master Clock Rates

View File

@ -38,6 +38,13 @@ options available not listed here.
recover_mb_eeprom | Disable version checks. Can damage hardware. Only recommended for recovering devices with corrupted EEPROMs. | X3x0 | recover_mb_eeprom=1
serialize_init | Force serial initialization of motherboards (default is parallel) | X3x0, all MPM devices | serialize_init=1
force_reinit | Force reinitialization of device | N3x0, X4x0 | force_reinit=1
force_mtu | Skip MTU detection and use this value instead. Warning: can cause issues if MTU value is not valid! | X3x0, E3x0, N3x0, X4x0 | force_mtu=8000
Notes:
- The `force_mtu` argument is only recommended in rare cases where
auto-detection of the MTU fails because of a restrictive network
configuration. Note that it is generally preferable to set a per-link MTU
using the `mtu` stream argument (see \ref page_transport for details).
In addition, many of the streaming-related options can be set per-device at configuration time.
See \ref config_stream_args and \ref page_transport for more details.
@ -243,6 +250,10 @@ The following parameters are supported:
the FPGA state to reenable transmission. Note this mode is only useful
for non time critical transmission (e.g. sending samples to the replay
block).
- `mtu` (applies to RFNoC devices only): Overrides the MTU value for this
streamer, ignoring limits from the underlying link.
\subsubsection config_stream_args_transport Transport-related Stream Arguments
The following arguments that alter the behavior of the underlying transport

View File

@ -29,6 +29,8 @@ using namespace uhd::mpmd::xport;
namespace {
constexpr char LOG_ID[] = "MPMD::XPORT::UDP";
//! Maximum CHDR packet size in bytes.
// Our 10GbE connections use custom FPGA code which caps frames at 8192 bytes.
// However, we artificially limit this to a smaller frame size, which gives us
@ -187,7 +189,7 @@ size_t run_mtu_plausibility_check(const size_t detected_mtu)
constexpr size_t MAX_1GBE_MTU_COERCE_VALUE = 1500; // bytes
if (detected_mtu > MIN_1GBE_MTU_COERCE_VALUE
&& detected_mtu < MAX_1GBE_MTU_COERCE_VALUE) {
UHD_LOG_DEBUG("MPMD",
UHD_LOG_DEBUG(LOG_ID,
"MTU discovery detected "
<< detected_mtu
<< " bytes. This may be due to a faulty MTU discovery. Coercing to "
@ -235,7 +237,7 @@ size_t discover_mtu(const std::string& address,
return dpdk_simple::make_broadcast(addr, port);
};
#else
UHD_LOG_WARNING("MPMD",
UHD_LOG_WARNING(LOG_ID,
"DPDK was requested but is not available, falling back to regular UDP");
#endif
}
@ -264,7 +266,7 @@ size_t discover_mtu(const std::string& address,
"discovery return packet!");
}
};
UHD_LOG_TRACE("MPMD", "Determining UDP MTU... ");
UHD_LOG_TRACE(LOG_ID, "Determining UDP MTU... ");
size_t seq_no = 0;
while (min_frame_size < max_frame_size) {
// Only test multiples of 4 bytes!
@ -280,7 +282,7 @@ size_t discover_mtu(const std::string& address,
";%04lu,%04lu",
seq_no++,
test_frame_size);
UHD_LOG_TRACE("MPMD", "Testing frame size " << test_frame_size);
UHD_LOG_TRACE(LOG_ID, "Testing frame size " << test_frame_size);
udp->send(boost::asio::buffer(&send_buf[0], test_frame_size));
const size_t len = udp->recv(boost::asio::buffer(recv_buf), echo_timeout);
@ -295,14 +297,14 @@ size_t discover_mtu(const std::string& address,
// This is an odd case. Something must have snipped the packet
// on the way back. Still, we'll just back off and try
// something smaller.
UHD_LOG_DEBUG("MPMD", "Unexpected packet truncation during MTU discovery.");
UHD_LOG_DEBUG(LOG_ID, "Unexpected packet truncation during MTU discovery.");
require_bufs_match(len);
max_frame_size = len;
}
}
min_frame_size = run_mtu_plausibility_check(min_frame_size);
UHD_LOG_DEBUG("MPMD", "Path MTU for address " << address << ": " << min_frame_size);
UHD_LOG_DEBUG(LOG_ID, "Path MTU for address " << address << ": " << min_frame_size);
return min_frame_size;
}
@ -324,11 +326,24 @@ mpmd_link_if_ctrl_udp::mpmd_link_if_ctrl_udp(const uhd::device_addr_t& mb_args,
mb_args.has_key("use_dpdk"); // FIXME use constrained_device_args
const std::string mpm_discovery_port = _mb_args.get(
mpmd_impl::MPM_DISCOVERY_PORT_KEY, std::to_string(mpmd_impl::MPM_DISCOVERY_PORT));
auto discover_mtu_for_ip = [mpm_discovery_port, use_dpdk](
const std::string& ip_addr, size_t max_frame_size) {
const bool force_mtu = mb_args.has_key("force_mtu");
if (force_mtu) {
_mtu = mb_args.cast<size_t>("force_mtu", MPMD_1GE_DATA_FRAME_MAX_SIZE)
& ~size_t(3);
UHD_LOG_INFO(LOG_ID,
"Using manual override to set MTU to: "
<< _mtu
<< " bytes. Note this may cause issues if Ethernet link is not "
"configured correspondingly.");
}
auto discover_mtu_for_ip = [mpm_discovery_port, use_dpdk](const std::string& ip_addr,
size_t min_frame_size,
size_t max_frame_size) {
return discover_mtu(ip_addr,
mpm_discovery_port,
IP_PROTOCOL_MIN_MTU_SIZE - IP_PROTOCOL_UDP_PLUS_IP_HEADER,
min_frame_size,
max_frame_size,
MPMD_MTU_DISCOVERY_TIMEOUT,
use_dpdk);
@ -347,11 +362,25 @@ mpmd_link_if_ctrl_udp::mpmd_link_if_ctrl_udp(const uhd::device_addr_t& mb_args,
<< std::to_string(info.if_mtu));
_mtu = std::min(_mtu, info.if_mtu);
} else {
_mtu = std::min(_mtu,
discover_mtu_for_ip(ip_addr,
info.link_rate == MAX_RATE_1GIGE
? MPMD_1GE_DATA_FRAME_MAX_SIZE
: MPMD_10GE_DATA_FRAME_MAX_SIZE));
if (force_mtu) {
// If force_mtu is set, we still do a single ping on the discovery
// port to test the validity of the connection, but we fix the MTU
// size. The (_mtu - 4) is to make the discovery algorithm
// work.
size_t discovered_mtu = discover_mtu_for_ip(ip_addr, _mtu - 4, _mtu);
if (discovered_mtu < _mtu) {
UHD_LOG_WARNING(LOG_ID,
"Manually set MTU " << _mtu << " failed to test on address "
<< ip_addr);
}
} else {
_mtu = std::min(_mtu,
discover_mtu_for_ip(ip_addr,
IP_PROTOCOL_MIN_MTU_SIZE - IP_PROTOCOL_UDP_PLUS_IP_HEADER,
info.link_rate == MAX_RATE_1GIGE
? MPMD_1GE_DATA_FRAME_MAX_SIZE
: MPMD_10GE_DATA_FRAME_MAX_SIZE));
}
}
_available_addrs.push_back(ip_addr);
} catch (const uhd::exception& ex) {
@ -423,7 +452,7 @@ uhd::transport::both_links_t mpmd_link_if_ctrl_udp::get_link(const size_t link_i
true,
enable_fc);
#else
UHD_LOG_WARNING("MPMD", "Cannot create DPDK transport, falling back to UDP");
UHD_LOG_WARNING(LOG_ID, "Cannot create DPDK transport, falling back to UDP");
#endif
}
auto link = uhd::transport::udp_boost_asio_link::make(ip_addr,