blob: 34311fa75aaf5893da564ee18c9cf3fb3cead7a6 [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
Garrick Evans3388a032020-03-24 11:25:55 +09005#include "patchpanel/arc_service.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +09006
Hugo Benichi6c0233e2020-10-06 22:37:57 +09007#include <fcntl.h>
Garrick Evans54861622019-07-19 09:05:09 +09008#include <linux/rtnetlink.h>
9#include <net/if.h>
Garrick Evans6e4eb3b2020-03-09 07:18:31 +090010#include <sys/ioctl.h>
Garrick Evans71e4a862020-05-18 12:22:23 +090011#include <sys/utsname.h>
Hugo Benichi6c0233e2020-10-06 22:37:57 +090012#include <unistd.h>
Garrick Evans54861622019-07-19 09:05:09 +090013
Garrick Evans5d55f5e2019-07-17 15:28:10 +090014#include <utility>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090015#include <vector>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090016
Garrick Evans54861622019-07-19 09:05:09 +090017#include <base/bind.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090018#include <base/files/file_path.h>
19#include <base/files/file_util.h>
Hugo Benichi6c0233e2020-10-06 22:37:57 +090020#include <base/files/scoped_file.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090021#include <base/logging.h>
22#include <base/strings/string_number_conversions.h>
23#include <base/strings/string_util.h>
Garrick Evans54861622019-07-19 09:05:09 +090024#include <base/strings/stringprintf.h>
Qijiang Fan2d7aeb42020-05-19 02:06:39 +090025#include <base/system/sys_info.h>
Garrick Evans1f5a3612019-11-08 12:59:03 +090026#include <brillo/key_value_store.h>
Garrick Evansb4eb3892019-11-13 12:07:07 +090027#include <chromeos/constants/vm_tools.h>
Garrick Evans54861622019-07-19 09:05:09 +090028
Jason Jeremy Iman3081d0e2020-03-04 15:52:06 +090029#include "patchpanel/adb_proxy.h"
Garrick Evans3388a032020-03-24 11:25:55 +090030#include "patchpanel/datapath.h"
31#include "patchpanel/mac_address_generator.h"
32#include "patchpanel/manager.h"
33#include "patchpanel/minijailed_process_runner.h"
34#include "patchpanel/net_util.h"
35#include "patchpanel/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090036
Garrick Evans3388a032020-03-24 11:25:55 +090037namespace patchpanel {
Garrick Evans5d55f5e2019-07-17 15:28:10 +090038namespace {
Hugo Benichi6c0233e2020-10-06 22:37:57 +090039const int32_t kAndroidRootUid = 655360;
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +090040constexpr uint32_t kInvalidId = 0;
Hugo Benichi33860d72020-07-09 16:34:01 +090041constexpr char kArcNetnsName[] = "arc_netns";
Garrick Evanse94b6de2020-02-20 09:19:13 +090042constexpr char kArcIfname[] = "arc0";
43constexpr char kArcBridge[] = "arcbr0";
Garrick Evans6e4eb3b2020-03-09 07:18:31 +090044constexpr std::array<const char*, 2> kEthernetInterfacePrefixes{{"eth", "usb"}};
45constexpr std::array<const char*, 2> kWifiInterfacePrefixes{{"wlan", "mlan"}};
Garrick Evans86c7d9c2020-03-17 09:25:48 +090046constexpr std::array<const char*, 2> kCellInterfacePrefixes{{"wwan", "rmnet"}};
Garrick Evans54861622019-07-19 09:05:09 +090047
Garrick Evans71e4a862020-05-18 12:22:23 +090048bool KernelVersion(int* major, int* minor) {
49 struct utsname u;
50 if (uname(&u) != 0) {
51 PLOG(ERROR) << "uname failed";
52 *major = *minor = 0;
53 return false;
54 }
55 int unused;
56 if (sscanf(u.release, "%d.%d.%d", major, minor, &unused) != 3) {
57 LOG(ERROR) << "unexpected release string: " << u.release;
58 *major = *minor = 0;
59 return false;
60 }
61 return true;
62}
63
Hugo Benichif0f10c72020-07-09 10:42:45 +090064void OneTimeContainerSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090065 static bool done = false;
66 if (done)
67 return;
68
Garrick Evans6d227b92019-12-03 16:11:29 +090069 auto& runner = datapath.runner();
70
71 // Load networking modules needed by Android that are not compiled in the
72 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansc53b9702020-05-13 13:20:09 +090073 // Expected for all kernels.
Garrick Evans8e8e3472020-01-23 14:03:50 +090074 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090075 // The netfilter modules needed by netd for iptables commands.
76 "ip6table_filter",
77 "ip6t_ipv6header",
78 "ip6t_REJECT",
Garrick Evansa34b5862019-11-20 09:34:01 +090079 // The ipsec modules for AH and ESP encryption for ipv6.
80 "ah6",
81 "esp6",
82 }) != 0) {
83 LOG(ERROR) << "One or more required kernel modules failed to load."
84 << " Some Android functionality may be broken.";
85 }
Garrick Evansc53b9702020-05-13 13:20:09 +090086 // The xfrm modules needed for Android's ipsec APIs on kernels < 5.4.
Garrick Evans71e4a862020-05-18 12:22:23 +090087 int major, minor;
88 if (KernelVersion(&major, &minor) &&
89 (major < 5 || (major == 5 && minor < 4)) &&
90 runner.modprobe_all({
91 "xfrm4_mode_transport",
92 "xfrm4_mode_tunnel",
93 "xfrm6_mode_transport",
94 "xfrm6_mode_tunnel",
95 }) != 0) {
Garrick Evansc53b9702020-05-13 13:20:09 +090096 LOG(ERROR) << "One or more required kernel modules failed to load."
97 << " Some Android functionality may be broken.";
98 }
99
Garrick Evansa34b5862019-11-20 09:34:01 +0900100 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +0900101 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +0900102 // This module is not available in kernels < 3.18
103 "nf_reject_ipv6",
104 // These modules are needed for supporting Chrome traffic on Android
105 // VPN which uses Android's NAT feature. Android NAT sets up
106 // iptables
107 // rules that use these conntrack modules for FTP/TFTP.
108 "nf_nat_ftp",
109 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +0900110 // The tun module is needed by the Android 464xlat clatd process.
111 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +0900112 }) != 0) {
113 LOG(WARNING) << "One or more optional kernel modules failed to load.";
114 }
115
Garrick Evans6d227b92019-12-03 16:11:29 +0900116 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +0900117 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900118 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
119 }
120
Garrick Evansa34b5862019-11-20 09:34:01 +0900121 done = true;
122}
123
Hugo Benichi6c0233e2020-10-06 22:37:57 +0900124// Makes Android root(the owner of the mtu sysfs file for device |ifname|.
125void SetContainerSysfsMtuOwner(uint32_t pid,
126 const std::string& ifname,
127 const std::string& basename) {
128 const std::string current_mnt_ns = "/proc/self/ns/mnt";
129 const std::string target_mnt_ns = "/proc/" + std::to_string(pid) + "/ns/mnt";
130 const std::string sysfs_mtu_path =
131 "/sys/class/net/" + ifname + "/" + basename;
132
133 base::ScopedFD current_ns_fd(open(current_mnt_ns.c_str(), O_RDONLY));
134 if (!current_ns_fd.is_valid()) {
135 PLOG(ERROR) << " Could not open " << current_mnt_ns;
136 return;
137 }
138
139 base::ScopedFD target_ns_fd(open(target_mnt_ns.c_str(), O_RDONLY));
140 if (!target_ns_fd.is_valid()) {
141 PLOG(ERROR) << " Could not open " << target_mnt_ns;
142 return;
143 }
144
145 if (setns(target_ns_fd.get(), CLONE_NEWNS) == -1) {
146 PLOG(ERROR) << "Could not enter " << target_mnt_ns;
147 return;
148 }
149
150 if (chown(sysfs_mtu_path.c_str(), kAndroidRootUid, kAndroidRootUid) == -1)
151 LOG(ERROR) << "Failed to change ownership of " + sysfs_mtu_path;
152
153 if (setns(current_ns_fd.get(), CLONE_NEWNS) == -1)
154 PLOG(ERROR) << "Could not re-enter " << current_mnt_ns;
155}
156
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900157ArcService::InterfaceType InterfaceTypeFor(const std::string& ifname) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900158 for (const auto& prefix : kEthernetInterfacePrefixes) {
159 if (base::StartsWith(ifname, prefix,
160 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900161 return ArcService::InterfaceType::ETHERNET;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900162 }
163 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900164 for (const auto& prefix : kWifiInterfacePrefixes) {
165 if (base::StartsWith(ifname, prefix,
166 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900167 return ArcService::InterfaceType::WIFI;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900168 }
169 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900170 for (const auto& prefix : kCellInterfacePrefixes) {
171 if (base::StartsWith(ifname, prefix,
172 base::CompareCase::INSENSITIVE_ASCII)) {
173 return ArcService::InterfaceType::CELL;
174 }
175 }
176 return ArcService::InterfaceType::UNKNOWN;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900177}
178
179bool IsMulticastInterface(const std::string& ifname) {
180 if (ifname.empty()) {
181 return false;
182 }
183
184 int fd = socket(AF_INET, SOCK_DGRAM, 0);
185 if (fd < 0) {
186 // If IPv4 fails, try to open a socket using IPv6.
187 fd = socket(AF_INET6, SOCK_DGRAM, 0);
188 if (fd < 0) {
189 LOG(ERROR) << "Unable to create socket";
190 return false;
191 }
192 }
193
194 struct ifreq ifr;
195 memset(&ifr, 0, sizeof(ifr));
196 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
197 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
198 PLOG(ERROR) << "SIOCGIFFLAGS failed for " << ifname;
199 close(fd);
200 return false;
201 }
202
203 close(fd);
204 return (ifr.ifr_flags & IFF_MULTICAST);
205}
206
Hugo Benichif0f10c72020-07-09 10:42:45 +0900207// Returns the ARC management device used for VPN forwarding, ADB-over-TCP.
208std::unique_ptr<Device> MakeArcDevice(AddressManager* addr_mgr,
209 GuestMessage::GuestType guest) {
210 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(AddressManager::Guest::ARC);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900211 if (!ipv4_subnet) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900212 LOG(ERROR) << "Subnet already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900213 return nullptr;
214 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900215
Garrick Evanse94b6de2020-02-20 09:19:13 +0900216 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
217 if (!host_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900218 LOG(ERROR) << "Bridge address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900219 return nullptr;
220 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900221
Garrick Evanse94b6de2020-02-20 09:19:13 +0900222 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
223 if (!guest_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900224 LOG(ERROR) << "ARC address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900225 return nullptr;
226 }
227
Hugo Benichif0f10c72020-07-09 10:42:45 +0900228 int subnet_index = (guest == GuestMessage::ARC_VM) ? 1 : kAnySubnetIndex;
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900229
Hugo Benichif0f10c72020-07-09 10:42:45 +0900230 auto config = std::make_unique<Device::Config>(
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900231 addr_mgr->GenerateMacAddress(subnet_index), std::move(ipv4_subnet),
232 std::move(host_ipv4_addr), std::move(guest_ipv4_addr));
Garrick Evanse94b6de2020-02-20 09:19:13 +0900233
Hugo Benichif0f10c72020-07-09 10:42:45 +0900234 Device::Options opts{
235 .fwd_multicast = false,
236 .ipv6_enabled = false,
Jason Jeremy Iman3081d0e2020-03-04 15:52:06 +0900237 .adb_allowed = false,
Hugo Benichif0f10c72020-07-09 10:42:45 +0900238 };
239
240 return std::make_unique<Device>(kArcIfname, kArcBridge, kArcIfname,
241 std::move(config), opts);
242}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900243} // namespace
244
Garrick Evans69b85872020-02-04 11:40:26 +0900245ArcService::ArcService(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900246 Datapath* datapath,
247 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900248 TrafficForwarder* forwarder,
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900249 GuestMessage::GuestType guest)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900250 : shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900251 datapath_(datapath),
252 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900253 forwarder_(forwarder),
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900254 guest_(guest),
255 id_(kInvalidId) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900256 arc_device_ = MakeArcDevice(addr_mgr, guest_);
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900257 AllocateAddressConfigs();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900258 shill_client_->RegisterDevicesChangedHandler(
259 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Jie Jiang84c76a12020-04-17 16:45:20 +0900260 shill_client_->ScanDevices();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900261}
262
263ArcService::~ArcService() {
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900264 if (IsStarted()) {
265 Stop(id_);
Garrick Evans664a82f2019-12-17 12:18:05 +0900266 }
Garrick Evans54861622019-07-19 09:05:09 +0900267}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900268
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900269bool ArcService::IsStarted() const {
270 return id_ != kInvalidId;
271}
272
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900273void ArcService::AllocateAddressConfigs() {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900274 // The first usable subnet is the "other" ARC device subnet.
Garrick Evansc7071122020-04-17 12:31:57 +0900275 // As a temporary workaround, for ARCVM, allocate fixed MAC addresses.
276 uint8_t mac_addr_index = 2;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900277 // Allocate 2 subnets each for Ethernet and WiFi and 1 for LTE WAN interfaces.
278 for (const auto itype :
279 {InterfaceType::ETHERNET, InterfaceType::ETHERNET, InterfaceType::WIFI,
280 InterfaceType::WIFI, InterfaceType::CELL}) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900281 auto ipv4_subnet =
282 addr_mgr_->AllocateIPv4Subnet(AddressManager::Guest::ARC_NET);
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900283 if (!ipv4_subnet) {
284 LOG(ERROR) << "Subnet already in use or unavailable";
285 continue;
286 }
287 // For here out, use the same slices.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900288 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
289 if (!host_ipv4_addr) {
290 LOG(ERROR) << "Bridge address already in use or unavailable";
291 continue;
292 }
293 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
294 if (!guest_ipv4_addr) {
295 LOG(ERROR) << "ARC address already in use or unavailable";
296 continue;
297 }
298
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900299 MacAddress mac_addr = (guest_ == GuestMessage::ARC_VM)
Garrick Evansc7071122020-04-17 12:31:57 +0900300 ? addr_mgr_->GenerateMacAddress(mac_addr_index++)
301 : addr_mgr_->GenerateMacAddress();
Hugo Benichi8e448422020-07-07 10:49:00 +0900302 available_configs_[itype].emplace_back(std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900303 mac_addr, std::move(ipv4_subnet), std::move(host_ipv4_addr),
304 std::move(guest_ipv4_addr)));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900305 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900306
Hugo Benichi8e448422020-07-07 10:49:00 +0900307 for (const auto& kv : available_configs_)
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900308 for (const auto& c : kv.second)
Hugo Benichi8e448422020-07-07 10:49:00 +0900309 all_configs_.emplace_back(c.get());
Hugo Benichif0f10c72020-07-09 10:42:45 +0900310 // Append arc0 config so that the necessary tap device gets created.
311 all_configs_.insert(all_configs_.begin(), &arc_device_->config());
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900312}
313
314std::unique_ptr<Device::Config> ArcService::AcquireConfig(
315 const std::string& ifname) {
316 auto itype = InterfaceTypeFor(ifname);
317 if (itype == InterfaceType::UNKNOWN) {
318 LOG(ERROR) << "Unsupported interface: " << ifname;
319 return nullptr;
320 }
321
Hugo Benichi8e448422020-07-07 10:49:00 +0900322 auto& configs = available_configs_[itype];
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900323 if (configs.empty()) {
324 LOG(ERROR) << "No more addresses available. Cannot make device for "
325 << ifname;
326 return nullptr;
327 }
328 std::unique_ptr<Device::Config> config;
329 config = std::move(configs.front());
330 configs.pop_front();
331 return config;
332}
333
334void ArcService::ReleaseConfig(const std::string& ifname,
335 std::unique_ptr<Device::Config> config) {
336 auto itype = InterfaceTypeFor(ifname);
337 if (itype == InterfaceType::UNKNOWN) {
338 LOG(ERROR) << "Unsupported interface: " << ifname;
339 return;
340 }
341
Hugo Benichi8e448422020-07-07 10:49:00 +0900342 available_configs_[itype].push_front(std::move(config));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900343}
344
Garrick Evans015b0d62020-02-07 09:06:38 +0900345bool ArcService::Start(uint32_t id) {
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900346 if (IsStarted()) {
347 LOG(WARNING) << "Already running - did something crash?"
348 << " Stopping and restarting...";
349 Stop(id_);
Garrick Evansa51d0a12019-11-28 13:51:23 +0900350 }
351
Hugo Benichif0f10c72020-07-09 10:42:45 +0900352 std::string arc_device_ifname;
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900353 if (guest_ == GuestMessage::ARC_VM) {
Hugo Benichi8e448422020-07-07 10:49:00 +0900354 // Allocate TAP devices for all configs.
355 for (auto* config : all_configs_) {
356 auto mac = config->mac_addr();
357 auto tap = datapath_->AddTAP("" /* auto-generate name */, &mac,
358 nullptr /* no ipv4 subnet */,
359 vm_tools::kCrosVmUser);
360 if (tap.empty()) {
361 LOG(ERROR) << "Failed to create TAP device";
362 continue;
363 }
364
365 config->set_tap_ifname(tap);
366 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900367 arc_device_ifname = arc_device_->config().tap_ifname();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900368 } else {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900369 OneTimeContainerSetup(*datapath_);
Hugo Benichi33860d72020-07-09 16:34:01 +0900370 if (!datapath_->NetnsAttachName(kArcNetnsName, id)) {
371 LOG(ERROR) << "Failed to attach name " << kArcNetnsName << " to pid "
372 << id;
373 return false;
374 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900375 arc_device_ifname = ArcVethHostName(arc_device_->guest_ifname());
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900376 if (!datapath_->ConnectVethPair(id, kArcNetnsName, arc_device_ifname,
377 arc_device_->guest_ifname(),
378 arc_device_->config().mac_addr(),
379 arc_device_->config().guest_ipv4_addr(), 30,
380 arc_device_->options().fwd_multicast)) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900381 LOG(ERROR) << "Cannot create virtual link for device "
382 << arc_device_->phys_ifname();
383 return false;
384 }
385 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900386 id_ = id;
387
388 // Create the bridge for the management device arc0.
389 // Per crbug/1008686 this device cannot be deleted and then re-added.
390 // So instead of removing the bridge when the service stops, bring down the
391 // device instead and re-up it on restart.
392 if (!datapath_->AddBridge(kArcBridge, arc_device_->config().host_ipv4_addr(),
393 30) &&
394 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
395 LOG(ERROR) << "Failed to bring up arc bridge " << kArcBridge;
396 return false;
397 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900398
399 if (!datapath_->AddToBridge(kArcBridge, arc_device_ifname)) {
400 LOG(ERROR) << "Failed to bridge arc device " << arc_device_ifname << " to "
401 << kArcBridge;
402 return false;
403 }
Hugo Benichi33860d72020-07-09 16:34:01 +0900404 LOG(INFO) << "Started ARC management device " << *arc_device_.get();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900405
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900406 // Start already known Shill <-> ARC mapped devices.
Hugo Benichif0f10c72020-07-09 10:42:45 +0900407 for (const auto& ifname : shill_devices_)
408 AddDevice(ifname);
Garrick Evanscb791e72019-11-11 15:44:34 +0900409
Garrick Evansf29f5a32019-12-06 11:34:25 +0900410 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900411}
412
Garrick Evans015b0d62020-02-07 09:06:38 +0900413void ArcService::Stop(uint32_t id) {
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900414 if (!IsStarted()) {
415 LOG(ERROR) << "ArcService was not running";
416 return;
417 }
418
419 // After the ARC container has stopped, the pid is not known anymore.
420 if (guest_ == GuestMessage::ARC_VM && id_ != id) {
421 LOG(ERROR) << "Mismatched ARCVM CIDs " << id_ << " != " << id;
422 return;
423 }
424
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900425 // Stop Shill <-> ARC mapped devices.
Hugo Benichif0f10c72020-07-09 10:42:45 +0900426 for (const auto& ifname : shill_devices_)
427 RemoveDevice(ifname);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900428
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900429 // Per crbug/1008686 this device cannot be deleted and then re-added.
430 // So instead of removing the bridge, bring it down and mark it. This will
431 // allow us to detect if the device is re-added in case of a crash restart
432 // and do the right thing.
433 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
434 LOG(ERROR) << "Failed to bring down arc bridge "
435 << "- it may not restart correctly";
436
Hugo Benichi33860d72020-07-09 16:34:01 +0900437 if (guest_ == GuestMessage::ARC) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900438 datapath_->RemoveInterface(ArcVethHostName(arc_device_->phys_ifname()));
Hugo Benichi33860d72020-07-09 16:34:01 +0900439 if (!datapath_->NetnsDeleteName(kArcNetnsName))
440 LOG(WARNING) << "Failed to delete netns name " << kArcNetnsName;
Hugo Benichif0f10c72020-07-09 10:42:45 +0900441 }
442
443 // Destroy allocated TAP devices if any, including the ARC management device.
444 for (auto* config : all_configs_) {
445 if (config->tap_ifname().empty())
446 continue;
447 datapath_->RemoveInterface(config->tap_ifname());
448 config->set_tap_ifname("");
Hugo Benichi33860d72020-07-09 16:34:01 +0900449 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900450
Hugo Benichi33860d72020-07-09 16:34:01 +0900451 LOG(INFO) << "Stopped ARC management device " << *arc_device_.get();
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900452 id_ = kInvalidId;
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900453}
454
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900455void ArcService::OnDevicesChanged(const std::set<std::string>& added,
456 const std::set<std::string>& removed) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900457 for (const std::string& ifname : removed) {
458 shill_devices_.erase(ifname);
459 RemoveDevice(ifname);
460 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900461
Hugo Benichif0f10c72020-07-09 10:42:45 +0900462 for (const std::string& ifname : added) {
463 shill_devices_.insert(ifname);
464 AddDevice(ifname);
465 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900466}
467
468void ArcService::AddDevice(const std::string& ifname) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900469 if (!IsStarted())
470 return;
471
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900472 if (ifname.empty())
473 return;
474
475 if (devices_.find(ifname) != devices_.end()) {
476 LOG(DFATAL) << "Attemping to add already tracked device: " << ifname;
477 return;
478 }
479
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900480 auto itype = InterfaceTypeFor(ifname);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900481 Device::Options opts{
482 .fwd_multicast = IsMulticastInterface(ifname),
483 // TODO(crbug/726815) Also enable |ipv6_enabled| for cellular networks
Hugo Benichif0f10c72020-07-09 10:42:45 +0900484 // once IPv6 is enabled on cellular networks in Shill.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900485 .ipv6_enabled =
486 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Jason Jeremy Iman3081d0e2020-03-04 15:52:06 +0900487 .adb_allowed =
488 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900489 };
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900490
491 auto config = AcquireConfig(ifname);
492 if (!config) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900493 LOG(ERROR) << "Cannot acquire a Config for " << ifname;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900494 return;
495 }
496
Garrick Evans8a067562020-05-11 12:47:30 +0900497 auto device = std::make_unique<Device>(ifname, ArcBridgeName(ifname), ifname,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900498 std::move(config), opts);
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900499 LOG(INFO) << "Starting device " << *device;
Garrick Evans54861622019-07-19 09:05:09 +0900500
501 // Create the bridge.
Hugo Benichif0f10c72020-07-09 10:42:45 +0900502 if (!datapath_->AddBridge(device->host_ifname(),
503 device->config().host_ipv4_addr(), 30)) {
504 LOG(ERROR) << "Failed to setup bridge " << device->host_ifname();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900505 return;
Garrick Evans54861622019-07-19 09:05:09 +0900506 }
507
Hugo Benichi8d622b52020-08-13 15:24:12 +0900508 datapath_->StartRoutingDevice(device->phys_ifname(), device->host_ifname(),
509 device->config().guest_ipv4_addr(),
510 TrafficSource::ARC);
Garrick Evans2c263102019-07-26 16:07:18 +0900511
Hugo Benichicf904022020-07-07 09:21:58 +0900512 std::string virtual_device_ifname;
513 if (guest_ == GuestMessage::ARC_VM) {
514 virtual_device_ifname = device->config().tap_ifname();
515 if (virtual_device_ifname.empty()) {
516 LOG(ERROR) << "No TAP device for " << *device;
517 return;
518 }
519 } else {
520 virtual_device_ifname = ArcVethHostName(device->guest_ifname());
521 if (!datapath_->ConnectVethPair(
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900522 id_, kArcNetnsName, virtual_device_ifname, device->guest_ifname(),
Hugo Benichicf904022020-07-07 09:21:58 +0900523 device->config().mac_addr(), device->config().guest_ipv4_addr(), 30,
524 device->options().fwd_multicast)) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900525 LOG(ERROR) << "Cannot create veth link for device " << *device;
Hugo Benichicf904022020-07-07 09:21:58 +0900526 return;
527 }
Hugo Benichi6c0233e2020-10-06 22:37:57 +0900528 // Allow netd to write to /sys/class/net/<guest_ifname>/mtu (b/169936104).
529 SetContainerSysfsMtuOwner(id_, device->guest_ifname(), "mtu");
Hugo Benichicf904022020-07-07 09:21:58 +0900530 }
531
532 if (!datapath_->AddToBridge(device->host_ifname(), virtual_device_ifname)) {
533 if (guest_ == GuestMessage::ARC) {
534 datapath_->RemoveInterface(virtual_device_ifname);
535 }
536 LOG(ERROR) << "Failed to bridge interface " << virtual_device_ifname;
Hugo Benichi4833fda2020-07-06 14:56:56 +0900537 return;
538 }
539
Jason Jeremy Iman3081d0e2020-03-04 15:52:06 +0900540 if (device->options().adb_allowed &&
541 !datapath_->AddAdbPortAccessRule(ifname)) {
542 LOG(ERROR) << "Failed to add ADB port access rule";
543 }
544
Hugo Benichi4833fda2020-07-06 14:56:56 +0900545 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
546 device->options().ipv6_enabled,
547 device->options().fwd_multicast);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900548 devices_.emplace(ifname, std::move(device));
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900549}
550
551void ArcService::RemoveDevice(const std::string& ifname) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900552 if (!IsStarted())
553 return;
554
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900555 const auto it = devices_.find(ifname);
556 if (it == devices_.end()) {
557 LOG(WARNING) << "Unknown device: " << ifname;
Garrick Evanscb791e72019-11-11 15:44:34 +0900558 return;
559 }
560
Hugo Benichif0f10c72020-07-09 10:42:45 +0900561 const auto* device = it->second.get();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900562 LOG(INFO) << "Removing device " << *device;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900563
Hugo Benichi4833fda2020-07-06 14:56:56 +0900564 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
565 device->options().ipv6_enabled,
566 device->options().fwd_multicast);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900567
568 // ARCVM TAP devices are removed in VmImpl::Stop() when the service stops
Hugo Benichi4833fda2020-07-06 14:56:56 +0900569 if (guest_ == GuestMessage::ARC)
570 datapath_->RemoveInterface(ArcVethHostName(device->phys_ifname()));
Garrick Evans54861622019-07-19 09:05:09 +0900571
Hugo Benichi8d622b52020-08-13 15:24:12 +0900572 datapath_->StopRoutingDevice(device->phys_ifname(), device->host_ifname(),
573 device->config().guest_ipv4_addr(),
574 TrafficSource::ARC);
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900575 datapath_->RemoveBridge(device->host_ifname());
Jason Jeremy Iman3081d0e2020-03-04 15:52:06 +0900576 if (device->options().adb_allowed)
577 datapath_->DeleteAdbPortAccessRule(ifname);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900578
579 ReleaseConfig(ifname, it->second->release_config());
580 devices_.erase(it);
Garrick Evanscb791e72019-11-11 15:44:34 +0900581}
582
Garrick Evans38b25a42020-04-06 15:17:42 +0900583std::vector<const Device::Config*> ArcService::GetDeviceConfigs() const {
Hugo Benichi8e448422020-07-07 10:49:00 +0900584 std::vector<const Device::Config*> configs;
585 for (auto* c : all_configs_)
586 configs.emplace_back(c);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900587
Hugo Benichi8e448422020-07-07 10:49:00 +0900588 return configs;
Garrick Evanse94b6de2020-02-20 09:19:13 +0900589}
Garrick Evans02e6e872020-11-30 11:53:13 +0900590
591void ArcService::ScanDevices(
592 base::RepeatingCallback<void(const Device&)> callback) const {
593 for (const auto& [_, d] : devices_)
594 callback.Run(*d.get());
595}
596
Garrick Evans3388a032020-03-24 11:25:55 +0900597} // namespace patchpanel