blob: 1511ecca16aa98310b386686f222f13f0d762965 [file] [log] [blame]
Garrick Evans5d55f5e2019-07-17 15:28:10 +09001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "arc/network/arc_service.h"
6
Garrick Evans54861622019-07-19 09:05:09 +09007#include <linux/rtnetlink.h>
8#include <net/if.h>
Garrick Evans6e4eb3b2020-03-09 07:18:31 +09009#include <sys/ioctl.h>
Garrick Evans54861622019-07-19 09:05:09 +090010
Garrick Evans5d55f5e2019-07-17 15:28:10 +090011#include <utility>
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090012#include <vector>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090013
Garrick Evans54861622019-07-19 09:05:09 +090014#include <base/bind.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090015#include <base/files/file_path.h>
16#include <base/files/file_util.h>
17#include <base/logging.h>
18#include <base/strings/string_number_conversions.h>
19#include <base/strings/string_util.h>
Garrick Evans54861622019-07-19 09:05:09 +090020#include <base/strings/stringprintf.h>
Garrick Evans1f5a3612019-11-08 12:59:03 +090021#include <brillo/key_value_store.h>
Garrick Evansb4eb3892019-11-13 12:07:07 +090022#include <chromeos/constants/vm_tools.h>
Garrick Evans54861622019-07-19 09:05:09 +090023
24#include "arc/network/datapath.h"
Garrick Evans54861622019-07-19 09:05:09 +090025#include "arc/network/mac_address_generator.h"
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090026#include "arc/network/manager.h"
Garrick Evans3915af32019-07-25 15:44:34 +090027#include "arc/network/minijailed_process_runner.h"
Garrick Evans54861622019-07-19 09:05:09 +090028#include "arc/network/net_util.h"
29#include "arc/network/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090030
31namespace arc_networkd {
Garrick Evansf29f5a32019-12-06 11:34:25 +090032namespace test {
33GuestMessage::GuestType guest = GuestMessage::UNKNOWN_GUEST;
34} // namespace test
35
Garrick Evans5d55f5e2019-07-17 15:28:10 +090036namespace {
Garrick Evans015b0d62020-02-07 09:06:38 +090037constexpr pid_t kInvalidPID = 0;
Garrick Evansb4eb3892019-11-13 12:07:07 +090038constexpr pid_t kTestPID = -2;
Garrick Evans015b0d62020-02-07 09:06:38 +090039constexpr uint32_t kInvalidCID = 0;
Garrick Evanse94b6de2020-02-20 09:19:13 +090040constexpr char kArcIfname[] = "arc0";
41constexpr char kArcBridge[] = "arcbr0";
42constexpr char kArcVmIfname[] = "arc1";
43constexpr char kArcVmBridge[] = "arc_br1";
Garrick Evans6e4eb3b2020-03-09 07:18:31 +090044constexpr std::array<const char*, 2> kEthernetInterfacePrefixes{{"eth", "usb"}};
45constexpr std::array<const char*, 2> kWifiInterfacePrefixes{{"wlan", "mlan"}};
Garrick Evans86c7d9c2020-03-17 09:25:48 +090046constexpr std::array<const char*, 2> kCellInterfacePrefixes{{"wwan", "rmnet"}};
Garrick Evans54861622019-07-19 09:05:09 +090047
Garrick Evans6d227b92019-12-03 16:11:29 +090048void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090049 static bool done = false;
50 if (done)
51 return;
52
Garrick Evans6d227b92019-12-03 16:11:29 +090053 auto& runner = datapath.runner();
54
55 // Load networking modules needed by Android that are not compiled in the
56 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansa34b5862019-11-20 09:34:01 +090057 // These must succeed.
Garrick Evans8e8e3472020-01-23 14:03:50 +090058 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090059 // The netfilter modules needed by netd for iptables commands.
60 "ip6table_filter",
61 "ip6t_ipv6header",
62 "ip6t_REJECT",
63 // The xfrm modules needed for Android's ipsec APIs.
64 "xfrm4_mode_transport",
65 "xfrm4_mode_tunnel",
66 "xfrm6_mode_transport",
67 "xfrm6_mode_tunnel",
68 // The ipsec modules for AH and ESP encryption for ipv6.
69 "ah6",
70 "esp6",
71 }) != 0) {
72 LOG(ERROR) << "One or more required kernel modules failed to load."
73 << " Some Android functionality may be broken.";
74 }
75 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +090076 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090077 // This module is not available in kernels < 3.18
78 "nf_reject_ipv6",
79 // These modules are needed for supporting Chrome traffic on Android
80 // VPN which uses Android's NAT feature. Android NAT sets up
81 // iptables
82 // rules that use these conntrack modules for FTP/TFTP.
83 "nf_nat_ftp",
84 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +090085 // The tun module is needed by the Android 464xlat clatd process.
86 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +090087 }) != 0) {
88 LOG(WARNING) << "One or more optional kernel modules failed to load.";
89 }
90
Garrick Evans6d227b92019-12-03 16:11:29 +090091 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +090092 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +090093 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
94 }
95
Garrick Evansa34b5862019-11-20 09:34:01 +090096 done = true;
97}
98
Garrick Evans508a4bc2019-11-14 08:45:52 +090099bool IsArcVm() {
100 const base::FilePath path("/run/chrome/is_arcvm");
101 std::string contents;
102 if (!base::ReadFileToString(path, &contents)) {
103 PLOG(ERROR) << "Could not read " << path.value();
104 }
105 return contents == "1";
106}
107
Garrick Evansf29f5a32019-12-06 11:34:25 +0900108GuestMessage::GuestType ArcGuest() {
109 if (test::guest != GuestMessage::UNKNOWN_GUEST)
110 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900111
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900112 return IsArcVm() ? GuestMessage::ARC_VM : GuestMessage::ARC;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900113}
114
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900115ArcService::InterfaceType InterfaceTypeFor(const std::string& ifname) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900116 for (const auto& prefix : kEthernetInterfacePrefixes) {
117 if (base::StartsWith(ifname, prefix,
118 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900119 return ArcService::InterfaceType::ETHERNET;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900120 }
121 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900122 for (const auto& prefix : kWifiInterfacePrefixes) {
123 if (base::StartsWith(ifname, prefix,
124 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900125 return ArcService::InterfaceType::WIFI;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900126 }
127 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900128 for (const auto& prefix : kCellInterfacePrefixes) {
129 if (base::StartsWith(ifname, prefix,
130 base::CompareCase::INSENSITIVE_ASCII)) {
131 return ArcService::InterfaceType::CELL;
132 }
133 }
134 return ArcService::InterfaceType::UNKNOWN;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900135}
136
137bool IsMulticastInterface(const std::string& ifname) {
138 if (ifname.empty()) {
139 return false;
140 }
141
142 int fd = socket(AF_INET, SOCK_DGRAM, 0);
143 if (fd < 0) {
144 // If IPv4 fails, try to open a socket using IPv6.
145 fd = socket(AF_INET6, SOCK_DGRAM, 0);
146 if (fd < 0) {
147 LOG(ERROR) << "Unable to create socket";
148 return false;
149 }
150 }
151
152 struct ifreq ifr;
153 memset(&ifr, 0, sizeof(ifr));
154 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
155 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
156 PLOG(ERROR) << "SIOCGIFFLAGS failed for " << ifname;
157 close(fd);
158 return false;
159 }
160
161 close(fd);
162 return (ifr.ifr_flags & IFF_MULTICAST);
163}
164
Garrick Evanse94b6de2020-02-20 09:19:13 +0900165// Returns the configuration for the ARC management interface used for VPN
166// forwarding, ADB-over-TCP and single-networked ARCVM.
167std::unique_ptr<Device::Config> MakeArcConfig(AddressManager* addr_mgr,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900168 AddressManager::Guest guest) {
169 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(guest);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900170 if (!ipv4_subnet) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900171 LOG(ERROR) << "Subnet already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900172 return nullptr;
173 }
174 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
175 if (!host_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900176 LOG(ERROR) << "Bridge address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900177 return nullptr;
178 }
179 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
180 if (!guest_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900181 LOG(ERROR) << "ARC address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900182 return nullptr;
183 }
184
185 return std::make_unique<Device::Config>(
Garrick Evanse94b6de2020-02-20 09:19:13 +0900186 addr_mgr->GenerateMacAddress(), std::move(ipv4_subnet),
187 std::move(host_ipv4_addr), std::move(guest_ipv4_addr));
188}
189
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900190} // namespace
191
Garrick Evans69b85872020-02-04 11:40:26 +0900192ArcService::ArcService(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900193 Datapath* datapath,
194 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900195 TrafficForwarder* forwarder,
196 bool enable_arcvm_multinet)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900197 : shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900198 datapath_(datapath),
199 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900200 forwarder_(forwarder),
201 enable_arcvm_multinet_(enable_arcvm_multinet) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900202 AllocateAddressConfigs();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900203 shill_client_->RegisterDevicesChangedHandler(
204 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
205 shill_client_->ScanDevices(
206 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900207 shill_client_->RegisterDefaultInterfaceChangedHandler(base::Bind(
208 &ArcService::OnDefaultInterfaceChanged, weak_factory_.GetWeakPtr()));
Garrick Evansf29f5a32019-12-06 11:34:25 +0900209}
210
211ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900212 if (impl_) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900213 Stop(impl_->id());
Garrick Evans664a82f2019-12-17 12:18:05 +0900214 }
Garrick Evans54861622019-07-19 09:05:09 +0900215}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900216
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900217void ArcService::AllocateAddressConfigs() {
218 configs_.clear();
219 // The first usable subnet is the "other" ARC device subnet.
220 // TODO(garrick): This can be removed and ARC_NET will be widened once ARCVM
221 // switches over to use .0/30.
222 AddressManager::Guest alloc =
223 IsArcVm() ? AddressManager::Guest::ARC : AddressManager::Guest::VM_ARC;
224 // Allocate 2 subnets each for Ethernet and WiFi and 1 for LTE WAN interfaces.
225 for (const auto itype :
226 {InterfaceType::ETHERNET, InterfaceType::ETHERNET, InterfaceType::WIFI,
227 InterfaceType::WIFI, InterfaceType::CELL}) {
228 auto ipv4_subnet = addr_mgr_->AllocateIPv4Subnet(alloc);
229 if (!ipv4_subnet) {
230 LOG(ERROR) << "Subnet already in use or unavailable";
231 continue;
232 }
233 // For here out, use the same slices.
234 alloc = AddressManager::Guest::ARC_NET;
235 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
236 if (!host_ipv4_addr) {
237 LOG(ERROR) << "Bridge address already in use or unavailable";
238 continue;
239 }
240 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
241 if (!guest_ipv4_addr) {
242 LOG(ERROR) << "ARC address already in use or unavailable";
243 continue;
244 }
245
246 configs_[itype].emplace_back(std::make_unique<Device::Config>(
247 addr_mgr_->GenerateMacAddress(), std::move(ipv4_subnet),
248 std::move(host_ipv4_addr), std::move(guest_ipv4_addr)));
249 }
250}
251
Garrick Evans2961c7c2020-04-03 11:34:40 +0900252std::vector<Device::Config*> ArcService::ReallocateAddressConfigs() {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900253 std::vector<std::string> existing_devices;
254 for (const auto& d : devices_) {
255 existing_devices.emplace_back(d.first);
256 }
257 for (const auto& d : existing_devices) {
258 RemoveDevice(d);
259 }
260 AllocateAddressConfigs();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900261 std::vector<Device::Config*> configs;
262 if (enable_arcvm_multinet_) {
263 for (const auto& kv : configs_)
264 for (const auto& c : kv.second)
265 configs.push_back(c.get());
266 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900267 for (const auto& d : existing_devices) {
268 AddDevice(d);
269 }
Garrick Evans2961c7c2020-04-03 11:34:40 +0900270 return configs;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900271}
272
273std::unique_ptr<Device::Config> ArcService::AcquireConfig(
274 const std::string& ifname) {
275 auto itype = InterfaceTypeFor(ifname);
276 if (itype == InterfaceType::UNKNOWN) {
277 LOG(ERROR) << "Unsupported interface: " << ifname;
278 return nullptr;
279 }
280
281 auto& configs = configs_[itype];
282 if (configs.empty()) {
283 LOG(ERROR) << "No more addresses available. Cannot make device for "
284 << ifname;
285 return nullptr;
286 }
287 std::unique_ptr<Device::Config> config;
288 config = std::move(configs.front());
289 configs.pop_front();
290 return config;
291}
292
293void ArcService::ReleaseConfig(const std::string& ifname,
294 std::unique_ptr<Device::Config> config) {
295 auto itype = InterfaceTypeFor(ifname);
296 if (itype == InterfaceType::UNKNOWN) {
297 LOG(ERROR) << "Unsupported interface: " << ifname;
298 return;
299 }
300
301 configs_[itype].push_front(std::move(config));
302}
303
Garrick Evans015b0d62020-02-07 09:06:38 +0900304bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900305 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900306 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900307 if (impl_->IsStarted(&prev_id)) {
308 LOG(WARNING) << "Already running - did something crash?"
309 << " Stopping and restarting...";
310 Stop(prev_id);
311 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900312 }
313
Garrick Evans2961c7c2020-04-03 11:34:40 +0900314 auto configs = ReallocateAddressConfigs();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900315 const auto guest = ArcGuest();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900316 if (guest == GuestMessage::ARC_VM) {
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900317 impl_ = std::make_unique<VmImpl>(shill_client_, datapath_, addr_mgr_,
Garrick Evans2961c7c2020-04-03 11:34:40 +0900318 forwarder_, configs);
319 } else {
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900320 impl_ = std::make_unique<ContainerImpl>(datapath_, addr_mgr_, forwarder_,
321 guest);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900322 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900323 if (!impl_->Start(id)) {
324 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900325 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900326 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900327
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900328 // Start already known Shill <-> ARC mapped devices.
329 for (const auto& d : devices_)
330 StartDevice(d.second.get());
Garrick Evanscb791e72019-11-11 15:44:34 +0900331
Garrick Evansf29f5a32019-12-06 11:34:25 +0900332 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900333}
334
Garrick Evans015b0d62020-02-07 09:06:38 +0900335void ArcService::Stop(uint32_t id) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900336 // Stop Shill <-> ARC mapped devices.
337 for (const auto& d : devices_)
338 StopDevice(d.second.get());
Garrick Evansf29f5a32019-12-06 11:34:25 +0900339
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900340 if (impl_) {
341 impl_->Stop(id);
342 impl_.reset();
343 }
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900344}
345
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900346void ArcService::OnDevicesChanged(const std::set<std::string>& added,
347 const std::set<std::string>& removed) {
348 for (const std::string& name : removed)
349 RemoveDevice(name);
350
351 for (const std::string& name : added)
352 AddDevice(name);
353}
354
355void ArcService::AddDevice(const std::string& ifname) {
356 if (ifname.empty())
357 return;
358
359 if (devices_.find(ifname) != devices_.end()) {
360 LOG(DFATAL) << "Attemping to add already tracked device: " << ifname;
361 return;
362 }
363
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900364 auto itype = InterfaceTypeFor(ifname);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900365 Device::Options opts{
366 .fwd_multicast = IsMulticastInterface(ifname),
367 // TODO(crbug/726815) Also enable |ipv6_enabled| for cellular networks
368 // once IPv6 is enabled on cellular networks in shill.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900369 .ipv6_enabled =
370 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900371 };
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900372
373 auto config = AcquireConfig(ifname);
374 if (!config) {
375 LOG(ERROR) << "Cannot add device for " << ifname;
376 return;
377 }
378
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900379 std::string host_ifname = base::StringPrintf("arc_%s", ifname.c_str());
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900380 auto device = std::make_unique<Device>(ifname, host_ifname, ifname,
381 std::move(config), opts);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900382
383 StartDevice(device.get());
384 devices_.emplace(ifname, std::move(device));
385}
386
387void ArcService::StartDevice(Device* device) {
388 if (!impl_ || !impl_->IsStarted())
389 return;
390
391 // For now, only start devices for ARC++.
392 if (impl_->guest() != GuestMessage::ARC)
393 return;
394
Garrick Evans54861622019-07-19 09:05:09 +0900395 const auto& config = device->config();
396
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900397 LOG(INFO) << "Adding device " << device->phys_ifname()
398 << " bridge: " << device->host_ifname()
399 << " guest_iface: " << device->guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900400
401 // Create the bridge.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900402 if (!datapath_->AddBridge(device->host_ifname(), config.host_ipv4_addr(),
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900403 30)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900404 LOG(ERROR) << "Failed to setup arc bridge: " << device->host_ifname();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900405 return;
Garrick Evans54861622019-07-19 09:05:09 +0900406 }
407
Garrick Evanse94b6de2020-02-20 09:19:13 +0900408 // Set up iptables.
409 if (!datapath_->AddInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900410 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
Garrick Evanse94b6de2020-02-20 09:19:13 +0900411 LOG(ERROR) << "Failed to configure ingress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900412 << device->phys_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900413
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900414 if (!datapath_->AddOutboundIPv4(device->host_ifname()))
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900415 LOG(ERROR) << "Failed to configure egress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900416 << device->phys_ifname();
Garrick Evans2c263102019-07-26 16:07:18 +0900417
Garrick Evansd90a3822019-11-12 17:53:08 +0900418 if (!impl_->OnStartDevice(device)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900419 LOG(ERROR) << "Failed to start device " << device->phys_ifname();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900420 }
421}
422
423void ArcService::RemoveDevice(const std::string& ifname) {
424 const auto it = devices_.find(ifname);
425 if (it == devices_.end()) {
426 LOG(WARNING) << "Unknown device: " << ifname;
Garrick Evanscb791e72019-11-11 15:44:34 +0900427 return;
428 }
429
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900430 // If the container is down, this call does nothing.
431 StopDevice(it->second.get());
432
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900433 ReleaseConfig(ifname, it->second->release_config());
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900434 devices_.erase(it);
Garrick Evans54861622019-07-19 09:05:09 +0900435}
436
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900437void ArcService::StopDevice(Device* device) {
438 if (!impl_ || !impl_->IsStarted())
439 return;
440
441 // For now, devices are only started for ARC++.
442 if (impl_->guest() != GuestMessage::ARC)
443 return;
444
445 impl_->OnStopDevice(device);
Garrick Evans54861622019-07-19 09:05:09 +0900446
447 const auto& config = device->config();
448
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900449 LOG(INFO) << "Removing device " << device->phys_ifname()
450 << " bridge: " << device->host_ifname()
451 << " guest_iface: " << device->guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900452
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900453 datapath_->RemoveOutboundIPv4(device->host_ifname());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900454 datapath_->RemoveInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900455 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
Garrick Evans54861622019-07-19 09:05:09 +0900456
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900457 datapath_->RemoveBridge(device->host_ifname());
Garrick Evanscb791e72019-11-11 15:44:34 +0900458}
459
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900460void ArcService::OnDefaultInterfaceChanged(const std::string& new_ifname,
461 const std::string& prev_ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900462 if (impl_)
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900463 impl_->OnDefaultInterfaceChanged(new_ifname, prev_ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900464}
Garrick Evansba575742019-07-17 15:48:08 +0900465
Garrick Evans38b25a42020-04-06 15:17:42 +0900466std::vector<const Device::Config*> ArcService::GetDeviceConfigs() const {
467 if (impl_)
468 return impl_->GetDeviceConfigs();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900469
Garrick Evans38b25a42020-04-06 15:17:42 +0900470 return {};
Garrick Evanse94b6de2020-02-20 09:19:13 +0900471}
472
Garrick Evansd90a3822019-11-12 17:53:08 +0900473// ARC++ specific functions.
474
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900475ArcService::ContainerImpl::ContainerImpl(Datapath* datapath,
476 AddressManager* addr_mgr,
477 TrafficForwarder* forwarder,
Garrick Evansd90a3822019-11-12 17:53:08 +0900478 GuestMessage::GuestType guest)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900479 : pid_(kInvalidPID),
480 datapath_(datapath),
481 addr_mgr_(addr_mgr),
482 forwarder_(forwarder),
483 guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900484 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900485}
Garrick Evansd90a3822019-11-12 17:53:08 +0900486
Garrick Evansb4eb3892019-11-13 12:07:07 +0900487GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
488 return guest_;
489}
490
Garrick Evans015b0d62020-02-07 09:06:38 +0900491uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900492 return pid_;
493}
494
Garrick Evans015b0d62020-02-07 09:06:38 +0900495bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900496 // This could happen if something crashes and the stop signal is not sent.
497 // It can probably be addressed by stopping and restarting the service.
498 if (pid_ != kInvalidPID)
499 return false;
500
Garrick Evans4dec0c42019-11-29 12:51:57 +0900501 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900502 LOG(ERROR) << "Cannot start service - invalid container PID";
503 return false;
504 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900505 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900506
Garrick Evanse94b6de2020-02-20 09:19:13 +0900507 Device::Options opts{
508 .fwd_multicast = false,
509 .ipv6_enabled = false,
Garrick Evanse94b6de2020-02-20 09:19:13 +0900510 };
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900511 auto config = MakeArcConfig(addr_mgr_, AddressManager::Guest::ARC);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900512
513 // Create the bridge.
514 // Per crbug/1008686 this device cannot be deleted and then re-added.
515 // So instead of removing the bridge when the service stops, bring down the
516 // device instead and re-up it on restart.
517 if (!datapath_->AddBridge(kArcBridge, config->host_ipv4_addr(), 30) &&
518 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
519 LOG(ERROR) << "Failed to bring up arc bridge: " << kArcBridge;
520 return false;
521 }
522
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900523 arc_device_ = std::make_unique<Device>(kArcIfname, kArcBridge, kArcIfname,
524 std::move(config), opts);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900525
526 OnStartDevice(arc_device_.get());
527
Garrick Evansd90a3822019-11-12 17:53:08 +0900528 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
529 return true;
530}
531
Garrick Evans015b0d62020-02-07 09:06:38 +0900532void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900533 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900534 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900535
Garrick Evanse94b6de2020-02-20 09:19:13 +0900536 // Per crbug/1008686 this device cannot be deleted and then re-added.
537 // So instead of removing the bridge, bring it down and mark it. This will
538 // allow us to detect if the device is re-added in case of a crash restart
539 // and do the right thing.
540 if (arc_device_) {
541 OnStopDevice(arc_device_.get());
542 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
543 LOG(ERROR) << "Failed to bring down arc bridge "
544 << "- it may not restart correctly";
545 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900546
547 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
548 pid_ = kInvalidPID;
549}
550
Garrick Evans015b0d62020-02-07 09:06:38 +0900551bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900552 if (pid)
553 *pid = pid_;
554
Garrick Evansd90a3822019-11-12 17:53:08 +0900555 return pid_ != kInvalidPID;
556}
557
558bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900559 LOG(INFO) << "Starting device " << device->phys_ifname()
560 << " bridge: " << device->host_ifname()
561 << " guest_iface: " << device->guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900562
Garrick Evans2470caa2020-03-04 14:15:41 +0900563 // Set up the virtual pair inside the container namespace.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900564 const std::string veth_ifname = ArcVethHostName(device->guest_ifname());
Garrick Evans2470caa2020-03-04 14:15:41 +0900565 {
566 ScopedNS ns(pid_);
567 if (!ns.IsValid() && pid_ != kTestPID) {
568 LOG(ERROR)
569 << "Cannot create virtual link -- invalid container namespace?";
570 return false;
571 }
572
573 if (!datapath_->AddVirtualInterfacePair(veth_ifname,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900574 device->guest_ifname())) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900575 LOG(ERROR) << "Failed to create virtual interface pair for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900576 << device->phys_ifname();
Garrick Evans2470caa2020-03-04 14:15:41 +0900577 return false;
578 }
579
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900580 const auto& config = device->config();
581
Garrick Evans2470caa2020-03-04 14:15:41 +0900582 if (!datapath_->ConfigureInterface(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900583 device->guest_ifname(), config.mac_addr(), config.guest_ipv4_addr(),
584 30, true /* link up */, device->options().fwd_multicast)) {
585 LOG(ERROR) << "Failed to configure interface " << device->guest_ifname();
586 datapath_->RemoveInterface(device->guest_ifname());
Garrick Evans2470caa2020-03-04 14:15:41 +0900587 return false;
588 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900589 }
590
Garrick Evans2470caa2020-03-04 14:15:41 +0900591 // Now pull the host end out into the root namespace and add it to the bridge.
592 if (datapath_->runner().RestoreDefaultNamespace(veth_ifname, pid_) != 0) {
593 LOG(ERROR) << "Failed to prepare interface " << veth_ifname;
594 {
595 ScopedNS ns(pid_);
596 if (ns.IsValid()) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900597 datapath_->RemoveInterface(device->guest_ifname());
Garrick Evans2470caa2020-03-04 14:15:41 +0900598 } else {
599 LOG(ERROR) << "Failed to re-enter container namespace."
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900600 << " Subsequent attempts to restart "
601 << device->phys_ifname() << " may not succeed.";
Garrick Evans2470caa2020-03-04 14:15:41 +0900602 }
603 }
604 return false;
605 }
606 if (!datapath_->ToggleInterface(veth_ifname, true /*up*/)) {
607 LOG(ERROR) << "Failed to bring up interface " << veth_ifname;
Garrick Evansd90a3822019-11-12 17:53:08 +0900608 datapath_->RemoveInterface(veth_ifname);
Garrick Evansd90a3822019-11-12 17:53:08 +0900609 return false;
610 }
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900611 if (!datapath_->AddToBridge(device->host_ifname(), veth_ifname)) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900612 datapath_->RemoveInterface(veth_ifname);
613 LOG(ERROR) << "Failed to bridge interface " << veth_ifname;
614 return false;
615 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900616
Garrick Evans3bd06372020-03-23 10:42:58 +0900617 if (device != arc_device_.get()) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900618 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
619 device->options().ipv6_enabled,
620 device->options().fwd_multicast);
Garrick Evans3bd06372020-03-23 10:42:58 +0900621 } else {
622 // Signal the container that the network device is ready.
623 datapath_->runner().WriteSentinelToContainer(pid_);
624 }
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900625
Garrick Evansd90a3822019-11-12 17:53:08 +0900626 return true;
627}
628
629void ArcService::ContainerImpl::OnStopDevice(Device* device) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900630 LOG(INFO) << "Stopping device " << device->phys_ifname()
631 << " bridge: " << device->host_ifname()
632 << " guest_iface: " << device->guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900633
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900634 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900635 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900636 device->options().ipv6_enabled,
637 device->options().fwd_multicast);
638
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900639 datapath_->RemoveInterface(ArcVethHostName(device->phys_ifname()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900640}
641
642void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900643 const std::string& new_ifname, const std::string& prev_ifname) {}
Garrick Evansd90a3822019-11-12 17:53:08 +0900644
Garrick Evansb4eb3892019-11-13 12:07:07 +0900645// VM specific functions
646
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900647ArcService::VmImpl::VmImpl(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900648 Datapath* datapath,
649 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900650 TrafficForwarder* forwarder,
Garrick Evans2961c7c2020-04-03 11:34:40 +0900651 const std::vector<Device::Config*>& configs)
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900652 : cid_(kInvalidCID),
653 shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900654 datapath_(datapath),
655 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900656 forwarder_(forwarder),
Garrick Evans2961c7c2020-04-03 11:34:40 +0900657 configs_(configs) {}
Garrick Evansb4eb3892019-11-13 12:07:07 +0900658
659GuestMessage::GuestType ArcService::VmImpl::guest() const {
660 return GuestMessage::ARC_VM;
661}
662
Garrick Evans015b0d62020-02-07 09:06:38 +0900663uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900664 return cid_;
665}
666
Garrick Evans38b25a42020-04-06 15:17:42 +0900667std::vector<const Device::Config*> ArcService::VmImpl::GetDeviceConfigs()
668 const {
669 std::vector<const Device::Config*> configs;
670 for (const auto* c : configs_)
671 configs.emplace_back(c);
672
673 return configs;
674}
675
Garrick Evans015b0d62020-02-07 09:06:38 +0900676bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900677 // This can happen if concierge crashes and doesn't send the vm down RPC.
678 // It can probably be addressed by stopping and restarting the service.
679 if (cid_ != kInvalidCID)
680 return false;
681
Garrick Evans015b0d62020-02-07 09:06:38 +0900682 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900683 LOG(ERROR) << "Invalid VM cid " << cid;
684 return false;
685 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900686 cid_ = cid;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900687
Garrick Evanse94b6de2020-02-20 09:19:13 +0900688 Device::Options opts{
689 .fwd_multicast = true,
690 .ipv6_enabled = true,
Garrick Evanse94b6de2020-02-20 09:19:13 +0900691 };
Garrick Evans2961c7c2020-04-03 11:34:40 +0900692 auto arc_config = MakeArcConfig(addr_mgr_, AddressManager::Guest::VM_ARC);
693 configs_.insert(configs_.begin(), arc_config.get());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900694
Garrick Evans2961c7c2020-04-03 11:34:40 +0900695 // Allocate TAP devices for all configs.
696 for (auto* config : configs_) {
697 // Since the interface will be added to the bridge, no address configuration
698 // should be provided here.
699 auto tap = datapath_->AddTAP(
700 "" /* auto-generate name */, nullptr /* no mac addr */,
701 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
702 if (tap.empty()) {
703 LOG(ERROR) << "Failed to create TAP device";
704 continue;
705 }
706
707 config->set_tap_ifname(tap);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900708 }
709
Garrick Evans2961c7c2020-04-03 11:34:40 +0900710 arc_device_ = std::make_unique<Device>(
711 kArcVmIfname, kArcVmBridge, kArcVmIfname, std::move(arc_config), opts);
712 // Create the bridge.
713 if (!datapath_->AddBridge(kArcVmBridge,
714 arc_device_->config().host_ipv4_addr(), 30)) {
715 LOG(ERROR) << "Failed to setup arc bridge for device " << *arc_device_;
716 return false;
717 }
Garrick Evanse94b6de2020-02-20 09:19:13 +0900718 OnStartDevice(arc_device_.get());
719
720 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
Garrick Evansb4eb3892019-11-13 12:07:07 +0900721 return true;
722}
723
Garrick Evans015b0d62020-02-07 09:06:38 +0900724void ArcService::VmImpl::Stop(uint32_t cid) {
Garrick Evans21173b12019-11-20 15:23:16 +0900725 if (cid_ != cid) {
726 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
727 return;
728 }
729
Garrick Evans2961c7c2020-04-03 11:34:40 +0900730 for (auto* config : configs_) {
731 const auto& tap = config->tap_ifname();
732 if (!tap.empty()) {
733 datapath_->RemoveInterface(tap);
734 config->set_tap_ifname("");
735 }
736 }
737
Garrick Evanse94b6de2020-02-20 09:19:13 +0900738 OnStopDevice(arc_device_.get());
739 datapath_->RemoveBridge(kArcVmBridge);
740 arc_device_.reset();
741
Garrick Evansb4eb3892019-11-13 12:07:07 +0900742 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
743 cid_ = kInvalidCID;
744}
745
Garrick Evans015b0d62020-02-07 09:06:38 +0900746bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900747 if (cid)
748 *cid = cid_;
749
Garrick Evans015b0d62020-02-07 09:06:38 +0900750 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900751}
752
753bool ArcService::VmImpl::OnStartDevice(Device* device) {
Garrick Evansf5862122020-03-16 09:13:45 +0900754 // TODO(garrick): Remove once ARCVM P is gone.
Garrick Evans2961c7c2020-04-03 11:34:40 +0900755 if (device == arc_device_.get() && !IsMultinetEnabled())
Garrick Evansf5862122020-03-16 09:13:45 +0900756 return OnStartArcPDevice();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900757
Garrick Evans2961c7c2020-04-03 11:34:40 +0900758 std::string tap;
759 for (auto* config : configs_) {
760 if (config == &device->config()) {
761 tap = config->tap_ifname();
762 break;
763 }
764 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900765 if (tap.empty()) {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900766 LOG(ERROR) << "No TAP device for: " << *device;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900767 return false;
768 }
769
Garrick Evans2961c7c2020-04-03 11:34:40 +0900770 LOG(INFO) << "Starting device " << *device << " cid: " << cid_;
771
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900772 if (!datapath_->AddToBridge(device->host_ifname(), tap)) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900773 LOG(ERROR) << "Failed to bridge TAP device " << tap;
774 datapath_->RemoveInterface(tap);
775 return false;
776 }
777
Garrick Evansf5862122020-03-16 09:13:45 +0900778 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900779 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
780 device->options().ipv6_enabled,
781 device->options().fwd_multicast);
Garrick Evansf5862122020-03-16 09:13:45 +0900782
783 return true;
784}
785
786bool ArcService::VmImpl::OnStartArcPDevice() {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900787 LOG(INFO) << "Starting device " << *arc_device_ << " cid: " << cid_;
Garrick Evansf5862122020-03-16 09:13:45 +0900788
Garrick Evans2961c7c2020-04-03 11:34:40 +0900789 if (!datapath_->AddToBridge(kArcVmBridge,
790 arc_device_->config().tap_ifname())) {
791 LOG(ERROR) << "Failed to bridge TAP device " << *arc_device_;
Garrick Evansf5862122020-03-16 09:13:45 +0900792 return false;
793 }
794
Garrick Evansf5862122020-03-16 09:13:45 +0900795 // Setup the iptables.
796 if (!datapath_->AddLegacyIPv4DNAT(
797 IPv4AddressToString(arc_device_->config().guest_ipv4_addr())))
798 LOG(ERROR) << "Failed to configure ARC traffic rules";
799
800 if (!datapath_->AddOutboundIPv4(kArcVmBridge))
801 LOG(ERROR) << "Failed to configure egress traffic rules";
802
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900803 OnDefaultInterfaceChanged(shill_client_->default_interface(),
804 "" /*previous*/);
Garrick Evansbcce09e2020-03-10 15:08:04 +0900805
Garrick Evansb4eb3892019-11-13 12:07:07 +0900806 return true;
807}
808
809void ArcService::VmImpl::OnStopDevice(Device* device) {
Garrick Evansf5862122020-03-16 09:13:45 +0900810 // TODO(garrick): Remove once ARCVM P is gone.
Garrick Evans2961c7c2020-04-03 11:34:40 +0900811 if (device == arc_device_.get() && !IsMultinetEnabled())
Garrick Evansf5862122020-03-16 09:13:45 +0900812 return OnStopArcPDevice();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900813
Garrick Evans2961c7c2020-04-03 11:34:40 +0900814 LOG(INFO) << "Stopping device " << *device << " cid: " << cid_;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900815
Garrick Evansf5862122020-03-16 09:13:45 +0900816 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900817 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
Garrick Evansf5862122020-03-16 09:13:45 +0900818 device->options().ipv6_enabled,
819 device->options().fwd_multicast);
Garrick Evansbcce09e2020-03-10 15:08:04 +0900820
Garrick Evans2961c7c2020-04-03 11:34:40 +0900821 for (auto* config : configs_) {
822 if (config == &device->config()) {
823 config->set_tap_ifname("");
824 break;
825 }
826 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900827}
828
Garrick Evansf5862122020-03-16 09:13:45 +0900829void ArcService::VmImpl::OnStopArcPDevice() {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900830 LOG(INFO) << "Stopping device " << *arc_device_.get() << " cid: " << cid_;
Garrick Evansf5862122020-03-16 09:13:45 +0900831
832 datapath_->RemoveOutboundIPv4(kArcVmBridge);
833 datapath_->RemoveLegacyIPv4DNAT();
834
835 OnDefaultInterfaceChanged("" /*new_ifname*/,
836 shill_client_->default_interface());
837
Garrick Evans2961c7c2020-04-03 11:34:40 +0900838 arc_device_->config().set_tap_ifname("");
Garrick Evansf5862122020-03-16 09:13:45 +0900839}
840
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900841void ArcService::VmImpl::OnDefaultInterfaceChanged(
842 const std::string& new_ifname, const std::string& prev_ifname) {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900843 if (!IsStarted() || IsMultinetEnabled())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900844 return;
845
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900846 forwarder_->StopForwarding(prev_ifname, kArcVmBridge, true /*ipv6*/,
847 true /*multicast*/);
848
Garrick Evansb4eb3892019-11-13 12:07:07 +0900849 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900850
851 // If a new default interface was given, then re-enable with that.
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900852 if (!new_ifname.empty()) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900853 datapath_->AddLegacyIPv4InboundDNAT(new_ifname);
Jason Jeremy Iman0e9f8262020-03-06 14:50:49 +0900854 forwarder_->StartForwarding(new_ifname, kArcVmBridge, true /*ipv6*/,
855 true /*multicast*/);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900856 }
857}
858
Garrick Evans2961c7c2020-04-03 11:34:40 +0900859bool ArcService::VmImpl::IsMultinetEnabled() const {
860 return configs_.size() > 1;
861}
862
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900863} // namespace arc_networkd