Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions lldp_handler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#include "nmos/lldp_handler.h"

#include "cpprest/host_utils.h"
#include "cpprest/json.h"
#include "nmos/json_fields.h"
#include "nmos/model.h"
#include "nmos/node_interfaces.h"
#include "nmos/slog.h"

namespace nmos
{
namespace experimental
{
// make an LLDP handler to update the node interfaces JSON data with attached_network_device details
lldp::lldp_handler make_lldp_handler(nmos::model& model, slog::base_gate& gate)
{
return [&model, &gate](const std::string& interface_id, const lldp::lldp_data_unit& lldpdu)
{
const auto host_interfaces = nmos::get_host_interfaces(model.settings);
const auto interfaces = nmos::experimental::node_interfaces(host_interfaces);

auto interface = interfaces.find(utility::s2us(interface_id));
if (interfaces.end() == interface)
{
slog::log<slog::severities::error>(gate, SLOG_FLF) << "LLDP received - no matching network interface " << interface_id << " to update";
return;
}

const auto& interface_name = interface->second.name;

using web::json::value_of;

auto lock = model.write_lock();
auto& resources = model.node_resources;

auto resource = nmos::find_self_resource(resources);
if (resources.end() != resource)
{
auto& json_interfaces = nmos::fields::interfaces(resource->data);

const auto json_interface = std::find_if(json_interfaces.begin(), json_interfaces.end(), [&](const web::json::value& nv)
{
return nmos::fields::name(nv) == interface_name;
});

if (json_interfaces.end() == json_interface)
{
slog::log<slog::severities::error>(gate, SLOG_FLF) << "LLDP received - no matching network interface " << interface_id << " to update";
return;
}

const auto attached_network_device = value_of({
{ nmos::fields::chassis_id, utility::s2us(lldp::parse_chassis_id(lldpdu.chassis_id)) },
{ nmos::fields::port_id, utility::s2us(lldp::parse_port_id(lldpdu.port_id)) }
});

// has the attached_network_device info changed?
if (nmos::fields::attached_network_device(*json_interface) != attached_network_device)
{
slog::log<slog::severities::more_info>(gate, SLOG_FLF) << "LLDP received - updating attached network device info for network interface " << interface->second.name;

nmos::modify_resource(resources, resource->id, [&interface_name, &attached_network_device](nmos::resource& resource)
{
resource.data[nmos::fields::version] = web::json::value::string(nmos::make_version());

auto& json_interfaces = nmos::fields::interfaces(resource.data);

const auto json_interface = std::find_if(json_interfaces.begin(), json_interfaces.end(), [&](const web::json::value& nv)
{
return nmos::fields::name(nv) == interface_name;
});

if (json_interfaces.end() != json_interface)
{
(*json_interface)[nmos::fields::attached_network_device] = attached_network_device;
}
});

slog::log<slog::severities::too_much_info>(gate, SLOG_FLF) << "Notifying attached network device info updated";
model.notify();
}
}
else
{
slog::log<slog::severities::error>(gate, SLOG_FLF) << "Self resource not found!";
}
};
}
}
}
26 changes: 26 additions & 0 deletions lldp_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef NMOS_LLDP_HANDLER_H
#define NMOS_LLDP_HANDLER_H

#include <map>
#include "cpprest/details/basic_types.h"
#include "lldp/lldp.h" // forward declaration of lldp::lldp_handler

namespace slog
{
class base_gate;
}

namespace nmos
{
struct model;

struct node_interface;

namespace experimental
{
// make an LLDP handler to update the node interfaces JSON data with attached_network_device details
lldp::lldp_handler make_lldp_handler(nmos::model& model, slog::base_gate& gate);
}
}

#endif
48 changes: 48 additions & 0 deletions lldp_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#ifdef HAVE_LLDP
#include "nmos/lldp_manager.h"

#include "lldp/lldp_manager.h"
#include "cpprest/json.h"
#include "nmos/json_fields.h"
#include "nmos/lldp_handler.h"
#include "nmos/model.h"
#include "nmos/node_interfaces.h"
#include "nmos/slog.h"

namespace nmos
{
namespace experimental
{
// make an LLDP manager configured to receive LLDP frames on the specified interfaces
// and update the node interfaces JSON data with attached_network_device details
// and optionally, transmit LLDP frames for these interfaces
lldp::lldp_manager make_lldp_manager(nmos::model& model, const std::map<utility::string_t, node_interface>& interfaces, bool transmit, slog::base_gate& gate)
{
// use default configuration for now
lldp::lldp_manager manager(gate);

const auto status = transmit ? lldp::management_status::transmit_receive : lldp::management_status::receive;

manager.set_handler(make_lldp_handler(model, gate));

for (const auto& interface : interfaces)
{
// data with default TTL
const auto data = lldp::normal_data_unit(
lldp::make_chassis_id(utility::us2s(interface.second.chassis_id)),
lldp::make_port_id(utility::us2s(interface.second.port_id)),
{ utility::us2s(interface.second.name) },
utility::us2s(nmos::get_host_name(model.settings))
);

auto configure = manager.configure_interface(utility::us2s(interface.first), status, data);
// current configure_interface implementation is synchronous, but just to make clear...
// for now, wait for it to complete
configure.wait();
}

return manager;
}
}
}
#endif
Loading