face: UnicastEthernetTransport
Change-Id: I4d19f52835d9268f2ea63fd4e0b1a0a5aed95c47 Refs: #4011
This commit is contained in:
@@ -49,6 +49,6 @@ export ASAN_OPTIONS
|
||||
|
||||
# Then use sudo to run those tests that need superuser powers
|
||||
sudo -E ./build/unit-tests-core -t TestPrivilegeHelper $(ut_log_args core-privilege)
|
||||
sudo -E ./build/unit-tests-daemon -t Face/TestEthernetTransport $(ut_log_args daemon-ethernet)
|
||||
sudo -E ./build/unit-tests-daemon -t Face/*EthernetTransport $(ut_log_args daemon-ethernet)
|
||||
sudo -E ./build/unit-tests-daemon -t Face/*Factory/ProcessConfig $(ut_log_args daemon-face-config)
|
||||
sudo -E ./build/unit-tests-daemon -t Mgmt/TestGeneralConfigSection/UserAndGroupConfig,NoUserConfig $(ut_log_args daemon-user-config)
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
*/
|
||||
|
||||
#include "ethernet-factory.hpp"
|
||||
#include "ethernet-transport.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "multicast-ethernet-transport.hpp"
|
||||
#include "core/logger.hpp"
|
||||
#include <boost/range/adaptors.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
@@ -165,7 +165,7 @@ EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& netif,
|
||||
opts.allowReassembly = true;
|
||||
|
||||
auto linkService = make_unique<face::GenericLinkService>(opts);
|
||||
auto transport = make_unique<face::EthernetTransport>(netif, address, m_mcastConfig.linkType);
|
||||
auto transport = make_unique<face::MulticastEthernetTransport>(netif, address, m_mcastConfig.linkType);
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
m_mcastFaces[key] = face;
|
||||
|
||||
@@ -33,27 +33,11 @@
|
||||
#include <arpa/inet.h> // for htons() and ntohs()
|
||||
#include <net/ethernet.h> // for struct ether_header
|
||||
#include <net/if.h> // for struct ifreq
|
||||
#include <stdio.h> // for snprintf()
|
||||
#include <sys/ioctl.h> // for ioctl()
|
||||
#include <unistd.h> // for dup()
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <netpacket/packet.h> // for struct packet_mreq
|
||||
#include <sys/socket.h> // for setsockopt()
|
||||
#endif
|
||||
|
||||
#ifdef SIOCADDMULTI
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <net/if_dl.h> // for struct sockaddr_dl
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(PCAP_NETMASK_UNKNOWN)
|
||||
/*
|
||||
* Value to pass to pcap_compile() as the netmask if you don't know what
|
||||
* the netmask is.
|
||||
*/
|
||||
#define PCAP_NETMASK_UNKNOWN 0xffffffff
|
||||
#define PCAP_NETMASK_UNKNOWN 0xffffffff
|
||||
#endif
|
||||
|
||||
namespace nfd {
|
||||
@@ -61,29 +45,20 @@ namespace face {
|
||||
|
||||
NFD_LOG_INIT("EthernetTransport");
|
||||
|
||||
EthernetTransport::EthernetTransport(const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& mcastAddress,
|
||||
ndn::nfd::LinkType linkType)
|
||||
EthernetTransport::EthernetTransport(const NetworkInterfaceInfo& localEndpoint,
|
||||
const ethernet::Address& remoteEndpoint)
|
||||
: m_pcap(nullptr, pcap_close)
|
||||
, m_socket(getGlobalIoService())
|
||||
, m_srcAddress(interface.etherAddress)
|
||||
, m_destAddress(mcastAddress)
|
||||
, m_interfaceName(interface.name)
|
||||
, m_srcAddress(localEndpoint.etherAddress)
|
||||
, m_destAddress(remoteEndpoint)
|
||||
, m_interfaceName(localEndpoint.name)
|
||||
#if defined(__linux__)
|
||||
, m_interfaceIndex(interface.index)
|
||||
, m_interfaceIndex(localEndpoint.index)
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
, m_nDropped(0)
|
||||
#endif
|
||||
{
|
||||
this->setLocalUri(FaceUri::fromDev(interface.name));
|
||||
this->setRemoteUri(FaceUri(mcastAddress));
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
|
||||
this->setLinkType(linkType);
|
||||
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
|
||||
pcapInit();
|
||||
|
||||
int fd = pcap_get_selectable_fd(m_pcap.get());
|
||||
@@ -98,37 +73,22 @@ EthernetTransport::EthernetTransport(const NetworkInterfaceInfo& interface,
|
||||
// do this after assigning m_socket because getInterfaceMtu uses it
|
||||
this->setMtu(getInterfaceMtu());
|
||||
|
||||
char filter[110];
|
||||
// note #1: we cannot use std::snprintf because it's not available
|
||||
// on some platforms (see #2299)
|
||||
// note #2: "not vlan" must appear last in the filter expression, or the
|
||||
// rest of the filter won't work as intended (see pcap-filter(7))
|
||||
snprintf(filter, sizeof(filter),
|
||||
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s) && (not vlan)",
|
||||
ethernet::ETHERTYPE_NDN,
|
||||
m_destAddress.toString().c_str(),
|
||||
m_srcAddress.toString().c_str());
|
||||
setPacketFilter(filter);
|
||||
|
||||
if (!m_destAddress.isBroadcast() && !joinMulticastGroup()) {
|
||||
NFD_LOG_FACE_WARN("Falling back to promiscuous mode");
|
||||
pcap_set_promisc(m_pcap.get(), 1);
|
||||
}
|
||||
|
||||
m_socket.async_read_some(boost::asio::null_buffers(),
|
||||
bind(&EthernetTransport::handleRead, this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void EthernetTransport::doSend(Transport::Packet&& packet)
|
||||
void
|
||||
EthernetTransport::doSend(Transport::Packet&& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
sendPacket(packet.packet);
|
||||
}
|
||||
|
||||
void EthernetTransport::doClose()
|
||||
void
|
||||
EthernetTransport::doClose()
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
@@ -158,7 +118,7 @@ EthernetTransport::pcapInit()
|
||||
|
||||
#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
|
||||
// Enable "immediate mode", effectively disabling any read buffering in the kernel.
|
||||
// This corresponds to the BIOCIMMEDIATE ioctl on BSD-like systems (including OS X)
|
||||
// This corresponds to the BIOCIMMEDIATE ioctl on BSD-like systems (including macOS)
|
||||
// where libpcap uses a BPF device. On Linux this forces libpcap not to use TPACKET_V3,
|
||||
// even if the kernel supports it, thus preventing bug #1511.
|
||||
pcap_set_immediate_mode(m_pcap.get(), 1);
|
||||
@@ -188,72 +148,6 @@ EthernetTransport::setPacketFilter(const char* filterString)
|
||||
BOOST_THROW_EXCEPTION(Error("pcap_setfilter: " + std::string(pcap_geterr(m_pcap.get()))));
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetTransport::joinMulticastGroup()
|
||||
{
|
||||
#if defined(__linux__)
|
||||
packet_mreq mr{};
|
||||
mr.mr_ifindex = m_interfaceIndex;
|
||||
mr.mr_type = PACKET_MR_MULTICAST;
|
||||
mr.mr_alen = m_destAddress.size();
|
||||
std::memcpy(mr.mr_address, m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
if (::setsockopt(m_socket.native_handle(), SOL_PACKET,
|
||||
PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == 0)
|
||||
return true; // success
|
||||
|
||||
NFD_LOG_FACE_WARN("setsockopt(PACKET_ADD_MEMBERSHIP) failed: " << std::strerror(errno));
|
||||
#endif
|
||||
|
||||
#if defined(SIOCADDMULTI)
|
||||
ifreq ifr{};
|
||||
std::strncpy(ifr.ifr_name, m_interfaceName.c_str(), sizeof(ifr.ifr_name) - 1);
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// see bug #2327
|
||||
using boost::asio::ip::udp;
|
||||
udp::socket sock(getGlobalIoService(), udp::v4());
|
||||
int fd = sock.native_handle();
|
||||
|
||||
/*
|
||||
* Differences between Linux and the BSDs (including OS X):
|
||||
* o BSD does not have ifr_hwaddr; use ifr_addr instead.
|
||||
* o While OS X seems to accept both AF_LINK and AF_UNSPEC as the address
|
||||
* family, FreeBSD explicitly requires AF_LINK, so we have to use AF_LINK
|
||||
* and sockaddr_dl instead of the generic sockaddr structure.
|
||||
* o BSD's sockaddr (and sockaddr_dl in particular) contains an additional
|
||||
* field, sa_len (sdl_len), which must be set to the total length of the
|
||||
* structure, including the length field itself.
|
||||
* o We do not specify the interface name, thus sdl_nlen is left at 0 and
|
||||
* LLADDR is effectively the same as sdl_data.
|
||||
*/
|
||||
sockaddr_dl* sdl = reinterpret_cast<sockaddr_dl*>(&ifr.ifr_addr);
|
||||
sdl->sdl_len = sizeof(ifr.ifr_addr);
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_alen = m_destAddress.size();
|
||||
std::memcpy(LLADDR(sdl), m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
static_assert(sizeof(ifr.ifr_addr) >= offsetof(sockaddr_dl, sdl_data) + ethernet::ADDR_LEN,
|
||||
"ifr_addr in struct ifreq is too small on this platform");
|
||||
#else
|
||||
int fd = m_socket.native_handle();
|
||||
|
||||
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
|
||||
std::memcpy(ifr.ifr_hwaddr.sa_data, m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= ethernet::ADDR_LEN,
|
||||
"ifr_hwaddr in struct ifreq is too small on this platform");
|
||||
#endif
|
||||
|
||||
if (::ioctl(fd, SIOCADDMULTI, &ifr) == 0)
|
||||
return true; // success
|
||||
|
||||
NFD_LOG_FACE_WARN("ioctl(SIOCADDMULTI) failed: " << std::strerror(errno));
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::sendPacket(const ndn::Block& block)
|
||||
{
|
||||
@@ -340,7 +234,7 @@ EthernetTransport::processIncomingPacket(const pcap_pkthdr* header, const uint8_
|
||||
|
||||
// check that our BPF filter is working correctly
|
||||
BOOST_ASSERT_MSG(ethernet::Address(eh->ether_dhost) == m_destAddress,
|
||||
"Received frame addressed to a different multicast group");
|
||||
"Received frame addressed to another host or multicast group");
|
||||
BOOST_ASSERT_MSG(sourceAddress != m_srcAddress,
|
||||
"Received frame sent by this host");
|
||||
|
||||
|
||||
@@ -43,9 +43,9 @@ namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/**
|
||||
* \brief A multicast Transport that uses raw Ethernet II frames
|
||||
* @brief Base class for Ethernet-based Transports
|
||||
*/
|
||||
class EthernetTransport final : public Transport
|
||||
class EthernetTransport : public Transport
|
||||
{
|
||||
public:
|
||||
class Error : public std::runtime_error
|
||||
@@ -58,42 +58,29 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates an Ethernet-based transport for multicast communication
|
||||
*/
|
||||
EthernetTransport(const NetworkInterfaceInfo& interface,
|
||||
const ethernet::Address& mcastAddress,
|
||||
ndn::nfd::LinkType linkType);
|
||||
|
||||
protected:
|
||||
EthernetTransport(const NetworkInterfaceInfo& localEndpoint,
|
||||
const ethernet::Address& remoteEndpoint);
|
||||
|
||||
void
|
||||
doClose() final;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Installs a BPF filter on the receiving socket
|
||||
* @param filterString string containing the BPF program source
|
||||
*/
|
||||
void
|
||||
doSend(Transport::Packet&& packet) final;
|
||||
setPacketFilter(const char* filterString);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Allocates and initializes a libpcap context for live capture
|
||||
*/
|
||||
void
|
||||
pcapInit();
|
||||
|
||||
/**
|
||||
* @brief Installs a BPF filter on the receiving socket
|
||||
*
|
||||
* @param filterString string containing the source BPF program
|
||||
*/
|
||||
void
|
||||
setPacketFilter(const char* filterString);
|
||||
|
||||
/**
|
||||
* @brief Enables receiving frames addressed to our MAC multicast group
|
||||
*
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
bool
|
||||
joinMulticastGroup();
|
||||
doSend(Transport::Packet&& packet) final;
|
||||
|
||||
/**
|
||||
* @brief Sends the specified TLV block on the network wrapped in an Ethernet frame
|
||||
@@ -130,7 +117,7 @@ private:
|
||||
size_t
|
||||
getInterfaceMtu();
|
||||
|
||||
private:
|
||||
protected:
|
||||
unique_ptr<pcap_t, void(*)(pcap_t*)> m_pcap;
|
||||
boost::asio::posix::stream_descriptor m_socket;
|
||||
|
||||
@@ -141,6 +128,7 @@ private:
|
||||
int m_interfaceIndex;
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef _DEBUG
|
||||
/// number of packets dropped by the kernel, as reported by libpcap
|
||||
unsigned int m_nDropped;
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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.
|
||||
*
|
||||
* NFD 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
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "multicast-ethernet-transport.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
|
||||
#include <pcap/pcap.h>
|
||||
|
||||
#include <cerrno> // for errno
|
||||
#include <cstring> // for memcpy(), strerror(), strncpy()
|
||||
#include <net/if.h> // for struct ifreq
|
||||
#include <stdio.h> // for snprintf()
|
||||
#include <sys/ioctl.h> // for ioctl()
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <netpacket/packet.h> // for struct packet_mreq
|
||||
#include <sys/socket.h> // for setsockopt()
|
||||
#endif
|
||||
|
||||
#ifdef SIOCADDMULTI
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <net/if_dl.h> // for struct sockaddr_dl
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT("MulticastEthernetTransport");
|
||||
|
||||
MulticastEthernetTransport::MulticastEthernetTransport(const NetworkInterfaceInfo& localEndpoint,
|
||||
const ethernet::Address& mcastAddress,
|
||||
ndn::nfd::LinkType linkType)
|
||||
: EthernetTransport(localEndpoint, mcastAddress)
|
||||
{
|
||||
this->setLocalUri(FaceUri::fromDev(m_interfaceName));
|
||||
this->setRemoteUri(FaceUri(m_destAddress));
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
|
||||
this->setLinkType(linkType);
|
||||
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
|
||||
char filter[110];
|
||||
// note #1: we cannot use std::snprintf because it's not available
|
||||
// on some platforms (see #2299)
|
||||
// note #2: "not vlan" must appear last in the filter expression, or the
|
||||
// rest of the filter won't work as intended (see pcap-filter(7))
|
||||
snprintf(filter, sizeof(filter),
|
||||
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s) && (not vlan)",
|
||||
ethernet::ETHERTYPE_NDN,
|
||||
m_destAddress.toString().c_str(),
|
||||
m_srcAddress.toString().c_str());
|
||||
setPacketFilter(filter);
|
||||
|
||||
if (!m_destAddress.isBroadcast() && !joinMulticastGroup()) {
|
||||
NFD_LOG_FACE_WARN("Falling back to promiscuous mode");
|
||||
pcap_set_promisc(m_pcap.get(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MulticastEthernetTransport::joinMulticastGroup()
|
||||
{
|
||||
#if defined(__linux__)
|
||||
packet_mreq mr{};
|
||||
mr.mr_ifindex = m_interfaceIndex;
|
||||
mr.mr_type = PACKET_MR_MULTICAST;
|
||||
mr.mr_alen = m_destAddress.size();
|
||||
std::memcpy(mr.mr_address, m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
if (::setsockopt(m_socket.native_handle(), SOL_PACKET,
|
||||
PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == 0)
|
||||
return true; // success
|
||||
|
||||
NFD_LOG_FACE_WARN("setsockopt(PACKET_ADD_MEMBERSHIP) failed: " << std::strerror(errno));
|
||||
#endif
|
||||
|
||||
#if defined(SIOCADDMULTI)
|
||||
ifreq ifr{};
|
||||
std::strncpy(ifr.ifr_name, m_interfaceName.c_str(), sizeof(ifr.ifr_name) - 1);
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// see bug #2327
|
||||
using boost::asio::ip::udp;
|
||||
udp::socket sock(getGlobalIoService(), udp::v4());
|
||||
int fd = sock.native_handle();
|
||||
|
||||
// Differences between Linux and the BSDs (including macOS):
|
||||
// o BSD does not have ifr_hwaddr; use ifr_addr instead.
|
||||
// o While macOS seems to accept both AF_LINK and AF_UNSPEC as the address
|
||||
// family, FreeBSD explicitly requires AF_LINK, so we have to use AF_LINK
|
||||
// and sockaddr_dl instead of the generic sockaddr structure.
|
||||
// o BSD's sockaddr (and sockaddr_dl in particular) contains an additional
|
||||
// field, sa_len (sdl_len), which must be set to the total length of the
|
||||
// structure, including the length field itself.
|
||||
// o We do not specify the interface name, thus sdl_nlen is left at 0 and
|
||||
// LLADDR is effectively the same as sdl_data.
|
||||
|
||||
sockaddr_dl* sdl = reinterpret_cast<sockaddr_dl*>(&ifr.ifr_addr);
|
||||
sdl->sdl_len = sizeof(ifr.ifr_addr);
|
||||
sdl->sdl_family = AF_LINK;
|
||||
sdl->sdl_alen = m_destAddress.size();
|
||||
std::memcpy(LLADDR(sdl), m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
static_assert(sizeof(ifr.ifr_addr) >= offsetof(sockaddr_dl, sdl_data) + ethernet::ADDR_LEN,
|
||||
"ifr_addr in struct ifreq is too small on this platform");
|
||||
#else
|
||||
int fd = m_socket.native_handle();
|
||||
|
||||
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
|
||||
std::memcpy(ifr.ifr_hwaddr.sa_data, m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= ethernet::ADDR_LEN,
|
||||
"ifr_hwaddr in struct ifreq is too small on this platform");
|
||||
#endif
|
||||
|
||||
if (::ioctl(fd, SIOCADDMULTI, &ifr) == 0)
|
||||
return true; // success
|
||||
|
||||
NFD_LOG_FACE_WARN("ioctl(SIOCADDMULTI) failed: " << std::strerror(errno));
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,59 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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.
|
||||
*
|
||||
* NFD 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
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_MULTICAST_ETHERNET_TRANSPORT_HPP
|
||||
#define NFD_DAEMON_FACE_MULTICAST_ETHERNET_TRANSPORT_HPP
|
||||
|
||||
#include "ethernet-transport.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/**
|
||||
* @brief A multicast Transport that uses raw Ethernet II frames
|
||||
*/
|
||||
class MulticastEthernetTransport final : public EthernetTransport
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Creates an Ethernet-based transport for multicast communication
|
||||
*/
|
||||
MulticastEthernetTransport(const NetworkInterfaceInfo& localEndpoint,
|
||||
const ethernet::Address& mcastAddress,
|
||||
ndn::nfd::LinkType linkType);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Enables receiving frames addressed to our MAC multicast group
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
bool
|
||||
joinMulticastGroup();
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_MULTICAST_ETHERNET_TRANSPORT_HPP
|
||||
@@ -0,0 +1,66 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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.
|
||||
*
|
||||
* NFD 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
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "unicast-ethernet-transport.hpp"
|
||||
|
||||
#include <stdio.h> // for snprintf()
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT("UnicastEthernetTransport");
|
||||
|
||||
UnicastEthernetTransport::UnicastEthernetTransport(const NetworkInterfaceInfo& localEndpoint,
|
||||
const ethernet::Address& remoteEndpoint,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
time::nanoseconds idleTimeout)
|
||||
: EthernetTransport(localEndpoint, remoteEndpoint)
|
||||
, m_idleTimeout(idleTimeout)
|
||||
{
|
||||
this->setLocalUri(FaceUri::fromDev(m_interfaceName));
|
||||
this->setRemoteUri(FaceUri(m_destAddress));
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
this->setPersistency(persistency);
|
||||
this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
|
||||
NFD_LOG_FACE_INFO("Creating transport");
|
||||
|
||||
char filter[110];
|
||||
// note #1: we cannot use std::snprintf because it's not available
|
||||
// on some platforms (see #2299)
|
||||
// note #2: "not vlan" must appear last in the filter expression, or the
|
||||
// rest of the filter won't work as intended (see pcap-filter(7))
|
||||
snprintf(filter, sizeof(filter),
|
||||
"(ether proto 0x%x) && (ether src %s) && (ether dst %s) && (not vlan)",
|
||||
ethernet::ETHERTYPE_NDN,
|
||||
m_destAddress.toString().c_str(),
|
||||
m_srcAddress.toString().c_str());
|
||||
setPacketFilter(filter);
|
||||
|
||||
// TODO: implement close on idle and persistency change
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,55 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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.
|
||||
*
|
||||
* NFD 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
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_UNICAST_ETHERNET_TRANSPORT_HPP
|
||||
#define NFD_DAEMON_FACE_UNICAST_ETHERNET_TRANSPORT_HPP
|
||||
|
||||
#include "ethernet-transport.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/**
|
||||
* @brief A unicast Transport that uses raw Ethernet II frames
|
||||
*/
|
||||
class UnicastEthernetTransport final : public EthernetTransport
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Creates an Ethernet-based transport for unicast communication
|
||||
*/
|
||||
UnicastEthernetTransport(const NetworkInterfaceInfo& localEndpoint,
|
||||
const ethernet::Address& remoteEndpoint,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
time::nanoseconds idleTimeout);
|
||||
|
||||
private:
|
||||
const time::nanoseconds m_idleTimeout;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FACE_UNICAST_ETHERNET_TRANSPORT_HPP
|
||||
@@ -27,7 +27,8 @@
|
||||
#define NFD_TESTS_DAEMON_FACE_ETHERNET_FIXTURE_HPP
|
||||
|
||||
#include "core/network-interface.hpp"
|
||||
#include "face/ethernet-transport.hpp"
|
||||
#include "face/multicast-ethernet-transport.hpp"
|
||||
#include "face/unicast-ethernet-transport.hpp"
|
||||
|
||||
#include "test-common.hpp"
|
||||
|
||||
@@ -43,7 +44,8 @@ protected:
|
||||
for (const auto& netif : listNetworkInterfaces()) {
|
||||
if (!netif.isLoopback() && netif.isUp()) {
|
||||
try {
|
||||
EthernetTransport transport(netif, ethernet::getBroadcastAddress(), ndn::nfd::LINK_TYPE_MULTI_ACCESS);
|
||||
MulticastEthernetTransport transport(netif, ethernet::getBroadcastAddress(),
|
||||
ndn::nfd::LINK_TYPE_MULTI_ACCESS);
|
||||
netifs.push_back(netif);
|
||||
}
|
||||
catch (const EthernetTransport::Error&) {
|
||||
@@ -53,7 +55,32 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initializeUnicast(ethernet::Address remoteAddr = {0x0A, 0x01, 0x23, 0x45, 0x67, 0x89},
|
||||
ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
|
||||
{
|
||||
BOOST_ASSERT(netifs.size() > 0);
|
||||
localEp = netifs.front().name;
|
||||
remoteEp = remoteAddr;
|
||||
transport = make_unique<UnicastEthernetTransport>(netifs.front(), remoteEp,
|
||||
persistency, time::seconds(5));
|
||||
}
|
||||
|
||||
void
|
||||
initializeMulticast(ethernet::Address mcastGroup = ethernet::getDefaultMulticastAddress(),
|
||||
ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_MULTI_ACCESS)
|
||||
{
|
||||
BOOST_ASSERT(netifs.size() > 0);
|
||||
localEp = netifs.front().name;
|
||||
remoteEp = mcastGroup;
|
||||
transport = make_unique<MulticastEthernetTransport>(netifs.front(), remoteEp, linkType);
|
||||
}
|
||||
|
||||
protected:
|
||||
unique_ptr<EthernetTransport> transport;
|
||||
std::string localEp;
|
||||
ethernet::Address remoteEp;
|
||||
|
||||
/** \brief EthernetTransport-capable network interfaces
|
||||
*/
|
||||
std::vector<NetworkInterfaceInfo> netifs;
|
||||
|
||||
+14
-22
@@ -23,54 +23,46 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "face/ethernet-transport.hpp"
|
||||
|
||||
#include "transport-test-common.hpp"
|
||||
|
||||
#include "ethernet-fixture.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
namespace tests {
|
||||
|
||||
using namespace nfd::tests;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Face)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestEthernetTransport, EthernetFixture)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestMulticastEthernetTransport, EthernetFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(StaticProperties)
|
||||
{
|
||||
SKIP_IF_ETHERNET_NETIF_COUNT_LT(1);
|
||||
initializeMulticast();
|
||||
|
||||
auto netif = netifs.front();
|
||||
EthernetTransport transport(netif,
|
||||
ethernet::getDefaultMulticastAddress(),
|
||||
ndn::nfd::LINK_TYPE_MULTI_ACCESS);
|
||||
checkStaticPropertiesInitialized(transport);
|
||||
checkStaticPropertiesInitialized(*transport);
|
||||
|
||||
BOOST_CHECK_EQUAL(transport.getLocalUri(), FaceUri::fromDev(netif.name));
|
||||
BOOST_CHECK_EQUAL(transport.getRemoteUri(), FaceUri(ethernet::getDefaultMulticastAddress()));
|
||||
BOOST_CHECK_EQUAL(transport.getScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
BOOST_CHECK_EQUAL(transport.getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
|
||||
BOOST_CHECK_EQUAL(transport.getLinkType(), ndn::nfd::LINK_TYPE_MULTI_ACCESS);
|
||||
BOOST_CHECK_EQUAL(transport->getLocalUri(), FaceUri("dev://" + localEp));
|
||||
BOOST_CHECK_EQUAL(transport->getRemoteUri(), FaceUri("ether://[" + remoteEp.toString() + "]"));
|
||||
BOOST_CHECK_EQUAL(transport->getScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
BOOST_CHECK_EQUAL(transport->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
|
||||
BOOST_CHECK_EQUAL(transport->getLinkType(), ndn::nfd::LINK_TYPE_MULTI_ACCESS);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(PersistencyChange)
|
||||
{
|
||||
SKIP_IF_ETHERNET_NETIF_COUNT_LT(1);
|
||||
EthernetTransport transport(netifs.front(),
|
||||
ethernet::getDefaultMulticastAddress(),
|
||||
ndn::nfd::LINK_TYPE_MULTI_ACCESS);
|
||||
initializeMulticast();
|
||||
|
||||
BOOST_CHECK_EQUAL(transport.canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND), false);
|
||||
BOOST_CHECK_EQUAL(transport.canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERSISTENT), false);
|
||||
BOOST_CHECK_EQUAL(transport.canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERMANENT), true);
|
||||
BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND), false);
|
||||
BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERSISTENT), false);
|
||||
BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERMANENT), true);
|
||||
}
|
||||
|
||||
///\todo #3369 add the equivalent of these test cases from ethernet.t.cpp
|
||||
/// as of commit:65caf200924b28748037750449e28bcb548dbc9c
|
||||
/// SendPacket, ProcessIncomingPacket
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestEthernetTransport
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestMulticastEthernetTransport
|
||||
BOOST_AUTO_TEST_SUITE_END() // Face
|
||||
|
||||
} // namespace tests
|
||||
@@ -0,0 +1,66 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD 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.
|
||||
*
|
||||
* NFD 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
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "transport-test-common.hpp"
|
||||
|
||||
#include "ethernet-fixture.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
namespace tests {
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Face)
|
||||
BOOST_FIXTURE_TEST_SUITE(TestUnicastEthernetTransport, EthernetFixture)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(StaticProperties)
|
||||
{
|
||||
SKIP_IF_ETHERNET_NETIF_COUNT_LT(1);
|
||||
initializeUnicast();
|
||||
|
||||
checkStaticPropertiesInitialized(*transport);
|
||||
|
||||
BOOST_CHECK_EQUAL(transport->getLocalUri(), FaceUri("dev://" + localEp));
|
||||
BOOST_CHECK_EQUAL(transport->getRemoteUri(), FaceUri("ether://[" + remoteEp.toString() + "]"));
|
||||
BOOST_CHECK_EQUAL(transport->getScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
BOOST_CHECK_EQUAL(transport->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
|
||||
BOOST_CHECK_EQUAL(transport->getLinkType(), ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(PersistencyChange)
|
||||
{
|
||||
SKIP_IF_ETHERNET_NETIF_COUNT_LT(1);
|
||||
initializeUnicast();
|
||||
|
||||
BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND), false);
|
||||
BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERSISTENT), true);
|
||||
BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERMANENT), false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // TestUnicastEthernetTransport
|
||||
BOOST_AUTO_TEST_SUITE_END() // Face
|
||||
|
||||
} // namespace tests
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
Reference in New Issue
Block a user