Enable cpuQuota options, fix cpuQuota logic
[platform/core/security/vasum.git] / server / zone-admin.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Jan Olszak <j.olszak@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author  Jan Olszak (j.olszak@samsung.com)
22  * @brief   Implementation of class for administrating one zone
23  */
24
25 #include "config.hpp"
26
27 #include "zone-admin.hpp"
28 #include "exception.hpp"
29
30 #include "logger/logger.hpp"
31 #include "utils/paths.hpp"
32 #include "utils/c-array.hpp"
33 #include "lxc/cgroup.hpp"
34
35 #include <cassert>
36 #include <climits>
37
38
39 namespace vasum {
40
41 namespace {
42
43 // TODO: this should be in zone's configuration file
44 const int SHUTDOWN_WAIT = 10;
45
46 } // namespace
47
48 const std::uint64_t DEFAULT_CPU_SHARES = 1024;
49 const std::uint64_t DEFAULT_VCPU_PERIOD_MS = 100000;
50
51 ZoneAdmin::ZoneAdmin(const std::string& zoneId,
52                      const std::string& zonesPath,
53                      const std::string& lxcTemplatePrefix,
54                      const ZoneConfig& config,
55                      const ZoneDynamicConfig& dynamicConfig)
56     : mConfig(config),
57       mZone(zonesPath, zoneId),
58       mId(zoneId),
59       mDetachOnExit(false),
60       mDestroyOnExit(false)
61 {
62     LOGD(mId << ": Instantiating ZoneAdmin object");
63
64     if (!mZone.isDefined()) {
65
66         const std::string lxcTemplate = utils::getAbsolutePath(config.lxcTemplate,
67                                                                lxcTemplatePrefix);
68         LOGI(mId << ": Creating zone from template: " << lxcTemplate);
69         utils::CStringArrayBuilder args;
70         if (!dynamicConfig.ipv4Gateway.empty()) {
71             args.add("--ipv4-gateway");
72             args.add(dynamicConfig.ipv4Gateway.c_str());
73         }
74         if (!dynamicConfig.ipv4.empty()) {
75             args.add("--ipv4");
76             args.add(dynamicConfig.ipv4.c_str());
77         }
78         const std::string vt = std::to_string(dynamicConfig.vt);
79         if (dynamicConfig.vt > 0) {
80             args.add("--vt");
81             args.add(vt.c_str());
82         }
83         if (!mZone.create(lxcTemplate, args.c_array())) {
84             throw ZoneOperationException("Could not create zone");
85         }
86     }
87 }
88
89
90 ZoneAdmin::~ZoneAdmin()
91 {
92     LOGD(mId << ": Destroying ZoneAdmin object...");
93
94     if (mDestroyOnExit) {
95         if (!mZone.stop()) {
96             LOGE(mId << ": Failed to stop the zone");
97         }
98         if (!mZone.destroy()) {
99             LOGE(mId << ": Failed to destroy the zone");
100         }
101     }
102
103     if (!mDetachOnExit) {
104         // Try to forcefully stop
105         if (!mZone.stop()) {
106             LOGE(mId << ": Failed to stop the zone");
107         }
108     }
109
110     LOGD(mId << ": ZoneAdmin object destroyed");
111 }
112
113
114 const std::string& ZoneAdmin::getId() const
115 {
116     return mId;
117 }
118
119
120 void ZoneAdmin::start()
121 {
122     LOGD(mId << ": Starting...");
123     if (isRunning()) {
124         LOGD(mId << ": Already running - nothing to do...");
125         return;
126     }
127
128     utils::CStringArrayBuilder args;
129     for (const std::string& arg : mConfig.initWithArgs) {
130         args.add(arg.c_str());
131     }
132     if (args.empty()) {
133         args.add("/sbin/init");
134     }
135
136     if (!mZone.start(args.c_array())) {
137         throw ZoneOperationException("Could not start zone");
138     }
139
140     LOGD(mId << ": Started");
141 }
142
143
144 void ZoneAdmin::stop()
145 {
146     LOGD(mId << ": Stopping procedure started...");
147     if (isStopped()) {
148         LOGD(mId << ": Already crashed/down/off - nothing to do");
149         return;
150     }
151
152     if (!mZone.shutdown(SHUTDOWN_WAIT)) {
153         // force stop
154         if (!mZone.stop()) {
155             throw ZoneOperationException("Could not stop zone");
156         }
157     }
158
159     LOGD(mId << ": Stopping procedure ended");
160 }
161
162
163 void ZoneAdmin::destroy()
164 {
165     LOGD(mId << ": Destroying procedure started...");
166
167     if (!mZone.destroy()) {
168         throw ZoneOperationException("Could not destroy zone");
169     }
170
171     LOGD(mId << ": Destroying procedure ended");
172 }
173
174
175 bool ZoneAdmin::isRunning()
176 {
177     return mZone.getState() == lxc::LxcZone::State::RUNNING;
178 }
179
180
181 bool ZoneAdmin::isStopped()
182 {
183     return mZone.getState() == lxc::LxcZone::State::STOPPED;
184 }
185
186
187 void ZoneAdmin::suspend()
188 {
189     LOGD(mId << ": Pausing...");
190     if (!mZone.freeze()) {
191         throw ZoneOperationException("Could not pause zone");
192     }
193     LOGD(mId << ": Paused");
194 }
195
196
197 void ZoneAdmin::resume()
198 {
199     LOGD(mId << ": Resuming...");
200     if (!mZone.unfreeze()) {
201         throw ZoneOperationException("Could not resume zone");
202     }
203     LOGD(mId << ": Resumed");
204 }
205
206
207 bool ZoneAdmin::isPaused()
208 {
209     return mZone.getState() == lxc::LxcZone::State::FROZEN;
210 }
211
212
213 void ZoneAdmin::setSchedulerLevel(SchedulerLevel sched)
214 {
215     assert(isRunning());
216
217     switch (sched) {
218     case SchedulerLevel::FOREGROUND:
219         LOGD(mId << ": Setting SchedulerLevel::FOREGROUND");
220         setSchedulerParams(DEFAULT_CPU_SHARES,
221                            DEFAULT_VCPU_PERIOD_MS,
222                            mConfig.cpuQuotaForeground);
223         break;
224     case SchedulerLevel::BACKGROUND:
225         LOGD(mId << ": Setting SchedulerLevel::BACKGROUND");
226         setSchedulerParams(DEFAULT_CPU_SHARES,
227                            DEFAULT_VCPU_PERIOD_MS,
228                            mConfig.cpuQuotaBackground);
229         break;
230     default:
231         assert(0 && "Unknown sched parameter value");
232     }
233 }
234
235
236 void ZoneAdmin::setSchedulerParams(std::uint64_t cpuShares,
237                                    std::uint64_t vcpuPeriod,
238                                    std::int64_t vcpuQuota)
239 {
240     assert(vcpuPeriod >= 1000 && vcpuPeriod <= 1000000);
241     assert(vcpuQuota == -1 ||
242            (vcpuQuota >= 1000 && vcpuQuota <= static_cast<std::int64_t>(ULLONG_MAX / 1000)));
243
244     if (!lxc::setCgroup(mId, "cpu", "cpu.shares", std::to_string(cpuShares)) ||
245         !lxc::setCgroup(mId, "cpu", "cpu.cfs_period_us", std::to_string(vcpuPeriod)) ||
246         !lxc::setCgroup(mId, "cpu", "cpu.cfs_quota_us", std::to_string(vcpuQuota))) {
247
248         LOGE(mId << ": Error while setting the zone's scheduler params");
249         throw ZoneOperationException("Could not set scheduler params");
250     }
251 }
252
253 void ZoneAdmin::setDetachOnExit()
254 {
255     mDetachOnExit = true;
256 }
257
258 void ZoneAdmin::setDestroyOnExit()
259 {
260     mDestroyOnExit = true;
261 }
262
263 std::int64_t ZoneAdmin::getSchedulerQuota()
264 {
265     std::string ret;
266     if (!lxc::getCgroup(mId, "cpu", "cpu.cfs_quota_us", ret)) {
267         LOGE(mId << ": Error while getting the zone's scheduler quota param");
268         throw ZoneOperationException("Could not get scheduler quota param");
269     }
270     return std::stoll(ret);
271 }
272
273 void ZoneAdmin::createNetdevVeth(const std::string& /* zoneDev */,
274                                  const std::string& /* hostDev */)
275 {
276     throw ZoneOperationException("Not implemented");
277 }
278
279 void ZoneAdmin::createNetdevMacvlan(const std::string& /* zoneDev */,
280                                     const std::string& /* hostDev */,
281                                     const uint32_t& /* mode */)
282 {
283     throw ZoneOperationException("Not implemented");
284 }
285
286 void ZoneAdmin::moveNetdev(const std::string& /* devId */)
287 {
288     throw ZoneOperationException("Not implemented");
289 }
290
291 } // namespace vasum