blob: 67e8dff1f1f7125e45b60553e8741bc1026b1d63 [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>
William A. Kennington III60903ee2023-06-02 15:17:49 -070013#include <stdplus/str/maps.hpp>
Patrick Williams89d734b2023-05-10 07:50:25 -050014#include <xyz/openbmc_project/Common/error.hpp>
15
16#include <filesystem>
17#include <fstream>
18#include <memory>
William A. Kennington III0b111d42022-10-04 18:06:11 -070019#include <string>
20#include <vector>
William A. Kennington III0b111d42022-10-04 18:06:11 -070021
22namespace phosphor::network::inventory
23{
24
25using phosphor::logging::elog;
William A. Kennington III0b111d42022-10-04 18:06:11 -070026using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
27
28using DbusObjectPath = std::string;
29using DbusInterface = std::string;
30using PropertyValue = std::string;
31using DbusService = std::string;
William A. Kennington III60903ee2023-06-02 15:17:49 -070032using ObjectTree =
33 stdplus::string_umap<stdplus::string_umap<std::vector<std::string>>>;
William A. Kennington III0b111d42022-10-04 18:06:11 -070034
35constexpr auto firstBootPath = "/var/lib/network/firstBoot_";
36constexpr auto configFile = "/usr/share/network/config.json";
37
38constexpr auto invNetworkIntf =
39 "xyz.openbmc_project.Inventory.Item.NetworkInterface";
40constexpr auto invRoot = "/xyz/openbmc_project/inventory";
41constexpr auto mapperBus = "xyz.openbmc_project.ObjectMapper";
42constexpr auto mapperObj = "/xyz/openbmc_project/object_mapper";
43constexpr auto mapperIntf = "xyz.openbmc_project.ObjectMapper";
44constexpr auto propIntf = "org.freedesktop.DBus.Properties";
45constexpr auto methodGet = "Get";
46
47Manager* manager = nullptr;
48std::unique_ptr<sdbusplus::bus::match_t> EthInterfaceMatch = nullptr;
Patrick Williamsde333e12023-02-10 15:50:04 -060049std::unique_ptr<sdbusplus::bus::match_t> MacAddressMatch = nullptr;
William A. Kennington III0b111d42022-10-04 18:06:11 -070050std::vector<std::string> first_boot_status;
Patrick Williamsde333e12023-02-10 15:50:04 -060051nlohmann::json configJson;
William A. Kennington III0b111d42022-10-04 18:06:11 -070052
53void setFirstBootMACOnInterface(const std::string& intf, const std::string& mac)
54{
55 for (const auto& interface : manager->interfaces)
56 {
57 if (interface.first == intf)
58 {
59 auto returnMAC = interface.second->macAddress(mac);
60 if (returnMAC == mac)
61 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -070062 lg2::info("Setting MAC {NET_MAC} on interface {NET_INTF}",
63 "NET_MAC", mac, "NET_INTF", intf);
William A. Kennington III0b111d42022-10-04 18:06:11 -070064 std::error_code ec;
65 if (std::filesystem::is_directory("/var/lib/network", ec))
66 {
67 std::ofstream persistentFile(firstBootPath + intf);
68 }
69 break;
70 }
71 else
72 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -070073 lg2::info("MAC is Not Set on ethernet Interface");
William A. Kennington III0b111d42022-10-04 18:06:11 -070074 }
75 }
76 }
77}
78
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -070079stdplus::EtherAddr getfromInventory(sdbusplus::bus_t& bus,
80 const std::string& intfName)
William A. Kennington III0b111d42022-10-04 18:06:11 -070081{
Patrick Williamsde333e12023-02-10 15:50:04 -060082 std::string interfaceName = configJson[intfName];
William A. Kennington III0b111d42022-10-04 18:06:11 -070083
84 std::vector<DbusInterface> interfaces;
85 interfaces.emplace_back(invNetworkIntf);
86
87 auto depth = 0;
88
Patrick Williamsad205022024-08-16 15:20:07 -040089 auto mapperCall =
90 bus.new_method_call(mapperBus, mapperObj, mapperIntf, "GetSubTree");
William A. Kennington III0b111d42022-10-04 18:06:11 -070091
92 mapperCall.append(invRoot, depth, interfaces);
93
Patrick Williams3c4f35e2025-11-04 22:51:04 -050094 auto mapperReply = [&]() {
95 try
96 {
97 return bus.call(mapperCall);
98 }
99 catch (const sdbusplus::exception::SdBusError& e)
100 {
101 lg2::error("Error in mapper call");
102 elog<InternalFailure>();
103 }
104 }();
William A. Kennington III0b111d42022-10-04 18:06:11 -0700105
106 ObjectTree objectTree;
107 mapperReply.read(objectTree);
108
109 if (objectTree.empty())
110 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700111 lg2::error("No Object has implemented the interface {NET_INTF}",
112 "NET_INTF", invNetworkIntf);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700113 elog<InternalFailure>();
114 }
115
116 DbusObjectPath objPath;
117 DbusService service;
118
119 if (1 == objectTree.size())
120 {
121 objPath = objectTree.begin()->first;
122 service = objectTree.begin()->second.begin()->first;
123 }
124 else
125 {
126 // If there are more than 2 objects, object path must contain the
127 // interface name
Patrick Williams89d734b2023-05-10 07:50:25 -0500128 for (const auto& object : objectTree)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700129 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700130 lg2::info("Get info on interface {NET_INTF}, object {OBJ}",
131 "NET_INTF", interfaceName, "OBJ", object.first);
Anderson Kuoef080362025-06-05 19:12:37 +0800132 if (object.first.ends_with("/" + interfaceName))
William A. Kennington III0b111d42022-10-04 18:06:11 -0700133 {
134 objPath = object.first;
135 service = object.second.begin()->first;
136 break;
137 }
138 }
139
140 if (objPath.empty())
141 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700142 lg2::error("Can't find the object for the interface {NET_INTF}",
143 "NET_INTF", interfaceName);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700144 elog<InternalFailure>();
145 }
146 }
147
148 auto method = bus.new_method_call(service.c_str(), objPath.c_str(),
149 propIntf, methodGet);
150
151 method.append(invNetworkIntf, "MACAddress");
152
Patrick Williams3c4f35e2025-11-04 22:51:04 -0500153 auto reply = [&]() {
154 try
155 {
156 return bus.call(method);
157 }
158 catch (const sdbusplus::exception::SdBusError& e)
159 {
160 lg2::error(
161 "Failed to get MACAddress for path {DBUS_PATH} interface {DBUS_INTF}",
162 "DBUS_PATH", objPath, "DBUS_INTF", invNetworkIntf);
163 elog<InternalFailure>();
164 }
165 }();
William A. Kennington III0b111d42022-10-04 18:06:11 -0700166
167 std::variant<std::string> value;
168 reply.read(value);
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700169 return stdplus::fromStr<stdplus::EtherAddr>(std::get<std::string>(value));
William A. Kennington III0b111d42022-10-04 18:06:11 -0700170}
171
Patrick Williamsde333e12023-02-10 15:50:04 -0600172bool setInventoryMACOnSystem(sdbusplus::bus_t& bus, const std::string& intfname)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700173{
174 try
175 {
176 auto inventoryMAC = getfromInventory(bus, intfname);
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700177 if (inventoryMAC != stdplus::EtherAddr{})
William A. Kennington III0b111d42022-10-04 18:06:11 -0700178 {
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700179 auto macStr = stdplus::toStr(inventoryMAC);
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700180 lg2::info(
181 "Mac Address {NET_MAC} in Inventory on Interface {NET_INTF}",
182 "NET_MAC", macStr, "NET_INTF", intfname);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700183 setFirstBootMACOnInterface(intfname, macStr);
184 first_boot_status.push_back(intfname);
185 bool status = true;
186 for (const auto& keys : configJson.items())
187 {
188 if (!(std::find(first_boot_status.begin(),
Patrick Williamsad205022024-08-16 15:20:07 -0400189 first_boot_status.end(), keys.key()) !=
190 first_boot_status.end()))
William A. Kennington III0b111d42022-10-04 18:06:11 -0700191 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700192 lg2::info("Interface {NET_INTF} MAC is NOT set from VPD",
193 "NET_INTF", keys.key());
William A. Kennington III0b111d42022-10-04 18:06:11 -0700194 status = false;
195 }
196 }
197 if (status)
198 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700199 lg2::info("Removing the match for ethernet interfaces");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700200 EthInterfaceMatch = nullptr;
201 }
202 }
203 else
204 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700205 lg2::info("Nothing is present in Inventory");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700206 return false;
207 }
208 }
209 catch (const std::exception& e)
210 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700211 lg2::error("Exception occurred during getting of MAC "
212 "address from Inventory");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700213 return false;
214 }
215 return true;
216}
217
Manojkiran Edad92826d2024-06-17 14:43:14 +0530218// register the matches to be monitored from inventory manager
Patrick Williamsde333e12023-02-10 15:50:04 -0600219void registerSignals(sdbusplus::bus_t& bus)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700220{
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700221 lg2::info("Registering the Inventory Signals Matcher");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700222
William A. Kennington III0b111d42022-10-04 18:06:11 -0700223 auto callback = [&](sdbusplus::message_t& m) {
224 std::map<DbusObjectPath,
225 std::map<DbusInterface, std::variant<PropertyValue>>>
226 interfacesProperties;
227
228 sdbusplus::message::object_path objPath;
229 m.read(objPath, interfacesProperties);
230
231 for (const auto& pattern : configJson.items())
232 {
Anderson Kuoef080362025-06-05 19:12:37 +0800233 if (objPath.str.ends_with("/" + pattern.value().get<std::string>()))
William A. Kennington III0b111d42022-10-04 18:06:11 -0700234 {
235 for (auto& interface : interfacesProperties)
236 {
237 if (interface.first == invNetworkIntf)
238 {
239 for (const auto& property : interface.second)
240 {
241 if (property.first == "MACAddress")
242 {
Chanh Nguyen947454b2024-09-11 09:37:23 +0000243 // Only set mac address on interface once the
244 // firstboot file does not exist or it is being
245 // FORCE_SYNC_MAC_FROM_INVENTORY
246 if (FORCE_SYNC_MAC_FROM_INVENTORY ||
247 !std::filesystem::exists(
248 firstBootPath + pattern.key()))
249 {
250 setFirstBootMACOnInterface(
251 pattern.key(),
252 std::get<std::string>(property.second));
253 }
William A. Kennington III0b111d42022-10-04 18:06:11 -0700254 break;
255 }
256 }
257 break;
258 }
259 }
260 }
261 }
262 };
263
264 MacAddressMatch = std::make_unique<sdbusplus::bus::match_t>(
265 bus,
266 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
267 "member='InterfacesAdded',path='/xyz/openbmc_project/"
268 "inventory'",
269 callback);
270}
271
Patrick Williamsde333e12023-02-10 15:50:04 -0600272void watchEthernetInterface(sdbusplus::bus_t& bus)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700273{
Patrick Williamsde333e12023-02-10 15:50:04 -0600274 auto handle_interface = [&](auto infname) {
275 if (configJson.find(infname) == configJson.end())
276 {
277 // ethernet interface not found in configJSON
278 // check if it is not sit0 interface, as it is
279 // expected.
280 if (infname != "sit0")
281 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700282 lg2::error("Wrong Interface Name in Config Json");
Patrick Williamsde333e12023-02-10 15:50:04 -0600283 }
284 }
285 else
286 {
287 registerSignals(bus);
Patrick Williamsde333e12023-02-10 15:50:04 -0600288
289 if (setInventoryMACOnSystem(bus, infname))
290 {
291 MacAddressMatch = nullptr;
292 }
293 }
294 };
295
296 auto mycallback = [&, handle_interface](sdbusplus::message_t& m) {
William A. Kennington III0b111d42022-10-04 18:06:11 -0700297 std::map<DbusObjectPath,
298 std::map<DbusInterface, std::variant<PropertyValue>>>
299 interfacesProperties;
300
301 sdbusplus::message::object_path objPath;
302 std::pair<std::string, std::string> ethPair;
303 m.read(objPath, interfacesProperties);
Patrick Williamsde333e12023-02-10 15:50:04 -0600304
William A. Kennington III0b111d42022-10-04 18:06:11 -0700305 for (const auto& interfaces : interfacesProperties)
306 {
William A. Kennington III1d25ca42023-05-30 16:55:28 -0700307 lg2::info("Check {DBUS_INTF} for sdbus response", "DBUS_INTF",
308 interfaces.first);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700309 if (interfaces.first ==
310 "xyz.openbmc_project.Network.EthernetInterface")
311 {
312 for (const auto& property : interfaces.second)
313 {
314 if (property.first == "InterfaceName")
315 {
Patrick Williamsde333e12023-02-10 15:50:04 -0600316 handle_interface(
317 std::get<std::string>(property.second));
William A. Kennington III0b111d42022-10-04 18:06:11 -0700318
William A. Kennington III0b111d42022-10-04 18:06:11 -0700319 break;
320 }
321 }
322 break;
323 }
324 }
325 };
Manojkiran Edad92826d2024-06-17 14:43:14 +0530326
327 // The VPD may already have been assigned because phosphor-inventory-manager
328 // started ahead of the network service. Read the VPD directly and assign
329 // the MAC address despite this possibility.
William A. Kennington III0b111d42022-10-04 18:06:11 -0700330
William A. Kennington III0b111d42022-10-04 18:06:11 -0700331 for (const auto& interfaceString : configJson.items())
332 {
Asmitha Karunanithi2eec06d2023-09-13 10:50:50 -0500333 if (FORCE_SYNC_MAC_FROM_INVENTORY ||
334 !std::filesystem::exists(firstBootPath + interfaceString.key()))
William A. Kennington III0b111d42022-10-04 18:06:11 -0700335 {
Jagpal Singh Gill49f9d252023-04-17 15:15:39 -0700336 lg2::info("Check VPD for MAC: {REASON}", "REASON",
337 (FORCE_SYNC_MAC_FROM_INVENTORY)
338 ? "Force sync enabled"
339 : "First boot file is not present");
William A. Kennington III0b111d42022-10-04 18:06:11 -0700340 EthInterfaceMatch = std::make_unique<sdbusplus::bus::match_t>(
341 bus,
342 "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
343 "member='InterfacesAdded',path='/xyz/openbmc_project/network'",
344 mycallback);
Patrick Williamsde333e12023-02-10 15:50:04 -0600345
346 for (const auto& intf : manager->interfaces)
347 {
348 if (intf.first == interfaceString.key())
349 {
350 handle_interface(intf.first);
351 }
352 }
William A. Kennington III0b111d42022-10-04 18:06:11 -0700353 }
354 }
355}
356
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800357std::unique_ptr<Runtime> watch(stdplus::PinnedRef<sdbusplus::bus_t> bus,
358 stdplus::PinnedRef<Manager> m)
William A. Kennington III0b111d42022-10-04 18:06:11 -0700359{
William A. Kennington III9ede1b72022-11-21 01:59:28 -0800360 manager = &m.get();
William A. Kennington III0b111d42022-10-04 18:06:11 -0700361 std::ifstream in(configFile);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700362 in >> configJson;
Patrick Williamsde333e12023-02-10 15:50:04 -0600363 watchEthernetInterface(bus);
William A. Kennington III0b111d42022-10-04 18:06:11 -0700364 return nullptr;
365}
366
367} // namespace phosphor::network::inventory