xref: /openbmc/bmcweb/features/redfish/lib/redfish_util.hpp (revision deae6a789444debc4724fb6902fc5def299afbee)
1c5d03ff4SJennifer Lee /*
26be832e2SEd Tanous Copyright (c) 2019 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
15c5d03ff4SJennifer Lee */
16c5d03ff4SJennifer Lee #pragma once
17c5d03ff4SJennifer Lee 
183ccb3adbSEd Tanous #include "async_resp.hpp"
193ccb3adbSEd Tanous #include "dbus_utility.hpp"
203ccb3adbSEd Tanous #include "error_messages.hpp"
213ccb3adbSEd Tanous 
22e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
23cf7eba09SNan Zhou #include <sdbusplus/asio/property.hpp>
24cf7eba09SNan Zhou 
25e99073f5SGeorge Liu #include <array>
26cf7eba09SNan Zhou #include <charconv>
273544d2a7SEd Tanous #include <ranges>
28e99073f5SGeorge Liu #include <string_view>
29cf7eba09SNan Zhou 
30c5d03ff4SJennifer Lee namespace redfish
31c5d03ff4SJennifer Lee {
32c5d03ff4SJennifer Lee 
33b4bec66bSAbhishek Patel enum NetworkProtocolUnitStructFields
34b4bec66bSAbhishek Patel {
35b4bec66bSAbhishek Patel     NET_PROTO_UNIT_NAME,
36b4bec66bSAbhishek Patel     NET_PROTO_UNIT_DESC,
37b4bec66bSAbhishek Patel     NET_PROTO_UNIT_LOAD_STATE,
38b4bec66bSAbhishek Patel     NET_PROTO_UNIT_ACTIVE_STATE,
39b4bec66bSAbhishek Patel     NET_PROTO_UNIT_SUB_STATE,
40b4bec66bSAbhishek Patel     NET_PROTO_UNIT_DEVICE,
41b4bec66bSAbhishek Patel     NET_PROTO_UNIT_OBJ_PATH,
42b4bec66bSAbhishek Patel     NET_PROTO_UNIT_ALWAYS_0,
43b4bec66bSAbhishek Patel     NET_PROTO_UNIT_ALWAYS_EMPTY,
44b4bec66bSAbhishek Patel     NET_PROTO_UNIT_ALWAYS_ROOT_PATH
45b4bec66bSAbhishek Patel };
46b4bec66bSAbhishek Patel 
47b4bec66bSAbhishek Patel enum NetworkProtocolListenResponseElements
48b4bec66bSAbhishek Patel {
49b4bec66bSAbhishek Patel     NET_PROTO_LISTEN_TYPE,
50b4bec66bSAbhishek Patel     NET_PROTO_LISTEN_STREAM
51b4bec66bSAbhishek Patel };
52b4bec66bSAbhishek Patel 
53b4bec66bSAbhishek Patel /**
54b4bec66bSAbhishek Patel  * @brief D-Bus Unit structure returned in array from ListUnits Method
55b4bec66bSAbhishek Patel  */
56b4bec66bSAbhishek Patel using UnitStruct =
57b4bec66bSAbhishek Patel     std::tuple<std::string, std::string, std::string, std::string, std::string,
58b4bec66bSAbhishek Patel                std::string, sdbusplus::message::object_path, uint32_t,
59b4bec66bSAbhishek Patel                std::string, sdbusplus::message::object_path>;
60b4bec66bSAbhishek Patel 
61c5d03ff4SJennifer Lee template <typename CallbackFunc>
628d1b46d7Szhanghch05 void getMainChassisId(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
63c5d03ff4SJennifer Lee                       CallbackFunc&& callback)
64c5d03ff4SJennifer Lee {
65c5d03ff4SJennifer Lee     // Find managed chassis
66e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
67e99073f5SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Board",
68e99073f5SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Chassis"};
69e99073f5SGeorge Liu     dbus::utility::getSubTree(
70e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
718cb2c024SEd Tanous         [callback = std::forward<CallbackFunc>(callback),
72e99073f5SGeorge Liu          asyncResp](const boost::system::error_code& ec,
73b9d36b47SEd Tanous                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
74c5d03ff4SJennifer Lee             if (ec)
75c5d03ff4SJennifer Lee             {
7662598e31SEd Tanous                 BMCWEB_LOG_ERROR("{}", ec);
77c5d03ff4SJennifer Lee                 return;
78c5d03ff4SJennifer Lee             }
7926f6976fSEd Tanous             if (subtree.empty())
80c5d03ff4SJennifer Lee             {
8162598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Can't find chassis!");
82c5d03ff4SJennifer Lee                 return;
83c5d03ff4SJennifer Lee             }
84c5d03ff4SJennifer Lee 
85f23b7296SEd Tanous             std::size_t idPos = subtree[0].first.rfind('/');
86c5d03ff4SJennifer Lee             if (idPos == std::string::npos ||
87c5d03ff4SJennifer Lee                 (idPos + 1) >= subtree[0].first.size())
88c5d03ff4SJennifer Lee             {
89c5d03ff4SJennifer Lee                 messages::internalError(asyncResp->res);
9062598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Can't parse chassis ID!");
91c5d03ff4SJennifer Lee                 return;
92c5d03ff4SJennifer Lee             }
93c5d03ff4SJennifer Lee             std::string chassisId = subtree[0].first.substr(idPos + 1);
9462598e31SEd Tanous             BMCWEB_LOG_DEBUG("chassisId = {}", chassisId);
95c5d03ff4SJennifer Lee             callback(chassisId, asyncResp);
96e99073f5SGeorge Liu         });
97c5d03ff4SJennifer Lee }
98b4bec66bSAbhishek Patel 
99b4bec66bSAbhishek Patel template <typename CallbackFunc>
1005c3e9272SAbhishek Patel void getPortStatusAndPath(
1015c3e9272SAbhishek Patel     std::span<const std::pair<std::string_view, std::string_view>>
1025c3e9272SAbhishek Patel         protocolToDBus,
103b4bec66bSAbhishek Patel     CallbackFunc&& callback)
104b4bec66bSAbhishek Patel {
105b4bec66bSAbhishek Patel     crow::connections::systemBus->async_method_call(
1068cb2c024SEd Tanous         [protocolToDBus, callback = std::forward<CallbackFunc>(callback)](
1075e7e2dc5SEd Tanous             const boost::system::error_code& ec,
108b4bec66bSAbhishek Patel             const std::vector<UnitStruct>& r) {
1095c3e9272SAbhishek Patel             std::vector<std::tuple<std::string, std::string, bool>> socketData;
110b4bec66bSAbhishek Patel             if (ec)
111b4bec66bSAbhishek Patel             {
11262598e31SEd Tanous                 BMCWEB_LOG_ERROR("{}", ec);
113b4bec66bSAbhishek Patel                 // return error code
1145c3e9272SAbhishek Patel                 callback(ec, socketData);
115b4bec66bSAbhishek Patel                 return;
116b4bec66bSAbhishek Patel             }
117b4bec66bSAbhishek Patel 
1185c3e9272SAbhishek Patel             // save all service output into vector
119b4bec66bSAbhishek Patel             for (const UnitStruct& unit : r)
120b4bec66bSAbhishek Patel             {
121b4bec66bSAbhishek Patel                 // Only traverse through <xyz>.socket units
122bd79bce8SPatrick Williams                 const std::string& unitName =
123bd79bce8SPatrick Williams                     std::get<NET_PROTO_UNIT_NAME>(unit);
124b4bec66bSAbhishek Patel 
125b4bec66bSAbhishek Patel                 // find "." into unitsName
126b4bec66bSAbhishek Patel                 size_t lastCharPos = unitName.rfind('.');
127b4bec66bSAbhishek Patel                 if (lastCharPos == std::string::npos)
128b4bec66bSAbhishek Patel                 {
129b4bec66bSAbhishek Patel                     continue;
130b4bec66bSAbhishek Patel                 }
131b4bec66bSAbhishek Patel 
132b4bec66bSAbhishek Patel                 // is unitsName end with ".socket"
133b4bec66bSAbhishek Patel                 std::string unitNameEnd = unitName.substr(lastCharPos);
13455f79e6fSEd Tanous                 if (unitNameEnd != ".socket")
135b4bec66bSAbhishek Patel                 {
136b4bec66bSAbhishek Patel                     continue;
137b4bec66bSAbhishek Patel                 }
138b4bec66bSAbhishek Patel 
139b4bec66bSAbhishek Patel                 // find "@" into unitsName
140b4bec66bSAbhishek Patel                 if (size_t atCharPos = unitName.rfind('@');
141b4bec66bSAbhishek Patel                     atCharPos != std::string::npos)
142b4bec66bSAbhishek Patel                 {
143b4bec66bSAbhishek Patel                     lastCharPos = atCharPos;
144b4bec66bSAbhishek Patel                 }
145b4bec66bSAbhishek Patel 
146b4bec66bSAbhishek Patel                 // unitsName without "@eth(x).socket", only <xyz>
147b4bec66bSAbhishek Patel                 // unitsName without ".socket", only <xyz>
148b4bec66bSAbhishek Patel                 std::string unitNameStr = unitName.substr(0, lastCharPos);
149b4bec66bSAbhishek Patel 
1505c3e9272SAbhishek Patel                 for (const auto& kv : protocolToDBus)
1515c3e9272SAbhishek Patel                 {
152b4bec66bSAbhishek Patel                     // We are interested in services, which starts with
153b4bec66bSAbhishek Patel                     // mapped service name
1545c3e9272SAbhishek Patel                     if (unitNameStr != kv.second)
155b4bec66bSAbhishek Patel                     {
156b4bec66bSAbhishek Patel                         continue;
157b4bec66bSAbhishek Patel                     }
158b4bec66bSAbhishek Patel 
159b4bec66bSAbhishek Patel                     const std::string& socketPath =
160b4bec66bSAbhishek Patel                         std::get<NET_PROTO_UNIT_OBJ_PATH>(unit);
161b4bec66bSAbhishek Patel                     const std::string& unitState =
162b4bec66bSAbhishek Patel                         std::get<NET_PROTO_UNIT_SUB_STATE>(unit);
163b4bec66bSAbhishek Patel 
16489492a15SPatrick Williams                     bool isProtocolEnabled = ((unitState == "running") ||
16589492a15SPatrick Williams                                               (unitState == "listening"));
1665c3e9272SAbhishek Patel 
167e6feae51SAndrew Geissler                     // Some protocols may have multiple services associated with
168bd79bce8SPatrick Williams                     // them (for example IPMI). Look to see if we've already
169bd79bce8SPatrick Williams                     // added an entry for the current protocol.
1703544d2a7SEd Tanous                     auto find = std::ranges::find_if(
1713544d2a7SEd Tanous                         socketData,
172bd79bce8SPatrick Williams                         [&kv](const std::tuple<std::string, std::string, bool>&
173bd79bce8SPatrick Williams                                   i) { return std::get<1>(i) == kv.first; });
174e6feae51SAndrew Geissler                     if (find != socketData.end())
175e6feae51SAndrew Geissler                     {
176bd79bce8SPatrick Williams                         // It only takes one enabled systemd service to consider
177bd79bce8SPatrick Williams                         // a protocol enabled so if the current entry already
178bd79bce8SPatrick Williams                         // has it enabled (or the new one is disabled) then just
179bd79bce8SPatrick Williams                         // continue, otherwise remove the current one and add
180bd79bce8SPatrick Williams                         // this new one.
181e6feae51SAndrew Geissler                         if (std::get<2>(*find) || !isProtocolEnabled)
182e6feae51SAndrew Geissler                         {
183bd79bce8SPatrick Williams                             // Already registered as enabled or current one is
184bd79bce8SPatrick Williams                             // not enabled, nothing to do
18562598e31SEd Tanous                             BMCWEB_LOG_DEBUG(
18662598e31SEd Tanous                                 "protocolName: {}, already true or current one is false: {}",
18762598e31SEd Tanous                                 kv.first, isProtocolEnabled);
188e6feae51SAndrew Geissler                             break;
189e6feae51SAndrew Geissler                         }
190bd79bce8SPatrick Williams                         // Remove existing entry and replace with new one
191bd79bce8SPatrick Williams                         // (below)
192e6feae51SAndrew Geissler                         socketData.erase(find);
193e6feae51SAndrew Geissler                     }
194e6feae51SAndrew Geissler 
1955c3e9272SAbhishek Patel                     socketData.emplace_back(socketPath, std::string(kv.first),
1965c3e9272SAbhishek Patel                                             isProtocolEnabled);
197b4bec66bSAbhishek Patel                     // We found service, return from inner loop.
1985c3e9272SAbhishek Patel                     break;
1995c3e9272SAbhishek Patel                 }
200b4bec66bSAbhishek Patel             }
201b4bec66bSAbhishek Patel 
2025c3e9272SAbhishek Patel             callback(ec, socketData);
203b4bec66bSAbhishek Patel         },
204b4bec66bSAbhishek Patel         "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
205b4bec66bSAbhishek Patel         "org.freedesktop.systemd1.Manager", "ListUnits");
206b4bec66bSAbhishek Patel }
207b4bec66bSAbhishek Patel 
208b4bec66bSAbhishek Patel template <typename CallbackFunc>
209b4bec66bSAbhishek Patel void getPortNumber(const std::string& socketPath, CallbackFunc&& callback)
210b4bec66bSAbhishek Patel {
211*deae6a78SEd Tanous     dbus::utility::getProperty<
2121e1e598dSJonathan Doman         std::vector<std::tuple<std::string, std::string>>>(
2131e1e598dSJonathan Doman         *crow::connections::systemBus, "org.freedesktop.systemd1", socketPath,
2141e1e598dSJonathan Doman         "org.freedesktop.systemd1.Socket", "Listen",
2158cb2c024SEd Tanous         [callback = std::forward<CallbackFunc>(callback)](
2165e7e2dc5SEd Tanous             const boost::system::error_code& ec,
2171e1e598dSJonathan Doman             const std::vector<std::tuple<std::string, std::string>>& resp) {
218b4bec66bSAbhishek Patel             if (ec)
219b4bec66bSAbhishek Patel             {
22062598e31SEd Tanous                 BMCWEB_LOG_ERROR("{}", ec);
221b4bec66bSAbhishek Patel                 callback(ec, 0);
222b4bec66bSAbhishek Patel                 return;
223b4bec66bSAbhishek Patel             }
22426f6976fSEd Tanous             if (resp.empty())
225b4bec66bSAbhishek Patel             {
226b4bec66bSAbhishek Patel                 // Network Protocol Listen Response Elements is empty
227b4bec66bSAbhishek Patel                 boost::system::error_code ec1 =
228b4bec66bSAbhishek Patel                     boost::system::errc::make_error_code(
229b4bec66bSAbhishek Patel                         boost::system::errc::bad_message);
230b4bec66bSAbhishek Patel                 // return error code
231b4bec66bSAbhishek Patel                 callback(ec1, 0);
23262598e31SEd Tanous                 BMCWEB_LOG_ERROR("{}", ec1);
233b4bec66bSAbhishek Patel                 return;
234b4bec66bSAbhishek Patel             }
235b4bec66bSAbhishek Patel             const std::string& listenStream =
2361e1e598dSJonathan Doman                 std::get<NET_PROTO_LISTEN_STREAM>(resp[0]);
237b4bec66bSAbhishek Patel             const char* pa = &listenStream[listenStream.rfind(':') + 1];
238b4bec66bSAbhishek Patel             int port{0};
239b4bec66bSAbhishek Patel             if (auto [p, ec2] = std::from_chars(pa, nullptr, port);
240b4bec66bSAbhishek Patel                 ec2 != std::errc())
241b4bec66bSAbhishek Patel             {
242b4bec66bSAbhishek Patel                 // there is only two possibility invalid_argument and
243b4bec66bSAbhishek Patel                 // result_out_of_range
244b4bec66bSAbhishek Patel                 boost::system::error_code ec3 =
245b4bec66bSAbhishek Patel                     boost::system::errc::make_error_code(
246b4bec66bSAbhishek Patel                         boost::system::errc::invalid_argument);
247b4bec66bSAbhishek Patel                 if (ec2 == std::errc::result_out_of_range)
248b4bec66bSAbhishek Patel                 {
249b4bec66bSAbhishek Patel                     ec3 = boost::system::errc::make_error_code(
250b4bec66bSAbhishek Patel                         boost::system::errc::result_out_of_range);
251b4bec66bSAbhishek Patel                 }
252b4bec66bSAbhishek Patel                 // return error code
253b4bec66bSAbhishek Patel                 callback(ec3, 0);
25462598e31SEd Tanous                 BMCWEB_LOG_ERROR("{}", ec3);
255b4bec66bSAbhishek Patel             }
256b4bec66bSAbhishek Patel             callback(ec, port);
2571e1e598dSJonathan Doman         });
258b4bec66bSAbhishek Patel }
259b4bec66bSAbhishek Patel 
260c5d03ff4SJennifer Lee } // namespace redfish
261