blob: 06dd3693e95240abb4174f59b5084f9546c050db [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;
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
Garrick Evans6d227b92019-12-03 16:11:29 +090059void OneTimeSetup(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
Garrick Evanse94b6de2020-02-20 09:19:13 +0900169// Returns the configuration for the ARC management interface used for VPN
170// forwarding, ADB-over-TCP and single-networked ARCVM.
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900171std::unique_ptr<Device::Config> MakeArcConfig(
172 AddressManager* addr_mgr,
173 AddressManager::Guest guest,
174 GuestMessage::GuestType guest_type) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900175 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(guest);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900176 if (!ipv4_subnet) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900177 LOG(ERROR) << "Subnet already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900178 return nullptr;
179 }
180 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
181 if (!host_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900182 LOG(ERROR) << "Bridge address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900183 return nullptr;
184 }
185 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
186 if (!guest_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900187 LOG(ERROR) << "ARC address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900188 return nullptr;
189 }
190
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900191 int subnet_index = (guest_type == GuestMessage::ARC_VM) ? 1 : kAnySubnetIndex;
192
Garrick Evanse94b6de2020-02-20 09:19:13 +0900193 return std::make_unique<Device::Config>(
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900194 addr_mgr->GenerateMacAddress(subnet_index), std::move(ipv4_subnet),
195 std::move(host_ipv4_addr), std::move(guest_ipv4_addr));
Garrick Evanse94b6de2020-02-20 09:19:13 +0900196}
197
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900198} // namespace
199
Garrick Evans69b85872020-02-04 11:40:26 +0900200ArcService::ArcService(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900201 Datapath* datapath,
202 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900203 TrafficForwarder* forwarder,
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900204 GuestMessage::GuestType guest)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900205 : shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900206 datapath_(datapath),
207 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900208 forwarder_(forwarder),
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900209 guest_(guest) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900210 AllocateAddressConfigs();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900211 shill_client_->RegisterDevicesChangedHandler(
212 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Jie Jiang84c76a12020-04-17 16:45:20 +0900213 shill_client_->ScanDevices();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900214}
215
216ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900217 if (impl_) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900218 Stop(impl_->id());
Garrick Evans664a82f2019-12-17 12:18:05 +0900219 }
Garrick Evans54861622019-07-19 09:05:09 +0900220}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900221
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900222void ArcService::AllocateAddressConfigs() {
223 configs_.clear();
224 // The first usable subnet is the "other" ARC device subnet.
Garrick Evansc7071122020-04-17 12:31:57 +0900225 // As a temporary workaround, for ARCVM, allocate fixed MAC addresses.
226 uint8_t mac_addr_index = 2;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900227 // Allocate 2 subnets each for Ethernet and WiFi and 1 for LTE WAN interfaces.
228 for (const auto itype :
229 {InterfaceType::ETHERNET, InterfaceType::ETHERNET, InterfaceType::WIFI,
230 InterfaceType::WIFI, InterfaceType::CELL}) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900231 auto ipv4_subnet =
232 addr_mgr_->AllocateIPv4Subnet(AddressManager::Guest::ARC_NET);
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900233 if (!ipv4_subnet) {
234 LOG(ERROR) << "Subnet already in use or unavailable";
235 continue;
236 }
237 // For here out, use the same slices.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900238 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
239 if (!host_ipv4_addr) {
240 LOG(ERROR) << "Bridge address already in use or unavailable";
241 continue;
242 }
243 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
244 if (!guest_ipv4_addr) {
245 LOG(ERROR) << "ARC address already in use or unavailable";
246 continue;
247 }
248
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900249 MacAddress mac_addr = (guest_ == GuestMessage::ARC_VM)
Garrick Evansc7071122020-04-17 12:31:57 +0900250 ? addr_mgr_->GenerateMacAddress(mac_addr_index++)
251 : addr_mgr_->GenerateMacAddress();
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900252 configs_[itype].emplace_back(std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900253 mac_addr, std::move(ipv4_subnet), std::move(host_ipv4_addr),
254 std::move(guest_ipv4_addr)));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900255 }
256}
257
Garrick Evans2961c7c2020-04-03 11:34:40 +0900258std::vector<Device::Config*> ArcService::ReallocateAddressConfigs() {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900259 std::vector<std::string> existing_devices;
260 for (const auto& d : devices_) {
261 existing_devices.emplace_back(d.first);
262 }
263 for (const auto& d : existing_devices) {
264 RemoveDevice(d);
265 }
266 AllocateAddressConfigs();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900267 std::vector<Device::Config*> configs;
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900268 for (const auto& kv : configs_) {
269 for (const auto& c : kv.second)
270 configs.push_back(c.get());
Garrick Evans2961c7c2020-04-03 11:34:40 +0900271 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900272 for (const auto& d : existing_devices) {
273 AddDevice(d);
274 }
Garrick Evans2961c7c2020-04-03 11:34:40 +0900275 return configs;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900276}
277
278std::unique_ptr<Device::Config> ArcService::AcquireConfig(
279 const std::string& ifname) {
280 auto itype = InterfaceTypeFor(ifname);
281 if (itype == InterfaceType::UNKNOWN) {
282 LOG(ERROR) << "Unsupported interface: " << ifname;
283 return nullptr;
284 }
285
286 auto& configs = configs_[itype];
287 if (configs.empty()) {
288 LOG(ERROR) << "No more addresses available. Cannot make device for "
289 << ifname;
290 return nullptr;
291 }
292 std::unique_ptr<Device::Config> config;
293 config = std::move(configs.front());
294 configs.pop_front();
295 return config;
296}
297
298void ArcService::ReleaseConfig(const std::string& ifname,
299 std::unique_ptr<Device::Config> config) {
300 auto itype = InterfaceTypeFor(ifname);
301 if (itype == InterfaceType::UNKNOWN) {
302 LOG(ERROR) << "Unsupported interface: " << ifname;
303 return;
304 }
305
306 configs_[itype].push_front(std::move(config));
307}
308
Garrick Evans015b0d62020-02-07 09:06:38 +0900309bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900310 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900311 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900312 if (impl_->IsStarted(&prev_id)) {
313 LOG(WARNING) << "Already running - did something crash?"
314 << " Stopping and restarting...";
315 Stop(prev_id);
316 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900317 }
318
Garrick Evans2961c7c2020-04-03 11:34:40 +0900319 auto configs = ReallocateAddressConfigs();
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900320 std::unique_ptr<Device::Config> arc_device_config =
321 MakeArcConfig(addr_mgr_, AddressManager::Guest::ARC, guest_);
322 if (guest_ == GuestMessage::ARC_VM) {
323 // Append arc0 config separately from ArcService::ReallocateAddressConfigs()
324 // so that VmImpl::Start() can create the necessary tap device.
325 configs.insert(configs.begin(), arc_device_config.get());
326 impl_ = std::make_unique<VmImpl>(datapath_, forwarder_, configs);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900327 } else {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900328 impl_ = std::make_unique<ContainerImpl>(datapath_, forwarder_);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900329 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900330 if (!impl_->Start(id)) {
331 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900332 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900333 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900334
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900335 // Create the bridge for the management device arc0.
336 // Per crbug/1008686 this device cannot be deleted and then re-added.
337 // So instead of removing the bridge when the service stops, bring down the
338 // device instead and re-up it on restart.
339 if (!datapath_->AddBridge(kArcBridge, arc_device_config->host_ipv4_addr(),
340 30) &&
341 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
342 LOG(ERROR) << "Failed to bring up arc bridge " << kArcBridge;
343 return false;
344 }
345
346 Device::Options opts{
347 .fwd_multicast = false,
348 .ipv6_enabled = false,
349 };
350 arc_device_ = std::make_unique<Device>(kArcIfname, kArcBridge, kArcIfname,
351 std::move(arc_device_config), opts);
352
353 std::string arc_device_ifname;
354 if (guest_ == GuestMessage::ARC_VM) {
355 arc_device_ifname = arc_device_->config().tap_ifname();
356 // The tap device associated with arc_device is created by VmImpl::Start().
357 } else {
358 arc_device_ifname = ArcVethHostName(arc_device_->guest_ifname());
359 if (!datapath_->ConnectVethPair(impl_->id(), arc_device_ifname,
360 arc_device_->guest_ifname(),
361 arc_device_->config().mac_addr(),
362 arc_device_->config().guest_ipv4_addr(), 30,
363 arc_device_->options().fwd_multicast)) {
364 LOG(ERROR) << "Cannot create virtual link for device "
365 << arc_device_->phys_ifname();
366 return false;
367 }
368 }
369
370 if (!datapath_->AddToBridge(kArcBridge, arc_device_ifname)) {
371 LOG(ERROR) << "Failed to bridge arc device " << arc_device_ifname << " to "
372 << kArcBridge;
373 return false;
374 }
375 LOG(INFO) << "Started ARC management device " << arc_device_.get();
376
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900377 // Start already known Shill <-> ARC mapped devices.
378 for (const auto& d : devices_)
379 StartDevice(d.second.get());
Garrick Evanscb791e72019-11-11 15:44:34 +0900380
Garrick Evansf29f5a32019-12-06 11:34:25 +0900381 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900382}
383
Garrick Evans015b0d62020-02-07 09:06:38 +0900384void ArcService::Stop(uint32_t id) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900385 // Stop Shill <-> ARC mapped devices.
386 for (const auto& d : devices_)
387 StopDevice(d.second.get());
Garrick Evansf29f5a32019-12-06 11:34:25 +0900388
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900389 // Per crbug/1008686 this device cannot be deleted and then re-added.
390 // So instead of removing the bridge, bring it down and mark it. This will
391 // allow us to detect if the device is re-added in case of a crash restart
392 // and do the right thing.
393 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
394 LOG(ERROR) << "Failed to bring down arc bridge "
395 << "- it may not restart correctly";
396
397 if (guest_ == GuestMessage::ARC)
398 datapath_->RemoveInterface(ArcVethHostName(arc_device_->phys_ifname()));
399
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900400 if (impl_) {
401 impl_->Stop(id);
402 impl_.reset();
403 }
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900404
405 LOG(INFO) << "Stopped ARC management device " << arc_device_.get();
406 arc_device_.reset();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900407}
408
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900409void ArcService::OnDevicesChanged(const std::set<std::string>& added,
410 const std::set<std::string>& removed) {
411 for (const std::string& name : removed)
412 RemoveDevice(name);
413
414 for (const std::string& name : added)
415 AddDevice(name);
416}
417
418void ArcService::AddDevice(const std::string& ifname) {
419 if (ifname.empty())
420 return;
421
422 if (devices_.find(ifname) != devices_.end()) {
423 LOG(DFATAL) << "Attemping to add already tracked device: " << ifname;
424 return;
425 }
426
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900427 auto itype = InterfaceTypeFor(ifname);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900428 Device::Options opts{
429 .fwd_multicast = IsMulticastInterface(ifname),
430 // TODO(crbug/726815) Also enable |ipv6_enabled| for cellular networks
431 // once IPv6 is enabled on cellular networks in shill.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900432 .ipv6_enabled =
433 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900434 };
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900435
436 auto config = AcquireConfig(ifname);
437 if (!config) {
438 LOG(ERROR) << "Cannot add device for " << ifname;
439 return;
440 }
441
Garrick Evans8a067562020-05-11 12:47:30 +0900442 auto device = std::make_unique<Device>(ifname, ArcBridgeName(ifname), ifname,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900443 std::move(config), opts);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900444
445 StartDevice(device.get());
446 devices_.emplace(ifname, std::move(device));
447}
448
449void ArcService::StartDevice(Device* device) {
450 if (!impl_ || !impl_->IsStarted())
451 return;
452
Garrick Evans54861622019-07-19 09:05:09 +0900453 const auto& config = device->config();
454
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900455 LOG(INFO) << "Starting device " << *device;
Garrick Evans54861622019-07-19 09:05:09 +0900456
457 // Create the bridge.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900458 if (!datapath_->AddBridge(device->host_ifname(), config.host_ipv4_addr(),
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900459 30)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900460 LOG(ERROR) << "Failed to setup arc bridge: " << device->host_ifname();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900461 return;
Garrick Evans54861622019-07-19 09:05:09 +0900462 }
463
Garrick Evanse94b6de2020-02-20 09:19:13 +0900464 // Set up iptables.
465 if (!datapath_->AddInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900466 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
Garrick Evanse94b6de2020-02-20 09:19:13 +0900467 LOG(ERROR) << "Failed to configure ingress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900468 << device->phys_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900469
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900470 if (!datapath_->AddOutboundIPv4(device->host_ifname()))
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900471 LOG(ERROR) << "Failed to configure egress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900472 << device->phys_ifname();
Garrick Evans2c263102019-07-26 16:07:18 +0900473
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900474 if (!impl_->OnStartDevice(device))
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900475 LOG(ERROR) << "Failed to start device " << device->phys_ifname();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900476}
477
478void ArcService::RemoveDevice(const std::string& ifname) {
479 const auto it = devices_.find(ifname);
480 if (it == devices_.end()) {
481 LOG(WARNING) << "Unknown device: " << ifname;
Garrick Evanscb791e72019-11-11 15:44:34 +0900482 return;
483 }
484
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900485 // If the container is down, this call does nothing.
486 StopDevice(it->second.get());
487
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900488 ReleaseConfig(ifname, it->second->release_config());
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900489 devices_.erase(it);
Garrick Evans54861622019-07-19 09:05:09 +0900490}
491
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900492void ArcService::StopDevice(Device* device) {
493 if (!impl_ || !impl_->IsStarted())
494 return;
495
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900496 LOG(INFO) << "Removing device " << *device;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900497
498 impl_->OnStopDevice(device);
Garrick Evans54861622019-07-19 09:05:09 +0900499
500 const auto& config = device->config();
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900501 datapath_->RemoveOutboundIPv4(device->host_ifname());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900502 datapath_->RemoveInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900503 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900504 datapath_->RemoveBridge(device->host_ifname());
Garrick Evanscb791e72019-11-11 15:44:34 +0900505}
506
Garrick Evans38b25a42020-04-06 15:17:42 +0900507std::vector<const Device::Config*> ArcService::GetDeviceConfigs() const {
508 if (impl_)
509 return impl_->GetDeviceConfigs();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900510
Garrick Evans38b25a42020-04-06 15:17:42 +0900511 return {};
Garrick Evanse94b6de2020-02-20 09:19:13 +0900512}
513
Garrick Evansd90a3822019-11-12 17:53:08 +0900514// ARC++ specific functions.
515
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900516ArcService::ContainerImpl::ContainerImpl(Datapath* datapath,
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900517 TrafficForwarder* forwarder)
518 : pid_(kInvalidPID), datapath_(datapath), forwarder_(forwarder) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900519 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900520}
Garrick Evansd90a3822019-11-12 17:53:08 +0900521
Garrick Evans015b0d62020-02-07 09:06:38 +0900522uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900523 return pid_;
524}
525
Garrick Evans015b0d62020-02-07 09:06:38 +0900526bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900527 // This could happen if something crashes and the stop signal is not sent.
528 // It can probably be addressed by stopping and restarting the service.
529 if (pid_ != kInvalidPID)
530 return false;
531
Garrick Evans4dec0c42019-11-29 12:51:57 +0900532 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900533 LOG(ERROR) << "Cannot start service - invalid container PID";
534 return false;
535 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900536 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900537
Garrick Evansd90a3822019-11-12 17:53:08 +0900538 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
539 return true;
540}
541
Garrick Evans015b0d62020-02-07 09:06:38 +0900542void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900543 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900544 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900545
Garrick Evansd90a3822019-11-12 17:53:08 +0900546 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
547 pid_ = kInvalidPID;
548}
549
Garrick Evans015b0d62020-02-07 09:06:38 +0900550bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900551 if (pid)
552 *pid = pid_;
553
Garrick Evansd90a3822019-11-12 17:53:08 +0900554 return pid_ != kInvalidPID;
555}
556
557bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900558 // Set up the virtual pair inside the container namespace.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900559 const std::string veth_ifname = ArcVethHostName(device->guest_ifname());
Hugo Benichi76675592020-04-08 14:29:57 +0900560 const auto& config = device->config();
561 if (!datapath_->ConnectVethPair(pid_, veth_ifname, device->guest_ifname(),
562 config.mac_addr(), config.guest_ipv4_addr(),
563 30, device->options().fwd_multicast)) {
564 LOG(ERROR) << "Cannot create virtual link for device "
565 << device->phys_ifname();
Garrick Evansd90a3822019-11-12 17:53:08 +0900566 return false;
567 }
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900568 if (!datapath_->AddToBridge(device->host_ifname(), veth_ifname)) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900569 datapath_->RemoveInterface(veth_ifname);
570 LOG(ERROR) << "Failed to bridge interface " << veth_ifname;
571 return false;
572 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900573
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900574 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
575 device->options().ipv6_enabled,
576 device->options().fwd_multicast);
Garrick Evansd90a3822019-11-12 17:53:08 +0900577 return true;
578}
579
580void ArcService::ContainerImpl::OnStopDevice(Device* device) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900581 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
582 device->options().ipv6_enabled,
583 device->options().fwd_multicast);
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900584 datapath_->RemoveInterface(ArcVethHostName(device->phys_ifname()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900585}
586
Garrick Evansb4eb3892019-11-13 12:07:07 +0900587// VM specific functions
588
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900589ArcService::VmImpl::VmImpl(Datapath* datapath,
Garrick Evansf5862122020-03-16 09:13:45 +0900590 TrafficForwarder* forwarder,
Garrick Evans2961c7c2020-04-03 11:34:40 +0900591 const std::vector<Device::Config*>& configs)
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900592 : cid_(kInvalidCID),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900593 datapath_(datapath),
Garrick Evansf5862122020-03-16 09:13:45 +0900594 forwarder_(forwarder),
Garrick Evans2961c7c2020-04-03 11:34:40 +0900595 configs_(configs) {}
Garrick Evansb4eb3892019-11-13 12:07:07 +0900596
Garrick Evans015b0d62020-02-07 09:06:38 +0900597uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900598 return cid_;
599}
600
Garrick Evans38b25a42020-04-06 15:17:42 +0900601std::vector<const Device::Config*> ArcService::VmImpl::GetDeviceConfigs()
602 const {
603 std::vector<const Device::Config*> configs;
604 for (const auto* c : configs_)
605 configs.emplace_back(c);
606
607 return configs;
608}
609
Garrick Evans015b0d62020-02-07 09:06:38 +0900610bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900611 // This can happen if concierge crashes and doesn't send the vm down RPC.
612 // It can probably be addressed by stopping and restarting the service.
613 if (cid_ != kInvalidCID)
614 return false;
615
Garrick Evans015b0d62020-02-07 09:06:38 +0900616 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900617 LOG(ERROR) << "Invalid VM cid " << cid;
618 return false;
619 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900620 cid_ = cid;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900621
Garrick Evans2961c7c2020-04-03 11:34:40 +0900622 // Allocate TAP devices for all configs.
623 for (auto* config : configs_) {
Garrick Evansc7071122020-04-17 12:31:57 +0900624 auto mac = config->mac_addr();
625 auto tap =
626 datapath_->AddTAP("" /* auto-generate name */, &mac,
627 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900628 if (tap.empty()) {
629 LOG(ERROR) << "Failed to create TAP device";
630 continue;
631 }
632
633 config->set_tap_ifname(tap);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900634 }
635
Garrick Evanse94b6de2020-02-20 09:19:13 +0900636 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
Garrick Evansb4eb3892019-11-13 12:07:07 +0900637 return true;
638}
639
Garrick Evans015b0d62020-02-07 09:06:38 +0900640void ArcService::VmImpl::Stop(uint32_t cid) {
Garrick Evans21173b12019-11-20 15:23:16 +0900641 if (cid_ != cid) {
642 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
643 return;
644 }
645
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900646 for (auto* config : configs_)
647 if (!config->tap_ifname().empty())
648 datapath_->RemoveInterface(config->tap_ifname());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900649
Garrick Evansb4eb3892019-11-13 12:07:07 +0900650 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
651 cid_ = kInvalidCID;
652}
653
Garrick Evans015b0d62020-02-07 09:06:38 +0900654bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900655 if (cid)
656 *cid = cid_;
657
Garrick Evans015b0d62020-02-07 09:06:38 +0900658 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900659}
660
661bool ArcService::VmImpl::OnStartDevice(Device* device) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900662 const std::string& tap = device->config().tap_ifname();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900663 if (tap.empty()) {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900664 LOG(ERROR) << "No TAP device for: " << *device;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900665 return false;
666 }
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900667 if (!datapath_->AddToBridge(device->host_ifname(), tap)) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900668 LOG(ERROR) << "Failed to bridge TAP device " << tap;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900669 return false;
670 }
671
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900672 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
673 device->options().ipv6_enabled,
674 device->options().fwd_multicast);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900675 return true;
676}
677
678void ArcService::VmImpl::OnStopDevice(Device* device) {
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900679 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
680 device->options().ipv6_enabled,
681 device->options().fwd_multicast);
682 // TAP devices are removed in VmImpl::Stop().
Garrick Evansb4eb3892019-11-13 12:07:07 +0900683}
Garrick Evans3388a032020-03-24 11:25:55 +0900684} // namespace patchpanel