blob: 117f972d3480cb867a4201fdd5f8c3382ec8fe98 [file] [log] [blame]
Jennifer Leec5d03ff2019-03-08 15:42:58 -08001/*
Ed Tanous6be832e2024-09-10 11:44:48 -07002Copyright (c) 2019 Intel Corporation
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
Jennifer Leec5d03ff2019-03-08 15:42:58 -080015*/
Jennifer Leec5d03ff2019-03-08 15:42:58 -080016#pragma once
17
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "async_resp.hpp"
19#include "dbus_utility.hpp"
20#include "error_messages.hpp"
21
George Liue99073f2022-12-09 11:06:16 +080022#include <boost/system/error_code.hpp>
Nan Zhoucf7eba02022-07-21 23:53:20 +000023#include <sdbusplus/asio/property.hpp>
24
George Liue99073f2022-12-09 11:06:16 +080025#include <array>
Nan Zhoucf7eba02022-07-21 23:53:20 +000026#include <charconv>
Ed Tanous3544d2a2023-08-06 18:12:20 -070027#include <ranges>
George Liue99073f2022-12-09 11:06:16 +080028#include <string_view>
Nan Zhoucf7eba02022-07-21 23:53:20 +000029
Jennifer Leec5d03ff2019-03-08 15:42:58 -080030namespace redfish
31{
32
Abhishek Patelb4bec662021-06-21 17:32:02 -050033enum NetworkProtocolUnitStructFields
34{
35 NET_PROTO_UNIT_NAME,
36 NET_PROTO_UNIT_DESC,
37 NET_PROTO_UNIT_LOAD_STATE,
38 NET_PROTO_UNIT_ACTIVE_STATE,
39 NET_PROTO_UNIT_SUB_STATE,
40 NET_PROTO_UNIT_DEVICE,
41 NET_PROTO_UNIT_OBJ_PATH,
42 NET_PROTO_UNIT_ALWAYS_0,
43 NET_PROTO_UNIT_ALWAYS_EMPTY,
44 NET_PROTO_UNIT_ALWAYS_ROOT_PATH
45};
46
47enum NetworkProtocolListenResponseElements
48{
49 NET_PROTO_LISTEN_TYPE,
50 NET_PROTO_LISTEN_STREAM
51};
52
53/**
54 * @brief D-Bus Unit structure returned in array from ListUnits Method
55 */
56using UnitStruct =
57 std::tuple<std::string, std::string, std::string, std::string, std::string,
58 std::string, sdbusplus::message::object_path, uint32_t,
59 std::string, sdbusplus::message::object_path>;
60
Jennifer Leec5d03ff2019-03-08 15:42:58 -080061template <typename CallbackFunc>
zhanghch058d1b46d2021-04-01 11:18:24 +080062void getMainChassisId(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
Jennifer Leec5d03ff2019-03-08 15:42:58 -080063 CallbackFunc&& callback)
64{
65 // Find managed chassis
George Liue99073f2022-12-09 11:06:16 +080066 constexpr std::array<std::string_view, 2> interfaces = {
67 "xyz.openbmc_project.Inventory.Item.Board",
68 "xyz.openbmc_project.Inventory.Item.Chassis"};
69 dbus::utility::getSubTree(
70 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -070071 [callback = std::forward<CallbackFunc>(callback),
George Liue99073f2022-12-09 11:06:16 +080072 asyncResp](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -080073 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -040074 if (ec)
75 {
76 BMCWEB_LOG_ERROR("{}", ec);
77 return;
78 }
79 if (subtree.empty())
80 {
81 BMCWEB_LOG_DEBUG("Can't find chassis!");
82 return;
83 }
Jennifer Leec5d03ff2019-03-08 15:42:58 -080084
Patrick Williamsbd79bce2024-08-16 15:22:20 -040085 std::size_t idPos = subtree[0].first.rfind('/');
86 if (idPos == std::string::npos ||
87 (idPos + 1) >= subtree[0].first.size())
88 {
89 messages::internalError(asyncResp->res);
90 BMCWEB_LOG_DEBUG("Can't parse chassis ID!");
91 return;
92 }
93 std::string chassisId = subtree[0].first.substr(idPos + 1);
94 BMCWEB_LOG_DEBUG("chassisId = {}", chassisId);
95 callback(chassisId, asyncResp);
96 });
Jennifer Leec5d03ff2019-03-08 15:42:58 -080097}
Abhishek Patelb4bec662021-06-21 17:32:02 -050098
99template <typename CallbackFunc>
Abhishek Patel5c3e9272021-06-24 10:11:33 -0500100void getPortStatusAndPath(
101 std::span<const std::pair<std::string_view, std::string_view>>
102 protocolToDBus,
103 CallbackFunc&& callback)
Abhishek Patelb4bec662021-06-21 17:32:02 -0500104{
105 crow::connections::systemBus->async_method_call(
Ed Tanous8cb2c022024-03-27 16:31:46 -0700106 [protocolToDBus, callback = std::forward<CallbackFunc>(callback)](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800107 const boost::system::error_code& ec,
Ed Tanousf94c4ec2022-01-06 12:44:41 -0800108 const std::vector<UnitStruct>& r) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400109 std::vector<std::tuple<std::string, std::string, bool>> socketData;
110 if (ec)
Ed Tanous002d39b2022-05-31 08:59:27 -0700111 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400112 BMCWEB_LOG_ERROR("{}", ec);
113 // return error code
114 callback(ec, socketData);
115 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700116 }
117
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400118 // save all service output into vector
119 for (const UnitStruct& unit : r)
Ed Tanous002d39b2022-05-31 08:59:27 -0700120 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400121 // Only traverse through <xyz>.socket units
122 const std::string& unitName =
123 std::get<NET_PROTO_UNIT_NAME>(unit);
Ed Tanous002d39b2022-05-31 08:59:27 -0700124
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400125 // find "." into unitsName
126 size_t lastCharPos = unitName.rfind('.');
127 if (lastCharPos == std::string::npos)
Abhishek Patel5c3e9272021-06-24 10:11:33 -0500128 {
129 continue;
130 }
131
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400132 // is unitsName end with ".socket"
133 std::string unitNameEnd = unitName.substr(lastCharPos);
134 if (unitNameEnd != ".socket")
Andrew Geisslere6feae52023-04-06 10:27:41 -0600135 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400136 continue;
Andrew Geisslere6feae52023-04-06 10:27:41 -0600137 }
138
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400139 // find "@" into unitsName
140 if (size_t atCharPos = unitName.rfind('@');
141 atCharPos != std::string::npos)
142 {
143 lastCharPos = atCharPos;
144 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700145
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400146 // unitsName without "@eth(x).socket", only <xyz>
147 // unitsName without ".socket", only <xyz>
148 std::string unitNameStr = unitName.substr(0, lastCharPos);
149
150 for (const auto& kv : protocolToDBus)
151 {
152 // We are interested in services, which starts with
153 // mapped service name
154 if (unitNameStr != kv.second)
155 {
156 continue;
157 }
158
159 const std::string& socketPath =
160 std::get<NET_PROTO_UNIT_OBJ_PATH>(unit);
161 const std::string& unitState =
162 std::get<NET_PROTO_UNIT_SUB_STATE>(unit);
163
164 bool isProtocolEnabled = ((unitState == "running") ||
165 (unitState == "listening"));
166
167 // Some protocols may have multiple services associated with
168 // them (for example IPMI). Look to see if we've already
169 // added an entry for the current protocol.
170 auto find = std::ranges::find_if(
171 socketData,
172 [&kv](const std::tuple<std::string, std::string, bool>&
173 i) { return std::get<1>(i) == kv.first; });
174 if (find != socketData.end())
175 {
176 // It only takes one enabled systemd service to consider
177 // a protocol enabled so if the current entry already
178 // has it enabled (or the new one is disabled) then just
179 // continue, otherwise remove the current one and add
180 // this new one.
181 if (std::get<2>(*find) || !isProtocolEnabled)
182 {
183 // Already registered as enabled or current one is
184 // not enabled, nothing to do
185 BMCWEB_LOG_DEBUG(
186 "protocolName: {}, already true or current one is false: {}",
187 kv.first, isProtocolEnabled);
188 break;
189 }
190 // Remove existing entry and replace with new one
191 // (below)
192 socketData.erase(find);
193 }
194
195 socketData.emplace_back(socketPath, std::string(kv.first),
196 isProtocolEnabled);
197 // We found service, return from inner loop.
198 break;
199 }
200 }
201
202 callback(ec, socketData);
203 },
Abhishek Patelb4bec662021-06-21 17:32:02 -0500204 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
205 "org.freedesktop.systemd1.Manager", "ListUnits");
206}
207
208template <typename CallbackFunc>
209void getPortNumber(const std::string& socketPath, CallbackFunc&& callback)
210{
Ed Tanousdeae6a72024-11-11 21:58:57 -0800211 dbus::utility::getProperty<
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700212 std::vector<std::tuple<std::string, std::string>>>(
213 *crow::connections::systemBus, "org.freedesktop.systemd1", socketPath,
214 "org.freedesktop.systemd1.Socket", "Listen",
Ed Tanous8cb2c022024-03-27 16:31:46 -0700215 [callback = std::forward<CallbackFunc>(callback)](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800216 const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700217 const std::vector<std::tuple<std::string, std::string>>& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400218 if (ec)
Abhishek Patelb4bec662021-06-21 17:32:02 -0500219 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400220 BMCWEB_LOG_ERROR("{}", ec);
221 callback(ec, 0);
222 return;
Abhishek Patelb4bec662021-06-21 17:32:02 -0500223 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400224 if (resp.empty())
225 {
226 // Network Protocol Listen Response Elements is empty
227 boost::system::error_code ec1 =
228 boost::system::errc::make_error_code(
229 boost::system::errc::bad_message);
230 // return error code
231 callback(ec1, 0);
232 BMCWEB_LOG_ERROR("{}", ec1);
233 return;
234 }
235 const std::string& listenStream =
236 std::get<NET_PROTO_LISTEN_STREAM>(resp[0]);
237 const char* pa = &listenStream[listenStream.rfind(':') + 1];
238 int port{0};
239 if (auto [p, ec2] = std::from_chars(pa, nullptr, port);
240 ec2 != std::errc())
241 {
242 // there is only two possibility invalid_argument and
243 // result_out_of_range
244 boost::system::error_code ec3 =
245 boost::system::errc::make_error_code(
246 boost::system::errc::invalid_argument);
247 if (ec2 == std::errc::result_out_of_range)
248 {
249 ec3 = boost::system::errc::make_error_code(
250 boost::system::errc::result_out_of_range);
251 }
252 // return error code
253 callback(ec3, 0);
254 BMCWEB_LOG_ERROR("{}", ec3);
255 }
256 callback(ec, port);
257 });
Abhishek Patelb4bec662021-06-21 17:32:02 -0500258}
259
Jennifer Leec5d03ff2019-03-08 15:42:58 -0800260} // namespace redfish