From 6bd6d0b50a7046fb20e7605f0aeadf35963a458d Mon Sep 17 00:00:00 2001 From: Davide Pesavento Date: Sat, 25 Mar 2017 15:16:40 -0400 Subject: [PATCH] face: UnicastEthernetTransport Change-Id: I4d19f52835d9268f2ea63fd4e0b1a0a5aed95c47 Refs: #4011 --- .jenkins.d/20-tests.sh | 2 +- daemon/face/ethernet-factory.cpp | 4 +- daemon/face/ethernet-transport.cpp | 132 ++------------- daemon/face/ethernet-transport.hpp | 40 ++--- daemon/face/multicast-ethernet-transport.cpp | 150 ++++++++++++++++++ daemon/face/multicast-ethernet-transport.hpp | 59 +++++++ daemon/face/unicast-ethernet-transport.cpp | 66 ++++++++ daemon/face/unicast-ethernet-transport.hpp | 55 +++++++ tests/daemon/face/ethernet-fixture.hpp | 31 +++- ...cpp => multicast-ethernet-transport.t.cpp} | 36 ++--- .../face/unicast-ethernet-transport.t.cpp | 66 ++++++++ 11 files changed, 469 insertions(+), 172 deletions(-) create mode 100644 daemon/face/multicast-ethernet-transport.cpp create mode 100644 daemon/face/multicast-ethernet-transport.hpp create mode 100644 daemon/face/unicast-ethernet-transport.cpp create mode 100644 daemon/face/unicast-ethernet-transport.hpp rename tests/daemon/face/{ethernet-transport.t.cpp => multicast-ethernet-transport.t.cpp} (58%) create mode 100644 tests/daemon/face/unicast-ethernet-transport.t.cpp diff --git a/.jenkins.d/20-tests.sh b/.jenkins.d/20-tests.sh index e214f314..1e39e10e 100755 --- a/.jenkins.d/20-tests.sh +++ b/.jenkins.d/20-tests.sh @@ -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) diff --git a/daemon/face/ethernet-factory.cpp b/daemon/face/ethernet-factory.cpp index 7263118c..1b348fc4 100644 --- a/daemon/face/ethernet-factory.cpp +++ b/daemon/face/ethernet-factory.cpp @@ -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 #include @@ -165,7 +165,7 @@ EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& netif, opts.allowReassembly = true; auto linkService = make_unique(opts); - auto transport = make_unique(netif, address, m_mcastConfig.linkType); + auto transport = make_unique(netif, address, m_mcastConfig.linkType); auto face = make_shared(std::move(linkService), std::move(transport)); m_mcastFaces[key] = face; diff --git a/daemon/face/ethernet-transport.cpp b/daemon/face/ethernet-transport.cpp index 4b039c65..be44e0c8 100644 --- a/daemon/face/ethernet-transport.cpp +++ b/daemon/face/ethernet-transport.cpp @@ -33,27 +33,11 @@ #include // for htons() and ntohs() #include // for struct ether_header #include // for struct ifreq -#include // for snprintf() #include // for ioctl() #include // for dup() -#if defined(__linux__) -#include // for struct packet_mreq -#include // for setsockopt() -#endif - -#ifdef SIOCADDMULTI -#if defined(__APPLE__) || defined(__FreeBSD__) -#include // 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(&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"); diff --git a/daemon/face/ethernet-transport.hpp b/daemon/face/ethernet-transport.hpp index 0777d74e..8164a330 100644 --- a/daemon/face/ethernet-transport.hpp +++ b/daemon/face/ethernet-transport.hpp @@ -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 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; diff --git a/daemon/face/multicast-ethernet-transport.cpp b/daemon/face/multicast-ethernet-transport.cpp new file mode 100644 index 00000000..7e7f3435 --- /dev/null +++ b/daemon/face/multicast-ethernet-transport.cpp @@ -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 . + */ + +#include "multicast-ethernet-transport.hpp" +#include "core/global-io.hpp" + +#include + +#include // for errno +#include // for memcpy(), strerror(), strncpy() +#include // for struct ifreq +#include // for snprintf() +#include // for ioctl() + +#if defined(__linux__) +#include // for struct packet_mreq +#include // for setsockopt() +#endif + +#ifdef SIOCADDMULTI +#if defined(__APPLE__) || defined(__FreeBSD__) +#include // 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(&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 diff --git a/daemon/face/multicast-ethernet-transport.hpp b/daemon/face/multicast-ethernet-transport.hpp new file mode 100644 index 00000000..6d25b41f --- /dev/null +++ b/daemon/face/multicast-ethernet-transport.hpp @@ -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 . + */ + +#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 diff --git a/daemon/face/unicast-ethernet-transport.cpp b/daemon/face/unicast-ethernet-transport.cpp new file mode 100644 index 00000000..e21a793e --- /dev/null +++ b/daemon/face/unicast-ethernet-transport.cpp @@ -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 . + */ + +#include "unicast-ethernet-transport.hpp" + +#include // 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 diff --git a/daemon/face/unicast-ethernet-transport.hpp b/daemon/face/unicast-ethernet-transport.hpp new file mode 100644 index 00000000..b1a856be --- /dev/null +++ b/daemon/face/unicast-ethernet-transport.hpp @@ -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 . + */ + +#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 diff --git a/tests/daemon/face/ethernet-fixture.hpp b/tests/daemon/face/ethernet-fixture.hpp index 5769637f..029bb6ee 100644 --- a/tests/daemon/face/ethernet-fixture.hpp +++ b/tests/daemon/face/ethernet-fixture.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(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(netifs.front(), remoteEp, linkType); + } + protected: + unique_ptr transport; + std::string localEp; + ethernet::Address remoteEp; + /** \brief EthernetTransport-capable network interfaces */ std::vector netifs; diff --git a/tests/daemon/face/ethernet-transport.t.cpp b/tests/daemon/face/multicast-ethernet-transport.t.cpp similarity index 58% rename from tests/daemon/face/ethernet-transport.t.cpp rename to tests/daemon/face/multicast-ethernet-transport.t.cpp index c0d51380..ebcbe101 100644 --- a/tests/daemon/face/ethernet-transport.t.cpp +++ b/tests/daemon/face/multicast-ethernet-transport.t.cpp @@ -23,54 +23,46 @@ * NFD, e.g., in COPYING.md file. If not, see . */ -#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 diff --git a/tests/daemon/face/unicast-ethernet-transport.t.cpp b/tests/daemon/face/unicast-ethernet-transport.t.cpp new file mode 100644 index 00000000..c02fab98 --- /dev/null +++ b/tests/daemon/face/unicast-ethernet-transport.t.cpp @@ -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 . + */ + +#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