| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 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 |  | 
| James Feist | dc7bbdc | 2019-05-16 15:33:06 -0700 | [diff] [blame] | 17 | #include "callback_manager.hpp" | 
 | 18 |  | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 19 | #include <boost/container/flat_map.hpp> | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 20 | #include <sdbusplus/asio/connection.hpp> | 
 | 21 | #include <sdbusplus/asio/object_server.hpp> | 
| Jason M. Bills | 0d5c071 | 2020-12-08 10:10:47 -0800 | [diff] [blame^] | 22 |  | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 23 | #include <variant> | 
 | 24 |  | 
 | 25 | constexpr const char* fatalLedPath = | 
 | 26 |     "/xyz/openbmc_project/led/groups/status_critical"; | 
 | 27 | constexpr const char* criticalLedPath = | 
 | 28 |     "/xyz/openbmc_project/led/groups/status_non_critical"; | 
 | 29 | constexpr const char* warningLedPath = | 
 | 30 |     "/xyz/openbmc_project/led/groups/status_degraded"; | 
| James Feist | e409fc7 | 2019-03-05 12:19:43 -0800 | [diff] [blame] | 31 | constexpr const char* okLedPath = "/xyz/openbmc_project/led/groups/status_ok"; | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 32 |  | 
 | 33 | constexpr const char* ledIface = "xyz.openbmc_project.Led.Group"; | 
 | 34 | constexpr const char* ledAssertProp = "Asserted"; | 
 | 35 | constexpr const char* ledManagerBusname = | 
 | 36 |     "xyz.openbmc_project.LED.GroupManager"; | 
 | 37 |  | 
| James Feist | dc7bbdc | 2019-05-16 15:33:06 -0700 | [diff] [blame] | 38 | std::unique_ptr<AssociationManager> associationManager; | 
 | 39 |  | 
| James Feist | e409fc7 | 2019-03-05 12:19:43 -0800 | [diff] [blame] | 40 | enum class StatusSetting | 
 | 41 | { | 
 | 42 |     none, | 
 | 43 |     ok, | 
 | 44 |     warn, | 
 | 45 |     critical, | 
 | 46 |     fatal | 
 | 47 | }; | 
 | 48 |  | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 49 | constexpr const bool debug = false; | 
 | 50 |  | 
 | 51 | // final led state tracking | 
| James Feist | e409fc7 | 2019-03-05 12:19:43 -0800 | [diff] [blame] | 52 | StatusSetting currentPriority = StatusSetting::none; | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 53 |  | 
 | 54 | // maps of <object-path, <property, asserted>> | 
 | 55 | boost::container::flat_map<std::string, | 
 | 56 |                            boost::container::flat_map<std::string, bool>> | 
 | 57 |     fatalAssertMap; | 
 | 58 | boost::container::flat_map<std::string, | 
 | 59 |                            boost::container::flat_map<std::string, bool>> | 
 | 60 |     criticalAssertMap; | 
 | 61 | boost::container::flat_map<std::string, | 
 | 62 |                            boost::container::flat_map<std::string, bool>> | 
 | 63 |     warningAssertMap; | 
 | 64 |  | 
 | 65 | std::vector<std::string> assertedInMap( | 
 | 66 |     const boost::container::flat_map< | 
 | 67 |         std::string, boost::container::flat_map<std::string, bool>>& map) | 
 | 68 | { | 
 | 69 |     std::vector<std::string> ret; | 
 | 70 |     // if any of the properties are true, return true | 
 | 71 |     for (const auto& pair : map) | 
 | 72 |     { | 
 | 73 |         for (const auto& item : pair.second) | 
 | 74 |         { | 
 | 75 |             if (item.second) | 
 | 76 |             { | 
 | 77 |                 ret.push_back(pair.first); | 
 | 78 |             } | 
 | 79 |         } | 
 | 80 |     } | 
 | 81 |     return ret; | 
 | 82 | } | 
 | 83 |  | 
| Richard Marian Thomaiyar | 2816121 | 2019-04-13 21:11:23 +0530 | [diff] [blame] | 84 | void updateLedStatus(std::shared_ptr<sdbusplus::asio::connection>& conn, | 
 | 85 |                      bool forceRefresh = false) | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 86 | { | 
| James Feist | dc7bbdc | 2019-05-16 15:33:06 -0700 | [diff] [blame] | 87 |     std::vector<std::string> fatalVector = assertedInMap(fatalAssertMap); | 
 | 88 |     bool fatal = fatalVector.size(); | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 89 |  | 
| James Feist | dc7bbdc | 2019-05-16 15:33:06 -0700 | [diff] [blame] | 90 |     std::vector<std::string> criticalVector = assertedInMap(criticalAssertMap); | 
 | 91 |     bool critical = criticalVector.size(); | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 92 |  | 
| James Feist | dc7bbdc | 2019-05-16 15:33:06 -0700 | [diff] [blame] | 93 |     std::vector<std::string> warningVector = assertedInMap(warningAssertMap); | 
 | 94 |     bool warn = warningVector.size(); | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 95 |  | 
| James Feist | dc7bbdc | 2019-05-16 15:33:06 -0700 | [diff] [blame] | 96 |     associationManager->setLocalAssociations(fatalVector, criticalVector, | 
 | 97 |                                              warningVector); | 
| James Feist | e409fc7 | 2019-03-05 12:19:43 -0800 | [diff] [blame] | 98 |  | 
 | 99 |     StatusSetting last = currentPriority; | 
 | 100 |  | 
 | 101 |     if (fatal) | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 102 |     { | 
| James Feist | e409fc7 | 2019-03-05 12:19:43 -0800 | [diff] [blame] | 103 |         currentPriority = StatusSetting::fatal; | 
 | 104 |     } | 
 | 105 |     else if (critical) | 
 | 106 |     { | 
 | 107 |         currentPriority = StatusSetting::critical; | 
 | 108 |     } | 
 | 109 |     else if (warn) | 
 | 110 |     { | 
 | 111 |         currentPriority = StatusSetting::warn; | 
 | 112 |     } | 
 | 113 |     else | 
 | 114 |     { | 
 | 115 |         currentPriority = StatusSetting::ok; | 
 | 116 |     } | 
 | 117 |  | 
 | 118 |     std::vector<std::pair<std::string, std::variant<bool>>> ledsToSet; | 
 | 119 |  | 
| Richard Marian Thomaiyar | 2816121 | 2019-04-13 21:11:23 +0530 | [diff] [blame] | 120 |     if (last != currentPriority || forceRefresh) | 
| James Feist | e409fc7 | 2019-03-05 12:19:43 -0800 | [diff] [blame] | 121 |     { | 
 | 122 |         switch (currentPriority) | 
 | 123 |         { | 
 | 124 |             case (StatusSetting::fatal): | 
 | 125 |             { | 
 | 126 |                 ledsToSet.push_back(std::make_pair(fatalLedPath, true)); | 
 | 127 |                 ledsToSet.push_back(std::make_pair(criticalLedPath, false)); | 
 | 128 |                 ledsToSet.push_back(std::make_pair(warningLedPath, false)); | 
 | 129 |                 ledsToSet.push_back(std::make_pair(okLedPath, false)); | 
 | 130 |                 break; | 
 | 131 |             } | 
 | 132 |             case (StatusSetting::critical): | 
 | 133 |             { | 
 | 134 |                 ledsToSet.push_back(std::make_pair(fatalLedPath, false)); | 
 | 135 |                 ledsToSet.push_back(std::make_pair(criticalLedPath, true)); | 
 | 136 |                 ledsToSet.push_back(std::make_pair(warningLedPath, false)); | 
 | 137 |                 ledsToSet.push_back(std::make_pair(okLedPath, false)); | 
 | 138 |                 break; | 
 | 139 |             } | 
 | 140 |             case (StatusSetting::warn): | 
 | 141 |             { | 
 | 142 |                 ledsToSet.push_back(std::make_pair(fatalLedPath, false)); | 
 | 143 |                 ledsToSet.push_back(std::make_pair(criticalLedPath, false)); | 
 | 144 |                 ledsToSet.push_back(std::make_pair(warningLedPath, true)); | 
 | 145 |                 ledsToSet.push_back(std::make_pair(okLedPath, false)); | 
 | 146 |                 break; | 
 | 147 |             } | 
 | 148 |             case (StatusSetting::ok): | 
 | 149 |             { | 
 | 150 |                 ledsToSet.push_back(std::make_pair(fatalLedPath, false)); | 
 | 151 |                 ledsToSet.push_back(std::make_pair(criticalLedPath, false)); | 
 | 152 |                 ledsToSet.push_back(std::make_pair(warningLedPath, false)); | 
 | 153 |                 ledsToSet.push_back(std::make_pair(okLedPath, true)); | 
 | 154 |                 break; | 
 | 155 |             } | 
 | 156 |         } | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 157 |     } | 
 | 158 |  | 
 | 159 |     for (const auto& ledPair : ledsToSet) | 
 | 160 |     { | 
 | 161 |         conn->async_method_call( | 
 | 162 |             [ledPair](const boost::system::error_code ec) { | 
 | 163 |                 if (ec) | 
 | 164 |                 { | 
 | 165 |                     std::cerr << "Cannot set " << ledPair.first << " to " | 
 | 166 |                               << std::boolalpha | 
 | 167 |                               << std::get<bool>(ledPair.second) << "\n"; | 
 | 168 |                 } | 
 | 169 |                 if constexpr (debug) | 
 | 170 |                 { | 
 | 171 |                     std::cerr << "Set " << ledPair.first << " to " | 
 | 172 |                               << std::boolalpha | 
 | 173 |                               << std::get<bool>(ledPair.second) << "\n"; | 
 | 174 |                 } | 
 | 175 |             }, | 
 | 176 |             ledManagerBusname, ledPair.first, "org.freedesktop.DBus.Properties", | 
 | 177 |             "Set", ledIface, ledAssertProp, ledPair.second); | 
 | 178 |     } | 
 | 179 | } | 
 | 180 |  | 
 | 181 | void createThresholdMatch(std::shared_ptr<sdbusplus::asio::connection>& conn) | 
 | 182 | { | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 183 |  | 
| James Feist | 7b23840 | 2019-06-25 11:56:49 -0700 | [diff] [blame] | 184 |     static sdbusplus::bus::match::match match( | 
 | 185 |         static_cast<sdbusplus::bus::bus&>(*conn), | 
 | 186 |         "type='signal',interface='org.freedesktop.DBus.Properties'," | 
 | 187 |         "path_" | 
 | 188 |         "namespace='/xyz/openbmc_project/" | 
 | 189 |         "sensors',arg0namespace='xyz.openbmc_project.Sensor.Threshold'", | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 190 |         [&conn](sdbusplus::message::message& message) { | 
 | 191 |             std::string objectName; | 
 | 192 |             boost::container::flat_map<std::string, std::variant<bool>> values; | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 193 |  | 
| James Feist | 7b23840 | 2019-06-25 11:56:49 -0700 | [diff] [blame] | 194 |             try | 
 | 195 |             { | 
 | 196 |                 message.read(objectName, values); | 
 | 197 |             } | 
 | 198 |             catch (sdbusplus::exception_t&) | 
 | 199 |             { | 
 | 200 |                 return; | 
 | 201 |             } | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 202 |             if constexpr (debug) | 
 | 203 |             { | 
 | 204 |                 std::cerr << "Threshold callback " << message.get_path() | 
 | 205 |                           << "\n"; | 
 | 206 |             } | 
 | 207 |  | 
 | 208 |             auto findCriticalLow = values.find("CriticalAlarmLow"); | 
 | 209 |             auto findCriticalHigh = values.find("CriticalAlarmHigh"); | 
 | 210 |  | 
 | 211 |             auto findWarnLow = values.find("WarningAlarmLow"); | 
 | 212 |             auto findWarnHigh = values.find("WarningAlarmHigh"); | 
 | 213 |  | 
 | 214 |             if (findCriticalLow != values.end()) | 
 | 215 |             { | 
 | 216 |                 criticalAssertMap[message.get_path()]["Low"] = | 
 | 217 |                     std::get<bool>(findCriticalLow->second); | 
 | 218 |             } | 
 | 219 |             if (findCriticalHigh != values.end()) | 
 | 220 |             { | 
 | 221 |                 criticalAssertMap[message.get_path()]["High"] = | 
 | 222 |                     std::get<bool>(findCriticalHigh->second); | 
 | 223 |             } | 
 | 224 |             if (findWarnLow != values.end()) | 
 | 225 |             { | 
 | 226 |                 warningAssertMap[message.get_path()]["Low"] = | 
 | 227 |                     std::get<bool>(findWarnLow->second); | 
 | 228 |             } | 
 | 229 |             if (findWarnHigh != values.end()) | 
 | 230 |             { | 
 | 231 |                 warningAssertMap[message.get_path()]["High"] = | 
 | 232 |                     std::get<bool>(findWarnHigh->second); | 
 | 233 |             } | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 234 |  | 
| James Feist | 7b23840 | 2019-06-25 11:56:49 -0700 | [diff] [blame] | 235 |             associationManager->setSensorAssociations( | 
 | 236 |                 assertedInMap(criticalAssertMap), | 
 | 237 |                 assertedInMap(warningAssertMap)); | 
 | 238 |  | 
 | 239 |             updateLedStatus(conn); | 
 | 240 |         }); | 
 | 241 | } | 
 | 242 |  | 
 | 243 | void createAssociationMatch(std::shared_ptr<sdbusplus::asio::connection>& conn) | 
 | 244 | { | 
 | 245 |     static sdbusplus::bus::match::match match( | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 246 |         static_cast<sdbusplus::bus::bus&>(*conn), | 
| James Feist | e409fc7 | 2019-03-05 12:19:43 -0800 | [diff] [blame] | 247 |         "type='signal',interface='org.freedesktop.DBus.Properties'," | 
| James Feist | 7b23840 | 2019-06-25 11:56:49 -0700 | [diff] [blame] | 248 |         "arg0namespace='" + | 
 | 249 |             std::string(associationIface) + "'", | 
 | 250 |         [&conn](sdbusplus::message::message& message) { | 
 | 251 |             if (message.get_path() == rootPath) | 
 | 252 |             { | 
 | 253 |                 return; // it's us | 
 | 254 |             } | 
 | 255 |             std::string objectName; | 
 | 256 |             boost::container::flat_map<std::string, | 
 | 257 |                                        std::variant<std::vector<Association>>> | 
 | 258 |                 values; | 
 | 259 |             try | 
 | 260 |             { | 
 | 261 |                 message.read(objectName, values); | 
 | 262 |             } | 
 | 263 |             catch (sdbusplus::exception_t&) | 
 | 264 |             { | 
 | 265 |                 return; | 
 | 266 |             } | 
 | 267 |  | 
 | 268 |             if constexpr (debug) | 
 | 269 |             { | 
 | 270 |                 std::cerr << "Association callback " << message.get_path() | 
 | 271 |                           << "\n"; | 
 | 272 |             } | 
 | 273 |  | 
 | 274 |             auto findAssociations = values.find("associations"); | 
 | 275 |             if (findAssociations == values.end()) | 
 | 276 |             { | 
 | 277 |                 return; | 
 | 278 |             } | 
 | 279 |             const std::vector<Association>* associations = | 
 | 280 |                 std::get_if<std::vector<Association>>( | 
 | 281 |                     &findAssociations->second); | 
 | 282 |  | 
 | 283 |             if (associations == nullptr) | 
 | 284 |             { | 
 | 285 |                 std::cerr << "Illegal Association on " << message.get_path() | 
 | 286 |                           << "\n"; | 
 | 287 |                 return; | 
 | 288 |             } | 
 | 289 |  | 
 | 290 |             bool localWarning = false; | 
 | 291 |             bool localCritical = false; | 
 | 292 |             bool globalWarning = false; | 
 | 293 |             bool globalCritical = false; | 
 | 294 |  | 
 | 295 |             for (const auto& [forward, reverse, path] : *associations) | 
 | 296 |             { | 
 | 297 |                 if (path == rootPath) | 
 | 298 |                 { | 
 | 299 |                     globalWarning = globalWarning ? true : reverse == "warning"; | 
 | 300 |                     globalCritical = | 
 | 301 |                         globalCritical ? true : reverse == "critical"; | 
 | 302 |  | 
 | 303 |                     if constexpr (1) | 
 | 304 |                     { | 
 | 305 |                         std::cerr << "got global "; | 
 | 306 |                     } | 
 | 307 |                 } | 
 | 308 |                 else | 
 | 309 |                 { | 
 | 310 |                     localWarning = localWarning ? true : reverse == "warning"; | 
 | 311 |                     localCritical = | 
 | 312 |                         localCritical ? true : reverse == "critical"; | 
 | 313 |                 } | 
 | 314 |                 if (globalCritical && localCritical) | 
 | 315 |                 { | 
 | 316 |                     break; | 
 | 317 |                 } | 
 | 318 |             } | 
 | 319 |  | 
 | 320 |             bool fatal = globalCritical && localCritical; | 
 | 321 |             bool critical = globalWarning && localCritical; | 
 | 322 |             bool warning = globalWarning && localWarning; | 
 | 323 |  | 
 | 324 |             fatalAssertMap[message.get_path()]["association"] = fatal; | 
 | 325 |             criticalAssertMap[message.get_path()]["association"] = critical; | 
 | 326 |             warningAssertMap[message.get_path()]["association"] = warning; | 
 | 327 |  | 
 | 328 |             updateLedStatus(conn); | 
 | 329 |         }); | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 330 | } | 
 | 331 |  | 
 | 332 | int main(int argc, char** argv) | 
 | 333 | { | 
 | 334 |     boost::asio::io_service io; | 
 | 335 |     auto conn = std::make_shared<sdbusplus::asio::connection>(io); | 
 | 336 |     conn->request_name("xyz.openbmc_project.CallbackManager"); | 
 | 337 |     sdbusplus::asio::object_server objServer(conn); | 
| James Feist | dc7bbdc | 2019-05-16 15:33:06 -0700 | [diff] [blame] | 338 |     std::shared_ptr<sdbusplus::asio::dbus_interface> rootIface = | 
 | 339 |         objServer.add_interface(rootPath, | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 340 |                                 "xyz.openbmc_project.CallbackManager"); | 
| James Feist | dc7bbdc | 2019-05-16 15:33:06 -0700 | [diff] [blame] | 341 |     rootIface->register_method("RetriggerLEDUpdate", | 
 | 342 |                                [&conn]() { updateLedStatus(conn, true); }); | 
 | 343 |     rootIface->initialize(); | 
 | 344 |  | 
 | 345 |     std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface = | 
 | 346 |         objServer.add_interface(rootPath, globalInventoryIface); | 
 | 347 |     inventoryIface->initialize(); | 
 | 348 |  | 
 | 349 |     associationManager = std::make_unique<AssociationManager>(objServer, conn); | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 350 |  | 
 | 351 |     createThresholdMatch(conn); | 
| James Feist | 7b23840 | 2019-06-25 11:56:49 -0700 | [diff] [blame] | 352 |     createAssociationMatch(conn); | 
| James Feist | e409fc7 | 2019-03-05 12:19:43 -0800 | [diff] [blame] | 353 |     updateLedStatus(conn); | 
| James Feist | 03a02ad | 2019-02-06 12:38:50 -0800 | [diff] [blame] | 354 |  | 
 | 355 |     io.run(); | 
 | 356 |  | 
 | 357 |     return 0; | 
 | 358 | } |