blob: 2270fe810023e5bbbdc36f6bda9e00808d1f64ba [file] [log] [blame]
Garrick Evans5d55f5e2019-07-17 15:28:10 +09001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Garrick Evans3388a032020-03-24 11:25:55 +09005#include "patchpanel/arc_service.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +09006
Garrick Evans54861622019-07-19 09:05:09 +09007#include <linux/rtnetlink.h>
8#include <net/if.h>
Garrick Evans6e4eb3b2020-03-09 07:18:31 +09009#include <sys/ioctl.h>
Garrick Evans71e4a862020-05-18 12:22:23 +090010#include <sys/utsname.h>
Garrick Evans54861622019-07-19 09:05:09 +090011
Garrick Evans5d55f5e2019-07-17 15:28:10 +090012#include <utility>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090013#include <vector>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090014
Garrick Evans54861622019-07-19 09:05:09 +090015#include <base/bind.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090016#include <base/files/file_path.h>
17#include <base/files/file_util.h>
18#include <base/logging.h>
19#include <base/strings/string_number_conversions.h>
20#include <base/strings/string_util.h>
Garrick Evans54861622019-07-19 09:05:09 +090021#include <base/strings/stringprintf.h>
Qijiang Fan2d7aeb42020-05-19 02:06:39 +090022#include <base/system/sys_info.h>
Garrick Evans1f5a3612019-11-08 12:59:03 +090023#include <brillo/key_value_store.h>
Garrick Evansb4eb3892019-11-13 12:07:07 +090024#include <chromeos/constants/vm_tools.h>
Garrick Evans54861622019-07-19 09:05:09 +090025
Garrick Evans3388a032020-03-24 11:25:55 +090026#include "patchpanel/datapath.h"
27#include "patchpanel/mac_address_generator.h"
28#include "patchpanel/manager.h"
29#include "patchpanel/minijailed_process_runner.h"
30#include "patchpanel/net_util.h"
31#include "patchpanel/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090032
Garrick Evans3388a032020-03-24 11:25:55 +090033namespace patchpanel {
Garrick Evansf29f5a32019-12-06 11:34:25 +090034namespace test {
35GuestMessage::GuestType guest = GuestMessage::UNKNOWN_GUEST;
36} // namespace test
37
Garrick Evans5d55f5e2019-07-17 15:28:10 +090038namespace {
Garrick Evans015b0d62020-02-07 09:06:38 +090039constexpr pid_t kInvalidPID = 0;
Garrick Evans015b0d62020-02-07 09:06:38 +090040constexpr uint32_t kInvalidCID = 0;
Garrick Evanse94b6de2020-02-20 09:19:13 +090041constexpr char kArcIfname[] = "arc0";
42constexpr char kArcBridge[] = "arcbr0";
43constexpr char kArcVmIfname[] = "arc1";
44constexpr char kArcVmBridge[] = "arc_br1";
Garrick Evans6e4eb3b2020-03-09 07:18:31 +090045constexpr std::array<const char*, 2> kEthernetInterfacePrefixes{{"eth", "usb"}};
46constexpr std::array<const char*, 2> kWifiInterfacePrefixes{{"wlan", "mlan"}};
Garrick Evans86c7d9c2020-03-17 09:25:48 +090047constexpr std::array<const char*, 2> kCellInterfacePrefixes{{"wwan", "rmnet"}};
Garrick Evans54861622019-07-19 09:05:09 +090048
Garrick Evans71e4a862020-05-18 12:22:23 +090049bool KernelVersion(int* major, int* minor) {
50 struct utsname u;
51 if (uname(&u) != 0) {
52 PLOG(ERROR) << "uname failed";
53 *major = *minor = 0;
54 return false;
55 }
56 int unused;
57 if (sscanf(u.release, "%d.%d.%d", major, minor, &unused) != 3) {
58 LOG(ERROR) << "unexpected release string: " << u.release;
59 *major = *minor = 0;
60 return false;
61 }
62 return true;
63}
64
Garrick Evans6d227b92019-12-03 16:11:29 +090065void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090066 static bool done = false;
67 if (done)
68 return;
69
Garrick Evans6d227b92019-12-03 16:11:29 +090070 auto& runner = datapath.runner();
71
72 // Load networking modules needed by Android that are not compiled in the
73 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansc53b9702020-05-13 13:20:09 +090074 // Expected for all kernels.
Garrick Evans8e8e3472020-01-23 14:03:50 +090075 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090076 // The netfilter modules needed by netd for iptables commands.
77 "ip6table_filter",
78 "ip6t_ipv6header",
79 "ip6t_REJECT",
Garrick Evansa34b5862019-11-20 09:34:01 +090080 // The ipsec modules for AH and ESP encryption for ipv6.
81 "ah6",
82 "esp6",
83 }) != 0) {
84 LOG(ERROR) << "One or more required kernel modules failed to load."
85 << " Some Android functionality may be broken.";
86 }
Garrick Evansc53b9702020-05-13 13:20:09 +090087 // The xfrm modules needed for Android's ipsec APIs on kernels < 5.4.
Garrick Evans71e4a862020-05-18 12:22:23 +090088 int major, minor;
89 if (KernelVersion(&major, &minor) &&
90 (major < 5 || (major == 5 && minor < 4)) &&
91 runner.modprobe_all({
92 "xfrm4_mode_transport",
93 "xfrm4_mode_tunnel",
94 "xfrm6_mode_transport",
95 "xfrm6_mode_tunnel",
96 }) != 0) {
Garrick Evansc53b9702020-05-13 13:20:09 +090097 LOG(ERROR) << "One or more required kernel modules failed to load."
98 << " Some Android functionality may be broken.";
99 }
100
Garrick Evansa34b5862019-11-20 09:34:01 +0900101 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +0900102 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +0900103 // This module is not available in kernels < 3.18
104 "nf_reject_ipv6",
105 // These modules are needed for supporting Chrome traffic on Android
106 // VPN which uses Android's NAT feature. Android NAT sets up
107 // iptables
108 // rules that use these conntrack modules for FTP/TFTP.
109 "nf_nat_ftp",
110 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +0900111 // The tun module is needed by the Android 464xlat clatd process.
112 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +0900113 }) != 0) {
114 LOG(WARNING) << "One or more optional kernel modules failed to load.";
115 }
116
Garrick Evans6d227b92019-12-03 16:11:29 +0900117 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +0900118 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900119 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
120 }
121
Garrick Evansa34b5862019-11-20 09:34:01 +0900122 done = true;
123}
124
Garrick Evans508a4bc2019-11-14 08:45:52 +0900125bool IsArcVm() {
Yusuke Sato9243a642020-05-27 18:00:05 -0700126 if (test::guest != GuestMessage::UNKNOWN_GUEST) {
Garrick Evansc7071122020-04-17 12:31:57 +0900127 LOG(WARNING) << "Overridden for testing";
Yusuke Sato9243a642020-05-27 18:00:05 -0700128 return test::guest == GuestMessage::ARC_VM;
Garrick Evansc7071122020-04-17 12:31:57 +0900129 }
Yusuke Sato9243a642020-05-27 18:00:05 -0700130 return USE_ARCVM;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900131}
132
Garrick Evansf29f5a32019-12-06 11:34:25 +0900133GuestMessage::GuestType ArcGuest() {
134 if (test::guest != GuestMessage::UNKNOWN_GUEST)
135 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900136
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900137 return IsArcVm() ? GuestMessage::ARC_VM : GuestMessage::ARC;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900138}
139
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900140ArcService::InterfaceType InterfaceTypeFor(const std::string& ifname) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900141 for (const auto& prefix : kEthernetInterfacePrefixes) {
142 if (base::StartsWith(ifname, prefix,
143 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900144 return ArcService::InterfaceType::ETHERNET;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900145 }
146 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900147 for (const auto& prefix : kWifiInterfacePrefixes) {
148 if (base::StartsWith(ifname, prefix,
149 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900150 return ArcService::InterfaceType::WIFI;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900151 }
152 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900153 for (const auto& prefix : kCellInterfacePrefixes) {
154 if (base::StartsWith(ifname, prefix,
155 base::CompareCase::INSENSITIVE_ASCII)) {
156 return ArcService::InterfaceType::CELL;
157 }
158 }
159 return ArcService::InterfaceType::UNKNOWN;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900160}
161
162bool IsMulticastInterface(const std::string& ifname) {
163 if (ifname.empty()) {
164 return false;
165 }
166
167 int fd = socket(AF_INET, SOCK_DGRAM, 0);
168 if (fd < 0) {
169 // If IPv4 fails, try to open a socket using IPv6.
170 fd = socket(AF_INET6, SOCK_DGRAM, 0);
171 if (fd < 0) {
172 LOG(ERROR) << "Unable to create socket";
173 return false;
174 }
175 }
176
177 struct ifreq ifr;
178 memset(&ifr, 0, sizeof(ifr));
179 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
180 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
181 PLOG(ERROR) << "SIOCGIFFLAGS failed for " << ifname;
182 close(fd);
183 return false;
184 }
185
186 close(fd);
187 return (ifr.ifr_flags & IFF_MULTICAST);
188}
189
Garrick Evanse94b6de2020-02-20 09:19:13 +0900190// Returns the configuration for the ARC management interface used for VPN
191// forwarding, ADB-over-TCP and single-networked ARCVM.
192std::unique_ptr<Device::Config> MakeArcConfig(AddressManager* addr_mgr,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900193 AddressManager::Guest guest) {
194 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(guest);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900195 if (!ipv4_subnet) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900196 LOG(ERROR) << "Subnet already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900197 return nullptr;
198 }
199 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
200 if (!host_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900201 LOG(ERROR) << "Bridge address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900202 return nullptr;
203 }
204 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
205 if (!guest_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900206 LOG(ERROR) << "ARC address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900207 return nullptr;
208 }
209
210 return std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900211 addr_mgr->GenerateMacAddress(IsArcVm() ? 1 : kAnySubnetIndex),
212 std::move(ipv4_subnet), std::move(host_ipv4_addr),
213 std::move(guest_ipv4_addr));
Garrick Evanse94b6de2020-02-20 09:19:13 +0900214}
215
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900216} // namespace
217
Garrick Evans69b85872020-02-04 11:40:26 +0900218ArcService::ArcService(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900219 Datapath* datapath,
220 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900221 TrafficForwarder* forwarder,
222 bool enable_arcvm_multinet)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900223 : shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900224 datapath_(datapath),
225 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900226 forwarder_(forwarder),
227 enable_arcvm_multinet_(enable_arcvm_multinet) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900228 AllocateAddressConfigs();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900229 shill_client_->RegisterDevicesChangedHandler(
230 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Jie Jiang84c76a12020-04-17 16:45:20 +0900231 shill_client_->ScanDevices();
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900232 shill_client_->RegisterDefaultInterfaceChangedHandler(base::Bind(
233 &ArcService::OnDefaultInterfaceChanged, weak_factory_.GetWeakPtr()));
Garrick Evansf29f5a32019-12-06 11:34:25 +0900234}
235
236ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900237 if (impl_) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900238 Stop(impl_->id());
Garrick Evans664a82f2019-12-17 12:18:05 +0900239 }
Garrick Evans54861622019-07-19 09:05:09 +0900240}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900241
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900242void ArcService::AllocateAddressConfigs() {
243 configs_.clear();
244 // The first usable subnet is the "other" ARC device subnet.
245 // TODO(garrick): This can be removed and ARC_NET will be widened once ARCVM
246 // switches over to use .0/30.
Garrick Evansc7071122020-04-17 12:31:57 +0900247 const bool is_arcvm = IsArcVm();
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900248 AddressManager::Guest alloc =
Garrick Evansc7071122020-04-17 12:31:57 +0900249 is_arcvm ? AddressManager::Guest::ARC : AddressManager::Guest::VM_ARC;
250 // As a temporary workaround, for ARCVM, allocate fixed MAC addresses.
251 uint8_t mac_addr_index = 2;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900252 // Allocate 2 subnets each for Ethernet and WiFi and 1 for LTE WAN interfaces.
253 for (const auto itype :
254 {InterfaceType::ETHERNET, InterfaceType::ETHERNET, InterfaceType::WIFI,
255 InterfaceType::WIFI, InterfaceType::CELL}) {
256 auto ipv4_subnet = addr_mgr_->AllocateIPv4Subnet(alloc);
257 if (!ipv4_subnet) {
258 LOG(ERROR) << "Subnet already in use or unavailable";
259 continue;
260 }
261 // For here out, use the same slices.
262 alloc = AddressManager::Guest::ARC_NET;
263 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
264 if (!host_ipv4_addr) {
265 LOG(ERROR) << "Bridge address already in use or unavailable";
266 continue;
267 }
268 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
269 if (!guest_ipv4_addr) {
270 LOG(ERROR) << "ARC address already in use or unavailable";
271 continue;
272 }
273
Garrick Evansc7071122020-04-17 12:31:57 +0900274 MacAddress mac_addr = is_arcvm
275 ? addr_mgr_->GenerateMacAddress(mac_addr_index++)
276 : addr_mgr_->GenerateMacAddress();
277
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900278 configs_[itype].emplace_back(std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900279 mac_addr, std::move(ipv4_subnet), std::move(host_ipv4_addr),
280 std::move(guest_ipv4_addr)));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900281 }
282}
283
Garrick Evans2961c7c2020-04-03 11:34:40 +0900284std::vector<Device::Config*> ArcService::ReallocateAddressConfigs() {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900285 std::vector<std::string> existing_devices;
286 for (const auto& d : devices_) {
287 existing_devices.emplace_back(d.first);
288 }
289 for (const auto& d : existing_devices) {
290 RemoveDevice(d);
291 }
292 AllocateAddressConfigs();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900293 std::vector<Device::Config*> configs;
294 if (enable_arcvm_multinet_) {
295 for (const auto& kv : configs_)
296 for (const auto& c : kv.second)
297 configs.push_back(c.get());
298 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900299 for (const auto& d : existing_devices) {
300 AddDevice(d);
301 }
Garrick Evans2961c7c2020-04-03 11:34:40 +0900302 return configs;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900303}
304
305std::unique_ptr<Device::Config> ArcService::AcquireConfig(
306 const std::string& ifname) {
307 auto itype = InterfaceTypeFor(ifname);
308 if (itype == InterfaceType::UNKNOWN) {
309 LOG(ERROR) << "Unsupported interface: " << ifname;
310 return nullptr;
311 }
312
313 auto& configs = configs_[itype];
314 if (configs.empty()) {
315 LOG(ERROR) << "No more addresses available. Cannot make device for "
316 << ifname;
317 return nullptr;
318 }
319 std::unique_ptr<Device::Config> config;
320 config = std::move(configs.front());
321 configs.pop_front();
322 return config;
323}
324
325void ArcService::ReleaseConfig(const std::string& ifname,
326 std::unique_ptr<Device::Config> config) {
327 auto itype = InterfaceTypeFor(ifname);
328 if (itype == InterfaceType::UNKNOWN) {
329 LOG(ERROR) << "Unsupported interface: " << ifname;
330 return;
331 }
332
333 configs_[itype].push_front(std::move(config));
334}
335
Garrick Evans015b0d62020-02-07 09:06:38 +0900336bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900337 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900338 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900339 if (impl_->IsStarted(&prev_id)) {
340 LOG(WARNING) << "Already running - did something crash?"
341 << " Stopping and restarting...";
342 Stop(prev_id);
343 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900344 }
345
Garrick Evans2961c7c2020-04-03 11:34:40 +0900346 auto configs = ReallocateAddressConfigs();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900347 const auto guest = ArcGuest();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900348 if (guest == GuestMessage::ARC_VM) {
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900349 impl_ = std::make_unique<VmImpl>(shill_client_, datapath_, addr_mgr_,
Garrick Evans2961c7c2020-04-03 11:34:40 +0900350 forwarder_, configs);
351 } else {
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900352 impl_ = std::make_unique<ContainerImpl>(datapath_, addr_mgr_, forwarder_,
353 guest);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900354 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900355 if (!impl_->Start(id)) {
356 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900357 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900358 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900359
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900360 // Start already known Shill <-> ARC mapped devices.
361 for (const auto& d : devices_)
362 StartDevice(d.second.get());
Garrick Evanscb791e72019-11-11 15:44:34 +0900363
Garrick Evansf29f5a32019-12-06 11:34:25 +0900364 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900365}
366
Garrick Evans015b0d62020-02-07 09:06:38 +0900367void ArcService::Stop(uint32_t id) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900368 // Stop Shill <-> ARC mapped devices.
369 for (const auto& d : devices_)
370 StopDevice(d.second.get());
Garrick Evansf29f5a32019-12-06 11:34:25 +0900371
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900372 if (impl_) {
373 impl_->Stop(id);
374 impl_.reset();
375 }
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900376}
377
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900378void ArcService::OnDevicesChanged(const std::set<std::string>& added,
379 const std::set<std::string>& removed) {
380 for (const std::string& name : removed)
381 RemoveDevice(name);
382
383 for (const std::string& name : added)
384 AddDevice(name);
385}
386
387void ArcService::AddDevice(const std::string& ifname) {
388 if (ifname.empty())
389 return;
390
391 if (devices_.find(ifname) != devices_.end()) {
392 LOG(DFATAL) << "Attemping to add already tracked device: " << ifname;
393 return;
394 }
395
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900396 auto itype = InterfaceTypeFor(ifname);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900397 Device::Options opts{
398 .fwd_multicast = IsMulticastInterface(ifname),
399 // TODO(crbug/726815) Also enable |ipv6_enabled| for cellular networks
400 // once IPv6 is enabled on cellular networks in shill.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900401 .ipv6_enabled =
402 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900403 };
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900404
405 auto config = AcquireConfig(ifname);
406 if (!config) {
407 LOG(ERROR) << "Cannot add device for " << ifname;
408 return;
409 }
410
Garrick Evans8a067562020-05-11 12:47:30 +0900411 auto device = std::make_unique<Device>(ifname, ArcBridgeName(ifname), ifname,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900412 std::move(config), opts);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900413
414 StartDevice(device.get());
415 devices_.emplace(ifname, std::move(device));
416}
417
418void ArcService::StartDevice(Device* device) {
419 if (!impl_ || !impl_->IsStarted())
420 return;
421
422 // For now, only start devices for ARC++.
423 if (impl_->guest() != GuestMessage::ARC)
424 return;
425
Garrick Evans54861622019-07-19 09:05:09 +0900426 const auto& config = device->config();
427
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900428 LOG(INFO) << "Adding device " << device->phys_ifname()
429 << " bridge: " << device->host_ifname()
430 << " guest_iface: " << device->guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900431
432 // Create the bridge.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900433 if (!datapath_->AddBridge(device->host_ifname(), config.host_ipv4_addr(),
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900434 30)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900435 LOG(ERROR) << "Failed to setup arc bridge: " << device->host_ifname();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900436 return;
Garrick Evans54861622019-07-19 09:05:09 +0900437 }
438
Garrick Evanse94b6de2020-02-20 09:19:13 +0900439 // Set up iptables.
440 if (!datapath_->AddInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900441 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
Garrick Evanse94b6de2020-02-20 09:19:13 +0900442 LOG(ERROR) << "Failed to configure ingress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900443 << device->phys_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900444
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900445 if (!datapath_->AddOutboundIPv4(device->host_ifname()))
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900446 LOG(ERROR) << "Failed to configure egress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900447 << device->phys_ifname();
Garrick Evans2c263102019-07-26 16:07:18 +0900448
Garrick Evansd90a3822019-11-12 17:53:08 +0900449 if (!impl_->OnStartDevice(device)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900450 LOG(ERROR) << "Failed to start device " << device->phys_ifname();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900451 }
452}
453
454void ArcService::RemoveDevice(const std::string& ifname) {
455 const auto it = devices_.find(ifname);
456 if (it == devices_.end()) {
457 LOG(WARNING) << "Unknown device: " << ifname;
Garrick Evanscb791e72019-11-11 15:44:34 +0900458 return;
459 }
460
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900461 // If the container is down, this call does nothing.
462 StopDevice(it->second.get());
463
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900464 ReleaseConfig(ifname, it->second->release_config());
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900465 devices_.erase(it);
Garrick Evans54861622019-07-19 09:05:09 +0900466}
467
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900468void ArcService::StopDevice(Device* device) {
469 if (!impl_ || !impl_->IsStarted())
470 return;
471
472 // For now, devices are only started for ARC++.
473 if (impl_->guest() != GuestMessage::ARC)
474 return;
475
476 impl_->OnStopDevice(device);
Garrick Evans54861622019-07-19 09:05:09 +0900477
478 const auto& config = device->config();
479
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900480 LOG(INFO) << "Removing device " << device->phys_ifname()
481 << " bridge: " << device->host_ifname()
482 << " guest_iface: " << device->guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900483
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900484 datapath_->RemoveOutboundIPv4(device->host_ifname());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900485 datapath_->RemoveInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900486 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
Garrick Evans54861622019-07-19 09:05:09 +0900487
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900488 datapath_->RemoveBridge(device->host_ifname());
Garrick Evanscb791e72019-11-11 15:44:34 +0900489}
490
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900491void ArcService::OnDefaultInterfaceChanged(const std::string& new_ifname,
492 const std::string& prev_ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900493 if (impl_)
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900494 impl_->OnDefaultInterfaceChanged(new_ifname, prev_ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900495}
Garrick Evansba575742019-07-17 15:48:08 +0900496
Garrick Evans38b25a42020-04-06 15:17:42 +0900497std::vector<const Device::Config*> ArcService::GetDeviceConfigs() const {
498 if (impl_)
499 return impl_->GetDeviceConfigs();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900500
Garrick Evans38b25a42020-04-06 15:17:42 +0900501 return {};
Garrick Evanse94b6de2020-02-20 09:19:13 +0900502}
503
Garrick Evansd90a3822019-11-12 17:53:08 +0900504// ARC++ specific functions.
505
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900506ArcService::ContainerImpl::ContainerImpl(Datapath* datapath,
507 AddressManager* addr_mgr,
508 TrafficForwarder* forwarder,
Garrick Evansd90a3822019-11-12 17:53:08 +0900509 GuestMessage::GuestType guest)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900510 : pid_(kInvalidPID),
511 datapath_(datapath),
512 addr_mgr_(addr_mgr),
513 forwarder_(forwarder),
514 guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900515 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900516}
Garrick Evansd90a3822019-11-12 17:53:08 +0900517
Garrick Evansb4eb3892019-11-13 12:07:07 +0900518GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
519 return guest_;
520}
521
Garrick Evans015b0d62020-02-07 09:06:38 +0900522uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900523 return pid_;
524}
525
Garrick Evans015b0d62020-02-07 09:06:38 +0900526bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900527 // This could happen if something crashes and the stop signal is not sent.
528 // It can probably be addressed by stopping and restarting the service.
529 if (pid_ != kInvalidPID)
530 return false;
531
Garrick Evans4dec0c42019-11-29 12:51:57 +0900532 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900533 LOG(ERROR) << "Cannot start service - invalid container PID";
534 return false;
535 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900536 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900537
Garrick Evanse94b6de2020-02-20 09:19:13 +0900538 Device::Options opts{
539 .fwd_multicast = false,
540 .ipv6_enabled = false,
Garrick Evanse94b6de2020-02-20 09:19:13 +0900541 };
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900542 auto config = MakeArcConfig(addr_mgr_, AddressManager::Guest::ARC);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900543
544 // Create the bridge.
545 // Per crbug/1008686 this device cannot be deleted and then re-added.
546 // So instead of removing the bridge when the service stops, bring down the
547 // device instead and re-up it on restart.
548 if (!datapath_->AddBridge(kArcBridge, config->host_ipv4_addr(), 30) &&
549 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
550 LOG(ERROR) << "Failed to bring up arc bridge: " << kArcBridge;
551 return false;
552 }
553
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900554 arc_device_ = std::make_unique<Device>(kArcIfname, kArcBridge, kArcIfname,
555 std::move(config), opts);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900556
557 OnStartDevice(arc_device_.get());
558
Garrick Evansd90a3822019-11-12 17:53:08 +0900559 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
560 return true;
561}
562
Garrick Evans015b0d62020-02-07 09:06:38 +0900563void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900564 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900565 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900566
Garrick Evanse94b6de2020-02-20 09:19:13 +0900567 // Per crbug/1008686 this device cannot be deleted and then re-added.
568 // So instead of removing the bridge, bring it down and mark it. This will
569 // allow us to detect if the device is re-added in case of a crash restart
570 // and do the right thing.
571 if (arc_device_) {
572 OnStopDevice(arc_device_.get());
573 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
574 LOG(ERROR) << "Failed to bring down arc bridge "
575 << "- it may not restart correctly";
576 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900577
578 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
579 pid_ = kInvalidPID;
580}
581
Garrick Evans015b0d62020-02-07 09:06:38 +0900582bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900583 if (pid)
584 *pid = pid_;
585
Garrick Evansd90a3822019-11-12 17:53:08 +0900586 return pid_ != kInvalidPID;
587}
588
589bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900590 LOG(INFO) << "Starting device " << device->phys_ifname()
591 << " bridge: " << device->host_ifname()
592 << " guest_iface: " << device->guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900593
Garrick Evans2470caa2020-03-04 14:15:41 +0900594 // Set up the virtual pair inside the container namespace.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900595 const std::string veth_ifname = ArcVethHostName(device->guest_ifname());
Hugo Benichi76675592020-04-08 14:29:57 +0900596 const auto& config = device->config();
597 if (!datapath_->ConnectVethPair(pid_, veth_ifname, device->guest_ifname(),
598 config.mac_addr(), config.guest_ipv4_addr(),
599 30, device->options().fwd_multicast)) {
600 LOG(ERROR) << "Cannot create virtual link for device "
601 << device->phys_ifname();
Garrick Evansd90a3822019-11-12 17:53:08 +0900602 return false;
603 }
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900604 if (!datapath_->AddToBridge(device->host_ifname(), veth_ifname)) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900605 datapath_->RemoveInterface(veth_ifname);
606 LOG(ERROR) << "Failed to bridge interface " << veth_ifname;
607 return false;
608 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900609
Garrick Evans3bd06372020-03-23 10:42:58 +0900610 if (device != arc_device_.get()) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900611 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
612 device->options().ipv6_enabled,
613 device->options().fwd_multicast);
Garrick Evans3bd06372020-03-23 10:42:58 +0900614 }
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900615
Garrick Evansd90a3822019-11-12 17:53:08 +0900616 return true;
617}
618
619void ArcService::ContainerImpl::OnStopDevice(Device* device) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900620 LOG(INFO) << "Stopping device " << device->phys_ifname()
621 << " bridge: " << device->host_ifname()
622 << " guest_iface: " << device->guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900623
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900624 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900625 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900626 device->options().ipv6_enabled,
627 device->options().fwd_multicast);
628
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900629 datapath_->RemoveInterface(ArcVethHostName(device->phys_ifname()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900630}
631
632void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900633 const std::string& new_ifname, const std::string& prev_ifname) {}
Garrick Evansd90a3822019-11-12 17:53:08 +0900634
Garrick Evansb4eb3892019-11-13 12:07:07 +0900635// VM specific functions
636
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900637ArcService::VmImpl::VmImpl(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900638 Datapath* datapath,
639 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900640 TrafficForwarder* forwarder,
Garrick Evans2961c7c2020-04-03 11:34:40 +0900641 const std::vector<Device::Config*>& configs)
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900642 : cid_(kInvalidCID),
643 shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900644 datapath_(datapath),
645 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900646 forwarder_(forwarder),
Garrick Evans2961c7c2020-04-03 11:34:40 +0900647 configs_(configs) {}
Garrick Evansb4eb3892019-11-13 12:07:07 +0900648
649GuestMessage::GuestType ArcService::VmImpl::guest() const {
650 return GuestMessage::ARC_VM;
651}
652
Garrick Evans015b0d62020-02-07 09:06:38 +0900653uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900654 return cid_;
655}
656
Garrick Evans38b25a42020-04-06 15:17:42 +0900657std::vector<const Device::Config*> ArcService::VmImpl::GetDeviceConfigs()
658 const {
659 std::vector<const Device::Config*> configs;
660 for (const auto* c : configs_)
661 configs.emplace_back(c);
662
663 return configs;
664}
665
Garrick Evans015b0d62020-02-07 09:06:38 +0900666bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900667 // This can happen if concierge crashes and doesn't send the vm down RPC.
668 // It can probably be addressed by stopping and restarting the service.
669 if (cid_ != kInvalidCID)
670 return false;
671
Garrick Evans015b0d62020-02-07 09:06:38 +0900672 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900673 LOG(ERROR) << "Invalid VM cid " << cid;
674 return false;
675 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900676 cid_ = cid;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900677
Garrick Evanse94b6de2020-02-20 09:19:13 +0900678 Device::Options opts{
679 .fwd_multicast = true,
680 .ipv6_enabled = true,
Garrick Evanse94b6de2020-02-20 09:19:13 +0900681 };
Garrick Evans2961c7c2020-04-03 11:34:40 +0900682 auto arc_config = MakeArcConfig(addr_mgr_, AddressManager::Guest::VM_ARC);
683 configs_.insert(configs_.begin(), arc_config.get());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900684
Garrick Evans2961c7c2020-04-03 11:34:40 +0900685 // Allocate TAP devices for all configs.
686 for (auto* config : configs_) {
Garrick Evansc7071122020-04-17 12:31:57 +0900687 auto mac = config->mac_addr();
688 auto tap =
689 datapath_->AddTAP("" /* auto-generate name */, &mac,
690 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900691 if (tap.empty()) {
692 LOG(ERROR) << "Failed to create TAP device";
693 continue;
694 }
695
696 config->set_tap_ifname(tap);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900697 }
698
Garrick Evans2961c7c2020-04-03 11:34:40 +0900699 arc_device_ = std::make_unique<Device>(
700 kArcVmIfname, kArcVmBridge, kArcVmIfname, std::move(arc_config), opts);
701 // Create the bridge.
702 if (!datapath_->AddBridge(kArcVmBridge,
703 arc_device_->config().host_ipv4_addr(), 30)) {
704 LOG(ERROR) << "Failed to setup arc bridge for device " << *arc_device_;
705 return false;
706 }
Garrick Evanse94b6de2020-02-20 09:19:13 +0900707 OnStartDevice(arc_device_.get());
708
709 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
Garrick Evansb4eb3892019-11-13 12:07:07 +0900710 return true;
711}
712
Garrick Evans015b0d62020-02-07 09:06:38 +0900713void ArcService::VmImpl::Stop(uint32_t cid) {
Garrick Evans21173b12019-11-20 15:23:16 +0900714 if (cid_ != cid) {
715 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
716 return;
717 }
718
Garrick Evans2961c7c2020-04-03 11:34:40 +0900719 for (auto* config : configs_) {
720 const auto& tap = config->tap_ifname();
721 if (!tap.empty()) {
722 datapath_->RemoveInterface(tap);
723 config->set_tap_ifname("");
724 }
725 }
726
Garrick Evanse94b6de2020-02-20 09:19:13 +0900727 OnStopDevice(arc_device_.get());
728 datapath_->RemoveBridge(kArcVmBridge);
729 arc_device_.reset();
730
Garrick Evansb4eb3892019-11-13 12:07:07 +0900731 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
732 cid_ = kInvalidCID;
733}
734
Garrick Evans015b0d62020-02-07 09:06:38 +0900735bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900736 if (cid)
737 *cid = cid_;
738
Garrick Evans015b0d62020-02-07 09:06:38 +0900739 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900740}
741
742bool ArcService::VmImpl::OnStartDevice(Device* device) {
Garrick Evansf5862122020-03-16 09:13:45 +0900743 // TODO(garrick): Remove once ARCVM P is gone.
Garrick Evans2961c7c2020-04-03 11:34:40 +0900744 if (device == arc_device_.get() && !IsMultinetEnabled())
Garrick Evansf5862122020-03-16 09:13:45 +0900745 return OnStartArcPDevice();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900746
Garrick Evans2961c7c2020-04-03 11:34:40 +0900747 std::string tap;
748 for (auto* config : configs_) {
749 if (config == &device->config()) {
750 tap = config->tap_ifname();
751 break;
752 }
753 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900754 if (tap.empty()) {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900755 LOG(ERROR) << "No TAP device for: " << *device;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900756 return false;
757 }
758
Garrick Evans2961c7c2020-04-03 11:34:40 +0900759 LOG(INFO) << "Starting device " << *device << " cid: " << cid_;
760
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900761 if (!datapath_->AddToBridge(device->host_ifname(), tap)) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900762 LOG(ERROR) << "Failed to bridge TAP device " << tap;
763 datapath_->RemoveInterface(tap);
764 return false;
765 }
766
Garrick Evansf5862122020-03-16 09:13:45 +0900767 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900768 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
769 device->options().ipv6_enabled,
770 device->options().fwd_multicast);
Garrick Evansf5862122020-03-16 09:13:45 +0900771
772 return true;
773}
774
775bool ArcService::VmImpl::OnStartArcPDevice() {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900776 LOG(INFO) << "Starting device " << *arc_device_ << " cid: " << cid_;
Garrick Evansf5862122020-03-16 09:13:45 +0900777
Garrick Evans2961c7c2020-04-03 11:34:40 +0900778 if (!datapath_->AddToBridge(kArcVmBridge,
779 arc_device_->config().tap_ifname())) {
780 LOG(ERROR) << "Failed to bridge TAP device " << *arc_device_;
Garrick Evansf5862122020-03-16 09:13:45 +0900781 return false;
782 }
783
Garrick Evansf5862122020-03-16 09:13:45 +0900784 // Setup the iptables.
785 if (!datapath_->AddLegacyIPv4DNAT(
786 IPv4AddressToString(arc_device_->config().guest_ipv4_addr())))
787 LOG(ERROR) << "Failed to configure ARC traffic rules";
788
789 if (!datapath_->AddOutboundIPv4(kArcVmBridge))
790 LOG(ERROR) << "Failed to configure egress traffic rules";
791
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900792 OnDefaultInterfaceChanged(shill_client_->default_interface(),
793 "" /*previous*/);
Garrick Evansbcce09e2020-03-10 15:08:04 +0900794
Garrick Evansb4eb3892019-11-13 12:07:07 +0900795 return true;
796}
797
798void ArcService::VmImpl::OnStopDevice(Device* device) {
Garrick Evansf5862122020-03-16 09:13:45 +0900799 // TODO(garrick): Remove once ARCVM P is gone.
Garrick Evans2961c7c2020-04-03 11:34:40 +0900800 if (device == arc_device_.get() && !IsMultinetEnabled())
Garrick Evansf5862122020-03-16 09:13:45 +0900801 return OnStopArcPDevice();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900802
Garrick Evans2961c7c2020-04-03 11:34:40 +0900803 LOG(INFO) << "Stopping device " << *device << " cid: " << cid_;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900804
Garrick Evansf5862122020-03-16 09:13:45 +0900805 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900806 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
Garrick Evansf5862122020-03-16 09:13:45 +0900807 device->options().ipv6_enabled,
808 device->options().fwd_multicast);
Garrick Evansbcce09e2020-03-10 15:08:04 +0900809
Garrick Evans2961c7c2020-04-03 11:34:40 +0900810 for (auto* config : configs_) {
811 if (config == &device->config()) {
812 config->set_tap_ifname("");
813 break;
814 }
815 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900816}
817
Garrick Evansf5862122020-03-16 09:13:45 +0900818void ArcService::VmImpl::OnStopArcPDevice() {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900819 LOG(INFO) << "Stopping device " << *arc_device_.get() << " cid: " << cid_;
Garrick Evansf5862122020-03-16 09:13:45 +0900820
821 datapath_->RemoveOutboundIPv4(kArcVmBridge);
822 datapath_->RemoveLegacyIPv4DNAT();
823
824 OnDefaultInterfaceChanged("" /*new_ifname*/,
825 shill_client_->default_interface());
826
Garrick Evans2961c7c2020-04-03 11:34:40 +0900827 arc_device_->config().set_tap_ifname("");
Garrick Evansf5862122020-03-16 09:13:45 +0900828}
829
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900830void ArcService::VmImpl::OnDefaultInterfaceChanged(
831 const std::string& new_ifname, const std::string& prev_ifname) {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900832 if (!IsStarted() || IsMultinetEnabled())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900833 return;
834
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900835 forwarder_->StopForwarding(prev_ifname, kArcVmBridge, true /*ipv6*/,
836 true /*multicast*/);
837
Garrick Evansb4eb3892019-11-13 12:07:07 +0900838 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900839
840 // If a new default interface was given, then re-enable with that.
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900841 if (!new_ifname.empty()) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900842 datapath_->AddLegacyIPv4InboundDNAT(new_ifname);
Jason Jeremy Iman0e9f8262020-03-06 14:50:49 +0900843 forwarder_->StartForwarding(new_ifname, kArcVmBridge, true /*ipv6*/,
844 true /*multicast*/);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900845 }
846}
847
Garrick Evans2961c7c2020-04-03 11:34:40 +0900848bool ArcService::VmImpl::IsMultinetEnabled() const {
849 return configs_.size() > 1;
850}
851
Garrick Evans3388a032020-03-24 11:25:55 +0900852} // namespace patchpanel