summaryrefslogtreecommitdiff
path: root/redfish-core
diff options
context:
space:
mode:
authorSunitha Harish <sunithaharish04@gmail.com>2023-04-07 14:46:49 +0300
committerGunnar Mills <gmills@us.ibm.com>2024-03-06 06:47:10 +0300
commitce73d5c8517e0b85d85de345f10c82c24cbb067b (patch)
tree296d5568063cc7b0553035d9f951990212284c42 /redfish-core
parent1c79f93e70e8e08f2b17a0bb8c38bcfd929bb3e9 (diff)
downloadbmcweb-ce73d5c8517e0b85d85de345f10c82c24cbb067b.tar.xz
Support PATCH on IPv6StaticDefaultGateways
Currently there is no support to setting up the Static Default IPv6 gateway via redfish. This commit adds IPv6StaticDefaultGateways parameter to the ethernet interface, on which user can send PATCH request and setup the Static IPv6 gateway for the interface. Tested: GET https://${bmc}/redfish/v1/Managers/bmc/EthernetInterfaces/<id> ``` "IPv6StaticDefaultGateways": [ { "Address": "2002:903:15F:325:9:3:29:1", "PrefixLength": 24 }, { "Address": "2002:90:15F:325:9:3:29:1", "PrefixLength": 24 } ], ``` PATCH https://${bmc}/redfish/v1/Managers/bmc/EthernetInterfaces/<id> -d '{"IPv6StaticDefaultGateways": [{"Address": "2002:903:15F:325:9:3:29:1", "PrefixLength": 24}]}' PATCH https://${bmc}/redfish/v1/Managers/bmc/EthernetInterfaces/<id> -d '{"IPv6StaticDefaultGateways": [{"Address": "2002:903:15F:325:9:3:29:1"}]}' PATCH https://${bmc}/redfish/v1/Managers/bmc/EthernetInterfaces/<id> -d '{"IPv6StaticDefaultGateways": [{}, {"Address": "2002:903:15F:325:9:3:29:1","PrefixLength": 24}]}' PATCH https://${bmc}/redfish/v1/Managers/bmc/EthernetInterfaces/<id> -d '{"IPv6StaticDefaultGateways": [null, {}]}' PATCH https://${bmc}/redfish/v1/Managers/bmc/EthernetInterfaces/<id> -d '{"IPv6StaticDefaultGateways": [{"PrefixLength": 24}]}' --> this will return PropertyMissing error Redfish validator passed. Change-Id: If6aaa6981a9272a733594f0ee313873a09f67758 Signed-off-by: Sunitha Harish <sunithaharish04@gmail.com> Signed-off-by: Ravi Teja <raviteja28031990@gmail.com> Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
Diffstat (limited to 'redfish-core')
-rw-r--r--redfish-core/lib/ethernet.hpp306
1 files changed, 292 insertions, 14 deletions
diff --git a/redfish-core/lib/ethernet.hpp b/redfish-core/lib/ethernet.hpp
index 1574d81317..8bd4cdc62b 100644
--- a/redfish-core/lib/ethernet.hpp
+++ b/redfish-core/lib/ethernet.hpp
@@ -28,9 +28,11 @@
#include "utils/ip_utils.hpp"
#include "utils/json_utils.hpp"
+#include <boost/system/error_code.hpp>
#include <boost/url/format.hpp>
#include <array>
+#include <memory>
#include <optional>
#include <ranges>
#include <regex>
@@ -71,6 +73,18 @@ struct IPv6AddressData
std::string origin;
uint8_t prefixLength = 0;
};
+
+/**
+ * Structure for keeping static route data required by Redfish
+ */
+struct StaticGatewayData
+{
+ std::string id;
+ std::string gateway;
+ size_t prefixLength = 0;
+ std::string protocol;
+};
+
/**
* Structure for keeping basic single Ethernet Interface information
* available from DBus
@@ -96,6 +110,7 @@ struct EthernetInterfaceData
std::string hostName;
std::string defaultGateway;
std::string ipv6DefaultGateway;
+ std::string ipv6StaticDefaultGateway;
std::string macAddress;
std::optional<uint32_t> vlanId;
std::vector<std::string> nameServers;
@@ -811,6 +826,45 @@ inline void deleteAndCreateIPAddress(
"xyz.openbmc_project.Object.Delete", "Delete");
}
+inline bool extractIPv6DefaultGatewayData(
+ const std::string& ethifaceId,
+ const dbus::utility::ManagedObjectType& dbusData,
+ std::vector<StaticGatewayData>& staticGatewayConfig)
+{
+ std::string staticGatewayPathStart("/xyz/openbmc_project/network/");
+ staticGatewayPathStart += ethifaceId;
+
+ for (const auto& objpath : dbusData)
+ {
+ if (!std::string_view(objpath.first.str)
+ .starts_with(staticGatewayPathStart))
+ {
+ continue;
+ }
+ for (const auto& interface : objpath.second)
+ {
+ if (interface.first != "xyz.openbmc_project.Network.StaticGateway")
+ {
+ continue;
+ }
+ StaticGatewayData& staticGateway =
+ staticGatewayConfig.emplace_back();
+ staticGateway.id = objpath.first.filename();
+
+ bool success = sdbusplus::unpackPropertiesNoThrow(
+ redfish::dbus_utils::UnpackErrorPrinter(), interface.second,
+ "Gateway", staticGateway.gateway, "PrefixLength",
+ staticGateway.prefixLength, "ProtocolType",
+ staticGateway.protocol);
+ if (!success)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
/**
* @brief Creates IPv6 with given data
*
@@ -825,6 +879,9 @@ inline void createIPv6(const std::string& ifaceId, uint8_t prefixLength,
const std::string& address,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
{
+ sdbusplus::message::object_path path("/xyz/openbmc_project/network");
+ path /= ifaceId;
+
auto createIpHandler = [asyncResp,
address](const boost::system::error_code& ec) {
if (ec)
@@ -840,17 +897,209 @@ inline void createIPv6(const std::string& ifaceId, uint8_t prefixLength,
}
}
};
- // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
- // does not have associated gateway property
+ // Passing null for gateway, as per redfish spec IPv6StaticAddresses
+ // object does not have associated gateway property
crow::connections::systemBus->async_method_call(
- std::move(createIpHandler), "xyz.openbmc_project.Network",
- "/xyz/openbmc_project/network/" + ifaceId,
+ std::move(createIpHandler), "xyz.openbmc_project.Network", path,
"xyz.openbmc_project.Network.IP.Create", "IP",
"xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
"");
}
/**
+ * @brief Deletes given IPv6 Static Gateway
+ *
+ * @param[in] ifaceId Id of interface whose IP should be deleted
+ * @param[in] ipHash DBus Hash id of IP that should be deleted
+ * @param[io] asyncResp Response object that will be returned to client
+ *
+ * @return None
+ */
+inline void
+ deleteIPv6Gateway(std::string_view gatewayId,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ sdbusplus::message::object_path path("/xyz/openbmc_project/network");
+ path /= gatewayId;
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code& ec) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ }
+ },
+ "xyz.openbmc_project.Network", path,
+ "xyz.openbmc_project.Object.Delete", "Delete");
+}
+
+/**
+ * @brief Creates IPv6 static default gateway with given data
+ *
+ * @param[in] ifaceId Id of interface whose IP should be added
+ * @param[in] prefixLength Prefix length that needs to be added
+ * @param[in] gateway Gateway address that needs to be added
+ * @param[io] asyncResp Response object that will be returned to client
+ *
+ * @return None
+ */
+inline void createIPv6DefaultGateway(
+ std::string_view ifaceId, size_t prefixLength, std::string_view gateway,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ sdbusplus::message::object_path path("/xyz/openbmc_project/network");
+ path /= ifaceId;
+ auto createIpHandler = [asyncResp](const boost::system::error_code& ec) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ }
+ };
+ crow::connections::systemBus->async_method_call(
+ std::move(createIpHandler), "xyz.openbmc_project.Network", path,
+ "xyz.openbmc_project.Network.StaticGateway.Create", "StaticGateway",
+ gateway, prefixLength, "xyz.openbmc_project.Network.IP.Protocol.IPv6");
+}
+
+/**
+ * @brief Deletes the IPv6 default gateway entry for this interface and
+ * creates a replacement IPv6 default gateway entry
+ *
+ * @param[in] ifaceId Id of interface upon which to create the IPv6
+ * entry
+ * @param[in] gateway IPv6 gateway to assign to this interface
+ * @param[in] prefixLength IPv6 prefix syntax for the subnet mask
+ * @param[io] asyncResp Response object that will be returned to client
+ *
+ * @return None
+ */
+inline void deleteAndCreateIPv6DefaultGateway(
+ std::string_view ifaceId, std::string_view gatewayId,
+ std::string_view gateway, size_t prefixLength,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ sdbusplus::message::object_path path("/xyz/openbmc_project/network");
+ path /= gatewayId;
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, ifaceId, gateway,
+ prefixLength](const boost::system::error_code& ec) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ createIPv6DefaultGateway(ifaceId, prefixLength, gateway, asyncResp);
+ },
+ "xyz.openbmc_project.Network", path,
+ "xyz.openbmc_project.Object.Delete", "Delete");
+}
+
+/**
+ * @brief Sets IPv6 default gateway with given data
+ *
+ * @param[in] ifaceId Id of interface whose gateway should be added
+ * @param[in] input Contains address that needs to be added
+ * @param[in] staticGatewayData Current static gateways in the system
+ * @param[io] asyncResp Response object that will be returned to client
+ *
+ * @return None
+ */
+
+inline void handleIPv6DefaultGateway(
+ const std::string& ifaceId, const nlohmann::json::array_t& input,
+ const std::vector<StaticGatewayData>& staticGatewayData,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ size_t entryIdx = 1;
+ std::vector<StaticGatewayData>::const_iterator staticGatewayEntry =
+ staticGatewayData.begin();
+
+ for (const nlohmann::json& thisJson : input)
+ {
+ // find the next gateway entry
+ while (staticGatewayEntry != staticGatewayData.end())
+ {
+ if (staticGatewayEntry->protocol ==
+ "xyz.openbmc_project.Network.IP.Protocol.IPv6")
+ {
+ break;
+ }
+ staticGatewayEntry++;
+ }
+ std::string pathString = "IPv6StaticDefaultGateways/" +
+ std::to_string(entryIdx);
+ if (thisJson.is_null())
+ {
+ if (staticGatewayEntry == staticGatewayData.end())
+ {
+ messages::resourceCannotBeDeleted(asyncResp->res);
+ return;
+ }
+ deleteIPv6Gateway(staticGatewayEntry->id, asyncResp);
+ return;
+ }
+ if (thisJson.is_object() && thisJson.empty())
+ {
+ // Do nothing, but make sure the entry exists.
+ if (staticGatewayEntry == staticGatewayData.end())
+ {
+ messages::propertyValueFormatError(asyncResp->res, thisJson,
+ pathString);
+ return;
+ }
+ }
+ std::optional<std::string> address;
+ std::optional<size_t> prefixLength;
+
+ nlohmann::json thisJsonCopy = thisJson;
+ if (!json_util::readJson(thisJsonCopy, asyncResp->res, "Address",
+ address, "PrefixLength", prefixLength))
+ {
+ return;
+ }
+ const std::string* addr = nullptr;
+ size_t prefix = 0;
+ if (address)
+ {
+ addr = &(*address);
+ }
+ else if (staticGatewayEntry != staticGatewayData.end())
+ {
+ addr = &(staticGatewayEntry->gateway);
+ }
+ else
+ {
+ messages::propertyMissing(asyncResp->res, pathString + "/Address");
+ return;
+ }
+ if (prefixLength)
+ {
+ prefix = *prefixLength;
+ }
+ else if (staticGatewayEntry != staticGatewayData.end())
+ {
+ prefix = staticGatewayEntry->prefixLength;
+ }
+ else
+ {
+ messages::propertyMissing(asyncResp->res,
+ pathString + "/PrefixLength");
+ return;
+ }
+ if (staticGatewayEntry != staticGatewayData.end())
+ {
+ deleteAndCreateIPv6DefaultGateway(ifaceId, staticGatewayEntry->id,
+ *addr, prefix, asyncResp);
+ staticGatewayEntry++;
+ }
+ else
+ {
+ createIPv6DefaultGateway(ifaceId, prefix, *addr, asyncResp);
+ }
+ entryIdx++;
+ }
+}
+
+/**
* Function that retrieves all properties for given Ethernet Interface
* Object
* from EntityManager Network Manager
@@ -872,17 +1121,18 @@ void getEthernetIfaceData(const std::string& ethifaceId,
EthernetInterfaceData ethData{};
std::vector<IPv4AddressData> ipv4Data;
std::vector<IPv6AddressData> ipv6Data;
+ std::vector<StaticGatewayData> ipv6GatewayData;
if (ec)
{
- callback(false, ethData, ipv4Data, ipv6Data);
+ callback(false, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
return;
}
bool found = extractEthernetInterfaceData(ethifaceId, resp, ethData);
if (!found)
{
- callback(false, ethData, ipv4Data, ipv6Data);
+ callback(false, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
return;
}
@@ -899,8 +1149,12 @@ void getEthernetIfaceData(const std::string& ethifaceId,
}
extractIPV6Data(ethifaceId, resp, ipv6Data);
+ if (!extractIPv6DefaultGatewayData(ethifaceId, resp, ipv6GatewayData))
+ {
+ callback(false, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
+ }
// Finally make a callback with useful data
- callback(true, ethData, ipv4Data, ipv6Data);
+ callback(true, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
});
}
@@ -1614,7 +1868,8 @@ inline void
const std::string& ifaceId,
const EthernetInterfaceData& ethData,
const std::vector<IPv4AddressData>& ipv4Data,
- const std::vector<IPv6AddressData>& ipv6Data)
+ const std::vector<IPv6AddressData>& ipv6Data,
+ const std::vector<StaticGatewayData>& ipv6GatewayData)
{
nlohmann::json& jsonResponse = asyncResp->res.jsonValue;
jsonResponse["Id"] = ifaceId;
@@ -1741,6 +1996,17 @@ inline void
jsonResponse["IPv6DefaultGateway"] = ipv6GatewayStr;
+ nlohmann::json::array_t ipv6StaticGatewayArray;
+ for (const auto& ipv6GatewayConfig : ipv6GatewayData)
+ {
+ nlohmann::json::object_t ipv6Gateway;
+ ipv6Gateway["Address"] = ipv6GatewayConfig.gateway;
+ ipv6Gateway["PrefixLength"] = ipv6GatewayConfig.prefixLength;
+ ipv6StaticGatewayArray.emplace_back(std::move(ipv6Gateway));
+ }
+ jsonResponse["IPv6StaticDefaultGateways"] =
+ std::move(ipv6StaticGatewayArray);
+
nlohmann::json& ipv6Array = jsonResponse["IPv6Addresses"];
nlohmann::json& ipv6StaticArray = jsonResponse["IPv6StaticAddresses"];
ipv6Array = nlohmann::json::array();
@@ -1988,10 +2254,11 @@ inline void requestEthernetInterfacesRoutes(App& app)
}
getEthernetIfaceData(
ifaceId,
- [asyncResp, ifaceId](const bool& success,
- const EthernetInterfaceData& ethData,
- const std::vector<IPv4AddressData>& ipv4Data,
- const std::vector<IPv6AddressData>& ipv6Data) {
+ [asyncResp,
+ ifaceId](const bool& success, const EthernetInterfaceData& ethData,
+ const std::vector<IPv4AddressData>& ipv4Data,
+ const std::vector<IPv6AddressData>& ipv6Data,
+ const std::vector<StaticGatewayData>& ipv6GatewayData) {
if (!success)
{
// TODO(Pawel)consider distinguish between non
@@ -2007,7 +2274,8 @@ inline void requestEthernetInterfacesRoutes(App& app)
asyncResp->res.jsonValue["Description"] =
"Management Network Interface";
- parseInterfaceData(asyncResp, ifaceId, ethData, ipv4Data, ipv6Data);
+ parseInterfaceData(asyncResp, ifaceId, ethData, ipv4Data, ipv6Data,
+ ipv6GatewayData);
});
});
@@ -2027,6 +2295,7 @@ inline void requestEthernetInterfacesRoutes(App& app)
std::optional<std::string> ipv6DefaultGateway;
std::optional<nlohmann::json::array_t> ipv4StaticAddresses;
std::optional<nlohmann::json::array_t> ipv6StaticAddresses;
+ std::optional<nlohmann::json::array_t> ipv6StaticDefaultGateways;
std::optional<std::vector<std::string>> staticNameServers;
std::optional<nlohmann::json> dhcpv4;
std::optional<nlohmann::json> dhcpv6;
@@ -2045,6 +2314,7 @@ inline void requestEthernetInterfacesRoutes(App& app)
"IPv4StaticAddresses", ipv4StaticAddresses,
"IPv6DefaultGateway", ipv6DefaultGateway,
"IPv6StaticAddresses", ipv6StaticAddresses,
+ "IPv6StaticDefaultGateways", ipv6StaticDefaultGateways,
"InterfaceEnabled", interfaceEnabled,
"MACAddress", macAddress,
"MTUSize", mtuSize,
@@ -2090,13 +2360,15 @@ inline void requestEthernetInterfacesRoutes(App& app)
ipv4StaticAddresses = std::move(ipv4StaticAddresses),
ipv6DefaultGateway = std::move(ipv6DefaultGateway),
ipv6StaticAddresses = std::move(ipv6StaticAddresses),
+ ipv6StaticDefaultGateway = std::move(ipv6StaticDefaultGateways),
staticNameServers = std::move(staticNameServers),
dhcpv4 = std::move(dhcpv4), dhcpv6 = std::move(dhcpv6), mtuSize,
ipv6AutoConfigEnabled, v4dhcpParms = std::move(v4dhcpParms),
v6dhcpParms = std::move(v6dhcpParms), interfaceEnabled](
const bool& success, const EthernetInterfaceData& ethData,
const std::vector<IPv4AddressData>& ipv4Data,
- const std::vector<IPv6AddressData>& ipv6Data) {
+ const std::vector<IPv6AddressData>& ipv6Data,
+ const std::vector<StaticGatewayData>& ipv6GatewayData) {
if (!success)
{
// ... otherwise return error
@@ -2165,6 +2437,12 @@ inline void requestEthernetInterfacesRoutes(App& app)
ipv6Data, asyncResp);
}
+ if (ipv6StaticDefaultGateway)
+ {
+ handleIPv6DefaultGateway(ifaceId, *ipv6StaticDefaultGateway,
+ ipv6GatewayData, asyncResp);
+ }
+
if (interfaceEnabled)
{
setEthernetInterfaceBoolProperty(ifaceId, "NICEnabled",