Static neighbor support
This changes adds support for assigning static ARP / NDP
neighbors on each ethernet interface.
Tested:
Ran inside a romulus VM and made sure that `ip neigh add`
commands triggered the refresh of static_neighbor objects.
Also verified that static neighbors could be added through
the CreateStatic dbus interface. Verified that deleting those
static entries would persist to the system.
Change-Id: Ifaf753525c532b6dade392d7eb4ebd6d7242d480
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/Makefile.am b/Makefile.am
index 726507e..16688dd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,8 @@
# Build these headers, don't install them
nobase_nodist_include_HEADERS = \
xyz/openbmc_project/Network/VLAN/Create/server.hpp \
- xyz/openbmc_project/Network/IP/Create/server.hpp
+ xyz/openbmc_project/Network/IP/Create/server.hpp \
+ xyz/openbmc_project/Network/Neighbor/CreateStatic/server.hpp
if HAVE_SYSTEMD
systemdsystemunit_DATA = \
@@ -15,6 +16,7 @@
noinst_HEADERS = \
ethernet_interface.hpp \
+ neighbor.hpp \
network_config.hpp \
network_manager.hpp \
ipaddress.hpp \
@@ -45,6 +47,7 @@
phosphor_network_manager_SOURCES = \
ethernet_interface.cpp \
+ neighbor.cpp \
ipaddress.cpp \
network_config.cpp \
network_manager.cpp \
@@ -52,6 +55,7 @@
system_configuration.cpp \
xyz/openbmc_project/Network/VLAN/Create/server.cpp \
xyz/openbmc_project/Network/IP/Create/server.cpp \
+ xyz/openbmc_project/Network/Neighbor/CreateStatic/server.cpp \
util.cpp \
routing_table.cpp \
config_parser.cpp \
@@ -65,13 +69,17 @@
xyz/openbmc_project/Network/VLAN/Create/server.cpp \
xyz/openbmc_project/Network/VLAN/Create/server.hpp \
xyz/openbmc_project/Network/IP/Create/server.cpp \
- xyz/openbmc_project/Network/IP/Create/server.hpp
+ xyz/openbmc_project/Network/IP/Create/server.hpp \
+ xyz/openbmc_project/Network/Neighbor/CreateStatic/server.cpp \
+ xyz/openbmc_project/Network/Neighbor/CreateStatic/server.hpp
BUILT_SOURCES = \
xyz/openbmc_project/Network/VLAN/Create/server.cpp \
xyz/openbmc_project/Network/VLAN/Create/server.hpp \
xyz/openbmc_project/Network/IP/Create/server.cpp \
- xyz/openbmc_project/Network/IP/Create/server.hpp
+ xyz/openbmc_project/Network/IP/Create/server.hpp \
+ xyz/openbmc_project/Network/Neighbor/CreateStatic/server.cpp \
+ xyz/openbmc_project/Network/Neighbor/CreateStatic/server.hpp
phosphor_network_manager_LDFLAGS = \
$(SYSTEMD_LIBS) \
@@ -106,4 +114,13 @@
$(SDBUSPLUSPLUS) -r $(srcdir) interface server-header xyz.openbmc_project.Network.IP.Create > $@
sed -i '5i #include \"xyz\/openbmc_project\/Network\/IP\/server.hpp\"' $@
+xyz/openbmc_project/Network/Neighbor/CreateStatic/server.cpp: xyz/openbmc_project/Network/Neighbor/CreateStatic.interface.yaml xyz/openbmc_project/Network/Neighbor/CreateStatic/server.hpp
+ @mkdir -p `dirname $@`
+ $(SDBUSPLUSPLUS) -r $(srcdir) interface server-cpp xyz.openbmc_project.Network.Neighbor.CreateStatic > $@
+
+xyz/openbmc_project/Network/Neighbor/CreateStatic/server.hpp: xyz/openbmc_project/Network/Neighbor/CreateStatic.interface.yaml
+ @mkdir -p `dirname $@`
+ $(SDBUSPLUSPLUS) -r $(srcdir) interface server-header xyz.openbmc_project.Network.Neighbor.CreateStatic > $@
+ sed -i '5i #include \"xyz\/openbmc_project\/Network\/Neighbor\/server.hpp\"' $@
+
SUBDIRS = test
diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
index 154efcb..92ba2cc 100644
--- a/ethernet_interface.cpp
+++ b/ethernet_interface.cpp
@@ -4,6 +4,7 @@
#include "config_parser.hpp"
#include "ipaddress.hpp"
+#include "neighbor.hpp"
#include "network_manager.hpp"
#include "routing_table.hpp"
#include "vlan_interface.hpp"
@@ -104,6 +105,28 @@
}
}
+void EthernetInterface::createStaticNeighborObjects()
+{
+ staticNeighbors.clear();
+
+ auto neighbors = getCurrentNeighbors();
+ for (const auto& neighbor : neighbors)
+ {
+ if (!neighbor.permanent || !neighbor.mac ||
+ neighbor.interface != interfaceName())
+ {
+ continue;
+ }
+ std::string ip = toString(neighbor.address);
+ std::string mac = mac_address::toString(*neighbor.mac);
+ std::string objectPath = generateStaticNeighborObjectPath(ip, mac);
+ staticNeighbors.emplace(ip,
+ std::make_shared<phosphor::network::Neighbor>(
+ bus, objectPath.c_str(), *this, ip, mac,
+ Neighbor::State::Permanent));
+ }
+}
+
ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
uint8_t prefixLength, std::string gateway)
{
@@ -155,6 +178,34 @@
return objectPath;
}
+ObjectPath EthernetInterface::neighbor(std::string iPAddress,
+ std::string mACAddress)
+{
+ if (!isValidIP(AF_INET, iPAddress) && !isValidIP(AF_INET6, iPAddress))
+ {
+ log<level::ERR>("Not a valid IP address",
+ entry("ADDRESS=%s", iPAddress.c_str()));
+ elog<InvalidArgument>(Argument::ARGUMENT_NAME("iPAddress"),
+ Argument::ARGUMENT_VALUE(iPAddress.c_str()));
+ }
+ if (!mac_address::validate(mACAddress))
+ {
+ log<level::ERR>("Not a valid MAC address",
+ entry("MACADDRESS=%s", iPAddress.c_str()));
+ elog<InvalidArgument>(Argument::ARGUMENT_NAME("mACAddress"),
+ Argument::ARGUMENT_VALUE(mACAddress.c_str()));
+ }
+
+ std::string objectPath =
+ generateStaticNeighborObjectPath(iPAddress, mACAddress);
+ staticNeighbors.emplace(iPAddress,
+ std::make_shared<phosphor::network::Neighbor>(
+ bus, objectPath.c_str(), *this, iPAddress,
+ mACAddress, Neighbor::State::Permanent));
+ manager.writeToConfigurationFile();
+ return objectPath;
+}
+
/*
Note: We don't have support for ethtool now
will enable this code once we bring the ethtool
@@ -251,6 +302,17 @@
return hexId.str();
}
+std::string EthernetInterface::generateNeighborId(const std::string& iPAddress,
+ const std::string& mACAddress)
+{
+ std::stringstream hexId;
+ std::string hashString = iPAddress + mACAddress;
+
+ // Only want 8 hex digits.
+ hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
+ return hexId.str();
+}
+
void EthernetInterface::deleteObject(const std::string& ipaddress)
{
auto it = addrs.find(ipaddress);
@@ -263,6 +325,19 @@
manager.writeToConfigurationFile();
}
+void EthernetInterface::deleteStaticNeighborObject(const std::string& iPAddress)
+{
+ auto it = staticNeighbors.find(iPAddress);
+ if (it == staticNeighbors.end())
+ {
+ log<level::ERR>(
+ "DeleteStaticNeighborObject:Unable to find the object.");
+ return;
+ }
+ staticNeighbors.erase(it);
+ manager.writeToConfigurationFile();
+}
+
void EthernetInterface::deleteVLANFromSystem(const std::string& interface)
{
auto confDir = manager.getConfDir();
@@ -330,6 +405,16 @@
return objectPath.string();
}
+std::string EthernetInterface::generateStaticNeighborObjectPath(
+ const std::string& iPAddress, const std::string& mACAddress) const
+{
+ std::experimental::filesystem::path objectPath;
+ objectPath /= objPath;
+ objectPath /= "static_neighbor";
+ objectPath /= generateNeighborId(iPAddress, mACAddress);
+ return objectPath.string();
+}
+
bool EthernetInterface::dHCPEnabled(bool value)
{
if (value == EthernetInterfaceIntf::dHCPEnabled())
@@ -419,6 +504,7 @@
// Fetch the ip address from the system
// and create the dbus object.
vlanIntf->createIPAddressObjects();
+ vlanIntf->createStaticNeighborObjects();
this->vlanInterfaces.emplace(std::move(vlanInterfaceName),
std::move(vlanIntf));
@@ -608,6 +694,15 @@
}
}
+ // Write the neighbor sections
+ for (const auto& neighbor : staticNeighbors)
+ {
+ stream << "[Neighbor]"
+ << "\n";
+ stream << "Address=" << neighbor.second->iPAddress() << "\n";
+ stream << "MACAddress=" << neighbor.second->mACAddress() << "\n";
+ }
+
// Write the dhcp section irrespective of whether DHCP is enabled or not
writeDHCPSection(stream);
diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp
index c65726a..5551950 100644
--- a/ethernet_interface.hpp
+++ b/ethernet_interface.hpp
@@ -3,6 +3,7 @@
#include "types.hpp"
#include "util.hpp"
#include "xyz/openbmc_project/Network/IP/Create/server.hpp"
+#include "xyz/openbmc_project/Network/Neighbor/CreateStatic/server.hpp"
#include <experimental/filesystem>
#include <sdbusplus/bus.hpp>
@@ -21,6 +22,7 @@
sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface,
sdbusplus::xyz::openbmc_project::Network::server::MACAddress,
sdbusplus::xyz::openbmc_project::Network::IP::server::Create,
+ sdbusplus::xyz::openbmc_project::Network::Neighbor::server::CreateStatic,
sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll>;
using IP = sdbusplus::xyz::openbmc_project::Network::server::IP;
@@ -43,6 +45,8 @@
class IPAddress;
+class Neighbor;
+
using LinkSpeed = uint16_t;
using DuplexMode = uint8_t;
using Autoneg = uint8_t;
@@ -50,6 +54,7 @@
using InterfaceName = std::string;
using InterfaceInfo = std::tuple<LinkSpeed, DuplexMode, Autoneg>;
using AddressMap = std::map<std::string, std::shared_ptr<IPAddress>>;
+using NeighborMap = std::map<std::string, std::shared_ptr<Neighbor>>;
using VlanInterfaceMap =
std::map<InterfaceName, std::unique_ptr<VlanInterface>>;
@@ -90,11 +95,22 @@
ObjectPath iP(IP::Protocol addressType, std::string ipaddress,
uint8_t prefixLength, std::string gateway) override;
+ /** @brief Function to create static neighbor dbus object.
+ * @param[in] ipAddress - IP address.
+ * @param[in] macAddress - Low level MAC address.
+ */
+ ObjectPath neighbor(std::string iPAddress, std::string mACAddress) override;
+
/* @brief delete the dbus object of the given ipaddress.
* @param[in] ipaddress - IP address.
*/
void deleteObject(const std::string& ipaddress);
+ /* @brief delete the dbus object of the given ipaddress.
+ * @param[in] ipaddress - IP address.
+ */
+ void deleteStaticNeighborObject(const std::string& ipAddress);
+
/* @brief delete the vlan dbus object of the given interface.
* Also deletes the device file and the network file.
* @param[in] interface - VLAN Interface.
@@ -107,6 +123,10 @@
*/
void createIPAddressObjects();
+ /* @brief creates the dbus object(Neighbor) given in the neighbor list.
+ */
+ void createStaticNeighborObjects();
+
/* @brief Gets all the ip addresses.
* @returns the list of ipaddress.
*/
@@ -115,6 +135,14 @@
return addrs;
}
+ /* @brief Gets all the static neighbor entries.
+ * @returns Static neighbor map.
+ */
+ const NeighborMap& getStaticNeighbors() const
+ {
+ return staticNeighbors;
+ }
+
/** Set value of DHCPEnabled */
bool dHCPEnabled(bool value) override;
@@ -192,6 +220,10 @@
uint8_t prefixLength,
const std::string& gateway) const;
+ std::string
+ generateStaticNeighborObjectPath(const std::string& iPAddress,
+ const std::string& mACAddress) const;
+
/** @brief generates the id by doing hash of ipaddress,
* prefixlength and the gateway.
* @param[in] ipaddress - IP address.
@@ -204,6 +236,15 @@
uint8_t prefixLength,
const std::string& gateway);
+ /** @brief generates the id by doing hash of ipaddress
+ * and the mac address.
+ * @param[in] iPAddress - IP address.
+ * @param[in] mACAddress - Gateway address.
+ * @return hash string.
+ */
+ static std::string generateNeighborId(const std::string& iPAddress,
+ const std::string& mACAddress);
+
/** @brief write the dhcp section **/
void writeDHCPSection(std::fstream& stream);
@@ -232,6 +273,9 @@
/** @brief Persistent map of IPAddress dbus objects and their names */
AddressMap addrs;
+ /** @brief Persistent map of Neighbor dbus objects and their names */
+ NeighborMap staticNeighbors;
+
/** @brief Persistent map of VLAN interface dbus objects and their names */
VlanInterfaceMap vlanInterfaces;
diff --git a/neighbor.cpp b/neighbor.cpp
new file mode 100644
index 0000000..f7e6f05
--- /dev/null
+++ b/neighbor.cpp
@@ -0,0 +1,240 @@
+#include "config.h"
+
+#include "neighbor.hpp"
+
+#include "ethernet_interface.hpp"
+#include "util.hpp"
+
+#include <linux/neighbour.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <cstring>
+#include <stdexcept>
+#include <string_view>
+#include <system_error>
+
+namespace phosphor
+{
+namespace network
+{
+
+NeighborInfo parseNeighbor(std::string_view msg)
+{
+ struct ndmsg ndm;
+ if (msg.size() < sizeof(ndm))
+ {
+ throw std::runtime_error("Bad neighbor msg");
+ }
+ memcpy(&ndm, msg.data(), sizeof(ndm));
+ auto attrs = msg.substr(sizeof(ndm));
+
+ NeighborInfo info;
+ info.interface.resize(IF_NAMESIZE);
+ if (if_indextoname(ndm.ndm_ifindex, info.interface.data()) == nullptr)
+ {
+ throw std::system_error(errno, std::generic_category(),
+ "if_indextoname");
+ }
+ info.interface.resize(strlen(info.interface.c_str()));
+ info.permanent = ndm.ndm_state & NUD_PERMANENT;
+ bool set_addr = false;
+ while (!attrs.empty())
+ {
+ struct rtattr hdr;
+ if (attrs.size() < sizeof(hdr))
+ {
+ throw std::runtime_error("Bad rtattr header");
+ }
+ memcpy(&hdr, attrs.data(), sizeof(hdr));
+ if (hdr.rta_len < sizeof(hdr))
+ {
+ throw std::runtime_error("Invalid rtattr length");
+ }
+ if (attrs.size() < hdr.rta_len)
+ {
+ throw std::runtime_error("Not enough data for rtattr");
+ }
+ auto data = attrs.substr(RTA_LENGTH(0), hdr.rta_len - RTA_LENGTH(0));
+ if (hdr.rta_type == NDA_LLADDR)
+ {
+ info.mac = mac_address::fromBuf(data);
+ }
+ else if (hdr.rta_type == NDA_DST)
+ {
+ info.address = addrFromBuf(ndm.ndm_family, data);
+ set_addr = true;
+ }
+ attrs.remove_prefix(RTA_ALIGN(hdr.rta_len));
+ }
+ if (!set_addr)
+ {
+ throw std::runtime_error("Missing address");
+ }
+ return info;
+}
+
+bool parseNeighborMsgs(std::string_view msgs, std::vector<NeighborInfo>& info)
+{
+ while (!msgs.empty())
+ {
+ struct nlmsghdr hdr;
+ if (msgs.size() < sizeof(hdr))
+ {
+ throw std::runtime_error("Bad neighbor netlink header");
+ }
+ memcpy(&hdr, msgs.data(), sizeof(hdr));
+ if (hdr.nlmsg_type == NLMSG_DONE)
+ {
+ if (msgs.size() > hdr.nlmsg_len)
+ {
+ throw std::runtime_error("Unexpected extra netlink messages");
+ }
+ return true;
+ }
+ else if (hdr.nlmsg_type != RTM_NEWNEIGH)
+ {
+ throw std::runtime_error("Bad neighbor msg type");
+ }
+ if (hdr.nlmsg_len < sizeof(hdr))
+ {
+ throw std::runtime_error("Invalid nlmsg length");
+ }
+ if (msgs.size() < hdr.nlmsg_len)
+ {
+ throw std::runtime_error("Bad neighbor payload");
+ }
+ auto msg = msgs.substr(NLMSG_HDRLEN, hdr.nlmsg_len - NLMSG_HDRLEN);
+ msgs.remove_prefix(NLMSG_ALIGN(hdr.nlmsg_len));
+ info.push_back(parseNeighbor(msg));
+ }
+
+ return false;
+}
+
+std::vector<NeighborInfo> receiveNeighbors(int sock)
+{
+ // We need to make sure we have enough room for an entire packet otherwise
+ // it gets truncated. The netlink docs guarantee packets will not exceed 8K
+ char buf[8192];
+
+ struct iovec iov;
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+
+ struct sockaddr_nl from;
+ memset(&from, 0, sizeof(from));
+ from.nl_family = AF_NETLINK;
+
+ struct msghdr hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msg_name = &from;
+ hdr.msg_namelen = sizeof(from);
+ hdr.msg_iov = &iov;
+ hdr.msg_iovlen = 1;
+
+ std::vector<NeighborInfo> info;
+ while (true)
+ {
+ ssize_t recvd = recvmsg(sock, &hdr, 0);
+ if (recvd <= 0)
+ {
+ throw std::system_error(errno, std::generic_category(),
+ "recvmsg neighbor");
+ }
+ if (parseNeighborMsgs(std::string_view(buf, recvd), info))
+ {
+ return info;
+ }
+ }
+}
+
+void requestNeighbors(int sock)
+{
+ struct sockaddr_nl dst;
+ memset(&dst, 0, sizeof(dst));
+ dst.nl_family = AF_NETLINK;
+
+ struct
+ {
+ struct nlmsghdr hdr;
+ struct ndmsg msg;
+ } data;
+ memset(&data, 0, sizeof(data));
+ data.hdr.nlmsg_len = sizeof(data);
+ data.hdr.nlmsg_type = RTM_GETNEIGH;
+ data.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ data.msg.ndm_family = AF_UNSPEC;
+
+ struct iovec iov;
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = &data;
+ iov.iov_len = sizeof(data);
+
+ struct msghdr hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msg_name = reinterpret_cast<struct sockaddr*>(&dst);
+ hdr.msg_namelen = sizeof(dst);
+ hdr.msg_iov = &iov;
+ hdr.msg_iovlen = 1;
+
+ if (sendmsg(sock, &hdr, 0) < 0)
+ {
+ throw std::system_error(errno, std::generic_category(),
+ "sendmsg neighbor dump");
+ }
+}
+
+int getNetlink(int protocol)
+{
+ int sock = socket(AF_NETLINK, SOCK_DGRAM, protocol);
+ if (sock < 0)
+ {
+ throw std::system_error(errno, std::generic_category(), "netlink open");
+ }
+
+ struct sockaddr_nl local;
+ memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ int r =
+ bind(sock, reinterpret_cast<struct sockaddr*>(&local), sizeof(local));
+ if (r < 0)
+ {
+ close(sock);
+ throw std::system_error(errno, std::generic_category(), "netlink bind");
+ }
+ return sock;
+}
+
+std::vector<NeighborInfo> getCurrentNeighbors()
+{
+ Descriptor netlink(getNetlink(NETLINK_ROUTE));
+ requestNeighbors(netlink());
+ return receiveNeighbors(netlink());
+}
+
+Neighbor::Neighbor(sdbusplus::bus::bus& bus, const char* objPath,
+ EthernetInterface& parent, const std::string& ipAddress,
+ const std::string& macAddress, State state) :
+ NeighborObj(bus, objPath, true),
+ parent(parent)
+{
+ this->iPAddress(ipAddress);
+ this->mACAddress(macAddress);
+ this->state(state);
+
+ // Emit deferred signal.
+ emit_object_added();
+}
+
+void Neighbor::delete_()
+{
+ parent.deleteStaticNeighborObject(iPAddress());
+}
+
+} // namespace network
+} // namespace phosphor
diff --git a/neighbor.hpp b/neighbor.hpp
new file mode 100644
index 0000000..e103d95
--- /dev/null
+++ b/neighbor.hpp
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "types.hpp"
+#include "util.hpp"
+
+#include <netinet/in.h>
+
+#include <optional>
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/server/object.hpp>
+#include <string>
+#include <vector>
+#include <xyz/openbmc_project/Network/Neighbor/server.hpp>
+#include <xyz/openbmc_project/Object/Delete/server.hpp>
+
+namespace phosphor
+{
+namespace network
+{
+
+using NeighborIntf = sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
+
+using NeighborObj = sdbusplus::server::object::object<
+ NeighborIntf, sdbusplus::xyz::openbmc_project::Object::server::Delete>;
+
+class EthernetInterface;
+
+/** @class NeighborInfo
+ * @brief Information about a neighbor from the kernel
+ */
+struct NeighborInfo
+{
+ std::string interface;
+ InAddrAny address;
+ std::optional<MacAddr> mac;
+ bool permanent;
+};
+
+/** @brief Returns a list of the current system neighbor table
+ */
+std::vector<NeighborInfo> getCurrentNeighbors();
+
+/** @class Neighbor
+ * @brief OpenBMC network neighbor implementation.
+ * @details A concrete implementation for the
+ * xyz.openbmc_project.Network.Neighbor dbus interface.
+ */
+class Neighbor : public NeighborObj
+{
+ public:
+ using State = NeighborIntf::State;
+
+ Neighbor() = delete;
+ Neighbor(const Neighbor&) = delete;
+ Neighbor& operator=(const Neighbor&) = delete;
+ Neighbor(Neighbor&&) = delete;
+ Neighbor& operator=(Neighbor&&) = delete;
+ virtual ~Neighbor() = default;
+
+ /** @brief Constructor to put object onto bus at a dbus path.
+ * @param[in] bus - Bus to attach to.
+ * @param[in] objPath - Path to attach at.
+ * @param[in] parent - Parent object.
+ * @param[in] ipAddress - IP address.
+ * @param[in] macAddress - Low level MAC address.
+ * @param[in] state - The state of the neighbor entry.
+ */
+ Neighbor(sdbusplus::bus::bus& bus, const char* objPath,
+ EthernetInterface& parent, const std::string& ipAddress,
+ const std::string& macAddress, State state);
+
+ /** @brief Delete this d-bus object.
+ */
+ void delete_() override;
+
+ private:
+ /** @brief Parent Object. */
+ EthernetInterface& parent;
+};
+
+} // namespace network
+} // namespace phosphor
diff --git a/network_manager.cpp b/network_manager.cpp
index fa5da0f..043d7a2 100644
--- a/network_manager.cpp
+++ b/network_manager.cpp
@@ -150,6 +150,7 @@
bus, objPath.string(), dhcp, *this);
intf->createIPAddressObjects();
+ intf->createStaticNeighborObjects();
this->interfaces.emplace(
std::make_pair(std::move(interface), std::move(intf)));
diff --git a/rtnetlink_server.cpp b/rtnetlink_server.cpp
index 732055a..1c4fd53 100644
--- a/rtnetlink_server.cpp
+++ b/rtnetlink_server.cpp
@@ -14,6 +14,7 @@
#include <memory>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
+#include <string_view>
#include <xyz/openbmc_project/Common/error.hpp>
namespace phosphor
@@ -26,7 +27,7 @@
namespace rtnetlink
{
-static bool shouldRefresh(const struct nlmsghdr& hdr)
+static bool shouldRefresh(const struct nlmsghdr& hdr, std::string_view data)
{
switch (hdr.nlmsg_type)
{
@@ -37,6 +38,18 @@
{
return true;
}
+ case RTM_NEWNEIGH:
+ case RTM_DELNEIGH:
+ {
+ struct ndmsg ndm;
+ if (data.size() < sizeof(ndm))
+ {
+ return false;
+ }
+ memcpy(&ndm, data.data(), sizeof(ndm));
+ // We only want to refresh for static neighbors
+ return ndm.ndm_state & NUD_PERMANENT;
+ }
}
return false;
@@ -57,7 +70,10 @@
(netLinkHeader->nlmsg_type != NLMSG_DONE);
netLinkHeader = NLMSG_NEXT(netLinkHeader, len))
{
- if (shouldRefresh(*netLinkHeader))
+ std::string_view data(
+ reinterpret_cast<const char*>(NLMSG_DATA(netLinkHeader)),
+ netLinkHeader->nlmsg_len - NLMSG_HDRLEN);
+ if (shouldRefresh(*netLinkHeader, data))
{
// starting the timer here to make sure that we don't want
// create the child objects multiple times.
@@ -125,7 +141,7 @@
std::memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
- RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
+ RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH;
if (bind(smartSock(), (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
diff --git a/test/Makefile.am b/test/Makefile.am
index 78636fc..ffa4655 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -49,6 +49,7 @@
$(top_builddir)/network_manager.o \
$(top_builddir)/network_config.o \
$(top_builddir)/ipaddress.o \
+ $(top_builddir)/neighbor.o \
$(top_builddir)/routing_table.o \
$(top_builddir)/util.o \
$(top_builddir)/rtnetlink_server.o \
@@ -57,7 +58,8 @@
$(top_builddir)/config_parser.o \
$(top_builddir)/vlan_interface.o \
$(top_builddir)/xyz/openbmc_project/Network/VLAN/Create/phosphor_network_manager-server.o \
- $(top_builddir)/xyz/openbmc_project/Network/IP/Create/phosphor_network_manager-server.o
+ $(top_builddir)/xyz/openbmc_project/Network/IP/Create/phosphor_network_manager-server.o \
+ $(top_builddir)/xyz/openbmc_project/Network/Neighbor/CreateStatic/phosphor_network_manager-server.o
test_dns_updater_LDADD = $(top_builddir)/dns_updater.o
test_watch_LDADD = $(top_builddir)/watch.o
diff --git a/xyz/openbmc_project/Network/Neighbor/CreateStatic.interface.yaml b/xyz/openbmc_project/Network/Neighbor/CreateStatic.interface.yaml
new file mode 100644
index 0000000..a4ceabb
--- /dev/null
+++ b/xyz/openbmc_project/Network/Neighbor/CreateStatic.interface.yaml
@@ -0,0 +1,21 @@
+description: >
+methods:
+ - name: Neighbor
+ description: >
+ Create a static neighbor entry.
+ parameters:
+ - name: IPAddress
+ type: string
+ description: >
+ IP Address.
+ - name: MACAddress
+ type: string
+ description: >
+ MAC Address.
+ returns:
+ - name: Path
+ type: path
+ description: >
+ The path for the created neighbor object.
+ errors:
+ - xyz.openbmc_project.Common.Error.InvalidArgument