diff options
Diffstat (limited to 'host/lib/usrp/mpmd')
| -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 */ | 
