blob: 865f39bb2848ba7ab49fc18797f226c1484219f5 [file] [log] [blame]
Kevin Cernekee95d4ae92016-06-19 10:26:29 -07001// Copyright 2016 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/manager.h"
Kevin Cernekee4e62cc12016-12-03 11:50:53 -08006
Kevin Cernekee95d4ae92016-06-19 10:26:29 -07007#include <arpa/inet.h>
Garrick Evans4ac09852020-01-16 14:09:22 +09008#include <net/if.h>
Hugo Benichi935eca92018-07-03 13:47:24 +09009#include <netinet/in.h>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070010#include <stdint.h>
Hugo Benichi7352ad92020-04-07 16:11:59 +090011#include <sys/epoll.h>
Garrick Evans54861622019-07-19 09:05:09 +090012#include <sys/prctl.h>
Garrick Evans96e03042019-05-28 14:30:52 +090013#include <sys/socket.h>
14#include <sys/un.h>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070015
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080016#include <utility>
17
Hugo Benichicc6850f2020-01-17 13:26:06 +090018#include <base/bind.h>
Taoyu Lia0727dc2020-09-24 19:54:59 +090019#include <base/files/scoped_file.h>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070020#include <base/logging.h>
Qijiang Fan886c4692021-02-19 11:54:10 +090021#include <base/notreached.h>
Taoyu Lic85c44b2019-12-04 17:32:57 +090022#include <base/strings/string_number_conversions.h>
Garrick Evans96e03042019-05-28 14:30:52 +090023#include <base/strings/string_split.h>
Garrick Evans6f258d02019-06-28 16:32:07 +090024#include <base/strings/string_util.h>
Taoyu Li179dcc62019-10-17 11:21:08 +090025#include <base/strings/stringprintf.h>
hschamf9546312020-04-14 15:12:40 +090026#include <base/threading/thread_task_runner_handle.h>
Taoyu Lic85c44b2019-12-04 17:32:57 +090027#include <brillo/key_value_store.h>
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080028#include <brillo/minijail/minijail.h>
29
Garrick Evans3388a032020-03-24 11:25:55 +090030#include "patchpanel/ipc.pb.h"
31#include "patchpanel/mac_address_generator.h"
32#include "patchpanel/net_util.h"
33#include "patchpanel/routing_service.h"
34#include "patchpanel/scoped_ns.h"
Garrick Evans428e4762018-12-11 15:18:42 +090035
Garrick Evans3388a032020-03-24 11:25:55 +090036namespace patchpanel {
Garrick Evans08843932019-09-17 14:41:08 +090037namespace {
Garrick Evans4c042572019-12-17 13:42:25 +090038constexpr int kSubprocessRestartDelayMs = 900;
Garrick Evans08843932019-09-17 14:41:08 +090039
Hugo Benichi7352ad92020-04-07 16:11:59 +090040// Time interval between epoll checks on file descriptors committed by callers
41// of ConnectNamespace DBus API.
42constexpr const base::TimeDelta kConnectNamespaceCheckInterval =
Hugo Benichifa9462e2020-06-26 09:50:48 +090043 base::TimeDelta::FromSeconds(5);
Hugo Benichi7352ad92020-04-07 16:11:59 +090044
Garrick Evans08843932019-09-17 14:41:08 +090045// Passes |method_call| to |handler| and passes the response to
46// |response_sender|. If |handler| returns nullptr, an empty response is
47// created and sent.
48void HandleSynchronousDBusMethodCall(
49 base::Callback<std::unique_ptr<dbus::Response>(dbus::MethodCall*)> handler,
50 dbus::MethodCall* method_call,
51 dbus::ExportedObject::ResponseSender response_sender) {
52 std::unique_ptr<dbus::Response> response = handler.Run(method_call);
53 if (!response)
54 response = dbus::Response::FromMethodCall(method_call);
Qijiang Fan0c657d42020-08-24 19:07:50 +090055 std::move(response_sender).Run(std::move(response));
Garrick Evans08843932019-09-17 14:41:08 +090056}
57
Hugo Benichi69c989d2021-03-01 00:23:39 +090058bool IsIPv6NDProxyEnabled(ShillClient::Device::Type type) {
59 static const std::set<ShillClient::Device::Type> ndproxy_allowed_types{
60 ShillClient::Device::Type::kCellular,
61 ShillClient::Device::Type::kEthernet,
62 ShillClient::Device::Type::kEthernetEap,
63 ShillClient::Device::Type::kWifi,
64 };
65 return ndproxy_allowed_types.find(type) != ndproxy_allowed_types.end();
66}
67
Garrick Evans08843932019-09-17 14:41:08 +090068} // namespace
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070069
Taoyu Lice7caa62019-10-01 15:43:33 +090070Manager::Manager(std::unique_ptr<HelperProcess> adb_proxy,
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090071 std::unique_ptr<HelperProcess> mcast_proxy,
Garrick Evans1f5a3612019-11-08 12:59:03 +090072 std::unique_ptr<HelperProcess> nd_proxy)
Garrick Evans3915af32019-07-25 15:44:34 +090073 : adb_proxy_(std::move(adb_proxy)),
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090074 mcast_proxy_(std::move(mcast_proxy)),
Garrick Evans4ee5ce22020-03-18 07:05:17 +090075 nd_proxy_(std::move(nd_proxy)) {
Taoyu Li179dcc62019-10-17 11:21:08 +090076 runner_ = std::make_unique<MinijailedProcessRunner>();
Jason Jeremy Imana7273a32020-08-04 11:25:31 +090077 datapath_ = std::make_unique<Datapath>(runner_.get(), &firewall_);
Hugo Benichi7352ad92020-04-07 16:11:59 +090078 connected_namespaces_epollfd_ = epoll_create(1 /* size */);
Taoyu Li179dcc62019-10-17 11:21:08 +090079}
Long Chengd4415582019-09-24 19:16:09 +000080
Jason Jeremy Imanf4156cb2019-11-14 15:36:22 +090081std::map<const std::string, bool> Manager::cached_feature_enabled_ = {};
82
83bool Manager::ShouldEnableFeature(
84 int min_android_sdk_version,
85 int min_chrome_milestone,
86 const std::vector<std::string>& supported_boards,
87 const std::string& feature_name) {
88 static const char kLsbReleasePath[] = "/etc/lsb-release";
89
90 const auto& cached_result = cached_feature_enabled_.find(feature_name);
91 if (cached_result != cached_feature_enabled_.end())
92 return cached_result->second;
93
94 auto check = [min_android_sdk_version, min_chrome_milestone,
95 &supported_boards, &feature_name]() {
96 brillo::KeyValueStore store;
97 if (!store.Load(base::FilePath(kLsbReleasePath))) {
98 LOG(ERROR) << "Could not read lsb-release";
99 return false;
100 }
101
102 std::string value;
103 if (!store.GetString("CHROMEOS_ARC_ANDROID_SDK_VERSION", &value)) {
104 LOG(ERROR) << feature_name
105 << " disabled - cannot determine Android SDK version";
106 return false;
107 }
108 int ver = 0;
109 if (!base::StringToInt(value.c_str(), &ver)) {
110 LOG(ERROR) << feature_name << " disabled - invalid Android SDK version";
111 return false;
112 }
113 if (ver < min_android_sdk_version) {
114 LOG(INFO) << feature_name << " disabled for Android SDK " << value;
115 return false;
116 }
117
118 if (!store.GetString("CHROMEOS_RELEASE_CHROME_MILESTONE", &value)) {
119 LOG(ERROR) << feature_name
120 << " disabled - cannot determine ChromeOS milestone";
121 return false;
122 }
123 if (!base::StringToInt(value.c_str(), &ver)) {
124 LOG(ERROR) << feature_name << " disabled - invalid ChromeOS milestone";
125 return false;
126 }
127 if (ver < min_chrome_milestone) {
128 LOG(INFO) << feature_name << " disabled for ChromeOS milestone " << value;
129 return false;
130 }
131
132 if (!store.GetString("CHROMEOS_RELEASE_BOARD", &value)) {
133 LOG(ERROR) << feature_name << " disabled - cannot determine board";
134 return false;
135 }
136 if (!supported_boards.empty() &&
137 std::find(supported_boards.begin(), supported_boards.end(), value) ==
138 supported_boards.end()) {
139 LOG(INFO) << feature_name << " disabled for board " << value;
140 return false;
141 }
142 return true;
143 };
144
145 bool result = check();
146 cached_feature_enabled_.emplace(feature_name, result);
147 return result;
148}
149
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700150int Manager::OnInit() {
Garrick Evans54861622019-07-19 09:05:09 +0900151 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800152
153 // Handle subprocess lifecycle.
154 process_reaper_.Register(this);
Hugo Benichi935eca92018-07-03 13:47:24 +0900155
156 CHECK(process_reaper_.WatchForChild(
Garrick Evans96e03042019-05-28 14:30:52 +0900157 FROM_HERE, adb_proxy_->pid(),
158 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
159 adb_proxy_->pid())))
160 << "Failed to watch adb-proxy child process";
Taoyu Liaf944c92019-10-01 12:22:31 +0900161 CHECK(process_reaper_.WatchForChild(
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +0900162 FROM_HERE, mcast_proxy_->pid(),
163 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
164 nd_proxy_->pid())))
165 << "Failed to watch multicast-proxy child process";
166 CHECK(process_reaper_.WatchForChild(
Taoyu Liaf944c92019-10-01 12:22:31 +0900167 FROM_HERE, nd_proxy_->pid(),
168 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
169 nd_proxy_->pid())))
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +0900170 << "Failed to watch nd-proxy child process";
Garrick Evans96e03042019-05-28 14:30:52 +0900171
Garrick Evans49879532018-12-03 13:15:36 +0900172 // Run after Daemon::OnInit().
hschamf9546312020-04-14 15:12:40 +0900173 base::ThreadTaskRunnerHandle::Get()->PostTask(
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700174 FROM_HERE,
175 base::Bind(&Manager::InitialSetup, weak_factory_.GetWeakPtr()));
176
177 return DBusDaemon::OnInit();
178}
179
180void Manager::InitialSetup() {
Garrick Evans08843932019-09-17 14:41:08 +0900181 LOG(INFO) << "Setting up DBus service interface";
182 dbus_svc_path_ = bus_->GetExportedObject(
183 dbus::ObjectPath(patchpanel::kPatchPanelServicePath));
184 if (!dbus_svc_path_) {
185 LOG(FATAL) << "Failed to export " << patchpanel::kPatchPanelServicePath
186 << " object";
187 }
188
Hugo Benichi76be34a2020-08-26 22:35:54 +0900189 shill_client_ = std::make_unique<ShillClient>(bus_);
190
Garrick Evans08843932019-09-17 14:41:08 +0900191 using ServiceMethod =
192 std::unique_ptr<dbus::Response> (Manager::*)(dbus::MethodCall*);
193 const std::map<const char*, ServiceMethod> kServiceMethods = {
194 {patchpanel::kArcStartupMethod, &Manager::OnArcStartup},
195 {patchpanel::kArcShutdownMethod, &Manager::OnArcShutdown},
196 {patchpanel::kArcVmStartupMethod, &Manager::OnArcVmStartup},
197 {patchpanel::kArcVmShutdownMethod, &Manager::OnArcVmShutdown},
Garrick Evans47c19272019-11-21 10:58:21 +0900198 {patchpanel::kTerminaVmStartupMethod, &Manager::OnTerminaVmStartup},
199 {patchpanel::kTerminaVmShutdownMethod, &Manager::OnTerminaVmShutdown},
Garrick Evans51d5b552020-01-30 10:42:06 +0900200 {patchpanel::kPluginVmStartupMethod, &Manager::OnPluginVmStartup},
201 {patchpanel::kPluginVmShutdownMethod, &Manager::OnPluginVmShutdown},
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900202 {patchpanel::kSetVpnIntentMethod, &Manager::OnSetVpnIntent},
Hugo Benichib56b77c2020-01-15 16:00:56 +0900203 {patchpanel::kConnectNamespaceMethod, &Manager::OnConnectNamespace},
Jie Jiang493cde42020-07-17 21:43:39 +0900204 {patchpanel::kGetTrafficCountersMethod, &Manager::OnGetTrafficCounters},
Jason Jeremy Imanb2a421e2020-07-04 20:48:32 +0900205 {patchpanel::kModifyPortRuleMethod, &Manager::OnModifyPortRule},
Garrick Evans02e6e872020-11-30 11:53:13 +0900206 {patchpanel::kGetDevicesMethod, &Manager::OnGetDevices},
Garrick Evans08843932019-09-17 14:41:08 +0900207 };
208
209 for (const auto& kv : kServiceMethods) {
210 if (!dbus_svc_path_->ExportMethodAndBlock(
211 patchpanel::kPatchPanelInterface, kv.first,
212 base::Bind(&HandleSynchronousDBusMethodCall,
213 base::Bind(kv.second, base::Unretained(this))))) {
214 LOG(FATAL) << "Failed to export method " << kv.first;
215 }
216 }
217
218 if (!bus_->RequestOwnershipAndBlock(patchpanel::kPatchPanelServiceName,
219 dbus::Bus::REQUIRE_PRIMARY)) {
220 LOG(FATAL) << "Failed to take ownership of "
221 << patchpanel::kPatchPanelServiceName;
222 }
223 LOG(INFO) << "DBus service interface ready";
224
Hugo Benichifda77232020-08-21 18:28:15 +0900225 routing_svc_ = std::make_unique<RoutingService>();
Hugo Benichi058a26a2020-11-26 10:10:39 +0900226 counters_svc_ =
227 std::make_unique<CountersService>(datapath_.get(), runner_.get());
Hugo Benichifda77232020-08-21 18:28:15 +0900228
Hugo Benichibf811c62020-09-07 17:30:45 +0900229 // b/162966185: Allow Jetstream to disable:
230 // - the IP forwarding setup used for hosting VMs and containers,
231 // - the iptables rules for fwmark based routing.
232 if (!USE_JETSTREAM_ROUTING) {
233 datapath_->Start();
Hugo Benichi2a940542020-10-26 18:50:49 +0900234 shill_client_->RegisterDefaultDeviceChangedHandler(base::BindRepeating(
235 &Manager::OnDefaultDeviceChanged, weak_factory_.GetWeakPtr()));
Hugo Benichibf811c62020-09-07 17:30:45 +0900236 shill_client_->RegisterDevicesChangedHandler(base::BindRepeating(
237 &Manager::OnDevicesChanged, weak_factory_.GetWeakPtr()));
Hugo Benichi1e0656f2021-02-15 15:43:38 +0900238 shill_client_->RegisterIPConfigsChangedHandler(base::BindRepeating(
239 &Manager::OnIPConfigsChanged, weak_factory_.GetWeakPtr()));
Hugo Benichibf811c62020-09-07 17:30:45 +0900240 }
Hugo Benichifda77232020-08-21 18:28:15 +0900241
Taoyu Lia0727dc2020-09-24 19:54:59 +0900242 nd_proxy_->RegisterNDProxyMessageHandler(
243 base::Bind(&Manager::OnNDProxyMessage, weak_factory_.GetWeakPtr()));
Hugo Benichifda77232020-08-21 18:28:15 +0900244
Hugo Benichifda77232020-08-21 18:28:15 +0900245 auto* const forwarder = static_cast<TrafficForwarder*>(this);
246
247 GuestMessage::GuestType arc_guest =
248 USE_ARCVM ? GuestMessage::ARC_VM : GuestMessage::ARC;
Garrick Evans209a80a2020-11-30 14:42:40 +0900249 arc_svc_ = std::make_unique<ArcService>(
250 shill_client_.get(), datapath_.get(), &addr_mgr_, forwarder, arc_guest,
251 base::BindRepeating(&Manager::OnDeviceChanged,
252 weak_factory_.GetWeakPtr()));
253 cros_svc_ = std::make_unique<CrostiniService>(
Hugo Benichi69c989d2021-03-01 00:23:39 +0900254 &addr_mgr_, datapath_.get(),
Garrick Evans209a80a2020-11-30 14:42:40 +0900255 base::BindRepeating(&Manager::OnDeviceChanged,
256 weak_factory_.GetWeakPtr()));
Jie Jiang84966852020-09-18 18:49:05 +0900257 network_monitor_svc_ = std::make_unique<NetworkMonitorService>(
258 shill_client_.get(),
Jie Jiang25c1b972020-11-12 15:42:53 +0900259 base::BindRepeating(&Manager::OnNeighborReachabilityEvent,
Jie Jiang84966852020-09-18 18:49:05 +0900260 weak_factory_.GetWeakPtr()));
Hugo Benichifda77232020-08-21 18:28:15 +0900261 network_monitor_svc_->Start();
Hugo Benichi058a26a2020-11-26 10:10:39 +0900262 counters_svc_->Init(shill_client_->get_devices());
Hugo Benichifda77232020-08-21 18:28:15 +0900263 nd_proxy_->Listen();
264}
265
266void Manager::OnShutdown(int* exit_code) {
267 LOG(INFO) << "Shutting down and cleaning up";
Jie Jiang84966852020-09-18 18:49:05 +0900268 network_monitor_svc_.reset();
Hugo Benichifda77232020-08-21 18:28:15 +0900269 cros_svc_.reset();
270 arc_svc_.reset();
271 close(connected_namespaces_epollfd_);
272 // Tear down any remaining connected namespace.
273 std::vector<int> connected_namespaces_fdkeys;
274 for (const auto& kv : connected_namespaces_)
275 connected_namespaces_fdkeys.push_back(kv.first);
276 for (const int fdkey : connected_namespaces_fdkeys)
277 DisconnectNamespace(fdkey);
Hugo Benichibf811c62020-09-07 17:30:45 +0900278 if (!USE_JETSTREAM_ROUTING)
279 datapath_->Stop();
Jie Jiang00592cf2020-12-17 11:23:49 +0900280
281 brillo::DBusDaemon::OnShutdown(exit_code);
Hugo Benichifda77232020-08-21 18:28:15 +0900282}
283
284void Manager::OnSubprocessExited(pid_t pid, const siginfo_t&) {
285 LOG(ERROR) << "Subprocess " << pid << " exited unexpectedly -"
286 << " attempting to restart";
287
288 HelperProcess* proc;
289 if (pid == adb_proxy_->pid()) {
290 proc = adb_proxy_.get();
291 } else if (pid == mcast_proxy_->pid()) {
292 proc = mcast_proxy_.get();
293 } else if (pid == nd_proxy_->pid()) {
294 proc = nd_proxy_.get();
295 } else {
296 LOG(DFATAL) << "Unknown child process";
297 return;
298 }
299
300 process_reaper_.ForgetChild(pid);
301
302 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
303 FROM_HERE,
304 base::Bind(&Manager::RestartSubprocess, weak_factory_.GetWeakPtr(), proc),
305 base::TimeDelta::FromMilliseconds((2 << proc->restarts()) *
306 kSubprocessRestartDelayMs));
307}
308
309void Manager::RestartSubprocess(HelperProcess* subproc) {
310 if (subproc->Restart()) {
311 DCHECK(process_reaper_.WatchForChild(
312 FROM_HERE, subproc->pid(),
313 base::Bind(&Manager::OnSubprocessExited, weak_factory_.GetWeakPtr(),
314 subproc->pid())))
315 << "Failed to watch child process " << subproc->pid();
316 }
317}
318
Hugo Benichi2a940542020-10-26 18:50:49 +0900319void Manager::OnDefaultDeviceChanged(const ShillClient::Device& new_device,
320 const ShillClient::Device& prev_device) {
321 // Only take into account interface switches and ignore layer 3 property
322 // changes.
323 if (prev_device.ifname == new_device.ifname)
324 return;
325
Hugo Benichi058a26a2020-11-26 10:10:39 +0900326 if (prev_device.type == ShillClient::Device::Type::kVPN) {
Hugo Benichi2a940542020-10-26 18:50:49 +0900327 datapath_->StopVpnRouting(prev_device.ifname);
Hugo Benichi058a26a2020-11-26 10:10:39 +0900328 counters_svc_->OnVpnDeviceRemoved(prev_device.ifname);
329 }
Hugo Benichi2a940542020-10-26 18:50:49 +0900330
Hugo Benichi058a26a2020-11-26 10:10:39 +0900331 if (new_device.type == ShillClient::Device::Type::kVPN) {
Hugo Benichi2a940542020-10-26 18:50:49 +0900332 datapath_->StartVpnRouting(new_device.ifname);
Hugo Benichi058a26a2020-11-26 10:10:39 +0900333 counters_svc_->OnVpnDeviceAdded(new_device.ifname);
334 }
Hugo Benichi69c989d2021-03-01 00:23:39 +0900335
336 // When the default logical network changes, Crostini's tap devices must leave
337 // their current forwarding group for multicast and IPv6 ndproxy and join the
338 // forwarding group of the new logical default network.
339 for (const auto* tap_device : cros_svc_->GetDevices()) {
340 bool was_multicast =
341 multicast_virtual_ifnames_.find(tap_device->host_ifname()) !=
342 multicast_virtual_ifnames_.end();
343 StopForwarding(prev_device.ifname, tap_device->host_ifname(),
344 IsIPv6NDProxyEnabled(prev_device.type), was_multicast);
345 StartForwarding(new_device.ifname, tap_device->host_ifname(),
346 IsIPv6NDProxyEnabled(new_device.type),
347 IsMulticastInterface(new_device.ifname));
348 }
Hugo Benichi2a940542020-10-26 18:50:49 +0900349}
350
Hugo Benichi76be34a2020-08-26 22:35:54 +0900351void Manager::OnDevicesChanged(const std::set<std::string>& added,
352 const std::set<std::string>& removed) {
Hugo Benichi058a26a2020-11-26 10:10:39 +0900353 for (const std::string& ifname : removed) {
Hugo Benichi76be34a2020-08-26 22:35:54 +0900354 datapath_->StopConnectionPinning(ifname);
Hugo Benichi1e0656f2021-02-15 15:43:38 +0900355 datapath_->RemoveRedirectDnsRule(ifname);
Hugo Benichi058a26a2020-11-26 10:10:39 +0900356 counters_svc_->OnPhysicalDeviceRemoved(ifname);
357 }
Hugo Benichi76be34a2020-08-26 22:35:54 +0900358
Hugo Benichi058a26a2020-11-26 10:10:39 +0900359 for (const std::string& ifname : added) {
Hugo Benichi76be34a2020-08-26 22:35:54 +0900360 datapath_->StartConnectionPinning(ifname);
Hugo Benichi1e0656f2021-02-15 15:43:38 +0900361 ShillClient::Device device;
362 if (!shill_client_->GetDeviceProperties(ifname, &device))
363 continue;
364
365 if (!device.ipconfig.ipv4_dns_addresses.empty())
366 datapath_->AddRedirectDnsRule(ifname,
367 device.ipconfig.ipv4_dns_addresses.front());
368
Hugo Benichi058a26a2020-11-26 10:10:39 +0900369 counters_svc_->OnPhysicalDeviceAdded(ifname);
370 }
Hugo Benichi76be34a2020-08-26 22:35:54 +0900371}
372
Hugo Benichi1e0656f2021-02-15 15:43:38 +0900373void Manager::OnIPConfigsChanged(const std::string& device,
374 const ShillClient::IPConfig& ipconfig) {
375 if (ipconfig.ipv4_dns_addresses.empty()) {
376 datapath_->RemoveRedirectDnsRule(device);
377 } else {
378 datapath_->AddRedirectDnsRule(device, ipconfig.ipv4_dns_addresses.front());
379 }
380}
381
Garrick Evans209a80a2020-11-30 14:42:40 +0900382void Manager::OnDeviceChanged(const Device& device,
383 Device::ChangeEvent event,
384 GuestMessage::GuestType guest_type) {
385 dbus::Signal signal(kPatchPanelInterface, kNetworkDeviceChangedSignal);
386 NetworkDeviceChangedSignal proto;
387 proto.set_event(event == Device::ChangeEvent::ADDED
388 ? NetworkDeviceChangedSignal::DEVICE_ADDED
389 : NetworkDeviceChangedSignal::DEVICE_REMOVED);
390 auto* dev = proto.mutable_device();
391 dev->set_ifname(device.host_ifname());
Garrick Evans9ccd2a62021-02-18 14:48:28 +0900392 dev->set_phys_ifname(device.phys_ifname());
Garrick Evans209a80a2020-11-30 14:42:40 +0900393 dev->set_ipv4_addr(device.config().guest_ipv4_addr());
394 if (const auto* subnet = device.config().ipv4_subnet()) {
395 auto* sub = dev->mutable_ipv4_subnet();
396 sub->set_base_addr(subnet->BaseAddress());
397 sub->set_prefix_len(subnet->PrefixLength());
398 }
399 switch (guest_type) {
400 case GuestMessage::ARC:
401 dev->set_guest_type(NetworkDevice::ARC);
402 break;
403 case GuestMessage::ARC_VM:
404 dev->set_guest_type(NetworkDevice::ARCVM);
405 break;
406 case GuestMessage::TERMINA_VM:
407 dev->set_guest_type(NetworkDevice::TERMINA_VM);
408 break;
409 case GuestMessage::PLUGIN_VM:
410 dev->set_guest_type(NetworkDevice::PLUGIN_VM);
411 break;
412 default:
413 LOG(ERROR) << "Unknown device type";
414 }
415
Hugo Benichi69c989d2021-03-01 00:23:39 +0900416 if (guest_type == GuestMessage::TERMINA_VM ||
417 guest_type == GuestMessage::PLUGIN_VM) {
418 const ShillClient::Device& default_device = shill_client_->default_device();
419 if (event == Device::ChangeEvent::ADDED) {
420 StartForwarding(default_device.ifname, device.host_ifname(),
421 IsIPv6NDProxyEnabled(default_device.type),
422 IsMulticastInterface(default_device.ifname));
423 } else if (event == Device::ChangeEvent::REMOVED) {
424 bool was_multicast =
425 multicast_virtual_ifnames_.find(device.host_ifname()) !=
426 multicast_virtual_ifnames_.end();
427 StopForwarding(default_device.ifname, device.host_ifname(),
428 IsIPv6NDProxyEnabled(default_device.type), was_multicast);
429 }
430 }
431
Garrick Evans209a80a2020-11-30 14:42:40 +0900432 dbus::MessageWriter(&signal).AppendProtoAsArrayOfBytes(proto);
433 dbus_svc_path_->SendSignal(&signal);
434}
435
Garrick Evanse94a14e2019-11-11 10:32:13 +0900436bool Manager::StartArc(pid_t pid) {
Garrick Evans508a4bc2019-11-14 08:45:52 +0900437 if (!arc_svc_->Start(pid))
438 return false;
Garrick Evanse94a14e2019-11-11 10:32:13 +0900439
440 GuestMessage msg;
441 msg.set_event(GuestMessage::START);
442 msg.set_type(GuestMessage::ARC);
443 msg.set_arc_pid(pid);
444 SendGuestMessage(msg);
445
446 return true;
447}
448
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900449void Manager::StopArc() {
Garrick Evanse94a14e2019-11-11 10:32:13 +0900450 GuestMessage msg;
451 msg.set_event(GuestMessage::STOP);
452 msg.set_type(GuestMessage::ARC);
453 SendGuestMessage(msg);
454
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900455 // After the ARC container has stopped, the pid is not known anymore.
456 // The pid argument is ignored by ArcService.
457 arc_svc_->Stop(0);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900458}
459
Garrick Evans015b0d62020-02-07 09:06:38 +0900460bool Manager::StartArcVm(uint32_t cid) {
Garrick Evans508a4bc2019-11-14 08:45:52 +0900461 if (!arc_svc_->Start(cid))
462 return false;
Garrick Evanse94a14e2019-11-11 10:32:13 +0900463
464 GuestMessage msg;
465 msg.set_event(GuestMessage::START);
466 msg.set_type(GuestMessage::ARC_VM);
467 msg.set_arcvm_vsock_cid(cid);
468 SendGuestMessage(msg);
469
470 return true;
471}
472
Garrick Evans015b0d62020-02-07 09:06:38 +0900473void Manager::StopArcVm(uint32_t cid) {
Garrick Evanse94a14e2019-11-11 10:32:13 +0900474 GuestMessage msg;
475 msg.set_event(GuestMessage::STOP);
476 msg.set_type(GuestMessage::ARC_VM);
477 SendGuestMessage(msg);
478
Garrick Evans21173b12019-11-20 15:23:16 +0900479 arc_svc_->Stop(cid);
Garrick Evanse94a14e2019-11-11 10:32:13 +0900480}
481
Garrick Evans51d5b552020-01-30 10:42:06 +0900482bool Manager::StartCrosVm(uint64_t vm_id,
483 GuestMessage::GuestType vm_type,
Garrick Evans53a2a982020-02-05 10:53:35 +0900484 uint32_t subnet_index) {
Garrick Evans51d5b552020-01-30 10:42:06 +0900485 DCHECK(vm_type == GuestMessage::TERMINA_VM ||
486 vm_type == GuestMessage::PLUGIN_VM);
487
488 if (!cros_svc_->Start(vm_id, vm_type == GuestMessage::TERMINA_VM,
489 subnet_index))
Garrick Evans47c19272019-11-21 10:58:21 +0900490 return false;
491
492 GuestMessage msg;
493 msg.set_event(GuestMessage::START);
Garrick Evans51d5b552020-01-30 10:42:06 +0900494 msg.set_type(vm_type);
Garrick Evans47c19272019-11-21 10:58:21 +0900495 SendGuestMessage(msg);
496
497 return true;
498}
499
Garrick Evans51d5b552020-01-30 10:42:06 +0900500void Manager::StopCrosVm(uint64_t vm_id, GuestMessage::GuestType vm_type) {
Garrick Evans47c19272019-11-21 10:58:21 +0900501 GuestMessage msg;
502 msg.set_event(GuestMessage::STOP);
Garrick Evans51d5b552020-01-30 10:42:06 +0900503 msg.set_type(vm_type);
Garrick Evans47c19272019-11-21 10:58:21 +0900504 SendGuestMessage(msg);
505
Garrick Evans51d5b552020-01-30 10:42:06 +0900506 cros_svc_->Stop(vm_id, vm_type == GuestMessage::TERMINA_VM);
Garrick Evans47c19272019-11-21 10:58:21 +0900507}
508
Garrick Evans02e6e872020-11-30 11:53:13 +0900509std::unique_ptr<dbus::Response> Manager::OnGetDevices(
510 dbus::MethodCall* method_call) {
511 std::unique_ptr<dbus::Response> dbus_response(
512 dbus::Response::FromMethodCall(method_call));
513
514 dbus::MessageReader reader(method_call);
515 dbus::MessageWriter writer(dbus_response.get());
516
517 patchpanel::GetDevicesRequest request;
518 patchpanel::GetDevicesResponse response;
519
520 if (!reader.PopArrayOfBytesAsProto(&request)) {
521 LOG(ERROR) << "Unable to parse request";
522 writer.AppendProtoAsArrayOfBytes(response);
523 return dbus_response;
524 }
525
526 static const auto arc_guest_type =
527 USE_ARCVM ? NetworkDevice::ARCVM : NetworkDevice::ARC;
528
529 arc_svc_->ScanDevices(base::BindRepeating(
530 [](patchpanel::GetDevicesResponse* resp, const Device& device) {
531 auto* dev = resp->add_devices();
532 dev->set_ifname(device.host_ifname());
Garrick Evans9ccd2a62021-02-18 14:48:28 +0900533 dev->set_phys_ifname(device.phys_ifname());
Garrick Evans02e6e872020-11-30 11:53:13 +0900534 dev->set_ipv4_addr(device.config().guest_ipv4_addr());
535 dev->set_guest_type(arc_guest_type);
536 if (const auto* subnet = device.config().ipv4_subnet()) {
537 auto* sub = dev->mutable_ipv4_subnet();
538 sub->set_base_addr(subnet->BaseAddress());
539 sub->set_prefix_len(subnet->PrefixLength());
540 }
541 },
542 &response));
543
544 cros_svc_->ScanDevices(base::BindRepeating(
545 [](patchpanel::GetDevicesResponse* resp, uint64_t vm_id, bool is_termina,
546 const Device& device) {
547 auto* dev = resp->add_devices();
548 dev->set_ifname(device.host_ifname());
Garrick Evans9ccd2a62021-02-18 14:48:28 +0900549 dev->set_phys_ifname(device.phys_ifname());
Garrick Evans02e6e872020-11-30 11:53:13 +0900550 dev->set_ipv4_addr(device.config().guest_ipv4_addr());
551 dev->set_guest_type(is_termina ? NetworkDevice::TERMINA_VM
552 : NetworkDevice::PLUGIN_VM);
553 if (const auto* subnet = device.config().ipv4_subnet()) {
554 auto* sub = dev->mutable_ipv4_subnet();
555 sub->set_base_addr(subnet->BaseAddress());
556 sub->set_prefix_len(subnet->PrefixLength());
557 }
558 },
559 &response));
560
561 writer.AppendProtoAsArrayOfBytes(response);
562 return dbus_response;
563}
564
Garrick Evans08843932019-09-17 14:41:08 +0900565std::unique_ptr<dbus::Response> Manager::OnArcStartup(
566 dbus::MethodCall* method_call) {
567 LOG(INFO) << "ARC++ starting up";
568
569 std::unique_ptr<dbus::Response> dbus_response(
570 dbus::Response::FromMethodCall(method_call));
571
572 dbus::MessageReader reader(method_call);
573 dbus::MessageWriter writer(dbus_response.get());
574
575 patchpanel::ArcStartupRequest request;
576 patchpanel::ArcStartupResponse response;
577
578 if (!reader.PopArrayOfBytesAsProto(&request)) {
579 LOG(ERROR) << "Unable to parse request";
580 writer.AppendProtoAsArrayOfBytes(response);
581 return dbus_response;
582 }
583
Garrick Evanse01bf072019-11-15 09:08:19 +0900584 if (!StartArc(request.pid()))
585 LOG(ERROR) << "Failed to start ARC++ network service";
Garrick Evanse94a14e2019-11-11 10:32:13 +0900586
Garrick Evans08843932019-09-17 14:41:08 +0900587 writer.AppendProtoAsArrayOfBytes(response);
588 return dbus_response;
589}
590
591std::unique_ptr<dbus::Response> Manager::OnArcShutdown(
592 dbus::MethodCall* method_call) {
593 LOG(INFO) << "ARC++ shutting down";
594
595 std::unique_ptr<dbus::Response> dbus_response(
596 dbus::Response::FromMethodCall(method_call));
597
598 dbus::MessageReader reader(method_call);
599 dbus::MessageWriter writer(dbus_response.get());
600
601 patchpanel::ArcShutdownRequest request;
602 patchpanel::ArcShutdownResponse response;
603
604 if (!reader.PopArrayOfBytesAsProto(&request)) {
605 LOG(ERROR) << "Unable to parse request";
606 writer.AppendProtoAsArrayOfBytes(response);
607 return dbus_response;
608 }
609
Hugo Benichi4d4bb8f2020-07-07 12:16:07 +0900610 StopArc();
Garrick Evanse94a14e2019-11-11 10:32:13 +0900611
Garrick Evans08843932019-09-17 14:41:08 +0900612 writer.AppendProtoAsArrayOfBytes(response);
613 return dbus_response;
614}
615
616std::unique_ptr<dbus::Response> Manager::OnArcVmStartup(
617 dbus::MethodCall* method_call) {
618 LOG(INFO) << "ARCVM starting up";
619
620 std::unique_ptr<dbus::Response> dbus_response(
621 dbus::Response::FromMethodCall(method_call));
622
623 dbus::MessageReader reader(method_call);
624 dbus::MessageWriter writer(dbus_response.get());
625
626 patchpanel::ArcVmStartupRequest request;
627 patchpanel::ArcVmStartupResponse response;
628
629 if (!reader.PopArrayOfBytesAsProto(&request)) {
630 LOG(ERROR) << "Unable to parse request";
631 writer.AppendProtoAsArrayOfBytes(response);
632 return dbus_response;
633 }
634
Garrick Evans47c19272019-11-21 10:58:21 +0900635 if (!StartArcVm(request.cid())) {
Garrick Evanse01bf072019-11-15 09:08:19 +0900636 LOG(ERROR) << "Failed to start ARCVM network service";
Garrick Evans47c19272019-11-21 10:58:21 +0900637 writer.AppendProtoAsArrayOfBytes(response);
638 return dbus_response;
Garrick Evanse01bf072019-11-15 09:08:19 +0900639 }
Garrick Evanse94a14e2019-11-11 10:32:13 +0900640
Garrick Evans47c19272019-11-21 10:58:21 +0900641 // Populate the response with the known devices.
Garrick Evans38b25a42020-04-06 15:17:42 +0900642 for (const auto* config : arc_svc_->GetDeviceConfigs()) {
643 if (config->tap_ifname().empty())
644 continue;
Garrick Evans47c19272019-11-21 10:58:21 +0900645
Garrick Evans38b25a42020-04-06 15:17:42 +0900646 auto* dev = response.add_devices();
647 dev->set_ifname(config->tap_ifname());
648 dev->set_ipv4_addr(config->guest_ipv4_addr());
Garrick Evansa0c9c972020-11-30 09:54:59 +0900649 dev->set_guest_type(NetworkDevice::ARCVM);
Garrick Evans38b25a42020-04-06 15:17:42 +0900650 }
Garrick Evanse94b6de2020-02-20 09:19:13 +0900651
Garrick Evans08843932019-09-17 14:41:08 +0900652 writer.AppendProtoAsArrayOfBytes(response);
653 return dbus_response;
654}
655
656std::unique_ptr<dbus::Response> Manager::OnArcVmShutdown(
657 dbus::MethodCall* method_call) {
658 LOG(INFO) << "ARCVM shutting down";
659
660 std::unique_ptr<dbus::Response> dbus_response(
661 dbus::Response::FromMethodCall(method_call));
662
663 dbus::MessageReader reader(method_call);
664 dbus::MessageWriter writer(dbus_response.get());
665
666 patchpanel::ArcVmShutdownRequest request;
667 patchpanel::ArcVmShutdownResponse response;
668
669 if (!reader.PopArrayOfBytesAsProto(&request)) {
670 LOG(ERROR) << "Unable to parse request";
671 writer.AppendProtoAsArrayOfBytes(response);
672 return dbus_response;
673 }
674
Garrick Evans21173b12019-11-20 15:23:16 +0900675 StopArcVm(request.cid());
Garrick Evanse94a14e2019-11-11 10:32:13 +0900676
Garrick Evans08843932019-09-17 14:41:08 +0900677 writer.AppendProtoAsArrayOfBytes(response);
678 return dbus_response;
679}
680
Garrick Evans47c19272019-11-21 10:58:21 +0900681std::unique_ptr<dbus::Response> Manager::OnTerminaVmStartup(
682 dbus::MethodCall* method_call) {
683 LOG(INFO) << "Termina VM starting up";
684
685 std::unique_ptr<dbus::Response> dbus_response(
686 dbus::Response::FromMethodCall(method_call));
687
688 dbus::MessageReader reader(method_call);
689 dbus::MessageWriter writer(dbus_response.get());
690
691 patchpanel::TerminaVmStartupRequest request;
692 patchpanel::TerminaVmStartupResponse response;
693
694 if (!reader.PopArrayOfBytesAsProto(&request)) {
695 LOG(ERROR) << "Unable to parse request";
696 writer.AppendProtoAsArrayOfBytes(response);
697 return dbus_response;
698 }
699
700 const int32_t cid = request.cid();
Garrick Evans53a2a982020-02-05 10:53:35 +0900701 if (!StartCrosVm(cid, GuestMessage::TERMINA_VM)) {
Garrick Evans47c19272019-11-21 10:58:21 +0900702 LOG(ERROR) << "Failed to start Termina VM network service";
703 writer.AppendProtoAsArrayOfBytes(response);
704 return dbus_response;
705 }
706
Garrick Evans51d5b552020-01-30 10:42:06 +0900707 const auto* const tap = cros_svc_->TAP(cid, true /*is_termina*/);
Garrick Evansb1c93712020-01-22 09:28:25 +0900708 if (!tap) {
709 LOG(DFATAL) << "TAP device missing";
710 writer.AppendProtoAsArrayOfBytes(response);
711 return dbus_response;
712 }
Garrick Evans47c19272019-11-21 10:58:21 +0900713
Garrick Evansb1c93712020-01-22 09:28:25 +0900714 auto* dev = response.mutable_device();
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900715 dev->set_ifname(tap->host_ifname());
Garrick Evansa0c9c972020-11-30 09:54:59 +0900716 dev->set_guest_type(NetworkDevice::TERMINA_VM);
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900717 const auto* subnet = tap->config().ipv4_subnet();
Garrick Evansb1c93712020-01-22 09:28:25 +0900718 if (!subnet) {
719 LOG(DFATAL) << "Missing required subnet for {cid: " << cid << "}";
720 writer.AppendProtoAsArrayOfBytes(response);
721 return dbus_response;
722 }
723 auto* resp_subnet = dev->mutable_ipv4_subnet();
724 resp_subnet->set_base_addr(subnet->BaseAddress());
725 resp_subnet->set_prefix_len(subnet->PrefixLength());
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900726 subnet = tap->config().lxd_ipv4_subnet();
Garrick Evansb1c93712020-01-22 09:28:25 +0900727 if (!subnet) {
728 LOG(DFATAL) << "Missing required lxd subnet for {cid: " << cid << "}";
729 writer.AppendProtoAsArrayOfBytes(response);
730 return dbus_response;
731 }
732 resp_subnet = response.mutable_container_subnet();
733 resp_subnet->set_base_addr(subnet->BaseAddress());
734 resp_subnet->set_prefix_len(subnet->PrefixLength());
Garrick Evans47c19272019-11-21 10:58:21 +0900735
736 writer.AppendProtoAsArrayOfBytes(response);
737 return dbus_response;
738}
739
740std::unique_ptr<dbus::Response> Manager::OnTerminaVmShutdown(
741 dbus::MethodCall* method_call) {
742 LOG(INFO) << "Termina VM shutting down";
743
744 std::unique_ptr<dbus::Response> dbus_response(
745 dbus::Response::FromMethodCall(method_call));
746
747 dbus::MessageReader reader(method_call);
748 dbus::MessageWriter writer(dbus_response.get());
749
750 patchpanel::TerminaVmShutdownRequest request;
751 patchpanel::TerminaVmShutdownResponse response;
752
753 if (!reader.PopArrayOfBytesAsProto(&request)) {
754 LOG(ERROR) << "Unable to parse request";
755 writer.AppendProtoAsArrayOfBytes(response);
756 return dbus_response;
757 }
758
Garrick Evans51d5b552020-01-30 10:42:06 +0900759 StopCrosVm(request.cid(), GuestMessage::TERMINA_VM);
760
761 writer.AppendProtoAsArrayOfBytes(response);
762 return dbus_response;
763}
764
765std::unique_ptr<dbus::Response> Manager::OnPluginVmStartup(
766 dbus::MethodCall* method_call) {
767 LOG(INFO) << "Plugin VM starting up";
768
769 std::unique_ptr<dbus::Response> dbus_response(
770 dbus::Response::FromMethodCall(method_call));
771
772 dbus::MessageReader reader(method_call);
773 dbus::MessageWriter writer(dbus_response.get());
774
775 patchpanel::PluginVmStartupRequest request;
776 patchpanel::PluginVmStartupResponse response;
777
778 if (!reader.PopArrayOfBytesAsProto(&request)) {
779 LOG(ERROR) << "Unable to parse request";
780 writer.AppendProtoAsArrayOfBytes(response);
781 return dbus_response;
782 }
783
Garrick Evans08fb34b2020-02-20 10:50:17 +0900784 const uint64_t vm_id = request.id();
Garrick Evans53a2a982020-02-05 10:53:35 +0900785 if (!StartCrosVm(vm_id, GuestMessage::PLUGIN_VM, request.subnet_index())) {
Garrick Evans51d5b552020-01-30 10:42:06 +0900786 LOG(ERROR) << "Failed to start Plugin VM network service";
787 writer.AppendProtoAsArrayOfBytes(response);
788 return dbus_response;
789 }
790
791 const auto* const tap = cros_svc_->TAP(vm_id, false /*is_termina*/);
792 if (!tap) {
793 LOG(DFATAL) << "TAP device missing";
794 writer.AppendProtoAsArrayOfBytes(response);
795 return dbus_response;
796 }
797
Garrick Evans51d5b552020-01-30 10:42:06 +0900798 auto* dev = response.mutable_device();
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900799 dev->set_ifname(tap->host_ifname());
Garrick Evansa0c9c972020-11-30 09:54:59 +0900800 dev->set_guest_type(NetworkDevice::PLUGIN_VM);
Garrick Evans6c7dcb82020-03-16 15:21:05 +0900801 const auto* subnet = tap->config().ipv4_subnet();
Garrick Evans51d5b552020-01-30 10:42:06 +0900802 if (!subnet) {
803 LOG(DFATAL) << "Missing required subnet for {cid: " << vm_id << "}";
804 writer.AppendProtoAsArrayOfBytes(response);
805 return dbus_response;
806 }
807 auto* resp_subnet = dev->mutable_ipv4_subnet();
808 resp_subnet->set_base_addr(subnet->BaseAddress());
809 resp_subnet->set_prefix_len(subnet->PrefixLength());
810
811 writer.AppendProtoAsArrayOfBytes(response);
812 return dbus_response;
813}
814
815std::unique_ptr<dbus::Response> Manager::OnPluginVmShutdown(
816 dbus::MethodCall* method_call) {
817 LOG(INFO) << "Plugin VM shutting down";
818
819 std::unique_ptr<dbus::Response> dbus_response(
820 dbus::Response::FromMethodCall(method_call));
821
822 dbus::MessageReader reader(method_call);
823 dbus::MessageWriter writer(dbus_response.get());
824
825 patchpanel::PluginVmShutdownRequest request;
826 patchpanel::PluginVmShutdownResponse response;
827
828 if (!reader.PopArrayOfBytesAsProto(&request)) {
829 LOG(ERROR) << "Unable to parse request";
830 writer.AppendProtoAsArrayOfBytes(response);
831 return dbus_response;
832 }
833
834 StopCrosVm(request.id(), GuestMessage::PLUGIN_VM);
Garrick Evans47c19272019-11-21 10:58:21 +0900835
836 writer.AppendProtoAsArrayOfBytes(response);
837 return dbus_response;
838}
839
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900840std::unique_ptr<dbus::Response> Manager::OnSetVpnIntent(
841 dbus::MethodCall* method_call) {
842 std::unique_ptr<dbus::Response> dbus_response(
843 dbus::Response::FromMethodCall(method_call));
844
845 dbus::MessageReader reader(method_call);
846 dbus::MessageWriter writer(dbus_response.get());
847
848 patchpanel::SetVpnIntentRequest request;
849 patchpanel::SetVpnIntentResponse response;
850
851 bool success = reader.PopArrayOfBytesAsProto(&request);
852 if (!success) {
853 LOG(ERROR) << "Unable to parse SetVpnIntentRequest";
854 // Do not return yet to make sure we close the received fd.
855 }
856
857 base::ScopedFD client_socket;
858 reader.PopFileDescriptor(&client_socket);
859
860 if (success)
861 success = routing_svc_->SetVpnFwmark(client_socket.get(), request.policy());
862
863 response.set_success(success);
Hugo Benichib56b77c2020-01-15 16:00:56 +0900864
865 writer.AppendProtoAsArrayOfBytes(response);
866 return dbus_response;
867}
868
869std::unique_ptr<dbus::Response> Manager::OnConnectNamespace(
870 dbus::MethodCall* method_call) {
871 std::unique_ptr<dbus::Response> dbus_response(
872 dbus::Response::FromMethodCall(method_call));
873
874 dbus::MessageReader reader(method_call);
875 dbus::MessageWriter writer(dbus_response.get());
876
877 patchpanel::ConnectNamespaceRequest request;
Hugo Benichib56b77c2020-01-15 16:00:56 +0900878
879 if (!reader.PopArrayOfBytesAsProto(&request)) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900880 LOG(ERROR) << "Unable to parse ConnectNamespaceRequest";
881 // Do not return yet to make sure we close the received fd and
882 // validate other arguments.
Hugo Benichi7c342672020-09-08 09:18:14 +0900883 writer.AppendProtoAsArrayOfBytes(patchpanel::ConnectNamespaceResponse());
884 return dbus_response;
Hugo Benichib56b77c2020-01-15 16:00:56 +0900885 }
886
Hugo Benichicc6850f2020-01-17 13:26:06 +0900887 base::ScopedFD client_fd;
888 reader.PopFileDescriptor(&client_fd);
889 if (!client_fd.is_valid()) {
890 LOG(ERROR) << "ConnectNamespaceRequest: invalid file descriptor";
Hugo Benichi7c342672020-09-08 09:18:14 +0900891 writer.AppendProtoAsArrayOfBytes(patchpanel::ConnectNamespaceResponse());
892 return dbus_response;
Hugo Benichicc6850f2020-01-17 13:26:06 +0900893 }
894
895 pid_t pid = request.pid();
Garrick Evans263bd952020-12-03 20:27:43 +0900896 if (pid == 1 || pid == getpid()) {
897 LOG(ERROR) << "ConnectNamespaceRequest: privileged namespace pid " << pid;
898 writer.AppendProtoAsArrayOfBytes(patchpanel::ConnectNamespaceResponse());
899 return dbus_response;
900 }
Hugo Benichicc6850f2020-01-17 13:26:06 +0900901 {
Hugo Benichi0781d402021-02-22 13:43:11 +0900902 ScopedNS ns(pid, ScopedNS::Type::Network);
Hugo Benichicc6850f2020-01-17 13:26:06 +0900903 if (!ns.IsValid()) {
904 LOG(ERROR) << "ConnectNamespaceRequest: invalid namespace pid " << pid;
Hugo Benichi7c342672020-09-08 09:18:14 +0900905 writer.AppendProtoAsArrayOfBytes(patchpanel::ConnectNamespaceResponse());
906 return dbus_response;
Hugo Benichicc6850f2020-01-17 13:26:06 +0900907 }
908 }
909
910 const std::string& outbound_ifname = request.outbound_physical_device();
911 if (!outbound_ifname.empty() && !shill_client_->has_device(outbound_ifname)) {
912 LOG(ERROR) << "ConnectNamespaceRequest: invalid outbound ifname "
913 << outbound_ifname;
Hugo Benichi7c342672020-09-08 09:18:14 +0900914 writer.AppendProtoAsArrayOfBytes(patchpanel::ConnectNamespaceResponse());
915 return dbus_response;
Hugo Benichicc6850f2020-01-17 13:26:06 +0900916 }
917
Hugo Benichi7c342672020-09-08 09:18:14 +0900918 auto response = ConnectNamespace(std::move(client_fd), request);
919 writer.AppendProtoAsArrayOfBytes(*response);
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900920 return dbus_response;
921}
922
Jie Jiang493cde42020-07-17 21:43:39 +0900923std::unique_ptr<dbus::Response> Manager::OnGetTrafficCounters(
924 dbus::MethodCall* method_call) {
925 std::unique_ptr<dbus::Response> dbus_response(
926 dbus::Response::FromMethodCall(method_call));
927
928 dbus::MessageReader reader(method_call);
929 dbus::MessageWriter writer(dbus_response.get());
930
931 patchpanel::TrafficCountersRequest request;
932 patchpanel::TrafficCountersResponse response;
933
934 if (!reader.PopArrayOfBytesAsProto(&request)) {
935 LOG(ERROR) << "Unable to parse TrafficCountersRequest";
936 writer.AppendProtoAsArrayOfBytes(response);
937 return dbus_response;
938 }
939
940 const std::set<std::string> devices{request.devices().begin(),
941 request.devices().end()};
942 const auto counters = counters_svc_->GetCounters(devices);
943 for (const auto& kv : counters) {
944 auto* traffic_counter = response.add_counters();
945 const auto& source_and_device = kv.first;
946 const auto& counter = kv.second;
947 traffic_counter->set_source(source_and_device.first);
948 traffic_counter->set_device(source_and_device.second);
949 traffic_counter->set_rx_bytes(counter.rx_bytes);
950 traffic_counter->set_rx_packets(counter.rx_packets);
951 traffic_counter->set_tx_bytes(counter.tx_bytes);
952 traffic_counter->set_tx_packets(counter.tx_packets);
953 }
954
955 writer.AppendProtoAsArrayOfBytes(response);
956 return dbus_response;
957}
958
Jason Jeremy Imanb2a421e2020-07-04 20:48:32 +0900959std::unique_ptr<dbus::Response> Manager::OnModifyPortRule(
960 dbus::MethodCall* method_call) {
961 std::unique_ptr<dbus::Response> dbus_response(
962 dbus::Response::FromMethodCall(method_call));
963
964 dbus::MessageReader reader(method_call);
965 dbus::MessageWriter writer(dbus_response.get());
966
967 patchpanel::ModifyPortRuleRequest request;
968 patchpanel::ModifyPortRuleResponse response;
969
970 if (!reader.PopArrayOfBytesAsProto(&request)) {
971 LOG(ERROR) << "Unable to parse ModifyPortRequest";
972 writer.AppendProtoAsArrayOfBytes(response);
973 return dbus_response;
974 }
975
Jason Jeremy Imanc28df852020-07-11 17:38:26 +0900976 response.set_success(ModifyPortRule(request));
Jason Jeremy Imanb2a421e2020-07-04 20:48:32 +0900977 writer.AppendProtoAsArrayOfBytes(response);
978 return dbus_response;
979}
980
Jie Jiang25c1b972020-11-12 15:42:53 +0900981void Manager::OnNeighborReachabilityEvent(
Jie Jiang84966852020-09-18 18:49:05 +0900982 int ifindex,
983 const shill::IPAddress& ip_addr,
984 NeighborLinkMonitor::NeighborRole role,
Jie Jiang25c1b972020-11-12 15:42:53 +0900985 NeighborReachabilityEventSignal::EventType event_type) {
Jie Jiang84966852020-09-18 18:49:05 +0900986 if (!ip_addr.IsValid()) {
987 LOG(DFATAL) << "ip_addr is not valid";
988 return;
989 }
990
Jie Jiang25c1b972020-11-12 15:42:53 +0900991 using SignalProto = NeighborReachabilityEventSignal;
Jie Jiang84966852020-09-18 18:49:05 +0900992 SignalProto proto;
993 proto.set_ifindex(ifindex);
994 proto.set_ip_addr(ip_addr.ToString());
Jie Jiang25c1b972020-11-12 15:42:53 +0900995 proto.set_type(event_type);
Jie Jiang84966852020-09-18 18:49:05 +0900996 switch (role) {
997 case NeighborLinkMonitor::NeighborRole::kGateway:
998 proto.set_role(SignalProto::GATEWAY);
999 break;
1000 case NeighborLinkMonitor::NeighborRole::kDNSServer:
1001 proto.set_role(SignalProto::DNS_SERVER);
1002 break;
1003 case NeighborLinkMonitor::NeighborRole::kGatewayAndDNSServer:
1004 proto.set_role(SignalProto::GATEWAY_AND_DNS_SERVER);
1005 break;
1006 default:
1007 NOTREACHED();
1008 }
1009
Jie Jiang25c1b972020-11-12 15:42:53 +09001010 dbus::Signal signal(kPatchPanelInterface, kNeighborReachabilityEventSignal);
Jie Jiang84966852020-09-18 18:49:05 +09001011 dbus::MessageWriter writer(&signal);
1012 if (!writer.AppendProtoAsArrayOfBytes(proto)) {
Jie Jiang25c1b972020-11-12 15:42:53 +09001013 LOG(ERROR) << "Failed to encode proto NeighborReachabilityEventSignal";
Jie Jiang84966852020-09-18 18:49:05 +09001014 return;
1015 }
1016
1017 dbus_svc_path_->SendSignal(&signal);
1018}
1019
Hugo Benichi7c342672020-09-08 09:18:14 +09001020std::unique_ptr<patchpanel::ConnectNamespaceResponse> Manager::ConnectNamespace(
Hugo Benichiadf1ec52020-01-17 16:23:58 +09001021 base::ScopedFD client_fd,
Hugo Benichi7c342672020-09-08 09:18:14 +09001022 const patchpanel::ConnectNamespaceRequest& request) {
1023 auto response = std::make_unique<patchpanel::ConnectNamespaceResponse>();
1024
Hugo Benichiadf1ec52020-01-17 16:23:58 +09001025 std::unique_ptr<Subnet> subnet =
1026 addr_mgr_.AllocateIPv4Subnet(AddressManager::Guest::MINIJAIL_NETNS);
1027 if (!subnet) {
Hugo Benichi7c342672020-09-08 09:18:14 +09001028 LOG(ERROR) << "ConnectNamespace: exhausted IPv4 subnet space";
1029 return response;
Hugo Benichie8758b52020-04-03 14:49:01 +09001030 }
Hugo Benichiadf1ec52020-01-17 16:23:58 +09001031
Hugo Benichi7352ad92020-04-07 16:11:59 +09001032 // Dup the client fd into our own: this guarantees that the fd number will
1033 // be stable and tied to the actual kernel resources used by the client.
1034 base::ScopedFD local_client_fd(dup(client_fd.get()));
1035 if (!local_client_fd.is_valid()) {
Hugo Benichi7c342672020-09-08 09:18:14 +09001036 PLOG(ERROR) << "ConnectNamespace: failed to dup() client fd";
1037 return response;
Hugo Benichi7352ad92020-04-07 16:11:59 +09001038 }
1039
Hugo Benichi7c342672020-09-08 09:18:14 +09001040 // Add the duped fd to the epoll watcher.
Hugo Benichi7352ad92020-04-07 16:11:59 +09001041 // TODO(hugobenichi) Find a way to reuse base::FileDescriptorWatcher for
1042 // listening to EPOLLHUP.
1043 struct epoll_event epevent;
1044 epevent.events = EPOLLIN; // EPOLLERR | EPOLLHUP are always waited for.
1045 epevent.data.fd = local_client_fd.get();
1046 if (epoll_ctl(connected_namespaces_epollfd_, EPOLL_CTL_ADD,
1047 local_client_fd.get(), &epevent) != 0) {
Hugo Benichi7c342672020-09-08 09:18:14 +09001048 PLOG(ERROR) << "ConnectNamespace: epoll_ctl(EPOLL_CTL_ADD) failed";
1049 return response;
Hugo Benichi7352ad92020-04-07 16:11:59 +09001050 }
1051
Hugo Benichi7c342672020-09-08 09:18:14 +09001052 const std::string ifname_id = std::to_string(connected_namespaces_next_id_);
Hugo Benichifcf81022020-12-04 11:01:37 +09001053 ConnectedNamespace nsinfo = {};
1054 nsinfo.pid = request.pid();
1055 nsinfo.netns_name = "connected_netns_" + ifname_id;
Hugo Benichi93306e52020-12-04 16:08:00 +09001056 nsinfo.source = ProtoToTrafficSource(request.traffic_source());
1057 if (nsinfo.source == TrafficSource::UNKNOWN)
1058 nsinfo.source = TrafficSource::SYSTEM;
Hugo Benichifcf81022020-12-04 11:01:37 +09001059 nsinfo.outbound_ifname = request.outbound_physical_device();
Hugo Benichi93306e52020-12-04 16:08:00 +09001060 nsinfo.route_on_vpn = request.route_on_vpn();
Hugo Benichifcf81022020-12-04 11:01:37 +09001061 nsinfo.host_ifname = "arc_ns" + ifname_id;
1062 nsinfo.peer_ifname = "veth" + ifname_id;
1063 nsinfo.peer_subnet = std::move(subnet);
1064 nsinfo.peer_mac_addr = addr_mgr_.GenerateMacAddress();
1065
1066 if (!datapath_->StartRoutingNamespace(nsinfo)) {
Hugo Benichi7c342672020-09-08 09:18:14 +09001067 LOG(ERROR) << "ConnectNamespace: failed to setup datapath";
1068 if (epoll_ctl(connected_namespaces_epollfd_, EPOLL_CTL_DEL,
1069 local_client_fd.get(), nullptr) != 0)
1070 PLOG(ERROR) << "ConnectNamespace: epoll_ctl(EPOLL_CTL_DEL) failed";
1071 return response;
1072 }
1073
Hugo Benichifcf81022020-12-04 11:01:37 +09001074 // Prepare the response before storing ConnectedNamespace.
1075 response->set_peer_ifname(nsinfo.peer_ifname);
1076 response->set_peer_ipv4_address(nsinfo.peer_subnet->AddressAtOffset(1));
1077 response->set_host_ifname(nsinfo.host_ifname);
1078 response->set_host_ipv4_address(nsinfo.peer_subnet->AddressAtOffset(0));
Hugo Benichi7c342672020-09-08 09:18:14 +09001079 auto* response_subnet = response->mutable_ipv4_subnet();
Hugo Benichifcf81022020-12-04 11:01:37 +09001080 response_subnet->set_base_addr(nsinfo.peer_subnet->BaseAddress());
1081 response_subnet->set_prefix_len(nsinfo.peer_subnet->PrefixLength());
Hugo Benichiadf1ec52020-01-17 16:23:58 +09001082
Hugo Benichifcf81022020-12-04 11:01:37 +09001083 LOG(INFO) << "Connected network namespace " << nsinfo;
1084
1085 // Store ConnectedNamespace
Hugo Benichiadf1ec52020-01-17 16:23:58 +09001086 connected_namespaces_next_id_++;
Hugo Benichi7352ad92020-04-07 16:11:59 +09001087 int fdkey = local_client_fd.release();
Hugo Benichifcf81022020-12-04 11:01:37 +09001088 connected_namespaces_.insert(std::make_pair(fdkey, std::move(nsinfo)));
Hugo Benichi7352ad92020-04-07 16:11:59 +09001089
1090 if (connected_namespaces_.size() == 1) {
1091 LOG(INFO) << "Starting ConnectNamespace client fds monitoring";
1092 CheckConnectedNamespaces();
1093 }
Hugo Benichi7c342672020-09-08 09:18:14 +09001094
1095 return response;
Hugo Benichiadf1ec52020-01-17 16:23:58 +09001096}
1097
1098void Manager::DisconnectNamespace(int client_fd) {
1099 auto it = connected_namespaces_.find(client_fd);
1100 if (it == connected_namespaces_.end()) {
Hugo Benichifcf81022020-12-04 11:01:37 +09001101 LOG(ERROR) << "No ConnectedNamespace found for client_fd " << client_fd;
Hugo Benichiadf1ec52020-01-17 16:23:58 +09001102 return;
1103 }
1104
Hugo Benichi7352ad92020-04-07 16:11:59 +09001105 // Remove the client fd dupe from the epoll watcher and close it.
1106 if (epoll_ctl(connected_namespaces_epollfd_, EPOLL_CTL_DEL, client_fd,
Hugo Benichie8758b52020-04-03 14:49:01 +09001107 nullptr) != 0)
Hugo Benichi7352ad92020-04-07 16:11:59 +09001108 PLOG(ERROR) << "DisconnectNamespace: epoll_ctl(EPOLL_CTL_DEL) failed";
Hugo Benichie8758b52020-04-03 14:49:01 +09001109 if (close(client_fd) < 0)
Hugo Benichi7352ad92020-04-07 16:11:59 +09001110 PLOG(ERROR) << "DisconnectNamespace: close(client_fd) failed";
Hugo Benichi7352ad92020-04-07 16:11:59 +09001111
Hugo Benichifcf81022020-12-04 11:01:37 +09001112 datapath_->StopRoutingNamespace(it->second);
Hugo Benichiadf1ec52020-01-17 16:23:58 +09001113 LOG(INFO) << "Disconnected network namespace " << it->second;
Hugo Benichiadf1ec52020-01-17 16:23:58 +09001114 // This release the allocated IPv4 subnet.
1115 connected_namespaces_.erase(it);
1116}
1117
Hugo Benichi7352ad92020-04-07 16:11:59 +09001118// TODO(hugobenichi) Generalize this check to all resources created by
1119// patchpanel on behalf of a remote client.
1120void Manager::CheckConnectedNamespaces() {
1121 int max_event = 10;
1122 struct epoll_event epevents[max_event];
1123 int nready = epoll_wait(connected_namespaces_epollfd_, epevents, max_event,
1124 0 /* do not block */);
1125 if (nready < 0)
1126 PLOG(ERROR) << "CheckConnectedNamespaces: epoll_wait(0) failed";
1127
1128 for (int i = 0; i < nready; i++)
1129 if (epevents[i].events & (EPOLLHUP | EPOLLERR))
1130 DisconnectNamespace(epevents[i].data.fd);
1131
1132 if (connected_namespaces_.empty()) {
1133 LOG(INFO) << "Stopping ConnectNamespace client fds monitoring";
1134 return;
1135 }
1136
Qijiang Fan2d7aeb42020-05-19 02:06:39 +09001137 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
Hugo Benichi7352ad92020-04-07 16:11:59 +09001138 FROM_HERE,
1139 base::Bind(&Manager::CheckConnectedNamespaces,
Hugo Benichie8758b52020-04-03 14:49:01 +09001140 weak_factory_.GetWeakPtr()),
Hugo Benichi7352ad92020-04-07 16:11:59 +09001141 kConnectNamespaceCheckInterval);
1142}
1143
Jason Jeremy Imanc28df852020-07-11 17:38:26 +09001144bool Manager::ModifyPortRule(const patchpanel::ModifyPortRuleRequest& request) {
1145 switch (request.proto()) {
1146 case patchpanel::ModifyPortRuleRequest::TCP:
1147 case patchpanel::ModifyPortRuleRequest::UDP:
1148 break;
1149 default:
1150 LOG(ERROR) << "Unknown protocol " << request.proto();
1151 return false;
1152 }
1153
1154 switch (request.op()) {
1155 case patchpanel::ModifyPortRuleRequest::CREATE:
1156 switch (request.type()) {
1157 case patchpanel::ModifyPortRuleRequest::ACCESS:
1158 return firewall_.AddAcceptRules(request.proto(),
1159 request.input_dst_port(),
1160 request.input_ifname());
1161 case patchpanel::ModifyPortRuleRequest::LOCKDOWN:
1162 return firewall_.AddLoopbackLockdownRules(request.proto(),
1163 request.input_dst_port());
1164 case patchpanel::ModifyPortRuleRequest::FORWARDING:
1165 return firewall_.AddIpv4ForwardRule(
1166 request.proto(), request.input_dst_ip(), request.input_dst_port(),
1167 request.input_ifname(), request.dst_ip(), request.dst_port());
1168 default:
1169 LOG(ERROR) << "Unknown port rule type " << request.type();
1170 return false;
1171 }
1172 case patchpanel::ModifyPortRuleRequest::DELETE:
1173 switch (request.type()) {
1174 case patchpanel::ModifyPortRuleRequest::ACCESS:
1175 return firewall_.DeleteAcceptRules(request.proto(),
1176 request.input_dst_port(),
1177 request.input_ifname());
1178 case patchpanel::ModifyPortRuleRequest::LOCKDOWN:
1179 return firewall_.DeleteLoopbackLockdownRules(
1180 request.proto(), request.input_dst_port());
1181 case patchpanel::ModifyPortRuleRequest::FORWARDING:
1182 return firewall_.DeleteIpv4ForwardRule(
1183 request.proto(), request.input_dst_ip(), request.input_dst_port(),
1184 request.input_ifname(), request.dst_ip(), request.dst_port());
1185 default:
1186 LOG(ERROR) << "Unknown port rule type " << request.type();
1187 return false;
1188 }
1189 default:
1190 LOG(ERROR) << "Unknown operation " << request.op();
1191 return false;
1192 }
1193}
1194
Garrick Evanse94a14e2019-11-11 10:32:13 +09001195void Manager::SendGuestMessage(const GuestMessage& msg) {
Garrick Evans96e03042019-05-28 14:30:52 +09001196 IpHelperMessage ipm;
1197 *ipm.mutable_guest_message() = msg;
Garrick Evans96e03042019-05-28 14:30:52 +09001198 adb_proxy_->SendMessage(ipm);
Garrick Evanse94a14e2019-11-11 10:32:13 +09001199 mcast_proxy_->SendMessage(ipm);
1200 nd_proxy_->SendMessage(ipm);
Garrick Evans96e03042019-05-28 14:30:52 +09001201}
1202
Garrick Evans4ac09852020-01-16 14:09:22 +09001203void Manager::StartForwarding(const std::string& ifname_physical,
1204 const std::string& ifname_virtual,
Garrick Evans4ac09852020-01-16 14:09:22 +09001205 bool ipv6,
1206 bool multicast) {
Taoyu Li7dca19a2020-03-16 16:27:07 +09001207 if (ifname_physical.empty() || ifname_virtual.empty())
Garrick Evans4ac09852020-01-16 14:09:22 +09001208 return;
1209
1210 IpHelperMessage ipm;
1211 DeviceMessage* msg = ipm.mutable_device_message();
1212 msg->set_dev_ifname(ifname_physical);
Garrick Evans4ac09852020-01-16 14:09:22 +09001213 msg->set_br_ifname(ifname_virtual);
1214
1215 if (ipv6) {
1216 LOG(INFO) << "Starting IPv6 forwarding from " << ifname_physical << " to "
1217 << ifname_virtual;
1218
1219 if (!datapath_->AddIPv6Forwarding(ifname_physical, ifname_virtual)) {
1220 LOG(ERROR) << "Failed to setup iptables forwarding rule for IPv6 from "
1221 << ifname_physical << " to " << ifname_virtual;
1222 }
1223 if (!datapath_->MaskInterfaceFlags(ifname_physical, IFF_ALLMULTI)) {
1224 LOG(WARNING) << "Failed to setup all multicast mode for interface "
1225 << ifname_physical;
1226 }
1227 if (!datapath_->MaskInterfaceFlags(ifname_virtual, IFF_ALLMULTI)) {
1228 LOG(WARNING) << "Failed to setup all multicast mode for interface "
1229 << ifname_virtual;
1230 }
1231 nd_proxy_->SendMessage(ipm);
1232 }
1233
1234 if (multicast) {
Hugo Benichi69c989d2021-03-01 00:23:39 +09001235 multicast_virtual_ifnames_.insert(ifname_virtual);
Garrick Evans4ac09852020-01-16 14:09:22 +09001236 LOG(INFO) << "Starting multicast forwarding from " << ifname_physical
1237 << " to " << ifname_virtual;
1238 mcast_proxy_->SendMessage(ipm);
1239 }
1240}
1241
1242void Manager::StopForwarding(const std::string& ifname_physical,
1243 const std::string& ifname_virtual,
1244 bool ipv6,
1245 bool multicast) {
1246 if (ifname_physical.empty())
1247 return;
1248
1249 IpHelperMessage ipm;
1250 DeviceMessage* msg = ipm.mutable_device_message();
1251 msg->set_dev_ifname(ifname_physical);
1252 msg->set_teardown(true);
Taoyu Li7dca19a2020-03-16 16:27:07 +09001253 if (!ifname_virtual.empty()) {
1254 msg->set_br_ifname(ifname_virtual);
1255 }
Garrick Evans4ac09852020-01-16 14:09:22 +09001256
1257 if (ipv6) {
Taoyu Li7dca19a2020-03-16 16:27:07 +09001258 if (ifname_virtual.empty()) {
1259 LOG(INFO) << "Stopping IPv6 forwarding on " << ifname_physical;
1260 } else {
1261 LOG(INFO) << "Stopping IPv6 forwarding from " << ifname_physical << " to "
1262 << ifname_virtual;
1263 datapath_->RemoveIPv6Forwarding(ifname_physical, ifname_virtual);
1264 }
Garrick Evans4ac09852020-01-16 14:09:22 +09001265 nd_proxy_->SendMessage(ipm);
1266 }
1267
1268 if (multicast) {
Hugo Benichi69c989d2021-03-01 00:23:39 +09001269 multicast_virtual_ifnames_.erase(ifname_virtual);
Taoyu Li7dca19a2020-03-16 16:27:07 +09001270 if (ifname_virtual.empty()) {
1271 LOG(INFO) << "Stopping multicast forwarding on " << ifname_physical;
1272 } else {
1273 LOG(INFO) << "Stopping multicast forwarding from " << ifname_physical
1274 << " to " << ifname_virtual;
1275 }
Garrick Evans4ac09852020-01-16 14:09:22 +09001276 mcast_proxy_->SendMessage(ipm);
1277 }
1278}
1279
Taoyu Lia0727dc2020-09-24 19:54:59 +09001280void Manager::OnNDProxyMessage(const NDProxyMessage& msg) {
1281 LOG_IF(DFATAL, msg.ifname().empty())
Garrick Evans4ac09852020-01-16 14:09:22 +09001282 << "Received DeviceMessage w/ empty dev_ifname";
Taoyu Lia0727dc2020-09-24 19:54:59 +09001283 switch (msg.type()) {
1284 case NDProxyMessage::ADD_ROUTE:
1285 if (!datapath_->AddIPv6HostRoute(msg.ifname(), msg.ip6addr(), 128)) {
1286 LOG(WARNING) << "Failed to setup the IPv6 route for interface "
1287 << msg.ifname() << ", addr " << msg.ip6addr();
1288 }
1289 break;
1290 case NDProxyMessage::ADD_ADDR:
1291 if (!datapath_->AddIPv6Address(msg.ifname(), msg.ip6addr())) {
1292 LOG(WARNING) << "Failed to setup the IPv6 address for interface "
1293 << msg.ifname() << ", addr " << msg.ip6addr();
1294 }
1295 break;
1296 case NDProxyMessage::DEL_ADDR:
1297 datapath_->RemoveIPv6Address(msg.ifname(), msg.ip6addr());
1298 break;
1299 default:
1300 LOG(ERROR) << "Unknown NDProxy event " << msg.type();
1301 NOTREACHED();
Garrick Evans4ac09852020-01-16 14:09:22 +09001302 }
1303}
1304
Garrick Evans3388a032020-03-24 11:25:55 +09001305} // namespace patchpanel