blob: 4a524571d96b19ede106ebbe8fb680af3b862c41 [file] [log] [blame]
Garrick Evans5d55f5e2019-07-17 15:28:10 +09001// Copyright 2019 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
5#include "arc/network/arc_service.h"
6
Garrick Evans54861622019-07-19 09:05:09 +09007#include <linux/rtnetlink.h>
8#include <net/if.h>
9
Garrick Evans5d55f5e2019-07-17 15:28:10 +090010#include <utility>
11
Garrick Evans54861622019-07-19 09:05:09 +090012#include <base/bind.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090013#include <base/files/file_path.h>
14#include <base/files/file_util.h>
15#include <base/logging.h>
16#include <base/strings/string_number_conversions.h>
17#include <base/strings/string_util.h>
Garrick Evans54861622019-07-19 09:05:09 +090018#include <base/strings/stringprintf.h>
Garrick Evans1f5a3612019-11-08 12:59:03 +090019#include <brillo/key_value_store.h>
Garrick Evansb4eb3892019-11-13 12:07:07 +090020#include <chromeos/constants/vm_tools.h>
Garrick Evans54861622019-07-19 09:05:09 +090021#include <shill/net/rtnl_message.h>
22
23#include "arc/network/datapath.h"
Garrick Evans54861622019-07-19 09:05:09 +090024#include "arc/network/mac_address_generator.h"
Garrick Evans3915af32019-07-25 15:44:34 +090025#include "arc/network/minijailed_process_runner.h"
Garrick Evans54861622019-07-19 09:05:09 +090026#include "arc/network/net_util.h"
27#include "arc/network/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090028
29namespace arc_networkd {
Garrick Evansf29f5a32019-12-06 11:34:25 +090030
31namespace test {
32GuestMessage::GuestType guest = GuestMessage::UNKNOWN_GUEST;
33} // namespace test
34
Garrick Evans5d55f5e2019-07-17 15:28:10 +090035namespace {
Garrick Evans54861622019-07-19 09:05:09 +090036constexpr pid_t kInvalidPID = -1;
Garrick Evansb4eb3892019-11-13 12:07:07 +090037constexpr pid_t kTestPID = -2;
38constexpr int32_t kInvalidCID = -1;
Garrick Evans260ff302019-07-25 11:22:50 +090039constexpr int kInvalidTableID = -1;
40constexpr int kMaxTableRetries = 10; // Based on 1 second delay.
41constexpr base::TimeDelta kTableRetryDelay = base::TimeDelta::FromSeconds(1);
42// Android adds a constant to the interface index to derive the table id.
43// This is defined in system/netd/server/RouteController.h
44constexpr int kRouteControllerRouteTableOffsetFromIndex = 1000;
Garrick Evans54861622019-07-19 09:05:09 +090045
46// This wrapper is required since the base class is a singleton that hides its
47// constructor. It is necessary here because the message loop thread has to be
48// reassociated to the container's network namespace; and since the container
49// can be repeatedly created and destroyed, the handler must be as well.
50class RTNetlinkHandler : public shill::RTNLHandler {
51 public:
52 RTNetlinkHandler() = default;
53 ~RTNetlinkHandler() = default;
54
55 private:
56 DISALLOW_COPY_AND_ASSIGN(RTNetlinkHandler);
57};
Garrick Evans5d55f5e2019-07-17 15:28:10 +090058
Garrick Evans260ff302019-07-25 11:22:50 +090059int GetAndroidRoutingTableId(const std::string& ifname, pid_t pid) {
60 base::FilePath ifindex_path(base::StringPrintf(
61 "/proc/%d/root/sys/class/net/%s/ifindex", pid, ifname.c_str()));
62 std::string contents;
63 if (!base::ReadFileToString(ifindex_path, &contents)) {
64 PLOG(WARNING) << "Could not read " << ifindex_path.value();
65 return kInvalidTableID;
66 }
67
68 base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
69 int table_id = kInvalidTableID;
70 if (!base::StringToInt(contents, &table_id)) {
71 LOG(ERROR) << "Could not parse ifindex from " << ifindex_path.value()
72 << ": " << contents;
73 return kInvalidTableID;
74 }
75 table_id += kRouteControllerRouteTableOffsetFromIndex;
76
77 LOG(INFO) << "Found table id " << table_id << " for container interface "
78 << ifname;
79 return table_id;
80}
81
Garrick Evans1f5a3612019-11-08 12:59:03 +090082bool ShouldEnableMultinet() {
83 static const char kLsbReleasePath[] = "/etc/lsb-release";
84 static int kMinAndroidSdkVersion = 28; // P
Garrick Evans1f5a3612019-11-08 12:59:03 +090085
86 brillo::KeyValueStore store;
87 if (!store.Load(base::FilePath(kLsbReleasePath))) {
88 LOG(ERROR) << "Could not read lsb-release";
89 return false;
90 }
91
92 std::string value;
93 if (!store.GetString("CHROMEOS_ARC_ANDROID_SDK_VERSION", &value)) {
94 LOG(ERROR) << "ARC multi-networking disabled - cannot determine Android "
95 "SDK version";
96 return false;
97 }
98 int ver = 0;
99 if (!base::StringToInt(value.c_str(), &ver)) {
100 LOG(ERROR) << "ARC multi-networking disabled - invalid Android SDK version";
101 return false;
102 }
103 if (ver < kMinAndroidSdkVersion) {
104 LOG(INFO) << "ARC multi-networking disabled for Android SDK " << value;
105 return false;
106 }
Garrick Evans1f5a3612019-11-08 12:59:03 +0900107 return true;
108}
109
Garrick Evans6d227b92019-12-03 16:11:29 +0900110void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +0900111 static bool done = false;
112 if (done)
113 return;
114
Garrick Evans6d227b92019-12-03 16:11:29 +0900115 auto& runner = datapath.runner();
116
117 // Load networking modules needed by Android that are not compiled in the
118 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansa34b5862019-11-20 09:34:01 +0900119 // These must succeed.
Garrick Evans8e8e3472020-01-23 14:03:50 +0900120 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +0900121 // The netfilter modules needed by netd for iptables commands.
122 "ip6table_filter",
123 "ip6t_ipv6header",
124 "ip6t_REJECT",
125 // The xfrm modules needed for Android's ipsec APIs.
126 "xfrm4_mode_transport",
127 "xfrm4_mode_tunnel",
128 "xfrm6_mode_transport",
129 "xfrm6_mode_tunnel",
130 // The ipsec modules for AH and ESP encryption for ipv6.
131 "ah6",
132 "esp6",
133 }) != 0) {
134 LOG(ERROR) << "One or more required kernel modules failed to load."
135 << " Some Android functionality may be broken.";
136 }
137 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +0900138 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +0900139 // This module is not available in kernels < 3.18
140 "nf_reject_ipv6",
141 // These modules are needed for supporting Chrome traffic on Android
142 // VPN which uses Android's NAT feature. Android NAT sets up
143 // iptables
144 // rules that use these conntrack modules for FTP/TFTP.
145 "nf_nat_ftp",
146 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +0900147 // The tun module is needed by the Android 464xlat clatd process.
148 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +0900149 }) != 0) {
150 LOG(WARNING) << "One or more optional kernel modules failed to load.";
151 }
152
Garrick Evans6d227b92019-12-03 16:11:29 +0900153 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +0900154 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900155 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
156 }
157
Garrick Evansa34b5862019-11-20 09:34:01 +0900158 done = true;
159}
160
Garrick Evans508a4bc2019-11-14 08:45:52 +0900161bool IsArcVm() {
162 const base::FilePath path("/run/chrome/is_arcvm");
163 std::string contents;
164 if (!base::ReadFileToString(path, &contents)) {
165 PLOG(ERROR) << "Could not read " << path.value();
166 }
167 return contents == "1";
168}
169
Garrick Evansf29f5a32019-12-06 11:34:25 +0900170GuestMessage::GuestType ArcGuest() {
171 if (test::guest != GuestMessage::UNKNOWN_GUEST)
172 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900173
174 return IsArcVm() ? GuestMessage::ARC_VM
175 : ShouldEnableMultinet() ? GuestMessage::ARC
176 : GuestMessage::ARC_LEGACY;
177}
178
Garrick Evansbc91a352020-01-16 16:43:26 +0900179constexpr const char kArcDevicePrefix[] = "arc";
180bool IsArcDevice(const std::string& ifname) {
181 return base::StartsWith(ifname, kArcDevicePrefix,
182 base::CompareCase::INSENSITIVE_ASCII);
183}
184
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900185} // namespace
186
Garrick Evansf29f5a32019-12-06 11:34:25 +0900187ArcService::ArcService(DeviceManagerBase* dev_mgr, Datapath* datapath)
188 : dev_mgr_(dev_mgr), datapath_(datapath) {
189 DCHECK(dev_mgr_);
Taoyu Li179dcc62019-10-17 11:21:08 +0900190 DCHECK(datapath_);
Garrick Evans3915af32019-07-25 15:44:34 +0900191
Garrick Evansf29f5a32019-12-06 11:34:25 +0900192 dev_mgr_->RegisterDeviceAddedHandler(
193 GuestMessage::ARC,
194 base::Bind(&ArcService::OnDeviceAdded, base::Unretained(this)));
195 dev_mgr_->RegisterDeviceRemovedHandler(
196 GuestMessage::ARC,
197 base::Bind(&ArcService::OnDeviceRemoved, base::Unretained(this)));
198 dev_mgr_->RegisterDefaultInterfaceChangedHandler(
199 GuestMessage::ARC, base::Bind(&ArcService::OnDefaultInterfaceChanged,
200 base::Unretained(this)));
201}
202
203ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900204 if (impl_) {
205 // Stop the service.
206 Stop(impl_->id());
207 // Delete all the bridges and veth pairs.
208 dev_mgr_->ProcessDevices(
209 base::Bind(&ArcService::OnDeviceRemoved, weak_factory_.GetWeakPtr()));
210 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900211 dev_mgr_->UnregisterAllGuestHandlers(GuestMessage::ARC);
Garrick Evans54861622019-07-19 09:05:09 +0900212}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900213
Garrick Evans508a4bc2019-11-14 08:45:52 +0900214bool ArcService::Start(int32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900215 if (impl_) {
216 int32_t prev_id;
217 if (impl_->IsStarted(&prev_id)) {
218 LOG(WARNING) << "Already running - did something crash?"
219 << " Stopping and restarting...";
220 Stop(prev_id);
221 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900222 }
223
Garrick Evansf29f5a32019-12-06 11:34:25 +0900224 const auto guest = ArcGuest();
225 if (guest == GuestMessage::ARC_VM)
226 impl_ = std::make_unique<VmImpl>(dev_mgr_, datapath_);
227 else
228 impl_ = std::make_unique<ContainerImpl>(dev_mgr_, datapath_, guest);
229
230 if (!impl_->Start(id)) {
231 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900232 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900233 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900234
235 // Start known host devices, any new ones will be setup in the process.
236 dev_mgr_->ProcessDevices(
237 base::Bind(&ArcService::StartDevice, weak_factory_.GetWeakPtr()));
238
239 // If this is the first time the service is starting this will create the
240 // Android bridge device; otherwise it does nothing (this is a workaround for
241 // the bug in Shill that casues a Bus crash when it sees the ARC bridge a
242 // second time). Do this after processing the existing devices so it doesn't
243 // get started twice.
Garrick Evanscfd42822019-11-15 12:38:23 +0900244 std::string arc;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900245 switch (guest) {
Garrick Evanscfd42822019-11-15 12:38:23 +0900246 case GuestMessage::ARC:
247 arc = kAndroidDevice;
248 break;
249 case GuestMessage::ARC_LEGACY:
250 arc = kAndroidLegacyDevice;
251 break;
252 case GuestMessage::ARC_VM:
253 arc = kAndroidVmDevice;
254 break;
255 default:
256 LOG(DFATAL) << "Unexpected guest: " << guest;
Garrick Evans21173b12019-11-20 15:23:16 +0900257 return false;
Garrick Evanscfd42822019-11-15 12:38:23 +0900258 }
259 dev_mgr_->Add(arc);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900260 dev_mgr_->OnGuestStart(guest);
261 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900262}
263
Garrick Evans21173b12019-11-20 15:23:16 +0900264void ArcService::Stop(int32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900265 if (!impl_)
266 return;
267
268 dev_mgr_->OnGuestStop(impl_->guest());
Garrick Evans54861622019-07-19 09:05:09 +0900269
270 // Stop known host devices. Note that this does not teardown any existing
271 // devices.
272 dev_mgr_->ProcessDevices(
273 base::Bind(&ArcService::StopDevice, weak_factory_.GetWeakPtr()));
Garrick Evans21173b12019-11-20 15:23:16 +0900274
275 impl_->Stop(id);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900276 impl_.reset();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900277}
278
Garrick Evans8ff08452019-11-25 09:24:26 +0900279bool ArcService::AllowDevice(Device* device) const {
Garrick Evansa1134d72019-12-02 14:25:37 +0900280 if (!device->IsArc())
Garrick Evans0001d012019-11-22 10:06:10 +0900281 return false;
282
Garrick Evans8ff08452019-11-25 09:24:26 +0900283 // ARC P+ is multi-network enabled and should process all devices.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900284 if ((impl_ && impl_->guest() == GuestMessage::ARC) ||
285 (!impl_ && ArcGuest() == GuestMessage::ARC))
Garrick Evans8ff08452019-11-25 09:24:26 +0900286 return true;
287
288 // ARC N and ARCVM (for now) are both single-network - meaning they only use
289 // the "default" device which uses the default interface from shill.
290 return device->UsesDefaultInterface();
291}
292
Garrick Evans54861622019-07-19 09:05:09 +0900293void ArcService::OnDeviceAdded(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900294 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900295 return;
Garrick Evansba575742019-07-17 15:48:08 +0900296
Garrick Evans54861622019-07-19 09:05:09 +0900297 const auto& config = device->config();
298
299 LOG(INFO) << "Adding device " << device->ifname()
300 << " bridge: " << config.host_ifname()
Garrick Evans310ab552019-10-08 11:07:53 +0900301 << " guest_iface: " << config.guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900302
303 // Create the bridge.
304 if (!datapath_->AddBridge(config.host_ifname(),
305 IPv4AddressToString(config.host_ipv4_addr()))) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900306 // Per crbug/1008686 this device cannot be deleted and then re-added.
307 // It could be that arc-networkd was restarted after a crash and this device
308 // is being re-added.
309 if (!device->IsAndroid()) {
310 LOG(ERROR) << "Failed to setup arc bridge: " << config.host_ifname();
311 return;
312 }
313 if (!datapath_->MaskInterfaceFlags(config.host_ifname(), IFF_UP)) {
314 LOG(ERROR) << "Failed to bring up arc bridge: " << config.host_ifname();
315 return;
316 }
Garrick Evans54861622019-07-19 09:05:09 +0900317 }
318
319 // Setup the iptables.
Garrick Evans8ff08452019-11-25 09:24:26 +0900320 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900321 if (!datapath_->AddLegacyIPv4DNAT(
322 IPv4AddressToString(config.guest_ipv4_addr())))
323 LOG(ERROR) << "Failed to configure ARC traffic rules";
324
325 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
326 LOG(ERROR) << "Failed to configure egress traffic rules";
327 } else if (!device->IsAndroid()) {
328 if (!datapath_->AddInboundIPv4DNAT(
329 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
330 LOG(ERROR) << "Failed to configure ingress traffic rules for "
331 << device->ifname();
332
333 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
334 LOG(ERROR) << "Failed to configure egress traffic rules";
335 }
336
Garrick Evansa1134d72019-12-02 14:25:37 +0900337 device->set_context(std::make_unique<Context>());
Garrick Evans54861622019-07-19 09:05:09 +0900338
339 StartDevice(device);
340}
341
342void ArcService::StartDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900343 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900344 return;
345
Garrick Evans310ab552019-10-08 11:07:53 +0900346 // This can happen if OnDeviceAdded is invoked when the container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900347 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900348 return;
349
Garrick Evans2c263102019-07-26 16:07:18 +0900350 // If there is no context, then this is a new device and it needs to run
351 // through the full setup process.
Garrick Evansa1134d72019-12-02 14:25:37 +0900352 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900353 if (!ctx)
Garrick Evans54861622019-07-19 09:05:09 +0900354 return OnDeviceAdded(device);
355
Garrick Evans2c263102019-07-26 16:07:18 +0900356 if (ctx->IsStarted()) {
357 LOG(ERROR) << "Attempt to restart device " << device->ifname();
358 return;
359 }
360
Garrick Evansd90a3822019-11-12 17:53:08 +0900361 if (!impl_->OnStartDevice(device)) {
Garrick Evanscb791e72019-11-11 15:44:34 +0900362 LOG(ERROR) << "Failed to start device " << device->ifname();
363 return;
364 }
365
Garrick Evansb4eb3892019-11-13 12:07:07 +0900366 ctx->Start();
Garrick Evans54861622019-07-19 09:05:09 +0900367}
368
369void ArcService::OnDeviceRemoved(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900370 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900371 return;
372
Garrick Evans310ab552019-10-08 11:07:53 +0900373 // If the container is down, this call does nothing.
Garrick Evans54861622019-07-19 09:05:09 +0900374 StopDevice(device);
375
376 const auto& config = device->config();
377
378 LOG(INFO) << "Removing device " << device->ifname()
379 << " bridge: " << config.host_ifname()
380 << " guest_iface: " << config.guest_ifname();
381
Taoyu Lif7e8b572019-12-13 15:22:09 +0900382 device->StopIPv6RoutingLegacy();
Garrick Evans8ff08452019-11-25 09:24:26 +0900383 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900384 datapath_->RemoveOutboundIPv4(config.host_ifname());
385 datapath_->RemoveLegacyIPv4DNAT();
386 } else if (!device->IsAndroid()) {
387 datapath_->RemoveOutboundIPv4(config.host_ifname());
388 datapath_->RemoveInboundIPv4DNAT(
389 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
390 }
391
Garrick Evans664a82f2019-12-17 12:18:05 +0900392 // Per crbug/1008686 this device cannot be deleted and then re-added.
393 // So instead of removing the bridge, bring it down and mark it. This will
394 // allow us to detect if the device is re-added in case of a crash restart and
395 // do the right thing.
396 if (device->IsAndroid()) {
397 // This can be safely deleted now.
398 datapath_->RemoveInterface(ArcVethHostName("arc0"));
399 if (!datapath_->MaskInterfaceFlags(config.host_ifname(), IFF_DEBUG, IFF_UP))
400 LOG(ERROR) << "Failed to bring down arc bridge "
401 << "- it may not restart correctly";
402 } else {
403 datapath_->RemoveBridge(config.host_ifname());
404 }
Garrick Evans54861622019-07-19 09:05:09 +0900405
Garrick Evansa1134d72019-12-02 14:25:37 +0900406 device->set_context(nullptr);
Garrick Evans54861622019-07-19 09:05:09 +0900407}
408
409void ArcService::StopDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900410 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900411 return;
412
Garrick Evans310ab552019-10-08 11:07:53 +0900413 // This can happen if the device if OnDeviceRemoved is invoked when the
414 // container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900415 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900416 return;
417
Garrick Evansa1134d72019-12-02 14:25:37 +0900418 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900419 if (!ctx) {
420 LOG(ERROR) << "Attempt to stop removed device " << device->ifname();
421 return;
422 }
423
424 if (!ctx->IsStarted()) {
425 LOG(ERROR) << "Attempt to re-stop device " << device->ifname();
426 return;
427 }
428
Garrick Evansd90a3822019-11-12 17:53:08 +0900429 impl_->OnStopDevice(device);
Garrick Evanscb791e72019-11-11 15:44:34 +0900430
431 ctx->Stop();
432}
433
Garrick Evans54861622019-07-19 09:05:09 +0900434void ArcService::OnDefaultInterfaceChanged(const std::string& ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900435 if (impl_)
436 impl_->OnDefaultInterfaceChanged(ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900437}
Garrick Evansba575742019-07-17 15:48:08 +0900438
Garrick Evans2c263102019-07-26 16:07:18 +0900439// Context
440
441ArcService::Context::Context() : Device::Context() {
442 Stop();
443}
444
445void ArcService::Context::Start() {
446 Stop();
447 started_ = true;
448}
449
450void ArcService::Context::Stop() {
451 started_ = false;
452 link_up_ = false;
453 routing_table_id_ = kInvalidTableID;
454 routing_table_attempts_ = 0;
455}
456
457bool ArcService::Context::IsStarted() const {
458 return started_;
459}
460
461bool ArcService::Context::IsLinkUp() const {
462 return link_up_;
463}
464
465bool ArcService::Context::SetLinkUp(bool link_up) {
466 if (link_up == link_up_)
467 return false;
468
469 link_up_ = link_up;
470 return true;
471}
472
473bool ArcService::Context::HasIPv6() const {
474 return routing_table_id_ != kInvalidTableID;
475}
476
477bool ArcService::Context::SetHasIPv6(int routing_table_id) {
478 if (routing_table_id <= kRouteControllerRouteTableOffsetFromIndex)
479 return false;
480
481 routing_table_id_ = routing_table_id;
482 return true;
483}
484
Garrick Evansdc3fc452019-09-06 14:15:04 +0900485void ArcService::Context::ClearIPv6() {
486 routing_table_id_ = kInvalidTableID;
487 routing_table_attempts_ = 0;
488}
489
Garrick Evans2c263102019-07-26 16:07:18 +0900490int ArcService::Context::RoutingTableID() const {
491 return routing_table_id_;
492}
493
494int ArcService::Context::RoutingTableAttempts() {
495 return routing_table_attempts_++;
496}
497
Garrick Evansb4eb3892019-11-13 12:07:07 +0900498const std::string& ArcService::Context::TAP() const {
499 return tap_;
500}
501
502void ArcService::Context::SetTAP(const std::string& tap) {
503 tap_ = tap;
504}
505
Garrick Evansd90a3822019-11-12 17:53:08 +0900506// ARC++ specific functions.
507
508ArcService::ContainerImpl::ContainerImpl(DeviceManagerBase* dev_mgr,
509 Datapath* datapath,
510 GuestMessage::GuestType guest)
Garrick Evansa34b5862019-11-20 09:34:01 +0900511 : pid_(kInvalidPID), dev_mgr_(dev_mgr), datapath_(datapath), guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900512 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900513}
Garrick Evansd90a3822019-11-12 17:53:08 +0900514
Garrick Evansb4eb3892019-11-13 12:07:07 +0900515GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
516 return guest_;
517}
518
Garrick Evans664a82f2019-12-17 12:18:05 +0900519int32_t ArcService::ContainerImpl::id() const {
520 return pid_;
521}
522
Garrick Evans508a4bc2019-11-14 08:45:52 +0900523bool ArcService::ContainerImpl::Start(int32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900524 // This could happen if something crashes and the stop signal is not sent.
525 // It can probably be addressed by stopping and restarting the service.
526 if (pid_ != kInvalidPID)
527 return false;
528
Garrick Evans8ff08452019-11-25 09:24:26 +0900529 // TODO(garrick): Remove this test hack.
530 if (pid == kTestPID) {
531 LOG(WARNING) << "Running with test PID";
532 pid_ = pid;
533 return true;
534 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900535 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900536 LOG(ERROR) << "Cannot start service - invalid container PID";
537 return false;
538 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900539 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900540
Garrick Evansbc91a352020-01-16 16:43:26 +0900541 // Start listening for RTNetlink messages to be notified when a virtual ARC
542 // interface is brought up or down.
543 // TODO(garrick): Delete when NDProxy is enabled on all boards.
544 {
545 host_link_listener_ = std::make_unique<shill::RTNLListener>(
546 shill::RTNLHandler::kRequestLink,
547 Bind(&ArcService::ContainerImpl::HostLinkMsgHandler,
548 weak_factory_.GetWeakPtr()));
549 shill::RTNLHandler::GetInstance()->Start(RTMGRP_LINK);
550 }
551
Garrick Evansd90a3822019-11-12 17:53:08 +0900552 // Start listening for RTNetlink messages in the container's net namespace
553 // to be notified whenever it brings up an interface.
554 {
555 ScopedNS ns(pid_);
556 if (ns.IsValid()) {
557 rtnl_handler_ = std::make_unique<RTNetlinkHandler>();
558 rtnl_handler_->Start(RTMGRP_LINK);
559 link_listener_ = std::make_unique<shill::RTNLListener>(
560 shill::RTNLHandler::kRequestLink,
561 Bind(&ArcService::ContainerImpl::LinkMsgHandler,
562 weak_factory_.GetWeakPtr()),
563 rtnl_handler_.get());
564 } else {
565 // This is bad - it means we won't ever be able to tell when the container
566 // brings up an interface.
567 LOG(ERROR)
568 << "Cannot start netlink listener - invalid container namespace?";
569 return false;
570 }
571 }
572
573 dev_mgr_->RegisterDeviceIPv6AddressFoundHandler(
Garrick Evansb4eb3892019-11-13 12:07:07 +0900574 guest(), base::Bind(&ArcService::ContainerImpl::SetupIPv6,
575 weak_factory_.GetWeakPtr()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900576
577 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
578 return true;
579}
580
Garrick Evans21173b12019-11-20 15:23:16 +0900581void ArcService::ContainerImpl::Stop(int32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900582 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900583 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900584
Garrick Evansd90a3822019-11-12 17:53:08 +0900585 rtnl_handler_->RemoveListener(link_listener_.get());
586 link_listener_.reset();
587 rtnl_handler_.reset();
588
589 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
590 pid_ = kInvalidPID;
591}
592
Garrick Evansa51d0a12019-11-28 13:51:23 +0900593bool ArcService::ContainerImpl::IsStarted(int32_t* pid) const {
594 if (pid)
595 *pid = pid_;
596
Garrick Evansd90a3822019-11-12 17:53:08 +0900597 return pid_ != kInvalidPID;
598}
599
600bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
601 const auto& config = device->config();
602
603 LOG(INFO) << "Starting device " << device->ifname()
604 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900605 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900606
607 std::string veth_ifname = datapath_->AddVirtualBridgedInterface(
608 device->ifname(), MacAddressToString(config.guest_mac_addr()),
609 config.host_ifname());
610 if (veth_ifname.empty()) {
611 LOG(ERROR) << "Failed to create virtual interface for container";
612 return false;
613 }
614
615 if (!datapath_->AddInterfaceToContainer(
616 pid_, veth_ifname, config.guest_ifname(),
617 IPv4AddressToString(config.guest_ipv4_addr()),
618 device->options().fwd_multicast)) {
619 LOG(ERROR) << "Failed to create container interface.";
620 datapath_->RemoveInterface(veth_ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900621 return false;
622 }
623
624 // Signal the container that the network device is ready.
Garrick Evans8ff08452019-11-25 09:24:26 +0900625 if (device->IsAndroid()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900626 datapath_->runner().WriteSentinelToContainer(base::IntToString(pid_));
627 }
Taoyu Li1c96d272019-12-13 14:17:43 +0900628 dev_mgr_->StartForwarding(*device);
Garrick Evansd90a3822019-11-12 17:53:08 +0900629 return true;
630}
631
632void ArcService::ContainerImpl::OnStopDevice(Device* device) {
633 const auto& config = device->config();
634
635 LOG(INFO) << "Stopping device " << device->ifname()
636 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900637 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900638
Taoyu Lif7e8b572019-12-13 15:22:09 +0900639 device->StopIPv6RoutingLegacy();
Garrick Evansd90a3822019-11-12 17:53:08 +0900640 if (!device->IsAndroid()) {
641 datapath_->RemoveInterface(ArcVethHostName(device->ifname()));
642 }
643}
644
645void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
646 const std::string& ifname) {
647 if (!IsStarted())
648 return;
649
650 // For ARC N, we must always be able to find the arc0 device and, at a
651 // minimum, disable it.
Garrick Evansb4eb3892019-11-13 12:07:07 +0900652 if (guest() == GuestMessage::ARC_LEGACY) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900653 datapath_->RemoveLegacyIPv4InboundDNAT();
654 auto* device = dev_mgr_->FindByGuestInterface("arc0");
655 if (!device) {
656 LOG(DFATAL) << "Expected legacy Android device missing";
657 return;
658 }
Taoyu Lif7e8b572019-12-13 15:22:09 +0900659 device->StopIPv6RoutingLegacy();
Garrick Evansd90a3822019-11-12 17:53:08 +0900660
661 // If a new default interface was given, then re-enable with that.
662 if (!ifname.empty()) {
663 datapath_->AddLegacyIPv4InboundDNAT(ifname);
Taoyu Lif7e8b572019-12-13 15:22:09 +0900664 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900665 }
666 return;
667 }
668
669 // For ARC P and later, we're only concerned with resetting the device when it
670 // becomes the default (again) in order to ensure any previous configuration.
671 // is cleared.
672 if (ifname.empty())
673 return;
674
675 auto* device = dev_mgr_->FindByGuestInterface(ifname);
676 if (!device) {
677 LOG(ERROR) << "Expected default device missing: " << ifname;
678 return;
679 }
680 device->StopIPv6RoutingLegacy();
681 device->StartIPv6RoutingLegacy(ifname);
682}
683
684void ArcService::ContainerImpl::LinkMsgHandler(const shill::RTNLMessage& msg) {
685 if (!msg.HasAttribute(IFLA_IFNAME)) {
686 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
687 return;
688 }
689 bool link_up = msg.link_status().flags & IFF_UP;
690 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
691 std::string ifname(reinterpret_cast<const char*>(
692 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
693
694 auto* device = dev_mgr_->FindByGuestInterface(ifname);
695 if (!device)
696 return;
697
Garrick Evansa1134d72019-12-02 14:25:37 +0900698 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900699 if (!ctx) {
700 LOG(DFATAL) << "Context missing";
701 return;
702 }
703
704 // If the link status is unchanged, there is nothing to do.
705 if (!ctx->SetLinkUp(link_up))
706 return;
707
708 if (!link_up) {
709 LOG(INFO) << ifname << " is now down";
710 return;
711 }
712 LOG(INFO) << ifname << " is now up";
713
Garrick Evans8ff08452019-11-25 09:24:26 +0900714 if (device->UsesDefaultInterface()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900715 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
716 return;
717 }
718
Garrick Evans8ff08452019-11-25 09:24:26 +0900719 if (device->IsAndroid())
720 return;
721
Taoyu Lif7e8b572019-12-13 15:22:09 +0900722 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900723}
724
Garrick Evansbc91a352020-01-16 16:43:26 +0900725// TODO(garrick): Remove once NDProxy is enabled on all boards.
726void ArcService::ContainerImpl::HostLinkMsgHandler(
727 const shill::RTNLMessage& msg) {
728 if (!msg.HasAttribute(IFLA_IFNAME)) {
729 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
730 return;
731 }
732
733 // Only consider virtual interfaces that were created for guests; for now this
734 // only includes those prefixed with 'arc'.
735 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
736 std::string ifname(reinterpret_cast<const char*>(
737 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
738 if (!IsArcDevice(ifname))
739 return;
740
741 bool link_up = msg.link_status().flags & IFF_UP;
742 Device* device = dev_mgr_->FindByHostInterface(ifname);
743
744 if (!device || !device->HostLinkUp(link_up))
745 return;
746
747 if (!link_up) {
748 LOG(INFO) << ifname << " is now down";
749 device->StopIPv6RoutingLegacy();
750 return;
751 }
752
753 // The link is now up.
754 LOG(INFO) << ifname << " is now up";
755
756 if (device->UsesDefaultInterface())
757 device->StartIPv6RoutingLegacy(dev_mgr_->DefaultInterface());
758 else if (!device->IsAndroid())
759 device->StartIPv6RoutingLegacy(device->config().guest_ifname());
760}
761
Garrick Evansd90a3822019-11-12 17:53:08 +0900762void ArcService::ContainerImpl::SetupIPv6(Device* device) {
763 device->RegisterIPv6TeardownHandler(base::Bind(
764 &ArcService::ContainerImpl::TeardownIPv6, weak_factory_.GetWeakPtr()));
765
766 auto& ipv6_config = device->ipv6_config();
767 if (ipv6_config.ifname.empty())
768 return;
769
Garrick Evansa1134d72019-12-02 14:25:37 +0900770 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900771 if (!ctx) {
772 LOG(DFATAL) << "Context missing";
773 return;
774 }
775 if (ctx->HasIPv6())
776 return;
777
778 LOG(INFO) << "Setting up IPv6 for " << ipv6_config.ifname;
779
780 int table_id =
781 GetAndroidRoutingTableId(device->config().guest_ifname(), pid_);
782 if (table_id == kInvalidTableID) {
783 if (ctx->RoutingTableAttempts() < kMaxTableRetries) {
784 LOG(INFO) << "Could not look up routing table ID for container interface "
785 << device->config().guest_ifname() << " - trying again...";
786 base::MessageLoop::current()->task_runner()->PostDelayedTask(
787 FROM_HERE,
788 base::Bind(&ArcService::ContainerImpl::SetupIPv6,
789 weak_factory_.GetWeakPtr(), device),
790 kTableRetryDelay);
791 } else {
792 LOG(DFATAL)
793 << "Could not look up routing table ID for container interface "
794 << device->config().guest_ifname();
795 }
796 return;
797 }
798
799 LOG(INFO) << "Setting IPv6 address " << ipv6_config.addr
800 << "/128, gateway=" << ipv6_config.router << " on "
801 << ipv6_config.ifname;
802
803 char buf[INET6_ADDRSTRLEN] = {0};
804 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
805 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
806 return;
807 }
808 std::string addr = buf;
809
810 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
811 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
812 return;
813 }
814 std::string router = buf;
815
816 const auto& config = device->config();
817 {
818 ScopedNS ns(pid_);
819 if (!ns.IsValid()) {
820 LOG(ERROR) << "Invalid container namespace (" << pid_
821 << ") - cannot configure IPv6.";
822 return;
823 }
Taoyu Li90c13912019-11-26 17:56:54 +0900824 // Tag the interface so that ARC can detect this manual configuration and
825 // skip disabling and re-enabling IPv6 (b/144545910).
Garrick Evans664a82f2019-12-17 12:18:05 +0900826 if (!datapath_->MaskInterfaceFlags(config.guest_ifname(), IFF_DEBUG)) {
Taoyu Li90c13912019-11-26 17:56:54 +0900827 LOG(ERROR) << "Failed to mark IPv6 manual config flag on interface";
828 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900829 if (!datapath_->AddIPv6GatewayRoutes(config.guest_ifname(), addr, router,
830 ipv6_config.prefix_len, table_id)) {
831 LOG(ERROR) << "Failed to setup IPv6 routes in the container";
832 return;
833 }
834 }
835
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900836 if (!datapath_->AddIPv6HostRoute(config.host_ifname(), addr, 128)) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900837 LOG(ERROR) << "Failed to setup the IPv6 route for interface "
838 << config.host_ifname();
839 return;
840 }
841
842 if (!datapath_->AddIPv6Neighbor(ipv6_config.ifname, addr)) {
843 LOG(ERROR) << "Failed to setup the IPv6 neighbor proxy";
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900844 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr, 128);
Garrick Evansd90a3822019-11-12 17:53:08 +0900845 return;
846 }
847
Taoyu Li2980ee92019-11-18 17:49:32 +0900848 if (!datapath_->AddIPv6Forwarding(ipv6_config.ifname,
849 device->config().host_ifname())) {
850 LOG(ERROR) << "Failed to setup iptables for IPv6";
851 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900852 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr, 128);
Taoyu Li2980ee92019-11-18 17:49:32 +0900853 return;
854 }
855
Garrick Evansd90a3822019-11-12 17:53:08 +0900856 ctx->SetHasIPv6(table_id);
857}
858
859void ArcService::ContainerImpl::TeardownIPv6(Device* device) {
Garrick Evansa1134d72019-12-02 14:25:37 +0900860 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900861 if (!ctx || !ctx->HasIPv6())
862 return;
863
864 auto& ipv6_config = device->ipv6_config();
865 LOG(INFO) << "Clearing IPv6 for " << ipv6_config.ifname;
866 int table_id = ctx->RoutingTableID();
867 ctx->ClearIPv6();
868
869 char buf[INET6_ADDRSTRLEN] = {0};
870 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
871 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
872 return;
873 }
874 std::string addr = buf;
875
876 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
877 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
878 return;
879 }
880 std::string router = buf;
881
882 const auto& config = device->config();
Taoyu Li2980ee92019-11-18 17:49:32 +0900883 datapath_->RemoveIPv6Forwarding(ipv6_config.ifname, config.host_ifname());
Garrick Evansd90a3822019-11-12 17:53:08 +0900884 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900885 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr, 128);
Garrick Evansd90a3822019-11-12 17:53:08 +0900886
887 ScopedNS ns(pid_);
888 if (ns.IsValid()) {
889 datapath_->RemoveIPv6GatewayRoutes(config.guest_ifname(), addr, router,
890 ipv6_config.prefix_len, table_id);
891 }
892}
893
Garrick Evansb4eb3892019-11-13 12:07:07 +0900894// VM specific functions
895
896ArcService::VmImpl::VmImpl(DeviceManagerBase* dev_mgr, Datapath* datapath)
897 : cid_(kInvalidCID), dev_mgr_(dev_mgr), datapath_(datapath) {}
898
899GuestMessage::GuestType ArcService::VmImpl::guest() const {
900 return GuestMessage::ARC_VM;
901}
902
Garrick Evans664a82f2019-12-17 12:18:05 +0900903int32_t ArcService::VmImpl::id() const {
904 return cid_;
905}
906
Garrick Evans508a4bc2019-11-14 08:45:52 +0900907bool ArcService::VmImpl::Start(int32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900908 // This can happen if concierge crashes and doesn't send the vm down RPC.
909 // It can probably be addressed by stopping and restarting the service.
910 if (cid_ != kInvalidCID)
911 return false;
912
Garrick Evansb4eb3892019-11-13 12:07:07 +0900913 if (cid <= kInvalidCID) {
914 LOG(ERROR) << "Invalid VM cid " << cid;
915 return false;
916 }
917
918 cid_ = cid;
919 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
920
921 return true;
922}
923
Garrick Evans21173b12019-11-20 15:23:16 +0900924void ArcService::VmImpl::Stop(int32_t cid) {
925 if (cid_ != cid) {
926 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
927 return;
928 }
929
Garrick Evansb4eb3892019-11-13 12:07:07 +0900930 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
931 cid_ = kInvalidCID;
932}
933
Garrick Evansa51d0a12019-11-28 13:51:23 +0900934bool ArcService::VmImpl::IsStarted(int32_t* cid) const {
935 if (cid)
936 *cid = cid_;
937
Garrick Evansb4eb3892019-11-13 12:07:07 +0900938 return cid_ > kInvalidCID;
939}
940
941bool ArcService::VmImpl::OnStartDevice(Device* device) {
942 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900943 // configurations.
944 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900945 return false;
946
947 const auto& config = device->config();
948
949 LOG(INFO) << "Starting device " << device->ifname()
950 << " bridge: " << config.host_ifname()
951 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
952
Garrick Evansa1134d72019-12-02 14:25:37 +0900953 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900954 if (!ctx) {
955 LOG(ERROR) << "Context missing";
956 return false;
957 }
958
959 // Since the interface will be added to the bridge, no address configuration
960 // should be provided here.
961 std::string tap =
962 datapath_->AddTAP("" /* auto-generate name */, nullptr /* no mac addr */,
963 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
964 if (tap.empty()) {
965 LOG(ERROR) << "Failed to create TAP device for VM";
966 return false;
967 }
968
969 if (!datapath_->AddToBridge(config.host_ifname(), tap)) {
970 LOG(ERROR) << "Failed to bridge TAP device " << tap;
971 datapath_->RemoveInterface(tap);
972 return false;
973 }
974
975 ctx->SetTAP(tap);
976 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
977 // configurations; but for now ARCVM needs to be treated like ARC++ N.
978 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
Taoyu Li1c96d272019-12-13 14:17:43 +0900979 dev_mgr_->StartForwarding(*device);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900980 return true;
981}
982
983void ArcService::VmImpl::OnStopDevice(Device* device) {
984 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900985 // configurations.
986 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900987 return;
988
989 const auto& config = device->config();
990
991 LOG(INFO) << "Stopping " << device->ifname()
992 << " bridge: " << config.host_ifname()
993 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
994
Garrick Evansa1134d72019-12-02 14:25:37 +0900995 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900996 if (!ctx) {
997 LOG(ERROR) << "Context missing";
998 return;
999 }
1000
Taoyu Lif7e8b572019-12-13 15:22:09 +09001001 device->StopIPv6RoutingLegacy();
Garrick Evansb4eb3892019-11-13 12:07:07 +09001002 datapath_->RemoveInterface(ctx->TAP());
1003}
1004
1005void ArcService::VmImpl::OnDefaultInterfaceChanged(const std::string& ifname) {
1006 if (!IsStarted())
1007 return;
1008
1009 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
1010 // configurations; but for now ARCVM needs to be treated like ARC++ N.
1011 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansf29f5a32019-12-06 11:34:25 +09001012 auto* device = dev_mgr_->FindByGuestInterface("arc1");
Garrick Evansb4eb3892019-11-13 12:07:07 +09001013 if (!device) {
1014 LOG(DFATAL) << "Expected Android device missing";
1015 return;
1016 }
Taoyu Lif7e8b572019-12-13 15:22:09 +09001017 device->StopIPv6RoutingLegacy();
Garrick Evansb4eb3892019-11-13 12:07:07 +09001018
1019 // If a new default interface was given, then re-enable with that.
1020 if (!ifname.empty()) {
1021 datapath_->AddLegacyIPv4InboundDNAT(ifname);
Taoyu Lif7e8b572019-12-13 15:22:09 +09001022 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansb4eb3892019-11-13 12:07:07 +09001023 }
1024}
1025
Garrick Evans5d55f5e2019-07-17 15:28:10 +09001026} // namespace arc_networkd