blob: 9f2008f617feb1ca83d43bac889b15c7af549922 [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",
147 }) != 0) {
148 LOG(WARNING) << "One or more optional kernel modules failed to load.";
149 }
150
Garrick Evans6d227b92019-12-03 16:11:29 +0900151 // This is only needed for CTS (b/27932574).
152 if (runner.Chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
153 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
154 }
155
Garrick Evansa34b5862019-11-20 09:34:01 +0900156 done = true;
157}
158
Garrick Evans508a4bc2019-11-14 08:45:52 +0900159bool IsArcVm() {
160 const base::FilePath path("/run/chrome/is_arcvm");
161 std::string contents;
162 if (!base::ReadFileToString(path, &contents)) {
163 PLOG(ERROR) << "Could not read " << path.value();
164 }
165 return contents == "1";
166}
167
Garrick Evansf29f5a32019-12-06 11:34:25 +0900168GuestMessage::GuestType ArcGuest() {
169 if (test::guest != GuestMessage::UNKNOWN_GUEST)
170 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900171
172 return IsArcVm() ? GuestMessage::ARC_VM
173 : ShouldEnableMultinet() ? GuestMessage::ARC
174 : GuestMessage::ARC_LEGACY;
175}
176
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900177} // namespace
178
Garrick Evansf29f5a32019-12-06 11:34:25 +0900179ArcService::ArcService(DeviceManagerBase* dev_mgr, Datapath* datapath)
180 : dev_mgr_(dev_mgr), datapath_(datapath) {
181 DCHECK(dev_mgr_);
Taoyu Li179dcc62019-10-17 11:21:08 +0900182 DCHECK(datapath_);
Garrick Evans3915af32019-07-25 15:44:34 +0900183
Garrick Evansf29f5a32019-12-06 11:34:25 +0900184 dev_mgr_->RegisterDeviceAddedHandler(
185 GuestMessage::ARC,
186 base::Bind(&ArcService::OnDeviceAdded, base::Unretained(this)));
187 dev_mgr_->RegisterDeviceRemovedHandler(
188 GuestMessage::ARC,
189 base::Bind(&ArcService::OnDeviceRemoved, base::Unretained(this)));
190 dev_mgr_->RegisterDefaultInterfaceChangedHandler(
191 GuestMessage::ARC, base::Bind(&ArcService::OnDefaultInterfaceChanged,
192 base::Unretained(this)));
193}
194
195ArcService::~ArcService() {
196 dev_mgr_->UnregisterAllGuestHandlers(GuestMessage::ARC);
Garrick Evans54861622019-07-19 09:05:09 +0900197}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900198
Garrick Evans508a4bc2019-11-14 08:45:52 +0900199bool ArcService::Start(int32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900200 if (impl_) {
201 int32_t prev_id;
202 if (impl_->IsStarted(&prev_id)) {
203 LOG(WARNING) << "Already running - did something crash?"
204 << " Stopping and restarting...";
205 Stop(prev_id);
206 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900207 }
208
Garrick Evansf29f5a32019-12-06 11:34:25 +0900209 const auto guest = ArcGuest();
210 if (guest == GuestMessage::ARC_VM)
211 impl_ = std::make_unique<VmImpl>(dev_mgr_, datapath_);
212 else
213 impl_ = std::make_unique<ContainerImpl>(dev_mgr_, datapath_, guest);
214
215 if (!impl_->Start(id)) {
216 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900217 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900218 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900219
220 // Start known host devices, any new ones will be setup in the process.
221 dev_mgr_->ProcessDevices(
222 base::Bind(&ArcService::StartDevice, weak_factory_.GetWeakPtr()));
223
224 // If this is the first time the service is starting this will create the
225 // Android bridge device; otherwise it does nothing (this is a workaround for
226 // the bug in Shill that casues a Bus crash when it sees the ARC bridge a
227 // second time). Do this after processing the existing devices so it doesn't
228 // get started twice.
Garrick Evanscfd42822019-11-15 12:38:23 +0900229 std::string arc;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900230 switch (guest) {
Garrick Evanscfd42822019-11-15 12:38:23 +0900231 case GuestMessage::ARC:
232 arc = kAndroidDevice;
233 break;
234 case GuestMessage::ARC_LEGACY:
235 arc = kAndroidLegacyDevice;
236 break;
237 case GuestMessage::ARC_VM:
238 arc = kAndroidVmDevice;
239 break;
240 default:
241 LOG(DFATAL) << "Unexpected guest: " << guest;
Garrick Evans21173b12019-11-20 15:23:16 +0900242 return false;
Garrick Evanscfd42822019-11-15 12:38:23 +0900243 }
244 dev_mgr_->Add(arc);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900245 dev_mgr_->OnGuestStart(guest);
246 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900247}
248
Garrick Evans21173b12019-11-20 15:23:16 +0900249void ArcService::Stop(int32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900250 if (!impl_)
251 return;
252
253 dev_mgr_->OnGuestStop(impl_->guest());
Garrick Evans54861622019-07-19 09:05:09 +0900254
255 // Stop known host devices. Note that this does not teardown any existing
256 // devices.
257 dev_mgr_->ProcessDevices(
258 base::Bind(&ArcService::StopDevice, weak_factory_.GetWeakPtr()));
Garrick Evans21173b12019-11-20 15:23:16 +0900259
260 impl_->Stop(id);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900261 impl_.reset();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900262}
263
Garrick Evans8ff08452019-11-25 09:24:26 +0900264bool ArcService::AllowDevice(Device* device) const {
Garrick Evansa1134d72019-12-02 14:25:37 +0900265 if (!device->IsArc())
Garrick Evans0001d012019-11-22 10:06:10 +0900266 return false;
267
Garrick Evans8ff08452019-11-25 09:24:26 +0900268 // ARC P+ is multi-network enabled and should process all devices.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900269 if ((impl_ && impl_->guest() == GuestMessage::ARC) ||
270 (!impl_ && ArcGuest() == GuestMessage::ARC))
Garrick Evans8ff08452019-11-25 09:24:26 +0900271 return true;
272
273 // ARC N and ARCVM (for now) are both single-network - meaning they only use
274 // the "default" device which uses the default interface from shill.
275 return device->UsesDefaultInterface();
276}
277
Garrick Evans54861622019-07-19 09:05:09 +0900278void ArcService::OnDeviceAdded(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900279 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900280 return;
Garrick Evansba575742019-07-17 15:48:08 +0900281
Garrick Evans54861622019-07-19 09:05:09 +0900282 const auto& config = device->config();
283
284 LOG(INFO) << "Adding device " << device->ifname()
285 << " bridge: " << config.host_ifname()
Garrick Evans310ab552019-10-08 11:07:53 +0900286 << " guest_iface: " << config.guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900287
288 // Create the bridge.
289 if (!datapath_->AddBridge(config.host_ifname(),
290 IPv4AddressToString(config.host_ipv4_addr()))) {
291 LOG(ERROR) << "Failed to setup arc bridge: " << config.host_ifname();
292 return;
293 }
294
295 // Setup the iptables.
Garrick Evans8ff08452019-11-25 09:24:26 +0900296 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900297 if (!datapath_->AddLegacyIPv4DNAT(
298 IPv4AddressToString(config.guest_ipv4_addr())))
299 LOG(ERROR) << "Failed to configure ARC traffic rules";
300
301 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
302 LOG(ERROR) << "Failed to configure egress traffic rules";
303 } else if (!device->IsAndroid()) {
304 if (!datapath_->AddInboundIPv4DNAT(
305 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
306 LOG(ERROR) << "Failed to configure ingress traffic rules for "
307 << device->ifname();
308
309 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
310 LOG(ERROR) << "Failed to configure egress traffic rules";
311 }
312
Garrick Evansa1134d72019-12-02 14:25:37 +0900313 device->set_context(std::make_unique<Context>());
Garrick Evans54861622019-07-19 09:05:09 +0900314
315 StartDevice(device);
316}
317
318void ArcService::StartDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900319 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900320 return;
321
Garrick Evans310ab552019-10-08 11:07:53 +0900322 // This can happen if OnDeviceAdded is invoked when the container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900323 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900324 return;
325
Garrick Evans2c263102019-07-26 16:07:18 +0900326 // If there is no context, then this is a new device and it needs to run
327 // through the full setup process.
Garrick Evansa1134d72019-12-02 14:25:37 +0900328 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900329 if (!ctx)
Garrick Evans54861622019-07-19 09:05:09 +0900330 return OnDeviceAdded(device);
331
Garrick Evans2c263102019-07-26 16:07:18 +0900332 if (ctx->IsStarted()) {
333 LOG(ERROR) << "Attempt to restart device " << device->ifname();
334 return;
335 }
336
Garrick Evansd90a3822019-11-12 17:53:08 +0900337 if (!impl_->OnStartDevice(device)) {
Garrick Evanscb791e72019-11-11 15:44:34 +0900338 LOG(ERROR) << "Failed to start device " << device->ifname();
339 return;
340 }
341
Garrick Evansb4eb3892019-11-13 12:07:07 +0900342 ctx->Start();
Garrick Evans54861622019-07-19 09:05:09 +0900343}
344
345void ArcService::OnDeviceRemoved(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900346 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900347 return;
348
Garrick Evans310ab552019-10-08 11:07:53 +0900349 // If the container is down, this call does nothing.
Garrick Evans54861622019-07-19 09:05:09 +0900350 StopDevice(device);
351
352 const auto& config = device->config();
353
354 LOG(INFO) << "Removing device " << device->ifname()
355 << " bridge: " << config.host_ifname()
356 << " guest_iface: " << config.guest_ifname();
357
Garrick Evans260ff302019-07-25 11:22:50 +0900358 device->Disable();
Garrick Evans8ff08452019-11-25 09:24:26 +0900359 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900360 datapath_->RemoveOutboundIPv4(config.host_ifname());
361 datapath_->RemoveLegacyIPv4DNAT();
362 } else if (!device->IsAndroid()) {
363 datapath_->RemoveOutboundIPv4(config.host_ifname());
364 datapath_->RemoveInboundIPv4DNAT(
365 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
366 }
367
368 datapath_->RemoveBridge(config.host_ifname());
369
Garrick Evansa1134d72019-12-02 14:25:37 +0900370 device->set_context(nullptr);
Garrick Evans54861622019-07-19 09:05:09 +0900371}
372
373void ArcService::StopDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900374 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900375 return;
376
Garrick Evans310ab552019-10-08 11:07:53 +0900377 // This can happen if the device if OnDeviceRemoved is invoked when the
378 // container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900379 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900380 return;
381
Garrick Evansa1134d72019-12-02 14:25:37 +0900382 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900383 if (!ctx) {
384 LOG(ERROR) << "Attempt to stop removed device " << device->ifname();
385 return;
386 }
387
388 if (!ctx->IsStarted()) {
389 LOG(ERROR) << "Attempt to re-stop device " << device->ifname();
390 return;
391 }
392
Garrick Evansd90a3822019-11-12 17:53:08 +0900393 impl_->OnStopDevice(device);
Garrick Evanscb791e72019-11-11 15:44:34 +0900394
395 ctx->Stop();
396}
397
Garrick Evans54861622019-07-19 09:05:09 +0900398void ArcService::OnDefaultInterfaceChanged(const std::string& ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900399 if (impl_)
400 impl_->OnDefaultInterfaceChanged(ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900401}
Garrick Evansba575742019-07-17 15:48:08 +0900402
Garrick Evans2c263102019-07-26 16:07:18 +0900403// Context
404
405ArcService::Context::Context() : Device::Context() {
406 Stop();
407}
408
409void ArcService::Context::Start() {
410 Stop();
411 started_ = true;
412}
413
414void ArcService::Context::Stop() {
415 started_ = false;
416 link_up_ = false;
417 routing_table_id_ = kInvalidTableID;
418 routing_table_attempts_ = 0;
419}
420
421bool ArcService::Context::IsStarted() const {
422 return started_;
423}
424
425bool ArcService::Context::IsLinkUp() const {
426 return link_up_;
427}
428
429bool ArcService::Context::SetLinkUp(bool link_up) {
430 if (link_up == link_up_)
431 return false;
432
433 link_up_ = link_up;
434 return true;
435}
436
437bool ArcService::Context::HasIPv6() const {
438 return routing_table_id_ != kInvalidTableID;
439}
440
441bool ArcService::Context::SetHasIPv6(int routing_table_id) {
442 if (routing_table_id <= kRouteControllerRouteTableOffsetFromIndex)
443 return false;
444
445 routing_table_id_ = routing_table_id;
446 return true;
447}
448
Garrick Evansdc3fc452019-09-06 14:15:04 +0900449void ArcService::Context::ClearIPv6() {
450 routing_table_id_ = kInvalidTableID;
451 routing_table_attempts_ = 0;
452}
453
Garrick Evans2c263102019-07-26 16:07:18 +0900454int ArcService::Context::RoutingTableID() const {
455 return routing_table_id_;
456}
457
458int ArcService::Context::RoutingTableAttempts() {
459 return routing_table_attempts_++;
460}
461
Garrick Evansb4eb3892019-11-13 12:07:07 +0900462const std::string& ArcService::Context::TAP() const {
463 return tap_;
464}
465
466void ArcService::Context::SetTAP(const std::string& tap) {
467 tap_ = tap;
468}
469
Garrick Evansd90a3822019-11-12 17:53:08 +0900470// ARC++ specific functions.
471
472ArcService::ContainerImpl::ContainerImpl(DeviceManagerBase* dev_mgr,
473 Datapath* datapath,
474 GuestMessage::GuestType guest)
Garrick Evansa34b5862019-11-20 09:34:01 +0900475 : pid_(kInvalidPID), dev_mgr_(dev_mgr), datapath_(datapath), guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900476 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900477}
Garrick Evansd90a3822019-11-12 17:53:08 +0900478
Garrick Evansb4eb3892019-11-13 12:07:07 +0900479GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
480 return guest_;
481}
482
Garrick Evans508a4bc2019-11-14 08:45:52 +0900483bool ArcService::ContainerImpl::Start(int32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900484 // This could happen if something crashes and the stop signal is not sent.
485 // It can probably be addressed by stopping and restarting the service.
486 if (pid_ != kInvalidPID)
487 return false;
488
Garrick Evans8ff08452019-11-25 09:24:26 +0900489 // TODO(garrick): Remove this test hack.
490 if (pid == kTestPID) {
491 LOG(WARNING) << "Running with test PID";
492 pid_ = pid;
493 return true;
494 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900495 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900496 LOG(ERROR) << "Cannot start service - invalid container PID";
497 return false;
498 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900499 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900500
501 // Start listening for RTNetlink messages in the container's net namespace
502 // to be notified whenever it brings up an interface.
503 {
504 ScopedNS ns(pid_);
505 if (ns.IsValid()) {
506 rtnl_handler_ = std::make_unique<RTNetlinkHandler>();
507 rtnl_handler_->Start(RTMGRP_LINK);
508 link_listener_ = std::make_unique<shill::RTNLListener>(
509 shill::RTNLHandler::kRequestLink,
510 Bind(&ArcService::ContainerImpl::LinkMsgHandler,
511 weak_factory_.GetWeakPtr()),
512 rtnl_handler_.get());
513 } else {
514 // This is bad - it means we won't ever be able to tell when the container
515 // brings up an interface.
516 LOG(ERROR)
517 << "Cannot start netlink listener - invalid container namespace?";
518 return false;
519 }
520 }
521
522 dev_mgr_->RegisterDeviceIPv6AddressFoundHandler(
Garrick Evansb4eb3892019-11-13 12:07:07 +0900523 guest(), base::Bind(&ArcService::ContainerImpl::SetupIPv6,
524 weak_factory_.GetWeakPtr()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900525
526 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
527 return true;
528}
529
Garrick Evans21173b12019-11-20 15:23:16 +0900530void ArcService::ContainerImpl::Stop(int32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900531 if (!IsStarted())
532 return;
533
Garrick Evansd90a3822019-11-12 17:53:08 +0900534 rtnl_handler_->RemoveListener(link_listener_.get());
535 link_listener_.reset();
536 rtnl_handler_.reset();
537
538 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
539 pid_ = kInvalidPID;
540}
541
Garrick Evansa51d0a12019-11-28 13:51:23 +0900542bool ArcService::ContainerImpl::IsStarted(int32_t* pid) const {
543 if (pid)
544 *pid = pid_;
545
Garrick Evansd90a3822019-11-12 17:53:08 +0900546 return pid_ != kInvalidPID;
547}
548
549bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
550 const auto& config = device->config();
551
552 LOG(INFO) << "Starting device " << device->ifname()
553 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900554 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900555
556 std::string veth_ifname = datapath_->AddVirtualBridgedInterface(
557 device->ifname(), MacAddressToString(config.guest_mac_addr()),
558 config.host_ifname());
559 if (veth_ifname.empty()) {
560 LOG(ERROR) << "Failed to create virtual interface for container";
561 return false;
562 }
563
564 if (!datapath_->AddInterfaceToContainer(
565 pid_, veth_ifname, config.guest_ifname(),
566 IPv4AddressToString(config.guest_ipv4_addr()),
567 device->options().fwd_multicast)) {
568 LOG(ERROR) << "Failed to create container interface.";
569 datapath_->RemoveInterface(veth_ifname);
570 datapath_->RemoveBridge(config.host_ifname());
571 return false;
572 }
573
574 // Signal the container that the network device is ready.
Garrick Evans8ff08452019-11-25 09:24:26 +0900575 if (device->IsAndroid()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900576 datapath_->runner().WriteSentinelToContainer(base::IntToString(pid_));
577 }
578
579 return true;
580}
581
582void ArcService::ContainerImpl::OnStopDevice(Device* device) {
583 const auto& config = device->config();
584
585 LOG(INFO) << "Stopping device " << device->ifname()
586 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900587 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900588
589 device->Disable();
590 if (!device->IsAndroid()) {
591 datapath_->RemoveInterface(ArcVethHostName(device->ifname()));
592 }
593}
594
595void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
596 const std::string& ifname) {
597 if (!IsStarted())
598 return;
599
600 // For ARC N, we must always be able to find the arc0 device and, at a
601 // minimum, disable it.
Garrick Evansb4eb3892019-11-13 12:07:07 +0900602 if (guest() == GuestMessage::ARC_LEGACY) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900603 datapath_->RemoveLegacyIPv4InboundDNAT();
604 auto* device = dev_mgr_->FindByGuestInterface("arc0");
605 if (!device) {
606 LOG(DFATAL) << "Expected legacy Android device missing";
607 return;
608 }
609 device->Disable();
610
611 // If a new default interface was given, then re-enable with that.
612 if (!ifname.empty()) {
613 datapath_->AddLegacyIPv4InboundDNAT(ifname);
614 device->Enable(ifname);
615 }
616 return;
617 }
618
619 // For ARC P and later, we're only concerned with resetting the device when it
620 // becomes the default (again) in order to ensure any previous configuration.
621 // is cleared.
622 if (ifname.empty())
623 return;
624
625 auto* device = dev_mgr_->FindByGuestInterface(ifname);
626 if (!device) {
627 LOG(ERROR) << "Expected default device missing: " << ifname;
628 return;
629 }
630 device->StopIPv6RoutingLegacy();
631 device->StartIPv6RoutingLegacy(ifname);
632}
633
634void ArcService::ContainerImpl::LinkMsgHandler(const shill::RTNLMessage& msg) {
635 if (!msg.HasAttribute(IFLA_IFNAME)) {
636 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
637 return;
638 }
639 bool link_up = msg.link_status().flags & IFF_UP;
640 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
641 std::string ifname(reinterpret_cast<const char*>(
642 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
643
644 auto* device = dev_mgr_->FindByGuestInterface(ifname);
645 if (!device)
646 return;
647
Garrick Evansa1134d72019-12-02 14:25:37 +0900648 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900649 if (!ctx) {
650 LOG(DFATAL) << "Context missing";
651 return;
652 }
653
654 // If the link status is unchanged, there is nothing to do.
655 if (!ctx->SetLinkUp(link_up))
656 return;
657
658 if (!link_up) {
659 LOG(INFO) << ifname << " is now down";
660 return;
661 }
662 LOG(INFO) << ifname << " is now up";
663
Garrick Evans8ff08452019-11-25 09:24:26 +0900664 if (device->UsesDefaultInterface()) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900665 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
666 return;
667 }
668
Garrick Evans8ff08452019-11-25 09:24:26 +0900669 if (device->IsAndroid())
670 return;
671
Garrick Evansd90a3822019-11-12 17:53:08 +0900672 device->Enable(ifname);
673}
674
675void ArcService::ContainerImpl::SetupIPv6(Device* device) {
676 device->RegisterIPv6TeardownHandler(base::Bind(
677 &ArcService::ContainerImpl::TeardownIPv6, weak_factory_.GetWeakPtr()));
678
679 auto& ipv6_config = device->ipv6_config();
680 if (ipv6_config.ifname.empty())
681 return;
682
Garrick Evansa1134d72019-12-02 14:25:37 +0900683 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900684 if (!ctx) {
685 LOG(DFATAL) << "Context missing";
686 return;
687 }
688 if (ctx->HasIPv6())
689 return;
690
691 LOG(INFO) << "Setting up IPv6 for " << ipv6_config.ifname;
692
693 int table_id =
694 GetAndroidRoutingTableId(device->config().guest_ifname(), pid_);
695 if (table_id == kInvalidTableID) {
696 if (ctx->RoutingTableAttempts() < kMaxTableRetries) {
697 LOG(INFO) << "Could not look up routing table ID for container interface "
698 << device->config().guest_ifname() << " - trying again...";
699 base::MessageLoop::current()->task_runner()->PostDelayedTask(
700 FROM_HERE,
701 base::Bind(&ArcService::ContainerImpl::SetupIPv6,
702 weak_factory_.GetWeakPtr(), device),
703 kTableRetryDelay);
704 } else {
705 LOG(DFATAL)
706 << "Could not look up routing table ID for container interface "
707 << device->config().guest_ifname();
708 }
709 return;
710 }
711
712 LOG(INFO) << "Setting IPv6 address " << ipv6_config.addr
713 << "/128, gateway=" << ipv6_config.router << " on "
714 << ipv6_config.ifname;
715
716 char buf[INET6_ADDRSTRLEN] = {0};
717 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
718 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
719 return;
720 }
721 std::string addr = buf;
722
723 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
724 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
725 return;
726 }
727 std::string router = buf;
728
729 const auto& config = device->config();
730 {
731 ScopedNS ns(pid_);
732 if (!ns.IsValid()) {
733 LOG(ERROR) << "Invalid container namespace (" << pid_
734 << ") - cannot configure IPv6.";
735 return;
736 }
Taoyu Li90c13912019-11-26 17:56:54 +0900737 // Tag the interface so that ARC can detect this manual configuration and
738 // skip disabling and re-enabling IPv6 (b/144545910).
739 if (!datapath_->SetInterfaceFlag(config.guest_ifname(), IFF_DEBUG)) {
740 LOG(ERROR) << "Failed to mark IPv6 manual config flag on interface";
741 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900742 if (!datapath_->AddIPv6GatewayRoutes(config.guest_ifname(), addr, router,
743 ipv6_config.prefix_len, table_id)) {
744 LOG(ERROR) << "Failed to setup IPv6 routes in the container";
745 return;
746 }
747 }
748
749 if (!datapath_->AddIPv6HostRoute(config.host_ifname(), addr,
750 ipv6_config.prefix_len)) {
751 LOG(ERROR) << "Failed to setup the IPv6 route for interface "
752 << config.host_ifname();
753 return;
754 }
755
756 if (!datapath_->AddIPv6Neighbor(ipv6_config.ifname, addr)) {
757 LOG(ERROR) << "Failed to setup the IPv6 neighbor proxy";
758 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
759 ipv6_config.prefix_len);
760 return;
761 }
762
Taoyu Li2980ee92019-11-18 17:49:32 +0900763 if (!datapath_->AddIPv6Forwarding(ipv6_config.ifname,
764 device->config().host_ifname())) {
765 LOG(ERROR) << "Failed to setup iptables for IPv6";
766 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
767 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
768 ipv6_config.prefix_len);
769 return;
770 }
771
Garrick Evansd90a3822019-11-12 17:53:08 +0900772 ctx->SetHasIPv6(table_id);
773}
774
775void ArcService::ContainerImpl::TeardownIPv6(Device* device) {
Garrick Evansa1134d72019-12-02 14:25:37 +0900776 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900777 if (!ctx || !ctx->HasIPv6())
778 return;
779
780 auto& ipv6_config = device->ipv6_config();
781 LOG(INFO) << "Clearing IPv6 for " << ipv6_config.ifname;
782 int table_id = ctx->RoutingTableID();
783 ctx->ClearIPv6();
784
785 char buf[INET6_ADDRSTRLEN] = {0};
786 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
787 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
788 return;
789 }
790 std::string addr = buf;
791
792 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
793 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
794 return;
795 }
796 std::string router = buf;
797
798 const auto& config = device->config();
Taoyu Li2980ee92019-11-18 17:49:32 +0900799 datapath_->RemoveIPv6Forwarding(ipv6_config.ifname, config.host_ifname());
Garrick Evansd90a3822019-11-12 17:53:08 +0900800 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
801 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
802 ipv6_config.prefix_len);
803
804 ScopedNS ns(pid_);
805 if (ns.IsValid()) {
806 datapath_->RemoveIPv6GatewayRoutes(config.guest_ifname(), addr, router,
807 ipv6_config.prefix_len, table_id);
808 }
809}
810
Garrick Evansb4eb3892019-11-13 12:07:07 +0900811// VM specific functions
812
813ArcService::VmImpl::VmImpl(DeviceManagerBase* dev_mgr, Datapath* datapath)
814 : cid_(kInvalidCID), dev_mgr_(dev_mgr), datapath_(datapath) {}
815
816GuestMessage::GuestType ArcService::VmImpl::guest() const {
817 return GuestMessage::ARC_VM;
818}
819
Garrick Evans508a4bc2019-11-14 08:45:52 +0900820bool ArcService::VmImpl::Start(int32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900821 // This can happen if concierge crashes and doesn't send the vm down RPC.
822 // It can probably be addressed by stopping and restarting the service.
823 if (cid_ != kInvalidCID)
824 return false;
825
Garrick Evansb4eb3892019-11-13 12:07:07 +0900826 if (cid <= kInvalidCID) {
827 LOG(ERROR) << "Invalid VM cid " << cid;
828 return false;
829 }
830
831 cid_ = cid;
832 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
833
834 return true;
835}
836
Garrick Evans21173b12019-11-20 15:23:16 +0900837void ArcService::VmImpl::Stop(int32_t cid) {
838 if (cid_ != cid) {
839 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
840 return;
841 }
842
Garrick Evansb4eb3892019-11-13 12:07:07 +0900843 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
844 cid_ = kInvalidCID;
845}
846
Garrick Evansa51d0a12019-11-28 13:51:23 +0900847bool ArcService::VmImpl::IsStarted(int32_t* cid) const {
848 if (cid)
849 *cid = cid_;
850
Garrick Evansb4eb3892019-11-13 12:07:07 +0900851 return cid_ > kInvalidCID;
852}
853
854bool ArcService::VmImpl::OnStartDevice(Device* device) {
855 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900856 // configurations.
857 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900858 return false;
859
860 const auto& config = device->config();
861
862 LOG(INFO) << "Starting device " << device->ifname()
863 << " bridge: " << config.host_ifname()
864 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
865
Garrick Evansa1134d72019-12-02 14:25:37 +0900866 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900867 if (!ctx) {
868 LOG(ERROR) << "Context missing";
869 return false;
870 }
871
872 // Since the interface will be added to the bridge, no address configuration
873 // should be provided here.
874 std::string tap =
875 datapath_->AddTAP("" /* auto-generate name */, nullptr /* no mac addr */,
876 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
877 if (tap.empty()) {
878 LOG(ERROR) << "Failed to create TAP device for VM";
879 return false;
880 }
881
882 if (!datapath_->AddToBridge(config.host_ifname(), tap)) {
883 LOG(ERROR) << "Failed to bridge TAP device " << tap;
884 datapath_->RemoveInterface(tap);
885 return false;
886 }
887
888 ctx->SetTAP(tap);
889 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
890 // configurations; but for now ARCVM needs to be treated like ARC++ N.
891 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
892 return true;
893}
894
895void ArcService::VmImpl::OnStopDevice(Device* device) {
896 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900897 // configurations.
898 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900899 return;
900
901 const auto& config = device->config();
902
903 LOG(INFO) << "Stopping " << device->ifname()
904 << " bridge: " << config.host_ifname()
905 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
906
Garrick Evansa1134d72019-12-02 14:25:37 +0900907 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900908 if (!ctx) {
909 LOG(ERROR) << "Context missing";
910 return;
911 }
912
913 device->Disable();
914 datapath_->RemoveInterface(ctx->TAP());
915}
916
917void ArcService::VmImpl::OnDefaultInterfaceChanged(const std::string& ifname) {
918 if (!IsStarted())
919 return;
920
921 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
922 // configurations; but for now ARCVM needs to be treated like ARC++ N.
923 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900924 auto* device = dev_mgr_->FindByGuestInterface("arc1");
Garrick Evansb4eb3892019-11-13 12:07:07 +0900925 if (!device) {
926 LOG(DFATAL) << "Expected Android device missing";
927 return;
928 }
929 device->Disable();
930
931 // If a new default interface was given, then re-enable with that.
932 if (!ifname.empty()) {
933 datapath_->AddLegacyIPv4InboundDNAT(ifname);
934 device->Enable(ifname);
935 }
936}
937
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900938} // namespace arc_networkd