blob: 9a001acc7c83e26e5045317baf32e38e27cc2b94 [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>
Garrick Evans4ac09852020-01-16 14:09:22 +09008#include <net/if.h>
Hugo Benichi935eca92018-07-03 13:47:24 +09009#include <netinet/in.h>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070010#include <stdint.h>
Garrick Evans54861622019-07-19 09:05:09 +090011#include <sys/prctl.h>
Garrick Evans96e03042019-05-28 14:30:52 +090012#include <sys/socket.h>
13#include <sys/un.h>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070014
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080015#include <utility>
16
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070017#include <base/bind.h>
Hugo Benichi7d9d8db2020-03-30 15:56:56 +090018#include "base/files/scoped_file.h"
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070019#include <base/logging.h>
Long Chengd4415582019-09-24 19:16:09 +000020#include <base/message_loop/message_loop.h>
Taoyu Lic85c44b2019-12-04 17:32:57 +090021#include <base/strings/string_number_conversions.h>
Garrick Evans96e03042019-05-28 14:30:52 +090022#include <base/strings/string_split.h>
Garrick Evans6f258d02019-06-28 16:32:07 +090023#include <base/strings/string_util.h>
Taoyu Li179dcc62019-10-17 11:21:08 +090024#include <base/strings/stringprintf.h>
Taoyu Lic85c44b2019-12-04 17:32:57 +090025#include <brillo/key_value_store.h>
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080026#include <brillo/minijail/minijail.h>
27
Garrick Evans428e4762018-12-11 15:18:42 +090028#include "arc/network/ipc.pb.h"
Hugo Benichi7d9d8db2020-03-30 15:56:56 +090029#include "arc/network/routing_service.h"
Garrick Evans428e4762018-12-11 15:18:42 +090030
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070031namespace arc_networkd {
Garrick Evans08843932019-09-17 14:41:08 +090032namespace {
Garrick Evans4c042572019-12-17 13:42:25 +090033constexpr int kSubprocessRestartDelayMs = 900;
Garrick Evans08843932019-09-17 14:41:08 +090034
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090035constexpr char kNDProxyFeatureName[] = "ARC NDProxy";
36constexpr int kNDProxyMinAndroidSdkVersion = 28; // P
37constexpr int kNDProxyMinChromeMilestone = 80;
Taoyu Lic85c44b2019-12-04 17:32:57 +090038
Garrick Evansf5862122020-03-16 09:13:45 +090039constexpr char kArcVmMultinetFeatureName[] = "ARCVM Multinet";
40constexpr int kArcVmMultinetMinAndroidSdkVersion = 29; // R DEV
41constexpr int kArcVmMultinetMinChromeMilestone = 99; // DISABLED
42
Garrick Evans08843932019-09-17 14:41:08 +090043// Passes |method_call| to |handler| and passes the response to
44// |response_sender|. If |handler| returns nullptr, an empty response is
45// created and sent.
46void HandleSynchronousDBusMethodCall(
47 base::Callback<std::unique_ptr<dbus::Response>(dbus::MethodCall*)> handler,
48 dbus::MethodCall* method_call,
49 dbus::ExportedObject::ResponseSender response_sender) {
50 std::unique_ptr<dbus::Response> response = handler.Run(method_call);
51 if (!response)
52 response = dbus::Response::FromMethodCall(method_call);
53 response_sender.Run(std::move(response));
54}
55
56} // namespace
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070057
Taoyu Lice7caa62019-10-01 15:43:33 +090058Manager::Manager(std::unique_ptr<HelperProcess> adb_proxy,
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090059 std::unique_ptr<HelperProcess> mcast_proxy,
Garrick Evans1f5a3612019-11-08 12:59:03 +090060 std::unique_ptr<HelperProcess> nd_proxy)
Garrick Evans3915af32019-07-25 15:44:34 +090061 : adb_proxy_(std::move(adb_proxy)),
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090062 mcast_proxy_(std::move(mcast_proxy)),
Garrick Evans4ee5ce22020-03-18 07:05:17 +090063 nd_proxy_(std::move(nd_proxy)) {
Taoyu Li179dcc62019-10-17 11:21:08 +090064 runner_ = std::make_unique<MinijailedProcessRunner>();
65 datapath_ = std::make_unique<Datapath>(runner_.get());
66}
Long Chengd4415582019-09-24 19:16:09 +000067
Garrick Evans207e7482019-12-16 11:54:36 +090068Manager::~Manager() {
69 OnShutdown(nullptr);
70}
71
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090072std::map<const std::string, bool> Manager::cached_feature_enabled_ = {};
73
74bool Manager::ShouldEnableFeature(
75 int min_android_sdk_version,
76 int min_chrome_milestone,
77 const std::vector<std::string>& supported_boards,
78 const std::string& feature_name) {
79 static const char kLsbReleasePath[] = "/etc/lsb-release";
80
81 const auto& cached_result = cached_feature_enabled_.find(feature_name);
82 if (cached_result != cached_feature_enabled_.end())
83 return cached_result->second;
84
85 auto check = [min_android_sdk_version, min_chrome_milestone,
86 &supported_boards, &feature_name]() {
87 brillo::KeyValueStore store;
88 if (!store.Load(base::FilePath(kLsbReleasePath))) {
89 LOG(ERROR) << "Could not read lsb-release";
90 return false;
91 }
92
93 std::string value;
94 if (!store.GetString("CHROMEOS_ARC_ANDROID_SDK_VERSION", &value)) {
95 LOG(ERROR) << feature_name
96 << " disabled - cannot determine Android SDK version";
97 return false;
98 }
99 int ver = 0;
100 if (!base::StringToInt(value.c_str(), &ver)) {
101 LOG(ERROR) << feature_name << " disabled - invalid Android SDK version";
102 return false;
103 }
104 if (ver < min_android_sdk_version) {
105 LOG(INFO) << feature_name << " disabled for Android SDK " << value;
106 return false;
107 }
108
109 if (!store.GetString("CHROMEOS_RELEASE_CHROME_MILESTONE", &value)) {
110 LOG(ERROR) << feature_name
111 << " disabled - cannot determine ChromeOS milestone";
112 return false;
113 }
114 if (!base::StringToInt(value.c_str(), &ver)) {
115 LOG(ERROR) << feature_name << " disabled - invalid ChromeOS milestone";
116 return false;
117 }
118 if (ver < min_chrome_milestone) {
119 LOG(INFO) << feature_name << " disabled for ChromeOS milestone " << value;
120 return false;
121 }
122
123 if (!store.GetString("CHROMEOS_RELEASE_BOARD", &value)) {
124 LOG(ERROR) << feature_name << " disabled - cannot determine board";
125 return false;
126 }
127 if (!supported_boards.empty() &&
128 std::find(supported_boards.begin(), supported_boards.end(), value) ==
129 supported_boards.end()) {
130 LOG(INFO) << feature_name << " disabled for board " << value;
131 return false;
132 }
133 return true;
134 };
135
136 bool result = check();
137 cached_feature_enabled_.emplace(feature_name, result);
138 return result;
139}
140
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700141int Manager::OnInit() {
Garrick Evans54861622019-07-19 09:05:09 +0900142 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800143
144 // Handle subprocess lifecycle.
145 process_reaper_.Register(this);
Hugo Benichi935eca92018-07-03 13:47:24 +0900146
147 CHECK(process_reaper_.WatchForChild(
Garrick Evans96e03042019-05-28 14:30:52 +0900148 FROM_HERE, adb_proxy_->pid(),
149 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
150 adb_proxy_->pid())))
151 << "Failed to watch adb-proxy child process";
Taoyu Liaf944c92019-10-01 12:22:31 +0900152 CHECK(process_reaper_.WatchForChild(
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +0900153 FROM_HERE, mcast_proxy_->pid(),
154 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
155 nd_proxy_->pid())))
156 << "Failed to watch multicast-proxy child process";
157 CHECK(process_reaper_.WatchForChild(
Taoyu Liaf944c92019-10-01 12:22:31 +0900158 FROM_HERE, nd_proxy_->pid(),
159 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
160 nd_proxy_->pid())))
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +0900161 << "Failed to watch nd-proxy child process";
Garrick Evans96e03042019-05-28 14:30:52 +0900162
Garrick Evans49879532018-12-03 13:15:36 +0900163 // Run after Daemon::OnInit().
Eric Caruso9ce54182018-01-04 11:19:47 -0800164 base::MessageLoopForIO::current()->task_runner()->PostTask(
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700165 FROM_HERE,
166 base::Bind(&Manager::InitialSetup, weak_factory_.GetWeakPtr()));
167
168 return DBusDaemon::OnInit();
169}
170
171void Manager::InitialSetup() {
Garrick Evans08843932019-09-17 14:41:08 +0900172 LOG(INFO) << "Setting up DBus service interface";
173 dbus_svc_path_ = bus_->GetExportedObject(
174 dbus::ObjectPath(patchpanel::kPatchPanelServicePath));
175 if (!dbus_svc_path_) {
176 LOG(FATAL) << "Failed to export " << patchpanel::kPatchPanelServicePath
177 << " object";
178 }
179
180 using ServiceMethod =
181 std::unique_ptr<dbus::Response> (Manager::*)(dbus::MethodCall*);
182 const std::map<const char*, ServiceMethod> kServiceMethods = {
183 {patchpanel::kArcStartupMethod, &Manager::OnArcStartup},
184 {patchpanel::kArcShutdownMethod, &Manager::OnArcShutdown},
185 {patchpanel::kArcVmStartupMethod, &Manager::OnArcVmStartup},
186 {patchpanel::kArcVmShutdownMethod, &Manager::OnArcVmShutdown},
Garrick Evans47c19272019-11-21 10:58:21 +0900187 {patchpanel::kTerminaVmStartupMethod, &Manager::OnTerminaVmStartup},
188 {patchpanel::kTerminaVmShutdownMethod, &Manager::OnTerminaVmShutdown},
Garrick Evans51d5b552020-01-30 10:42:06 +0900189 {patchpanel::kPluginVmStartupMethod, &Manager::OnPluginVmStartup},
190 {patchpanel::kPluginVmShutdownMethod, &Manager::OnPluginVmShutdown},
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900191 {patchpanel::kSetVpnIntentMethod, &Manager::OnSetVpnIntent},
Hugo Benichib56b77c2020-01-15 16:00:56 +0900192 {patchpanel::kConnectNamespaceMethod, &Manager::OnConnectNamespace},
Garrick Evans08843932019-09-17 14:41:08 +0900193 };
194
195 for (const auto& kv : kServiceMethods) {
196 if (!dbus_svc_path_->ExportMethodAndBlock(
197 patchpanel::kPatchPanelInterface, kv.first,
198 base::Bind(&HandleSynchronousDBusMethodCall,
199 base::Bind(kv.second, base::Unretained(this))))) {
200 LOG(FATAL) << "Failed to export method " << kv.first;
201 }
202 }
203
204 if (!bus_->RequestOwnershipAndBlock(patchpanel::kPatchPanelServiceName,
205 dbus::Bus::REQUIRE_PRIMARY)) {
206 LOG(FATAL) << "Failed to take ownership of "
207 << patchpanel::kPatchPanelServiceName;
208 }
209 LOG(INFO) << "DBus service interface ready";
210
Taoyu Li6d479442019-12-09 13:02:29 +0900211 auto& runner = datapath_->runner();
Garrick Evans28d194e2019-12-17 10:22:28 +0900212 // Limit local port range: Android owns 47104-61000.
213 // TODO(garrick): The original history behind this tweak is gone. Some
214 // investigation is needed to see if it is still applicable.
Garrick Evans8e8e3472020-01-23 14:03:50 +0900215 if (runner.sysctl_w("net.ipv4.ip_local_port_range", "32768 47103") != 0) {
Garrick Evans28d194e2019-12-17 10:22:28 +0900216 LOG(ERROR) << "Failed to limit local port range. Some Android features or"
217 << " apps may not work correctly.";
218 }
Taoyu Li6d479442019-12-09 13:02:29 +0900219 // Enable IPv6 packet forarding
Garrick Evans8e8e3472020-01-23 14:03:50 +0900220 if (runner.sysctl_w("net.ipv6.conf.all.forwarding", "1") != 0) {
Taoyu Li6d479442019-12-09 13:02:29 +0900221 LOG(ERROR) << "Failed to update net.ipv6.conf.all.forwarding."
222 << " IPv6 functionality may be broken.";
223 }
224 // Kernel proxy_ndp is only needed for legacy IPv6 configuration
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +0900225 if (!ShouldEnableFeature(kNDProxyMinAndroidSdkVersion,
Garrick Evansf5862122020-03-16 09:13:45 +0900226 kNDProxyMinChromeMilestone, {},
227 kNDProxyFeatureName) &&
Garrick Evans8e8e3472020-01-23 14:03:50 +0900228 runner.sysctl_w("net.ipv6.conf.all.proxy_ndp", "1") != 0) {
Taoyu Li6d479442019-12-09 13:02:29 +0900229 LOG(ERROR) << "Failed to update net.ipv6.conf.all.proxy_ndp."
230 << " IPv6 functionality may be broken.";
231 }
232
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900233 routing_svc_ = std::make_unique<RoutingService>();
234
Garrick Evans4ac09852020-01-16 14:09:22 +0900235 nd_proxy_->RegisterDeviceMessageHandler(base::Bind(
236 &Manager::OnDeviceMessageFromNDProxy, weak_factory_.GetWeakPtr()));
237
Garrick Evans69b85872020-02-04 11:40:26 +0900238 shill_client_ = std::make_unique<ShillClient>(bus_);
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900239 auto* const forwarder = static_cast<TrafficForwarder*>(this);
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900240
Garrick Evansf5862122020-03-16 09:13:45 +0900241 arc_svc_ = std::make_unique<ArcService>(
242 shill_client_.get(), datapath_.get(), &addr_mgr_, forwarder,
243 ShouldEnableFeature(kArcVmMultinetMinAndroidSdkVersion,
244 kArcVmMultinetMinChromeMilestone, {},
245 kArcVmMultinetFeatureName));
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900246 cros_svc_ = std::make_unique<CrostiniService>(shill_client_.get(), &addr_mgr_,
247 datapath_.get(), forwarder);
Taoyu Liaf944c92019-10-01 12:22:31 +0900248
249 nd_proxy_->Listen();
Long Chengd4415582019-09-24 19:16:09 +0000250}
Garrick Evans49879532018-12-03 13:15:36 +0900251
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800252void Manager::OnShutdown(int* exit_code) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900253 LOG(INFO) << "Shutting down and cleaning up";
Garrick Evans207e7482019-12-16 11:54:36 +0900254 cros_svc_.reset();
255 arc_svc_.reset();
Garrick Evans28d194e2019-12-17 10:22:28 +0900256
257 // Restore original local port range.
258 // TODO(garrick): The original history behind this tweak is gone. Some
259 // investigation is needed to see if it is still applicable.
Garrick Evans8e8e3472020-01-23 14:03:50 +0900260 if (datapath_->runner().sysctl_w("net.ipv4.ip_local_port_range",
261 "32768 61000") != 0) {
Garrick Evans28d194e2019-12-17 10:22:28 +0900262 LOG(ERROR) << "Failed to restore local port range";
263 }
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800264}
265
Garrick Evans4c042572019-12-17 13:42:25 +0900266void Manager::OnSubprocessExited(pid_t pid, const siginfo_t&) {
267 LOG(ERROR) << "Subprocess " << pid << " exited unexpectedly -"
268 << " attempting to restart";
269
270 HelperProcess* proc;
271 if (pid == adb_proxy_->pid()) {
272 proc = adb_proxy_.get();
273 } else if (pid == mcast_proxy_->pid()) {
274 proc = mcast_proxy_.get();
275 } else if (pid == nd_proxy_->pid()) {
276 proc = nd_proxy_.get();
277 } else {
278 LOG(DFATAL) << "Unknown child process";
279 return;
280 }
281
282 process_reaper_.ForgetChild(pid);
283
284 base::MessageLoopForIO::current()->task_runner()->PostDelayedTask(
285 FROM_HERE,
286 base::Bind(&Manager::RestartSubprocess, weak_factory_.GetWeakPtr(), proc),
287 base::TimeDelta::FromMilliseconds((2 << proc->restarts()) *
288 kSubprocessRestartDelayMs));
289}
290
291void Manager::RestartSubprocess(HelperProcess* subproc) {
292 if (subproc->Restart()) {
293 DCHECK(process_reaper_.WatchForChild(
294 FROM_HERE, subproc->pid(),
295 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
296 subproc->pid())))
297 << "Failed to watch child process " << subproc->pid();
298 }
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800299}
300
Garrick Evanse94a14e2019-11-11 10:32:13 +0900301bool Manager::StartArc(pid_t pid) {
Garrick Evans508a4bc2019-11-14 08:45:52 +0900302 if (!arc_svc_->Start(pid))
303 return false;
Garrick Evanse94a14e2019-11-11 10:32:13 +0900304
305 GuestMessage msg;
306 msg.set_event(GuestMessage::START);
307 msg.set_type(GuestMessage::ARC);
308 msg.set_arc_pid(pid);
309 SendGuestMessage(msg);
310
311 return true;
312}
313
Garrick Evans21173b12019-11-20 15:23:16 +0900314void Manager::StopArc(pid_t pid) {
Garrick Evanse94a14e2019-11-11 10:32:13 +0900315 GuestMessage msg;
316 msg.set_event(GuestMessage::STOP);
317 msg.set_type(GuestMessage::ARC);
318 SendGuestMessage(msg);
319
Garrick Evans21173b12019-11-20 15:23:16 +0900320 arc_svc_->Stop(pid);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900321}
322
Garrick Evans015b0d62020-02-07 09:06:38 +0900323bool Manager::StartArcVm(uint32_t cid) {
Garrick Evans508a4bc2019-11-14 08:45:52 +0900324 if (!arc_svc_->Start(cid))
325 return false;
Garrick Evanse94a14e2019-11-11 10:32:13 +0900326
327 GuestMessage msg;
328 msg.set_event(GuestMessage::START);
329 msg.set_type(GuestMessage::ARC_VM);
330 msg.set_arcvm_vsock_cid(cid);
331 SendGuestMessage(msg);
332
333 return true;
334}
335
Garrick Evans015b0d62020-02-07 09:06:38 +0900336void Manager::StopArcVm(uint32_t cid) {
Garrick Evanse94a14e2019-11-11 10:32:13 +0900337 GuestMessage msg;
338 msg.set_event(GuestMessage::STOP);
339 msg.set_type(GuestMessage::ARC_VM);
340 SendGuestMessage(msg);
341
Garrick Evans21173b12019-11-20 15:23:16 +0900342 arc_svc_->Stop(cid);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900343}
344
Garrick Evans51d5b552020-01-30 10:42:06 +0900345bool Manager::StartCrosVm(uint64_t vm_id,
346 GuestMessage::GuestType vm_type,
Garrick Evans53a2a982020-02-05 10:53:35 +0900347 uint32_t subnet_index) {
Garrick Evans51d5b552020-01-30 10:42:06 +0900348 DCHECK(vm_type == GuestMessage::TERMINA_VM ||
349 vm_type == GuestMessage::PLUGIN_VM);
350
351 if (!cros_svc_->Start(vm_id, vm_type == GuestMessage::TERMINA_VM,
352 subnet_index))
Garrick Evans47c19272019-11-21 10:58:21 +0900353 return false;
354
355 GuestMessage msg;
356 msg.set_event(GuestMessage::START);
Garrick Evans51d5b552020-01-30 10:42:06 +0900357 msg.set_type(vm_type);
Garrick Evans47c19272019-11-21 10:58:21 +0900358 SendGuestMessage(msg);
359
360 return true;
361}
362
Garrick Evans51d5b552020-01-30 10:42:06 +0900363void Manager::StopCrosVm(uint64_t vm_id, GuestMessage::GuestType vm_type) {
Garrick Evans47c19272019-11-21 10:58:21 +0900364 GuestMessage msg;
365 msg.set_event(GuestMessage::STOP);
Garrick Evans51d5b552020-01-30 10:42:06 +0900366 msg.set_type(vm_type);
Garrick Evans47c19272019-11-21 10:58:21 +0900367 SendGuestMessage(msg);
368
Garrick Evans51d5b552020-01-30 10:42:06 +0900369 cros_svc_->Stop(vm_id, vm_type == GuestMessage::TERMINA_VM);
Garrick Evans47c19272019-11-21 10:58:21 +0900370}
371
Garrick Evans08843932019-09-17 14:41:08 +0900372std::unique_ptr<dbus::Response> Manager::OnArcStartup(
373 dbus::MethodCall* method_call) {
374 LOG(INFO) << "ARC++ starting up";
375
376 std::unique_ptr<dbus::Response> dbus_response(
377 dbus::Response::FromMethodCall(method_call));
378
379 dbus::MessageReader reader(method_call);
380 dbus::MessageWriter writer(dbus_response.get());
381
382 patchpanel::ArcStartupRequest request;
383 patchpanel::ArcStartupResponse response;
384
385 if (!reader.PopArrayOfBytesAsProto(&request)) {
386 LOG(ERROR) << "Unable to parse request";
387 writer.AppendProtoAsArrayOfBytes(response);
388 return dbus_response;
389 }
390
Garrick Evanse01bf072019-11-15 09:08:19 +0900391 if (!StartArc(request.pid()))
392 LOG(ERROR) << "Failed to start ARC++ network service";
Garrick Evanse94a14e2019-11-11 10:32:13 +0900393
Garrick Evans08843932019-09-17 14:41:08 +0900394 writer.AppendProtoAsArrayOfBytes(response);
395 return dbus_response;
396}
397
398std::unique_ptr<dbus::Response> Manager::OnArcShutdown(
399 dbus::MethodCall* method_call) {
400 LOG(INFO) << "ARC++ shutting down";
401
402 std::unique_ptr<dbus::Response> dbus_response(
403 dbus::Response::FromMethodCall(method_call));
404
405 dbus::MessageReader reader(method_call);
406 dbus::MessageWriter writer(dbus_response.get());
407
408 patchpanel::ArcShutdownRequest request;
409 patchpanel::ArcShutdownResponse response;
410
411 if (!reader.PopArrayOfBytesAsProto(&request)) {
412 LOG(ERROR) << "Unable to parse request";
413 writer.AppendProtoAsArrayOfBytes(response);
414 return dbus_response;
415 }
416
Garrick Evans21173b12019-11-20 15:23:16 +0900417 StopArc(request.pid());
Garrick Evanse94a14e2019-11-11 10:32:13 +0900418
Garrick Evans08843932019-09-17 14:41:08 +0900419 writer.AppendProtoAsArrayOfBytes(response);
420 return dbus_response;
421}
422
423std::unique_ptr<dbus::Response> Manager::OnArcVmStartup(
424 dbus::MethodCall* method_call) {
425 LOG(INFO) << "ARCVM starting up";
426
427 std::unique_ptr<dbus::Response> dbus_response(
428 dbus::Response::FromMethodCall(method_call));
429
430 dbus::MessageReader reader(method_call);
431 dbus::MessageWriter writer(dbus_response.get());
432
433 patchpanel::ArcVmStartupRequest request;
434 patchpanel::ArcVmStartupResponse response;
435
436 if (!reader.PopArrayOfBytesAsProto(&request)) {
437 LOG(ERROR) << "Unable to parse request";
438 writer.AppendProtoAsArrayOfBytes(response);
439 return dbus_response;
440 }
441
Garrick Evans47c19272019-11-21 10:58:21 +0900442 if (!StartArcVm(request.cid())) {
Garrick Evanse01bf072019-11-15 09:08:19 +0900443 LOG(ERROR) << "Failed to start ARCVM network service";
Garrick Evans47c19272019-11-21 10:58:21 +0900444 writer.AppendProtoAsArrayOfBytes(response);
445 return dbus_response;
Garrick Evanse01bf072019-11-15 09:08:19 +0900446 }
Garrick Evanse94a14e2019-11-11 10:32:13 +0900447
Garrick Evans47c19272019-11-21 10:58:21 +0900448 // Populate the response with the known devices.
Garrick Evans38b25a42020-04-06 15:17:42 +0900449 for (const auto* config : arc_svc_->GetDeviceConfigs()) {
450 if (config->tap_ifname().empty())
451 continue;
Garrick Evans47c19272019-11-21 10:58:21 +0900452
Garrick Evans38b25a42020-04-06 15:17:42 +0900453 auto* dev = response.add_devices();
454 dev->set_ifname(config->tap_ifname());
455 dev->set_ipv4_addr(config->guest_ipv4_addr());
456 }
Garrick Evanse94b6de2020-02-20 09:19:13 +0900457
Garrick Evans08843932019-09-17 14:41:08 +0900458 writer.AppendProtoAsArrayOfBytes(response);
459 return dbus_response;
460}
461
462std::unique_ptr<dbus::Response> Manager::OnArcVmShutdown(
463 dbus::MethodCall* method_call) {
464 LOG(INFO) << "ARCVM shutting down";
465
466 std::unique_ptr<dbus::Response> dbus_response(
467 dbus::Response::FromMethodCall(method_call));
468
469 dbus::MessageReader reader(method_call);
470 dbus::MessageWriter writer(dbus_response.get());
471
472 patchpanel::ArcVmShutdownRequest request;
473 patchpanel::ArcVmShutdownResponse response;
474
475 if (!reader.PopArrayOfBytesAsProto(&request)) {
476 LOG(ERROR) << "Unable to parse request";
477 writer.AppendProtoAsArrayOfBytes(response);
478 return dbus_response;
479 }
480
Garrick Evans21173b12019-11-20 15:23:16 +0900481 StopArcVm(request.cid());
Garrick Evanse94a14e2019-11-11 10:32:13 +0900482
Garrick Evans08843932019-09-17 14:41:08 +0900483 writer.AppendProtoAsArrayOfBytes(response);
484 return dbus_response;
485}
486
Garrick Evans47c19272019-11-21 10:58:21 +0900487std::unique_ptr<dbus::Response> Manager::OnTerminaVmStartup(
488 dbus::MethodCall* method_call) {
489 LOG(INFO) << "Termina VM starting up";
490
491 std::unique_ptr<dbus::Response> dbus_response(
492 dbus::Response::FromMethodCall(method_call));
493
494 dbus::MessageReader reader(method_call);
495 dbus::MessageWriter writer(dbus_response.get());
496
497 patchpanel::TerminaVmStartupRequest request;
498 patchpanel::TerminaVmStartupResponse response;
499
500 if (!reader.PopArrayOfBytesAsProto(&request)) {
501 LOG(ERROR) << "Unable to parse request";
502 writer.AppendProtoAsArrayOfBytes(response);
503 return dbus_response;
504 }
505
506 const int32_t cid = request.cid();
Garrick Evans53a2a982020-02-05 10:53:35 +0900507 if (!StartCrosVm(cid, GuestMessage::TERMINA_VM)) {
Garrick Evans47c19272019-11-21 10:58:21 +0900508 LOG(ERROR) << "Failed to start Termina VM network service";
509 writer.AppendProtoAsArrayOfBytes(response);
510 return dbus_response;
511 }
512
Garrick Evans51d5b552020-01-30 10:42:06 +0900513 const auto* const tap = cros_svc_->TAP(cid, true /*is_termina*/);
Garrick Evansb1c93712020-01-22 09:28:25 +0900514 if (!tap) {
515 LOG(DFATAL) << "TAP device missing";
516 writer.AppendProtoAsArrayOfBytes(response);
517 return dbus_response;
518 }
Garrick Evans47c19272019-11-21 10:58:21 +0900519
Garrick Evansb1c93712020-01-22 09:28:25 +0900520 auto* dev = response.mutable_device();
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900521 dev->set_ifname(tap->host_ifname());
522 const auto* subnet = tap->config().ipv4_subnet();
Garrick Evansb1c93712020-01-22 09:28:25 +0900523 if (!subnet) {
524 LOG(DFATAL) << "Missing required subnet for {cid: " << cid << "}";
525 writer.AppendProtoAsArrayOfBytes(response);
526 return dbus_response;
527 }
528 auto* resp_subnet = dev->mutable_ipv4_subnet();
529 resp_subnet->set_base_addr(subnet->BaseAddress());
530 resp_subnet->set_prefix_len(subnet->PrefixLength());
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900531 subnet = tap->config().lxd_ipv4_subnet();
Garrick Evansb1c93712020-01-22 09:28:25 +0900532 if (!subnet) {
533 LOG(DFATAL) << "Missing required lxd subnet for {cid: " << cid << "}";
534 writer.AppendProtoAsArrayOfBytes(response);
535 return dbus_response;
536 }
537 resp_subnet = response.mutable_container_subnet();
538 resp_subnet->set_base_addr(subnet->BaseAddress());
539 resp_subnet->set_prefix_len(subnet->PrefixLength());
Garrick Evans47c19272019-11-21 10:58:21 +0900540
541 writer.AppendProtoAsArrayOfBytes(response);
542 return dbus_response;
543}
544
545std::unique_ptr<dbus::Response> Manager::OnTerminaVmShutdown(
546 dbus::MethodCall* method_call) {
547 LOG(INFO) << "Termina VM shutting down";
548
549 std::unique_ptr<dbus::Response> dbus_response(
550 dbus::Response::FromMethodCall(method_call));
551
552 dbus::MessageReader reader(method_call);
553 dbus::MessageWriter writer(dbus_response.get());
554
555 patchpanel::TerminaVmShutdownRequest request;
556 patchpanel::TerminaVmShutdownResponse response;
557
558 if (!reader.PopArrayOfBytesAsProto(&request)) {
559 LOG(ERROR) << "Unable to parse request";
560 writer.AppendProtoAsArrayOfBytes(response);
561 return dbus_response;
562 }
563
Garrick Evans51d5b552020-01-30 10:42:06 +0900564 StopCrosVm(request.cid(), GuestMessage::TERMINA_VM);
565
566 writer.AppendProtoAsArrayOfBytes(response);
567 return dbus_response;
568}
569
570std::unique_ptr<dbus::Response> Manager::OnPluginVmStartup(
571 dbus::MethodCall* method_call) {
572 LOG(INFO) << "Plugin VM starting up";
573
574 std::unique_ptr<dbus::Response> dbus_response(
575 dbus::Response::FromMethodCall(method_call));
576
577 dbus::MessageReader reader(method_call);
578 dbus::MessageWriter writer(dbus_response.get());
579
580 patchpanel::PluginVmStartupRequest request;
581 patchpanel::PluginVmStartupResponse response;
582
583 if (!reader.PopArrayOfBytesAsProto(&request)) {
584 LOG(ERROR) << "Unable to parse request";
585 writer.AppendProtoAsArrayOfBytes(response);
586 return dbus_response;
587 }
588
Garrick Evans08fb34b2020-02-20 10:50:17 +0900589 const uint64_t vm_id = request.id();
Garrick Evans53a2a982020-02-05 10:53:35 +0900590 if (!StartCrosVm(vm_id, GuestMessage::PLUGIN_VM, request.subnet_index())) {
Garrick Evans51d5b552020-01-30 10:42:06 +0900591 LOG(ERROR) << "Failed to start Plugin VM network service";
592 writer.AppendProtoAsArrayOfBytes(response);
593 return dbus_response;
594 }
595
596 const auto* const tap = cros_svc_->TAP(vm_id, false /*is_termina*/);
597 if (!tap) {
598 LOG(DFATAL) << "TAP device missing";
599 writer.AppendProtoAsArrayOfBytes(response);
600 return dbus_response;
601 }
602
Garrick Evans51d5b552020-01-30 10:42:06 +0900603 auto* dev = response.mutable_device();
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900604 dev->set_ifname(tap->host_ifname());
605 const auto* subnet = tap->config().ipv4_subnet();
Garrick Evans51d5b552020-01-30 10:42:06 +0900606 if (!subnet) {
607 LOG(DFATAL) << "Missing required subnet for {cid: " << vm_id << "}";
608 writer.AppendProtoAsArrayOfBytes(response);
609 return dbus_response;
610 }
611 auto* resp_subnet = dev->mutable_ipv4_subnet();
612 resp_subnet->set_base_addr(subnet->BaseAddress());
613 resp_subnet->set_prefix_len(subnet->PrefixLength());
614
615 writer.AppendProtoAsArrayOfBytes(response);
616 return dbus_response;
617}
618
619std::unique_ptr<dbus::Response> Manager::OnPluginVmShutdown(
620 dbus::MethodCall* method_call) {
621 LOG(INFO) << "Plugin VM shutting down";
622
623 std::unique_ptr<dbus::Response> dbus_response(
624 dbus::Response::FromMethodCall(method_call));
625
626 dbus::MessageReader reader(method_call);
627 dbus::MessageWriter writer(dbus_response.get());
628
629 patchpanel::PluginVmShutdownRequest request;
630 patchpanel::PluginVmShutdownResponse response;
631
632 if (!reader.PopArrayOfBytesAsProto(&request)) {
633 LOG(ERROR) << "Unable to parse request";
634 writer.AppendProtoAsArrayOfBytes(response);
635 return dbus_response;
636 }
637
638 StopCrosVm(request.id(), GuestMessage::PLUGIN_VM);
Garrick Evans47c19272019-11-21 10:58:21 +0900639
640 writer.AppendProtoAsArrayOfBytes(response);
641 return dbus_response;
642}
643
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900644std::unique_ptr<dbus::Response> Manager::OnSetVpnIntent(
645 dbus::MethodCall* method_call) {
646 std::unique_ptr<dbus::Response> dbus_response(
647 dbus::Response::FromMethodCall(method_call));
648
649 dbus::MessageReader reader(method_call);
650 dbus::MessageWriter writer(dbus_response.get());
651
652 patchpanel::SetVpnIntentRequest request;
653 patchpanel::SetVpnIntentResponse response;
654
655 bool success = reader.PopArrayOfBytesAsProto(&request);
656 if (!success) {
657 LOG(ERROR) << "Unable to parse SetVpnIntentRequest";
658 // Do not return yet to make sure we close the received fd.
659 }
660
661 base::ScopedFD client_socket;
662 reader.PopFileDescriptor(&client_socket);
663
664 if (success)
665 success = routing_svc_->SetVpnFwmark(client_socket.get(), request.policy());
666
667 response.set_success(success);
Hugo Benichib56b77c2020-01-15 16:00:56 +0900668
669 writer.AppendProtoAsArrayOfBytes(response);
670 return dbus_response;
671}
672
673std::unique_ptr<dbus::Response> Manager::OnConnectNamespace(
674 dbus::MethodCall* method_call) {
675 std::unique_ptr<dbus::Response> dbus_response(
676 dbus::Response::FromMethodCall(method_call));
677
678 dbus::MessageReader reader(method_call);
679 dbus::MessageWriter writer(dbus_response.get());
680
681 patchpanel::ConnectNamespaceRequest request;
682 patchpanel::ConnectNamespaceResponse response;
683
684 if (!reader.PopArrayOfBytesAsProto(&request)) {
685 LOG(ERROR) << "Unable to parse request";
686 writer.AppendProtoAsArrayOfBytes(response);
687 return dbus_response;
688 }
689
690 // TODO(hugobenichi, b/147712924): Implement
691
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900692 writer.AppendProtoAsArrayOfBytes(response);
693 return dbus_response;
694}
695
Garrick Evanse94a14e2019-11-11 10:32:13 +0900696void Manager::SendGuestMessage(const GuestMessage& msg) {
Garrick Evans96e03042019-05-28 14:30:52 +0900697 IpHelperMessage ipm;
698 *ipm.mutable_guest_message() = msg;
Garrick Evans96e03042019-05-28 14:30:52 +0900699 adb_proxy_->SendMessage(ipm);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900700 mcast_proxy_->SendMessage(ipm);
701 nd_proxy_->SendMessage(ipm);
Garrick Evans96e03042019-05-28 14:30:52 +0900702}
703
Garrick Evans4ac09852020-01-16 14:09:22 +0900704void Manager::StartForwarding(const std::string& ifname_physical,
705 const std::string& ifname_virtual,
Garrick Evans4ac09852020-01-16 14:09:22 +0900706 bool ipv6,
707 bool multicast) {
Taoyu Li7dca19a2020-03-16 16:27:07 +0900708 if (ifname_physical.empty() || ifname_virtual.empty())
Garrick Evans4ac09852020-01-16 14:09:22 +0900709 return;
710
711 IpHelperMessage ipm;
712 DeviceMessage* msg = ipm.mutable_device_message();
713 msg->set_dev_ifname(ifname_physical);
Garrick Evans4ac09852020-01-16 14:09:22 +0900714 msg->set_br_ifname(ifname_virtual);
715
716 if (ipv6) {
717 LOG(INFO) << "Starting IPv6 forwarding from " << ifname_physical << " to "
718 << ifname_virtual;
719
720 if (!datapath_->AddIPv6Forwarding(ifname_physical, ifname_virtual)) {
721 LOG(ERROR) << "Failed to setup iptables forwarding rule for IPv6 from "
722 << ifname_physical << " to " << ifname_virtual;
723 }
724 if (!datapath_->MaskInterfaceFlags(ifname_physical, IFF_ALLMULTI)) {
725 LOG(WARNING) << "Failed to setup all multicast mode for interface "
726 << ifname_physical;
727 }
728 if (!datapath_->MaskInterfaceFlags(ifname_virtual, IFF_ALLMULTI)) {
729 LOG(WARNING) << "Failed to setup all multicast mode for interface "
730 << ifname_virtual;
731 }
732 nd_proxy_->SendMessage(ipm);
733 }
734
735 if (multicast) {
736 LOG(INFO) << "Starting multicast forwarding from " << ifname_physical
737 << " to " << ifname_virtual;
738 mcast_proxy_->SendMessage(ipm);
739 }
740}
741
742void Manager::StopForwarding(const std::string& ifname_physical,
743 const std::string& ifname_virtual,
744 bool ipv6,
745 bool multicast) {
746 if (ifname_physical.empty())
747 return;
748
749 IpHelperMessage ipm;
750 DeviceMessage* msg = ipm.mutable_device_message();
751 msg->set_dev_ifname(ifname_physical);
752 msg->set_teardown(true);
Taoyu Li7dca19a2020-03-16 16:27:07 +0900753 if (!ifname_virtual.empty()) {
754 msg->set_br_ifname(ifname_virtual);
755 }
Garrick Evans4ac09852020-01-16 14:09:22 +0900756
757 if (ipv6) {
Taoyu Li7dca19a2020-03-16 16:27:07 +0900758 if (ifname_virtual.empty()) {
759 LOG(INFO) << "Stopping IPv6 forwarding on " << ifname_physical;
760 } else {
761 LOG(INFO) << "Stopping IPv6 forwarding from " << ifname_physical << " to "
762 << ifname_virtual;
763 datapath_->RemoveIPv6Forwarding(ifname_physical, ifname_virtual);
764 }
Garrick Evans4ac09852020-01-16 14:09:22 +0900765 nd_proxy_->SendMessage(ipm);
766 }
767
768 if (multicast) {
Taoyu Li7dca19a2020-03-16 16:27:07 +0900769 if (ifname_virtual.empty()) {
770 LOG(INFO) << "Stopping multicast forwarding on " << ifname_physical;
771 } else {
772 LOG(INFO) << "Stopping multicast forwarding from " << ifname_physical
773 << " to " << ifname_virtual;
774 }
Garrick Evans4ac09852020-01-16 14:09:22 +0900775 mcast_proxy_->SendMessage(ipm);
776 }
777}
778
Garrick Evans4ac09852020-01-16 14:09:22 +0900779void Manager::OnDeviceMessageFromNDProxy(const DeviceMessage& msg) {
780 LOG_IF(DFATAL, msg.dev_ifname().empty())
781 << "Received DeviceMessage w/ empty dev_ifname";
782
783 if (!datapath_->AddIPv6HostRoute(msg.dev_ifname(), msg.guest_ip6addr(),
784 128)) {
785 LOG(WARNING) << "Failed to setup the IPv6 route for interface "
786 << msg.dev_ifname();
787 }
788}
789
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700790} // namespace arc_networkd