blob: f865a78282bf493f01dbac43ff98954e571d0aa6 [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 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -070060 lg2::info("Setting MAC {NET_MAC} on interface {NET_INTF}",
61 "NET_MAC", mac, "NET_INTF", intf);
William A. Kennington III0b111d42022-10-04 18:06:11 -070062 std::error_code ec;
63 if (std::filesystem::is_directory("/var/lib/network", ec))
64 {
65 std::ofstream persistentFile(firstBootPath + intf);
66 }
67 break;
68 }
69 else
70 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -070071 lg2::info("MAC is Not Set on ethernet Interface");
William A. Kennington III0b111d42022-10-04 18:06:11 -070072 }
73 }
74 }
75}
76
77ether_addr getfromInventory(sdbusplus::bus_t& bus, const std::string& intfName)
78{
Patrick Williamsde333e12023-02-10 15:50:04 -060079 std::string interfaceName = configJson[intfName];
William A. Kennington III0b111d42022-10-04 18:06:11 -070080
81 std::vector<DbusInterface> interfaces;
82 interfaces.emplace_back(invNetworkIntf);
83
84 auto depth = 0;
85
Patrick Williams89d734b2023-05-10 07:50:25 -050086 auto mapperCall = bus.new_method_call(mapperBus, mapperObj, mapperIntf,
87 "GetSubTree");
William A. Kennington III0b111d42022-10-04 18:06:11 -070088
89 mapperCall.append(invRoot, depth, interfaces);
90
91 auto mapperReply = bus.call(mapperCall);
92 if (mapperReply.is_method_error())
93 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -070094 lg2::error("Error in mapper call");
William A. Kennington III0b111d42022-10-04 18:06:11 -070095 elog<InternalFailure>();
96 }
97
98 ObjectTree objectTree;
99 mapperReply.read(objectTree);
100
101 if (objectTree.empty())
102 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700103 lg2::error("No Object has implemented the interface {NET_INTF}",
104 "NET_INTF", invNetworkIntf);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700105 elog<InternalFailure>();
106 }
107
108 DbusObjectPath objPath;
109 DbusService service;
110
111 if (1 == objectTree.size())
112 {
113 objPath = objectTree.begin()->first;
114 service = objectTree.begin()->second.begin()->first;
115 }
116 else
117 {
118 // If there are more than 2 objects, object path must contain the
119 // interface name
Patrick Williams89d734b2023-05-10 07:50:25 -0500120 for (const auto& object : objectTree)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700121 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700122 lg2::info("Get info on interface {NET_INTF}, object {OBJ}",
123 "NET_INTF", interfaceName, "OBJ", object.first);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700124
125 if (std::string::npos != object.first.find(interfaceName.c_str()))
126 {
127 objPath = object.first;
128 service = object.second.begin()->first;
129 break;
130 }
131 }
132
133 if (objPath.empty())
134 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700135 lg2::error("Can't find the object for the interface {NET_INTF}",
136 "NET_INTF", interfaceName);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700137 elog<InternalFailure>();
138 }
139 }
140
141 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
142 propIntf, methodGet);
143
144 method.append(invNetworkIntf, "MACAddress");
145
146 auto reply = bus.call(method);
147 if (reply.is_method_error())
148 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700149 lg2::error(
150 "Failed to get MACAddress for path {DBUS_PATH} interface {DBUS_INTF}",
151 "DBUS_PATH", objPath, "DBUS_INTF", invNetworkIntf);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700152 elog<InternalFailure>();
153 }
154
155 std::variant<std::string> value;
156 reply.read(value);
157 return ToAddr<ether_addr>{}(std::get<std::string>(value));
158}
159
Patrick Williamsde333e12023-02-10 15:50:04 -0600160bool setInventoryMACOnSystem(sdbusplus::bus_t& bus, const std::string& intfname)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700161{
162 try
163 {
164 auto inventoryMAC = getfromInventory(bus, intfname);
165 if (inventoryMAC != ether_addr{})
166 {
167 auto macStr = std::to_string(inventoryMAC);
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700168 lg2::info(
169 "Mac Address {NET_MAC} in Inventory on Interface {NET_INTF}",
170 "NET_MAC", macStr, "NET_INTF", intfname);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700171 setFirstBootMACOnInterface(intfname, macStr);
172 first_boot_status.push_back(intfname);
173 bool status = true;
174 for (const auto& keys : configJson.items())
175 {
176 if (!(std::find(first_boot_status.begin(),
177 first_boot_status.end(),
178 keys.key()) != first_boot_status.end()))
179 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700180 lg2::info("Interface {NET_INTF} MAC is NOT set from VPD",
181 "NET_INTF", keys.key());
William A. Kennington III0b111d42022-10-04 18:06:11 -0700182 status = false;
183 }
184 }
185 if (status)
186 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700187 lg2::info("Removing the match for ethernet interfaces");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700188 EthInterfaceMatch = nullptr;
189 }
190 }
191 else
192 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700193 lg2::info("Nothing is present in Inventory");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700194 return false;
195 }
196 }
197 catch (const std::exception& e)
198 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700199 lg2::error("Exception occurred during getting of MAC "
200 "address from Inventory");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700201 return false;
202 }
203 return true;
204}
205
206// register the macthes to be monitored from inventory manager
Patrick Williamsde333e12023-02-10 15:50:04 -0600207void registerSignals(sdbusplus::bus_t& bus)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700208{
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700209 lg2::info("Registering the Inventory Signals Matcher");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700210
William A. Kennington III0b111d42022-10-04 18:06:11 -0700211 auto callback = [&](sdbusplus::message_t& m) {
212 std::map<DbusObjectPath,
213 std::map<DbusInterface, std::variant<PropertyValue>>>
214 interfacesProperties;
215
216 sdbusplus::message::object_path objPath;
217 m.read(objPath, interfacesProperties);
218
219 for (const auto& pattern : configJson.items())
220 {
221 if (objPath.str.find(pattern.value()) != std::string::npos)
222 {
223 for (auto& interface : interfacesProperties)
224 {
225 if (interface.first == invNetworkIntf)
226 {
227 for (const auto& property : interface.second)
228 {
229 if (property.first == "MACAddress")
230 {
231 setFirstBootMACOnInterface(
232 pattern.key(),
233 std::get<std::string>(property.second));
234 break;
235 }
236 }
237 break;
238 }
239 }
240 }
241 }
242 };
243
244 MacAddressMatch = std::make_unique<sdbusplus::bus::match_t>(
245 bus,
246 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
247 "member='InterfacesAdded',path='/xyz/openbmc_project/"
248 "inventory'",
249 callback);
250}
251
Patrick Williamsde333e12023-02-10 15:50:04 -0600252void watchEthernetInterface(sdbusplus::bus_t& bus)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700253{
Patrick Williamsde333e12023-02-10 15:50:04 -0600254 auto handle_interface = [&](auto infname) {
255 if (configJson.find(infname) == configJson.end())
256 {
257 // ethernet interface not found in configJSON
258 // check if it is not sit0 interface, as it is
259 // expected.
260 if (infname != "sit0")
261 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700262 lg2::error("Wrong Interface Name in Config Json");
Patrick Williamsde333e12023-02-10 15:50:04 -0600263 }
264 }
265 else
266 {
267 registerSignals(bus);
268 EthInterfaceMatch = nullptr;
269
270 if (setInventoryMACOnSystem(bus, infname))
271 {
272 MacAddressMatch = nullptr;
273 }
274 }
275 };
276
277 auto mycallback = [&, handle_interface](sdbusplus::message_t& m) {
William A. Kennington III0b111d42022-10-04 18:06:11 -0700278 std::map<DbusObjectPath,
279 std::map<DbusInterface, std::variant<PropertyValue>>>
280 interfacesProperties;
281
282 sdbusplus::message::object_path objPath;
283 std::pair<std::string, std::string> ethPair;
284 m.read(objPath, interfacesProperties);
Patrick Williamsde333e12023-02-10 15:50:04 -0600285
William A. Kennington III0b111d42022-10-04 18:06:11 -0700286 for (const auto& interfaces : interfacesProperties)
287 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700288 lg2::info("Check {DBUS_INTF} for sdbus response", "DBUS_INTF",
289 interfaces.first);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700290 if (interfaces.first ==
291 "xyz.openbmc_project.Network.EthernetInterface")
292 {
293 for (const auto& property : interfaces.second)
294 {
295 if (property.first == "InterfaceName")
296 {
Patrick Williamsde333e12023-02-10 15:50:04 -0600297 handle_interface(
298 std::get<std::string>(property.second));
William A. Kennington III0b111d42022-10-04 18:06:11 -0700299
William A. Kennington III0b111d42022-10-04 18:06:11 -0700300 break;
301 }
302 }
303 break;
304 }
305 }
306 };
307 // Incase if phosphor-inventory-manager started early and the VPD is already
308 // collected by the time network service has come up, better to check the
309 // VPD directly and set the MAC Address on the respective Interface.
310
311 bool registeredSignals = false;
312 for (const auto& interfaceString : configJson.items())
313 {
314 if ((FORCE_SYNC_MAC_FROM_INVENTORY ||
315 !std::filesystem::exists(firstBootPath + interfaceString.key())) &&
316 !registeredSignals)
317 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700318 lg2::info("Check VPD for MAC: {REASON}", "REASON",
319 (FORCE_SYNC_MAC_FROM_INVENTORY)
320 ? "Force sync enabled"
321 : "First boot file is not present");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700322 EthInterfaceMatch = std::make_unique<sdbusplus::bus::match_t>(
323 bus,
324 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
325 "member='InterfacesAdded',path='/xyz/openbmc_project/network'",
326 mycallback);
327 registeredSignals = true;
Patrick Williamsde333e12023-02-10 15:50:04 -0600328
329 for (const auto& intf : manager->interfaces)
330 {
331 if (intf.first == interfaceString.key())
332 {
333 handle_interface(intf.first);
334 }
335 }
William A. Kennington III0b111d42022-10-04 18:06:11 -0700336 }
337 }
338}
339
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800340std::unique_ptr<Runtime> watch(stdplus::PinnedRef<sdbusplus::bus_t> bus,
341 stdplus::PinnedRef<Manager> m)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700342{
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800343 manager = &m.get();
William A. Kennington III0b111d42022-10-04 18:06:11 -0700344 std::ifstream in(configFile);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700345 in >> configJson;
Patrick Williamsde333e12023-02-10 15:50:04 -0600346 watchEthernetInterface(bus);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700347 return nullptr;
348}
349
350} // namespace phosphor::network::inventory