blob: 734a48a1ffe065d98e5f3e28e81fc2f8f3194446 [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>
Manojkiran Edacc099a82020-05-11 14:25:16 +053014#include <nlohmann/json.hpp>
Ratan Guptaf6657382017-11-10 17:58:17 +053015#include <phosphor-logging/elog-errors.hpp>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053016#include <phosphor-logging/log.hpp>
Ratan Guptacb7098d2017-04-14 17:46:05 +053017#include <sdbusplus/bus.hpp>
Manojkiran Edacc099a82020-05-11 14:25:16 +053018#include <sdbusplus/bus/match.hpp>
Ratan Guptacb7098d2017-04-14 17:46:05 +053019#include <sdbusplus/server/manager.hpp>
William A. Kennington III3a70fa22018-09-20 18:48:20 -070020#include <sdeventplus/event.hpp>
Ratan Guptaf6657382017-11-10 17:58:17 +053021#include <xyz/openbmc_project/Common/error.hpp>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053022
William A. Kennington III09095f82018-09-27 12:05:12 -070023using phosphor::logging::elog;
24using phosphor::logging::entry;
25using phosphor::logging::level;
26using phosphor::logging::log;
27using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Manojkiran Edacc099a82020-05-11 14:25:16 +053028using DbusObjectPath = std::string;
29using DbusInterface = std::string;
30using PropertyValue = std::string;
William A. Kennington III09095f82018-09-27 12:05:12 -070031
William A. Kennington III483e7772019-02-12 19:03:15 -080032constexpr char NETWORK_CONF_DIR[] = "/etc/systemd/network";
33
William A. Kennington III5f1eb462019-02-12 19:47:51 -080034constexpr char DEFAULT_OBJPATH[] = "/xyz/openbmc_project/network";
35
Manojkiran Edacc099a82020-05-11 14:25:16 +053036constexpr auto firstBootPath = "/var/lib/network/firstBoot_";
37constexpr auto configFile = "/usr/share/network/config.json";
38
39constexpr auto invNetworkIntf =
40 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
41
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053042namespace phosphor
43{
44namespace network
45{
46
47std::unique_ptr<phosphor::network::Manager> manager = nullptr;
William A. Kennington III3a70fa22018-09-20 18:48:20 -070048std::unique_ptr<Timer> refreshObjectTimer = nullptr;
49std::unique_ptr<Timer> restartTimer = nullptr;
Ratan Guptaa54d8f82017-09-08 17:05:46 +053050
Manojkiran Edacc099a82020-05-11 14:25:16 +053051#if SYNC_MAC_FROM_INVENTORY
52std::unique_ptr<sdbusplus::bus::match::match> EthInterfaceMatch = nullptr;
53std::vector<std::string> first_boot_status;
54
55bool setInventoryMACOnSystem(sdbusplus::bus::bus& bus,
56 const nlohmann::json& configJson,
57 const std::string& intfname)
58{
59 try
60 {
61 auto inventoryMAC = mac_address::getfromInventory(bus, intfname);
62 if (!mac_address::toString(inventoryMAC).empty())
63 {
64 log<level::INFO>("Mac Address in Inventory on "),
65 entry("Interface : ", intfname.c_str()),
66 entry("MAC Address :",
67 (mac_address::toString(inventoryMAC)).c_str());
68 manager->setFistBootMACOnInterface(std::make_pair(
69 intfname.c_str(), mac_address::toString(inventoryMAC)));
70 first_boot_status.push_back(intfname.c_str());
71 bool status = true;
72 for (const auto& keys : configJson.items())
73 {
74 if (!(std::find(first_boot_status.begin(),
75 first_boot_status.end(),
76 keys.key()) != first_boot_status.end()))
77 {
78 log<level::INFO>("Interface MAC is NOT set from VPD"),
79 entry("INTERFACE", keys.key().c_str());
80 status = false;
81 }
82 }
83 if (status)
84 {
85 log<level::INFO>("Removing the match for ethernet interfaces");
86 phosphor::network::EthInterfaceMatch = nullptr;
87 }
88 }
89 else
90 {
91 log<level::INFO>("Nothing is present in Inventory");
92 return false;
93 }
94 }
95 catch (const std::exception& e)
96 {
97 log<level::ERR>("Exception occurred during getting of MAC "
98 "address from Inventory");
99 return false;
100 }
101 return true;
102}
103
104// register the macthes to be monitored from inventory manager
105void registerSignals(sdbusplus::bus::bus& bus, const nlohmann::json& configJson)
106{
107 log<level::INFO>("Registering the Inventory Signals Matcher");
108
109 static std::unique_ptr<sdbusplus::bus::match::match> MacAddressMatch;
110
111 auto callback = [&](sdbusplus::message::message& m) {
112 std::map<DbusObjectPath,
113 std::map<DbusInterface, std::variant<PropertyValue>>>
114 interfacesProperties;
115
116 sdbusplus::message::object_path objPath;
117 std::pair<std::string, std::string> ethPair;
118 m.read(objPath, interfacesProperties);
119
120 for (const auto& pattern : configJson.items())
121 {
122 if (objPath.str.find(pattern.value()) != std::string::npos)
123 {
124 for (auto& interface : interfacesProperties)
125 {
126 if (interface.first == invNetworkIntf)
127 {
128 for (const auto& property : interface.second)
129 {
130 if (property.first == "MACAddress")
131 {
132 ethPair = std::make_pair(
133 pattern.key(),
134 std::get<std::string>(property.second));
135 break;
136 }
137 }
138 break;
139 }
140 }
141 if (!(ethPair.first.empty() || ethPair.second.empty()))
142 {
143 manager->setFistBootMACOnInterface(ethPair);
144 }
145 }
146 }
147 };
148
149 MacAddressMatch = std::make_unique<sdbusplus::bus::match::match>(
150 bus,
151 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
152 "member='InterfacesAdded',path='/xyz/openbmc_project/"
153 "inventory'",
154 callback);
155}
156
157void watchEthernetInterface(sdbusplus::bus::bus& bus,
158 const nlohmann::json& configJson)
159{
160 auto mycallback = [&](sdbusplus::message::message& m) {
161 std::map<DbusObjectPath,
162 std::map<DbusInterface, std::variant<PropertyValue>>>
163 interfacesProperties;
164
165 sdbusplus::message::object_path objPath;
166 std::pair<std::string, std::string> ethPair;
167 m.read(objPath, interfacesProperties);
168 for (const auto& interfaces : interfacesProperties)
169 {
170 if (interfaces.first ==
171 "xyz.openbmc_project.Network.EthernetInterface")
172 {
173 for (const auto& property : interfaces.second)
174 {
175 if (property.first == "InterfaceName")
176 {
177 std::string infname =
178 std::get<std::string>(property.second);
179
180 if (configJson.find(infname) == configJson.end())
181 {
182 // ethernet interface not found in configJSON
183 // check if it is not sit0 interface, as it is
184 // expected.
185 if (infname != "sit0")
186 {
187 log<level::ERR>(
188 "Wrong Interface Name in Config Json");
189 }
190 }
191 else
192 {
193 if (!phosphor::network::setInventoryMACOnSystem(
194 bus, configJson, infname))
195 {
196 phosphor::network::registerSignals(bus,
197 configJson);
198 phosphor::network::EthInterfaceMatch = nullptr;
199 }
200 }
201 break;
202 }
203 }
204 break;
205 }
206 }
207 };
208 // Incase if phosphor-inventory-manager started early and the VPD is already
209 // collected by the time network service has come up, better to check the
210 // VPD directly and set the MAC Address on the respective Interface.
211
212 bool registeredSignals = false;
213 for (const auto& interfaceString : configJson.items())
214 {
215 if (!std::filesystem::exists(firstBootPath + interfaceString.key()) &&
216 !registeredSignals)
217 {
218
219 log<level::INFO>(
220 "First boot file is not present, check VPD for MAC");
221 phosphor::network::EthInterfaceMatch = std::make_unique<
222 sdbusplus::bus::match::match>(
223 bus,
224 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
225 "member='InterfacesAdded',path='/xyz/openbmc_project/network'",
226 mycallback);
227 registeredSignals = true;
228 }
229 }
230}
231
232#endif
233
Ratan Gupta16f12882017-09-22 18:26:11 +0530234/** @brief refresh the network objects. */
Ratan Guptaa54d8f82017-09-08 17:05:46 +0530235void refreshObjects()
236{
Ratan Gupta16f12882017-09-22 18:26:11 +0530237 if (manager)
238 {
Ratan Gupta310a0b12017-11-15 17:40:24 +0530239 log<level::INFO>("Refreshing the objects.");
Ratan Gupta16f12882017-09-22 18:26:11 +0530240 manager->createChildObjects();
Ratan Gupta310a0b12017-11-15 17:40:24 +0530241 log<level::INFO>("Refreshing complete.");
Ratan Gupta16f12882017-09-22 18:26:11 +0530242 }
243}
244
245/** @brief restart the systemd networkd. */
246void restartNetwork()
247{
Ratan Gupta895f9e52018-11-26 20:57:34 +0530248 if (manager)
249 {
250 manager->restartSystemdUnit("systemd-networkd.service");
251 }
Ratan Guptaa54d8f82017-09-08 17:05:46 +0530252}
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530253
Ratan Gupta16f12882017-09-22 18:26:11 +0530254void initializeTimers()
255{
William A. Kennington III3a70fa22018-09-20 18:48:20 -0700256 auto event = sdeventplus::Event::get_default();
257 refreshObjectTimer =
258 std::make_unique<Timer>(event, std::bind(refreshObjects));
259 restartTimer = std::make_unique<Timer>(event, std::bind(restartNetwork));
Ratan Gupta16f12882017-09-22 18:26:11 +0530260}
261
William A. Kennington III3a70fa22018-09-20 18:48:20 -0700262} // namespace network
263} // namespace phosphor
264
Ratan Guptaf6657382017-11-10 17:58:17 +0530265void createNetLinkSocket(phosphor::Descriptor& smartSock)
266{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500267 // RtnetLink socket
Ratan Guptaf6657382017-11-10 17:58:17 +0530268 auto fd = socket(PF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
269 if (fd < 0)
270 {
Ratan Guptaf6657382017-11-10 17:58:17 +0530271 log<level::ERR>("Unable to create the net link socket",
William A. Kennington III798c2812018-09-27 12:07:39 -0700272 entry("ERRNO=%d", errno));
Ratan Guptaf6657382017-11-10 17:58:17 +0530273 elog<InternalFailure>();
274 }
275 smartSock.set(fd);
276}
277
Manojkiran Edaaa57fa52020-06-13 14:59:53 +0530278int main(int /*argc*/, char** /*argv*/)
Ratan Gupta8c834932017-04-14 16:30:24 +0530279{
William A. Kennington III3a70fa22018-09-20 18:48:20 -0700280 phosphor::network::initializeTimers();
Ratan Guptaa54d8f82017-09-08 17:05:46 +0530281
Ratan Guptacb7098d2017-04-14 17:46:05 +0530282 auto bus = sdbusplus::bus::new_default();
283
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +0530284 // Need sd_event to watch for OCC device errors
285 sd_event* event = nullptr;
286 auto r = sd_event_default(&event);
287 if (r < 0)
288 {
289 log<level::ERR>("Error creating a default sd_event handler");
290 return r;
291 }
292
293 phosphor::network::EventPtr eventPtr{event};
294 event = nullptr;
295
296 // Attach the bus to sd_event to service user requests
297 bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
298
Ratan Guptacb7098d2017-04-14 17:46:05 +0530299 // Add sdbusplus Object Manager for the 'root' path of the network manager.
William A. Kennington III5f1eb462019-02-12 19:47:51 -0800300 sdbusplus::server::manager::manager objManager(bus, DEFAULT_OBJPATH);
301 bus.request_name(DEFAULT_BUSNAME);
Ratan Guptacb7098d2017-04-14 17:46:05 +0530302
Gunnar Mills57d9c502018-09-14 14:42:34 -0500303 phosphor::network::manager = std::make_unique<phosphor::network::Manager>(
William A. Kennington III5f1eb462019-02-12 19:47:51 -0800304 bus, DEFAULT_OBJPATH, NETWORK_CONF_DIR);
Ratan Guptacb7098d2017-04-14 17:46:05 +0530305
Ratan Guptab610caf2017-09-19 09:33:51 +0530306 // create the default network files if the network file
307 // is not there for any interface.
308 // Parameter false means don't create the network
309 // files forcefully.
310 if (phosphor::network::manager->createDefaultNetworkFiles(false))
311 {
312 // if files created restart the network.
313 // don't need to call the create child objects as eventhandler
314 // will create it.
Ratan Gupta16f12882017-09-22 18:26:11 +0530315 phosphor::network::restartNetwork();
Ratan Guptab610caf2017-09-19 09:33:51 +0530316 }
Ratan Guptae9629412017-12-21 08:20:25 +0530317 else
318 {
319 // this will add the additional fixes which is needed
320 // in the existing network file.
321 phosphor::network::manager->writeToConfigurationFile();
Ratan Gupta2939f182018-02-14 23:14:54 +0530322 // whenever the configuration file gets written it restart
323 // the network which creates the network objects
Ratan Guptae9629412017-12-21 08:20:25 +0530324 }
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +0530325
Gunnar Mills57d9c502018-09-14 14:42:34 -0500326 // RtnetLink socket
Ratan Guptaf6657382017-11-10 17:58:17 +0530327 phosphor::Descriptor smartSock;
328 createNetLinkSocket(smartSock);
329
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +0530330 // RTNETLINK event handler
Ratan Guptaf6657382017-11-10 17:58:17 +0530331 phosphor::network::rtnetlink::Server svr(eventPtr, smartSock);
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +0530332
Manojkiran Edacc099a82020-05-11 14:25:16 +0530333#if SYNC_MAC_FROM_INVENTORY
334 std::ifstream in(configFile);
335 nlohmann::json configJson;
336 in >> configJson;
337 phosphor::network::watchEthernetInterface(bus, configJson);
338#endif
Vishwanatha Subbanna18891c62017-10-17 15:22:46 +0530339 sd_event_loop(eventPtr.get());
Ratan Gupta8c834932017-04-14 16:30:24 +0530340}