Backend changes for Populating Nameservers(DNS & Static)
- As per the proposed design :
https://lists.ozlabs.org/pipermail/openbmc/2019-September/018399.html
Depends on :
https://gerrit.openbmc-project.xyz/#/c/openbmc/phosphor-dbus-interfaces/+/26060/
The idea of this commit is to
- Support NameServers(Read Only) property to display current
Nameservers (both DHCP provided& Static) configured on the
interface.
- Support StaticNameServers(Writable) property by which user
can set the Nameservers on an interface.
Tested By:
1.Configure a DNS via DHCP Server & Make sure NameServer property
populates accordingly.
2.With DNS from DHCP existing, set a name server using PATCH on
StaticNameServer property & make sure both properties populate
the data as per the proposal.
3.Make sure /etc/resolv.conf is populated with the right content
in case of DHCP/Static and DHCP & Static (Co-existing)
4.Make sure network configuration file is updated properly when
user sets a staic name server.
Signed-off-by: Manojkiran Eda <manojkiran.eda@gmail.com>
Change-Id: If10b9aa683d2b50e51780e91323c6d10a5ec3710
diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
index ed1e1ba..600ab83 100644
--- a/ethernet_interface.cpp
+++ b/ethernet_interface.cpp
@@ -35,7 +35,14 @@
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
+using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
using Argument = xyz::openbmc_project::Common::InvalidArgument;
+constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1";
+constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link";
+constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
+constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/";
+constexpr auto METHOD_GET = "Get";
struct EthernetIntfSocket
{
@@ -78,7 +85,6 @@
MacAddressIntf::mACAddress(getMACAddress(intfName));
}
EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
- EthernetInterfaceIntf::nameservers(getNameServerFromConf());
#if NIC_SUPPORTS_ETHTOOL
InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
@@ -494,6 +500,12 @@
ServerList EthernetInterface::nameservers(ServerList value)
{
+ elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
+ return EthernetInterfaceIntf::nameservers();
+}
+
+ServerList EthernetInterface::staticNameServers(ServerList value)
+{
for (const auto& nameserverip : value)
{
if (!isValidIP(AF_INET, nameserverip) &&
@@ -502,13 +514,13 @@
log<level::ERR>("Not a valid IP address"),
entry("ADDRESS=%s", nameserverip.c_str());
elog<InvalidArgument>(
- Argument::ARGUMENT_NAME("Nameserver"),
+ Argument::ARGUMENT_NAME("StaticNameserver"),
Argument::ARGUMENT_VALUE(nameserverip.c_str()));
}
}
try
{
- EthernetInterfaceIntf::nameservers(value);
+ EthernetInterfaceIntf::staticNameServers(value);
writeConfigurationFile();
// resolved reads the DNS server configuration from the
// network file.
@@ -518,10 +530,16 @@
{
log<level::ERR>("Exception processing DNS entries");
}
- return EthernetInterfaceIntf::nameservers();
+ return EthernetInterfaceIntf::staticNameServers();
}
-ServerList EthernetInterface::getNameServerFromConf()
+void EthernetInterface::loadNameServers()
+{
+ EthernetInterfaceIntf::nameservers(getNameServerFromResolvd());
+ EthernetInterfaceIntf::staticNameServers(getstaticNameServerFromConf());
+}
+
+ServerList EthernetInterface::getstaticNameServerFromConf()
{
fs::path confPath = manager.getConfDir();
@@ -541,6 +559,58 @@
return servers;
}
+ServerList EthernetInterface::getNameServerFromResolvd()
+{
+ ServerList servers;
+ std::string OBJ_PATH = RESOLVED_SERVICE_PATH + std::to_string(ifIndex());
+
+ /*
+ The DNS property under org.freedesktop.resolve1.Link interface contains
+ an array containing all DNS servers currently used by resolved. It
+ contains similar information as the DNS server data written to
+ /run/systemd/resolve/resolv.conf.
+
+ Each structure in the array consists of a numeric network interface index,
+ an address family, and a byte array containing the DNS server address
+ (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6).
+ The array contains DNS servers configured system-wide, including those
+ possibly read from a foreign /etc/resolv.conf or the DNS= setting in
+ /etc/systemd/resolved.conf, as well as per-interface DNS server
+ information either retrieved from systemd-networkd or configured by
+ external software via SetLinkDNS().
+ */
+
+ using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>;
+ std::variant<type> name; // Variable to capture the DNS property
+ auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(),
+ PROPERTY_INTERFACE, METHOD_GET);
+
+ method.append(RESOLVED_INTERFACE, "DNS");
+ auto reply = bus.call(method);
+
+ try
+ {
+ reply.read(name);
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ log<level::ERR>("Failed to get DNS information from Systemd-Resolved");
+ }
+ auto tupleVector = std::get_if<type>(&name);
+ for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i)
+ {
+ std::vector<uint8_t> ipaddress = std::get<1>(*i);
+ std::string address;
+ for (auto byte : ipaddress)
+ {
+ address += std::to_string(byte) + ".";
+ }
+ address.pop_back();
+ servers.push_back(address);
+ }
+ return servers;
+}
+
void EthernetInterface::loadVLAN(VlanId id)
{
std::string vlanInterfaceName = interfaceName() + "." + std::to_string(id);
@@ -706,7 +776,7 @@
}
// Add the DNS entry
- for (const auto& dns : EthernetInterfaceIntf::nameservers())
+ for (const auto& dns : EthernetInterfaceIntf::staticNameServers())
{
stream << "DNS=" << dns << "\n";
}