Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/platform/backends/hyperv_api/hcn/hyperv_hcn_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ HRESULT HCNAPI::HcnEnumerateEndpoints(PCWSTR Query, PWSTR* Endpoints, PWSTR* Err
{
return ::HcnEnumerateEndpoints(Query, Endpoints, ErrorRecord);
}
HRESULT HCNAPI::HcnQueryEndpointProperties(HCN_ENDPOINT Endpoint,
PCWSTR Query,
PWSTR* Properties,
PWSTR* ErrorRecord) const
{
return ::HcnQueryEndpointProperties(Endpoint, Query, Properties, ErrorRecord);
}
HRESULT HCNAPI::HcnEnumerateNetworks(PCWSTR Query, PWSTR* Networks, PWSTR* ErrorRecord) const
{
return ::HcnEnumerateNetworks(Query, Networks, ErrorRecord);
Expand Down
4 changes: 4 additions & 0 deletions src/platform/backends/hyperv_api/hcn/hyperv_hcn_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ struct HCNAPI : public Singleton<HCNAPI>
[[nodiscard]] virtual HRESULT HcnEnumerateEndpoints(PCWSTR Query,
PWSTR* Endpoints,
PWSTR* ErrorRecord) const;
[[nodiscard]] virtual HRESULT HcnQueryEndpointProperties(HCN_ENDPOINT Endpoint,
PCWSTR Query,
PWSTR* Properties,
PWSTR* ErrorRecord) const;
[[nodiscard]] virtual HRESULT HcnEnumerateNetworks(PCWSTR Query,
PWSTR* Networks,
PWSTR* ErrorRecord) const;
Expand Down
29 changes: 29 additions & 0 deletions src/platform/backends/hyperv_api/hcn/hyperv_hcn_endpoint_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (C) Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#pragma once

#include <string>
#include <vector>

namespace multipass::hyperv::hcn
{
struct HcnEndpointInfo
{
std::vector<std::string> ip_addresses;
};
} // namespace multipass::hyperv::hcn
90 changes: 88 additions & 2 deletions src/platform/backends/hyperv_api/hcn/hyperv_hcn_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <ztd/out_ptr.hpp>

#include <cassert>
#include <optional>
#include <string>
#include <type_traits>

Expand Down Expand Up @@ -186,6 +187,52 @@ std::pair<OperationResult, UniqueHcnNetwork> open_network(const std::string& net
return std::make_pair(result, std::move(network));
}

std::pair<OperationResult, UniqueHcnEndpoint> open_endpoint(const std::string& endpoint_guid)
{
mpl::trace(log_category, "open_endpoint(...) > endpoint_guid: {}", endpoint_guid);

UniqueHcnEndpoint endpoint{};
const auto result = perform_hcn_operation([&](auto&& rmsgbuf) {
return API().HcnOpenEndpoint(guid_from_string(endpoint_guid), out_ptr(endpoint), rmsgbuf);
});

return std::make_pair(result, std::move(endpoint));
}

std::optional<std::vector<std::string>> endpoint_ip_addresses(const boost::json::object& endpoint)
{
std::vector<std::string> addresses;
const auto append_address = [&addresses](const boost::json::value& address) {
if (!address.is_string())
return false;

addresses.emplace_back(address.as_string());
return true;
};

if (const auto* configurations = endpoint.if_contains("IpConfigurations"))
{
if (!configurations->is_array())
return std::nullopt;

for (const auto& configuration : configurations->as_array())
{
if (!configuration.is_object())
return std::nullopt;

if (const auto* address = configuration.as_object().if_contains("IpAddress");
address && !append_address(*address))
return std::nullopt;
}
}

if (const auto* address = endpoint.if_contains("IPAddress");
address && !append_address(*address))
return std::nullopt;

return addresses;
}

} // namespace

// ---------------------------------------------------------
Expand Down Expand Up @@ -263,6 +310,44 @@ OperationResult HCNWrapper::delete_endpoint(const std::string& endpoint_guid) co

// ---------------------------------------------------------

OperationResult HCNWrapper::query_endpoint(const std::string& endpoint_guid,
HcnEndpointInfo& out_info) const
{
mpl::trace(log_category, "HCNWrapper::query_endpoint(...) > endpoint_guid: {}", endpoint_guid);

const auto& [open_result, endpoint] = open_endpoint(endpoint_guid);
Comment thread
Copilot marked this conversation as resolved.
if (!open_result)
return open_result;

UniqueCotaskmemString properties{}, result_msgbuf{};
const auto result = ResultCode{API().HcnQueryEndpointProperties(endpoint.get(),
L"{}",
out_ptr(properties),
out_ptr(result_msgbuf))};
if (!result.success())
return {result, {result_msgbuf ? result_msgbuf.get() : L""}};

if (!properties)
return {E_UNEXPECTED, L"HCN returned no endpoint properties"};

const auto properties_as_str = wchar_to_utf8(properties.get());
mpl::trace(log_category, "query_endpoint result: {}", properties_as_str);

std::error_code ec;
const auto parsed = boost::json::parse(properties_as_str, ec);
if (ec || !parsed.is_object())
return {E_UNEXPECTED, L"Failed to process JSON returned from the API"};

auto addresses = endpoint_ip_addresses(parsed.as_object());
if (!addresses)
return {E_UNEXPECTED, L"Failed to process JSON returned from the API"};

out_info.ip_addresses = std::move(*addresses);
return {result, L""};
}

// ---------------------------------------------------------

OperationResult HCNWrapper::enumerate_attached_endpoints(
const std::string& vm_guid,
std::vector<std::string>& endpoint_guids) const
Expand Down Expand Up @@ -360,8 +445,9 @@ OperationResult HCNWrapper::enumerate_networks(std::vector<std::string>& out_net
UniqueCotaskmemString enumerate_result{}, result_msgbuf{};

// List all HCN network GUIDs
const auto result =
API().HcnEnumerateNetworks(L"{}", out_ptr(enumerate_result), out_ptr(result_msgbuf));
const auto result = API().HcnEnumerateNetworks(L"{}",
out_ptr(enumerate_result),
out_ptr(result_msgbuf));
if (enumerate_result)
{
// json_output would contain the network GUIDs.
Expand Down
3 changes: 3 additions & 0 deletions src/platform/backends/hyperv_api/hcn/hyperv_hcn_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <hyperv_api/hcn/hyperv_hcn_create_endpoint_params.h>
#include <hyperv_api/hcn/hyperv_hcn_create_network_params.h>
#include <hyperv_api/hcn/hyperv_hcn_endpoint_info.h>
#include <hyperv_api/hcn/hyperv_hcn_network_info.h>
#include <hyperv_api/hyperv_api_operation_result.h>

Expand All @@ -44,6 +45,8 @@ struct HCNWrapper : public Singleton<HCNWrapper>
[[nodiscard]] virtual OperationResult create_endpoint(
const CreateEndpointParameters& params) const;
[[nodiscard]] virtual OperationResult delete_endpoint(const std::string& endpoint_guid) const;
[[nodiscard]] virtual OperationResult query_endpoint(const std::string& endpoint_guid,
HcnEndpointInfo& out_info) const;
[[nodiscard]] virtual OperationResult enumerate_attached_endpoints(
const std::string& vm_guid,
std::vector<std::string>& endpoint_guids) const;
Expand Down
Loading
Loading