summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRatan Gupta <ratagupt@in.ibm.com>2017-08-18 17:10:07 +0530
committerRatan Gupta <ratagupt@in.ibm.com>2017-09-09 00:44:57 +0530
commitbd303b1097695f6e6ddadef96d64476830fbdc19 (patch)
tree930362073665d9a0d1c881f07eb5d4e7c4ba580b
parent4f67dac2061f5fafbae83aba9d44029b994275a7 (diff)
downloadphosphor-networkd-bd303b1097695f6e6ddadef96d64476830fbdc19.tar.gz
phosphor-networkd-bd303b1097695f6e6ddadef96d64476830fbdc19.zip
Implement Set function for MAC address
Change-Id: I16992dda259246a66512792f06cbbb874e56a15d Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
-rw-r--r--ethernet_interface.cpp78
-rw-r--r--ethernet_interface.hpp9
-rw-r--r--util.cpp143
-rw-r--r--util.hpp74
-rw-r--r--vlan_interface.cpp2
-rw-r--r--vlan_interface.hpp6
6 files changed, 302 insertions, 10 deletions
diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
index c24a3e8..39c12cf 100644
--- a/ethernet_interface.cpp
+++ b/ethernet_interface.cpp
@@ -33,10 +33,6 @@ namespace network
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
-constexpr auto MAC_ADDRESS_FORMAT = "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx";
-constexpr size_t SIZE_MAC = 18;
-constexpr size_t SIZE_BUFF = 512;
-
EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
const std::string& objPath,
bool dhcpEnabled,
@@ -51,7 +47,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
std::replace(intfName.begin(), intfName.end(), '_', '.');
interfaceName(intfName);
EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
- mACAddress(getMACAddress(intfName));
+ MacAddressIntf::mACAddress(getMACAddress(intfName));
// Emit deferred signal.
if (emitSignal)
@@ -116,7 +112,7 @@ void EthernetInterface::iP(IP::Protocol protType,
if (dHCPEnabled())
{
log<level::INFO>("DHCP enabled on the interface"),
- entry("INTERFACE=%s",interfaceName());
+ entry("INTERFACE=%s",interfaceName().c_str());
return;
}
@@ -200,7 +196,7 @@ std::string EthernetInterface::getMACAddress(
const std::string& interfaceName) const
{
struct ifreq ifr{};
- char macAddress[SIZE_MAC] {};
+ char macAddress[mac_address::size] {};
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock < 0)
@@ -218,7 +214,7 @@ std::string EthernetInterface::getMACAddress(
return macAddress;
}
- snprintf(macAddress, SIZE_MAC, MAC_ADDRESS_FORMAT,
+ snprintf(macAddress, mac_address::size, mac_address::format,
ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1],
ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
@@ -510,5 +506,71 @@ void EthernetInterface::writeDHCPSection(std::fstream& stream)
}
}
+std::string EthernetInterface::mACAddress(std::string value)
+{
+ if (!mac_address::validate(value))
+ {
+ log<level::DEBUG>("MACAddress is not valid.",
+ entry("MAC=%s", value.c_str()));
+ return MacAddressIntf::mACAddress();
+ }
+
+ // check whether MAC is broadcast mac.
+ auto intMac = mac_address::internal::convertToInt(value);
+
+ if (!(intMac ^ mac_address::broadcastMac))
+ {
+ log<level::DEBUG>("MACAddress is a broadcast mac.",
+ entry("MAC=%s", value.c_str()));
+ return MacAddressIntf::mACAddress();
+ }
+
+ // Allow the mac to be set if one of the condition is true.
+ // 1) Incoming Mac is of local admin type.
+ // or
+ // 2) Incoming mac is same as eeprom Mac.
+
+ if (!(intMac & mac_address::localAdminMask))
+ {
+ try
+ {
+ auto inventoryMac = mac_address::getfromInventory(bus);
+ auto intInventoryMac = mac_address::internal::convertToInt(inventoryMac);
+
+ if (intInventoryMac != intMac)
+ {
+ log<level::DEBUG>("Given MAC address is neither a local Admin \
+ type nor is same as in inventory");
+ return MacAddressIntf::mACAddress();
+ }
+ }
+ catch(InternalFailure& e)
+ {
+ log<level::ERR>("Exception occured during getting of MAC \
+ address from Inventory");
+ return MacAddressIntf::mACAddress();
+ }
+ }
+ auto interface = interfaceName();
+ execute("/sbin/fw_setenv", "fw_setenv", "ethaddr", value.c_str());
+ //TODO: would replace below three calls
+ // with restarting of systemd-netwokd
+ // through https://github.com/systemd/systemd/issues/6696
+ execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "down");
+ execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "address",
+ value.c_str());
+
+ execute("/sbin/ip", "ip", "link", "set", "dev", interface.c_str(), "up");
+
+ auto mac = MacAddressIntf::mACAddress(std::move(value));
+ //update all the vlan interfaces
+ for(const auto& intf: vlanInterfaces)
+ {
+ intf.second->updateMacAddress();
+ }
+ return mac;
+
+}
+
}//namespace network
}//namespace phosphor
diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp
index 5283da4..3a746d2 100644
--- a/ethernet_interface.hpp
+++ b/ethernet_interface.hpp
@@ -27,6 +27,8 @@ using IP = sdbusplus::xyz::openbmc_project::Network::server::IP;
using EthernetInterfaceIntf =
sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
+using MacAddressIntf =
+ sdbusplus::xyz::openbmc_project::Network::server::MACAddress;
namespace fs = std::experimental::filesystem;
@@ -113,6 +115,12 @@ class EthernetInterface : public Ifaces
/** Set value of DHCPEnabled */
bool dHCPEnabled(bool value) override;
+ /** @brief sets the MAC address.
+ * @param[in] value - MAC address which needs to be set on the system.
+ * @returns macAddress of the interface.
+ */
+ std::string mACAddress(std::string value) override;
+
/** @brief create Vlan interface.
* @param[in] id- VLAN identifier.
*/
@@ -130,6 +138,7 @@ class EthernetInterface : public Ifaces
using EthernetInterfaceIntf::dHCPEnabled;
using EthernetInterfaceIntf::interfaceName;
+ using MacAddressIntf::mACAddress;
protected:
diff --git a/util.cpp b/util.cpp
index e5394ba..679b2cb 100644
--- a/util.cpp
+++ b/util.cpp
@@ -364,11 +364,152 @@ bool getDHCPValue(const std::string& confDir, const std::string& intf)
}
catch (InternalFailure& e)
{
- log<level::INFO>("Exception occured during getting of DHCP value");
+ log<level::INFO>("Exception occured during getting of DHCP value");
}
return dhcp;
}
+namespace internal
+{
+
+void executeCommandinChildProcess(const char* path, char** args)
+{
+ using namespace std::string_literals;
+ pid_t pid = fork();
+ int status {};
+
+ if (pid == 0)
+ {
+ execv(path, args);
+ auto error = errno;
+ // create the command from var args.
+ std::string command = path + " "s;
+
+ for(int i = 0; args[i]; i++)
+ {
+ command += args[i] + " "s;
+ }
+
+ log<level::ERR>("Couldn't exceute the command",
+ entry("ERRNO=%d", error),
+ entry("CMD=%s", command.c_str()));
+ elog<InternalFailure>();
+ }
+ else if (pid < 0)
+ {
+ auto error = errno;
+ log<level::ERR>("Error occurred during fork",
+ entry("ERRNO=%d", error));
+ elog<InternalFailure>();
+ }
+ else if (pid > 0)
+ {
+ while (waitpid(pid, &status, 0) == -1)
+ {
+ if (errno != EINTR)
+ { //Error other than EINTR
+ status = -1;
+ break;
+ }
+ }
+
+ if(status < 0)
+ {
+ std::string command = path + " "s;
+ for(int i = 0; args[i]; i++)
+ {
+ command += args[i] + " "s;
+ }
+
+ log<level::ERR>("Unable to execute the command",
+ entry("CMD=%s", command.c_str(),
+ entry("STATUS=%d", status)));
+ elog<InternalFailure>();
+ }
+ }
+
+}
+} //namespace internal
+
+namespace mac_address
+{
+
+constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
+constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
+constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
+constexpr auto propIntf = "org.freedesktop.DBus.Properties";
+constexpr auto methodGet = "Get";
+
+using DbusObjectPath = std::string;
+using DbusService = std::string;
+using DbusInterface = std::string;
+using ObjectTree = std::map<DbusObjectPath,
+ std::map<DbusService, std::vector<DbusInterface>>>;
+
+constexpr auto invBus = "xyz.openbmc_project.Inventory.Manager";
+constexpr auto invNetworkIntf =
+ "xyz.openbmc_project.Inventory.Item.NetworkInterface";
+constexpr auto invRoot = "/xyz/openbmc_project/inventory";
+
+std::string getfromInventory(sdbusplus::bus::bus& bus)
+{
+ std::vector<DbusInterface> interfaces;
+ interfaces.emplace_back(invNetworkIntf);
+
+ auto depth = 0;
+
+ auto mapperCall = bus.new_method_call(mapperBus,
+ mapperObj,
+ mapperIntf,
+ "GetSubTree");
+
+ mapperCall.append(invRoot, depth, interfaces);
+
+ auto mapperReply = bus.call(mapperCall);
+ if (mapperReply.is_method_error())
+ {
+ log<level::ERR>("Error in mapper call");
+ elog<InternalFailure>();
+ }
+
+ ObjectTree objectTree;
+ mapperReply.read(objectTree);
+
+ if (objectTree.empty())
+ {
+ log<level::ERR>("No Object has implemented the interface",
+ entry("INTERFACE=%s", invNetworkIntf));
+ elog<InternalFailure>();
+ }
+
+ // It is expected that only one object have impelmented this interface.
+
+ auto objPath = objectTree.begin()->first;
+ auto service = objectTree.begin()->second.begin()->first;
+
+ sdbusplus::message::variant<std::string> value;
+
+ auto method = bus.new_method_call(
+ service.c_str(),
+ objPath.c_str(),
+ propIntf,
+ methodGet);
+
+ method.append(invNetworkIntf, "MACAddress");
+
+ auto reply = bus.call(method);
+ if (reply.is_method_error())
+ {
+ log<level::ERR>("Failed to get MACAddress",
+ entry("PATH=%s", objPath.c_str()),
+ entry("INTERFACE=%s", invNetworkIntf));
+ elog<InternalFailure>();
+ }
+
+ reply.read(value);
+ return value.get<std::string>();
+}
+}//namespace mac_address
}//namespace network
}//namespace phosphor
diff --git a/util.hpp b/util.hpp
index 2015b0c..2d5c3f3 100644
--- a/util.hpp
+++ b/util.hpp
@@ -5,11 +5,60 @@
#include "config.h"
#include "types.hpp"
#include <sdbusplus/bus.hpp>
+#include <regex>
namespace phosphor
{
namespace network
{
+namespace mac_address
+{
+
+constexpr auto regex = "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$";
+constexpr auto localAdminMask = 0x020000000000;
+constexpr auto broadcastMac = 0xFFFFFFFFFFFF;
+
+constexpr auto format = "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx";
+constexpr size_t size = 18;
+
+/** @brief validate the mac address
+ * @param[in] value - MAC address.
+ * @returns true if validate otherwise false.
+ */
+inline bool validate(const std::string& value)
+{
+ std::regex regexToCheck(regex);
+ return std::regex_search(value, regexToCheck);
+}
+
+/** @brief gets the MAC address from the Inventory.
+ * @param[in] bus - DBUS Bus Object.
+ */
+std::string getfromInventory(sdbusplus::bus::bus& bus);
+
+namespace internal
+{
+/** @brief Converts the given mac address into unsigned 64 bit integer
+ * @param[in] value - MAC address.
+ * @returns converted unsigned 64 bit number.
+ */
+inline uint64_t convertToInt(const std::string& value)
+{
+ unsigned char mac[6];
+
+ sscanf(value.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ mac + 0, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5);
+ return
+ static_cast<uint64_t>(mac[0]) << 40 |
+ static_cast<uint64_t>(mac[1]) << 32 |
+ static_cast<uint64_t>(mac[2]) << 24 |
+ static_cast<uint64_t>(mac[3]) << 16 |
+ static_cast<uint64_t>(mac[4]) << 8 |
+ static_cast<uint64_t>(mac[5]);
+}
+
+}//namespace internal
+}//namespace mac_address
/* @brief converts the given subnet into prefix notation.
* @param[in] addressFamily - IP address family(AF_INET/AF_INET6).
@@ -74,6 +123,31 @@ void deleteInterface(const std::string& intf);
*/
bool getDHCPValue(const std::string& confDir, const std::string& intf);
+namespace internal
+{
+
+/* @brief runs the given command in child process.
+ * @param[in] path - path of the binary file which needs to be execeuted.
+ * @param[in] args - arguments of the command.
+ */
+void executeCommandinChildProcess(const char* path, char** args);
+
+} // namespace internal
+
+/* @brief runs the given command in child process.
+ * @param[in] path -path of the binary file which needs to be execeuted.
+ * @param[in] tArgs - arguments of the command.
+ */
+template<typename... ArgTypes>
+void execute(const char* path, ArgTypes&&... tArgs)
+{
+ using expandType = char*[];
+
+ expandType args = { const_cast<char*>(tArgs)..., nullptr };
+
+ internal::executeCommandinChildProcess(path, args);
+}
+
} //namespace network
class Descriptor
diff --git a/vlan_interface.cpp b/vlan_interface.cpp
index 8684a73..8f7c5ce 100644
--- a/vlan_interface.cpp
+++ b/vlan_interface.cpp
@@ -33,7 +33,7 @@ VlanInterface::VlanInterface(sdbusplus::bus::bus& bus,
{
id(vlanID);
VlanIface::interfaceName(EthernetInterface::interfaceName());
- mACAddress(parentInterface.mACAddress());
+ MacAddressIntf::mACAddress(parentInterface.mACAddress());
emit_object_added();
}
diff --git a/vlan_interface.hpp b/vlan_interface.hpp
index d9ea078..3f273b7 100644
--- a/vlan_interface.hpp
+++ b/vlan_interface.hpp
@@ -63,6 +63,12 @@ class VlanInterface : public VlanIface,
and creates the vlan interface.*/
void writeDeviceFile();
+ /** @brief copy the mac address from the parent interface.*/
+ void updateMacAddress()
+ {
+ MacAddressIntf::mACAddress(parentInterface.mACAddress());
+ }
+
private:
/** @brief VLAN Identifier. */
OpenPOWER on IntegriCloud