blob: e998d09c7a3e6db841860abd513e561eaa313c3c [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 {
Garrick Evans015b0d62020-02-07 09:06:38 +090035constexpr pid_t kInvalidPID = 0;
Garrick Evans015b0d62020-02-07 09:06:38 +090036constexpr uint32_t kInvalidCID = 0;
Hugo Benichi33860d72020-07-09 16:34:01 +090037constexpr char kArcNetnsName[] = "arc_netns";
Garrick Evanse94b6de2020-02-20 09:19:13 +090038constexpr char kArcIfname[] = "arc0";
39constexpr char kArcBridge[] = "arcbr0";
Garrick Evans6e4eb3b2020-03-09 07:18:31 +090040constexpr std::array<const char*, 2> kEthernetInterfacePrefixes{{"eth", "usb"}};
41constexpr std::array<const char*, 2> kWifiInterfacePrefixes{{"wlan", "mlan"}};
Garrick Evans86c7d9c2020-03-17 09:25:48 +090042constexpr std::array<const char*, 2> kCellInterfacePrefixes{{"wwan", "rmnet"}};
Garrick Evans54861622019-07-19 09:05:09 +090043
Garrick Evans71e4a862020-05-18 12:22:23 +090044bool KernelVersion(int* major, int* minor) {
45 struct utsname u;
46 if (uname(&u) != 0) {
47 PLOG(ERROR) << "uname failed";
48 *major = *minor = 0;
49 return false;
50 }
51 int unused;
52 if (sscanf(u.release, "%d.%d.%d", major, minor, &unused) != 3) {
53 LOG(ERROR) << "unexpected release string: " << u.release;
54 *major = *minor = 0;
55 return false;
56 }
57 return true;
58}
59
Garrick Evans6d227b92019-12-03 16:11:29 +090060void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090061 static bool done = false;
62 if (done)
63 return;
64
Garrick Evans6d227b92019-12-03 16:11:29 +090065 auto& runner = datapath.runner();
66
67 // Load networking modules needed by Android that are not compiled in the
68 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansc53b9702020-05-13 13:20:09 +090069 // Expected for all kernels.
Garrick Evans8e8e3472020-01-23 14:03:50 +090070 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090071 // The netfilter modules needed by netd for iptables commands.
72 "ip6table_filter",
73 "ip6t_ipv6header",
74 "ip6t_REJECT",
Garrick Evansa34b5862019-11-20 09:34:01 +090075 // The ipsec modules for AH and ESP encryption for ipv6.
76 "ah6",
77 "esp6",
78 }) != 0) {
79 LOG(ERROR) << "One or more required kernel modules failed to load."
80 << " Some Android functionality may be broken.";
81 }
Garrick Evansc53b9702020-05-13 13:20:09 +090082 // The xfrm modules needed for Android's ipsec APIs on kernels < 5.4.
Garrick Evans71e4a862020-05-18 12:22:23 +090083 int major, minor;
84 if (KernelVersion(&major, &minor) &&
85 (major < 5 || (major == 5 && minor < 4)) &&
86 runner.modprobe_all({
87 "xfrm4_mode_transport",
88 "xfrm4_mode_tunnel",
89 "xfrm6_mode_transport",
90 "xfrm6_mode_tunnel",
91 }) != 0) {
Garrick Evansc53b9702020-05-13 13:20:09 +090092 LOG(ERROR) << "One or more required kernel modules failed to load."
93 << " Some Android functionality may be broken.";
94 }
95
Garrick Evansa34b5862019-11-20 09:34:01 +090096 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +090097 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090098 // This module is not available in kernels < 3.18
99 "nf_reject_ipv6",
100 // These modules are needed for supporting Chrome traffic on Android
101 // VPN which uses Android's NAT feature. Android NAT sets up
102 // iptables
103 // rules that use these conntrack modules for FTP/TFTP.
104 "nf_nat_ftp",
105 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +0900106 // The tun module is needed by the Android 464xlat clatd process.
107 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +0900108 }) != 0) {
109 LOG(WARNING) << "One or more optional kernel modules failed to load.";
110 }
111
Garrick Evans6d227b92019-12-03 16:11:29 +0900112 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +0900113 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900114 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
115 }
116
Garrick Evansa34b5862019-11-20 09:34:01 +0900117 done = true;
118}
119
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900120ArcService::InterfaceType InterfaceTypeFor(const std::string& ifname) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900121 for (const auto& prefix : kEthernetInterfacePrefixes) {
122 if (base::StartsWith(ifname, prefix,
123 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900124 return ArcService::InterfaceType::ETHERNET;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900125 }
126 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900127 for (const auto& prefix : kWifiInterfacePrefixes) {
128 if (base::StartsWith(ifname, prefix,
129 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900130 return ArcService::InterfaceType::WIFI;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900131 }
132 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900133 for (const auto& prefix : kCellInterfacePrefixes) {
134 if (base::StartsWith(ifname, prefix,
135 base::CompareCase::INSENSITIVE_ASCII)) {
136 return ArcService::InterfaceType::CELL;
137 }
138 }
139 return ArcService::InterfaceType::UNKNOWN;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900140}
141
142bool IsMulticastInterface(const std::string& ifname) {
143 if (ifname.empty()) {
144 return false;
145 }
146
147 int fd = socket(AF_INET, SOCK_DGRAM, 0);
148 if (fd < 0) {
149 // If IPv4 fails, try to open a socket using IPv6.
150 fd = socket(AF_INET6, SOCK_DGRAM, 0);
151 if (fd < 0) {
152 LOG(ERROR) << "Unable to create socket";
153 return false;
154 }
155 }
156
157 struct ifreq ifr;
158 memset(&ifr, 0, sizeof(ifr));
159 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
160 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
161 PLOG(ERROR) << "SIOCGIFFLAGS failed for " << ifname;
162 close(fd);
163 return false;
164 }
165
166 close(fd);
167 return (ifr.ifr_flags & IFF_MULTICAST);
168}
169
Garrick Evanse94b6de2020-02-20 09:19:13 +0900170// Returns the configuration for the ARC management interface used for VPN
171// forwarding, ADB-over-TCP and single-networked ARCVM.
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900172std::unique_ptr<Device::Config> MakeArcConfig(
173 AddressManager* addr_mgr,
174 AddressManager::Guest guest,
175 GuestMessage::GuestType guest_type) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900176 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(guest);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900177 if (!ipv4_subnet) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900178 LOG(ERROR) << "Subnet already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900179 return nullptr;
180 }
181 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
182 if (!host_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900183 LOG(ERROR) << "Bridge address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900184 return nullptr;
185 }
186 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
187 if (!guest_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900188 LOG(ERROR) << "ARC address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900189 return nullptr;
190 }
191
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900192 int subnet_index = (guest_type == GuestMessage::ARC_VM) ? 1 : kAnySubnetIndex;
193
Garrick Evanse94b6de2020-02-20 09:19:13 +0900194 return std::make_unique<Device::Config>(
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900195 addr_mgr->GenerateMacAddress(subnet_index), std::move(ipv4_subnet),
196 std::move(host_ipv4_addr), std::move(guest_ipv4_addr));
Garrick Evanse94b6de2020-02-20 09:19:13 +0900197}
198
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900199} // namespace
200
Garrick Evans69b85872020-02-04 11:40:26 +0900201ArcService::ArcService(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900202 Datapath* datapath,
203 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900204 TrafficForwarder* forwarder,
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900205 GuestMessage::GuestType guest)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900206 : shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900207 datapath_(datapath),
208 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900209 forwarder_(forwarder),
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900210 guest_(guest) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900211 AllocateAddressConfigs();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900212 shill_client_->RegisterDevicesChangedHandler(
213 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Jie Jiang84c76a12020-04-17 16:45:20 +0900214 shill_client_->ScanDevices();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900215}
216
217ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900218 if (impl_) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900219 Stop(impl_->id());
Garrick Evans664a82f2019-12-17 12:18:05 +0900220 }
Garrick Evans54861622019-07-19 09:05:09 +0900221}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900222
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900223void ArcService::AllocateAddressConfigs() {
Hugo Benichi8e448422020-07-07 10:49:00 +0900224 available_configs_.clear();
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900225 // The first usable subnet is the "other" ARC device subnet.
Garrick Evansc7071122020-04-17 12:31:57 +0900226 // As a temporary workaround, for ARCVM, allocate fixed MAC addresses.
227 uint8_t mac_addr_index = 2;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900228 // Allocate 2 subnets each for Ethernet and WiFi and 1 for LTE WAN interfaces.
229 for (const auto itype :
230 {InterfaceType::ETHERNET, InterfaceType::ETHERNET, InterfaceType::WIFI,
231 InterfaceType::WIFI, InterfaceType::CELL}) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900232 auto ipv4_subnet =
233 addr_mgr_->AllocateIPv4Subnet(AddressManager::Guest::ARC_NET);
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900234 if (!ipv4_subnet) {
235 LOG(ERROR) << "Subnet already in use or unavailable";
236 continue;
237 }
238 // For here out, use the same slices.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900239 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
240 if (!host_ipv4_addr) {
241 LOG(ERROR) << "Bridge address already in use or unavailable";
242 continue;
243 }
244 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
245 if (!guest_ipv4_addr) {
246 LOG(ERROR) << "ARC address already in use or unavailable";
247 continue;
248 }
249
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900250 MacAddress mac_addr = (guest_ == GuestMessage::ARC_VM)
Garrick Evansc7071122020-04-17 12:31:57 +0900251 ? addr_mgr_->GenerateMacAddress(mac_addr_index++)
252 : addr_mgr_->GenerateMacAddress();
Hugo Benichi8e448422020-07-07 10:49:00 +0900253 available_configs_[itype].emplace_back(std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900254 mac_addr, std::move(ipv4_subnet), std::move(host_ipv4_addr),
255 std::move(guest_ipv4_addr)));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900256 }
257}
258
Hugo Benichi8e448422020-07-07 10:49:00 +0900259void ArcService::ReallocateAddressConfigs() {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900260 std::vector<std::string> existing_devices;
261 for (const auto& d : devices_) {
262 existing_devices.emplace_back(d.first);
263 }
264 for (const auto& d : existing_devices) {
265 RemoveDevice(d);
266 }
267 AllocateAddressConfigs();
Hugo Benichi8e448422020-07-07 10:49:00 +0900268 all_configs_.clear();
269 for (const auto& kv : available_configs_)
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900270 for (const auto& c : kv.second)
Hugo Benichi8e448422020-07-07 10:49:00 +0900271 all_configs_.emplace_back(c.get());
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900272 for (const auto& d : existing_devices) {
273 AddDevice(d);
274 }
275}
276
277std::unique_ptr<Device::Config> ArcService::AcquireConfig(
278 const std::string& ifname) {
279 auto itype = InterfaceTypeFor(ifname);
280 if (itype == InterfaceType::UNKNOWN) {
281 LOG(ERROR) << "Unsupported interface: " << ifname;
282 return nullptr;
283 }
284
Hugo Benichi8e448422020-07-07 10:49:00 +0900285 auto& configs = available_configs_[itype];
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900286 if (configs.empty()) {
287 LOG(ERROR) << "No more addresses available. Cannot make device for "
288 << ifname;
289 return nullptr;
290 }
291 std::unique_ptr<Device::Config> config;
292 config = std::move(configs.front());
293 configs.pop_front();
294 return config;
295}
296
297void ArcService::ReleaseConfig(const std::string& ifname,
298 std::unique_ptr<Device::Config> config) {
299 auto itype = InterfaceTypeFor(ifname);
300 if (itype == InterfaceType::UNKNOWN) {
301 LOG(ERROR) << "Unsupported interface: " << ifname;
302 return;
303 }
304
Hugo Benichi8e448422020-07-07 10:49:00 +0900305 available_configs_[itype].push_front(std::move(config));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900306}
307
Garrick Evans015b0d62020-02-07 09:06:38 +0900308bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900309 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900310 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900311 if (impl_->IsStarted(&prev_id)) {
312 LOG(WARNING) << "Already running - did something crash?"
313 << " Stopping and restarting...";
314 Stop(prev_id);
315 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900316 }
317
Hugo Benichi8e448422020-07-07 10:49:00 +0900318 ReallocateAddressConfigs();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900319 std::unique_ptr<Device::Config> arc_device_config =
320 MakeArcConfig(addr_mgr_, AddressManager::Guest::ARC, guest_);
321 if (guest_ == GuestMessage::ARC_VM) {
322 // Append arc0 config separately from ArcService::ReallocateAddressConfigs()
323 // so that VmImpl::Start() can create the necessary tap device.
Hugo Benichi8e448422020-07-07 10:49:00 +0900324 all_configs_.insert(all_configs_.begin(), arc_device_config.get());
325 // Allocate TAP devices for all configs.
326 for (auto* config : all_configs_) {
327 auto mac = config->mac_addr();
328 auto tap = datapath_->AddTAP("" /* auto-generate name */, &mac,
329 nullptr /* no ipv4 subnet */,
330 vm_tools::kCrosVmUser);
331 if (tap.empty()) {
332 LOG(ERROR) << "Failed to create TAP device";
333 continue;
334 }
335
336 config->set_tap_ifname(tap);
337 }
338 impl_ = std::make_unique<VmImpl>(datapath_);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900339 } else {
Hugo Benichi4833fda2020-07-06 14:56:56 +0900340 impl_ = std::make_unique<ContainerImpl>(datapath_);
Hugo Benichi33860d72020-07-09 16:34:01 +0900341 if (!datapath_->NetnsAttachName(kArcNetnsName, id)) {
342 LOG(ERROR) << "Failed to attach name " << kArcNetnsName << " to pid "
343 << id;
344 return false;
345 }
Garrick Evans2961c7c2020-04-03 11:34:40 +0900346 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900347 if (!impl_->Start(id)) {
348 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900349 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900350 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900351
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900352 // Create the bridge for the management device arc0.
353 // Per crbug/1008686 this device cannot be deleted and then re-added.
354 // So instead of removing the bridge when the service stops, bring down the
355 // device instead and re-up it on restart.
356 if (!datapath_->AddBridge(kArcBridge, arc_device_config->host_ipv4_addr(),
357 30) &&
358 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
359 LOG(ERROR) << "Failed to bring up arc bridge " << kArcBridge;
360 return false;
361 }
362
363 Device::Options opts{
364 .fwd_multicast = false,
365 .ipv6_enabled = false,
366 };
367 arc_device_ = std::make_unique<Device>(kArcIfname, kArcBridge, kArcIfname,
368 std::move(arc_device_config), opts);
369
370 std::string arc_device_ifname;
371 if (guest_ == GuestMessage::ARC_VM) {
372 arc_device_ifname = arc_device_->config().tap_ifname();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900373 } else {
374 arc_device_ifname = ArcVethHostName(arc_device_->guest_ifname());
Hugo Benichi33860d72020-07-09 16:34:01 +0900375 if (!datapath_->ConnectVethPair(
376 impl_->id(), kArcNetnsName, arc_device_ifname,
377 arc_device_->guest_ifname(), arc_device_->config().mac_addr(),
378 arc_device_->config().guest_ipv4_addr(), 30,
379 arc_device_->options().fwd_multicast)) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900380 LOG(ERROR) << "Cannot create virtual link for device "
381 << arc_device_->phys_ifname();
382 return false;
383 }
384 }
385
386 if (!datapath_->AddToBridge(kArcBridge, arc_device_ifname)) {
387 LOG(ERROR) << "Failed to bridge arc device " << arc_device_ifname << " to "
388 << kArcBridge;
389 return false;
390 }
Hugo Benichi33860d72020-07-09 16:34:01 +0900391 LOG(INFO) << "Started ARC management device " << *arc_device_.get();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900392
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900393 // Start already known Shill <-> ARC mapped devices.
394 for (const auto& d : devices_)
395 StartDevice(d.second.get());
Garrick Evanscb791e72019-11-11 15:44:34 +0900396
Garrick Evansf29f5a32019-12-06 11:34:25 +0900397 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900398}
399
Garrick Evans015b0d62020-02-07 09:06:38 +0900400void ArcService::Stop(uint32_t id) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900401 // Stop Shill <-> ARC mapped devices.
402 for (const auto& d : devices_)
403 StopDevice(d.second.get());
Garrick Evansf29f5a32019-12-06 11:34:25 +0900404
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900405 // Per crbug/1008686 this device cannot be deleted and then re-added.
406 // So instead of removing the bridge, bring it down and mark it. This will
407 // allow us to detect if the device is re-added in case of a crash restart
408 // and do the right thing.
409 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
410 LOG(ERROR) << "Failed to bring down arc bridge "
411 << "- it may not restart correctly";
412
Hugo Benichi33860d72020-07-09 16:34:01 +0900413 if (guest_ == GuestMessage::ARC) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900414 datapath_->RemoveInterface(ArcVethHostName(arc_device_->phys_ifname()));
Hugo Benichi33860d72020-07-09 16:34:01 +0900415 if (!datapath_->NetnsDeleteName(kArcNetnsName))
416 LOG(WARNING) << "Failed to delete netns name " << kArcNetnsName;
Hugo Benichi8e448422020-07-07 10:49:00 +0900417 } else {
418 // Destroy pre allocated TAP devices, including the ARC management device.
419 for (const auto* config : all_configs_)
420 if (!config->tap_ifname().empty())
421 datapath_->RemoveInterface(config->tap_ifname());
Hugo Benichi33860d72020-07-09 16:34:01 +0900422 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900423
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900424 if (impl_) {
425 impl_->Stop(id);
426 impl_.reset();
427 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900428
Hugo Benichi33860d72020-07-09 16:34:01 +0900429 LOG(INFO) << "Stopped ARC management device " << *arc_device_.get();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900430 arc_device_.reset();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900431}
432
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900433void ArcService::OnDevicesChanged(const std::set<std::string>& added,
434 const std::set<std::string>& removed) {
435 for (const std::string& name : removed)
436 RemoveDevice(name);
437
438 for (const std::string& name : added)
439 AddDevice(name);
440}
441
442void ArcService::AddDevice(const std::string& ifname) {
443 if (ifname.empty())
444 return;
445
446 if (devices_.find(ifname) != devices_.end()) {
447 LOG(DFATAL) << "Attemping to add already tracked device: " << ifname;
448 return;
449 }
450
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900451 auto itype = InterfaceTypeFor(ifname);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900452 Device::Options opts{
453 .fwd_multicast = IsMulticastInterface(ifname),
454 // TODO(crbug/726815) Also enable |ipv6_enabled| for cellular networks
455 // once IPv6 is enabled on cellular networks in shill.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900456 .ipv6_enabled =
457 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900458 };
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900459
460 auto config = AcquireConfig(ifname);
461 if (!config) {
462 LOG(ERROR) << "Cannot add device for " << ifname;
463 return;
464 }
465
Garrick Evans8a067562020-05-11 12:47:30 +0900466 auto device = std::make_unique<Device>(ifname, ArcBridgeName(ifname), ifname,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900467 std::move(config), opts);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900468
469 StartDevice(device.get());
470 devices_.emplace(ifname, std::move(device));
471}
472
473void ArcService::StartDevice(Device* device) {
474 if (!impl_ || !impl_->IsStarted())
475 return;
476
Garrick Evans54861622019-07-19 09:05:09 +0900477 const auto& config = device->config();
478
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900479 LOG(INFO) << "Starting device " << *device;
Garrick Evans54861622019-07-19 09:05:09 +0900480
481 // Create the bridge.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900482 if (!datapath_->AddBridge(device->host_ifname(), config.host_ipv4_addr(),
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900483 30)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900484 LOG(ERROR) << "Failed to setup arc bridge: " << device->host_ifname();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900485 return;
Garrick Evans54861622019-07-19 09:05:09 +0900486 }
487
Garrick Evanse94b6de2020-02-20 09:19:13 +0900488 // Set up iptables.
489 if (!datapath_->AddInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900490 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
Garrick Evanse94b6de2020-02-20 09:19:13 +0900491 LOG(ERROR) << "Failed to configure ingress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900492 << device->phys_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900493
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900494 if (!datapath_->AddOutboundIPv4(device->host_ifname()))
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900495 LOG(ERROR) << "Failed to configure egress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900496 << device->phys_ifname();
Garrick Evans2c263102019-07-26 16:07:18 +0900497
Hugo Benichi4833fda2020-07-06 14:56:56 +0900498 if (!impl_->OnStartDevice(device)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900499 LOG(ERROR) << "Failed to start device " << device->phys_ifname();
Hugo Benichi4833fda2020-07-06 14:56:56 +0900500 return;
501 }
502
503 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
504 device->options().ipv6_enabled,
505 device->options().fwd_multicast);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900506}
507
508void ArcService::RemoveDevice(const std::string& ifname) {
509 const auto it = devices_.find(ifname);
510 if (it == devices_.end()) {
511 LOG(WARNING) << "Unknown device: " << ifname;
Garrick Evanscb791e72019-11-11 15:44:34 +0900512 return;
513 }
514
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900515 // If the container is down, this call does nothing.
516 StopDevice(it->second.get());
517
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900518 ReleaseConfig(ifname, it->second->release_config());
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900519 devices_.erase(it);
Garrick Evans54861622019-07-19 09:05:09 +0900520}
521
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900522void ArcService::StopDevice(Device* device) {
523 if (!impl_ || !impl_->IsStarted())
524 return;
525
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900526 LOG(INFO) << "Removing device " << *device;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900527
Hugo Benichi4833fda2020-07-06 14:56:56 +0900528 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
529 device->options().ipv6_enabled,
530 device->options().fwd_multicast);
531 // TAP devices are removed in VmImpl::Stop().
532 if (guest_ == GuestMessage::ARC)
533 datapath_->RemoveInterface(ArcVethHostName(device->phys_ifname()));
Garrick Evans54861622019-07-19 09:05:09 +0900534
535 const auto& config = device->config();
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900536 datapath_->RemoveOutboundIPv4(device->host_ifname());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900537 datapath_->RemoveInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900538 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900539 datapath_->RemoveBridge(device->host_ifname());
Garrick Evanscb791e72019-11-11 15:44:34 +0900540}
541
Garrick Evans38b25a42020-04-06 15:17:42 +0900542std::vector<const Device::Config*> ArcService::GetDeviceConfigs() const {
Hugo Benichi8e448422020-07-07 10:49:00 +0900543 std::vector<const Device::Config*> configs;
544 for (auto* c : all_configs_)
545 configs.emplace_back(c);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900546
Hugo Benichi8e448422020-07-07 10:49:00 +0900547 return configs;
Garrick Evanse94b6de2020-02-20 09:19:13 +0900548}
549
Garrick Evansd90a3822019-11-12 17:53:08 +0900550// ARC++ specific functions.
551
Hugo Benichi4833fda2020-07-06 14:56:56 +0900552ArcService::ContainerImpl::ContainerImpl(Datapath* datapath)
553 : pid_(kInvalidPID), datapath_(datapath) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900554 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900555}
Garrick Evansd90a3822019-11-12 17:53:08 +0900556
Garrick Evans015b0d62020-02-07 09:06:38 +0900557uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900558 return pid_;
559}
560
Garrick Evans015b0d62020-02-07 09:06:38 +0900561bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900562 // This could happen if something crashes and the stop signal is not sent.
563 // It can probably be addressed by stopping and restarting the service.
564 if (pid_ != kInvalidPID)
565 return false;
566
Garrick Evans4dec0c42019-11-29 12:51:57 +0900567 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900568 LOG(ERROR) << "Cannot start service - invalid container PID";
569 return false;
570 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900571 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900572
Garrick Evansd90a3822019-11-12 17:53:08 +0900573 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
574 return true;
575}
576
Garrick Evans015b0d62020-02-07 09:06:38 +0900577void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900578 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900579 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900580
Garrick Evansd90a3822019-11-12 17:53:08 +0900581 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
582 pid_ = kInvalidPID;
583}
584
Garrick Evans015b0d62020-02-07 09:06:38 +0900585bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900586 if (pid)
587 *pid = pid_;
588
Garrick Evansd90a3822019-11-12 17:53:08 +0900589 return pid_ != kInvalidPID;
590}
591
592bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900593 // Set up the virtual pair inside the container namespace.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900594 const std::string veth_ifname = ArcVethHostName(device->guest_ifname());
Hugo Benichi76675592020-04-08 14:29:57 +0900595 const auto& config = device->config();
Hugo Benichi33860d72020-07-09 16:34:01 +0900596 if (!datapath_->ConnectVethPair(pid_, kArcNetnsName, veth_ifname,
597 device->guest_ifname(), config.mac_addr(),
598 config.guest_ipv4_addr(), 30,
599 device->options().fwd_multicast)) {
Hugo Benichi76675592020-04-08 14:29:57 +0900600 LOG(ERROR) << "Cannot create virtual link for device "
601 << device->phys_ifname();
Garrick Evansd90a3822019-11-12 17:53:08 +0900602 return false;
603 }
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900604 if (!datapath_->AddToBridge(device->host_ifname(), veth_ifname)) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900605 datapath_->RemoveInterface(veth_ifname);
606 LOG(ERROR) << "Failed to bridge interface " << veth_ifname;
607 return false;
608 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900609 return true;
610}
611
Garrick Evansb4eb3892019-11-13 12:07:07 +0900612// VM specific functions
613
Hugo Benichi8e448422020-07-07 10:49:00 +0900614ArcService::VmImpl::VmImpl(Datapath* datapath)
615 : cid_(kInvalidCID), datapath_(datapath) {}
Garrick Evansb4eb3892019-11-13 12:07:07 +0900616
Garrick Evans015b0d62020-02-07 09:06:38 +0900617uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900618 return cid_;
619}
620
Garrick Evans015b0d62020-02-07 09:06:38 +0900621bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900622 // This can happen if concierge crashes and doesn't send the vm down RPC.
623 // It can probably be addressed by stopping and restarting the service.
624 if (cid_ != kInvalidCID)
625 return false;
626
Garrick Evans015b0d62020-02-07 09:06:38 +0900627 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900628 LOG(ERROR) << "Invalid VM cid " << cid;
629 return false;
630 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900631 cid_ = cid;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900632
Garrick Evanse94b6de2020-02-20 09:19:13 +0900633 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
Garrick Evansb4eb3892019-11-13 12:07:07 +0900634 return true;
635}
636
Garrick Evans015b0d62020-02-07 09:06:38 +0900637void ArcService::VmImpl::Stop(uint32_t cid) {
Garrick Evans21173b12019-11-20 15:23:16 +0900638 if (cid_ != cid) {
639 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
640 return;
641 }
642
Garrick Evansb4eb3892019-11-13 12:07:07 +0900643 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
644 cid_ = kInvalidCID;
645}
646
Garrick Evans015b0d62020-02-07 09:06:38 +0900647bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900648 if (cid)
649 *cid = cid_;
650
Garrick Evans015b0d62020-02-07 09:06:38 +0900651 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900652}
653
654bool ArcService::VmImpl::OnStartDevice(Device* device) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900655 const std::string& tap = device->config().tap_ifname();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900656 if (tap.empty()) {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900657 LOG(ERROR) << "No TAP device for: " << *device;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900658 return false;
659 }
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900660 if (!datapath_->AddToBridge(device->host_ifname(), tap)) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900661 LOG(ERROR) << "Failed to bridge TAP device " << tap;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900662 return false;
663 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900664 return true;
665}
Garrick Evans3388a032020-03-24 11:25:55 +0900666} // namespace patchpanel