Add network static gateway configuration support

This commit enables static gateway configuration on EthernetInterface
Implements CreateStaticGateway method which creates a new d-bus object
with StaticGateway interface.

Tested By:
Run StaticGateway D-bus method and verified D-bus object and
configuration.
Delete StaticGateway object
Add static gateway
Delete static gateway

Change-Id: I3fbc6f85ede00b6c1949a0ac85f501037a69c831
Signed-off-by: Ravi Teja <raviteja28031990@gmail.com>
diff --git a/src/ethernet_interface.cpp b/src/ethernet_interface.cpp
index 10229ac..8e76931 100644
--- a/src/ethernet_interface.cpp
+++ b/src/ethernet_interface.cpp
@@ -7,6 +7,8 @@
 #include "system_queries.hpp"
 #include "util.hpp"
 
+#include <arpa/inet.h>
+#include <fcntl.h>
 #include <linux/rtnetlink.h>
 #include <net/if.h>
 #include <net/if_arp.h>
@@ -134,6 +136,10 @@
     {
         addStaticNeigh(neigh);
     }
+    for (const auto& [_, staticGateway] : info.staticGateways)
+    {
+        addStaticGateway(staticGateway);
+    }
 }
 
 void EthernetInterface::updateInfo(const InterfaceInfo& info, bool skipSignal)
@@ -224,6 +230,39 @@
     }
 }
 
+void EthernetInterface::addStaticGateway(const StaticGatewayInfo& info)
+{
+    if (!info.gateway)
+    {
+        lg2::error("Missing static gateway on {NET_INTF}", "NET_INTF",
+                   interfaceName());
+        return;
+    }
+
+    IP::Protocol protocolType;
+    if (*info.protocol == "IPv4")
+    {
+        protocolType = IP::Protocol::IPv4;
+    }
+    else if (*info.protocol == "IPv6")
+    {
+        protocolType = IP::Protocol::IPv6;
+    }
+
+    if (auto it = staticGateways.find(*info.gateway);
+        it != staticGateways.end())
+    {
+        it->second->StaticGatewayObj::gateway(*info.gateway);
+    }
+    else
+    {
+        staticGateways.emplace(*info.gateway,
+                               std::make_unique<StaticGateway>(
+                                   bus, std::string_view(objPath), *this,
+                                   *info.gateway, protocolType));
+    }
+}
+
 ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress,
                                  uint8_t prefixLength, std::string)
 {
@@ -347,6 +386,43 @@
     return it->second->getObjPath();
 }
 
+ObjectPath EthernetInterface::staticGateway(std::string gateway,
+                                            IP::Protocol protocolType)
+{
+    std::optional<stdplus::InAnyAddr> addr;
+    std::string route;
+    try
+    {
+        addr.emplace(stdplus::fromStr<stdplus::InAnyAddr>(gateway));
+        route = gateway;
+    }
+    catch (const std::exception& e)
+    {
+        lg2::error("Not a valid IP address {GATEWAY}: {ERROR}", "GATEWAY",
+                   gateway, "ERROR", e);
+        elog<InvalidArgument>(Argument::ARGUMENT_NAME("gateway"),
+                              Argument::ARGUMENT_VALUE(gateway.c_str()));
+    }
+
+    auto it = staticGateways.find(route);
+    if (it == staticGateways.end())
+    {
+        it = std::get<0>(staticGateways.emplace(
+            route,
+            std::make_unique<StaticGateway>(bus, std::string_view(objPath),
+                                            *this, gateway, protocolType)));
+    }
+    else
+    {
+        it->second->StaticGatewayObj::gateway(gateway);
+    }
+
+    writeConfigurationFile();
+    manager.get().reloadConfigs();
+
+    return it->second->getObjPath();
+}
+
 bool EthernetInterface::ipv6AcceptRA(bool value)
 {
     if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value))
@@ -788,6 +864,17 @@
         dhcp6["SendHostname"].emplace_back(
             tfStr(dhcp6Conf->sendHostNameEnabled()));
     }
+
+    {
+        auto& sroutes = config.map["Route"];
+        for (const auto& temp : staticGateways)
+        {
+            auto& staticGateway = sroutes.emplace_back();
+            staticGateway["Gateway"].emplace_back(temp.second->gateway());
+            staticGateway["GatewayOnLink"].emplace_back("true");
+        }
+    }
+
     auto path =
         config::pathForIntfConf(manager.get().getConfDir(), interfaceName());
     config.writeFile(path);