blob: 66a9a432a0fbc3a9af36221b7b5119d3aeac18dc [file] [log] [blame]
Garrick Evans08843932019-09-17 14:41:08 +09001// 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
Jason Jeremy Imanadffbcb2020-08-31 13:21:36 +09005#include "patchpanel/dbus/client.h"
Garrick Evans08843932019-09-17 14:41:08 +09006
Hugo Benichicc6850f2020-01-17 13:26:06 +09007#include <fcntl.h>
8
Jie Jiang0a70acf2020-10-02 11:57:32 +09009#include <base/bind.h>
Garrick Evans08843932019-09-17 14:41:08 +090010#include <base/logging.h>
11#include <chromeos/dbus/service_constants.h>
12#include <dbus/message.h>
13#include <dbus/object_path.h>
14
Garrick Evans3388a032020-03-24 11:25:55 +090015#include "patchpanel/net_util.h"
Hugo Benichicc6850f2020-01-17 13:26:06 +090016
Garrick Evans08843932019-09-17 14:41:08 +090017namespace patchpanel {
18
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +090019namespace {
20
21std::ostream& operator<<(std::ostream& stream,
22 const ModifyPortRuleRequest& request) {
23 stream << "{ operation: "
24 << ModifyPortRuleRequest::Operation_Name(request.op())
25 << ", rule type: "
26 << ModifyPortRuleRequest::RuleType_Name(request.type())
27 << ", protocol: "
28 << ModifyPortRuleRequest::Protocol_Name(request.proto());
29 if (!request.input_ifname().empty()) {
30 stream << ", input interface name: " << request.input_ifname();
31 }
32 if (!request.input_dst_ip().empty()) {
33 stream << ", input destination IP: " << request.input_dst_ip();
34 }
35 stream << ", input destination port: " << request.input_dst_port();
36 if (!request.dst_ip().empty()) {
37 stream << ", destination IP: " << request.dst_ip();
38 }
39 if (request.dst_port() != 0) {
40 stream << ", destination port: " << request.dst_port();
41 }
42 stream << " }";
43 return stream;
44}
45
Jie Jiang0a70acf2020-10-02 11:57:32 +090046void OnGetTrafficCountersDBusResponse(
47 Client::GetTrafficCountersCallback callback,
48 dbus::Response* dbus_response) {
49 if (!dbus_response) {
50 LOG(ERROR) << "Failed to send TrafficCountersRequest message to patchpanel "
51 "service";
52 std::move(callback).Run({});
53 return;
54 }
55
56 TrafficCountersResponse response;
57 dbus::MessageReader reader(dbus_response);
58 if (!reader.PopArrayOfBytesAsProto(&response)) {
59 LOG(ERROR) << "Failed to parse TrafficCountersResponse proto";
60 std::move(callback).Run({});
61 return;
62 }
63
64 std::move(callback).Run(
65 {response.counters().begin(), response.counters().end()});
66}
67
Jie Jiang25c1b972020-11-12 15:42:53 +090068void OnNeighborReachabilityEventSignal(
69 const Client::NeighborReachabilityEventHandler& handler,
Jie Jiange2e4c0b2020-09-16 18:48:43 +090070 dbus::Signal* signal) {
71 dbus::MessageReader reader(signal);
Jie Jiang25c1b972020-11-12 15:42:53 +090072 NeighborReachabilityEventSignal proto;
Jie Jiange2e4c0b2020-09-16 18:48:43 +090073 if (!reader.PopArrayOfBytesAsProto(&proto)) {
74 LOG(ERROR) << "Failed to parse NeighborConnectedStateChangedSignal proto";
75 return;
76 }
77
78 handler.Run(proto);
79}
80
81void OnSignalConnectedCallback(const std::string& interface_name,
82 const std::string& signal_name,
83 bool success) {
84 if (!success)
85 LOG(ERROR) << "Failed to connect to " << signal_name;
86}
87
Jie Jiang81c84db2020-09-29 17:40:16 +090088class ClientImpl : public Client {
89 public:
90 ClientImpl(const scoped_refptr<dbus::Bus>& bus, dbus::ObjectProxy* proxy)
91 : bus_(std::move(bus)), proxy_(proxy) {}
Qijiang Fan6bc59e12020-11-11 02:51:06 +090092 ClientImpl(const ClientImpl&) = delete;
93 ClientImpl& operator=(const ClientImpl&) = delete;
94
Jie Jiang81c84db2020-09-29 17:40:16 +090095 ~ClientImpl();
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +090096
Jie Jiang81c84db2020-09-29 17:40:16 +090097 bool NotifyArcStartup(pid_t pid) override;
98 bool NotifyArcShutdown() override;
Garrick Evans08843932019-09-17 14:41:08 +090099
Jie Jiang81c84db2020-09-29 17:40:16 +0900100 std::vector<NetworkDevice> NotifyArcVmStartup(uint32_t cid) override;
101 bool NotifyArcVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900102
Jie Jiang81c84db2020-09-29 17:40:16 +0900103 bool NotifyTerminaVmStartup(uint32_t cid,
104 NetworkDevice* device,
105 IPv4Subnet* container_subnet) override;
106 bool NotifyTerminaVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900107
Jie Jiang81c84db2020-09-29 17:40:16 +0900108 bool NotifyPluginVmStartup(uint64_t vm_id,
109 int subnet_index,
110 NetworkDevice* device) override;
111 bool NotifyPluginVmShutdown(uint64_t vm_id) override;
Garrick Evans93a83fc2020-03-31 15:16:55 +0900112
Jie Jiang81c84db2020-09-29 17:40:16 +0900113 bool DefaultVpnRouting(int socket) override;
114
115 bool RouteOnVpn(int socket) override;
116
117 bool BypassVpn(int socket) override;
118
119 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
120 ConnectNamespace(pid_t pid,
121 const std::string& outbound_ifname,
122 bool forward_user_traffic) override;
123
124 void GetTrafficCounters(const std::set<std::string>& devices,
125 GetTrafficCountersCallback callback) override;
126
127 bool ModifyPortRule(patchpanel::ModifyPortRuleRequest::Operation op,
128 patchpanel::ModifyPortRuleRequest::RuleType type,
129 patchpanel::ModifyPortRuleRequest::Protocol proto,
130 const std::string& input_ifname,
131 const std::string& input_dst_ip,
132 uint32_t input_dst_port,
133 const std::string& dst_ip,
134 uint32_t dst_port) override;
135
Garrick Evans9e637982020-11-30 11:59:27 +0900136 std::vector<NetworkDevice> GetDevices() override;
137
Jie Jiang25c1b972020-11-12 15:42:53 +0900138 void RegisterNeighborReachabilityEventHandler(
139 NeighborReachabilityEventHandler handler) override;
Jie Jiang81c84db2020-09-29 17:40:16 +0900140
141 private:
142 scoped_refptr<dbus::Bus> bus_;
143 dbus::ObjectProxy* proxy_ = nullptr; // owned by bus_
144
145 bool SendSetVpnIntentRequest(int socket,
146 SetVpnIntentRequest::VpnRoutingPolicy policy);
Jie Jiang81c84db2020-09-29 17:40:16 +0900147};
148
149ClientImpl::~ClientImpl() {
Garrick Evans93a83fc2020-03-31 15:16:55 +0900150 if (bus_)
151 bus_->ShutdownAndBlock();
Garrick Evans08843932019-09-17 14:41:08 +0900152}
153
Jie Jiang81c84db2020-09-29 17:40:16 +0900154bool ClientImpl::NotifyArcStartup(pid_t pid) {
Garrick Evans08843932019-09-17 14:41:08 +0900155 dbus::MethodCall method_call(kPatchPanelInterface, kArcStartupMethod);
156 dbus::MessageWriter writer(&method_call);
157
158 ArcStartupRequest request;
159 request.set_pid(static_cast<uint32_t>(pid));
160
161 if (!writer.AppendProtoAsArrayOfBytes(request)) {
162 LOG(ERROR) << "Failed to encode ArcStartupRequest proto";
163 return false;
164 }
165
166 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
167 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
168 if (!dbus_response) {
169 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
170 return false;
171 }
172
173 dbus::MessageReader reader(dbus_response.get());
174 ArcStartupResponse response;
175 if (!reader.PopArrayOfBytesAsProto(&response)) {
176 LOG(ERROR) << "Failed to parse response proto";
177 return false;
178 }
179
180 return true;
181}
182
Jie Jiang81c84db2020-09-29 17:40:16 +0900183bool ClientImpl::NotifyArcShutdown() {
Garrick Evans08843932019-09-17 14:41:08 +0900184 dbus::MethodCall method_call(kPatchPanelInterface, kArcShutdownMethod);
185 dbus::MessageWriter writer(&method_call);
186
187 ArcShutdownRequest request;
Garrick Evans08843932019-09-17 14:41:08 +0900188 if (!writer.AppendProtoAsArrayOfBytes(request)) {
189 LOG(ERROR) << "Failed to encode ArcShutdownRequest proto";
190 return false;
191 }
192
193 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
194 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
195 if (!dbus_response) {
196 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
197 return false;
198 }
199
200 dbus::MessageReader reader(dbus_response.get());
201 ArcShutdownResponse response;
202 if (!reader.PopArrayOfBytesAsProto(&response)) {
203 LOG(ERROR) << "Failed to parse response proto";
204 return false;
205 }
206
207 return true;
208}
209
Jie Jiang81c84db2020-09-29 17:40:16 +0900210std::vector<NetworkDevice> ClientImpl::NotifyArcVmStartup(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900211 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmStartupMethod);
212 dbus::MessageWriter writer(&method_call);
213
214 ArcVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900215 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900216
217 if (!writer.AppendProtoAsArrayOfBytes(request)) {
218 LOG(ERROR) << "Failed to encode ArcVmStartupRequest proto";
219 return {};
220 }
221
222 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
223 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
224 if (!dbus_response) {
225 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
226 return {};
227 }
228
229 dbus::MessageReader reader(dbus_response.get());
230 ArcVmStartupResponse response;
231 if (!reader.PopArrayOfBytesAsProto(&response)) {
232 LOG(ERROR) << "Failed to parse response proto";
233 return {};
234 }
235
Garrick Evans3388a032020-03-24 11:25:55 +0900236 std::vector<NetworkDevice> devices;
Garrick Evans08843932019-09-17 14:41:08 +0900237 for (const auto& d : response.devices()) {
238 devices.emplace_back(d);
239 }
240 return devices;
241}
242
Jie Jiang81c84db2020-09-29 17:40:16 +0900243bool ClientImpl::NotifyArcVmShutdown(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900244 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmShutdownMethod);
245 dbus::MessageWriter writer(&method_call);
246
247 ArcVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900248 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900249
250 if (!writer.AppendProtoAsArrayOfBytes(request)) {
251 LOG(ERROR) << "Failed to encode ArcVmShutdownRequest proto";
252 return false;
253 }
254
255 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
256 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
257 if (!dbus_response) {
258 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
259 return false;
260 }
261
262 dbus::MessageReader reader(dbus_response.get());
263 ArcVmShutdownResponse response;
264 if (!reader.PopArrayOfBytesAsProto(&response)) {
265 LOG(ERROR) << "Failed to parse response proto";
266 return false;
267 }
268
269 return true;
270}
271
Jie Jiang81c84db2020-09-29 17:40:16 +0900272bool ClientImpl::NotifyTerminaVmStartup(uint32_t cid,
273 NetworkDevice* device,
274 IPv4Subnet* container_subnet) {
Garrick Evans27b74032019-11-19 13:33:47 +0900275 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmStartupMethod);
276 dbus::MessageWriter writer(&method_call);
277
278 TerminaVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900279 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900280
281 if (!writer.AppendProtoAsArrayOfBytes(request)) {
282 LOG(ERROR) << "Failed to encode TerminaVmStartupRequest proto";
283 return false;
284 }
285
286 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
287 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
288 if (!dbus_response) {
289 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
290 return false;
291 }
292
293 dbus::MessageReader reader(dbus_response.get());
294 TerminaVmStartupResponse response;
295 if (!reader.PopArrayOfBytesAsProto(&response)) {
296 LOG(ERROR) << "Failed to parse response proto";
297 return false;
298 }
299
300 if (!response.has_device()) {
301 LOG(ERROR) << "No device found";
302 return false;
303 }
304 *device = response.device();
305
306 if (response.has_container_subnet()) {
307 *container_subnet = response.container_subnet();
308 } else {
309 LOG(WARNING) << "No container subnet found";
310 }
311
312 return true;
313}
314
Jie Jiang81c84db2020-09-29 17:40:16 +0900315bool ClientImpl::NotifyTerminaVmShutdown(uint32_t cid) {
Garrick Evans27b74032019-11-19 13:33:47 +0900316 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmShutdownMethod);
317 dbus::MessageWriter writer(&method_call);
318
319 TerminaVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900320 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900321
322 if (!writer.AppendProtoAsArrayOfBytes(request)) {
323 LOG(ERROR) << "Failed to encode TerminaVmShutdownRequest proto";
324 return false;
325 }
326
327 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
328 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
329 if (!dbus_response) {
330 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
331 return false;
332 }
333
334 dbus::MessageReader reader(dbus_response.get());
335 TerminaVmShutdownResponse response;
336 if (!reader.PopArrayOfBytesAsProto(&response)) {
337 LOG(ERROR) << "Failed to parse response proto";
338 return false;
339 }
340
341 return true;
342}
343
Jie Jiang81c84db2020-09-29 17:40:16 +0900344bool ClientImpl::NotifyPluginVmStartup(uint64_t vm_id,
345 int subnet_index,
346 NetworkDevice* device) {
Garrick Evans376f0672020-01-07 15:31:50 +0900347 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmStartupMethod);
348 dbus::MessageWriter writer(&method_call);
349
350 PluginVmStartupRequest request;
351 request.set_id(vm_id);
352 request.set_subnet_index(subnet_index);
353
354 if (!writer.AppendProtoAsArrayOfBytes(request)) {
355 LOG(ERROR) << "Failed to encode PluginVmStartupRequest proto";
356 return false;
357 }
358
359 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
360 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
361 if (!dbus_response) {
362 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
363 return false;
364 }
365
366 dbus::MessageReader reader(dbus_response.get());
367 PluginVmStartupResponse response;
368 if (!reader.PopArrayOfBytesAsProto(&response)) {
369 LOG(ERROR) << "Failed to parse response proto";
370 return false;
371 }
372
373 if (!response.has_device()) {
374 LOG(ERROR) << "No device found";
375 return false;
376 }
377 *device = response.device();
378
379 return true;
380}
381
Jie Jiang81c84db2020-09-29 17:40:16 +0900382bool ClientImpl::NotifyPluginVmShutdown(uint64_t vm_id) {
Garrick Evans376f0672020-01-07 15:31:50 +0900383 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmShutdownMethod);
384 dbus::MessageWriter writer(&method_call);
385
386 PluginVmShutdownRequest request;
387 request.set_id(vm_id);
388
389 if (!writer.AppendProtoAsArrayOfBytes(request)) {
390 LOG(ERROR) << "Failed to encode PluginVmShutdownRequest proto";
391 return false;
392 }
393
394 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
395 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
396 if (!dbus_response) {
397 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
398 return false;
399 }
400
401 dbus::MessageReader reader(dbus_response.get());
Garrick Evans9751a1e2020-02-20 11:02:10 +0900402 PluginVmShutdownResponse response;
Garrick Evans376f0672020-01-07 15:31:50 +0900403 if (!reader.PopArrayOfBytesAsProto(&response)) {
404 LOG(ERROR) << "Failed to parse response proto";
405 return false;
406 }
407
408 return true;
409}
410
Jie Jiang81c84db2020-09-29 17:40:16 +0900411bool ClientImpl::DefaultVpnRouting(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900412 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::DEFAULT_ROUTING);
413}
414
Jie Jiang81c84db2020-09-29 17:40:16 +0900415bool ClientImpl::RouteOnVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900416 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::ROUTE_ON_VPN);
417}
418
Jie Jiang81c84db2020-09-29 17:40:16 +0900419bool ClientImpl::BypassVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900420 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::BYPASS_VPN);
421}
422
Jie Jiang81c84db2020-09-29 17:40:16 +0900423bool ClientImpl::SendSetVpnIntentRequest(
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900424 int socket, SetVpnIntentRequest::VpnRoutingPolicy policy) {
425 dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnIntentMethod);
426 dbus::MessageWriter writer(&method_call);
427
428 SetVpnIntentRequest request;
429 SetVpnIntentResponse response;
430 request.set_policy(policy);
431
432 if (!writer.AppendProtoAsArrayOfBytes(request)) {
433 LOG(ERROR) << "Failed to encode SetVpnIntentRequest proto";
434 return false;
435 }
436 writer.AppendFileDescriptor(socket);
437
438 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
439 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
440 if (!dbus_response) {
441 LOG(ERROR)
442 << "Failed to send SetVpnIntentRequest message to patchpanel service";
443 return false;
444 }
445
446 dbus::MessageReader reader(dbus_response.get());
447 if (!reader.PopArrayOfBytesAsProto(&response)) {
448 LOG(ERROR) << "Failed to parse SetVpnIntentResponse proto";
449 return false;
450 }
451
452 if (!response.success()) {
453 LOG(ERROR) << "SetVpnIntentRequest failed";
454 return false;
455 }
456 return true;
457}
458
Hugo Benichicc6850f2020-01-17 13:26:06 +0900459std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
Jie Jiang81c84db2020-09-29 17:40:16 +0900460ClientImpl::ConnectNamespace(pid_t pid,
461 const std::string& outbound_ifname,
462 bool forward_user_traffic) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900463 // Prepare and serialize the request proto.
464 ConnectNamespaceRequest request;
465 request.set_pid(static_cast<int32_t>(pid));
466 request.set_outbound_physical_device(outbound_ifname);
467 request.set_allow_user_traffic(forward_user_traffic);
468
469 dbus::MethodCall method_call(kPatchPanelInterface, kConnectNamespaceMethod);
470 dbus::MessageWriter writer(&method_call);
471 if (!writer.AppendProtoAsArrayOfBytes(request)) {
472 LOG(ERROR) << "Failed to encode ConnectNamespaceRequest proto";
473 return {};
474 }
475
476 // Prepare an fd pair and append one fd directly after the serialized request.
477 int pipe_fds[2] = {-1, -1};
478 if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
479 PLOG(ERROR) << "Failed to create a pair of fds with pipe2()";
480 return {};
481 }
482 base::ScopedFD fd_local(pipe_fds[0]);
483 // MessageWriter::AppendFileDescriptor duplicates the fd, so use ScopeFD to
484 // make sure the original fd is closed eventually.
485 base::ScopedFD fd_remote(pipe_fds[1]);
486 writer.AppendFileDescriptor(pipe_fds[1]);
487
488 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
489 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
490 if (!dbus_response) {
491 LOG(ERROR) << "Failed to send ConnectNamespace message to patchpanel";
492 return {};
493 }
494
495 dbus::MessageReader reader(dbus_response.get());
496 ConnectNamespaceResponse response;
497 if (!reader.PopArrayOfBytesAsProto(&response)) {
498 LOG(ERROR) << "Failed to parse ConnectNamespaceResponse proto";
499 return {};
500 }
501
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900502 if (response.peer_ifname().empty() || response.host_ifname().empty()) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900503 LOG(ERROR) << "ConnectNamespace for netns pid " << pid << " failed";
504 return {};
505 }
506
Garrick Evans3388a032020-03-24 11:25:55 +0900507 std::string subnet_info = IPv4AddressToCidrString(
Hugo Benichicc6850f2020-01-17 13:26:06 +0900508 response.ipv4_subnet().base_addr(), response.ipv4_subnet().prefix_len());
509 LOG(INFO) << "ConnectNamespace for netns pid " << pid
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900510 << " succeeded: peer_ifname=" << response.peer_ifname()
511 << " peer_ipv4_address="
512 << IPv4AddressToString(response.peer_ipv4_address())
513 << " host_ifname=" << response.host_ifname()
514 << " host_ipv4_address="
515 << IPv4AddressToString(response.host_ipv4_address())
Hugo Benichicc6850f2020-01-17 13:26:06 +0900516 << " subnet=" << subnet_info;
517
518 return std::make_pair(std::move(fd_local), std::move(response));
519}
520
Jie Jiang81c84db2020-09-29 17:40:16 +0900521void ClientImpl::GetTrafficCounters(const std::set<std::string>& devices,
522 GetTrafficCountersCallback callback) {
Jie Jiange02d1202020-07-27 16:57:04 +0900523 dbus::MethodCall method_call(kPatchPanelInterface, kGetTrafficCountersMethod);
524 dbus::MessageWriter writer(&method_call);
525
526 TrafficCountersRequest request;
527 for (const auto& device : devices) {
528 request.add_devices(device);
529 }
530
531 if (!writer.AppendProtoAsArrayOfBytes(request)) {
532 LOG(ERROR) << "Failed to encode TrafficCountersRequest proto";
Jie Jiang0a70acf2020-10-02 11:57:32 +0900533 std::move(callback).Run({});
534 return;
Jie Jiange02d1202020-07-27 16:57:04 +0900535 }
536
Jie Jiang0a70acf2020-10-02 11:57:32 +0900537 proxy_->CallMethod(
538 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
539 base::BindOnce(&OnGetTrafficCountersDBusResponse, std::move(callback)));
Jie Jiange02d1202020-07-27 16:57:04 +0900540}
541
Jie Jiang81c84db2020-09-29 17:40:16 +0900542bool ClientImpl::ModifyPortRule(ModifyPortRuleRequest::Operation op,
543 ModifyPortRuleRequest::RuleType type,
544 ModifyPortRuleRequest::Protocol proto,
545 const std::string& input_ifname,
546 const std::string& input_dst_ip,
547 uint32_t input_dst_port,
548 const std::string& dst_ip,
549 uint32_t dst_port) {
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900550 dbus::MethodCall method_call(kPatchPanelInterface, kModifyPortRuleMethod);
551 dbus::MessageWriter writer(&method_call);
552
553 ModifyPortRuleRequest request;
554 ModifyPortRuleResponse response;
555
556 request.set_op(op);
557 request.set_type(type);
558 request.set_proto(proto);
559 request.set_input_ifname(input_ifname);
560 request.set_input_dst_ip(input_dst_ip);
561 request.set_input_dst_port(input_dst_port);
562 request.set_dst_ip(dst_ip);
563 request.set_dst_port(dst_port);
564
565 if (!writer.AppendProtoAsArrayOfBytes(request)) {
566 LOG(ERROR) << "Failed to encode ModifyPortRuleRequest proto " << request;
567 return false;
568 }
569
570 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
571 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
572 if (!dbus_response) {
573 LOG(ERROR)
574 << "Failed to send ModifyPortRuleRequest message to patchpanel service "
575 << request;
576 return false;
577 }
578
579 dbus::MessageReader reader(dbus_response.get());
580 if (!reader.PopArrayOfBytesAsProto(&response)) {
581 LOG(ERROR) << "Failed to parse ModifyPortRuleResponse proto " << request;
582 return false;
583 }
584
585 if (!response.success()) {
586 LOG(ERROR) << "ModifyPortRuleRequest failed " << request;
587 return false;
588 }
589 return true;
590}
591
Garrick Evans9e637982020-11-30 11:59:27 +0900592std::vector<NetworkDevice> ClientImpl::GetDevices() {
593 dbus::MethodCall method_call(kPatchPanelInterface, kGetDevicesMethod);
594 dbus::MessageWriter writer(&method_call);
595
596 GetDevicesRequest request;
597 if (!writer.AppendProtoAsArrayOfBytes(request)) {
598 LOG(ERROR) << "Failed to encode GetDevicesRequest proto";
599 return {};
600 }
601
602 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
603 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
604 if (!dbus_response) {
605 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
606 return {};
607 }
608
609 dbus::MessageReader reader(dbus_response.get());
610 GetDevicesResponse response;
611 if (!reader.PopArrayOfBytesAsProto(&response)) {
612 LOG(ERROR) << "Failed to parse response proto";
613 return {};
614 }
615
616 std::vector<NetworkDevice> devices;
617 for (const auto& d : response.devices()) {
618 devices.emplace_back(d);
619 }
620 return devices;
621}
622
Jie Jiang25c1b972020-11-12 15:42:53 +0900623void ClientImpl::RegisterNeighborReachabilityEventHandler(
624 NeighborReachabilityEventHandler handler) {
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900625 proxy_->ConnectToSignal(
Jie Jiang25c1b972020-11-12 15:42:53 +0900626 kPatchPanelInterface, kNeighborReachabilityEventSignal,
627 base::BindRepeating(OnNeighborReachabilityEventSignal, handler),
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900628 base::BindOnce(OnSignalConnectedCallback));
629}
630
Jie Jiang81c84db2020-09-29 17:40:16 +0900631} // namespace
632
633// static
634std::unique_ptr<Client> Client::New() {
635 dbus::Bus::Options opts;
636 opts.bus_type = dbus::Bus::SYSTEM;
637 scoped_refptr<dbus::Bus> bus(new dbus::Bus(std::move(opts)));
638
639 if (!bus->Connect()) {
640 LOG(ERROR) << "Failed to connect to system bus";
641 return nullptr;
642 }
643
644 dbus::ObjectProxy* proxy = bus->GetObjectProxy(
645 kPatchPanelServiceName, dbus::ObjectPath(kPatchPanelServicePath));
646 if (!proxy) {
647 LOG(ERROR) << "Unable to get dbus proxy for " << kPatchPanelServiceName;
648 return nullptr;
649 }
650
651 return std::make_unique<ClientImpl>(std::move(bus), proxy);
652}
653
654std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus,
655 dbus::ObjectProxy* proxy) {
656 return std::make_unique<ClientImpl>(std::move(bus), proxy);
657}
658
Garrick Evans08843932019-09-17 14:41:08 +0900659} // namespace patchpanel