blob: 8003812d08e1ece6099cf9f793cf4f28019956cb [file] [log] [blame]
Garrick Evans5d55f5e2019-07-17 15:28:10 +09001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "arc/network/arc_service.h"
6
Garrick Evans54861622019-07-19 09:05:09 +09007#include <linux/rtnetlink.h>
8#include <net/if.h>
9
Garrick Evans5d55f5e2019-07-17 15:28:10 +090010#include <utility>
11
Garrick Evans54861622019-07-19 09:05:09 +090012#include <base/bind.h>
Garrick Evans5d55f5e2019-07-17 15:28:10 +090013#include <base/files/file_path.h>
14#include <base/files/file_util.h>
15#include <base/logging.h>
16#include <base/strings/string_number_conversions.h>
17#include <base/strings/string_util.h>
Garrick Evans54861622019-07-19 09:05:09 +090018#include <base/strings/stringprintf.h>
19#include <shill/net/rtnl_message.h>
20
21#include "arc/network/datapath.h"
22#include "arc/network/ipc.pb.h"
23#include "arc/network/mac_address_generator.h"
Garrick Evans3915af32019-07-25 15:44:34 +090024#include "arc/network/minijailed_process_runner.h"
Garrick Evans54861622019-07-19 09:05:09 +090025#include "arc/network/net_util.h"
26#include "arc/network/scoped_ns.h"
Garrick Evans5d55f5e2019-07-17 15:28:10 +090027
28namespace arc_networkd {
29namespace {
Garrick Evans54861622019-07-19 09:05:09 +090030constexpr pid_t kInvalidPID = -1;
31constexpr pid_t kTestPID = -2;
Garrick Evans260ff302019-07-25 11:22:50 +090032constexpr int kInvalidTableID = -1;
33constexpr int kMaxTableRetries = 10; // Based on 1 second delay.
34constexpr base::TimeDelta kTableRetryDelay = base::TimeDelta::FromSeconds(1);
35// Android adds a constant to the interface index to derive the table id.
36// This is defined in system/netd/server/RouteController.h
37constexpr int kRouteControllerRouteTableOffsetFromIndex = 1000;
Garrick Evans54861622019-07-19 09:05:09 +090038
39// This wrapper is required since the base class is a singleton that hides its
40// constructor. It is necessary here because the message loop thread has to be
41// reassociated to the container's network namespace; and since the container
42// can be repeatedly created and destroyed, the handler must be as well.
43class RTNetlinkHandler : public shill::RTNLHandler {
44 public:
45 RTNetlinkHandler() = default;
46 ~RTNetlinkHandler() = default;
47
48 private:
49 DISALLOW_COPY_AND_ASSIGN(RTNetlinkHandler);
50};
Garrick Evans5d55f5e2019-07-17 15:28:10 +090051
Garrick Evans260ff302019-07-25 11:22:50 +090052int GetAndroidRoutingTableId(const std::string& ifname, pid_t pid) {
53 base::FilePath ifindex_path(base::StringPrintf(
54 "/proc/%d/root/sys/class/net/%s/ifindex", pid, ifname.c_str()));
55 std::string contents;
56 if (!base::ReadFileToString(ifindex_path, &contents)) {
57 PLOG(WARNING) << "Could not read " << ifindex_path.value();
58 return kInvalidTableID;
59 }
60
61 base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
62 int table_id = kInvalidTableID;
63 if (!base::StringToInt(contents, &table_id)) {
64 LOG(ERROR) << "Could not parse ifindex from " << ifindex_path.value()
65 << ": " << contents;
66 return kInvalidTableID;
67 }
68 table_id += kRouteControllerRouteTableOffsetFromIndex;
69
70 LOG(INFO) << "Found table id " << table_id << " for container interface "
71 << ifname;
72 return table_id;
73}
74
Garrick Evans5d55f5e2019-07-17 15:28:10 +090075// TODO(garrick): Remove this workaround ASAP.
76int GetContainerPID() {
77 const base::FilePath path("/run/containers/android-run_oci/container.pid");
78 std::string pid_str;
79 if (!base::ReadFileToStringWithMaxSize(path, &pid_str, 16 /* max size */)) {
80 LOG(ERROR) << "Failed to read pid file";
Garrick Evans54861622019-07-19 09:05:09 +090081 return kInvalidPID;
Garrick Evans5d55f5e2019-07-17 15:28:10 +090082 }
83 int pid;
84 if (!base::StringToInt(base::TrimWhitespaceASCII(pid_str, base::TRIM_ALL),
85 &pid)) {
86 LOG(ERROR) << "Failed to convert container pid string";
Garrick Evans54861622019-07-19 09:05:09 +090087 return kInvalidPID;
Garrick Evans5d55f5e2019-07-17 15:28:10 +090088 }
89 LOG(INFO) << "Read container pid as " << pid;
90 return pid;
91}
92
93} // namespace
94
Garrick Evans54861622019-07-19 09:05:09 +090095ArcService::ArcService(DeviceManagerBase* dev_mgr,
96 bool is_legacy,
97 std::unique_ptr<Datapath> datapath)
Garrick Evans5d55f5e2019-07-17 15:28:10 +090098 : GuestService(is_legacy ? GuestMessage::ARC_LEGACY : GuestMessage::ARC,
Garrick Evans54861622019-07-19 09:05:09 +090099 dev_mgr),
100 pid_(kInvalidPID) {
Garrick Evans260ff302019-07-25 11:22:50 +0900101 if (!datapath) {
102 runner_ = std::make_unique<MinijailedProcessRunner>();
103 datapath = std::make_unique<Datapath>(runner_.get());
104 }
Garrick Evans54861622019-07-19 09:05:09 +0900105
106 datapath_ = std::move(datapath);
Garrick Evans260ff302019-07-25 11:22:50 +0900107 dev_mgr_->RegisterDeviceIPv6AddressFoundHandler(
108 base::Bind(&ArcService::SetupIPv6, weak_factory_.GetWeakPtr()));
Garrick Evans3915af32019-07-25 15:44:34 +0900109
110 // Load networking modules needed by Android that are not compiled in the
111 // kernel. Android does not allow auto-loading of kernel modules.
112 MinijailedProcessRunner runner;
113
114 // These must succeed.
115 if (runner.ModprobeAll({
116 // The netfilter modules needed by netd for iptables commands.
117 "ip6table_filter",
118 "ip6t_ipv6header",
119 "ip6t_REJECT",
120 // The xfrm modules needed for Android's ipsec APIs.
121 "xfrm4_mode_transport",
122 "xfrm4_mode_tunnel",
123 "xfrm6_mode_transport",
124 "xfrm6_mode_tunnel",
125 // The ipsec modules for AH and ESP encryption for ipv6.
126 "ah6",
127 "esp6",
128 }) != 0) {
129 LOG(ERROR) << "One or more required kernel modules failed to load.";
130 }
131
132 // Optional modules.
133 if (runner.ModprobeAll({
134 // This module is not available in kernels < 3.18
135 "nf_reject_ipv6",
136 // These modules are needed for supporting Chrome traffic on Android
137 // VPN which uses Android's NAT feature. Android NAT sets up iptables
138 // rules that use these conntrack modules for FTP/TFTP.
139 "nf_nat_ftp",
140 "nf_nat_tftp",
141 }) != 0) {
142 LOG(WARNING) << "One or more optional kernel modules failed to load.";
143 }
Garrick Evans54861622019-07-19 09:05:09 +0900144}
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900145
146void ArcService::OnStart() {
Garrick Evans54861622019-07-19 09:05:09 +0900147 LOG(INFO) << "ARC++ network service starting";
148 pid_ = GetContainerPID();
149 if (pid_ == kInvalidPID) {
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900150 LOG(ERROR) << "Cannot start service - invalid container PID";
151 return;
152 }
153
Garrick Evans54861622019-07-19 09:05:09 +0900154 // Start listening for RTNetlink messages in the container's net namespace
155 // to be notified whenever it brings up an interface.
156 {
157 ScopedNS ns(pid_);
158 if (ns.IsValid()) {
159 rtnl_handler_ = std::make_unique<RTNetlinkHandler>();
160 rtnl_handler_->Start(RTMGRP_LINK);
161 link_listener_ = std::make_unique<shill::RTNLListener>(
162 shill::RTNLHandler::kRequestLink,
163 Bind(&ArcService::LinkMsgHandler, weak_factory_.GetWeakPtr()),
164 rtnl_handler_.get());
165 } else {
166 // This is bad - it means we won't ever be able to tell when the container
167 // brings up an interface.
168 LOG(ERROR)
169 << "Cannot start netlink listener - invalid container namespace?";
170 }
171 }
172
173 // Start known host devices, any new ones will be setup in the process.
174 dev_mgr_->ProcessDevices(
175 base::Bind(&ArcService::StartDevice, weak_factory_.GetWeakPtr()));
176
177 // If this is the first time the service is starting this will create the
178 // Android bridge device; otherwise it does nothing. Do this after processing
179 // the existing devices so it doesn't get started twice.
180 dev_mgr_->Add(guest_ == GuestMessage::ARC_LEGACY ? kAndroidLegacyDevice
181 : kAndroidDevice);
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900182
183 GuestMessage msg;
184 msg.set_event(GuestMessage::START);
Garrick Evans54861622019-07-19 09:05:09 +0900185 msg.set_arc_pid(pid_);
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900186 msg.set_type(guest_);
187 DispatchMessage(msg);
Garrick Evans54861622019-07-19 09:05:09 +0900188
189 // Finally, call the base implementation.
190 GuestService::OnStart();
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900191}
192
193void ArcService::OnStop() {
Garrick Evans54861622019-07-19 09:05:09 +0900194 LOG(INFO) << "ARC++ network service stopping";
195 // Call the base implementation.
196 GuestService::OnStop();
197
198 // Stop known host devices. Note that this does not teardown any existing
199 // devices.
200 dev_mgr_->ProcessDevices(
201 base::Bind(&ArcService::StopDevice, weak_factory_.GetWeakPtr()));
202
203 rtnl_handler_->RemoveListener(link_listener_.get());
204 link_listener_.reset();
205 rtnl_handler_.reset();
206
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900207 GuestMessage msg;
208 msg.set_event(GuestMessage::STOP);
209 msg.set_type(guest_);
210 DispatchMessage(msg);
211
Garrick Evans54861622019-07-19 09:05:09 +0900212 pid_ = kInvalidPID;
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900213}
214
Garrick Evans54861622019-07-19 09:05:09 +0900215void ArcService::OnDeviceAdded(Device* device) {
216 if (!ShouldProcessDevice(*device))
217 return;
Garrick Evansba575742019-07-17 15:48:08 +0900218
Garrick Evans54861622019-07-19 09:05:09 +0900219 const auto& config = device->config();
220
221 LOG(INFO) << "Adding device " << device->ifname()
222 << " bridge: " << config.host_ifname()
223 << " guest_iface: " << config.guest_ifname()
224 << " for container pid " << pid_;
225
226 // Create the bridge.
227 if (!datapath_->AddBridge(config.host_ifname(),
228 IPv4AddressToString(config.host_ipv4_addr()))) {
229 LOG(ERROR) << "Failed to setup arc bridge: " << config.host_ifname();
230 return;
231 }
232
233 // Setup the iptables.
234 if (device->IsLegacyAndroid()) {
235 if (!datapath_->AddLegacyIPv4DNAT(
236 IPv4AddressToString(config.guest_ipv4_addr())))
237 LOG(ERROR) << "Failed to configure ARC traffic rules";
238
239 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
240 LOG(ERROR) << "Failed to configure egress traffic rules";
241 } else if (!device->IsAndroid()) {
242 if (!datapath_->AddInboundIPv4DNAT(
243 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr())))
244 LOG(ERROR) << "Failed to configure ingress traffic rules for "
245 << device->ifname();
246
247 if (!datapath_->AddOutboundIPv4(config.host_ifname()))
248 LOG(ERROR) << "Failed to configure egress traffic rules";
249 }
250
Garrick Evans2c263102019-07-26 16:07:18 +0900251 device->set_context(guest_, std::make_unique<Context>());
Garrick Evans54861622019-07-19 09:05:09 +0900252
253 StartDevice(device);
254}
255
256void ArcService::StartDevice(Device* device) {
257 if (!ShouldProcessDevice(*device))
258 return;
259
Garrick Evans2c263102019-07-26 16:07:18 +0900260 // If there is no context, then this is a new device and it needs to run
261 // through the full setup process.
262 Context* ctx = dynamic_cast<Context*>(device->context(guest_));
263 if (!ctx)
Garrick Evans54861622019-07-19 09:05:09 +0900264 return OnDeviceAdded(device);
265
Garrick Evans2c263102019-07-26 16:07:18 +0900266 if (ctx->IsStarted()) {
267 LOG(ERROR) << "Attempt to restart device " << device->ifname();
268 return;
269 }
270
271 const auto& config = device->config();
272
Garrick Evans54861622019-07-19 09:05:09 +0900273 LOG(INFO) << "Starting device " << device->ifname()
274 << " bridge: " << config.host_ifname()
275 << " guest_iface: " << config.guest_ifname()
276 << " for container pid " << pid_;
277
278 std::string veth_ifname = datapath_->AddVirtualBridgedInterface(
279 device->ifname(), MacAddressToString(config.guest_mac_addr()),
280 config.host_ifname());
281 if (veth_ifname.empty()) {
282 LOG(ERROR) << "Failed to create virtual interface for container";
283 return;
284 }
285
286 if (!datapath_->AddInterfaceToContainer(
287 pid_, veth_ifname, config.guest_ifname(),
288 IPv4AddressToString(config.guest_ipv4_addr()),
289 device->options().fwd_multicast)) {
290 LOG(ERROR) << "Failed to create container interface.";
291 datapath_->RemoveInterface(veth_ifname);
292 datapath_->RemoveBridge(config.host_ifname());
293 return;
294 }
295
296 // Signal the container that the network device is ready.
297 // This is only applicable for arc0.
298 if (device->IsAndroid() || device->IsLegacyAndroid()) {
Garrick Evans260ff302019-07-25 11:22:50 +0900299 datapath_->runner().WriteSentinelToContainer(base::IntToString(pid_));
Garrick Evans54861622019-07-19 09:05:09 +0900300 }
Garrick Evans2c263102019-07-26 16:07:18 +0900301
302 ctx->Start();
Garrick Evans54861622019-07-19 09:05:09 +0900303}
304
305void ArcService::OnDeviceRemoved(Device* device) {
306 if (!ShouldProcessDevice(*device))
307 return;
308
309 StopDevice(device);
310
311 const auto& config = device->config();
312
313 LOG(INFO) << "Removing device " << device->ifname()
314 << " bridge: " << config.host_ifname()
315 << " guest_iface: " << config.guest_ifname();
316
Garrick Evans260ff302019-07-25 11:22:50 +0900317 device->Disable();
Garrick Evans54861622019-07-19 09:05:09 +0900318 if (device->IsLegacyAndroid()) {
319 datapath_->RemoveOutboundIPv4(config.host_ifname());
320 datapath_->RemoveLegacyIPv4DNAT();
321 } else if (!device->IsAndroid()) {
322 datapath_->RemoveOutboundIPv4(config.host_ifname());
323 datapath_->RemoveInboundIPv4DNAT(
324 device->ifname(), IPv4AddressToString(config.guest_ipv4_addr()));
325 }
326
327 datapath_->RemoveBridge(config.host_ifname());
328
Garrick Evans2c263102019-07-26 16:07:18 +0900329 device->set_context(guest_, nullptr);
Garrick Evans54861622019-07-19 09:05:09 +0900330}
331
332void ArcService::StopDevice(Device* device) {
Garrick Evans54861622019-07-19 09:05:09 +0900333 if (!ShouldProcessDevice(*device))
334 return;
335
Garrick Evans2c263102019-07-26 16:07:18 +0900336 Context* ctx = dynamic_cast<Context*>(device->context(guest_));
337 if (!ctx) {
338 LOG(ERROR) << "Attempt to stop removed device " << device->ifname();
339 return;
340 }
341
342 if (!ctx->IsStarted()) {
343 LOG(ERROR) << "Attempt to re-stop device " << device->ifname();
344 return;
345 }
346
347 const auto& config = device->config();
348
Garrick Evans54861622019-07-19 09:05:09 +0900349 LOG(INFO) << "Stopping device " << device->ifname()
350 << " bridge: " << config.host_ifname()
351 << " guest_iface: " << config.guest_ifname();
352
353 device->Disable();
354 if (!device->IsAndroid()) {
355 datapath_->RemoveInterface(ArcVethHostName(device->ifname()));
356 }
Garrick Evans2c263102019-07-26 16:07:18 +0900357
358 ctx->Stop();
Garrick Evans54861622019-07-19 09:05:09 +0900359}
360
361bool ArcService::ShouldProcessDevice(const Device& device) const {
362 // ARC N uses legacy single networking and only requires the arcbr0/arc0
363 // configuration. Any other device can be safely ignored.
364 if (guest_ == GuestMessage::ARC_LEGACY && !device.IsLegacyAndroid())
365 return false;
366
367 // If ARC isn't running, there is nothing to do. This call must have been
368 // triggered by a device hot-plug event or something similar in DeviceManager.
369 // It's OK to ignore because if the container is gone there is nothing to do.
Garrick Evans2c263102019-07-26 16:07:18 +0900370 return pid_ != kInvalidPID;
Garrick Evans54861622019-07-19 09:05:09 +0900371}
372
373void ArcService::OnDefaultInterfaceChanged(const std::string& ifname) {
374 if (pid_ == kInvalidPID || guest_ != GuestMessage::ARC_LEGACY)
375 return;
376
377 datapath_->RemoveLegacyIPv4InboundDNAT();
378
379 auto* device = dev_mgr_->FindByGuestInterface("arc0");
380 if (!device) {
381 LOG(DFATAL) << "Expected legacy Android device missing";
382 return;
383 }
384
385 device->Disable();
386 if (!ifname.empty()) {
387 datapath_->AddLegacyIPv4InboundDNAT(ifname);
388 device->Enable(ifname);
389 }
390}
391
392void ArcService::LinkMsgHandler(const shill::RTNLMessage& msg) {
393 if (!msg.HasAttribute(IFLA_IFNAME)) {
394 LOG(ERROR) << "Link event message does not have IFLA_IFNAME";
395 return;
396 }
397 bool link_up = msg.link_status().flags & IFF_UP;
398 shill::ByteString b(msg.GetAttribute(IFLA_IFNAME));
399 std::string ifname(reinterpret_cast<const char*>(
400 b.GetSubstring(0, IFNAMSIZ).GetConstData()));
401
402 auto* device = dev_mgr_->FindByGuestInterface(ifname);
Garrick Evans2c263102019-07-26 16:07:18 +0900403 if (!device)
404 return;
405
406 Context* ctx = dynamic_cast<Context*>(device->context(guest_));
407 if (!ctx) {
408 LOG(DFATAL) << "Context missing";
409 return;
410 }
411
412 // If the link status is unchanged, there is nothing to do.
413 if (!ctx->SetLinkUp(link_up))
Garrick Evans54861622019-07-19 09:05:09 +0900414 return;
415
416 if (!link_up) {
417 LOG(INFO) << ifname << " is now down";
418 return;
419 }
420 LOG(INFO) << ifname << " is now up";
421
422 if (device->IsAndroid())
423 return;
424
425 if (device->IsLegacyAndroid()) {
426 OnDefaultInterfaceChanged(dev_mgr_->DefaultInterface());
427 return;
428 }
429
430 device->Enable(ifname);
431}
432
Garrick Evans260ff302019-07-25 11:22:50 +0900433void ArcService::SetupIPv6(Device* device) {
434 device->RegisterIPv6TeardownHandler(
435 base::Bind(&ArcService::TeardownIPv6, weak_factory_.GetWeakPtr()));
436
437 auto& ipv6_config = device->ipv6_config();
438 if (ipv6_config.ifname.empty())
439 return;
440
Garrick Evans2c263102019-07-26 16:07:18 +0900441 Context* ctx = dynamic_cast<Context*>(device->context(guest_));
442 if (!ctx) {
443 LOG(DFATAL) << "Context missing";
444 return;
445 }
446 if (ctx->HasIPv6())
447 return;
448
Garrick Evans260ff302019-07-25 11:22:50 +0900449 LOG(INFO) << "Setting up IPv6 for " << ipv6_config.ifname;
450
Garrick Evans2c263102019-07-26 16:07:18 +0900451 int table_id =
Garrick Evans260ff302019-07-25 11:22:50 +0900452 GetAndroidRoutingTableId(device->config().guest_ifname(), pid_);
Garrick Evans2c263102019-07-26 16:07:18 +0900453 if (table_id == kInvalidTableID) {
454 if (ctx->RoutingTableAttempts() < kMaxTableRetries) {
Garrick Evans260ff302019-07-25 11:22:50 +0900455 LOG(INFO) << "Could not look up routing table ID for container interface "
456 << device->config().guest_ifname() << " - trying again...";
457 base::MessageLoop::current()->task_runner()->PostDelayedTask(
458 FROM_HERE,
459 base::Bind(&ArcService::SetupIPv6, weak_factory_.GetWeakPtr(),
460 device),
461 kTableRetryDelay);
462 } else {
463 LOG(DFATAL)
464 << "Could not look up routing table ID for container interface "
465 << device->config().guest_ifname();
466 }
467 return;
468 }
469
470 LOG(INFO) << "Setting IPv6 address " << ipv6_config.addr
471 << "/128, gateway=" << ipv6_config.router << " on "
472 << ipv6_config.ifname;
473
474 char buf[INET6_ADDRSTRLEN] = {0};
475 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
476 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
477 return;
478 }
479 std::string addr = buf;
480
481 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
482 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
483 return;
484 }
485 std::string router = buf;
486
487 const auto& config = device->config();
488 {
489 ScopedNS ns(pid_);
490 if (!ns.IsValid()) {
491 LOG(ERROR) << "Invalid container namespace (" << pid_
492 << ") - cannot configure IPv6.";
493 return;
494 }
495 if (!datapath_->AddIPv6GatewayRoutes(config.guest_ifname(), addr, router,
Garrick Evans2c263102019-07-26 16:07:18 +0900496 ipv6_config.prefix_len, table_id)) {
Garrick Evans260ff302019-07-25 11:22:50 +0900497 LOG(ERROR) << "Failed to setup IPv6 routes in the container";
498 return;
499 }
500 }
501
502 if (!datapath_->AddIPv6HostRoute(config.host_ifname(), addr,
503 ipv6_config.prefix_len)) {
504 LOG(ERROR) << "Failed to setup the IPv6 route for interface "
505 << config.host_ifname();
506 return;
507 }
508
509 if (!datapath_->AddIPv6Neighbor(ipv6_config.ifname, addr)) {
510 LOG(ERROR) << "Failed to setup the IPv6 neighbor proxy";
511 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
512 ipv6_config.prefix_len);
513 return;
514 }
515
516 if (!datapath_->AddIPv6Forwarding(ipv6_config.ifname,
517 device->config().host_ifname())) {
518 LOG(ERROR) << "Failed to setup iptables for IPv6";
519 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
520 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
521 ipv6_config.prefix_len);
522 return;
523 }
524
Garrick Evans2c263102019-07-26 16:07:18 +0900525 ctx->SetHasIPv6(table_id);
Garrick Evans260ff302019-07-25 11:22:50 +0900526}
527
528void ArcService::TeardownIPv6(Device* device) {
Garrick Evans2c263102019-07-26 16:07:18 +0900529 Context* ctx = dynamic_cast<Context*>(device->context(guest_));
530 if (!ctx || !ctx->HasIPv6())
Garrick Evans260ff302019-07-25 11:22:50 +0900531 return;
532
Garrick Evans2c263102019-07-26 16:07:18 +0900533 auto& ipv6_config = device->ipv6_config();
Garrick Evans260ff302019-07-25 11:22:50 +0900534 LOG(INFO) << "Clearing IPv6 for " << ipv6_config.ifname;
Garrick Evans2c263102019-07-26 16:07:18 +0900535 int table_id = ctx->RoutingTableID();
536 ctx->SetHasIPv6(kInvalidTableID);
Garrick Evans260ff302019-07-25 11:22:50 +0900537
538 char buf[INET6_ADDRSTRLEN] = {0};
539 if (!inet_ntop(AF_INET6, &ipv6_config.addr, buf, sizeof(buf))) {
540 LOG(DFATAL) << "Invalid address: " << ipv6_config.addr;
541 return;
542 }
543 std::string addr = buf;
544
545 if (!inet_ntop(AF_INET6, &ipv6_config.router, buf, sizeof(buf))) {
546 LOG(DFATAL) << "Invalid router address: " << ipv6_config.router;
547 return;
548 }
549 std::string router = buf;
550
551 const auto& config = device->config();
552 datapath_->RemoveIPv6Forwarding(ipv6_config.ifname, config.host_ifname());
553 datapath_->RemoveIPv6Neighbor(ipv6_config.ifname, addr);
554 datapath_->RemoveIPv6HostRoute(config.host_ifname(), addr,
555 ipv6_config.prefix_len);
556
557 ScopedNS ns(pid_);
558 if (ns.IsValid()) {
559 datapath_->RemoveIPv6GatewayRoutes(config.guest_ifname(), addr, router,
Garrick Evans2c263102019-07-26 16:07:18 +0900560 ipv6_config.prefix_len, table_id);
Garrick Evans260ff302019-07-25 11:22:50 +0900561 }
562}
563
Garrick Evans54861622019-07-19 09:05:09 +0900564void ArcService::SetPIDForTestingOnly() {
565 pid_ = kTestPID;
566}
Garrick Evansba575742019-07-17 15:48:08 +0900567
Garrick Evans2c263102019-07-26 16:07:18 +0900568// Context
569
570ArcService::Context::Context() : Device::Context() {
571 Stop();
572}
573
574void ArcService::Context::Start() {
575 Stop();
576 started_ = true;
577}
578
579void ArcService::Context::Stop() {
580 started_ = false;
581 link_up_ = false;
582 routing_table_id_ = kInvalidTableID;
583 routing_table_attempts_ = 0;
584}
585
586bool ArcService::Context::IsStarted() const {
587 return started_;
588}
589
590bool ArcService::Context::IsLinkUp() const {
591 return link_up_;
592}
593
594bool ArcService::Context::SetLinkUp(bool link_up) {
595 if (link_up == link_up_)
596 return false;
597
598 link_up_ = link_up;
599 return true;
600}
601
602bool ArcService::Context::HasIPv6() const {
603 return routing_table_id_ != kInvalidTableID;
604}
605
606bool ArcService::Context::SetHasIPv6(int routing_table_id) {
607 if (routing_table_id <= kRouteControllerRouteTableOffsetFromIndex)
608 return false;
609
610 routing_table_id_ = routing_table_id;
611 return true;
612}
613
614int ArcService::Context::RoutingTableID() const {
615 return routing_table_id_;
616}
617
618int ArcService::Context::RoutingTableAttempts() {
619 return routing_table_attempts_++;
620}
621
Garrick Evans5d55f5e2019-07-17 15:28:10 +0900622} // namespace arc_networkd