uhd/host/lib/usrp/mpmd/mpmd_xport_mgr.cpp
Alex Williams ad2720d718 mpmd,transport,prefs: Add xport_mgr for dpdk_zero_copy
Add configuration sections to the UHD config file for NIC entries. Keys
are based on MAC addresses, and the entries beneath the section describe
which CPU and I/O thread to use for the NIC and its IPv4 address.

Make ring sizes configurable for uhd-dpdk. Ring size is now an argument
for packet buffers. Note that the maximum number of available buffers
is still determined at init!

Add ability to receive broadcasts to uhd-dpdk. This is controllable by
a boolean in the sockarg during socket creation. dpdk_zero_copy will
filter broadcast packets out.

Add dpdk_simple transport (to mirror udp_simple). This transport allows
receiving from broadcast addresses, but it only permits one outstanding
buffer at a time.

Fix IP checksum handling in UHD-DPDK.
TX checksums were not being calculated in the NIC, and in RX, the check
for IP checksums allowed values of zero (reported as none). Now packets
with bad IP checksums will be dropped.
2019-01-25 13:30:22 -08:00

173 lines
6 KiB
C++

//
// Copyright 2017 Ettus Research, National Instruments Company
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include "mpmd_xport_mgr.hpp"
#include "mpmd_impl.hpp"
#include "mpmd_xport_ctrl_base.hpp"
#include "mpmd_xport_ctrl_udp.hpp"
#ifdef HAVE_LIBERIO
# include "mpmd_xport_ctrl_liberio.hpp"
#endif
#ifdef HAVE_DPDK
# include "mpmd_xport_ctrl_dpdk_udp.hpp"
#endif
uhd::dict<std::string, std::string> uhd::mpmd::xport::filter_args(
const uhd::device_addr_t& args, const std::string& prefix)
{
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);
UHD_ASSERT_THROW(_xport_ctrls.count(xport_medium) > 0);
UHD_ASSERT_THROW(_xport_ctrls.at(xport_medium));
// When we've picked our preferred option, pass it to the transport
// implementation for execution:
return _xport_ctrls.at(xport_medium)
->make_transport(xport_info_out, xport_type, xport_args);
}
size_t get_mtu(const uhd::direction_t dir) const
{
if (_xport_ctrls.empty()) {
UHD_LOG_WARNING("MPMD",
"Cannot determine MTU, no transport controls have been "
"established!");
return 0;
}
size_t mtu = ~size_t(0);
for (const auto& xport_ctrl_pair : _xport_ctrls) {
mtu = std::min(mtu, xport_ctrl_pair.second->get_mtu(dir));
}
return mtu;
}
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
{
for (const auto& xport_info : xport_info_list) {
const std::string xport_medium = xport_info.at("type");
if (_xport_ctrls.count(xport_medium) != 0 and _xport_ctrls.at(xport_medium)
and _xport_ctrls.at(xport_medium)->is_valid(xport_info)) {
return xport_info;
}
}
throw uhd::runtime_error(
"Could not select a transport option! "
"Either a transport hint was not specified or the specified "
"hint does not support communication with RFNoC blocks.");
}
//! 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") {
#ifdef HAVE_DPDK
if (mb_args.has_key("use_dpdk")) {
return mpmd_xport_ctrl_base::uptr(new mpmd_xport_ctrl_dpdk_udp(mb_args));
}
#endif
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 {
UHD_LOG_WARNING(
"MPMD", "Cannot instantiate transport medium " << xport_medium);
return nullptr;
}
}
//! This will try to make _xport_ctrls contain 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 << "'");
auto mgr_impl = make_mgr_impl(xport_medium, _mb_args);
if (mgr_impl) {
_xport_ctrls[xport_medium] = std::move(mgr_impl);
}
}
}
/**************************************************************************
* Private attributes
*************************************************************************/
//! Cache available xport manager implementations
//
// Should only every be populated by require_xport_mgr()
std::unordered_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));
}