blob: d8c5ae358e5da5a4a320cf641e37d5166ddbe739 [file] [log] [blame]
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +01001/*
Ed Tanous6be832e2024-09-10 11:44:48 -07002Copyright (c) 2018 Intel Corporation
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
Rapkiewicz, Pawel9391bb92018-03-20 03:12:18 +010015*/
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