xref: /openbmc/phosphor-networkd/src/network_manager.cpp (revision 85dc57a57c5e8c9394bad5c787d6f837eae76178)
1 #include "config.h"
2 
3 #include "network_manager.hpp"
4 
5 #include "config_parser.hpp"
6 #include "ipaddress.hpp"
7 #include "system_queries.hpp"
8 #include "types.hpp"
9 
10 #include <filesystem>
11 #include <fstream>
12 #include <phosphor-logging/elog-errors.hpp>
13 #include <phosphor-logging/log.hpp>
14 #include <xyz/openbmc_project/Common/error.hpp>
15 
16 constexpr char SYSTEMD_BUSNAME[] = "org.freedesktop.systemd1";
17 constexpr char SYSTEMD_PATH[] = "/org/freedesktop/systemd1";
18 constexpr char SYSTEMD_INTERFACE[] = "org.freedesktop.systemd1.Manager";
19 constexpr auto FirstBootFile = "/var/lib/network/firstBoot_";
20 
21 constexpr char NETWORKD_BUSNAME[] = "org.freedesktop.network1";
22 constexpr char NETWORKD_PATH[] = "/org/freedesktop/network1";
23 constexpr char NETWORKD_INTERFACE[] = "org.freedesktop.network1.Manager";
24 
25 namespace phosphor
26 {
27 namespace network
28 {
29 
30 extern std::unique_ptr<Timer> refreshObjectTimer;
31 extern std::unique_ptr<Timer> reloadTimer;
32 using namespace phosphor::logging;
33 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
34 using Argument = xyz::openbmc_project::Common::InvalidArgument;
35 
36 Manager::Manager(sdbusplus::bus_t& bus, const char* objPath,
37                  const fs::path& confDir) :
38     details::VLANCreateIface(bus, objPath,
39                              details::VLANCreateIface::action::defer_emit),
40     bus(bus), objectPath(objPath)
41 {
42     setConfDir(confDir);
43 }
44 
45 void Manager::setConfDir(const fs::path& dir)
46 {
47     confDir = dir;
48 
49     if (!fs::exists(confDir))
50     {
51         if (!fs::create_directories(confDir))
52         {
53             log<level::ERR>("Unable to create the network conf dir",
54                             entry("DIR=%s", confDir.c_str()));
55             elog<InternalFailure>();
56         }
57     }
58 }
59 
60 void Manager::createInterfaces()
61 {
62     // clear all the interfaces first
63     interfaces.clear();
64     interfacesByIdx.clear();
65     for (auto& interface : system::getInterfaces())
66     {
67         config::Parser config(
68             config::pathForIntfConf(confDir, *interface.name));
69         auto intf = std::make_unique<EthernetInterface>(bus, *this, interface,
70                                                         objectPath, config);
71         intf->createIPAddressObjects();
72         intf->createStaticNeighborObjects();
73         intf->loadNameServers(config);
74         intf->loadNTPServers(config);
75         auto ptr = intf.get();
76         interfaces.emplace(std::move(*interface.name), std::move(intf));
77         interfacesByIdx.emplace(interface.idx, ptr);
78     }
79 }
80 
81 void Manager::createChildObjects()
82 {
83     routeTable.refresh();
84 
85     // creates the ethernet interface dbus object.
86     createInterfaces();
87 
88     systemConf.reset(nullptr);
89     dhcpConf.reset(nullptr);
90 
91     fs::path objPath = objectPath;
92     objPath /= "config";
93 
94     // create the system conf object.
95     systemConf = std::make_unique<phosphor::network::SystemConfiguration>(
96         bus, objPath.string());
97     // create the dhcp conf object.
98     objPath /= "dhcp";
99     dhcpConf = std::make_unique<phosphor::network::dhcp::Configuration>(
100         bus, objPath.string(), *this);
101 }
102 
103 ObjectPath Manager::vlan(std::string interfaceName, uint32_t id)
104 {
105     if (id == 0 || id >= 4095)
106     {
107         log<level::ERR>("VLAN ID is not valid", entry("VLANID=%u", id));
108         elog<InvalidArgument>(
109             Argument::ARGUMENT_NAME("VLANId"),
110             Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
111     }
112 
113     auto it = interfaces.find(interfaceName);
114     if (it == interfaces.end())
115     {
116         using ResourceErr =
117             phosphor::logging::xyz::openbmc_project::Common::ResourceNotFound;
118         elog<ResourceNotFound>(ResourceErr::RESOURCE(interfaceName.c_str()));
119     }
120     return it->second->createVLAN(id);
121 }
122 
123 void Manager::reset()
124 {
125     if (fs::is_directory(confDir))
126     {
127         for (const auto& file : fs::directory_iterator(confDir))
128         {
129             fs::remove(file.path());
130         }
131     }
132     log<level::INFO>("Network Factory Reset queued.");
133 }
134 
135 // Need to merge the below function with the code which writes the
136 // config file during factory reset.
137 // TODO openbmc/openbmc#1751
138 void Manager::writeToConfigurationFile()
139 {
140     // write all the static ip address in the systemd-network conf file
141     for (const auto& intf : interfaces)
142     {
143         intf.second->writeConfigurationFile();
144     }
145 }
146 
147 #ifdef SYNC_MAC_FROM_INVENTORY
148 void Manager::setFistBootMACOnInterface(
149     const std::pair<std::string, std::string>& inventoryEthPair)
150 {
151     for (const auto& interface : interfaces)
152     {
153         if (interface.first == inventoryEthPair.first)
154         {
155             auto returnMAC =
156                 interface.second->macAddress(inventoryEthPair.second);
157             if (returnMAC == inventoryEthPair.second)
158             {
159                 log<level::INFO>("Set the MAC on "),
160                     entry("interface : ", interface.first.c_str()),
161                     entry("MAC : ", inventoryEthPair.second.c_str());
162                 std::error_code ec;
163                 if (std::filesystem::is_directory("/var/lib/network", ec))
164                 {
165                     std::ofstream persistentFile(FirstBootFile +
166                                                  interface.first);
167                 }
168                 break;
169             }
170             else
171             {
172                 log<level::INFO>("MAC is Not Set on ethernet Interface");
173             }
174         }
175     }
176 }
177 
178 #endif
179 
180 void Manager::reloadConfigsNoRefresh()
181 {
182     reloadTimer->restartOnce(reloadTimeout);
183 }
184 
185 void Manager::reloadConfigs()
186 {
187     reloadConfigsNoRefresh();
188     // Ensure that the next refresh happens after reconfiguration
189     refreshObjectTimer->setRemaining(reloadTimeout + refreshTimeout);
190 }
191 
192 void Manager::doReloadConfigs()
193 {
194     for (auto& hook : reloadPreHooks)
195     {
196         try
197         {
198             hook();
199         }
200         catch (const std::exception& ex)
201         {
202             log<level::ERR>("Failed executing reload hook, ignoring",
203                             entry("ERR=%s", ex.what()));
204         }
205     }
206     reloadPreHooks.clear();
207     try
208     {
209         auto method = bus.new_method_call(NETWORKD_BUSNAME, NETWORKD_PATH,
210                                           NETWORKD_INTERFACE, "Reload");
211         bus.call_noreply(method);
212     }
213     catch (const sdbusplus::exception_t& ex)
214     {
215         log<level::ERR>("Failed to reload configuration",
216                         entry("ERR=%s", ex.what()));
217         elog<InternalFailure>();
218     }
219     // Ensure reconfiguration has enough time
220     if (refreshObjectTimer->isEnabled())
221     {
222         refreshObjectTimer->setRemaining(refreshTimeout);
223     }
224 }
225 
226 } // namespace network
227 } // namespace phosphor
228