blob: 349c2eaaaeaab06da11ffc80867c5eb2eaf7c7a3 [file] [log] [blame]
Ratan Guptaa54d8f82017-09-08 17:05:46 +05301#include "config.h"
Gunnar Mills57d9c502018-09-14 14:42:34 -05002
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05303#include "network_manager.hpp"
4#include "rtnetlink_server.hpp"
William A. Kennington III3a70fa22018-09-20 18:48:20 -07005#include "types.hpp"
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +05306#include "watch.hpp"
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05307
Ratan Guptaf6657382017-11-10 17:58:17 +05308#include <linux/netlink.h>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +05309
Manojkiran Edacc099a82020-05-11 14:25:16 +053010#include <filesystem>
11#include <fstream>
William A. Kennington III3a70fa22018-09-20 18:48:20 -070012#include <functional>
Ratan Guptaf6657382017-11-10 17:58:17 +053013#include <memory>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070014#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +053015#include <nlohmann/json.hpp>
William A. Kennington IIIde433b72021-05-17 22:59:28 -070016#endif
Ratan Guptaf6657382017-11-10 17:58:17 +053017#include <phosphor-logging/elog-errors.hpp>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053018#include <phosphor-logging/log.hpp>
Ratan Guptacb7098d2017-04-14 17:46:05 +053019#include <sdbusplus/bus.hpp>
Manojkiran Edacc099a82020-05-11 14:25:16 +053020#include <sdbusplus/bus/match.hpp>
Ratan Guptacb7098d2017-04-14 17:46:05 +053021#include <sdbusplus/server/manager.hpp>
William A. Kennington III3a70fa22018-09-20 18:48:20 -070022#include <sdeventplus/event.hpp>
Ratan Guptaf6657382017-11-10 17:58:17 +053023#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053024
William A. Kennington III09095f82018-09-27 12:05:12 -070025using phosphor::logging::elog;
26using phosphor::logging::entry;
27using phosphor::logging::level;
28using phosphor::logging::log;
29using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Manojkiran Edacc099a82020-05-11 14:25:16 +053030using DbusObjectPath = std::string;
31using DbusInterface = std::string;
32using PropertyValue = std::string;
William A. Kennington III09095f82018-09-27 12:05:12 -070033
William A. Kennington III483e7772019-02-12 19:03:15 -080034constexpr char NETWORK_CONF_DIR[] = "/etc/systemd/network";
35
William A. Kennington III5f1eb462019-02-12 19:47:51 -080036constexpr char DEFAULT_OBJPATH[] = "/xyz/openbmc_project/network";
37
Manojkiran Edacc099a82020-05-11 14:25:16 +053038constexpr auto firstBootPath = "/var/lib/network/firstBoot_";
39constexpr auto configFile = "/usr/share/network/config.json";
40
41constexpr auto invNetworkIntf =
42 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
43
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053044namespace phosphor
45{
46namespace network
47{
48
49std::unique_ptr<phosphor::network::Manager> manager = nullptr;
William A. Kennington III3a70fa22018-09-20 18:48:20 -070050std::unique_ptr<Timer> refreshObjectTimer = nullptr;
William A. Kennington IIIc7cf25f2021-11-09 16:16:59 -080051std::unique_ptr<Timer> reloadTimer = nullptr;
Ratan Guptaa54d8f82017-09-08 17:05:46 +053052
William A. Kennington III6f39c5e2021-05-13 18:39:23 -070053#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +053054std::unique_ptr<sdbusplus::bus::match::match> EthInterfaceMatch = nullptr;
55std::vector<std::string> first_boot_status;
56
57bool setInventoryMACOnSystem(sdbusplus::bus::bus& bus,
58 const nlohmann::json& configJson,
59 const std::string& intfname)
60{
61 try
62 {
63 auto inventoryMAC = mac_address::getfromInventory(bus, intfname);
64 if (!mac_address::toString(inventoryMAC).empty())
65 {
66 log<level::INFO>("Mac Address in Inventory on "),
67 entry("Interface : ", intfname.c_str()),
68 entry("MAC Address :",
69 (mac_address::toString(inventoryMAC)).c_str());
70 manager->setFistBootMACOnInterface(std::make_pair(
71 intfname.c_str(), mac_address::toString(inventoryMAC)));
72 first_boot_status.push_back(intfname.c_str());
73 bool status = true;
74 for (const auto& keys : configJson.items())
75 {
76 if (!(std::find(first_boot_status.begin(),
77 first_boot_status.end(),
78 keys.key()) != first_boot_status.end()))
79 {
80 log<level::INFO>("Interface MAC is NOT set from VPD"),
81 entry("INTERFACE", keys.key().c_str());
82 status = false;
83 }
84 }
85 if (status)
86 {
87 log<level::INFO>("Removing the match for ethernet interfaces");
88 phosphor::network::EthInterfaceMatch = nullptr;
89 }
90 }
91 else
92 {
93 log<level::INFO>("Nothing is present in Inventory");
94 return false;
95 }
96 }
97 catch (const std::exception& e)
98 {
99 log<level::ERR>("Exception occurred during getting of MAC "
100 "address from Inventory");
101 return false;
102 }
103 return true;
104}
105
106// register the macthes to be monitored from inventory manager
107void registerSignals(sdbusplus::bus::bus& bus, const nlohmann::json& configJson)
108{
109 log<level::INFO>("Registering the Inventory Signals Matcher");
110
111 static std::unique_ptr<sdbusplus::bus::match::match> MacAddressMatch;
112
113 auto callback = [&](sdbusplus::message::message& m) {
114 std::map<DbusObjectPath,
115 std::map<DbusInterface, std::variant<PropertyValue>>>
116 interfacesProperties;
117
118 sdbusplus::message::object_path objPath;
119 std::pair<std::string, std::string> ethPair;
120 m.read(objPath, interfacesProperties);
121
122 for (const auto& pattern : configJson.items())
123 {
124 if (objPath.str.find(pattern.value()) != std::string::npos)
125 {
126 for (auto& interface : interfacesProperties)
127 {
128 if (interface.first == invNetworkIntf)
129 {
130 for (const auto& property : interface.second)
131 {
132 if (property.first == "MACAddress")
133 {
134 ethPair = std::make_pair(
135 pattern.key(),
136 std::get<std::string>(property.second));
137 break;
138 }
139 }
140 break;
141 }
142 }
143 if (!(ethPair.first.empty() || ethPair.second.empty()))
144 {
145 manager->setFistBootMACOnInterface(ethPair);
146 }
147 }
148 }
149 };
150
151 MacAddressMatch = std::make_unique<sdbusplus::bus::match::match>(
152 bus,
153 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
154 "member='InterfacesAdded',path='/xyz/openbmc_project/"
155 "inventory'",
156 callback);
157}
158
159void watchEthernetInterface(sdbusplus::bus::bus& bus,
160 const nlohmann::json& configJson)
161{
162 auto mycallback = [&](sdbusplus::message::message& m) {
163 std::map<DbusObjectPath,
164 std::map<DbusInterface, std::variant<PropertyValue>>>
165 interfacesProperties;
166
167 sdbusplus::message::object_path objPath;
168 std::pair<std::string, std::string> ethPair;
169 m.read(objPath, interfacesProperties);
170 for (const auto& interfaces : interfacesProperties)
171 {
172 if (interfaces.first ==
173 "xyz.openbmc_project.Network.EthernetInterface")
174 {
175 for (const auto& property : interfaces.second)
176 {
177 if (property.first == "InterfaceName")
178 {
179 std::string infname =
180 std::get<std::string>(property.second);
181
182 if (configJson.find(infname) == configJson.end())
183 {
184 // ethernet interface not found in configJSON
185 // check if it is not sit0 interface, as it is
186 // expected.
187 if (infname != "sit0")
188 {
189 log<level::ERR>(
190 "Wrong Interface Name in Config Json");
191 }
192 }
193 else
194 {
195 if (!phosphor::network::setInventoryMACOnSystem(
196 bus, configJson, infname))
197 {
198 phosphor::network::registerSignals(bus,
199 configJson);
200 phosphor::network::EthInterfaceMatch = nullptr;
201 }
202 }
203 break;
204 }
205 }
206 break;
207 }
208 }
209 };
210 // Incase if phosphor-inventory-manager started early and the VPD is already
211 // collected by the time network service has come up, better to check the
212 // VPD directly and set the MAC Address on the respective Interface.
213
214 bool registeredSignals = false;
215 for (const auto& interfaceString : configJson.items())
216 {
217 if (!std::filesystem::exists(firstBootPath + interfaceString.key()) &&
218 !registeredSignals)
219 {
220
221 log<level::INFO>(
222 "First boot file is not present, check VPD for MAC");
223 phosphor::network::EthInterfaceMatch = std::make_unique<
224 sdbusplus::bus::match::match>(
225 bus,
226 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
227 "member='InterfacesAdded',path='/xyz/openbmc_project/network'",
228 mycallback);
229 registeredSignals = true;
230 }
231 }
232}
233
234#endif
235
Ratan Gupta16f12882017-09-22 18:26:11 +0530236/** @brief refresh the network objects. */
Ratan Guptaa54d8f82017-09-08 17:05:46 +0530237void refreshObjects()
238{
Ratan Gupta16f12882017-09-22 18:26:11 +0530239 if (manager)
240 {
Ratan Gupta310a0b12017-11-15 17:40:24 +0530241 log<level::INFO>("Refreshing the objects.");
Ratan Gupta16f12882017-09-22 18:26:11 +0530242 manager->createChildObjects();
Ratan Gupta310a0b12017-11-15 17:40:24 +0530243 log<level::INFO>("Refreshing complete.");
Ratan Gupta16f12882017-09-22 18:26:11 +0530244 }
245}
246
William A. Kennington IIIc7cf25f2021-11-09 16:16:59 -0800247void reloadNetworkd()
248{
249 if (manager)
250 {
251 log<level::INFO>("Sending networkd reload");
252 manager->doReloadConfigs();
253 log<level::INFO>("Done networkd reload");
254 }
255}
256
Ratan Gupta16f12882017-09-22 18:26:11 +0530257void initializeTimers()
258{
William A. Kennington III3a70fa22018-09-20 18:48:20 -0700259 auto event = sdeventplus::Event::get_default();
260 refreshObjectTimer =
261 std::make_unique<Timer>(event, std::bind(refreshObjects));
William A. Kennington IIIc7cf25f2021-11-09 16:16:59 -0800262 reloadTimer = std::make_unique<Timer>(event, std::bind(reloadNetworkd));
Ratan Gupta16f12882017-09-22 18:26:11 +0530263}
264
William A. Kennington III3a70fa22018-09-20 18:48:20 -0700265} // namespace network
266} // namespace phosphor
267
Ratan Guptaf6657382017-11-10 17:58:17 +0530268void createNetLinkSocket(phosphor::Descriptor& smartSock)
269{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500270 // RtnetLink socket
Ratan Guptaf6657382017-11-10 17:58:17 +0530271 auto fd = socket(PF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
272 if (fd < 0)
273 {
Ratan Guptaf6657382017-11-10 17:58:17 +0530274 log<level::ERR>("Unable to create the net link socket",
William A. Kennington III798c2812018-09-27 12:07:39 -0700275 entry("ERRNO=%d", errno));
Ratan Guptaf6657382017-11-10 17:58:17 +0530276 elog<InternalFailure>();
277 }
278 smartSock.set(fd);
279}
280
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530281int main(int /*argc*/, char** /*argv*/)
Ratan Gupta8c834932017-04-14 16:30:24 +0530282{
William A. Kennington III3a70fa22018-09-20 18:48:20 -0700283 phosphor::network::initializeTimers();
Ratan Guptaa54d8f82017-09-08 17:05:46 +0530284
Ratan Guptacb7098d2017-04-14 17:46:05 +0530285 auto bus = sdbusplus::bus::new_default();
286
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530287 // Need sd_event to watch for OCC device errors
288 sd_event* event = nullptr;
289 auto r = sd_event_default(&event);
290 if (r < 0)
291 {
292 log<level::ERR>("Error creating a default sd_event handler");
293 return r;
294 }
295
296 phosphor::network::EventPtr eventPtr{event};
297 event = nullptr;
298
299 // Attach the bus to sd_event to service user requests
300 bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
301
Ratan Guptacb7098d2017-04-14 17:46:05 +0530302 // Add sdbusplus Object Manager for the 'root' path of the network manager.
William A. Kennington III5f1eb462019-02-12 19:47:51 -0800303 sdbusplus::server::manager::manager objManager(bus, DEFAULT_OBJPATH);
304 bus.request_name(DEFAULT_BUSNAME);
Ratan Guptacb7098d2017-04-14 17:46:05 +0530305
Gunnar Mills57d9c502018-09-14 14:42:34 -0500306 phosphor::network::manager = std::make_unique<phosphor::network::Manager>(
William A. Kennington III5f1eb462019-02-12 19:47:51 -0800307 bus, DEFAULT_OBJPATH, NETWORK_CONF_DIR);
Ratan Guptacb7098d2017-04-14 17:46:05 +0530308
Ratan Guptab610caf2017-09-19 09:33:51 +0530309 // create the default network files if the network file
310 // is not there for any interface.
311 // Parameter false means don't create the network
312 // files forcefully.
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700313 if (phosphor::network::manager->createDefaultNetworkFiles(false))
Ratan Guptae9629412017-12-21 08:20:25 +0530314 {
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700315 phosphor::network::manager->reloadConfigs();
Ratan Guptae9629412017-12-21 08:20:25 +0530316 }
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +0530317
Gunnar Mills57d9c502018-09-14 14:42:34 -0500318 // RtnetLink socket
Ratan Guptaf6657382017-11-10 17:58:17 +0530319 phosphor::Descriptor smartSock;
320 createNetLinkSocket(smartSock);
321
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +0530322 // RTNETLINK event handler
Ratan Guptaf6657382017-11-10 17:58:17 +0530323 phosphor::network::rtnetlink::Server svr(eventPtr, smartSock);
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +0530324
William A. Kennington III6f39c5e2021-05-13 18:39:23 -0700325#ifdef SYNC_MAC_FROM_INVENTORY
Manojkiran Edacc099a82020-05-11 14:25:16 +0530326 std::ifstream in(configFile);
327 nlohmann::json configJson;
328 in >> configJson;
329 phosphor::network::watchEthernetInterface(bus, configJson);
330#endif
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700331
332 // Trigger the initial object scan
William A. Kennington III26c40a42021-11-03 18:27:52 -0700333 // This is intentionally deferred, to ensure that systemd-networkd is
334 // fully configured.
335 phosphor::network::refreshObjectTimer->restartOnce(
336 phosphor::network::refreshTimeout);
William A. Kennington IIIbd649af2021-10-08 17:55:13 -0700337
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +0530338 sd_event_loop(eventPtr.get());
Ratan Gupta8c834932017-04-14 16:30:24 +0530339}