blob: 8d8658416e966f335615212e75087392ba942798 [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 Evans54861622019-07-19 09:05:09 +090020#include <shill/net/rtnl_message.h>
21
22#include "arc/network/datapath.h"
23#include "arc/network/ipc.pb.h"
24#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 {
30namespace {
Garrick Evans54861622019-07-19 09:05:09 +090031constexpr pid_t kInvalidPID = -1;
Garrick Evans260ff302019-07-25 11:22:50 +090032constexpr int kInvalidTableID = -1;
33constexpr int kMaxTableRetries = 10; // Based on 1 second delay.
34constexpr base::TimeDelta kTableRetryDelay = base::TimeDelta::FromSeconds(1);
35// Android adds a constant to the interface index to derive the table id.
36// This is defined in system/netd/server/RouteController.h
37constexpr int kRouteControllerRouteTableOffsetFromIndex = 1000;
Garrick Evans54861622019-07-19 09:05:09 +090038
39// This wrapper is required since the base class is a singleton that hides its
40// constructor. It is necessary here because the message loop thread has to be
41// reassociated to the container's network namespace; and since the container
42// can be repeatedly created and destroyed, the handler must be as well.
43class RTNetlinkHandler : public shill::RTNLHandler {
44 public:
45 RTNetlinkHandler() = default;
46 ~RTNetlinkHandler() = default;
47
48 private:
49 DISALLOW_COPY_AND_ASSIGN(RTNetlinkHandler);
50};
Garrick Evans5d55f5e2019-07-17 15:28:10 +090051
Garrick Evans260ff302019-07-25 11:22:50 +090052int GetAndroidRoutingTableId(const std::string& ifname, pid_t pid) {
53 base::FilePath ifindex_path(base::StringPrintf(
54 "/proc/%d/root/sys/class/net/%s/ifindex", pid, ifname.c_str()));
55 std::string contents;
56 if (!base::ReadFileToString(ifindex_path, &contents)) {
57 PLOG(WARNING) << "Could not read " << ifindex_path.value();
58 return kInvalidTableID;
59 }
60
61 base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
62 int table_id = kInvalidTableID;
63 if (!base::StringToInt(contents, &table_id)) {
64 LOG(ERROR) << "Could not parse ifindex from " << ifindex_path.value()
65 << ": " << contents;
66 return kInvalidTableID;
67 }
68 table_id += kRouteControllerRouteTableOffsetFromIndex;
69
70 LOG(INFO) << "Found table id " << table_id << " for container interface "
71 << ifname;
72 return table_id;
73}
74
Garrick Evans1f5a3612019-11-08 12:59:03 +090075bool ShouldEnableMultinet() {
76 static const char kLsbReleasePath[] = "/etc/lsb-release";
77 static int kMinAndroidSdkVersion = 28; // P
78 static int kMinChromeMilestone = 76;
79
80 brillo::KeyValueStore store;
81 if (!store.Load(base::FilePath(kLsbReleasePath))) {
82 LOG(ERROR) << "Could not read lsb-release";
83 return false;
84 }
85
86 std::string value;
87 if (!store.GetString("CHROMEOS_ARC_ANDROID_SDK_VERSION", &value)) {
88 LOG(ERROR) << "ARC multi-networking disabled - cannot determine Android "
89 "SDK version";
90 return false;
91 }
92 int ver = 0;
93 if (!base::StringToInt(value.c_str(), &ver)) {
94 LOG(ERROR) << "ARC multi-networking disabled - invalid Android SDK version";
95 return false;
96 }
97 if (ver < kMinAndroidSdkVersion) {
98 LOG(INFO) << "ARC multi-networking disabled for Android SDK " << value;
99 return false;
100 }
101 if (!store.GetString("CHROMEOS_RELEASE_CHROME_MILESTONE", &value)) {
102 LOG(ERROR)
103 << "ARC multi-networking disabled - cannot determine Chrome milestone";
104 return false;
105 }
106 if (atoi(value.c_str()) < kMinChromeMilestone) {
107 LOG(INFO) << "ARC multi-networking disabled for Chrome M" << value;
108 return false;
109 }
110 return true;
111}
112
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900113// TODO(garrick): Remove this workaround ASAP.
114int GetContainerPID() {
115 const base::FilePath path("/run/containers/android-run_oci/container.pid");
116 std::string pid_str;
117 if (!base::ReadFileToStringWithMaxSize(path, &pid_str, 16 /* max size */)) {
118 LOG(ERROR) << "Failed to read pid file";
Garrick Evans54861622019-07-19 09:05:09 +0900119 return kInvalidPID;
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900120 }
121 int pid;
122 if (!base::StringToInt(base::TrimWhitespaceASCII(pid_str, base::TRIM_ALL),
123 &pid)) {
124 LOG(ERROR) << "Failed to convert container pid string";
Garrick Evans54861622019-07-19 09:05:09 +0900125 return kInvalidPID;
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900126 }
127 LOG(INFO) << "Read container pid as " << pid;
128 return pid;
129}
130
131} // namespace
132
Garrick Evans54861622019-07-19 09:05:09 +0900133ArcService::ArcService(DeviceManagerBase* dev_mgr,
Taoyu Li179dcc62019-10-17 11:21:08 +0900134 Datapath* datapath,
Garrick Evans1f5a3612019-11-08 12:59:03 +0900135 bool* is_legacy)
136 : GuestService((is_legacy ? !*is_legacy : ShouldEnableMultinet())
137 ? GuestMessage::ARC
138 : GuestMessage::ARC_LEGACY,
Garrick Evans54861622019-07-19 09:05:09 +0900139 dev_mgr),
Taoyu Li179dcc62019-10-17 11:21:08 +0900140 datapath_(datapath),
Garrick Evansd90a3822019-11-12 17:53:08 +0900141 impl_(std::make_unique<ContainerImpl>(dev_mgr, datapath, guest_)) {
Taoyu Li179dcc62019-10-17 11:21:08 +0900142 DCHECK(datapath_);
Garrick Evans3915af32019-07-25 15:44:34 +0900143
144 // Load networking modules needed by Android that are not compiled in the
145 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evans3915af32019-07-25 15:44:34 +0900146
147 // These must succeed.
Taoyu Lia0c43a72019-10-01 10:29:57 +0900148 if (datapath_->runner().ModprobeAll({
Garrick Evans3915af32019-07-25 15:44:34 +0900149 // The netfilter modules needed by netd for iptables commands.
150 "ip6table_filter",
151 "ip6t_ipv6header",
152 "ip6t_REJECT",
153 // The xfrm modules needed for Android's ipsec APIs.
154 "xfrm4_mode_transport",
155 "xfrm4_mode_tunnel",
156 "xfrm6_mode_transport",
157 "xfrm6_mode_tunnel",
158 // The ipsec modules for AH and ESP encryption for ipv6.
159 "ah6",
160 "esp6",
161 }) != 0) {
162 LOG(ERROR) << "One or more required kernel modules failed to load.";
163 }
164
165 // Optional modules.
Taoyu Lia0c43a72019-10-01 10:29:57 +0900166 if (datapath_->runner().ModprobeAll({
Garrick Evans3915af32019-07-25 15:44:34 +0900167 // This module is not available in kernels < 3.18
168 "nf_reject_ipv6",
169 // These modules are needed for supporting Chrome traffic on Android
170 // VPN which uses Android's NAT feature. Android NAT sets up iptables
171 // rules that use these conntrack modules for FTP/TFTP.
172 "nf_nat_ftp",
173 "nf_nat_tftp",
174 }) != 0) {
175 LOG(WARNING) << "One or more optional kernel modules failed to load.";
176 }
Garrick Evans54861622019-07-19 09:05:09 +0900177}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900178
179void ArcService::OnStart() {
Garrick Evansd90a3822019-11-12 17:53:08 +0900180 if (!impl_->OnStart()) {
Garrick Evanscb791e72019-11-11 15:44:34 +0900181 LOG(ERROR) << "Failed to start ARC++ network service";
182 return;
183 }
184
185 // Start known host devices, any new ones will be setup in the process.
186 dev_mgr_->ProcessDevices(
187 base::Bind(&ArcService::StartDevice, weak_factory_.GetWeakPtr()));
188
189 // If this is the first time the service is starting this will create the
190 // Android bridge device; otherwise it does nothing (this is a workaround for
191 // the bug in Shill that casues a Bus crash when it sees the ARC bridge a
192 // second time). Do this after processing the existing devices so it doesn't
193 // get started twice.
194 dev_mgr_->Add(guest_ == GuestMessage::ARC_LEGACY ? kAndroidLegacyDevice
195 : kAndroidDevice);
196
197 // Finally, call the base implementation.
198 GuestService::OnStart();
199}
200
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900201void ArcService::OnStop() {
Garrick Evans54861622019-07-19 09:05:09 +0900202 // Call the base implementation.
203 GuestService::OnStop();
204
205 // Stop known host devices. Note that this does not teardown any existing
206 // devices.
207 dev_mgr_->ProcessDevices(
208 base::Bind(&ArcService::StopDevice, weak_factory_.GetWeakPtr()));
209
Garrick Evansd90a3822019-11-12 17:53:08 +0900210 impl_->OnStop();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900211}
212
Garrick Evans54861622019-07-19 09:05:09 +0900213void ArcService::OnDeviceAdded(Device* device) {
Garrick Evans310ab552019-10-08 11:07:53 +0900214 // ARC N uses legacy single networking and only requires the arcbr0/arc0
215 // configuration. Any other device can be safely ignored.
216 if (guest_ == GuestMessage::ARC_LEGACY && !device->IsLegacyAndroid())
Garrick Evans54861622019-07-19 09:05:09 +0900217 return;
Garrick Evansba575742019-07-17 15:48:08 +0900218
Garrick Evans54861622019-07-19 09:05:09 +0900219 const auto& config = device->config();
220
221 LOG(INFO) << "Adding device " << device->ifname()
222 << " bridge: " << config.host_ifname()
Garrick Evans310ab552019-10-08 11:07:53 +0900223 << " guest_iface: " << config.guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900224
225 // Create the bridge.
226 if (!datapath_->AddBridge(config.host_ifname(),
227 IPv4AddressToString(config.host_ipv4_addr()))) {
228 LOG(ERROR) << "Failed to setup arc bridge: " << config.host_ifname();
229 return;
230 }
231
232 // Setup the iptables.
233 if (device->IsLegacyAndroid()) {
234 if (!datapath_->AddLegacyIPv4DNAT(
235 IPv4AddressToString(config.guest_ipv4_addr())))
236 LOG(ERROR) << "Failed to configure ARC traffic rules";
237
238 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
239 LOG(ERROR) << "Failed to configure egress traffic rules";
240 } else if (!device->IsAndroid()) {
241 if (!datapath_->AddInboundIPv4DNAT(
242 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
243 LOG(ERROR) << "Failed to configure ingress traffic rules for "
244 << device->ifname();
245
246 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
247 LOG(ERROR) << "Failed to configure egress traffic rules";
248 }
249
Garrick Evans2c263102019-07-26 16:07:18 +0900250 device->set_context(guest_, std::make_unique<Context>());
Garrick Evans54861622019-07-19 09:05:09 +0900251
252 StartDevice(device);
253}
254
255void ArcService::StartDevice(Device* device) {
Garrick Evans310ab552019-10-08 11:07:53 +0900256 // This can happen if OnDeviceAdded is invoked when the container is down.
Garrick Evansd90a3822019-11-12 17:53:08 +0900257 if (!impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900258 return;
259
Garrick Evans2c263102019-07-26 16:07:18 +0900260 // If there is no context, then this is a new device and it needs to run
261 // through the full setup process.
262 Context* ctx = dynamic_cast<Context*>(device->context(guest_));
263 if (!ctx)
Garrick Evans54861622019-07-19 09:05:09 +0900264 return OnDeviceAdded(device);
265
Garrick Evans2c263102019-07-26 16:07:18 +0900266 if (ctx->IsStarted()) {
267 LOG(ERROR) << "Attempt to restart device " << device->ifname();
268 return;
269 }
270
Garrick Evansd90a3822019-11-12 17:53:08 +0900271 if (!impl_->OnStartDevice(device)) {
Garrick Evanscb791e72019-11-11 15:44:34 +0900272 LOG(ERROR) << "Failed to start device " << device->ifname();
273 return;
274 }
275
Garrick Evansd90a3822019-11-12 17:53:08 +0900276 ctx->Start();
Garrick Evans54861622019-07-19 09:05:09 +0900277}
278
279void ArcService::OnDeviceRemoved(Device* device) {
Garrick Evans310ab552019-10-08 11:07:53 +0900280 // ARC N uses legacy single networking and only requires the arcbr0/arc0
281 // configuration. Any other device can be safely ignored.
282 if (guest_ == GuestMessage::ARC_LEGACY && !device->IsLegacyAndroid())
Garrick Evans54861622019-07-19 09:05:09 +0900283 return;
284
Garrick Evans310ab552019-10-08 11:07:53 +0900285 // If the container is down, this call does nothing.
Garrick Evans54861622019-07-19 09:05:09 +0900286 StopDevice(device);
287
288 const auto& config = device->config();
289
290 LOG(INFO) << "Removing device " << device->ifname()
291 << " bridge: " << config.host_ifname()
292 << " guest_iface: " << config.guest_ifname();
293
Garrick Evans260ff302019-07-25 11:22:50 +0900294 device->Disable();
Garrick Evans54861622019-07-19 09:05:09 +0900295 if (device->IsLegacyAndroid()) {
296 datapath_->RemoveOutboundIPv4(config.host_ifname());
297 datapath_->RemoveLegacyIPv4DNAT();
298 } else if (!device->IsAndroid()) {
299 datapath_->RemoveOutboundIPv4(config.host_ifname());
300 datapath_->RemoveInboundIPv4DNAT(
301 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
302 }
303
304 datapath_->RemoveBridge(config.host_ifname());
305
Garrick Evans2c263102019-07-26 16:07:18 +0900306 device->set_context(guest_, nullptr);
Garrick Evans54861622019-07-19 09:05:09 +0900307}
308
309void ArcService::StopDevice(Device* device) {
Garrick Evans310ab552019-10-08 11:07:53 +0900310 // This can happen if the device if OnDeviceRemoved is invoked when the
311 // container is down.
Garrick Evansd90a3822019-11-12 17:53:08 +0900312 if (!impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900313 return;
314
Garrick Evans2c263102019-07-26 16:07:18 +0900315 Context* ctx = dynamic_cast<Context*>(device->context(guest_));
316 if (!ctx) {
317 LOG(ERROR) << "Attempt to stop removed device " << device->ifname();
318 return;
319 }
320
321 if (!ctx->IsStarted()) {
322 LOG(ERROR) << "Attempt to re-stop device " << device->ifname();
323 return;
324 }
325
Garrick Evansd90a3822019-11-12 17:53:08 +0900326 impl_->OnStopDevice(device);
Garrick Evanscb791e72019-11-11 15:44:34 +0900327
328 ctx->Stop();
329}
330
Garrick Evans54861622019-07-19 09:05:09 +0900331void ArcService::OnDefaultInterfaceChanged(const std::string& ifname) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900332 impl_->OnDefaultInterfaceChanged(ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900333}
Garrick Evansba575742019-07-17 15:48:08 +0900334
Garrick Evans2c263102019-07-26 16:07:18 +0900335// Context
336
337ArcService::Context::Context() : Device::Context() {
338 Stop();
339}
340
341void ArcService::Context::Start() {
342 Stop();
343 started_ = true;
344}
345
346void ArcService::Context::Stop() {
347 started_ = false;
348 link_up_ = false;
349 routing_table_id_ = kInvalidTableID;
350 routing_table_attempts_ = 0;
351}
352
353bool ArcService::Context::IsStarted() const {
354 return started_;
355}
356
357bool ArcService::Context::IsLinkUp() const {
358 return link_up_;
359}
360
361bool ArcService::Context::SetLinkUp(bool link_up) {
362 if (link_up == link_up_)
363 return false;
364
365 link_up_ = link_up;
366 return true;
367}
368
369bool ArcService::Context::HasIPv6() const {
370 return routing_table_id_ != kInvalidTableID;
371}
372
373bool ArcService::Context::SetHasIPv6(int routing_table_id) {
374 if (routing_table_id <= kRouteControllerRouteTableOffsetFromIndex)
375 return false;
376
377 routing_table_id_ = routing_table_id;
378 return true;
379}
380
Garrick Evansdc3fc452019-09-06 14:15:04 +0900381void ArcService::Context::ClearIPv6() {
382 routing_table_id_ = kInvalidTableID;
383 routing_table_attempts_ = 0;
384}
385
Garrick Evans2c263102019-07-26 16:07:18 +0900386int ArcService::Context::RoutingTableID() const {
387 return routing_table_id_;
388}
389
390int ArcService::Context::RoutingTableAttempts() {
391 return routing_table_attempts_++;
392}
393
Garrick Evansd90a3822019-11-12 17:53:08 +0900394// ARC++ specific functions.
395
396ArcService::ContainerImpl::ContainerImpl(DeviceManagerBase* dev_mgr,
397 Datapath* datapath,
398 GuestMessage::GuestType guest)
399 : pid_(kInvalidPID),
400 dev_mgr_(dev_mgr),
401 datapath_(datapath),
402 guest_(guest) {}
403
404bool ArcService::ContainerImpl::OnStart() {
405 pid_ = GetContainerPID();
406 if (pid_ == kInvalidPID) {
407 LOG(ERROR) << "Cannot start service - invalid container PID";
408 return false;
409 }
410
411 // Start listening for RTNetlink messages in the container's net namespace
412 // to be notified whenever it brings up an interface.
413 {
414 ScopedNS ns(pid_);
415 if (ns.IsValid()) {
416 rtnl_handler_ = std::make_unique<RTNetlinkHandler>();
417 rtnl_handler_->Start(RTMGRP_LINK);
418 link_listener_ = std::make_unique<shill::RTNLListener>(
419 shill::RTNLHandler::kRequestLink,
420 Bind(&ArcService::ContainerImpl::LinkMsgHandler,
421 weak_factory_.GetWeakPtr()),
422 rtnl_handler_.get());
423 } else {
424 // This is bad - it means we won't ever be able to tell when the container
425 // brings up an interface.
426 LOG(ERROR)
427 << "Cannot start netlink listener - invalid container namespace?";
428 return false;
429 }
430 }
431
432 dev_mgr_->RegisterDeviceIPv6AddressFoundHandler(
433 guest_, base::Bind(&ArcService::ContainerImpl::SetupIPv6,
434 weak_factory_.GetWeakPtr()));
435
436 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
437 return true;
438}
439
440void ArcService::ContainerImpl::OnStop() {
441 rtnl_handler_->RemoveListener(link_listener_.get());
442 link_listener_.reset();
443 rtnl_handler_.reset();
444
445 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
446 pid_ = kInvalidPID;
447}
448
449bool ArcService::ContainerImpl::IsStarted() const {
450 return pid_ != kInvalidPID;
451}
452
453bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
454 const auto& config = device->config();
455
456 LOG(INFO) << "Starting device " << device->ifname()
457 << " bridge: " << config.host_ifname()
458 << " guest_iface: " << config.guest_ifname()
459 << " for container pid " << pid_;
460
461 std::string veth_ifname = datapath_->AddVirtualBridgedInterface(
462 device->ifname(), MacAddressToString(config.guest_mac_addr()),
463 config.host_ifname());
464 if (veth_ifname.empty()) {
465 LOG(ERROR) << "Failed to create virtual interface for container";
466 return false;
467 }
468
469 if (!datapath_->AddInterfaceToContainer(
470 pid_, veth_ifname, config.guest_ifname(),
471 IPv4AddressToString(config.guest_ipv4_addr()),
472 device->options().fwd_multicast)) {
473 LOG(ERROR) << "Failed to create container interface.";
474 datapath_->RemoveInterface(veth_ifname);
475 datapath_->RemoveBridge(config.host_ifname());
476 return false;
477 }
478
479 // Signal the container that the network device is ready.
480 // This is only applicable for arc0.
481 if (device->IsAndroid() || device->IsLegacyAndroid()) {
482 datapath_->runner().WriteSentinelToContainer(base::IntToString(pid_));
483 }
484
485 return true;
486}
487
488void ArcService::ContainerImpl::OnStopDevice(Device* device) {
489 const auto& config = device->config();
490
491 LOG(INFO) << "Stopping device " << device->ifname()
492 << " bridge: " << config.host_ifname()
493 << " guest_iface: " << config.guest_ifname()
494 << " for container pid " << pid_;
495
496 device->Disable();
497 if (!device->IsAndroid()) {
498 datapath_->RemoveInterface(ArcVethHostName(device->ifname()));
499 }
500}
501
502void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
503 const std::string& ifname) {
504 if (!IsStarted())
505 return;
506
507 // For ARC N, we must always be able to find the arc0 device and, at a
508 // minimum, disable it.
509 if (guest_ == GuestMessage::ARC_LEGACY) {
510 datapath_->RemoveLegacyIPv4InboundDNAT();
511 auto* device = dev_mgr_->FindByGuestInterface("arc0");
512 if (!device) {
513 LOG(DFATAL) << "Expected legacy Android device missing";
514 return;
515 }
516 device->Disable();
517
518 // If a new default interface was given, then re-enable with that.
519 if (!ifname.empty()) {
520 datapath_->AddLegacyIPv4InboundDNAT(ifname);
521 device->Enable(ifname);
522 }
523 return;
524 }
525
526 // For ARC P and later, we're only concerned with resetting the device when it
527 // becomes the default (again) in order to ensure any previous configuration.
528 // is cleared.
529 if (ifname.empty())
530 return;
531
532 auto* device = dev_mgr_->FindByGuestInterface(ifname);
533 if (!device) {
534 LOG(ERROR) << "Expected default device missing: " << ifname;
535 return;
536 }
537 device->StopIPv6RoutingLegacy();
538 device->StartIPv6RoutingLegacy(ifname);
539}
540
541void ArcService::ContainerImpl::LinkMsgHandler(const shill::RTNLMessage& msg) {
542 if (!msg.HasAttribute(IFLA_IFNAME)) {
543 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
544 return;
545 }
546 bool link_up = msg.link_status().flags & IFF_UP;
547 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
548 std::string ifname(reinterpret_cast<const char*>(
549 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
550
551 auto* device = dev_mgr_->FindByGuestInterface(ifname);
552 if (!device)
553 return;
554
555 Context* ctx = dynamic_cast<Context*>(device->context(guest_));
556 if (!ctx) {
557 LOG(DFATAL) << "Context missing";
558 return;
559 }
560
561 // If the link status is unchanged, there is nothing to do.
562 if (!ctx->SetLinkUp(link_up))
563 return;
564
565 if (!link_up) {
566 LOG(INFO) << ifname << " is now down";
567 return;
568 }
569 LOG(INFO) << ifname << " is now up";
570
571 if (device->IsAndroid())
572 return;
573
574 if (device->IsLegacyAndroid()) {
575 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
576 return;
577 }
578
579 device->Enable(ifname);
580}
581
582void ArcService::ContainerImpl::SetupIPv6(Device* device) {
583 device->RegisterIPv6TeardownHandler(base::Bind(
584 &ArcService::ContainerImpl::TeardownIPv6, weak_factory_.GetWeakPtr()));
585
586 auto& ipv6_config = device->ipv6_config();
587 if (ipv6_config.ifname.empty())
588 return;
589
590 Context* ctx = dynamic_cast<Context*>(device->context(guest_));
591 if (!ctx) {
592 LOG(DFATAL) << "Context missing";
593 return;
594 }
595 if (ctx->HasIPv6())
596 return;
597
598 LOG(INFO) << "Setting up IPv6 for " << ipv6_config.ifname;
599
600 int table_id =
601 GetAndroidRoutingTableId(device->config().guest_ifname(), pid_);
602 if (table_id == kInvalidTableID) {
603 if (ctx->RoutingTableAttempts() < kMaxTableRetries) {
604 LOG(INFO) << "Could not look up routing table ID for container interface "
605 << device->config().guest_ifname() << " - trying again...";
606 base::MessageLoop::current()->task_runner()->PostDelayedTask(
607 FROM_HERE,
608 base::Bind(&ArcService::ContainerImpl::SetupIPv6,
609 weak_factory_.GetWeakPtr(), device),
610 kTableRetryDelay);
611 } else {
612 LOG(DFATAL)
613 << "Could not look up routing table ID for container interface "
614 << device->config().guest_ifname();
615 }
616 return;
617 }
618
619 LOG(INFO) << "Setting IPv6 address " << ipv6_config.addr
620 << "/128, gateway=" << ipv6_config.router << " on "
621 << ipv6_config.ifname;
622
623 char buf[INET6_ADDRSTRLEN] = {0};
624 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
625 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
626 return;
627 }
628 std::string addr = buf;
629
630 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
631 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
632 return;
633 }
634 std::string router = buf;
635
636 const auto& config = device->config();
637 {
638 ScopedNS ns(pid_);
639 if (!ns.IsValid()) {
640 LOG(ERROR) << "Invalid container namespace (" << pid_
641 << ") - cannot configure IPv6.";
642 return;
643 }
644 if (!datapath_->AddIPv6GatewayRoutes(config.guest_ifname(), addr, router,
645 ipv6_config.prefix_len, table_id)) {
646 LOG(ERROR) << "Failed to setup IPv6 routes in the container";
647 return;
648 }
649 }
650
651 if (!datapath_->AddIPv6HostRoute(config.host_ifname(), addr,
652 ipv6_config.prefix_len)) {
653 LOG(ERROR) << "Failed to setup the IPv6 route for interface "
654 << config.host_ifname();
655 return;
656 }
657
658 if (!datapath_->AddIPv6Neighbor(ipv6_config.ifname, addr)) {
659 LOG(ERROR) << "Failed to setup the IPv6 neighbor proxy";
660 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
661 ipv6_config.prefix_len);
662 return;
663 }
664
665 ctx->SetHasIPv6(table_id);
666}
667
668void ArcService::ContainerImpl::TeardownIPv6(Device* device) {
669 Context* ctx = dynamic_cast<Context*>(device->context(guest_));
670 if (!ctx || !ctx->HasIPv6())
671 return;
672
673 auto& ipv6_config = device->ipv6_config();
674 LOG(INFO) << "Clearing IPv6 for " << ipv6_config.ifname;
675 int table_id = ctx->RoutingTableID();
676 ctx->ClearIPv6();
677
678 char buf[INET6_ADDRSTRLEN] = {0};
679 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
680 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
681 return;
682 }
683 std::string addr = buf;
684
685 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
686 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
687 return;
688 }
689 std::string router = buf;
690
691 const auto& config = device->config();
692 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
693 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
694 ipv6_config.prefix_len);
695
696 ScopedNS ns(pid_);
697 if (ns.IsValid()) {
698 datapath_->RemoveIPv6GatewayRoutes(config.guest_ifname(), addr, router,
699 ipv6_config.prefix_len, table_id);
700 }
701}
702
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900703} // namespace arc_networkd