diff options
author | Martin Braun <martin.braun@ettus.com> | 2019-12-02 23:06:39 -0800 |
---|---|---|
committer | Brent Stapleton <brent.stapleton@ettus.com> | 2019-12-20 16:32:22 -0800 |
commit | 4547f2de85f0d8b258a89cea71af774fce8616b7 (patch) | |
tree | d1239e074c5a35b449638a34aa3a6f74a53adfbb /host/lib/usrp | |
parent | 4e38eef817813c1bbd8a9cf972e4cf0134d24308 (diff) | |
download | uhd-4547f2de85f0d8b258a89cea71af774fce8616b7.tar.gz uhd-4547f2de85f0d8b258a89cea71af774fce8616b7.tar.bz2 uhd-4547f2de85f0d8b258a89cea71af774fce8616b7.zip |
x300,mpmd: Enable DPDK
x300:
- Remove obsolete variables from x300_eth_mgr and X300 motherboard
components
- Added some documentation / comments
- Use constrained device args in more places
- Enables the use of use_dpdk=1
- Switches between regular (kernel-based) and DPDK UDP
mpmd:
- Merge link_if_ctrl for udp and dpdk_udp
- Update cmake options
Diffstat (limited to 'host/lib/usrp')
-rw-r--r-- | host/lib/usrp/mpmd/CMakeLists.txt | 30 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_find.cpp | 10 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp | 279 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp | 48 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.cpp | 126 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.hpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_link_if_mgr.cpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/x300/CMakeLists.txt | 4 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_eth_mgr.cpp | 152 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_eth_mgr.hpp | 23 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.hpp | 1 |
12 files changed, 216 insertions, 465 deletions
diff --git a/host/lib/usrp/mpmd/CMakeLists.txt b/host/lib/usrp/mpmd/CMakeLists.txt index ce06913a3..1eab1f39b 100644 --- a/host/lib/usrp/mpmd/CMakeLists.txt +++ b/host/lib/usrp/mpmd/CMakeLists.txt @@ -1,21 +1,11 @@ # # Copyright 2017 Ettus Research, a National Instruments Company +# Copyright 2019 Ettus Research, a National Instruments Brand # # SPDX-License-Identifier: GPL-3.0-or-later # if(ENABLE_MPMD) - if(ENABLE_LIBERIO) - message(STATUS "Compiling MPMD with liberio support...") - add_definitions(-DHAVE_LIBERIO) - endif(ENABLE_LIBERIO) - - if(ENABLE_DPDK) - message(STATUS "Compiling MPMD without DPDK support for now...") - # message(STATUS "Compiling MPMD with DPDK support...") - # add_definitions(-DHAVE_DPDK) - endif(ENABLE_DPDK) - LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_find.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_image_loader.cpp @@ -29,15 +19,23 @@ if(ENABLE_MPMD) ) if(ENABLE_LIBERIO) + message(STATUS "Compiling MPMD with liberio support...") LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_link_if_ctrl_liberio.cpp ) + set_property( + SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_link_if_mgr.cpp + PROPERTY COMPILE_DEFINITIONS HAVE_LIBERIO + ) endif(ENABLE_LIBERIO) - # if(ENABLE_DPDK) - # LIBUHD_APPEND_SOURCES( - # ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_link_if_ctrl_dpdk_udp.cpp - # ) - # endif(ENABLE_DPDK) + if(ENABLE_DPDK) + set_property( + SOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_link_if_ctrl_udp.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_find.cpp + PROPERTY COMPILE_DEFINITIONS HAVE_DPDK + ) + endif(ENABLE_DPDK) endif(ENABLE_MPMD) diff --git a/host/lib/usrp/mpmd/mpmd_find.cpp b/host/lib/usrp/mpmd/mpmd_find.cpp index 3e8bcc72f..b5f20559c 100644 --- a/host/lib/usrp/mpmd/mpmd_find.cpp +++ b/host/lib/usrp/mpmd/mpmd_find.cpp @@ -9,13 +9,15 @@ #include "mpmd_devices.hpp" #include "mpmd_impl.hpp" #include "mpmd_link_if_mgr.hpp" -#include <uhdlib/transport/dpdk_common.hpp> #include <uhd/transport/if_addrs.hpp> #include <uhd/transport/udp_simple.hpp> #include <uhd/types/device_addr.hpp> #include <boost/algorithm/string.hpp> #include <boost/asio.hpp> #include <future> +#ifdef HAVE_DPDK +# include <uhdlib/transport/dpdk/common.hpp> +#endif using namespace uhd; using namespace uhd::mpmd; @@ -198,9 +200,9 @@ device_addrs_t mpmd_find(const device_addr_t& hint_) #ifdef HAVE_DPDK // Start DPDK so links come up if (hint_.has_key("use_dpdk")) { - auto& dpdk_ctx = uhd::transport::uhd_dpdk_ctx::get(); - if (not dpdk_ctx.is_init_done()) { - dpdk_ctx.init(hint_); + auto dpdk_ctx = uhd::transport::dpdk::dpdk_ctx::get(); + if (not dpdk_ctx->is_init_done()) { + dpdk_ctx->init(hint_); } } #endif diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp deleted file mode 100644 index 2a3a48b62..000000000 --- a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp +++ /dev/null @@ -1,279 +0,0 @@ -// -// Copyright 2017 Ettus Research, National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "mpmd_impl.hpp" -#include "mpmd_link_if_mgr.hpp" -#include "mpmd_link_if_ctrl_dpdk_udp.hpp" -#include <uhd/transport/udp_simple.hpp> -#include <uhd/transport/udp_constants.hpp> -#include <uhdlib/transport/dpdk_zero_copy.hpp> -#include <arpa/inet.h> - - -using namespace uhd; -using namespace uhd::mpmd::xport; - -namespace { -constexpr unsigned int MPMD_UDP_RESERVED_FRAME_SIZE = 64; - -//! Maximum CHDR packet size in bytes -const size_t MPMD_10GE_DATA_FRAME_MAX_SIZE = 4000; -const size_t MPMD_10GE_DATA_FRAME_DEFAULT_SIZE = 4000; -const size_t MPMD_10GE_MSG_FRAME_DEFAULT_SIZE = 256; - -//! Number of send/recv frames -const size_t MPMD_ETH_NUM_SEND_FRAMES = 32; -const size_t MPMD_ETH_NUM_RECV_FRAMES = 128; -const size_t MPMD_ETH_NUM_CTRL_FRAMES = 32; - -//! For MTU discovery, the time we wait for a packet before calling it -// oversized (seconds). -const double MPMD_MTU_DISCOVERY_TIMEOUT = 0.02; - -std::vector<std::string> get_addrs_from_mb_args( - const uhd::device_addr_t& mb_args -) { - // mb_args must always include addr - if (not mb_args.has_key(FIRST_ADDR_KEY)) { - throw uhd::runtime_error("The " + FIRST_ADDR_KEY + " key must be specified in " - "device args to create an Ethernet transport to an RFNoC block"); - } - std::vector<std::string> addrs{mb_args[FIRST_ADDR_KEY]}; - if (mb_args.has_key(SECOND_ADDR_KEY)){ - addrs.push_back(mb_args[SECOND_ADDR_KEY]); - } - return addrs; -} - -/*! Do a binary search to discover MTU - * - * Uses the MPM echo service to figure out MTU. We simply send a bunch of - * packets and see if they come back until we converged on the path MTU. - * The end result must lie between \p min_frame_size and \p max_frame_size. - * - * \param address IP address - * \param port UDP port - * \param min_frame_size Minimum frame size, initialize algorithm to start - * with this value - * \param max_frame_size Maximum frame size, initialize algorithm to start - * with this value - * \param echo_timeout Timeout value in seconds. For frame sizes that - * exceed the MTU, we don't expect a response, and this - * is the amount of time we'll wait before we assume - * the frame size exceeds the MTU. - */ -size_t discover_mtu( - const std::string &address, - const std::string &port, - size_t min_frame_size, - size_t max_frame_size, - const double echo_timeout = 0.020 -) { - const auto &ctx = uhd::transport::uhd_dpdk_ctx::get(); - const size_t echo_prefix_offset = - uhd::mpmd::mpmd_impl::MPM_ECHO_CMD.size(); - const size_t mtu_hdr_len = echo_prefix_offset + 10; - const int port_id = ctx.get_route(address); - UHD_ASSERT_THROW(port_id >= 0); - UHD_ASSERT_THROW(min_frame_size < max_frame_size); - UHD_ASSERT_THROW(min_frame_size % 4 == 0); - UHD_ASSERT_THROW(max_frame_size % 4 == 0); - UHD_ASSERT_THROW(min_frame_size >= echo_prefix_offset + mtu_hdr_len); - using namespace uhd::transport; - uhd::transport::zero_copy_xport_params buff_args; - buff_args.recv_frame_size = max_frame_size; - buff_args.send_frame_size = max_frame_size; - buff_args.num_send_frames = 1; - buff_args.num_recv_frames = 1; - auto dev_addr = uhd::device_addr_t(); - dpdk_zero_copy::sptr sock = dpdk_zero_copy::make(ctx, - (unsigned int) port_id, address, port, "0", buff_args, dev_addr); - std::string send_buf(uhd::mpmd::mpmd_impl::MPM_ECHO_CMD); - send_buf.resize(max_frame_size, '#'); - UHD_ASSERT_THROW(send_buf.size() == max_frame_size); - - // Little helper to check returned packets match the sent ones - auto require_bufs_match = [&send_buf, mtu_hdr_len]( - const uint8_t *recv_buf, - const size_t len - ){ - if (len < mtu_hdr_len or std::memcmp( - (void *) &recv_buf[0], - (void *) &send_buf[0], - mtu_hdr_len - ) != 0) { - throw uhd::runtime_error("Unexpected content of MTU " - "discovery return packet!"); - } - }; - UHD_LOG_TRACE("MPMD", "Determining UDP MTU... "); - size_t seq_no = 0; - while (min_frame_size < max_frame_size) { - managed_send_buffer::sptr msbuf = sock->get_send_buff(0); - UHD_ASSERT_THROW(msbuf.get() != nullptr); - max_frame_size = std::min(msbuf->size(), max_frame_size); - // Only test multiples of 4 bytes! - const size_t test_frame_size = - (max_frame_size/2 + min_frame_size/2 + 3) & ~size_t(3); - // Encode sequence number and current size in the string, makes it - // easy to debug in code or Wireshark. Is also used for identifying - // response packets. - std::sprintf( - &send_buf[echo_prefix_offset], - ";%04lu,%04lu", - seq_no++, - test_frame_size - ); - // Copy to real buffer - UHD_LOG_TRACE("MPMD", "Testing frame size " << test_frame_size); - auto *tx_buf = msbuf->cast<uint8_t *>(); - std::memcpy(tx_buf, &send_buf[0], test_frame_size); - msbuf->commit(test_frame_size); - msbuf.reset(); - - managed_recv_buffer::sptr mrbuf = sock->get_recv_buff(echo_timeout); - if (mrbuf.get() == nullptr || mrbuf->size() == 0) { - // Nothing received, so this is probably too big - max_frame_size = test_frame_size - 4; - } else if (mrbuf->size() >= test_frame_size) { - // Size went through, so bump the minimum - require_bufs_match(mrbuf->cast<uint8_t *>(), mrbuf->size()); - min_frame_size = test_frame_size; - } else if (mrbuf->size() < test_frame_size) { - // 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."); - require_bufs_match(mrbuf->cast<uint8_t *>(), mrbuf->size()); - max_frame_size = mrbuf->size(); - } - mrbuf.reset(); - } - UHD_LOG_DEBUG("MPMD", - "Path MTU for address " << address << ": " << min_frame_size); - return min_frame_size; -} - -} - - -mpmd_link_if_ctrl_dpdk_udp::mpmd_link_if_ctrl_dpdk_udp( - const uhd::device_addr_t& mb_args -) : _mb_args(mb_args) - , _ctx(uhd::transport::uhd_dpdk_ctx::get()) - , _recv_args(filter_args(mb_args, "recv")) - , _send_args(filter_args(mb_args, "send")) - , _available_addrs(get_addrs_from_mb_args(mb_args)) - , _mtu(MPMD_10GE_DATA_FRAME_MAX_SIZE) -{ - if (not _ctx.is_init_done()) { - _ctx.init(mb_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](const std::string &ip_addr){ - return discover_mtu( - ip_addr, - mpm_discovery_port, - IP_PROTOCOL_MIN_MTU_SIZE-IP_PROTOCOL_UDP_PLUS_IP_HEADER, - MPMD_10GE_DATA_FRAME_MAX_SIZE, - MPMD_MTU_DISCOVERY_TIMEOUT - ); - }; - - for (const auto &ip_addr : _available_addrs) { - _mtu = std::min(_mtu, discover_mtu_for_ip(ip_addr)); - } -} - -// uhd::both_xports_t -// mpmd_link_if_ctrl_dpdk_udp::make_transport( -// mpmd_link_if_mgr::xport_info_t &xport_info, -// const uhd::transport::link_type_t xport_type, -// const uhd::device_addr_t& xport_args -//) { - -//// Constrain by this transport's MTU and the MTU in the xport_args -// const size_t send_mtu = std::min(get_mtu(uhd::TX_DIRECTION), -// xport_args.cast<size_t>("mtu", get_mtu(uhd::TX_DIRECTION))); -// const size_t recv_mtu = std::min(get_mtu(uhd::RX_DIRECTION), -// xport_args.cast<size_t>("mtu", get_mtu(uhd::RX_DIRECTION))); - -//// Create actual UHD-DPDK UDP transport -// transport::zero_copy_xport_params default_buff_args; -// default_buff_args.num_recv_frames = MPMD_ETH_NUM_CTRL_FRAMES; -// default_buff_args.num_send_frames = MPMD_ETH_NUM_CTRL_FRAMES; -// default_buff_args.recv_frame_size = MPMD_10GE_MSG_FRAME_DEFAULT_SIZE; -// default_buff_args.send_frame_size = MPMD_10GE_MSG_FRAME_DEFAULT_SIZE; - -// if (xport_type == uhd::transport::link_type_t::RX_DATA) { -// default_buff_args.num_recv_frames = -// xport_args.cast<size_t>("num_recv_frames", MPMD_ETH_NUM_RECV_FRAMES); -// default_buff_args.recv_frame_size = std::min( -// xport_args.cast<size_t>("recv_frame_size", -// MPMD_10GE_DATA_FRAME_DEFAULT_SIZE), -// recv_mtu); -//} else if (xport_type == uhd::transport::link_type_t::TX_DATA) { -// default_buff_args.num_send_frames = -// xport_args.cast<size_t>("num_send_frames", MPMD_ETH_NUM_SEND_FRAMES); -// default_buff_args.send_frame_size = std::min( -// xport_args.cast<size_t>("send_frame_size", -// MPMD_10GE_DATA_FRAME_DEFAULT_SIZE), -// send_mtu); -//} - -// UHD_LOG_TRACE("BUFF", "num_recv_frames=" << default_buff_args.num_recv_frames -//<< ", num_send_frames=" << default_buff_args.num_send_frames -//<< ", recv_frame_size=" << default_buff_args.recv_frame_size -//<< ", send_frame_size=" << default_buff_args.send_frame_size); - -// int dpdk_port_id = _ctx.get_route(xport_info["ipv4"]); -// if (dpdk_port_id < 0) { -// throw uhd::runtime_error("Could not find a DPDK port with route to " + -// xport_info["ipv4"]); -//} -// auto recv = transport::dpdk_zero_copy::make( -//_ctx, -//(const unsigned int) dpdk_port_id, -// xport_info["ipv4"], -// xport_info["port"], -//"0", -// default_buff_args, -// uhd::device_addr_t() -//); -// const uint16_t port = recv->get_local_port(); -// const std::string src_ip_addr = recv->get_local_addr(); -// xport_info["src_port"] = std::to_string(port); -// xport_info["src_ipv4"] = src_ip_addr; - -//// Create both_xports_t object and finish: -// both_xports_t xports; -// xports.endianness = uhd::ENDIANNESS_BIG; -// xports.send_sid = sid_t(xport_info["send_sid"]); -// xports.recv_sid = xports.send_sid.reversed(); -// xports.recv_buff_size = -// (default_buff_args.recv_frame_size-MPMD_UDP_RESERVED_FRAME_SIZE)*default_buff_args.num_recv_frames; -// xports.send_buff_size = -// (default_buff_args.send_frame_size-MPMD_UDP_RESERVED_FRAME_SIZE)*default_buff_args.num_send_frames; -// xports.recv = recv; // Note: This is a type cast! -// xports.send = recv; // This too -// return xports; -//} - -bool mpmd_link_if_ctrl_dpdk_udp::is_valid( - const mpmd_link_if_mgr::xport_info_t& xport_info -) const { - int dpdk_port_id = _ctx.get_route(xport_info.at("ipv4")); - return (dpdk_port_id >= 0); -} - -size_t mpmd_link_if_ctrl_dpdk_udp::get_mtu(const uhd::direction_t /*dir*/) const -{ - return _mtu; -} diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp deleted file mode 100644 index 8f4f1c7d1..000000000 --- a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_MPMD_XPORT_CTRL_DPDK_UDP_HPP -#define INCLUDED_MPMD_XPORT_CTRL_DPDK_UDP_HPP - -#include "mpmd_link_if_ctrl_base.hpp" -#include <uhd/types/device_addr.hpp> -#include <uhdlib/transport/dpdk_zero_copy.hpp> - -namespace uhd { namespace mpmd { namespace xport { - -/*! UDP transport manager - * - * Opens UDP sockets - */ -class mpmd_link_if_ctrl_dpdk_udp : public mpmd_link_if_ctrl_base -{ -public: - mpmd_link_if_ctrl_dpdk_udp( - const uhd::device_addr_t& mb_args - ); - - bool is_valid( - const mpmd_link_if_mgr::xport_info_t& xport_info - ) const; - - size_t get_mtu( - const uhd::direction_t dir - ) const; - -private: - const uhd::device_addr_t _mb_args; - uhd::transport::uhd_dpdk_ctx &_ctx; - const uhd::dict<std::string, std::string> _recv_args; - const uhd::dict<std::string, std::string> _send_args; - //! A list of IP addresses we can connect our CHDR connections to - const std::vector<std::string> _available_addrs; - //! MTU - size_t _mtu; -}; - -}}} /* namespace uhd::mpmd::xport */ - -#endif /* INCLUDED_MPMD_XPORT_CTRL_DPDK_UDP_HPP */ diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.cpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.cpp index a87a9cada..aeb1c6436 100644 --- a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.cpp +++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.cpp @@ -1,5 +1,6 @@ // // Copyright 2017 Ettus Research, National Instruments Company +// Copyright 2019 Ettus Research, National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // @@ -16,6 +17,10 @@ #include <uhdlib/transport/udp_common.hpp> #include <uhdlib/utils/narrow.hpp> #include <string> +#ifdef HAVE_DPDK +//# include <uhdlib/transport/dpdk_simple.hpp> +# include <uhdlib/transport/udp_dpdk_link.hpp> +#endif using namespace uhd; using namespace uhd::transport; @@ -124,8 +129,19 @@ size_t discover_mtu(const std::string& address, const std::string& port, size_t min_frame_size, size_t max_frame_size, - const double echo_timeout = 0.020) + const double echo_timeout, + const bool use_dpdk) { + if (use_dpdk) { +#ifdef HAVE_DPDK + // FIXME + UHD_LOG_WARNING("MPMD", "Using hard-coded MTU of 8000 for DPDK"); + return 8000; +#else + UHD_LOG_WARNING("MPMD", + "DPDK was requested but is not available, falling back to regular UDP"); +#endif + } const size_t echo_prefix_offset = uhd::mpmd::mpmd_impl::MPM_ECHO_CMD.size(); const size_t mtu_hdr_len = echo_prefix_offset + 10; UHD_ASSERT_THROW(min_frame_size < max_frame_size); @@ -186,6 +202,87 @@ size_t discover_mtu(const std::string& address, return min_frame_size; } +// DPDK version +//size_t discover_mtu(const std::string& address, + //const std::string& port, + //size_t min_frame_size, + //size_t max_frame_size, + //const double echo_timeout = 0.020) +//{ + //const auto& ctx = uhd::transport::uhd_dpdk_ctx::get(); + //const size_t echo_prefix_offset = uhd::mpmd::mpmd_impl::MPM_ECHO_CMD.size(); + //const size_t mtu_hdr_len = echo_prefix_offset + 10; + //const int port_id = ctx.get_route(address); + //UHD_ASSERT_THROW(port_id >= 0); + //UHD_ASSERT_THROW(min_frame_size < max_frame_size); + //UHD_ASSERT_THROW(min_frame_size % 4 == 0); + //UHD_ASSERT_THROW(max_frame_size % 4 == 0); + //UHD_ASSERT_THROW(min_frame_size >= echo_prefix_offset + mtu_hdr_len); + //using namespace uhd::transport; + //uhd::transport::zero_copy_xport_params buff_args; + //buff_args.recv_frame_size = max_frame_size; + //buff_args.send_frame_size = max_frame_size; + //buff_args.num_send_frames = 1; + //buff_args.num_recv_frames = 1; + //auto dev_addr = uhd::device_addr_t(); + //dpdk_zero_copy::sptr sock = dpdk_zero_copy::make( + //ctx, (unsigned int)port_id, address, port, "0", buff_args, dev_addr); + //std::string send_buf(uhd::mpmd::mpmd_impl::MPM_ECHO_CMD); + //send_buf.resize(max_frame_size, '#'); + //UHD_ASSERT_THROW(send_buf.size() == max_frame_size); + + //// Little helper to check returned packets match the sent ones + //auto require_bufs_match = [&send_buf, mtu_hdr_len]( + //const uint8_t* recv_buf, const size_t len) { + //if (len < mtu_hdr_len + //or std::memcmp((void*)&recv_buf[0], (void*)&send_buf[0], mtu_hdr_len) != 0) { + //throw uhd::runtime_error("Unexpected content of MTU " + //"discovery return packet!"); + //} + //}; + //UHD_LOG_TRACE("MPMD", "Determining UDP MTU... "); + //size_t seq_no = 0; + //while (min_frame_size < max_frame_size) { + //managed_send_buffer::sptr msbuf = sock->get_send_buff(0); + //UHD_ASSERT_THROW(msbuf.get() != nullptr); + //max_frame_size = std::min(msbuf->size(), max_frame_size); + //// Only test multiples of 4 bytes! + //const size_t test_frame_size = (max_frame_size / 2 + min_frame_size / 2 + 3) + //& ~size_t(3); + //// Encode sequence number and current size in the string, makes it + //// easy to debug in code or Wireshark. Is also used for identifying + //// response packets. + //std::sprintf( + //&send_buf[echo_prefix_offset], ";%04lu,%04lu", seq_no++, test_frame_size); + //// Copy to real buffer + //UHD_LOG_TRACE("MPMD", "Testing frame size " << test_frame_size); + //auto* tx_buf = msbuf->cast<uint8_t*>(); + //std::memcpy(tx_buf, &send_buf[0], test_frame_size); + //msbuf->commit(test_frame_size); + //msbuf.reset(); + + //managed_recv_buffer::sptr mrbuf = sock->get_recv_buff(echo_timeout); + //if (mrbuf.get() == nullptr || mrbuf->size() == 0) { + //// Nothing received, so this is probably too big + //max_frame_size = test_frame_size - 4; + //} else if (mrbuf->size() >= test_frame_size) { + //// Size went through, so bump the minimum + //require_bufs_match(mrbuf->cast<uint8_t*>(), mrbuf->size()); + //min_frame_size = test_frame_size; + //} else if (mrbuf->size() < test_frame_size) { + //// 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."); + //require_bufs_match(mrbuf->cast<uint8_t*>(), mrbuf->size()); + //max_frame_size = mrbuf->size(); + //} + //mrbuf.reset(); + //} + //UHD_LOG_DEBUG("MPMD", "Path MTU for address " << address << ": " << min_frame_size); + //return min_frame_size; +//} + } // namespace @@ -198,14 +295,16 @@ mpmd_link_if_ctrl_udp::mpmd_link_if_ctrl_udp(const uhd::device_addr_t& mb_args, , _udp_info(get_udp_info_from_xport_info(xport_info)) , _mtu(MPMD_10GE_DATA_FRAME_MAX_SIZE) { + const bool use_dpdk = 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](const std::string& ip_addr) { + auto discover_mtu_for_ip = [mpm_discovery_port, use_dpdk](const std::string& ip_addr) { return discover_mtu(ip_addr, mpm_discovery_port, IP_PROTOCOL_MIN_MTU_SIZE - IP_PROTOCOL_UDP_PLUS_IP_HEADER, MPMD_10GE_DATA_FRAME_MAX_SIZE, - MPMD_MTU_DISCOVERY_TIMEOUT); + MPMD_MTU_DISCOVERY_TIMEOUT, + use_dpdk); }; const std::vector<std::string> requested_addrs( @@ -259,19 +358,26 @@ uhd::transport::both_links_t mpmd_link_if_ctrl_udp::get_link(const size_t link_i link_args); // Enforce a minimum bound of the number of receive and send frames. - link_params.num_send_frames = std::max(uhd::rfnoc::MIN_NUM_FRAMES, link_params.num_send_frames); - link_params.num_recv_frames = std::max(uhd::rfnoc::MIN_NUM_FRAMES, link_params.num_recv_frames); + link_params.num_send_frames = + std::max(uhd::rfnoc::MIN_NUM_FRAMES, link_params.num_send_frames); + link_params.num_recv_frames = + std::max(uhd::rfnoc::MIN_NUM_FRAMES, link_params.num_recv_frames); + if (_mb_args.has_key("use_dpdk")) { // FIXME use constrained device args +#ifdef HAVE_DPDK + auto link = uhd::transport::udp_dpdk_link::make(ip_addr, udp_port, link_params); + return std::make_tuple( + link, link_params.send_buff_size, link, link_params.recv_buff_size, true); +#else + UHD_LOG_WARNING("X300", "Cannot create DPDK transport, falling back to UDP"); +#endif + } auto link = uhd::transport::udp_boost_asio_link::make(ip_addr, udp_port, link_params, link_params.recv_buff_size, link_params.send_buff_size); - return std::tuple<send_link_if::sptr, - size_t, - recv_link_if::sptr, - size_t, - bool>( + return std::make_tuple( link, link_params.send_buff_size, link, link_params.recv_buff_size, true); } diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.hpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.hpp index 33db83b47..c80f1e613 100644 --- a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.hpp +++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_udp.hpp @@ -14,7 +14,7 @@ namespace uhd { namespace mpmd { namespace xport { -/*! UDP link interface controller +/*! UDP link interface controller (for both kernel-based UDP and DPDK) * * Opens UDP sockets */ diff --git a/host/lib/usrp/mpmd/mpmd_link_if_mgr.cpp b/host/lib/usrp/mpmd/mpmd_link_if_mgr.cpp index 6bb6cae3a..4b36e7ba4 100644 --- a/host/lib/usrp/mpmd/mpmd_link_if_mgr.cpp +++ b/host/lib/usrp/mpmd/mpmd_link_if_mgr.cpp @@ -12,9 +12,6 @@ #ifdef HAVE_LIBERIO # include "mpmd_link_if_ctrl_liberio.hpp" #endif -#ifdef HAVE_DPDK -# include "mpmd_link_if_ctrl_dpdk_udp.hpp" -#endif uhd::dict<std::string, std::string> uhd::mpmd::xport::filter_args( const uhd::device_addr_t& args, const std::string& prefix) diff --git a/host/lib/usrp/x300/CMakeLists.txt b/host/lib/usrp/x300/CMakeLists.txt index 1bd71dab4..b00ee357c 100644 --- a/host/lib/usrp/x300/CMakeLists.txt +++ b/host/lib/usrp/x300/CMakeLists.txt @@ -35,4 +35,8 @@ if(ENABLE_X300) ${CMAKE_CURRENT_SOURCE_DIR}/x300_prop_tree.cpp ${CMAKE_CURRENT_SOURCE_DIR}/cdecode.c ) + + if(ENABLE_DPDK) + add_definitions(-DHAVE_DPDK) + endif(ENABLE_DPDK) endif(ENABLE_X300) diff --git a/host/lib/usrp/x300/x300_eth_mgr.cpp b/host/lib/usrp/x300/x300_eth_mgr.cpp index 7177032c6..fd826e484 100644 --- a/host/lib/usrp/x300/x300_eth_mgr.cpp +++ b/host/lib/usrp/x300/x300_eth_mgr.cpp @@ -7,6 +7,7 @@ #include "x300_eth_mgr.hpp" #include "x300_claim.hpp" #include "x300_defaults.hpp" +#include "x300_device_args.hpp" #include "x300_fw_common.h" #include "x300_mb_eeprom.hpp" #include "x300_mb_eeprom_iface.hpp" @@ -17,16 +18,17 @@ #include <uhd/transport/udp_constants.hpp> #include <uhd/transport/udp_simple.hpp> #include <uhd/transport/udp_zero_copy.hpp> +#include <uhd/utils/algorithm.hpp> #include <uhd/utils/byteswap.hpp> #include <uhdlib/rfnoc/device_id.hpp> #include <uhdlib/rfnoc/rfnoc_common.hpp> #include <uhdlib/transport/udp_boost_asio_link.hpp> #include <uhdlib/transport/udp_common.hpp> #include <uhdlib/usrp/cores/i2c_core_100_wb32.hpp> -//#ifdef HAVE_DPDK -//# include <uhdlib/transport/dpdk_simple.hpp> -//# include <uhdlib/transport/dpdk_zero_copy.hpp> -//#endif +#ifdef HAVE_DPDK +# include <uhdlib/transport/dpdk_simple.hpp> +# include <uhdlib/transport/udp_dpdk_link.hpp> +#endif #include <boost/asio.hpp> #include <string> @@ -69,42 +71,41 @@ constexpr size_t MAX_RATE_1GIGE = (size_t)( // bytes/s /****************************************************************************** * Static Methods *****************************************************************************/ -eth_manager::udp_simple_factory_t eth_manager::x300_get_udp_factory( - const device_addr_t& args) +eth_manager::udp_simple_factory_t eth_manager::x300_get_udp_factory(const bool use_dpdk) { udp_simple_factory_t udp_make_connected = udp_simple::make_connected; - if (args.has_key("use_dpdk")) { -//#ifdef HAVE_DPDK -// udp_make_connected = [](const std::string& addr, const std::string& port) { -// auto& ctx = uhd::transport::uhd_dpdk_ctx::get(); -// return dpdk_simple::make_connected(ctx, addr, port); -// }; -//#else + if (use_dpdk) { +#ifdef HAVE_DPDK + udp_make_connected = [](const std::string& addr, const std::string& port) { + return dpdk_simple::make_connected(addr, port); + }; +#else UHD_LOG_WARNING( "DPDK", "Detected use_dpdk argument, but DPDK support not built in."); -//#endif +#endif } return udp_make_connected; } device_addrs_t eth_manager::find(const device_addr_t& hint) { + x300_device_args_t hint_args; + hint_args.parse(hint); + udp_simple_factory_t udp_make_broadcast = udp_simple::make_broadcast; - udp_simple_factory_t udp_make_connected = x300_get_udp_factory(hint); + udp_simple_factory_t udp_make_connected = + x300_get_udp_factory(hint_args.get_use_dpdk()); #ifdef HAVE_DPDK - if (hint.has_key("use_dpdk")) { -// auto& dpdk_ctx = uhd::transport::uhd_dpdk_ctx::get(); -// if (not dpdk_ctx.is_init_done()) { -// dpdk_ctx.init(hint); -// } -// udp_make_broadcast = [](const std::string& addr, const std::string& port) { -// auto& ctx = uhd::transport::uhd_dpdk_ctx::get(); -// return dpdk_simple::make_broadcast(ctx, addr, port); -// }; + if (hint_args.get_use_dpdk()) { + auto dpdk_ctx = uhd::transport::dpdk::dpdk_ctx::get(); + if (not dpdk_ctx->is_init_done()) { + dpdk_ctx->init(hint); + } + udp_make_broadcast = dpdk_simple::make_broadcast; } #endif - udp_simple::sptr comm = - udp_make_broadcast(hint["addr"], BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)); + udp_simple::sptr comm = udp_make_broadcast( + hint_args.get_first_addr(), BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)); // load request struct x300_fw_comms_t request = x300_fw_comms_t(); @@ -177,9 +178,8 @@ device_addrs_t eth_manager::find(const device_addr_t& hint) /****************************************************************************** * Structors *****************************************************************************/ -eth_manager::eth_manager(const x300_device_args_t& args, - uhd::property_tree::sptr tree, - const uhd::fs_path& root_path) +eth_manager::eth_manager( + const x300_device_args_t& args, uhd::property_tree::sptr, const uhd::fs_path&) : _args(args) { UHD_ASSERT_THROW(!args.get_first_addr().empty()); @@ -201,10 +201,7 @@ eth_manager::eth_manager(const x300_device_args_t& args, _local_device_ids.push_back(device_id); eth_conns[device_id] = init; - _x300_make_udp_connected = x300_get_udp_factory(dev_addr); - - tree->create<double>(root_path / "link_max_rate").set(10e9); - _tree = tree->subtree(root_path); + _x300_make_udp_connected = x300_get_udp_factory(args.get_use_dpdk()); } both_links_t eth_manager::get_links(link_type_t link_type, @@ -213,12 +210,13 @@ both_links_t eth_manager::get_links(link_type_t link_type, const sep_id_t& /*remote_epid*/, const device_addr_t& link_args) { - if (std::find(_local_device_ids.cbegin(), _local_device_ids.cend(), local_device_id) - == _local_device_ids.cend()) { - throw uhd::runtime_error( - std::string("[X300] Cannot create Ethernet link through local device ID ") + if (!uhd::has(_local_device_ids, local_device_id)) { + const std::string err_msg = + std::string("Cannot create Ethernet link through local device ID ") + std::to_string(local_device_id) - + ", no such device associated with this motherboard!"); + + ", no such device associated with this motherboard!"; + UHD_LOG_ERROR("X300", err_msg); + throw uhd::runtime_error(err_msg); } // FIXME: We now need to properly associate local_device_id with the right // entry in eth_conn. We should probably do the load balancing elsewhere, @@ -236,56 +234,6 @@ both_links_t eth_manager::get_links(link_type_t link_type, default_buff_args.send_frame_size = std::min(send_mtu, ETH_MSG_FRAME_SIZE); default_buff_args.recv_frame_size = std::min(recv_mtu, ETH_MSG_FRAME_SIZE); - if (_args.get_use_dpdk()) { -//#ifdef HAVE_DPDK - // auto& dpdk_ctx = uhd::transport::uhd_dpdk_ctx::get(); - -// default_buff_args.num_recv_frames = ETH_MSG_NUM_FRAMES; -// default_buff_args.num_send_frames = ETH_MSG_NUM_FRAMES; -// if (link_type == link_type_t::CTRL) { -//// Increasing number of recv frames here because ctrl_iface uses it -//// to determine how many control packets can be in flight before it -//// must wait for an ACK -// default_buff_args.num_recv_frames = -// uhd::rfnoc::CMD_FIFO_SIZE / uhd::rfnoc::MAX_CMD_PKT_SIZE; -//} else if (xport_type == uhd::transport::link_type_t::TX_DATA) { -// size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE -//? GE_DATA_FRAME_SEND_SIZE -//: XGE_DATA_FRAME_SEND_SIZE; -// default_buff_args.send_frame_size = args.cast<size_t>( -//"send_frame_size", std::min(default_frame_size, send_mtu)); -// default_buff_args.num_send_frames = -// args.cast<size_t>("num_send_frames", default_buff_args.num_send_frames); -// default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0); -//} else if (xport_type == uhd::transport::link_type_t::RX_DATA) { -// size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE -//? GE_DATA_FRAME_RECV_SIZE -//: XGE_DATA_FRAME_RECV_SIZE; -// default_buff_args.recv_frame_size = args.cast<size_t>( -//"recv_frame_size", std::min(default_frame_size, recv_mtu)); -// default_buff_args.num_recv_frames = -// args.cast<size_t>("num_recv_frames", default_buff_args.num_recv_frames); -// default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0); -//} - -// int dpdk_port_id = dpdk_ctx.get_route(conn.addr); -// if (dpdk_port_id < 0) { -// throw uhd::runtime_error( -//"Could not find a DPDK port with route to " + conn.addr); -//} -// auto recv = transport::dpdk_zero_copy::make(dpdk_ctx, -//(const unsigned int)dpdk_port_id, -// conn.addr, -// BOOST_STRINGIZE(X300_VITA_UDP_PORT), -//"0", -// default_buff_args, -// uhd::device_addr_t()); - -//#else - UHD_LOG_WARNING("X300", "Cannot create DPDK transport, falling back to UDP"); -//#endif - } - // Buffering is done in the socket buffers, so size them relative to // the link rate link_params_t default_link_params; @@ -315,7 +263,19 @@ both_links_t eth_manager::get_links(link_type_t link_type, link_params.num_send_frames = std::max(uhd::rfnoc::MIN_NUM_FRAMES, link_params.num_send_frames); link_params.num_recv_frames = std::max(uhd::rfnoc::MIN_NUM_FRAMES, link_params.num_recv_frames); + // Dummy variables for populating the return tuple size_t recv_buff_size, send_buff_size; + if (_args.get_use_dpdk()) { +#ifdef HAVE_DPDK + auto link = uhd::transport::udp_dpdk_link::make( + conn.addr, BOOST_STRINGIZE(X300_VITA_UDP_PORT), link_params); + return std::make_tuple(link, send_buff_size, link, recv_buff_size, true); +#else + UHD_LOG_WARNING("X300", "Cannot create DPDK transport, falling back to UDP"); +#endif + } + + // No DPDK, then return regular/kernel UDP auto link = uhd::transport::udp_boost_asio_link::make(conn.addr, BOOST_STRINGIZE(X300_VITA_UDP_PORT), link_params, @@ -333,11 +293,10 @@ wb_iface::sptr eth_manager::get_ctrl_iface() get_pri_eth().addr, BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT))); } +// - Populates _max_frame_sizes void eth_manager::init_link( const mboard_eeprom_t& mb_eeprom, const std::string& loaded_fpga_image) { - double link_max_rate = 0.0; - // Discover ethernet interfaces on the device discover_eth(mb_eeprom, loaded_fpga_image); @@ -392,6 +351,8 @@ void eth_manager::init_link( UHD_LOGGER_ERROR("X300") << e.what(); } + // Check actual frame sizes against user-requested frame sizes, and print + // warnings if they don't match if ((recv_args.has_key("recv_frame_size")) && (req_max_frame_size.recv_frame_size > _max_frame_sizes.recv_frame_size)) { UHD_LOGGER_WARNING("X300") @@ -416,11 +377,10 @@ void eth_manager::init_link( << "UHD will use the auto-detected max frame size for this connection."; } - // Check frame sizes + // Check actual frame sizes against detected frame sizes, and print + // warnings if they don't match for (auto conn_pair : eth_conns) { auto conn = conn_pair.second; - link_max_rate += conn.link_rate; - size_t rec_send_frame_size = conn.link_rate == MAX_RATE_1GIGE ? GE_DATA_FRAME_SEND_SIZE : XGE_DATA_FRAME_SEND_SIZE; @@ -452,10 +412,6 @@ void eth_manager::init_link( "argument."; } } - - _tree->create<size_t>("mtu/recv").set(_max_frame_sizes.recv_frame_size); - _tree->create<size_t>("mtu/send").set(_max_frame_sizes.send_frame_size); - _tree->access<double>("link_max_rate").set(link_max_rate); } size_t eth_manager::get_mtu(uhd::direction_t dir) @@ -468,7 +424,7 @@ size_t eth_manager::get_mtu(uhd::direction_t dir) void eth_manager::discover_eth( const mboard_eeprom_t mb_eeprom, const std::string& loaded_fpga_image) { - udp_simple_factory_t udp_make_connected = x300_get_udp_factory(_args.get_orig_args()); + udp_simple_factory_t udp_make_connected = x300_get_udp_factory(_args.get_use_dpdk()); // Load all valid, non-duplicate IP addrs std::vector<std::string> ip_addrs{_args.get_first_addr()}; if (not _args.get_second_addr().empty() diff --git a/host/lib/usrp/x300/x300_eth_mgr.hpp b/host/lib/usrp/x300/x300_eth_mgr.hpp index 1f4013e17..19b6064dd 100644 --- a/host/lib/usrp/x300/x300_eth_mgr.hpp +++ b/host/lib/usrp/x300/x300_eth_mgr.hpp @@ -99,7 +99,13 @@ private: return eth_conns.at(_local_device_ids.at(0)); } - static udp_simple_factory_t x300_get_udp_factory(const device_addr_t& args); + //! Create a factory function for UDP traffic + // + // \note This is static rather than local to x300_eth_mgr.cpp to get access + // to udp_simple_factory_t + // \param use_dpdk If true, use a DPDK transport instead of a regular UDP + // transport + static udp_simple_factory_t x300_get_udp_factory(const bool use_dpdk); /*! * Automatically determine the maximum frame size available by sending a UDP packet @@ -109,15 +115,22 @@ private: frame_size_t determine_max_frame_size( const std::string& addr, const frame_size_t& user_mtu); - // Discover the ethernet connections per motherboard + //! Discover the ethernet connections per motherboard + // + // - Gets called during init_link() + // - Populates eth_conn + // - Populates _local_device_ids + // + // \throws uhd::runtime_error if no Ethernet connections can be found void discover_eth( const uhd::usrp::mboard_eeprom_t mb_eeprom, const std::string& loaded_fpga_image); - + /************************************************************************** + * Attributes + *************************************************************************/ + // Cache the initial device args that brought up this motherboard const x300_device_args_t _args; - uhd::property_tree::sptr _tree; - udp_simple_factory_t _x300_make_udp_connected; std::map<uhd::rfnoc::device_id_t, x300_eth_conn_t> eth_conns; diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 636202d33..273485577 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -23,6 +23,9 @@ #include <chrono> #include <fstream> #include <thread> +#ifdef HAVE_DPDK +# include <uhdlib/transport/dpdk/common.hpp> +#endif uhd::uart_iface::sptr x300_make_uart_iface(uhd::wb_iface::sptr iface); diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index a3276152a..a493d4e8c 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -90,7 +90,6 @@ private: std::string loaded_fpga_image; size_t hw_rev; - std::string current_refclk_src; uhd::usrp::x300::conn_manager::sptr conn_mgr; }; |