blob: b419f65a64f1dc46933ed736b4ba79197d6b2b44 [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,
56 }),
Taoyu Li179dcc62019-10-17 11:21:08 +090057 gsock_(AF_UNIX, SOCK_DGRAM) {
58 runner_ = std::make_unique<MinijailedProcessRunner>();
59 datapath_ = std::make_unique<Datapath>(runner_.get());
60}
Long Chengd4415582019-09-24 19:16:09 +000061
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070062int Manager::OnInit() {
Garrick Evans54861622019-07-19 09:05:09 +090063 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080064
65 // Handle subprocess lifecycle.
66 process_reaper_.Register(this);
Hugo Benichi935eca92018-07-03 13:47:24 +090067
68 CHECK(process_reaper_.WatchForChild(
Garrick Evans96e03042019-05-28 14:30:52 +090069 FROM_HERE, adb_proxy_->pid(),
70 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
71 adb_proxy_->pid())))
72 << "Failed to watch adb-proxy child process";
Taoyu Liaf944c92019-10-01 12:22:31 +090073 CHECK(process_reaper_.WatchForChild(
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090074 FROM_HERE, mcast_proxy_->pid(),
75 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
76 nd_proxy_->pid())))
77 << "Failed to watch multicast-proxy child process";
78 CHECK(process_reaper_.WatchForChild(
Taoyu Liaf944c92019-10-01 12:22:31 +090079 FROM_HERE, nd_proxy_->pid(),
80 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
81 nd_proxy_->pid())))
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090082 << "Failed to watch nd-proxy child process";
Garrick Evans96e03042019-05-28 14:30:52 +090083
Long Chengd4415582019-09-24 19:16:09 +000084 // Setup the socket for guests to connect and notify certain events.
Garrick Evans5d55f5e2019-07-17 15:28:10 +090085 // TODO(garrick): Remove once DBus API available.
Long Chengd4415582019-09-24 19:16:09 +000086 struct sockaddr_un addr = {0};
87 socklen_t addrlen = 0;
88 FillGuestSocketAddr(&addr, &addrlen);
89 if (!gsock_.Bind((const struct sockaddr*)&addr, addrlen)) {
90 LOG(ERROR) << "Cannot bind guest socket @" << kGuestSocketPath
91 << "; exiting";
92 return -1;
93 }
94
Garrick Evans6f258d02019-06-28 16:32:07 +090095 // TODO(garrick): Remove this workaround ASAP.
96 // Handle signals for ARC lifecycle.
97 RegisterHandler(SIGUSR1,
98 base::Bind(&Manager::OnSignal, base::Unretained(this)));
99 RegisterHandler(SIGUSR2,
100 base::Bind(&Manager::OnSignal, base::Unretained(this)));
Long Chengd4415582019-09-24 19:16:09 +0000101 gsock_watcher_ = base::FileDescriptorWatcher::WatchReadable(
102 gsock_.fd(), base::BindRepeating(&Manager::OnFileCanReadWithoutBlocking,
103 base::Unretained(this)));
Garrick Evans49879532018-12-03 13:15:36 +0900104
105 // Run after Daemon::OnInit().
Eric Caruso9ce54182018-01-04 11:19:47 -0800106 base::MessageLoopForIO::current()->task_runner()->PostTask(
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700107 FROM_HERE,
108 base::Bind(&Manager::InitialSetup, weak_factory_.GetWeakPtr()));
109
110 return DBusDaemon::OnInit();
111}
112
113void Manager::InitialSetup() {
Garrick Evans08843932019-09-17 14:41:08 +0900114 LOG(INFO) << "Setting up DBus service interface";
115 dbus_svc_path_ = bus_->GetExportedObject(
116 dbus::ObjectPath(patchpanel::kPatchPanelServicePath));
117 if (!dbus_svc_path_) {
118 LOG(FATAL) << "Failed to export " << patchpanel::kPatchPanelServicePath
119 << " object";
120 }
121
122 using ServiceMethod =
123 std::unique_ptr<dbus::Response> (Manager::*)(dbus::MethodCall*);
124 const std::map<const char*, ServiceMethod> kServiceMethods = {
125 {patchpanel::kArcStartupMethod, &Manager::OnArcStartup},
126 {patchpanel::kArcShutdownMethod, &Manager::OnArcShutdown},
127 {patchpanel::kArcVmStartupMethod, &Manager::OnArcVmStartup},
128 {patchpanel::kArcVmShutdownMethod, &Manager::OnArcVmShutdown},
129 };
130
131 for (const auto& kv : kServiceMethods) {
132 if (!dbus_svc_path_->ExportMethodAndBlock(
133 patchpanel::kPatchPanelInterface, kv.first,
134 base::Bind(&HandleSynchronousDBusMethodCall,
135 base::Bind(kv.second, base::Unretained(this))))) {
136 LOG(FATAL) << "Failed to export method " << kv.first;
137 }
138 }
139
140 if (!bus_->RequestOwnershipAndBlock(patchpanel::kPatchPanelServiceName,
141 dbus::Bus::REQUIRE_PRIMARY)) {
142 LOG(FATAL) << "Failed to take ownership of "
143 << patchpanel::kPatchPanelServiceName;
144 }
145 LOG(INFO) << "DBus service interface ready";
146
Garrick Evans428e4762018-12-11 15:18:42 +0900147 device_mgr_ = std::make_unique<DeviceManager>(
Garrick Evans08843932019-09-17 14:41:08 +0900148 std::make_unique<ShillClient>(bus_), &addr_mgr_, datapath_.get(),
Garrick Evans1f5a3612019-11-08 12:59:03 +0900149 mcast_proxy_.get(), nd_proxy_.get());
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900150
Garrick Evans1f5a3612019-11-08 12:59:03 +0900151 arc_svc_ = std::make_unique<ArcService>(device_mgr_.get(), datapath_.get());
Taoyu Liaf944c92019-10-01 12:22:31 +0900152
153 nd_proxy_->Listen();
Long Chengd4415582019-09-24 19:16:09 +0000154}
Garrick Evans49879532018-12-03 13:15:36 +0900155
Long Chengd4415582019-09-24 19:16:09 +0000156void Manager::OnFileCanReadWithoutBlocking() {
157 char buf[128] = {0};
158 std::vector<base::ScopedFD> fds{};
159 ssize_t len =
160 base::UnixDomainSocket::RecvMsg(gsock_.fd(), buf, sizeof(buf), &fds);
161
162 if (len <= 0) {
163 PLOG(WARNING) << "Read failed";
164 return;
165 }
166
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900167 // Only expecting ARCVM start/stop events from Concierge here.
168 auto event = ArcGuestEvent::Parse(buf);
169 if (!event || !event->isVm()) {
170 LOG(WARNING) << "Unexpected message received: " << buf;
171 return;
172 }
173
174 GuestMessage msg;
175 msg.set_type(GuestMessage::ARC_VM);
176 msg.set_arcvm_vsock_cid(event->id());
177 msg.set_event(event->isStarting() ? GuestMessage::START : GuestMessage::STOP);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900178 SendGuestMessage(msg);
Garrick Evans49879532018-12-03 13:15:36 +0900179}
180
Garrick Evans6f258d02019-06-28 16:32:07 +0900181// TODO(garrick): Remove this workaround ASAP.
182bool Manager::OnSignal(const struct signalfd_siginfo& info) {
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900183 // Only ARC++ scripts send signals so nothing to do for VM.
Garrick Evanse94a14e2019-11-11 10:32:13 +0900184 if (info.ssi_signo == SIGUSR1) {
185 // For now this value is ignored and the service discovers the
186 // container pid on its own. Later, this is arrive via DBus message.
187 StartArc(0 /*pid*/);
188 } else {
189 StopArc();
190 }
191
192 // Stay registered.
Garrick Evans6f258d02019-06-28 16:32:07 +0900193 return false;
194}
195
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800196void Manager::OnShutdown(int* exit_code) {
Garrick Evans428e4762018-12-11 15:18:42 +0900197 device_mgr_.reset();
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800198}
199
200void Manager::OnSubprocessExited(pid_t pid, const siginfo_t& info) {
Hugo Benichi10a2af42018-08-27 10:09:42 +0900201 LOG(ERROR) << "Subprocess " << pid << " exited unexpectedly";
202 Quit();
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800203}
204
Garrick Evanse94a14e2019-11-11 10:32:13 +0900205bool Manager::StartArc(pid_t pid) {
206 // TOSO(garrick): Use pid.
207 arc_svc_->OnStart();
208
209 GuestMessage msg;
210 msg.set_event(GuestMessage::START);
211 msg.set_type(GuestMessage::ARC);
212 msg.set_arc_pid(pid);
213 SendGuestMessage(msg);
214
215 return true;
216}
217
218void Manager::StopArc() {
219 GuestMessage msg;
220 msg.set_event(GuestMessage::STOP);
221 msg.set_type(GuestMessage::ARC);
222 SendGuestMessage(msg);
223
224 arc_svc_->OnStop();
225}
226
227bool Manager::StartArcVm(int cid) {
228 // TODO(garrick0: Start ARCVM
229
230 GuestMessage msg;
231 msg.set_event(GuestMessage::START);
232 msg.set_type(GuestMessage::ARC_VM);
233 msg.set_arcvm_vsock_cid(cid);
234 SendGuestMessage(msg);
235
236 return true;
237}
238
239void Manager::StopArcVm() {
240 GuestMessage msg;
241 msg.set_event(GuestMessage::STOP);
242 msg.set_type(GuestMessage::ARC_VM);
243 SendGuestMessage(msg);
244
245 // TODO(garrick): Stop ARCVM
246}
247
Garrick Evans08843932019-09-17 14:41:08 +0900248std::unique_ptr<dbus::Response> Manager::OnArcStartup(
249 dbus::MethodCall* method_call) {
250 LOG(INFO) << "ARC++ starting up";
251
252 std::unique_ptr<dbus::Response> dbus_response(
253 dbus::Response::FromMethodCall(method_call));
254
255 dbus::MessageReader reader(method_call);
256 dbus::MessageWriter writer(dbus_response.get());
257
258 patchpanel::ArcStartupRequest request;
259 patchpanel::ArcStartupResponse response;
260
261 if (!reader.PopArrayOfBytesAsProto(&request)) {
262 LOG(ERROR) << "Unable to parse request";
263 writer.AppendProtoAsArrayOfBytes(response);
264 return dbus_response;
265 }
266
Garrick Evanse94a14e2019-11-11 10:32:13 +0900267 StartArc(request.pid());
268
Garrick Evans08843932019-09-17 14:41:08 +0900269 // TODO(garrick): create and start ArcService.
270 writer.AppendProtoAsArrayOfBytes(response);
271 return dbus_response;
272}
273
274std::unique_ptr<dbus::Response> Manager::OnArcShutdown(
275 dbus::MethodCall* method_call) {
276 LOG(INFO) << "ARC++ shutting down";
277
278 std::unique_ptr<dbus::Response> dbus_response(
279 dbus::Response::FromMethodCall(method_call));
280
281 dbus::MessageReader reader(method_call);
282 dbus::MessageWriter writer(dbus_response.get());
283
284 patchpanel::ArcShutdownRequest request;
285 patchpanel::ArcShutdownResponse response;
286
287 if (!reader.PopArrayOfBytesAsProto(&request)) {
288 LOG(ERROR) << "Unable to parse request";
289 writer.AppendProtoAsArrayOfBytes(response);
290 return dbus_response;
291 }
292
Garrick Evanse94a14e2019-11-11 10:32:13 +0900293 StopArc();
294
Garrick Evans08843932019-09-17 14:41:08 +0900295 // TODO(garrick): delete ArcService.
296 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 // TODO(garrick): create and start ArcVmService.
322 writer.AppendProtoAsArrayOfBytes(response);
323 return dbus_response;
324}
325
326std::unique_ptr<dbus::Response> Manager::OnArcVmShutdown(
327 dbus::MethodCall* method_call) {
328 LOG(INFO) << "ARCVM shutting down";
329
330 std::unique_ptr<dbus::Response> dbus_response(
331 dbus::Response::FromMethodCall(method_call));
332
333 dbus::MessageReader reader(method_call);
334 dbus::MessageWriter writer(dbus_response.get());
335
336 patchpanel::ArcVmShutdownRequest request;
337 patchpanel::ArcVmShutdownResponse response;
338
339 if (!reader.PopArrayOfBytesAsProto(&request)) {
340 LOG(ERROR) << "Unable to parse request";
341 writer.AppendProtoAsArrayOfBytes(response);
342 return dbus_response;
343 }
344
Garrick Evanse94a14e2019-11-11 10:32:13 +0900345 StopArcVm();
346
Garrick Evans08843932019-09-17 14:41:08 +0900347 writer.AppendProtoAsArrayOfBytes(response);
348 return dbus_response;
349}
350
Garrick Evanse94a14e2019-11-11 10:32:13 +0900351void Manager::SendGuestMessage(const GuestMessage& msg) {
Garrick Evans96e03042019-05-28 14:30:52 +0900352 IpHelperMessage ipm;
353 *ipm.mutable_guest_message() = msg;
Garrick Evans96e03042019-05-28 14:30:52 +0900354 adb_proxy_->SendMessage(ipm);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900355 mcast_proxy_->SendMessage(ipm);
356 nd_proxy_->SendMessage(ipm);
Garrick Evans96e03042019-05-28 14:30:52 +0900357}
358
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700359} // namespace arc_networkd