blob: e4aad8802505f3ab947be6b85e82141cef83f58a [file] [log] [blame]
William A. Kennington III0b111d42022-10-04 18:06:11 -07001#include "config.h"
2
3#include "inventory_mac.hpp"
4
5#include "network_manager.hpp"
6#include "types.hpp"
7
William A. Kennington III0b111d42022-10-04 18:06:11 -07008#include <nlohmann/json.hpp>
9#include <phosphor-logging/elog-errors.hpp>
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -070010#include <phosphor-logging/lg2.hpp>
William A. Kennington III0b111d42022-10-04 18:06:11 -070011#include <sdbusplus/bus.hpp>
12#include <sdbusplus/bus/match.hpp>
Patrick Williams89d734b2023-05-10 07:50:25 -050013#include <xyz/openbmc_project/Common/error.hpp>
14
15#include <filesystem>
16#include <fstream>
17#include <memory>
William A. Kennington III0b111d42022-10-04 18:06:11 -070018#include <string>
19#include <vector>
William A. Kennington III0b111d42022-10-04 18:06:11 -070020
21namespace phosphor::network::inventory
22{
23
24using phosphor::logging::elog;
William A. Kennington III0b111d42022-10-04 18:06:11 -070025using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
26
27using DbusObjectPath = std::string;
28using DbusInterface = std::string;
29using PropertyValue = std::string;
30using DbusService = std::string;
31using ObjectTree = string_umap<string_umap<std::vector<std::string>>>;
32
33constexpr auto firstBootPath = "/var/lib/network/firstBoot_";
34constexpr auto configFile = "/usr/share/network/config.json";
35
36constexpr auto invNetworkIntf =
37 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
38constexpr auto invRoot = "/xyz/openbmc_project/inventory";
39constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
40constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
41constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
42constexpr auto propIntf = "org.freedesktop.DBus.Properties";
43constexpr auto methodGet = "Get";
44
45Manager* manager = nullptr;
46std::unique_ptr<sdbusplus::bus::match_t> EthInterfaceMatch = nullptr;
Patrick Williamsde333e12023-02-10 15:50:04 -060047std::unique_ptr<sdbusplus::bus::match_t> MacAddressMatch = nullptr;
William A. Kennington III0b111d42022-10-04 18:06:11 -070048std::vector<std::string> first_boot_status;
Patrick Williamsde333e12023-02-10 15:50:04 -060049nlohmann::json configJson;
William A. Kennington III0b111d42022-10-04 18:06:11 -070050
51void setFirstBootMACOnInterface(const std::string& intf, const std::string& mac)
52{
53 for (const auto& interface : manager->interfaces)
54 {
55 if (interface.first == intf)
56 {
57 auto returnMAC = interface.second->macAddress(mac);
58 if (returnMAC == mac)
59 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -070060 lg2::info(
61 "Setting MAC {MAC_ADDRESS} on interface {INTERFACE_NAME}",
62 "MAC_ADDRESS", mac, "INTERFACE_NAME", intf);
William A. Kennington III0b111d42022-10-04 18:06:11 -070063 std::error_code ec;
64 if (std::filesystem::is_directory("/var/lib/network", ec))
65 {
66 std::ofstream persistentFile(firstBootPath + intf);
67 }
68 break;
69 }
70 else
71 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -070072 lg2::info("MAC is Not Set on ethernet Interface");
William A. Kennington III0b111d42022-10-04 18:06:11 -070073 }
74 }
75 }
76}
77
78ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
79{
Patrick Williamsde333e12023-02-10 15:50:04 -060080 std::string interfaceName = configJson[intfName];
William A. Kennington III0b111d42022-10-04 18:06:11 -070081
82 std::vector<DbusInterface> interfaces;
83 interfaces.emplace_back(invNetworkIntf);
84
85 auto depth = 0;
86
Patrick Williams89d734b2023-05-10 07:50:25 -050087 auto mapperCall = bus.new_method_call(mapperBus, mapperObj, mapperIntf,
88 "GetSubTree");
William A. Kennington III0b111d42022-10-04 18:06:11 -070089
90 mapperCall.append(invRoot, depth, interfaces);
91
92 auto mapperReply = bus.call(mapperCall);
93 if (mapperReply.is_method_error())
94 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -070095 lg2::error("Error in mapper call");
William A. Kennington III0b111d42022-10-04 18:06:11 -070096 elog<InternalFailure>();
97 }
98
99 ObjectTree objectTree;
100 mapperReply.read(objectTree);
101
102 if (objectTree.empty())
103 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700104 lg2::error("No Object has implemented the interface {INTERFACE_NAME}",
105 "INTERFACE_NAME", invNetworkIntf);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700106 elog<InternalFailure>();
107 }
108
109 DbusObjectPath objPath;
110 DbusService service;
111
112 if (1 == objectTree.size())
113 {
114 objPath = objectTree.begin()->first;
115 service = objectTree.begin()->second.begin()->first;
116 }
117 else
118 {
119 // If there are more than 2 objects, object path must contain the
120 // interface name
Patrick Williams89d734b2023-05-10 07:50:25 -0500121 for (const auto& object : objectTree)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700122 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700123 lg2::info("Get info on interface {INTERFACE_NAME}, object {OBJECT}",
124 "INTERFACE_NAME", interfaceName, "OBJECT", object.first);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700125
126 if (std::string::npos != object.first.find(interfaceName.c_str()))
127 {
128 objPath = object.first;
129 service = object.second.begin()->first;
130 break;
131 }
132 }
133
134 if (objPath.empty())
135 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700136 lg2::error(
137 "Can't find the object for the interface {INTERFACE_NAME}",
138 "INTERFACE_NAME", interfaceName);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700139 elog<InternalFailure>();
140 }
141 }
142
143 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
144 propIntf, methodGet);
145
146 method.append(invNetworkIntf, "MACAddress");
147
148 auto reply = bus.call(method);
149 if (reply.is_method_error())
150 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700151 lg2::error("Failed to get MACAddress for path {PATH} interface "
152 "{INTERFACE_NAME}",
153 "PATH", objPath, "INTERFACE_NAME", invNetworkIntf);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700154 elog<InternalFailure>();
155 }
156
157 std::variant<std::string> value;
158 reply.read(value);
159 return ToAddr<ether_addr>{}(std::get<std::string>(value));
160}
161
Patrick Williamsde333e12023-02-10 15:50:04 -0600162bool setInventoryMACOnSystem(sdbusplus::bus_t& bus, const std::string& intfname)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700163{
164 try
165 {
166 auto inventoryMAC = getfromInventory(bus, intfname);
167 if (inventoryMAC != ether_addr{})
168 {
169 auto macStr = std::to_string(inventoryMAC);
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700170 lg2::info("Mac Address {MAC_ADDRESS} in Inventory on Interface "
171 "{INTERFACE_NAME}",
172 "MAC_ADDRESS", macStr, "INTERFACE_NAME", intfname);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700173 setFirstBootMACOnInterface(intfname, macStr);
174 first_boot_status.push_back(intfname);
175 bool status = true;
176 for (const auto& keys : configJson.items())
177 {
178 if (!(std::find(first_boot_status.begin(),
179 first_boot_status.end(),
180 keys.key()) != first_boot_status.end()))
181 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700182 lg2::info(
183 "Interface {INTERFACE_NAME} MAC is NOT set from VPD",
184 "INTERFACE_NAME", keys.key());
William A. Kennington III0b111d42022-10-04 18:06:11 -0700185 status = false;
186 }
187 }
188 if (status)
189 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700190 lg2::info("Removing the match for ethernet interfaces");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700191 EthInterfaceMatch = nullptr;
192 }
193 }
194 else
195 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700196 lg2::info("Nothing is present in Inventory");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700197 return false;
198 }
199 }
200 catch (const std::exception& e)
201 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700202 lg2::error("Exception occurred during getting of MAC "
203 "address from Inventory");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700204 return false;
205 }
206 return true;
207}
208
209// register the macthes to be monitored from inventory manager
Patrick Williamsde333e12023-02-10 15:50:04 -0600210void registerSignals(sdbusplus::bus_t& bus)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700211{
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700212 lg2::info("Registering the Inventory Signals Matcher");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700213
William A. Kennington III0b111d42022-10-04 18:06:11 -0700214 auto callback = [&](sdbusplus::message_t& m) {
215 std::map<DbusObjectPath,
216 std::map<DbusInterface, std::variant<PropertyValue>>>
217 interfacesProperties;
218
219 sdbusplus::message::object_path objPath;
220 m.read(objPath, interfacesProperties);
221
222 for (const auto& pattern : configJson.items())
223 {
224 if (objPath.str.find(pattern.value()) != std::string::npos)
225 {
226 for (auto& interface : interfacesProperties)
227 {
228 if (interface.first == invNetworkIntf)
229 {
230 for (const auto& property : interface.second)
231 {
232 if (property.first == "MACAddress")
233 {
234 setFirstBootMACOnInterface(
235 pattern.key(),
236 std::get<std::string>(property.second));
237 break;
238 }
239 }
240 break;
241 }
242 }
243 }
244 }
245 };
246
247 MacAddressMatch = std::make_unique<sdbusplus::bus::match_t>(
248 bus,
249 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
250 "member='InterfacesAdded',path='/xyz/openbmc_project/"
251 "inventory'",
252 callback);
253}
254
Patrick Williamsde333e12023-02-10 15:50:04 -0600255void watchEthernetInterface(sdbusplus::bus_t& bus)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700256{
Patrick Williamsde333e12023-02-10 15:50:04 -0600257 auto handle_interface = [&](auto infname) {
258 if (configJson.find(infname) == configJson.end())
259 {
260 // ethernet interface not found in configJSON
261 // check if it is not sit0 interface, as it is
262 // expected.
263 if (infname != "sit0")
264 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700265 lg2::error("Wrong Interface Name in Config Json");
Patrick Williamsde333e12023-02-10 15:50:04 -0600266 }
267 }
268 else
269 {
270 registerSignals(bus);
271 EthInterfaceMatch = nullptr;
272
273 if (setInventoryMACOnSystem(bus, infname))
274 {
275 MacAddressMatch = nullptr;
276 }
277 }
278 };
279
280 auto mycallback = [&, handle_interface](sdbusplus::message_t& m) {
William A. Kennington III0b111d42022-10-04 18:06:11 -0700281 std::map<DbusObjectPath,
282 std::map<DbusInterface, std::variant<PropertyValue>>>
283 interfacesProperties;
284
285 sdbusplus::message::object_path objPath;
286 std::pair<std::string, std::string> ethPair;
287 m.read(objPath, interfacesProperties);
Patrick Williamsde333e12023-02-10 15:50:04 -0600288
William A. Kennington III0b111d42022-10-04 18:06:11 -0700289 for (const auto& interfaces : interfacesProperties)
290 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700291 lg2::info("Check {INTERFACE_NAME} for sdbus response",
292 "INTERFACE_NAME", interfaces.first);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700293 if (interfaces.first ==
294 "xyz.openbmc_project.Network.EthernetInterface")
295 {
296 for (const auto& property : interfaces.second)
297 {
298 if (property.first == "InterfaceName")
299 {
Patrick Williamsde333e12023-02-10 15:50:04 -0600300 handle_interface(
301 std::get<std::string>(property.second));
William A. Kennington III0b111d42022-10-04 18:06:11 -0700302
William A. Kennington III0b111d42022-10-04 18:06:11 -0700303 break;
304 }
305 }
306 break;
307 }
308 }
309 };
310 // Incase if phosphor-inventory-manager started early and the VPD is already
311 // collected by the time network service has come up, better to check the
312 // VPD directly and set the MAC Address on the respective Interface.
313
314 bool registeredSignals = false;
315 for (const auto& interfaceString : configJson.items())
316 {
317 if ((FORCE_SYNC_MAC_FROM_INVENTORY ||
318 !std::filesystem::exists(firstBootPath + interfaceString.key())) &&
319 !registeredSignals)
320 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700321 lg2::info("Check VPD for MAC: {REASON}", "REASON",
322 (FORCE_SYNC_MAC_FROM_INVENTORY)
323 ? "Force sync enabled"
324 : "First boot file is not present");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700325 EthInterfaceMatch = std::make_unique<sdbusplus::bus::match_t>(
326 bus,
327 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
328 "member='InterfacesAdded',path='/xyz/openbmc_project/network'",
329 mycallback);
330 registeredSignals = true;
Patrick Williamsde333e12023-02-10 15:50:04 -0600331
332 for (const auto& intf : manager->interfaces)
333 {
334 if (intf.first == interfaceString.key())
335 {
336 handle_interface(intf.first);
337 }
338 }
William A. Kennington III0b111d42022-10-04 18:06:11 -0700339 }
340 }
341}
342
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800343std::unique_ptr<Runtime> watch(stdplus::PinnedRef<sdbusplus::bus_t> bus,
344 stdplus::PinnedRef<Manager> m)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700345{
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800346 manager = &m.get();
William A. Kennington III0b111d42022-10-04 18:06:11 -0700347 std::ifstream in(configFile);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700348 in >> configJson;
Patrick Williamsde333e12023-02-10 15:50:04 -0600349 watchEthernetInterface(bus);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700350 return nullptr;
351}
352
353} // namespace phosphor::network::inventory