blob: 62ca4916b488305d3c763c7ca5a7657057d15011 [file] [log] [blame]
Gunnar Mills57d9c502018-09-14 14:42:34 -05001#include "config.h"
2
Ratan Gupta6811f822017-04-14 16:34:56 +05303#include "network_manager.hpp"
Patrick Venture189d44e2018-07-09 12:30:59 -07004
William A. Kennington III09f3a4a2022-10-25 02:59:16 -07005#include "config_parser.hpp"
Ratan Gupta5978dd12017-07-25 13:47:13 +05306#include "ipaddress.hpp"
William A. Kennington III2e09d272022-10-14 17:15:00 -07007#include "system_queries.hpp"
William A. Kennington III3a70fa22018-09-20 18:48:20 -07008#include "types.hpp"
William A. Kennington IIIb8006122022-11-13 18:15:15 -08009#include "util.hpp"
10
11#include <net/if.h>
Ratan Gupta738a67f2017-04-21 10:38:05 +053012
Manojkiran Edacc099a82020-05-11 14:25:16 +053013#include <filesystem>
Patrick Venture189d44e2018-07-09 12:30:59 -070014#include <fstream>
Patrick Venture189d44e2018-07-09 12:30:59 -070015#include <phosphor-logging/elog-errors.hpp>
16#include <phosphor-logging/log.hpp>
William A. Kennington III80d29012022-11-12 02:31:40 -080017#include <sdbusplus/message.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070018#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta6811f822017-04-14 16:34:56 +053019
William A. Kennington IIIf1aa51c2019-02-12 19:58:11 -080020constexpr char SYSTEMD_BUSNAME[] = "org.freedesktop.systemd1";
21constexpr char SYSTEMD_PATH[] = "/org/freedesktop/systemd1";
22constexpr char SYSTEMD_INTERFACE[] = "org.freedesktop.systemd1.Manager";
Manojkiran Edacc099a82020-05-11 14:25:16 +053023constexpr auto FirstBootFile = "/var/lib/network/firstBoot_";
William A. Kennington IIIf1aa51c2019-02-12 19:58:11 -080024
William A. Kennington III56ecc782021-10-07 18:44:50 -070025constexpr char NETWORKD_BUSNAME[] = "org.freedesktop.network1";
26constexpr char NETWORKD_PATH[] = "/org/freedesktop/network1";
27constexpr char NETWORKD_INTERFACE[] = "org.freedesktop.network1.Manager";
28
Ratan Gupta6811f822017-04-14 16:34:56 +053029namespace phosphor
30{
31namespace network
32{
Ratan Gupta82549cc2017-04-21 08:45:23 +053033
William A. Kennington IIId41db382021-11-09 20:42:29 -080034extern std::unique_ptr<Timer> refreshObjectTimer;
William A. Kennington IIIc7cf25f2021-11-09 16:16:59 -080035extern std::unique_ptr<Timer> reloadTimer;
Ratan Gupta6811f822017-04-14 16:34:56 +053036using namespace phosphor::logging;
Ratan Guptaef85eb92017-06-15 08:57:54 +053037using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Jiaqing Zhaob685cb62022-04-12 22:57:34 +080038using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta6811f822017-04-14 16:34:56 +053039
William A. Kennington III80d29012022-11-12 02:31:40 -080040static constexpr const char enabledMatch[] =
41 "type='signal',sender='org.freedesktop.network1',path_namespace='/org/"
42 "freedesktop/network1/"
43 "link',interface='org.freedesktop.DBus.Properties',member='"
44 "PropertiesChanged',arg0='org.freedesktop.network1.Link',";
45
Patrick Williamsc38b0712022-07-22 19:26:54 -050046Manager::Manager(sdbusplus::bus_t& bus, const char* objPath,
William A. Kennington IIIbe3bd2f2022-10-11 14:11:27 -070047 const fs::path& confDir) :
Patrick Williams166b9592022-03-30 16:09:16 -050048 details::VLANCreateIface(bus, objPath,
49 details::VLANCreateIface::action::defer_emit),
William A. Kennington III80d29012022-11-12 02:31:40 -080050 bus(bus), objectPath(objPath),
51 systemdNetworkdEnabledMatch(
52 bus, enabledMatch, [&](sdbusplus::message_t& m) {
53 std::string intf;
54 std::unordered_map<std::string, std::variant<std::string>> values;
55 try
56 {
57 m.read(intf, values);
58 auto it = values.find("AdministrativeState");
59 if (it == values.end())
60 {
61 return;
62 }
63 const std::string_view obj = m.get_path();
64 auto sep = obj.rfind('/');
65 if (sep == obj.npos || sep + 3 > obj.size())
66 {
67 throw std::invalid_argument("Invalid obj path");
68 }
69 auto ifidx = DecodeInt<unsigned, 10>{}(obj.substr(sep + 3));
70 const auto& state = std::get<std::string>(it->second);
71 handleAdminState(state, ifidx);
72 }
73 catch (const std::exception& e)
74 {
75 log<level::ERR>(
76 fmt::format("AdministrativeState match parsing failed: {}",
77 e.what())
78 .c_str(),
79 entry("ERROR=%s", e.what()));
80 }
81 })
Ratan Gupta6811f822017-04-14 16:34:56 +053082{
Ratan Gupta255d5142017-08-10 09:02:08 +053083 setConfDir(confDir);
William A. Kennington III80d29012022-11-12 02:31:40 -080084 std::vector<
85 std::tuple<int32_t, std::string, sdbusplus::message::object_path>>
86 links;
87 try
88 {
89 auto rsp =
90 bus.new_method_call("org.freedesktop.network1",
91 "/org/freedesktop/network1",
92 "org.freedesktop.network1.Manager", "ListLinks")
93 .call();
94 rsp.read(links);
95 }
96 catch (const sdbusplus::exception::SdBusError& e)
97 {
98 // Any failures are systemd-network not being ready
99 }
100 for (const auto& link : links)
101 {
102 unsigned ifidx = std::get<0>(link);
103 auto obj = fmt::format("/org/freedesktop/network1/link/_3{}", ifidx);
104 auto req =
105 bus.new_method_call("org.freedesktop.network1", obj.c_str(),
106 "org.freedesktop.DBus.Properties", "Get");
107 req.append("org.freedesktop.network1.Link", "AdministrativeState");
108 auto rsp = req.call();
109 std::variant<std::string> val;
110 rsp.read(val);
111 handleAdminState(std::get<std::string>(val), ifidx);
112 }
Ratan Guptaef85eb92017-06-15 08:57:54 +0530113}
114
115void Manager::setConfDir(const fs::path& dir)
116{
117 confDir = dir;
Ratan Gupta255d5142017-08-10 09:02:08 +0530118
119 if (!fs::exists(confDir))
120 {
121 if (!fs::create_directories(confDir))
122 {
123 log<level::ERR>("Unable to create the network conf dir",
124 entry("DIR=%s", confDir.c_str()));
125 elog<InternalFailure>();
126 }
127 }
Ratan Gupta29b0e432017-05-25 12:51:40 +0530128}
129
William A. Kennington IIIf30d5602022-11-13 17:09:55 -0800130void Manager::createInterface(const UndiscoveredInfo& info, bool enabled)
William A. Kennington III80d29012022-11-12 02:31:40 -0800131{
William A. Kennington IIIf30d5602022-11-13 17:09:55 -0800132 removeInterface(info.intf);
133 config::Parser config(config::pathForIntfConf(confDir, *info.intf.name));
William A. Kennington III80d29012022-11-12 02:31:40 -0800134 auto intf = std::make_unique<EthernetInterface>(
William A. Kennington IIIf30d5602022-11-13 17:09:55 -0800135 bus, *this, info.intf, objectPath, config, true, enabled);
William A. Kennington III80d29012022-11-12 02:31:40 -0800136 intf->createIPAddressObjects();
137 intf->createStaticNeighborObjects();
138 intf->loadNameServers(config);
139 intf->loadNTPServers(config);
140 auto ptr = intf.get();
William A. Kennington IIIf30d5602022-11-13 17:09:55 -0800141 interfaces.insert_or_assign(*info.intf.name, std::move(intf));
142 interfacesByIdx.insert_or_assign(info.intf.idx, ptr);
William A. Kennington III80d29012022-11-12 02:31:40 -0800143}
144
William A. Kennington III0813a242022-11-12 18:07:11 -0800145void Manager::addInterface(const InterfaceInfo& info)
146{
William A. Kennington IIIb8006122022-11-13 18:15:15 -0800147 if (info.flags & IFF_LOOPBACK)
148 {
149 return;
150 }
151 if (!info.name)
152 {
153 throw std::invalid_argument("Interface missing name");
154 }
155 const auto& ignored = internal::getIgnoredInterfaces();
156 if (ignored.find(*info.name) != ignored.end())
157 {
158 auto msg = fmt::format("Ignoring interface {}\n", *info.name);
159 log<level::INFO>(msg.c_str());
160 return;
161 }
162
William A. Kennington III0813a242022-11-12 18:07:11 -0800163 auto it = systemdNetworkdEnabled.find(info.idx);
164 if (it != systemdNetworkdEnabled.end())
165 {
William A. Kennington IIIf30d5602022-11-13 17:09:55 -0800166 createInterface({info}, it->second);
William A. Kennington III0813a242022-11-12 18:07:11 -0800167 }
168 else
169 {
William A. Kennington IIIf30d5602022-11-13 17:09:55 -0800170 undiscoveredIntfInfo.insert_or_assign(
171 info.idx, UndiscoveredInfo{std::move(info)});
William A. Kennington III0813a242022-11-12 18:07:11 -0800172 }
173}
174
175void Manager::removeInterface(const InterfaceInfo& info)
176{
177 auto iit = interfacesByIdx.find(info.idx);
178 auto nit = interfaces.end();
179 if (info.name)
180 {
181 nit = interfaces.find(*info.name);
182 if (nit != interfaces.end() && iit != interfacesByIdx.end() &&
183 nit->second.get() != iit->second)
184 {
185 fmt::print(stderr, "Removed interface desync detected\n");
186 fflush(stderr);
187 std::abort();
188 }
189 }
190 else if (iit != interfacesByIdx.end())
191 {
192 for (nit = interfaces.begin(); nit != interfaces.end(); ++nit)
193 {
194 if (nit->second.get() == iit->second)
195 {
196 break;
197 }
198 }
199 }
200
201 if (iit != interfacesByIdx.end())
202 {
203 interfacesByIdx.erase(iit);
204 }
205 else
206 {
207 undiscoveredIntfInfo.erase(info.idx);
208 }
209 if (nit != interfaces.end())
210 {
211 interfaces.erase(nit);
212 }
213}
214
William A. Kennington IIIed5ff472022-11-12 16:24:02 -0800215inline void getIntfOrLog(const decltype(Manager::interfacesByIdx)& intfs,
216 unsigned idx, auto&& cb)
217{
218 auto it = intfs.find(idx);
219 if (it == intfs.end())
220 {
221 auto msg = fmt::format("Interface `{}` not found", idx);
222 log<level::ERR>(msg.c_str(), entry("IFIDX=%u", idx));
223 return;
224 }
225 cb(*it->second);
226}
227
228void Manager::addAddress(const AddressInfo& info)
229{
230 getIntfOrLog(interfacesByIdx, info.ifidx,
231 [&](auto& intf) { intf.addAddr(info); });
232}
233
234void Manager::removeAddress(const AddressInfo& info)
235{
236 getIntfOrLog(interfacesByIdx, info.ifidx,
237 [&](auto& intf) { intf.addrs.erase(info.ifaddr); });
238}
239
240void Manager::addNeighbor(const NeighborInfo& info)
241{
242 getIntfOrLog(interfacesByIdx, info.ifidx,
243 [&](auto& intf) { intf.addStaticNeigh(info); });
244}
245
246void Manager::removeNeighbor(const NeighborInfo& info)
247{
248 if (info.addr)
249 {
250 getIntfOrLog(interfacesByIdx, info.ifidx, [&](auto& intf) {
251 intf.staticNeighbors.erase(*info.addr);
252 });
253 }
254}
255
256void Manager::addDefGw(unsigned ifidx, InAddrAny addr)
257{
258 getIntfOrLog(interfacesByIdx, ifidx, [&](auto& intf) {
259 std::visit(
260 [&](auto addr) {
261 if constexpr (std::is_same_v<in_addr, decltype(addr)>)
262 {
263 intf.EthernetInterfaceIntf::defaultGateway(
264 std::to_string(addr));
265 }
266 else if constexpr (std::is_same_v<in6_addr, decltype(addr)>)
267 {
268 intf.EthernetInterfaceIntf::defaultGateway6(
269 std::to_string(addr));
270 }
271 else
272 {
273 static_assert(!std::is_same_v<void, decltype(addr)>);
274 }
275 },
276 addr);
277 });
278}
279
280void Manager::removeDefGw(unsigned ifidx, InAddrAny addr)
281{
282 getIntfOrLog(interfacesByIdx, ifidx, [&](auto& intf) {
283 std::visit(
284 [&](auto addr) {
285 if constexpr (std::is_same_v<in_addr, decltype(addr)>)
286 {
287 if (intf.defaultGateway() == std::to_string(addr))
288 {
289 intf.EthernetInterfaceIntf::defaultGateway("");
290 }
291 }
292 else if constexpr (std::is_same_v<in6_addr, decltype(addr)>)
293 {
294 if (intf.defaultGateway6() == std::to_string(addr))
295 {
296 intf.EthernetInterfaceIntf::defaultGateway6("");
297 }
298 }
299 else
300 {
301 static_assert(!std::is_same_v<void, decltype(addr)>);
302 }
303 },
304 addr);
305 });
306}
307
Ratan Gupta29b0e432017-05-25 12:51:40 +0530308void Manager::createInterfaces()
309{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500310 // clear all the interfaces first
Ratan Guptaef85eb92017-06-15 08:57:54 +0530311 interfaces.clear();
William A. Kennington III67b09da2022-10-31 14:09:53 -0700312 interfacesByIdx.clear();
William A. Kennington III80d29012022-11-12 02:31:40 -0800313 for (auto& info : system::getInterfaces())
Ratan Gupta6811f822017-04-14 16:34:56 +0530314 {
William A. Kennington III0813a242022-11-12 18:07:11 -0800315 addInterface(info);
Ratan Gupta6811f822017-04-14 16:34:56 +0530316 }
317}
318
Ratan Guptaef85eb92017-06-15 08:57:54 +0530319void Manager::createChildObjects()
320{
William A. Kennington IIIe0564842021-10-23 16:02:22 -0700321 routeTable.refresh();
322
Ratan Guptaef85eb92017-06-15 08:57:54 +0530323 // creates the ethernet interface dbus object.
324 createInterfaces();
Ratan Guptae05083a2017-09-16 07:12:11 +0530325
326 systemConf.reset(nullptr);
327 dhcpConf.reset(nullptr);
328
Ratan Guptaef85eb92017-06-15 08:57:54 +0530329 fs::path objPath = objectPath;
330 objPath /= "config";
Ratan Guptae05083a2017-09-16 07:12:11 +0530331
332 // create the system conf object.
Ratan Guptaef85eb92017-06-15 08:57:54 +0530333 systemConf = std::make_unique<phosphor::network::SystemConfiguration>(
Jiaqing Zhao24b5a612022-04-11 16:46:16 +0800334 bus, objPath.string());
Ratan Guptad16f88c2017-07-11 17:47:57 +0530335 // create the dhcp conf object.
336 objPath /= "dhcp";
337 dhcpConf = std::make_unique<phosphor::network::dhcp::Configuration>(
Gunnar Mills57d9c502018-09-14 14:42:34 -0500338 bus, objPath.string(), *this);
Ratan Guptaef85eb92017-06-15 08:57:54 +0530339}
340
William A. Kennington III085bbdc2022-10-05 02:45:37 -0700341ObjectPath Manager::vlan(std::string interfaceName, uint32_t id)
Ratan Gupta6811f822017-04-14 16:34:56 +0530342{
Jiaqing Zhaob685cb62022-04-12 22:57:34 +0800343 if (id == 0 || id >= 4095)
344 {
345 log<level::ERR>("VLAN ID is not valid", entry("VLANID=%u", id));
346 elog<InvalidArgument>(
347 Argument::ARGUMENT_NAME("VLANId"),
348 Argument::ARGUMENT_VALUE(std::to_string(id).c_str()));
349 }
350
William A. Kennington III96444792022-10-05 15:16:22 -0700351 auto it = interfaces.find(interfaceName);
352 if (it == interfaces.end())
353 {
354 using ResourceErr =
355 phosphor::logging::xyz::openbmc_project::Common::ResourceNotFound;
356 elog<ResourceNotFound>(ResourceErr::RESOURCE(interfaceName.c_str()));
357 }
358 return it->second->createVLAN(id);
Ratan Gupta6811f822017-04-14 16:34:56 +0530359}
360
Michael Tritz29f2fd62017-05-22 15:27:26 -0500361void Manager::reset()
362{
William A. Kennington III9a1d9af2021-11-09 17:51:05 -0800363 if (fs::is_directory(confDir))
Michael Tritz29f2fd62017-05-22 15:27:26 -0500364 {
William A. Kennington III9a1d9af2021-11-09 17:51:05 -0800365 for (const auto& file : fs::directory_iterator(confDir))
366 {
367 fs::remove(file.path());
368 }
Michael Tritz29f2fd62017-05-22 15:27:26 -0500369 }
William A. Kennington III9a1d9af2021-11-09 17:51:05 -0800370 log<level::INFO>("Network Factory Reset queued.");
Michael Tritz29f2fd62017-05-22 15:27:26 -0500371}
372
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530373// Need to merge the below function with the code which writes the
374// config file during factory reset.
Gunnar Mills57d9c502018-09-14 14:42:34 -0500375// TODO openbmc/openbmc#1751
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530376void Manager::writeToConfigurationFile()
377{
378 // write all the static ip address in the systemd-network conf file
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530379 for (const auto& intf : interfaces)
380 {
Ratan Gupta2b106532017-07-25 16:05:02 +0530381 intf.second->writeConfigurationFile();
Ratan Gupta4f1c18b2017-05-25 12:59:35 +0530382 }
Ratan Guptae05083a2017-09-16 07:12:11 +0530383}
384
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700385#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530386void Manager::setFistBootMACOnInterface(
387 const std::pair<std::string, std::string>& inventoryEthPair)
388{
389 for (const auto& interface : interfaces)
390 {
391 if (interface.first == inventoryEthPair.first)
392 {
393 auto returnMAC =
Patrick Williams6aef7692021-05-01 06:39:41 -0500394 interface.second->macAddress(inventoryEthPair.second);
Manojkiran Edacc099a82020-05-11 14:25:16 +0530395 if (returnMAC == inventoryEthPair.second)
396 {
397 log<level::INFO>("Set the MAC on "),
398 entry("interface : ", interface.first.c_str()),
399 entry("MAC : ", inventoryEthPair.second.c_str());
400 std::error_code ec;
401 if (std::filesystem::is_directory("/var/lib/network", ec))
402 {
403 std::ofstream persistentFile(FirstBootFile +
404 interface.first);
405 }
406 break;
407 }
408 else
409 {
410 log<level::INFO>("MAC is Not Set on ethernet Interface");
411 }
412 }
413 }
414}
415
416#endif
417
William A. Kennington III85dc57a2022-11-07 16:53:24 -0800418void Manager::reloadConfigsNoRefresh()
William A. Kennington III56ecc782021-10-07 18:44:50 -0700419{
William A. Kennington IIIc7cf25f2021-11-09 16:16:59 -0800420 reloadTimer->restartOnce(reloadTimeout);
William A. Kennington III85dc57a2022-11-07 16:53:24 -0800421}
422
423void Manager::reloadConfigs()
424{
425 reloadConfigsNoRefresh();
William A. Kennington IIId41db382021-11-09 20:42:29 -0800426 // Ensure that the next refresh happens after reconfiguration
427 refreshObjectTimer->setRemaining(reloadTimeout + refreshTimeout);
William A. Kennington IIIc7cf25f2021-11-09 16:16:59 -0800428}
429
430void Manager::doReloadConfigs()
431{
William A. Kennington III6ff633a2021-11-09 17:09:12 -0800432 for (auto& hook : reloadPreHooks)
433 {
434 try
435 {
436 hook();
437 }
438 catch (const std::exception& ex)
439 {
440 log<level::ERR>("Failed executing reload hook, ignoring",
441 entry("ERR=%s", ex.what()));
442 }
443 }
444 reloadPreHooks.clear();
William A. Kennington III56ecc782021-10-07 18:44:50 -0700445 try
446 {
447 auto method = bus.new_method_call(NETWORKD_BUSNAME, NETWORKD_PATH,
448 NETWORKD_INTERFACE, "Reload");
449 bus.call_noreply(method);
450 }
Patrick Williamsc38b0712022-07-22 19:26:54 -0500451 catch (const sdbusplus::exception_t& ex)
William A. Kennington III56ecc782021-10-07 18:44:50 -0700452 {
453 log<level::ERR>("Failed to reload configuration",
454 entry("ERR=%s", ex.what()));
455 elog<InternalFailure>();
456 }
William A. Kennington IIId41db382021-11-09 20:42:29 -0800457 // Ensure reconfiguration has enough time
William A. Kennington III85dc57a2022-11-07 16:53:24 -0800458 if (refreshObjectTimer->isEnabled())
459 {
460 refreshObjectTimer->setRemaining(refreshTimeout);
461 }
William A. Kennington III56ecc782021-10-07 18:44:50 -0700462}
463
William A. Kennington III80d29012022-11-12 02:31:40 -0800464void Manager::handleAdminState(std::string_view state, unsigned ifidx)
465{
466 if (state == "initialized" || state == "linger")
467 {
468 systemdNetworkdEnabled.erase(ifidx);
469 }
470 else
471 {
472 bool managed = state != "unmanaged";
473 systemdNetworkdEnabled.insert_or_assign(ifidx, managed);
474 if (auto it = undiscoveredIntfInfo.find(ifidx);
475 it != undiscoveredIntfInfo.end())
476 {
477 auto info = std::move(it->second);
478 undiscoveredIntfInfo.erase(it);
William A. Kennington III0813a242022-11-12 18:07:11 -0800479 createInterface(info, managed);
William A. Kennington III80d29012022-11-12 02:31:40 -0800480 }
481 else if (auto it = interfacesByIdx.find(ifidx);
482 it != interfacesByIdx.end())
483 {
484 it->second->EthernetInterfaceIntf::nicEnabled(managed);
485 }
486 }
487}
488
Gunnar Mills57d9c502018-09-14 14:42:34 -0500489} // namespace network
490} // namespace phosphor