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