Vishwanatha | 81ee91f | 2016-08-30 17:17:13 +0530 | [diff] [blame] | 1 | #include <map> |
| 2 | #include <systemd/sd-bus.h> |
Deepak Kodihalli | 4188567 | 2017-07-25 06:49:45 -0500 | [diff] [blame] | 3 | #include <sdbusplus/bus/match.hpp> |
Deepak Kodihalli | 20ed79e | 2017-07-25 05:48:58 -0500 | [diff] [blame] | 4 | #include "settings.hpp" |
Vishwanatha | 81ee91f | 2016-08-30 17:17:13 +0530 | [diff] [blame] | 5 | |
| 6 | /** @class TimeConfig |
| 7 | * @brief Maintains various time modes and time owners. |
| 8 | */ |
| 9 | class TimeConfig |
| 10 | { |
| 11 | public: |
| 12 | /** @brief Supported time modes |
| 13 | * NTP Time sourced by Network Time Server |
| 14 | * MANUAL User of the system need to set the time |
| 15 | */ |
| 16 | enum class timeModes |
| 17 | { |
| 18 | NTP, |
| 19 | MANUAL |
| 20 | }; |
| 21 | |
| 22 | /** @brief Supported time owners |
| 23 | * BMC Time source may be NTP or MANUAL but it has to be set natively |
| 24 | * on the BMC. Meaning, host can not set the time. What it also |
| 25 | * means is that when BMC gets IPMI_SET_SEL_TIME, then its ignored. |
| 26 | * similarly, when BMC gets IPMI_GET_SEL_TIME, then the BMC's time |
| 27 | * is returned. |
| 28 | * |
| 29 | * HOST Its only IPMI_SEL_SEL_TIME that will set the time on BMC. |
| 30 | * Meaning, IPMI_GET_SEL_TIME and request to get BMC time will |
| 31 | * result in same value. |
| 32 | * |
| 33 | * SPLIT Both BMC and HOST will maintain their individual clocks but then |
| 34 | * the time information is stored in BMC. BMC can have either NTP |
| 35 | * or MANUAL as it's source of time and will set the time directly |
| 36 | * on the BMC. When IPMI_SET_SEL_TIME is received, then the delta |
| 37 | * between that and BMC's time is calculated and is stored. |
| 38 | * When BMC reads the time, the current time is returned. |
| 39 | * When IPMI_GET_SEL_TIME is received, BMC's time is retrieved and |
| 40 | * then the delta offset is factored in prior to returning. |
| 41 | * |
| 42 | * BOTH: BMC's time is set with whoever that sets the time. Similarly, |
| 43 | * BMC's time is returned to whoever that asks the time. |
| 44 | */ |
| 45 | enum class timeOwners |
| 46 | { |
| 47 | BMC, |
| 48 | HOST, |
| 49 | SPLIT, |
| 50 | BOTH |
| 51 | }; |
| 52 | |
| 53 | // Do not have a usecase of copying this object so disable |
| 54 | TimeConfig(); |
| 55 | ~TimeConfig() = default; |
| 56 | TimeConfig(const TimeConfig&) = delete; |
| 57 | TimeConfig& operator=(const TimeConfig&) = delete; |
| 58 | TimeConfig(TimeConfig&&) = delete; |
| 59 | TimeConfig& operator=(TimeConfig&&) = delete; |
| 60 | |
| 61 | inline auto getCurrTimeMode() const |
| 62 | { |
| 63 | return iv_CurrTimeMode; |
| 64 | } |
| 65 | |
| 66 | inline auto getCurrTimeOwner() const |
| 67 | { |
| 68 | return iv_CurrTimeOwner; |
| 69 | } |
| 70 | |
| 71 | inline auto getRequestedTimeMode() const |
| 72 | { |
| 73 | return iv_RequestedTimeMode; |
| 74 | } |
| 75 | |
| 76 | inline auto getRequestedTimeOwner() const |
| 77 | { |
| 78 | return iv_RequestedTimeOwner; |
| 79 | } |
| 80 | |
| 81 | inline auto isSplitModeChanged() const |
| 82 | { |
| 83 | return iv_SplitModeChanged; |
| 84 | } |
| 85 | |
| 86 | inline void updateSplitModeFlag(const bool& value) |
| 87 | { |
| 88 | iv_SplitModeChanged = value; |
| 89 | } |
| 90 | |
| 91 | inline sd_bus* getDbus() const |
| 92 | { |
| 93 | return iv_dbus; |
| 94 | } |
| 95 | |
| 96 | /** brief Generic file reader used to read time mode, |
| 97 | * time owner, host time, host offset and useDhcpNtp |
| 98 | * |
| 99 | * @param[in] filename - Name of file where data is preserved. |
| 100 | * @return - File content |
| 101 | */ |
| 102 | template <typename T> |
| 103 | T readData(const char* fileName) |
| 104 | { |
| 105 | T data = T(); |
| 106 | if(std::ifstream(fileName)) |
| 107 | { |
| 108 | std::ifstream file(fileName, std::ios::in); |
| 109 | file >> data; |
| 110 | file.close(); |
| 111 | } |
| 112 | return data; |
| 113 | } |
| 114 | |
| 115 | /** @brief Generic file writer used to write time mode, |
| 116 | * time owner, host time, host offset and useDhcpNtp |
| 117 | * |
| 118 | * @param[in] filename - Name of file where data is preserved. |
| 119 | * @param[in] data - Data to be written to file |
| 120 | * @return - 0 for now. But will be changed to raising |
| 121 | * - Exception |
| 122 | */ |
| 123 | template <typename T> |
Patrick Williams | f0c91c0 | 2016-11-09 21:35:04 -0600 | [diff] [blame] | 124 | auto writeData(const char* fileName, T&& data) |
Vishwanatha | 81ee91f | 2016-08-30 17:17:13 +0530 | [diff] [blame] | 125 | { |
| 126 | std::ofstream file(fileName, std::ios::out); |
| 127 | file << data; |
| 128 | file.close(); |
| 129 | return 0; |
| 130 | } |
| 131 | |
| 132 | /** @brief Reads saved data and populates below properties |
| 133 | * - Current Time Mode |
| 134 | * - Current Time Owner |
| 135 | * - Whether to use NTP settings given by DHCP |
| 136 | * - Last known host offset |
| 137 | * |
| 138 | * @param[in] dbus - Handler to sd_bus used by time manager |
| 139 | * |
| 140 | * @return - < 0 for failure and others for success |
| 141 | */ |
| 142 | int processInitialSettings(sd_bus* dbus); |
| 143 | |
| 144 | /** @brief Accepts time mode string, returns the equivalent enum |
| 145 | * |
| 146 | * @param[in] timeModeStr - Current Time Mode in string |
| 147 | * |
| 148 | * @return - Equivalent ENUM |
| 149 | * - Input : "NTP", Output: timeModes::NTP |
| 150 | */ |
| 151 | static timeModes getTimeMode(const char* timeModeStr); |
| 152 | |
| 153 | /** @brief Accepts timeMode enum and returns it's string equivalent |
| 154 | * |
| 155 | * @param[in] timeMode - Current Time Mode Enum |
| 156 | * |
| 157 | * @return - Equivalent string |
| 158 | * - Input : timeModes::NTP, Output : "NTP" |
| 159 | */ |
| 160 | static const char* modeStr(const timeModes timeMode); |
| 161 | |
| 162 | /** @brief Accepts timeOwner string and returns it's equivalent enum |
| 163 | * |
| 164 | * @param[in] timeOwnerStr - Current Time Owner in string |
| 165 | * |
| 166 | * @return - Equivalent ENUM |
| 167 | * - Input : "BMC", output : timeOwners::BMC |
| 168 | */ |
| 169 | static timeOwners getTimeOwner(const char* timeOwnerStr); |
| 170 | |
| 171 | /** @brief Accepts timeOwner enum and returns it's string equivalent |
| 172 | * |
| 173 | * @param[in] timeOwner - Current Time Mode Enum |
| 174 | * |
| 175 | * @return - Equivalent string |
| 176 | * - Input : timeOwners::BMC, Output : "BMC" |
| 177 | */ |
| 178 | static const char* ownerStr(const timeOwners timeOwner); |
| 179 | |
| 180 | /** @brief Gets called when the settings property changes. |
| 181 | * Walks the map and then applies the changes |
| 182 | * |
| 183 | * @param[in] key - Name of the property |
| 184 | * @param[in] value - Value |
| 185 | * |
| 186 | * @return - < 0 on failure, success otherwise |
| 187 | */ |
| 188 | int updatePropertyVal(const char* key, const std::string& value); |
| 189 | |
| 190 | // Acts on the time property changes / reads initial property |
| 191 | using READER = std::string (TimeConfig::*) (const char*); |
| 192 | using UPDATER = int (TimeConfig::*) (const std::string&); |
| 193 | using FUNCTOR = std::tuple<READER, UPDATER>; |
| 194 | |
| 195 | // Most of this is statically constructed and PGOOD is added later. |
| 196 | static std::map<std::string, FUNCTOR> iv_TimeParams; |
| 197 | |
Deepak Kodihalli | 4188567 | 2017-07-25 06:49:45 -0500 | [diff] [blame] | 198 | /** @brief Callback to handle change in a setting |
| 199 | * |
| 200 | * @param[in] msg - sdbusplus dbusmessage |
| 201 | * |
| 202 | * @return 0 on success, < 0 on failure. |
| 203 | */ |
| 204 | int settingsChanged(sdbusplus::message::message& msg); |
| 205 | |
Vishwanatha | 81ee91f | 2016-08-30 17:17:13 +0530 | [diff] [blame] | 206 | private: |
| 207 | // Bus initialised by manager on a call to process initial settings |
| 208 | sd_bus *iv_dbus; |
| 209 | |
| 210 | /** @brief 'Requested' is what is asked by user in settings |
| 211 | * 'Current' is what the TimeManager is really using since its not |
| 212 | * possible to apply the mode and owner as and when the user updates |
| 213 | * Settings. They are only applied when the system power is off. |
| 214 | */ |
| 215 | timeModes iv_CurrTimeMode; |
| 216 | timeModes iv_RequestedTimeMode; |
| 217 | |
| 218 | timeOwners iv_CurrTimeOwner; |
| 219 | timeOwners iv_RequestedTimeOwner; |
| 220 | |
| 221 | /** @brief One of the entry in .network file indicates whether the |
| 222 | * systemd-timesyncd should use the NTP server list that are sent by DHCP |
| 223 | * server or not. If the value is 'yes', then NTP server list sent by DHCP |
| 224 | * are used. else entries that are configured statically with NTP= are used |
| 225 | */ |
| 226 | std::string iv_CurrDhcpNtp; |
| 227 | |
| 228 | /** @brief Dictated by state of pgood. When the pgood value is 'zero', then |
| 229 | * its an indication that we are okay to apply any pending Mode / Owner |
| 230 | * values. Meaning, Current will be updated with what is in Requested. |
| 231 | */ |
| 232 | bool iv_SettingChangeAllowed; |
| 233 | |
| 234 | // Needed to nudge Time Manager to reset offset |
| 235 | bool iv_SplitModeChanged; |
| 236 | |
Deepak Kodihalli | 20ed79e | 2017-07-25 05:48:58 -0500 | [diff] [blame] | 237 | /** @brief Settings objects of intereset */ |
| 238 | settings::Objects settings; |
| 239 | |
Deepak Kodihalli | 4188567 | 2017-07-25 06:49:45 -0500 | [diff] [blame] | 240 | /** @brief sbdbusplus match objects */ |
| 241 | std::vector<sdbusplus::bus::match_t> settingsMatches; |
| 242 | |
Vishwanatha | 81ee91f | 2016-08-30 17:17:13 +0530 | [diff] [blame] | 243 | static constexpr auto cv_TimeModeFile = "/var/lib/obmc/saved_timeMode"; |
| 244 | static constexpr auto cv_TimeOwnerFile = "/var/lib/obmc/saved_timeOwner"; |
| 245 | static constexpr auto cv_DhcpNtpFile = "/var/lib/obmc/saved_dhcpNtp"; |
| 246 | |
| 247 | /** @brief Wrapper that looks up in the mapper service for a given |
| 248 | * object path and returns the service name |
| 249 | * |
| 250 | * @param[in] objpath - dbus object path |
| 251 | * |
| 252 | * @return - unique_ptr holding service name. |
| 253 | * - Caller needs to validate if its populated |
| 254 | */ |
| 255 | std::unique_ptr<char> getProvider(const char* objPath); |
| 256 | |
| 257 | /** @brief Helper function for processInitialSettings. |
| 258 | * Reads saved data and populates below properties. Only the values are |
| 259 | * read from the file system. but it will not take the action on those. |
| 260 | * Actions on these are taken by processInitialSettings |
| 261 | * |
| 262 | * - Current Time Mode |
| 263 | * - Current Time Owner |
| 264 | * - Whether to use NTP settings given by DHCP |
| 265 | * - Current Pgood state |
| 266 | * |
| 267 | * @return - < 0 for failure and success on others |
| 268 | */ |
| 269 | int readPersistentData(); |
| 270 | |
| 271 | /** @brief Updates the 'ntp' field in systemd/timedate1, |
| 272 | * which enables / disables NTP syncing |
| 273 | * |
| 274 | * @param[in] newTimeMode - Time Mode Enum |
| 275 | * |
| 276 | * @return - < 0 on failure and success on others |
| 277 | */ |
| 278 | int modifyNtpSettings(const timeModes& newTimeMode); |
| 279 | |
| 280 | /** @brief Accepts system setting parameter and returns its value |
| 281 | * |
| 282 | * @param[in] key - Name of the property |
| 283 | * |
| 284 | * @return - Value as string |
| 285 | */ |
| 286 | std::string getSystemSettings(const char* key); |
| 287 | |
Deepak Kodihalli | 4188567 | 2017-07-25 06:49:45 -0500 | [diff] [blame] | 288 | /** @brief Returns the time owner setting |
| 289 | * |
| 290 | * @param[in] path - Time owner setting object path |
| 291 | * |
| 292 | * @return - Value as string |
| 293 | */ |
| 294 | std::string getTimeOwnerSetting(const char* path); |
| 295 | |
| 296 | /** @brief Returns the time sync method setting |
| 297 | * |
| 298 | * @param[in] path - Time sync method setting object path |
| 299 | * |
| 300 | * @return - Value as string |
| 301 | */ |
| 302 | std::string getTimeSyncMethodSetting(const char* path); |
| 303 | |
Vishwanatha | 81ee91f | 2016-08-30 17:17:13 +0530 | [diff] [blame] | 304 | /** @brief Reads the data hosted by /org/openbmc/control/power0 |
| 305 | * |
| 306 | * @param[in] key - Name of the property |
| 307 | * |
| 308 | * @return - Value as string |
| 309 | */ |
| 310 | std::string getPowerSetting(const char* key); |
| 311 | |
| 312 | /** @brief Accepts Mode string and applies only if conditions allow it. |
| 313 | * |
| 314 | * @param[in] newModeStr - Requested Time Mode |
| 315 | * |
| 316 | * @return - < 0 on failure, success otherwise |
| 317 | */ |
| 318 | int updateTimeMode(const std::string& newModeStr); |
| 319 | |
| 320 | /** @brief Accepts Ownere string and applies only if conditions allow it. |
| 321 | * |
| 322 | * @param[in] newOwnerStr - Requested Time Owner |
| 323 | * |
| 324 | * @return - < 0 on failure, success otherwise |
| 325 | */ |
| 326 | |
| 327 | int updateTimeOwner(const std::string& newownerStr); |
| 328 | |
| 329 | /** @brief Updates .network file with UseNtp= provided by NetworkManager |
| 330 | * |
| 331 | * @param[in] useDhcpNtp - will be 'yes' or 'no' |
| 332 | * |
| 333 | * @return - < 0 on failure, success otherwise |
| 334 | */ |
| 335 | int updateNetworkSettings(const std::string& useDhcpNtp); |
| 336 | |
| 337 | /** @brief Accepts current pgood value and then updates any pending mode |
| 338 | * or owner requests |
| 339 | * |
| 340 | * @param[in] useDhcpNtp - will be 'yes' or 'no' |
| 341 | * |
| 342 | * @return - < 0 on failure, success otherwise |
| 343 | */ |
| 344 | int processPgoodChange(const std::string& newPgood); |
| 345 | }; |