blob: 8ff13668a0233db8ca95548d585dbc344716737d [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>
Qijiang Fan2d7aeb42020-05-19 02:06:39 +090021#include <base/system/sys_info.h>
Garrick Evans1f5a3612019-11-08 12:59:03 +090022#include <brillo/key_value_store.h>
Garrick Evansb4eb3892019-11-13 12:07:07 +090023#include <chromeos/constants/vm_tools.h>
Garrick Evans54861622019-07-19 09:05:09 +090024
Garrick Evans3388a032020-03-24 11:25:55 +090025#include "patchpanel/datapath.h"
26#include "patchpanel/mac_address_generator.h"
27#include "patchpanel/manager.h"
28#include "patchpanel/minijailed_process_runner.h"
29#include "patchpanel/net_util.h"
30#include "patchpanel/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090031
Garrick Evans3388a032020-03-24 11:25:55 +090032namespace patchpanel {
Garrick Evansf29f5a32019-12-06 11:34:25 +090033namespace test {
34GuestMessage::GuestType guest = GuestMessage::UNKNOWN_GUEST;
35} // namespace test
36
Garrick Evans5d55f5e2019-07-17 15:28:10 +090037namespace {
Garrick Evans015b0d62020-02-07 09:06:38 +090038constexpr pid_t kInvalidPID = 0;
Garrick 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 Evansc53b9702020-05-13 13:20:09 +090057 // Expected for all kernels.
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",
Garrick Evansa34b5862019-11-20 09:34:01 +090063 // The ipsec modules for AH and ESP encryption for ipv6.
64 "ah6",
65 "esp6",
66 }) != 0) {
67 LOG(ERROR) << "One or more required kernel modules failed to load."
68 << " Some Android functionality may be broken.";
69 }
Garrick Evansc53b9702020-05-13 13:20:09 +090070 // The xfrm modules needed for Android's ipsec APIs on kernels < 5.4.
71 int32_t major, minor, fix;
72 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &fix);
73 if ((major < 5 || (major == 5 && minor < 4)) && runner.modprobe_all({
74 "xfrm4_mode_transport",
75 "xfrm4_mode_tunnel",
76 "xfrm6_mode_transport",
77 "xfrm6_mode_tunnel",
78 }) != 0) {
79 LOG(ERROR) << "One or more required kernel modules failed to load."
80 << " Some Android functionality may be broken.";
81 }
82
Garrick Evansa34b5862019-11-20 09:34:01 +090083 // Optional modules.
Garrick Evans8e8e3472020-01-23 14:03:50 +090084 if (runner.modprobe_all({
Garrick Evansa34b5862019-11-20 09:34:01 +090085 // This module is not available in kernels < 3.18
86 "nf_reject_ipv6",
87 // These modules are needed for supporting Chrome traffic on Android
88 // VPN which uses Android's NAT feature. Android NAT sets up
89 // iptables
90 // rules that use these conntrack modules for FTP/TFTP.
91 "nf_nat_ftp",
92 "nf_nat_tftp",
Hugo Benichia0cde9e2019-12-16 11:57:20 +090093 // The tun module is needed by the Android 464xlat clatd process.
94 "tun",
Garrick Evansa34b5862019-11-20 09:34:01 +090095 }) != 0) {
96 LOG(WARNING) << "One or more optional kernel modules failed to load.";
97 }
98
Garrick Evans6d227b92019-12-03 16:11:29 +090099 // This is only needed for CTS (b/27932574).
Garrick Evans8e8e3472020-01-23 14:03:50 +0900100 if (runner.chown("655360", "655360", "/sys/class/xt_idletimer") != 0) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900101 LOG(ERROR) << "Failed to change ownership of xt_idletimer.";
102 }
103
Garrick Evansa34b5862019-11-20 09:34:01 +0900104 done = true;
105}
106
Garrick Evans508a4bc2019-11-14 08:45:52 +0900107bool IsArcVm() {
Garrick Evansc7071122020-04-17 12:31:57 +0900108 if (test::guest == GuestMessage::ARC_VM) {
109 LOG(WARNING) << "Overridden for testing";
110 return true;
111 }
112
Garrick Evans508a4bc2019-11-14 08:45:52 +0900113 const base::FilePath path("/run/chrome/is_arcvm");
114 std::string contents;
115 if (!base::ReadFileToString(path, &contents)) {
116 PLOG(ERROR) << "Could not read " << path.value();
117 }
118 return contents == "1";
119}
120
Garrick Evansf29f5a32019-12-06 11:34:25 +0900121GuestMessage::GuestType ArcGuest() {
122 if (test::guest != GuestMessage::UNKNOWN_GUEST)
123 return test::guest;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900124
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900125 return IsArcVm() ? GuestMessage::ARC_VM : GuestMessage::ARC;
Garrick Evans508a4bc2019-11-14 08:45:52 +0900126}
127
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900128ArcService::InterfaceType InterfaceTypeFor(const std::string& ifname) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900129 for (const auto& prefix : kEthernetInterfacePrefixes) {
130 if (base::StartsWith(ifname, prefix,
131 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900132 return ArcService::InterfaceType::ETHERNET;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900133 }
134 }
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900135 for (const auto& prefix : kWifiInterfacePrefixes) {
136 if (base::StartsWith(ifname, prefix,
137 base::CompareCase::INSENSITIVE_ASCII)) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900138 return ArcService::InterfaceType::WIFI;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900139 }
140 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900141 for (const auto& prefix : kCellInterfacePrefixes) {
142 if (base::StartsWith(ifname, prefix,
143 base::CompareCase::INSENSITIVE_ASCII)) {
144 return ArcService::InterfaceType::CELL;
145 }
146 }
147 return ArcService::InterfaceType::UNKNOWN;
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900148}
149
150bool IsMulticastInterface(const std::string& ifname) {
151 if (ifname.empty()) {
152 return false;
153 }
154
155 int fd = socket(AF_INET, SOCK_DGRAM, 0);
156 if (fd < 0) {
157 // If IPv4 fails, try to open a socket using IPv6.
158 fd = socket(AF_INET6, SOCK_DGRAM, 0);
159 if (fd < 0) {
160 LOG(ERROR) << "Unable to create socket";
161 return false;
162 }
163 }
164
165 struct ifreq ifr;
166 memset(&ifr, 0, sizeof(ifr));
167 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ);
168 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
169 PLOG(ERROR) << "SIOCGIFFLAGS failed for " << ifname;
170 close(fd);
171 return false;
172 }
173
174 close(fd);
175 return (ifr.ifr_flags & IFF_MULTICAST);
176}
177
Garrick Evanse94b6de2020-02-20 09:19:13 +0900178// Returns the configuration for the ARC management interface used for VPN
179// forwarding, ADB-over-TCP and single-networked ARCVM.
180std::unique_ptr<Device::Config> MakeArcConfig(AddressManager* addr_mgr,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900181 AddressManager::Guest guest) {
182 auto ipv4_subnet = addr_mgr->AllocateIPv4Subnet(guest);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900183 if (!ipv4_subnet) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900184 LOG(ERROR) << "Subnet already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900185 return nullptr;
186 }
187 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
188 if (!host_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900189 LOG(ERROR) << "Bridge address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900190 return nullptr;
191 }
192 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
193 if (!guest_ipv4_addr) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900194 LOG(ERROR) << "ARC address already in use or unavailable";
Garrick Evanse94b6de2020-02-20 09:19:13 +0900195 return nullptr;
196 }
197
198 return std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900199 addr_mgr->GenerateMacAddress(IsArcVm() ? 1 : kAnySubnetIndex),
200 std::move(ipv4_subnet), std::move(host_ipv4_addr),
201 std::move(guest_ipv4_addr));
Garrick Evanse94b6de2020-02-20 09:19:13 +0900202}
203
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900204} // namespace
205
Garrick Evans69b85872020-02-04 11:40:26 +0900206ArcService::ArcService(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900207 Datapath* datapath,
208 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900209 TrafficForwarder* forwarder,
210 bool enable_arcvm_multinet)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900211 : shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900212 datapath_(datapath),
213 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900214 forwarder_(forwarder),
215 enable_arcvm_multinet_(enable_arcvm_multinet) {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900216 AllocateAddressConfigs();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900217 shill_client_->RegisterDevicesChangedHandler(
218 base::Bind(&ArcService::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Jie Jiang84c76a12020-04-17 16:45:20 +0900219 shill_client_->ScanDevices();
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900220 shill_client_->RegisterDefaultInterfaceChangedHandler(base::Bind(
221 &ArcService::OnDefaultInterfaceChanged, weak_factory_.GetWeakPtr()));
Garrick Evansf29f5a32019-12-06 11:34:25 +0900222}
223
224ArcService::~ArcService() {
Garrick Evans664a82f2019-12-17 12:18:05 +0900225 if (impl_) {
Garrick Evans664a82f2019-12-17 12:18:05 +0900226 Stop(impl_->id());
Garrick Evans664a82f2019-12-17 12:18:05 +0900227 }
Garrick Evans54861622019-07-19 09:05:09 +0900228}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900229
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900230void ArcService::AllocateAddressConfigs() {
231 configs_.clear();
232 // The first usable subnet is the "other" ARC device subnet.
233 // TODO(garrick): This can be removed and ARC_NET will be widened once ARCVM
234 // switches over to use .0/30.
Garrick Evansc7071122020-04-17 12:31:57 +0900235 const bool is_arcvm = IsArcVm();
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900236 AddressManager::Guest alloc =
Garrick Evansc7071122020-04-17 12:31:57 +0900237 is_arcvm ? AddressManager::Guest::ARC : AddressManager::Guest::VM_ARC;
238 // As a temporary workaround, for ARCVM, allocate fixed MAC addresses.
239 uint8_t mac_addr_index = 2;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900240 // Allocate 2 subnets each for Ethernet and WiFi and 1 for LTE WAN interfaces.
241 for (const auto itype :
242 {InterfaceType::ETHERNET, InterfaceType::ETHERNET, InterfaceType::WIFI,
243 InterfaceType::WIFI, InterfaceType::CELL}) {
244 auto ipv4_subnet = addr_mgr_->AllocateIPv4Subnet(alloc);
245 if (!ipv4_subnet) {
246 LOG(ERROR) << "Subnet already in use or unavailable";
247 continue;
248 }
249 // For here out, use the same slices.
250 alloc = AddressManager::Guest::ARC_NET;
251 auto host_ipv4_addr = ipv4_subnet->AllocateAtOffset(0);
252 if (!host_ipv4_addr) {
253 LOG(ERROR) << "Bridge address already in use or unavailable";
254 continue;
255 }
256 auto guest_ipv4_addr = ipv4_subnet->AllocateAtOffset(1);
257 if (!guest_ipv4_addr) {
258 LOG(ERROR) << "ARC address already in use or unavailable";
259 continue;
260 }
261
Garrick Evansc7071122020-04-17 12:31:57 +0900262 MacAddress mac_addr = is_arcvm
263 ? addr_mgr_->GenerateMacAddress(mac_addr_index++)
264 : addr_mgr_->GenerateMacAddress();
265
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900266 configs_[itype].emplace_back(std::make_unique<Device::Config>(
Garrick Evansc7071122020-04-17 12:31:57 +0900267 mac_addr, std::move(ipv4_subnet), std::move(host_ipv4_addr),
268 std::move(guest_ipv4_addr)));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900269 }
270}
271
Garrick Evans2961c7c2020-04-03 11:34:40 +0900272std::vector<Device::Config*> ArcService::ReallocateAddressConfigs() {
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900273 std::vector<std::string> existing_devices;
274 for (const auto& d : devices_) {
275 existing_devices.emplace_back(d.first);
276 }
277 for (const auto& d : existing_devices) {
278 RemoveDevice(d);
279 }
280 AllocateAddressConfigs();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900281 std::vector<Device::Config*> configs;
282 if (enable_arcvm_multinet_) {
283 for (const auto& kv : configs_)
284 for (const auto& c : kv.second)
285 configs.push_back(c.get());
286 }
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900287 for (const auto& d : existing_devices) {
288 AddDevice(d);
289 }
Garrick Evans2961c7c2020-04-03 11:34:40 +0900290 return configs;
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900291}
292
293std::unique_ptr<Device::Config> ArcService::AcquireConfig(
294 const std::string& ifname) {
295 auto itype = InterfaceTypeFor(ifname);
296 if (itype == InterfaceType::UNKNOWN) {
297 LOG(ERROR) << "Unsupported interface: " << ifname;
298 return nullptr;
299 }
300
301 auto& configs = configs_[itype];
302 if (configs.empty()) {
303 LOG(ERROR) << "No more addresses available. Cannot make device for "
304 << ifname;
305 return nullptr;
306 }
307 std::unique_ptr<Device::Config> config;
308 config = std::move(configs.front());
309 configs.pop_front();
310 return config;
311}
312
313void ArcService::ReleaseConfig(const std::string& ifname,
314 std::unique_ptr<Device::Config> config) {
315 auto itype = InterfaceTypeFor(ifname);
316 if (itype == InterfaceType::UNKNOWN) {
317 LOG(ERROR) << "Unsupported interface: " << ifname;
318 return;
319 }
320
321 configs_[itype].push_front(std::move(config));
322}
323
Garrick Evans015b0d62020-02-07 09:06:38 +0900324bool ArcService::Start(uint32_t id) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900325 if (impl_) {
Garrick Evans015b0d62020-02-07 09:06:38 +0900326 uint32_t prev_id;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900327 if (impl_->IsStarted(&prev_id)) {
328 LOG(WARNING) << "Already running - did something crash?"
329 << " Stopping and restarting...";
330 Stop(prev_id);
331 }
Garrick Evansa51d0a12019-11-28 13:51:23 +0900332 }
333
Garrick Evans2961c7c2020-04-03 11:34:40 +0900334 auto configs = ReallocateAddressConfigs();
Garrick Evansf29f5a32019-12-06 11:34:25 +0900335 const auto guest = ArcGuest();
Garrick Evans2961c7c2020-04-03 11:34:40 +0900336 if (guest == GuestMessage::ARC_VM) {
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900337 impl_ = std::make_unique<VmImpl>(shill_client_, datapath_, addr_mgr_,
Garrick Evans2961c7c2020-04-03 11:34:40 +0900338 forwarder_, configs);
339 } else {
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900340 impl_ = std::make_unique<ContainerImpl>(datapath_, addr_mgr_, forwarder_,
341 guest);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900342 }
Garrick Evansf29f5a32019-12-06 11:34:25 +0900343 if (!impl_->Start(id)) {
344 impl_.reset();
Garrick Evans508a4bc2019-11-14 08:45:52 +0900345 return false;
Garrick Evansf29f5a32019-12-06 11:34:25 +0900346 }
Garrick Evanscb791e72019-11-11 15:44:34 +0900347
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900348 // Start already known Shill <-> ARC mapped devices.
349 for (const auto& d : devices_)
350 StartDevice(d.second.get());
Garrick Evanscb791e72019-11-11 15:44:34 +0900351
Garrick Evansf29f5a32019-12-06 11:34:25 +0900352 return true;
Garrick Evanscb791e72019-11-11 15:44:34 +0900353}
354
Garrick Evans015b0d62020-02-07 09:06:38 +0900355void ArcService::Stop(uint32_t id) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900356 // Stop Shill <-> ARC mapped devices.
357 for (const auto& d : devices_)
358 StopDevice(d.second.get());
Garrick Evansf29f5a32019-12-06 11:34:25 +0900359
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900360 if (impl_) {
361 impl_->Stop(id);
362 impl_.reset();
363 }
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900364}
365
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900366void ArcService::OnDevicesChanged(const std::set<std::string>& added,
367 const std::set<std::string>& removed) {
368 for (const std::string& name : removed)
369 RemoveDevice(name);
370
371 for (const std::string& name : added)
372 AddDevice(name);
373}
374
375void ArcService::AddDevice(const std::string& ifname) {
376 if (ifname.empty())
377 return;
378
379 if (devices_.find(ifname) != devices_.end()) {
380 LOG(DFATAL) << "Attemping to add already tracked device: " << ifname;
381 return;
382 }
383
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900384 auto itype = InterfaceTypeFor(ifname);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900385 Device::Options opts{
386 .fwd_multicast = IsMulticastInterface(ifname),
387 // TODO(crbug/726815) Also enable |ipv6_enabled| for cellular networks
388 // once IPv6 is enabled on cellular networks in shill.
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900389 .ipv6_enabled =
390 (itype == InterfaceType::ETHERNET || itype == InterfaceType::WIFI),
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900391 };
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900392
393 auto config = AcquireConfig(ifname);
394 if (!config) {
395 LOG(ERROR) << "Cannot add device for " << ifname;
396 return;
397 }
398
Garrick Evans8a067562020-05-11 12:47:30 +0900399 auto device = std::make_unique<Device>(ifname, ArcBridgeName(ifname), ifname,
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900400 std::move(config), opts);
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900401
402 StartDevice(device.get());
403 devices_.emplace(ifname, std::move(device));
404}
405
406void ArcService::StartDevice(Device* device) {
407 if (!impl_ || !impl_->IsStarted())
408 return;
409
410 // For now, only start devices for ARC++.
411 if (impl_->guest() != GuestMessage::ARC)
412 return;
413
Garrick Evans54861622019-07-19 09:05:09 +0900414 const auto& config = device->config();
415
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900416 LOG(INFO) << "Adding device " << device->phys_ifname()
417 << " bridge: " << device->host_ifname()
418 << " guest_iface: " << device->guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900419
420 // Create the bridge.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900421 if (!datapath_->AddBridge(device->host_ifname(), config.host_ipv4_addr(),
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900422 30)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900423 LOG(ERROR) << "Failed to setup arc bridge: " << device->host_ifname();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900424 return;
Garrick Evans54861622019-07-19 09:05:09 +0900425 }
426
Garrick Evanse94b6de2020-02-20 09:19:13 +0900427 // Set up iptables.
428 if (!datapath_->AddInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900429 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
Garrick Evanse94b6de2020-02-20 09:19:13 +0900430 LOG(ERROR) << "Failed to configure ingress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900431 << device->phys_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900432
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900433 if (!datapath_->AddOutboundIPv4(device->host_ifname()))
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900434 LOG(ERROR) << "Failed to configure egress traffic rules for "
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900435 << device->phys_ifname();
Garrick Evans2c263102019-07-26 16:07:18 +0900436
Garrick Evansd90a3822019-11-12 17:53:08 +0900437 if (!impl_->OnStartDevice(device)) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900438 LOG(ERROR) << "Failed to start device " << device->phys_ifname();
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900439 }
440}
441
442void ArcService::RemoveDevice(const std::string& ifname) {
443 const auto it = devices_.find(ifname);
444 if (it == devices_.end()) {
445 LOG(WARNING) << "Unknown device: " << ifname;
Garrick Evanscb791e72019-11-11 15:44:34 +0900446 return;
447 }
448
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900449 // If the container is down, this call does nothing.
450 StopDevice(it->second.get());
451
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900452 ReleaseConfig(ifname, it->second->release_config());
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900453 devices_.erase(it);
Garrick Evans54861622019-07-19 09:05:09 +0900454}
455
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900456void ArcService::StopDevice(Device* device) {
457 if (!impl_ || !impl_->IsStarted())
458 return;
459
460 // For now, devices are only started for ARC++.
461 if (impl_->guest() != GuestMessage::ARC)
462 return;
463
464 impl_->OnStopDevice(device);
Garrick Evans54861622019-07-19 09:05:09 +0900465
466 const auto& config = device->config();
467
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900468 LOG(INFO) << "Removing device " << device->phys_ifname()
469 << " bridge: " << device->host_ifname()
470 << " guest_iface: " << device->guest_ifname();
Garrick Evans54861622019-07-19 09:05:09 +0900471
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900472 datapath_->RemoveOutboundIPv4(device->host_ifname());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900473 datapath_->RemoveInboundIPv4DNAT(
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900474 device->phys_ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
Garrick Evans54861622019-07-19 09:05:09 +0900475
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900476 datapath_->RemoveBridge(device->host_ifname());
Garrick Evanscb791e72019-11-11 15:44:34 +0900477}
478
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900479void ArcService::OnDefaultInterfaceChanged(const std::string& new_ifname,
480 const std::string& prev_ifname) {
Garrick Evansf29f5a32019-12-06 11:34:25 +0900481 if (impl_)
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900482 impl_->OnDefaultInterfaceChanged(new_ifname, prev_ifname);
Garrick Evans54861622019-07-19 09:05:09 +0900483}
Garrick Evansba575742019-07-17 15:48:08 +0900484
Garrick Evans38b25a42020-04-06 15:17:42 +0900485std::vector<const Device::Config*> ArcService::GetDeviceConfigs() const {
486 if (impl_)
487 return impl_->GetDeviceConfigs();
Garrick Evanse94b6de2020-02-20 09:19:13 +0900488
Garrick Evans38b25a42020-04-06 15:17:42 +0900489 return {};
Garrick Evanse94b6de2020-02-20 09:19:13 +0900490}
491
Garrick Evansd90a3822019-11-12 17:53:08 +0900492// ARC++ specific functions.
493
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900494ArcService::ContainerImpl::ContainerImpl(Datapath* datapath,
495 AddressManager* addr_mgr,
496 TrafficForwarder* forwarder,
Garrick Evansd90a3822019-11-12 17:53:08 +0900497 GuestMessage::GuestType guest)
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900498 : pid_(kInvalidPID),
499 datapath_(datapath),
500 addr_mgr_(addr_mgr),
501 forwarder_(forwarder),
502 guest_(guest) {
Garrick Evans6d227b92019-12-03 16:11:29 +0900503 OneTimeSetup(*datapath_);
Garrick Evansa34b5862019-11-20 09:34:01 +0900504}
Garrick Evansd90a3822019-11-12 17:53:08 +0900505
Garrick Evansb4eb3892019-11-13 12:07:07 +0900506GuestMessage::GuestType ArcService::ContainerImpl::guest() const {
507 return guest_;
508}
509
Garrick Evans015b0d62020-02-07 09:06:38 +0900510uint32_t ArcService::ContainerImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900511 return pid_;
512}
513
Garrick Evans015b0d62020-02-07 09:06:38 +0900514bool ArcService::ContainerImpl::Start(uint32_t pid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900515 // This could happen if something crashes and the stop signal is not sent.
516 // It can probably be addressed by stopping and restarting the service.
517 if (pid_ != kInvalidPID)
518 return false;
519
Garrick Evans4dec0c42019-11-29 12:51:57 +0900520 if (pid == kInvalidPID) {
Garrick Evansd90a3822019-11-12 17:53:08 +0900521 LOG(ERROR) << "Cannot start service - invalid container PID";
522 return false;
523 }
Garrick Evans4dec0c42019-11-29 12:51:57 +0900524 pid_ = pid;
Garrick Evansd90a3822019-11-12 17:53:08 +0900525
Garrick Evanse94b6de2020-02-20 09:19:13 +0900526 Device::Options opts{
527 .fwd_multicast = false,
528 .ipv6_enabled = false,
Garrick Evanse94b6de2020-02-20 09:19:13 +0900529 };
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900530 auto config = MakeArcConfig(addr_mgr_, AddressManager::Guest::ARC);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900531
532 // Create the bridge.
533 // Per crbug/1008686 this device cannot be deleted and then re-added.
534 // So instead of removing the bridge when the service stops, bring down the
535 // device instead and re-up it on restart.
536 if (!datapath_->AddBridge(kArcBridge, config->host_ipv4_addr(), 30) &&
537 !datapath_->MaskInterfaceFlags(kArcBridge, IFF_UP)) {
538 LOG(ERROR) << "Failed to bring up arc bridge: " << kArcBridge;
539 return false;
540 }
541
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900542 arc_device_ = std::make_unique<Device>(kArcIfname, kArcBridge, kArcIfname,
543 std::move(config), opts);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900544
545 OnStartDevice(arc_device_.get());
546
Garrick Evansd90a3822019-11-12 17:53:08 +0900547 LOG(INFO) << "ARC++ network service started {pid: " << pid_ << "}";
548 return true;
549}
550
Garrick Evans015b0d62020-02-07 09:06:38 +0900551void ArcService::ContainerImpl::Stop(uint32_t /*pid*/) {
Garrick Evans4dec0c42019-11-29 12:51:57 +0900552 if (!IsStarted())
Taoyu Li1c96d272019-12-13 14:17:43 +0900553 return;
Garrick Evans4dec0c42019-11-29 12:51:57 +0900554
Garrick Evanse94b6de2020-02-20 09:19:13 +0900555 // Per crbug/1008686 this device cannot be deleted and then re-added.
556 // So instead of removing the bridge, bring it down and mark it. This will
557 // allow us to detect if the device is re-added in case of a crash restart
558 // and do the right thing.
559 if (arc_device_) {
560 OnStopDevice(arc_device_.get());
561 if (!datapath_->MaskInterfaceFlags(kArcBridge, IFF_DEBUG, IFF_UP))
562 LOG(ERROR) << "Failed to bring down arc bridge "
563 << "- it may not restart correctly";
564 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900565
566 LOG(INFO) << "ARC++ network service stopped {pid: " << pid_ << "}";
567 pid_ = kInvalidPID;
568}
569
Garrick Evans015b0d62020-02-07 09:06:38 +0900570bool ArcService::ContainerImpl::IsStarted(uint32_t* pid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900571 if (pid)
572 *pid = pid_;
573
Garrick Evansd90a3822019-11-12 17:53:08 +0900574 return pid_ != kInvalidPID;
575}
576
577bool ArcService::ContainerImpl::OnStartDevice(Device* device) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900578 LOG(INFO) << "Starting device " << device->phys_ifname()
579 << " bridge: " << device->host_ifname()
580 << " guest_iface: " << device->guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900581
Garrick Evans2470caa2020-03-04 14:15:41 +0900582 // Set up the virtual pair inside the container namespace.
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900583 const std::string veth_ifname = ArcVethHostName(device->guest_ifname());
Hugo Benichi76675592020-04-08 14:29:57 +0900584 const auto& config = device->config();
585 if (!datapath_->ConnectVethPair(pid_, veth_ifname, device->guest_ifname(),
586 config.mac_addr(), config.guest_ipv4_addr(),
587 30, device->options().fwd_multicast)) {
588 LOG(ERROR) << "Cannot create virtual link for device "
589 << device->phys_ifname();
Garrick Evansd90a3822019-11-12 17:53:08 +0900590 return false;
591 }
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900592 if (!datapath_->AddToBridge(device->host_ifname(), veth_ifname)) {
Garrick Evans2470caa2020-03-04 14:15:41 +0900593 datapath_->RemoveInterface(veth_ifname);
594 LOG(ERROR) << "Failed to bridge interface " << veth_ifname;
595 return false;
596 }
Garrick Evansd90a3822019-11-12 17:53:08 +0900597
Garrick Evans3bd06372020-03-23 10:42:58 +0900598 if (device != arc_device_.get()) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900599 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
600 device->options().ipv6_enabled,
601 device->options().fwd_multicast);
Garrick Evans3bd06372020-03-23 10:42:58 +0900602 } else {
603 // Signal the container that the network device is ready.
604 datapath_->runner().WriteSentinelToContainer(pid_);
605 }
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900606
Garrick Evansd90a3822019-11-12 17:53:08 +0900607 return true;
608}
609
610void ArcService::ContainerImpl::OnStopDevice(Device* device) {
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900611 LOG(INFO) << "Stopping device " << device->phys_ifname()
612 << " bridge: " << device->host_ifname()
613 << " guest_iface: " << device->guest_ifname() << " pid: " << pid_;
Garrick Evansd90a3822019-11-12 17:53:08 +0900614
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900615 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900616 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900617 device->options().ipv6_enabled,
618 device->options().fwd_multicast);
619
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900620 datapath_->RemoveInterface(ArcVethHostName(device->phys_ifname()));
Garrick Evansd90a3822019-11-12 17:53:08 +0900621}
622
623void ArcService::ContainerImpl::OnDefaultInterfaceChanged(
Garrick Evansb05a7ff2020-02-18 12:59:55 +0900624 const std::string& new_ifname, const std::string& prev_ifname) {}
Garrick Evansd90a3822019-11-12 17:53:08 +0900625
Garrick Evansb4eb3892019-11-13 12:07:07 +0900626// VM specific functions
627
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900628ArcService::VmImpl::VmImpl(ShillClient* shill_client,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900629 Datapath* datapath,
630 AddressManager* addr_mgr,
Garrick Evansf5862122020-03-16 09:13:45 +0900631 TrafficForwarder* forwarder,
Garrick Evans2961c7c2020-04-03 11:34:40 +0900632 const std::vector<Device::Config*>& configs)
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900633 : cid_(kInvalidCID),
634 shill_client_(shill_client),
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900635 datapath_(datapath),
636 addr_mgr_(addr_mgr),
Garrick Evansf5862122020-03-16 09:13:45 +0900637 forwarder_(forwarder),
Garrick Evans2961c7c2020-04-03 11:34:40 +0900638 configs_(configs) {}
Garrick Evansb4eb3892019-11-13 12:07:07 +0900639
640GuestMessage::GuestType ArcService::VmImpl::guest() const {
641 return GuestMessage::ARC_VM;
642}
643
Garrick Evans015b0d62020-02-07 09:06:38 +0900644uint32_t ArcService::VmImpl::id() const {
Garrick Evans664a82f2019-12-17 12:18:05 +0900645 return cid_;
646}
647
Garrick Evans38b25a42020-04-06 15:17:42 +0900648std::vector<const Device::Config*> ArcService::VmImpl::GetDeviceConfigs()
649 const {
650 std::vector<const Device::Config*> configs;
651 for (const auto* c : configs_)
652 configs.emplace_back(c);
653
654 return configs;
655}
656
Garrick Evans015b0d62020-02-07 09:06:38 +0900657bool ArcService::VmImpl::Start(uint32_t cid) {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900658 // This can happen if concierge crashes and doesn't send the vm down RPC.
659 // It can probably be addressed by stopping and restarting the service.
660 if (cid_ != kInvalidCID)
661 return false;
662
Garrick Evans015b0d62020-02-07 09:06:38 +0900663 if (cid == kInvalidCID) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900664 LOG(ERROR) << "Invalid VM cid " << cid;
665 return false;
666 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900667 cid_ = cid;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900668
Garrick Evanse94b6de2020-02-20 09:19:13 +0900669 Device::Options opts{
670 .fwd_multicast = true,
671 .ipv6_enabled = true,
Garrick Evanse94b6de2020-02-20 09:19:13 +0900672 };
Garrick Evans2961c7c2020-04-03 11:34:40 +0900673 auto arc_config = MakeArcConfig(addr_mgr_, AddressManager::Guest::VM_ARC);
674 configs_.insert(configs_.begin(), arc_config.get());
Garrick Evanse94b6de2020-02-20 09:19:13 +0900675
Garrick Evans2961c7c2020-04-03 11:34:40 +0900676 // Allocate TAP devices for all configs.
677 for (auto* config : configs_) {
Garrick Evansc7071122020-04-17 12:31:57 +0900678 auto mac = config->mac_addr();
679 auto tap =
680 datapath_->AddTAP("" /* auto-generate name */, &mac,
681 nullptr /* no ipv4 subnet */, vm_tools::kCrosVmUser);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900682 if (tap.empty()) {
683 LOG(ERROR) << "Failed to create TAP device";
684 continue;
685 }
686
687 config->set_tap_ifname(tap);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900688 }
689
Garrick Evans2961c7c2020-04-03 11:34:40 +0900690 arc_device_ = std::make_unique<Device>(
691 kArcVmIfname, kArcVmBridge, kArcVmIfname, std::move(arc_config), opts);
692 // Create the bridge.
693 if (!datapath_->AddBridge(kArcVmBridge,
694 arc_device_->config().host_ipv4_addr(), 30)) {
695 LOG(ERROR) << "Failed to setup arc bridge for device " << *arc_device_;
696 return false;
697 }
Garrick Evanse94b6de2020-02-20 09:19:13 +0900698 OnStartDevice(arc_device_.get());
699
700 LOG(INFO) << "ARCVM network service started {cid: " << cid_ << "}";
Garrick Evansb4eb3892019-11-13 12:07:07 +0900701 return true;
702}
703
Garrick Evans015b0d62020-02-07 09:06:38 +0900704void ArcService::VmImpl::Stop(uint32_t cid) {
Garrick Evans21173b12019-11-20 15:23:16 +0900705 if (cid_ != cid) {
706 LOG(ERROR) << "Mismatched ARCVM CIDs " << cid_ << " != " << cid;
707 return;
708 }
709
Garrick Evans2961c7c2020-04-03 11:34:40 +0900710 for (auto* config : configs_) {
711 const auto& tap = config->tap_ifname();
712 if (!tap.empty()) {
713 datapath_->RemoveInterface(tap);
714 config->set_tap_ifname("");
715 }
716 }
717
Garrick Evanse94b6de2020-02-20 09:19:13 +0900718 OnStopDevice(arc_device_.get());
719 datapath_->RemoveBridge(kArcVmBridge);
720 arc_device_.reset();
721
Garrick Evansb4eb3892019-11-13 12:07:07 +0900722 LOG(INFO) << "ARCVM network service stopped {cid: " << cid_ << "}";
723 cid_ = kInvalidCID;
724}
725
Garrick Evans015b0d62020-02-07 09:06:38 +0900726bool ArcService::VmImpl::IsStarted(uint32_t* cid) const {
Garrick Evansa51d0a12019-11-28 13:51:23 +0900727 if (cid)
728 *cid = cid_;
729
Garrick Evans015b0d62020-02-07 09:06:38 +0900730 return cid_ != kInvalidCID;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900731}
732
733bool ArcService::VmImpl::OnStartDevice(Device* device) {
Garrick Evansf5862122020-03-16 09:13:45 +0900734 // TODO(garrick): Remove once ARCVM P is gone.
Garrick Evans2961c7c2020-04-03 11:34:40 +0900735 if (device == arc_device_.get() && !IsMultinetEnabled())
Garrick Evansf5862122020-03-16 09:13:45 +0900736 return OnStartArcPDevice();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900737
Garrick Evans2961c7c2020-04-03 11:34:40 +0900738 std::string tap;
739 for (auto* config : configs_) {
740 if (config == &device->config()) {
741 tap = config->tap_ifname();
742 break;
743 }
744 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900745 if (tap.empty()) {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900746 LOG(ERROR) << "No TAP device for: " << *device;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900747 return false;
748 }
749
Garrick Evans2961c7c2020-04-03 11:34:40 +0900750 LOG(INFO) << "Starting device " << *device << " cid: " << cid_;
751
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900752 if (!datapath_->AddToBridge(device->host_ifname(), tap)) {
Garrick Evansb4eb3892019-11-13 12:07:07 +0900753 LOG(ERROR) << "Failed to bridge TAP device " << tap;
754 datapath_->RemoveInterface(tap);
755 return false;
756 }
757
Garrick Evansf5862122020-03-16 09:13:45 +0900758 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900759 forwarder_->StartForwarding(device->phys_ifname(), device->host_ifname(),
760 device->options().ipv6_enabled,
761 device->options().fwd_multicast);
Garrick Evansf5862122020-03-16 09:13:45 +0900762
763 return true;
764}
765
766bool ArcService::VmImpl::OnStartArcPDevice() {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900767 LOG(INFO) << "Starting device " << *arc_device_ << " cid: " << cid_;
Garrick Evansf5862122020-03-16 09:13:45 +0900768
Garrick Evans2961c7c2020-04-03 11:34:40 +0900769 if (!datapath_->AddToBridge(kArcVmBridge,
770 arc_device_->config().tap_ifname())) {
771 LOG(ERROR) << "Failed to bridge TAP device " << *arc_device_;
Garrick Evansf5862122020-03-16 09:13:45 +0900772 return false;
773 }
774
Garrick Evansf5862122020-03-16 09:13:45 +0900775 // Setup the iptables.
776 if (!datapath_->AddLegacyIPv4DNAT(
777 IPv4AddressToString(arc_device_->config().guest_ipv4_addr())))
778 LOG(ERROR) << "Failed to configure ARC traffic rules";
779
780 if (!datapath_->AddOutboundIPv4(kArcVmBridge))
781 LOG(ERROR) << "Failed to configure egress traffic rules";
782
Garrick Evansbbdf4b42020-03-05 12:59:06 +0900783 OnDefaultInterfaceChanged(shill_client_->default_interface(),
784 "" /*previous*/);
Garrick Evansbcce09e2020-03-10 15:08:04 +0900785
Garrick Evansb4eb3892019-11-13 12:07:07 +0900786 return true;
787}
788
789void ArcService::VmImpl::OnStopDevice(Device* device) {
Garrick Evansf5862122020-03-16 09:13:45 +0900790 // TODO(garrick): Remove once ARCVM P is gone.
Garrick Evans2961c7c2020-04-03 11:34:40 +0900791 if (device == arc_device_.get() && !IsMultinetEnabled())
Garrick Evansf5862122020-03-16 09:13:45 +0900792 return OnStopArcPDevice();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900793
Garrick Evans2961c7c2020-04-03 11:34:40 +0900794 LOG(INFO) << "Stopping device " << *device << " cid: " << cid_;
Garrick Evansb4eb3892019-11-13 12:07:07 +0900795
Garrick Evansf5862122020-03-16 09:13:45 +0900796 if (device != arc_device_.get())
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900797 forwarder_->StopForwarding(device->phys_ifname(), device->host_ifname(),
Garrick Evansf5862122020-03-16 09:13:45 +0900798 device->options().ipv6_enabled,
799 device->options().fwd_multicast);
Garrick Evansbcce09e2020-03-10 15:08:04 +0900800
Garrick Evans2961c7c2020-04-03 11:34:40 +0900801 for (auto* config : configs_) {
802 if (config == &device->config()) {
803 config->set_tap_ifname("");
804 break;
805 }
806 }
Garrick Evansb4eb3892019-11-13 12:07:07 +0900807}
808
Garrick Evansf5862122020-03-16 09:13:45 +0900809void ArcService::VmImpl::OnStopArcPDevice() {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900810 LOG(INFO) << "Stopping device " << *arc_device_.get() << " cid: " << cid_;
Garrick Evansf5862122020-03-16 09:13:45 +0900811
812 datapath_->RemoveOutboundIPv4(kArcVmBridge);
813 datapath_->RemoveLegacyIPv4DNAT();
814
815 OnDefaultInterfaceChanged("" /*new_ifname*/,
816 shill_client_->default_interface());
817
Garrick Evans2961c7c2020-04-03 11:34:40 +0900818 arc_device_->config().set_tap_ifname("");
Garrick Evansf5862122020-03-16 09:13:45 +0900819}
820
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900821void ArcService::VmImpl::OnDefaultInterfaceChanged(
822 const std::string& new_ifname, const std::string& prev_ifname) {
Garrick Evans2961c7c2020-04-03 11:34:40 +0900823 if (!IsStarted() || IsMultinetEnabled())
Garrick Evansb4eb3892019-11-13 12:07:07 +0900824 return;
825
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900826 forwarder_->StopForwarding(prev_ifname, kArcVmBridge, true /*ipv6*/,
827 true /*multicast*/);
828
Garrick Evansb4eb3892019-11-13 12:07:07 +0900829 datapath_->RemoveLegacyIPv4InboundDNAT();
Garrick Evansb4eb3892019-11-13 12:07:07 +0900830
831 // If a new default interface was given, then re-enable with that.
Garrick Evans1b1f67c2020-02-04 16:21:25 +0900832 if (!new_ifname.empty()) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900833 datapath_->AddLegacyIPv4InboundDNAT(new_ifname);
Jason Jeremy Iman0e9f8262020-03-06 14:50:49 +0900834 forwarder_->StartForwarding(new_ifname, kArcVmBridge, true /*ipv6*/,
835 true /*multicast*/);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900836 }
837}
838
Garrick Evans2961c7c2020-04-03 11:34:40 +0900839bool ArcService::VmImpl::IsMultinetEnabled() const {
840 return configs_.size() > 1;
841}
842
Garrick Evans3388a032020-03-24 11:25:55 +0900843} // namespace patchpanel