blob: a9fe586076977459b0bd424288d4d904970a269a [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
Garrick Evans54861622019-07-19 09:05:09 +09007#include <linux/rtnetlink.h>
8#include <net/if.h>
Garrick Evans6e4eb3b2020-03-09 07:18:31 +09009#include <sys/ioctl.h>
Garrick Evans71e4a862020-05-18 12:22:23 +090010#include <sys/utsname.h>
Garrick Evans54861622019-07-19 09:05:09 +090011
Garrick Evans5d55f5e2019-07-17 15:28:10 +090012#include <utility>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090013#include <vector>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090014
Garrick Evans54861622019-07-19 09:05:09 +090015#include <base/bind.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090016#include <base/files/file_path.h>
17#include <base/files/file_util.h>
18#include <base/logging.h>
19#include <base/strings/string_number_conversions.h>
20#include <base/strings/string_util.h>
Garrick Evans54861622019-07-19 09:05:09 +090021#include <base/strings/stringprintf.h>
Qijiang Fan2d7aeb42020-05-19 02:06:39 +090022#include <base/system/sys_info.h>
Garrick Evans1f5a3612019-11-08 12:59:03 +090023#include <brillo/key_value_store.h>
Garrick Evansb4eb3892019-11-13 12:07:07 +090024#include <chromeos/constants/vm_tools.h>
Garrick Evans54861622019-07-19 09:05:09 +090025
Garrick Evans3388a032020-03-24 11:25:55 +090026#include "patchpanel/datapath.h"
27#include "patchpanel/mac_address_generator.h"
28#include "patchpanel/manager.h"
29#include "patchpanel/minijailed_process_runner.h"
30#include "patchpanel/net_util.h"
31#include "patchpanel/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090032
Garrick Evans3388a032020-03-24 11:25:55 +090033namespace patchpanel {
Garrick Evans5d55f5e2019-07-17 15:28:10 +090034namespace {
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +090035constexpr uint32_t kInvalidId = 0;
Hugo Benichi33860d72020-07-09 16:34:01 +090036constexpr char kArcNetnsName[] = "arc_netns";
Garrick Evanse94b6de2020-02-20 09:19:13 +090037constexpr char kArcIfname[] = "arc0";
38constexpr char kArcBridge[] = "arcbr0";
Garrick Evans6e4eb3b2020-03-09 07:18:31 +090039constexpr std::array<const char*, 2> kEthernetInterfacePrefixes{{"eth", "usb"}};
40constexpr std::array<const char*, 2> kWifiInterfacePrefixes{{"wlan", "mlan"}};
Garrick Evans86c7d9c2020-03-17 09:25:48 +090041constexpr std::array<const char*, 2> kCellInterfacePrefixes{{"wwan", "rmnet"}};
Garrick Evans54861622019-07-19 09:05:09 +090042
Garrick Evans71e4a862020-05-18 12:22:23 +090043bool KernelVersion(int* major, int* minor) {
44 struct utsname u;
45 if (uname(&u) != 0) {
46 PLOG(ERROR) << "uname failed";
47 *major = *minor = 0;
48 return false;
49 }
50 int unused;
51 if (sscanf(u.release, "%d.%d.%d", major, minor, &unused) != 3) {
52 LOG(ERROR) << "unexpected release string: " << u.release;
53 *major = *minor = 0;
54 return false;
55 }
56 return true;
57}
58
Hugo Benichif0f10c72020-07-09 10:42:45 +090059void OneTimeContainerSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090060 static bool done = false;
61 if (done)
62 return;
63
Garrick Evans6d227b92019-12-03 16:11:29 +090064 auto& runner = datapath.runner();
65
66 // Load networking modules needed by Android that are not compiled in the
67 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansc53b9702020-05-13 13:20:09 +090068 // Expected for all kernels.
Garrick Evans8e8e3472020-01-23 14:03:50 +090069 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090070 // The netfilter modules needed by netd for iptables commands.
71 "ip6table_filter",
72 "ip6t_ipv6header",
73 "ip6t_REJECT",
Garrick Evansa34b5862019-11-20 09:34:01 +090074 // The ipsec modules for AH and ESP encryption for ipv6.
75 "ah6",
76 "esp6",
77 }) != 0) {
78 LOG(ERROR) << "One or more required kernel modules failed to load."
79 << " Some Android functionality may be broken.";
80 }
Garrick Evansc53b9702020-05-13 13:20:09 +090081 // The xfrm modules needed for Android's ipsec APIs on kernels < 5.4.
Garrick Evans71e4a862020-05-18 12:22:23 +090082 int major, minor;
83 if (KernelVersion(&major, &minor) &&
84 (major < 5 || (major == 5 && minor < 4)) &&
85 runner.modprobe_all({
86 "xfrm4_mode_transport",
87 "xfrm4_mode_tunnel",
88 "xfrm6_mode_transport",
89 "xfrm6_mode_tunnel",
90 }) != 0) {
Garrick Evansc53b9702020-05-13 13:20:09 +090091 LOG(ERROR) << "One or more required kernel modules failed to load."
92 << " Some Android functionality may be broken.";
93 }
94
Garrick Evansa34b5862019-11-20 09:34:01 +090095 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +090096 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090097 // This module is not available in kernels < 3.18
98 "nf_reject_ipv6",
99 // These modules are needed for supporting Chrome traffic on Android
100 // VPN which uses Android's NAT feature. Android NAT sets up
101 // iptables
102 // rules that use these conntrack modules for FTP/TFTP.
103 "nf_nat_ftp",
104 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +0900105 // The tun module is needed by the Android 464xlat clatd process.
106 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +0900107 }) != 0) {
108 LOG(WARNING) << "One or more optional kernel modules failed to load.";
109 }
110
Garrick Evans6d227b92019-12-03 16:11:29 +0900111 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +0900112 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900113 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
114 }
115
Garrick Evansa34b5862019-11-20 09:34:01 +0900116 done = true;
117}
118
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900119ArcService::InterfaceType InterfaceTypeFor(const std::string& ifname) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900120 for (const auto& prefix : kEthernetInterfacePrefixes) {
121 if (base::StartsWith(ifname, prefix,
122 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900123 return ArcService::InterfaceType::ETHERNET;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900124 }
125 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900126 for (const auto& prefix : kWifiInterfacePrefixes) {
127 if (base::StartsWith(ifname, prefix,
128 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900129 return ArcService::InterfaceType::WIFI;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900130 }
131 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900132 for (const auto& prefix : kCellInterfacePrefixes) {
133 if (base::StartsWith(ifname, prefix,
134 base::CompareCase::INSENSITIVE_ASCII)) {
135 return ArcService::InterfaceType::CELL;
136 }
137 }
138 return ArcService::InterfaceType::UNKNOWN;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900139}
140
141bool IsMulticastInterface(const std::string& ifname) {
142 if (ifname.empty()) {
143 return false;
144 }
145
146 int fd = socket(AF_INET, SOCK_DGRAM, 0);
147 if (fd < 0) {
148 // If IPv4 fails, try to open a socket using IPv6.
149 fd = socket(AF_INET6, SOCK_DGRAM, 0);
150 if (fd < 0) {
151 LOG(ERROR) << "Unable to create socket";
152 return false;
153 }
154 }
155
156 struct ifreq ifr;
157 memset(&ifr, 0, sizeof(ifr));
158 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
159 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
160 PLOG(ERROR) << "SIOCGIFFLAGS failed for " << ifname;
161 close(fd);
162 return false;
163 }
164
165 close(fd);
166 return (ifr.ifr_flags & IFF_MULTICAST);
167}
168
Hugo Benichif0f10c72020-07-09 10:42:45 +0900169// Returns the ARC management device used for VPN forwarding, ADB-over-TCP.
170std::unique_ptr<Device> MakeArcDevice(AddressManager* addr_mgr,
171 GuestMessage::GuestType guest) {
172 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(AddressManager::Guest::ARC);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900173 if (!ipv4_subnet) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900174 LOG(ERROR) << "Subnet already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900175 return nullptr;
176 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900177
Garrick Evanse94b6de2020-02-20 09:19:13 +0900178 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
179 if (!host_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900180 LOG(ERROR) << "Bridge address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900181 return nullptr;
182 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900183
Garrick Evanse94b6de2020-02-20 09:19:13 +0900184 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
185 if (!guest_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900186 LOG(ERROR) << "ARC address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900187 return nullptr;
188 }
189
Hugo Benichif0f10c72020-07-09 10:42:45 +0900190 int subnet_index = (guest == GuestMessage::ARC_VM) ? 1 : kAnySubnetIndex;
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900191
Hugo Benichif0f10c72020-07-09 10:42:45 +0900192 auto config = std::make_unique<Device::Config>(
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900193 addr_mgr->GenerateMacAddress(subnet_index), std::move(ipv4_subnet),
194 std::move(host_ipv4_addr), std::move(guest_ipv4_addr));
Garrick Evanse94b6de2020-02-20 09:19:13 +0900195
Hugo Benichif0f10c72020-07-09 10:42:45 +0900196 Device::Options opts{
197 .fwd_multicast = false,
198 .ipv6_enabled = false,
199 };
200
201 return std::make_unique<Device>(kArcIfname, kArcBridge, kArcIfname,
202 std::move(config), opts);
203}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900204} // namespace
205
Garrick Evans69b85872020-02-04 11:40:26 +0900206ArcService::ArcService(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900207 Datapath* datapath,
208 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900209 TrafficForwarder* forwarder,
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900210 GuestMessage::GuestType guest)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900211 : shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900212 datapath_(datapath),
213 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900214 forwarder_(forwarder),
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900215 guest_(guest),
216 id_(kInvalidId) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900217 arc_device_ = MakeArcDevice(addr_mgr, guest_);
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900218 AllocateAddressConfigs();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900219 shill_client_->RegisterDevicesChangedHandler(
220 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Jie Jiang84c76a12020-04-17 16:45:20 +0900221 shill_client_->ScanDevices();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900222}
223
224ArcService::~ArcService() {
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900225 if (IsStarted()) {
226 Stop(id_);
Garrick Evans664a82f2019-12-17 12:18:05 +0900227 }
Garrick Evans54861622019-07-19 09:05:09 +0900228}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900229
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900230bool ArcService::IsStarted() const {
231 return id_ != kInvalidId;
232}
233
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900234void ArcService::AllocateAddressConfigs() {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900235 // The first usable subnet is the "other" ARC device subnet.
Garrick Evansc7071122020-04-17 12:31:57 +0900236 // As a temporary workaround, for ARCVM, allocate fixed MAC addresses.
237 uint8_t mac_addr_index = 2;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900238 // Allocate 2 subnets each for Ethernet and WiFi and 1 for LTE WAN interfaces.
239 for (const auto itype :
240 {InterfaceType::ETHERNET, InterfaceType::ETHERNET, InterfaceType::WIFI,
241 InterfaceType::WIFI, InterfaceType::CELL}) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900242 auto ipv4_subnet =
243 addr_mgr_->AllocateIPv4Subnet(AddressManager::Guest::ARC_NET);
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900244 if (!ipv4_subnet) {
245 LOG(ERROR) << "Subnet already in use or unavailable";
246 continue;
247 }
248 // For here out, use the same slices.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900249 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
250 if (!host_ipv4_addr) {
251 LOG(ERROR) << "Bridge address already in use or unavailable";
252 continue;
253 }
254 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
255 if (!guest_ipv4_addr) {
256 LOG(ERROR) << "ARC address already in use or unavailable";
257 continue;
258 }
259
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900260 MacAddress mac_addr = (guest_ == GuestMessage::ARC_VM)
Garrick Evansc7071122020-04-17 12:31:57 +0900261 ? addr_mgr_->GenerateMacAddress(mac_addr_index++)
262 : addr_mgr_->GenerateMacAddress();
Hugo Benichi8e448422020-07-07 10:49:00 +0900263 available_configs_[itype].emplace_back(std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900264 mac_addr, std::move(ipv4_subnet), std::move(host_ipv4_addr),
265 std::move(guest_ipv4_addr)));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900266 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900267
Hugo Benichi8e448422020-07-07 10:49:00 +0900268 for (const auto& kv : available_configs_)
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900269 for (const auto& c : kv.second)
Hugo Benichi8e448422020-07-07 10:49:00 +0900270 all_configs_.emplace_back(c.get());
Hugo Benichif0f10c72020-07-09 10:42:45 +0900271 // Append arc0 config so that the necessary tap device gets created.
272 all_configs_.insert(all_configs_.begin(), &arc_device_->config());
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900273}
274
275std::unique_ptr<Device::Config> ArcService::AcquireConfig(
276 const std::string& ifname) {
277 auto itype = InterfaceTypeFor(ifname);
278 if (itype == InterfaceType::UNKNOWN) {
279 LOG(ERROR) << "Unsupported interface: " << ifname;
280 return nullptr;
281 }
282
Hugo Benichi8e448422020-07-07 10:49:00 +0900283 auto& configs = available_configs_[itype];
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900284 if (configs.empty()) {
285 LOG(ERROR) << "No more addresses available. Cannot make device for "
286 << ifname;
287 return nullptr;
288 }
289 std::unique_ptr<Device::Config> config;
290 config = std::move(configs.front());
291 configs.pop_front();
292 return config;
293}
294
295void ArcService::ReleaseConfig(const std::string& ifname,
296 std::unique_ptr<Device::Config> config) {
297 auto itype = InterfaceTypeFor(ifname);
298 if (itype == InterfaceType::UNKNOWN) {
299 LOG(ERROR) << "Unsupported interface: " << ifname;
300 return;
301 }
302
Hugo Benichi8e448422020-07-07 10:49:00 +0900303 available_configs_[itype].push_front(std::move(config));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900304}
305
Garrick Evans015b0d62020-02-07 09:06:38 +0900306bool ArcService::Start(uint32_t id) {
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900307 if (IsStarted()) {
308 LOG(WARNING) << "Already running - did something crash?"
309 << " Stopping and restarting...";
310 Stop(id_);
Garrick Evansa51d0a12019-11-28 13:51:23 +0900311 }
312
Hugo Benichif0f10c72020-07-09 10:42:45 +0900313 std::string arc_device_ifname;
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900314 if (guest_ == GuestMessage::ARC_VM) {
Hugo Benichi8e448422020-07-07 10:49:00 +0900315 // Allocate TAP devices for all configs.
316 for (auto* config : all_configs_) {
317 auto mac = config->mac_addr();
318 auto tap = datapath_->AddTAP("" /* auto-generate name */, &mac,
319 nullptr /* no ipv4 subnet */,
320 vm_tools::kCrosVmUser);
321 if (tap.empty()) {
322 LOG(ERROR) << "Failed to create TAP device";
323 continue;
324 }
325
326 config->set_tap_ifname(tap);
327 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900328 arc_device_ifname = arc_device_->config().tap_ifname();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900329 } else {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900330 OneTimeContainerSetup(*datapath_);
Hugo Benichi33860d72020-07-09 16:34:01 +0900331 if (!datapath_->NetnsAttachName(kArcNetnsName, id)) {
332 LOG(ERROR) << "Failed to attach name " << kArcNetnsName << " to pid "
333 << id;
334 return false;
335 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900336 arc_device_ifname = ArcVethHostName(arc_device_->guest_ifname());
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900337 if (!datapath_->ConnectVethPair(id, kArcNetnsName, arc_device_ifname,
338 arc_device_->guest_ifname(),
339 arc_device_->config().mac_addr(),
340 arc_device_->config().guest_ipv4_addr(), 30,
341 arc_device_->options().fwd_multicast)) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900342 LOG(ERROR) << "Cannot create virtual link for device "
343 << arc_device_->phys_ifname();
344 return false;
345 }
346 }
Hugo Benichif0f10c72020-07-09 10:42:45 +0900347 id_ = id;
348
349 // Create the bridge for the management device arc0.
350 // Per crbug/1008686 this device cannot be deleted and then re-added.
351 // So instead of removing the bridge when the service stops, bring down the
352 // device instead and re-up it on restart.
353 if (!datapath_->AddBridge(kArcBridge, arc_device_->config().host_ipv4_addr(),
354 30) &&
355 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
356 LOG(ERROR) << "Failed to bring up arc bridge " << kArcBridge;
357 return false;
358 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900359
360 if (!datapath_->AddToBridge(kArcBridge, arc_device_ifname)) {
361 LOG(ERROR) << "Failed to bridge arc device " << arc_device_ifname << " to "
362 << kArcBridge;
363 return false;
364 }
Hugo Benichi33860d72020-07-09 16:34:01 +0900365 LOG(INFO) << "Started ARC management device " << *arc_device_.get();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900366
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900367 // Start already known Shill <-> ARC mapped devices.
Hugo Benichif0f10c72020-07-09 10:42:45 +0900368 for (const auto& ifname : shill_devices_)
369 AddDevice(ifname);
Garrick Evanscb791e72019-11-11 15:44:34 +0900370
Garrick Evansf29f5a32019-12-06 11:34:25 +0900371 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900372}
373
Garrick Evans015b0d62020-02-07 09:06:38 +0900374void ArcService::Stop(uint32_t id) {
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900375 if (!IsStarted()) {
376 LOG(ERROR) << "ArcService was not running";
377 return;
378 }
379
380 // After the ARC container has stopped, the pid is not known anymore.
381 if (guest_ == GuestMessage::ARC_VM && id_ != id) {
382 LOG(ERROR) << "Mismatched ARCVM CIDs " << id_ << " != " << id;
383 return;
384 }
385
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900386 // Stop Shill <-> ARC mapped devices.
Hugo Benichif0f10c72020-07-09 10:42:45 +0900387 for (const auto& ifname : shill_devices_)
388 RemoveDevice(ifname);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900389
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900390 // Per crbug/1008686 this device cannot be deleted and then re-added.
391 // So instead of removing the bridge, bring it down and mark it. This will
392 // allow us to detect if the device is re-added in case of a crash restart
393 // and do the right thing.
394 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
395 LOG(ERROR) << "Failed to bring down arc bridge "
396 << "- it may not restart correctly";
397
Hugo Benichi33860d72020-07-09 16:34:01 +0900398 if (guest_ == GuestMessage::ARC) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900399 datapath_->RemoveInterface(ArcVethHostName(arc_device_->phys_ifname()));
Hugo Benichi33860d72020-07-09 16:34:01 +0900400 if (!datapath_->NetnsDeleteName(kArcNetnsName))
401 LOG(WARNING) << "Failed to delete netns name " << kArcNetnsName;
Hugo Benichif0f10c72020-07-09 10:42:45 +0900402 }
403
404 // Destroy allocated TAP devices if any, including the ARC management device.
405 for (auto* config : all_configs_) {
406 if (config->tap_ifname().empty())
407 continue;
408 datapath_->RemoveInterface(config->tap_ifname());
409 config->set_tap_ifname("");
Hugo Benichi33860d72020-07-09 16:34:01 +0900410 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900411
Hugo Benichi33860d72020-07-09 16:34:01 +0900412 LOG(INFO) << "Stopped ARC management device " << *arc_device_.get();
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900413 id_ = kInvalidId;
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900414}
415
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900416void ArcService::OnDevicesChanged(const std::set<std::string>& added,
417 const std::set<std::string>& removed) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900418 for (const std::string& ifname : removed) {
419 shill_devices_.erase(ifname);
420 RemoveDevice(ifname);
421 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900422
Hugo Benichif0f10c72020-07-09 10:42:45 +0900423 for (const std::string& ifname : added) {
424 shill_devices_.insert(ifname);
425 AddDevice(ifname);
426 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900427}
428
429void ArcService::AddDevice(const std::string& ifname) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900430 if (!IsStarted())
431 return;
432
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900433 if (ifname.empty())
434 return;
435
436 if (devices_.find(ifname) != devices_.end()) {
437 LOG(DFATAL) << "Attemping to add already tracked device: " << ifname;
438 return;
439 }
440
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900441 auto itype = InterfaceTypeFor(ifname);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900442 Device::Options opts{
443 .fwd_multicast = IsMulticastInterface(ifname),
444 // TODO(crbug/726815) Also enable |ipv6_enabled| for cellular networks
Hugo Benichif0f10c72020-07-09 10:42:45 +0900445 // once IPv6 is enabled on cellular networks in Shill.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900446 .ipv6_enabled =
447 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900448 };
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900449
450 auto config = AcquireConfig(ifname);
451 if (!config) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900452 LOG(ERROR) << "Cannot acquire a Config for " << ifname;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900453 return;
454 }
455
Garrick Evans8a067562020-05-11 12:47:30 +0900456 auto device = std::make_unique<Device>(ifname, ArcBridgeName(ifname), ifname,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900457 std::move(config), opts);
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900458 LOG(INFO) << "Starting device " << *device;
Garrick Evans54861622019-07-19 09:05:09 +0900459
460 // Create the bridge.
Hugo Benichif0f10c72020-07-09 10:42:45 +0900461 if (!datapath_->AddBridge(device->host_ifname(),
462 device->config().host_ipv4_addr(), 30)) {
463 LOG(ERROR) << "Failed to setup bridge " << device->host_ifname();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900464 return;
Garrick Evans54861622019-07-19 09:05:09 +0900465 }
466
Garrick Evanse94b6de2020-02-20 09:19:13 +0900467 // Set up iptables.
468 if (!datapath_->AddInboundIPv4DNAT(
Hugo Benichif0f10c72020-07-09 10:42:45 +0900469 device->phys_ifname(),
470 IPv4AddressToString(device->config().guest_ipv4_addr())))
Garrick Evanse94b6de2020-02-20 09:19:13 +0900471 LOG(ERROR) << "Failed to configure ingress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900472 << device->phys_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900473
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900474 if (!datapath_->AddOutboundIPv4(device->host_ifname()))
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900475 LOG(ERROR) << "Failed to configure egress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900476 << device->phys_ifname();
Garrick Evans2c263102019-07-26 16:07:18 +0900477
Hugo Benichicf904022020-07-07 09:21:58 +0900478 std::string virtual_device_ifname;
479 if (guest_ == GuestMessage::ARC_VM) {
480 virtual_device_ifname = device->config().tap_ifname();
481 if (virtual_device_ifname.empty()) {
482 LOG(ERROR) << "No TAP device for " << *device;
483 return;
484 }
485 } else {
486 virtual_device_ifname = ArcVethHostName(device->guest_ifname());
487 if (!datapath_->ConnectVethPair(
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900488 id_, kArcNetnsName, virtual_device_ifname, device->guest_ifname(),
Hugo Benichicf904022020-07-07 09:21:58 +0900489 device->config().mac_addr(), device->config().guest_ipv4_addr(), 30,
490 device->options().fwd_multicast)) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900491 LOG(ERROR) << "Cannot create veth link for device " << *device;
Hugo Benichicf904022020-07-07 09:21:58 +0900492 return;
493 }
494 }
495
496 if (!datapath_->AddToBridge(device->host_ifname(), virtual_device_ifname)) {
497 if (guest_ == GuestMessage::ARC) {
498 datapath_->RemoveInterface(virtual_device_ifname);
499 }
500 LOG(ERROR) << "Failed to bridge interface " << virtual_device_ifname;
Hugo Benichi4833fda2020-07-06 14:56:56 +0900501 return;
502 }
503
504 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
505 device->options().ipv6_enabled,
506 device->options().fwd_multicast);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900507 devices_.emplace(ifname, std::move(device));
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900508}
509
510void ArcService::RemoveDevice(const std::string& ifname) {
Hugo Benichif0f10c72020-07-09 10:42:45 +0900511 if (!IsStarted())
512 return;
513
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900514 const auto it = devices_.find(ifname);
515 if (it == devices_.end()) {
516 LOG(WARNING) << "Unknown device: " << ifname;
Garrick Evanscb791e72019-11-11 15:44:34 +0900517 return;
518 }
519
Hugo Benichif0f10c72020-07-09 10:42:45 +0900520 const auto* device = it->second.get();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900521 LOG(INFO) << "Removing device " << *device;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900522
Hugo Benichi4833fda2020-07-06 14:56:56 +0900523 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
524 device->options().ipv6_enabled,
525 device->options().fwd_multicast);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900526
527 // ARCVM TAP devices are removed in VmImpl::Stop() when the service stops
Hugo Benichi4833fda2020-07-06 14:56:56 +0900528 if (guest_ == GuestMessage::ARC)
529 datapath_->RemoveInterface(ArcVethHostName(device->phys_ifname()));
Garrick Evans54861622019-07-19 09:05:09 +0900530
531 const auto& config = device->config();
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900532 datapath_->RemoveOutboundIPv4(device->host_ifname());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900533 datapath_->RemoveInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900534 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900535 datapath_->RemoveBridge(device->host_ifname());
Hugo Benichif0f10c72020-07-09 10:42:45 +0900536
537 ReleaseConfig(ifname, it->second->release_config());
538 devices_.erase(it);
Garrick Evanscb791e72019-11-11 15:44:34 +0900539}
540
Garrick Evans38b25a42020-04-06 15:17:42 +0900541std::vector<const Device::Config*> ArcService::GetDeviceConfigs() const {
Hugo Benichi8e448422020-07-07 10:49:00 +0900542 std::vector<const Device::Config*> configs;
543 for (auto* c : all_configs_)
544 configs.emplace_back(c);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900545
Hugo Benichi8e448422020-07-07 10:49:00 +0900546 return configs;
Garrick Evanse94b6de2020-02-20 09:19:13 +0900547}
Garrick Evans3388a032020-03-24 11:25:55 +0900548} // namespace patchpanel