| // Copyright 2023 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "patchpanel/patchpanel_adaptor.h" |
| |
| #include <chromeos/dbus/patchpanel/dbus-constants.h> |
| #include <shill/net/process_manager.h> |
| |
| #include "patchpanel/downstream_network_service.h" |
| #include "patchpanel/proto_utils.h" |
| |
| namespace patchpanel { |
| |
| PatchpanelAdaptor::PatchpanelAdaptor(const base::FilePath& cmd_path, |
| scoped_refptr<::dbus::Bus> bus, |
| System* system, |
| shill::ProcessManager* process_manager, |
| MetricsLibraryInterface* metrics, |
| std::unique_ptr<RTNLClient> rtnl_client) |
| : org::chromium::PatchPanelAdaptor(this), |
| dbus_object_(nullptr, bus, dbus::ObjectPath(kPatchPanelServicePath)), |
| metrics_(metrics), |
| manager_( |
| std::make_unique<Manager>(cmd_path, |
| system, |
| process_manager, |
| metrics_, |
| this, |
| std::make_unique<ShillClient>(bus, system), |
| std::move(rtnl_client))) {} |
| |
| void PatchpanelAdaptor::RegisterAsync( |
| brillo::dbus_utils::AsyncEventSequencer::CompletionAction cb) { |
| RegisterWithDBusObject(&dbus_object_); |
| dbus_object_.RegisterAsync(std::move(cb)); |
| } |
| |
| ArcShutdownResponse PatchpanelAdaptor::ArcShutdown( |
| const ArcShutdownRequest& request) { |
| LOG(INFO) << "ARC++ shutting down"; |
| RecordDbusEvent(DbusUmaEvent::kArcShutdown); |
| |
| manager_->ArcShutdown(); |
| RecordDbusEvent(DbusUmaEvent::kArcShutdownSuccess); |
| return {}; |
| } |
| |
| ArcStartupResponse PatchpanelAdaptor::ArcStartup( |
| const ArcStartupRequest& request) { |
| LOG(INFO) << "ARC++ starting up"; |
| RecordDbusEvent(DbusUmaEvent::kArcStartup); |
| |
| if (!manager_->ArcStartup(request.pid())) { |
| LOG(ERROR) << "Failed to start ARC++ network service"; |
| } else { |
| RecordDbusEvent(DbusUmaEvent::kArcStartupSuccess); |
| } |
| return {}; |
| } |
| |
| ArcVmShutdownResponse PatchpanelAdaptor::ArcVmShutdown( |
| const ArcVmShutdownRequest& request) { |
| LOG(INFO) << "ARCVM shutting down"; |
| RecordDbusEvent(DbusUmaEvent::kArcVmShutdown); |
| |
| manager_->ArcVmShutdown(request.cid()); |
| RecordDbusEvent(DbusUmaEvent::kArcVmShutdownSuccess); |
| return {}; |
| } |
| |
| ArcVmStartupResponse PatchpanelAdaptor::ArcVmStartup( |
| const ArcVmStartupRequest& request) { |
| LOG(INFO) << "ARCVM starting up"; |
| RecordDbusEvent(DbusUmaEvent::kArcVmStartup); |
| |
| const auto device_configs = manager_->ArcVmStartup(request.cid()); |
| if (!device_configs) { |
| LOG(ERROR) << "Failed to start ARCVM network service"; |
| return {}; |
| } |
| |
| // Populate the response with the interface configurations of the known ARC |
| // Devices |
| patchpanel::ArcVmStartupResponse response; |
| for (const auto* config : *device_configs) { |
| if (config->tap_ifname().empty()) |
| continue; |
| |
| // TODO(hugobenichi) Use FillDeviceProto. |
| auto* dev = response.add_devices(); |
| dev->set_ifname(config->tap_ifname()); |
| dev->set_ipv4_addr(config->guest_ipv4_addr().ToInAddr().s_addr); |
| dev->set_guest_type(NetworkDevice::ARCVM); |
| } |
| |
| RecordDbusEvent(DbusUmaEvent::kArcVmStartupSuccess); |
| return response; |
| } |
| |
| ConnectNamespaceResponse PatchpanelAdaptor::ConnectNamespace( |
| const ConnectNamespaceRequest& request, const base::ScopedFD& client_fd) { |
| RecordDbusEvent(DbusUmaEvent::kConnectNamespace); |
| |
| const auto response = manager_->ConnectNamespace(request, client_fd); |
| if (!response.netns_name().empty()) { |
| RecordDbusEvent(DbusUmaEvent::kConnectNamespaceSuccess); |
| } |
| return response; |
| } |
| |
| LocalOnlyNetworkResponse PatchpanelAdaptor::CreateLocalOnlyNetwork( |
| const LocalOnlyNetworkRequest& request, const base::ScopedFD& client_fd) { |
| RecordDbusEvent(DbusUmaEvent::kCreateLocalOnlyNetwork); |
| |
| const auto response_code = |
| manager_->CreateLocalOnlyNetwork(request, client_fd); |
| if (response_code == patchpanel::DownstreamNetworkResult::SUCCESS) { |
| RecordDbusEvent(DbusUmaEvent::kCreateLocalOnlyNetworkSuccess); |
| } |
| metrics_->SendEnumToUMA(kCreateLocalOnlyNetworkUmaEventMetrics, |
| DownstreamNetworkResultToUMAEvent(response_code)); |
| |
| LocalOnlyNetworkResponse response; |
| response.set_response_code(response_code); |
| return response; |
| } |
| |
| TetheredNetworkResponse PatchpanelAdaptor::CreateTetheredNetwork( |
| const TetheredNetworkRequest& request, const base::ScopedFD& client_fd) { |
| RecordDbusEvent(DbusUmaEvent::kCreateTetheredNetwork); |
| |
| const auto response_code = |
| manager_->CreateTetheredNetwork(request, client_fd); |
| if (response_code == patchpanel::DownstreamNetworkResult::SUCCESS) { |
| RecordDbusEvent(DbusUmaEvent::kCreateTetheredNetworkSuccess); |
| } |
| metrics_->SendEnumToUMA(kCreateTetheredNetworkUmaEventMetrics, |
| DownstreamNetworkResultToUMAEvent(response_code)); |
| |
| TetheredNetworkResponse response; |
| response.set_response_code(response_code); |
| return response; |
| } |
| |
| GetDevicesResponse PatchpanelAdaptor::GetDevices( |
| const GetDevicesRequest& request) const { |
| return manager_->GetDevices(); |
| } |
| |
| GetDownstreamNetworkInfoResponse PatchpanelAdaptor::GetDownstreamNetworkInfo( |
| const GetDownstreamNetworkInfoRequest& request) const { |
| RecordDbusEvent(DbusUmaEvent::kGetDownstreamNetworkInfo); |
| |
| const auto& downstream_ifname = request.downstream_ifname(); |
| const auto downstream_info = |
| manager_->GetDownstreamNetworkInfo(downstream_ifname); |
| if (!downstream_info) { |
| LOG(ERROR) << __func__ << ": no DownstreamNetwork for interface " |
| << downstream_ifname; |
| return {}; |
| } |
| |
| RecordDbusEvent(DbusUmaEvent::kGetDownstreamNetworkInfoSuccess); |
| GetDownstreamNetworkInfoResponse response; |
| response.set_success(true); |
| FillDownstreamNetworkProto(downstream_info->first, |
| response.mutable_downstream_network()); |
| for (const auto& info : downstream_info->second) { |
| FillNetworkClientInfoProto(info, response.add_clients_info()); |
| } |
| return response; |
| } |
| |
| TrafficCountersResponse PatchpanelAdaptor::GetTrafficCounters( |
| const TrafficCountersRequest& request) const { |
| RecordDbusEvent(DbusUmaEvent::kGetTrafficCounters); |
| |
| const std::set<std::string> shill_devices{request.devices().begin(), |
| request.devices().end()}; |
| const auto counters = manager_->GetTrafficCounters(shill_devices); |
| |
| TrafficCountersResponse response; |
| for (const auto& kv : counters) { |
| auto* traffic_counter = response.add_counters(); |
| const auto& key = kv.first; |
| const auto& counter = kv.second; |
| traffic_counter->set_source(key.source); |
| traffic_counter->set_device(key.ifname); |
| traffic_counter->set_ip_family(key.ip_family); |
| traffic_counter->set_rx_bytes(counter.rx_bytes); |
| traffic_counter->set_rx_packets(counter.rx_packets); |
| traffic_counter->set_tx_bytes(counter.tx_bytes); |
| traffic_counter->set_tx_packets(counter.tx_packets); |
| } |
| |
| RecordDbusEvent(DbusUmaEvent::kGetTrafficCountersSuccess); |
| return response; |
| } |
| |
| ModifyPortRuleResponse PatchpanelAdaptor::ModifyPortRule( |
| const ModifyPortRuleRequest& request) { |
| RecordDbusEvent(DbusUmaEvent::kModifyPortRule); |
| |
| const bool success = manager_->ModifyPortRule(request); |
| if (success) { |
| RecordDbusEvent(DbusUmaEvent::kModifyPortRuleSuccess); |
| } |
| |
| ModifyPortRuleResponse response; |
| response.set_success(success); |
| return response; |
| } |
| |
| ParallelsVmShutdownResponse PatchpanelAdaptor::ParallelsVmShutdown( |
| const ParallelsVmShutdownRequest& request) { |
| LOG(INFO) << "Parallels VM shutting down"; |
| RecordDbusEvent(DbusUmaEvent::kParallelsVmShutdown); |
| |
| manager_->ParallelsVmShutdown(request.id()); |
| |
| RecordDbusEvent(DbusUmaEvent::kParallelsVmShutdownSuccess); |
| return {}; |
| } |
| |
| ParallelsVmStartupResponse PatchpanelAdaptor::ParallelsVmStartup( |
| const ParallelsVmStartupRequest& request) { |
| const int subnet_index = request.subnet_index(); |
| const uint64_t vm_id = request.id(); |
| LOG(INFO) << __func__ << "(cid: " << vm_id |
| << ", subnet_index: " << subnet_index << ")"; |
| RecordDbusEvent(DbusUmaEvent::kParallelsVmStartup); |
| |
| if (subnet_index < 0) { |
| LOG(ERROR) << __func__ << "(cid: " << vm_id |
| << ", subnet_index: " << subnet_index |
| << "): Invalid subnet index"; |
| return {}; |
| } |
| const auto* const parallels_device = |
| manager_->ParallelsVmStartup(vm_id, static_cast<uint32_t>(subnet_index)); |
| if (!parallels_device) { |
| LOG(ERROR) << __func__ << "(cid: " << vm_id |
| << ", subnet_index: " << subnet_index |
| << "): Failed to create virtual Device"; |
| return {}; |
| } |
| ParallelsVmStartupResponse response; |
| FillParallelsAllocationProto(*parallels_device, &response); |
| RecordDbusEvent(DbusUmaEvent::kParallelsVmStartupSuccess); |
| return response; |
| } |
| |
| SetDnsRedirectionRuleResponse PatchpanelAdaptor::SetDnsRedirectionRule( |
| const SetDnsRedirectionRuleRequest& request, |
| const base::ScopedFD& client_fd) { |
| RecordDbusEvent(DbusUmaEvent::kSetDnsRedirectionRule); |
| |
| const bool success = manager_->SetDnsRedirectionRule(request, client_fd); |
| if (success) { |
| RecordDbusEvent(DbusUmaEvent::kSetDnsRedirectionRuleSuccess); |
| } |
| |
| SetDnsRedirectionRuleResponse response; |
| response.set_success(success); |
| return response; |
| } |
| |
| SetVpnIntentResponse PatchpanelAdaptor::SetVpnIntent( |
| const SetVpnIntentRequest& request, const base::ScopedFD& socket_fd) { |
| RecordDbusEvent(DbusUmaEvent::kSetVpnIntent); |
| |
| const bool success = manager_->SetVpnIntent(request.policy(), socket_fd); |
| if (!success) { |
| LOG(ERROR) << "Failed to set VpnIntent: " << request.policy(); |
| return {}; |
| } |
| |
| RecordDbusEvent(DbusUmaEvent::kSetVpnIntentSuccess); |
| SetVpnIntentResponse response; |
| response.set_success(true); |
| return response; |
| } |
| |
| SetVpnLockdownResponse PatchpanelAdaptor::SetVpnLockdown( |
| const SetVpnLockdownRequest& request) { |
| RecordDbusEvent(DbusUmaEvent::kSetVpnLockdown); |
| |
| manager_->SetVpnLockdown(request.enable_vpn_lockdown()); |
| |
| RecordDbusEvent(DbusUmaEvent::kSetVpnLockdownSuccess); |
| return {}; |
| } |
| |
| TerminaVmShutdownResponse PatchpanelAdaptor::TerminaVmShutdown( |
| const TerminaVmShutdownRequest& request) { |
| LOG(INFO) << "Termina VM shutting down"; |
| RecordDbusEvent(DbusUmaEvent::kTerminaVmShutdown); |
| |
| manager_->TerminaVmShutdown(request.cid()); |
| |
| RecordDbusEvent(DbusUmaEvent::kTerminaVmShutdownSuccess); |
| return {}; |
| } |
| |
| TerminaVmStartupResponse PatchpanelAdaptor::TerminaVmStartup( |
| const TerminaVmStartupRequest& request) { |
| const uint32_t cid = request.cid(); |
| LOG(INFO) << __func__ << "(cid: " << cid << ")"; |
| RecordDbusEvent(DbusUmaEvent::kTerminaVmStartup); |
| const auto* termina_device = manager_->TerminaVmStartup(cid); |
| if (!termina_device) { |
| LOG(ERROR) << __func__ << "(cid: " << cid << ")" |
| << ": Failed to create virtual Device"; |
| return {}; |
| } |
| if (!termina_device->lxd_ipv4_subnet()) { |
| LOG(ERROR) << __func__ << "(cid: " << cid << ")" |
| << ": Missing LXD container IPv4 subnet"; |
| return {}; |
| } |
| if (!termina_device->lxd_ipv4_address()) { |
| LOG(ERROR) << __func__ << "(cid: " << cid << ")" |
| << ": Missing LXD container IPv4 address"; |
| return {}; |
| } |
| TerminaVmStartupResponse response; |
| FillTerminaAllocationProto(*termina_device, &response); |
| RecordDbusEvent(DbusUmaEvent::kTerminaVmStartupSuccess); |
| return response; |
| } |
| |
| NotifyAndroidWifiMulticastLockChangeResponse |
| PatchpanelAdaptor::NotifyAndroidWifiMulticastLockChange( |
| const NotifyAndroidWifiMulticastLockChangeRequest& request) { |
| manager_->NotifyAndroidWifiMulticastLockChange(request.held()); |
| return {}; |
| } |
| |
| NotifyAndroidInteractiveStateResponse |
| PatchpanelAdaptor::NotifyAndroidInteractiveState( |
| const NotifyAndroidInteractiveStateRequest& request) { |
| manager_->NotifyAndroidInteractiveState(request.interactive()); |
| return {}; |
| } |
| |
| void PatchpanelAdaptor::OnNetworkDeviceChanged( |
| NetworkDevice* virtual_device, NetworkDeviceChangedSignal::Event event) { |
| NetworkDeviceChangedSignal signal; |
| signal.set_event(event); |
| signal.set_allocated_device(virtual_device); // Passes ownership |
| SendNetworkDeviceChangedSignal(signal); |
| } |
| |
| void PatchpanelAdaptor::OnNetworkConfigurationChanged() { |
| NetworkConfigurationChangedSignal signal; |
| SendNetworkConfigurationChangedSignal(signal); |
| } |
| |
| void PatchpanelAdaptor::OnNeighborReachabilityEvent( |
| int ifindex, |
| const net_base::IPAddress& ip_addr, |
| NeighborLinkMonitor::NeighborRole role, |
| NeighborReachabilityEventSignal::EventType event_type) { |
| NeighborReachabilityEventSignal signal; |
| signal.set_ifindex(ifindex); |
| signal.set_ip_addr(ip_addr.ToString()); |
| signal.set_type(event_type); |
| switch (role) { |
| case NeighborLinkMonitor::NeighborRole::kGateway: |
| signal.set_role(NeighborReachabilityEventSignal::GATEWAY); |
| break; |
| case NeighborLinkMonitor::NeighborRole::kDNSServer: |
| signal.set_role(NeighborReachabilityEventSignal::DNS_SERVER); |
| break; |
| case NeighborLinkMonitor::NeighborRole::kGatewayAndDNSServer: |
| signal.set_role(NeighborReachabilityEventSignal::GATEWAY_AND_DNS_SERVER); |
| break; |
| default: |
| NOTREACHED(); |
| } |
| SendNeighborReachabilityEventSignal(signal); |
| } |
| |
| void PatchpanelAdaptor::RecordDbusEvent(DbusUmaEvent event) const { |
| metrics_->SendEnumToUMA(kDbusUmaEventMetrics, event); |
| } |
| |
| } // namespace patchpanel |