blob: 6e829b274e09483ab55934b1dd273506e5fd8f3e [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";
Garrick Evans6e4eb3b2020-03-09 07:18:31 +090043constexpr std::array<const char*, 2> kEthernetInterfacePrefixes{{"eth", "usb"}};
44constexpr std::array<const char*, 2> kWifiInterfacePrefixes{{"wlan", "mlan"}};
Garrick Evans86c7d9c2020-03-17 09:25:48 +090045constexpr std::array<const char*, 2> kCellInterfacePrefixes{{"wwan", "rmnet"}};
Garrick Evans54861622019-07-19 09:05:09 +090046
Garrick Evans71e4a862020-05-18 12:22:23 +090047bool KernelVersion(int* major, int* minor) {
48 struct utsname u;
49 if (uname(&u) != 0) {
50 PLOG(ERROR) << "uname failed";
51 *major = *minor = 0;
52 return false;
53 }
54 int unused;
55 if (sscanf(u.release, "%d.%d.%d", major, minor, &unused) != 3) {
56 LOG(ERROR) << "unexpected release string: " << u.release;
57 *major = *minor = 0;
58 return false;
59 }
60 return true;
61}
62
Hugo Benichif0f10c72020-07-09 10:42:45 +090063void OneTimeContainerSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090064 static bool done = false;
65 if (done)
66 return;
67
Garrick Evans6d227b92019-12-03 16:11:29 +090068 auto& runner = datapath.runner();
69
70 // Load networking modules needed by Android that are not compiled in the
71 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansc53b9702020-05-13 13:20:09 +090072 // Expected for all kernels.
Garrick Evans8e8e3472020-01-23 14:03:50 +090073 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090074 // The netfilter modules needed by netd for iptables commands.
75 "ip6table_filter",
76 "ip6t_ipv6header",
77 "ip6t_REJECT",
Garrick Evansa34b5862019-11-20 09:34:01 +090078 // The ipsec modules for AH and ESP encryption for ipv6.
79 "ah6",
80 "esp6",
81 }) != 0) {
82 LOG(ERROR) << "One or more required kernel modules failed to load."
83 << " Some Android functionality may be broken.";
84 }
Garrick Evansc53b9702020-05-13 13:20:09 +090085 // The xfrm modules needed for Android's ipsec APIs on kernels < 5.4.
Garrick Evans71e4a862020-05-18 12:22:23 +090086 int major, minor;
87 if (KernelVersion(&major, &minor) &&
88 (major < 5 || (major == 5 && minor < 4)) &&
89 runner.modprobe_all({
90 "xfrm4_mode_transport",
91 "xfrm4_mode_tunnel",
92 "xfrm6_mode_transport",
93 "xfrm6_mode_tunnel",
94 }) != 0) {
Garrick Evansc53b9702020-05-13 13:20:09 +090095 LOG(ERROR) << "One or more required kernel modules failed to load."
96 << " Some Android functionality may be broken.";
97 }
98
Garrick Evansa34b5862019-11-20 09:34:01 +090099 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +0900100 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +0900101 // This module is not available in kernels < 3.18
102 "nf_reject_ipv6",
103 // These modules are needed for supporting Chrome traffic on Android
104 // VPN which uses Android's NAT feature. Android NAT sets up
105 // iptables
106 // rules that use these conntrack modules for FTP/TFTP.
107 "nf_nat_ftp",
108 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +0900109 // The tun module is needed by the Android 464xlat clatd process.
110 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +0900111 }) != 0) {
112 LOG(WARNING) << "One or more optional kernel modules failed to load.";
113 }
114
Garrick Evans6d227b92019-12-03 16:11:29 +0900115 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +0900116 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900117 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
118 }
119
Garrick Evansa34b5862019-11-20 09:34:01 +0900120 done = true;
121}
122
Hugo Benichi6c0233e2020-10-06 22:37:57 +0900123// Makes Android root(the owner of the mtu sysfs file for device |ifname|.
124void SetContainerSysfsMtuOwner(uint32_t pid,
125 const std::string& ifname,
126 const std::string& basename) {
127 const std::string current_mnt_ns = "/proc/self/ns/mnt";
128 const std::string target_mnt_ns = "/proc/" + std::to_string(pid) + "/ns/mnt";
129 const std::string sysfs_mtu_path =
130 "/sys/class/net/" + ifname + "/" + basename;
131
132 base::ScopedFD current_ns_fd(open(current_mnt_ns.c_str(), O_RDONLY));
133 if (!current_ns_fd.is_valid()) {
134 PLOG(ERROR) << " Could not open " << current_mnt_ns;
135 return;
136 }
137
138 base::ScopedFD target_ns_fd(open(target_mnt_ns.c_str(), O_RDONLY));
139 if (!target_ns_fd.is_valid()) {
140 PLOG(ERROR) << " Could not open " << target_mnt_ns;
141 return;
142 }
143
144 if (setns(target_ns_fd.get(), CLONE_NEWNS) == -1) {
145 PLOG(ERROR) << "Could not enter " << target_mnt_ns;
146 return;
147 }
148
149 if (chown(sysfs_mtu_path.c_str(), kAndroidRootUid, kAndroidRootUid) == -1)
150 LOG(ERROR) << "Failed to change ownership of " + sysfs_mtu_path;
151
152 if (setns(current_ns_fd.get(), CLONE_NEWNS) == -1)
153 PLOG(ERROR) << "Could not re-enter " << current_mnt_ns;
154}
155
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900156ArcService::InterfaceType InterfaceTypeFor(const std::string& ifname) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900157 for (const auto& prefix : kEthernetInterfacePrefixes) {
158 if (base::StartsWith(ifname, prefix,
159 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900160 return ArcService::InterfaceType::ETHERNET;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900161 }
162 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900163 for (const auto& prefix : kWifiInterfacePrefixes) {
164 if (base::StartsWith(ifname, prefix,
165 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900166 return ArcService::InterfaceType::WIFI;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900167 }
168 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900169 for (const auto& prefix : kCellInterfacePrefixes) {
170 if (base::StartsWith(ifname, prefix,
171 base::CompareCase::INSENSITIVE_ASCII)) {
172 return ArcService::InterfaceType::CELL;
173 }
174 }
175 return ArcService::InterfaceType::UNKNOWN;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900176}
177
178bool IsMulticastInterface(const std::string& ifname) {
179 if (ifname.empty()) {
180 return false;
181 }
182
183 int fd = socket(AF_INET, SOCK_DGRAM, 0);
184 if (fd < 0) {
185 // If IPv4 fails, try to open a socket using IPv6.
186 fd = socket(AF_INET6, SOCK_DGRAM, 0);
187 if (fd < 0) {
188 LOG(ERROR) << "Unable to create socket";
189 return false;
190 }
191 }
192
193 struct ifreq ifr;
194 memset(&ifr, 0, sizeof(ifr));
195 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
196 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
197 PLOG(ERROR) << "SIOCGIFFLAGS failed for " << ifname;
198 close(fd);
199 return false;
200 }
201
202 close(fd);
203 return (ifr.ifr_flags & IFF_MULTICAST);
204}
205
Hugo Benichif0f10c72020-07-09 10:42:45 +0900206// Returns the ARC management device used for VPN forwarding, ADB-over-TCP.
207std::unique_ptr<Device> MakeArcDevice(AddressManager* addr_mgr,
208 GuestMessage::GuestType guest) {
209 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(AddressManager::Guest::ARC);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900210 if (!ipv4_subnet) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900211 LOG(ERROR) << "Subnet already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900212 return nullptr;
213 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900214
Garrick Evanse94b6de2020-02-20 09:19:13 +0900215 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
216 if (!host_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900217 LOG(ERROR) << "Bridge address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900218 return nullptr;
219 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900220
Garrick Evanse94b6de2020-02-20 09:19:13 +0900221 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
222 if (!guest_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900223 LOG(ERROR) << "ARC address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900224 return nullptr;
225 }
226
Hugo Benichif0f10c72020-07-09 10:42:45 +0900227 int subnet_index = (guest == GuestMessage::ARC_VM) ? 1 : kAnySubnetIndex;
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900228
Hugo Benichif0f10c72020-07-09 10:42:45 +0900229 auto config = std::make_unique<Device::Config>(
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900230 addr_mgr->GenerateMacAddress(subnet_index), std::move(ipv4_subnet),
231 std::move(host_ipv4_addr), std::move(guest_ipv4_addr));
Garrick Evanse94b6de2020-02-20 09:19:13 +0900232
Hugo Benichif0f10c72020-07-09 10:42:45 +0900233 Device::Options opts{
234 .fwd_multicast = false,
235 .ipv6_enabled = false,
Jason Jeremy Iman3081d0e2020-03-04 15:52:06 +0900236 .adb_allowed = false,
Hugo Benichif0f10c72020-07-09 10:42:45 +0900237 };
238
239 return std::make_unique<Device>(kArcIfname, kArcBridge, kArcIfname,
240 std::move(config), opts);
241}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900242} // namespace
243
Garrick Evans69b85872020-02-04 11:40:26 +0900244ArcService::ArcService(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900245 Datapath* datapath,
246 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900247 TrafficForwarder* forwarder,
Garrick Evans209a80a2020-11-30 14:42:40 +0900248 GuestMessage::GuestType guest,
249 Device::ChangeEventHandler device_changed_handler)
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),
Garrick Evans209a80a2020-11-30 14:42:40 +0900255 device_changed_handler_(device_changed_handler),
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900256 id_(kInvalidId) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900257 arc_device_ = MakeArcDevice(addr_mgr, guest_);
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900258 AllocateAddressConfigs();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900259 shill_client_->RegisterDevicesChangedHandler(
260 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Jie Jiang84c76a12020-04-17 16:45:20 +0900261 shill_client_->ScanDevices();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900262}
263
264ArcService::~ArcService() {
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900265 if (IsStarted()) {
266 Stop(id_);
Garrick Evans664a82f2019-12-17 12:18:05 +0900267 }
Garrick Evans54861622019-07-19 09:05:09 +0900268}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900269
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900270bool ArcService::IsStarted() const {
271 return id_ != kInvalidId;
272}
273
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900274void ArcService::AllocateAddressConfigs() {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900275 // The first usable subnet is the "other" ARC device subnet.
Garrick Evansc7071122020-04-17 12:31:57 +0900276 // As a temporary workaround, for ARCVM, allocate fixed MAC addresses.
277 uint8_t mac_addr_index = 2;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900278 // Allocate 2 subnets each for Ethernet and WiFi and 1 for LTE WAN interfaces.
279 for (const auto itype :
280 {InterfaceType::ETHERNET, InterfaceType::ETHERNET, InterfaceType::WIFI,
281 InterfaceType::WIFI, InterfaceType::CELL}) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900282 auto ipv4_subnet =
283 addr_mgr_->AllocateIPv4Subnet(AddressManager::Guest::ARC_NET);
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900284 if (!ipv4_subnet) {
285 LOG(ERROR) << "Subnet already in use or unavailable";
286 continue;
287 }
288 // For here out, use the same slices.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900289 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
290 if (!host_ipv4_addr) {
291 LOG(ERROR) << "Bridge address already in use or unavailable";
292 continue;
293 }
294 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
295 if (!guest_ipv4_addr) {
296 LOG(ERROR) << "ARC address already in use or unavailable";
297 continue;
298 }
299
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900300 MacAddress mac_addr = (guest_ == GuestMessage::ARC_VM)
Garrick Evansc7071122020-04-17 12:31:57 +0900301 ? addr_mgr_->GenerateMacAddress(mac_addr_index++)
302 : addr_mgr_->GenerateMacAddress();
Hugo Benichi8e448422020-07-07 10:49:00 +0900303 available_configs_[itype].emplace_back(std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900304 mac_addr, std::move(ipv4_subnet), std::move(host_ipv4_addr),
305 std::move(guest_ipv4_addr)));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900306 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900307
Hugo Benichi8e448422020-07-07 10:49:00 +0900308 for (const auto& kv : available_configs_)
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900309 for (const auto& c : kv.second)
Hugo Benichi8e448422020-07-07 10:49:00 +0900310 all_configs_.emplace_back(c.get());
Hugo Benichif0f10c72020-07-09 10:42:45 +0900311 // Append arc0 config so that the necessary tap device gets created.
312 all_configs_.insert(all_configs_.begin(), &arc_device_->config());
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900313}
314
315std::unique_ptr<Device::Config> ArcService::AcquireConfig(
316 const std::string& ifname) {
317 auto itype = InterfaceTypeFor(ifname);
318 if (itype == InterfaceType::UNKNOWN) {
319 LOG(ERROR) << "Unsupported interface: " << ifname;
320 return nullptr;
321 }
322
Hugo Benichi8e448422020-07-07 10:49:00 +0900323 auto& configs = available_configs_[itype];
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900324 if (configs.empty()) {
325 LOG(ERROR) << "No more addresses available. Cannot make device for "
326 << ifname;
327 return nullptr;
328 }
329 std::unique_ptr<Device::Config> config;
330 config = std::move(configs.front());
331 configs.pop_front();
332 return config;
333}
334
335void ArcService::ReleaseConfig(const std::string& ifname,
336 std::unique_ptr<Device::Config> config) {
337 auto itype = InterfaceTypeFor(ifname);
338 if (itype == InterfaceType::UNKNOWN) {
339 LOG(ERROR) << "Unsupported interface: " << ifname;
340 return;
341 }
342
Hugo Benichi8e448422020-07-07 10:49:00 +0900343 available_configs_[itype].push_front(std::move(config));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900344}
345
Garrick Evans015b0d62020-02-07 09:06:38 +0900346bool ArcService::Start(uint32_t id) {
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900347 if (IsStarted()) {
348 LOG(WARNING) << "Already running - did something crash?"
349 << " Stopping and restarting...";
350 Stop(id_);
Garrick Evansa51d0a12019-11-28 13:51:23 +0900351 }
352
Hugo Benichif0f10c72020-07-09 10:42:45 +0900353 std::string arc_device_ifname;
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900354 if (guest_ == GuestMessage::ARC_VM) {
Hugo Benichi8e448422020-07-07 10:49:00 +0900355 // Allocate TAP devices for all configs.
356 for (auto* config : all_configs_) {
357 auto mac = config->mac_addr();
358 auto tap = datapath_->AddTAP("" /* auto-generate name */, &mac,
359 nullptr /* no ipv4 subnet */,
360 vm_tools::kCrosVmUser);
361 if (tap.empty()) {
362 LOG(ERROR) << "Failed to create TAP device";
363 continue;
364 }
365
366 config->set_tap_ifname(tap);
367 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900368 arc_device_ifname = arc_device_->config().tap_ifname();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900369 } else {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900370 OneTimeContainerSetup(*datapath_);
Hugo Benichi33860d72020-07-09 16:34:01 +0900371 if (!datapath_->NetnsAttachName(kArcNetnsName, id)) {
372 LOG(ERROR) << "Failed to attach name " << kArcNetnsName << " to pid "
373 << id;
374 return false;
375 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900376 arc_device_ifname = ArcVethHostName(arc_device_->guest_ifname());
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900377 if (!datapath_->ConnectVethPair(id, kArcNetnsName, arc_device_ifname,
378 arc_device_->guest_ifname(),
379 arc_device_->config().mac_addr(),
380 arc_device_->config().guest_ipv4_addr(), 30,
381 arc_device_->options().fwd_multicast)) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900382 LOG(ERROR) << "Cannot create virtual link for device "
383 << arc_device_->phys_ifname();
384 return false;
385 }
Hugo Benichi40fbf0b2021-01-20 19:44:15 +0900386 // Allow netd to write to /sys/class/net/arc0/mtu (b/175571457).
387 SetContainerSysfsMtuOwner(id, arc_device_->guest_ifname(), "mtu");
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900388 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900389 id_ = id;
390
391 // Create the bridge for the management device arc0.
392 // Per crbug/1008686 this device cannot be deleted and then re-added.
393 // So instead of removing the bridge when the service stops, bring down the
394 // device instead and re-up it on restart.
395 if (!datapath_->AddBridge(kArcBridge, arc_device_->config().host_ipv4_addr(),
396 30) &&
397 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
398 LOG(ERROR) << "Failed to bring up arc bridge " << kArcBridge;
399 return false;
400 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900401
402 if (!datapath_->AddToBridge(kArcBridge, arc_device_ifname)) {
403 LOG(ERROR) << "Failed to bridge arc device " << arc_device_ifname << " to "
404 << kArcBridge;
405 return false;
406 }
Hugo Benichi33860d72020-07-09 16:34:01 +0900407 LOG(INFO) << "Started ARC management device " << *arc_device_.get();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900408
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900409 // Start already known Shill <-> ARC mapped devices.
Hugo Benichif0f10c72020-07-09 10:42:45 +0900410 for (const auto& ifname : shill_devices_)
411 AddDevice(ifname);
Garrick Evanscb791e72019-11-11 15:44:34 +0900412
Garrick Evansf29f5a32019-12-06 11:34:25 +0900413 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900414}
415
Garrick Evans015b0d62020-02-07 09:06:38 +0900416void ArcService::Stop(uint32_t id) {
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900417 if (!IsStarted()) {
418 LOG(ERROR) << "ArcService was not running";
419 return;
420 }
421
422 // After the ARC container has stopped, the pid is not known anymore.
423 if (guest_ == GuestMessage::ARC_VM && id_ != id) {
424 LOG(ERROR) << "Mismatched ARCVM CIDs " << id_ << " != " << id;
425 return;
426 }
427
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900428 // Stop Shill <-> ARC mapped devices.
Hugo Benichif0f10c72020-07-09 10:42:45 +0900429 for (const auto& ifname : shill_devices_)
430 RemoveDevice(ifname);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900431
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900432 // Per crbug/1008686 this device cannot be deleted and then re-added.
433 // So instead of removing the bridge, bring it down and mark it. This will
434 // allow us to detect if the device is re-added in case of a crash restart
435 // and do the right thing.
436 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
437 LOG(ERROR) << "Failed to bring down arc bridge "
438 << "- it may not restart correctly";
439
Hugo Benichi33860d72020-07-09 16:34:01 +0900440 if (guest_ == GuestMessage::ARC) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900441 datapath_->RemoveInterface(ArcVethHostName(arc_device_->phys_ifname()));
Hugo Benichi33860d72020-07-09 16:34:01 +0900442 if (!datapath_->NetnsDeleteName(kArcNetnsName))
443 LOG(WARNING) << "Failed to delete netns name " << kArcNetnsName;
Hugo Benichif0f10c72020-07-09 10:42:45 +0900444 }
445
446 // Destroy allocated TAP devices if any, including the ARC management device.
447 for (auto* config : all_configs_) {
448 if (config->tap_ifname().empty())
449 continue;
450 datapath_->RemoveInterface(config->tap_ifname());
451 config->set_tap_ifname("");
Hugo Benichi33860d72020-07-09 16:34:01 +0900452 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900453
Hugo Benichi33860d72020-07-09 16:34:01 +0900454 LOG(INFO) << "Stopped ARC management device " << *arc_device_.get();
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900455 id_ = kInvalidId;
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900456}
457
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900458void ArcService::OnDevicesChanged(const std::set<std::string>& added,
459 const std::set<std::string>& removed) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900460 for (const std::string& ifname : removed) {
461 shill_devices_.erase(ifname);
462 RemoveDevice(ifname);
463 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900464
Hugo Benichif0f10c72020-07-09 10:42:45 +0900465 for (const std::string& ifname : added) {
466 shill_devices_.insert(ifname);
467 AddDevice(ifname);
468 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900469}
470
471void ArcService::AddDevice(const std::string& ifname) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900472 if (!IsStarted())
473 return;
474
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900475 if (ifname.empty())
476 return;
477
478 if (devices_.find(ifname) != devices_.end()) {
479 LOG(DFATAL) << "Attemping to add already tracked device: " << ifname;
480 return;
481 }
482
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900483 auto itype = InterfaceTypeFor(ifname);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900484 Device::Options opts{
485 .fwd_multicast = IsMulticastInterface(ifname),
486 // TODO(crbug/726815) Also enable |ipv6_enabled| for cellular networks
Hugo Benichif0f10c72020-07-09 10:42:45 +0900487 // once IPv6 is enabled on cellular networks in Shill.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900488 .ipv6_enabled =
489 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Jason Jeremy Iman3081d0e2020-03-04 15:52:06 +0900490 .adb_allowed =
491 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900492 };
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900493
494 auto config = AcquireConfig(ifname);
495 if (!config) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900496 LOG(ERROR) << "Cannot acquire a Config for " << ifname;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900497 return;
498 }
499
Garrick Evans8a067562020-05-11 12:47:30 +0900500 auto device = std::make_unique<Device>(ifname, ArcBridgeName(ifname), ifname,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900501 std::move(config), opts);
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900502 LOG(INFO) << "Starting device " << *device;
Garrick Evans54861622019-07-19 09:05:09 +0900503
504 // Create the bridge.
Hugo Benichif0f10c72020-07-09 10:42:45 +0900505 if (!datapath_->AddBridge(device->host_ifname(),
506 device->config().host_ipv4_addr(), 30)) {
507 LOG(ERROR) << "Failed to setup bridge " << device->host_ifname();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900508 return;
Garrick Evans54861622019-07-19 09:05:09 +0900509 }
510
Hugo Benichi8d622b52020-08-13 15:24:12 +0900511 datapath_->StartRoutingDevice(device->phys_ifname(), device->host_ifname(),
512 device->config().guest_ipv4_addr(),
Hugo Benichi93306e52020-12-04 16:08:00 +0900513 TrafficSource::ARC, false /*route_on_vpn*/);
Garrick Evans2c263102019-07-26 16:07:18 +0900514
Hugo Benichicf904022020-07-07 09:21:58 +0900515 std::string virtual_device_ifname;
516 if (guest_ == GuestMessage::ARC_VM) {
517 virtual_device_ifname = device->config().tap_ifname();
518 if (virtual_device_ifname.empty()) {
519 LOG(ERROR) << "No TAP device for " << *device;
520 return;
521 }
522 } else {
523 virtual_device_ifname = ArcVethHostName(device->guest_ifname());
524 if (!datapath_->ConnectVethPair(
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900525 id_, kArcNetnsName, virtual_device_ifname, device->guest_ifname(),
Hugo Benichicf904022020-07-07 09:21:58 +0900526 device->config().mac_addr(), device->config().guest_ipv4_addr(), 30,
527 device->options().fwd_multicast)) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900528 LOG(ERROR) << "Cannot create veth link for device " << *device;
Hugo Benichicf904022020-07-07 09:21:58 +0900529 return;
530 }
Hugo Benichi6c0233e2020-10-06 22:37:57 +0900531 // Allow netd to write to /sys/class/net/<guest_ifname>/mtu (b/169936104).
532 SetContainerSysfsMtuOwner(id_, device->guest_ifname(), "mtu");
Hugo Benichicf904022020-07-07 09:21:58 +0900533 }
534
535 if (!datapath_->AddToBridge(device->host_ifname(), virtual_device_ifname)) {
536 if (guest_ == GuestMessage::ARC) {
537 datapath_->RemoveInterface(virtual_device_ifname);
538 }
539 LOG(ERROR) << "Failed to bridge interface " << virtual_device_ifname;
Hugo Benichi4833fda2020-07-06 14:56:56 +0900540 return;
541 }
542
Jason Jeremy Iman3081d0e2020-03-04 15:52:06 +0900543 if (device->options().adb_allowed &&
544 !datapath_->AddAdbPortAccessRule(ifname)) {
545 LOG(ERROR) << "Failed to add ADB port access rule";
546 }
547
Hugo Benichi4833fda2020-07-06 14:56:56 +0900548 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
549 device->options().ipv6_enabled,
550 device->options().fwd_multicast);
Garrick Evans209a80a2020-11-30 14:42:40 +0900551 device_changed_handler_.Run(*device, Device::ChangeEvent::ADDED, guest_);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900552 devices_.emplace(ifname, std::move(device));
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900553}
554
555void ArcService::RemoveDevice(const std::string& ifname) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900556 if (!IsStarted())
557 return;
558
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900559 const auto it = devices_.find(ifname);
560 if (it == devices_.end()) {
561 LOG(WARNING) << "Unknown device: " << ifname;
Garrick Evanscb791e72019-11-11 15:44:34 +0900562 return;
563 }
564
Hugo Benichif0f10c72020-07-09 10:42:45 +0900565 const auto* device = it->second.get();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900566 LOG(INFO) << "Removing device " << *device;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900567
Garrick Evans209a80a2020-11-30 14:42:40 +0900568 device_changed_handler_.Run(*device, Device::ChangeEvent::REMOVED, guest_);
569
Hugo Benichi4833fda2020-07-06 14:56:56 +0900570 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
571 device->options().ipv6_enabled,
572 device->options().fwd_multicast);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900573
574 // ARCVM TAP devices are removed in VmImpl::Stop() when the service stops
Hugo Benichi4833fda2020-07-06 14:56:56 +0900575 if (guest_ == GuestMessage::ARC)
576 datapath_->RemoveInterface(ArcVethHostName(device->phys_ifname()));
Garrick Evans54861622019-07-19 09:05:09 +0900577
Hugo Benichi8d622b52020-08-13 15:24:12 +0900578 datapath_->StopRoutingDevice(device->phys_ifname(), device->host_ifname(),
579 device->config().guest_ipv4_addr(),
Hugo Benichi93306e52020-12-04 16:08:00 +0900580 TrafficSource::ARC, false /*route_on_vpn*/);
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900581 datapath_->RemoveBridge(device->host_ifname());
Jason Jeremy Iman3081d0e2020-03-04 15:52:06 +0900582 if (device->options().adb_allowed)
583 datapath_->DeleteAdbPortAccessRule(ifname);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900584
585 ReleaseConfig(ifname, it->second->release_config());
586 devices_.erase(it);
Garrick Evanscb791e72019-11-11 15:44:34 +0900587}
588
Garrick Evans38b25a42020-04-06 15:17:42 +0900589std::vector<const Device::Config*> ArcService::GetDeviceConfigs() const {
Hugo Benichi8e448422020-07-07 10:49:00 +0900590 std::vector<const Device::Config*> configs;
591 for (auto* c : all_configs_)
592 configs.emplace_back(c);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900593
Hugo Benichi8e448422020-07-07 10:49:00 +0900594 return configs;
Garrick Evanse94b6de2020-02-20 09:19:13 +0900595}
Garrick Evans02e6e872020-11-30 11:53:13 +0900596
597void ArcService::ScanDevices(
598 base::RepeatingCallback<void(const Device&)> callback) const {
599 for (const auto& [_, d] : devices_)
600 callback.Run(*d.get());
601}
602
Garrick Evans3388a032020-03-24 11:25:55 +0900603} // namespace patchpanel