blob: e1a537903d55c68dd5215a4414861340c2273212 [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
5#include "arc/network/arc_service.h"
6
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 Evans54861622019-07-19 09:05:09 +090010
Garrick Evans5d55f5e2019-07-17 15:28:10 +090011#include <utility>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090012#include <vector>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090013
Garrick Evans54861622019-07-19 09:05:09 +090014#include <base/bind.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090015#include <base/files/file_path.h>
16#include <base/files/file_util.h>
17#include <base/logging.h>
18#include <base/strings/string_number_conversions.h>
19#include <base/strings/string_util.h>
Garrick Evans54861622019-07-19 09:05:09 +090020#include <base/strings/stringprintf.h>
Garrick Evans1f5a3612019-11-08 12:59:03 +090021#include <brillo/key_value_store.h>
Garrick Evansb4eb3892019-11-13 12:07:07 +090022#include <chromeos/constants/vm_tools.h>
Garrick Evans54861622019-07-19 09:05:09 +090023
24#include "arc/network/datapath.h"
Garrick Evans54861622019-07-19 09:05:09 +090025#include "arc/network/mac_address_generator.h"
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090026#include "arc/network/manager.h"
Garrick Evans3915af32019-07-25 15:44:34 +090027#include "arc/network/minijailed_process_runner.h"
Garrick Evans54861622019-07-19 09:05:09 +090028#include "arc/network/net_util.h"
29#include "arc/network/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090030
31namespace arc_networkd {
Garrick Evansf29f5a32019-12-06 11:34:25 +090032namespace test {
33GuestMessage::GuestType guest = GuestMessage::UNKNOWN_GUEST;
34} // namespace test
35
Garrick Evans5d55f5e2019-07-17 15:28:10 +090036namespace {
Garrick Evans015b0d62020-02-07 09:06:38 +090037constexpr pid_t kInvalidPID = 0;
Garrick Evansb4eb3892019-11-13 12:07:07 +090038constexpr pid_t kTestPID = -2;
Garrick Evans015b0d62020-02-07 09:06:38 +090039constexpr uint32_t kInvalidCID = 0;
Garrick Evanse94b6de2020-02-20 09:19:13 +090040constexpr char kArcIfname[] = "arc0";
41constexpr char kArcBridge[] = "arcbr0";
42constexpr char kArcVmIfname[] = "arc1";
43constexpr char kArcVmBridge[] = "arc_br1";
Garrick Evans6e4eb3b2020-03-09 07:18:31 +090044constexpr std::array<const char*, 2> kEthernetInterfacePrefixes{{"eth", "usb"}};
45constexpr std::array<const char*, 2> kWifiInterfacePrefixes{{"wlan", "mlan"}};
Garrick Evans54861622019-07-19 09:05:09 +090046
Garrick Evans6d227b92019-12-03 16:11:29 +090047void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090048 static bool done = false;
49 if (done)
50 return;
51
Garrick Evans6d227b92019-12-03 16:11:29 +090052 auto& runner = datapath.runner();
53
54 // Load networking modules needed by Android that are not compiled in the
55 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansa34b5862019-11-20 09:34:01 +090056 // These must succeed.
Garrick Evans8e8e3472020-01-23 14:03:50 +090057 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090058 // The netfilter modules needed by netd for iptables commands.
59 "ip6table_filter",
60 "ip6t_ipv6header",
61 "ip6t_REJECT",
62 // The xfrm modules needed for Android's ipsec APIs.
63 "xfrm4_mode_transport",
64 "xfrm4_mode_tunnel",
65 "xfrm6_mode_transport",
66 "xfrm6_mode_tunnel",
67 // The ipsec modules for AH and ESP encryption for ipv6.
68 "ah6",
69 "esp6",
70 }) != 0) {
71 LOG(ERROR) << "One or more required kernel modules failed to load."
72 << " Some Android functionality may be broken.";
73 }
74 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +090075 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090076 // This module is not available in kernels < 3.18
77 "nf_reject_ipv6",
78 // These modules are needed for supporting Chrome traffic on Android
79 // VPN which uses Android's NAT feature. Android NAT sets up
80 // iptables
81 // rules that use these conntrack modules for FTP/TFTP.
82 "nf_nat_ftp",
83 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +090084 // The tun module is needed by the Android 464xlat clatd process.
85 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +090086 }) != 0) {
87 LOG(WARNING) << "One or more optional kernel modules failed to load.";
88 }
89
Garrick Evans6d227b92019-12-03 16:11:29 +090090 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +090091 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +090092 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
93 }
94
Garrick Evansa34b5862019-11-20 09:34:01 +090095 done = true;
96}
97
Garrick Evans508a4bc2019-11-14 08:45:52 +090098bool IsArcVm() {
99 const base::FilePath path("/run/chrome/is_arcvm");
100 std::string contents;
101 if (!base::ReadFileToString(path, &contents)) {
102 PLOG(ERROR) << "Could not read " << path.value();
103 }
104 return contents == "1";
105}
106
Garrick Evansf29f5a32019-12-06 11:34:25 +0900107GuestMessage::GuestType ArcGuest() {
108 if (test::guest != GuestMessage::UNKNOWN_GUEST)
109 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900110
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900111 return IsArcVm() ? GuestMessage::ARC_VM : GuestMessage::ARC;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900112}
113
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900114bool IsEthernetInterface(const std::string& ifname) {
115 for (const auto& prefix : kEthernetInterfacePrefixes) {
116 if (base::StartsWith(ifname, prefix,
117 base::CompareCase::INSENSITIVE_ASCII)) {
118 return true;
119 }
120 }
121 return false;
122}
123
124bool IsWifiInterface(const std::string& ifname) {
125 for (const auto& prefix : kWifiInterfacePrefixes) {
126 if (base::StartsWith(ifname, prefix,
127 base::CompareCase::INSENSITIVE_ASCII)) {
128 return true;
129 }
130 }
131 return false;
132}
133
134bool IsMulticastInterface(const std::string& ifname) {
135 if (ifname.empty()) {
136 return false;
137 }
138
139 int fd = socket(AF_INET, SOCK_DGRAM, 0);
140 if (fd < 0) {
141 // If IPv4 fails, try to open a socket using IPv6.
142 fd = socket(AF_INET6, SOCK_DGRAM, 0);
143 if (fd < 0) {
144 LOG(ERROR) << "Unable to create socket";
145 return false;
146 }
147 }
148
149 struct ifreq ifr;
150 memset(&ifr, 0, sizeof(ifr));
151 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
152 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
153 PLOG(ERROR) << "SIOCGIFFLAGS failed for " << ifname;
154 close(fd);
155 return false;
156 }
157
158 close(fd);
159 return (ifr.ifr_flags & IFF_MULTICAST);
160}
161
Garrick Evanse94b6de2020-02-20 09:19:13 +0900162// Returns the configuration for the ARC management interface used for VPN
163// forwarding, ADB-over-TCP and single-networked ARCVM.
164std::unique_ptr<Device::Config> MakeArcConfig(AddressManager* addr_mgr,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900165 AddressManager::Guest guest) {
166 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(guest);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900167 if (!ipv4_subnet) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900168 LOG(ERROR) << "Subnet already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900169 return nullptr;
170 }
171 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
172 if (!host_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900173 LOG(ERROR) << "Bridge address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900174 return nullptr;
175 }
176 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
177 if (!guest_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900178 LOG(ERROR) << "ARC address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900179 return nullptr;
180 }
181
182 return std::make_unique<Device::Config>(
Garrick Evanse94b6de2020-02-20 09:19:13 +0900183 addr_mgr->GenerateMacAddress(), std::move(ipv4_subnet),
184 std::move(host_ipv4_addr), std::move(guest_ipv4_addr));
185}
186
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900187} // namespace
188
Garrick Evans69b85872020-02-04 11:40:26 +0900189ArcService::ArcService(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900190 Datapath* datapath,
191 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900192 TrafficForwarder* forwarder,
193 bool enable_arcvm_multinet)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900194 : shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900195 datapath_(datapath),
196 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900197 forwarder_(forwarder),
198 enable_arcvm_multinet_(enable_arcvm_multinet) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900199 shill_client_->RegisterDevicesChangedHandler(
200 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
201 shill_client_->ScanDevices(
202 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900203 shill_client_->RegisterDefaultInterfaceChangedHandler(base::Bind(
204 &ArcService::OnDefaultInterfaceChanged, weak_factory_.GetWeakPtr()));
Garrick Evansf29f5a32019-12-06 11:34:25 +0900205}
206
207ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900208 if (impl_) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900209 Stop(impl_->id());
Garrick Evans664a82f2019-12-17 12:18:05 +0900210 }
Garrick Evans54861622019-07-19 09:05:09 +0900211}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900212
Garrick Evans015b0d62020-02-07 09:06:38 +0900213bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900214 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900215 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900216 if (impl_->IsStarted(&prev_id)) {
217 LOG(WARNING) << "Already running - did something crash?"
218 << " Stopping and restarting...";
219 Stop(prev_id);
220 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900221 }
222
Garrick Evansf29f5a32019-12-06 11:34:25 +0900223 const auto guest = ArcGuest();
224 if (guest == GuestMessage::ARC_VM)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900225 impl_ = std::make_unique<VmImpl>(shill_client_, datapath_, addr_mgr_,
Garrick Evansf5862122020-03-16 09:13:45 +0900226 forwarder_, enable_arcvm_multinet_);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900227 else
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900228 impl_ = std::make_unique<ContainerImpl>(datapath_, addr_mgr_, forwarder_,
229 guest);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900230
231 if (!impl_->Start(id)) {
232 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900233 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900234 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900235
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900236 // Start already known Shill <-> ARC mapped devices.
237 for (const auto& d : devices_)
238 StartDevice(d.second.get());
Garrick Evanscb791e72019-11-11 15:44:34 +0900239
Garrick Evansf29f5a32019-12-06 11:34:25 +0900240 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900241}
242
Garrick Evans015b0d62020-02-07 09:06:38 +0900243void ArcService::Stop(uint32_t id) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900244 // Stop Shill <-> ARC mapped devices.
245 for (const auto& d : devices_)
246 StopDevice(d.second.get());
Garrick Evansf29f5a32019-12-06 11:34:25 +0900247
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900248 if (impl_) {
249 impl_->Stop(id);
250 impl_.reset();
251 }
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900252}
253
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900254void ArcService::OnDevicesChanged(const std::set<std::string>& added,
255 const std::set<std::string>& removed) {
256 for (const std::string& name : removed)
257 RemoveDevice(name);
258
259 for (const std::string& name : added)
260 AddDevice(name);
261}
262
263void ArcService::AddDevice(const std::string& ifname) {
264 if (ifname.empty())
265 return;
266
267 if (devices_.find(ifname) != devices_.end()) {
268 LOG(DFATAL) << "Attemping to add already tracked device: " << ifname;
269 return;
270 }
271
272 Device::Options opts{
273 .fwd_multicast = IsMulticastInterface(ifname),
274 // TODO(crbug/726815) Also enable |ipv6_enabled| for cellular networks
275 // once IPv6 is enabled on cellular networks in shill.
276 .ipv6_enabled = IsEthernetInterface(ifname) || IsWifiInterface(ifname),
277 .use_default_interface = false,
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900278 };
279 std::string host_ifname = base::StringPrintf("arc_%s", ifname.c_str());
280 auto ipv4_subnet =
281 addr_mgr_->AllocateIPv4Subnet(AddressManager::Guest::ARC_NET);
282 if (!ipv4_subnet) {
283 LOG(ERROR) << "Subnet already in use or unavailable. Cannot make device: "
284 << ifname;
285 return;
286 }
287 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
288 if (!host_ipv4_addr) {
289 LOG(ERROR)
290 << "Bridge address already in use or unavailable. Cannot make device: "
291 << ifname;
292 return;
293 }
294 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
295 if (!guest_ipv4_addr) {
296 LOG(ERROR)
297 << "ARC address already in use or unavailable. Cannot make device: "
298 << ifname;
299 return;
300 }
301
302 auto config = std::make_unique<Device::Config>(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900303 addr_mgr_->GenerateMacAddress(), std::move(ipv4_subnet),
304 std::move(host_ipv4_addr), std::move(guest_ipv4_addr));
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900305
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900306 auto device = std::make_unique<Device>(ifname, host_ifname, ifname,
307 std::move(config), opts);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900308
309 StartDevice(device.get());
310 devices_.emplace(ifname, std::move(device));
311}
312
313void ArcService::StartDevice(Device* device) {
314 if (!impl_ || !impl_->IsStarted())
315 return;
316
317 // For now, only start devices for ARC++.
318 if (impl_->guest() != GuestMessage::ARC)
319 return;
320
Garrick Evans54861622019-07-19 09:05:09 +0900321 const auto& config = device->config();
322
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900323 LOG(INFO) << "Adding device " << device->phys_ifname()
324 << " bridge: " << device->host_ifname()
325 << " guest_iface: " << device->guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900326
327 // Create the bridge.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900328 if (!datapath_->AddBridge(device->host_ifname(), config.host_ipv4_addr(),
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900329 30)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900330 LOG(ERROR) << "Failed to setup arc bridge: " << device->host_ifname();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900331 return;
Garrick Evans54861622019-07-19 09:05:09 +0900332 }
333
Garrick Evanse94b6de2020-02-20 09:19:13 +0900334 // Set up iptables.
335 if (!datapath_->AddInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900336 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
Garrick Evanse94b6de2020-02-20 09:19:13 +0900337 LOG(ERROR) << "Failed to configure ingress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900338 << device->phys_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900339
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900340 if (!datapath_->AddOutboundIPv4(device->host_ifname()))
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900341 LOG(ERROR) << "Failed to configure egress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900342 << device->phys_ifname();
Garrick Evans2c263102019-07-26 16:07:18 +0900343
Garrick Evansd90a3822019-11-12 17:53:08 +0900344 if (!impl_->OnStartDevice(device)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900345 LOG(ERROR) << "Failed to start device " << device->phys_ifname();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900346 }
347}
348
349void ArcService::RemoveDevice(const std::string& ifname) {
350 const auto it = devices_.find(ifname);
351 if (it == devices_.end()) {
352 LOG(WARNING) << "Unknown device: " << ifname;
Garrick Evanscb791e72019-11-11 15:44:34 +0900353 return;
354 }
355
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900356 // If the container is down, this call does nothing.
357 StopDevice(it->second.get());
358
359 devices_.erase(it);
Garrick Evans54861622019-07-19 09:05:09 +0900360}
361
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900362void ArcService::StopDevice(Device* device) {
363 if (!impl_ || !impl_->IsStarted())
364 return;
365
366 // For now, devices are only started for ARC++.
367 if (impl_->guest() != GuestMessage::ARC)
368 return;
369
370 impl_->OnStopDevice(device);
Garrick Evans54861622019-07-19 09:05:09 +0900371
372 const auto& config = device->config();
373
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900374 LOG(INFO) << "Removing device " << device->phys_ifname()
375 << " bridge: " << device->host_ifname()
376 << " guest_iface: " << device->guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900377
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900378 datapath_->RemoveOutboundIPv4(device->host_ifname());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900379 datapath_->RemoveInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900380 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
Garrick Evans54861622019-07-19 09:05:09 +0900381
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900382 datapath_->RemoveBridge(device->host_ifname());
Garrick Evanscb791e72019-11-11 15:44:34 +0900383}
384
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900385void ArcService::OnDefaultInterfaceChanged(const std::string& new_ifname,
386 const std::string& prev_ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900387 if (impl_)
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900388 impl_->OnDefaultInterfaceChanged(new_ifname, prev_ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900389}
Garrick Evansba575742019-07-17 15:48:08 +0900390
Garrick Evanse94b6de2020-02-20 09:19:13 +0900391Device* ArcService::ArcDevice() const {
392 if (!impl_)
393 return nullptr;
394
395 return impl_->ArcDevice();
396}
397
Garrick Evansd90a3822019-11-12 17:53:08 +0900398// ARC++ specific functions.
399
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900400ArcService::ContainerImpl::ContainerImpl(Datapath* datapath,
401 AddressManager* addr_mgr,
402 TrafficForwarder* forwarder,
Garrick Evansd90a3822019-11-12 17:53:08 +0900403 GuestMessage::GuestType guest)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900404 : pid_(kInvalidPID),
405 datapath_(datapath),
406 addr_mgr_(addr_mgr),
407 forwarder_(forwarder),
408 guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900409 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900410}
Garrick Evansd90a3822019-11-12 17:53:08 +0900411
Garrick Evansb4eb3892019-11-13 12:07:07 +0900412GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
413 return guest_;
414}
415
Garrick Evans015b0d62020-02-07 09:06:38 +0900416uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900417 return pid_;
418}
419
Garrick Evans015b0d62020-02-07 09:06:38 +0900420bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900421 // This could happen if something crashes and the stop signal is not sent.
422 // It can probably be addressed by stopping and restarting the service.
423 if (pid_ != kInvalidPID)
424 return false;
425
Garrick Evans4dec0c42019-11-29 12:51:57 +0900426 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900427 LOG(ERROR) << "Cannot start service - invalid container PID";
428 return false;
429 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900430 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900431
Garrick Evanse94b6de2020-02-20 09:19:13 +0900432 Device::Options opts{
433 .fwd_multicast = false,
434 .ipv6_enabled = false,
435 .use_default_interface = false,
Garrick Evanse94b6de2020-02-20 09:19:13 +0900436 };
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900437 auto config = MakeArcConfig(addr_mgr_, AddressManager::Guest::ARC);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900438
439 // Create the bridge.
440 // Per crbug/1008686 this device cannot be deleted and then re-added.
441 // So instead of removing the bridge when the service stops, bring down the
442 // device instead and re-up it on restart.
443 if (!datapath_->AddBridge(kArcBridge, config->host_ipv4_addr(), 30) &&
444 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
445 LOG(ERROR) << "Failed to bring up arc bridge: " << kArcBridge;
446 return false;
447 }
448
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900449 arc_device_ = std::make_unique<Device>(kArcIfname, kArcBridge, kArcIfname,
450 std::move(config), opts);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900451
452 OnStartDevice(arc_device_.get());
453
Garrick Evansd90a3822019-11-12 17:53:08 +0900454 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
455 return true;
456}
457
Garrick Evans015b0d62020-02-07 09:06:38 +0900458void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900459 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900460 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900461
Garrick Evanse94b6de2020-02-20 09:19:13 +0900462 // Per crbug/1008686 this device cannot be deleted and then re-added.
463 // So instead of removing the bridge, bring it down and mark it. This will
464 // allow us to detect if the device is re-added in case of a crash restart
465 // and do the right thing.
466 if (arc_device_) {
467 OnStopDevice(arc_device_.get());
468 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
469 LOG(ERROR) << "Failed to bring down arc bridge "
470 << "- it may not restart correctly";
471 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900472
473 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
474 pid_ = kInvalidPID;
475}
476
Garrick Evans015b0d62020-02-07 09:06:38 +0900477bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900478 if (pid)
479 *pid = pid_;
480
Garrick Evansd90a3822019-11-12 17:53:08 +0900481 return pid_ != kInvalidPID;
482}
483
484bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900485 LOG(INFO) << "Starting device " << device->phys_ifname()
486 << " bridge: " << device->host_ifname()
487 << " guest_iface: " << device->guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900488
Garrick Evans2470caa2020-03-04 14:15:41 +0900489 // Set up the virtual pair inside the container namespace.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900490 const std::string veth_ifname = ArcVethHostName(device->guest_ifname());
Garrick Evans2470caa2020-03-04 14:15:41 +0900491 {
492 ScopedNS ns(pid_);
493 if (!ns.IsValid() && pid_ != kTestPID) {
494 LOG(ERROR)
495 << "Cannot create virtual link -- invalid container namespace?";
496 return false;
497 }
498
499 if (!datapath_->AddVirtualInterfacePair(veth_ifname,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900500 device->guest_ifname())) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900501 LOG(ERROR) << "Failed to create virtual interface pair for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900502 << device->phys_ifname();
Garrick Evans2470caa2020-03-04 14:15:41 +0900503 return false;
504 }
505
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900506 const auto& config = device->config();
507
Garrick Evans2470caa2020-03-04 14:15:41 +0900508 if (!datapath_->ConfigureInterface(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900509 device->guest_ifname(), config.mac_addr(), config.guest_ipv4_addr(),
510 30, true /* link up */, device->options().fwd_multicast)) {
511 LOG(ERROR) << "Failed to configure interface " << device->guest_ifname();
512 datapath_->RemoveInterface(device->guest_ifname());
Garrick Evans2470caa2020-03-04 14:15:41 +0900513 return false;
514 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900515 }
516
Garrick Evans2470caa2020-03-04 14:15:41 +0900517 // Now pull the host end out into the root namespace and add it to the bridge.
518 if (datapath_->runner().RestoreDefaultNamespace(veth_ifname, pid_) != 0) {
519 LOG(ERROR) << "Failed to prepare interface " << veth_ifname;
520 {
521 ScopedNS ns(pid_);
522 if (ns.IsValid()) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900523 datapath_->RemoveInterface(device->guest_ifname());
Garrick Evans2470caa2020-03-04 14:15:41 +0900524 } else {
525 LOG(ERROR) << "Failed to re-enter container namespace."
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900526 << " Subsequent attempts to restart "
527 << device->phys_ifname() << " may not succeed.";
Garrick Evans2470caa2020-03-04 14:15:41 +0900528 }
529 }
530 return false;
531 }
532 if (!datapath_->ToggleInterface(veth_ifname, true /*up*/)) {
533 LOG(ERROR) << "Failed to bring up interface " << veth_ifname;
Garrick Evansd90a3822019-11-12 17:53:08 +0900534 datapath_->RemoveInterface(veth_ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900535 return false;
536 }
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900537 if (!datapath_->AddToBridge(device->host_ifname(), veth_ifname)) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900538 datapath_->RemoveInterface(veth_ifname);
539 LOG(ERROR) << "Failed to bridge interface " << veth_ifname;
540 return false;
541 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900542
Garrick Evans3bd06372020-03-23 10:42:58 +0900543 if (device != arc_device_.get()) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900544 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
545 device->options().ipv6_enabled,
546 device->options().fwd_multicast);
Garrick Evans3bd06372020-03-23 10:42:58 +0900547 } else {
548 // Signal the container that the network device is ready.
549 datapath_->runner().WriteSentinelToContainer(pid_);
550 }
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900551
Garrick Evansd90a3822019-11-12 17:53:08 +0900552 return true;
553}
554
555void ArcService::ContainerImpl::OnStopDevice(Device* device) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900556 LOG(INFO) << "Stopping device " << device->phys_ifname()
557 << " bridge: " << device->host_ifname()
558 << " guest_iface: " << device->guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900559
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900560 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900561 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900562 device->options().ipv6_enabled,
563 device->options().fwd_multicast);
564
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900565 datapath_->RemoveInterface(ArcVethHostName(device->phys_ifname()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900566}
567
568void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900569 const std::string& new_ifname, const std::string& prev_ifname) {}
Garrick Evansd90a3822019-11-12 17:53:08 +0900570
Garrick Evansb4eb3892019-11-13 12:07:07 +0900571// VM specific functions
572
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900573ArcService::VmImpl::VmImpl(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900574 Datapath* datapath,
575 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900576 TrafficForwarder* forwarder,
577 bool enable_multinet)
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900578 : cid_(kInvalidCID),
579 shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900580 datapath_(datapath),
581 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900582 forwarder_(forwarder),
583 enable_multinet_(enable_multinet) {}
Garrick Evansb4eb3892019-11-13 12:07:07 +0900584
585GuestMessage::GuestType ArcService::VmImpl::guest() const {
586 return GuestMessage::ARC_VM;
587}
588
Garrick Evans015b0d62020-02-07 09:06:38 +0900589uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900590 return cid_;
591}
592
Garrick Evans015b0d62020-02-07 09:06:38 +0900593bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900594 // This can happen if concierge crashes and doesn't send the vm down RPC.
595 // It can probably be addressed by stopping and restarting the service.
596 if (cid_ != kInvalidCID)
597 return false;
598
Garrick Evans015b0d62020-02-07 09:06:38 +0900599 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900600 LOG(ERROR) << "Invalid VM cid " << cid;
601 return false;
602 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900603 cid_ = cid;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900604
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900605 // Allocate pool of 6 TAP devices and IPv4 allocs
606
Garrick Evanse94b6de2020-02-20 09:19:13 +0900607 Device::Options opts{
608 .fwd_multicast = true,
609 .ipv6_enabled = true,
610 .use_default_interface = true,
Garrick Evanse94b6de2020-02-20 09:19:13 +0900611 };
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900612 auto config = MakeArcConfig(addr_mgr_, AddressManager::Guest::VM_ARC);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900613
614 // Create the bridge.
615 if (!datapath_->AddBridge(kArcVmBridge, config->host_ipv4_addr(), 30)) {
616 LOG(ERROR) << "Failed to setup arc bridge: " << kArcVmBridge;
617 return false;
618 }
619
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900620 arc_device_ = std::make_unique<Device>(kArcVmIfname, kArcVmBridge,
621 kArcVmIfname, std::move(config), opts);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900622
623 OnStartDevice(arc_device_.get());
624
625 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
Garrick Evansb4eb3892019-11-13 12:07:07 +0900626 return true;
627}
628
Garrick Evans015b0d62020-02-07 09:06:38 +0900629void ArcService::VmImpl::Stop(uint32_t cid) {
Garrick Evans21173b12019-11-20 15:23:16 +0900630 if (cid_ != cid) {
631 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
632 return;
633 }
634
Garrick Evanse94b6de2020-02-20 09:19:13 +0900635 OnStopDevice(arc_device_.get());
636 datapath_->RemoveBridge(kArcVmBridge);
637 arc_device_.reset();
638
Garrick Evansb4eb3892019-11-13 12:07:07 +0900639 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
640 cid_ = kInvalidCID;
641}
642
Garrick Evans015b0d62020-02-07 09:06:38 +0900643bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900644 if (cid)
645 *cid = cid_;
646
Garrick Evans015b0d62020-02-07 09:06:38 +0900647 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900648}
649
650bool ArcService::VmImpl::OnStartDevice(Device* device) {
Garrick Evansf5862122020-03-16 09:13:45 +0900651 // TODO(garrick): Remove once ARCVM P is gone.
652 if (device == arc_device_.get() && !enable_multinet_)
653 return OnStartArcPDevice();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900654
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900655 LOG(INFO) << "Starting device " << device->phys_ifname()
656 << " bridge: " << device->host_ifname()
657 << " guest_iface: " << device->guest_ifname() << " cid: " << cid_;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900658
Garrick Evansb4eb3892019-11-13 12:07:07 +0900659 // Since the interface will be added to the bridge, no address configuration
660 // should be provided here.
661 std::string tap =
662 datapath_->AddTAP("" /* auto-generate name */, nullptr /* no mac addr */,
663 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
664 if (tap.empty()) {
665 LOG(ERROR) << "Failed to create TAP device for VM";
666 return false;
667 }
668
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900669 if (!datapath_->AddToBridge(device->host_ifname(), tap)) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900670 LOG(ERROR) << "Failed to bridge TAP device " << tap;
671 datapath_->RemoveInterface(tap);
672 return false;
673 }
674
Garrick Evansf5862122020-03-16 09:13:45 +0900675 device->set_tap_ifname(tap);
676
677 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900678 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
679 device->options().ipv6_enabled,
680 device->options().fwd_multicast);
Garrick Evansf5862122020-03-16 09:13:45 +0900681
682 return true;
683}
684
685bool ArcService::VmImpl::OnStartArcPDevice() {
686 LOG(INFO) << "Starting device " << kArcVmIfname << " bridge: " << kArcVmBridge
687 << " guest_iface: " << kArcVmIfname << " cid: " << cid_;
688
689 // Since the interface will be added to the bridge, no address configuration
690 // should be provided here.
691 std::string tap =
692 datapath_->AddTAP("" /* auto-generate name */, nullptr /* no mac addr */,
693 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
694 if (tap.empty()) {
695 LOG(ERROR) << "Failed to create TAP device for VM";
696 return false;
697 }
698
699 if (!datapath_->AddToBridge(kArcVmBridge, tap)) {
700 LOG(ERROR) << "Failed to bridge TAP device " << tap;
701 datapath_->RemoveInterface(tap);
702 return false;
703 }
704
705 arc_device_->set_tap_ifname(tap);
706
707 // Setup the iptables.
708 if (!datapath_->AddLegacyIPv4DNAT(
709 IPv4AddressToString(arc_device_->config().guest_ipv4_addr())))
710 LOG(ERROR) << "Failed to configure ARC traffic rules";
711
712 if (!datapath_->AddOutboundIPv4(kArcVmBridge))
713 LOG(ERROR) << "Failed to configure egress traffic rules";
714
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900715 OnDefaultInterfaceChanged(shill_client_->default_interface(),
716 "" /*previous*/);
Garrick Evansbcce09e2020-03-10 15:08:04 +0900717
Garrick Evansb4eb3892019-11-13 12:07:07 +0900718 return true;
719}
720
721void ArcService::VmImpl::OnStopDevice(Device* device) {
Garrick Evansf5862122020-03-16 09:13:45 +0900722 // TODO(garrick): Remove once ARCVM P is gone.
723 if (device == arc_device_.get() && !enable_multinet_)
724 return OnStopArcPDevice();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900725
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900726 LOG(INFO) << "Stopping " << device->phys_ifname()
727 << " bridge: " << device->host_ifname()
728 << " guest_iface: " << device->guest_ifname() << " cid: " << cid_;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900729
Garrick Evansf5862122020-03-16 09:13:45 +0900730 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900731 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
Garrick Evansf5862122020-03-16 09:13:45 +0900732 device->options().ipv6_enabled,
733 device->options().fwd_multicast);
Garrick Evansbcce09e2020-03-10 15:08:04 +0900734
735 datapath_->RemoveInterface(device->tap_ifname());
736 device->set_tap_ifname("");
Garrick Evansb4eb3892019-11-13 12:07:07 +0900737}
738
Garrick Evansf5862122020-03-16 09:13:45 +0900739void ArcService::VmImpl::OnStopArcPDevice() {
740 LOG(INFO) << "Stopping " << kArcVmIfname << " bridge: " << kArcVmBridge
741 << " guest_iface: " << kArcVmIfname << " cid: " << cid_;
742
743 datapath_->RemoveOutboundIPv4(kArcVmBridge);
744 datapath_->RemoveLegacyIPv4DNAT();
745
746 OnDefaultInterfaceChanged("" /*new_ifname*/,
747 shill_client_->default_interface());
748
749 datapath_->RemoveInterface(arc_device_->tap_ifname());
750 arc_device_->set_tap_ifname("");
751}
752
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900753void ArcService::VmImpl::OnDefaultInterfaceChanged(
754 const std::string& new_ifname, const std::string& prev_ifname) {
Garrick Evansf5862122020-03-16 09:13:45 +0900755 if (!IsStarted() || enable_multinet_)
Garrick Evansb4eb3892019-11-13 12:07:07 +0900756 return;
757
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900758 forwarder_->StopForwarding(prev_ifname, kArcVmBridge, true /*ipv6*/,
759 true /*multicast*/);
760
Garrick Evansb4eb3892019-11-13 12:07:07 +0900761 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900762
763 // If a new default interface was given, then re-enable with that.
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900764 if (!new_ifname.empty()) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900765 datapath_->AddLegacyIPv4InboundDNAT(new_ifname);
Jason Jeremy Iman0e9f8262020-03-06 14:50:49 +0900766 forwarder_->StartForwarding(new_ifname, kArcVmBridge, true /*ipv6*/,
767 true /*multicast*/);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900768 }
769}
770
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900771} // namespace arc_networkd