blob: bb75072b01680e9047350180e74f08400fc320bf [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>
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 {
Garrick Evans4c042572019-12-17 13:42:25 +090031constexpr int kSubprocessRestartDelayMs = 900;
Garrick Evans08843932019-09-17 14:41:08 +090032
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090033constexpr char kNDProxyFeatureName[] = "ARC NDProxy";
34constexpr int kNDProxyMinAndroidSdkVersion = 28; // P
35constexpr int kNDProxyMinChromeMilestone = 80;
Taoyu Lic85c44b2019-12-04 17:32:57 +090036
Garrick Evans08843932019-09-17 14:41:08 +090037// Passes |method_call| to |handler| and passes the response to
38// |response_sender|. If |handler| returns nullptr, an empty response is
39// created and sent.
40void HandleSynchronousDBusMethodCall(
41 base::Callback<std::unique_ptr<dbus::Response>(dbus::MethodCall*)> handler,
42 dbus::MethodCall* method_call,
43 dbus::ExportedObject::ResponseSender response_sender) {
44 std::unique_ptr<dbus::Response> response = handler.Run(method_call);
45 if (!response)
46 response = dbus::Response::FromMethodCall(method_call);
47 response_sender.Run(std::move(response));
48}
49
50} // namespace
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070051
Taoyu Lice7caa62019-10-01 15:43:33 +090052Manager::Manager(std::unique_ptr<HelperProcess> adb_proxy,
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090053 std::unique_ptr<HelperProcess> mcast_proxy,
Garrick Evans1f5a3612019-11-08 12:59:03 +090054 std::unique_ptr<HelperProcess> nd_proxy)
Garrick Evans3915af32019-07-25 15:44:34 +090055 : adb_proxy_(std::move(adb_proxy)),
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090056 mcast_proxy_(std::move(mcast_proxy)),
Taoyu Lice7caa62019-10-01 15:43:33 +090057 nd_proxy_(std::move(nd_proxy)),
Garrick Evans96e03042019-05-28 14:30:52 +090058 addr_mgr_({
Garrick Evansf4a93292019-03-13 14:19:43 +090059 AddressManager::Guest::ARC,
60 AddressManager::Guest::ARC_NET,
Garrick Evans47c19272019-11-21 10:58:21 +090061 AddressManager::Guest::CONTAINER,
Garrick Evans508a4bc2019-11-14 08:45:52 +090062 AddressManager::Guest::VM_ARC,
Garrick Evans47c19272019-11-21 10:58:21 +090063 AddressManager::Guest::VM_TERMINA,
Garrick Evans51d5b552020-01-30 10:42:06 +090064 AddressManager::Guest::VM_PLUGIN_EXT,
Garrick Evansf7acc772019-10-21 15:26:15 +090065 }) {
Taoyu Li179dcc62019-10-17 11:21:08 +090066 runner_ = std::make_unique<MinijailedProcessRunner>();
67 datapath_ = std::make_unique<Datapath>(runner_.get());
68}
Long Chengd4415582019-09-24 19:16:09 +000069
Garrick Evans207e7482019-12-16 11:54:36 +090070Manager::~Manager() {
71 OnShutdown(nullptr);
72}
73
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090074std::map<const std::string, bool> Manager::cached_feature_enabled_ = {};
75
76bool Manager::ShouldEnableFeature(
77 int min_android_sdk_version,
78 int min_chrome_milestone,
79 const std::vector<std::string>& supported_boards,
80 const std::string& feature_name) {
81 static const char kLsbReleasePath[] = "/etc/lsb-release";
82
83 const auto& cached_result = cached_feature_enabled_.find(feature_name);
84 if (cached_result != cached_feature_enabled_.end())
85 return cached_result->second;
86
87 auto check = [min_android_sdk_version, min_chrome_milestone,
88 &supported_boards, &feature_name]() {
89 brillo::KeyValueStore store;
90 if (!store.Load(base::FilePath(kLsbReleasePath))) {
91 LOG(ERROR) << "Could not read lsb-release";
92 return false;
93 }
94
95 std::string value;
96 if (!store.GetString("CHROMEOS_ARC_ANDROID_SDK_VERSION", &value)) {
97 LOG(ERROR) << feature_name
98 << " disabled - cannot determine Android SDK version";
99 return false;
100 }
101 int ver = 0;
102 if (!base::StringToInt(value.c_str(), &ver)) {
103 LOG(ERROR) << feature_name << " disabled - invalid Android SDK version";
104 return false;
105 }
106 if (ver < min_android_sdk_version) {
107 LOG(INFO) << feature_name << " disabled for Android SDK " << value;
108 return false;
109 }
110
111 if (!store.GetString("CHROMEOS_RELEASE_CHROME_MILESTONE", &value)) {
112 LOG(ERROR) << feature_name
113 << " disabled - cannot determine ChromeOS milestone";
114 return false;
115 }
116 if (!base::StringToInt(value.c_str(), &ver)) {
117 LOG(ERROR) << feature_name << " disabled - invalid ChromeOS milestone";
118 return false;
119 }
120 if (ver < min_chrome_milestone) {
121 LOG(INFO) << feature_name << " disabled for ChromeOS milestone " << value;
122 return false;
123 }
124
125 if (!store.GetString("CHROMEOS_RELEASE_BOARD", &value)) {
126 LOG(ERROR) << feature_name << " disabled - cannot determine board";
127 return false;
128 }
129 if (!supported_boards.empty() &&
130 std::find(supported_boards.begin(), supported_boards.end(), value) ==
131 supported_boards.end()) {
132 LOG(INFO) << feature_name << " disabled for board " << value;
133 return false;
134 }
135 return true;
136 };
137
138 bool result = check();
139 cached_feature_enabled_.emplace(feature_name, result);
140 return result;
141}
142
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700143int Manager::OnInit() {
Garrick Evans54861622019-07-19 09:05:09 +0900144 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800145
146 // Handle subprocess lifecycle.
147 process_reaper_.Register(this);
Hugo Benichi935eca92018-07-03 13:47:24 +0900148
149 CHECK(process_reaper_.WatchForChild(
Garrick Evans96e03042019-05-28 14:30:52 +0900150 FROM_HERE, adb_proxy_->pid(),
151 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
152 adb_proxy_->pid())))
153 << "Failed to watch adb-proxy child process";
Taoyu Liaf944c92019-10-01 12:22:31 +0900154 CHECK(process_reaper_.WatchForChild(
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +0900155 FROM_HERE, mcast_proxy_->pid(),
156 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
157 nd_proxy_->pid())))
158 << "Failed to watch multicast-proxy child process";
159 CHECK(process_reaper_.WatchForChild(
Taoyu Liaf944c92019-10-01 12:22:31 +0900160 FROM_HERE, nd_proxy_->pid(),
161 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
162 nd_proxy_->pid())))
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +0900163 << "Failed to watch nd-proxy child process";
Garrick Evans96e03042019-05-28 14:30:52 +0900164
Garrick Evans49879532018-12-03 13:15:36 +0900165 // Run after Daemon::OnInit().
Eric Caruso9ce54182018-01-04 11:19:47 -0800166 base::MessageLoopForIO::current()->task_runner()->PostTask(
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700167 FROM_HERE,
168 base::Bind(&Manager::InitialSetup, weak_factory_.GetWeakPtr()));
169
170 return DBusDaemon::OnInit();
171}
172
173void Manager::InitialSetup() {
Garrick Evans08843932019-09-17 14:41:08 +0900174 LOG(INFO) << "Setting up DBus service interface";
175 dbus_svc_path_ = bus_->GetExportedObject(
176 dbus::ObjectPath(patchpanel::kPatchPanelServicePath));
177 if (!dbus_svc_path_) {
178 LOG(FATAL) << "Failed to export " << patchpanel::kPatchPanelServicePath
179 << " object";
180 }
181
182 using ServiceMethod =
183 std::unique_ptr<dbus::Response> (Manager::*)(dbus::MethodCall*);
184 const std::map<const char*, ServiceMethod> kServiceMethods = {
185 {patchpanel::kArcStartupMethod, &Manager::OnArcStartup},
186 {patchpanel::kArcShutdownMethod, &Manager::OnArcShutdown},
187 {patchpanel::kArcVmStartupMethod, &Manager::OnArcVmStartup},
188 {patchpanel::kArcVmShutdownMethod, &Manager::OnArcVmShutdown},
Garrick Evans47c19272019-11-21 10:58:21 +0900189 {patchpanel::kTerminaVmStartupMethod, &Manager::OnTerminaVmStartup},
190 {patchpanel::kTerminaVmShutdownMethod, &Manager::OnTerminaVmShutdown},
Garrick Evans51d5b552020-01-30 10:42:06 +0900191 {patchpanel::kPluginVmStartupMethod, &Manager::OnPluginVmStartup},
192 {patchpanel::kPluginVmShutdownMethod, &Manager::OnPluginVmShutdown},
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,
226 kNDProxyMinChromeMilestone,
227 std::vector<std::string>(), 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
Garrick Evans4ac09852020-01-16 14:09:22 +0900233 nd_proxy_->RegisterDeviceMessageHandler(base::Bind(
234 &Manager::OnDeviceMessageFromNDProxy, weak_factory_.GetWeakPtr()));
235
Garrick Evans69b85872020-02-04 11:40:26 +0900236 shill_client_ = std::make_unique<ShillClient>(bus_);
Garrick Evans428e4762018-12-11 15:18:42 +0900237 device_mgr_ = std::make_unique<DeviceManager>(
Garrick Evans69b85872020-02-04 11:40:26 +0900238 shill_client_.get(), &addr_mgr_, datapath_.get(),
Garrick Evans4ac09852020-01-16 14:09:22 +0900239 static_cast<TrafficForwarder*>(this));
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900240
Garrick Evans69b85872020-02-04 11:40:26 +0900241 arc_svc_ = std::make_unique<ArcService>(shill_client_.get(),
242 device_mgr_.get(), datapath_.get());
243 cros_svc_ = std::make_unique<CrostiniService>(
244 shill_client_.get(), device_mgr_.get(), datapath_.get());
Taoyu Liaf944c92019-10-01 12:22:31 +0900245
246 nd_proxy_->Listen();
Long Chengd4415582019-09-24 19:16:09 +0000247}
Garrick Evans49879532018-12-03 13:15:36 +0900248
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800249void Manager::OnShutdown(int* exit_code) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900250 if (!device_mgr_)
251 return;
252
253 LOG(INFO) << "Shutting down and cleaning up";
Garrick Evans207e7482019-12-16 11:54:36 +0900254 cros_svc_.reset();
255 arc_svc_.reset();
Garrick Evans428e4762018-12-11 15:18:42 +0900256 device_mgr_.reset();
Garrick Evans28d194e2019-12-17 10:22:28 +0900257
258 // Restore original local port range.
259 // TODO(garrick): The original history behind this tweak is gone. Some
260 // investigation is needed to see if it is still applicable.
Garrick Evans8e8e3472020-01-23 14:03:50 +0900261 if (datapath_->runner().sysctl_w("net.ipv4.ip_local_port_range",
262 "32768 61000") != 0) {
Garrick Evans28d194e2019-12-17 10:22:28 +0900263 LOG(ERROR) << "Failed to restore local port range";
264 }
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800265}
266
Garrick Evans4c042572019-12-17 13:42:25 +0900267void Manager::OnSubprocessExited(pid_t pid, const siginfo_t&) {
268 LOG(ERROR) << "Subprocess " << pid << " exited unexpectedly -"
269 << " attempting to restart";
270
271 HelperProcess* proc;
272 if (pid == adb_proxy_->pid()) {
273 proc = adb_proxy_.get();
274 } else if (pid == mcast_proxy_->pid()) {
275 proc = mcast_proxy_.get();
276 } else if (pid == nd_proxy_->pid()) {
277 proc = nd_proxy_.get();
278 } else {
279 LOG(DFATAL) << "Unknown child process";
280 return;
281 }
282
283 process_reaper_.ForgetChild(pid);
284
285 base::MessageLoopForIO::current()->task_runner()->PostDelayedTask(
286 FROM_HERE,
287 base::Bind(&Manager::RestartSubprocess, weak_factory_.GetWeakPtr(), proc),
288 base::TimeDelta::FromMilliseconds((2 << proc->restarts()) *
289 kSubprocessRestartDelayMs));
290}
291
292void Manager::RestartSubprocess(HelperProcess* subproc) {
293 if (subproc->Restart()) {
294 DCHECK(process_reaper_.WatchForChild(
295 FROM_HERE, subproc->pid(),
296 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
297 subproc->pid())))
298 << "Failed to watch child process " << subproc->pid();
299 }
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800300}
301
Garrick Evanse94a14e2019-11-11 10:32:13 +0900302bool Manager::StartArc(pid_t pid) {
Garrick Evans508a4bc2019-11-14 08:45:52 +0900303 if (!arc_svc_->Start(pid))
304 return false;
Garrick Evanse94a14e2019-11-11 10:32:13 +0900305
306 GuestMessage msg;
307 msg.set_event(GuestMessage::START);
308 msg.set_type(GuestMessage::ARC);
309 msg.set_arc_pid(pid);
310 SendGuestMessage(msg);
311
312 return true;
313}
314
Garrick Evans21173b12019-11-20 15:23:16 +0900315void Manager::StopArc(pid_t pid) {
Garrick Evanse94a14e2019-11-11 10:32:13 +0900316 GuestMessage msg;
317 msg.set_event(GuestMessage::STOP);
318 msg.set_type(GuestMessage::ARC);
319 SendGuestMessage(msg);
320
Garrick Evans21173b12019-11-20 15:23:16 +0900321 arc_svc_->Stop(pid);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900322}
323
Garrick Evans015b0d62020-02-07 09:06:38 +0900324bool Manager::StartArcVm(uint32_t cid) {
Garrick Evans508a4bc2019-11-14 08:45:52 +0900325 if (!arc_svc_->Start(cid))
326 return false;
Garrick Evanse94a14e2019-11-11 10:32:13 +0900327
328 GuestMessage msg;
329 msg.set_event(GuestMessage::START);
330 msg.set_type(GuestMessage::ARC_VM);
331 msg.set_arcvm_vsock_cid(cid);
332 SendGuestMessage(msg);
333
334 return true;
335}
336
Garrick Evans015b0d62020-02-07 09:06:38 +0900337void Manager::StopArcVm(uint32_t cid) {
Garrick Evanse94a14e2019-11-11 10:32:13 +0900338 GuestMessage msg;
339 msg.set_event(GuestMessage::STOP);
340 msg.set_type(GuestMessage::ARC_VM);
341 SendGuestMessage(msg);
342
Garrick Evans21173b12019-11-20 15:23:16 +0900343 arc_svc_->Stop(cid);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900344}
345
Garrick Evans51d5b552020-01-30 10:42:06 +0900346bool Manager::StartCrosVm(uint64_t vm_id,
347 GuestMessage::GuestType vm_type,
348 int subnet_index) {
349 DCHECK(vm_type == GuestMessage::TERMINA_VM ||
350 vm_type == GuestMessage::PLUGIN_VM);
351
352 if (!cros_svc_->Start(vm_id, vm_type == GuestMessage::TERMINA_VM,
353 subnet_index))
Garrick Evans47c19272019-11-21 10:58:21 +0900354 return false;
355
356 GuestMessage msg;
357 msg.set_event(GuestMessage::START);
Garrick Evans51d5b552020-01-30 10:42:06 +0900358 msg.set_type(vm_type);
Garrick Evans47c19272019-11-21 10:58:21 +0900359 SendGuestMessage(msg);
360
361 return true;
362}
363
Garrick Evans51d5b552020-01-30 10:42:06 +0900364void Manager::StopCrosVm(uint64_t vm_id, GuestMessage::GuestType vm_type) {
Garrick Evans47c19272019-11-21 10:58:21 +0900365 GuestMessage msg;
366 msg.set_event(GuestMessage::STOP);
Garrick Evans51d5b552020-01-30 10:42:06 +0900367 msg.set_type(vm_type);
Garrick Evans47c19272019-11-21 10:58:21 +0900368 SendGuestMessage(msg);
369
Garrick Evans51d5b552020-01-30 10:42:06 +0900370 cros_svc_->Stop(vm_id, vm_type == GuestMessage::TERMINA_VM);
Garrick Evans47c19272019-11-21 10:58:21 +0900371}
372
Garrick Evans08843932019-09-17 14:41:08 +0900373std::unique_ptr<dbus::Response> Manager::OnArcStartup(
374 dbus::MethodCall* method_call) {
375 LOG(INFO) << "ARC++ starting up";
376
377 std::unique_ptr<dbus::Response> dbus_response(
378 dbus::Response::FromMethodCall(method_call));
379
380 dbus::MessageReader reader(method_call);
381 dbus::MessageWriter writer(dbus_response.get());
382
383 patchpanel::ArcStartupRequest request;
384 patchpanel::ArcStartupResponse response;
385
386 if (!reader.PopArrayOfBytesAsProto(&request)) {
387 LOG(ERROR) << "Unable to parse request";
388 writer.AppendProtoAsArrayOfBytes(response);
389 return dbus_response;
390 }
391
Garrick Evanse01bf072019-11-15 09:08:19 +0900392 if (!StartArc(request.pid()))
393 LOG(ERROR) << "Failed to start ARC++ network service";
Garrick Evanse94a14e2019-11-11 10:32:13 +0900394
Garrick Evans08843932019-09-17 14:41:08 +0900395 writer.AppendProtoAsArrayOfBytes(response);
396 return dbus_response;
397}
398
399std::unique_ptr<dbus::Response> Manager::OnArcShutdown(
400 dbus::MethodCall* method_call) {
401 LOG(INFO) << "ARC++ shutting down";
402
403 std::unique_ptr<dbus::Response> dbus_response(
404 dbus::Response::FromMethodCall(method_call));
405
406 dbus::MessageReader reader(method_call);
407 dbus::MessageWriter writer(dbus_response.get());
408
409 patchpanel::ArcShutdownRequest request;
410 patchpanel::ArcShutdownResponse response;
411
412 if (!reader.PopArrayOfBytesAsProto(&request)) {
413 LOG(ERROR) << "Unable to parse request";
414 writer.AppendProtoAsArrayOfBytes(response);
415 return dbus_response;
416 }
417
Garrick Evans21173b12019-11-20 15:23:16 +0900418 StopArc(request.pid());
Garrick Evanse94a14e2019-11-11 10:32:13 +0900419
Garrick Evans08843932019-09-17 14:41:08 +0900420 writer.AppendProtoAsArrayOfBytes(response);
421 return dbus_response;
422}
423
424std::unique_ptr<dbus::Response> Manager::OnArcVmStartup(
425 dbus::MethodCall* method_call) {
426 LOG(INFO) << "ARCVM starting up";
427
428 std::unique_ptr<dbus::Response> dbus_response(
429 dbus::Response::FromMethodCall(method_call));
430
431 dbus::MessageReader reader(method_call);
432 dbus::MessageWriter writer(dbus_response.get());
433
434 patchpanel::ArcVmStartupRequest request;
435 patchpanel::ArcVmStartupResponse response;
436
437 if (!reader.PopArrayOfBytesAsProto(&request)) {
438 LOG(ERROR) << "Unable to parse request";
439 writer.AppendProtoAsArrayOfBytes(response);
440 return dbus_response;
441 }
442
Garrick Evans47c19272019-11-21 10:58:21 +0900443 if (!StartArcVm(request.cid())) {
Garrick Evanse01bf072019-11-15 09:08:19 +0900444 LOG(ERROR) << "Failed to start ARCVM network service";
Garrick Evans47c19272019-11-21 10:58:21 +0900445 writer.AppendProtoAsArrayOfBytes(response);
446 return dbus_response;
Garrick Evanse01bf072019-11-15 09:08:19 +0900447 }
Garrick Evanse94a14e2019-11-11 10:32:13 +0900448
Garrick Evans47c19272019-11-21 10:58:21 +0900449 // Populate the response with the known devices.
450 auto build_resp = [](patchpanel::ArcVmStartupResponse* resp, Device* device) {
451 auto* ctx = dynamic_cast<ArcService::Context*>(device->context());
452 if (!ctx || ctx->TAP().empty())
453 return;
454
455 const auto& config = device->config();
456 auto* dev = resp->add_devices();
457 dev->set_ifname(ctx->TAP());
458 dev->set_ipv4_addr(config.guest_ipv4_addr());
459 };
460
461 device_mgr_->ProcessDevices(
462 base::Bind(build_resp, base::Unretained(&response)));
463
Garrick Evans08843932019-09-17 14:41:08 +0900464 writer.AppendProtoAsArrayOfBytes(response);
465 return dbus_response;
466}
467
468std::unique_ptr<dbus::Response> Manager::OnArcVmShutdown(
469 dbus::MethodCall* method_call) {
470 LOG(INFO) << "ARCVM shutting down";
471
472 std::unique_ptr<dbus::Response> dbus_response(
473 dbus::Response::FromMethodCall(method_call));
474
475 dbus::MessageReader reader(method_call);
476 dbus::MessageWriter writer(dbus_response.get());
477
478 patchpanel::ArcVmShutdownRequest request;
479 patchpanel::ArcVmShutdownResponse response;
480
481 if (!reader.PopArrayOfBytesAsProto(&request)) {
482 LOG(ERROR) << "Unable to parse request";
483 writer.AppendProtoAsArrayOfBytes(response);
484 return dbus_response;
485 }
486
Garrick Evans21173b12019-11-20 15:23:16 +0900487 StopArcVm(request.cid());
Garrick Evanse94a14e2019-11-11 10:32:13 +0900488
Garrick Evans08843932019-09-17 14:41:08 +0900489 writer.AppendProtoAsArrayOfBytes(response);
490 return dbus_response;
491}
492
Garrick Evans47c19272019-11-21 10:58:21 +0900493std::unique_ptr<dbus::Response> Manager::OnTerminaVmStartup(
494 dbus::MethodCall* method_call) {
495 LOG(INFO) << "Termina VM starting up";
496
497 std::unique_ptr<dbus::Response> dbus_response(
498 dbus::Response::FromMethodCall(method_call));
499
500 dbus::MessageReader reader(method_call);
501 dbus::MessageWriter writer(dbus_response.get());
502
503 patchpanel::TerminaVmStartupRequest request;
504 patchpanel::TerminaVmStartupResponse response;
505
506 if (!reader.PopArrayOfBytesAsProto(&request)) {
507 LOG(ERROR) << "Unable to parse request";
508 writer.AppendProtoAsArrayOfBytes(response);
509 return dbus_response;
510 }
511
512 const int32_t cid = request.cid();
Garrick Evans51d5b552020-01-30 10:42:06 +0900513 if (!StartCrosVm(cid, GuestMessage::TERMINA_VM, kAnySubnetIndex)) {
Garrick Evans47c19272019-11-21 10:58:21 +0900514 LOG(ERROR) << "Failed to start Termina VM network service";
515 writer.AppendProtoAsArrayOfBytes(response);
516 return dbus_response;
517 }
518
Garrick Evans51d5b552020-01-30 10:42:06 +0900519 const auto* const tap = cros_svc_->TAP(cid, true /*is_termina*/);
Garrick Evansb1c93712020-01-22 09:28:25 +0900520 if (!tap) {
521 LOG(DFATAL) << "TAP device missing";
522 writer.AppendProtoAsArrayOfBytes(response);
523 return dbus_response;
524 }
Garrick Evans47c19272019-11-21 10:58:21 +0900525
Garrick Evansb1c93712020-01-22 09:28:25 +0900526 const auto& config = tap->config();
527 auto* dev = response.mutable_device();
528 dev->set_ifname(config.host_ifname());
529 const auto* subnet = config.ipv4_subnet();
530 if (!subnet) {
531 LOG(DFATAL) << "Missing required subnet for {cid: " << cid << "}";
532 writer.AppendProtoAsArrayOfBytes(response);
533 return dbus_response;
534 }
535 auto* resp_subnet = dev->mutable_ipv4_subnet();
536 resp_subnet->set_base_addr(subnet->BaseAddress());
537 resp_subnet->set_prefix_len(subnet->PrefixLength());
538 subnet = config.lxd_ipv4_subnet();
539 if (!subnet) {
540 LOG(DFATAL) << "Missing required lxd subnet for {cid: " << cid << "}";
541 writer.AppendProtoAsArrayOfBytes(response);
542 return dbus_response;
543 }
544 resp_subnet = response.mutable_container_subnet();
545 resp_subnet->set_base_addr(subnet->BaseAddress());
546 resp_subnet->set_prefix_len(subnet->PrefixLength());
Garrick Evans47c19272019-11-21 10:58:21 +0900547
548 writer.AppendProtoAsArrayOfBytes(response);
549 return dbus_response;
550}
551
552std::unique_ptr<dbus::Response> Manager::OnTerminaVmShutdown(
553 dbus::MethodCall* method_call) {
554 LOG(INFO) << "Termina VM shutting down";
555
556 std::unique_ptr<dbus::Response> dbus_response(
557 dbus::Response::FromMethodCall(method_call));
558
559 dbus::MessageReader reader(method_call);
560 dbus::MessageWriter writer(dbus_response.get());
561
562 patchpanel::TerminaVmShutdownRequest request;
563 patchpanel::TerminaVmShutdownResponse response;
564
565 if (!reader.PopArrayOfBytesAsProto(&request)) {
566 LOG(ERROR) << "Unable to parse request";
567 writer.AppendProtoAsArrayOfBytes(response);
568 return dbus_response;
569 }
570
Garrick Evans51d5b552020-01-30 10:42:06 +0900571 StopCrosVm(request.cid(), GuestMessage::TERMINA_VM);
572
573 writer.AppendProtoAsArrayOfBytes(response);
574 return dbus_response;
575}
576
577std::unique_ptr<dbus::Response> Manager::OnPluginVmStartup(
578 dbus::MethodCall* method_call) {
579 LOG(INFO) << "Plugin VM starting up";
580
581 std::unique_ptr<dbus::Response> dbus_response(
582 dbus::Response::FromMethodCall(method_call));
583
584 dbus::MessageReader reader(method_call);
585 dbus::MessageWriter writer(dbus_response.get());
586
587 patchpanel::PluginVmStartupRequest request;
588 patchpanel::PluginVmStartupResponse response;
589
590 if (!reader.PopArrayOfBytesAsProto(&request)) {
591 LOG(ERROR) << "Unable to parse request";
592 writer.AppendProtoAsArrayOfBytes(response);
593 return dbus_response;
594 }
595
596 const int32_t vm_id = request.id();
597 // This field is 1-based so 0 (the proto default value) indicates that any
598 // subnet is acceptable, but the address manager is 0-based so we need to
599 // subtract 1 from the index here.
600 const int subnet_index = request.subnet_index() - 1;
601 if (!StartCrosVm(vm_id, GuestMessage::PLUGIN_VM, subnet_index)) {
602 LOG(ERROR) << "Failed to start Plugin VM network service";
603 writer.AppendProtoAsArrayOfBytes(response);
604 return dbus_response;
605 }
606
607 const auto* const tap = cros_svc_->TAP(vm_id, false /*is_termina*/);
608 if (!tap) {
609 LOG(DFATAL) << "TAP device missing";
610 writer.AppendProtoAsArrayOfBytes(response);
611 return dbus_response;
612 }
613
614 const auto& config = tap->config();
615 auto* dev = response.mutable_device();
616 dev->set_ifname(config.host_ifname());
617 const auto* subnet = config.ipv4_subnet();
618 if (!subnet) {
619 LOG(DFATAL) << "Missing required subnet for {cid: " << vm_id << "}";
620 writer.AppendProtoAsArrayOfBytes(response);
621 return dbus_response;
622 }
623 auto* resp_subnet = dev->mutable_ipv4_subnet();
624 resp_subnet->set_base_addr(subnet->BaseAddress());
625 resp_subnet->set_prefix_len(subnet->PrefixLength());
626
627 writer.AppendProtoAsArrayOfBytes(response);
628 return dbus_response;
629}
630
631std::unique_ptr<dbus::Response> Manager::OnPluginVmShutdown(
632 dbus::MethodCall* method_call) {
633 LOG(INFO) << "Plugin VM shutting down";
634
635 std::unique_ptr<dbus::Response> dbus_response(
636 dbus::Response::FromMethodCall(method_call));
637
638 dbus::MessageReader reader(method_call);
639 dbus::MessageWriter writer(dbus_response.get());
640
641 patchpanel::PluginVmShutdownRequest request;
642 patchpanel::PluginVmShutdownResponse response;
643
644 if (!reader.PopArrayOfBytesAsProto(&request)) {
645 LOG(ERROR) << "Unable to parse request";
646 writer.AppendProtoAsArrayOfBytes(response);
647 return dbus_response;
648 }
649
650 StopCrosVm(request.id(), GuestMessage::PLUGIN_VM);
Garrick Evans47c19272019-11-21 10:58:21 +0900651
652 writer.AppendProtoAsArrayOfBytes(response);
653 return dbus_response;
654}
655
Garrick Evanse94a14e2019-11-11 10:32:13 +0900656void Manager::SendGuestMessage(const GuestMessage& msg) {
Garrick Evans96e03042019-05-28 14:30:52 +0900657 IpHelperMessage ipm;
658 *ipm.mutable_guest_message() = msg;
Garrick Evans96e03042019-05-28 14:30:52 +0900659 adb_proxy_->SendMessage(ipm);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900660 mcast_proxy_->SendMessage(ipm);
661 nd_proxy_->SendMessage(ipm);
Garrick Evans96e03042019-05-28 14:30:52 +0900662}
663
Garrick Evans4ac09852020-01-16 14:09:22 +0900664void Manager::StartForwarding(const std::string& ifname_physical,
665 const std::string& ifname_virtual,
666 uint32_t ipv4_addr_virtual,
667 bool ipv6,
668 bool multicast) {
669 if (ifname_physical.empty())
670 return;
671
672 IpHelperMessage ipm;
673 DeviceMessage* msg = ipm.mutable_device_message();
674 msg->set_dev_ifname(ifname_physical);
675 msg->set_guest_ip4addr(ipv4_addr_virtual);
676 msg->set_br_ifname(ifname_virtual);
677
678 if (ipv6) {
679 LOG(INFO) << "Starting IPv6 forwarding from " << ifname_physical << " to "
680 << ifname_virtual;
681
682 if (!datapath_->AddIPv6Forwarding(ifname_physical, ifname_virtual)) {
683 LOG(ERROR) << "Failed to setup iptables forwarding rule for IPv6 from "
684 << ifname_physical << " to " << ifname_virtual;
685 }
686 if (!datapath_->MaskInterfaceFlags(ifname_physical, IFF_ALLMULTI)) {
687 LOG(WARNING) << "Failed to setup all multicast mode for interface "
688 << ifname_physical;
689 }
690 if (!datapath_->MaskInterfaceFlags(ifname_virtual, IFF_ALLMULTI)) {
691 LOG(WARNING) << "Failed to setup all multicast mode for interface "
692 << ifname_virtual;
693 }
694 nd_proxy_->SendMessage(ipm);
695 }
696
697 if (multicast) {
698 LOG(INFO) << "Starting multicast forwarding from " << ifname_physical
699 << " to " << ifname_virtual;
700 mcast_proxy_->SendMessage(ipm);
701 }
702}
703
704void Manager::StopForwarding(const std::string& ifname_physical,
705 const std::string& ifname_virtual,
706 bool ipv6,
707 bool multicast) {
708 if (ifname_physical.empty())
709 return;
710
711 IpHelperMessage ipm;
712 DeviceMessage* msg = ipm.mutable_device_message();
713 msg->set_dev_ifname(ifname_physical);
714 msg->set_teardown(true);
715
716 if (ipv6) {
717 LOG(INFO) << "Stopping IPv6 forwarding from " << ifname_physical << " to "
718 << ifname_virtual;
719
720 datapath_->RemoveIPv6Forwarding(ifname_physical, ifname_virtual);
721 nd_proxy_->SendMessage(ipm);
722 }
723
724 if (multicast) {
725 LOG(INFO) << "Stopping multicast forwarding from " << ifname_physical
726 << " to " << ifname_virtual;
727 mcast_proxy_->SendMessage(ipm);
728 }
729}
730
731bool Manager::ForwardsLegacyIPv6() const {
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +0900732 return !ShouldEnableFeature(kNDProxyMinAndroidSdkVersion,
733 kNDProxyMinChromeMilestone,
734 std::vector<std::string>(), kNDProxyFeatureName);
Garrick Evans4ac09852020-01-16 14:09:22 +0900735}
736
737void Manager::OnDeviceMessageFromNDProxy(const DeviceMessage& msg) {
738 LOG_IF(DFATAL, msg.dev_ifname().empty())
739 << "Received DeviceMessage w/ empty dev_ifname";
740
741 if (!datapath_->AddIPv6HostRoute(msg.dev_ifname(), msg.guest_ip6addr(),
742 128)) {
743 LOG(WARNING) << "Failed to setup the IPv6 route for interface "
744 << msg.dev_ifname();
745 }
746}
747
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700748} // namespace arc_networkd