xref: /openbmc/phosphor-networkd/src/network_manager.cpp (revision ee2cba8a7d22ef4a251181087e9ef9bfc5c4b165)
1 #include "config.h"
2 
3 #include "network_manager.hpp"
4 
5 #include "ipaddress.hpp"
6 #include "network_config.hpp"
7 #include "types.hpp"
8 #include "util.hpp"
9 
10 #include <arpa/inet.h>
11 #include <dirent.h>
12 #include <net/if.h>
13 
14 #include <algorithm>
15 #include <bitset>
16 #include <filesystem>
17 #include <fstream>
18 #include <map>
19 #include <phosphor-logging/elog-errors.hpp>
20 #include <phosphor-logging/log.hpp>
21 #include <string>
22 #include <xyz/openbmc_project/Common/error.hpp>
23 
24 constexpr char SYSTEMD_BUSNAME[] = "org.freedesktop.systemd1";
25 constexpr char SYSTEMD_PATH[] = "/org/freedesktop/systemd1";
26 constexpr char SYSTEMD_INTERFACE[] = "org.freedesktop.systemd1.Manager";
27 constexpr auto FirstBootFile = "/var/lib/network/firstBoot_";
28 
29 constexpr char NETWORKD_BUSNAME[] = "org.freedesktop.network1";
30 constexpr char NETWORKD_PATH[] = "/org/freedesktop/network1";
31 constexpr char NETWORKD_INTERFACE[] = "org.freedesktop.network1.Manager";
32 
33 namespace phosphor
34 {
35 namespace network
36 {
37 
38 extern std::unique_ptr<Timer> refreshObjectTimer;
39 using namespace phosphor::logging;
40 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
41 
42 Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath,
43                  const std::string& path) :
44     details::VLANCreateIface(bus, objPath, true),
45     bus(bus), objectPath(objPath)
46 {
47     fs::path confDir(path);
48     setConfDir(confDir);
49 }
50 
51 bool Manager::createDefaultNetworkFiles(bool force)
52 {
53     auto isCreated = false;
54     try
55     {
56         // Directory would have created before with
57         // setConfDir function.
58         if (force)
59         {
60             // Factory Reset case
61             // we need to forcefully write the files
62             // so delete the existing ones.
63             if (fs::is_directory(confDir))
64             {
65                 for (const auto& file : fs::directory_iterator(confDir))
66                 {
67                     fs::remove(file.path());
68                 }
69             }
70         }
71 
72         auto interfaceStrList = getInterfaces();
73         for (const auto& interface : interfaceStrList)
74         {
75             // if the interface has '.' in the name, it means that this is a
76             // VLAN - don't create the network file.
77             if (interface.find(".") != std::string::npos)
78             {
79                 continue;
80             }
81 
82             auto fileName = systemd::config::networkFilePrefix + interface +
83                             systemd::config::networkFileSuffix;
84 
85             fs::path filePath = confDir;
86             filePath /= fileName;
87 
88             // create the interface specific network file
89             // if not exist or we forcefully wants to write
90             // the network file.
91 
92             if (force || !fs::is_regular_file(filePath.string()))
93             {
94                 bmc::writeDHCPDefault(filePath.string(), interface);
95                 log<level::INFO>("Created the default network file.",
96                                  entry("INTERFACE=%s", interface.c_str()));
97                 isCreated = true;
98             }
99         }
100     }
101     catch (const std::exception& e)
102     {
103         log<level::ERR>("Unable to create the default network file");
104     }
105 
106     return isCreated;
107 }
108 
109 void Manager::setConfDir(const fs::path& dir)
110 {
111     confDir = dir;
112 
113     if (!fs::exists(confDir))
114     {
115         if (!fs::create_directories(confDir))
116         {
117             log<level::ERR>("Unable to create the network conf dir",
118                             entry("DIR=%s", confDir.c_str()));
119             elog<InternalFailure>();
120         }
121     }
122 }
123 
124 void Manager::createInterfaces()
125 {
126     // clear all the interfaces first
127     interfaces.clear();
128 
129     auto interfaceStrList = getInterfaces();
130 
131     for (auto& interface : interfaceStrList)
132     {
133         fs::path objPath = objectPath;
134         auto index = interface.find(".");
135 
136         // interface can be of vlan type or normal ethernet interface.
137         // vlan interface looks like "interface.vlanid",so here by looking
138         // at the interface name we decide that we need
139         // to create the vlaninterface or normal physical interface.
140         if (index != std::string::npos)
141         {
142             // it is vlan interface
143             auto interfaceName = interface.substr(0, index);
144             auto vlanid = interface.substr(index + 1);
145             uint32_t vlanInt = std::stoul(vlanid);
146 
147             interfaces[interfaceName]->loadVLAN(vlanInt);
148             continue;
149         }
150         // normal ethernet interface
151         objPath /= interface;
152 
153         auto dhcp = getDHCPValue(confDir, interface);
154 
155         auto intf = std::make_shared<phosphor::network::EthernetInterface>(
156             bus, objPath.string(), dhcp, *this);
157 
158         intf->createIPAddressObjects();
159         intf->createStaticNeighborObjects();
160         intf->loadNameServers();
161 
162         this->interfaces.emplace(
163             std::make_pair(std::move(interface), std::move(intf)));
164     }
165 }
166 
167 void Manager::createChildObjects()
168 {
169     routeTable.refresh();
170 
171     // creates the ethernet interface dbus object.
172     createInterfaces();
173 
174     systemConf.reset(nullptr);
175     dhcpConf.reset(nullptr);
176 
177     fs::path objPath = objectPath;
178     objPath /= "config";
179 
180     // create the system conf object.
181     systemConf = std::make_unique<phosphor::network::SystemConfiguration>(
182         bus, objPath.string(), *this);
183     // create the dhcp conf object.
184     objPath /= "dhcp";
185     dhcpConf = std::make_unique<phosphor::network::dhcp::Configuration>(
186         bus, objPath.string(), *this);
187 }
188 
189 ObjectPath Manager::vlan(IntfName interfaceName, uint32_t id)
190 {
191     if (!hasInterface(interfaceName))
192     {
193         elog<ResourceNotFound>();
194     }
195 
196     return interfaces[interfaceName]->createVLAN(id);
197 }
198 
199 void Manager::reset()
200 {
201     if (!createDefaultNetworkFiles(true))
202     {
203         log<level::ERR>("Network Factory Reset failed.");
204         return;
205         // TODO: openbmc/openbmc#1721 - Log ResetFailed error here.
206     }
207 
208     log<level::INFO>("Network Factory Reset done.");
209 }
210 
211 // Need to merge the below function with the code which writes the
212 // config file during factory reset.
213 // TODO openbmc/openbmc#1751
214 void Manager::writeToConfigurationFile()
215 {
216     // write all the static ip address in the systemd-network conf file
217     for (const auto& intf : interfaces)
218     {
219         intf.second->writeConfigurationFile();
220     }
221 }
222 
223 #ifdef SYNC_MAC_FROM_INVENTORY
224 void Manager::setFistBootMACOnInterface(
225     const std::pair<std::string, std::string>& inventoryEthPair)
226 {
227     for (const auto& interface : interfaces)
228     {
229         if (interface.first == inventoryEthPair.first)
230         {
231             auto returnMAC =
232                 interface.second->macAddress(inventoryEthPair.second);
233             if (returnMAC == inventoryEthPair.second)
234             {
235                 log<level::INFO>("Set the MAC on "),
236                     entry("interface : ", interface.first.c_str()),
237                     entry("MAC : ", inventoryEthPair.second.c_str());
238                 std::error_code ec;
239                 if (std::filesystem::is_directory("/var/lib/network", ec))
240                 {
241                     std::ofstream persistentFile(FirstBootFile +
242                                                  interface.first);
243                 }
244                 break;
245             }
246             else
247             {
248                 log<level::INFO>("MAC is Not Set on ethernet Interface");
249             }
250         }
251     }
252 }
253 
254 #endif
255 
256 void Manager::reloadConfigs()
257 {
258     try
259     {
260         auto method = bus.new_method_call(NETWORKD_BUSNAME, NETWORKD_PATH,
261                                           NETWORKD_INTERFACE, "Reload");
262         bus.call_noreply(method);
263     }
264     catch (const sdbusplus::exception::exception& ex)
265     {
266         log<level::ERR>("Failed to reload configuration",
267                         entry("ERR=%s", ex.what()));
268         elog<InternalFailure>();
269     }
270 }
271 
272 } // namespace network
273 } // namespace phosphor
274