blob: 7bc11547884697a7a50866dc15da3ebc73d17f64 [file] [log] [blame]
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
19#include "dbus_singleton.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080020#include "dbus_utility.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080021#include "error_messages.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070022#include "generated/enums/ethernet_interface.hpp"
23#include "generated/enums/resource.hpp"
Ed Tanous2c5875a2023-05-15 09:56:06 -070024#include "human_sort.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080025#include "query.hpp"
26#include "registries/privilege_registry.hpp"
Ed Tanous033f1e42022-08-15 09:47:37 -070027#include "utils/ip_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080028#include "utils/json_utils.hpp"
Ed Tanous033f1e42022-08-15 09:47:37 -070029
Sunitha Harishce73d5c2023-04-07 06:46:49 -050030#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070031#include <boost/url/format.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050032
George Liu7a1dbc42022-12-07 16:03:22 +080033#include <array>
Ed Tanous3dfed532024-03-06 14:41:27 -080034#include <cstddef>
Sunitha Harishce73d5c2023-04-07 06:46:49 -050035#include <memory>
Ed Tanousa24526d2018-12-10 15:17:59 -080036#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070037#include <ranges>
Joshi-Mansiab6554f2020-03-10 18:33:36 +053038#include <regex>
George Liu7a1dbc42022-12-07 16:03:22 +080039#include <string_view>
Ed Tanous3dfed532024-03-06 14:41:27 -080040#include <variant>
Ed Tanous77179532023-02-28 10:45:28 -080041#include <vector>
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010042
Ed Tanous1abe55e2018-09-05 08:30:59 -070043namespace redfish
44{
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010045
Ed Tanous4a0cb852018-10-15 07:55:04 -070046enum class LinkType
47{
48 Local,
49 Global
50};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010051
Johnathan Mantey743eb1c2024-04-03 12:05:57 -070052enum class IpVersion
53{
54 IpV4,
55 IpV6
56};
57
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010058/**
59 * Structure for keeping IPv4 data required by Redfish
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010060 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070061struct IPv4AddressData
62{
63 std::string id;
Ed Tanous4a0cb852018-10-15 07:55:04 -070064 std::string address;
65 std::string domain;
66 std::string gateway;
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 std::string netmask;
68 std::string origin;
Ed Tanous77179532023-02-28 10:45:28 -080069 LinkType linktype{};
70 bool isActive{};
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010071};
72
73/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -050074 * Structure for keeping IPv6 data required by Redfish
75 */
76struct IPv6AddressData
77{
78 std::string id;
79 std::string address;
80 std::string origin;
Ed Tanous77179532023-02-28 10:45:28 -080081 uint8_t prefixLength = 0;
Ravi Tejae48c0fc2019-04-16 08:37:20 -050082};
Sunitha Harishce73d5c2023-04-07 06:46:49 -050083
84/**
85 * Structure for keeping static route data required by Redfish
86 */
87struct StaticGatewayData
88{
89 std::string id;
90 std::string gateway;
91 size_t prefixLength = 0;
92 std::string protocol;
93};
94
Ravi Tejae48c0fc2019-04-16 08:37:20 -050095/**
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010096 * Structure for keeping basic single Ethernet Interface information
97 * available from DBus
98 */
Ed Tanous1abe55e2018-09-05 08:30:59 -070099struct EthernetInterfaceData
100{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700101 uint32_t speed;
Tejas Patil35fb5312021-09-20 15:35:20 +0530102 size_t mtuSize;
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800103 bool autoNeg;
Jishnu CMe4588152023-05-11 00:04:40 -0500104 bool dnsv4Enabled;
105 bool dnsv6Enabled;
Ravi Teja91c441e2024-02-23 09:03:43 -0600106 bool domainv4Enabled;
107 bool domainv6Enabled;
Jishnu CMe4588152023-05-11 00:04:40 -0500108 bool ntpv4Enabled;
109 bool ntpv6Enabled;
110 bool hostNamev4Enabled;
111 bool hostNamev6Enabled;
Johnathan Manteyaa05fb22020-01-08 12:08:44 -0800112 bool linkUp;
Johnathan Manteyeeedda22019-10-29 16:09:52 -0700113 bool nicEnabled;
Ravi Tejab10d8db2022-05-24 09:04:12 -0500114 bool ipv6AcceptRa;
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800115 std::string dhcpEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700116 std::string operatingMode;
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800117 std::string hostName;
118 std::string defaultGateway;
119 std::string ipv6DefaultGateway;
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500120 std::string ipv6StaticDefaultGateway;
Asmitha Karunanithi4652c642024-07-30 11:35:53 -0500121 std::optional<std::string> macAddress;
Jiaqing Zhao17e22022022-04-14 18:58:06 +0800122 std::optional<uint32_t> vlanId;
manojkiran.eda@gmail.com0f6efdc2019-10-03 04:53:44 -0500123 std::vector<std::string> nameServers;
124 std::vector<std::string> staticNameServers;
Jennifer Leed24bfc72019-03-05 13:03:37 -0800125 std::vector<std::string> domainnames;
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100126};
127
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700128struct DHCPParameters
129{
130 std::optional<bool> dhcpv4Enabled;
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800131 std::optional<bool> useDnsServers;
132 std::optional<bool> useNtpServers;
133 std::optional<bool> useDomainName;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700134 std::optional<std::string> dhcpv6OperatingMode;
135};
136
Ed Tanous4a0cb852018-10-15 07:55:04 -0700137// Helper function that changes bits netmask notation (i.e. /24)
138// into full dot notation
139inline std::string getNetmask(unsigned int bits)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700140{
Ed Tanous4a0cb852018-10-15 07:55:04 -0700141 uint32_t value = 0xffffffff << (32 - bits);
142 std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
143 std::to_string((value >> 16) & 0xff) + "." +
144 std::to_string((value >> 8) & 0xff) + "." +
145 std::to_string(value & 0xff);
146 return netmask;
147}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +0100148
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800149inline bool translateDhcpEnabledToBool(const std::string& inputDHCP,
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700150 bool isIPv4)
151{
152 if (isIPv4)
153 {
154 return (
155 (inputDHCP ==
156 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v4") ||
157 (inputDHCP ==
158 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both"));
159 }
160 return ((inputDHCP ==
161 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v6") ||
162 (inputDHCP ==
163 "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both"));
164}
165
Ed Tanous2c70f802020-09-28 14:29:23 -0700166inline std::string getDhcpEnabledEnumeration(bool isIPv4, bool isIPv6)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700167{
168 if (isIPv4 && isIPv6)
169 {
170 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both";
171 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700172 if (isIPv4)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700173 {
174 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v4";
175 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700176 if (isIPv6)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700177 {
178 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v6";
179 }
180 return "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.none";
181}
182
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400183inline std::string translateAddressOriginDbusToRedfish(
184 const std::string& inputOrigin, bool isIPv4)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700185{
186 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700187 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700188 return "Static";
189 }
190 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
191 {
192 if (isIPv4)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700194 return "IPv4LinkLocal";
195 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700196 return "LinkLocal";
Ed Tanous4a0cb852018-10-15 07:55:04 -0700197 }
198 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
199 {
200 if (isIPv4)
201 {
202 return "DHCP";
203 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700204 return "DHCPv6";
Ed Tanous4a0cb852018-10-15 07:55:04 -0700205 }
206 if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
207 {
208 return "SLAAC";
209 }
210 return "";
211}
212
Ed Tanous02cad962022-06-30 16:50:15 -0700213inline bool extractEthernetInterfaceData(
214 const std::string& ethifaceId,
215 const dbus::utility::ManagedObjectType& dbusData,
216 EthernetInterfaceData& ethData)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700217{
Ed Tanous4c9afe42019-05-03 16:59:57 -0700218 bool idFound = false;
Ed Tanous02cad962022-06-30 16:50:15 -0700219 for (const auto& objpath : dbusData)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700220 {
Ed Tanous02cad962022-06-30 16:50:15 -0700221 for (const auto& ifacePair : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700222 {
Ed Tanous81ce6092020-12-17 16:54:55 +0000223 if (objpath.first == "/xyz/openbmc_project/network/" + ethifaceId)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700224 {
Ed Tanous4c9afe42019-05-03 16:59:57 -0700225 idFound = true;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700226 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700227 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500228 for (const auto& propertyPair : ifacePair.second)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700229 {
Ed Tanous4a0cb852018-10-15 07:55:04 -0700230 if (propertyPair.first == "MACAddress")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700231 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500232 const std::string* mac =
Ed Tanousabf2add2019-01-22 16:40:12 -0800233 std::get_if<std::string>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700234 if (mac != nullptr)
235 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800236 ethData.macAddress = *mac;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700237 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700238 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700239 }
240 }
241 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
242 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500243 for (const auto& propertyPair : ifacePair.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700244 {
245 if (propertyPair.first == "Id")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700246 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500247 const uint32_t* id =
Ed Tanousabf2add2019-01-22 16:40:12 -0800248 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700249 if (id != nullptr)
250 {
Jiaqing Zhao17e22022022-04-14 18:58:06 +0800251 ethData.vlanId = *id;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700252 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700253 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700254 }
255 }
256 else if (ifacePair.first ==
257 "xyz.openbmc_project.Network.EthernetInterface")
258 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500259 for (const auto& propertyPair : ifacePair.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700260 {
261 if (propertyPair.first == "AutoNeg")
262 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700263 const bool* autoNeg =
Ed Tanousabf2add2019-01-22 16:40:12 -0800264 std::get_if<bool>(&propertyPair.second);
Ed Tanous2c70f802020-09-28 14:29:23 -0700265 if (autoNeg != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700266 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800267 ethData.autoNeg = *autoNeg;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700268 }
269 }
270 else if (propertyPair.first == "Speed")
271 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500272 const uint32_t* speed =
Ed Tanousabf2add2019-01-22 16:40:12 -0800273 std::get_if<uint32_t>(&propertyPair.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700274 if (speed != nullptr)
275 {
276 ethData.speed = *speed;
277 }
278 }
Tejas Patil35fb5312021-09-20 15:35:20 +0530279 else if (propertyPair.first == "MTU")
280 {
Anthony3e7a8da2023-10-23 14:22:43 +0800281 const size_t* mtuSize =
282 std::get_if<size_t>(&propertyPair.second);
Tejas Patil35fb5312021-09-20 15:35:20 +0530283 if (mtuSize != nullptr)
284 {
285 ethData.mtuSize = *mtuSize;
286 }
287 }
Johnathan Manteyaa05fb22020-01-08 12:08:44 -0800288 else if (propertyPair.first == "LinkUp")
289 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500290 const bool* linkUp =
Johnathan Manteyaa05fb22020-01-08 12:08:44 -0800291 std::get_if<bool>(&propertyPair.second);
292 if (linkUp != nullptr)
293 {
294 ethData.linkUp = *linkUp;
295 }
296 }
Johnathan Manteyeeedda22019-10-29 16:09:52 -0700297 else if (propertyPair.first == "NICEnabled")
298 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500299 const bool* nicEnabled =
Johnathan Manteyeeedda22019-10-29 16:09:52 -0700300 std::get_if<bool>(&propertyPair.second);
301 if (nicEnabled != nullptr)
302 {
303 ethData.nicEnabled = *nicEnabled;
304 }
305 }
Ravi Tejab10d8db2022-05-24 09:04:12 -0500306 else if (propertyPair.first == "IPv6AcceptRA")
307 {
308 const bool* ipv6AcceptRa =
309 std::get_if<bool>(&propertyPair.second);
310 if (ipv6AcceptRa != nullptr)
311 {
312 ethData.ipv6AcceptRa = *ipv6AcceptRa;
313 }
314 }
RAJESWARAN THILLAIGOVINDANf85837b2019-04-04 05:18:53 -0500315 else if (propertyPair.first == "Nameservers")
Ed Tanous4a0cb852018-10-15 07:55:04 -0700316 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500317 const std::vector<std::string>* nameservers =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500318 std::get_if<std::vector<std::string>>(
Ed Tanous029573d2019-02-01 10:57:49 -0800319 &propertyPair.second);
320 if (nameservers != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700321 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700322 ethData.nameServers = *nameservers;
manojkiran.eda@gmail.com0f6efdc2019-10-03 04:53:44 -0500323 }
324 }
325 else if (propertyPair.first == "StaticNameServers")
326 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500327 const std::vector<std::string>* staticNameServers =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500328 std::get_if<std::vector<std::string>>(
manojkiran.eda@gmail.com0f6efdc2019-10-03 04:53:44 -0500329 &propertyPair.second);
330 if (staticNameServers != nullptr)
331 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700332 ethData.staticNameServers = *staticNameServers;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700333 }
334 }
manojkiraneda2a133282019-02-19 13:09:43 +0530335 else if (propertyPair.first == "DHCPEnabled")
336 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700337 const std::string* dhcpEnabled =
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700338 std::get_if<std::string>(&propertyPair.second);
Ed Tanous2c70f802020-09-28 14:29:23 -0700339 if (dhcpEnabled != nullptr)
manojkiraneda2a133282019-02-19 13:09:43 +0530340 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800341 ethData.dhcpEnabled = *dhcpEnabled;
manojkiraneda2a133282019-02-19 13:09:43 +0530342 }
343 }
Jennifer Leed24bfc72019-03-05 13:03:37 -0800344 else if (propertyPair.first == "DomainName")
345 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500346 const std::vector<std::string>* domainNames =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500347 std::get_if<std::vector<std::string>>(
Jennifer Leed24bfc72019-03-05 13:03:37 -0800348 &propertyPair.second);
349 if (domainNames != nullptr)
350 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700351 ethData.domainnames = *domainNames;
Jennifer Leed24bfc72019-03-05 13:03:37 -0800352 }
353 }
Ravi Teja9010ec22019-08-01 23:30:25 -0500354 else if (propertyPair.first == "DefaultGateway")
355 {
356 const std::string* defaultGateway =
357 std::get_if<std::string>(&propertyPair.second);
358 if (defaultGateway != nullptr)
359 {
360 std::string defaultGatewayStr = *defaultGateway;
361 if (defaultGatewayStr.empty())
362 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800363 ethData.defaultGateway = "0.0.0.0";
Ravi Teja9010ec22019-08-01 23:30:25 -0500364 }
365 else
366 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800367 ethData.defaultGateway = defaultGatewayStr;
Ravi Teja9010ec22019-08-01 23:30:25 -0500368 }
369 }
370 }
371 else if (propertyPair.first == "DefaultGateway6")
372 {
373 const std::string* defaultGateway6 =
374 std::get_if<std::string>(&propertyPair.second);
375 if (defaultGateway6 != nullptr)
376 {
377 std::string defaultGateway6Str =
378 *defaultGateway6;
379 if (defaultGateway6Str.empty())
380 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800381 ethData.ipv6DefaultGateway =
Ravi Teja9010ec22019-08-01 23:30:25 -0500382 "0:0:0:0:0:0:0:0";
383 }
384 else
385 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800386 ethData.ipv6DefaultGateway =
Ravi Teja9010ec22019-08-01 23:30:25 -0500387 defaultGateway6Str;
388 }
389 }
390 }
Ed Tanous029573d2019-02-01 10:57:49 -0800391 }
392 }
393 }
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700394
Jishnu CMe4588152023-05-11 00:04:40 -0500395 sdbusplus::message::object_path path(
396 "/xyz/openbmc_project/network");
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400397 sdbusplus::message::object_path dhcp4Path =
398 path / ethifaceId / "dhcp4";
Jishnu CMe4588152023-05-11 00:04:40 -0500399
400 if (sdbusplus::message::object_path(objpath.first) == dhcp4Path)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700401 {
402 if (ifacePair.first ==
403 "xyz.openbmc_project.Network.DHCPConfiguration")
404 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500405 for (const auto& propertyPair : ifacePair.second)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700406 {
407 if (propertyPair.first == "DNSEnabled")
408 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700409 const bool* dnsEnabled =
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700410 std::get_if<bool>(&propertyPair.second);
Ed Tanous2c70f802020-09-28 14:29:23 -0700411 if (dnsEnabled != nullptr)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700412 {
Jishnu CMe4588152023-05-11 00:04:40 -0500413 ethData.dnsv4Enabled = *dnsEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700414 }
415 }
Ravi Teja91c441e2024-02-23 09:03:43 -0600416 else if (propertyPair.first == "DomainEnabled")
417 {
418 const bool* domainEnabled =
419 std::get_if<bool>(&propertyPair.second);
420 if (domainEnabled != nullptr)
421 {
422 ethData.domainv4Enabled = *domainEnabled;
423 }
424 }
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700425 else if (propertyPair.first == "NTPEnabled")
426 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700427 const bool* ntpEnabled =
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700428 std::get_if<bool>(&propertyPair.second);
Ed Tanous2c70f802020-09-28 14:29:23 -0700429 if (ntpEnabled != nullptr)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700430 {
Jishnu CMe4588152023-05-11 00:04:40 -0500431 ethData.ntpv4Enabled = *ntpEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700432 }
433 }
434 else if (propertyPair.first == "HostNameEnabled")
435 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700436 const bool* hostNameEnabled =
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700437 std::get_if<bool>(&propertyPair.second);
Ed Tanous2c70f802020-09-28 14:29:23 -0700438 if (hostNameEnabled != nullptr)
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700439 {
Jishnu CMe4588152023-05-11 00:04:40 -0500440 ethData.hostNamev4Enabled = *hostNameEnabled;
441 }
442 }
443 }
444 }
445 }
446
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400447 sdbusplus::message::object_path dhcp6Path =
448 path / ethifaceId / "dhcp6";
Jishnu CMe4588152023-05-11 00:04:40 -0500449
450 if (sdbusplus::message::object_path(objpath.first) == dhcp6Path)
451 {
452 if (ifacePair.first ==
453 "xyz.openbmc_project.Network.DHCPConfiguration")
454 {
455 for (const auto& propertyPair : ifacePair.second)
456 {
457 if (propertyPair.first == "DNSEnabled")
458 {
459 const bool* dnsEnabled =
460 std::get_if<bool>(&propertyPair.second);
461 if (dnsEnabled != nullptr)
462 {
463 ethData.dnsv6Enabled = *dnsEnabled;
464 }
465 }
Ravi Teja91c441e2024-02-23 09:03:43 -0600466 if (propertyPair.first == "DomainEnabled")
467 {
468 const bool* domainEnabled =
469 std::get_if<bool>(&propertyPair.second);
470 if (domainEnabled != nullptr)
471 {
472 ethData.domainv6Enabled = *domainEnabled;
473 }
474 }
Jishnu CMe4588152023-05-11 00:04:40 -0500475 else if (propertyPair.first == "NTPEnabled")
476 {
477 const bool* ntpEnabled =
478 std::get_if<bool>(&propertyPair.second);
479 if (ntpEnabled != nullptr)
480 {
481 ethData.ntpv6Enabled = *ntpEnabled;
482 }
483 }
484 else if (propertyPair.first == "HostNameEnabled")
485 {
486 const bool* hostNameEnabled =
487 std::get_if<bool>(&propertyPair.second);
488 if (hostNameEnabled != nullptr)
489 {
490 ethData.hostNamev6Enabled = *hostNameEnabled;
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700491 }
492 }
Johnathan Mantey1f8c7b52019-06-18 12:44:21 -0700493 }
494 }
495 }
Ed Tanous029573d2019-02-01 10:57:49 -0800496 // System configuration shows up in the global namespace, so no need
497 // to check eth number
498 if (ifacePair.first ==
499 "xyz.openbmc_project.Network.SystemConfiguration")
500 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500501 for (const auto& propertyPair : ifacePair.second)
Ed Tanous029573d2019-02-01 10:57:49 -0800502 {
503 if (propertyPair.first == "HostName")
504 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500505 const std::string* hostname =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500506 std::get_if<std::string>(&propertyPair.second);
Ed Tanous029573d2019-02-01 10:57:49 -0800507 if (hostname != nullptr)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700508 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +0800509 ethData.hostName = *hostname;
Ed Tanous029573d2019-02-01 10:57:49 -0800510 }
511 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700512 }
513 }
514 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700515 }
Ed Tanous4c9afe42019-05-03 16:59:57 -0700516 return idFound;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700517}
518
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500519// Helper function that extracts data for single ethernet ipv6 address
Ed Tanous77179532023-02-28 10:45:28 -0800520inline void extractIPV6Data(const std::string& ethifaceId,
521 const dbus::utility::ManagedObjectType& dbusData,
522 std::vector<IPv6AddressData>& ipv6Config)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500523{
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400524 const std::string ipPathStart =
525 "/xyz/openbmc_project/network/" + ethifaceId;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500526
527 // Since there might be several IPv6 configurations aligned with
528 // single ethernet interface, loop over all of them
Ed Tanous81ce6092020-12-17 16:54:55 +0000529 for (const auto& objpath : dbusData)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500530 {
531 // Check if proper pattern for object path appears
Tony Lee353163e2022-11-23 11:06:10 +0800532 if (objpath.first.str.starts_with(ipPathStart + "/"))
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500533 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800534 for (const auto& interface : objpath.second)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500535 {
536 if (interface.first == "xyz.openbmc_project.Network.IP")
537 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400538 auto type = std::ranges::find_if(
539 interface.second, [](const auto& property) {
540 return property.first == "Type";
541 });
Tony Lee353163e2022-11-23 11:06:10 +0800542 if (type == interface.second.end())
543 {
544 continue;
545 }
546
547 const std::string* typeStr =
548 std::get_if<std::string>(&type->second);
549
550 if (typeStr == nullptr ||
551 (*typeStr !=
552 "xyz.openbmc_project.Network.IP.Protocol.IPv6"))
553 {
554 continue;
555 }
556
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500557 // Instance IPv6AddressData structure, and set as
558 // appropriate
Ed Tanous77179532023-02-28 10:45:28 -0800559 IPv6AddressData& ipv6Address = ipv6Config.emplace_back();
Ed Tanous2c70f802020-09-28 14:29:23 -0700560 ipv6Address.id =
Tony Lee353163e2022-11-23 11:06:10 +0800561 objpath.first.str.substr(ipPathStart.size());
Ed Tanous9eb808c2022-01-25 10:19:23 -0800562 for (const auto& property : interface.second)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500563 {
564 if (property.first == "Address")
565 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500566 const std::string* address =
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500567 std::get_if<std::string>(&property.second);
568 if (address != nullptr)
569 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700570 ipv6Address.address = *address;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500571 }
572 }
573 else if (property.first == "Origin")
574 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500575 const std::string* origin =
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500576 std::get_if<std::string>(&property.second);
577 if (origin != nullptr)
578 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700579 ipv6Address.origin =
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500580 translateAddressOriginDbusToRedfish(*origin,
581 false);
582 }
583 }
584 else if (property.first == "PrefixLength")
585 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500586 const uint8_t* prefix =
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500587 std::get_if<uint8_t>(&property.second);
588 if (prefix != nullptr)
589 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700590 ipv6Address.prefixLength = *prefix;
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500591 }
592 }
Asmitha Karunanithi889ff692021-11-29 08:43:30 -0600593 else if (property.first == "Type" ||
594 property.first == "Gateway")
595 {
596 // Type & Gateway is not used
597 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500598 else
599 {
Ed Tanous62598e32023-07-17 17:06:25 -0700600 BMCWEB_LOG_ERROR(
601 "Got extra property: {} on the {} object",
602 property.first, objpath.first.str);
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500603 }
604 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500605 }
606 }
607 }
608 }
609}
610
Ed Tanous4a0cb852018-10-15 07:55:04 -0700611// Helper function that extracts data for single ethernet ipv4 address
Ed Tanous77179532023-02-28 10:45:28 -0800612inline void extractIPData(const std::string& ethifaceId,
613 const dbus::utility::ManagedObjectType& dbusData,
614 std::vector<IPv4AddressData>& ipv4Config)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700615{
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400616 const std::string ipPathStart =
617 "/xyz/openbmc_project/network/" + ethifaceId;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700618
619 // Since there might be several IPv4 configurations aligned with
620 // single ethernet interface, loop over all of them
Ed Tanous81ce6092020-12-17 16:54:55 +0000621 for (const auto& objpath : dbusData)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700622 {
623 // Check if proper pattern for object path appears
Tony Lee353163e2022-11-23 11:06:10 +0800624 if (objpath.first.str.starts_with(ipPathStart + "/"))
Ed Tanous4a0cb852018-10-15 07:55:04 -0700625 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800626 for (const auto& interface : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700627 {
628 if (interface.first == "xyz.openbmc_project.Network.IP")
629 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400630 auto type = std::ranges::find_if(
631 interface.second, [](const auto& property) {
632 return property.first == "Type";
633 });
Tony Lee353163e2022-11-23 11:06:10 +0800634 if (type == interface.second.end())
635 {
636 continue;
637 }
638
639 const std::string* typeStr =
640 std::get_if<std::string>(&type->second);
641
642 if (typeStr == nullptr ||
643 (*typeStr !=
644 "xyz.openbmc_project.Network.IP.Protocol.IPv4"))
645 {
646 continue;
647 }
648
Ed Tanous4a0cb852018-10-15 07:55:04 -0700649 // Instance IPv4AddressData structure, and set as
650 // appropriate
Ed Tanous77179532023-02-28 10:45:28 -0800651 IPv4AddressData& ipv4Address = ipv4Config.emplace_back();
Ed Tanous2c70f802020-09-28 14:29:23 -0700652 ipv4Address.id =
Tony Lee353163e2022-11-23 11:06:10 +0800653 objpath.first.str.substr(ipPathStart.size());
Ed Tanous9eb808c2022-01-25 10:19:23 -0800654 for (const auto& property : interface.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700655 {
656 if (property.first == "Address")
657 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500658 const std::string* address =
Ed Tanousabf2add2019-01-22 16:40:12 -0800659 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700660 if (address != nullptr)
661 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700662 ipv4Address.address = *address;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700663 }
664 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700665 else if (property.first == "Origin")
666 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500667 const std::string* origin =
Ed Tanousabf2add2019-01-22 16:40:12 -0800668 std::get_if<std::string>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700669 if (origin != nullptr)
670 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700671 ipv4Address.origin =
Ed Tanous4a0cb852018-10-15 07:55:04 -0700672 translateAddressOriginDbusToRedfish(*origin,
673 true);
674 }
675 }
676 else if (property.first == "PrefixLength")
677 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500678 const uint8_t* mask =
Ed Tanousabf2add2019-01-22 16:40:12 -0800679 std::get_if<uint8_t>(&property.second);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700680 if (mask != nullptr)
681 {
682 // convert it to the string
Ed Tanous2c70f802020-09-28 14:29:23 -0700683 ipv4Address.netmask = getNetmask(*mask);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700684 }
685 }
Asmitha Karunanithi889ff692021-11-29 08:43:30 -0600686 else if (property.first == "Type" ||
687 property.first == "Gateway")
688 {
689 // Type & Gateway is not used
690 }
Ed Tanous4a0cb852018-10-15 07:55:04 -0700691 else
692 {
Ed Tanous62598e32023-07-17 17:06:25 -0700693 BMCWEB_LOG_ERROR(
694 "Got extra property: {} on the {} object",
695 property.first, objpath.first.str);
Ed Tanous4a0cb852018-10-15 07:55:04 -0700696 }
697 }
698 // Check if given address is local, or global
Ed Tanous2c70f802020-09-28 14:29:23 -0700699 ipv4Address.linktype =
Ed Tanous11ba3972022-07-11 09:50:41 -0700700 ipv4Address.address.starts_with("169.254.")
Johnathan Mantey18659d12019-06-07 10:26:29 -0700701 ? LinkType::Local
702 : LinkType::Global;
Ed Tanous4a0cb852018-10-15 07:55:04 -0700703 }
704 }
705 }
706 }
707}
708
709/**
Johnathan Mantey743eb1c2024-04-03 12:05:57 -0700710 * @brief Modifies the default gateway assigned to the NIC
711 *
712 * @param[in] ifaceId Id of network interface whose default gateway is to be
713 * changed
714 * @param[in] gateway The new gateway value. Assigning an empty string
715 * causes the gateway to be deleted
716 * @param[io] asyncResp Response object that will be returned to client
717 *
718 * @return None
719 */
720inline void updateIPv4DefaultGateway(
721 const std::string& ifaceId, const std::string& gateway,
722 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
723{
724 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +0530725 asyncResp, "Gateway", "xyz.openbmc_project.Network",
Johnathan Mantey743eb1c2024-04-03 12:05:57 -0700726 sdbusplus::message::object_path("/xyz/openbmc_project/network") /
727 ifaceId,
728 "xyz.openbmc_project.Network.EthernetInterface", "DefaultGateway",
Ginu Georgee93abac2024-06-14 17:35:27 +0530729 gateway);
Johnathan Mantey743eb1c2024-04-03 12:05:57 -0700730}
731
732/**
733 * @brief Deletes given static IP address for the interface
Ed Tanous4a0cb852018-10-15 07:55:04 -0700734 *
735 * @param[in] ifaceId Id of interface whose IP should be deleted
Ed Tanous4a0cb852018-10-15 07:55:04 -0700736 * @param[in] ipHash DBus Hash id of IP that should be deleted
737 * @param[io] asyncResp Response object that will be returned to client
738 *
739 * @return None
740 */
Ravi Teja9c5e5852023-02-26 21:33:52 -0600741inline void deleteIPAddress(const std::string& ifaceId,
742 const std::string& ipHash,
743 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700744{
745 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800746 [asyncResp](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400747 if (ec)
748 {
749 messages::internalError(asyncResp->res);
750 }
751 },
Ed Tanous4a0cb852018-10-15 07:55:04 -0700752 "xyz.openbmc_project.Network",
Ravi Teja9c5e5852023-02-26 21:33:52 -0600753 "/xyz/openbmc_project/network/" + ifaceId + ipHash,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700754 "xyz.openbmc_project.Object.Delete", "Delete");
755}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700756
Ed Tanous4a0cb852018-10-15 07:55:04 -0700757/**
Johnathan Mantey01784822019-06-18 12:44:21 -0700758 * @brief Creates a static IPv4 entry
Ed Tanous4a0cb852018-10-15 07:55:04 -0700759 *
Johnathan Mantey01784822019-06-18 12:44:21 -0700760 * @param[in] ifaceId Id of interface upon which to create the IPv4 entry
761 * @param[in] prefixLength IPv4 prefix syntax for the subnet mask
762 * @param[in] gateway IPv4 address of this interfaces gateway
763 * @param[in] address IPv4 address to assign to this interface
764 * @param[io] asyncResp Response object that will be returned to client
Ed Tanous4a0cb852018-10-15 07:55:04 -0700765 *
766 * @return None
767 */
Ed Tanouscb13a392020-07-25 19:02:03 +0000768inline void createIPv4(const std::string& ifaceId, uint8_t prefixLength,
769 const std::string& gateway, const std::string& address,
zhanghch058d1b46d2021-04-01 11:18:24 +0800770 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous4a0cb852018-10-15 07:55:04 -0700771{
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400772 auto createIpHandler =
773 [asyncResp, ifaceId, gateway](const boost::system::error_code& ec) {
774 if (ec)
775 {
776 messages::internalError(asyncResp->res);
777 return;
778 }
779 };
Ravi Teja9010ec22019-08-01 23:30:25 -0500780
Ed Tanous4a0cb852018-10-15 07:55:04 -0700781 crow::connections::systemBus->async_method_call(
Ravi Teja9010ec22019-08-01 23:30:25 -0500782 std::move(createIpHandler), "xyz.openbmc_project.Network",
Ed Tanous4a0cb852018-10-15 07:55:04 -0700783 "/xyz/openbmc_project/network/" + ifaceId,
784 "xyz.openbmc_project.Network.IP.Create", "IP",
Johnathan Mantey01784822019-06-18 12:44:21 -0700785 "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, prefixLength,
Ed Tanous4a0cb852018-10-15 07:55:04 -0700786 gateway);
787}
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500788
789/**
Johnathan Mantey743eb1c2024-04-03 12:05:57 -0700790 * @brief Deletes the IP entry for this interface and creates a replacement
791 * static entry
Johnathan Mantey01784822019-06-18 12:44:21 -0700792 *
Johnathan Mantey743eb1c2024-04-03 12:05:57 -0700793 * @param[in] ifaceId Id of interface upon which to create the IPv6 entry
794 * @param[in] id The unique hash entry identifying the DBus entry
795 * @param[in] prefixLength Prefix syntax for the subnet mask
796 * @param[in] address Address to assign to this interface
797 * @param[in] numStaticAddrs Count of IPv4 static addresses
798 * @param[io] asyncResp Response object that will be returned to client
Johnathan Mantey01784822019-06-18 12:44:21 -0700799 *
800 * @return None
801 */
Ravi Teja9c5e5852023-02-26 21:33:52 -0600802
Ravi Teja9c5e5852023-02-26 21:33:52 -0600803inline void deleteAndCreateIPAddress(
804 IpVersion version, const std::string& ifaceId, const std::string& id,
805 uint8_t prefixLength, const std::string& address,
806 const std::string& gateway,
807 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Johnathan Mantey01784822019-06-18 12:44:21 -0700808{
809 crow::connections::systemBus->async_method_call(
Ravi Teja9c5e5852023-02-26 21:33:52 -0600810 [asyncResp, version, ifaceId, address, prefixLength,
811 gateway](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400812 if (ec)
Johnathan Mantey01784822019-06-18 12:44:21 -0700813 {
814 messages::internalError(asyncResp->res);
815 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400816 std::string protocol = "xyz.openbmc_project.Network.IP.Protocol.";
817 protocol += version == IpVersion::IpV4 ? "IPv4" : "IPv6";
818 crow::connections::systemBus->async_method_call(
819 [asyncResp](const boost::system::error_code& ec2) {
820 if (ec2)
821 {
822 messages::internalError(asyncResp->res);
823 }
824 },
825 "xyz.openbmc_project.Network",
826 "/xyz/openbmc_project/network/" + ifaceId,
827 "xyz.openbmc_project.Network.IP.Create", "IP", protocol,
828 address, prefixLength, gateway);
Patrick Williams5a39f772023-10-20 11:20:21 -0500829 },
Johnathan Mantey01784822019-06-18 12:44:21 -0700830 "xyz.openbmc_project.Network",
Ravi Teja9c5e5852023-02-26 21:33:52 -0600831 "/xyz/openbmc_project/network/" + ifaceId + id,
Johnathan Mantey01784822019-06-18 12:44:21 -0700832 "xyz.openbmc_project.Object.Delete", "Delete");
833}
834
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500835inline bool extractIPv6DefaultGatewayData(
836 const std::string& ethifaceId,
837 const dbus::utility::ManagedObjectType& dbusData,
838 std::vector<StaticGatewayData>& staticGatewayConfig)
839{
840 std::string staticGatewayPathStart("/xyz/openbmc_project/network/");
841 staticGatewayPathStart += ethifaceId;
842
843 for (const auto& objpath : dbusData)
844 {
845 if (!std::string_view(objpath.first.str)
846 .starts_with(staticGatewayPathStart))
847 {
848 continue;
849 }
850 for (const auto& interface : objpath.second)
851 {
852 if (interface.first != "xyz.openbmc_project.Network.StaticGateway")
853 {
854 continue;
855 }
856 StaticGatewayData& staticGateway =
857 staticGatewayConfig.emplace_back();
858 staticGateway.id = objpath.first.filename();
859
860 bool success = sdbusplus::unpackPropertiesNoThrow(
861 redfish::dbus_utils::UnpackErrorPrinter(), interface.second,
Ravi Tejaab0d4392024-09-03 12:27:40 -0500862 "Gateway", staticGateway.gateway, "ProtocolType",
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500863 staticGateway.protocol);
864 if (!success)
865 {
866 return false;
867 }
868 }
869 }
870 return true;
871}
872
Johnathan Mantey01784822019-06-18 12:44:21 -0700873/**
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500874 * @brief Creates IPv6 with given data
875 *
876 * @param[in] ifaceId Id of interface whose IP should be added
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500877 * @param[in] prefixLength Prefix length that needs to be added
878 * @param[in] address IP address that needs to be added
879 * @param[io] asyncResp Response object that will be returned to client
880 *
881 * @return None
882 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500883inline void createIPv6(const std::string& ifaceId, uint8_t prefixLength,
884 const std::string& address,
zhanghch058d1b46d2021-04-01 11:18:24 +0800885 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500886{
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500887 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
888 path /= ifaceId;
889
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400890 auto createIpHandler =
891 [asyncResp, address](const boost::system::error_code& ec) {
892 if (ec)
Nitin Kumar Kotaniafc23ef82023-06-29 04:55:09 -0500893 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400894 if (ec == boost::system::errc::io_error)
895 {
896 messages::propertyValueFormatError(asyncResp->res, address,
897 "Address");
898 }
899 else
900 {
901 messages::internalError(asyncResp->res);
902 }
Nitin Kumar Kotaniafc23ef82023-06-29 04:55:09 -0500903 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400904 };
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500905 // Passing null for gateway, as per redfish spec IPv6StaticAddresses
906 // object does not have associated gateway property
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500907 crow::connections::systemBus->async_method_call(
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500908 std::move(createIpHandler), "xyz.openbmc_project.Network", path,
Ravi Tejae48c0fc2019-04-16 08:37:20 -0500909 "xyz.openbmc_project.Network.IP.Create", "IP",
910 "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
911 "");
912}
913
Ed Tanous4a0cb852018-10-15 07:55:04 -0700914/**
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500915 * @brief Deletes given IPv6 Static Gateway
916 *
917 * @param[in] ifaceId Id of interface whose IP should be deleted
918 * @param[in] ipHash DBus Hash id of IP that should be deleted
919 * @param[io] asyncResp Response object that will be returned to client
920 *
921 * @return None
922 */
923inline void
Ravi Teja739b27b2024-08-27 21:03:53 -0500924 deleteIPv6Gateway(std::string_view ifaceId, std::string_view gatewayId,
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500925 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
926{
927 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
Ravi Teja739b27b2024-08-27 21:03:53 -0500928 path /= ifaceId;
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500929 path /= gatewayId;
930 crow::connections::systemBus->async_method_call(
931 [asyncResp](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400932 if (ec)
933 {
934 messages::internalError(asyncResp->res);
935 }
936 },
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500937 "xyz.openbmc_project.Network", path,
938 "xyz.openbmc_project.Object.Delete", "Delete");
939}
940
941/**
942 * @brief Creates IPv6 static default gateway with given data
943 *
944 * @param[in] ifaceId Id of interface whose IP should be added
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500945 * @param[in] gateway Gateway address that needs to be added
946 * @param[io] asyncResp Response object that will be returned to client
947 *
948 * @return None
949 */
950inline void createIPv6DefaultGateway(
Ravi Tejaab0d4392024-09-03 12:27:40 -0500951 std::string_view ifaceId, std::string_view gateway,
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500952 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
953{
954 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
955 path /= ifaceId;
956 auto createIpHandler = [asyncResp](const boost::system::error_code& ec) {
957 if (ec)
958 {
959 messages::internalError(asyncResp->res);
960 }
961 };
962 crow::connections::systemBus->async_method_call(
963 std::move(createIpHandler), "xyz.openbmc_project.Network", path,
964 "xyz.openbmc_project.Network.StaticGateway.Create", "StaticGateway",
Ravi Tejaab0d4392024-09-03 12:27:40 -0500965 gateway, "xyz.openbmc_project.Network.IP.Protocol.IPv6");
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500966}
967
968/**
969 * @brief Deletes the IPv6 default gateway entry for this interface and
970 * creates a replacement IPv6 default gateway entry
971 *
972 * @param[in] ifaceId Id of interface upon which to create the IPv6
973 * entry
974 * @param[in] gateway IPv6 gateway to assign to this interface
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500975 * @param[io] asyncResp Response object that will be returned to client
976 *
977 * @return None
978 */
979inline void deleteAndCreateIPv6DefaultGateway(
980 std::string_view ifaceId, std::string_view gatewayId,
Ravi Tejaab0d4392024-09-03 12:27:40 -0500981 std::string_view gateway,
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500982 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
983{
984 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
Ravi Teja739b27b2024-08-27 21:03:53 -0500985 path /= ifaceId;
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500986 path /= gatewayId;
987 crow::connections::systemBus->async_method_call(
Ravi Tejaab0d4392024-09-03 12:27:40 -0500988 [asyncResp, ifaceId, gateway](const boost::system::error_code& ec) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400989 if (ec)
990 {
991 messages::internalError(asyncResp->res);
992 return;
993 }
Ravi Tejaab0d4392024-09-03 12:27:40 -0500994 createIPv6DefaultGateway(ifaceId, gateway, asyncResp);
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400995 },
Sunitha Harishce73d5c2023-04-07 06:46:49 -0500996 "xyz.openbmc_project.Network", path,
997 "xyz.openbmc_project.Object.Delete", "Delete");
998}
999
1000/**
1001 * @brief Sets IPv6 default gateway with given data
1002 *
1003 * @param[in] ifaceId Id of interface whose gateway should be added
1004 * @param[in] input Contains address that needs to be added
1005 * @param[in] staticGatewayData Current static gateways in the system
1006 * @param[io] asyncResp Response object that will be returned to client
1007 *
1008 * @return None
1009 */
1010
1011inline void handleIPv6DefaultGateway(
Ed Tanous3dfed532024-03-06 14:41:27 -08001012 const std::string& ifaceId,
1013 std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>& input,
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001014 const std::vector<StaticGatewayData>& staticGatewayData,
1015 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1016{
1017 size_t entryIdx = 1;
1018 std::vector<StaticGatewayData>::const_iterator staticGatewayEntry =
1019 staticGatewayData.begin();
1020
Ed Tanous3dfed532024-03-06 14:41:27 -08001021 for (std::variant<nlohmann::json::object_t, std::nullptr_t>& thisJson :
1022 input)
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001023 {
1024 // find the next gateway entry
1025 while (staticGatewayEntry != staticGatewayData.end())
1026 {
1027 if (staticGatewayEntry->protocol ==
1028 "xyz.openbmc_project.Network.IP.Protocol.IPv6")
1029 {
1030 break;
1031 }
1032 staticGatewayEntry++;
1033 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001034 std::string pathString =
1035 "IPv6StaticDefaultGateways/" + std::to_string(entryIdx);
Ed Tanous3dfed532024-03-06 14:41:27 -08001036 nlohmann::json::object_t* obj =
1037 std::get_if<nlohmann::json::object_t>(&thisJson);
1038 if (obj == nullptr)
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001039 {
1040 if (staticGatewayEntry == staticGatewayData.end())
1041 {
1042 messages::resourceCannotBeDeleted(asyncResp->res);
1043 return;
1044 }
Ravi Teja739b27b2024-08-27 21:03:53 -05001045 deleteIPv6Gateway(ifaceId, staticGatewayEntry->id, asyncResp);
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001046 return;
1047 }
Ed Tanous3dfed532024-03-06 14:41:27 -08001048 if (obj->empty())
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001049 {
1050 // Do nothing, but make sure the entry exists.
1051 if (staticGatewayEntry == staticGatewayData.end())
1052 {
Ed Tanous3dfed532024-03-06 14:41:27 -08001053 messages::propertyValueFormatError(asyncResp->res, *obj,
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001054 pathString);
1055 return;
1056 }
1057 }
1058 std::optional<std::string> address;
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001059
Ravi Tejaab0d4392024-09-03 12:27:40 -05001060 if (!json_util::readJsonObject(*obj, asyncResp->res, "Address",
1061 address))
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001062 {
1063 return;
1064 }
1065 const std::string* addr = nullptr;
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001066 if (address)
1067 {
1068 addr = &(*address);
1069 }
1070 else if (staticGatewayEntry != staticGatewayData.end())
1071 {
1072 addr = &(staticGatewayEntry->gateway);
1073 }
1074 else
1075 {
1076 messages::propertyMissing(asyncResp->res, pathString + "/Address");
1077 return;
1078 }
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001079 if (staticGatewayEntry != staticGatewayData.end())
1080 {
1081 deleteAndCreateIPv6DefaultGateway(ifaceId, staticGatewayEntry->id,
Ravi Tejaab0d4392024-09-03 12:27:40 -05001082 *addr, asyncResp);
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001083 staticGatewayEntry++;
1084 }
1085 else
1086 {
Ravi Tejaab0d4392024-09-03 12:27:40 -05001087 createIPv6DefaultGateway(ifaceId, *addr, asyncResp);
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001088 }
1089 entryIdx++;
1090 }
1091}
1092
1093/**
Ed Tanous4a0cb852018-10-15 07:55:04 -07001094 * Function that retrieves all properties for given Ethernet Interface
1095 * Object
1096 * from EntityManager Network Manager
1097 * @param ethiface_id a eth interface id to query on DBus
1098 * @param callback a function that shall be called to convert Dbus output
1099 * into JSON
1100 */
1101template <typename CallbackFunc>
Ed Tanous81ce6092020-12-17 16:54:55 +00001102void getEthernetIfaceData(const std::string& ethifaceId,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001103 CallbackFunc&& callback)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001104{
George Liuf5892d02023-03-01 10:37:08 +08001105 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
1106 dbus::utility::getManagedObjects(
1107 "xyz.openbmc_project.Network", path,
Ed Tanousf94c4ec2022-01-06 12:44:41 -08001108 [ethifaceId{std::string{ethifaceId}},
Ed Tanous8cb2c022024-03-27 16:31:46 -07001109 callback = std::forward<CallbackFunc>(callback)](
Ed Tanous8b242752023-06-27 17:17:13 -07001110 const boost::system::error_code& ec,
Ed Tanous3dfed532024-03-06 14:41:27 -08001111 const dbus::utility::ManagedObjectType& resp) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001112 EthernetInterfaceData ethData{};
1113 std::vector<IPv4AddressData> ipv4Data;
1114 std::vector<IPv6AddressData> ipv6Data;
1115 std::vector<StaticGatewayData> ipv6GatewayData;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001116
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001117 if (ec)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001118 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001119 callback(false, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
1120 return;
Ed Tanous4a0cb852018-10-15 07:55:04 -07001121 }
1122
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001123 bool found =
1124 extractEthernetInterfaceData(ethifaceId, resp, ethData);
1125 if (!found)
1126 {
1127 callback(false, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
1128 return;
1129 }
1130
1131 extractIPData(ethifaceId, resp, ipv4Data);
1132 // Fix global GW
1133 for (IPv4AddressData& ipv4 : ipv4Data)
1134 {
1135 if (((ipv4.linktype == LinkType::Global) &&
1136 (ipv4.gateway == "0.0.0.0")) ||
1137 (ipv4.origin == "DHCP") || (ipv4.origin == "Static"))
1138 {
1139 ipv4.gateway = ethData.defaultGateway;
1140 }
1141 }
1142
1143 extractIPV6Data(ethifaceId, resp, ipv6Data);
1144 if (!extractIPv6DefaultGatewayData(ethifaceId, resp,
1145 ipv6GatewayData))
1146 {
1147 callback(false, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
1148 }
1149 // Finally make a callback with useful data
1150 callback(true, ethData, ipv4Data, ipv6Data, ipv6GatewayData);
1151 });
Ed Tanous271584a2019-07-09 16:24:22 -07001152}
Ed Tanous4a0cb852018-10-15 07:55:04 -07001153
1154/**
1155 * Function that retrieves all Ethernet Interfaces available through Network
1156 * Manager
1157 * @param callback a function that shall be called to convert Dbus output
1158 * into JSON.
1159 */
1160template <typename CallbackFunc>
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001161void getEthernetIfaceList(CallbackFunc&& callback)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001162{
George Liuf5892d02023-03-01 10:37:08 +08001163 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
1164 dbus::utility::getManagedObjects(
1165 "xyz.openbmc_project.Network", path,
Ed Tanous8cb2c022024-03-27 16:31:46 -07001166 [callback = std::forward<CallbackFunc>(callback)](
Ed Tanous8b242752023-06-27 17:17:13 -07001167 const boost::system::error_code& ec,
George Liuf5892d02023-03-01 10:37:08 +08001168 const dbus::utility::ManagedObjectType& resp) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001169 // Callback requires vector<string> to retrieve all available
1170 // ethernet interfaces
1171 std::vector<std::string> ifaceList;
1172 ifaceList.reserve(resp.size());
1173 if (ec)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001174 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001175 callback(false, ifaceList);
1176 return;
1177 }
1178
1179 // Iterate over all retrieved ObjectPaths.
1180 for (const auto& objpath : resp)
1181 {
1182 // And all interfaces available for certain ObjectPath.
1183 for (const auto& interface : objpath.second)
Ed Tanous4a0cb852018-10-15 07:55:04 -07001184 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001185 // If interface is
1186 // xyz.openbmc_project.Network.EthernetInterface, this is
1187 // what we're looking for.
1188 if (interface.first ==
1189 "xyz.openbmc_project.Network.EthernetInterface")
Ed Tanous1abe55e2018-09-05 08:30:59 -07001190 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001191 std::string ifaceId = objpath.first.filename();
1192 if (ifaceId.empty())
1193 {
1194 continue;
1195 }
1196 // and put it into output vector.
1197 ifaceList.emplace_back(ifaceId);
Ed Tanous1abe55e2018-09-05 08:30:59 -07001198 }
1199 }
Ed Tanous4a0cb852018-10-15 07:55:04 -07001200 }
Ed Tanous2c5875a2023-05-15 09:56:06 -07001201
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001202 std::ranges::sort(ifaceList, AlphanumLess<std::string>());
Ed Tanous2c5875a2023-05-15 09:56:06 -07001203
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001204 // Finally make a callback with useful data
1205 callback(true, ifaceList);
1206 });
Ed Tanous271584a2019-07-09 16:24:22 -07001207}
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001208
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001209inline void
1210 handleHostnamePatch(const std::string& hostname,
1211 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001212{
Ed Tanousbf648f72021-06-03 15:00:14 -07001213 // SHOULD handle host names of up to 255 characters(RFC 1123)
1214 if (hostname.length() > 255)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001215 {
Ed Tanousbf648f72021-06-03 15:00:14 -07001216 messages::propertyValueFormatError(asyncResp->res, hostname,
1217 "HostName");
1218 return;
1219 }
Ed Tanousd02aad32024-02-13 14:43:34 -08001220 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301221 asyncResp, "HostName", "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08001222 sdbusplus::message::object_path("/xyz/openbmc_project/network/config"),
1223 "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
Ginu Georgee93abac2024-06-14 17:35:27 +05301224 hostname);
Ed Tanousbf648f72021-06-03 15:00:14 -07001225}
1226
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001227inline void
Tejas Patil35fb5312021-09-20 15:35:20 +05301228 handleMTUSizePatch(const std::string& ifaceId, const size_t mtuSize,
1229 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1230{
Ed Tanousd02aad32024-02-13 14:43:34 -08001231 sdbusplus::message::object_path objPath("/xyz/openbmc_project/network");
1232 objPath /= ifaceId;
Ginu Georgee93abac2024-06-14 17:35:27 +05301233 setDbusProperty(asyncResp, "MTUSize", "xyz.openbmc_project.Network",
1234 objPath, "xyz.openbmc_project.Network.EthernetInterface",
1235 "MTU", mtuSize);
Tejas Patil35fb5312021-09-20 15:35:20 +05301236}
1237
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001238inline void handleDomainnamePatch(
1239 const std::string& ifaceId, const std::string& domainname,
1240 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001241{
1242 std::vector<std::string> vectorDomainname = {domainname};
Ed Tanousd02aad32024-02-13 14:43:34 -08001243 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301244 asyncResp, "FQDN", "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08001245 sdbusplus::message::object_path("/xyz/openbmc_project/network") /
1246 ifaceId,
Ginu Georgee93abac2024-06-14 17:35:27 +05301247 "xyz.openbmc_project.Network.EthernetInterface", "DomainName",
Ed Tanousd02aad32024-02-13 14:43:34 -08001248 vectorDomainname);
Ed Tanousbf648f72021-06-03 15:00:14 -07001249}
1250
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001251inline bool isHostnameValid(const std::string& hostname)
Ed Tanousbf648f72021-06-03 15:00:14 -07001252{
1253 // A valid host name can never have the dotted-decimal form (RFC 1123)
Ed Tanous3544d2a2023-08-06 18:12:20 -07001254 if (std::ranges::all_of(hostname, ::isdigit))
Ed Tanousbf648f72021-06-03 15:00:14 -07001255 {
1256 return false;
1257 }
1258 // Each label(hostname/subdomains) within a valid FQDN
1259 // MUST handle host names of up to 63 characters (RFC 1123)
1260 // labels cannot start or end with hyphens (RFC 952)
1261 // labels can start with numbers (RFC 1123)
Ed Tanous4b242742023-05-11 09:51:51 -07001262 const static std::regex pattern(
Ed Tanousbf648f72021-06-03 15:00:14 -07001263 "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$");
1264
1265 return std::regex_match(hostname, pattern);
1266}
1267
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001268inline bool isDomainnameValid(const std::string& domainname)
Ed Tanousbf648f72021-06-03 15:00:14 -07001269{
1270 // Can have multiple subdomains
1271 // Top Level Domain's min length is 2 character
Ed Tanous4b242742023-05-11 09:51:51 -07001272 const static std::regex pattern(
George Liu0fda0f12021-11-16 10:06:17 +08001273 "^([A-Za-z0-9][a-zA-Z0-9\\-]{1,61}|[a-zA-Z0-9]{1,30}\\.)*[a-zA-Z]{2,}$");
Ed Tanousbf648f72021-06-03 15:00:14 -07001274
1275 return std::regex_match(domainname, pattern);
1276}
1277
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001278inline void handleFqdnPatch(const std::string& ifaceId, const std::string& fqdn,
1279 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001280{
1281 // Total length of FQDN must not exceed 255 characters(RFC 1035)
1282 if (fqdn.length() > 255)
1283 {
1284 messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN");
1285 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -07001286 }
1287
Ed Tanousbf648f72021-06-03 15:00:14 -07001288 size_t pos = fqdn.find('.');
1289 if (pos == std::string::npos)
Ed Tanous1abe55e2018-09-05 08:30:59 -07001290 {
Ed Tanousbf648f72021-06-03 15:00:14 -07001291 messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN");
1292 return;
1293 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001294
Ed Tanousbf648f72021-06-03 15:00:14 -07001295 std::string hostname;
1296 std::string domainname;
1297 domainname = (fqdn).substr(pos + 1);
1298 hostname = (fqdn).substr(0, pos);
1299
1300 if (!isHostnameValid(hostname) || !isDomainnameValid(domainname))
1301 {
1302 messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN");
1303 return;
1304 }
1305
1306 handleHostnamePatch(hostname, asyncResp);
1307 handleDomainnamePatch(ifaceId, domainname, asyncResp);
1308}
1309
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001310inline void handleMACAddressPatch(
1311 const std::string& ifaceId, const std::string& macAddress,
1312 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001313{
Ed Tanousd02aad32024-02-13 14:43:34 -08001314 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301315 asyncResp, "MACAddress", "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08001316 sdbusplus::message::object_path("/xyz/openbmc_project/network") /
1317 ifaceId,
Ginu Georgee93abac2024-06-14 17:35:27 +05301318 "xyz.openbmc_project.Network.MACAddress", "MACAddress", macAddress);
Ed Tanousbf648f72021-06-03 15:00:14 -07001319}
1320
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001321inline void setDHCPEnabled(const std::string& ifaceId,
1322 const std::string& propertyName, const bool v4Value,
1323 const bool v6Value,
1324 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001325{
1326 const std::string dhcp = getDhcpEnabledEnumeration(v4Value, v6Value);
Ed Tanousd02aad32024-02-13 14:43:34 -08001327 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301328 asyncResp, "DHCPv4", "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08001329 sdbusplus::message::object_path("/xyz/openbmc_project/network") /
1330 ifaceId,
Ginu Georgee93abac2024-06-14 17:35:27 +05301331 "xyz.openbmc_project.Network.EthernetInterface", propertyName, dhcp);
Ed Tanousbf648f72021-06-03 15:00:14 -07001332}
1333
Jishnu CMe4588152023-05-11 00:04:40 -05001334enum class NetworkType
1335{
1336 dhcp4,
1337 dhcp6
1338};
1339
1340inline void setDHCPConfig(const std::string& propertyName, const bool& value,
1341 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1342 const std::string& ethifaceId, NetworkType type)
Ed Tanousbf648f72021-06-03 15:00:14 -07001343{
Ed Tanous62598e32023-07-17 17:06:25 -07001344 BMCWEB_LOG_DEBUG("{} = {}", propertyName, value);
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001345 std::string redfishPropertyName;
Jishnu CMe4588152023-05-11 00:04:40 -05001346 sdbusplus::message::object_path path("/xyz/openbmc_project/network/");
1347 path /= ethifaceId;
1348
1349 if (type == NetworkType::dhcp4)
1350 {
1351 path /= "dhcp4";
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001352 redfishPropertyName = "DHCPv4";
Jishnu CMe4588152023-05-11 00:04:40 -05001353 }
1354 else
1355 {
1356 path /= "dhcp6";
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001357 redfishPropertyName = "DHCPv6";
Jishnu CMe4588152023-05-11 00:04:40 -05001358 }
1359
Ginu Georgee93abac2024-06-14 17:35:27 +05301360 setDbusProperty(
1361 asyncResp, redfishPropertyName, "xyz.openbmc_project.Network", path,
1362 "xyz.openbmc_project.Network.DHCPConfiguration", propertyName, value);
Ed Tanousbf648f72021-06-03 15:00:14 -07001363}
1364
Ravi Tejab10d8db2022-05-24 09:04:12 -05001365inline void handleSLAACAutoConfigPatch(
1366 const std::string& ifaceId, bool ipv6AutoConfigEnabled,
1367 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1368{
1369 sdbusplus::message::object_path path("/xyz/openbmc_project/network");
1370 path /= ifaceId;
Ginu Georgee93abac2024-06-14 17:35:27 +05301371 setDbusProperty(asyncResp,
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001372 "StatelessAddressAutoConfig/IPv6AutoConfigEnabled",
Ginu Georgee93abac2024-06-14 17:35:27 +05301373 "xyz.openbmc_project.Network", path,
1374 "xyz.openbmc_project.Network.EthernetInterface",
1375 "IPv6AcceptRA", ipv6AutoConfigEnabled);
Ravi Tejab10d8db2022-05-24 09:04:12 -05001376}
1377
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001378inline void handleDHCPPatch(
1379 const std::string& ifaceId, const EthernetInterfaceData& ethData,
1380 const DHCPParameters& v4dhcpParms, const DHCPParameters& v6dhcpParms,
1381 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001382{
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001383 bool ipv4Active = translateDhcpEnabledToBool(ethData.dhcpEnabled, true);
1384 bool ipv6Active = translateDhcpEnabledToBool(ethData.dhcpEnabled, false);
Ed Tanousbf648f72021-06-03 15:00:14 -07001385
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001386 if (ipv4Active)
1387 {
1388 updateIPv4DefaultGateway(ifaceId, "", asyncResp);
1389 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001390 bool nextv4DHCPState =
1391 v4dhcpParms.dhcpv4Enabled ? *v4dhcpParms.dhcpv4Enabled : ipv4Active;
1392
1393 bool nextv6DHCPState{};
1394 if (v6dhcpParms.dhcpv6OperatingMode)
1395 {
Ravi Tejab10d8db2022-05-24 09:04:12 -05001396 if ((*v6dhcpParms.dhcpv6OperatingMode != "Enabled") &&
Ed Tanousbf648f72021-06-03 15:00:14 -07001397 (*v6dhcpParms.dhcpv6OperatingMode != "Disabled"))
1398 {
1399 messages::propertyValueFormatError(asyncResp->res,
1400 *v6dhcpParms.dhcpv6OperatingMode,
1401 "OperatingMode");
1402 return;
1403 }
Ravi Tejab10d8db2022-05-24 09:04:12 -05001404 nextv6DHCPState = (*v6dhcpParms.dhcpv6OperatingMode == "Enabled");
Ed Tanousbf648f72021-06-03 15:00:14 -07001405 }
1406 else
1407 {
1408 nextv6DHCPState = ipv6Active;
1409 }
1410
Jishnu CMe4588152023-05-11 00:04:40 -05001411 bool nextDNSv4 = ethData.dnsv4Enabled;
1412 bool nextDNSv6 = ethData.dnsv6Enabled;
1413 if (v4dhcpParms.useDnsServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001414 {
Jishnu CMe4588152023-05-11 00:04:40 -05001415 nextDNSv4 = *v4dhcpParms.useDnsServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001416 }
Jishnu CMe4588152023-05-11 00:04:40 -05001417 if (v6dhcpParms.useDnsServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001418 {
Jishnu CMe4588152023-05-11 00:04:40 -05001419 nextDNSv6 = *v6dhcpParms.useDnsServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001420 }
1421
Jishnu CMe4588152023-05-11 00:04:40 -05001422 bool nextNTPv4 = ethData.ntpv4Enabled;
1423 bool nextNTPv6 = ethData.ntpv6Enabled;
1424 if (v4dhcpParms.useNtpServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001425 {
Jishnu CMe4588152023-05-11 00:04:40 -05001426 nextNTPv4 = *v4dhcpParms.useNtpServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001427 }
Jishnu CMe4588152023-05-11 00:04:40 -05001428 if (v6dhcpParms.useNtpServers)
Ed Tanousbf648f72021-06-03 15:00:14 -07001429 {
Jishnu CMe4588152023-05-11 00:04:40 -05001430 nextNTPv6 = *v6dhcpParms.useNtpServers;
Ed Tanousbf648f72021-06-03 15:00:14 -07001431 }
1432
Ravi Teja91c441e2024-02-23 09:03:43 -06001433 bool nextUsev4Domain = ethData.domainv4Enabled;
1434 bool nextUsev6Domain = ethData.domainv6Enabled;
Jishnu CMe4588152023-05-11 00:04:40 -05001435 if (v4dhcpParms.useDomainName)
Ed Tanousbf648f72021-06-03 15:00:14 -07001436 {
Jishnu CMe4588152023-05-11 00:04:40 -05001437 nextUsev4Domain = *v4dhcpParms.useDomainName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001438 }
Jishnu CMe4588152023-05-11 00:04:40 -05001439 if (v6dhcpParms.useDomainName)
Ed Tanousbf648f72021-06-03 15:00:14 -07001440 {
Jishnu CMe4588152023-05-11 00:04:40 -05001441 nextUsev6Domain = *v6dhcpParms.useDomainName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001442 }
1443
Ed Tanous62598e32023-07-17 17:06:25 -07001444 BMCWEB_LOG_DEBUG("set DHCPEnabled...");
Ed Tanousbf648f72021-06-03 15:00:14 -07001445 setDHCPEnabled(ifaceId, "DHCPEnabled", nextv4DHCPState, nextv6DHCPState,
1446 asyncResp);
Ed Tanous62598e32023-07-17 17:06:25 -07001447 BMCWEB_LOG_DEBUG("set DNSEnabled...");
Jishnu CMe4588152023-05-11 00:04:40 -05001448 setDHCPConfig("DNSEnabled", nextDNSv4, asyncResp, ifaceId,
1449 NetworkType::dhcp4);
Ed Tanous62598e32023-07-17 17:06:25 -07001450 BMCWEB_LOG_DEBUG("set NTPEnabled...");
Jishnu CMe4588152023-05-11 00:04:40 -05001451 setDHCPConfig("NTPEnabled", nextNTPv4, asyncResp, ifaceId,
1452 NetworkType::dhcp4);
Ravi Teja91c441e2024-02-23 09:03:43 -06001453 BMCWEB_LOG_DEBUG("set DomainEnabled...");
1454 setDHCPConfig("DomainEnabled", nextUsev4Domain, asyncResp, ifaceId,
Jishnu CMe4588152023-05-11 00:04:40 -05001455 NetworkType::dhcp4);
1456 BMCWEB_LOG_DEBUG("set DNSEnabled for dhcp6...");
1457 setDHCPConfig("DNSEnabled", nextDNSv6, asyncResp, ifaceId,
1458 NetworkType::dhcp6);
1459 BMCWEB_LOG_DEBUG("set NTPEnabled for dhcp6...");
1460 setDHCPConfig("NTPEnabled", nextNTPv6, asyncResp, ifaceId,
1461 NetworkType::dhcp6);
Ravi Teja91c441e2024-02-23 09:03:43 -06001462 BMCWEB_LOG_DEBUG("set DomainEnabled for dhcp6...");
1463 setDHCPConfig("DomainEnabled", nextUsev6Domain, asyncResp, ifaceId,
Jishnu CMe4588152023-05-11 00:04:40 -05001464 NetworkType::dhcp6);
Ed Tanousbf648f72021-06-03 15:00:14 -07001465}
1466
Ed Tanous77179532023-02-28 10:45:28 -08001467inline std::vector<IPv4AddressData>::const_iterator getNextStaticIpEntry(
1468 const std::vector<IPv4AddressData>::const_iterator& head,
1469 const std::vector<IPv4AddressData>::const_iterator& end)
Ed Tanousbf648f72021-06-03 15:00:14 -07001470{
1471 return std::find_if(head, end, [](const IPv4AddressData& value) {
1472 return value.origin == "Static";
1473 });
1474}
1475
Ed Tanous77179532023-02-28 10:45:28 -08001476inline std::vector<IPv6AddressData>::const_iterator getNextStaticIpEntry(
1477 const std::vector<IPv6AddressData>::const_iterator& head,
1478 const std::vector<IPv6AddressData>::const_iterator& end)
Ed Tanousbf648f72021-06-03 15:00:14 -07001479{
1480 return std::find_if(head, end, [](const IPv6AddressData& value) {
1481 return value.origin == "Static";
1482 });
1483}
1484
Ed Tanous3dfed532024-03-06 14:41:27 -08001485inline void handleIPv4StaticPatch(
1486 const std::string& ifaceId,
1487 std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>& input,
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001488 const EthernetInterfaceData& ethData,
Ed Tanous3dfed532024-03-06 14:41:27 -08001489 const std::vector<IPv4AddressData>& ipv4Data,
1490 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanousbf648f72021-06-03 15:00:14 -07001491{
Ed Tanousbf648f72021-06-03 15:00:14 -07001492 unsigned entryIdx = 1;
1493 // Find the first static IP address currently active on the NIC and
1494 // match it to the first JSON element in the IPv4StaticAddresses array.
1495 // Match each subsequent JSON element to the next static IP programmed
1496 // into the NIC.
Ed Tanous77179532023-02-28 10:45:28 -08001497 std::vector<IPv4AddressData>::const_iterator nicIpEntry =
Ed Tanousbf648f72021-06-03 15:00:14 -07001498 getNextStaticIpEntry(ipv4Data.cbegin(), ipv4Data.cend());
1499
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001500 bool gatewayValueAssigned{};
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001501 bool preserveGateway{};
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001502 std::string activePath{};
1503 std::string activeGateway{};
1504 if (!ethData.defaultGateway.empty() && ethData.defaultGateway != "0.0.0.0")
1505 {
1506 // The NIC is already configured with a default gateway. Use this if
1507 // the leading entry in the PATCH is '{}', which is preserving an active
1508 // static address.
1509 activeGateway = ethData.defaultGateway;
1510 activePath = "IPv4StaticAddresses/1";
1511 gatewayValueAssigned = true;
1512 }
1513
Ed Tanous3dfed532024-03-06 14:41:27 -08001514 for (std::variant<nlohmann::json::object_t, std::nullptr_t>& thisJson :
1515 input)
Ed Tanousbf648f72021-06-03 15:00:14 -07001516 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001517 std::string pathString =
1518 "IPv4StaticAddresses/" + std::to_string(entryIdx);
Ed Tanous3dfed532024-03-06 14:41:27 -08001519 nlohmann::json::object_t* obj =
1520 std::get_if<nlohmann::json::object_t>(&thisJson);
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001521 if (obj == nullptr)
1522 {
1523 if (nicIpEntry != ipv4Data.cend())
1524 {
1525 deleteIPAddress(ifaceId, nicIpEntry->id, asyncResp);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001526 nicIpEntry =
1527 getNextStaticIpEntry(++nicIpEntry, ipv4Data.cend());
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001528 if (!preserveGateway && (nicIpEntry == ipv4Data.cend()))
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001529 {
1530 // All entries have been processed, and this last has
1531 // requested the IP address be deleted. No prior entry
1532 // performed an action that created or modified a
1533 // gateway. Deleting this IP address means the default
1534 // gateway entry has to be removed as well.
1535 updateIPv4DefaultGateway(ifaceId, "", asyncResp);
1536 }
1537 entryIdx++;
1538 continue;
1539 }
1540 // Received a DELETE action on an entry not assigned to the NIC
1541 messages::resourceCannotBeDeleted(asyncResp->res);
1542 return;
1543 }
1544
1545 // An Add/Modify action is requested
1546 if (!obj->empty())
Ed Tanousbf648f72021-06-03 15:00:14 -07001547 {
1548 std::optional<std::string> address;
1549 std::optional<std::string> subnetMask;
1550 std::optional<std::string> gateway;
1551
Ed Tanous3dfed532024-03-06 14:41:27 -08001552 if (!json_util::readJsonObject(*obj, asyncResp->res, "Address",
1553 address, "SubnetMask", subnetMask,
1554 "Gateway", gateway))
Ed Tanousbf648f72021-06-03 15:00:14 -07001555 {
Ed Tanous3dfed532024-03-06 14:41:27 -08001556 messages::propertyValueFormatError(asyncResp->res, *obj,
Ed Tanousf818b042022-06-27 13:17:35 -07001557 pathString);
Ed Tanousbf648f72021-06-03 15:00:14 -07001558 return;
1559 }
1560
1561 // Find the address/subnet/gateway values. Any values that are
1562 // not explicitly provided are assumed to be unmodified from the
1563 // current state of the interface. Merge existing state into the
1564 // current request.
Ed Tanousbf648f72021-06-03 15:00:14 -07001565 if (address)
1566 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001567 if (!ip_util::ipv4VerifyIpAndGetBitcount(*address))
Ed Tanousbf648f72021-06-03 15:00:14 -07001568 {
1569 messages::propertyValueFormatError(asyncResp->res, *address,
1570 pathString + "/Address");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001571 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001572 }
1573 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001574 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001575 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001576 address = (nicIpEntry->address);
Ed Tanousbf648f72021-06-03 15:00:14 -07001577 }
1578 else
1579 {
1580 messages::propertyMissing(asyncResp->res,
1581 pathString + "/Address");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001582 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001583 }
1584
Ed Tanouse01d0c32023-06-30 13:21:32 -07001585 uint8_t prefixLength = 0;
Ed Tanousbf648f72021-06-03 15:00:14 -07001586 if (subnetMask)
1587 {
Ed Tanous033f1e42022-08-15 09:47:37 -07001588 if (!ip_util::ipv4VerifyIpAndGetBitcount(*subnetMask,
1589 &prefixLength))
Ed Tanousbf648f72021-06-03 15:00:14 -07001590 {
1591 messages::propertyValueFormatError(
1592 asyncResp->res, *subnetMask,
1593 pathString + "/SubnetMask");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001594 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001595 }
1596 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001597 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001598 {
Ed Tanous033f1e42022-08-15 09:47:37 -07001599 if (!ip_util::ipv4VerifyIpAndGetBitcount(nicIpEntry->netmask,
1600 &prefixLength))
Ed Tanousbf648f72021-06-03 15:00:14 -07001601 {
1602 messages::propertyValueFormatError(
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001603 asyncResp->res, nicIpEntry->netmask,
Ed Tanousbf648f72021-06-03 15:00:14 -07001604 pathString + "/SubnetMask");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001605 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001606 }
1607 }
1608 else
1609 {
1610 messages::propertyMissing(asyncResp->res,
1611 pathString + "/SubnetMask");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001612 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001613 }
1614
1615 if (gateway)
1616 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001617 if (!ip_util::ipv4VerifyIpAndGetBitcount(*gateway))
Ed Tanousbf648f72021-06-03 15:00:14 -07001618 {
1619 messages::propertyValueFormatError(asyncResp->res, *gateway,
1620 pathString + "/Gateway");
Ed Tanouse01d0c32023-06-30 13:21:32 -07001621 return;
Ed Tanousbf648f72021-06-03 15:00:14 -07001622 }
1623 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001624 else if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001625 {
Ed Tanouse01d0c32023-06-30 13:21:32 -07001626 gateway = nicIpEntry->gateway;
Ed Tanousbf648f72021-06-03 15:00:14 -07001627 }
1628 else
1629 {
1630 messages::propertyMissing(asyncResp->res,
1631 pathString + "/Gateway");
Ed Tanousbf648f72021-06-03 15:00:14 -07001632 return;
1633 }
1634
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001635 if (gatewayValueAssigned)
1636 {
1637 if (activeGateway != gateway)
1638 {
1639 // A NIC can only have a single active gateway value.
1640 // If any gateway in the array of static addresses
1641 // mismatch the PATCH is in error.
1642 std::string arg1 = pathString + "/Gateway";
1643 std::string arg2 = activePath + "/Gateway";
1644 messages::propertyValueConflict(asyncResp->res, arg1, arg2);
1645 return;
1646 }
1647 }
1648 else
1649 {
1650 // Capture the very first gateway value from the incoming
1651 // JSON record and use it at the default gateway.
1652 updateIPv4DefaultGateway(ifaceId, *gateway, asyncResp);
1653 activeGateway = *gateway;
1654 activePath = pathString;
1655 gatewayValueAssigned = true;
1656 }
1657
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001658 if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001659 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001660 deleteAndCreateIPAddress(IpVersion::IpV4, ifaceId,
Ed Tanous77eb0152023-09-06 10:19:18 -07001661 nicIpEntry->id, prefixLength, *address,
1662 *gateway, asyncResp);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001663 nicIpEntry =
1664 getNextStaticIpEntry(++nicIpEntry, ipv4Data.cend());
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001665 preserveGateway = true;
Ed Tanousbf648f72021-06-03 15:00:14 -07001666 }
1667 else
1668 {
1669 createIPv4(ifaceId, prefixLength, *gateway, *address,
1670 asyncResp);
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001671 preserveGateway = true;
Ed Tanousbf648f72021-06-03 15:00:14 -07001672 }
1673 entryIdx++;
1674 }
1675 else
1676 {
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001677 // Received {}, do not modify this address
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001678 if (nicIpEntry != ipv4Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001679 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001680 nicIpEntry =
1681 getNextStaticIpEntry(++nicIpEntry, ipv4Data.cend());
Johnathan Mantey4a8f5d42024-05-24 08:00:46 -07001682 preserveGateway = true;
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001683 entryIdx++;
Ed Tanousbf648f72021-06-03 15:00:14 -07001684 }
Johnathan Mantey743eb1c2024-04-03 12:05:57 -07001685 else
1686 {
1687 // Requested a DO NOT MODIFY action on an entry not assigned
1688 // to the NIC
1689 messages::propertyValueFormatError(asyncResp->res, *obj,
1690 pathString);
1691 return;
1692 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001693 }
1694 }
1695}
1696
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001697inline void handleStaticNameServersPatch(
Ed Tanousbf648f72021-06-03 15:00:14 -07001698 const std::string& ifaceId,
1699 const std::vector<std::string>& updatedStaticNameServers,
1700 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1701{
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001702 setDbusProperty(
Ginu Georgee93abac2024-06-14 17:35:27 +05301703 asyncResp, "StaticNameServers", "xyz.openbmc_project.Network",
Asmitha Karunanithi1847f2a2024-03-26 22:03:48 -05001704 sdbusplus::message::object_path("/xyz/openbmc_project/network") /
1705 ifaceId,
George Liu9ae226f2023-06-21 17:56:46 +08001706 "xyz.openbmc_project.Network.EthernetInterface", "StaticNameServers",
Ginu Georgee93abac2024-06-14 17:35:27 +05301707 updatedStaticNameServers);
Ed Tanousbf648f72021-06-03 15:00:14 -07001708}
1709
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001710inline void handleIPv6StaticAddressesPatch(
Ed Tanous3dfed532024-03-06 14:41:27 -08001711 const std::string& ifaceId,
1712 std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>& input,
Ed Tanous77179532023-02-28 10:45:28 -08001713 const std::vector<IPv6AddressData>& ipv6Data,
Ed Tanousbf648f72021-06-03 15:00:14 -07001714 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1715{
Ed Tanousbf648f72021-06-03 15:00:14 -07001716 size_t entryIdx = 1;
Ed Tanous77179532023-02-28 10:45:28 -08001717 std::vector<IPv6AddressData>::const_iterator nicIpEntry =
Ed Tanousbf648f72021-06-03 15:00:14 -07001718 getNextStaticIpEntry(ipv6Data.cbegin(), ipv6Data.cend());
Ed Tanous3dfed532024-03-06 14:41:27 -08001719 for (std::variant<nlohmann::json::object_t, std::nullptr_t>& thisJson :
1720 input)
Ed Tanousbf648f72021-06-03 15:00:14 -07001721 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001722 std::string pathString =
1723 "IPv6StaticAddresses/" + std::to_string(entryIdx);
Ed Tanous3dfed532024-03-06 14:41:27 -08001724 nlohmann::json::object_t* obj =
1725 std::get_if<nlohmann::json::object_t>(&thisJson);
1726 if (obj != nullptr && !obj->empty())
Ed Tanousbf648f72021-06-03 15:00:14 -07001727 {
1728 std::optional<std::string> address;
1729 std::optional<uint8_t> prefixLength;
Ed Tanous3dfed532024-03-06 14:41:27 -08001730 nlohmann::json::object_t thisJsonCopy = *obj;
1731 if (!json_util::readJsonObject(thisJsonCopy, asyncResp->res,
1732 "Address", address, "PrefixLength",
1733 prefixLength))
Ed Tanousbf648f72021-06-03 15:00:14 -07001734 {
Ed Tanous3dfed532024-03-06 14:41:27 -08001735 messages::propertyValueFormatError(asyncResp->res, thisJsonCopy,
Ed Tanousf818b042022-06-27 13:17:35 -07001736 pathString);
Ed Tanousbf648f72021-06-03 15:00:14 -07001737 return;
1738 }
1739
Ed Tanousbf648f72021-06-03 15:00:14 -07001740 // Find the address and prefixLength values. Any values that are
1741 // not explicitly provided are assumed to be unmodified from the
1742 // current state of the interface. Merge existing state into the
1743 // current request.
Ed Tanousd547d8d2024-03-16 18:04:41 -07001744 if (!address)
Ed Tanousbf648f72021-06-03 15:00:14 -07001745 {
Ed Tanousd547d8d2024-03-16 18:04:41 -07001746 if (nicIpEntry == ipv6Data.end())
1747 {
1748 messages::propertyMissing(asyncResp->res,
1749 pathString + "/Address");
1750 return;
1751 }
1752 address = nicIpEntry->address;
Ed Tanousbf648f72021-06-03 15:00:14 -07001753 }
1754
Ed Tanousd547d8d2024-03-16 18:04:41 -07001755 if (!prefixLength)
Ed Tanousbf648f72021-06-03 15:00:14 -07001756 {
Ed Tanousd547d8d2024-03-16 18:04:41 -07001757 if (nicIpEntry == ipv6Data.end())
1758 {
1759 messages::propertyMissing(asyncResp->res,
1760 pathString + "/PrefixLength");
1761 return;
1762 }
1763 prefixLength = nicIpEntry->prefixLength;
Ed Tanousbf648f72021-06-03 15:00:14 -07001764 }
1765
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001766 if (nicIpEntry != ipv6Data.end())
Ed Tanousbf648f72021-06-03 15:00:14 -07001767 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001768 deleteAndCreateIPAddress(IpVersion::IpV6, ifaceId,
Ed Tanousd547d8d2024-03-16 18:04:41 -07001769 nicIpEntry->id, *prefixLength,
1770 *address, "", asyncResp);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001771 nicIpEntry =
1772 getNextStaticIpEntry(++nicIpEntry, ipv6Data.cend());
Ed Tanousbf648f72021-06-03 15:00:14 -07001773 }
1774 else
1775 {
Ed Tanousd547d8d2024-03-16 18:04:41 -07001776 createIPv6(ifaceId, *prefixLength, *address, asyncResp);
Ed Tanousbf648f72021-06-03 15:00:14 -07001777 }
1778 entryIdx++;
1779 }
1780 else
1781 {
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001782 if (nicIpEntry == ipv6Data.end())
Ed Tanousbf648f72021-06-03 15:00:14 -07001783 {
1784 // Requesting a DELETE/DO NOT MODIFY action for an item
1785 // that isn't present on the eth(n) interface. Input JSON is
1786 // in error, so bail out.
Ed Tanous3dfed532024-03-06 14:41:27 -08001787 if (obj == nullptr)
Ed Tanousbf648f72021-06-03 15:00:14 -07001788 {
1789 messages::resourceCannotBeDeleted(asyncResp->res);
1790 return;
1791 }
Ed Tanous3dfed532024-03-06 14:41:27 -08001792 messages::propertyValueFormatError(asyncResp->res, *obj,
Ed Tanousf818b042022-06-27 13:17:35 -07001793 pathString);
Ed Tanousbf648f72021-06-03 15:00:14 -07001794 return;
1795 }
1796
Ed Tanous3dfed532024-03-06 14:41:27 -08001797 if (obj == nullptr)
Ed Tanousbf648f72021-06-03 15:00:14 -07001798 {
Ravi Teja9c5e5852023-02-26 21:33:52 -06001799 deleteIPAddress(ifaceId, nicIpEntry->id, asyncResp);
Ed Tanousbf648f72021-06-03 15:00:14 -07001800 }
Jiaqing Zhao85ffe862021-12-31 15:41:59 +08001801 if (nicIpEntry != ipv6Data.cend())
Ed Tanousbf648f72021-06-03 15:00:14 -07001802 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001803 nicIpEntry =
1804 getNextStaticIpEntry(++nicIpEntry, ipv6Data.cend());
Ed Tanousbf648f72021-06-03 15:00:14 -07001805 }
1806 entryIdx++;
1807 }
1808 }
1809}
1810
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001811inline std::string extractParentInterfaceName(const std::string& ifaceId)
1812{
1813 std::size_t pos = ifaceId.find('_');
1814 return ifaceId.substr(0, pos);
1815}
1816
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001817inline void parseInterfaceData(
1818 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1819 const std::string& ifaceId, const EthernetInterfaceData& ethData,
1820 const std::vector<IPv4AddressData>& ipv4Data,
1821 const std::vector<IPv6AddressData>& ipv6Data,
1822 const std::vector<StaticGatewayData>& ipv6GatewayData)
Ed Tanousbf648f72021-06-03 15:00:14 -07001823{
Ed Tanousbf648f72021-06-03 15:00:14 -07001824 nlohmann::json& jsonResponse = asyncResp->res.jsonValue;
1825 jsonResponse["Id"] = ifaceId;
Ed Tanous253f11b2024-05-16 09:38:31 -07001826 jsonResponse["@odata.id"] =
1827 boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces/{}",
1828 BMCWEB_REDFISH_MANAGER_URI_NAME, ifaceId);
Ed Tanousbf648f72021-06-03 15:00:14 -07001829 jsonResponse["InterfaceEnabled"] = ethData.nicEnabled;
1830
Ed Tanousbf648f72021-06-03 15:00:14 -07001831 if (ethData.nicEnabled)
1832 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001833 jsonResponse["LinkStatus"] =
1834 ethData.linkUp ? ethernet_interface::LinkStatus::LinkUp
1835 : ethernet_interface::LinkStatus::LinkDown;
1836 jsonResponse["Status"]["State"] = resource::State::Enabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001837 }
1838 else
1839 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001840 jsonResponse["LinkStatus"] = ethernet_interface::LinkStatus::NoLink;
1841 jsonResponse["Status"]["State"] = resource::State::Disabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001842 }
1843
Ed Tanousbf648f72021-06-03 15:00:14 -07001844 jsonResponse["SpeedMbps"] = ethData.speed;
Tejas Patil35fb5312021-09-20 15:35:20 +05301845 jsonResponse["MTUSize"] = ethData.mtuSize;
Asmitha Karunanithi4652c642024-07-30 11:35:53 -05001846 if (ethData.macAddress)
1847 {
1848 jsonResponse["MACAddress"] = *ethData.macAddress;
1849 }
Ed Tanousbf648f72021-06-03 15:00:14 -07001850 jsonResponse["DHCPv4"]["DHCPEnabled"] =
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001851 translateDhcpEnabledToBool(ethData.dhcpEnabled, true);
Jishnu CMe4588152023-05-11 00:04:40 -05001852 jsonResponse["DHCPv4"]["UseNTPServers"] = ethData.ntpv4Enabled;
1853 jsonResponse["DHCPv4"]["UseDNSServers"] = ethData.dnsv4Enabled;
Ravi Tejade9ad762024-06-03 02:00:15 -05001854 jsonResponse["DHCPv4"]["UseDomainName"] = ethData.domainv4Enabled;
Ed Tanousbf648f72021-06-03 15:00:14 -07001855 jsonResponse["DHCPv6"]["OperatingMode"] =
Patrick Williamsbd79bce2024-08-16 15:22:20 -04001856 translateDhcpEnabledToBool(ethData.dhcpEnabled, false)
1857 ? "Enabled"
1858 : "Disabled";
Jishnu CMe4588152023-05-11 00:04:40 -05001859 jsonResponse["DHCPv6"]["UseNTPServers"] = ethData.ntpv6Enabled;
1860 jsonResponse["DHCPv6"]["UseDNSServers"] = ethData.dnsv6Enabled;
Ravi Tejade9ad762024-06-03 02:00:15 -05001861 jsonResponse["DHCPv6"]["UseDomainName"] = ethData.domainv6Enabled;
Ravi Tejab10d8db2022-05-24 09:04:12 -05001862 jsonResponse["StatelessAddressAutoConfig"]["IPv6AutoConfigEnabled"] =
1863 ethData.ipv6AcceptRa;
Ed Tanousbf648f72021-06-03 15:00:14 -07001864
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001865 if (!ethData.hostName.empty())
Ed Tanousbf648f72021-06-03 15:00:14 -07001866 {
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001867 jsonResponse["HostName"] = ethData.hostName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001868
1869 // When domain name is empty then it means, that it is a network
1870 // without domain names, and the host name itself must be treated as
1871 // FQDN
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001872 std::string fqdn = ethData.hostName;
Ed Tanousbf648f72021-06-03 15:00:14 -07001873 if (!ethData.domainnames.empty())
1874 {
1875 fqdn += "." + ethData.domainnames[0];
1876 }
1877 jsonResponse["FQDN"] = fqdn;
1878 }
1879
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001880 if (ethData.vlanId)
1881 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001882 jsonResponse["EthernetInterfaceType"] =
1883 ethernet_interface::EthernetDeviceType::Virtual;
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001884 jsonResponse["VLAN"]["VLANEnable"] = true;
1885 jsonResponse["VLAN"]["VLANId"] = *ethData.vlanId;
1886 jsonResponse["VLAN"]["Tagged"] = true;
1887
1888 nlohmann::json::array_t relatedInterfaces;
1889 nlohmann::json& parentInterface = relatedInterfaces.emplace_back();
1890 parentInterface["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001891 boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces",
1892 BMCWEB_REDFISH_MANAGER_URI_NAME,
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001893 extractParentInterfaceName(ifaceId));
1894 jsonResponse["Links"]["RelatedInterfaces"] =
1895 std::move(relatedInterfaces);
1896 }
1897 else
1898 {
Ed Tanous539d8c62024-06-19 14:38:27 -07001899 jsonResponse["EthernetInterfaceType"] =
1900 ethernet_interface::EthernetDeviceType::Physical;
Jiaqing Zhao7857cb82023-03-03 11:23:08 +08001901 }
1902
Ed Tanousbf648f72021-06-03 15:00:14 -07001903 jsonResponse["NameServers"] = ethData.nameServers;
1904 jsonResponse["StaticNameServers"] = ethData.staticNameServers;
1905
1906 nlohmann::json& ipv4Array = jsonResponse["IPv4Addresses"];
1907 nlohmann::json& ipv4StaticArray = jsonResponse["IPv4StaticAddresses"];
1908 ipv4Array = nlohmann::json::array();
1909 ipv4StaticArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001910 for (const auto& ipv4Config : ipv4Data)
Ed Tanousbf648f72021-06-03 15:00:14 -07001911 {
Ed Tanousbf648f72021-06-03 15:00:14 -07001912 std::string gatewayStr = ipv4Config.gateway;
1913 if (gatewayStr.empty())
1914 {
1915 gatewayStr = "0.0.0.0";
1916 }
Ed Tanous14766872022-03-15 10:44:42 -07001917 nlohmann::json::object_t ipv4;
1918 ipv4["AddressOrigin"] = ipv4Config.origin;
1919 ipv4["SubnetMask"] = ipv4Config.netmask;
1920 ipv4["Address"] = ipv4Config.address;
1921 ipv4["Gateway"] = gatewayStr;
Ed Tanousbf648f72021-06-03 15:00:14 -07001922
Ed Tanousbf648f72021-06-03 15:00:14 -07001923 if (ipv4Config.origin == "Static")
1924 {
Ed Tanous14766872022-03-15 10:44:42 -07001925 ipv4StaticArray.push_back(ipv4);
Ed Tanousbf648f72021-06-03 15:00:14 -07001926 }
Ed Tanous14766872022-03-15 10:44:42 -07001927
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001928 ipv4Array.emplace_back(std::move(ipv4));
Ed Tanousbf648f72021-06-03 15:00:14 -07001929 }
1930
Jiaqing Zhao82695a52022-04-14 15:15:59 +08001931 std::string ipv6GatewayStr = ethData.ipv6DefaultGateway;
Ed Tanousbf648f72021-06-03 15:00:14 -07001932 if (ipv6GatewayStr.empty())
1933 {
1934 ipv6GatewayStr = "0:0:0:0:0:0:0:0";
1935 }
1936
1937 jsonResponse["IPv6DefaultGateway"] = ipv6GatewayStr;
1938
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001939 nlohmann::json::array_t ipv6StaticGatewayArray;
1940 for (const auto& ipv6GatewayConfig : ipv6GatewayData)
1941 {
1942 nlohmann::json::object_t ipv6Gateway;
1943 ipv6Gateway["Address"] = ipv6GatewayConfig.gateway;
Sunitha Harishce73d5c2023-04-07 06:46:49 -05001944 ipv6StaticGatewayArray.emplace_back(std::move(ipv6Gateway));
1945 }
1946 jsonResponse["IPv6StaticDefaultGateways"] =
1947 std::move(ipv6StaticGatewayArray);
1948
Ed Tanousbf648f72021-06-03 15:00:14 -07001949 nlohmann::json& ipv6Array = jsonResponse["IPv6Addresses"];
1950 nlohmann::json& ipv6StaticArray = jsonResponse["IPv6StaticAddresses"];
1951 ipv6Array = nlohmann::json::array();
1952 ipv6StaticArray = nlohmann::json::array();
1953 nlohmann::json& ipv6AddrPolicyTable =
1954 jsonResponse["IPv6AddressPolicyTable"];
1955 ipv6AddrPolicyTable = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001956 for (const auto& ipv6Config : ipv6Data)
Ed Tanousbf648f72021-06-03 15:00:14 -07001957 {
Ed Tanous14766872022-03-15 10:44:42 -07001958 nlohmann::json::object_t ipv6;
1959 ipv6["Address"] = ipv6Config.address;
1960 ipv6["PrefixLength"] = ipv6Config.prefixLength;
1961 ipv6["AddressOrigin"] = ipv6Config.origin;
Sunitha Harishf8361272023-03-16 03:23:59 -05001962
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001963 ipv6Array.emplace_back(std::move(ipv6));
Ed Tanousbf648f72021-06-03 15:00:14 -07001964 if (ipv6Config.origin == "Static")
1965 {
Ed Tanous14766872022-03-15 10:44:42 -07001966 nlohmann::json::object_t ipv6Static;
1967 ipv6Static["Address"] = ipv6Config.address;
1968 ipv6Static["PrefixLength"] = ipv6Config.prefixLength;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001969 ipv6StaticArray.emplace_back(std::move(ipv6Static));
Ed Tanousbf648f72021-06-03 15:00:14 -07001970 }
1971 }
1972}
1973
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08001974inline void afterDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1975 const std::string& ifaceId,
1976 const boost::system::error_code& ec,
1977 const sdbusplus::message_t& m)
1978{
1979 if (!ec)
1980 {
1981 return;
1982 }
1983 const sd_bus_error* dbusError = m.get_error();
1984 if (dbusError == nullptr)
1985 {
1986 messages::internalError(asyncResp->res);
1987 return;
1988 }
Ed Tanous62598e32023-07-17 17:06:25 -07001989 BMCWEB_LOG_DEBUG("DBus error: {}", dbusError->name);
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08001990
1991 if (std::string_view("org.freedesktop.DBus.Error.UnknownObject") ==
1992 dbusError->name)
1993 {
1994 messages::resourceNotFound(asyncResp->res, "EthernetInterface",
1995 ifaceId);
1996 return;
1997 }
1998 if (std::string_view("org.freedesktop.DBus.Error.UnknownMethod") ==
1999 dbusError->name)
2000 {
2001 messages::resourceCannotBeDeleted(asyncResp->res);
2002 return;
2003 }
2004 messages::internalError(asyncResp->res);
2005}
2006
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002007inline void afterVlanCreate(
2008 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2009 const std::string& parentInterfaceUri, const std::string& vlanInterface,
2010 const boost::system::error_code& ec, const sdbusplus::message_t& m
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002011
2012)
2013{
2014 if (ec)
2015 {
2016 const sd_bus_error* dbusError = m.get_error();
2017 if (dbusError == nullptr)
2018 {
2019 messages::internalError(asyncResp->res);
2020 return;
2021 }
Ed Tanous62598e32023-07-17 17:06:25 -07002022 BMCWEB_LOG_DEBUG("DBus error: {}", dbusError->name);
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002023
2024 if (std::string_view(
2025 "xyz.openbmc_project.Common.Error.ResourceNotFound") ==
2026 dbusError->name)
2027 {
2028 messages::propertyValueNotInList(
2029 asyncResp->res, parentInterfaceUri,
2030 "Links/RelatedInterfaces/0/@odata.id");
2031 return;
2032 }
2033 if (std::string_view(
2034 "xyz.openbmc_project.Common.Error.InvalidArgument") ==
2035 dbusError->name)
2036 {
2037 messages::resourceAlreadyExists(asyncResp->res, "EthernetInterface",
2038 "Id", vlanInterface);
2039 return;
2040 }
2041 messages::internalError(asyncResp->res);
2042 return;
2043 }
2044
Ed Tanous253f11b2024-05-16 09:38:31 -07002045 const boost::urls::url vlanInterfaceUri =
2046 boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces/{}",
2047 BMCWEB_REDFISH_MANAGER_URI_NAME, vlanInterface);
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002048 asyncResp->res.addHeader("Location", vlanInterfaceUri.buffer());
2049}
2050
Ed Tanousbf648f72021-06-03 15:00:14 -07002051inline void requestEthernetInterfacesRoutes(App& app)
2052{
Ed Tanous253f11b2024-05-16 09:38:31 -07002053 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/")
Ed Tanoused398212021-06-09 17:05:54 -07002054 .privileges(redfish::privileges::getEthernetInterfaceCollection)
Ed Tanous14766872022-03-15 10:44:42 -07002055 .methods(boost::beast::http::verb::get)(
2056 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002057 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2058 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002059 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2060 {
2061 return;
2062 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002063
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002064 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2065 {
2066 messages::resourceNotFound(asyncResp->res, "Manager",
2067 managerId);
2068 return;
2069 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002070
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002071 asyncResp->res.jsonValue["@odata.type"] =
2072 "#EthernetInterfaceCollection.EthernetInterfaceCollection";
2073 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2074 "/redfish/v1/Managers/{}/EthernetInterfaces",
2075 BMCWEB_REDFISH_MANAGER_URI_NAME);
2076 asyncResp->res.jsonValue["Name"] =
2077 "Ethernet Network Interface Collection";
2078 asyncResp->res.jsonValue["Description"] =
2079 "Collection of EthernetInterfaces for this Manager";
2080
2081 // Get eth interface list, and call the below callback for JSON
2082 // preparation
2083 getEthernetIfaceList(
2084 [asyncResp](const bool& success,
2085 const std::vector<std::string>& ifaceList) {
2086 if (!success)
2087 {
2088 messages::internalError(asyncResp->res);
2089 return;
2090 }
2091
2092 nlohmann::json& ifaceArray =
2093 asyncResp->res.jsonValue["Members"];
2094 ifaceArray = nlohmann::json::array();
2095 for (const std::string& ifaceItem : ifaceList)
2096 {
2097 nlohmann::json::object_t iface;
2098 iface["@odata.id"] = boost::urls::format(
2099 "/redfish/v1/Managers/{}/EthernetInterfaces/{}",
2100 BMCWEB_REDFISH_MANAGER_URI_NAME, ifaceItem);
2101 ifaceArray.push_back(std::move(iface));
2102 }
2103
2104 asyncResp->res.jsonValue["Members@odata.count"] =
2105 ifaceArray.size();
2106 asyncResp->res.jsonValue["@odata.id"] =
2107 boost::urls::format(
2108 "/redfish/v1/Managers/{}/EthernetInterfaces",
Ed Tanous253f11b2024-05-16 09:38:31 -07002109 BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002110 });
2111 });
Johnathan Mantey01784822019-06-18 12:44:21 -07002112
Ed Tanous253f11b2024-05-16 09:38:31 -07002113 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/")
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002114 .privileges(redfish::privileges::postEthernetInterfaceCollection)
2115 .methods(boost::beast::http::verb::post)(
2116 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002117 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2118 const std::string& managerId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002119 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2120 {
2121 return;
2122 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002123
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002124 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2125 {
2126 messages::resourceNotFound(asyncResp->res, "Manager",
2127 managerId);
2128 return;
2129 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002130
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002131 bool vlanEnable = false;
2132 uint32_t vlanId = 0;
2133 std::vector<nlohmann::json::object_t> relatedInterfaces;
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002134
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002135 if (!json_util::readJsonPatch(
2136 req, asyncResp->res, "VLAN/VLANEnable", vlanEnable,
2137 "VLAN/VLANId", vlanId, "Links/RelatedInterfaces",
2138 relatedInterfaces))
2139 {
2140 return;
2141 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002142
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002143 if (relatedInterfaces.size() != 1)
2144 {
2145 messages::arraySizeTooLong(asyncResp->res,
2146 "Links/RelatedInterfaces",
2147 relatedInterfaces.size());
2148 return;
2149 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002150
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002151 std::string parentInterfaceUri;
2152 if (!json_util::readJsonObject(relatedInterfaces[0],
2153 asyncResp->res, "@odata.id",
2154 parentInterfaceUri))
2155 {
2156 messages::propertyMissing(
2157 asyncResp->res, "Links/RelatedInterfaces/0/@odata.id");
2158 return;
2159 }
2160 BMCWEB_LOG_INFO("Parent Interface URI: {}", parentInterfaceUri);
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002161
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002162 boost::system::result<boost::urls::url_view> parsedUri =
2163 boost::urls::parse_relative_ref(parentInterfaceUri);
2164 if (!parsedUri)
2165 {
2166 messages::propertyValueFormatError(
2167 asyncResp->res, parentInterfaceUri,
2168 "Links/RelatedInterfaces/0/@odata.id");
2169 return;
2170 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002171
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002172 std::string parentInterface;
2173 if (!crow::utility::readUrlSegments(
2174 *parsedUri, "redfish", "v1", "Managers", "bmc",
2175 "EthernetInterfaces", std::ref(parentInterface)))
2176 {
2177 messages::propertyValueNotInList(
2178 asyncResp->res, parentInterfaceUri,
2179 "Links/RelatedInterfaces/0/@odata.id");
2180 return;
2181 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002182
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002183 if (!vlanEnable)
2184 {
2185 // In OpenBMC implementation, VLANEnable cannot be false on
2186 // create
2187 messages::propertyValueIncorrect(
2188 asyncResp->res, "VLAN/VLANEnable", "false");
2189 return;
2190 }
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002191
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002192 std::string vlanInterface =
2193 parentInterface + "_" + std::to_string(vlanId);
2194 crow::connections::systemBus->async_method_call(
2195 [asyncResp, parentInterfaceUri,
2196 vlanInterface](const boost::system::error_code& ec,
2197 const sdbusplus::message_t& m) {
2198 afterVlanCreate(asyncResp, parentInterfaceUri,
2199 vlanInterface, ec, m);
2200 },
2201 "xyz.openbmc_project.Network",
2202 "/xyz/openbmc_project/network",
2203 "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
2204 parentInterface, vlanId);
2205 });
Jiaqing Zhaob5ca3fd2023-03-08 15:14:58 +08002206
Ed Tanous253f11b2024-05-16 09:38:31 -07002207 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002208 .privileges(redfish::privileges::getEthernetInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07002209 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002210 [&app](const crow::Request& req,
2211 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002212 const std::string& managerId, const std::string& ifaceId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002213 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2214 {
2215 return;
2216 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002217
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002218 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2219 {
2220 messages::resourceNotFound(asyncResp->res, "Manager",
2221 managerId);
2222 return;
2223 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002224
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002225 getEthernetIfaceData(
2226 ifaceId,
2227 [asyncResp, ifaceId](
2228 const bool& success,
2229 const EthernetInterfaceData& ethData,
2230 const std::vector<IPv4AddressData>& ipv4Data,
2231 const std::vector<IPv6AddressData>& ipv6Data,
2232 const std::vector<StaticGatewayData>& ipv6GatewayData) {
2233 if (!success)
2234 {
2235 // TODO(Pawel)consider distinguish between non
2236 // existing object, and other errors
2237 messages::resourceNotFound(
2238 asyncResp->res, "EthernetInterface", ifaceId);
2239 return;
2240 }
Johnathan Mantey01784822019-06-18 12:44:21 -07002241
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002242 asyncResp->res.jsonValue["@odata.type"] =
2243 "#EthernetInterface.v1_9_0.EthernetInterface";
2244 asyncResp->res.jsonValue["Name"] =
2245 "Manager Ethernet Interface";
2246 asyncResp->res.jsonValue["Description"] =
2247 "Management Network Interface";
Ratan Guptaf476acb2019-03-02 16:46:57 +05302248
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002249 parseInterfaceData(asyncResp, ifaceId, ethData,
2250 ipv4Data, ipv6Data, ipv6GatewayData);
2251 });
2252 });
Johnathan Mantey01784822019-06-18 12:44:21 -07002253
Ed Tanous253f11b2024-05-16 09:38:31 -07002254 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002255 .privileges(redfish::privileges::patchEthernetInterface)
Ed Tanousbf648f72021-06-03 15:00:14 -07002256 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002257 [&app](const crow::Request& req,
2258 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002259 const std::string& managerId, const std::string& ifaceId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002260 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2261 {
2262 return;
2263 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002264
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002265 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2266 {
2267 messages::resourceNotFound(asyncResp->res, "Manager",
2268 managerId);
2269 return;
2270 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002271
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002272 std::optional<std::string> hostname;
2273 std::optional<std::string> fqdn;
2274 std::optional<std::string> macAddress;
2275 std::optional<std::string> ipv6DefaultGateway;
2276 std::optional<std::vector<
2277 std::variant<nlohmann::json::object_t, std::nullptr_t>>>
2278 ipv4StaticAddresses;
2279 std::optional<std::vector<
2280 std::variant<nlohmann::json::object_t, std::nullptr_t>>>
2281 ipv6StaticAddresses;
2282 std::optional<std::vector<
2283 std::variant<nlohmann::json::object_t, std::nullptr_t>>>
2284 ipv6StaticDefaultGateways;
2285 std::optional<std::vector<std::string>> staticNameServers;
2286 std::optional<bool> ipv6AutoConfigEnabled;
2287 std::optional<bool> interfaceEnabled;
2288 std::optional<size_t> mtuSize;
2289 DHCPParameters v4dhcpParms;
2290 DHCPParameters v6dhcpParms;
2291 // clang-format off
Ed Tanous3dfed532024-03-06 14:41:27 -08002292 if (!json_util::readJsonPatch(req, asyncResp->res,
2293 "DHCPv4/DHCPEnabled", v4dhcpParms.dhcpv4Enabled,
2294 "DHCPv4/UseDNSServers", v4dhcpParms.useDnsServers,
2295 "DHCPv4/UseDomainName", v4dhcpParms.useDomainName,
2296 "DHCPv4/UseNTPServers", v4dhcpParms.useNtpServers,
2297 "DHCPv6/OperatingMode", v6dhcpParms.dhcpv6OperatingMode,
2298 "DHCPv6/UseDNSServers", v6dhcpParms.useDnsServers,
2299 "DHCPv6/UseDomainName", v6dhcpParms.useDomainName,
2300 "DHCPv6/UseNTPServers", v6dhcpParms.useNtpServers,
Ravi Tejab10d8db2022-05-24 09:04:12 -05002301 "FQDN", fqdn,
2302 "HostName", hostname,
2303 "IPv4StaticAddresses", ipv4StaticAddresses,
2304 "IPv6DefaultGateway", ipv6DefaultGateway,
2305 "IPv6StaticAddresses", ipv6StaticAddresses,
Sunitha Harishce73d5c2023-04-07 06:46:49 -05002306 "IPv6StaticDefaultGateways", ipv6StaticDefaultGateways,
Ravi Tejab10d8db2022-05-24 09:04:12 -05002307 "InterfaceEnabled", interfaceEnabled,
2308 "MACAddress", macAddress,
2309 "MTUSize", mtuSize,
2310 "StatelessAddressAutoConfig/IPv6AutoConfigEnabled", ipv6AutoConfigEnabled,
2311 "StaticNameServers", staticNameServers
2312 )
2313 )
Ed Tanous002d39b2022-05-31 08:59:27 -07002314 {
2315 return;
2316 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002317 // clang-format on
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002318
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002319 // Get single eth interface data, and call the below callback
2320 // for JSON preparation
2321 getEthernetIfaceData(
2322 ifaceId,
2323 [asyncResp, ifaceId, hostname = std::move(hostname),
2324 fqdn = std::move(fqdn), macAddress = std::move(macAddress),
2325 ipv4StaticAddresses = std::move(ipv4StaticAddresses),
2326 ipv6DefaultGateway = std::move(ipv6DefaultGateway),
2327 ipv6StaticAddresses = std::move(ipv6StaticAddresses),
2328 ipv6StaticDefaultGateway =
2329 std::move(ipv6StaticDefaultGateways),
2330 staticNameServers = std::move(staticNameServers), mtuSize,
2331 ipv6AutoConfigEnabled,
2332 v4dhcpParms = std::move(v4dhcpParms),
2333 v6dhcpParms = std::move(v6dhcpParms), interfaceEnabled](
2334 const bool success,
2335 const EthernetInterfaceData& ethData,
2336 const std::vector<IPv4AddressData>& ipv4Data,
2337 const std::vector<IPv6AddressData>& ipv6Data,
2338 const std::vector<StaticGatewayData>&
2339 ipv6GatewayData) mutable {
2340 if (!success)
2341 {
2342 // ... otherwise return error
2343 // TODO(Pawel)consider distinguish between non
2344 // existing object, and other errors
2345 messages::resourceNotFound(
2346 asyncResp->res, "EthernetInterface", ifaceId);
2347 return;
2348 }
Ravi Tejae48c0fc2019-04-16 08:37:20 -05002349
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002350 handleDHCPPatch(ifaceId, ethData, v4dhcpParms,
2351 v6dhcpParms, asyncResp);
Tejas Patil35fb5312021-09-20 15:35:20 +05302352
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002353 if (hostname)
2354 {
2355 handleHostnamePatch(*hostname, asyncResp);
2356 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002357
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002358 if (ipv6AutoConfigEnabled)
2359 {
2360 handleSLAACAutoConfigPatch(
2361 ifaceId, *ipv6AutoConfigEnabled, asyncResp);
2362 }
Ravi Tejab10d8db2022-05-24 09:04:12 -05002363
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002364 if (fqdn)
2365 {
2366 handleFqdnPatch(ifaceId, *fqdn, asyncResp);
2367 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002368
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002369 if (macAddress)
2370 {
2371 handleMACAddressPatch(ifaceId, *macAddress,
2372 asyncResp);
2373 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002374
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002375 if (ipv4StaticAddresses)
2376 {
2377 handleIPv4StaticPatch(ifaceId, *ipv4StaticAddresses,
2378 ethData, ipv4Data, asyncResp);
2379 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002380
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002381 if (staticNameServers)
2382 {
2383 handleStaticNameServersPatch(
2384 ifaceId, *staticNameServers, asyncResp);
2385 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002386
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002387 if (ipv6DefaultGateway)
2388 {
2389 messages::propertyNotWritable(asyncResp->res,
2390 "IPv6DefaultGateway");
2391 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002392
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002393 if (ipv6StaticAddresses)
2394 {
2395 handleIPv6StaticAddressesPatch(ifaceId,
2396 *ipv6StaticAddresses,
2397 ipv6Data, asyncResp);
2398 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002399
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002400 if (ipv6StaticDefaultGateway)
2401 {
2402 handleIPv6DefaultGateway(
2403 ifaceId, *ipv6StaticDefaultGateway,
2404 ipv6GatewayData, asyncResp);
2405 }
Sunitha Harishce73d5c2023-04-07 06:46:49 -05002406
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002407 if (interfaceEnabled)
2408 {
2409 setDbusProperty(
2410 asyncResp, "InterfaceEnabled",
Ginu Georgee93abac2024-06-14 17:35:27 +05302411 "xyz.openbmc_project.Network",
Ed Tanousd02aad32024-02-13 14:43:34 -08002412 sdbusplus::message::object_path(
2413 "/xyz/openbmc_project/network") /
2414 ifaceId,
2415 "xyz.openbmc_project.Network.EthernetInterface",
Ginu Georgee93abac2024-06-14 17:35:27 +05302416 "NICEnabled", *interfaceEnabled);
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002417 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002418
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002419 if (mtuSize)
2420 {
2421 handleMTUSizePatch(ifaceId, *mtuSize, asyncResp);
2422 }
2423 });
2424 });
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08002425
Ed Tanous253f11b2024-05-16 09:38:31 -07002426 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/EthernetInterfaces/<str>/")
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08002427 .privileges(redfish::privileges::deleteEthernetInterface)
2428 .methods(boost::beast::http::verb::delete_)(
2429 [&app](const crow::Request& req,
2430 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002431 const std::string& managerId, const std::string& ifaceId) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002432 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2433 {
2434 return;
2435 }
Jiaqing Zhaoe7caf252023-03-09 11:14:44 +08002436
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002437 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2438 {
2439 messages::resourceNotFound(asyncResp->res, "Manager",
2440 managerId);
2441 return;
2442 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002443
Patrick Williamsbd79bce2024-08-16 15:22:20 -04002444 crow::connections::systemBus->async_method_call(
2445 [asyncResp, ifaceId](const boost::system::error_code& ec,
2446 const sdbusplus::message_t& m) {
2447 afterDelete(asyncResp, ifaceId, ec, m);
2448 },
2449 "xyz.openbmc_project.Network",
2450 std::string("/xyz/openbmc_project/network/") + ifaceId,
2451 "xyz.openbmc_project.Object.Delete", "Delete");
2452 });
Ed Tanousbf648f72021-06-03 15:00:14 -07002453}
2454
Ed Tanous1abe55e2018-09-05 08:30:59 -07002455} // namespace redfish