aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/mpmd/mpmd_find.cpp
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2018-01-23 18:27:11 -0800
committerMartin Braun <martin.braun@ettus.com>2018-02-07 17:01:06 -0800
commit3df3b6cc62911f1a87d2c7ff0775e7c2644900d5 (patch)
tree5d9d6b890be85f99c7686ad94dd4ba4278d20210 /host/lib/usrp/mpmd/mpmd_find.cpp
parent342971d2683b7b1a53f38b9e88749add37c9fa36 (diff)
downloaduhd-3df3b6cc62911f1a87d2c7ff0775e7c2644900d5.tar.gz
uhd-3df3b6cc62911f1a87d2c7ff0775e7c2644900d5.tar.bz2
uhd-3df3b6cc62911f1a87d2c7ff0775e7c2644900d5.zip
mpmd: Factor find and prop tree init code out of mpmd_impl.cpp
No functional changes.
Diffstat (limited to 'host/lib/usrp/mpmd/mpmd_find.cpp')
-rw-r--r--host/lib/usrp/mpmd/mpmd_find.cpp251
1 files changed, 251 insertions, 0 deletions
diff --git a/host/lib/usrp/mpmd/mpmd_find.cpp b/host/lib/usrp/mpmd/mpmd_find.cpp
new file mode 100644
index 000000000..2f70ec280
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_find.cpp
@@ -0,0 +1,251 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+
+// find-related code for MPM devices
+
+#include "mpmd_impl.hpp"
+#include <uhd/types/device_addr.hpp>
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/transport/if_addrs.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/asio.hpp>
+
+using namespace uhd;
+using namespace uhd::mpmd;
+
+constexpr char mpmd_impl::MPM_DISC_RESPONSE_PREAMBLE[];
+
+namespace {
+ //! How long we wait for discovery responses (in seconds)
+ constexpr double MPMD_FIND_TIMEOUT = 0.5;
+ constexpr char MPMD_CHDR_REACHABILITY_KEY[] = "reachable";
+ constexpr char MPMD_CHDR_REACHABILITY_NEGATIVE[] = "No";
+
+ device_addr_t flag_dev_as_unreachable(const device_addr_t& device_args)
+ {
+ device_addr_t flagged_device_args(device_args);
+ flagged_device_args[MPMD_CHDR_REACHABILITY_KEY] =
+ MPMD_CHDR_REACHABILITY_NEGATIVE;
+ return flagged_device_args;
+ }
+}
+
+device_addrs_t mpmd_find_with_addr(
+ const std::string& mgmt_addr,
+ const device_addr_t& hint_
+) {
+ UHD_ASSERT_THROW(not mgmt_addr.empty());
+ const std::string mpm_discovery_port = hint_.get(
+ mpmd_impl::MPM_DISCOVERY_PORT_KEY,
+ std::to_string(mpmd_impl::MPM_DISCOVERY_PORT)
+ );
+ UHD_LOG_DEBUG("MPMD",
+ "Discovering MPM devices on port " << mpm_discovery_port);
+
+ device_addrs_t addrs;
+ transport::udp_simple::sptr comm = transport::udp_simple::make_broadcast(
+ mgmt_addr, mpm_discovery_port);
+ comm->send(
+ boost::asio::buffer(
+ mpmd_impl::MPM_DISCOVERY_CMD.c_str(),
+ mpmd_impl::MPM_DISCOVERY_CMD.size()
+ )
+ );
+ while (true) {
+ 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) {
+ break;
+ }
+ const char* reply = (const char*)buff;
+ std::string reply_string = std::string(reply);
+ std::vector<std::string> result;
+ boost::algorithm::split(result, reply_string,
+ [](const char& in) { return in == ';'; },
+ boost::token_compress_on);
+ if (result.empty()) {
+ continue;
+ }
+ // Verify we didn't receive something other than an MPM discovery
+ // response
+ if (result[0] != mpmd_impl::MPM_DISC_RESPONSE_PREAMBLE) {
+ continue;
+ }
+ const std::string recv_addr = comm->get_recv_addr();
+
+ // remove external iface addrs if executed directly on device
+ bool external_iface = false;
+ for (const auto& addr : transport::get_if_addrs()) {
+ if ((addr.inet == comm->get_recv_addr()) &&
+ recv_addr !=
+ boost::asio::ip::address_v4::loopback().to_string()) {
+ external_iface = true;
+ break;
+ }
+ }
+ if (external_iface) {
+ continue;
+ }
+
+ // Create result to return
+ device_addr_t new_addr;
+ new_addr[xport::MGMT_ADDR_KEY] = recv_addr;
+ new_addr["type"] = "mpmd"; // hwd will overwrite this
+ // remove ident string and put other informations into device_args dict
+ result.erase(result.begin());
+ // parse key-value pairs in the discovery string and add them to the
+ // device_args
+ for (const auto& el : result) {
+ std::vector<std::string> value;
+ boost::algorithm::split(value, el,
+ [](const char& in) { return in == '='; },
+ boost::token_compress_on);
+ if (value[0] != xport::MGMT_ADDR_KEY) {
+ new_addr[value[0]] = value[1];
+ }
+ }
+ // filter the discovered device below by matching optional keys
+ if (
+ (not hint_.has_key("name") or hint_["name"] == new_addr["name"])
+ and (not hint_.has_key("serial") or hint_["serial"] == new_addr["serial"])
+ and (not hint_.has_key("type") or hint_["type"] == new_addr["type"])
+ and (not hint_.has_key("product") or hint_["product"] == new_addr["product"])
+ ){
+ UHD_LOG_TRACE("MPMD FIND",
+ "Found device that matches hints: " << new_addr.to_string());
+ addrs.push_back(new_addr);
+ } else {
+ UHD_LOG_DEBUG("MPMD FIND",
+ "Found device, but does not match hint: " << recv_addr
+ );
+ }
+ }
+ return addrs;
+};
+
+
+
+// Implements scenario 1) (see below)
+device_addrs_t mpmd_find_with_addrs(const device_addrs_t& hints)
+{
+ UHD_LOG_TRACE("MPMD FIND", "Finding with addrs.");
+ device_addrs_t found_devices;
+ found_devices.reserve(hints.size());
+ for (const auto& hint : hints) {
+ if (not (hint.has_key(xport::FIRST_ADDR_KEY) or
+ hint.has_key(xport::MGMT_ADDR_KEY))) {
+ UHD_LOG_DEBUG("MPMD FIND",
+ "No address given in hint " << hint.to_string());
+ continue;
+ }
+ const std::string mgmt_addr =
+ hint.get(xport::MGMT_ADDR_KEY, hint.get(xport::FIRST_ADDR_KEY, ""));
+ device_addrs_t reply_addrs = mpmd_find_with_addr(mgmt_addr, hint);
+ if (reply_addrs.size() > 1) {
+ UHD_LOG_ERROR("MPMD",
+ "Could not resolve device hint \"" << hint.to_string()
+ << "\" to a unique device.");
+ continue;
+ } else if (reply_addrs.empty()) {
+ continue;
+ }
+ UHD_LOG_TRACE("MPMD FIND",
+ "Device responded: " << reply_addrs[0].to_string());
+ found_devices.push_back(reply_addrs[0]);
+ }
+ if (found_devices.size() == 0) {
+ return device_addrs_t();
+ } else if (found_devices.size() == 1) {
+ return found_devices;
+ } else {
+ return device_addrs_t(1, combine_device_addrs(found_devices));
+ }
+}
+
+device_addrs_t mpmd_find_with_bcast(const device_addr_t& hint)
+{
+ device_addrs_t addrs;
+ UHD_LOG_TRACE("MPMD FIND",
+ "Broadcasting on all available interfaces to find MPM devices.");
+ for (const transport::if_addrs_t& if_addr : transport::get_if_addrs()) {
+ device_addrs_t reply_addrs = mpmd_find_with_addr(if_addr.bcast, hint);
+ addrs.insert(addrs.begin(), reply_addrs.begin(), reply_addrs.end());
+ }
+ return addrs;
+}
+
+/*! Find MPM devices based on a hint
+ *
+ * There are two scenarios:
+ *
+ * 1) an addr or mgmt_addr was defined
+ *
+ * In this case, we will go through all the addrs. If they point to a device,
+ * we will then compare the other attributes (serial, etc.). If they match,
+ * the device goes into a list.
+ *
+ * 2) No addrs were defined
+ *
+ * In this case, we do a broadcast ping to see if any devices respond. After
+ * that, we do the same matching.
+ *
+ */
+device_addrs_t mpmd_find(const device_addr_t& hint_)
+{
+ device_addrs_t hints = separate_device_addr(hint_);
+ UHD_LOG_TRACE("MPMD FIND",
+ "Finding with " << hints.size() << " different hint(s).");
+
+ // Scenario 1): User gave us at least one address
+ if (not hints.empty() and
+ (hints[0].has_key(xport::FIRST_ADDR_KEY) or
+ hints[0].has_key(xport::MGMT_ADDR_KEY))) {
+ // Note: We don't try and connect to the devices in this mode, because
+ // we only get here if the user specified addresses, and we assume she
+ // knows what she's doing.
+ return mpmd_find_with_addrs(hints);
+ }
+
+ // Scenario 2): User gave us no address, and we need to broadcast
+ if (hints.empty()) {
+ hints.resize(1);
+ }
+ const auto bcast_mpm_devs = mpmd_find_with_bcast(hints[0]);
+ UHD_LOG_TRACE("MPMD FIND",
+ "Found " << bcast_mpm_devs.size() << " device via broadcast.");
+ const bool find_all = hint_.has_key(mpmd_impl::MPM_FINDALL_KEY);
+ if (find_all) {
+ UHD_LOG_TRACE("MPMD FIND",
+ "User provided " << mpmd_impl::MPM_FINDALL_KEY << ", will not "
+ "check devices for CHDR accessibility.");
+ }
+ // Filter found devices for those that we can actually talk to via CHDR
+ device_addrs_t filtered_mpm_devs;
+ for (const auto &mpm_dev : bcast_mpm_devs) {
+ const auto reachable_device_addr =
+ mpmd_mboard_impl::is_device_reachable(mpm_dev);
+ if (bool(reachable_device_addr)) {
+ filtered_mpm_devs.push_back(reachable_device_addr.get());
+ } else if (find_all) {
+ filtered_mpm_devs.emplace_back(
+ flag_dev_as_unreachable(mpm_dev)
+ );
+ }
+ }
+
+ if (filtered_mpm_devs.empty() and not bcast_mpm_devs.empty()) {
+ UHD_LOG_INFO("MPMD FIND",
+ "Found MPM devices, but none are reachable for a UHD session. "
+ "Specify " << mpmd_impl::MPM_FINDALL_KEY << " to find all devices."
+ );
+ }
+
+ return filtered_mpm_devs;
+}