1 #include "manager.hpp" 2 #include "utils.hpp" 3 4 #include <phosphor-logging/log.hpp> 5 6 namespace rules = sdbusplus::bus::match::rules; 7 8 namespace // anonymous 9 { 10 constexpr auto SETTINGS_SERVICE = "org.openbmc.settings.Host"; 11 constexpr auto SETTINGS_PATH = "/org/openbmc/settings/host0"; 12 constexpr auto SETTINGS_INTERFACE = "org.openbmc.settings.Host"; 13 14 // TODO: Use new settings in xyz.openbmc_project 15 const auto MATCH_PROPERTY_CHANGE = 16 rules::type::signal() + 17 rules::member("PropertiesChanged") + 18 rules::path("/org/openbmc/settings/host0") + 19 rules::interface("org.freedesktop.DBus.Properties"); 20 21 const auto MATCH_PGOOD_CHANGE = 22 rules::type::signal() + 23 rules::member("PropertiesChanged") + 24 rules::path("/org/openbmc/control/power0") + 25 rules::interface("org.freedesktop.DBus.Properties"); 26 27 constexpr auto POWER_SERVICE = "org.openbmc.control.Power"; 28 constexpr auto POWER_PATH = "/org/openbmc/control/power0"; 29 constexpr auto POWER_INTERFACE = POWER_SERVICE; 30 constexpr auto PGOOD_STR = "pgood"; 31 32 constexpr auto SYSTEMD_TIME_SERVICE = "org.freedesktop.timedate1"; 33 constexpr auto SYSTEMD_TIME_PATH = "/org/freedesktop/timedate1"; 34 constexpr auto SYSTEMD_TIME_INTERFACE = SYSTEMD_TIME_SERVICE; 35 constexpr auto METHOD_SET_NTP = "SetNTP"; 36 37 constexpr auto OBMC_NETWORK_SERVICE = "org.openbmc.NetworkManager"; 38 constexpr auto OBMC_NETWORK_PATH = "/org/openbmc/NetworkManager/Interface"; 39 constexpr auto OBMC_NETWORK_INTERFACE = OBMC_NETWORK_SERVICE; 40 constexpr auto METHOD_UPDATE_USE_NTP = "UpdateUseNtpField"; 41 } 42 43 namespace phosphor 44 { 45 namespace time 46 { 47 48 using namespace phosphor::logging; 49 50 const std::set<std::string> 51 Manager::managedProperties = {PROPERTY_TIME_MODE, PROPERTY_TIME_OWNER}; 52 53 const std::map<std::string, Owner> Manager::ownerMap = 54 { 55 { "BMC", Owner::BMC }, 56 { "HOST", Owner::HOST }, 57 { "SPLIT", Owner::SPLIT }, 58 { "BOTH", Owner::BOTH }, 59 }; 60 61 Manager::Manager(sdbusplus::bus::bus& bus) 62 : bus(bus), 63 propertyChangeMatch(bus, MATCH_PROPERTY_CHANGE, onPropertyChanged, this), 64 pgoodChangeMatch(bus, MATCH_PGOOD_CHANGE, onPgoodChanged, this) 65 { 66 checkHostOn(); 67 68 // Restore settings from persistent storage 69 restoreSettings(); 70 71 // Check the settings daemon to process the new settings 72 onPropertyChanged(PROPERTY_TIME_MODE, getSettings(PROPERTY_TIME_MODE)); 73 onPropertyChanged(PROPERTY_TIME_OWNER, getSettings(PROPERTY_TIME_OWNER)); 74 75 checkDhcpNtp(); 76 } 77 78 void Manager::addListener(PropertyChangeListner* listener) 79 { 80 // Notify listener about the initial value 81 listener->onModeChanged(timeMode); 82 listener->onOwnerChanged(timeOwner); 83 84 listeners.insert(listener); 85 } 86 87 void Manager::restoreSettings() 88 { 89 auto mode = utils::readData<std::string>(modeFile); 90 if (!mode.empty()) 91 { 92 timeMode = convertToMode(mode); 93 } 94 auto owner = utils::readData<std::string>(ownerFile); 95 if (!owner.empty()) 96 { 97 timeOwner = convertToOwner(owner); 98 } 99 } 100 101 void Manager::checkHostOn() 102 { 103 int pgood = utils::getProperty<int>(bus, 104 POWER_SERVICE, 105 POWER_PATH, 106 POWER_INTERFACE, 107 PGOOD_STR); 108 hostOn = static_cast<bool>(pgood); 109 } 110 111 void Manager::checkDhcpNtp() 112 { 113 std::string useDhcpNtp = utils::getProperty<std::string>( 114 bus, 115 SETTINGS_SERVICE, 116 SETTINGS_PATH, 117 SETTINGS_INTERFACE, 118 PROPERTY_DHCP_NTP); 119 updateDhcpNtpSetting(useDhcpNtp); 120 } 121 122 void Manager::onPropertyChanged(const std::string& key, 123 const std::string& value) 124 { 125 if (hostOn) 126 { 127 // If host is on, set the values as requested time mode/owner. 128 // And when host becomes off, notify the listners. 129 setPropertyAsRequested(key, value); 130 } 131 else 132 { 133 // If host is off, notify listners 134 if (key == PROPERTY_TIME_MODE) 135 { 136 setCurrentTimeMode(value); 137 for (const auto listener : listeners) 138 { 139 listener->onModeChanged(timeMode); 140 } 141 // When time_mode is updated, update the NTP setting 142 updateNtpSetting(value); 143 } 144 else if (key == PROPERTY_TIME_OWNER) 145 { 146 setCurrentTimeOwner(value); 147 for (const auto listener : listeners) 148 { 149 listener->onOwnerChanged(timeOwner); 150 } 151 } 152 } 153 } 154 155 int Manager::onPropertyChanged(sd_bus_message* msg, 156 void* userData, 157 sd_bus_error* retError) 158 { 159 using properties = std::map < std::string, 160 sdbusplus::message::variant<std::string> >; 161 auto m = sdbusplus::message::message(msg); 162 // message type: sa{sv}as 163 std::string ignore; 164 properties props; 165 m.read(ignore, props); 166 auto manager = static_cast<Manager*>(userData); 167 for (const auto& item : props) 168 { 169 if (managedProperties.find(item.first) != managedProperties.end()) 170 { 171 // For managed properties, notify listeners 172 manager->onPropertyChanged( 173 item.first, item.second.get<std::string>()); 174 } 175 else if (item.first == PROPERTY_DHCP_NTP) 176 { 177 // For other manager interested properties, handle specifically 178 manager->updateDhcpNtpSetting(item.second.get<std::string>()); 179 } 180 } 181 return 0; 182 } 183 184 void Manager::setPropertyAsRequested(const std::string& key, 185 const std::string& value) 186 { 187 if (key == PROPERTY_TIME_MODE) 188 { 189 setRequestedMode(value); 190 } 191 else if (key == PROPERTY_TIME_OWNER) 192 { 193 setRequestedOwner(value); 194 } 195 else 196 { 197 // The key shall be already the supported one 198 // TODO: use elog API 199 assert(false); 200 } 201 } 202 203 void Manager::setRequestedMode(const std::string& mode) 204 { 205 requestedMode = mode; 206 } 207 208 void Manager::setRequestedOwner(const std::string& owner) 209 { 210 requestedOwner = owner; 211 } 212 213 void Manager::updateNtpSetting(const std::string& value) 214 { 215 bool isNtp = (value == "NTP"); 216 auto method = bus.new_method_call(SYSTEMD_TIME_SERVICE, 217 SYSTEMD_TIME_PATH, 218 SYSTEMD_TIME_INTERFACE, 219 METHOD_SET_NTP); 220 method.append(isNtp, false); // isNtp: 'true/false' means Enable/Disable 221 // 'false' meaning no policy-kit 222 223 if (bus.call(method)) 224 { 225 log<level::INFO>("Updated NTP setting", 226 entry("ENABLED:%d", isNtp)); 227 } 228 else 229 { 230 log<level::ERR>("Failed to update NTP setting"); 231 } 232 } 233 234 void Manager::updateDhcpNtpSetting(const std::string& useDhcpNtp) 235 { 236 auto method = bus.new_method_call(OBMC_NETWORK_SERVICE, 237 OBMC_NETWORK_PATH, 238 OBMC_NETWORK_INTERFACE, 239 METHOD_UPDATE_USE_NTP); 240 method.append(useDhcpNtp); 241 242 if (bus.call(method)) 243 { 244 log<level::INFO>("Updated use ntp field", 245 entry("USENTPFIELD:%s", useDhcpNtp.c_str())); 246 } 247 else 248 { 249 log<level::ERR>("Failed to update UseNtpField"); 250 } 251 } 252 253 void Manager::onPgoodChanged(bool pgood) 254 { 255 hostOn = pgood; 256 if (hostOn) 257 { 258 return; 259 } 260 if (!requestedMode.empty()) 261 { 262 setCurrentTimeMode(requestedMode); 263 for (const auto& listener : listeners) 264 { 265 listener->onModeChanged(timeMode); 266 } 267 updateNtpSetting(requestedMode); 268 setRequestedMode({}); // Clear requested mode 269 } 270 if (!requestedOwner.empty()) 271 { 272 setCurrentTimeOwner(requestedOwner); 273 for (const auto& listener : listeners) 274 { 275 listener->onOwnerChanged(timeOwner); 276 } 277 setRequestedOwner({}); // Clear requested owner 278 } 279 } 280 281 int Manager::onPgoodChanged(sd_bus_message* msg, 282 void* userData, 283 sd_bus_error* retError) 284 { 285 using properties = std::map < std::string, 286 sdbusplus::message::variant<int> >; 287 auto m = sdbusplus::message::message(msg); 288 // message type: sa{sv}as 289 std::string ignore; 290 properties props; 291 m.read(ignore, props); 292 for (const auto& item : props) 293 { 294 if (item.first == PGOOD_STR) 295 { 296 static_cast<Manager*>(userData) 297 ->onPgoodChanged(static_cast<bool>(item.second.get<int>())); 298 } 299 } 300 return 0; 301 } 302 303 void Manager::setCurrentTimeMode(const std::string& mode) 304 { 305 log<level::INFO>("Time mode is changed", 306 entry("MODE=%s", mode.c_str())); 307 timeMode = convertToMode(mode); 308 utils::writeData(modeFile, mode); 309 } 310 311 void Manager::setCurrentTimeOwner(const std::string& owner) 312 { 313 log<level::INFO>("Time owner is changed", 314 entry("OWNER=%s", owner.c_str())); 315 timeOwner = convertToOwner(owner); 316 utils::writeData(ownerFile, owner); 317 } 318 319 std::string Manager::getSettings(const char* value) const 320 { 321 return utils::getProperty<std::string>( 322 bus, 323 SETTINGS_SERVICE, 324 SETTINGS_PATH, 325 SETTINGS_INTERFACE, 326 value); 327 } 328 329 Mode Manager::convertToMode(const std::string& mode) 330 { 331 if (mode == "NTP") 332 { 333 return Mode::NTP; 334 } 335 else if (mode == "MANUAL") 336 { 337 return Mode::MANUAL; 338 } 339 else 340 { 341 log<level::ERR>("Unrecognized mode", 342 entry("%s", mode.c_str())); 343 return Mode::NTP; 344 } 345 } 346 347 Owner Manager::convertToOwner(const std::string& owner) 348 { 349 auto it = ownerMap.find(owner); 350 if (it == ownerMap.end()) 351 { 352 log<level::ERR>("Unrecognized owner", 353 entry("%s", owner.c_str())); 354 return Owner::BMC; 355 } 356 return it->second; 357 } 358 359 } 360 } 361