blob: b3762b63445139496690ae33b817fab92b1afbb3 [file] [log] [blame]
Kevin Cernekee95d4ae92016-06-19 10:26:29 -07001// Copyright 2016 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Hidehiko Abe3a7e5132018-02-15 13:07:50 +09005#include "arc/network/manager.h"
Kevin Cernekee4e62cc12016-12-03 11:50:53 -08006
Kevin Cernekee95d4ae92016-06-19 10:26:29 -07007#include <arpa/inet.h>
Hugo Benichi935eca92018-07-03 13:47:24 +09008#include <netinet/in.h>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -07009#include <stdint.h>
Garrick Evans54861622019-07-19 09:05:09 +090010#include <sys/prctl.h>
Garrick Evans96e03042019-05-28 14:30:52 +090011#include <sys/socket.h>
12#include <sys/un.h>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070013
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080014#include <utility>
Garrick Evans96e03042019-05-28 14:30:52 +090015#include <vector>
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080016
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070017#include <base/bind.h>
18#include <base/logging.h>
Long Chengd4415582019-09-24 19:16:09 +000019#include <base/message_loop/message_loop.h>
Taoyu Lic85c44b2019-12-04 17:32:57 +090020#include <base/strings/string_number_conversions.h>
Garrick Evans96e03042019-05-28 14:30:52 +090021#include <base/strings/string_split.h>
Garrick Evans6f258d02019-06-28 16:32:07 +090022#include <base/strings/string_util.h>
Taoyu Li179dcc62019-10-17 11:21:08 +090023#include <base/strings/stringprintf.h>
Taoyu Lic85c44b2019-12-04 17:32:57 +090024#include <brillo/key_value_store.h>
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080025#include <brillo/minijail/minijail.h>
26
Garrick Evans428e4762018-12-11 15:18:42 +090027#include "arc/network/ipc.pb.h"
28
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070029namespace arc_networkd {
Garrick Evans08843932019-09-17 14:41:08 +090030namespace {
31
Taoyu Lic85c44b2019-12-04 17:32:57 +090032bool ShouldEnableNDProxy() {
33 static const char kLsbReleasePath[] = "/etc/lsb-release";
34 static int kMinAndroidSdkVersion = 28; // P
35 static int kMinChromeMilestone = 80;
36 static std::array<std::string, 2> kSupportedBoards = {"atlas", "eve"};
37
38 brillo::KeyValueStore store;
39 if (!store.Load(base::FilePath(kLsbReleasePath))) {
40 LOG(ERROR) << "Could not read lsb-release";
41 return false;
42 }
43
44 std::string value;
45 if (!store.GetString("CHROMEOS_ARC_ANDROID_SDK_VERSION", &value)) {
46 LOG(ERROR) << "NDProxy disabled - cannot determine Android SDK version";
47 return false;
48 }
49 int ver = 0;
50 if (!base::StringToInt(value.c_str(), &ver)) {
51 LOG(ERROR) << "NDProxy disabled - invalid Android SDK version";
52 return false;
53 }
54 if (ver < kMinAndroidSdkVersion) {
55 LOG(INFO) << "NDProxy disabled for Android SDK " << value;
56 return false;
57 }
58
59 if (!store.GetString("CHROMEOS_RELEASE_CHROME_MILESTONE", &value)) {
60 LOG(ERROR) << "NDProxy disabled - cannot determine ChromeOS milestone";
61 return false;
62 }
63 if (!base::StringToInt(value.c_str(), &ver)) {
64 LOG(ERROR) << "NDProxy disabled - invalid ChromeOS milestone";
65 return false;
66 }
67 if (ver < kMinChromeMilestone) {
68 LOG(INFO) << "NDProxy disabled for ChromeOS milestone " << value;
69 return false;
70 }
71
72 if (!store.GetString("CHROMEOS_RELEASE_BOARD", &value)) {
73 LOG(ERROR) << "NDProxy disabled - cannot determine board";
74 return false;
75 }
76 if (std::find(kSupportedBoards.begin(), kSupportedBoards.end(), value) ==
77 kSupportedBoards.end()) {
78 LOG(INFO) << "NDProxy disabled for board " << value;
79 return false;
80 }
81 LOG(INFO) << "NDProxy enabled";
82 return true;
83}
84
Garrick Evans08843932019-09-17 14:41:08 +090085// Passes |method_call| to |handler| and passes the response to
86// |response_sender|. If |handler| returns nullptr, an empty response is
87// created and sent.
88void HandleSynchronousDBusMethodCall(
89 base::Callback<std::unique_ptr<dbus::Response>(dbus::MethodCall*)> handler,
90 dbus::MethodCall* method_call,
91 dbus::ExportedObject::ResponseSender response_sender) {
92 std::unique_ptr<dbus::Response> response = handler.Run(method_call);
93 if (!response)
94 response = dbus::Response::FromMethodCall(method_call);
95 response_sender.Run(std::move(response));
96}
97
98} // namespace
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070099
Taoyu Lice7caa62019-10-01 15:43:33 +0900100Manager::Manager(std::unique_ptr<HelperProcess> adb_proxy,
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +0900101 std::unique_ptr<HelperProcess> mcast_proxy,
Garrick Evans1f5a3612019-11-08 12:59:03 +0900102 std::unique_ptr<HelperProcess> nd_proxy)
Garrick Evans3915af32019-07-25 15:44:34 +0900103 : adb_proxy_(std::move(adb_proxy)),
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +0900104 mcast_proxy_(std::move(mcast_proxy)),
Taoyu Lice7caa62019-10-01 15:43:33 +0900105 nd_proxy_(std::move(nd_proxy)),
Garrick Evans96e03042019-05-28 14:30:52 +0900106 addr_mgr_({
Garrick Evansf4a93292019-03-13 14:19:43 +0900107 AddressManager::Guest::ARC,
108 AddressManager::Guest::ARC_NET,
Garrick Evans508a4bc2019-11-14 08:45:52 +0900109 AddressManager::Guest::VM_ARC,
Garrick Evansf7acc772019-10-21 15:26:15 +0900110 }) {
Taoyu Li179dcc62019-10-17 11:21:08 +0900111 runner_ = std::make_unique<MinijailedProcessRunner>();
112 datapath_ = std::make_unique<Datapath>(runner_.get());
113}
Long Chengd4415582019-09-24 19:16:09 +0000114
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700115int Manager::OnInit() {
Garrick Evans54861622019-07-19 09:05:09 +0900116 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800117
118 // Handle subprocess lifecycle.
119 process_reaper_.Register(this);
Hugo Benichi935eca92018-07-03 13:47:24 +0900120
121 CHECK(process_reaper_.WatchForChild(
Garrick Evans96e03042019-05-28 14:30:52 +0900122 FROM_HERE, adb_proxy_->pid(),
123 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
124 adb_proxy_->pid())))
125 << "Failed to watch adb-proxy child process";
Taoyu Liaf944c92019-10-01 12:22:31 +0900126 CHECK(process_reaper_.WatchForChild(
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +0900127 FROM_HERE, mcast_proxy_->pid(),
128 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
129 nd_proxy_->pid())))
130 << "Failed to watch multicast-proxy child process";
131 CHECK(process_reaper_.WatchForChild(
Taoyu Liaf944c92019-10-01 12:22:31 +0900132 FROM_HERE, nd_proxy_->pid(),
133 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
134 nd_proxy_->pid())))
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +0900135 << "Failed to watch nd-proxy child process";
Garrick Evans96e03042019-05-28 14:30:52 +0900136
Garrick Evans6f258d02019-06-28 16:32:07 +0900137 // TODO(garrick): Remove this workaround ASAP.
138 // Handle signals for ARC lifecycle.
139 RegisterHandler(SIGUSR1,
140 base::Bind(&Manager::OnSignal, base::Unretained(this)));
141 RegisterHandler(SIGUSR2,
142 base::Bind(&Manager::OnSignal, base::Unretained(this)));
Garrick Evans49879532018-12-03 13:15:36 +0900143
144 // Run after Daemon::OnInit().
Eric Caruso9ce54182018-01-04 11:19:47 -0800145 base::MessageLoopForIO::current()->task_runner()->PostTask(
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700146 FROM_HERE,
147 base::Bind(&Manager::InitialSetup, weak_factory_.GetWeakPtr()));
148
149 return DBusDaemon::OnInit();
150}
151
152void Manager::InitialSetup() {
Garrick Evans08843932019-09-17 14:41:08 +0900153 LOG(INFO) << "Setting up DBus service interface";
154 dbus_svc_path_ = bus_->GetExportedObject(
155 dbus::ObjectPath(patchpanel::kPatchPanelServicePath));
156 if (!dbus_svc_path_) {
157 LOG(FATAL) << "Failed to export " << patchpanel::kPatchPanelServicePath
158 << " object";
159 }
160
161 using ServiceMethod =
162 std::unique_ptr<dbus::Response> (Manager::*)(dbus::MethodCall*);
163 const std::map<const char*, ServiceMethod> kServiceMethods = {
164 {patchpanel::kArcStartupMethod, &Manager::OnArcStartup},
165 {patchpanel::kArcShutdownMethod, &Manager::OnArcShutdown},
166 {patchpanel::kArcVmStartupMethod, &Manager::OnArcVmStartup},
167 {patchpanel::kArcVmShutdownMethod, &Manager::OnArcVmShutdown},
168 };
169
170 for (const auto& kv : kServiceMethods) {
171 if (!dbus_svc_path_->ExportMethodAndBlock(
172 patchpanel::kPatchPanelInterface, kv.first,
173 base::Bind(&HandleSynchronousDBusMethodCall,
174 base::Bind(kv.second, base::Unretained(this))))) {
175 LOG(FATAL) << "Failed to export method " << kv.first;
176 }
177 }
178
179 if (!bus_->RequestOwnershipAndBlock(patchpanel::kPatchPanelServiceName,
180 dbus::Bus::REQUIRE_PRIMARY)) {
181 LOG(FATAL) << "Failed to take ownership of "
182 << patchpanel::kPatchPanelServiceName;
183 }
184 LOG(INFO) << "DBus service interface ready";
185
Garrick Evans428e4762018-12-11 15:18:42 +0900186 device_mgr_ = std::make_unique<DeviceManager>(
Garrick Evans08843932019-09-17 14:41:08 +0900187 std::make_unique<ShillClient>(bus_), &addr_mgr_, datapath_.get(),
Taoyu Lic85c44b2019-12-04 17:32:57 +0900188 mcast_proxy_.get(), ShouldEnableNDProxy() ? nd_proxy_.get() : nullptr);
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900189
Garrick Evans1f5a3612019-11-08 12:59:03 +0900190 arc_svc_ = std::make_unique<ArcService>(device_mgr_.get(), datapath_.get());
Taoyu Liaf944c92019-10-01 12:22:31 +0900191
192 nd_proxy_->Listen();
Long Chengd4415582019-09-24 19:16:09 +0000193}
Garrick Evans49879532018-12-03 13:15:36 +0900194
Garrick Evans6f258d02019-06-28 16:32:07 +0900195// TODO(garrick): Remove this workaround ASAP.
196bool Manager::OnSignal(const struct signalfd_siginfo& info) {
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900197 // Only ARC++ scripts send signals so nothing to do for VM.
Garrick Evanse94a14e2019-11-11 10:32:13 +0900198 if (info.ssi_signo == SIGUSR1) {
199 // For now this value is ignored and the service discovers the
200 // container pid on its own. Later, this is arrive via DBus message.
201 StartArc(0 /*pid*/);
202 } else {
Garrick Evans21173b12019-11-20 15:23:16 +0900203 StopArc(0 /*pid*/);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900204 }
205
206 // Stay registered.
Garrick Evans6f258d02019-06-28 16:32:07 +0900207 return false;
208}
209
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800210void Manager::OnShutdown(int* exit_code) {
Garrick Evans428e4762018-12-11 15:18:42 +0900211 device_mgr_.reset();
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800212}
213
214void Manager::OnSubprocessExited(pid_t pid, const siginfo_t& info) {
Hugo Benichi10a2af42018-08-27 10:09:42 +0900215 LOG(ERROR) << "Subprocess " << pid << " exited unexpectedly";
216 Quit();
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800217}
218
Garrick Evanse94a14e2019-11-11 10:32:13 +0900219bool Manager::StartArc(pid_t pid) {
Garrick Evans508a4bc2019-11-14 08:45:52 +0900220 if (!arc_svc_->Start(pid))
221 return false;
Garrick Evanse94a14e2019-11-11 10:32:13 +0900222
223 GuestMessage msg;
224 msg.set_event(GuestMessage::START);
225 msg.set_type(GuestMessage::ARC);
226 msg.set_arc_pid(pid);
227 SendGuestMessage(msg);
228
229 return true;
230}
231
Garrick Evans21173b12019-11-20 15:23:16 +0900232void Manager::StopArc(pid_t pid) {
Garrick Evanse94a14e2019-11-11 10:32:13 +0900233 GuestMessage msg;
234 msg.set_event(GuestMessage::STOP);
235 msg.set_type(GuestMessage::ARC);
236 SendGuestMessage(msg);
237
Garrick Evans21173b12019-11-20 15:23:16 +0900238 arc_svc_->Stop(pid);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900239}
240
Garrick Evans21173b12019-11-20 15:23:16 +0900241bool Manager::StartArcVm(int32_t cid) {
Garrick Evans508a4bc2019-11-14 08:45:52 +0900242 if (!arc_svc_->Start(cid))
243 return false;
Garrick Evanse94a14e2019-11-11 10:32:13 +0900244
245 GuestMessage msg;
246 msg.set_event(GuestMessage::START);
247 msg.set_type(GuestMessage::ARC_VM);
248 msg.set_arcvm_vsock_cid(cid);
249 SendGuestMessage(msg);
250
251 return true;
252}
253
Garrick Evans21173b12019-11-20 15:23:16 +0900254void Manager::StopArcVm(int32_t cid) {
Garrick Evanse94a14e2019-11-11 10:32:13 +0900255 GuestMessage msg;
256 msg.set_event(GuestMessage::STOP);
257 msg.set_type(GuestMessage::ARC_VM);
258 SendGuestMessage(msg);
259
Garrick Evans21173b12019-11-20 15:23:16 +0900260 arc_svc_->Stop(cid);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900261}
262
Garrick Evans08843932019-09-17 14:41:08 +0900263std::unique_ptr<dbus::Response> Manager::OnArcStartup(
264 dbus::MethodCall* method_call) {
265 LOG(INFO) << "ARC++ starting up";
266
267 std::unique_ptr<dbus::Response> dbus_response(
268 dbus::Response::FromMethodCall(method_call));
269
270 dbus::MessageReader reader(method_call);
271 dbus::MessageWriter writer(dbus_response.get());
272
273 patchpanel::ArcStartupRequest request;
274 patchpanel::ArcStartupResponse response;
275
276 if (!reader.PopArrayOfBytesAsProto(&request)) {
277 LOG(ERROR) << "Unable to parse request";
278 writer.AppendProtoAsArrayOfBytes(response);
279 return dbus_response;
280 }
281
Garrick Evanse01bf072019-11-15 09:08:19 +0900282 if (!StartArc(request.pid()))
283 LOG(ERROR) << "Failed to start ARC++ network service";
Garrick Evanse94a14e2019-11-11 10:32:13 +0900284
Garrick Evans08843932019-09-17 14:41:08 +0900285 writer.AppendProtoAsArrayOfBytes(response);
286 return dbus_response;
287}
288
289std::unique_ptr<dbus::Response> Manager::OnArcShutdown(
290 dbus::MethodCall* method_call) {
291 LOG(INFO) << "ARC++ shutting down";
292
293 std::unique_ptr<dbus::Response> dbus_response(
294 dbus::Response::FromMethodCall(method_call));
295
296 dbus::MessageReader reader(method_call);
297 dbus::MessageWriter writer(dbus_response.get());
298
299 patchpanel::ArcShutdownRequest request;
300 patchpanel::ArcShutdownResponse response;
301
302 if (!reader.PopArrayOfBytesAsProto(&request)) {
303 LOG(ERROR) << "Unable to parse request";
304 writer.AppendProtoAsArrayOfBytes(response);
305 return dbus_response;
306 }
307
Garrick Evans21173b12019-11-20 15:23:16 +0900308 StopArc(request.pid());
Garrick Evanse94a14e2019-11-11 10:32:13 +0900309
Garrick Evans08843932019-09-17 14:41:08 +0900310 writer.AppendProtoAsArrayOfBytes(response);
311 return dbus_response;
312}
313
314std::unique_ptr<dbus::Response> Manager::OnArcVmStartup(
315 dbus::MethodCall* method_call) {
316 LOG(INFO) << "ARCVM starting up";
317
318 std::unique_ptr<dbus::Response> dbus_response(
319 dbus::Response::FromMethodCall(method_call));
320
321 dbus::MessageReader reader(method_call);
322 dbus::MessageWriter writer(dbus_response.get());
323
324 patchpanel::ArcVmStartupRequest request;
325 patchpanel::ArcVmStartupResponse response;
326
327 if (!reader.PopArrayOfBytesAsProto(&request)) {
328 LOG(ERROR) << "Unable to parse request";
329 writer.AppendProtoAsArrayOfBytes(response);
330 return dbus_response;
331 }
332
Garrick Evanse01bf072019-11-15 09:08:19 +0900333 if (StartArcVm(request.cid())) {
334 // Populate the response with the known devices.
335 auto build_resp = [](patchpanel::ArcVmStartupResponse* resp,
336 Device* device) {
Garrick Evansa1134d72019-12-02 14:25:37 +0900337 auto* ctx = dynamic_cast<ArcService::Context*>(device->context());
Garrick Evanse01bf072019-11-15 09:08:19 +0900338 if (!ctx || ctx->TAP().empty())
339 return;
340
341 const auto& config = device->config();
342 auto* dev = resp->add_devices();
343 dev->set_ifname(ctx->TAP());
344 dev->set_ipv4_addr(config.guest_ipv4_addr());
345 };
346
347 device_mgr_->ProcessDevices(
348 base::Bind(build_resp, base::Unretained(&response)));
349 } else {
350 LOG(ERROR) << "Failed to start ARCVM network service";
351 }
Garrick Evanse94a14e2019-11-11 10:32:13 +0900352
Garrick Evans08843932019-09-17 14:41:08 +0900353 writer.AppendProtoAsArrayOfBytes(response);
354 return dbus_response;
355}
356
357std::unique_ptr<dbus::Response> Manager::OnArcVmShutdown(
358 dbus::MethodCall* method_call) {
359 LOG(INFO) << "ARCVM shutting down";
360
361 std::unique_ptr<dbus::Response> dbus_response(
362 dbus::Response::FromMethodCall(method_call));
363
364 dbus::MessageReader reader(method_call);
365 dbus::MessageWriter writer(dbus_response.get());
366
367 patchpanel::ArcVmShutdownRequest request;
368 patchpanel::ArcVmShutdownResponse response;
369
370 if (!reader.PopArrayOfBytesAsProto(&request)) {
371 LOG(ERROR) << "Unable to parse request";
372 writer.AppendProtoAsArrayOfBytes(response);
373 return dbus_response;
374 }
375
Garrick Evans21173b12019-11-20 15:23:16 +0900376 StopArcVm(request.cid());
Garrick Evanse94a14e2019-11-11 10:32:13 +0900377
Garrick Evans08843932019-09-17 14:41:08 +0900378 writer.AppendProtoAsArrayOfBytes(response);
379 return dbus_response;
380}
381
Garrick Evanse94a14e2019-11-11 10:32:13 +0900382void Manager::SendGuestMessage(const GuestMessage& msg) {
Garrick Evans96e03042019-05-28 14:30:52 +0900383 IpHelperMessage ipm;
384 *ipm.mutable_guest_message() = msg;
Garrick Evans96e03042019-05-28 14:30:52 +0900385 adb_proxy_->SendMessage(ipm);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900386 mcast_proxy_->SendMessage(ipm);
387 nd_proxy_->SendMessage(ipm);
Garrick Evans96e03042019-05-28 14:30:52 +0900388}
389
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700390} // namespace arc_networkd