blob: 0db3c5a3681cd1f8c63a31d6fdf777b34936c09e [file] [log] [blame]
Garrick Evans5d55f5e2019-07-17 15:28:10 +09001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "arc/network/arc_service.h"
6
Garrick Evans54861622019-07-19 09:05:09 +09007#include <linux/rtnetlink.h>
8#include <net/if.h>
9
Garrick Evans5d55f5e2019-07-17 15:28:10 +090010#include <utility>
11
Garrick Evans54861622019-07-19 09:05:09 +090012#include <base/bind.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090013#include <base/files/file_path.h>
14#include <base/files/file_util.h>
15#include <base/logging.h>
16#include <base/strings/string_number_conversions.h>
17#include <base/strings/string_util.h>
Garrick Evans54861622019-07-19 09:05:09 +090018#include <base/strings/stringprintf.h>
Garrick Evans1f5a3612019-11-08 12:59:03 +090019#include <brillo/key_value_store.h>
Garrick Evansb4eb3892019-11-13 12:07:07 +090020#include <chromeos/constants/vm_tools.h>
Garrick Evans54861622019-07-19 09:05:09 +090021#include <shill/net/rtnl_message.h>
22
23#include "arc/network/datapath.h"
Garrick Evans54861622019-07-19 09:05:09 +090024#include "arc/network/mac_address_generator.h"
Garrick Evans3915af32019-07-25 15:44:34 +090025#include "arc/network/minijailed_process_runner.h"
Garrick Evans54861622019-07-19 09:05:09 +090026#include "arc/network/net_util.h"
27#include "arc/network/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090028
29namespace arc_networkd {
Garrick Evansf29f5a32019-12-06 11:34:25 +090030
31namespace test {
32GuestMessage::GuestType guest = GuestMessage::UNKNOWN_GUEST;
33} // namespace test
34
Garrick Evans5d55f5e2019-07-17 15:28:10 +090035namespace {
Garrick Evans54861622019-07-19 09:05:09 +090036constexpr pid_t kInvalidPID = -1;
Garrick Evansb4eb3892019-11-13 12:07:07 +090037constexpr pid_t kTestPID = -2;
38constexpr int32_t kInvalidCID = -1;
Garrick Evans260ff302019-07-25 11:22:50 +090039constexpr int kInvalidTableID = -1;
40constexpr int kMaxTableRetries = 10; // Based on 1 second delay.
41constexpr base::TimeDelta kTableRetryDelay = base::TimeDelta::FromSeconds(1);
42// Android adds a constant to the interface index to derive the table id.
43// This is defined in system/netd/server/RouteController.h
44constexpr int kRouteControllerRouteTableOffsetFromIndex = 1000;
Garrick Evans54861622019-07-19 09:05:09 +090045
46// This wrapper is required since the base class is a singleton that hides its
47// constructor. It is necessary here because the message loop thread has to be
48// reassociated to the container's network namespace; and since the container
49// can be repeatedly created and destroyed, the handler must be as well.
50class RTNetlinkHandler : public shill::RTNLHandler {
51 public:
52 RTNetlinkHandler() = default;
53 ~RTNetlinkHandler() = default;
54
55 private:
56 DISALLOW_COPY_AND_ASSIGN(RTNetlinkHandler);
57};
Garrick Evans5d55f5e2019-07-17 15:28:10 +090058
Garrick Evans260ff302019-07-25 11:22:50 +090059int GetAndroidRoutingTableId(const std::string& ifname, pid_t pid) {
60 base::FilePath ifindex_path(base::StringPrintf(
61 "/proc/%d/root/sys/class/net/%s/ifindex", pid, ifname.c_str()));
62 std::string contents;
63 if (!base::ReadFileToString(ifindex_path, &contents)) {
64 PLOG(WARNING) << "Could not read " << ifindex_path.value();
65 return kInvalidTableID;
66 }
67
68 base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
69 int table_id = kInvalidTableID;
70 if (!base::StringToInt(contents, &table_id)) {
71 LOG(ERROR) << "Could not parse ifindex from " << ifindex_path.value()
72 << ": " << contents;
73 return kInvalidTableID;
74 }
75 table_id += kRouteControllerRouteTableOffsetFromIndex;
76
77 LOG(INFO) << "Found table id " << table_id << " for container interface "
78 << ifname;
79 return table_id;
80}
81
Garrick Evans1f5a3612019-11-08 12:59:03 +090082bool ShouldEnableMultinet() {
83 static const char kLsbReleasePath[] = "/etc/lsb-release";
84 static int kMinAndroidSdkVersion = 28; // P
Garrick Evans1f5a3612019-11-08 12:59:03 +090085
86 brillo::KeyValueStore store;
87 if (!store.Load(base::FilePath(kLsbReleasePath))) {
88 LOG(ERROR) << "Could not read lsb-release";
89 return false;
90 }
91
92 std::string value;
93 if (!store.GetString("CHROMEOS_ARC_ANDROID_SDK_VERSION", &value)) {
94 LOG(ERROR) << "ARC multi-networking disabled - cannot determine Android "
95 "SDK version";
96 return false;
97 }
98 int ver = 0;
99 if (!base::StringToInt(value.c_str(), &ver)) {
100 LOG(ERROR) << "ARC multi-networking disabled - invalid Android SDK version";
101 return false;
102 }
103 if (ver < kMinAndroidSdkVersion) {
104 LOG(INFO) << "ARC multi-networking disabled for Android SDK " << value;
105 return false;
106 }
Garrick Evans1f5a3612019-11-08 12:59:03 +0900107 return true;
108}
109
Garrick Evans6d227b92019-12-03 16:11:29 +0900110void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +0900111 static bool done = false;
112 if (done)
113 return;
114
Garrick Evans6d227b92019-12-03 16:11:29 +0900115 auto& runner = datapath.runner();
116
117 // Load networking modules needed by Android that are not compiled in the
118 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansa34b5862019-11-20 09:34:01 +0900119 // These must succeed.
Garrick Evans6d227b92019-12-03 16:11:29 +0900120 if (runner.ModprobeAll({
Garrick Evansa34b5862019-11-20 09:34:01 +0900121 // The netfilter modules needed by netd for iptables commands.
122 "ip6table_filter",
123 "ip6t_ipv6header",
124 "ip6t_REJECT",
125 // The xfrm modules needed for Android's ipsec APIs.
126 "xfrm4_mode_transport",
127 "xfrm4_mode_tunnel",
128 "xfrm6_mode_transport",
129 "xfrm6_mode_tunnel",
130 // The ipsec modules for AH and ESP encryption for ipv6.
131 "ah6",
132 "esp6",
133 }) != 0) {
134 LOG(ERROR) << "One or more required kernel modules failed to load."
135 << " Some Android functionality may be broken.";
136 }
137 // Optional modules.
Garrick Evans6d227b92019-12-03 16:11:29 +0900138 if (runner.ModprobeAll({
Garrick Evansa34b5862019-11-20 09:34:01 +0900139 // This module is not available in kernels < 3.18
140 "nf_reject_ipv6",
141 // These modules are needed for supporting Chrome traffic on Android
142 // VPN which uses Android's NAT feature. Android NAT sets up
143 // iptables
144 // rules that use these conntrack modules for FTP/TFTP.
145 "nf_nat_ftp",
146 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +0900147 // The tun module is needed by the Android 464xlat clatd process.
148 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +0900149 }) != 0) {
150 LOG(WARNING) << "One or more optional kernel modules failed to load.";
151 }
152
Garrick Evans6d227b92019-12-03 16:11:29 +0900153 // This is only needed for CTS (b/27932574).
154 if (runner.Chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
155 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
156 }
157
Garrick Evansa34b5862019-11-20 09:34:01 +0900158 done = true;
159}
160
Garrick Evans508a4bc2019-11-14 08:45:52 +0900161bool IsArcVm() {
162 const base::FilePath path("/run/chrome/is_arcvm");
163 std::string contents;
164 if (!base::ReadFileToString(path, &contents)) {
165 PLOG(ERROR) << "Could not read " << path.value();
166 }
167 return contents == "1";
168}
169
Garrick Evansf29f5a32019-12-06 11:34:25 +0900170GuestMessage::GuestType ArcGuest() {
171 if (test::guest != GuestMessage::UNKNOWN_GUEST)
172 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900173
174 return IsArcVm() ? GuestMessage::ARC_VM
175 : ShouldEnableMultinet() ? GuestMessage::ARC
176 : GuestMessage::ARC_LEGACY;
177}
178
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900179} // namespace
180
Garrick Evansf29f5a32019-12-06 11:34:25 +0900181ArcService::ArcService(DeviceManagerBase* dev_mgr, Datapath* datapath)
182 : dev_mgr_(dev_mgr), datapath_(datapath) {
183 DCHECK(dev_mgr_);
Taoyu Li179dcc62019-10-17 11:21:08 +0900184 DCHECK(datapath_);
Garrick Evans3915af32019-07-25 15:44:34 +0900185
Garrick Evansf29f5a32019-12-06 11:34:25 +0900186 dev_mgr_->RegisterDeviceAddedHandler(
187 GuestMessage::ARC,
188 base::Bind(&ArcService::OnDeviceAdded, base::Unretained(this)));
189 dev_mgr_->RegisterDeviceRemovedHandler(
190 GuestMessage::ARC,
191 base::Bind(&ArcService::OnDeviceRemoved, base::Unretained(this)));
192 dev_mgr_->RegisterDefaultInterfaceChangedHandler(
193 GuestMessage::ARC, base::Bind(&ArcService::OnDefaultInterfaceChanged,
194 base::Unretained(this)));
195}
196
197ArcService::~ArcService() {
198 dev_mgr_->UnregisterAllGuestHandlers(GuestMessage::ARC);
Garrick Evans54861622019-07-19 09:05:09 +0900199}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900200
Garrick Evans508a4bc2019-11-14 08:45:52 +0900201bool ArcService::Start(int32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900202 if (impl_) {
203 int32_t prev_id;
204 if (impl_->IsStarted(&prev_id)) {
205 LOG(WARNING) << "Already running - did something crash?"
206 << " Stopping and restarting...";
207 Stop(prev_id);
208 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900209 }
210
Garrick Evansf29f5a32019-12-06 11:34:25 +0900211 const auto guest = ArcGuest();
212 if (guest == GuestMessage::ARC_VM)
213 impl_ = std::make_unique<VmImpl>(dev_mgr_, datapath_);
214 else
215 impl_ = std::make_unique<ContainerImpl>(dev_mgr_, datapath_, guest);
216
217 if (!impl_->Start(id)) {
218 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900219 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900220 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900221
222 // Start known host devices, any new ones will be setup in the process.
223 dev_mgr_->ProcessDevices(
224 base::Bind(&ArcService::StartDevice, weak_factory_.GetWeakPtr()));
225
226 // If this is the first time the service is starting this will create the
227 // Android bridge device; otherwise it does nothing (this is a workaround for
228 // the bug in Shill that casues a Bus crash when it sees the ARC bridge a
229 // second time). Do this after processing the existing devices so it doesn't
230 // get started twice.
Garrick Evanscfd42822019-11-15 12:38:23 +0900231 std::string arc;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900232 switch (guest) {
Garrick Evanscfd42822019-11-15 12:38:23 +0900233 case GuestMessage::ARC:
234 arc = kAndroidDevice;
235 break;
236 case GuestMessage::ARC_LEGACY:
237 arc = kAndroidLegacyDevice;
238 break;
239 case GuestMessage::ARC_VM:
240 arc = kAndroidVmDevice;
241 break;
242 default:
243 LOG(DFATAL) << "Unexpected guest: " << guest;
Garrick Evans21173b12019-11-20 15:23:16 +0900244 return false;
Garrick Evanscfd42822019-11-15 12:38:23 +0900245 }
246 dev_mgr_->Add(arc);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900247 dev_mgr_->OnGuestStart(guest);
248 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900249}
250
Garrick Evans21173b12019-11-20 15:23:16 +0900251void ArcService::Stop(int32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900252 if (!impl_)
253 return;
254
255 dev_mgr_->OnGuestStop(impl_->guest());
Garrick Evans54861622019-07-19 09:05:09 +0900256
257 // Stop known host devices. Note that this does not teardown any existing
258 // devices.
259 dev_mgr_->ProcessDevices(
260 base::Bind(&ArcService::StopDevice, weak_factory_.GetWeakPtr()));
Garrick Evans21173b12019-11-20 15:23:16 +0900261
262 impl_->Stop(id);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900263 impl_.reset();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900264}
265
Garrick Evans8ff08452019-11-25 09:24:26 +0900266bool ArcService::AllowDevice(Device* device) const {
Garrick Evansa1134d72019-12-02 14:25:37 +0900267 if (!device->IsArc())
Garrick Evans0001d012019-11-22 10:06:10 +0900268 return false;
269
Garrick Evans8ff08452019-11-25 09:24:26 +0900270 // ARC P+ is multi-network enabled and should process all devices.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900271 if ((impl_ && impl_->guest() == GuestMessage::ARC) ||
272 (!impl_ && ArcGuest() == GuestMessage::ARC))
Garrick Evans8ff08452019-11-25 09:24:26 +0900273 return true;
274
275 // ARC N and ARCVM (for now) are both single-network - meaning they only use
276 // the "default" device which uses the default interface from shill.
277 return device->UsesDefaultInterface();
278}
279
Garrick Evans54861622019-07-19 09:05:09 +0900280void ArcService::OnDeviceAdded(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900281 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900282 return;
Garrick Evansba575742019-07-17 15:48:08 +0900283
Garrick Evans54861622019-07-19 09:05:09 +0900284 const auto& config = device->config();
285
286 LOG(INFO) << "Adding device " << device->ifname()
287 << " bridge: " << config.host_ifname()
Garrick Evans310ab552019-10-08 11:07:53 +0900288 << " guest_iface: " << config.guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900289
290 // Create the bridge.
291 if (!datapath_->AddBridge(config.host_ifname(),
292 IPv4AddressToString(config.host_ipv4_addr()))) {
293 LOG(ERROR) << "Failed to setup arc bridge: " << config.host_ifname();
294 return;
295 }
296
297 // Setup the iptables.
Garrick Evans8ff08452019-11-25 09:24:26 +0900298 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900299 if (!datapath_->AddLegacyIPv4DNAT(
300 IPv4AddressToString(config.guest_ipv4_addr())))
301 LOG(ERROR) << "Failed to configure ARC traffic rules";
302
303 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
304 LOG(ERROR) << "Failed to configure egress traffic rules";
305 } else if (!device->IsAndroid()) {
306 if (!datapath_->AddInboundIPv4DNAT(
307 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
308 LOG(ERROR) << "Failed to configure ingress traffic rules for "
309 << device->ifname();
310
311 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
312 LOG(ERROR) << "Failed to configure egress traffic rules";
313 }
314
Garrick Evansa1134d72019-12-02 14:25:37 +0900315 device->set_context(std::make_unique<Context>());
Garrick Evans54861622019-07-19 09:05:09 +0900316
317 StartDevice(device);
318}
319
320void ArcService::StartDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900321 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900322 return;
323
Garrick Evans310ab552019-10-08 11:07:53 +0900324 // This can happen if OnDeviceAdded is invoked when the container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900325 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900326 return;
327
Garrick Evans2c263102019-07-26 16:07:18 +0900328 // If there is no context, then this is a new device and it needs to run
329 // through the full setup process.
Garrick Evansa1134d72019-12-02 14:25:37 +0900330 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900331 if (!ctx)
Garrick Evans54861622019-07-19 09:05:09 +0900332 return OnDeviceAdded(device);
333
Garrick Evans2c263102019-07-26 16:07:18 +0900334 if (ctx->IsStarted()) {
335 LOG(ERROR) << "Attempt to restart device " << device->ifname();
336 return;
337 }
338
Garrick Evansd90a3822019-11-12 17:53:08 +0900339 if (!impl_->OnStartDevice(device)) {
Garrick Evanscb791e72019-11-11 15:44:34 +0900340 LOG(ERROR) << "Failed to start device " << device->ifname();
341 return;
342 }
343
Garrick Evansb4eb3892019-11-13 12:07:07 +0900344 ctx->Start();
Garrick Evans54861622019-07-19 09:05:09 +0900345}
346
347void ArcService::OnDeviceRemoved(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900348 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900349 return;
350
Garrick Evans310ab552019-10-08 11:07:53 +0900351 // If the container is down, this call does nothing.
Garrick Evans54861622019-07-19 09:05:09 +0900352 StopDevice(device);
353
354 const auto& config = device->config();
355
356 LOG(INFO) << "Removing device " << device->ifname()
357 << " bridge: " << config.host_ifname()
358 << " guest_iface: " << config.guest_ifname();
359
Taoyu Lif7e8b572019-12-13 15:22:09 +0900360 device->StopIPv6RoutingLegacy();
Garrick Evans8ff08452019-11-25 09:24:26 +0900361 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900362 datapath_->RemoveOutboundIPv4(config.host_ifname());
363 datapath_->RemoveLegacyIPv4DNAT();
364 } else if (!device->IsAndroid()) {
365 datapath_->RemoveOutboundIPv4(config.host_ifname());
366 datapath_->RemoveInboundIPv4DNAT(
367 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
368 }
369
370 datapath_->RemoveBridge(config.host_ifname());
371
Garrick Evansa1134d72019-12-02 14:25:37 +0900372 device->set_context(nullptr);
Garrick Evans54861622019-07-19 09:05:09 +0900373}
374
375void ArcService::StopDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900376 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900377 return;
378
Garrick Evans310ab552019-10-08 11:07:53 +0900379 // This can happen if the device if OnDeviceRemoved is invoked when the
380 // container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900381 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900382 return;
383
Garrick Evansa1134d72019-12-02 14:25:37 +0900384 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900385 if (!ctx) {
386 LOG(ERROR) << "Attempt to stop removed device " << device->ifname();
387 return;
388 }
389
390 if (!ctx->IsStarted()) {
391 LOG(ERROR) << "Attempt to re-stop device " << device->ifname();
392 return;
393 }
394
Garrick Evansd90a3822019-11-12 17:53:08 +0900395 impl_->OnStopDevice(device);
Garrick Evanscb791e72019-11-11 15:44:34 +0900396
397 ctx->Stop();
398}
399
Garrick Evans54861622019-07-19 09:05:09 +0900400void ArcService::OnDefaultInterfaceChanged(const std::string& ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900401 if (impl_)
402 impl_->OnDefaultInterfaceChanged(ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900403}
Garrick Evansba575742019-07-17 15:48:08 +0900404
Garrick Evans2c263102019-07-26 16:07:18 +0900405// Context
406
407ArcService::Context::Context() : Device::Context() {
408 Stop();
409}
410
411void ArcService::Context::Start() {
412 Stop();
413 started_ = true;
414}
415
416void ArcService::Context::Stop() {
417 started_ = false;
418 link_up_ = false;
419 routing_table_id_ = kInvalidTableID;
420 routing_table_attempts_ = 0;
421}
422
423bool ArcService::Context::IsStarted() const {
424 return started_;
425}
426
427bool ArcService::Context::IsLinkUp() const {
428 return link_up_;
429}
430
431bool ArcService::Context::SetLinkUp(bool link_up) {
432 if (link_up == link_up_)
433 return false;
434
435 link_up_ = link_up;
436 return true;
437}
438
439bool ArcService::Context::HasIPv6() const {
440 return routing_table_id_ != kInvalidTableID;
441}
442
443bool ArcService::Context::SetHasIPv6(int routing_table_id) {
444 if (routing_table_id <= kRouteControllerRouteTableOffsetFromIndex)
445 return false;
446
447 routing_table_id_ = routing_table_id;
448 return true;
449}
450
Garrick Evansdc3fc452019-09-06 14:15:04 +0900451void ArcService::Context::ClearIPv6() {
452 routing_table_id_ = kInvalidTableID;
453 routing_table_attempts_ = 0;
454}
455
Garrick Evans2c263102019-07-26 16:07:18 +0900456int ArcService::Context::RoutingTableID() const {
457 return routing_table_id_;
458}
459
460int ArcService::Context::RoutingTableAttempts() {
461 return routing_table_attempts_++;
462}
463
Garrick Evansb4eb3892019-11-13 12:07:07 +0900464const std::string& ArcService::Context::TAP() const {
465 return tap_;
466}
467
468void ArcService::Context::SetTAP(const std::string& tap) {
469 tap_ = tap;
470}
471
Garrick Evansd90a3822019-11-12 17:53:08 +0900472// ARC++ specific functions.
473
474ArcService::ContainerImpl::ContainerImpl(DeviceManagerBase* dev_mgr,
475 Datapath* datapath,
476 GuestMessage::GuestType guest)
Garrick Evansa34b5862019-11-20 09:34:01 +0900477 : pid_(kInvalidPID), dev_mgr_(dev_mgr), datapath_(datapath), guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900478 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900479}
Garrick Evansd90a3822019-11-12 17:53:08 +0900480
Garrick Evansb4eb3892019-11-13 12:07:07 +0900481GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
482 return guest_;
483}
484
Garrick Evans508a4bc2019-11-14 08:45:52 +0900485bool ArcService::ContainerImpl::Start(int32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900486 // This could happen if something crashes and the stop signal is not sent.
487 // It can probably be addressed by stopping and restarting the service.
488 if (pid_ != kInvalidPID)
489 return false;
490
Garrick Evans8ff08452019-11-25 09:24:26 +0900491 // TODO(garrick): Remove this test hack.
492 if (pid == kTestPID) {
493 LOG(WARNING) << "Running with test PID";
494 pid_ = pid;
495 return true;
496 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900497 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900498 LOG(ERROR) << "Cannot start service - invalid container PID";
499 return false;
500 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900501 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900502
503 // Start listening for RTNetlink messages in the container's net namespace
504 // to be notified whenever it brings up an interface.
505 {
506 ScopedNS ns(pid_);
507 if (ns.IsValid()) {
508 rtnl_handler_ = std::make_unique<RTNetlinkHandler>();
509 rtnl_handler_->Start(RTMGRP_LINK);
510 link_listener_ = std::make_unique<shill::RTNLListener>(
511 shill::RTNLHandler::kRequestLink,
512 Bind(&ArcService::ContainerImpl::LinkMsgHandler,
513 weak_factory_.GetWeakPtr()),
514 rtnl_handler_.get());
515 } else {
516 // This is bad - it means we won't ever be able to tell when the container
517 // brings up an interface.
518 LOG(ERROR)
519 << "Cannot start netlink listener - invalid container namespace?";
520 return false;
521 }
522 }
523
524 dev_mgr_->RegisterDeviceIPv6AddressFoundHandler(
Garrick Evansb4eb3892019-11-13 12:07:07 +0900525 guest(), base::Bind(&ArcService::ContainerImpl::SetupIPv6,
526 weak_factory_.GetWeakPtr()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900527
528 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
529 return true;
530}
531
Garrick Evans21173b12019-11-20 15:23:16 +0900532void ArcService::ContainerImpl::Stop(int32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900533 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900534 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900535
Garrick Evansd90a3822019-11-12 17:53:08 +0900536 rtnl_handler_->RemoveListener(link_listener_.get());
537 link_listener_.reset();
538 rtnl_handler_.reset();
539
540 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
541 pid_ = kInvalidPID;
542}
543
Garrick Evansa51d0a12019-11-28 13:51:23 +0900544bool ArcService::ContainerImpl::IsStarted(int32_t* pid) const {
545 if (pid)
546 *pid = pid_;
547
Garrick Evansd90a3822019-11-12 17:53:08 +0900548 return pid_ != kInvalidPID;
549}
550
551bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
552 const auto& config = device->config();
553
554 LOG(INFO) << "Starting device " << device->ifname()
555 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900556 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900557
558 std::string veth_ifname = datapath_->AddVirtualBridgedInterface(
559 device->ifname(), MacAddressToString(config.guest_mac_addr()),
560 config.host_ifname());
561 if (veth_ifname.empty()) {
562 LOG(ERROR) << "Failed to create virtual interface for container";
563 return false;
564 }
565
566 if (!datapath_->AddInterfaceToContainer(
567 pid_, veth_ifname, config.guest_ifname(),
568 IPv4AddressToString(config.guest_ipv4_addr()),
569 device->options().fwd_multicast)) {
570 LOG(ERROR) << "Failed to create container interface.";
571 datapath_->RemoveInterface(veth_ifname);
572 datapath_->RemoveBridge(config.host_ifname());
573 return false;
574 }
575
576 // Signal the container that the network device is ready.
Garrick Evans8ff08452019-11-25 09:24:26 +0900577 if (device->IsAndroid()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900578 datapath_->runner().WriteSentinelToContainer(base::IntToString(pid_));
579 }
Taoyu Li1c96d272019-12-13 14:17:43 +0900580 dev_mgr_->StartForwarding(*device);
Garrick Evansd90a3822019-11-12 17:53:08 +0900581 return true;
582}
583
584void ArcService::ContainerImpl::OnStopDevice(Device* device) {
585 const auto& config = device->config();
586
587 LOG(INFO) << "Stopping device " << device->ifname()
588 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900589 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900590
Taoyu Lif7e8b572019-12-13 15:22:09 +0900591 device->StopIPv6RoutingLegacy();
Garrick Evansd90a3822019-11-12 17:53:08 +0900592 if (!device->IsAndroid()) {
593 datapath_->RemoveInterface(ArcVethHostName(device->ifname()));
594 }
595}
596
597void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
598 const std::string& ifname) {
599 if (!IsStarted())
600 return;
601
602 // For ARC N, we must always be able to find the arc0 device and, at a
603 // minimum, disable it.
Garrick Evansb4eb3892019-11-13 12:07:07 +0900604 if (guest() == GuestMessage::ARC_LEGACY) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900605 datapath_->RemoveLegacyIPv4InboundDNAT();
606 auto* device = dev_mgr_->FindByGuestInterface("arc0");
607 if (!device) {
608 LOG(DFATAL) << "Expected legacy Android device missing";
609 return;
610 }
Taoyu Lif7e8b572019-12-13 15:22:09 +0900611 device->StopIPv6RoutingLegacy();
Garrick Evansd90a3822019-11-12 17:53:08 +0900612
613 // If a new default interface was given, then re-enable with that.
614 if (!ifname.empty()) {
615 datapath_->AddLegacyIPv4InboundDNAT(ifname);
Taoyu Lif7e8b572019-12-13 15:22:09 +0900616 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900617 }
618 return;
619 }
620
621 // For ARC P and later, we're only concerned with resetting the device when it
622 // becomes the default (again) in order to ensure any previous configuration.
623 // is cleared.
624 if (ifname.empty())
625 return;
626
627 auto* device = dev_mgr_->FindByGuestInterface(ifname);
628 if (!device) {
629 LOG(ERROR) << "Expected default device missing: " << ifname;
630 return;
631 }
632 device->StopIPv6RoutingLegacy();
633 device->StartIPv6RoutingLegacy(ifname);
634}
635
636void ArcService::ContainerImpl::LinkMsgHandler(const shill::RTNLMessage& msg) {
637 if (!msg.HasAttribute(IFLA_IFNAME)) {
638 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
639 return;
640 }
641 bool link_up = msg.link_status().flags & IFF_UP;
642 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
643 std::string ifname(reinterpret_cast<const char*>(
644 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
645
646 auto* device = dev_mgr_->FindByGuestInterface(ifname);
647 if (!device)
648 return;
649
Garrick Evansa1134d72019-12-02 14:25:37 +0900650 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900651 if (!ctx) {
652 LOG(DFATAL) << "Context missing";
653 return;
654 }
655
656 // If the link status is unchanged, there is nothing to do.
657 if (!ctx->SetLinkUp(link_up))
658 return;
659
660 if (!link_up) {
661 LOG(INFO) << ifname << " is now down";
662 return;
663 }
664 LOG(INFO) << ifname << " is now up";
665
Garrick Evans8ff08452019-11-25 09:24:26 +0900666 if (device->UsesDefaultInterface()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900667 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
668 return;
669 }
670
Garrick Evans8ff08452019-11-25 09:24:26 +0900671 if (device->IsAndroid())
672 return;
673
Taoyu Lif7e8b572019-12-13 15:22:09 +0900674 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900675}
676
677void ArcService::ContainerImpl::SetupIPv6(Device* device) {
678 device->RegisterIPv6TeardownHandler(base::Bind(
679 &ArcService::ContainerImpl::TeardownIPv6, weak_factory_.GetWeakPtr()));
680
681 auto& ipv6_config = device->ipv6_config();
682 if (ipv6_config.ifname.empty())
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 if (ctx->HasIPv6())
691 return;
692
693 LOG(INFO) << "Setting up IPv6 for " << ipv6_config.ifname;
694
695 int table_id =
696 GetAndroidRoutingTableId(device->config().guest_ifname(), pid_);
697 if (table_id == kInvalidTableID) {
698 if (ctx->RoutingTableAttempts() < kMaxTableRetries) {
699 LOG(INFO) << "Could not look up routing table ID for container interface "
700 << device->config().guest_ifname() << " - trying again...";
701 base::MessageLoop::current()->task_runner()->PostDelayedTask(
702 FROM_HERE,
703 base::Bind(&ArcService::ContainerImpl::SetupIPv6,
704 weak_factory_.GetWeakPtr(), device),
705 kTableRetryDelay);
706 } else {
707 LOG(DFATAL)
708 << "Could not look up routing table ID for container interface "
709 << device->config().guest_ifname();
710 }
711 return;
712 }
713
714 LOG(INFO) << "Setting IPv6 address " << ipv6_config.addr
715 << "/128, gateway=" << ipv6_config.router << " on "
716 << ipv6_config.ifname;
717
718 char buf[INET6_ADDRSTRLEN] = {0};
719 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
720 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
721 return;
722 }
723 std::string addr = buf;
724
725 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
726 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
727 return;
728 }
729 std::string router = buf;
730
731 const auto& config = device->config();
732 {
733 ScopedNS ns(pid_);
734 if (!ns.IsValid()) {
735 LOG(ERROR) << "Invalid container namespace (" << pid_
736 << ") - cannot configure IPv6.";
737 return;
738 }
Taoyu Li90c13912019-11-26 17:56:54 +0900739 // Tag the interface so that ARC can detect this manual configuration and
740 // skip disabling and re-enabling IPv6 (b/144545910).
741 if (!datapath_->SetInterfaceFlag(config.guest_ifname(), IFF_DEBUG)) {
742 LOG(ERROR) << "Failed to mark IPv6 manual config flag on interface";
743 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900744 if (!datapath_->AddIPv6GatewayRoutes(config.guest_ifname(), addr, router,
745 ipv6_config.prefix_len, table_id)) {
746 LOG(ERROR) << "Failed to setup IPv6 routes in the container";
747 return;
748 }
749 }
750
751 if (!datapath_->AddIPv6HostRoute(config.host_ifname(), addr,
752 ipv6_config.prefix_len)) {
753 LOG(ERROR) << "Failed to setup the IPv6 route for interface "
754 << config.host_ifname();
755 return;
756 }
757
758 if (!datapath_->AddIPv6Neighbor(ipv6_config.ifname, addr)) {
759 LOG(ERROR) << "Failed to setup the IPv6 neighbor proxy";
760 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
761 ipv6_config.prefix_len);
762 return;
763 }
764
Taoyu Li2980ee92019-11-18 17:49:32 +0900765 if (!datapath_->AddIPv6Forwarding(ipv6_config.ifname,
766 device->config().host_ifname())) {
767 LOG(ERROR) << "Failed to setup iptables for IPv6";
768 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
769 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
770 ipv6_config.prefix_len);
771 return;
772 }
773
Garrick Evansd90a3822019-11-12 17:53:08 +0900774 ctx->SetHasIPv6(table_id);
775}
776
777void ArcService::ContainerImpl::TeardownIPv6(Device* device) {
Garrick Evansa1134d72019-12-02 14:25:37 +0900778 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900779 if (!ctx || !ctx->HasIPv6())
780 return;
781
782 auto& ipv6_config = device->ipv6_config();
783 LOG(INFO) << "Clearing IPv6 for " << ipv6_config.ifname;
784 int table_id = ctx->RoutingTableID();
785 ctx->ClearIPv6();
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();
Taoyu Li2980ee92019-11-18 17:49:32 +0900801 datapath_->RemoveIPv6Forwarding(ipv6_config.ifname, config.host_ifname());
Garrick Evansd90a3822019-11-12 17:53:08 +0900802 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
803 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
804 ipv6_config.prefix_len);
805
806 ScopedNS ns(pid_);
807 if (ns.IsValid()) {
808 datapath_->RemoveIPv6GatewayRoutes(config.guest_ifname(), addr, router,
809 ipv6_config.prefix_len, table_id);
810 }
811}
812
Garrick Evansb4eb3892019-11-13 12:07:07 +0900813// VM specific functions
814
815ArcService::VmImpl::VmImpl(DeviceManagerBase* dev_mgr, Datapath* datapath)
816 : cid_(kInvalidCID), dev_mgr_(dev_mgr), datapath_(datapath) {}
817
818GuestMessage::GuestType ArcService::VmImpl::guest() const {
819 return GuestMessage::ARC_VM;
820}
821
Garrick Evans508a4bc2019-11-14 08:45:52 +0900822bool ArcService::VmImpl::Start(int32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900823 // This can happen if concierge crashes and doesn't send the vm down RPC.
824 // It can probably be addressed by stopping and restarting the service.
825 if (cid_ != kInvalidCID)
826 return false;
827
Garrick Evansb4eb3892019-11-13 12:07:07 +0900828 if (cid <= kInvalidCID) {
829 LOG(ERROR) << "Invalid VM cid " << cid;
830 return false;
831 }
832
833 cid_ = cid;
834 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
835
836 return true;
837}
838
Garrick Evans21173b12019-11-20 15:23:16 +0900839void ArcService::VmImpl::Stop(int32_t cid) {
840 if (cid_ != cid) {
841 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
842 return;
843 }
844
Garrick Evansb4eb3892019-11-13 12:07:07 +0900845 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
846 cid_ = kInvalidCID;
847}
848
Garrick Evansa51d0a12019-11-28 13:51:23 +0900849bool ArcService::VmImpl::IsStarted(int32_t* cid) const {
850 if (cid)
851 *cid = cid_;
852
Garrick Evansb4eb3892019-11-13 12:07:07 +0900853 return cid_ > kInvalidCID;
854}
855
856bool ArcService::VmImpl::OnStartDevice(Device* device) {
857 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900858 // configurations.
859 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900860 return false;
861
862 const auto& config = device->config();
863
864 LOG(INFO) << "Starting device " << device->ifname()
865 << " bridge: " << config.host_ifname()
866 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
867
Garrick Evansa1134d72019-12-02 14:25:37 +0900868 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900869 if (!ctx) {
870 LOG(ERROR) << "Context missing";
871 return false;
872 }
873
874 // Since the interface will be added to the bridge, no address configuration
875 // should be provided here.
876 std::string tap =
877 datapath_->AddTAP("" /* auto-generate name */, nullptr /* no mac addr */,
878 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
879 if (tap.empty()) {
880 LOG(ERROR) << "Failed to create TAP device for VM";
881 return false;
882 }
883
884 if (!datapath_->AddToBridge(config.host_ifname(), tap)) {
885 LOG(ERROR) << "Failed to bridge TAP device " << tap;
886 datapath_->RemoveInterface(tap);
887 return false;
888 }
889
890 ctx->SetTAP(tap);
891 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
892 // configurations; but for now ARCVM needs to be treated like ARC++ N.
893 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
Taoyu Li1c96d272019-12-13 14:17:43 +0900894 dev_mgr_->StartForwarding(*device);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900895 return true;
896}
897
898void ArcService::VmImpl::OnStopDevice(Device* device) {
899 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900900 // configurations.
901 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900902 return;
903
904 const auto& config = device->config();
905
906 LOG(INFO) << "Stopping " << device->ifname()
907 << " bridge: " << config.host_ifname()
908 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
909
Garrick Evansa1134d72019-12-02 14:25:37 +0900910 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900911 if (!ctx) {
912 LOG(ERROR) << "Context missing";
913 return;
914 }
915
Taoyu Lif7e8b572019-12-13 15:22:09 +0900916 device->StopIPv6RoutingLegacy();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900917 datapath_->RemoveInterface(ctx->TAP());
918}
919
920void ArcService::VmImpl::OnDefaultInterfaceChanged(const std::string& ifname) {
921 if (!IsStarted())
922 return;
923
924 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
925 // configurations; but for now ARCVM needs to be treated like ARC++ N.
926 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900927 auto* device = dev_mgr_->FindByGuestInterface("arc1");
Garrick Evansb4eb3892019-11-13 12:07:07 +0900928 if (!device) {
929 LOG(DFATAL) << "Expected Android device missing";
930 return;
931 }
Taoyu Lif7e8b572019-12-13 15:22:09 +0900932 device->StopIPv6RoutingLegacy();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900933
934 // If a new default interface was given, then re-enable with that.
935 if (!ifname.empty()) {
936 datapath_->AddLegacyIPv4InboundDNAT(ifname);
Taoyu Lif7e8b572019-12-13 15:22:09 +0900937 device->StartIPv6RoutingLegacy(ifname);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900938 }
939}
940
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900941} // namespace arc_networkd