blob: c6187778224748f9560ef88e46eedb49f6603285 [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>
9
Garrick Evans5d55f5e2019-07-17 15:28:10 +090010#include <utility>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090011#include <vector>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090012
Garrick Evans54861622019-07-19 09:05:09 +090013#include <base/bind.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090014#include <base/files/file_path.h>
15#include <base/files/file_util.h>
16#include <base/logging.h>
17#include <base/strings/string_number_conversions.h>
18#include <base/strings/string_util.h>
Garrick Evans54861622019-07-19 09:05:09 +090019#include <base/strings/stringprintf.h>
Garrick Evans1f5a3612019-11-08 12:59:03 +090020#include <brillo/key_value_store.h>
Garrick Evansb4eb3892019-11-13 12:07:07 +090021#include <chromeos/constants/vm_tools.h>
Garrick Evans54861622019-07-19 09:05:09 +090022
23#include "arc/network/datapath.h"
Garrick Evans54861622019-07-19 09:05:09 +090024#include "arc/network/mac_address_generator.h"
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090025#include "arc/network/manager.h"
Garrick Evans3915af32019-07-25 15:44:34 +090026#include "arc/network/minijailed_process_runner.h"
Garrick Evans54861622019-07-19 09:05:09 +090027#include "arc/network/net_util.h"
28#include "arc/network/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090029
30namespace arc_networkd {
Garrick Evansf29f5a32019-12-06 11:34:25 +090031namespace test {
32GuestMessage::GuestType guest = GuestMessage::UNKNOWN_GUEST;
33} // namespace test
34
Garrick Evans5d55f5e2019-07-17 15:28:10 +090035namespace {
Garrick Evans015b0d62020-02-07 09:06:38 +090036constexpr pid_t kInvalidPID = 0;
Garrick Evansb4eb3892019-11-13 12:07:07 +090037constexpr pid_t kTestPID = -2;
Garrick Evans015b0d62020-02-07 09:06:38 +090038constexpr uint32_t kInvalidCID = 0;
Garrick Evanse94b6de2020-02-20 09:19:13 +090039constexpr char kArcIfname[] = "arc0";
40constexpr char kArcBridge[] = "arcbr0";
41constexpr char kArcVmIfname[] = "arc1";
42constexpr char kArcVmBridge[] = "arc_br1";
Garrick Evans54861622019-07-19 09:05:09 +090043
Garrick Evans6d227b92019-12-03 16:11:29 +090044void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090045 static bool done = false;
46 if (done)
47 return;
48
Garrick Evans6d227b92019-12-03 16:11:29 +090049 auto& runner = datapath.runner();
50
51 // Load networking modules needed by Android that are not compiled in the
52 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansa34b5862019-11-20 09:34:01 +090053 // These must succeed.
Garrick Evans8e8e3472020-01-23 14:03:50 +090054 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090055 // The netfilter modules needed by netd for iptables commands.
56 "ip6table_filter",
57 "ip6t_ipv6header",
58 "ip6t_REJECT",
59 // The xfrm modules needed for Android's ipsec APIs.
60 "xfrm4_mode_transport",
61 "xfrm4_mode_tunnel",
62 "xfrm6_mode_transport",
63 "xfrm6_mode_tunnel",
64 // The ipsec modules for AH and ESP encryption for ipv6.
65 "ah6",
66 "esp6",
67 }) != 0) {
68 LOG(ERROR) << "One or more required kernel modules failed to load."
69 << " Some Android functionality may be broken.";
70 }
71 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +090072 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090073 // This module is not available in kernels < 3.18
74 "nf_reject_ipv6",
75 // These modules are needed for supporting Chrome traffic on Android
76 // VPN which uses Android's NAT feature. Android NAT sets up
77 // iptables
78 // rules that use these conntrack modules for FTP/TFTP.
79 "nf_nat_ftp",
80 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +090081 // The tun module is needed by the Android 464xlat clatd process.
82 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +090083 }) != 0) {
84 LOG(WARNING) << "One or more optional kernel modules failed to load.";
85 }
86
Garrick Evans6d227b92019-12-03 16:11:29 +090087 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +090088 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +090089 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
90 }
91
Garrick Evansa34b5862019-11-20 09:34:01 +090092 done = true;
93}
94
Garrick Evans508a4bc2019-11-14 08:45:52 +090095bool IsArcVm() {
96 const base::FilePath path("/run/chrome/is_arcvm");
97 std::string contents;
98 if (!base::ReadFileToString(path, &contents)) {
99 PLOG(ERROR) << "Could not read " << path.value();
100 }
101 return contents == "1";
102}
103
Garrick Evansf29f5a32019-12-06 11:34:25 +0900104GuestMessage::GuestType ArcGuest() {
105 if (test::guest != GuestMessage::UNKNOWN_GUEST)
106 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900107
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900108 return IsArcVm() ? GuestMessage::ARC_VM : GuestMessage::ARC;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900109}
110
Garrick Evanse94b6de2020-02-20 09:19:13 +0900111// Returns the configuration for the ARC management interface used for VPN
112// forwarding, ADB-over-TCP and single-networked ARCVM.
113std::unique_ptr<Device::Config> MakeArcConfig(AddressManager* addr_mgr,
114 bool is_arcvm) {
115 const char* ifname = is_arcvm ? kArcVmBridge : kArcBridge;
116 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(
117 is_arcvm ? AddressManager::Guest::VM_ARC : AddressManager::Guest::ARC);
118 if (!ipv4_subnet) {
119 LOG(ERROR) << "Subnet already in use or unavailable. Cannot make device: "
120 << ifname;
121 return nullptr;
122 }
123 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
124 if (!host_ipv4_addr) {
125 LOG(ERROR)
126 << "Bridge address already in use or unavailable. Cannot make device: "
127 << ifname;
128 return nullptr;
129 }
130 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
131 if (!guest_ipv4_addr) {
132 LOG(ERROR)
133 << "ARC address already in use or unavailable. Cannot make device: "
134 << ifname;
135 return nullptr;
136 }
137
138 return std::make_unique<Device::Config>(
139 ifname, is_arcvm ? kArcVmIfname : kArcIfname,
140 addr_mgr->GenerateMacAddress(), std::move(ipv4_subnet),
141 std::move(host_ipv4_addr), std::move(guest_ipv4_addr));
142}
143
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900144} // namespace
145
Garrick Evans69b85872020-02-04 11:40:26 +0900146ArcService::ArcService(ShillClient* shill_client,
147 DeviceManagerBase* dev_mgr,
148 Datapath* datapath)
149 : shill_client_(shill_client), dev_mgr_(dev_mgr), datapath_(datapath) {
150 DCHECK(shill_client_);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900151 DCHECK(dev_mgr_);
Taoyu Li179dcc62019-10-17 11:21:08 +0900152 DCHECK(datapath_);
Garrick Evans3915af32019-07-25 15:44:34 +0900153
Garrick Evansf29f5a32019-12-06 11:34:25 +0900154 dev_mgr_->RegisterDeviceAddedHandler(
155 GuestMessage::ARC,
156 base::Bind(&ArcService::OnDeviceAdded, base::Unretained(this)));
157 dev_mgr_->RegisterDeviceRemovedHandler(
158 GuestMessage::ARC,
159 base::Bind(&ArcService::OnDeviceRemoved, base::Unretained(this)));
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900160
161 shill_client_->RegisterDefaultInterfaceChangedHandler(base::Bind(
162 &ArcService::OnDefaultInterfaceChanged, weak_factory_.GetWeakPtr()));
Garrick Evansf29f5a32019-12-06 11:34:25 +0900163}
164
165ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900166 if (impl_) {
167 // Stop the service.
168 Stop(impl_->id());
169 // Delete all the bridges and veth pairs.
170 dev_mgr_->ProcessDevices(
171 base::Bind(&ArcService::OnDeviceRemoved, weak_factory_.GetWeakPtr()));
172 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900173 dev_mgr_->UnregisterAllGuestHandlers(GuestMessage::ARC);
Garrick Evans54861622019-07-19 09:05:09 +0900174}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900175
Garrick Evans015b0d62020-02-07 09:06:38 +0900176bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900177 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900178 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900179 if (impl_->IsStarted(&prev_id)) {
180 LOG(WARNING) << "Already running - did something crash?"
181 << " Stopping and restarting...";
182 Stop(prev_id);
183 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900184 }
185
Garrick Evansf29f5a32019-12-06 11:34:25 +0900186 const auto guest = ArcGuest();
187 if (guest == GuestMessage::ARC_VM)
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900188 impl_ = std::make_unique<VmImpl>(shill_client_, dev_mgr_, datapath_);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900189 else
190 impl_ = std::make_unique<ContainerImpl>(dev_mgr_, datapath_, guest);
191
192 if (!impl_->Start(id)) {
193 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900194 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900195 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900196
197 // Start known host devices, any new ones will be setup in the process.
198 dev_mgr_->ProcessDevices(
199 base::Bind(&ArcService::StartDevice, weak_factory_.GetWeakPtr()));
200
Garrick Evansf29f5a32019-12-06 11:34:25 +0900201 dev_mgr_->OnGuestStart(guest);
202 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900203}
204
Garrick Evans015b0d62020-02-07 09:06:38 +0900205void ArcService::Stop(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900206 if (!impl_)
207 return;
208
209 dev_mgr_->OnGuestStop(impl_->guest());
Garrick Evans54861622019-07-19 09:05:09 +0900210
211 // Stop known host devices. Note that this does not teardown any existing
212 // devices.
213 dev_mgr_->ProcessDevices(
214 base::Bind(&ArcService::StopDevice, weak_factory_.GetWeakPtr()));
Garrick Evans21173b12019-11-20 15:23:16 +0900215
216 impl_->Stop(id);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900217 impl_.reset();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900218}
219
Garrick Evans54861622019-07-19 09:05:09 +0900220void ArcService::OnDeviceAdded(Device* device) {
Garrick Evans54861622019-07-19 09:05:09 +0900221 const auto& config = device->config();
222
223 LOG(INFO) << "Adding device " << device->ifname()
224 << " bridge: " << config.host_ifname()
Garrick Evans310ab552019-10-08 11:07:53 +0900225 << " guest_iface: " << config.guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900226
227 // Create the bridge.
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900228 if (!datapath_->AddBridge(config.host_ifname(), config.host_ipv4_addr(),
229 30)) {
Garrick Evanse94b6de2020-02-20 09:19:13 +0900230 LOG(ERROR) << "Failed to setup arc bridge: " << config.host_ifname();
231 return;
Garrick Evans54861622019-07-19 09:05:09 +0900232 }
233
Garrick Evanse94b6de2020-02-20 09:19:13 +0900234 // Set up iptables.
235 if (!datapath_->AddInboundIPv4DNAT(
236 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
237 LOG(ERROR) << "Failed to configure ingress traffic rules for "
238 << device->ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900239
Garrick Evanse94b6de2020-02-20 09:19:13 +0900240 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
241 LOG(ERROR) << "Failed to configure egress traffic rules";
Garrick Evans54861622019-07-19 09:05:09 +0900242
Garrick Evansa1134d72019-12-02 14:25:37 +0900243 device->set_context(std::make_unique<Context>());
Garrick Evans54861622019-07-19 09:05:09 +0900244
245 StartDevice(device);
246}
247
248void ArcService::StartDevice(Device* device) {
Garrick Evans310ab552019-10-08 11:07:53 +0900249 // This can happen if OnDeviceAdded is invoked when the container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900250 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900251 return;
252
Garrick Evanse94b6de2020-02-20 09:19:13 +0900253 // For now, only start devices for ARC++.
254 if (impl_->guest() != GuestMessage::ARC)
255 return;
256
Garrick Evans2c263102019-07-26 16:07:18 +0900257 // If there is no context, then this is a new device and it needs to run
258 // through the full setup process.
Garrick Evansa1134d72019-12-02 14:25:37 +0900259 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900260 if (!ctx)
Garrick Evans54861622019-07-19 09:05:09 +0900261 return OnDeviceAdded(device);
262
Garrick Evans2c263102019-07-26 16:07:18 +0900263 if (ctx->IsStarted()) {
264 LOG(ERROR) << "Attempt to restart device " << device->ifname();
265 return;
266 }
267
Garrick Evansd90a3822019-11-12 17:53:08 +0900268 if (!impl_->OnStartDevice(device)) {
Garrick Evanscb791e72019-11-11 15:44:34 +0900269 LOG(ERROR) << "Failed to start device " << device->ifname();
270 return;
271 }
272
Garrick Evansb4eb3892019-11-13 12:07:07 +0900273 ctx->Start();
Garrick Evans54861622019-07-19 09:05:09 +0900274}
275
276void ArcService::OnDeviceRemoved(Device* device) {
Garrick Evans310ab552019-10-08 11:07:53 +0900277 // If the container is down, this call does nothing.
Garrick Evans54861622019-07-19 09:05:09 +0900278 StopDevice(device);
279
280 const auto& config = device->config();
281
282 LOG(INFO) << "Removing device " << device->ifname()
283 << " bridge: " << config.host_ifname()
284 << " guest_iface: " << config.guest_ifname();
285
Garrick Evanse94b6de2020-02-20 09:19:13 +0900286 datapath_->RemoveOutboundIPv4(config.host_ifname());
287 datapath_->RemoveInboundIPv4DNAT(
288 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
Garrick Evans54861622019-07-19 09:05:09 +0900289
Garrick Evanse94b6de2020-02-20 09:19:13 +0900290 datapath_->RemoveBridge(config.host_ifname());
Garrick Evans54861622019-07-19 09:05:09 +0900291
Garrick Evansa1134d72019-12-02 14:25:37 +0900292 device->set_context(nullptr);
Garrick Evans54861622019-07-19 09:05:09 +0900293}
294
295void ArcService::StopDevice(Device* device) {
Garrick Evans310ab552019-10-08 11:07:53 +0900296 // This can happen if the device if OnDeviceRemoved is invoked when the
297 // container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900298 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900299 return;
300
Garrick Evanse94b6de2020-02-20 09:19:13 +0900301 // For now, devices are only started for ARC++.
302 if (impl_->guest() != GuestMessage::ARC)
303 return;
304
Garrick Evansa1134d72019-12-02 14:25:37 +0900305 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900306 if (!ctx) {
307 LOG(ERROR) << "Attempt to stop removed device " << device->ifname();
308 return;
309 }
310
311 if (!ctx->IsStarted()) {
312 LOG(ERROR) << "Attempt to re-stop device " << device->ifname();
313 return;
314 }
315
Garrick Evansd90a3822019-11-12 17:53:08 +0900316 impl_->OnStopDevice(device);
Garrick Evanscb791e72019-11-11 15:44:34 +0900317
318 ctx->Stop();
319}
320
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900321void ArcService::OnDefaultInterfaceChanged(const std::string& new_ifname,
322 const std::string& prev_ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900323 if (impl_)
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900324 impl_->OnDefaultInterfaceChanged(new_ifname, prev_ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900325}
Garrick Evansba575742019-07-17 15:48:08 +0900326
Garrick Evanse94b6de2020-02-20 09:19:13 +0900327Device* ArcService::ArcDevice() const {
328 if (!impl_)
329 return nullptr;
330
331 return impl_->ArcDevice();
332}
333
Garrick Evans2c263102019-07-26 16:07:18 +0900334// Context
335
336ArcService::Context::Context() : Device::Context() {
337 Stop();
338}
339
340void ArcService::Context::Start() {
341 Stop();
342 started_ = true;
343}
344
345void ArcService::Context::Stop() {
346 started_ = false;
Garrick Evans2c263102019-07-26 16:07:18 +0900347}
348
349bool ArcService::Context::IsStarted() const {
350 return started_;
351}
352
Garrick Evansb4eb3892019-11-13 12:07:07 +0900353const std::string& ArcService::Context::TAP() const {
354 return tap_;
355}
356
357void ArcService::Context::SetTAP(const std::string& tap) {
358 tap_ = tap;
359}
360
Garrick Evansd90a3822019-11-12 17:53:08 +0900361// ARC++ specific functions.
362
363ArcService::ContainerImpl::ContainerImpl(DeviceManagerBase* dev_mgr,
364 Datapath* datapath,
365 GuestMessage::GuestType guest)
Garrick Evansa34b5862019-11-20 09:34:01 +0900366 : pid_(kInvalidPID), dev_mgr_(dev_mgr), datapath_(datapath), guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900367 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900368}
Garrick Evansd90a3822019-11-12 17:53:08 +0900369
Garrick Evansb4eb3892019-11-13 12:07:07 +0900370GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
371 return guest_;
372}
373
Garrick Evans015b0d62020-02-07 09:06:38 +0900374uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900375 return pid_;
376}
377
Garrick Evans015b0d62020-02-07 09:06:38 +0900378bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900379 // This could happen if something crashes and the stop signal is not sent.
380 // It can probably be addressed by stopping and restarting the service.
381 if (pid_ != kInvalidPID)
382 return false;
383
Garrick Evans4dec0c42019-11-29 12:51:57 +0900384 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900385 LOG(ERROR) << "Cannot start service - invalid container PID";
386 return false;
387 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900388 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900389
Garrick Evanse94b6de2020-02-20 09:19:13 +0900390 Device::Options opts{
391 .fwd_multicast = false,
392 .ipv6_enabled = false,
393 .use_default_interface = false,
394 .is_android = true,
395 .is_sticky = true,
396 };
397 auto config = MakeArcConfig(dev_mgr_->addr_mgr(), false /*is_arcvm*/);
398
399 // Create the bridge.
400 // Per crbug/1008686 this device cannot be deleted and then re-added.
401 // So instead of removing the bridge when the service stops, bring down the
402 // device instead and re-up it on restart.
403 if (!datapath_->AddBridge(kArcBridge, config->host_ipv4_addr(), 30) &&
404 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
405 LOG(ERROR) << "Failed to bring up arc bridge: " << kArcBridge;
406 return false;
407 }
408
409 arc_device_ = std::make_unique<Device>(kArcIfname, std::move(config), opts,
410 GuestMessage::ARC);
411
412 OnStartDevice(arc_device_.get());
413
Garrick Evansd90a3822019-11-12 17:53:08 +0900414 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
415 return true;
416}
417
Garrick Evans015b0d62020-02-07 09:06:38 +0900418void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900419 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900420 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900421
Garrick Evanse94b6de2020-02-20 09:19:13 +0900422 // Per crbug/1008686 this device cannot be deleted and then re-added.
423 // So instead of removing the bridge, bring it down and mark it. This will
424 // allow us to detect if the device is re-added in case of a crash restart
425 // and do the right thing.
426 if (arc_device_) {
427 OnStopDevice(arc_device_.get());
428 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
429 LOG(ERROR) << "Failed to bring down arc bridge "
430 << "- it may not restart correctly";
431 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900432
433 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
434 pid_ = kInvalidPID;
435}
436
Garrick Evans015b0d62020-02-07 09:06:38 +0900437bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900438 if (pid)
439 *pid = pid_;
440
Garrick Evansd90a3822019-11-12 17:53:08 +0900441 return pid_ != kInvalidPID;
442}
443
444bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
445 const auto& config = device->config();
446
447 LOG(INFO) << "Starting device " << device->ifname()
448 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900449 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900450
Garrick Evans2470caa2020-03-04 14:15:41 +0900451 // Set up the virtual pair inside the container namespace.
452 const std::string veth_ifname = ArcVethHostName(config.guest_ifname());
453 {
454 ScopedNS ns(pid_);
455 if (!ns.IsValid() && pid_ != kTestPID) {
456 LOG(ERROR)
457 << "Cannot create virtual link -- invalid container namespace?";
458 return false;
459 }
460
461 if (!datapath_->AddVirtualInterfacePair(veth_ifname,
462 config.guest_ifname())) {
463 LOG(ERROR) << "Failed to create virtual interface pair for "
464 << device->ifname();
465 return false;
466 }
467
468 if (!datapath_->ConfigureInterface(
469 config.guest_ifname(), config.guest_mac_addr(),
470 config.guest_ipv4_addr(), 30, true /* link up */,
471 device->options().fwd_multicast)) {
472 LOG(ERROR) << "Failed to configure interface " << config.guest_ifname();
473 datapath_->RemoveInterface(config.guest_ifname());
474 return false;
475 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900476 }
477
Garrick Evans2470caa2020-03-04 14:15:41 +0900478 // Now pull the host end out into the root namespace and add it to the bridge.
479 if (datapath_->runner().RestoreDefaultNamespace(veth_ifname, pid_) != 0) {
480 LOG(ERROR) << "Failed to prepare interface " << veth_ifname;
481 {
482 ScopedNS ns(pid_);
483 if (ns.IsValid()) {
484 datapath_->RemoveInterface(config.guest_ifname());
485 } else {
486 LOG(ERROR) << "Failed to re-enter container namespace."
487 << " Subsequent attempts to restart " << device->ifname()
488 << " may not succeed.";
489 }
490 }
491 return false;
492 }
493 if (!datapath_->ToggleInterface(veth_ifname, true /*up*/)) {
494 LOG(ERROR) << "Failed to bring up interface " << veth_ifname;
Garrick Evansd90a3822019-11-12 17:53:08 +0900495 datapath_->RemoveInterface(veth_ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900496 return false;
497 }
Garrick Evans2470caa2020-03-04 14:15:41 +0900498 if (!datapath_->AddToBridge(config.host_ifname(), veth_ifname)) {
499 datapath_->RemoveInterface(veth_ifname);
500 LOG(ERROR) << "Failed to bridge interface " << veth_ifname;
501 return false;
502 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900503
Garrick Evanse94b6de2020-02-20 09:19:13 +0900504 dev_mgr_->StartForwarding(*device, device->ifname());
Garrick Evansd90a3822019-11-12 17:53:08 +0900505 return true;
506}
507
508void ArcService::ContainerImpl::OnStopDevice(Device* device) {
509 const auto& config = device->config();
510
511 LOG(INFO) << "Stopping device " << device->ifname()
512 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900513 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900514
Garrick Evanse94b6de2020-02-20 09:19:13 +0900515 dev_mgr_->StopForwarding(*device, device->ifname());
516 datapath_->RemoveInterface(ArcVethHostName(device->ifname()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900517}
518
519void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900520 const std::string& new_ifname, const std::string& prev_ifname) {}
Garrick Evansd90a3822019-11-12 17:53:08 +0900521
Garrick Evansb4eb3892019-11-13 12:07:07 +0900522// VM specific functions
523
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900524ArcService::VmImpl::VmImpl(ShillClient* shill_client,
525 DeviceManagerBase* dev_mgr,
526 Datapath* datapath)
527 : cid_(kInvalidCID),
528 shill_client_(shill_client),
529 dev_mgr_(dev_mgr),
530 datapath_(datapath) {}
Garrick Evansb4eb3892019-11-13 12:07:07 +0900531
532GuestMessage::GuestType ArcService::VmImpl::guest() const {
533 return GuestMessage::ARC_VM;
534}
535
Garrick Evans015b0d62020-02-07 09:06:38 +0900536uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900537 return cid_;
538}
539
Garrick Evans015b0d62020-02-07 09:06:38 +0900540bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900541 // This can happen if concierge crashes and doesn't send the vm down RPC.
542 // It can probably be addressed by stopping and restarting the service.
543 if (cid_ != kInvalidCID)
544 return false;
545
Garrick Evans015b0d62020-02-07 09:06:38 +0900546 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900547 LOG(ERROR) << "Invalid VM cid " << cid;
548 return false;
549 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900550 cid_ = cid;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900551
Garrick Evanse94b6de2020-02-20 09:19:13 +0900552 Device::Options opts{
553 .fwd_multicast = true,
554 .ipv6_enabled = true,
555 .use_default_interface = true,
556 .is_android = true,
557 .is_sticky = true,
558 };
559 auto config = MakeArcConfig(dev_mgr_->addr_mgr(), true /*is_arcvm*/);
560
561 // Create the bridge.
562 if (!datapath_->AddBridge(kArcVmBridge, config->host_ipv4_addr(), 30)) {
563 LOG(ERROR) << "Failed to setup arc bridge: " << kArcVmBridge;
564 return false;
565 }
566
567 // Setup the iptables.
568 if (!datapath_->AddLegacyIPv4DNAT(
569 IPv4AddressToString(config->guest_ipv4_addr())))
570 LOG(ERROR) << "Failed to configure ARC traffic rules";
571
572 if (!datapath_->AddOutboundIPv4(kArcVmBridge))
573 LOG(ERROR) << "Failed to configure egress traffic rules";
574
575 arc_device_ = std::make_unique<Device>(kArcVmIfname, std::move(config), opts,
576 GuestMessage::ARC_VM);
577 arc_device_->set_context(std::make_unique<Context>());
578
579 OnStartDevice(arc_device_.get());
580
581 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
Garrick Evansb4eb3892019-11-13 12:07:07 +0900582 return true;
583}
584
Garrick Evans015b0d62020-02-07 09:06:38 +0900585void ArcService::VmImpl::Stop(uint32_t cid) {
Garrick Evans21173b12019-11-20 15:23:16 +0900586 if (cid_ != cid) {
587 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
588 return;
589 }
590
Garrick Evanse94b6de2020-02-20 09:19:13 +0900591 datapath_->RemoveOutboundIPv4(kArcVmBridge);
592 datapath_->RemoveLegacyIPv4DNAT();
593 OnStopDevice(arc_device_.get());
594 datapath_->RemoveBridge(kArcVmBridge);
595 arc_device_.reset();
596
Garrick Evansb4eb3892019-11-13 12:07:07 +0900597 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
598 cid_ = kInvalidCID;
599}
600
Garrick Evans015b0d62020-02-07 09:06:38 +0900601bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900602 if (cid)
603 *cid = cid_;
604
Garrick Evans015b0d62020-02-07 09:06:38 +0900605 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900606}
607
608bool ArcService::VmImpl::OnStartDevice(Device* device) {
609 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900610 // configurations.
611 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900612 return false;
613
614 const auto& config = device->config();
615
616 LOG(INFO) << "Starting device " << device->ifname()
617 << " bridge: " << config.host_ifname()
618 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
619
Garrick Evansa1134d72019-12-02 14:25:37 +0900620 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900621 if (!ctx) {
622 LOG(ERROR) << "Context missing";
623 return false;
624 }
625
626 // Since the interface will be added to the bridge, no address configuration
627 // should be provided here.
628 std::string tap =
629 datapath_->AddTAP("" /* auto-generate name */, nullptr /* no mac addr */,
630 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
631 if (tap.empty()) {
632 LOG(ERROR) << "Failed to create TAP device for VM";
633 return false;
634 }
635
636 if (!datapath_->AddToBridge(config.host_ifname(), tap)) {
637 LOG(ERROR) << "Failed to bridge TAP device " << tap;
638 datapath_->RemoveInterface(tap);
639 return false;
640 }
641
642 ctx->SetTAP(tap);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900643 ctx->Start();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900644 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
645 // configurations; but for now ARCVM needs to be treated like ARC++ N.
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900646 OnDefaultInterfaceChanged(shill_client_->default_interface(),
647 "" /*previous*/);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900648 return true;
649}
650
651void ArcService::VmImpl::OnStopDevice(Device* device) {
652 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900653 // configurations.
654 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900655 return;
656
657 const auto& config = device->config();
658
659 LOG(INFO) << "Stopping " << device->ifname()
660 << " bridge: " << config.host_ifname()
661 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
662
Garrick Evansa1134d72019-12-02 14:25:37 +0900663 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900664 if (!ctx) {
665 LOG(ERROR) << "Context missing";
666 return;
667 }
668
Garrick Evanse94b6de2020-02-20 09:19:13 +0900669 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
670 // configurations; but for now ARCVM needs to be treated like ARC++ N.
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900671 OnDefaultInterfaceChanged("" /*new_ifname*/,
672 shill_client_->default_interface());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900673 datapath_->RemoveInterface(ctx->TAP());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900674 ctx->Stop();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900675}
676
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900677void ArcService::VmImpl::OnDefaultInterfaceChanged(
678 const std::string& new_ifname, const std::string& prev_ifname) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900679 if (!IsStarted())
680 return;
681
Garrick Evanse94b6de2020-02-20 09:19:13 +0900682 dev_mgr_->StopForwarding(*arc_device_.get(), prev_ifname);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900683 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
684 // configurations; but for now ARCVM needs to be treated like ARC++ N.
685 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900686
687 // If a new default interface was given, then re-enable with that.
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900688 if (!new_ifname.empty()) {
Garrick Evanse94b6de2020-02-20 09:19:13 +0900689 dev_mgr_->StartForwarding(*arc_device_.get(), new_ifname);
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900690 datapath_->AddLegacyIPv4InboundDNAT(new_ifname);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900691 }
692}
693
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900694} // namespace arc_networkd