blob: b3c8cea3941dd72271942c7af56aebd82de6a09b [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
Garrick Evansf04f0442020-12-01 12:36:44 +090068void OnNetworkDeviceChangedSignal(
69 const Client::NetworkDeviceChangedSignalHandler& handler,
70 dbus::Signal* signal) {
71 dbus::MessageReader reader(signal);
72 NetworkDeviceChangedSignal proto;
73 if (!reader.PopArrayOfBytesAsProto(&proto)) {
74 LOG(ERROR) << "Failed to parse NetworkDeviceChangedSignal proto";
75 return;
76 }
77
78 handler.Run(proto);
79}
80
Jie Jiang25c1b972020-11-12 15:42:53 +090081void OnNeighborReachabilityEventSignal(
82 const Client::NeighborReachabilityEventHandler& handler,
Jie Jiange2e4c0b2020-09-16 18:48:43 +090083 dbus::Signal* signal) {
84 dbus::MessageReader reader(signal);
Jie Jiang25c1b972020-11-12 15:42:53 +090085 NeighborReachabilityEventSignal proto;
Jie Jiange2e4c0b2020-09-16 18:48:43 +090086 if (!reader.PopArrayOfBytesAsProto(&proto)) {
87 LOG(ERROR) << "Failed to parse NeighborConnectedStateChangedSignal proto";
88 return;
89 }
90
91 handler.Run(proto);
92}
93
94void OnSignalConnectedCallback(const std::string& interface_name,
95 const std::string& signal_name,
96 bool success) {
97 if (!success)
98 LOG(ERROR) << "Failed to connect to " << signal_name;
99}
100
Jie Jiang81c84db2020-09-29 17:40:16 +0900101class ClientImpl : public Client {
102 public:
103 ClientImpl(const scoped_refptr<dbus::Bus>& bus, dbus::ObjectProxy* proxy)
104 : bus_(std::move(bus)), proxy_(proxy) {}
Qijiang Fan6bc59e12020-11-11 02:51:06 +0900105 ClientImpl(const ClientImpl&) = delete;
106 ClientImpl& operator=(const ClientImpl&) = delete;
107
Jie Jiang81c84db2020-09-29 17:40:16 +0900108 ~ClientImpl();
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900109
Jie Jiang81c84db2020-09-29 17:40:16 +0900110 bool NotifyArcStartup(pid_t pid) override;
111 bool NotifyArcShutdown() override;
Garrick Evans08843932019-09-17 14:41:08 +0900112
Jie Jiang81c84db2020-09-29 17:40:16 +0900113 std::vector<NetworkDevice> NotifyArcVmStartup(uint32_t cid) override;
114 bool NotifyArcVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900115
Jie Jiang81c84db2020-09-29 17:40:16 +0900116 bool NotifyTerminaVmStartup(uint32_t cid,
117 NetworkDevice* device,
118 IPv4Subnet* container_subnet) override;
119 bool NotifyTerminaVmShutdown(uint32_t cid) override;
Garrick Evans08843932019-09-17 14:41:08 +0900120
Jie Jiang81c84db2020-09-29 17:40:16 +0900121 bool NotifyPluginVmStartup(uint64_t vm_id,
122 int subnet_index,
123 NetworkDevice* device) override;
124 bool NotifyPluginVmShutdown(uint64_t vm_id) override;
Garrick Evans93a83fc2020-03-31 15:16:55 +0900125
Jie Jiang81c84db2020-09-29 17:40:16 +0900126 bool DefaultVpnRouting(int socket) override;
127
128 bool RouteOnVpn(int socket) override;
129
130 bool BypassVpn(int socket) override;
131
132 std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
133 ConnectNamespace(pid_t pid,
134 const std::string& outbound_ifname,
135 bool forward_user_traffic) override;
136
137 void GetTrafficCounters(const std::set<std::string>& devices,
138 GetTrafficCountersCallback callback) override;
139
140 bool ModifyPortRule(patchpanel::ModifyPortRuleRequest::Operation op,
141 patchpanel::ModifyPortRuleRequest::RuleType type,
142 patchpanel::ModifyPortRuleRequest::Protocol proto,
143 const std::string& input_ifname,
144 const std::string& input_dst_ip,
145 uint32_t input_dst_port,
146 const std::string& dst_ip,
147 uint32_t dst_port) override;
148
Garrick Evans9e637982020-11-30 11:59:27 +0900149 std::vector<NetworkDevice> GetDevices() override;
150
Garrick Evansf04f0442020-12-01 12:36:44 +0900151 void RegisterNetworkDeviceChangedSignalHandler(
152 NetworkDeviceChangedSignalHandler handler) override;
153
Jie Jiang25c1b972020-11-12 15:42:53 +0900154 void RegisterNeighborReachabilityEventHandler(
155 NeighborReachabilityEventHandler handler) override;
Jie Jiang81c84db2020-09-29 17:40:16 +0900156
157 private:
158 scoped_refptr<dbus::Bus> bus_;
159 dbus::ObjectProxy* proxy_ = nullptr; // owned by bus_
160
161 bool SendSetVpnIntentRequest(int socket,
162 SetVpnIntentRequest::VpnRoutingPolicy policy);
Jie Jiang81c84db2020-09-29 17:40:16 +0900163};
164
165ClientImpl::~ClientImpl() {
Garrick Evans93a83fc2020-03-31 15:16:55 +0900166 if (bus_)
167 bus_->ShutdownAndBlock();
Garrick Evans08843932019-09-17 14:41:08 +0900168}
169
Jie Jiang81c84db2020-09-29 17:40:16 +0900170bool ClientImpl::NotifyArcStartup(pid_t pid) {
Garrick Evans08843932019-09-17 14:41:08 +0900171 dbus::MethodCall method_call(kPatchPanelInterface, kArcStartupMethod);
172 dbus::MessageWriter writer(&method_call);
173
174 ArcStartupRequest request;
175 request.set_pid(static_cast<uint32_t>(pid));
176
177 if (!writer.AppendProtoAsArrayOfBytes(request)) {
178 LOG(ERROR) << "Failed to encode ArcStartupRequest proto";
179 return false;
180 }
181
182 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
183 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
184 if (!dbus_response) {
185 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
186 return false;
187 }
188
189 dbus::MessageReader reader(dbus_response.get());
190 ArcStartupResponse response;
191 if (!reader.PopArrayOfBytesAsProto(&response)) {
192 LOG(ERROR) << "Failed to parse response proto";
193 return false;
194 }
195
196 return true;
197}
198
Jie Jiang81c84db2020-09-29 17:40:16 +0900199bool ClientImpl::NotifyArcShutdown() {
Garrick Evans08843932019-09-17 14:41:08 +0900200 dbus::MethodCall method_call(kPatchPanelInterface, kArcShutdownMethod);
201 dbus::MessageWriter writer(&method_call);
202
203 ArcShutdownRequest request;
Garrick Evans08843932019-09-17 14:41:08 +0900204 if (!writer.AppendProtoAsArrayOfBytes(request)) {
205 LOG(ERROR) << "Failed to encode ArcShutdownRequest proto";
206 return false;
207 }
208
209 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
210 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
211 if (!dbus_response) {
212 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
213 return false;
214 }
215
216 dbus::MessageReader reader(dbus_response.get());
217 ArcShutdownResponse response;
218 if (!reader.PopArrayOfBytesAsProto(&response)) {
219 LOG(ERROR) << "Failed to parse response proto";
220 return false;
221 }
222
223 return true;
224}
225
Jie Jiang81c84db2020-09-29 17:40:16 +0900226std::vector<NetworkDevice> ClientImpl::NotifyArcVmStartup(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900227 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmStartupMethod);
228 dbus::MessageWriter writer(&method_call);
229
230 ArcVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900231 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900232
233 if (!writer.AppendProtoAsArrayOfBytes(request)) {
234 LOG(ERROR) << "Failed to encode ArcVmStartupRequest proto";
235 return {};
236 }
237
238 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
239 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
240 if (!dbus_response) {
241 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
242 return {};
243 }
244
245 dbus::MessageReader reader(dbus_response.get());
246 ArcVmStartupResponse response;
247 if (!reader.PopArrayOfBytesAsProto(&response)) {
248 LOG(ERROR) << "Failed to parse response proto";
249 return {};
250 }
251
Garrick Evans3388a032020-03-24 11:25:55 +0900252 std::vector<NetworkDevice> devices;
Garrick Evans08843932019-09-17 14:41:08 +0900253 for (const auto& d : response.devices()) {
254 devices.emplace_back(d);
255 }
256 return devices;
257}
258
Jie Jiang81c84db2020-09-29 17:40:16 +0900259bool ClientImpl::NotifyArcVmShutdown(uint32_t cid) {
Garrick Evans08843932019-09-17 14:41:08 +0900260 dbus::MethodCall method_call(kPatchPanelInterface, kArcVmShutdownMethod);
261 dbus::MessageWriter writer(&method_call);
262
263 ArcVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900264 request.set_cid(cid);
Garrick Evans08843932019-09-17 14:41:08 +0900265
266 if (!writer.AppendProtoAsArrayOfBytes(request)) {
267 LOG(ERROR) << "Failed to encode ArcVmShutdownRequest proto";
268 return false;
269 }
270
271 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
272 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
273 if (!dbus_response) {
274 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
275 return false;
276 }
277
278 dbus::MessageReader reader(dbus_response.get());
279 ArcVmShutdownResponse response;
280 if (!reader.PopArrayOfBytesAsProto(&response)) {
281 LOG(ERROR) << "Failed to parse response proto";
282 return false;
283 }
284
285 return true;
286}
287
Jie Jiang81c84db2020-09-29 17:40:16 +0900288bool ClientImpl::NotifyTerminaVmStartup(uint32_t cid,
289 NetworkDevice* device,
290 IPv4Subnet* container_subnet) {
Garrick Evans27b74032019-11-19 13:33:47 +0900291 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmStartupMethod);
292 dbus::MessageWriter writer(&method_call);
293
294 TerminaVmStartupRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900295 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900296
297 if (!writer.AppendProtoAsArrayOfBytes(request)) {
298 LOG(ERROR) << "Failed to encode TerminaVmStartupRequest proto";
299 return false;
300 }
301
302 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
303 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
304 if (!dbus_response) {
305 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
306 return false;
307 }
308
309 dbus::MessageReader reader(dbus_response.get());
310 TerminaVmStartupResponse response;
311 if (!reader.PopArrayOfBytesAsProto(&response)) {
312 LOG(ERROR) << "Failed to parse response proto";
313 return false;
314 }
315
316 if (!response.has_device()) {
317 LOG(ERROR) << "No device found";
318 return false;
319 }
320 *device = response.device();
321
322 if (response.has_container_subnet()) {
323 *container_subnet = response.container_subnet();
324 } else {
325 LOG(WARNING) << "No container subnet found";
326 }
327
328 return true;
329}
330
Jie Jiang81c84db2020-09-29 17:40:16 +0900331bool ClientImpl::NotifyTerminaVmShutdown(uint32_t cid) {
Garrick Evans27b74032019-11-19 13:33:47 +0900332 dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmShutdownMethod);
333 dbus::MessageWriter writer(&method_call);
334
335 TerminaVmShutdownRequest request;
Garrick Evans0a189372020-02-07 08:55:27 +0900336 request.set_cid(cid);
Garrick Evans27b74032019-11-19 13:33:47 +0900337
338 if (!writer.AppendProtoAsArrayOfBytes(request)) {
339 LOG(ERROR) << "Failed to encode TerminaVmShutdownRequest proto";
340 return false;
341 }
342
343 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
344 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
345 if (!dbus_response) {
346 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
347 return false;
348 }
349
350 dbus::MessageReader reader(dbus_response.get());
351 TerminaVmShutdownResponse response;
352 if (!reader.PopArrayOfBytesAsProto(&response)) {
353 LOG(ERROR) << "Failed to parse response proto";
354 return false;
355 }
356
357 return true;
358}
359
Jie Jiang81c84db2020-09-29 17:40:16 +0900360bool ClientImpl::NotifyPluginVmStartup(uint64_t vm_id,
361 int subnet_index,
362 NetworkDevice* device) {
Garrick Evans376f0672020-01-07 15:31:50 +0900363 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmStartupMethod);
364 dbus::MessageWriter writer(&method_call);
365
366 PluginVmStartupRequest request;
367 request.set_id(vm_id);
368 request.set_subnet_index(subnet_index);
369
370 if (!writer.AppendProtoAsArrayOfBytes(request)) {
371 LOG(ERROR) << "Failed to encode PluginVmStartupRequest proto";
372 return false;
373 }
374
375 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
376 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
377 if (!dbus_response) {
378 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
379 return false;
380 }
381
382 dbus::MessageReader reader(dbus_response.get());
383 PluginVmStartupResponse response;
384 if (!reader.PopArrayOfBytesAsProto(&response)) {
385 LOG(ERROR) << "Failed to parse response proto";
386 return false;
387 }
388
389 if (!response.has_device()) {
390 LOG(ERROR) << "No device found";
391 return false;
392 }
393 *device = response.device();
394
395 return true;
396}
397
Jie Jiang81c84db2020-09-29 17:40:16 +0900398bool ClientImpl::NotifyPluginVmShutdown(uint64_t vm_id) {
Garrick Evans376f0672020-01-07 15:31:50 +0900399 dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmShutdownMethod);
400 dbus::MessageWriter writer(&method_call);
401
402 PluginVmShutdownRequest request;
403 request.set_id(vm_id);
404
405 if (!writer.AppendProtoAsArrayOfBytes(request)) {
406 LOG(ERROR) << "Failed to encode PluginVmShutdownRequest proto";
407 return false;
408 }
409
410 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
411 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
412 if (!dbus_response) {
413 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
414 return false;
415 }
416
417 dbus::MessageReader reader(dbus_response.get());
Garrick Evans9751a1e2020-02-20 11:02:10 +0900418 PluginVmShutdownResponse response;
Garrick Evans376f0672020-01-07 15:31:50 +0900419 if (!reader.PopArrayOfBytesAsProto(&response)) {
420 LOG(ERROR) << "Failed to parse response proto";
421 return false;
422 }
423
424 return true;
425}
426
Jie Jiang81c84db2020-09-29 17:40:16 +0900427bool ClientImpl::DefaultVpnRouting(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900428 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::DEFAULT_ROUTING);
429}
430
Jie Jiang81c84db2020-09-29 17:40:16 +0900431bool ClientImpl::RouteOnVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900432 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::ROUTE_ON_VPN);
433}
434
Jie Jiang81c84db2020-09-29 17:40:16 +0900435bool ClientImpl::BypassVpn(int socket) {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900436 return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::BYPASS_VPN);
437}
438
Jie Jiang81c84db2020-09-29 17:40:16 +0900439bool ClientImpl::SendSetVpnIntentRequest(
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900440 int socket, SetVpnIntentRequest::VpnRoutingPolicy policy) {
441 dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnIntentMethod);
442 dbus::MessageWriter writer(&method_call);
443
444 SetVpnIntentRequest request;
445 SetVpnIntentResponse response;
446 request.set_policy(policy);
447
448 if (!writer.AppendProtoAsArrayOfBytes(request)) {
449 LOG(ERROR) << "Failed to encode SetVpnIntentRequest proto";
450 return false;
451 }
452 writer.AppendFileDescriptor(socket);
453
454 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
455 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
456 if (!dbus_response) {
457 LOG(ERROR)
458 << "Failed to send SetVpnIntentRequest message to patchpanel service";
459 return false;
460 }
461
462 dbus::MessageReader reader(dbus_response.get());
463 if (!reader.PopArrayOfBytesAsProto(&response)) {
464 LOG(ERROR) << "Failed to parse SetVpnIntentResponse proto";
465 return false;
466 }
467
468 if (!response.success()) {
469 LOG(ERROR) << "SetVpnIntentRequest failed";
470 return false;
471 }
472 return true;
473}
474
Hugo Benichicc6850f2020-01-17 13:26:06 +0900475std::pair<base::ScopedFD, patchpanel::ConnectNamespaceResponse>
Jie Jiang81c84db2020-09-29 17:40:16 +0900476ClientImpl::ConnectNamespace(pid_t pid,
477 const std::string& outbound_ifname,
478 bool forward_user_traffic) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900479 // Prepare and serialize the request proto.
480 ConnectNamespaceRequest request;
481 request.set_pid(static_cast<int32_t>(pid));
482 request.set_outbound_physical_device(outbound_ifname);
483 request.set_allow_user_traffic(forward_user_traffic);
484
485 dbus::MethodCall method_call(kPatchPanelInterface, kConnectNamespaceMethod);
486 dbus::MessageWriter writer(&method_call);
487 if (!writer.AppendProtoAsArrayOfBytes(request)) {
488 LOG(ERROR) << "Failed to encode ConnectNamespaceRequest proto";
489 return {};
490 }
491
492 // Prepare an fd pair and append one fd directly after the serialized request.
493 int pipe_fds[2] = {-1, -1};
494 if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
495 PLOG(ERROR) << "Failed to create a pair of fds with pipe2()";
496 return {};
497 }
498 base::ScopedFD fd_local(pipe_fds[0]);
499 // MessageWriter::AppendFileDescriptor duplicates the fd, so use ScopeFD to
500 // make sure the original fd is closed eventually.
501 base::ScopedFD fd_remote(pipe_fds[1]);
502 writer.AppendFileDescriptor(pipe_fds[1]);
503
504 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
505 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
506 if (!dbus_response) {
507 LOG(ERROR) << "Failed to send ConnectNamespace message to patchpanel";
508 return {};
509 }
510
511 dbus::MessageReader reader(dbus_response.get());
512 ConnectNamespaceResponse response;
513 if (!reader.PopArrayOfBytesAsProto(&response)) {
514 LOG(ERROR) << "Failed to parse ConnectNamespaceResponse proto";
515 return {};
516 }
517
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900518 if (response.peer_ifname().empty() || response.host_ifname().empty()) {
Hugo Benichicc6850f2020-01-17 13:26:06 +0900519 LOG(ERROR) << "ConnectNamespace for netns pid " << pid << " failed";
520 return {};
521 }
522
Garrick Evans3388a032020-03-24 11:25:55 +0900523 std::string subnet_info = IPv4AddressToCidrString(
Hugo Benichicc6850f2020-01-17 13:26:06 +0900524 response.ipv4_subnet().base_addr(), response.ipv4_subnet().prefix_len());
525 LOG(INFO) << "ConnectNamespace for netns pid " << pid
Hugo Benichi2fd0c6e2020-04-17 16:12:05 +0900526 << " succeeded: peer_ifname=" << response.peer_ifname()
527 << " peer_ipv4_address="
528 << IPv4AddressToString(response.peer_ipv4_address())
529 << " host_ifname=" << response.host_ifname()
530 << " host_ipv4_address="
531 << IPv4AddressToString(response.host_ipv4_address())
Hugo Benichicc6850f2020-01-17 13:26:06 +0900532 << " subnet=" << subnet_info;
533
534 return std::make_pair(std::move(fd_local), std::move(response));
535}
536
Jie Jiang81c84db2020-09-29 17:40:16 +0900537void ClientImpl::GetTrafficCounters(const std::set<std::string>& devices,
538 GetTrafficCountersCallback callback) {
Jie Jiange02d1202020-07-27 16:57:04 +0900539 dbus::MethodCall method_call(kPatchPanelInterface, kGetTrafficCountersMethod);
540 dbus::MessageWriter writer(&method_call);
541
542 TrafficCountersRequest request;
543 for (const auto& device : devices) {
544 request.add_devices(device);
545 }
546
547 if (!writer.AppendProtoAsArrayOfBytes(request)) {
548 LOG(ERROR) << "Failed to encode TrafficCountersRequest proto";
Jie Jiang0a70acf2020-10-02 11:57:32 +0900549 std::move(callback).Run({});
550 return;
Jie Jiange02d1202020-07-27 16:57:04 +0900551 }
552
Jie Jiang0a70acf2020-10-02 11:57:32 +0900553 proxy_->CallMethod(
554 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
555 base::BindOnce(&OnGetTrafficCountersDBusResponse, std::move(callback)));
Jie Jiange02d1202020-07-27 16:57:04 +0900556}
557
Jie Jiang81c84db2020-09-29 17:40:16 +0900558bool ClientImpl::ModifyPortRule(ModifyPortRuleRequest::Operation op,
559 ModifyPortRuleRequest::RuleType type,
560 ModifyPortRuleRequest::Protocol proto,
561 const std::string& input_ifname,
562 const std::string& input_dst_ip,
563 uint32_t input_dst_port,
564 const std::string& dst_ip,
565 uint32_t dst_port) {
Jason Jeremy Iman6f1f3e72020-07-06 13:04:03 +0900566 dbus::MethodCall method_call(kPatchPanelInterface, kModifyPortRuleMethod);
567 dbus::MessageWriter writer(&method_call);
568
569 ModifyPortRuleRequest request;
570 ModifyPortRuleResponse response;
571
572 request.set_op(op);
573 request.set_type(type);
574 request.set_proto(proto);
575 request.set_input_ifname(input_ifname);
576 request.set_input_dst_ip(input_dst_ip);
577 request.set_input_dst_port(input_dst_port);
578 request.set_dst_ip(dst_ip);
579 request.set_dst_port(dst_port);
580
581 if (!writer.AppendProtoAsArrayOfBytes(request)) {
582 LOG(ERROR) << "Failed to encode ModifyPortRuleRequest proto " << request;
583 return false;
584 }
585
586 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
587 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
588 if (!dbus_response) {
589 LOG(ERROR)
590 << "Failed to send ModifyPortRuleRequest message to patchpanel service "
591 << request;
592 return false;
593 }
594
595 dbus::MessageReader reader(dbus_response.get());
596 if (!reader.PopArrayOfBytesAsProto(&response)) {
597 LOG(ERROR) << "Failed to parse ModifyPortRuleResponse proto " << request;
598 return false;
599 }
600
601 if (!response.success()) {
602 LOG(ERROR) << "ModifyPortRuleRequest failed " << request;
603 return false;
604 }
605 return true;
606}
607
Garrick Evans9e637982020-11-30 11:59:27 +0900608std::vector<NetworkDevice> ClientImpl::GetDevices() {
609 dbus::MethodCall method_call(kPatchPanelInterface, kGetDevicesMethod);
610 dbus::MessageWriter writer(&method_call);
611
612 GetDevicesRequest request;
613 if (!writer.AppendProtoAsArrayOfBytes(request)) {
614 LOG(ERROR) << "Failed to encode GetDevicesRequest proto";
615 return {};
616 }
617
618 std::unique_ptr<dbus::Response> dbus_response = proxy_->CallMethodAndBlock(
619 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
620 if (!dbus_response) {
621 LOG(ERROR) << "Failed to send dbus message to patchpanel service";
622 return {};
623 }
624
625 dbus::MessageReader reader(dbus_response.get());
626 GetDevicesResponse response;
627 if (!reader.PopArrayOfBytesAsProto(&response)) {
628 LOG(ERROR) << "Failed to parse response proto";
629 return {};
630 }
631
632 std::vector<NetworkDevice> devices;
633 for (const auto& d : response.devices()) {
634 devices.emplace_back(d);
635 }
636 return devices;
637}
638
Garrick Evansf04f0442020-12-01 12:36:44 +0900639void ClientImpl::RegisterNetworkDeviceChangedSignalHandler(
640 NetworkDeviceChangedSignalHandler handler) {
641 proxy_->ConnectToSignal(
642 kPatchPanelInterface, kNetworkDeviceChangedSignal,
643 base::BindRepeating(OnNetworkDeviceChangedSignal, handler),
644 base::BindOnce(OnSignalConnectedCallback));
645}
646
Jie Jiang25c1b972020-11-12 15:42:53 +0900647void ClientImpl::RegisterNeighborReachabilityEventHandler(
648 NeighborReachabilityEventHandler handler) {
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900649 proxy_->ConnectToSignal(
Jie Jiang25c1b972020-11-12 15:42:53 +0900650 kPatchPanelInterface, kNeighborReachabilityEventSignal,
651 base::BindRepeating(OnNeighborReachabilityEventSignal, handler),
Jie Jiange2e4c0b2020-09-16 18:48:43 +0900652 base::BindOnce(OnSignalConnectedCallback));
653}
654
Jie Jiang81c84db2020-09-29 17:40:16 +0900655} // namespace
656
657// static
658std::unique_ptr<Client> Client::New() {
659 dbus::Bus::Options opts;
660 opts.bus_type = dbus::Bus::SYSTEM;
661 scoped_refptr<dbus::Bus> bus(new dbus::Bus(std::move(opts)));
662
663 if (!bus->Connect()) {
664 LOG(ERROR) << "Failed to connect to system bus";
665 return nullptr;
666 }
667
668 dbus::ObjectProxy* proxy = bus->GetObjectProxy(
669 kPatchPanelServiceName, dbus::ObjectPath(kPatchPanelServicePath));
670 if (!proxy) {
671 LOG(ERROR) << "Unable to get dbus proxy for " << kPatchPanelServiceName;
672 return nullptr;
673 }
674
675 return std::make_unique<ClientImpl>(std::move(bus), proxy);
676}
677
678std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus,
679 dbus::ObjectProxy* proxy) {
680 return std::make_unique<ClientImpl>(std::move(bus), proxy);
681}
682
Garrick Evans08843932019-09-17 14:41:08 +0900683} // namespace patchpanel