blob: ff7d85ecfa4c181e58f1f0bf26ee552d30ce6e2d [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
Jie Jiang25c1b972020-11-12 15:42:53 +0900136 void RegisterNeighborReachabilityEventHandler(
137 NeighborReachabilityEventHandler handler) override;
Jie Jiang81c84db2020-09-29 17:40:16 +0900138
139 private:
140 scoped_refptr<dbus::Bus> bus_;
141 dbus::ObjectProxy* proxy_ = nullptr; // owned by bus_
142
143 bool SendSetVpnIntentRequest(int socket,
144 SetVpnIntentRequest::VpnRoutingPolicy policy);
Jie Jiang81c84db2020-09-29 17:40:16 +0900145};
146
147ClientImpl::~ClientImpl() {
Garrick Evans93a83fc2020-03-31 15:16:55 +0900148 if (bus_)
149 bus_->ShutdownAndBlock();
Garrick Evans08843932019-09-17 14:41:08 +0900150}
151
Jie Jiang81c84db2020-09-29 17:40:16 +0900152bool ClientImpl::NotifyArcStartup(pid_t pid) {
Garrick Evans08843932019-09-17 14:41:08 +0900153 dbus::MethodCall method_call(kPatchPanelInterface, kArcStartupMethod);
154 dbus::MessageWriter writer(&method_call);
155
156 ArcStartupRequest request;
157 request.set_pid(static_cast<uint32_t>(pid));
158
159 if (!writer.AppendProtoAsArrayOfBytes(request)) {
160 LOG(ERROR) << "Failed to encode ArcStartupRequest proto";
161 return false;
162 }
163
164 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
165 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
166 if (!dbus_response) {
167 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
168 return false;
169 }
170
171 dbus::MessageReader reader(dbus_response.get());
172 ArcStartupResponse response;
173 if (!reader.PopArrayOfBytesAsProto(&response)) {
174 LOG(ERROR) << "Failed to parse response proto";
175 return false;
176 }
177
178 return true;
179}
180
Jie Jiang81c84db2020-09-29 17:40:16 +0900181bool ClientImpl::NotifyArcShutdown() {
Garrick Evans08843932019-09-17 14:41:08 +0900182 dbus::MethodCall method_call(kPatchPanelInterface, kArcShutdownMethod);
183 dbus::MessageWriter writer(&method_call);
184
185 ArcShutdownRequest request;
Garrick Evans08843932019-09-17 14:41:08 +0900186 if (!writer.AppendProtoAsArrayOfBytes(request)) {
187 LOG(ERROR) << "Failed to encode ArcShutdownRequest proto";
188 return false;
189 }
190
191 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
192 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
193 if (!dbus_response) {
194 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
195 return false;
196 }
197
198 dbus::MessageReader reader(dbus_response.get());
199 ArcShutdownResponse response;
200 if (!reader.PopArrayOfBytesAsProto(&response)) {
201 LOG(ERROR) << "Failed to parse response proto";
202 return false;
203 }
204
205 return true;
206}
207
Jie Jiang81c84db2020-09-29 17:40:16 +0900208std::vector<NetworkDevice> ClientImpl::NotifyArcVmStartup(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900209 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmStartupMethod);
210 dbus::MessageWriter writer(&method_call);
211
212 ArcVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900213 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900214
215 if (!writer.AppendProtoAsArrayOfBytes(request)) {
216 LOG(ERROR) << "Failed to encode ArcVmStartupRequest proto";
217 return {};
218 }
219
220 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
221 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
222 if (!dbus_response) {
223 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
224 return {};
225 }
226
227 dbus::MessageReader reader(dbus_response.get());
228 ArcVmStartupResponse response;
229 if (!reader.PopArrayOfBytesAsProto(&response)) {
230 LOG(ERROR) << "Failed to parse response proto";
231 return {};
232 }
233
Garrick Evans3388a032020-03-24 11:25:55 +0900234 std::vector<NetworkDevice> devices;
Garrick Evans08843932019-09-17 14:41:08 +0900235 for (const auto& d : response.devices()) {
236 devices.emplace_back(d);
237 }
238 return devices;
239}
240
Jie Jiang81c84db2020-09-29 17:40:16 +0900241bool ClientImpl::NotifyArcVmShutdown(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900242 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmShutdownMethod);
243 dbus::MessageWriter writer(&method_call);
244
245 ArcVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900246 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900247
248 if (!writer.AppendProtoAsArrayOfBytes(request)) {
249 LOG(ERROR) << "Failed to encode ArcVmShutdownRequest proto";
250 return false;
251 }
252
253 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
254 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
255 if (!dbus_response) {
256 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
257 return false;
258 }
259
260 dbus::MessageReader reader(dbus_response.get());
261 ArcVmShutdownResponse response;
262 if (!reader.PopArrayOfBytesAsProto(&response)) {
263 LOG(ERROR) << "Failed to parse response proto";
264 return false;
265 }
266
267 return true;
268}
269
Jie Jiang81c84db2020-09-29 17:40:16 +0900270bool ClientImpl::NotifyTerminaVmStartup(uint32_t cid,
271 NetworkDevice* device,
272 IPv4Subnet* container_subnet) {
Garrick Evans27b74032019-11-19 13:33:47 +0900273 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmStartupMethod);
274 dbus::MessageWriter writer(&method_call);
275
276 TerminaVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900277 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900278
279 if (!writer.AppendProtoAsArrayOfBytes(request)) {
280 LOG(ERROR) << "Failed to encode TerminaVmStartupRequest proto";
281 return false;
282 }
283
284 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
285 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
286 if (!dbus_response) {
287 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
288 return false;
289 }
290
291 dbus::MessageReader reader(dbus_response.get());
292 TerminaVmStartupResponse response;
293 if (!reader.PopArrayOfBytesAsProto(&response)) {
294 LOG(ERROR) << "Failed to parse response proto";
295 return false;
296 }
297
298 if (!response.has_device()) {
299 LOG(ERROR) << "No device found";
300 return false;
301 }
302 *device = response.device();
303
304 if (response.has_container_subnet()) {
305 *container_subnet = response.container_subnet();
306 } else {
307 LOG(WARNING) << "No container subnet found";
308 }
309
310 return true;
311}
312
Jie Jiang81c84db2020-09-29 17:40:16 +0900313bool ClientImpl::NotifyTerminaVmShutdown(uint32_t cid) {
Garrick Evans27b74032019-11-19 13:33:47 +0900314 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmShutdownMethod);
315 dbus::MessageWriter writer(&method_call);
316
317 TerminaVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900318 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900319
320 if (!writer.AppendProtoAsArrayOfBytes(request)) {
321 LOG(ERROR) << "Failed to encode TerminaVmShutdownRequest proto";
322 return false;
323 }
324
325 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
326 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
327 if (!dbus_response) {
328 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
329 return false;
330 }
331
332 dbus::MessageReader reader(dbus_response.get());
333 TerminaVmShutdownResponse response;
334 if (!reader.PopArrayOfBytesAsProto(&response)) {
335 LOG(ERROR) << "Failed to parse response proto";
336 return false;
337 }
338
339 return true;
340}
341
Jie Jiang81c84db2020-09-29 17:40:16 +0900342bool ClientImpl::NotifyPluginVmStartup(uint64_t vm_id,
343 int subnet_index,
344 NetworkDevice* device) {
Garrick Evans376f0672020-01-07 15:31:50 +0900345 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmStartupMethod);
346 dbus::MessageWriter writer(&method_call);
347
348 PluginVmStartupRequest request;
349 request.set_id(vm_id);
350 request.set_subnet_index(subnet_index);
351
352 if (!writer.AppendProtoAsArrayOfBytes(request)) {
353 LOG(ERROR) << "Failed to encode PluginVmStartupRequest proto";
354 return false;
355 }
356
357 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
358 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
359 if (!dbus_response) {
360 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
361 return false;
362 }
363
364 dbus::MessageReader reader(dbus_response.get());
365 PluginVmStartupResponse response;
366 if (!reader.PopArrayOfBytesAsProto(&response)) {
367 LOG(ERROR) << "Failed to parse response proto";
368 return false;
369 }
370
371 if (!response.has_device()) {
372 LOG(ERROR) << "No device found";
373 return false;
374 }
375 *device = response.device();
376
377 return true;
378}
379
Jie Jiang81c84db2020-09-29 17:40:16 +0900380bool ClientImpl::NotifyPluginVmShutdown(uint64_t vm_id) {
Garrick Evans376f0672020-01-07 15:31:50 +0900381 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmShutdownMethod);
382 dbus::MessageWriter writer(&method_call);
383
384 PluginVmShutdownRequest request;
385 request.set_id(vm_id);
386
387 if (!writer.AppendProtoAsArrayOfBytes(request)) {
388 LOG(ERROR) << "Failed to encode PluginVmShutdownRequest proto";
389 return false;
390 }
391
392 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
393 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
394 if (!dbus_response) {
395 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
396 return false;
397 }
398
399 dbus::MessageReader reader(dbus_response.get());
Garrick Evans9751a1e2020-02-20 11:02:10 +0900400 PluginVmShutdownResponse response;
Garrick Evans376f0672020-01-07 15:31:50 +0900401 if (!reader.PopArrayOfBytesAsProto(&response)) {
402 LOG(ERROR) << "Failed to parse response proto";
403 return false;
404 }
405
406 return true;
407}
408
Jie Jiang81c84db2020-09-29 17:40:16 +0900409bool ClientImpl::DefaultVpnRouting(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900410 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::DEFAULT_ROUTING);
411}
412
Jie Jiang81c84db2020-09-29 17:40:16 +0900413bool ClientImpl::RouteOnVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900414 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::ROUTE_ON_VPN);
415}
416
Jie Jiang81c84db2020-09-29 17:40:16 +0900417bool ClientImpl::BypassVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900418 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::BYPASS_VPN);
419}
420
Jie Jiang81c84db2020-09-29 17:40:16 +0900421bool ClientImpl::SendSetVpnIntentRequest(
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900422 int socket, SetVpnIntentRequest::VpnRoutingPolicy policy) {
423 dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnIntentMethod);
424 dbus::MessageWriter writer(&method_call);
425
426 SetVpnIntentRequest request;
427 SetVpnIntentResponse response;
428 request.set_policy(policy);
429
430 if (!writer.AppendProtoAsArrayOfBytes(request)) {
431 LOG(ERROR) << "Failed to encode SetVpnIntentRequest proto";
432 return false;
433 }
434 writer.AppendFileDescriptor(socket);
435
436 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
437 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
438 if (!dbus_response) {
439 LOG(ERROR)
440 << "Failed to send SetVpnIntentRequest message to patchpanel service";
441 return false;
442 }
443
444 dbus::MessageReader reader(dbus_response.get());
445 if (!reader.PopArrayOfBytesAsProto(&response)) {
446 LOG(ERROR) << "Failed to parse SetVpnIntentResponse proto";
447 return false;
448 }
449
450 if (!response.success()) {
451 LOG(ERROR) << "SetVpnIntentRequest failed";
452 return false;
453 }
454 return true;
455}
456
Hugo Benichicc6850f2020-01-17 13:26:06 +0900457std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
Jie Jiang81c84db2020-09-29 17:40:16 +0900458ClientImpl::ConnectNamespace(pid_t pid,
459 const std::string& outbound_ifname,
460 bool forward_user_traffic) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900461 // Prepare and serialize the request proto.
462 ConnectNamespaceRequest request;
463 request.set_pid(static_cast<int32_t>(pid));
464 request.set_outbound_physical_device(outbound_ifname);
465 request.set_allow_user_traffic(forward_user_traffic);
466
467 dbus::MethodCall method_call(kPatchPanelInterface, kConnectNamespaceMethod);
468 dbus::MessageWriter writer(&method_call);
469 if (!writer.AppendProtoAsArrayOfBytes(request)) {
470 LOG(ERROR) << "Failed to encode ConnectNamespaceRequest proto";
471 return {};
472 }
473
474 // Prepare an fd pair and append one fd directly after the serialized request.
475 int pipe_fds[2] = {-1, -1};
476 if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
477 PLOG(ERROR) << "Failed to create a pair of fds with pipe2()";
478 return {};
479 }
480 base::ScopedFD fd_local(pipe_fds[0]);
481 // MessageWriter::AppendFileDescriptor duplicates the fd, so use ScopeFD to
482 // make sure the original fd is closed eventually.
483 base::ScopedFD fd_remote(pipe_fds[1]);
484 writer.AppendFileDescriptor(pipe_fds[1]);
485
486 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
487 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
488 if (!dbus_response) {
489 LOG(ERROR) << "Failed to send ConnectNamespace message to patchpanel";
490 return {};
491 }
492
493 dbus::MessageReader reader(dbus_response.get());
494 ConnectNamespaceResponse response;
495 if (!reader.PopArrayOfBytesAsProto(&response)) {
496 LOG(ERROR) << "Failed to parse ConnectNamespaceResponse proto";
497 return {};
498 }
499
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900500 if (response.peer_ifname().empty() || response.host_ifname().empty()) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900501 LOG(ERROR) << "ConnectNamespace for netns pid " << pid << " failed";
502 return {};
503 }
504
Garrick Evans3388a032020-03-24 11:25:55 +0900505 std::string subnet_info = IPv4AddressToCidrString(
Hugo Benichicc6850f2020-01-17 13:26:06 +0900506 response.ipv4_subnet().base_addr(), response.ipv4_subnet().prefix_len());
507 LOG(INFO) << "ConnectNamespace for netns pid " << pid
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900508 << " succeeded: peer_ifname=" << response.peer_ifname()
509 << " peer_ipv4_address="
510 << IPv4AddressToString(response.peer_ipv4_address())
511 << " host_ifname=" << response.host_ifname()
512 << " host_ipv4_address="
513 << IPv4AddressToString(response.host_ipv4_address())
Hugo Benichicc6850f2020-01-17 13:26:06 +0900514 << " subnet=" << subnet_info;
515
516 return std::make_pair(std::move(fd_local), std::move(response));
517}
518
Jie Jiang81c84db2020-09-29 17:40:16 +0900519void ClientImpl::GetTrafficCounters(const std::set<std::string>& devices,
520 GetTrafficCountersCallback callback) {
Jie Jiange02d1202020-07-27 16:57:04 +0900521 dbus::MethodCall method_call(kPatchPanelInterface, kGetTrafficCountersMethod);
522 dbus::MessageWriter writer(&method_call);
523
524 TrafficCountersRequest request;
525 for (const auto& device : devices) {
526 request.add_devices(device);
527 }
528
529 if (!writer.AppendProtoAsArrayOfBytes(request)) {
530 LOG(ERROR) << "Failed to encode TrafficCountersRequest proto";
Jie Jiang0a70acf2020-10-02 11:57:32 +0900531 std::move(callback).Run({});
532 return;
Jie Jiange02d1202020-07-27 16:57:04 +0900533 }
534
Jie Jiang0a70acf2020-10-02 11:57:32 +0900535 proxy_->CallMethod(
536 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
537 base::BindOnce(&OnGetTrafficCountersDBusResponse, std::move(callback)));
Jie Jiange02d1202020-07-27 16:57:04 +0900538}
539
Jie Jiang81c84db2020-09-29 17:40:16 +0900540bool ClientImpl::ModifyPortRule(ModifyPortRuleRequest::Operation op,
541 ModifyPortRuleRequest::RuleType type,
542 ModifyPortRuleRequest::Protocol proto,
543 const std::string& input_ifname,
544 const std::string& input_dst_ip,
545 uint32_t input_dst_port,
546 const std::string& dst_ip,
547 uint32_t dst_port) {
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900548 dbus::MethodCall method_call(kPatchPanelInterface, kModifyPortRuleMethod);
549 dbus::MessageWriter writer(&method_call);
550
551 ModifyPortRuleRequest request;
552 ModifyPortRuleResponse response;
553
554 request.set_op(op);
555 request.set_type(type);
556 request.set_proto(proto);
557 request.set_input_ifname(input_ifname);
558 request.set_input_dst_ip(input_dst_ip);
559 request.set_input_dst_port(input_dst_port);
560 request.set_dst_ip(dst_ip);
561 request.set_dst_port(dst_port);
562
563 if (!writer.AppendProtoAsArrayOfBytes(request)) {
564 LOG(ERROR) << "Failed to encode ModifyPortRuleRequest proto " << request;
565 return false;
566 }
567
568 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
569 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
570 if (!dbus_response) {
571 LOG(ERROR)
572 << "Failed to send ModifyPortRuleRequest message to patchpanel service "
573 << request;
574 return false;
575 }
576
577 dbus::MessageReader reader(dbus_response.get());
578 if (!reader.PopArrayOfBytesAsProto(&response)) {
579 LOG(ERROR) << "Failed to parse ModifyPortRuleResponse proto " << request;
580 return false;
581 }
582
583 if (!response.success()) {
584 LOG(ERROR) << "ModifyPortRuleRequest failed " << request;
585 return false;
586 }
587 return true;
588}
589
Jie Jiang25c1b972020-11-12 15:42:53 +0900590void ClientImpl::RegisterNeighborReachabilityEventHandler(
591 NeighborReachabilityEventHandler handler) {
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900592 proxy_->ConnectToSignal(
Jie Jiang25c1b972020-11-12 15:42:53 +0900593 kPatchPanelInterface, kNeighborReachabilityEventSignal,
594 base::BindRepeating(OnNeighborReachabilityEventSignal, handler),
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900595 base::BindOnce(OnSignalConnectedCallback));
596}
597
Jie Jiang81c84db2020-09-29 17:40:16 +0900598} // namespace
599
600// static
601std::unique_ptr<Client> Client::New() {
602 dbus::Bus::Options opts;
603 opts.bus_type = dbus::Bus::SYSTEM;
604 scoped_refptr<dbus::Bus> bus(new dbus::Bus(std::move(opts)));
605
606 if (!bus->Connect()) {
607 LOG(ERROR) << "Failed to connect to system bus";
608 return nullptr;
609 }
610
611 dbus::ObjectProxy* proxy = bus->GetObjectProxy(
612 kPatchPanelServiceName, dbus::ObjectPath(kPatchPanelServicePath));
613 if (!proxy) {
614 LOG(ERROR) << "Unable to get dbus proxy for " << kPatchPanelServiceName;
615 return nullptr;
616 }
617
618 return std::make_unique<ClientImpl>(std::move(bus), proxy);
619}
620
621std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus,
622 dbus::ObjectProxy* proxy) {
623 return std::make_unique<ClientImpl>(std::move(bus), proxy);
624}
625
Garrick Evans08843932019-09-17 14:41:08 +0900626} // namespace patchpanel