1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2022-2024. All rights
3 * reserved. SPDX-License-Identifier: Apache-2.0
4 */
5 #include "config_provider.hpp"
6
7 #include <boost/container/flat_map.hpp>
8 #include <phosphor-logging/lg2.hpp>
9 #include <sdbusplus/async/match.hpp>
10 #include <sdbusplus/bus/match.hpp>
11 #include <xyz/openbmc_project/ObjectMapper/client.hpp>
12
13 #include <ranges>
14 #include <string>
15
16 PHOSPHOR_LOG2_USING;
17
18 using VariantType =
19 std::variant<std::vector<std::string>, std::string, int64_t, uint64_t,
20 double, int32_t, uint32_t, int16_t, uint16_t, uint8_t, bool>;
21 using ConfigMap = boost::container::flat_map<std::string, VariantType>;
22 using ConfigData = boost::container::flat_map<std::string, ConfigMap>;
23
24 namespace gpio_presence
25 {
26
ConfigProvider(sdbusplus::async::context & ctx,const std::string & interface)27 ConfigProvider::ConfigProvider(sdbusplus::async::context& ctx,
28 const std::string& interface) :
29 interface(interface), ctx(ctx)
30 {}
31
initialize(AddedCallback addConfig,RemovedCallback removeConfig)32 auto ConfigProvider::initialize(AddedCallback addConfig,
33 RemovedCallback removeConfig)
34 -> sdbusplus::async::task<void>
35 {
36 ctx.spawn(handleInterfacesAdded(addConfig));
37 ctx.spawn(handleInterfacesRemoved(removeConfig));
38
39 co_await getConfig(addConfig);
40 }
41
getConfig(AddedCallback addConfig)42 auto ConfigProvider::getConfig(AddedCallback addConfig)
43 -> sdbusplus::async::task<void>
44 {
45 auto client = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>(ctx)
46 .service("xyz.openbmc_project.ObjectMapper")
47 .path("/xyz/openbmc_project/object_mapper");
48
49 debug("calling 'GetSubTree' to find instances of {INTF}", "INTF",
50 interface);
51
52 using SubTreeType =
53 std::map<std::string, std::map<std::string, std::vector<std::string>>>;
54 SubTreeType res = {};
55
56 try
57 {
58 std::vector<std::string> interfaces = {interface};
59 res = co_await client.get_sub_tree("/xyz/openbmc_project/inventory", 0,
60 interfaces);
61 }
62 catch (std::exception& e)
63 {
64 error("Failed GetSubTree call for configuration interface: {ERR}",
65 "ERR", e);
66 }
67
68 if (res.empty())
69 {
70 co_return;
71 }
72
73 // call the user callback for all the device that is already available
74 for (auto& [path, serviceInterfaceMap] : res)
75 {
76 for (const auto& service :
77 std::ranges::views::keys(serviceInterfaceMap))
78 {
79 debug("found configuration interface at {SERVICE} {PATH} {INTF}",
80 "SERVICE", service, "PATH", path, "INTF", interface);
81
82 addConfig(path);
83 }
84 }
85 }
86
87 namespace rules_intf = sdbusplus::bus::match::rules;
88
89 const auto senderRule = rules_intf::sender("xyz.openbmc_project.EntityManager");
90
handleInterfacesAdded(AddedCallback addConfig)91 auto ConfigProvider::handleInterfacesAdded(AddedCallback addConfig)
92 -> sdbusplus::async::task<void>
93 {
94 debug("setting up dbus match for interfaces added");
95
96 sdbusplus::async::match addedMatch(
97 ctx, rules_intf::interfacesAdded() + senderRule);
98
99 while (!ctx.stop_requested())
100 {
101 auto [objPath, intfMap] =
102 co_await addedMatch
103 .next<sdbusplus::message::object_path, ConfigData>();
104
105 debug("Detected interface added on {OBJPATH}", "OBJPATH", objPath);
106
107 if (!std::ranges::contains(std::views::keys(intfMap), interface))
108 {
109 continue;
110 }
111
112 try
113 {
114 addConfig(objPath);
115 }
116 catch (std::exception& e)
117 {
118 error("Incomplete or invalid config found: {ERR}", "ERR", e);
119 }
120 }
121 };
122
handleInterfacesRemoved(RemovedCallback removeConfig)123 auto ConfigProvider::handleInterfacesRemoved(RemovedCallback removeConfig)
124 -> sdbusplus::async::task<void>
125 {
126 debug("setting up dbus match for interfaces removed");
127
128 sdbusplus::async::match removedMatch(
129 ctx, rules_intf::interfacesRemoved() + senderRule);
130
131 while (!ctx.stop_requested())
132 {
133 auto [objectPath, interfaces] =
134 co_await removedMatch.next<sdbusplus::message::object_path,
135 std::vector<std::string>>();
136
137 if (!std::ranges::contains(interfaces, interface))
138 {
139 continue;
140 }
141
142 debug("Detected interface {INTF} removed on {OBJPATH}", "INTF",
143 interface, "OBJPATH", objectPath);
144
145 removeConfig(objectPath);
146 }
147 };
148
149 } // namespace gpio_presence
150