blob: 7bc40a6bd8d7d8301ba96d8c6ed4e919a87e6ab9 [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 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
Garrick Evans3388a032020-03-24 11:25:55 +090024#include "patchpanel/datapath.h"
25#include "patchpanel/mac_address_generator.h"
26#include "patchpanel/manager.h"
27#include "patchpanel/minijailed_process_runner.h"
28#include "patchpanel/net_util.h"
29#include "patchpanel/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090030
Garrick Evans3388a032020-03-24 11:25:55 +090031namespace patchpanel {
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 Evans015b0d62020-02-07 09:06:38 +090038constexpr uint32_t kInvalidCID = 0;
Garrick Evanse94b6de2020-02-20 09:19:13 +090039constexpr char kArcIfname[] = "arc0";
40constexpr char kArcBridge[] = "arcbr0";
41constexpr char kArcVmIfname[] = "arc1";
42constexpr char kArcVmBridge[] = "arc_br1";
Garrick Evans6e4eb3b2020-03-09 07:18:31 +090043constexpr std::array<const char*, 2> kEthernetInterfacePrefixes{{"eth", "usb"}};
44constexpr std::array<const char*, 2> kWifiInterfacePrefixes{{"wlan", "mlan"}};
Garrick Evans86c7d9c2020-03-17 09:25:48 +090045constexpr std::array<const char*, 2> kCellInterfacePrefixes{{"wwan", "rmnet"}};
Garrick Evans54861622019-07-19 09:05:09 +090046
Garrick Evans6d227b92019-12-03 16:11:29 +090047void OneTimeSetup(const Datapath& datapath) {
Garrick Evansa34b5862019-11-20 09:34:01 +090048 static bool done = false;
49 if (done)
50 return;
51
Garrick Evans6d227b92019-12-03 16:11:29 +090052 auto& runner = datapath.runner();
53
54 // Load networking modules needed by Android that are not compiled in the
55 // kernel. Android does not allow auto-loading of kernel modules.
Garrick Evansa34b5862019-11-20 09:34:01 +090056 // These must succeed.
Garrick Evans8e8e3472020-01-23 14:03:50 +090057 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090058 // The netfilter modules needed by netd for iptables commands.
59 "ip6table_filter",
60 "ip6t_ipv6header",
61 "ip6t_REJECT",
62 // The xfrm modules needed for Android's ipsec APIs.
63 "xfrm4_mode_transport",
64 "xfrm4_mode_tunnel",
65 "xfrm6_mode_transport",
66 "xfrm6_mode_tunnel",
67 // The ipsec modules for AH and ESP encryption for ipv6.
68 "ah6",
69 "esp6",
70 }) != 0) {
71 LOG(ERROR) << "One or more required kernel modules failed to load."
72 << " Some Android functionality may be broken.";
73 }
74 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +090075 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090076 // This module is not available in kernels < 3.18
77 "nf_reject_ipv6",
78 // These modules are needed for supporting Chrome traffic on Android
79 // VPN which uses Android's NAT feature. Android NAT sets up
80 // iptables
81 // rules that use these conntrack modules for FTP/TFTP.
82 "nf_nat_ftp",
83 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +090084 // The tun module is needed by the Android 464xlat clatd process.
85 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +090086 }) != 0) {
87 LOG(WARNING) << "One or more optional kernel modules failed to load.";
88 }
89
Garrick Evans6d227b92019-12-03 16:11:29 +090090 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +090091 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +090092 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
93 }
94
Garrick Evansa34b5862019-11-20 09:34:01 +090095 done = true;
96}
97
Garrick Evans508a4bc2019-11-14 08:45:52 +090098bool IsArcVm() {
Garrick Evansc7071122020-04-17 12:31:57 +090099 if (test::guest == GuestMessage::ARC_VM) {
100 LOG(WARNING) << "Overridden for testing";
101 return true;
102 }
103
Garrick Evans508a4bc2019-11-14 08:45:52 +0900104 const base::FilePath path("/run/chrome/is_arcvm");
105 std::string contents;
106 if (!base::ReadFileToString(path, &contents)) {
107 PLOG(ERROR) << "Could not read " << path.value();
108 }
109 return contents == "1";
110}
111
Garrick Evansf29f5a32019-12-06 11:34:25 +0900112GuestMessage::GuestType ArcGuest() {
113 if (test::guest != GuestMessage::UNKNOWN_GUEST)
114 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900115
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900116 return IsArcVm() ? GuestMessage::ARC_VM : GuestMessage::ARC;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900117}
118
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900119ArcService::InterfaceType InterfaceTypeFor(const std::string& ifname) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900120 for (const auto& prefix : kEthernetInterfacePrefixes) {
121 if (base::StartsWith(ifname, prefix,
122 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900123 return ArcService::InterfaceType::ETHERNET;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900124 }
125 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900126 for (const auto& prefix : kWifiInterfacePrefixes) {
127 if (base::StartsWith(ifname, prefix,
128 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900129 return ArcService::InterfaceType::WIFI;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900130 }
131 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900132 for (const auto& prefix : kCellInterfacePrefixes) {
133 if (base::StartsWith(ifname, prefix,
134 base::CompareCase::INSENSITIVE_ASCII)) {
135 return ArcService::InterfaceType::CELL;
136 }
137 }
138 return ArcService::InterfaceType::UNKNOWN;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900139}
140
141bool IsMulticastInterface(const std::string& ifname) {
142 if (ifname.empty()) {
143 return false;
144 }
145
146 int fd = socket(AF_INET, SOCK_DGRAM, 0);
147 if (fd < 0) {
148 // If IPv4 fails, try to open a socket using IPv6.
149 fd = socket(AF_INET6, SOCK_DGRAM, 0);
150 if (fd < 0) {
151 LOG(ERROR) << "Unable to create socket";
152 return false;
153 }
154 }
155
156 struct ifreq ifr;
157 memset(&ifr, 0, sizeof(ifr));
158 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
159 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
160 PLOG(ERROR) << "SIOCGIFFLAGS failed for " << ifname;
161 close(fd);
162 return false;
163 }
164
165 close(fd);
166 return (ifr.ifr_flags & IFF_MULTICAST);
167}
168
Garrick Evanse94b6de2020-02-20 09:19:13 +0900169// Returns the configuration for the ARC management interface used for VPN
170// forwarding, ADB-over-TCP and single-networked ARCVM.
171std::unique_ptr<Device::Config> MakeArcConfig(AddressManager* addr_mgr,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900172 AddressManager::Guest guest) {
173 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(guest);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900174 if (!ipv4_subnet) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900175 LOG(ERROR) << "Subnet already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900176 return nullptr;
177 }
178 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
179 if (!host_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900180 LOG(ERROR) << "Bridge address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900181 return nullptr;
182 }
183 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
184 if (!guest_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900185 LOG(ERROR) << "ARC address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900186 return nullptr;
187 }
188
189 return std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900190 addr_mgr->GenerateMacAddress(IsArcVm() ? 1 : kAnySubnetIndex),
191 std::move(ipv4_subnet), std::move(host_ipv4_addr),
192 std::move(guest_ipv4_addr));
Garrick Evanse94b6de2020-02-20 09:19:13 +0900193}
194
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900195} // namespace
196
Garrick Evans69b85872020-02-04 11:40:26 +0900197ArcService::ArcService(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900198 Datapath* datapath,
199 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900200 TrafficForwarder* forwarder,
201 bool enable_arcvm_multinet)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900202 : shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900203 datapath_(datapath),
204 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900205 forwarder_(forwarder),
206 enable_arcvm_multinet_(enable_arcvm_multinet) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900207 AllocateAddressConfigs();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900208 shill_client_->RegisterDevicesChangedHandler(
209 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
210 shill_client_->ScanDevices(
211 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900212 shill_client_->RegisterDefaultInterfaceChangedHandler(base::Bind(
213 &ArcService::OnDefaultInterfaceChanged, weak_factory_.GetWeakPtr()));
Garrick Evansf29f5a32019-12-06 11:34:25 +0900214}
215
216ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900217 if (impl_) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900218 Stop(impl_->id());
Garrick Evans664a82f2019-12-17 12:18:05 +0900219 }
Garrick Evans54861622019-07-19 09:05:09 +0900220}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900221
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900222void ArcService::AllocateAddressConfigs() {
223 configs_.clear();
224 // The first usable subnet is the "other" ARC device subnet.
225 // TODO(garrick): This can be removed and ARC_NET will be widened once ARCVM
226 // switches over to use .0/30.
Garrick Evansc7071122020-04-17 12:31:57 +0900227 const bool is_arcvm = IsArcVm();
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900228 AddressManager::Guest alloc =
Garrick Evansc7071122020-04-17 12:31:57 +0900229 is_arcvm ? AddressManager::Guest::ARC : AddressManager::Guest::VM_ARC;
230 // As a temporary workaround, for ARCVM, allocate fixed MAC addresses.
231 uint8_t mac_addr_index = 2;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900232 // Allocate 2 subnets each for Ethernet and WiFi and 1 for LTE WAN interfaces.
233 for (const auto itype :
234 {InterfaceType::ETHERNET, InterfaceType::ETHERNET, InterfaceType::WIFI,
235 InterfaceType::WIFI, InterfaceType::CELL}) {
236 auto ipv4_subnet = addr_mgr_->AllocateIPv4Subnet(alloc);
237 if (!ipv4_subnet) {
238 LOG(ERROR) << "Subnet already in use or unavailable";
239 continue;
240 }
241 // For here out, use the same slices.
242 alloc = AddressManager::Guest::ARC_NET;
243 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
244 if (!host_ipv4_addr) {
245 LOG(ERROR) << "Bridge address already in use or unavailable";
246 continue;
247 }
248 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
249 if (!guest_ipv4_addr) {
250 LOG(ERROR) << "ARC address already in use or unavailable";
251 continue;
252 }
253
Garrick Evansc7071122020-04-17 12:31:57 +0900254 MacAddress mac_addr = is_arcvm
255 ? addr_mgr_->GenerateMacAddress(mac_addr_index++)
256 : addr_mgr_->GenerateMacAddress();
257
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900258 configs_[itype].emplace_back(std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900259 mac_addr, std::move(ipv4_subnet), std::move(host_ipv4_addr),
260 std::move(guest_ipv4_addr)));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900261 }
262}
263
Garrick Evans2961c7c2020-04-03 11:34:40 +0900264std::vector<Device::Config*> ArcService::ReallocateAddressConfigs() {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900265 std::vector<std::string> existing_devices;
266 for (const auto& d : devices_) {
267 existing_devices.emplace_back(d.first);
268 }
269 for (const auto& d : existing_devices) {
270 RemoveDevice(d);
271 }
272 AllocateAddressConfigs();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900273 std::vector<Device::Config*> configs;
274 if (enable_arcvm_multinet_) {
275 for (const auto& kv : configs_)
276 for (const auto& c : kv.second)
277 configs.push_back(c.get());
278 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900279 for (const auto& d : existing_devices) {
280 AddDevice(d);
281 }
Garrick Evans2961c7c2020-04-03 11:34:40 +0900282 return configs;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900283}
284
285std::unique_ptr<Device::Config> ArcService::AcquireConfig(
286 const std::string& ifname) {
287 auto itype = InterfaceTypeFor(ifname);
288 if (itype == InterfaceType::UNKNOWN) {
289 LOG(ERROR) << "Unsupported interface: " << ifname;
290 return nullptr;
291 }
292
293 auto& configs = configs_[itype];
294 if (configs.empty()) {
295 LOG(ERROR) << "No more addresses available. Cannot make device for "
296 << ifname;
297 return nullptr;
298 }
299 std::unique_ptr<Device::Config> config;
300 config = std::move(configs.front());
301 configs.pop_front();
302 return config;
303}
304
305void ArcService::ReleaseConfig(const std::string& ifname,
306 std::unique_ptr<Device::Config> config) {
307 auto itype = InterfaceTypeFor(ifname);
308 if (itype == InterfaceType::UNKNOWN) {
309 LOG(ERROR) << "Unsupported interface: " << ifname;
310 return;
311 }
312
313 configs_[itype].push_front(std::move(config));
314}
315
Garrick Evans015b0d62020-02-07 09:06:38 +0900316bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900317 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900318 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900319 if (impl_->IsStarted(&prev_id)) {
320 LOG(WARNING) << "Already running - did something crash?"
321 << " Stopping and restarting...";
322 Stop(prev_id);
323 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900324 }
325
Garrick Evans2961c7c2020-04-03 11:34:40 +0900326 auto configs = ReallocateAddressConfigs();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900327 const auto guest = ArcGuest();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900328 if (guest == GuestMessage::ARC_VM) {
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900329 impl_ = std::make_unique<VmImpl>(shill_client_, datapath_, addr_mgr_,
Garrick Evans2961c7c2020-04-03 11:34:40 +0900330 forwarder_, configs);
331 } else {
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900332 impl_ = std::make_unique<ContainerImpl>(datapath_, addr_mgr_, forwarder_,
333 guest);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900334 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900335 if (!impl_->Start(id)) {
336 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900337 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900338 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900339
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900340 // Start already known Shill <-> ARC mapped devices.
341 for (const auto& d : devices_)
342 StartDevice(d.second.get());
Garrick Evanscb791e72019-11-11 15:44:34 +0900343
Garrick Evansf29f5a32019-12-06 11:34:25 +0900344 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900345}
346
Garrick Evans015b0d62020-02-07 09:06:38 +0900347void ArcService::Stop(uint32_t id) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900348 // Stop Shill <-> ARC mapped devices.
349 for (const auto& d : devices_)
350 StopDevice(d.second.get());
Garrick Evansf29f5a32019-12-06 11:34:25 +0900351
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900352 if (impl_) {
353 impl_->Stop(id);
354 impl_.reset();
355 }
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900356}
357
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900358void ArcService::OnDevicesChanged(const std::set<std::string>& added,
359 const std::set<std::string>& removed) {
360 for (const std::string& name : removed)
361 RemoveDevice(name);
362
363 for (const std::string& name : added)
364 AddDevice(name);
365}
366
367void ArcService::AddDevice(const std::string& ifname) {
368 if (ifname.empty())
369 return;
370
371 if (devices_.find(ifname) != devices_.end()) {
372 LOG(DFATAL) << "Attemping to add already tracked device: " << ifname;
373 return;
374 }
375
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900376 auto itype = InterfaceTypeFor(ifname);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900377 Device::Options opts{
378 .fwd_multicast = IsMulticastInterface(ifname),
379 // TODO(crbug/726815) Also enable |ipv6_enabled| for cellular networks
380 // once IPv6 is enabled on cellular networks in shill.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900381 .ipv6_enabled =
382 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900383 };
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900384
385 auto config = AcquireConfig(ifname);
386 if (!config) {
387 LOG(ERROR) << "Cannot add device for " << ifname;
388 return;
389 }
390
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900391 std::string host_ifname = base::StringPrintf("arc_%s", ifname.c_str());
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900392 auto device = std::make_unique<Device>(ifname, host_ifname, ifname,
393 std::move(config), opts);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900394
395 StartDevice(device.get());
396 devices_.emplace(ifname, std::move(device));
397}
398
399void ArcService::StartDevice(Device* device) {
400 if (!impl_ || !impl_->IsStarted())
401 return;
402
403 // For now, only start devices for ARC++.
404 if (impl_->guest() != GuestMessage::ARC)
405 return;
406
Garrick Evans54861622019-07-19 09:05:09 +0900407 const auto& config = device->config();
408
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900409 LOG(INFO) << "Adding device " << device->phys_ifname()
410 << " bridge: " << device->host_ifname()
411 << " guest_iface: " << device->guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900412
413 // Create the bridge.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900414 if (!datapath_->AddBridge(device->host_ifname(), config.host_ipv4_addr(),
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900415 30)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900416 LOG(ERROR) << "Failed to setup arc bridge: " << device->host_ifname();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900417 return;
Garrick Evans54861622019-07-19 09:05:09 +0900418 }
419
Garrick Evanse94b6de2020-02-20 09:19:13 +0900420 // Set up iptables.
421 if (!datapath_->AddInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900422 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
Garrick Evanse94b6de2020-02-20 09:19:13 +0900423 LOG(ERROR) << "Failed to configure ingress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900424 << device->phys_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900425
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900426 if (!datapath_->AddOutboundIPv4(device->host_ifname()))
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900427 LOG(ERROR) << "Failed to configure egress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900428 << device->phys_ifname();
Garrick Evans2c263102019-07-26 16:07:18 +0900429
Garrick Evansd90a3822019-11-12 17:53:08 +0900430 if (!impl_->OnStartDevice(device)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900431 LOG(ERROR) << "Failed to start device " << device->phys_ifname();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900432 }
433}
434
435void ArcService::RemoveDevice(const std::string& ifname) {
436 const auto it = devices_.find(ifname);
437 if (it == devices_.end()) {
438 LOG(WARNING) << "Unknown device: " << ifname;
Garrick Evanscb791e72019-11-11 15:44:34 +0900439 return;
440 }
441
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900442 // If the container is down, this call does nothing.
443 StopDevice(it->second.get());
444
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900445 ReleaseConfig(ifname, it->second->release_config());
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900446 devices_.erase(it);
Garrick Evans54861622019-07-19 09:05:09 +0900447}
448
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900449void ArcService::StopDevice(Device* device) {
450 if (!impl_ || !impl_->IsStarted())
451 return;
452
453 // For now, devices are only started for ARC++.
454 if (impl_->guest() != GuestMessage::ARC)
455 return;
456
457 impl_->OnStopDevice(device);
Garrick Evans54861622019-07-19 09:05:09 +0900458
459 const auto& config = device->config();
460
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900461 LOG(INFO) << "Removing device " << device->phys_ifname()
462 << " bridge: " << device->host_ifname()
463 << " guest_iface: " << device->guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900464
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900465 datapath_->RemoveOutboundIPv4(device->host_ifname());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900466 datapath_->RemoveInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900467 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
Garrick Evans54861622019-07-19 09:05:09 +0900468
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900469 datapath_->RemoveBridge(device->host_ifname());
Garrick Evanscb791e72019-11-11 15:44:34 +0900470}
471
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900472void ArcService::OnDefaultInterfaceChanged(const std::string& new_ifname,
473 const std::string& prev_ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900474 if (impl_)
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900475 impl_->OnDefaultInterfaceChanged(new_ifname, prev_ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900476}
Garrick Evansba575742019-07-17 15:48:08 +0900477
Garrick Evans38b25a42020-04-06 15:17:42 +0900478std::vector<const Device::Config*> ArcService::GetDeviceConfigs() const {
479 if (impl_)
480 return impl_->GetDeviceConfigs();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900481
Garrick Evans38b25a42020-04-06 15:17:42 +0900482 return {};
Garrick Evanse94b6de2020-02-20 09:19:13 +0900483}
484
Garrick Evansd90a3822019-11-12 17:53:08 +0900485// ARC++ specific functions.
486
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900487ArcService::ContainerImpl::ContainerImpl(Datapath* datapath,
488 AddressManager* addr_mgr,
489 TrafficForwarder* forwarder,
Garrick Evansd90a3822019-11-12 17:53:08 +0900490 GuestMessage::GuestType guest)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900491 : pid_(kInvalidPID),
492 datapath_(datapath),
493 addr_mgr_(addr_mgr),
494 forwarder_(forwarder),
495 guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900496 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900497}
Garrick Evansd90a3822019-11-12 17:53:08 +0900498
Garrick Evansb4eb3892019-11-13 12:07:07 +0900499GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
500 return guest_;
501}
502
Garrick Evans015b0d62020-02-07 09:06:38 +0900503uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900504 return pid_;
505}
506
Garrick Evans015b0d62020-02-07 09:06:38 +0900507bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900508 // This could happen if something crashes and the stop signal is not sent.
509 // It can probably be addressed by stopping and restarting the service.
510 if (pid_ != kInvalidPID)
511 return false;
512
Garrick Evans4dec0c42019-11-29 12:51:57 +0900513 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900514 LOG(ERROR) << "Cannot start service - invalid container PID";
515 return false;
516 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900517 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900518
Garrick Evanse94b6de2020-02-20 09:19:13 +0900519 Device::Options opts{
520 .fwd_multicast = false,
521 .ipv6_enabled = false,
Garrick Evanse94b6de2020-02-20 09:19:13 +0900522 };
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900523 auto config = MakeArcConfig(addr_mgr_, AddressManager::Guest::ARC);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900524
525 // Create the bridge.
526 // Per crbug/1008686 this device cannot be deleted and then re-added.
527 // So instead of removing the bridge when the service stops, bring down the
528 // device instead and re-up it on restart.
529 if (!datapath_->AddBridge(kArcBridge, config->host_ipv4_addr(), 30) &&
530 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
531 LOG(ERROR) << "Failed to bring up arc bridge: " << kArcBridge;
532 return false;
533 }
534
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900535 arc_device_ = std::make_unique<Device>(kArcIfname, kArcBridge, kArcIfname,
536 std::move(config), opts);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900537
538 OnStartDevice(arc_device_.get());
539
Garrick Evansd90a3822019-11-12 17:53:08 +0900540 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
541 return true;
542}
543
Garrick Evans015b0d62020-02-07 09:06:38 +0900544void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900545 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900546 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900547
Garrick Evanse94b6de2020-02-20 09:19:13 +0900548 // Per crbug/1008686 this device cannot be deleted and then re-added.
549 // So instead of removing the bridge, bring it down and mark it. This will
550 // allow us to detect if the device is re-added in case of a crash restart
551 // and do the right thing.
552 if (arc_device_) {
553 OnStopDevice(arc_device_.get());
554 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
555 LOG(ERROR) << "Failed to bring down arc bridge "
556 << "- it may not restart correctly";
557 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900558
559 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
560 pid_ = kInvalidPID;
561}
562
Garrick Evans015b0d62020-02-07 09:06:38 +0900563bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900564 if (pid)
565 *pid = pid_;
566
Garrick Evansd90a3822019-11-12 17:53:08 +0900567 return pid_ != kInvalidPID;
568}
569
570bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900571 LOG(INFO) << "Starting device " << device->phys_ifname()
572 << " bridge: " << device->host_ifname()
573 << " guest_iface: " << device->guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900574
Garrick Evans2470caa2020-03-04 14:15:41 +0900575 // Set up the virtual pair inside the container namespace.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900576 const std::string veth_ifname = ArcVethHostName(device->guest_ifname());
Hugo Benichi76675592020-04-08 14:29:57 +0900577 const auto& config = device->config();
578 if (!datapath_->ConnectVethPair(pid_, veth_ifname, device->guest_ifname(),
579 config.mac_addr(), config.guest_ipv4_addr(),
580 30, device->options().fwd_multicast)) {
581 LOG(ERROR) << "Cannot create virtual link for device "
582 << device->phys_ifname();
Garrick Evansd90a3822019-11-12 17:53:08 +0900583 return false;
584 }
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900585 if (!datapath_->AddToBridge(device->host_ifname(), veth_ifname)) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900586 datapath_->RemoveInterface(veth_ifname);
587 LOG(ERROR) << "Failed to bridge interface " << veth_ifname;
588 return false;
589 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900590
Garrick Evans3bd06372020-03-23 10:42:58 +0900591 if (device != arc_device_.get()) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900592 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
593 device->options().ipv6_enabled,
594 device->options().fwd_multicast);
Garrick Evans3bd06372020-03-23 10:42:58 +0900595 } else {
596 // Signal the container that the network device is ready.
597 datapath_->runner().WriteSentinelToContainer(pid_);
598 }
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900599
Garrick Evansd90a3822019-11-12 17:53:08 +0900600 return true;
601}
602
603void ArcService::ContainerImpl::OnStopDevice(Device* device) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900604 LOG(INFO) << "Stopping device " << device->phys_ifname()
605 << " bridge: " << device->host_ifname()
606 << " guest_iface: " << device->guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900607
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900608 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900609 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900610 device->options().ipv6_enabled,
611 device->options().fwd_multicast);
612
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900613 datapath_->RemoveInterface(ArcVethHostName(device->phys_ifname()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900614}
615
616void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900617 const std::string& new_ifname, const std::string& prev_ifname) {}
Garrick Evansd90a3822019-11-12 17:53:08 +0900618
Garrick Evansb4eb3892019-11-13 12:07:07 +0900619// VM specific functions
620
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900621ArcService::VmImpl::VmImpl(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900622 Datapath* datapath,
623 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900624 TrafficForwarder* forwarder,
Garrick Evans2961c7c2020-04-03 11:34:40 +0900625 const std::vector<Device::Config*>& configs)
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900626 : cid_(kInvalidCID),
627 shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900628 datapath_(datapath),
629 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900630 forwarder_(forwarder),
Garrick Evans2961c7c2020-04-03 11:34:40 +0900631 configs_(configs) {}
Garrick Evansb4eb3892019-11-13 12:07:07 +0900632
633GuestMessage::GuestType ArcService::VmImpl::guest() const {
634 return GuestMessage::ARC_VM;
635}
636
Garrick Evans015b0d62020-02-07 09:06:38 +0900637uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900638 return cid_;
639}
640
Garrick Evans38b25a42020-04-06 15:17:42 +0900641std::vector<const Device::Config*> ArcService::VmImpl::GetDeviceConfigs()
642 const {
643 std::vector<const Device::Config*> configs;
644 for (const auto* c : configs_)
645 configs.emplace_back(c);
646
647 return configs;
648}
649
Garrick Evans015b0d62020-02-07 09:06:38 +0900650bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900651 // This can happen if concierge crashes and doesn't send the vm down RPC.
652 // It can probably be addressed by stopping and restarting the service.
653 if (cid_ != kInvalidCID)
654 return false;
655
Garrick Evans015b0d62020-02-07 09:06:38 +0900656 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900657 LOG(ERROR) << "Invalid VM cid " << cid;
658 return false;
659 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900660 cid_ = cid;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900661
Garrick Evanse94b6de2020-02-20 09:19:13 +0900662 Device::Options opts{
663 .fwd_multicast = true,
664 .ipv6_enabled = true,
Garrick Evanse94b6de2020-02-20 09:19:13 +0900665 };
Garrick Evans2961c7c2020-04-03 11:34:40 +0900666 auto arc_config = MakeArcConfig(addr_mgr_, AddressManager::Guest::VM_ARC);
667 configs_.insert(configs_.begin(), arc_config.get());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900668
Garrick Evans2961c7c2020-04-03 11:34:40 +0900669 // Allocate TAP devices for all configs.
670 for (auto* config : configs_) {
Garrick Evansc7071122020-04-17 12:31:57 +0900671 auto mac = config->mac_addr();
672 auto tap =
673 datapath_->AddTAP("" /* auto-generate name */, &mac,
674 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900675 if (tap.empty()) {
676 LOG(ERROR) << "Failed to create TAP device";
677 continue;
678 }
679
680 config->set_tap_ifname(tap);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900681 }
682
Garrick Evans2961c7c2020-04-03 11:34:40 +0900683 arc_device_ = std::make_unique<Device>(
684 kArcVmIfname, kArcVmBridge, kArcVmIfname, std::move(arc_config), opts);
685 // Create the bridge.
686 if (!datapath_->AddBridge(kArcVmBridge,
687 arc_device_->config().host_ipv4_addr(), 30)) {
688 LOG(ERROR) << "Failed to setup arc bridge for device " << *arc_device_;
689 return false;
690 }
Garrick Evanse94b6de2020-02-20 09:19:13 +0900691 OnStartDevice(arc_device_.get());
692
693 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
Garrick Evansb4eb3892019-11-13 12:07:07 +0900694 return true;
695}
696
Garrick Evans015b0d62020-02-07 09:06:38 +0900697void ArcService::VmImpl::Stop(uint32_t cid) {
Garrick Evans21173b12019-11-20 15:23:16 +0900698 if (cid_ != cid) {
699 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
700 return;
701 }
702
Garrick Evans2961c7c2020-04-03 11:34:40 +0900703 for (auto* config : configs_) {
704 const auto& tap = config->tap_ifname();
705 if (!tap.empty()) {
706 datapath_->RemoveInterface(tap);
707 config->set_tap_ifname("");
708 }
709 }
710
Garrick Evanse94b6de2020-02-20 09:19:13 +0900711 OnStopDevice(arc_device_.get());
712 datapath_->RemoveBridge(kArcVmBridge);
713 arc_device_.reset();
714
Garrick Evansb4eb3892019-11-13 12:07:07 +0900715 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
716 cid_ = kInvalidCID;
717}
718
Garrick Evans015b0d62020-02-07 09:06:38 +0900719bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900720 if (cid)
721 *cid = cid_;
722
Garrick Evans015b0d62020-02-07 09:06:38 +0900723 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900724}
725
726bool ArcService::VmImpl::OnStartDevice(Device* device) {
Garrick Evansf5862122020-03-16 09:13:45 +0900727 // TODO(garrick): Remove once ARCVM P is gone.
Garrick Evans2961c7c2020-04-03 11:34:40 +0900728 if (device == arc_device_.get() && !IsMultinetEnabled())
Garrick Evansf5862122020-03-16 09:13:45 +0900729 return OnStartArcPDevice();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900730
Garrick Evans2961c7c2020-04-03 11:34:40 +0900731 std::string tap;
732 for (auto* config : configs_) {
733 if (config == &device->config()) {
734 tap = config->tap_ifname();
735 break;
736 }
737 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900738 if (tap.empty()) {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900739 LOG(ERROR) << "No TAP device for: " << *device;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900740 return false;
741 }
742
Garrick Evans2961c7c2020-04-03 11:34:40 +0900743 LOG(INFO) << "Starting device " << *device << " cid: " << cid_;
744
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900745 if (!datapath_->AddToBridge(device->host_ifname(), tap)) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900746 LOG(ERROR) << "Failed to bridge TAP device " << tap;
747 datapath_->RemoveInterface(tap);
748 return false;
749 }
750
Garrick Evansf5862122020-03-16 09:13:45 +0900751 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900752 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
753 device->options().ipv6_enabled,
754 device->options().fwd_multicast);
Garrick Evansf5862122020-03-16 09:13:45 +0900755
756 return true;
757}
758
759bool ArcService::VmImpl::OnStartArcPDevice() {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900760 LOG(INFO) << "Starting device " << *arc_device_ << " cid: " << cid_;
Garrick Evansf5862122020-03-16 09:13:45 +0900761
Garrick Evans2961c7c2020-04-03 11:34:40 +0900762 if (!datapath_->AddToBridge(kArcVmBridge,
763 arc_device_->config().tap_ifname())) {
764 LOG(ERROR) << "Failed to bridge TAP device " << *arc_device_;
Garrick Evansf5862122020-03-16 09:13:45 +0900765 return false;
766 }
767
Garrick Evansf5862122020-03-16 09:13:45 +0900768 // Setup the iptables.
769 if (!datapath_->AddLegacyIPv4DNAT(
770 IPv4AddressToString(arc_device_->config().guest_ipv4_addr())))
771 LOG(ERROR) << "Failed to configure ARC traffic rules";
772
773 if (!datapath_->AddOutboundIPv4(kArcVmBridge))
774 LOG(ERROR) << "Failed to configure egress traffic rules";
775
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900776 OnDefaultInterfaceChanged(shill_client_->default_interface(),
777 "" /*previous*/);
Garrick Evansbcce09e2020-03-10 15:08:04 +0900778
Garrick Evansb4eb3892019-11-13 12:07:07 +0900779 return true;
780}
781
782void ArcService::VmImpl::OnStopDevice(Device* device) {
Garrick Evansf5862122020-03-16 09:13:45 +0900783 // TODO(garrick): Remove once ARCVM P is gone.
Garrick Evans2961c7c2020-04-03 11:34:40 +0900784 if (device == arc_device_.get() && !IsMultinetEnabled())
Garrick Evansf5862122020-03-16 09:13:45 +0900785 return OnStopArcPDevice();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900786
Garrick Evans2961c7c2020-04-03 11:34:40 +0900787 LOG(INFO) << "Stopping device " << *device << " cid: " << cid_;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900788
Garrick Evansf5862122020-03-16 09:13:45 +0900789 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900790 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
Garrick Evansf5862122020-03-16 09:13:45 +0900791 device->options().ipv6_enabled,
792 device->options().fwd_multicast);
Garrick Evansbcce09e2020-03-10 15:08:04 +0900793
Garrick Evans2961c7c2020-04-03 11:34:40 +0900794 for (auto* config : configs_) {
795 if (config == &device->config()) {
796 config->set_tap_ifname("");
797 break;
798 }
799 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900800}
801
Garrick Evansf5862122020-03-16 09:13:45 +0900802void ArcService::VmImpl::OnStopArcPDevice() {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900803 LOG(INFO) << "Stopping device " << *arc_device_.get() << " cid: " << cid_;
Garrick Evansf5862122020-03-16 09:13:45 +0900804
805 datapath_->RemoveOutboundIPv4(kArcVmBridge);
806 datapath_->RemoveLegacyIPv4DNAT();
807
808 OnDefaultInterfaceChanged("" /*new_ifname*/,
809 shill_client_->default_interface());
810
Garrick Evans2961c7c2020-04-03 11:34:40 +0900811 arc_device_->config().set_tap_ifname("");
Garrick Evansf5862122020-03-16 09:13:45 +0900812}
813
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900814void ArcService::VmImpl::OnDefaultInterfaceChanged(
815 const std::string& new_ifname, const std::string& prev_ifname) {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900816 if (!IsStarted() || IsMultinetEnabled())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900817 return;
818
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900819 forwarder_->StopForwarding(prev_ifname, kArcVmBridge, true /*ipv6*/,
820 true /*multicast*/);
821
Garrick Evansb4eb3892019-11-13 12:07:07 +0900822 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900823
824 // If a new default interface was given, then re-enable with that.
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900825 if (!new_ifname.empty()) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900826 datapath_->AddLegacyIPv4InboundDNAT(new_ifname);
Jason Jeremy Iman0e9f8262020-03-06 14:50:49 +0900827 forwarder_->StartForwarding(new_ifname, kArcVmBridge, true /*ipv6*/,
828 true /*multicast*/);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900829 }
830}
831
Garrick Evans2961c7c2020-04-03 11:34:40 +0900832bool ArcService::VmImpl::IsMultinetEnabled() const {
833 return configs_.size() > 1;
834}
835
Garrick Evans3388a032020-03-24 11:25:55 +0900836} // namespace patchpanel