Added enable/disable control of the Network Interface Card

Implemented enable/disable function to perform
"ip link set eth(x) up"
"ip link set eth(x) down"
functionality from DBus.

Tested:

Confirmed Redfish PATCH commands on the InterfaceEnabled property
changes the NIC state. Confirmed the NIC is DOWN/UP using "ip link".
Confirmed "ip link" state changes can be obsserved from dbus-send
commands, and from Redfish GET actions.

Confirmed the link is inactive after a reboot.

Confirmed link stays down despite assigning an IP manually.

Confirmed link stays down despite enabling DHCP.

Change-Id: I4152b53055e6546f7a6ca81b5a5eef6f689bcc66
Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
index 600ab83..4827f68 100644
--- a/ethernet_interface.cpp
+++ b/ethernet_interface.cpp
@@ -91,6 +91,7 @@
     EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
     EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
     EthernetInterfaceIntf::linkUp(std::get<3>(ifInfo));
+    EthernetInterfaceIntf::nICEnabled(std::get<4>(ifInfo));
 #endif
 
     // Emit deferred signal.
@@ -269,11 +270,12 @@
     Autoneg autoneg{0};
     DuplexMode duplex{0};
     LinkUp linkState{false};
+    NICEnabled nicEnabled{false};
     EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
 
     if (eifSocket.sock < 0)
     {
-        return std::make_tuple(speed, duplex, autoneg, linkState);
+        return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
     }
 
     std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
@@ -287,9 +289,10 @@
         autoneg = edata.autoneg;
     }
 
+    nicEnabled = nICEnabled();
     linkState = linkUp();
 
-    return std::make_tuple(speed, duplex, autoneg, linkState);
+    return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
 }
 #endif
 
@@ -494,6 +497,66 @@
         log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
                         entry("ERROR=%s", strerror(errno)));
     }
+    return value;
+}
+
+bool EthernetInterface::nICEnabled() const
+{
+    EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+    bool value = EthernetInterfaceIntf::nICEnabled();
+
+    if (eifSocket.sock < 0)
+    {
+        return value;
+    }
+
+    ifreq ifr{0};
+    std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
+    if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
+    {
+        value = static_cast<bool>(ifr.ifr_flags & IFF_UP);
+    }
+    else
+    {
+        log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
+                        entry("ERROR=%s", strerror(errno)));
+    }
+    return value;
+}
+
+bool EthernetInterface::nICEnabled(bool value)
+{
+    if (value == EthernetInterfaceIntf::nICEnabled())
+    {
+        return value;
+    }
+
+    EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+    if (eifSocket.sock < 0)
+    {
+        return EthernetInterfaceIntf::nICEnabled();
+    }
+
+    ifreq ifr{0};
+    std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
+    if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) != 0)
+    {
+        log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
+                        entry("ERROR=%s", strerror(errno)));
+        return EthernetInterfaceIntf::nICEnabled();
+    }
+
+    ifr.ifr_flags &= ~IFF_UP;
+    ifr.ifr_flags |= value ? IFF_UP : 0;
+
+    if (ioctl(eifSocket.sock, SIOCSIFFLAGS, &ifr) != 0)
+    {
+        log<level::ERR>("ioctl failed for SIOCSIFFLAGS:",
+                        entry("ERROR=%s", strerror(errno)));
+        return EthernetInterfaceIntf::nICEnabled();
+    }
+    EthernetInterfaceIntf::nICEnabled(value);
+    writeConfigurationFile();
 
     return value;
 }
@@ -753,6 +816,11 @@
         stream << "MACAddress=" << mac << "\n";
     }
 
+    if (!nICEnabled())
+    {
+        stream << "Unmanaged=yes\n";
+    }
+
     // write the network section
     stream << "[Network]\n";
 #ifdef LINK_LOCAL_AUTOCONFIGURATION
diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp
index 4a0f030..f8086a4 100644
--- a/ethernet_interface.hpp
+++ b/ethernet_interface.hpp
@@ -51,9 +51,11 @@
 using DuplexMode = uint8_t;
 using Autoneg = uint8_t;
 using LinkUp = bool;
+using NICEnabled = bool;
 using VlanId = uint32_t;
 using InterfaceName = std::string;
-using InterfaceInfo = std::tuple<LinkSpeed, DuplexMode, Autoneg, LinkUp>;
+using InterfaceInfo =
+    std::tuple<LinkSpeed, DuplexMode, Autoneg, LinkUp, NICEnabled>;
 using AddressMap = std::map<std::string, std::shared_ptr<IPAddress>>;
 using NeighborMap = std::map<std::string, std::shared_ptr<Neighbor>>;
 using VlanInterfaceMap =
@@ -158,6 +160,12 @@
     /** Retrieve Link State */
     bool linkUp() const override;
 
+    /** Retrieve NIC State */
+    bool nICEnabled() const override;
+
+    /** Set value of NICEnabled */
+    bool nICEnabled(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 or throws an error.
@@ -212,6 +220,7 @@
     using EthernetInterfaceIntf::dHCPEnabled;
     using EthernetInterfaceIntf::interfaceName;
     using EthernetInterfaceIntf::linkUp;
+    using EthernetInterfaceIntf::nICEnabled;
     using MacAddressIntf::mACAddress;
 
     /** @brief Absolute path of the resolv conf file */