blob: c15337a777bc645fc3f88b8870860e1749c539cc [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"
24#include "arc/network/ipc.pb.h"
25#include "arc/network/mac_address_generator.h"
Garrick Evans3915af32019-07-25 15:44:34 +090026#include "arc/network/minijailed_process_runner.h"
Garrick Evans54861622019-07-19 09:05:09 +090027#include "arc/network/net_util.h"
28#include "arc/network/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090029
30namespace arc_networkd {
31namespace {
Garrick Evans54861622019-07-19 09:05:09 +090032constexpr pid_t kInvalidPID = -1;
Garrick Evansb4eb3892019-11-13 12:07:07 +090033constexpr pid_t kTestPID = -2;
34constexpr int32_t kInvalidCID = -1;
Garrick Evans260ff302019-07-25 11:22:50 +090035constexpr int kInvalidTableID = -1;
36constexpr int kMaxTableRetries = 10; // Based on 1 second delay.
37constexpr base::TimeDelta kTableRetryDelay = base::TimeDelta::FromSeconds(1);
38// Android adds a constant to the interface index to derive the table id.
39// This is defined in system/netd/server/RouteController.h
40constexpr int kRouteControllerRouteTableOffsetFromIndex = 1000;
Garrick Evans54861622019-07-19 09:05:09 +090041
42// This wrapper is required since the base class is a singleton that hides its
43// constructor. It is necessary here because the message loop thread has to be
44// reassociated to the container's network namespace; and since the container
45// can be repeatedly created and destroyed, the handler must be as well.
46class RTNetlinkHandler : public shill::RTNLHandler {
47 public:
48 RTNetlinkHandler() = default;
49 ~RTNetlinkHandler() = default;
50
51 private:
52 DISALLOW_COPY_AND_ASSIGN(RTNetlinkHandler);
53};
Garrick Evans5d55f5e2019-07-17 15:28:10 +090054
Garrick Evans260ff302019-07-25 11:22:50 +090055int GetAndroidRoutingTableId(const std::string& ifname, pid_t pid) {
56 base::FilePath ifindex_path(base::StringPrintf(
57 "/proc/%d/root/sys/class/net/%s/ifindex", pid, ifname.c_str()));
58 std::string contents;
59 if (!base::ReadFileToString(ifindex_path, &contents)) {
60 PLOG(WARNING) << "Could not read " << ifindex_path.value();
61 return kInvalidTableID;
62 }
63
64 base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
65 int table_id = kInvalidTableID;
66 if (!base::StringToInt(contents, &table_id)) {
67 LOG(ERROR) << "Could not parse ifindex from " << ifindex_path.value()
68 << ": " << contents;
69 return kInvalidTableID;
70 }
71 table_id += kRouteControllerRouteTableOffsetFromIndex;
72
73 LOG(INFO) << "Found table id " << table_id << " for container interface "
74 << ifname;
75 return table_id;
76}
77
Garrick Evans1f5a3612019-11-08 12:59:03 +090078bool ShouldEnableMultinet() {
79 static const char kLsbReleasePath[] = "/etc/lsb-release";
80 static int kMinAndroidSdkVersion = 28; // P
Garrick Evans1f5a3612019-11-08 12:59:03 +090081
82 brillo::KeyValueStore store;
83 if (!store.Load(base::FilePath(kLsbReleasePath))) {
84 LOG(ERROR) << "Could not read lsb-release";
85 return false;
86 }
87
88 std::string value;
89 if (!store.GetString("CHROMEOS_ARC_ANDROID_SDK_VERSION", &value)) {
90 LOG(ERROR) << "ARC multi-networking disabled - cannot determine Android "
91 "SDK version";
92 return false;
93 }
94 int ver = 0;
95 if (!base::StringToInt(value.c_str(), &ver)) {
96 LOG(ERROR) << "ARC multi-networking disabled - invalid Android SDK version";
97 return false;
98 }
99 if (ver < kMinAndroidSdkVersion) {
100 LOG(INFO) << "ARC multi-networking disabled for Android SDK " << value;
101 return false;
102 }
Garrick Evans1f5a3612019-11-08 12:59:03 +0900103 return true;
104}
105
Garrick Evans6d227b92019-12-03 16:11:29 +0900106void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +0900107 static bool done = false;
108 if (done)
109 return;
110
Garrick Evans6d227b92019-12-03 16:11:29 +0900111 auto& runner = datapath.runner();
112
113 // Load networking modules needed by Android that are not compiled in the
114 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansa34b5862019-11-20 09:34:01 +0900115 // These must succeed.
Garrick Evans6d227b92019-12-03 16:11:29 +0900116 if (runner.ModprobeAll({
Garrick Evansa34b5862019-11-20 09:34:01 +0900117 // The netfilter modules needed by netd for iptables commands.
118 "ip6table_filter",
119 "ip6t_ipv6header",
120 "ip6t_REJECT",
121 // The xfrm modules needed for Android's ipsec APIs.
122 "xfrm4_mode_transport",
123 "xfrm4_mode_tunnel",
124 "xfrm6_mode_transport",
125 "xfrm6_mode_tunnel",
126 // The ipsec modules for AH and ESP encryption for ipv6.
127 "ah6",
128 "esp6",
129 }) != 0) {
130 LOG(ERROR) << "One or more required kernel modules failed to load."
131 << " Some Android functionality may be broken.";
132 }
133 // Optional modules.
Garrick Evans6d227b92019-12-03 16:11:29 +0900134 if (runner.ModprobeAll({
Garrick Evansa34b5862019-11-20 09:34:01 +0900135 // This module is not available in kernels < 3.18
136 "nf_reject_ipv6",
137 // These modules are needed for supporting Chrome traffic on Android
138 // VPN which uses Android's NAT feature. Android NAT sets up
139 // iptables
140 // rules that use these conntrack modules for FTP/TFTP.
141 "nf_nat_ftp",
142 "nf_nat_tftp",
143 }) != 0) {
144 LOG(WARNING) << "One or more optional kernel modules failed to load.";
145 }
146
Garrick Evans6d227b92019-12-03 16:11:29 +0900147 // Enable IPv6 packet forarding and neighbor discovery.
148 if (runner.SysctlWrite("net.ipv6.conf.all.forwarding", "1") != 0 ||
149 runner.SysctlWrite("net.ipv6.conf.all.proxy_ndp", "1") != 0) {
150 LOG(ERROR) << "Failed to update kernel parameters. IPv6 routing and/or"
151 << " neighbor discovery may be broken.";
152 }
153
154 // This is only needed for CTS (b/27932574).
155 if (runner.Chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
156 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
157 }
158
Garrick Evansa34b5862019-11-20 09:34:01 +0900159 done = true;
160}
161
Garrick Evans508a4bc2019-11-14 08:45:52 +0900162bool IsArcVm() {
163 const base::FilePath path("/run/chrome/is_arcvm");
164 std::string contents;
165 if (!base::ReadFileToString(path, &contents)) {
166 PLOG(ERROR) << "Could not read " << path.value();
167 }
168 return contents == "1";
169}
170
171GuestMessage::GuestType ArcGuest(bool* is_legacy_override_for_testing) {
172 if (is_legacy_override_for_testing)
173 return *is_legacy_override_for_testing ? GuestMessage::ARC_LEGACY
174 : GuestMessage::ARC;
175
176 return IsArcVm() ? GuestMessage::ARC_VM
177 : ShouldEnableMultinet() ? GuestMessage::ARC
178 : GuestMessage::ARC_LEGACY;
179}
180
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900181} // namespace
182
Garrick Evans54861622019-07-19 09:05:09 +0900183ArcService::ArcService(DeviceManagerBase* dev_mgr,
Taoyu Li179dcc62019-10-17 11:21:08 +0900184 Datapath* datapath,
Garrick Evans1f5a3612019-11-08 12:59:03 +0900185 bool* is_legacy)
Garrick Evans508a4bc2019-11-14 08:45:52 +0900186 : GuestService(ArcGuest(is_legacy), dev_mgr), datapath_(datapath) {
Taoyu Li179dcc62019-10-17 11:21:08 +0900187 DCHECK(datapath_);
Garrick Evans3915af32019-07-25 15:44:34 +0900188
Garrick Evans508a4bc2019-11-14 08:45:52 +0900189 if (guest_ == GuestMessage::ARC_VM)
190 impl_ = std::make_unique<VmImpl>(dev_mgr, datapath);
191 else
192 impl_ = std::make_unique<ContainerImpl>(dev_mgr, datapath, guest_);
Garrick Evans54861622019-07-19 09:05:09 +0900193}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900194
Garrick Evans508a4bc2019-11-14 08:45:52 +0900195bool ArcService::Start(int32_t id) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900196 int32_t prev_id;
197 if (impl_->IsStarted(&prev_id)) {
198 LOG(WARNING) << "Already running - did something crash?"
199 << " Stopping and restarting...";
200 Stop(prev_id);
201 }
202
Garrick Evans508a4bc2019-11-14 08:45:52 +0900203 if (!impl_->Start(id))
204 return false;
Garrick Evanscb791e72019-11-11 15:44:34 +0900205
206 // Start known host devices, any new ones will be setup in the process.
207 dev_mgr_->ProcessDevices(
208 base::Bind(&ArcService::StartDevice, weak_factory_.GetWeakPtr()));
209
210 // If this is the first time the service is starting this will create the
211 // Android bridge device; otherwise it does nothing (this is a workaround for
212 // the bug in Shill that casues a Bus crash when it sees the ARC bridge a
213 // second time). Do this after processing the existing devices so it doesn't
214 // get started twice.
Garrick Evanscfd42822019-11-15 12:38:23 +0900215 std::string arc;
216 switch (const auto guest = impl_->guest()) {
217 case GuestMessage::ARC:
218 arc = kAndroidDevice;
219 break;
220 case GuestMessage::ARC_LEGACY:
221 arc = kAndroidLegacyDevice;
222 break;
223 case GuestMessage::ARC_VM:
224 arc = kAndroidVmDevice;
225 break;
226 default:
227 LOG(DFATAL) << "Unexpected guest: " << guest;
Garrick Evans21173b12019-11-20 15:23:16 +0900228 return false;
Garrick Evanscfd42822019-11-15 12:38:23 +0900229 }
230 dev_mgr_->Add(arc);
Garrick Evanscb791e72019-11-11 15:44:34 +0900231
232 // Finally, call the base implementation.
Garrick Evans21173b12019-11-20 15:23:16 +0900233 return GuestService::Start(id);
Garrick Evanscb791e72019-11-11 15:44:34 +0900234}
235
Garrick Evans21173b12019-11-20 15:23:16 +0900236void ArcService::Stop(int32_t id) {
Garrick Evans54861622019-07-19 09:05:09 +0900237 // Call the base implementation.
Garrick Evans21173b12019-11-20 15:23:16 +0900238 GuestService::Stop(id);
Garrick Evans54861622019-07-19 09:05:09 +0900239
240 // Stop known host devices. Note that this does not teardown any existing
241 // devices.
242 dev_mgr_->ProcessDevices(
243 base::Bind(&ArcService::StopDevice, weak_factory_.GetWeakPtr()));
Garrick Evans21173b12019-11-20 15:23:16 +0900244
245 impl_->Stop(id);
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900246}
247
Garrick Evans8ff08452019-11-25 09:24:26 +0900248bool ArcService::AllowDevice(Device* device) const {
Garrick Evansa1134d72019-12-02 14:25:37 +0900249 if (!device->IsArc())
Garrick Evans0001d012019-11-22 10:06:10 +0900250 return false;
251
Garrick Evans8ff08452019-11-25 09:24:26 +0900252 // ARC P+ is multi-network enabled and should process all devices.
253 if (guest_ == GuestMessage::ARC)
254 return true;
255
256 // ARC N and ARCVM (for now) are both single-network - meaning they only use
257 // the "default" device which uses the default interface from shill.
258 return device->UsesDefaultInterface();
259}
260
Garrick Evans54861622019-07-19 09:05:09 +0900261void ArcService::OnDeviceAdded(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900262 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900263 return;
Garrick Evansba575742019-07-17 15:48:08 +0900264
Garrick Evans54861622019-07-19 09:05:09 +0900265 const auto& config = device->config();
266
267 LOG(INFO) << "Adding device " << device->ifname()
268 << " bridge: " << config.host_ifname()
Garrick Evans310ab552019-10-08 11:07:53 +0900269 << " guest_iface: " << config.guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900270
271 // Create the bridge.
272 if (!datapath_->AddBridge(config.host_ifname(),
273 IPv4AddressToString(config.host_ipv4_addr()))) {
274 LOG(ERROR) << "Failed to setup arc bridge: " << config.host_ifname();
275 return;
276 }
277
278 // Setup the iptables.
Garrick Evans8ff08452019-11-25 09:24:26 +0900279 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900280 if (!datapath_->AddLegacyIPv4DNAT(
281 IPv4AddressToString(config.guest_ipv4_addr())))
282 LOG(ERROR) << "Failed to configure ARC traffic rules";
283
284 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
285 LOG(ERROR) << "Failed to configure egress traffic rules";
286 } else if (!device->IsAndroid()) {
287 if (!datapath_->AddInboundIPv4DNAT(
288 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
289 LOG(ERROR) << "Failed to configure ingress traffic rules for "
290 << device->ifname();
291
292 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
293 LOG(ERROR) << "Failed to configure egress traffic rules";
294 }
295
Garrick Evansa1134d72019-12-02 14:25:37 +0900296 device->set_context(std::make_unique<Context>());
Garrick Evans54861622019-07-19 09:05:09 +0900297
298 StartDevice(device);
299}
300
301void ArcService::StartDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900302 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900303 return;
304
Garrick Evans310ab552019-10-08 11:07:53 +0900305 // This can happen if OnDeviceAdded is invoked when the container is down.
Garrick Evansd90a3822019-11-12 17:53:08 +0900306 if (!impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900307 return;
308
Garrick Evans2c263102019-07-26 16:07:18 +0900309 // If there is no context, then this is a new device and it needs to run
310 // through the full setup process.
Garrick Evansa1134d72019-12-02 14:25:37 +0900311 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900312 if (!ctx)
Garrick Evans54861622019-07-19 09:05:09 +0900313 return OnDeviceAdded(device);
314
Garrick Evans2c263102019-07-26 16:07:18 +0900315 if (ctx->IsStarted()) {
316 LOG(ERROR) << "Attempt to restart device " << device->ifname();
317 return;
318 }
319
Garrick Evansd90a3822019-11-12 17:53:08 +0900320 if (!impl_->OnStartDevice(device)) {
Garrick Evanscb791e72019-11-11 15:44:34 +0900321 LOG(ERROR) << "Failed to start device " << device->ifname();
322 return;
323 }
324
Garrick Evansb4eb3892019-11-13 12:07:07 +0900325 ctx->Start();
Garrick Evans54861622019-07-19 09:05:09 +0900326}
327
328void ArcService::OnDeviceRemoved(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900329 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900330 return;
331
Garrick Evans310ab552019-10-08 11:07:53 +0900332 // If the container is down, this call does nothing.
Garrick Evans54861622019-07-19 09:05:09 +0900333 StopDevice(device);
334
335 const auto& config = device->config();
336
337 LOG(INFO) << "Removing device " << device->ifname()
338 << " bridge: " << config.host_ifname()
339 << " guest_iface: " << config.guest_ifname();
340
Garrick Evans260ff302019-07-25 11:22:50 +0900341 device->Disable();
Garrick Evans8ff08452019-11-25 09:24:26 +0900342 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900343 datapath_->RemoveOutboundIPv4(config.host_ifname());
344 datapath_->RemoveLegacyIPv4DNAT();
345 } else if (!device->IsAndroid()) {
346 datapath_->RemoveOutboundIPv4(config.host_ifname());
347 datapath_->RemoveInboundIPv4DNAT(
348 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
349 }
350
351 datapath_->RemoveBridge(config.host_ifname());
352
Garrick Evansa1134d72019-12-02 14:25:37 +0900353 device->set_context(nullptr);
Garrick Evans54861622019-07-19 09:05:09 +0900354}
355
356void ArcService::StopDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900357 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900358 return;
359
Garrick Evans310ab552019-10-08 11:07:53 +0900360 // This can happen if the device if OnDeviceRemoved is invoked when the
361 // container is down.
Garrick Evansd90a3822019-11-12 17:53:08 +0900362 if (!impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900363 return;
364
Garrick Evansa1134d72019-12-02 14:25:37 +0900365 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900366 if (!ctx) {
367 LOG(ERROR) << "Attempt to stop removed device " << device->ifname();
368 return;
369 }
370
371 if (!ctx->IsStarted()) {
372 LOG(ERROR) << "Attempt to re-stop device " << device->ifname();
373 return;
374 }
375
Garrick Evansd90a3822019-11-12 17:53:08 +0900376 impl_->OnStopDevice(device);
Garrick Evanscb791e72019-11-11 15:44:34 +0900377
378 ctx->Stop();
379}
380
Garrick Evans54861622019-07-19 09:05:09 +0900381void ArcService::OnDefaultInterfaceChanged(const std::string& ifname) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900382 impl_->OnDefaultInterfaceChanged(ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900383}
Garrick Evansba575742019-07-17 15:48:08 +0900384
Garrick Evans2c263102019-07-26 16:07:18 +0900385// Context
386
387ArcService::Context::Context() : Device::Context() {
388 Stop();
389}
390
391void ArcService::Context::Start() {
392 Stop();
393 started_ = true;
394}
395
396void ArcService::Context::Stop() {
397 started_ = false;
398 link_up_ = false;
399 routing_table_id_ = kInvalidTableID;
400 routing_table_attempts_ = 0;
401}
402
403bool ArcService::Context::IsStarted() const {
404 return started_;
405}
406
407bool ArcService::Context::IsLinkUp() const {
408 return link_up_;
409}
410
411bool ArcService::Context::SetLinkUp(bool link_up) {
412 if (link_up == link_up_)
413 return false;
414
415 link_up_ = link_up;
416 return true;
417}
418
419bool ArcService::Context::HasIPv6() const {
420 return routing_table_id_ != kInvalidTableID;
421}
422
423bool ArcService::Context::SetHasIPv6(int routing_table_id) {
424 if (routing_table_id <= kRouteControllerRouteTableOffsetFromIndex)
425 return false;
426
427 routing_table_id_ = routing_table_id;
428 return true;
429}
430
Garrick Evansdc3fc452019-09-06 14:15:04 +0900431void ArcService::Context::ClearIPv6() {
432 routing_table_id_ = kInvalidTableID;
433 routing_table_attempts_ = 0;
434}
435
Garrick Evans2c263102019-07-26 16:07:18 +0900436int ArcService::Context::RoutingTableID() const {
437 return routing_table_id_;
438}
439
440int ArcService::Context::RoutingTableAttempts() {
441 return routing_table_attempts_++;
442}
443
Garrick Evansb4eb3892019-11-13 12:07:07 +0900444const std::string& ArcService::Context::TAP() const {
445 return tap_;
446}
447
448void ArcService::Context::SetTAP(const std::string& tap) {
449 tap_ = tap;
450}
451
Garrick Evansd90a3822019-11-12 17:53:08 +0900452// ARC++ specific functions.
453
454ArcService::ContainerImpl::ContainerImpl(DeviceManagerBase* dev_mgr,
455 Datapath* datapath,
456 GuestMessage::GuestType guest)
Garrick Evansa34b5862019-11-20 09:34:01 +0900457 : pid_(kInvalidPID), dev_mgr_(dev_mgr), datapath_(datapath), guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900458 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900459}
Garrick Evansd90a3822019-11-12 17:53:08 +0900460
Garrick Evansb4eb3892019-11-13 12:07:07 +0900461GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
462 return guest_;
463}
464
Garrick Evans508a4bc2019-11-14 08:45:52 +0900465bool ArcService::ContainerImpl::Start(int32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900466 // This could happen if something crashes and the stop signal is not sent.
467 // It can probably be addressed by stopping and restarting the service.
468 if (pid_ != kInvalidPID)
469 return false;
470
Garrick Evans8ff08452019-11-25 09:24:26 +0900471 // TODO(garrick): Remove this test hack.
472 if (pid == kTestPID) {
473 LOG(WARNING) << "Running with test PID";
474 pid_ = pid;
475 return true;
476 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900477 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900478 LOG(ERROR) << "Cannot start service - invalid container PID";
479 return false;
480 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900481 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900482
483 // Start listening for RTNetlink messages in the container's net namespace
484 // to be notified whenever it brings up an interface.
485 {
486 ScopedNS ns(pid_);
487 if (ns.IsValid()) {
488 rtnl_handler_ = std::make_unique<RTNetlinkHandler>();
489 rtnl_handler_->Start(RTMGRP_LINK);
490 link_listener_ = std::make_unique<shill::RTNLListener>(
491 shill::RTNLHandler::kRequestLink,
492 Bind(&ArcService::ContainerImpl::LinkMsgHandler,
493 weak_factory_.GetWeakPtr()),
494 rtnl_handler_.get());
495 } else {
496 // This is bad - it means we won't ever be able to tell when the container
497 // brings up an interface.
498 LOG(ERROR)
499 << "Cannot start netlink listener - invalid container namespace?";
500 return false;
501 }
502 }
503
504 dev_mgr_->RegisterDeviceIPv6AddressFoundHandler(
Garrick Evansb4eb3892019-11-13 12:07:07 +0900505 guest(), base::Bind(&ArcService::ContainerImpl::SetupIPv6,
506 weak_factory_.GetWeakPtr()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900507
508 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
509 return true;
510}
511
Garrick Evans21173b12019-11-20 15:23:16 +0900512void ArcService::ContainerImpl::Stop(int32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900513 if (!IsStarted())
514 return;
515
Garrick Evansd90a3822019-11-12 17:53:08 +0900516 rtnl_handler_->RemoveListener(link_listener_.get());
517 link_listener_.reset();
518 rtnl_handler_.reset();
519
520 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
521 pid_ = kInvalidPID;
522}
523
Garrick Evansa51d0a12019-11-28 13:51:23 +0900524bool ArcService::ContainerImpl::IsStarted(int32_t* pid) const {
525 if (pid)
526 *pid = pid_;
527
Garrick Evansd90a3822019-11-12 17:53:08 +0900528 return pid_ != kInvalidPID;
529}
530
531bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
532 const auto& config = device->config();
533
534 LOG(INFO) << "Starting device " << device->ifname()
535 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900536 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900537
538 std::string veth_ifname = datapath_->AddVirtualBridgedInterface(
539 device->ifname(), MacAddressToString(config.guest_mac_addr()),
540 config.host_ifname());
541 if (veth_ifname.empty()) {
542 LOG(ERROR) << "Failed to create virtual interface for container";
543 return false;
544 }
545
546 if (!datapath_->AddInterfaceToContainer(
547 pid_, veth_ifname, config.guest_ifname(),
548 IPv4AddressToString(config.guest_ipv4_addr()),
549 device->options().fwd_multicast)) {
550 LOG(ERROR) << "Failed to create container interface.";
551 datapath_->RemoveInterface(veth_ifname);
552 datapath_->RemoveBridge(config.host_ifname());
553 return false;
554 }
555
556 // Signal the container that the network device is ready.
Garrick Evans8ff08452019-11-25 09:24:26 +0900557 if (device->IsAndroid()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900558 datapath_->runner().WriteSentinelToContainer(base::IntToString(pid_));
559 }
560
561 return true;
562}
563
564void ArcService::ContainerImpl::OnStopDevice(Device* device) {
565 const auto& config = device->config();
566
567 LOG(INFO) << "Stopping device " << device->ifname()
568 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900569 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900570
571 device->Disable();
572 if (!device->IsAndroid()) {
573 datapath_->RemoveInterface(ArcVethHostName(device->ifname()));
574 }
575}
576
577void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
578 const std::string& ifname) {
579 if (!IsStarted())
580 return;
581
582 // For ARC N, we must always be able to find the arc0 device and, at a
583 // minimum, disable it.
Garrick Evansb4eb3892019-11-13 12:07:07 +0900584 if (guest() == GuestMessage::ARC_LEGACY) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900585 datapath_->RemoveLegacyIPv4InboundDNAT();
586 auto* device = dev_mgr_->FindByGuestInterface("arc0");
587 if (!device) {
588 LOG(DFATAL) << "Expected legacy Android device missing";
589 return;
590 }
591 device->Disable();
592
593 // If a new default interface was given, then re-enable with that.
594 if (!ifname.empty()) {
595 datapath_->AddLegacyIPv4InboundDNAT(ifname);
596 device->Enable(ifname);
597 }
598 return;
599 }
600
601 // For ARC P and later, we're only concerned with resetting the device when it
602 // becomes the default (again) in order to ensure any previous configuration.
603 // is cleared.
604 if (ifname.empty())
605 return;
606
607 auto* device = dev_mgr_->FindByGuestInterface(ifname);
608 if (!device) {
609 LOG(ERROR) << "Expected default device missing: " << ifname;
610 return;
611 }
612 device->StopIPv6RoutingLegacy();
613 device->StartIPv6RoutingLegacy(ifname);
614}
615
616void ArcService::ContainerImpl::LinkMsgHandler(const shill::RTNLMessage& msg) {
617 if (!msg.HasAttribute(IFLA_IFNAME)) {
618 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
619 return;
620 }
621 bool link_up = msg.link_status().flags & IFF_UP;
622 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
623 std::string ifname(reinterpret_cast<const char*>(
624 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
625
626 auto* device = dev_mgr_->FindByGuestInterface(ifname);
627 if (!device)
628 return;
629
Garrick Evansa1134d72019-12-02 14:25:37 +0900630 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900631 if (!ctx) {
632 LOG(DFATAL) << "Context missing";
633 return;
634 }
635
636 // If the link status is unchanged, there is nothing to do.
637 if (!ctx->SetLinkUp(link_up))
638 return;
639
640 if (!link_up) {
641 LOG(INFO) << ifname << " is now down";
642 return;
643 }
644 LOG(INFO) << ifname << " is now up";
645
Garrick Evans8ff08452019-11-25 09:24:26 +0900646 if (device->UsesDefaultInterface()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900647 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
648 return;
649 }
650
Garrick Evans8ff08452019-11-25 09:24:26 +0900651 if (device->IsAndroid())
652 return;
653
Garrick Evansd90a3822019-11-12 17:53:08 +0900654 device->Enable(ifname);
655}
656
657void ArcService::ContainerImpl::SetupIPv6(Device* device) {
658 device->RegisterIPv6TeardownHandler(base::Bind(
659 &ArcService::ContainerImpl::TeardownIPv6, weak_factory_.GetWeakPtr()));
660
661 auto& ipv6_config = device->ipv6_config();
662 if (ipv6_config.ifname.empty())
663 return;
664
Garrick Evansa1134d72019-12-02 14:25:37 +0900665 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900666 if (!ctx) {
667 LOG(DFATAL) << "Context missing";
668 return;
669 }
670 if (ctx->HasIPv6())
671 return;
672
673 LOG(INFO) << "Setting up IPv6 for " << ipv6_config.ifname;
674
675 int table_id =
676 GetAndroidRoutingTableId(device->config().guest_ifname(), pid_);
677 if (table_id == kInvalidTableID) {
678 if (ctx->RoutingTableAttempts() < kMaxTableRetries) {
679 LOG(INFO) << "Could not look up routing table ID for container interface "
680 << device->config().guest_ifname() << " - trying again...";
681 base::MessageLoop::current()->task_runner()->PostDelayedTask(
682 FROM_HERE,
683 base::Bind(&ArcService::ContainerImpl::SetupIPv6,
684 weak_factory_.GetWeakPtr(), device),
685 kTableRetryDelay);
686 } else {
687 LOG(DFATAL)
688 << "Could not look up routing table ID for container interface "
689 << device->config().guest_ifname();
690 }
691 return;
692 }
693
694 LOG(INFO) << "Setting IPv6 address " << ipv6_config.addr
695 << "/128, gateway=" << ipv6_config.router << " on "
696 << ipv6_config.ifname;
697
698 char buf[INET6_ADDRSTRLEN] = {0};
699 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
700 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
701 return;
702 }
703 std::string addr = buf;
704
705 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
706 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
707 return;
708 }
709 std::string router = buf;
710
711 const auto& config = device->config();
712 {
713 ScopedNS ns(pid_);
714 if (!ns.IsValid()) {
715 LOG(ERROR) << "Invalid container namespace (" << pid_
716 << ") - cannot configure IPv6.";
717 return;
718 }
Taoyu Li90c13912019-11-26 17:56:54 +0900719 // Tag the interface so that ARC can detect this manual configuration and
720 // skip disabling and re-enabling IPv6 (b/144545910).
721 if (!datapath_->SetInterfaceFlag(config.guest_ifname(), IFF_DEBUG)) {
722 LOG(ERROR) << "Failed to mark IPv6 manual config flag on interface";
723 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900724 if (!datapath_->AddIPv6GatewayRoutes(config.guest_ifname(), addr, router,
725 ipv6_config.prefix_len, table_id)) {
726 LOG(ERROR) << "Failed to setup IPv6 routes in the container";
727 return;
728 }
729 }
730
731 if (!datapath_->AddIPv6HostRoute(config.host_ifname(), addr,
732 ipv6_config.prefix_len)) {
733 LOG(ERROR) << "Failed to setup the IPv6 route for interface "
734 << config.host_ifname();
735 return;
736 }
737
738 if (!datapath_->AddIPv6Neighbor(ipv6_config.ifname, addr)) {
739 LOG(ERROR) << "Failed to setup the IPv6 neighbor proxy";
740 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
741 ipv6_config.prefix_len);
742 return;
743 }
744
Taoyu Li2980ee92019-11-18 17:49:32 +0900745 if (!datapath_->AddIPv6Forwarding(ipv6_config.ifname,
746 device->config().host_ifname())) {
747 LOG(ERROR) << "Failed to setup iptables for IPv6";
748 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
749 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
750 ipv6_config.prefix_len);
751 return;
752 }
753
Garrick Evansd90a3822019-11-12 17:53:08 +0900754 ctx->SetHasIPv6(table_id);
755}
756
757void ArcService::ContainerImpl::TeardownIPv6(Device* device) {
Garrick Evansa1134d72019-12-02 14:25:37 +0900758 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900759 if (!ctx || !ctx->HasIPv6())
760 return;
761
762 auto& ipv6_config = device->ipv6_config();
763 LOG(INFO) << "Clearing IPv6 for " << ipv6_config.ifname;
764 int table_id = ctx->RoutingTableID();
765 ctx->ClearIPv6();
766
767 char buf[INET6_ADDRSTRLEN] = {0};
768 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
769 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
770 return;
771 }
772 std::string addr = buf;
773
774 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
775 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
776 return;
777 }
778 std::string router = buf;
779
780 const auto& config = device->config();
Taoyu Li2980ee92019-11-18 17:49:32 +0900781 datapath_->RemoveIPv6Forwarding(ipv6_config.ifname, config.host_ifname());
Garrick Evansd90a3822019-11-12 17:53:08 +0900782 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
783 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
784 ipv6_config.prefix_len);
785
786 ScopedNS ns(pid_);
787 if (ns.IsValid()) {
788 datapath_->RemoveIPv6GatewayRoutes(config.guest_ifname(), addr, router,
789 ipv6_config.prefix_len, table_id);
790 }
791}
792
Garrick Evansb4eb3892019-11-13 12:07:07 +0900793// VM specific functions
794
795ArcService::VmImpl::VmImpl(DeviceManagerBase* dev_mgr, Datapath* datapath)
796 : cid_(kInvalidCID), dev_mgr_(dev_mgr), datapath_(datapath) {}
797
798GuestMessage::GuestType ArcService::VmImpl::guest() const {
799 return GuestMessage::ARC_VM;
800}
801
Garrick Evans508a4bc2019-11-14 08:45:52 +0900802bool ArcService::VmImpl::Start(int32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900803 // This can happen if concierge crashes and doesn't send the vm down RPC.
804 // It can probably be addressed by stopping and restarting the service.
805 if (cid_ != kInvalidCID)
806 return false;
807
Garrick Evansb4eb3892019-11-13 12:07:07 +0900808 if (cid <= kInvalidCID) {
809 LOG(ERROR) << "Invalid VM cid " << cid;
810 return false;
811 }
812
813 cid_ = cid;
814 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
815
816 return true;
817}
818
Garrick Evans21173b12019-11-20 15:23:16 +0900819void ArcService::VmImpl::Stop(int32_t cid) {
820 if (cid_ != cid) {
821 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
822 return;
823 }
824
Garrick Evansb4eb3892019-11-13 12:07:07 +0900825 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
826 cid_ = kInvalidCID;
827}
828
Garrick Evansa51d0a12019-11-28 13:51:23 +0900829bool ArcService::VmImpl::IsStarted(int32_t* cid) const {
830 if (cid)
831 *cid = cid_;
832
Garrick Evansb4eb3892019-11-13 12:07:07 +0900833 return cid_ > kInvalidCID;
834}
835
836bool ArcService::VmImpl::OnStartDevice(Device* device) {
837 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900838 // configurations.
839 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900840 return false;
841
842 const auto& config = device->config();
843
844 LOG(INFO) << "Starting device " << device->ifname()
845 << " bridge: " << config.host_ifname()
846 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
847
Garrick Evansa1134d72019-12-02 14:25:37 +0900848 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900849 if (!ctx) {
850 LOG(ERROR) << "Context missing";
851 return false;
852 }
853
854 // Since the interface will be added to the bridge, no address configuration
855 // should be provided here.
856 std::string tap =
857 datapath_->AddTAP("" /* auto-generate name */, nullptr /* no mac addr */,
858 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
859 if (tap.empty()) {
860 LOG(ERROR) << "Failed to create TAP device for VM";
861 return false;
862 }
863
864 if (!datapath_->AddToBridge(config.host_ifname(), tap)) {
865 LOG(ERROR) << "Failed to bridge TAP device " << tap;
866 datapath_->RemoveInterface(tap);
867 return false;
868 }
869
870 ctx->SetTAP(tap);
871 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
872 // configurations; but for now ARCVM needs to be treated like ARC++ N.
873 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
874 return true;
875}
876
877void ArcService::VmImpl::OnStopDevice(Device* device) {
878 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900879 // configurations.
880 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900881 return;
882
883 const auto& config = device->config();
884
885 LOG(INFO) << "Stopping " << device->ifname()
886 << " bridge: " << config.host_ifname()
887 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
888
Garrick Evansa1134d72019-12-02 14:25:37 +0900889 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900890 if (!ctx) {
891 LOG(ERROR) << "Context missing";
892 return;
893 }
894
895 device->Disable();
896 datapath_->RemoveInterface(ctx->TAP());
897}
898
899void ArcService::VmImpl::OnDefaultInterfaceChanged(const std::string& ifname) {
900 if (!IsStarted())
901 return;
902
903 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
904 // configurations; but for now ARCVM needs to be treated like ARC++ N.
905 datapath_->RemoveLegacyIPv4InboundDNAT();
906 auto* device = dev_mgr_->FindByGuestInterface("arc0");
907 if (!device) {
908 LOG(DFATAL) << "Expected Android device missing";
909 return;
910 }
911 device->Disable();
912
913 // If a new default interface was given, then re-enable with that.
914 if (!ifname.empty()) {
915 datapath_->AddLegacyIPv4InboundDNAT(ifname);
916 device->Enable(ifname);
917 }
918}
919
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900920} // namespace arc_networkd