blob: 9dd28474dbcb2fd3f1e5580dc286ff38af3fa982 [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 Evansf29f5a32019-12-06 11:34:25 +0900166ArcService::ArcService(DeviceManagerBase* dev_mgr, Datapath* datapath)
167 : dev_mgr_(dev_mgr), datapath_(datapath) {
168 DCHECK(dev_mgr_);
Taoyu Li179dcc62019-10-17 11:21:08 +0900169 DCHECK(datapath_);
Garrick Evans3915af32019-07-25 15:44:34 +0900170
Garrick Evansf29f5a32019-12-06 11:34:25 +0900171 dev_mgr_->RegisterDeviceAddedHandler(
172 GuestMessage::ARC,
173 base::Bind(&ArcService::OnDeviceAdded, base::Unretained(this)));
174 dev_mgr_->RegisterDeviceRemovedHandler(
175 GuestMessage::ARC,
176 base::Bind(&ArcService::OnDeviceRemoved, base::Unretained(this)));
177 dev_mgr_->RegisterDefaultInterfaceChangedHandler(
178 GuestMessage::ARC, base::Bind(&ArcService::OnDefaultInterfaceChanged,
179 base::Unretained(this)));
180}
181
182ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900183 if (impl_) {
184 // Stop the service.
185 Stop(impl_->id());
186 // Delete all the bridges and veth pairs.
187 dev_mgr_->ProcessDevices(
188 base::Bind(&ArcService::OnDeviceRemoved, weak_factory_.GetWeakPtr()));
189 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900190 dev_mgr_->UnregisterAllGuestHandlers(GuestMessage::ARC);
Garrick Evans54861622019-07-19 09:05:09 +0900191}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900192
Garrick Evans015b0d62020-02-07 09:06:38 +0900193bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900194 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900195 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900196 if (impl_->IsStarted(&prev_id)) {
197 LOG(WARNING) << "Already running - did something crash?"
198 << " Stopping and restarting...";
199 Stop(prev_id);
200 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900201 }
202
Garrick Evansf29f5a32019-12-06 11:34:25 +0900203 const auto guest = ArcGuest();
204 if (guest == GuestMessage::ARC_VM)
205 impl_ = std::make_unique<VmImpl>(dev_mgr_, datapath_);
206 else
207 impl_ = std::make_unique<ContainerImpl>(dev_mgr_, datapath_, guest);
208
209 if (!impl_->Start(id)) {
210 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900211 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900212 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900213
214 // Start known host devices, any new ones will be setup in the process.
215 dev_mgr_->ProcessDevices(
216 base::Bind(&ArcService::StartDevice, weak_factory_.GetWeakPtr()));
217
218 // If this is the first time the service is starting this will create the
219 // Android bridge device; otherwise it does nothing (this is a workaround for
220 // the bug in Shill that casues a Bus crash when it sees the ARC bridge a
221 // second time). Do this after processing the existing devices so it doesn't
222 // get started twice.
Garrick Evanscfd42822019-11-15 12:38:23 +0900223 std::string arc;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900224 switch (guest) {
Garrick Evanscfd42822019-11-15 12:38:23 +0900225 case GuestMessage::ARC:
226 arc = kAndroidDevice;
227 break;
228 case GuestMessage::ARC_LEGACY:
229 arc = kAndroidLegacyDevice;
230 break;
231 case GuestMessage::ARC_VM:
232 arc = kAndroidVmDevice;
233 break;
234 default:
235 LOG(DFATAL) << "Unexpected guest: " << guest;
Garrick Evans21173b12019-11-20 15:23:16 +0900236 return false;
Garrick Evanscfd42822019-11-15 12:38:23 +0900237 }
238 dev_mgr_->Add(arc);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900239 dev_mgr_->OnGuestStart(guest);
240 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900241}
242
Garrick Evans015b0d62020-02-07 09:06:38 +0900243void ArcService::Stop(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900244 if (!impl_)
245 return;
246
247 dev_mgr_->OnGuestStop(impl_->guest());
Garrick Evans54861622019-07-19 09:05:09 +0900248
249 // Stop known host devices. Note that this does not teardown any existing
250 // devices.
251 dev_mgr_->ProcessDevices(
252 base::Bind(&ArcService::StopDevice, weak_factory_.GetWeakPtr()));
Garrick Evans21173b12019-11-20 15:23:16 +0900253
254 impl_->Stop(id);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900255 impl_.reset();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900256}
257
Garrick Evans8ff08452019-11-25 09:24:26 +0900258bool ArcService::AllowDevice(Device* device) const {
Garrick Evansa1134d72019-12-02 14:25:37 +0900259 if (!device->IsArc())
Garrick Evans0001d012019-11-22 10:06:10 +0900260 return false;
261
Garrick Evans8ff08452019-11-25 09:24:26 +0900262 // ARC P+ is multi-network enabled and should process all devices.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900263 if ((impl_ && impl_->guest() == GuestMessage::ARC) ||
264 (!impl_ && ArcGuest() == GuestMessage::ARC))
Garrick Evans8ff08452019-11-25 09:24:26 +0900265 return true;
266
267 // ARC N and ARCVM (for now) are both single-network - meaning they only use
268 // the "default" device which uses the default interface from shill.
269 return device->UsesDefaultInterface();
270}
271
Garrick Evans54861622019-07-19 09:05:09 +0900272void ArcService::OnDeviceAdded(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900273 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900274 return;
Garrick Evansba575742019-07-17 15:48:08 +0900275
Garrick Evans54861622019-07-19 09:05:09 +0900276 const auto& config = device->config();
277
278 LOG(INFO) << "Adding device " << device->ifname()
279 << " bridge: " << config.host_ifname()
Garrick Evans310ab552019-10-08 11:07:53 +0900280 << " guest_iface: " << config.guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900281
282 // Create the bridge.
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900283 if (!datapath_->AddBridge(config.host_ifname(), config.host_ipv4_addr(),
284 30)) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900285 // Per crbug/1008686 this device cannot be deleted and then re-added.
286 // It could be that arc-networkd was restarted after a crash and this device
287 // is being re-added.
288 if (!device->IsAndroid()) {
289 LOG(ERROR) << "Failed to setup arc bridge: " << config.host_ifname();
290 return;
291 }
292 if (!datapath_->MaskInterfaceFlags(config.host_ifname(), IFF_UP)) {
293 LOG(ERROR) << "Failed to bring up arc bridge: " << config.host_ifname();
294 return;
295 }
Garrick Evans54861622019-07-19 09:05:09 +0900296 }
297
298 // Setup the iptables.
Garrick Evans8ff08452019-11-25 09:24:26 +0900299 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900300 if (!datapath_->AddLegacyIPv4DNAT(
301 IPv4AddressToString(config.guest_ipv4_addr())))
302 LOG(ERROR) << "Failed to configure ARC traffic rules";
303
304 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
305 LOG(ERROR) << "Failed to configure egress traffic rules";
306 } else if (!device->IsAndroid()) {
307 if (!datapath_->AddInboundIPv4DNAT(
308 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
309 LOG(ERROR) << "Failed to configure ingress traffic rules for "
310 << device->ifname();
311
312 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
313 LOG(ERROR) << "Failed to configure egress traffic rules";
314 }
315
Garrick Evansa1134d72019-12-02 14:25:37 +0900316 device->set_context(std::make_unique<Context>());
Garrick Evans54861622019-07-19 09:05:09 +0900317
318 StartDevice(device);
319}
320
321void ArcService::StartDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900322 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900323 return;
324
Garrick Evans310ab552019-10-08 11:07:53 +0900325 // This can happen if OnDeviceAdded is invoked when the container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900326 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900327 return;
328
Garrick Evans2c263102019-07-26 16:07:18 +0900329 // If there is no context, then this is a new device and it needs to run
330 // through the full setup process.
Garrick Evansa1134d72019-12-02 14:25:37 +0900331 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900332 if (!ctx)
Garrick Evans54861622019-07-19 09:05:09 +0900333 return OnDeviceAdded(device);
334
Garrick Evans2c263102019-07-26 16:07:18 +0900335 if (ctx->IsStarted()) {
336 LOG(ERROR) << "Attempt to restart device " << device->ifname();
337 return;
338 }
339
Garrick Evansd90a3822019-11-12 17:53:08 +0900340 if (!impl_->OnStartDevice(device)) {
Garrick Evanscb791e72019-11-11 15:44:34 +0900341 LOG(ERROR) << "Failed to start device " << device->ifname();
342 return;
343 }
344
Garrick Evansb4eb3892019-11-13 12:07:07 +0900345 ctx->Start();
Garrick Evans54861622019-07-19 09:05:09 +0900346}
347
348void ArcService::OnDeviceRemoved(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900349 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900350 return;
351
Garrick Evans310ab552019-10-08 11:07:53 +0900352 // If the container is down, this call does nothing.
Garrick Evans54861622019-07-19 09:05:09 +0900353 StopDevice(device);
354
355 const auto& config = device->config();
356
357 LOG(INFO) << "Removing device " << device->ifname()
358 << " bridge: " << config.host_ifname()
359 << " guest_iface: " << config.guest_ifname();
360
Taoyu Lif7e8b572019-12-13 15:22:09 +0900361 device->StopIPv6RoutingLegacy();
Garrick Evans8ff08452019-11-25 09:24:26 +0900362 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900363 datapath_->RemoveOutboundIPv4(config.host_ifname());
364 datapath_->RemoveLegacyIPv4DNAT();
365 } else if (!device->IsAndroid()) {
366 datapath_->RemoveOutboundIPv4(config.host_ifname());
367 datapath_->RemoveInboundIPv4DNAT(
368 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
369 }
370
Garrick Evans664a82f2019-12-17 12:18:05 +0900371 // Per crbug/1008686 this device cannot be deleted and then re-added.
372 // So instead of removing the bridge, bring it down and mark it. This will
373 // allow us to detect if the device is re-added in case of a crash restart and
374 // do the right thing.
375 if (device->IsAndroid()) {
376 // This can be safely deleted now.
377 datapath_->RemoveInterface(ArcVethHostName("arc0"));
378 if (!datapath_->MaskInterfaceFlags(config.host_ifname(), IFF_DEBUG, IFF_UP))
379 LOG(ERROR) << "Failed to bring down arc bridge "
380 << "- it may not restart correctly";
381 } else {
382 datapath_->RemoveBridge(config.host_ifname());
383 }
Garrick Evans54861622019-07-19 09:05:09 +0900384
Garrick Evansa1134d72019-12-02 14:25:37 +0900385 device->set_context(nullptr);
Garrick Evans54861622019-07-19 09:05:09 +0900386}
387
388void ArcService::StopDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900389 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900390 return;
391
Garrick Evans310ab552019-10-08 11:07:53 +0900392 // This can happen if the device if OnDeviceRemoved is invoked when the
393 // container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900394 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900395 return;
396
Garrick Evansa1134d72019-12-02 14:25:37 +0900397 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900398 if (!ctx) {
399 LOG(ERROR) << "Attempt to stop removed device " << device->ifname();
400 return;
401 }
402
403 if (!ctx->IsStarted()) {
404 LOG(ERROR) << "Attempt to re-stop device " << device->ifname();
405 return;
406 }
407
Garrick Evansd90a3822019-11-12 17:53:08 +0900408 impl_->OnStopDevice(device);
Garrick Evanscb791e72019-11-11 15:44:34 +0900409
410 ctx->Stop();
411}
412
Garrick Evans54861622019-07-19 09:05:09 +0900413void ArcService::OnDefaultInterfaceChanged(const std::string& ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900414 if (impl_)
415 impl_->OnDefaultInterfaceChanged(ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900416}
Garrick Evansba575742019-07-17 15:48:08 +0900417
Garrick Evans2c263102019-07-26 16:07:18 +0900418// Context
419
420ArcService::Context::Context() : Device::Context() {
421 Stop();
422}
423
424void ArcService::Context::Start() {
425 Stop();
426 started_ = true;
427}
428
429void ArcService::Context::Stop() {
430 started_ = false;
431 link_up_ = false;
432 routing_table_id_ = kInvalidTableID;
433 routing_table_attempts_ = 0;
434}
435
436bool ArcService::Context::IsStarted() const {
437 return started_;
438}
439
440bool ArcService::Context::IsLinkUp() const {
441 return link_up_;
442}
443
444bool ArcService::Context::SetLinkUp(bool link_up) {
445 if (link_up == link_up_)
446 return false;
447
448 link_up_ = link_up;
449 return true;
450}
451
452bool ArcService::Context::HasIPv6() const {
453 return routing_table_id_ != kInvalidTableID;
454}
455
456bool ArcService::Context::SetHasIPv6(int routing_table_id) {
457 if (routing_table_id <= kRouteControllerRouteTableOffsetFromIndex)
458 return false;
459
460 routing_table_id_ = routing_table_id;
461 return true;
462}
463
Garrick Evansdc3fc452019-09-06 14:15:04 +0900464void ArcService::Context::ClearIPv6() {
465 routing_table_id_ = kInvalidTableID;
466 routing_table_attempts_ = 0;
467}
468
Garrick Evans2c263102019-07-26 16:07:18 +0900469int ArcService::Context::RoutingTableID() const {
470 return routing_table_id_;
471}
472
473int ArcService::Context::RoutingTableAttempts() {
474 return routing_table_attempts_++;
475}
476
Garrick Evansb4eb3892019-11-13 12:07:07 +0900477const std::string& ArcService::Context::TAP() const {
478 return tap_;
479}
480
481void ArcService::Context::SetTAP(const std::string& tap) {
482 tap_ = tap;
483}
484
Garrick Evansd90a3822019-11-12 17:53:08 +0900485// ARC++ specific functions.
486
487ArcService::ContainerImpl::ContainerImpl(DeviceManagerBase* dev_mgr,
488 Datapath* datapath,
489 GuestMessage::GuestType guest)
Garrick Evansa34b5862019-11-20 09:34:01 +0900490 : pid_(kInvalidPID), dev_mgr_(dev_mgr), datapath_(datapath), guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900491 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900492}
Garrick Evansd90a3822019-11-12 17:53:08 +0900493
Garrick Evansb4eb3892019-11-13 12:07:07 +0900494GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
495 return guest_;
496}
497
Garrick Evans015b0d62020-02-07 09:06:38 +0900498uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900499 return pid_;
500}
501
Garrick Evans015b0d62020-02-07 09:06:38 +0900502bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900503 // This could happen if something crashes and the stop signal is not sent.
504 // It can probably be addressed by stopping and restarting the service.
505 if (pid_ != kInvalidPID)
506 return false;
507
Garrick Evans8ff08452019-11-25 09:24:26 +0900508 // TODO(garrick): Remove this test hack.
509 if (pid == kTestPID) {
510 LOG(WARNING) << "Running with test PID";
511 pid_ = pid;
512 return true;
513 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900514 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900515 LOG(ERROR) << "Cannot start service - invalid container PID";
516 return false;
517 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900518 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900519
Garrick Evansbc91a352020-01-16 16:43:26 +0900520 // Start listening for RTNetlink messages to be notified when a virtual ARC
521 // interface is brought up or down.
522 // TODO(garrick): Delete when NDProxy is enabled on all boards.
523 {
524 host_link_listener_ = std::make_unique<shill::RTNLListener>(
525 shill::RTNLHandler::kRequestLink,
526 Bind(&ArcService::ContainerImpl::HostLinkMsgHandler,
527 weak_factory_.GetWeakPtr()));
528 shill::RTNLHandler::GetInstance()->Start(RTMGRP_LINK);
529 }
530
Garrick Evansd90a3822019-11-12 17:53:08 +0900531 // Start listening for RTNetlink messages in the container's net namespace
532 // to be notified whenever it brings up an interface.
533 {
534 ScopedNS ns(pid_);
535 if (ns.IsValid()) {
536 rtnl_handler_ = std::make_unique<RTNetlinkHandler>();
537 rtnl_handler_->Start(RTMGRP_LINK);
538 link_listener_ = std::make_unique<shill::RTNLListener>(
539 shill::RTNLHandler::kRequestLink,
540 Bind(&ArcService::ContainerImpl::LinkMsgHandler,
541 weak_factory_.GetWeakPtr()),
542 rtnl_handler_.get());
543 } else {
544 // This is bad - it means we won't ever be able to tell when the container
545 // brings up an interface.
546 LOG(ERROR)
547 << "Cannot start netlink listener - invalid container namespace?";
548 return false;
549 }
550 }
551
Garrick Evansd90a3822019-11-12 17:53:08 +0900552 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
553 return true;
554}
555
Garrick Evans015b0d62020-02-07 09:06:38 +0900556void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900557 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900558 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900559
Garrick Evansd90a3822019-11-12 17:53:08 +0900560 rtnl_handler_->RemoveListener(link_listener_.get());
561 link_listener_.reset();
562 rtnl_handler_.reset();
563
564 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
565 pid_ = kInvalidPID;
566}
567
Garrick Evans015b0d62020-02-07 09:06:38 +0900568bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900569 if (pid)
570 *pid = pid_;
571
Garrick Evansd90a3822019-11-12 17:53:08 +0900572 return pid_ != kInvalidPID;
573}
574
575bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
576 const auto& config = device->config();
577
578 LOG(INFO) << "Starting device " << device->ifname()
579 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900580 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900581
582 std::string veth_ifname = datapath_->AddVirtualBridgedInterface(
583 device->ifname(), MacAddressToString(config.guest_mac_addr()),
584 config.host_ifname());
585 if (veth_ifname.empty()) {
586 LOG(ERROR) << "Failed to create virtual interface for container";
587 return false;
588 }
589
590 if (!datapath_->AddInterfaceToContainer(
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900591 pid_, veth_ifname, config.guest_ifname(), config.guest_ipv4_addr(),
592 30, device->options().fwd_multicast)) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900593 LOG(ERROR) << "Failed to create container interface.";
594 datapath_->RemoveInterface(veth_ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900595 return false;
596 }
597
Garrick Evans708ec342020-01-21 10:00:29 +0900598 // Setup callback for legacy IPv6 discovery, if applicable.
599 if (device->options().ipv6_enabled &&
600 device->options().find_ipv6_routes_legacy) {
601 device->RegisterIPv6Handlers(
602 base::Bind(&ArcService::ContainerImpl::SetupIPv6,
603 weak_factory_.GetWeakPtr()),
604 base::Bind(&ArcService::ContainerImpl::TeardownIPv6,
605 weak_factory_.GetWeakPtr()));
606 }
607
Garrick Evansd90a3822019-11-12 17:53:08 +0900608 // Signal the container that the network device is ready.
Garrick Evans8ff08452019-11-25 09:24:26 +0900609 if (device->IsAndroid()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900610 datapath_->runner().WriteSentinelToContainer(base::IntToString(pid_));
611 }
Garrick Evans708ec342020-01-21 10:00:29 +0900612
Taoyu Li1c96d272019-12-13 14:17:43 +0900613 dev_mgr_->StartForwarding(*device);
Garrick Evansd90a3822019-11-12 17:53:08 +0900614 return true;
615}
616
617void ArcService::ContainerImpl::OnStopDevice(Device* device) {
618 const auto& config = device->config();
619
620 LOG(INFO) << "Stopping device " << device->ifname()
621 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900622 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900623
Taoyu Lif7e8b572019-12-13 15:22:09 +0900624 device->StopIPv6RoutingLegacy();
Garrick Evansd90a3822019-11-12 17:53:08 +0900625 if (!device->IsAndroid()) {
626 datapath_->RemoveInterface(ArcVethHostName(device->ifname()));
627 }
Garrick Evans708ec342020-01-21 10:00:29 +0900628
629 device->UnregisterIPv6Handlers();
Garrick Evansd90a3822019-11-12 17:53:08 +0900630}
631
632void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
633 const std::string& ifname) {
634 if (!IsStarted())
635 return;
636
637 // For ARC N, we must always be able to find the arc0 device and, at a
638 // minimum, disable it.
Garrick Evansb4eb3892019-11-13 12:07:07 +0900639 if (guest() == GuestMessage::ARC_LEGACY) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900640 datapath_->RemoveLegacyIPv4InboundDNAT();
641 auto* device = dev_mgr_->FindByGuestInterface("arc0");
642 if (!device) {
643 LOG(DFATAL) << "Expected legacy Android device missing";
644 return;
645 }
Taoyu Lif7e8b572019-12-13 15:22:09 +0900646 device->StopIPv6RoutingLegacy();
Garrick Evansd90a3822019-11-12 17:53:08 +0900647
648 // If a new default interface was given, then re-enable with that.
649 if (!ifname.empty()) {
650 datapath_->AddLegacyIPv4InboundDNAT(ifname);
Taoyu Lif7e8b572019-12-13 15:22:09 +0900651 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900652 }
653 return;
654 }
655
656 // For ARC P and later, we're only concerned with resetting the device when it
657 // becomes the default (again) in order to ensure any previous configuration.
658 // is cleared.
659 if (ifname.empty())
660 return;
661
662 auto* device = dev_mgr_->FindByGuestInterface(ifname);
663 if (!device) {
664 LOG(ERROR) << "Expected default device missing: " << ifname;
665 return;
666 }
667 device->StopIPv6RoutingLegacy();
668 device->StartIPv6RoutingLegacy(ifname);
669}
670
671void ArcService::ContainerImpl::LinkMsgHandler(const shill::RTNLMessage& msg) {
672 if (!msg.HasAttribute(IFLA_IFNAME)) {
673 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
674 return;
675 }
676 bool link_up = msg.link_status().flags & IFF_UP;
677 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
678 std::string ifname(reinterpret_cast<const char*>(
679 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
680
681 auto* device = dev_mgr_->FindByGuestInterface(ifname);
682 if (!device)
683 return;
684
Garrick Evansa1134d72019-12-02 14:25:37 +0900685 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900686 if (!ctx) {
687 LOG(DFATAL) << "Context missing";
688 return;
689 }
690
691 // If the link status is unchanged, there is nothing to do.
692 if (!ctx->SetLinkUp(link_up))
693 return;
694
695 if (!link_up) {
696 LOG(INFO) << ifname << " is now down";
697 return;
698 }
699 LOG(INFO) << ifname << " is now up";
700
Garrick Evans8ff08452019-11-25 09:24:26 +0900701 if (device->UsesDefaultInterface()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900702 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
703 return;
704 }
705
Garrick Evans8ff08452019-11-25 09:24:26 +0900706 if (device->IsAndroid())
707 return;
708
Taoyu Lif7e8b572019-12-13 15:22:09 +0900709 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900710}
711
Garrick Evansbc91a352020-01-16 16:43:26 +0900712// TODO(garrick): Remove once NDProxy is enabled on all boards.
713void ArcService::ContainerImpl::HostLinkMsgHandler(
714 const shill::RTNLMessage& msg) {
715 if (!msg.HasAttribute(IFLA_IFNAME)) {
716 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
717 return;
718 }
719
720 // Only consider virtual interfaces that were created for guests; for now this
721 // only includes those prefixed with 'arc'.
722 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
723 std::string ifname(reinterpret_cast<const char*>(
724 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
725 if (!IsArcDevice(ifname))
726 return;
727
728 bool link_up = msg.link_status().flags & IFF_UP;
729 Device* device = dev_mgr_->FindByHostInterface(ifname);
730
731 if (!device || !device->HostLinkUp(link_up))
732 return;
733
734 if (!link_up) {
735 LOG(INFO) << ifname << " is now down";
736 device->StopIPv6RoutingLegacy();
737 return;
738 }
739
740 // The link is now up.
741 LOG(INFO) << ifname << " is now up";
742
743 if (device->UsesDefaultInterface())
744 device->StartIPv6RoutingLegacy(dev_mgr_->DefaultInterface());
745 else if (!device->IsAndroid())
746 device->StartIPv6RoutingLegacy(device->config().guest_ifname());
747}
748
Garrick Evansd90a3822019-11-12 17:53:08 +0900749void ArcService::ContainerImpl::SetupIPv6(Device* device) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900750 auto& ipv6_config = device->ipv6_config();
751 if (ipv6_config.ifname.empty())
752 return;
753
Garrick Evansa1134d72019-12-02 14:25:37 +0900754 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900755 if (!ctx) {
756 LOG(DFATAL) << "Context missing";
757 return;
758 }
759 if (ctx->HasIPv6())
760 return;
761
762 LOG(INFO) << "Setting up IPv6 for " << ipv6_config.ifname;
763
764 int table_id =
765 GetAndroidRoutingTableId(device->config().guest_ifname(), pid_);
766 if (table_id == kInvalidTableID) {
767 if (ctx->RoutingTableAttempts() < kMaxTableRetries) {
768 LOG(INFO) << "Could not look up routing table ID for container interface "
769 << device->config().guest_ifname() << " - trying again...";
770 base::MessageLoop::current()->task_runner()->PostDelayedTask(
771 FROM_HERE,
772 base::Bind(&ArcService::ContainerImpl::SetupIPv6,
773 weak_factory_.GetWeakPtr(), device),
774 kTableRetryDelay);
775 } else {
776 LOG(DFATAL)
777 << "Could not look up routing table ID for container interface "
778 << device->config().guest_ifname();
779 }
780 return;
781 }
782
783 LOG(INFO) << "Setting IPv6 address " << ipv6_config.addr
784 << "/128, gateway=" << ipv6_config.router << " on "
785 << ipv6_config.ifname;
786
787 char buf[INET6_ADDRSTRLEN] = {0};
788 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
789 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
790 return;
791 }
792 std::string addr = buf;
793
794 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
795 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
796 return;
797 }
798 std::string router = buf;
799
800 const auto& config = device->config();
801 {
802 ScopedNS ns(pid_);
803 if (!ns.IsValid()) {
804 LOG(ERROR) << "Invalid container namespace (" << pid_
805 << ") - cannot configure IPv6.";
806 return;
807 }
Taoyu Li90c13912019-11-26 17:56:54 +0900808 // Tag the interface so that ARC can detect this manual configuration and
809 // skip disabling and re-enabling IPv6 (b/144545910).
Garrick Evans664a82f2019-12-17 12:18:05 +0900810 if (!datapath_->MaskInterfaceFlags(config.guest_ifname(), IFF_DEBUG)) {
Taoyu Li90c13912019-11-26 17:56:54 +0900811 LOG(ERROR) << "Failed to mark IPv6 manual config flag on interface";
812 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900813 if (!datapath_->AddIPv6GatewayRoutes(config.guest_ifname(), addr, router,
814 ipv6_config.prefix_len, table_id)) {
815 LOG(ERROR) << "Failed to setup IPv6 routes in the container";
816 return;
817 }
818 }
819
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900820 if (!datapath_->AddIPv6HostRoute(config.host_ifname(), addr, 128)) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900821 LOG(ERROR) << "Failed to setup the IPv6 route for interface "
822 << config.host_ifname();
823 return;
824 }
825
826 if (!datapath_->AddIPv6Neighbor(ipv6_config.ifname, addr)) {
827 LOG(ERROR) << "Failed to setup the IPv6 neighbor proxy";
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900828 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr, 128);
Garrick Evansd90a3822019-11-12 17:53:08 +0900829 return;
830 }
831
Taoyu Li2980ee92019-11-18 17:49:32 +0900832 if (!datapath_->AddIPv6Forwarding(ipv6_config.ifname,
833 device->config().host_ifname())) {
834 LOG(ERROR) << "Failed to setup iptables for IPv6";
835 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900836 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr, 128);
Taoyu Li2980ee92019-11-18 17:49:32 +0900837 return;
838 }
839
Garrick Evansd90a3822019-11-12 17:53:08 +0900840 ctx->SetHasIPv6(table_id);
841}
842
843void ArcService::ContainerImpl::TeardownIPv6(Device* device) {
Garrick Evansa1134d72019-12-02 14:25:37 +0900844 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900845 if (!ctx || !ctx->HasIPv6())
846 return;
847
848 auto& ipv6_config = device->ipv6_config();
849 LOG(INFO) << "Clearing IPv6 for " << ipv6_config.ifname;
850 int table_id = ctx->RoutingTableID();
851 ctx->ClearIPv6();
852
853 char buf[INET6_ADDRSTRLEN] = {0};
854 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
855 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
856 return;
857 }
858 std::string addr = buf;
859
860 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
861 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
862 return;
863 }
864 std::string router = buf;
865
866 const auto& config = device->config();
Taoyu Li2980ee92019-11-18 17:49:32 +0900867 datapath_->RemoveIPv6Forwarding(ipv6_config.ifname, config.host_ifname());
Garrick Evansd90a3822019-11-12 17:53:08 +0900868 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
Taoyu Li1ac4ab82020-01-07 16:37:45 +0900869 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr, 128);
Garrick Evansd90a3822019-11-12 17:53:08 +0900870
871 ScopedNS ns(pid_);
872 if (ns.IsValid()) {
873 datapath_->RemoveIPv6GatewayRoutes(config.guest_ifname(), addr, router,
874 ipv6_config.prefix_len, table_id);
875 }
876}
877
Garrick Evansb4eb3892019-11-13 12:07:07 +0900878// VM specific functions
879
880ArcService::VmImpl::VmImpl(DeviceManagerBase* dev_mgr, Datapath* datapath)
881 : cid_(kInvalidCID), dev_mgr_(dev_mgr), datapath_(datapath) {}
882
883GuestMessage::GuestType ArcService::VmImpl::guest() const {
884 return GuestMessage::ARC_VM;
885}
886
Garrick Evans015b0d62020-02-07 09:06:38 +0900887uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900888 return cid_;
889}
890
Garrick Evans015b0d62020-02-07 09:06:38 +0900891bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900892 // This can happen if concierge crashes and doesn't send the vm down RPC.
893 // It can probably be addressed by stopping and restarting the service.
894 if (cid_ != kInvalidCID)
895 return false;
896
Garrick Evans015b0d62020-02-07 09:06:38 +0900897 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900898 LOG(ERROR) << "Invalid VM cid " << cid;
899 return false;
900 }
901
902 cid_ = cid;
903 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
904
905 return true;
906}
907
Garrick Evans015b0d62020-02-07 09:06:38 +0900908void ArcService::VmImpl::Stop(uint32_t cid) {
Garrick Evans21173b12019-11-20 15:23:16 +0900909 if (cid_ != cid) {
910 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
911 return;
912 }
913
Garrick Evansb4eb3892019-11-13 12:07:07 +0900914 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
915 cid_ = kInvalidCID;
916}
917
Garrick Evans015b0d62020-02-07 09:06:38 +0900918bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900919 if (cid)
920 *cid = cid_;
921
Garrick Evans015b0d62020-02-07 09:06:38 +0900922 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900923}
924
925bool ArcService::VmImpl::OnStartDevice(Device* device) {
926 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900927 // configurations.
928 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900929 return false;
930
931 const auto& config = device->config();
932
933 LOG(INFO) << "Starting device " << device->ifname()
934 << " bridge: " << config.host_ifname()
935 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
936
Garrick Evansa1134d72019-12-02 14:25:37 +0900937 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900938 if (!ctx) {
939 LOG(ERROR) << "Context missing";
940 return false;
941 }
942
943 // Since the interface will be added to the bridge, no address configuration
944 // should be provided here.
945 std::string tap =
946 datapath_->AddTAP("" /* auto-generate name */, nullptr /* no mac addr */,
947 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
948 if (tap.empty()) {
949 LOG(ERROR) << "Failed to create TAP device for VM";
950 return false;
951 }
952
953 if (!datapath_->AddToBridge(config.host_ifname(), tap)) {
954 LOG(ERROR) << "Failed to bridge TAP device " << tap;
955 datapath_->RemoveInterface(tap);
956 return false;
957 }
958
959 ctx->SetTAP(tap);
960 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
961 // configurations; but for now ARCVM needs to be treated like ARC++ N.
962 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
Taoyu Li1c96d272019-12-13 14:17:43 +0900963 dev_mgr_->StartForwarding(*device);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900964 return true;
965}
966
967void ArcService::VmImpl::OnStopDevice(Device* device) {
968 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900969 // configurations.
970 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900971 return;
972
973 const auto& config = device->config();
974
975 LOG(INFO) << "Stopping " << device->ifname()
976 << " bridge: " << config.host_ifname()
977 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
978
Garrick Evansa1134d72019-12-02 14:25:37 +0900979 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900980 if (!ctx) {
981 LOG(ERROR) << "Context missing";
982 return;
983 }
984
Taoyu Lif7e8b572019-12-13 15:22:09 +0900985 device->StopIPv6RoutingLegacy();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900986 datapath_->RemoveInterface(ctx->TAP());
987}
988
989void ArcService::VmImpl::OnDefaultInterfaceChanged(const std::string& ifname) {
990 if (!IsStarted())
991 return;
992
993 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
994 // configurations; but for now ARCVM needs to be treated like ARC++ N.
995 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900996 auto* device = dev_mgr_->FindByGuestInterface("arc1");
Garrick Evansb4eb3892019-11-13 12:07:07 +0900997 if (!device) {
998 LOG(DFATAL) << "Expected Android device missing";
999 return;
1000 }
Taoyu Lif7e8b572019-12-13 15:22:09 +09001001 device->StopIPv6RoutingLegacy();
Garrick Evansb4eb3892019-11-13 12:07:07 +09001002
1003 // If a new default interface was given, then re-enable with that.
1004 if (!ifname.empty()) {
1005 datapath_->AddLegacyIPv4InboundDNAT(ifname);
Taoyu Lif7e8b572019-12-13 15:22:09 +09001006 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansb4eb3892019-11-13 12:07:07 +09001007 }
1008}
1009
Garrick Evans5d55f5e2019-07-17 15:28:10 +09001010} // namespace arc_networkd