blob: 5d03218f6b7b687e000a198920c0d47332b86e13 [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>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090011#include <vector>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090012
Garrick Evans54861622019-07-19 09:05:09 +090013#include <base/bind.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090014#include <base/files/file_path.h>
15#include <base/files/file_util.h>
16#include <base/logging.h>
17#include <base/strings/string_number_conversions.h>
18#include <base/strings/string_util.h>
Garrick Evans54861622019-07-19 09:05:09 +090019#include <base/strings/stringprintf.h>
Garrick Evans1f5a3612019-11-08 12:59:03 +090020#include <brillo/key_value_store.h>
Garrick Evansb4eb3892019-11-13 12:07:07 +090021#include <chromeos/constants/vm_tools.h>
Garrick Evans54861622019-07-19 09:05:09 +090022#include <shill/net/rtnl_message.h>
23
24#include "arc/network/datapath.h"
Garrick Evans54861622019-07-19 09:05:09 +090025#include "arc/network/mac_address_generator.h"
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090026#include "arc/network/manager.h"
Garrick Evans3915af32019-07-25 15:44:34 +090027#include "arc/network/minijailed_process_runner.h"
Garrick Evans54861622019-07-19 09:05:09 +090028#include "arc/network/net_util.h"
29#include "arc/network/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090030
31namespace arc_networkd {
Garrick Evansf29f5a32019-12-06 11:34:25 +090032
33namespace test {
34GuestMessage::GuestType guest = GuestMessage::UNKNOWN_GUEST;
35} // namespace test
36
Garrick Evans5d55f5e2019-07-17 15:28:10 +090037namespace {
Garrick Evans015b0d62020-02-07 09:06:38 +090038constexpr pid_t kInvalidPID = 0;
Garrick Evansb4eb3892019-11-13 12:07:07 +090039constexpr pid_t kTestPID = -2;
Garrick Evans015b0d62020-02-07 09:06:38 +090040constexpr uint32_t kInvalidCID = 0;
Garrick Evans260ff302019-07-25 11:22:50 +090041constexpr int kInvalidTableID = -1;
42constexpr int kMaxTableRetries = 10; // Based on 1 second delay.
43constexpr base::TimeDelta kTableRetryDelay = base::TimeDelta::FromSeconds(1);
44// Android adds a constant to the interface index to derive the table id.
45// This is defined in system/netd/server/RouteController.h
46constexpr int kRouteControllerRouteTableOffsetFromIndex = 1000;
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090047constexpr int kMultinetMinAndroidSdkVersion = 28;
48constexpr char kMultinetFeatureName[] = "ARC multi-networking";
Garrick Evans54861622019-07-19 09:05:09 +090049
50// This wrapper is required since the base class is a singleton that hides its
51// constructor. It is necessary here because the message loop thread has to be
52// reassociated to the container's network namespace; and since the container
53// can be repeatedly created and destroyed, the handler must be as well.
54class RTNetlinkHandler : public shill::RTNLHandler {
55 public:
56 RTNetlinkHandler() = default;
57 ~RTNetlinkHandler() = default;
58
59 private:
60 DISALLOW_COPY_AND_ASSIGN(RTNetlinkHandler);
61};
Garrick Evans5d55f5e2019-07-17 15:28:10 +090062
Garrick Evans260ff302019-07-25 11:22:50 +090063int GetAndroidRoutingTableId(const std::string& ifname, pid_t pid) {
64 base::FilePath ifindex_path(base::StringPrintf(
65 "/proc/%d/root/sys/class/net/%s/ifindex", pid, ifname.c_str()));
66 std::string contents;
67 if (!base::ReadFileToString(ifindex_path, &contents)) {
68 PLOG(WARNING) << "Could not read " << ifindex_path.value();
69 return kInvalidTableID;
70 }
71
72 base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
73 int table_id = kInvalidTableID;
74 if (!base::StringToInt(contents, &table_id)) {
75 LOG(ERROR) << "Could not parse ifindex from " << ifindex_path.value()
76 << ": " << contents;
77 return kInvalidTableID;
78 }
79 table_id += kRouteControllerRouteTableOffsetFromIndex;
80
81 LOG(INFO) << "Found table id " << table_id << " for container interface "
82 << ifname;
83 return table_id;
84}
85
Garrick Evans6d227b92019-12-03 16:11:29 +090086void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090087 static bool done = false;
88 if (done)
89 return;
90
Garrick Evans6d227b92019-12-03 16:11:29 +090091 auto& runner = datapath.runner();
92
93 // Load networking modules needed by Android that are not compiled in the
94 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansa34b5862019-11-20 09:34:01 +090095 // These must succeed.
Garrick Evans8e8e3472020-01-23 14:03:50 +090096 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090097 // The netfilter modules needed by netd for iptables commands.
98 "ip6table_filter",
99 "ip6t_ipv6header",
100 "ip6t_REJECT",
101 // The xfrm modules needed for Android's ipsec APIs.
102 "xfrm4_mode_transport",
103 "xfrm4_mode_tunnel",
104 "xfrm6_mode_transport",
105 "xfrm6_mode_tunnel",
106 // The ipsec modules for AH and ESP encryption for ipv6.
107 "ah6",
108 "esp6",
109 }) != 0) {
110 LOG(ERROR) << "One or more required kernel modules failed to load."
111 << " Some Android functionality may be broken.";
112 }
113 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +0900114 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +0900115 // This module is not available in kernels < 3.18
116 "nf_reject_ipv6",
117 // These modules are needed for supporting Chrome traffic on Android
118 // VPN which uses Android's NAT feature. Android NAT sets up
119 // iptables
120 // rules that use these conntrack modules for FTP/TFTP.
121 "nf_nat_ftp",
122 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +0900123 // The tun module is needed by the Android 464xlat clatd process.
124 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +0900125 }) != 0) {
126 LOG(WARNING) << "One or more optional kernel modules failed to load.";
127 }
128
Garrick Evans6d227b92019-12-03 16:11:29 +0900129 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +0900130 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900131 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
132 }
133
Garrick Evansa34b5862019-11-20 09:34:01 +0900134 done = true;
135}
136
Garrick Evans508a4bc2019-11-14 08:45:52 +0900137bool IsArcVm() {
138 const base::FilePath path("/run/chrome/is_arcvm");
139 std::string contents;
140 if (!base::ReadFileToString(path, &contents)) {
141 PLOG(ERROR) << "Could not read " << path.value();
142 }
143 return contents == "1";
144}
145
Garrick Evansf29f5a32019-12-06 11:34:25 +0900146GuestMessage::GuestType ArcGuest() {
147 if (test::guest != GuestMessage::UNKNOWN_GUEST)
148 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900149
150 return IsArcVm() ? GuestMessage::ARC_VM
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +0900151 : Manager::ShouldEnableFeature(kMultinetMinAndroidSdkVersion,
152 0, std::vector<std::string>(),
153 kMultinetFeatureName)
154 ? GuestMessage::ARC
155 : GuestMessage::ARC_LEGACY;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900156}
157
Garrick Evansbc91a352020-01-16 16:43:26 +0900158constexpr const char kArcDevicePrefix[] = "arc";
159bool IsArcDevice(const std::string& ifname) {
160 return base::StartsWith(ifname, kArcDevicePrefix,
161 base::CompareCase::INSENSITIVE_ASCII);
162}
163
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900164} // namespace
165
Garrick Evans69b85872020-02-04 11:40:26 +0900166ArcService::ArcService(ShillClient* shill_client,
167 DeviceManagerBase* dev_mgr,
168 Datapath* datapath)
169 : shill_client_(shill_client), dev_mgr_(dev_mgr), datapath_(datapath) {
170 DCHECK(shill_client_);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900171 DCHECK(dev_mgr_);
Taoyu Li179dcc62019-10-17 11:21:08 +0900172 DCHECK(datapath_);
Garrick Evans3915af32019-07-25 15:44:34 +0900173
Garrick Evansf29f5a32019-12-06 11:34:25 +0900174 dev_mgr_->RegisterDeviceAddedHandler(
175 GuestMessage::ARC,
176 base::Bind(&ArcService::OnDeviceAdded, base::Unretained(this)));
177 dev_mgr_->RegisterDeviceRemovedHandler(
178 GuestMessage::ARC,
179 base::Bind(&ArcService::OnDeviceRemoved, base::Unretained(this)));
180 dev_mgr_->RegisterDefaultInterfaceChangedHandler(
181 GuestMessage::ARC, base::Bind(&ArcService::OnDefaultInterfaceChanged,
182 base::Unretained(this)));
183}
184
185ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900186 if (impl_) {
187 // Stop the service.
188 Stop(impl_->id());
189 // Delete all the bridges and veth pairs.
190 dev_mgr_->ProcessDevices(
191 base::Bind(&ArcService::OnDeviceRemoved, weak_factory_.GetWeakPtr()));
192 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900193 dev_mgr_->UnregisterAllGuestHandlers(GuestMessage::ARC);
Garrick Evans54861622019-07-19 09:05:09 +0900194}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900195
Garrick Evans015b0d62020-02-07 09:06:38 +0900196bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900197 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900198 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900199 if (impl_->IsStarted(&prev_id)) {
200 LOG(WARNING) << "Already running - did something crash?"
201 << " Stopping and restarting...";
202 Stop(prev_id);
203 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900204 }
205
Garrick Evansf29f5a32019-12-06 11:34:25 +0900206 const auto guest = ArcGuest();
207 if (guest == GuestMessage::ARC_VM)
208 impl_ = std::make_unique<VmImpl>(dev_mgr_, datapath_);
209 else
210 impl_ = std::make_unique<ContainerImpl>(dev_mgr_, datapath_, guest);
211
212 if (!impl_->Start(id)) {
213 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900214 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900215 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900216
217 // Start known host devices, any new ones will be setup in the process.
218 dev_mgr_->ProcessDevices(
219 base::Bind(&ArcService::StartDevice, weak_factory_.GetWeakPtr()));
220
221 // If this is the first time the service is starting this will create the
222 // Android bridge device; otherwise it does nothing (this is a workaround for
223 // the bug in Shill that casues a Bus crash when it sees the ARC bridge a
224 // second time). Do this after processing the existing devices so it doesn't
225 // get started twice.
Garrick Evanscfd42822019-11-15 12:38:23 +0900226 std::string arc;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900227 switch (guest) {
Garrick Evanscfd42822019-11-15 12:38:23 +0900228 case GuestMessage::ARC:
229 arc = kAndroidDevice;
230 break;
231 case GuestMessage::ARC_LEGACY:
232 arc = kAndroidLegacyDevice;
233 break;
234 case GuestMessage::ARC_VM:
235 arc = kAndroidVmDevice;
236 break;
237 default:
238 LOG(DFATAL) << "Unexpected guest: " << guest;
Garrick Evans21173b12019-11-20 15:23:16 +0900239 return false;
Garrick Evanscfd42822019-11-15 12:38:23 +0900240 }
241 dev_mgr_->Add(arc);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900242 dev_mgr_->OnGuestStart(guest);
243 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900244}
245
Garrick Evans015b0d62020-02-07 09:06:38 +0900246void ArcService::Stop(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900247 if (!impl_)
248 return;
249
250 dev_mgr_->OnGuestStop(impl_->guest());
Garrick Evans54861622019-07-19 09:05:09 +0900251
252 // Stop known host devices. Note that this does not teardown any existing
253 // devices.
254 dev_mgr_->ProcessDevices(
255 base::Bind(&ArcService::StopDevice, weak_factory_.GetWeakPtr()));
Garrick Evans21173b12019-11-20 15:23:16 +0900256
257 impl_->Stop(id);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900258 impl_.reset();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900259}
260
Garrick Evans8ff08452019-11-25 09:24:26 +0900261bool ArcService::AllowDevice(Device* device) const {
Garrick Evansa1134d72019-12-02 14:25:37 +0900262 if (!device->IsArc())
Garrick Evans0001d012019-11-22 10:06:10 +0900263 return false;
264
Garrick Evans8ff08452019-11-25 09:24:26 +0900265 // ARC P+ is multi-network enabled and should process all devices.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900266 if ((impl_ && impl_->guest() == GuestMessage::ARC) ||
267 (!impl_ && ArcGuest() == GuestMessage::ARC))
Garrick Evans8ff08452019-11-25 09:24:26 +0900268 return true;
269
270 // ARC N and ARCVM (for now) are both single-network - meaning they only use
271 // the "default" device which uses the default interface from shill.
272 return device->UsesDefaultInterface();
273}
274
Garrick Evans54861622019-07-19 09:05:09 +0900275void ArcService::OnDeviceAdded(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900276 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900277 return;
Garrick Evansba575742019-07-17 15:48:08 +0900278
Garrick Evans54861622019-07-19 09:05:09 +0900279 const auto& config = device->config();
280
281 LOG(INFO) << "Adding device " << device->ifname()
282 << " bridge: " << config.host_ifname()
Garrick Evans310ab552019-10-08 11:07:53 +0900283 << " guest_iface: " << config.guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900284
285 // Create the bridge.
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900286 if (!datapath_->AddBridge(config.host_ifname(), config.host_ipv4_addr(),
287 30)) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900288 // Per crbug/1008686 this device cannot be deleted and then re-added.
289 // It could be that arc-networkd was restarted after a crash and this device
290 // is being re-added.
291 if (!device->IsAndroid()) {
292 LOG(ERROR) << "Failed to setup arc bridge: " << config.host_ifname();
293 return;
294 }
295 if (!datapath_->MaskInterfaceFlags(config.host_ifname(), IFF_UP)) {
296 LOG(ERROR) << "Failed to bring up arc bridge: " << config.host_ifname();
297 return;
298 }
Garrick Evans54861622019-07-19 09:05:09 +0900299 }
300
301 // Setup the iptables.
Garrick Evans8ff08452019-11-25 09:24:26 +0900302 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900303 if (!datapath_->AddLegacyIPv4DNAT(
304 IPv4AddressToString(config.guest_ipv4_addr())))
305 LOG(ERROR) << "Failed to configure ARC traffic rules";
306
307 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
308 LOG(ERROR) << "Failed to configure egress traffic rules";
309 } else if (!device->IsAndroid()) {
310 if (!datapath_->AddInboundIPv4DNAT(
311 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
312 LOG(ERROR) << "Failed to configure ingress traffic rules for "
313 << device->ifname();
314
315 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
316 LOG(ERROR) << "Failed to configure egress traffic rules";
317 }
318
Garrick Evansa1134d72019-12-02 14:25:37 +0900319 device->set_context(std::make_unique<Context>());
Garrick Evans54861622019-07-19 09:05:09 +0900320
321 StartDevice(device);
322}
323
324void ArcService::StartDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900325 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900326 return;
327
Garrick Evans310ab552019-10-08 11:07:53 +0900328 // This can happen if OnDeviceAdded is invoked when the container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900329 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900330 return;
331
Garrick Evans2c263102019-07-26 16:07:18 +0900332 // If there is no context, then this is a new device and it needs to run
333 // through the full setup process.
Garrick Evansa1134d72019-12-02 14:25:37 +0900334 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900335 if (!ctx)
Garrick Evans54861622019-07-19 09:05:09 +0900336 return OnDeviceAdded(device);
337
Garrick Evans2c263102019-07-26 16:07:18 +0900338 if (ctx->IsStarted()) {
339 LOG(ERROR) << "Attempt to restart device " << device->ifname();
340 return;
341 }
342
Garrick Evansd90a3822019-11-12 17:53:08 +0900343 if (!impl_->OnStartDevice(device)) {
Garrick Evanscb791e72019-11-11 15:44:34 +0900344 LOG(ERROR) << "Failed to start device " << device->ifname();
345 return;
346 }
347
Garrick Evansb4eb3892019-11-13 12:07:07 +0900348 ctx->Start();
Garrick Evans54861622019-07-19 09:05:09 +0900349}
350
351void ArcService::OnDeviceRemoved(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900352 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900353 return;
354
Garrick Evans310ab552019-10-08 11:07:53 +0900355 // If the container is down, this call does nothing.
Garrick Evans54861622019-07-19 09:05:09 +0900356 StopDevice(device);
357
358 const auto& config = device->config();
359
360 LOG(INFO) << "Removing device " << device->ifname()
361 << " bridge: " << config.host_ifname()
362 << " guest_iface: " << config.guest_ifname();
363
Taoyu Lif7e8b572019-12-13 15:22:09 +0900364 device->StopIPv6RoutingLegacy();
Garrick Evans8ff08452019-11-25 09:24:26 +0900365 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900366 datapath_->RemoveOutboundIPv4(config.host_ifname());
367 datapath_->RemoveLegacyIPv4DNAT();
368 } else if (!device->IsAndroid()) {
369 datapath_->RemoveOutboundIPv4(config.host_ifname());
370 datapath_->RemoveInboundIPv4DNAT(
371 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
372 }
373
Garrick Evans664a82f2019-12-17 12:18:05 +0900374 // Per crbug/1008686 this device cannot be deleted and then re-added.
375 // So instead of removing the bridge, bring it down and mark it. This will
376 // allow us to detect if the device is re-added in case of a crash restart and
377 // do the right thing.
378 if (device->IsAndroid()) {
379 // This can be safely deleted now.
380 datapath_->RemoveInterface(ArcVethHostName("arc0"));
381 if (!datapath_->MaskInterfaceFlags(config.host_ifname(), IFF_DEBUG, IFF_UP))
382 LOG(ERROR) << "Failed to bring down arc bridge "
383 << "- it may not restart correctly";
384 } else {
385 datapath_->RemoveBridge(config.host_ifname());
386 }
Garrick Evans54861622019-07-19 09:05:09 +0900387
Garrick Evansa1134d72019-12-02 14:25:37 +0900388 device->set_context(nullptr);
Garrick Evans54861622019-07-19 09:05:09 +0900389}
390
391void ArcService::StopDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900392 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900393 return;
394
Garrick Evans310ab552019-10-08 11:07:53 +0900395 // This can happen if the device if OnDeviceRemoved is invoked when the
396 // container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900397 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900398 return;
399
Garrick Evansa1134d72019-12-02 14:25:37 +0900400 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900401 if (!ctx) {
402 LOG(ERROR) << "Attempt to stop removed device " << device->ifname();
403 return;
404 }
405
406 if (!ctx->IsStarted()) {
407 LOG(ERROR) << "Attempt to re-stop device " << device->ifname();
408 return;
409 }
410
Garrick Evansd90a3822019-11-12 17:53:08 +0900411 impl_->OnStopDevice(device);
Garrick Evanscb791e72019-11-11 15:44:34 +0900412
413 ctx->Stop();
414}
415
Garrick Evans54861622019-07-19 09:05:09 +0900416void ArcService::OnDefaultInterfaceChanged(const std::string& ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900417 if (impl_)
418 impl_->OnDefaultInterfaceChanged(ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900419}
Garrick Evansba575742019-07-17 15:48:08 +0900420
Garrick Evans2c263102019-07-26 16:07:18 +0900421// Context
422
423ArcService::Context::Context() : Device::Context() {
424 Stop();
425}
426
427void ArcService::Context::Start() {
428 Stop();
429 started_ = true;
430}
431
432void ArcService::Context::Stop() {
433 started_ = false;
434 link_up_ = false;
435 routing_table_id_ = kInvalidTableID;
436 routing_table_attempts_ = 0;
437}
438
439bool ArcService::Context::IsStarted() const {
440 return started_;
441}
442
443bool ArcService::Context::IsLinkUp() const {
444 return link_up_;
445}
446
447bool ArcService::Context::SetLinkUp(bool link_up) {
448 if (link_up == link_up_)
449 return false;
450
451 link_up_ = link_up;
452 return true;
453}
454
455bool ArcService::Context::HasIPv6() const {
456 return routing_table_id_ != kInvalidTableID;
457}
458
459bool ArcService::Context::SetHasIPv6(int routing_table_id) {
460 if (routing_table_id <= kRouteControllerRouteTableOffsetFromIndex)
461 return false;
462
463 routing_table_id_ = routing_table_id;
464 return true;
465}
466
Garrick Evansdc3fc452019-09-06 14:15:04 +0900467void ArcService::Context::ClearIPv6() {
468 routing_table_id_ = kInvalidTableID;
469 routing_table_attempts_ = 0;
470}
471
Garrick Evans2c263102019-07-26 16:07:18 +0900472int ArcService::Context::RoutingTableID() const {
473 return routing_table_id_;
474}
475
476int ArcService::Context::RoutingTableAttempts() {
477 return routing_table_attempts_++;
478}
479
Garrick Evansb4eb3892019-11-13 12:07:07 +0900480const std::string& ArcService::Context::TAP() const {
481 return tap_;
482}
483
484void ArcService::Context::SetTAP(const std::string& tap) {
485 tap_ = tap;
486}
487
Garrick Evansd90a3822019-11-12 17:53:08 +0900488// ARC++ specific functions.
489
490ArcService::ContainerImpl::ContainerImpl(DeviceManagerBase* dev_mgr,
491 Datapath* datapath,
492 GuestMessage::GuestType guest)
Garrick Evansa34b5862019-11-20 09:34:01 +0900493 : pid_(kInvalidPID), dev_mgr_(dev_mgr), datapath_(datapath), guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900494 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900495}
Garrick Evansd90a3822019-11-12 17:53:08 +0900496
Garrick Evansb4eb3892019-11-13 12:07:07 +0900497GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
498 return guest_;
499}
500
Garrick Evans015b0d62020-02-07 09:06:38 +0900501uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900502 return pid_;
503}
504
Garrick Evans015b0d62020-02-07 09:06:38 +0900505bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900506 // This could happen if something crashes and the stop signal is not sent.
507 // It can probably be addressed by stopping and restarting the service.
508 if (pid_ != kInvalidPID)
509 return false;
510
Garrick Evans8ff08452019-11-25 09:24:26 +0900511 // TODO(garrick): Remove this test hack.
512 if (pid == kTestPID) {
513 LOG(WARNING) << "Running with test PID";
514 pid_ = pid;
515 return true;
516 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900517 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900518 LOG(ERROR) << "Cannot start service - invalid container PID";
519 return false;
520 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900521 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900522
Garrick Evansbc91a352020-01-16 16:43:26 +0900523 // Start listening for RTNetlink messages to be notified when a virtual ARC
524 // interface is brought up or down.
525 // TODO(garrick): Delete when NDProxy is enabled on all boards.
526 {
527 host_link_listener_ = std::make_unique<shill::RTNLListener>(
528 shill::RTNLHandler::kRequestLink,
529 Bind(&ArcService::ContainerImpl::HostLinkMsgHandler,
530 weak_factory_.GetWeakPtr()));
531 shill::RTNLHandler::GetInstance()->Start(RTMGRP_LINK);
532 }
533
Garrick Evansd90a3822019-11-12 17:53:08 +0900534 // Start listening for RTNetlink messages in the container's net namespace
535 // to be notified whenever it brings up an interface.
536 {
537 ScopedNS ns(pid_);
538 if (ns.IsValid()) {
539 rtnl_handler_ = std::make_unique<RTNetlinkHandler>();
540 rtnl_handler_->Start(RTMGRP_LINK);
541 link_listener_ = std::make_unique<shill::RTNLListener>(
542 shill::RTNLHandler::kRequestLink,
543 Bind(&ArcService::ContainerImpl::LinkMsgHandler,
544 weak_factory_.GetWeakPtr()),
545 rtnl_handler_.get());
546 } else {
547 // This is bad - it means we won't ever be able to tell when the container
548 // brings up an interface.
549 LOG(ERROR)
550 << "Cannot start netlink listener - invalid container namespace?";
551 return false;
552 }
553 }
554
Garrick Evansd90a3822019-11-12 17:53:08 +0900555 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
556 return true;
557}
558
Garrick Evans015b0d62020-02-07 09:06:38 +0900559void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900560 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900561 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900562
Garrick Evansd90a3822019-11-12 17:53:08 +0900563 rtnl_handler_->RemoveListener(link_listener_.get());
564 link_listener_.reset();
565 rtnl_handler_.reset();
566
567 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
568 pid_ = kInvalidPID;
569}
570
Garrick Evans015b0d62020-02-07 09:06:38 +0900571bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900572 if (pid)
573 *pid = pid_;
574
Garrick Evansd90a3822019-11-12 17:53:08 +0900575 return pid_ != kInvalidPID;
576}
577
578bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
579 const auto& config = device->config();
580
581 LOG(INFO) << "Starting device " << device->ifname()
582 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900583 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900584
585 std::string veth_ifname = datapath_->AddVirtualBridgedInterface(
586 device->ifname(), MacAddressToString(config.guest_mac_addr()),
587 config.host_ifname());
588 if (veth_ifname.empty()) {
589 LOG(ERROR) << "Failed to create virtual interface for container";
590 return false;
591 }
592
593 if (!datapath_->AddInterfaceToContainer(
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900594 pid_, veth_ifname, config.guest_ifname(), config.guest_ipv4_addr(),
595 30, device->options().fwd_multicast)) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900596 LOG(ERROR) << "Failed to create container interface.";
597 datapath_->RemoveInterface(veth_ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900598 return false;
599 }
600
Garrick Evans708ec342020-01-21 10:00:29 +0900601 // Setup callback for legacy IPv6 discovery, if applicable.
602 if (device->options().ipv6_enabled &&
603 device->options().find_ipv6_routes_legacy) {
604 device->RegisterIPv6Handlers(
605 base::Bind(&ArcService::ContainerImpl::SetupIPv6,
606 weak_factory_.GetWeakPtr()),
607 base::Bind(&ArcService::ContainerImpl::TeardownIPv6,
608 weak_factory_.GetWeakPtr()));
609 }
610
Garrick Evansd90a3822019-11-12 17:53:08 +0900611 // Signal the container that the network device is ready.
Garrick Evans8ff08452019-11-25 09:24:26 +0900612 if (device->IsAndroid()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900613 datapath_->runner().WriteSentinelToContainer(base::IntToString(pid_));
614 }
Garrick Evans708ec342020-01-21 10:00:29 +0900615
Taoyu Li1c96d272019-12-13 14:17:43 +0900616 dev_mgr_->StartForwarding(*device);
Garrick Evansd90a3822019-11-12 17:53:08 +0900617 return true;
618}
619
620void ArcService::ContainerImpl::OnStopDevice(Device* device) {
621 const auto& config = device->config();
622
623 LOG(INFO) << "Stopping device " << device->ifname()
624 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900625 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900626
Taoyu Lif7e8b572019-12-13 15:22:09 +0900627 device->StopIPv6RoutingLegacy();
Garrick Evansd90a3822019-11-12 17:53:08 +0900628 if (!device->IsAndroid()) {
629 datapath_->RemoveInterface(ArcVethHostName(device->ifname()));
630 }
Garrick Evans708ec342020-01-21 10:00:29 +0900631
632 device->UnregisterIPv6Handlers();
Garrick Evansd90a3822019-11-12 17:53:08 +0900633}
634
635void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
636 const std::string& ifname) {
637 if (!IsStarted())
638 return;
639
640 // For ARC N, we must always be able to find the arc0 device and, at a
641 // minimum, disable it.
Garrick Evansb4eb3892019-11-13 12:07:07 +0900642 if (guest() == GuestMessage::ARC_LEGACY) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900643 datapath_->RemoveLegacyIPv4InboundDNAT();
644 auto* device = dev_mgr_->FindByGuestInterface("arc0");
645 if (!device) {
646 LOG(DFATAL) << "Expected legacy Android device missing";
647 return;
648 }
Taoyu Lif7e8b572019-12-13 15:22:09 +0900649 device->StopIPv6RoutingLegacy();
Garrick Evansd90a3822019-11-12 17:53:08 +0900650
651 // If a new default interface was given, then re-enable with that.
652 if (!ifname.empty()) {
653 datapath_->AddLegacyIPv4InboundDNAT(ifname);
Taoyu Lif7e8b572019-12-13 15:22:09 +0900654 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900655 }
656 return;
657 }
658
659 // For ARC P and later, we're only concerned with resetting the device when it
660 // becomes the default (again) in order to ensure any previous configuration.
661 // is cleared.
662 if (ifname.empty())
663 return;
664
665 auto* device = dev_mgr_->FindByGuestInterface(ifname);
666 if (!device) {
667 LOG(ERROR) << "Expected default device missing: " << ifname;
668 return;
669 }
670 device->StopIPv6RoutingLegacy();
671 device->StartIPv6RoutingLegacy(ifname);
672}
673
674void ArcService::ContainerImpl::LinkMsgHandler(const shill::RTNLMessage& msg) {
675 if (!msg.HasAttribute(IFLA_IFNAME)) {
676 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
677 return;
678 }
679 bool link_up = msg.link_status().flags & IFF_UP;
680 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
681 std::string ifname(reinterpret_cast<const char*>(
682 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
683
684 auto* device = dev_mgr_->FindByGuestInterface(ifname);
685 if (!device)
686 return;
687
Garrick Evansa1134d72019-12-02 14:25:37 +0900688 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900689 if (!ctx) {
690 LOG(DFATAL) << "Context missing";
691 return;
692 }
693
694 // If the link status is unchanged, there is nothing to do.
695 if (!ctx->SetLinkUp(link_up))
696 return;
697
698 if (!link_up) {
699 LOG(INFO) << ifname << " is now down";
700 return;
701 }
702 LOG(INFO) << ifname << " is now up";
703
Garrick Evans8ff08452019-11-25 09:24:26 +0900704 if (device->UsesDefaultInterface()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900705 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
706 return;
707 }
708
Garrick Evans8ff08452019-11-25 09:24:26 +0900709 if (device->IsAndroid())
710 return;
711
Taoyu Lif7e8b572019-12-13 15:22:09 +0900712 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900713}
714
Garrick Evansbc91a352020-01-16 16:43:26 +0900715// TODO(garrick): Remove once NDProxy is enabled on all boards.
716void ArcService::ContainerImpl::HostLinkMsgHandler(
717 const shill::RTNLMessage& msg) {
718 if (!msg.HasAttribute(IFLA_IFNAME)) {
719 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
720 return;
721 }
722
723 // Only consider virtual interfaces that were created for guests; for now this
724 // only includes those prefixed with 'arc'.
725 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
726 std::string ifname(reinterpret_cast<const char*>(
727 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
728 if (!IsArcDevice(ifname))
729 return;
730
731 bool link_up = msg.link_status().flags & IFF_UP;
732 Device* device = dev_mgr_->FindByHostInterface(ifname);
733
734 if (!device || !device->HostLinkUp(link_up))
735 return;
736
737 if (!link_up) {
738 LOG(INFO) << ifname << " is now down";
739 device->StopIPv6RoutingLegacy();
740 return;
741 }
742
743 // The link is now up.
744 LOG(INFO) << ifname << " is now up";
745
746 if (device->UsesDefaultInterface())
747 device->StartIPv6RoutingLegacy(dev_mgr_->DefaultInterface());
748 else if (!device->IsAndroid())
749 device->StartIPv6RoutingLegacy(device->config().guest_ifname());
750}
751
Garrick Evansd90a3822019-11-12 17:53:08 +0900752void ArcService::ContainerImpl::SetupIPv6(Device* device) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900753 auto& ipv6_config = device->ipv6_config();
754 if (ipv6_config.ifname.empty())
755 return;
756
Garrick Evansa1134d72019-12-02 14:25:37 +0900757 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900758 if (!ctx) {
759 LOG(DFATAL) << "Context missing";
760 return;
761 }
762 if (ctx->HasIPv6())
763 return;
764
765 LOG(INFO) << "Setting up IPv6 for " << ipv6_config.ifname;
766
767 int table_id =
768 GetAndroidRoutingTableId(device->config().guest_ifname(), pid_);
769 if (table_id == kInvalidTableID) {
770 if (ctx->RoutingTableAttempts() < kMaxTableRetries) {
771 LOG(INFO) << "Could not look up routing table ID for container interface "
772 << device->config().guest_ifname() << " - trying again...";
773 base::MessageLoop::current()->task_runner()->PostDelayedTask(
774 FROM_HERE,
775 base::Bind(&ArcService::ContainerImpl::SetupIPv6,
776 weak_factory_.GetWeakPtr(), device),
777 kTableRetryDelay);
778 } else {
779 LOG(DFATAL)
780 << "Could not look up routing table ID for container interface "
781 << device->config().guest_ifname();
782 }
783 return;
784 }
785
786 LOG(INFO) << "Setting IPv6 address " << ipv6_config.addr
787 << "/128, gateway=" << ipv6_config.router << " on "
788 << ipv6_config.ifname;
789
790 char buf[INET6_ADDRSTRLEN] = {0};
791 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
792 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
793 return;
794 }
795 std::string addr = buf;
796
797 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
798 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
799 return;
800 }
801 std::string router = buf;
802
803 const auto& config = device->config();
804 {
805 ScopedNS ns(pid_);
806 if (!ns.IsValid()) {
807 LOG(ERROR) << "Invalid container namespace (" << pid_
808 << ") - cannot configure IPv6.";
809 return;
810 }
Taoyu Li90c13912019-11-26 17:56:54 +0900811 // Tag the interface so that ARC can detect this manual configuration and
812 // skip disabling and re-enabling IPv6 (b/144545910).
Garrick Evans664a82f2019-12-17 12:18:05 +0900813 if (!datapath_->MaskInterfaceFlags(config.guest_ifname(), IFF_DEBUG)) {
Taoyu Li90c13912019-11-26 17:56:54 +0900814 LOG(ERROR) << "Failed to mark IPv6 manual config flag on interface";
815 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900816 if (!datapath_->AddIPv6GatewayRoutes(config.guest_ifname(), addr, router,
817 ipv6_config.prefix_len, table_id)) {
818 LOG(ERROR) << "Failed to setup IPv6 routes in the container";
819 return;
820 }
821 }
822
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900823 if (!datapath_->AddIPv6HostRoute(config.host_ifname(), addr, 128)) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900824 LOG(ERROR) << "Failed to setup the IPv6 route for interface "
825 << config.host_ifname();
826 return;
827 }
828
829 if (!datapath_->AddIPv6Neighbor(ipv6_config.ifname, addr)) {
830 LOG(ERROR) << "Failed to setup the IPv6 neighbor proxy";
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900831 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr, 128);
Garrick Evansd90a3822019-11-12 17:53:08 +0900832 return;
833 }
834
Taoyu Li2980ee92019-11-18 17:49:32 +0900835 if (!datapath_->AddIPv6Forwarding(ipv6_config.ifname,
836 device->config().host_ifname())) {
837 LOG(ERROR) << "Failed to setup iptables for IPv6";
838 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900839 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr, 128);
Taoyu Li2980ee92019-11-18 17:49:32 +0900840 return;
841 }
842
Garrick Evansd90a3822019-11-12 17:53:08 +0900843 ctx->SetHasIPv6(table_id);
844}
845
846void ArcService::ContainerImpl::TeardownIPv6(Device* device) {
Garrick Evansa1134d72019-12-02 14:25:37 +0900847 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900848 if (!ctx || !ctx->HasIPv6())
849 return;
850
851 auto& ipv6_config = device->ipv6_config();
852 LOG(INFO) << "Clearing IPv6 for " << ipv6_config.ifname;
853 int table_id = ctx->RoutingTableID();
854 ctx->ClearIPv6();
855
856 char buf[INET6_ADDRSTRLEN] = {0};
857 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
858 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
859 return;
860 }
861 std::string addr = buf;
862
863 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
864 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
865 return;
866 }
867 std::string router = buf;
868
869 const auto& config = device->config();
Taoyu Li2980ee92019-11-18 17:49:32 +0900870 datapath_->RemoveIPv6Forwarding(ipv6_config.ifname, config.host_ifname());
Garrick Evansd90a3822019-11-12 17:53:08 +0900871 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900872 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr, 128);
Garrick Evansd90a3822019-11-12 17:53:08 +0900873
874 ScopedNS ns(pid_);
875 if (ns.IsValid()) {
876 datapath_->RemoveIPv6GatewayRoutes(config.guest_ifname(), addr, router,
877 ipv6_config.prefix_len, table_id);
878 }
879}
880
Garrick Evansb4eb3892019-11-13 12:07:07 +0900881// VM specific functions
882
883ArcService::VmImpl::VmImpl(DeviceManagerBase* dev_mgr, Datapath* datapath)
884 : cid_(kInvalidCID), dev_mgr_(dev_mgr), datapath_(datapath) {}
885
886GuestMessage::GuestType ArcService::VmImpl::guest() const {
887 return GuestMessage::ARC_VM;
888}
889
Garrick Evans015b0d62020-02-07 09:06:38 +0900890uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900891 return cid_;
892}
893
Garrick Evans015b0d62020-02-07 09:06:38 +0900894bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900895 // This can happen if concierge crashes and doesn't send the vm down RPC.
896 // It can probably be addressed by stopping and restarting the service.
897 if (cid_ != kInvalidCID)
898 return false;
899
Garrick Evans015b0d62020-02-07 09:06:38 +0900900 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900901 LOG(ERROR) << "Invalid VM cid " << cid;
902 return false;
903 }
904
905 cid_ = cid;
906 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
907
908 return true;
909}
910
Garrick Evans015b0d62020-02-07 09:06:38 +0900911void ArcService::VmImpl::Stop(uint32_t cid) {
Garrick Evans21173b12019-11-20 15:23:16 +0900912 if (cid_ != cid) {
913 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
914 return;
915 }
916
Garrick Evansb4eb3892019-11-13 12:07:07 +0900917 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
918 cid_ = kInvalidCID;
919}
920
Garrick Evans015b0d62020-02-07 09:06:38 +0900921bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900922 if (cid)
923 *cid = cid_;
924
Garrick Evans015b0d62020-02-07 09:06:38 +0900925 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900926}
927
928bool ArcService::VmImpl::OnStartDevice(Device* device) {
929 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900930 // configurations.
931 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900932 return false;
933
934 const auto& config = device->config();
935
936 LOG(INFO) << "Starting device " << device->ifname()
937 << " bridge: " << config.host_ifname()
938 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
939
Garrick Evansa1134d72019-12-02 14:25:37 +0900940 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900941 if (!ctx) {
942 LOG(ERROR) << "Context missing";
943 return false;
944 }
945
946 // Since the interface will be added to the bridge, no address configuration
947 // should be provided here.
948 std::string tap =
949 datapath_->AddTAP("" /* auto-generate name */, nullptr /* no mac addr */,
950 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
951 if (tap.empty()) {
952 LOG(ERROR) << "Failed to create TAP device for VM";
953 return false;
954 }
955
956 if (!datapath_->AddToBridge(config.host_ifname(), tap)) {
957 LOG(ERROR) << "Failed to bridge TAP device " << tap;
958 datapath_->RemoveInterface(tap);
959 return false;
960 }
961
962 ctx->SetTAP(tap);
963 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
964 // configurations; but for now ARCVM needs to be treated like ARC++ N.
965 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
Taoyu Li1c96d272019-12-13 14:17:43 +0900966 dev_mgr_->StartForwarding(*device);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900967 return true;
968}
969
970void ArcService::VmImpl::OnStopDevice(Device* device) {
971 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900972 // configurations.
973 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900974 return;
975
976 const auto& config = device->config();
977
978 LOG(INFO) << "Stopping " << device->ifname()
979 << " bridge: " << config.host_ifname()
980 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
981
Garrick Evansa1134d72019-12-02 14:25:37 +0900982 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900983 if (!ctx) {
984 LOG(ERROR) << "Context missing";
985 return;
986 }
987
Taoyu Lif7e8b572019-12-13 15:22:09 +0900988 device->StopIPv6RoutingLegacy();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900989 datapath_->RemoveInterface(ctx->TAP());
990}
991
992void ArcService::VmImpl::OnDefaultInterfaceChanged(const std::string& ifname) {
993 if (!IsStarted())
994 return;
995
996 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
997 // configurations; but for now ARCVM needs to be treated like ARC++ N.
998 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900999 auto* device = dev_mgr_->FindByGuestInterface("arc1");
Garrick Evansb4eb3892019-11-13 12:07:07 +09001000 if (!device) {
1001 LOG(DFATAL) << "Expected Android device missing";
1002 return;
1003 }
Taoyu Lif7e8b572019-12-13 15:22:09 +09001004 device->StopIPv6RoutingLegacy();
Garrick Evansb4eb3892019-11-13 12:07:07 +09001005
1006 // If a new default interface was given, then re-enable with that.
1007 if (!ifname.empty()) {
1008 datapath_->AddLegacyIPv4InboundDNAT(ifname);
Taoyu Lif7e8b572019-12-13 15:22:09 +09001009 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansb4eb3892019-11-13 12:07:07 +09001010 }
1011}
1012
Garrick Evans5d55f5e2019-07-17 15:28:10 +09001013} // namespace arc_networkd