diff options
author | Martin Braun <martin.braun@ettus.com> | 2017-12-01 16:14:11 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2017-12-22 15:05:58 -0800 |
commit | 87dbcd9f1a5b2b464c27af56c3a91ab00f66c441 (patch) | |
tree | 62ccd5be210d94862071aecda5ec3e667b036148 /host | |
parent | a927a364c5b07387be3a849b74546b98ba84db84 (diff) | |
download | uhd-87dbcd9f1a5b2b464c27af56c3a91ab00f66c441.tar.gz uhd-87dbcd9f1a5b2b464c27af56c3a91ab00f66c441.tar.bz2 uhd-87dbcd9f1a5b2b464c27af56c3a91ab00f66c441.zip |
mpmd: Refactor MPM transport architecture, use managers
This splits up the transport code in mpmd_impl across multiple classes
to properly leverage the request_xport/commit_xport API in MPM.
Different types of transport (UDP, liberio) use their own distinct
classes, which are generated dynamically on request.
This is a true refactoring despite the large amount of changes; there
are no functional differences.
Reviewed-By: Brent Stapleton <brent.stapleton@ettus.com>
Reviewed-By: Trung Tran <trung.tran@ettus.com>
Reviewed-By: Ashish Chaudhari <ashish.chaudhari@ettus.com>
Diffstat (limited to 'host')
-rw-r--r-- | host/lib/usrp/mpmd/CMakeLists.txt | 15 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_impl.cpp | 48 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_impl.hpp | 130 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_mboard_impl.cpp | 130 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_xport.cpp | 283 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_xport_ctrl_base.hpp | 45 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.cpp | 145 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.hpp | 59 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.cpp | 103 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.hpp | 46 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_xport_mgr.cpp | 148 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_xport_mgr.hpp | 95 |
12 files changed, 843 insertions, 404 deletions
diff --git a/host/lib/usrp/mpmd/CMakeLists.txt b/host/lib/usrp/mpmd/CMakeLists.txt index 5bc8e2d08..e4ce0e316 100644 --- a/host/lib/usrp/mpmd/CMakeLists.txt +++ b/host/lib/usrp/mpmd/CMakeLists.txt @@ -17,14 +17,23 @@ IF(ENABLE_MPMD) IF(ENABLE_LIBERIO) - MESSAGE(STATUS "Compiling MPM with liberio support...") - ADD_DEFINITIONS(-DHAVE_LIBERIO) + MESSAGE(STATUS "Compiling MPMD with liberio support...") + ADD_DEFINITIONS(-DHAVE_LIBERIO) ENDIF(ENABLE_LIBERIO) LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_image_loader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_mboard_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_image_loader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport_mgr.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport_ctrl_udp.cpp ) + + IF(ENABLE_LIBERIO) + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport_ctrl_liberio.cpp + ) + ENDIF(ENABLE_LIBERIO) + ENDIF(ENABLE_MPMD) diff --git a/host/lib/usrp/mpmd/mpmd_impl.cpp b/host/lib/usrp/mpmd/mpmd_impl.cpp index d020e3546..92f8039a4 100644 --- a/host/lib/usrp/mpmd/mpmd_impl.cpp +++ b/host/lib/usrp/mpmd/mpmd_impl.cpp @@ -1,18 +1,7 @@ // -// Copyright 2017 Ettus Research (National Instruments) +// Copyright 2017 Ettus Research, a National Instruments Company // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. +// SPDX-License-Identifier: GPL-3.0 // #include "mpmd_impl.hpp" @@ -39,6 +28,7 @@ #include <vector> using namespace uhd; +using namespace uhd::mpmd; namespace { /************************************************************************* @@ -274,6 +264,14 @@ namespace { } } + +/***************************************************************************** + * Static class attributes + ****************************************************************************/ +const std::string mpmd_impl::MPM_RPC_GET_LAST_ERROR_CMD = "get_last_error"; +const std::string mpmd_impl::MPM_DISCOVERY_CMD = "MPM-DISC"; +const std::string mpmd_impl::MPM_ECHO_CMD = "MPM-ECHO"; + /***************************************************************************** * Structors ****************************************************************************/ @@ -285,15 +283,6 @@ mpmd_impl::mpmd_impl(const device_addr_t& device_args) UHD_LOGGER_INFO("MPMD") << "Initializing device with args: " << device_args.to_string(); - for (const std::string& key : device_args.keys()) { - if (key.find("recv") != std::string::npos) { - recv_args[key] = device_args[key]; - } - if (key.find("send") != std::string::npos) { - send_args[key] = device_args[key]; - } - } - const device_addrs_t mb_args = separate_device_addr(device_args); _mb.reserve(mb_args.size()); @@ -506,13 +495,18 @@ device_addrs_t mpmd_find_with_addr(const device_addr_t& hint_) } transport::udp_simple::sptr comm = transport::udp_simple::make_broadcast( - query_addr, std::to_string(MPM_DISCOVERY_PORT)); + query_addr, std::to_string(mpmd_impl::MPM_DISCOVERY_PORT)); comm->send( - boost::asio::buffer(&MPM_DISCOVERY_CMD, sizeof(MPM_DISCOVERY_CMD))); + boost::asio::buffer( + mpmd_impl::MPM_DISCOVERY_CMD.c_str(), + mpmd_impl::MPM_DISCOVERY_CMD.size() + ) + ); while (true) { - char buff[4096] = {}; - const size_t nbytes = comm->recv( // TODO make sure we don't buf overflow - boost::asio::buffer(buff), + const size_t MAX_MTU = 8000; + char buff[MAX_MTU] = {}; + const size_t nbytes = comm->recv( + boost::asio::buffer(buff, MAX_MTU), MPMD_FIND_TIMEOUT ); if (nbytes == 0) { diff --git a/host/lib/usrp/mpmd/mpmd_impl.hpp b/host/lib/usrp/mpmd/mpmd_impl.hpp index 3143378dd..7b81be0f6 100644 --- a/host/lib/usrp/mpmd/mpmd_impl.hpp +++ b/host/lib/usrp/mpmd/mpmd_impl.hpp @@ -1,22 +1,13 @@ // -// Copyright 2017 Ettus Research (National Instruments) +// Copyright 2017 Ettus Research, a National Instruments Company // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. +// SPDX-License-Identifier: GPL-3.0 // #ifndef INCLUDED_MPMD_IMPL_HPP #define INCLUDED_MPMD_IMPL_HPP + +#include "mpmd_xport_mgr.hpp" #include "../../utils/rpc.hpp" #include "../device3/device3_impl.hpp" #include <uhd/stream.hpp> @@ -25,17 +16,9 @@ #include <uhd/utils/tasks.hpp> #include <uhd/transport/muxed_zero_copy_if.hpp> #include <map> +#include <memory> -static const size_t MPMD_RX_SW_BUFF_SIZE_ETH = 0x2000000;//32MiB For an ~8k frame size any size >32MiB is just wasted buffer space -static const size_t MPMD_RX_SW_BUFF_SIZE_ETH_MACOS = 0x100000; //1Mib - -static const size_t MPM_DISCOVERY_PORT = 49600; -static const size_t MPM_RPC_PORT = 49601; -static const char MPM_RPC_GET_LAST_ERROR_CMD[] = "get_last_error"; -static const char MPM_DISCOVERY_CMD[] = "MPM-DISC"; -static const char MPM_ECHO_CMD[] = "MPM-ECHO"; -static const size_t MPMD_10GE_DATA_FRAME_MAX_SIZE = 8000; // CHDR packet size in bytes - +namespace uhd { namespace mpmd { /*! Stores all attributes specific to a single MPM device */ @@ -93,28 +76,42 @@ class mpmd_mboard_impl /************************************************************************* * API ************************************************************************/ - uhd::sid_t allocate_sid(const uint16_t port, - const uhd::sid_t address, - const uint32_t xbar_src_addr, - const uint32_t xbar_src_dst, - const uint32_t dst_addr - ); - //! Configure a crossbar to have a certain local address void set_xbar_local_addr(const size_t xbar_index, const size_t local_addr); //! Return the local address of a given crossbar - size_t get_xbar_local_addr(const size_t xbar_index) { + size_t get_xbar_local_addr(const size_t xbar_index) const { return xbar_local_addrs.at(xbar_index); } + //! Device-specific make_transport implementation + // + // A major difference to the mpmd_impl::make_transport() is the meaning of + // the first argument (\p sid). mpmd_impl::make_transport() will add a + // source part to the SID which needs to be taken into account in this + // function. + // + // \param sid The full SID of this transport (UHD to device) + // \param xport_type Transport type (CTRL, RX_DATA, ...) + // \param args Any kind of args passed in via get_?x_stream() + uhd::both_xports_t make_transport( + const sid_t& sid, + usrp::device3_impl::xport_type_t xport_type, + const uhd::device_addr_t& args + ); + + + uhd::device_addr_t get_rx_hints() const; + uhd::device_addr_t get_tx_hints() const; + private: /************************************************************************* * Private methods ************************************************************************/ /*! Renew the claim onto the device. * - * This is meant to be called repeatedly, e.g., using a UHD task. + * This is meant to be called repeatedly, e.g., using a UHD task. See also + * _claimer_task. */ bool claim(); @@ -130,10 +127,11 @@ class mpmd_mboard_impl // what we use when addressing a crossbar in a CHDR header. std::vector<size_t> xbar_local_addrs; - /*! Continuously reclaims the device. */ uhd::task::sptr _claimer_task; + + uhd::mpmd::xport::mpmd_xport_mgr::uptr _xport_mgr; }; @@ -145,16 +143,36 @@ class mpmd_mboard_impl */ class mpmd_impl : public uhd::usrp::device3_impl { - public: +public: + //! Port on which the discovery process is listening + static const size_t MPM_DISCOVERY_PORT = 49600; + //! Port on which the RPC process is listening + static const size_t MPM_RPC_PORT = 49601; + //! This is the command that needs to be sent to the discovery port to + // trigger a response. + static const std::string MPM_DISCOVERY_CMD; + //! This is the command that will let you measure ping responses from the + // device via the discovery process. Useful for MTU discovery. + static const std::string MPM_ECHO_CMD; + //! This is the RPC command that will return the last known error from MPM. + static const std::string MPM_RPC_GET_LAST_ERROR_CMD; + + /************************************************************************** + * Structors + ************************************************************************/ mpmd_impl(const uhd::device_addr_t& device_addr); ~mpmd_impl(); + /************************************************************************** + * API + ************************************************************************/ uhd::both_xports_t make_transport(const uhd::sid_t&, uhd::usrp::device3_impl::xport_type_t, const uhd::device_addr_t&); private: uhd::device_addr_t get_rx_hints(size_t mb_index); + uhd::device_addr_t get_tx_hints(size_t mb_index); /************************************************************************* * Private methods/helpers @@ -185,49 +203,14 @@ class mpmd_impl : public uhd::usrp::device3_impl */ size_t allocate_xbar_local_addr(); - /*! Return the index of the motherboard carrying the crossbar at \p remote_addr + /*! Return the index of the motherboard given the local address of a + * crossbar */ - size_t identify_mboard_by_sid(const size_t remote_addr); - - using xport_info_t = std::map<std::string, std::string>; - using xport_info_list_t = std::vector<std::map<std::string, std::string>>; - - uhd::both_xports_t make_transport_udp( - const size_t mb_index, - xport_info_t &xport_info, - const xport_type_t xport_type, - const uhd::device_addr_t& xport_args - ); - -#ifdef HAVE_LIBERIO - /*! Create a muxed liberio transport for control packets */ - uhd::transport::muxed_zero_copy_if::sptr make_muxed_liberio_xport( - const std::string &tx_dev, - const std::string &rx_dev, - const uhd::transport::zero_copy_xport_params &buff_args, - const size_t max_muxed_ports - ); - - uhd::both_xports_t make_transport_liberio( - const size_t mb_index, - xport_info_t &xport_info, - const xport_type_t xport_type, - const uhd::device_addr_t& xport_args - ); -#endif + size_t identify_mboard_by_xbar_addr(const size_t xbar_addr) const; /************************************************************************* * Private attributes ************************************************************************/ - // FIXME move the next two into their own transport manager class - //! Control transport for one liberio connection - uhd::transport::muxed_zero_copy_if::sptr _ctrl_dma_xport; - //! Control transport for one liberio connection - uhd::transport::muxed_zero_copy_if::sptr _async_msg_dma_xport; - - uhd::dict<std::string, std::string> recv_args; - uhd::dict<std::string, std::string> send_args; - //! Stores the args with which the device was originally initialized uhd::device_addr_t _device_args; //! Stores a list of mboard references @@ -237,9 +220,12 @@ class mpmd_impl : public uhd::usrp::device3_impl // No-one touches this except allocate_xbar_local_addr(), gotcha? size_t _xbar_local_addr_ctr = 2; + // TODO make sure this can't wrap size_t _sid_framer; }; +}} /* namespace uhd::mpmd */ + uhd::device_addrs_t mpmd_find(const uhd::device_addr_t& hint_); #endif /* INCLUDED_MPMD_IMPL_HPP */ diff --git a/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp b/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp index 337504927..1038be26d 100644 --- a/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp +++ b/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp @@ -1,18 +1,7 @@ // -// Copyright 2017 Ettus Research (National Instruments) +// Copyright 2017 Ettus Research, a National Instruments Company // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. +// SPDX-License-Identifier: GPL-3.0 // #include "mpmd_impl.hpp" @@ -67,6 +56,7 @@ namespace { } using namespace uhd; +using namespace uhd::mpmd; /***************************************************************************** * Structors @@ -77,8 +67,9 @@ mpmd_mboard_impl::mpmd_mboard_impl( ) : mb_args(mb_args_) , rpc(uhd::rpc_client::make( rpc_server_addr, - MPM_RPC_PORT, - MPM_RPC_GET_LAST_ERROR_CMD)) + mpmd_impl::MPM_RPC_PORT, + mpmd_impl::MPM_RPC_GET_LAST_ERROR_CMD)) + , _xport_mgr(xport::mpmd_xport_mgr::make(mb_args)) { UHD_LOGGER_TRACE("MPMD") << "Initializing mboard, connecting to RPC server address: " @@ -96,7 +87,6 @@ mpmd_mboard_impl::mpmd_mboard_impl( init_device(rpc, mb_args); // RFNoC block clocks are now on. Noc-IDs can be read back. - auto device_info_dict = rpc->request<dev_info>("get_device_info"); for (const auto &info_pair : device_info_dict) { device_info[info_pair.first] = info_pair.second; @@ -120,24 +110,6 @@ mpmd_mboard_impl::mpmd_mboard_impl( this->num_xbars = rpc->request<size_t>("get_num_xbars"); // xbar_local_addrs is not yet valid after this! this->xbar_local_addrs.resize(this->num_xbars, 0xFF); - - // std::vector<std::string> data_ifaces = - // rpc.call<std::vector<std::string>>("get_interfaces", rpc_token); - - // discover path to device and tell MPM our MAC address seen at the data - // interfaces - // move this into make_transport - //for (const auto& iface : data_ifaces) { - //std::vector<std::string> addrs = rpc.call<std::vector<std::string>>( - //"get_interface_addrs", _rpc_token, iface); - //for (const auto& iface_addr : addrs) { - //if (rpc_client(iface_addr, MPM_RPC_PORT) - //.call<bool>("probe_interface", _rpc_token)) { - //data_interfaces.emplace(iface, iface_addr); - //break; - //} - //} - //} } mpmd_mboard_impl::~mpmd_mboard_impl() @@ -152,20 +124,6 @@ mpmd_mboard_impl::~mpmd_mboard_impl() /***************************************************************************** * API ****************************************************************************/ -uhd::sid_t mpmd_mboard_impl::allocate_sid( - const uint16_t port, - const uhd::sid_t address, - const uint32_t xbar_src_addr, - const uint32_t xbar_src_port, - const uint32_t dst_addr -) { - const auto sid = rpc->request_with_token<uint32_t>( - "allocate_sid", - port, address.get(), xbar_src_addr, xbar_src_port, dst_addr - ); - return uhd::sid_t(sid); -} - void mpmd_mboard_impl::set_xbar_local_addr( const size_t xbar_index, const size_t local_addr @@ -175,6 +133,82 @@ void mpmd_mboard_impl::set_xbar_local_addr( xbar_local_addrs.at(xbar_index) = local_addr; } +uhd::both_xports_t mpmd_mboard_impl::make_transport( + const sid_t& sid, + usrp::device3_impl::xport_type_t xport_type, + const uhd::device_addr_t& xport_args +) { + const std::string xport_type_str = [xport_type](){ + switch (xport_type) { + case mpmd_impl::CTRL: + return "CTRL"; + case mpmd_impl::ASYNC_MSG: + return "ASYNC_MSG"; + case mpmd_impl::RX_DATA: + return "RX_DATA"; + case mpmd_impl::TX_DATA: + return "TX_DATA"; + default: + UHD_THROW_INVALID_CODE_PATH(); + }; + }(); + + UHD_LOGGER_TRACE("MPMD") + << __func__ << "(): Creating new transport of type: " + << xport_type_str + ; + + using namespace uhd::mpmd::xport; + const auto xport_info_list = + rpc->request_with_token<mpmd_xport_mgr::xport_info_list_t>( + "request_xport", + sid.get_dst(), + sid.get_src(), + xport_type_str + ); + UHD_LOGGER_TRACE("MPMD") + << __func__ + << "(): request_xport() gave us " << xport_info_list.size() + << " option(s)." + ; + if (xport_info_list.empty()) { + UHD_LOG_ERROR("MPMD", "No viable transport path found!"); + throw uhd::runtime_error("No viable transport path found!"); + } + + xport::mpmd_xport_mgr::xport_info_t xport_info_out; + auto xports = _xport_mgr->make_transport( + xport_info_list, + xport_type, + xport_args, + xport_info_out + ); + + if (not rpc->request_with_token<bool>( + "commit_xport", + xport_info_out)) { + UHD_LOG_ERROR("MPMD", "Failed to create UDP transport!"); + throw uhd::runtime_error("commit_xport() failed!"); + } + + return xports; +} + +uhd::device_addr_t mpmd_mboard_impl::get_rx_hints() const +{ + // TODO: See if we need to do anything here. get_rx_stream() might care. + device_addr_t rx_hints; + return rx_hints; +} + +uhd::device_addr_t mpmd_mboard_impl::get_tx_hints() const +{ + // TODO: See if we need to do anything here. get_tx_stream() might care. + device_addr_t tx_hints; + return tx_hints; +} + + /***************************************************************************** * Private methods ****************************************************************************/ diff --git a/host/lib/usrp/mpmd/mpmd_xport.cpp b/host/lib/usrp/mpmd/mpmd_xport.cpp index 5dd29a6f7..c21da3839 100644 --- a/host/lib/usrp/mpmd/mpmd_xport.cpp +++ b/host/lib/usrp/mpmd/mpmd_xport.cpp @@ -4,57 +4,39 @@ // SPDX-License-Identifier: GPL-3.0 // -// make_transport logic for mpmd_impl. - +// make_transport logic for mpmd_impl. Note that mpmd_xport_mgr.* has most of +// the actual transport logic, this for transport-related APIs. #include "mpmd_impl.hpp" -#include "../transport/liberio_zero_copy.hpp" -#include <uhd/transport/udp_zero_copy.hpp> -#include <uhd/utils/byteswap.hpp> +#include "mpmd_xport_mgr.hpp" using namespace uhd; +using namespace uhd::mpmd; - -// TODO this does not consider the liberio use case! -uhd::device_addr_t mpmd_impl::get_rx_hints(size_t /* mb_index */) +uhd::device_addr_t mpmd_impl::get_rx_hints(size_t mb_index) { - //device_addr_t rx_hints = _mb[mb_index].recv_args; - device_addr_t rx_hints; // TODO don't ignore what the user tells us - // (default to a large recv buff) - if (not rx_hints.has_key("recv_buff_size")) - { - //For the ethernet transport, the buffer has to be set before creating - //the transport because it is independent of the frame size and # frames - //For nirio, the buffer size is not configurable by the user - #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) - //limit buffer resize on macos or it will error - rx_hints["recv_buff_size"] = boost::lexical_cast<std::string>(MPMD_RX_SW_BUFF_SIZE_ETH_MACOS); - #elif defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32) - //set to half-a-second of buffering at max rate - rx_hints["recv_buff_size"] = boost::lexical_cast<std::string>(MPMD_RX_SW_BUFF_SIZE_ETH); - #endif - } - return rx_hints; + return _mb.at(mb_index)->get_rx_hints(); } +uhd::device_addr_t mpmd_impl::get_tx_hints(size_t mb_index) +{ + return _mb.at(mb_index)->get_tx_hints(); +} -/****************************************************************************** - * General make_transport() + helpers - *****************************************************************************/ -size_t mpmd_impl::identify_mboard_by_sid(const size_t remote_addr) +size_t mpmd_impl::identify_mboard_by_xbar_addr(const size_t xbar_addr) const { for (size_t mb_index = 0; mb_index < _mb.size(); mb_index++) { for (size_t xbar_index = 0; xbar_index < _mb[mb_index]->num_xbars; xbar_index++) { - if (_mb[mb_index]->get_xbar_local_addr(xbar_index) == remote_addr) { + if (_mb.at(mb_index)->get_xbar_local_addr(xbar_index) == xbar_addr) { return mb_index; } } } throw uhd::lookup_error(str( - boost::format("Cannot identify mboard for remote address %d") - % remote_addr + boost::format("Cannot identify mboard for crossbar address %d") + % xbar_addr )); } @@ -63,59 +45,27 @@ both_xports_t mpmd_impl::make_transport( usrp::device3_impl::xport_type_t xport_type, const uhd::device_addr_t& args ) { - const size_t mb_index = identify_mboard_by_sid(dst_address.get_dst_addr()); - // Could also be a map... - const std::string xport_type_str = [xport_type](){ - switch (xport_type) { - case CTRL: - return "CTRL"; - case ASYNC_MSG: - return "ASYNC_MSG"; - case RX_DATA: - return "RX_DATA"; - case TX_DATA: - return "TX_DATA"; - default: - UHD_THROW_INVALID_CODE_PATH(); - }; - }(); - + const size_t mb_index = + identify_mboard_by_xbar_addr(dst_address.get_dst_addr()); + + const sid_t sid( + 0, + _sid_framer++, // FIXME make sure we only increment if actually valid + dst_address.get_dst_addr(), + dst_address.get_dst_endpoint() + ); UHD_LOGGER_TRACE("MPMD") - << "Creating new transport of type: " << xport_type_str - << " To mboard: " << mb_index - << " Destination address: " << dst_address.to_pp_string_hex().substr(6) + << "Creating new transport to mboard: " << mb_index + << " SID: " << sid.to_pp_string_hex() << " User-defined xport args: " << args.to_string() ; - const auto xport_info_list = - _mb[mb_index]->rpc->request_with_token<xport_info_list_t>( - "request_xport", - dst_address.get_dst(), - _sid_framer++, // FIXME make sure we only increment if actually valid - xport_type_str + both_xports_t xports = _mb[mb_index]->make_transport( + sid, + xport_type, + args ); UHD_LOGGER_TRACE("MPMD") - << "request_xport() gave us " << xport_info_list.size() - << " option(s)." - ; - - // This is not very elegant, and needs some kind of factory model or - // whatnot. - auto xport_info = xport_info_list.at(0); // In the future, actually pick one - // sensibly. This is what would - // enable dual Eth support. FIXME - both_xports_t xports; - if (xport_info["type"] == "UDP") { - xports = make_transport_udp(mb_index, xport_info, xport_type, args); -#ifdef HAVE_LIBERIO - } else if (xport_info["type"] == "liberio") { - xports = make_transport_liberio(mb_index, xport_info, xport_type, args); -#endif - } else { - UHD_THROW_INVALID_CODE_PATH(); - } - - UHD_LOGGER_TRACE("MPMD") << "xport info: send_sid==" << xports.send_sid.to_pp_string_hex() << " recv_sid==" << xports.recv_sid.to_pp_string_hex() << " endianness==" @@ -123,181 +73,6 @@ both_xports_t mpmd_impl::make_transport( << " recv_buff_size==" << xports.recv_buff_size << " send_buff_size==" << xports.send_buff_size ; - - return xports; -} - - -/****************************************************************************** - * UDP Transport - *****************************************************************************/ -both_xports_t mpmd_impl::make_transport_udp( - const size_t mb_index, - xport_info_t &xport_info, - const xport_type_t /*xport_type*/, - const uhd::device_addr_t& xport_args -) { - auto &rpc = _mb[mb_index]->rpc; - - transport::zero_copy_xport_params default_buff_args; - // Create actual UDP transport - // TODO don't hardcode these - default_buff_args.send_frame_size = 8000; - default_buff_args.recv_frame_size = 8000; - default_buff_args.num_recv_frames = 32; - default_buff_args.num_send_frames = 32; - - transport::udp_zero_copy::buff_params buff_params; - auto recv = transport::udp_zero_copy::make( - xport_info["ipv4"], - xport_info["port"], - default_buff_args, - buff_params, - xport_args - ); - 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; - - // Communicate it all back to MPM - if (not rpc->request_with_token<bool>("commit_xport", xport_info)) { - UHD_LOG_ERROR("MPMD", "Failed to create UDP transport!"); - throw uhd::runtime_error("commit_xport() failed!"); - } - - // 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 = buff_params.recv_buff_size; - xports.send_buff_size = buff_params.send_buff_size; - xports.recv = recv; // Note: This is a type cast! - xports.send = recv; // This too - return xports; -} - -/****************************************************************************** - * Liberio Transport - *****************************************************************************/ -#ifdef HAVE_LIBERIO -static uint32_t extract_sid_from_pkt(void* pkt, size_t) { - return uhd::sid_t(uhd::wtohx(static_cast<const uint32_t*>(pkt)[1])) - .get_dst(); -} - -uhd::transport::muxed_zero_copy_if::sptr mpmd_impl::make_muxed_liberio_xport( - const std::string &tx_dev, - const std::string &rx_dev, - const uhd::transport::zero_copy_xport_params &buff_args, - const size_t max_muxed_ports -) { - auto base_xport = transport::liberio_zero_copy::make( - tx_dev, rx_dev, buff_args); - - return uhd::transport::muxed_zero_copy_if::make( - base_xport, extract_sid_from_pkt, max_muxed_ports); -} - -both_xports_t mpmd_impl::make_transport_liberio( - const size_t mb_index, - xport_info_t &xport_info, - const xport_type_t xport_type, - const uhd::device_addr_t& xport_args -) { - auto &rpc = _mb[mb_index]->rpc; - - transport::zero_copy_xport_params default_buff_args; - /* default ones for RX / TX, override below */ - default_buff_args.send_frame_size = 4 * getpagesize(); - default_buff_args.recv_frame_size = 4 * getpagesize(); - default_buff_args.num_recv_frames = 128; - default_buff_args.num_send_frames = 128; - - if (xport_type == CTRL) { - default_buff_args.send_frame_size = 128; - default_buff_args.recv_frame_size = 128; - } else if (xport_type == ASYNC_MSG) { - default_buff_args.send_frame_size = 256; - default_buff_args.recv_frame_size = 256; - } else if (xport_type == RX_DATA) { - default_buff_args.send_frame_size = 64; - } else { - default_buff_args.recv_frame_size = 64; - } - - const std::string tx_dev = xport_info["tx_dev"]; - const std::string rx_dev = xport_info["rx_dev"]; - - both_xports_t xports; - xports.endianness = uhd::ENDIANNESS_LITTLE; - xports.send_sid = sid_t(xport_info["send_sid"]); - xports.recv_sid = xports.send_sid.reversed(); - - // this is kinda ghetto: scale buffer for muxed xports since we share the - // buffer... - float divisor = 1; - if (xport_type == CTRL) - divisor = 16; - else if (xport_type == ASYNC_MSG) - divisor = 4; - - - //if (xport_info["muxed"] == "True") { - //// FIXME tbw - //} - if (xport_type == CTRL) { - UHD_ASSERT_THROW(xport_info["muxed"] == "True"); - if (not _ctrl_dma_xport) { - default_buff_args.send_frame_size = 128; - default_buff_args.recv_frame_size = 128; - _ctrl_dma_xport = make_muxed_liberio_xport(tx_dev, rx_dev, - default_buff_args, int(divisor)); - } - - UHD_LOGGER_TRACE("MPMD") - << "Making (muxed) stream with num " << xports.recv_sid.get_dst(); - xports.recv = _ctrl_dma_xport->make_stream(xports.recv_sid.get_dst()); - } else if (xport_type == ASYNC_MSG) { - UHD_ASSERT_THROW(xport_info["muxed"] == "True"); - if (not _async_msg_dma_xport) { - default_buff_args.send_frame_size = 256; - default_buff_args.recv_frame_size = 256; - _async_msg_dma_xport = make_muxed_liberio_xport( - tx_dev, rx_dev, default_buff_args, int(divisor)); - } - - UHD_LOGGER_TRACE("MPMD") - << "making (muxed) stream with num " << xports.recv_sid.get_dst(); - xports.recv = - _async_msg_dma_xport->make_stream(xports.recv_sid.get_dst()); - } else { - xports.recv = - transport::liberio_zero_copy::make( - tx_dev, rx_dev, default_buff_args); - } - - transport::udp_zero_copy::buff_params buff_params; - buff_params.recv_buff_size = - float(default_buff_args.recv_frame_size) * - float(default_buff_args.num_recv_frames) / divisor; - buff_params.send_buff_size = - float(default_buff_args.send_frame_size) * - float(default_buff_args.num_send_frames) / divisor; - - - // Communicate it all back to MPM - if (not rpc->request_with_token<bool>("commit_xport", xport_info)) { - UHD_LOG_ERROR("MPMD", "Failed to create UDP transport!"); - throw uhd::runtime_error("commit_xport() failed!"); - } - - // Finish both_xports_t object and return: - xports.recv_buff_size = buff_params.recv_buff_size; - xports.send_buff_size = buff_params.send_buff_size; - xports.send = xports.recv; return xports; } -#endif /* HAVE_LIBERIO */ diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_base.hpp b/host/lib/usrp/mpmd/mpmd_xport_ctrl_base.hpp new file mode 100644 index 000000000..e5a3b7e31 --- /dev/null +++ b/host/lib/usrp/mpmd/mpmd_xport_ctrl_base.hpp @@ -0,0 +1,45 @@ +// +// Copyright 2017 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0 +// + +#ifndef INCLUDED_MPMD_XPORT_CTRL_BASE_HPP +#define INCLUDED_MPMD_XPORT_CTRL_BASE_HPP + +#include "mpmd_xport_mgr.hpp" +#include "../device3/device3_impl.hpp" +#include <uhd/types/device_addr.hpp> +#include <memory> + +namespace uhd { namespace mpmd { namespace xport { + +/*! Transport manager implementation base + */ +class mpmd_xport_ctrl_base +{ +public: + using uptr = std::unique_ptr<mpmd_xport_ctrl_base>; + + /*! This is the final step of a make_transport() sequence + * + * \param xport_info Contains all necessary transport info. The + * implementation may update this! + * \param xport_type CTRL, ASYNC_MSG, ... (see xport_type_t) + * \param xport_args Additional arguments. These can come from the user. + */ + virtual both_xports_t make_transport( + mpmd_xport_mgr::xport_info_t& xport_info, + const usrp::device3_impl::xport_type_t xport_type, + const uhd::device_addr_t& xport_args + ) = 0; + + //! Assert if an xport_info is even valid/feasible/available + virtual bool is_valid( + const mpmd_xport_mgr::xport_info_t& xport_info + ) const = 0; +}; + +}}} /* namespace uhd::mpmd::xport */ + +#endif /* INCLUDED_MPMD_XPORT_CTRL_BASE_HPP */ diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.cpp b/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.cpp new file mode 100644 index 000000000..2e4f024b4 --- /dev/null +++ b/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.cpp @@ -0,0 +1,145 @@ +// +// Copyright 2017 Ettus Research, National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0 +// + +#include "mpmd_xport_ctrl_liberio.hpp" +#include "../transport/liberio_zero_copy.hpp" +#include <uhd/transport/udp_zero_copy.hpp> +#include <uhd/utils/byteswap.hpp> + +using namespace uhd; +using namespace uhd::mpmd::xport; + +namespace { + + uint32_t extract_sid_from_pkt(void* pkt, size_t) { + return uhd::sid_t(uhd::wtohx(static_cast<const uint32_t*>(pkt)[1])) + .get_dst(); + } + +} + +mpmd_xport_ctrl_liberio::mpmd_xport_ctrl_liberio( + const uhd::device_addr_t& mb_args +) : _mb_args(mb_args) + , _recv_args(filter_args(mb_args, "recv")) + , _send_args(filter_args(mb_args, "send")) +{ + // nop +} + + +uhd::both_xports_t +mpmd_xport_ctrl_liberio::make_transport( + mpmd_xport_mgr::xport_info_t &xport_info, + const usrp::device3_impl::xport_type_t xport_type, + const uhd::device_addr_t& /*xport_args_*/ +) { + transport::zero_copy_xport_params default_buff_args; + /* default ones for RX / TX, override below */ + default_buff_args.send_frame_size = 4 * getpagesize(); + default_buff_args.recv_frame_size = 4 * getpagesize(); + default_buff_args.num_recv_frames = 128; + default_buff_args.num_send_frames = 128; + + if (xport_type == usrp::device3_impl::CTRL) { + default_buff_args.send_frame_size = 128; + default_buff_args.recv_frame_size = 128; + } else if (xport_type == usrp::device3_impl::ASYNC_MSG) { + default_buff_args.send_frame_size = 256; + default_buff_args.recv_frame_size = 256; + } else if (xport_type == usrp::device3_impl::RX_DATA) { + default_buff_args.send_frame_size = 64; + } else { + default_buff_args.recv_frame_size = 64; + } + + const std::string tx_dev = xport_info["tx_dev"]; + const std::string rx_dev = xport_info["rx_dev"]; + + both_xports_t xports; + xports.endianness = uhd::ENDIANNESS_LITTLE; + xports.send_sid = sid_t(xport_info["send_sid"]); + xports.recv_sid = xports.send_sid.reversed(); + + // this is kinda ghetto: scale buffer for muxed xports since we share the + // buffer... + float divisor = 1; + if (xport_type == usrp::device3_impl::CTRL) + divisor = 16; + else if (xport_type == usrp::device3_impl::ASYNC_MSG) + divisor = 4; + + + //if (xport_info["muxed"] == "True") { + //// FIXME tbw + //} + if (xport_type == usrp::device3_impl::CTRL) { + UHD_ASSERT_THROW(xport_info["muxed"] == "True"); + if (not _ctrl_dma_xport) { + default_buff_args.send_frame_size = 128; + default_buff_args.recv_frame_size = 128; + _ctrl_dma_xport = make_muxed_liberio_xport(tx_dev, rx_dev, + default_buff_args, int(divisor)); + } + + UHD_LOGGER_TRACE("MPMD") + << "Making (muxed) stream with num " << xports.recv_sid.get_dst(); + xports.recv = _ctrl_dma_xport->make_stream(xports.recv_sid.get_dst()); + } else if (xport_type == usrp::device3_impl::ASYNC_MSG) { + UHD_ASSERT_THROW(xport_info["muxed"] == "True"); + if (not _async_msg_dma_xport) { + default_buff_args.send_frame_size = 256; + default_buff_args.recv_frame_size = 256; + _async_msg_dma_xport = make_muxed_liberio_xport( + tx_dev, rx_dev, default_buff_args, int(divisor)); + } + + UHD_LOGGER_TRACE("MPMD") + << "making (muxed) stream with num " << xports.recv_sid.get_dst(); + xports.recv = + _async_msg_dma_xport->make_stream(xports.recv_sid.get_dst()); + } else { + xports.recv = + transport::liberio_zero_copy::make( + tx_dev, rx_dev, default_buff_args); + } + + transport::udp_zero_copy::buff_params buff_params; + buff_params.recv_buff_size = + float(default_buff_args.recv_frame_size) * + float(default_buff_args.num_recv_frames) / divisor; + buff_params.send_buff_size = + float(default_buff_args.send_frame_size) * + float(default_buff_args.num_send_frames) / divisor; + + + // Finish both_xports_t object and return: + xports.recv_buff_size = buff_params.recv_buff_size; + xports.send_buff_size = buff_params.send_buff_size; + xports.send = xports.recv; + return xports; +} + +bool mpmd_xport_ctrl_liberio::is_valid( + const mpmd_xport_mgr::xport_info_t& xport_info +) const { + return xport_info.at("type") == "liberio"; +} + +uhd::transport::muxed_zero_copy_if::sptr +mpmd_xport_ctrl_liberio::make_muxed_liberio_xport( + const std::string &tx_dev, + const std::string &rx_dev, + const uhd::transport::zero_copy_xport_params &buff_args, + const size_t max_muxed_ports +) { + auto base_xport = transport::liberio_zero_copy::make( + tx_dev, rx_dev, buff_args); + + return uhd::transport::muxed_zero_copy_if::make( + base_xport, extract_sid_from_pkt, max_muxed_ports); +} + diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.hpp b/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.hpp new file mode 100644 index 000000000..76bb88f03 --- /dev/null +++ b/host/lib/usrp/mpmd/mpmd_xport_ctrl_liberio.hpp @@ -0,0 +1,59 @@ +// +// Copyright 2017 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0 +// + +#ifndef INCLUDED_MPMD_XPORT_ctrl_liberio_HPP +#define INCLUDED_MPMD_XPORT_ctrl_liberio_HPP + +#include "mpmd_xport_ctrl_base.hpp" +#include <uhd/types/device_addr.hpp> +#include "../device3/device3_impl.hpp" +#include <uhd/transport/muxed_zero_copy_if.hpp> + +namespace uhd { namespace mpmd { namespace xport { + +/*! Liberio transport manager + */ +class mpmd_xport_ctrl_liberio : public mpmd_xport_ctrl_base +{ +public: + mpmd_xport_ctrl_liberio( + const uhd::device_addr_t& mb_args + ); + + /*! Open DMA interface to kernel (and thus to FPGA DMA engine) + */ + both_xports_t make_transport( + mpmd_xport_mgr::xport_info_t& xport_info, + const usrp::device3_impl::xport_type_t xport_type, + const uhd::device_addr_t& xport_args + ); + + bool is_valid( + const mpmd_xport_mgr::xport_info_t& xport_info + ) const; + +private: + /*! Create a muxed liberio transport for control packets */ + uhd::transport::muxed_zero_copy_if::sptr make_muxed_liberio_xport( + const std::string &tx_dev, + const std::string &rx_dev, + const uhd::transport::zero_copy_xport_params &buff_args, + const size_t max_muxed_ports + ); + + const uhd::device_addr_t _mb_args; + const uhd::dict<std::string, std::string> _recv_args; + const uhd::dict<std::string, std::string> _send_args; + + //! Control transport for one liberio connection + uhd::transport::muxed_zero_copy_if::sptr _ctrl_dma_xport; + //! Control transport for one liberio connection + uhd::transport::muxed_zero_copy_if::sptr _async_msg_dma_xport; +}; + +}}} /* namespace uhd::mpmd::xport */ + +#endif /* INCLUDED_MPMD_XPORT_ctrl_liberio_HPP */ diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.cpp b/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.cpp new file mode 100644 index 000000000..de4b3bbba --- /dev/null +++ b/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.cpp @@ -0,0 +1,103 @@ +// +// Copyright 2017 Ettus Research, National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0 +// + +#include "mpmd_xport_mgr.hpp" +#include "mpmd_xport_ctrl_udp.hpp" +#include <uhd/transport/udp_zero_copy.hpp> + +using namespace uhd; +using namespace uhd::mpmd::xport; + +namespace { + + #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) + const size_t MPMD_RX_SW_BUFF_SIZE_ETH = 0x100000; // 1Mib + #elif defined(UHD_PLATFORM_LINUX) || defined(UHD_PLATFORM_WIN32) + //For an ~8k frame size any size >32MiB is just wasted buffer space: + const size_t MPMD_RX_SW_BUFF_SIZE_ETH = 0x2000000; // 32 MiB + #endif + + const size_t MPMD_10GE_DATA_FRAME_MAX_SIZE = 8000; // CHDR packet size in bytes + + std::vector<std::string> get_addrs_from_mb_args( + const uhd::device_addr_t& mb_args + ) { + // mb_args must always include addr + std::vector<std::string> addrs{mb_args["addr"]}; + if (mb_args.has_key("second_addr")){ + addrs.push_back(mb_args["second_addr"]); + } + return addrs; + } +} + + +mpmd_xport_ctrl_udp::mpmd_xport_ctrl_udp( + const uhd::device_addr_t& mb_args +) : _mb_args(mb_args) + , _recv_args(filter_args(mb_args, "recv")) + , _send_args(filter_args(mb_args, "send")) + , _available_addrs(get_addrs_from_mb_args(mb_args)) +{ +} + +uhd::both_xports_t +mpmd_xport_ctrl_udp::make_transport( + mpmd_xport_mgr::xport_info_t &xport_info, + const usrp::device3_impl::xport_type_t xport_type, + const uhd::device_addr_t& xport_args_ +) { + auto xport_args = xport_args_; + + if (xport_type == usrp::device3_impl::RX_DATA + and not xport_args.has_key("recv_buff_size")) { + xport_args["recv_buff_size"] = + std::to_string(MPMD_RX_SW_BUFF_SIZE_ETH); + } + + transport::zero_copy_xport_params default_buff_args; + // Create actual UDP transport + // TODO don't hardcode these + default_buff_args.send_frame_size = 8000; + default_buff_args.recv_frame_size = 8000; + default_buff_args.num_recv_frames = 32; + default_buff_args.num_send_frames = 32; + + transport::udp_zero_copy::buff_params buff_params; + auto recv = transport::udp_zero_copy::make( + xport_info["ipv4"], + xport_info["port"], + default_buff_args, + buff_params, + xport_args + ); + 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 = buff_params.recv_buff_size; + xports.send_buff_size = buff_params.send_buff_size; + xports.recv = recv; // Note: This is a type cast! + xports.send = recv; // This too + return xports; +} + +bool mpmd_xport_ctrl_udp::is_valid( + const mpmd_xport_mgr::xport_info_t& xport_info +) const { + return std::find( + _available_addrs.cbegin(), + _available_addrs.cend(), + xport_info.at("ipv4") + ) != _available_addrs.cend(); +} + diff --git a/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.hpp b/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.hpp new file mode 100644 index 000000000..0c8c19479 --- /dev/null +++ b/host/lib/usrp/mpmd/mpmd_xport_ctrl_udp.hpp @@ -0,0 +1,46 @@ +// +// Copyright 2017 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0 +// + +#ifndef INCLUDED_MPMD_XPORT_ctrl_udp_HPP +#define INCLUDED_MPMD_XPORT_ctrl_udp_HPP + +#include "mpmd_xport_ctrl_base.hpp" +#include <uhd/types/device_addr.hpp> +#include "../device3/device3_impl.hpp" + +namespace uhd { namespace mpmd { namespace xport { + +/*! UDP transport manager + * + * Opens UDP sockets + */ +class mpmd_xport_ctrl_udp : public mpmd_xport_ctrl_base +{ +public: + mpmd_xport_ctrl_udp( + const uhd::device_addr_t& mb_args + ); + + both_xports_t make_transport( + mpmd_xport_mgr::xport_info_t& xport_info, + const usrp::device3_impl::xport_type_t xport_type, + const uhd::device_addr_t& xport_args + ); + + bool is_valid( + const mpmd_xport_mgr::xport_info_t& xport_info + ) const; + +private: + const uhd::device_addr_t _mb_args; + const uhd::dict<std::string, std::string> _recv_args; + const uhd::dict<std::string, std::string> _send_args; + const std::vector<std::string> _available_addrs; +}; + +}}} /* namespace uhd::mpmd::xport */ + +#endif /* INCLUDED_MPMD_XPORT_ctrl_udp_HPP */ diff --git a/host/lib/usrp/mpmd/mpmd_xport_mgr.cpp b/host/lib/usrp/mpmd/mpmd_xport_mgr.cpp new file mode 100644 index 000000000..242a46527 --- /dev/null +++ b/host/lib/usrp/mpmd/mpmd_xport_mgr.cpp @@ -0,0 +1,148 @@ +// +// Copyright 2017 Ettus Research, National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0 +// + +#include "mpmd_impl.hpp" +#include "mpmd_xport_mgr.hpp" +#include "mpmd_xport_ctrl_base.hpp" +#include "mpmd_xport_ctrl_udp.hpp" +#ifdef HAVE_LIBERIO +# include "mpmd_xport_ctrl_liberio.hpp" +#endif + +uhd::dict<std::string, std::string> uhd::mpmd::xport::filter_args( + const uhd::device_addr_t& args, + const std::string& prefix +) { + uhd::dict<std::string, std::string> filtered_args; + for (const std::string& key : args.keys()) { + if (key.find(prefix) != std::string::npos) { + filtered_args[key] = args[key]; + } + } + + return filtered_args; +} + +using namespace uhd::mpmd::xport; + +class mpmd_xport_mgr_impl : public mpmd_xport_mgr +{ +public: + mpmd_xport_mgr_impl( + const uhd::device_addr_t& mb_args + ) : _mb_args(mb_args) + { + // nop + } + + /************************************************************************** + * API (see mpmd_xport_mgr.hpp) + *************************************************************************/ + uhd::both_xports_t make_transport( + const xport_info_list_t &xport_info_list, + const uhd::usrp::device3_impl::xport_type_t xport_type, + const uhd::device_addr_t& xport_args, + xport_info_t& xport_info_out + ) { + for (const auto &xport_info : xport_info_list) { + require_xport_mgr(xport_info.at("type")); + } + + // Run our incredibly smart selection algorithm + xport_info_out = select_xport_option(xport_info_list); + const std::string xport_medium = xport_info_out.at("type"); + UHD_LOG_TRACE("MPMD", + __func__ << "(): xport medium is " << xport_medium); + + // When we've picked our preferred option, pass it to the transport + // implementation for execution: + return _xport_ctrls[xport_medium]->make_transport( + xport_info_out, + xport_type, + xport_args + ); + } + + +private: + /************************************************************************** + * Private methods / helpers + *************************************************************************/ + /*! Picks a transport option based on available data + * + * \param xport_info_list List of available options, they all need to be + * valid choices. + * + * \returns One element of \p xport_info_list based on a selection + * algorithm. + */ + xport_info_t select_xport_option( + const xport_info_list_t &xport_info_list + ) const { + // Naive xport picking method, this needs fixing (FIXME). + // Have algorithm run on baseline score, allocation, and random soup + return xport_info_list.at(0); + } + + //! Create an instance of an xport manager implementation + // + // \param xport_medium "UDP" or "liberio" + // \param mb_args Device args + mpmd_xport_ctrl_base::uptr make_mgr_impl( + const std::string &xport_medium, + const uhd::device_addr_t& mb_args + ) const { + if (xport_medium == "UDP") { + return mpmd_xport_ctrl_base::uptr( + new mpmd_xport_ctrl_udp(mb_args) + ); +#ifdef HAVE_LIBERIO + } else if (xport_medium == "liberio") { + return mpmd_xport_ctrl_base::uptr( + new mpmd_xport_ctrl_liberio(mb_args) + ); +#endif + } else { + throw uhd::key_error("Unknown transport medium!"); + } + } + + //! This will make sure that _xport_ctrls contains a valid transport manager + // for \p xport_medium + // + // When this function returns, it will be possible to access + // this->_xport_ctrls[xport_medium]. + // + // \param xport_medium Type of transport, e.g. "UDP", "liberio", ... + // + // \throws uhd::key_error if \p xport_medium is not known or registered + void require_xport_mgr(const std::string &xport_medium) + { + if (_xport_ctrls.count(xport_medium) == 0) { + UHD_LOG_TRACE("MPMD", + "Instantiating transport manager `" << xport_medium << "'"); + _xport_ctrls[xport_medium] = make_mgr_impl(xport_medium, _mb_args); + } + } + + /************************************************************************** + * Private attributes + *************************************************************************/ + //! Cache available xport manager implementations + // + // Should only every be populated by require_xport_mgr() + std::map<std::string, mpmd_xport_ctrl_base::uptr> _xport_ctrls; + + //! Motherboard args, can contain things like 'recv_buff_size' + const uhd::device_addr_t _mb_args; +}; + +mpmd_xport_mgr::uptr mpmd_xport_mgr::make( + const uhd::device_addr_t& mb_args +) { + return mpmd_xport_mgr::uptr(new mpmd_xport_mgr_impl(mb_args)); +} + diff --git a/host/lib/usrp/mpmd/mpmd_xport_mgr.hpp b/host/lib/usrp/mpmd/mpmd_xport_mgr.hpp new file mode 100644 index 000000000..2da4af323 --- /dev/null +++ b/host/lib/usrp/mpmd/mpmd_xport_mgr.hpp @@ -0,0 +1,95 @@ +// +// Copyright 2017 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0 +// + +#ifndef INCLUDED_MPMD_XPORT_MGR_HPP +#define INCLUDED_MPMD_XPORT_MGR_HPP + +#include "../device3/device3_impl.hpp" +#include <uhd/types/dict.hpp> +#include <memory> +#include <map> +#include <vector> +#include <string> + +namespace uhd { namespace mpmd { namespace xport { + +/*! Return filtered subset from a device_addr_t + * + * The return dictionary will contain all key/value pairs from \p args + * where the key begins with \p prefix. + * + * \param args Bucket of key/value pairs + * \param prefix Key prefix to match against + */ +uhd::dict<std::string, std::string> filter_args( + const uhd::device_addr_t& args, + const std::string& prefix +); + +/*! MPMD Transport Manager + * + * A transport manager is an object which sets up a physical connection to a + * CHDR device. Its implementation is specific to the underlying transport + * medium. For example, if the medium is Ethernet/UDP, this class will create + * sockets. + */ +class mpmd_xport_mgr +{ +public: + using uptr = std::unique_ptr<mpmd_xport_mgr>; + using xport_info_t = std::map<std::string, std::string>; + using xport_info_list_t = std::vector<std::map<std::string, std::string>>; + + /*! Return a reference to a transport manager + * + * \param mb_args Additional args from the motherboard. These may contain + * transport-related args (e.g., "recv_buff_size") which + * can be relevant to the underlying implementation. + * + * \returns Reference to manager object + * \throws uhd::key_error if \p xport_medium is not supported. The ctor of + * the underlying class that is requested can also throw. + */ + static uptr make( + const uhd::device_addr_t& mb_args + ); + + /*! Create a transports object + * + * Implementation details depend on the underlying implementation. + * In general, the implementations will follow the following recipe: + * 1. Pick a suitable element from \p xport_info_list + * 2. Do whatever system calls are necessary to create the physical + * transport; to do so, call the underlying implementation (UDP or + * whatever) + * 3. Update the selected element from xport_info_list + * 5. Return results + * + * \param xport_info_list List of possible options to choose from. Every + * element of this argument needs to have the same + * "type" key (e.g., they all need to be "UDP"). + * \param xport_type Transport type (CTRL, RX_DATA, ...) + * \param xport_args Arbitrary additional transport args. These could come + * from the user, or other places. + * \param xport_info_out The updated dictionary from xport_info_list that + * was eventually chosen + * + * \returns The both_xports_t object containing the actual transport info, + * and xport_info_out contains the updated transport option info. + * The latter needs to get sent back to MPM to complete the + * transport handshake. + */ + virtual both_xports_t make_transport( + const xport_info_list_t &xport_info_list, + const usrp::device3_impl::xport_type_t xport_type, + const uhd::device_addr_t& xport_args, + xport_info_t& xport_info_out + ) = 0; +}; + +}}} /* namespace uhd::mpmd::xport */ + +#endif /* INCLUDED_MPMD_XPORT_MGR_HPP */ |