blob: c0243930f4947e580e6f0054f4aba4fa8b2d87a4 [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#include <shill/net/rtnl_message.h>
23
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 +090032
33namespace test {
34GuestMessage::GuestType guest = GuestMessage::UNKNOWN_GUEST;
35} // namespace test
36
Garrick Evans5d55f5e2019-07-17 15:28:10 +090037namespace {
Garrick Evans015b0d62020-02-07 09:06:38 +090038constexpr pid_t kInvalidPID = 0;
Garrick Evansb4eb3892019-11-13 12:07:07 +090039constexpr pid_t kTestPID = -2;
Garrick Evans015b0d62020-02-07 09:06:38 +090040constexpr uint32_t kInvalidCID = 0;
Garrick Evans54861622019-07-19 09:05:09 +090041
42// This wrapper is required since the base class is a singleton that hides its
43// constructor. It is necessary here because the message loop thread has to be
44// reassociated to the container's network namespace; and since the container
45// can be repeatedly created and destroyed, the handler must be as well.
46class RTNetlinkHandler : public shill::RTNLHandler {
47 public:
48 RTNetlinkHandler() = default;
49 ~RTNetlinkHandler() = default;
50
51 private:
52 DISALLOW_COPY_AND_ASSIGN(RTNetlinkHandler);
53};
Garrick Evans5d55f5e2019-07-17 15:28:10 +090054
Garrick Evans6d227b92019-12-03 16:11:29 +090055void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090056 static bool done = false;
57 if (done)
58 return;
59
Garrick Evans6d227b92019-12-03 16:11:29 +090060 auto& runner = datapath.runner();
61
62 // Load networking modules needed by Android that are not compiled in the
63 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansa34b5862019-11-20 09:34:01 +090064 // These must succeed.
Garrick Evans8e8e3472020-01-23 14:03:50 +090065 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090066 // The netfilter modules needed by netd for iptables commands.
67 "ip6table_filter",
68 "ip6t_ipv6header",
69 "ip6t_REJECT",
70 // The xfrm modules needed for Android's ipsec APIs.
71 "xfrm4_mode_transport",
72 "xfrm4_mode_tunnel",
73 "xfrm6_mode_transport",
74 "xfrm6_mode_tunnel",
75 // The ipsec modules for AH and ESP encryption for ipv6.
76 "ah6",
77 "esp6",
78 }) != 0) {
79 LOG(ERROR) << "One or more required kernel modules failed to load."
80 << " Some Android functionality may be broken.";
81 }
82 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +090083 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090084 // This module is not available in kernels < 3.18
85 "nf_reject_ipv6",
86 // These modules are needed for supporting Chrome traffic on Android
87 // VPN which uses Android's NAT feature. Android NAT sets up
88 // iptables
89 // rules that use these conntrack modules for FTP/TFTP.
90 "nf_nat_ftp",
91 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +090092 // The tun module is needed by the Android 464xlat clatd process.
93 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +090094 }) != 0) {
95 LOG(WARNING) << "One or more optional kernel modules failed to load.";
96 }
97
Garrick Evans6d227b92019-12-03 16:11:29 +090098 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +090099 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900100 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
101 }
102
Garrick Evansa34b5862019-11-20 09:34:01 +0900103 done = true;
104}
105
Garrick Evans508a4bc2019-11-14 08:45:52 +0900106bool IsArcVm() {
107 const base::FilePath path("/run/chrome/is_arcvm");
108 std::string contents;
109 if (!base::ReadFileToString(path, &contents)) {
110 PLOG(ERROR) << "Could not read " << path.value();
111 }
112 return contents == "1";
113}
114
Garrick Evansf29f5a32019-12-06 11:34:25 +0900115GuestMessage::GuestType ArcGuest() {
116 if (test::guest != GuestMessage::UNKNOWN_GUEST)
117 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900118
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900119 return IsArcVm() ? GuestMessage::ARC_VM : GuestMessage::ARC;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900120}
121
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900122} // namespace
123
Garrick Evans69b85872020-02-04 11:40:26 +0900124ArcService::ArcService(ShillClient* shill_client,
125 DeviceManagerBase* dev_mgr,
126 Datapath* datapath)
127 : shill_client_(shill_client), dev_mgr_(dev_mgr), datapath_(datapath) {
128 DCHECK(shill_client_);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900129 DCHECK(dev_mgr_);
Taoyu Li179dcc62019-10-17 11:21:08 +0900130 DCHECK(datapath_);
Garrick Evans3915af32019-07-25 15:44:34 +0900131
Garrick Evansf29f5a32019-12-06 11:34:25 +0900132 dev_mgr_->RegisterDeviceAddedHandler(
133 GuestMessage::ARC,
134 base::Bind(&ArcService::OnDeviceAdded, base::Unretained(this)));
135 dev_mgr_->RegisterDeviceRemovedHandler(
136 GuestMessage::ARC,
137 base::Bind(&ArcService::OnDeviceRemoved, base::Unretained(this)));
138 dev_mgr_->RegisterDefaultInterfaceChangedHandler(
139 GuestMessage::ARC, base::Bind(&ArcService::OnDefaultInterfaceChanged,
140 base::Unretained(this)));
141}
142
143ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900144 if (impl_) {
145 // Stop the service.
146 Stop(impl_->id());
147 // Delete all the bridges and veth pairs.
148 dev_mgr_->ProcessDevices(
149 base::Bind(&ArcService::OnDeviceRemoved, weak_factory_.GetWeakPtr()));
150 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900151 dev_mgr_->UnregisterAllGuestHandlers(GuestMessage::ARC);
Garrick Evans54861622019-07-19 09:05:09 +0900152}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900153
Garrick Evans015b0d62020-02-07 09:06:38 +0900154bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900155 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900156 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900157 if (impl_->IsStarted(&prev_id)) {
158 LOG(WARNING) << "Already running - did something crash?"
159 << " Stopping and restarting...";
160 Stop(prev_id);
161 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900162 }
163
Garrick Evansf29f5a32019-12-06 11:34:25 +0900164 const auto guest = ArcGuest();
165 if (guest == GuestMessage::ARC_VM)
166 impl_ = std::make_unique<VmImpl>(dev_mgr_, datapath_);
167 else
168 impl_ = std::make_unique<ContainerImpl>(dev_mgr_, datapath_, guest);
169
170 if (!impl_->Start(id)) {
171 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900172 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900173 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900174
175 // Start known host devices, any new ones will be setup in the process.
176 dev_mgr_->ProcessDevices(
177 base::Bind(&ArcService::StartDevice, weak_factory_.GetWeakPtr()));
178
179 // If this is the first time the service is starting this will create the
180 // Android bridge device; otherwise it does nothing (this is a workaround for
181 // the bug in Shill that casues a Bus crash when it sees the ARC bridge a
182 // second time). Do this after processing the existing devices so it doesn't
183 // get started twice.
Garrick Evanscfd42822019-11-15 12:38:23 +0900184 std::string arc;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900185 switch (guest) {
Garrick Evanscfd42822019-11-15 12:38:23 +0900186 case GuestMessage::ARC:
187 arc = kAndroidDevice;
188 break;
Garrick Evanscfd42822019-11-15 12:38:23 +0900189 case GuestMessage::ARC_VM:
190 arc = kAndroidVmDevice;
191 break;
192 default:
193 LOG(DFATAL) << "Unexpected guest: " << guest;
Garrick Evans21173b12019-11-20 15:23:16 +0900194 return false;
Garrick Evanscfd42822019-11-15 12:38:23 +0900195 }
196 dev_mgr_->Add(arc);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900197 dev_mgr_->OnGuestStart(guest);
198 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900199}
200
Garrick Evans015b0d62020-02-07 09:06:38 +0900201void ArcService::Stop(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900202 if (!impl_)
203 return;
204
205 dev_mgr_->OnGuestStop(impl_->guest());
Garrick Evans54861622019-07-19 09:05:09 +0900206
207 // Stop known host devices. Note that this does not teardown any existing
208 // devices.
209 dev_mgr_->ProcessDevices(
210 base::Bind(&ArcService::StopDevice, weak_factory_.GetWeakPtr()));
Garrick Evans21173b12019-11-20 15:23:16 +0900211
212 impl_->Stop(id);
Garrick Evansf29f5a32019-12-06 11:34:25 +0900213 impl_.reset();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900214}
215
Garrick Evans8ff08452019-11-25 09:24:26 +0900216bool ArcService::AllowDevice(Device* device) const {
Garrick Evansa1134d72019-12-02 14:25:37 +0900217 if (!device->IsArc())
Garrick Evans0001d012019-11-22 10:06:10 +0900218 return false;
219
Garrick Evans8ff08452019-11-25 09:24:26 +0900220 // ARC P+ is multi-network enabled and should process all devices.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900221 if ((impl_ && impl_->guest() == GuestMessage::ARC) ||
222 (!impl_ && ArcGuest() == GuestMessage::ARC))
Garrick Evans8ff08452019-11-25 09:24:26 +0900223 return true;
224
225 // ARC N and ARCVM (for now) are both single-network - meaning they only use
226 // the "default" device which uses the default interface from shill.
227 return device->UsesDefaultInterface();
228}
229
Garrick Evans54861622019-07-19 09:05:09 +0900230void ArcService::OnDeviceAdded(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900231 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900232 return;
Garrick Evansba575742019-07-17 15:48:08 +0900233
Garrick Evans54861622019-07-19 09:05:09 +0900234 const auto& config = device->config();
235
236 LOG(INFO) << "Adding device " << device->ifname()
237 << " bridge: " << config.host_ifname()
Garrick Evans310ab552019-10-08 11:07:53 +0900238 << " guest_iface: " << config.guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900239
240 // Create the bridge.
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900241 if (!datapath_->AddBridge(config.host_ifname(), config.host_ipv4_addr(),
242 30)) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900243 // Per crbug/1008686 this device cannot be deleted and then re-added.
244 // It could be that arc-networkd was restarted after a crash and this device
245 // is being re-added.
246 if (!device->IsAndroid()) {
247 LOG(ERROR) << "Failed to setup arc bridge: " << config.host_ifname();
248 return;
249 }
250 if (!datapath_->MaskInterfaceFlags(config.host_ifname(), IFF_UP)) {
251 LOG(ERROR) << "Failed to bring up arc bridge: " << config.host_ifname();
252 return;
253 }
Garrick Evans54861622019-07-19 09:05:09 +0900254 }
255
256 // Setup the iptables.
Garrick Evans8ff08452019-11-25 09:24:26 +0900257 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900258 if (!datapath_->AddLegacyIPv4DNAT(
259 IPv4AddressToString(config.guest_ipv4_addr())))
260 LOG(ERROR) << "Failed to configure ARC traffic rules";
261
262 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
263 LOG(ERROR) << "Failed to configure egress traffic rules";
264 } else if (!device->IsAndroid()) {
265 if (!datapath_->AddInboundIPv4DNAT(
266 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
267 LOG(ERROR) << "Failed to configure ingress traffic rules for "
268 << device->ifname();
269
270 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
271 LOG(ERROR) << "Failed to configure egress traffic rules";
272 }
273
Garrick Evansa1134d72019-12-02 14:25:37 +0900274 device->set_context(std::make_unique<Context>());
Garrick Evans54861622019-07-19 09:05:09 +0900275
276 StartDevice(device);
277}
278
279void ArcService::StartDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900280 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900281 return;
282
Garrick Evans310ab552019-10-08 11:07:53 +0900283 // This can happen if OnDeviceAdded is invoked when the container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900284 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900285 return;
286
Garrick Evans2c263102019-07-26 16:07:18 +0900287 // If there is no context, then this is a new device and it needs to run
288 // through the full setup process.
Garrick Evansa1134d72019-12-02 14:25:37 +0900289 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900290 if (!ctx)
Garrick Evans54861622019-07-19 09:05:09 +0900291 return OnDeviceAdded(device);
292
Garrick Evans2c263102019-07-26 16:07:18 +0900293 if (ctx->IsStarted()) {
294 LOG(ERROR) << "Attempt to restart device " << device->ifname();
295 return;
296 }
297
Garrick Evansd90a3822019-11-12 17:53:08 +0900298 if (!impl_->OnStartDevice(device)) {
Garrick Evanscb791e72019-11-11 15:44:34 +0900299 LOG(ERROR) << "Failed to start device " << device->ifname();
300 return;
301 }
302
Garrick Evansb4eb3892019-11-13 12:07:07 +0900303 ctx->Start();
Garrick Evans54861622019-07-19 09:05:09 +0900304}
305
306void ArcService::OnDeviceRemoved(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900307 if (!AllowDevice(device))
Garrick Evans54861622019-07-19 09:05:09 +0900308 return;
309
Garrick Evans310ab552019-10-08 11:07:53 +0900310 // If the container is down, this call does nothing.
Garrick Evans54861622019-07-19 09:05:09 +0900311 StopDevice(device);
312
313 const auto& config = device->config();
314
315 LOG(INFO) << "Removing device " << device->ifname()
316 << " bridge: " << config.host_ifname()
317 << " guest_iface: " << config.guest_ifname();
318
Garrick Evans8ff08452019-11-25 09:24:26 +0900319 if (device->UsesDefaultInterface()) {
Garrick Evans54861622019-07-19 09:05:09 +0900320 datapath_->RemoveOutboundIPv4(config.host_ifname());
321 datapath_->RemoveLegacyIPv4DNAT();
322 } else if (!device->IsAndroid()) {
323 datapath_->RemoveOutboundIPv4(config.host_ifname());
324 datapath_->RemoveInboundIPv4DNAT(
325 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
326 }
327
Garrick Evans664a82f2019-12-17 12:18:05 +0900328 // Per crbug/1008686 this device cannot be deleted and then re-added.
329 // So instead of removing the bridge, bring it down and mark it. This will
330 // allow us to detect if the device is re-added in case of a crash restart and
331 // do the right thing.
332 if (device->IsAndroid()) {
333 // This can be safely deleted now.
334 datapath_->RemoveInterface(ArcVethHostName("arc0"));
335 if (!datapath_->MaskInterfaceFlags(config.host_ifname(), IFF_DEBUG, IFF_UP))
336 LOG(ERROR) << "Failed to bring down arc bridge "
337 << "- it may not restart correctly";
338 } else {
339 datapath_->RemoveBridge(config.host_ifname());
340 }
Garrick Evans54861622019-07-19 09:05:09 +0900341
Garrick Evansa1134d72019-12-02 14:25:37 +0900342 device->set_context(nullptr);
Garrick Evans54861622019-07-19 09:05:09 +0900343}
344
345void ArcService::StopDevice(Device* device) {
Garrick Evans8ff08452019-11-25 09:24:26 +0900346 if (!AllowDevice(device))
Garrick Evanscfd42822019-11-15 12:38:23 +0900347 return;
348
Garrick Evans310ab552019-10-08 11:07:53 +0900349 // This can happen if the device if OnDeviceRemoved is invoked when the
350 // container is down.
Garrick Evansf29f5a32019-12-06 11:34:25 +0900351 if (!impl_ || !impl_->IsStarted())
Garrick Evans54861622019-07-19 09:05:09 +0900352 return;
353
Garrick Evansa1134d72019-12-02 14:25:37 +0900354 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evans2c263102019-07-26 16:07:18 +0900355 if (!ctx) {
356 LOG(ERROR) << "Attempt to stop removed device " << device->ifname();
357 return;
358 }
359
360 if (!ctx->IsStarted()) {
361 LOG(ERROR) << "Attempt to re-stop device " << device->ifname();
362 return;
363 }
364
Garrick Evansd90a3822019-11-12 17:53:08 +0900365 impl_->OnStopDevice(device);
Garrick Evanscb791e72019-11-11 15:44:34 +0900366
367 ctx->Stop();
368}
369
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900370void ArcService::OnDefaultInterfaceChanged(const std::string& new_ifname,
371 const std::string& prev_ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900372 if (impl_)
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900373 impl_->OnDefaultInterfaceChanged(new_ifname, prev_ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900374}
Garrick Evansba575742019-07-17 15:48:08 +0900375
Garrick Evans2c263102019-07-26 16:07:18 +0900376// Context
377
378ArcService::Context::Context() : Device::Context() {
379 Stop();
380}
381
382void ArcService::Context::Start() {
383 Stop();
384 started_ = true;
385}
386
387void ArcService::Context::Stop() {
388 started_ = false;
389 link_up_ = false;
Garrick Evans2c263102019-07-26 16:07:18 +0900390}
391
392bool ArcService::Context::IsStarted() const {
393 return started_;
394}
395
396bool ArcService::Context::IsLinkUp() const {
397 return link_up_;
398}
399
400bool ArcService::Context::SetLinkUp(bool link_up) {
401 if (link_up == link_up_)
402 return false;
403
404 link_up_ = link_up;
405 return true;
406}
407
Garrick Evansb4eb3892019-11-13 12:07:07 +0900408const std::string& ArcService::Context::TAP() const {
409 return tap_;
410}
411
412void ArcService::Context::SetTAP(const std::string& tap) {
413 tap_ = tap;
414}
415
Garrick Evansd90a3822019-11-12 17:53:08 +0900416// ARC++ specific functions.
417
418ArcService::ContainerImpl::ContainerImpl(DeviceManagerBase* dev_mgr,
419 Datapath* datapath,
420 GuestMessage::GuestType guest)
Garrick Evansa34b5862019-11-20 09:34:01 +0900421 : pid_(kInvalidPID), dev_mgr_(dev_mgr), datapath_(datapath), guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900422 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900423}
Garrick Evansd90a3822019-11-12 17:53:08 +0900424
Garrick Evansb4eb3892019-11-13 12:07:07 +0900425GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
426 return guest_;
427}
428
Garrick Evans015b0d62020-02-07 09:06:38 +0900429uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900430 return pid_;
431}
432
Garrick Evans015b0d62020-02-07 09:06:38 +0900433bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900434 // This could happen if something crashes and the stop signal is not sent.
435 // It can probably be addressed by stopping and restarting the service.
436 if (pid_ != kInvalidPID)
437 return false;
438
Garrick Evans8ff08452019-11-25 09:24:26 +0900439 // TODO(garrick): Remove this test hack.
440 if (pid == kTestPID) {
441 LOG(WARNING) << "Running with test PID";
442 pid_ = pid;
443 return true;
444 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900445 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900446 LOG(ERROR) << "Cannot start service - invalid container PID";
447 return false;
448 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900449 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900450
451 // Start listening for RTNetlink messages in the container's net namespace
452 // to be notified whenever it brings up an interface.
453 {
454 ScopedNS ns(pid_);
455 if (ns.IsValid()) {
456 rtnl_handler_ = std::make_unique<RTNetlinkHandler>();
457 rtnl_handler_->Start(RTMGRP_LINK);
458 link_listener_ = std::make_unique<shill::RTNLListener>(
459 shill::RTNLHandler::kRequestLink,
460 Bind(&ArcService::ContainerImpl::LinkMsgHandler,
461 weak_factory_.GetWeakPtr()),
462 rtnl_handler_.get());
463 } else {
464 // This is bad - it means we won't ever be able to tell when the container
465 // brings up an interface.
466 LOG(ERROR)
467 << "Cannot start netlink listener - invalid container namespace?";
468 return false;
469 }
470 }
471
Garrick Evansd90a3822019-11-12 17:53:08 +0900472 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
473 return true;
474}
475
Garrick Evans015b0d62020-02-07 09:06:38 +0900476void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900477 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900478 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900479
Garrick Evansd90a3822019-11-12 17:53:08 +0900480 rtnl_handler_->RemoveListener(link_listener_.get());
481 link_listener_.reset();
482 rtnl_handler_.reset();
483
484 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
485 pid_ = kInvalidPID;
486}
487
Garrick Evans015b0d62020-02-07 09:06:38 +0900488bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900489 if (pid)
490 *pid = pid_;
491
Garrick Evansd90a3822019-11-12 17:53:08 +0900492 return pid_ != kInvalidPID;
493}
494
495bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
496 const auto& config = device->config();
497
498 LOG(INFO) << "Starting device " << device->ifname()
499 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900500 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900501
Garrick Evans2470caa2020-03-04 14:15:41 +0900502 // Set up the virtual pair inside the container namespace.
503 const std::string veth_ifname = ArcVethHostName(config.guest_ifname());
504 {
505 ScopedNS ns(pid_);
506 if (!ns.IsValid() && pid_ != kTestPID) {
507 LOG(ERROR)
508 << "Cannot create virtual link -- invalid container namespace?";
509 return false;
510 }
511
512 if (!datapath_->AddVirtualInterfacePair(veth_ifname,
513 config.guest_ifname())) {
514 LOG(ERROR) << "Failed to create virtual interface pair for "
515 << device->ifname();
516 return false;
517 }
518
519 if (!datapath_->ConfigureInterface(
520 config.guest_ifname(), config.guest_mac_addr(),
521 config.guest_ipv4_addr(), 30, true /* link up */,
522 device->options().fwd_multicast)) {
523 LOG(ERROR) << "Failed to configure interface " << config.guest_ifname();
524 datapath_->RemoveInterface(config.guest_ifname());
525 return false;
526 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900527 }
528
Garrick Evans2470caa2020-03-04 14:15:41 +0900529 // Now pull the host end out into the root namespace and add it to the bridge.
530 if (datapath_->runner().RestoreDefaultNamespace(veth_ifname, pid_) != 0) {
531 LOG(ERROR) << "Failed to prepare interface " << veth_ifname;
532 {
533 ScopedNS ns(pid_);
534 if (ns.IsValid()) {
535 datapath_->RemoveInterface(config.guest_ifname());
536 } else {
537 LOG(ERROR) << "Failed to re-enter container namespace."
538 << " Subsequent attempts to restart " << device->ifname()
539 << " may not succeed.";
540 }
541 }
542 return false;
543 }
544 if (!datapath_->ToggleInterface(veth_ifname, true /*up*/)) {
545 LOG(ERROR) << "Failed to bring up interface " << veth_ifname;
Garrick Evansd90a3822019-11-12 17:53:08 +0900546 datapath_->RemoveInterface(veth_ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900547 return false;
548 }
Garrick Evans2470caa2020-03-04 14:15:41 +0900549 if (!datapath_->AddToBridge(config.host_ifname(), veth_ifname)) {
550 datapath_->RemoveInterface(veth_ifname);
551 LOG(ERROR) << "Failed to bridge interface " << veth_ifname;
552 return false;
553 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900554
Taoyu Li1c96d272019-12-13 14:17:43 +0900555 dev_mgr_->StartForwarding(*device);
Garrick Evansd90a3822019-11-12 17:53:08 +0900556 return true;
557}
558
559void ArcService::ContainerImpl::OnStopDevice(Device* device) {
560 const auto& config = device->config();
561
562 LOG(INFO) << "Stopping device " << device->ifname()
563 << " bridge: " << config.host_ifname()
Garrick Evansb4eb3892019-11-13 12:07:07 +0900564 << " guest_iface: " << config.guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900565
Garrick Evansd90a3822019-11-12 17:53:08 +0900566 if (!device->IsAndroid()) {
567 datapath_->RemoveInterface(ArcVethHostName(device->ifname()));
568 }
569}
570
571void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900572 const std::string& new_ifname, const std::string& prev_ifname) {}
Garrick Evansd90a3822019-11-12 17:53:08 +0900573
574void ArcService::ContainerImpl::LinkMsgHandler(const shill::RTNLMessage& msg) {
575 if (!msg.HasAttribute(IFLA_IFNAME)) {
576 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
577 return;
578 }
579 bool link_up = msg.link_status().flags & IFF_UP;
580 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
581 std::string ifname(reinterpret_cast<const char*>(
582 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
583
584 auto* device = dev_mgr_->FindByGuestInterface(ifname);
585 if (!device)
586 return;
587
Garrick Evansa1134d72019-12-02 14:25:37 +0900588 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansd90a3822019-11-12 17:53:08 +0900589 if (!ctx) {
590 LOG(DFATAL) << "Context missing";
591 return;
592 }
593
594 // If the link status is unchanged, there is nothing to do.
595 if (!ctx->SetLinkUp(link_up))
596 return;
597
598 if (!link_up) {
599 LOG(INFO) << ifname << " is now down";
600 return;
601 }
602 LOG(INFO) << ifname << " is now up";
603
Garrick Evans8ff08452019-11-25 09:24:26 +0900604 if (device->UsesDefaultInterface()) {
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900605 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface(), "" /*previous*/);
Garrick Evansd90a3822019-11-12 17:53:08 +0900606 return;
607 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900608}
609
Garrick Evansb4eb3892019-11-13 12:07:07 +0900610// VM specific functions
611
612ArcService::VmImpl::VmImpl(DeviceManagerBase* dev_mgr, Datapath* datapath)
613 : cid_(kInvalidCID), dev_mgr_(dev_mgr), datapath_(datapath) {}
614
615GuestMessage::GuestType ArcService::VmImpl::guest() const {
616 return GuestMessage::ARC_VM;
617}
618
Garrick Evans015b0d62020-02-07 09:06:38 +0900619uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900620 return cid_;
621}
622
Garrick Evans015b0d62020-02-07 09:06:38 +0900623bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900624 // This can happen if concierge crashes and doesn't send the vm down RPC.
625 // It can probably be addressed by stopping and restarting the service.
626 if (cid_ != kInvalidCID)
627 return false;
628
Garrick Evans015b0d62020-02-07 09:06:38 +0900629 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900630 LOG(ERROR) << "Invalid VM cid " << cid;
631 return false;
632 }
633
634 cid_ = cid;
635 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
636
637 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
Garrick Evansb4eb3892019-11-13 12:07:07 +0900646 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
647 cid_ = kInvalidCID;
648}
649
Garrick Evans015b0d62020-02-07 09:06:38 +0900650bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900651 if (cid)
652 *cid = cid_;
653
Garrick Evans015b0d62020-02-07 09:06:38 +0900654 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900655}
656
657bool ArcService::VmImpl::OnStartDevice(Device* device) {
658 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900659 // configurations.
660 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900661 return false;
662
663 const auto& config = device->config();
664
665 LOG(INFO) << "Starting device " << device->ifname()
666 << " bridge: " << config.host_ifname()
667 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
668
Garrick Evansa1134d72019-12-02 14:25:37 +0900669 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900670 if (!ctx) {
671 LOG(ERROR) << "Context missing";
672 return false;
673 }
674
675 // Since the interface will be added to the bridge, no address configuration
676 // should be provided here.
677 std::string tap =
678 datapath_->AddTAP("" /* auto-generate name */, nullptr /* no mac addr */,
679 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
680 if (tap.empty()) {
681 LOG(ERROR) << "Failed to create TAP device for VM";
682 return false;
683 }
684
685 if (!datapath_->AddToBridge(config.host_ifname(), tap)) {
686 LOG(ERROR) << "Failed to bridge TAP device " << tap;
687 datapath_->RemoveInterface(tap);
688 return false;
689 }
690
691 ctx->SetTAP(tap);
692 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
693 // configurations; but for now ARCVM needs to be treated like ARC++ N.
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900694 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface(), "" /*previous*/);
Taoyu Li1c96d272019-12-13 14:17:43 +0900695 dev_mgr_->StartForwarding(*device);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900696 return true;
697}
698
699void ArcService::VmImpl::OnStopDevice(Device* device) {
700 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
Garrick Evans8ff08452019-11-25 09:24:26 +0900701 // configurations.
702 if (!device->UsesDefaultInterface())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900703 return;
704
705 const auto& config = device->config();
706
707 LOG(INFO) << "Stopping " << device->ifname()
708 << " bridge: " << config.host_ifname()
709 << " guest_iface: " << config.guest_ifname() << " cid: " << cid_;
710
Garrick Evansa1134d72019-12-02 14:25:37 +0900711 Context* ctx = dynamic_cast<Context*>(device->context());
Garrick Evansb4eb3892019-11-13 12:07:07 +0900712 if (!ctx) {
713 LOG(ERROR) << "Context missing";
714 return;
715 }
716
Garrick Evansb4eb3892019-11-13 12:07:07 +0900717 datapath_->RemoveInterface(ctx->TAP());
718}
719
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900720void ArcService::VmImpl::OnDefaultInterfaceChanged(
721 const std::string& new_ifname, const std::string& prev_ifname) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900722 if (!IsStarted())
723 return;
724
725 // TODO(garrick): Remove this once ARCVM supports ad hoc interface
726 // configurations; but for now ARCVM needs to be treated like ARC++ N.
727 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900728 auto* device = dev_mgr_->FindByGuestInterface("arc1");
Garrick Evansb4eb3892019-11-13 12:07:07 +0900729 if (!device) {
730 LOG(DFATAL) << "Expected Android device missing";
731 return;
732 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900733
734 // If a new default interface was given, then re-enable with that.
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900735 if (!new_ifname.empty()) {
736 datapath_->AddLegacyIPv4InboundDNAT(new_ifname);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900737 }
738}
739
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900740} // namespace arc_networkd