Get/set ipv4/ipv6 address, up/down interface
[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 #include "netdev.hpp"
30
31 #include "logger/logger.hpp"
32 #include "utils/paths.hpp"
33 #include "utils/c-array.hpp"
34 #include "lxc/cgroup.hpp"
35
36 #include <cassert>
37 #include <climits>
38 #include <thread>
39 #include <chrono>
40
41
42 namespace vasum {
43
44 namespace {
45
46 // TODO: this should be in zone's configuration file
47 const int SHUTDOWN_WAIT = 10;
48
49 } // namespace
50
51 const std::uint64_t DEFAULT_CPU_SHARES = 1024;
52 const std::uint64_t DEFAULT_VCPU_PERIOD_MS = 100000;
53
54 ZoneAdmin::ZoneAdmin(const std::string& zoneId,
55                      const std::string& zonesPath,
56                      const std::string& lxcTemplatePrefix,
57                      const ZoneConfig& config,
58                      const ZoneDynamicConfig& dynamicConfig)
59     : mConfig(config),
60       mDynamicConfig(dynamicConfig),
61       mZone(zonesPath, zoneId),
62       mId(zoneId),
63       mDetachOnExit(false),
64       mDestroyOnExit(false)
65 {
66     LOGD(mId << ": Instantiating ZoneAdmin object");
67
68     if (!mZone.isDefined()) {
69
70         const std::string lxcTemplate = utils::getAbsolutePath(config.lxcTemplate,
71                                                                lxcTemplatePrefix);
72         LOGI(mId << ": Creating zone from template: " << lxcTemplate);
73         utils::CStringArrayBuilder args;
74         if (!dynamicConfig.ipv4Gateway.empty()) {
75             args.add("--ipv4-gateway");
76             args.add(dynamicConfig.ipv4Gateway.c_str());
77         }
78         if (!dynamicConfig.ipv4.empty()) {
79             args.add("--ipv4");
80             args.add(dynamicConfig.ipv4.c_str());
81         }
82         const std::string vt = std::to_string(dynamicConfig.vt);
83         if (dynamicConfig.vt > 0) {
84             args.add("--vt");
85             args.add(vt.c_str());
86         }
87         if (!mZone.create(lxcTemplate, args.c_array())) {
88             throw ZoneOperationException("Could not create zone");
89         }
90     }
91 }
92
93
94 ZoneAdmin::~ZoneAdmin()
95 {
96     LOGD(mId << ": Destroying ZoneAdmin object...");
97
98     if (mDestroyOnExit) {
99         if (!mZone.stop()) {
100             LOGE(mId << ": Failed to stop the zone");
101         }
102         if (!mZone.destroy()) {
103             LOGE(mId << ": Failed to destroy the zone");
104         }
105     }
106
107     if (!mDetachOnExit) {
108         // Try to forcefully stop
109         if (!mZone.stop()) {
110             LOGE(mId << ": Failed to stop the zone");
111         }
112     }
113
114     LOGD(mId << ": ZoneAdmin object destroyed");
115 }
116
117
118 const std::string& ZoneAdmin::getId() const
119 {
120     return mId;
121 }
122
123
124 void ZoneAdmin::start()
125 {
126     LOGD(mId << ": Starting...");
127     if (isRunning()) {
128         LOGD(mId << ": Already running - nothing to do...");
129         return;
130     }
131
132     utils::CStringArrayBuilder args;
133     for (const std::string& arg : mConfig.initWithArgs) {
134         args.add(arg.c_str());
135     }
136     if (args.empty()) {
137         args.add("/sbin/init");
138     }
139
140     if (!mZone.start(args.c_array())) {
141         throw ZoneOperationException("Could not start zone");
142     }
143
144     // Wait until the full platform launch with graphical stack.
145     // VT should be activated by a graphical stack.
146     // If we do it with 'zoneToFocus.activateVT' before starting the graphical stack,
147     // graphical stack initialization failed and we finally switch to the black screen.
148     // Skip waiting when graphical stack is not running (unit tests).
149     if (mDynamicConfig.vt > 0) {
150         // TODO, timeout is a temporary solution
151         std::this_thread::sleep_for(std::chrono::milliseconds(4000));
152     }
153
154     LOGD(mId << ": Started");
155 }
156
157
158 void ZoneAdmin::stop()
159 {
160     LOGD(mId << ": Stopping procedure started...");
161     if (isStopped()) {
162         LOGD(mId << ": Already crashed/down/off - nothing to do");
163         return;
164     }
165
166     if (!mZone.shutdown(SHUTDOWN_WAIT)) {
167         // force stop
168         if (!mZone.stop()) {
169             throw ZoneOperationException("Could not stop zone");
170         }
171     }
172
173     LOGD(mId << ": Stopping procedure ended");
174 }
175
176
177 void ZoneAdmin::destroy()
178 {
179     LOGD(mId << ": Destroying procedure started...");
180
181     if (!mZone.destroy()) {
182         throw ZoneOperationException("Could not destroy zone");
183     }
184
185     LOGD(mId << ": Destroying procedure ended");
186 }
187
188
189 bool ZoneAdmin::isRunning()
190 {
191     return mZone.getState() == lxc::LxcZone::State::RUNNING;
192 }
193
194
195 bool ZoneAdmin::isStopped()
196 {
197     return mZone.getState() == lxc::LxcZone::State::STOPPED;
198 }
199
200
201 void ZoneAdmin::suspend()
202 {
203     LOGD(mId << ": Pausing...");
204     if (!mZone.freeze()) {
205         throw ZoneOperationException("Could not pause zone");
206     }
207     LOGD(mId << ": Paused");
208 }
209
210
211 void ZoneAdmin::resume()
212 {
213     LOGD(mId << ": Resuming...");
214     if (!mZone.unfreeze()) {
215         throw ZoneOperationException("Could not resume zone");
216     }
217     LOGD(mId << ": Resumed");
218 }
219
220
221 bool ZoneAdmin::isPaused()
222 {
223     return mZone.getState() == lxc::LxcZone::State::FROZEN;
224 }
225
226
227 void ZoneAdmin::setSchedulerLevel(SchedulerLevel sched)
228 {
229     assert(isRunning());
230
231     switch (sched) {
232     case SchedulerLevel::FOREGROUND:
233         LOGD(mId << ": Setting SchedulerLevel::FOREGROUND");
234         setSchedulerParams(DEFAULT_CPU_SHARES,
235                            DEFAULT_VCPU_PERIOD_MS,
236                            mConfig.cpuQuotaForeground);
237         break;
238     case SchedulerLevel::BACKGROUND:
239         LOGD(mId << ": Setting SchedulerLevel::BACKGROUND");
240         setSchedulerParams(DEFAULT_CPU_SHARES,
241                            DEFAULT_VCPU_PERIOD_MS,
242                            mConfig.cpuQuotaBackground);
243         break;
244     default:
245         assert(0 && "Unknown sched parameter value");
246     }
247 }
248
249
250 void ZoneAdmin::setSchedulerParams(std::uint64_t cpuShares,
251                                    std::uint64_t vcpuPeriod,
252                                    std::int64_t vcpuQuota)
253 {
254     assert(vcpuPeriod >= 1000 && vcpuPeriod <= 1000000);
255     assert(vcpuQuota == -1 ||
256            (vcpuQuota >= 1000 && vcpuQuota <= static_cast<std::int64_t>(ULLONG_MAX / 1000)));
257
258     if (!lxc::setCgroup(mId, "cpu", "cpu.shares", std::to_string(cpuShares)) ||
259         !lxc::setCgroup(mId, "cpu", "cpu.cfs_period_us", std::to_string(vcpuPeriod)) ||
260         !lxc::setCgroup(mId, "cpu", "cpu.cfs_quota_us", std::to_string(vcpuQuota))) {
261
262         LOGE(mId << ": Error while setting the zone's scheduler params");
263         throw ZoneOperationException("Could not set scheduler params");
264     }
265 }
266
267 void ZoneAdmin::setDetachOnExit()
268 {
269     mDetachOnExit = true;
270 }
271
272 void ZoneAdmin::setDestroyOnExit()
273 {
274     mDestroyOnExit = true;
275 }
276
277 std::int64_t ZoneAdmin::getSchedulerQuota()
278 {
279     std::string ret;
280     if (!lxc::getCgroup(mId, "cpu", "cpu.cfs_quota_us", ret)) {
281         LOGE(mId << ": Error while getting the zone's scheduler quota param");
282         throw ZoneOperationException("Could not get scheduler quota param");
283     }
284     return std::stoll(ret);
285 }
286
287 void ZoneAdmin::createNetdevVeth(const std::string& zoneDev,
288                                  const std::string& hostDev)
289 {
290     netdev::createVeth(mZone.getInitPid(), zoneDev, hostDev);
291 }
292
293 void ZoneAdmin::createNetdevMacvlan(const std::string& zoneDev,
294                                     const std::string& hostDev,
295                                     const uint32_t& mode)
296 {
297     netdev::createMacvlan(mZone.getInitPid(), zoneDev, hostDev, static_cast<macvlan_mode>(mode));
298 }
299
300 void ZoneAdmin::moveNetdev(const std::string& devId)
301 {
302     netdev::movePhys(mZone.getInitPid(), devId);
303 }
304
305 void ZoneAdmin::destroyNetdev(const std::string& devId)
306 {
307     netdev::destroyNetdev(devId, mZone.getInitPid());
308 }
309
310 void ZoneAdmin::setNetdevAttrs(const std::string& netdev, const NetdevAttrs& attrs)
311 {
312     netdev::setAttrs(mZone.getInitPid(), netdev, attrs);
313 }
314
315 ZoneAdmin::NetdevAttrs ZoneAdmin::getNetdevAttrs(const std::string& netdev)
316 {
317     return netdev::getAttrs(mZone.getInitPid(), netdev);
318 }
319
320 std::vector<std::string> ZoneAdmin::getNetdevList()
321 {
322     return netdev::listNetdev(mZone.getInitPid());
323 }
324
325 } // namespace vasum