blob: cec7d5d302df0fadbcacac22b3514d2febc3c927 [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>
20#include <base/posix/unix_domain_socket.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>
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080024#include <brillo/minijail/minijail.h>
25
Garrick Evans1cce71a2019-06-21 10:43:14 +090026#include "arc/network/guest_events.h"
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
32// Passes |method_call| to |handler| and passes the response to
33// |response_sender|. If |handler| returns nullptr, an empty response is
34// created and sent.
35void HandleSynchronousDBusMethodCall(
36 base::Callback<std::unique_ptr<dbus::Response>(dbus::MethodCall*)> handler,
37 dbus::MethodCall* method_call,
38 dbus::ExportedObject::ResponseSender response_sender) {
39 std::unique_ptr<dbus::Response> response = handler.Run(method_call);
40 if (!response)
41 response = dbus::Response::FromMethodCall(method_call);
42 response_sender.Run(std::move(response));
43}
44
45} // namespace
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070046
Taoyu Lice7caa62019-10-01 15:43:33 +090047Manager::Manager(std::unique_ptr<HelperProcess> adb_proxy,
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090048 std::unique_ptr<HelperProcess> mcast_proxy,
Garrick Evans1f5a3612019-11-08 12:59:03 +090049 std::unique_ptr<HelperProcess> nd_proxy)
Garrick Evans3915af32019-07-25 15:44:34 +090050 : adb_proxy_(std::move(adb_proxy)),
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090051 mcast_proxy_(std::move(mcast_proxy)),
Taoyu Lice7caa62019-10-01 15:43:33 +090052 nd_proxy_(std::move(nd_proxy)),
Garrick Evans96e03042019-05-28 14:30:52 +090053 addr_mgr_({
Garrick Evansf4a93292019-03-13 14:19:43 +090054 AddressManager::Guest::ARC,
55 AddressManager::Guest::ARC_NET,
Garrick Evans508a4bc2019-11-14 08:45:52 +090056 AddressManager::Guest::VM_ARC,
Garrick Evansf4a93292019-03-13 14:19:43 +090057 }),
Taoyu Li179dcc62019-10-17 11:21:08 +090058 gsock_(AF_UNIX, SOCK_DGRAM) {
59 runner_ = std::make_unique<MinijailedProcessRunner>();
60 datapath_ = std::make_unique<Datapath>(runner_.get());
61}
Long Chengd4415582019-09-24 19:16:09 +000062
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070063int Manager::OnInit() {
Garrick Evans54861622019-07-19 09:05:09 +090064 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080065
66 // Handle subprocess lifecycle.
67 process_reaper_.Register(this);
Hugo Benichi935eca92018-07-03 13:47:24 +090068
69 CHECK(process_reaper_.WatchForChild(
Garrick Evans96e03042019-05-28 14:30:52 +090070 FROM_HERE, adb_proxy_->pid(),
71 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
72 adb_proxy_->pid())))
73 << "Failed to watch adb-proxy child process";
Taoyu Liaf944c92019-10-01 12:22:31 +090074 CHECK(process_reaper_.WatchForChild(
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090075 FROM_HERE, mcast_proxy_->pid(),
76 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
77 nd_proxy_->pid())))
78 << "Failed to watch multicast-proxy child process";
79 CHECK(process_reaper_.WatchForChild(
Taoyu Liaf944c92019-10-01 12:22:31 +090080 FROM_HERE, nd_proxy_->pid(),
81 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
82 nd_proxy_->pid())))
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090083 << "Failed to watch nd-proxy child process";
Garrick Evans96e03042019-05-28 14:30:52 +090084
Long Chengd4415582019-09-24 19:16:09 +000085 // Setup the socket for guests to connect and notify certain events.
Garrick Evans5d55f5e2019-07-17 15:28:10 +090086 // TODO(garrick): Remove once DBus API available.
Long Chengd4415582019-09-24 19:16:09 +000087 struct sockaddr_un addr = {0};
88 socklen_t addrlen = 0;
89 FillGuestSocketAddr(&addr, &addrlen);
90 if (!gsock_.Bind((const struct sockaddr*)&addr, addrlen)) {
91 LOG(ERROR) << "Cannot bind guest socket @" << kGuestSocketPath
92 << "; exiting";
93 return -1;
94 }
95
Garrick Evans6f258d02019-06-28 16:32:07 +090096 // TODO(garrick): Remove this workaround ASAP.
97 // Handle signals for ARC lifecycle.
98 RegisterHandler(SIGUSR1,
99 base::Bind(&Manager::OnSignal, base::Unretained(this)));
100 RegisterHandler(SIGUSR2,
101 base::Bind(&Manager::OnSignal, base::Unretained(this)));
Long Chengd4415582019-09-24 19:16:09 +0000102 gsock_watcher_ = base::FileDescriptorWatcher::WatchReadable(
103 gsock_.fd(), base::BindRepeating(&Manager::OnFileCanReadWithoutBlocking,
104 base::Unretained(this)));
Garrick Evans49879532018-12-03 13:15:36 +0900105
106 // Run after Daemon::OnInit().
Eric Caruso9ce54182018-01-04 11:19:47 -0800107 base::MessageLoopForIO::current()->task_runner()->PostTask(
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700108 FROM_HERE,
109 base::Bind(&Manager::InitialSetup, weak_factory_.GetWeakPtr()));
110
111 return DBusDaemon::OnInit();
112}
113
114void Manager::InitialSetup() {
Garrick Evans08843932019-09-17 14:41:08 +0900115 LOG(INFO) << "Setting up DBus service interface";
116 dbus_svc_path_ = bus_->GetExportedObject(
117 dbus::ObjectPath(patchpanel::kPatchPanelServicePath));
118 if (!dbus_svc_path_) {
119 LOG(FATAL) << "Failed to export " << patchpanel::kPatchPanelServicePath
120 << " object";
121 }
122
123 using ServiceMethod =
124 std::unique_ptr<dbus::Response> (Manager::*)(dbus::MethodCall*);
125 const std::map<const char*, ServiceMethod> kServiceMethods = {
126 {patchpanel::kArcStartupMethod, &Manager::OnArcStartup},
127 {patchpanel::kArcShutdownMethod, &Manager::OnArcShutdown},
128 {patchpanel::kArcVmStartupMethod, &Manager::OnArcVmStartup},
129 {patchpanel::kArcVmShutdownMethod, &Manager::OnArcVmShutdown},
130 };
131
132 for (const auto& kv : kServiceMethods) {
133 if (!dbus_svc_path_->ExportMethodAndBlock(
134 patchpanel::kPatchPanelInterface, kv.first,
135 base::Bind(&HandleSynchronousDBusMethodCall,
136 base::Bind(kv.second, base::Unretained(this))))) {
137 LOG(FATAL) << "Failed to export method " << kv.first;
138 }
139 }
140
141 if (!bus_->RequestOwnershipAndBlock(patchpanel::kPatchPanelServiceName,
142 dbus::Bus::REQUIRE_PRIMARY)) {
143 LOG(FATAL) << "Failed to take ownership of "
144 << patchpanel::kPatchPanelServiceName;
145 }
146 LOG(INFO) << "DBus service interface ready";
147
Garrick Evans428e4762018-12-11 15:18:42 +0900148 device_mgr_ = std::make_unique<DeviceManager>(
Garrick Evans08843932019-09-17 14:41:08 +0900149 std::make_unique<ShillClient>(bus_), &addr_mgr_, datapath_.get(),
Garrick Evans1f5a3612019-11-08 12:59:03 +0900150 mcast_proxy_.get(), nd_proxy_.get());
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900151
Garrick Evans1f5a3612019-11-08 12:59:03 +0900152 arc_svc_ = std::make_unique<ArcService>(device_mgr_.get(), datapath_.get());
Taoyu Liaf944c92019-10-01 12:22:31 +0900153
154 nd_proxy_->Listen();
Long Chengd4415582019-09-24 19:16:09 +0000155}
Garrick Evans49879532018-12-03 13:15:36 +0900156
Long Chengd4415582019-09-24 19:16:09 +0000157void Manager::OnFileCanReadWithoutBlocking() {
158 char buf[128] = {0};
159 std::vector<base::ScopedFD> fds{};
160 ssize_t len =
161 base::UnixDomainSocket::RecvMsg(gsock_.fd(), buf, sizeof(buf), &fds);
162
163 if (len <= 0) {
164 PLOG(WARNING) << "Read failed";
165 return;
166 }
167
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900168 // Only expecting ARCVM start/stop events from Concierge here.
169 auto event = ArcGuestEvent::Parse(buf);
170 if (!event || !event->isVm()) {
171 LOG(WARNING) << "Unexpected message received: " << buf;
172 return;
173 }
174
175 GuestMessage msg;
176 msg.set_type(GuestMessage::ARC_VM);
177 msg.set_arcvm_vsock_cid(event->id());
178 msg.set_event(event->isStarting() ? GuestMessage::START : GuestMessage::STOP);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900179 SendGuestMessage(msg);
Garrick Evans49879532018-12-03 13:15:36 +0900180}
181
Garrick Evans6f258d02019-06-28 16:32:07 +0900182// TODO(garrick): Remove this workaround ASAP.
183bool Manager::OnSignal(const struct signalfd_siginfo& info) {
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900184 // Only ARC++ scripts send signals so nothing to do for VM.
Garrick Evanse94a14e2019-11-11 10:32:13 +0900185 if (info.ssi_signo == SIGUSR1) {
186 // For now this value is ignored and the service discovers the
187 // container pid on its own. Later, this is arrive via DBus message.
188 StartArc(0 /*pid*/);
189 } else {
190 StopArc();
191 }
192
193 // Stay registered.
Garrick Evans6f258d02019-06-28 16:32:07 +0900194 return false;
195}
196
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800197void Manager::OnShutdown(int* exit_code) {
Garrick Evans428e4762018-12-11 15:18:42 +0900198 device_mgr_.reset();
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800199}
200
201void Manager::OnSubprocessExited(pid_t pid, const siginfo_t& info) {
Hugo Benichi10a2af42018-08-27 10:09:42 +0900202 LOG(ERROR) << "Subprocess " << pid << " exited unexpectedly";
203 Quit();
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800204}
205
Garrick Evanse94a14e2019-11-11 10:32:13 +0900206bool Manager::StartArc(pid_t pid) {
Garrick Evans508a4bc2019-11-14 08:45:52 +0900207 if (!arc_svc_->Start(pid))
208 return false;
Garrick Evanse94a14e2019-11-11 10:32:13 +0900209
210 GuestMessage msg;
211 msg.set_event(GuestMessage::START);
212 msg.set_type(GuestMessage::ARC);
213 msg.set_arc_pid(pid);
214 SendGuestMessage(msg);
215
216 return true;
217}
218
219void Manager::StopArc() {
220 GuestMessage msg;
221 msg.set_event(GuestMessage::STOP);
222 msg.set_type(GuestMessage::ARC);
223 SendGuestMessage(msg);
224
Garrick Evans508a4bc2019-11-14 08:45:52 +0900225 arc_svc_->Stop();
Garrick Evanse94a14e2019-11-11 10:32:13 +0900226}
227
228bool Manager::StartArcVm(int cid) {
Garrick Evans508a4bc2019-11-14 08:45:52 +0900229 if (!arc_svc_->Start(cid))
230 return false;
Garrick Evanse94a14e2019-11-11 10:32:13 +0900231
232 GuestMessage msg;
233 msg.set_event(GuestMessage::START);
234 msg.set_type(GuestMessage::ARC_VM);
235 msg.set_arcvm_vsock_cid(cid);
236 SendGuestMessage(msg);
237
238 return true;
239}
240
241void Manager::StopArcVm() {
242 GuestMessage msg;
243 msg.set_event(GuestMessage::STOP);
244 msg.set_type(GuestMessage::ARC_VM);
245 SendGuestMessage(msg);
246
Garrick Evans508a4bc2019-11-14 08:45:52 +0900247 arc_svc_->Stop();
Garrick Evanse94a14e2019-11-11 10:32:13 +0900248}
249
Garrick Evans08843932019-09-17 14:41:08 +0900250std::unique_ptr<dbus::Response> Manager::OnArcStartup(
251 dbus::MethodCall* method_call) {
252 LOG(INFO) << "ARC++ starting up";
253
254 std::unique_ptr<dbus::Response> dbus_response(
255 dbus::Response::FromMethodCall(method_call));
256
257 dbus::MessageReader reader(method_call);
258 dbus::MessageWriter writer(dbus_response.get());
259
260 patchpanel::ArcStartupRequest request;
261 patchpanel::ArcStartupResponse response;
262
263 if (!reader.PopArrayOfBytesAsProto(&request)) {
264 LOG(ERROR) << "Unable to parse request";
265 writer.AppendProtoAsArrayOfBytes(response);
266 return dbus_response;
267 }
268
Garrick Evanse94a14e2019-11-11 10:32:13 +0900269 StartArc(request.pid());
270
Garrick Evans08843932019-09-17 14:41:08 +0900271 writer.AppendProtoAsArrayOfBytes(response);
272 return dbus_response;
273}
274
275std::unique_ptr<dbus::Response> Manager::OnArcShutdown(
276 dbus::MethodCall* method_call) {
277 LOG(INFO) << "ARC++ shutting down";
278
279 std::unique_ptr<dbus::Response> dbus_response(
280 dbus::Response::FromMethodCall(method_call));
281
282 dbus::MessageReader reader(method_call);
283 dbus::MessageWriter writer(dbus_response.get());
284
285 patchpanel::ArcShutdownRequest request;
286 patchpanel::ArcShutdownResponse response;
287
288 if (!reader.PopArrayOfBytesAsProto(&request)) {
289 LOG(ERROR) << "Unable to parse request";
290 writer.AppendProtoAsArrayOfBytes(response);
291 return dbus_response;
292 }
293
Garrick Evanse94a14e2019-11-11 10:32:13 +0900294 StopArc();
295
Garrick Evans08843932019-09-17 14:41:08 +0900296 writer.AppendProtoAsArrayOfBytes(response);
297 return dbus_response;
298}
299
300std::unique_ptr<dbus::Response> Manager::OnArcVmStartup(
301 dbus::MethodCall* method_call) {
302 LOG(INFO) << "ARCVM starting up";
303
304 std::unique_ptr<dbus::Response> dbus_response(
305 dbus::Response::FromMethodCall(method_call));
306
307 dbus::MessageReader reader(method_call);
308 dbus::MessageWriter writer(dbus_response.get());
309
310 patchpanel::ArcVmStartupRequest request;
311 patchpanel::ArcVmStartupResponse response;
312
313 if (!reader.PopArrayOfBytesAsProto(&request)) {
314 LOG(ERROR) << "Unable to parse request";
315 writer.AppendProtoAsArrayOfBytes(response);
316 return dbus_response;
317 }
318
Garrick Evanse94a14e2019-11-11 10:32:13 +0900319 StartArcVm(request.cid());
320
Garrick Evans08843932019-09-17 14:41:08 +0900321 writer.AppendProtoAsArrayOfBytes(response);
322 return dbus_response;
323}
324
325std::unique_ptr<dbus::Response> Manager::OnArcVmShutdown(
326 dbus::MethodCall* method_call) {
327 LOG(INFO) << "ARCVM shutting down";
328
329 std::unique_ptr<dbus::Response> dbus_response(
330 dbus::Response::FromMethodCall(method_call));
331
332 dbus::MessageReader reader(method_call);
333 dbus::MessageWriter writer(dbus_response.get());
334
335 patchpanel::ArcVmShutdownRequest request;
336 patchpanel::ArcVmShutdownResponse response;
337
338 if (!reader.PopArrayOfBytesAsProto(&request)) {
339 LOG(ERROR) << "Unable to parse request";
340 writer.AppendProtoAsArrayOfBytes(response);
341 return dbus_response;
342 }
343
Garrick Evanse94a14e2019-11-11 10:32:13 +0900344 StopArcVm();
345
Garrick Evans08843932019-09-17 14:41:08 +0900346 writer.AppendProtoAsArrayOfBytes(response);
347 return dbus_response;
348}
349
Garrick Evanse94a14e2019-11-11 10:32:13 +0900350void Manager::SendGuestMessage(const GuestMessage& msg) {
Garrick Evans96e03042019-05-28 14:30:52 +0900351 IpHelperMessage ipm;
352 *ipm.mutable_guest_message() = msg;
Garrick Evans96e03042019-05-28 14:30:52 +0900353 adb_proxy_->SendMessage(ipm);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900354 mcast_proxy_->SendMessage(ipm);
355 nd_proxy_->SendMessage(ipm);
Garrick Evans96e03042019-05-28 14:30:52 +0900356}
357
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700358} // namespace arc_networkd