1 /* 2 // Copyright (c) 2019 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 17 #include "dbuspassiveredundancy.hpp" 18 19 #include <iostream> 20 #include <sdbusplus/bus.hpp> 21 #include <sdbusplus/bus/match.hpp> 22 #include <set> 23 #include <unordered_map> 24 #include <variant> 25 26 namespace properties 27 { 28 29 constexpr const char* interface = "org.freedesktop.DBus.Properties"; 30 constexpr const char* get = "Get"; 31 constexpr const char* getAll = "GetAll"; 32 33 } // namespace properties 34 35 namespace redundancy 36 { 37 38 constexpr const char* collection = "Collection"; 39 constexpr const char* status = "Status"; 40 constexpr const char* interface = "xyz.openbmc_project.Control.FanRedundancy"; 41 42 } // namespace redundancy 43 44 DbusPassiveRedundancy::DbusPassiveRedundancy(sdbusplus::bus::bus& bus) : 45 match(bus, 46 "type='signal',member='PropertiesChanged',arg0namespace='" + 47 std::string(redundancy::interface) + "'", 48 std::move([this](sdbusplus::message::message& message) { 49 std::string objectName; 50 std::unordered_map< 51 std::string, 52 std::variant<std::string, std::vector<std::string>>> 53 result; 54 try 55 { 56 message.read(objectName, result); 57 } 58 catch (sdbusplus::exception_t&) 59 { 60 std::cerr << "Error reading match data"; 61 return; 62 } 63 auto findStatus = result.find("Status"); 64 if (findStatus == result.end()) 65 { 66 return; 67 } 68 std::string status = std::get<std::string>(findStatus->second); 69 70 auto methodCall = passiveBus.new_method_call( 71 message.get_sender(), message.get_path(), 72 properties::interface, properties::get); 73 methodCall.append(redundancy::interface, redundancy::collection); 74 std::variant<std::vector<std::string>> collection; 75 76 try 77 { 78 auto reply = passiveBus.call(methodCall); 79 reply.read(collection); 80 } 81 catch (sdbusplus::exception_t&) 82 { 83 std::cerr << "Error reading match data"; 84 return; 85 } 86 87 auto data = std::get<std::vector<std::string>>(collection); 88 if (status.rfind("Failed") != std::string::npos) 89 { 90 failed.insert(data.begin(), data.end()); 91 } 92 else 93 { 94 for (const auto& d : data) 95 { 96 failed.erase(d); 97 } 98 } 99 })), 100 passiveBus(bus) 101 { 102 populateFailures(); 103 } 104 105 void DbusPassiveRedundancy::populateFailures(void) 106 { 107 auto mapper = passiveBus.new_method_call( 108 "xyz.openbmc_project.ObjectMapper", 109 "/xyz/openbmc_project/object_mapper", 110 "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 111 mapper.append("/", 0, std::array<const char*, 1>{redundancy::interface}); 112 std::unordered_map< 113 std::string, std::unordered_map<std::string, std::vector<std::string>>> 114 respData; 115 try 116 { 117 auto resp = passiveBus.call(mapper); 118 resp.read(respData); 119 } 120 catch (sdbusplus::exception_t&) 121 { 122 std::cerr << "Populate Failures Mapper Error\n"; 123 return; 124 } 125 126 /* 127 * The subtree response looks like: 128 * {path : 129 * {busname: 130 * {interface, interface, interface, ...} 131 * } 132 * } 133 * 134 * This loops through this structure to pre-poulate the already failed items 135 */ 136 137 for (const auto& [path, interfaceDict] : respData) 138 { 139 for (const auto& [owner, _] : interfaceDict) 140 { 141 auto call = passiveBus.new_method_call(owner.c_str(), path.c_str(), 142 properties::interface, 143 properties::getAll); 144 call.append(redundancy::interface); 145 146 std::unordered_map< 147 std::string, 148 std::variant<std::string, std::vector<std::string>>> 149 getAll; 150 try 151 { 152 auto data = passiveBus.call(call); 153 data.read(getAll); 154 } 155 catch (sdbusplus::exception_t&) 156 { 157 std::cerr << "Populate Failures Mapper Error\n"; 158 return; 159 } 160 std::string status = 161 std::get<std::string>(getAll[redundancy::status]); 162 if (status.rfind("Failed") == std::string::npos) 163 { 164 continue; 165 } 166 std::vector<std::string> collection = 167 std::get<std::vector<std::string>>( 168 getAll[redundancy::collection]); 169 failed.insert(collection.begin(), collection.end()); 170 } 171 } 172 } 173 174 const std::set<std::string>& DbusPassiveRedundancy::getFailed() 175 { 176 return failed; 177 }