summaryrefslogtreecommitdiffstats
path: root/time-config.hpp
blob: 257ab3043ec73e06bb056e3a13c0cfe4a772926e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
#include <map>
#include <systemd/sd-bus.h>
#include <sdbusplus/bus/match.hpp>
#include "settings.hpp"

/** @class TimeConfig
 *  @brief Maintains various time modes and time owners.
 */
class TimeConfig
{
public:
    /** @brief Supported time modes
     *  NTP     Time sourced by Network Time Server
     *  MANUAL  User of the system need to set the time
     */
    enum class timeModes
    {
        NTP,
        MANUAL
    };

    /** @brief Supported time owners
     *  BMC     Time source may be NTP or MANUAL but it has to be set natively
     *          on the BMC. Meaning, host can not set the time. What it also
     *          means is that when BMC gets IPMI_SET_SEL_TIME, then its ignored.
     *          similarly, when BMC gets IPMI_GET_SEL_TIME, then the BMC's time
     *          is returned.
     *
     *  HOST    Its only IPMI_SEL_SEL_TIME that will set the time on BMC.
     *          Meaning, IPMI_GET_SEL_TIME and request to get BMC time will
     *          result in same value.
     *
     *  SPLIT   Both BMC and HOST will maintain their individual clocks but then
     *          the time information is stored in BMC. BMC can have either NTP
     *          or MANUAL as it's source of time and will set the time directly
     *          on the BMC. When IPMI_SET_SEL_TIME is received, then the delta
     *          between that and BMC's time is calculated and is stored.
     *          When BMC reads the time, the current time is returned.
     *          When IPMI_GET_SEL_TIME is received, BMC's time is retrieved and
     *          then the delta offset is factored in prior to returning.
     *
     *  BOTH:   BMC's time is set with whoever that sets the time. Similarly,
     *          BMC's time is returned to whoever that asks the time.
     */
    enum class timeOwners
    {
        BMC,
        HOST,
        SPLIT,
        BOTH
    };

    // Do not have a usecase of copying this object so disable
    TimeConfig();
    ~TimeConfig() = default;
    TimeConfig(const TimeConfig&) = delete;
    TimeConfig& operator=(const TimeConfig&) = delete;
    TimeConfig(TimeConfig&&) = delete;
    TimeConfig& operator=(TimeConfig&&) = delete;

    inline auto getCurrTimeMode() const
    {
        return iv_CurrTimeMode;
    }

    inline auto getCurrTimeOwner() const
    {
        return iv_CurrTimeOwner;
    }

    inline auto getRequestedTimeMode() const
    {
        return iv_RequestedTimeMode;
    }

    inline auto getRequestedTimeOwner() const
    {
        return iv_RequestedTimeOwner;
    }

    inline auto isSplitModeChanged() const
    {
        return iv_SplitModeChanged;
    }

    inline void updateSplitModeFlag(const bool& value)
    {
        iv_SplitModeChanged = value;
    }

    inline sd_bus* getDbus() const
    {
        return iv_dbus;
    }

    /** brief Generic file reader used to read time mode,
     *  time owner, host time,  host offset and useDhcpNtp
     *
     *  @param[in] filename - Name of file where data is preserved.
     *  @return             - File content
     */
    template <typename T>
    T readData(const char* fileName)
    {
        T data = T();
        if(std::ifstream(fileName))
        {
            std::ifstream file(fileName, std::ios::in);
            file >> data;
            file.close();
        }
        return data;
    }

    /** @brief Generic file writer used to write time mode,
     *  time owner, host time,  host offset and useDhcpNtp
     *
     *  @param[in] filename - Name of file where data is preserved.
     *  @param[in] data     - Data to be written to file
     *  @return             - 0 for now. But will be changed to raising
     *                      - Exception
     */
    template <typename T>
    auto writeData(const char* fileName, T&& data)
    {
        std::ofstream file(fileName, std::ios::out);
        file << data;
        file.close();
        return 0;
    }

    /** @brief Reads saved data and populates below properties
     *  - Current Time Mode
     *  - Current Time Owner
     *  - Whether to use NTP settings given by DHCP
     *  - Last known host offset
     *
     *  @param[in] dbus -  Handler to sd_bus used by time manager
     *
     *  @return         -  < 0 for failure and others for success
     */
    int processInitialSettings(sd_bus* dbus);

    /** @brief Accepts time mode string, returns the equivalent enum
     *
     *  @param[in] timeModeStr - Current Time Mode in string
     *
     *  @return                - Equivalent ENUM
     *                         - Input : "NTP", Output: timeModes::NTP
     */
    static timeModes getTimeMode(const char* timeModeStr);

    /** @brief Accepts timeMode enum and returns it's string equivalent
     *
     *  @param[in] timeMode - Current Time Mode Enum
     *
     *  @return             - Equivalent string
     *                      - Input : timeModes::NTP, Output : "NTP"
     */
    static const char* modeStr(const timeModes timeMode);

    /** @brief Accepts timeOwner string and returns it's equivalent enum
     *
     *  @param[in] timeOwnerStr - Current Time Owner in string
     *
     *  @return              - Equivalent ENUM
     *                       - Input : "BMC", output : timeOwners::BMC
     */
    static timeOwners getTimeOwner(const char* timeOwnerStr);

    /** @brief Accepts timeOwner enum and returns it's string equivalent
     *
     *  @param[in] timeOwner - Current Time Mode Enum
     *
     *  @return              - Equivalent string
     *                       - Input : timeOwners::BMC, Output : "BMC"
     */
    static const char* ownerStr(const timeOwners timeOwner);

    /** @brief Gets called when the settings property changes.
     *  Walks the map and then applies the changes
     *
     *  @param[in] key   - Name of the property
     *  @param[in] value - Value
     *
     *  @return              - < 0 on failure, success otherwise
     */
    int updatePropertyVal(const char* key, const std::string& value);

    // Acts on the time property changes / reads initial property
    using READER = std::string (TimeConfig::*) (const char*);
    using UPDATER = int (TimeConfig::*) (const std::string&);
    using FUNCTOR = std::tuple<READER, UPDATER>;

    // Most of this is statically constructed and PGOOD is added later.
    static std::map<std::string, FUNCTOR> iv_TimeParams;

    /** @brief Callback to handle change in a setting
     *
     *  @param[in] msg - sdbusplus dbusmessage
     *
     *  @return 0 on success, < 0 on failure.
     */
    int settingsChanged(sdbusplus::message::message& msg);

private:
    // Bus initialised by manager on a call to process initial settings
    sd_bus *iv_dbus;

    /** @brief 'Requested' is what is asked by user in settings
     * 'Current' is what the TimeManager is really using since its not
     *  possible to apply the mode and owner as and when the user updates
     *  Settings. They are only applied when the system power is off.
     */
    timeModes  iv_CurrTimeMode;
    timeModes  iv_RequestedTimeMode;

    timeOwners iv_CurrTimeOwner;
    timeOwners iv_RequestedTimeOwner;

    /** @brief One of the entry in .network file indicates whether the
     *  systemd-timesyncd should use the NTP server list that are sent by DHCP
     *  server or not. If the value is 'yes', then NTP server list sent by DHCP
     *  are used. else entries that are configured statically with NTP= are used
     */
    std::string iv_CurrDhcpNtp;

    /** @brief Dictated by state of pgood. When the pgood value is 'zero', then
     *  its an indication that we are okay to apply any pending Mode / Owner
     *  values. Meaning, Current will be updated with what is in Requested.
     */
    bool        iv_SettingChangeAllowed;

    // Needed to nudge Time Manager to reset offset
    bool        iv_SplitModeChanged;

    /** @brief Settings objects of intereset */
    settings::Objects settings;

    /** @brief sbdbusplus match objects */
    std::vector<sdbusplus::bus::match_t> settingsMatches;

    static constexpr auto cv_TimeModeFile = "/var/lib/obmc/saved_timeMode";
    static constexpr auto cv_TimeOwnerFile = "/var/lib/obmc/saved_timeOwner";
    static constexpr auto cv_DhcpNtpFile = "/var/lib/obmc/saved_dhcpNtp";

    /** @brief Wrapper that looks up in the mapper service for a given
     *  object path and returns the service name
     *
     *  @param[in] objpath - dbus object path
     *
     *  @return            - unique_ptr holding service name.
     *                     - Caller needs to validate if its populated
     */
    std::unique_ptr<char> getProvider(const char* objPath);

    /** @brief Helper function for processInitialSettings.
     *  Reads saved data and populates below properties. Only the values are
     *  read from the file system. but it will not take the action on those.
     *  Actions on these are taken by processInitialSettings
     *
     *  - Current Time Mode
     *  - Current Time Owner
     *  - Whether to use NTP settings given by DHCP
     *  - Current Pgood state
     *
     *  @return         -  < 0 for failure and success on others
     */
    int readPersistentData();

    /** @brief Updates the 'ntp' field in systemd/timedate1,
     *  which enables / disables NTP syncing
     *
     *  @param[in] newTimeMode - Time Mode Enum
     *
     *  @return                - < 0 on failure and success on others
     */
    int modifyNtpSettings(const timeModes& newTimeMode);

    /** @brief Accepts system setting parameter and returns its value
     *
     *  @param[in] key - Name of the property
     *
     *  @return        - Value as string
     */
    std::string getSystemSettings(const char* key);

    /** @brief Returns the time owner setting
     *
     *  @param[in] path - Time owner setting object path
     *
     *  @return        - Value as string
     */
    std::string getTimeOwnerSetting(const char* path);

    /** @brief Returns the time sync method setting
     *
     *  @param[in] path - Time sync method setting object path
     *
     *  @return        - Value as string
     */
    std::string getTimeSyncMethodSetting(const char* path);

    /** @brief Reads the data hosted by /org/openbmc/control/power0
     *
     *  @param[in] key - Name of the property
     *
     *  @return        - Value as string
     */
    std::string getPowerSetting(const char* key);

    /** @brief Accepts Mode string and applies only if conditions allow it.
     *
     *  @param[in] newModeStr - Requested Time Mode
     *
     *  @return               - < 0 on failure, success otherwise
     */
    int updateTimeMode(const std::string& newModeStr);

    /** @brief Accepts Ownere string and applies only if conditions allow it.
     *
     *  @param[in] newOwnerStr - Requested Time Owner
     *
     *  @return               - < 0 on failure, success otherwise
     */

    int updateTimeOwner(const std::string& newownerStr);

    /** @brief Updates .network file with UseNtp= provided by NetworkManager
     *
     *  @param[in] useDhcpNtp - will be 'yes' or 'no'
     *
     *  @return               - < 0 on failure, success otherwise
     */
    int updateNetworkSettings(const std::string& useDhcpNtp);

    /** @brief Accepts current pgood value and then updates any pending mode
     *  or owner requests
     *
     *  @param[in] useDhcpNtp - will be 'yes' or 'no'
     *
     *  @return               - < 0 on failure, success otherwise
     */
    int processPgoodChange(const std::string& newPgood);
};
OpenPOWER on IntegriCloud